Quote:
Originally Posted by Vince
One thing I see constantly, and which is not mentioned in the first post, is the excessive usage of GetPlayerName. A player can't change his name while connected (the exception of course being SetPlayerName) so it seems redundant to call the function over and over again. I would say using a wrapper is even worse. Simply store it in a variable when the player connects and then use that variable everywhere. The same goes for GetPlayerIP.
|
What makes it the worst is that there is an internal memcpy or something similar which is slow. However, raw function calls are many faster than dereferencing a 2D array. I have a foreach which is faster than y_iterate because it makes use of native function calls (to a plugin; plugin? that means insertion/deletion should be amazingly fast compared to its PAWN implementation).
Quote:
Originally Posted by Gammix
One thing i see a lot is masking natives. It takes really less time to retrieve player name/ip, yet slower than a variable but variable would only be useful when you are looping alot of players at a high rate, unless it's pretty fine i guess.
|
The speed loss is however, negligible when you create wrappers. In fact, sometimes wise use of wrappers can speed up the execution. Before you even ask me why I keep complaining about your code when you make such wrappers, I say it beacause your wrappers serve no purpose most of the times. You should make functions when you have large chunks of code repeating many times in your script. You may also do so when you have big chunk of code which does a specific job where moving that chunk into a function improves readability.
OT: If you have a function which modifies an array such as insertion, deletion, etc then
Code:
for(new y...)
{
Array[playerid][y] = something;
}
IS SLOWER THAN
Code:
stock DoSomething(arr[])
{
for(new y...)
{
arr[y] = something;
}
}
Why is it so? A quick look at how arrays are dereferenced in PAWN explains it.
AMX Assembly - Arrays & Strings Section
2D Array
Code:
#emit CONST.alt arr //Load the address of the array
#emit CONST.pri 2 //We want to access the 2nd sub-array
#emit IDXADDR //Address of the 2nd element of the major array
#emit MOVE.alt //Keep a copy of that address since we need to add it to the offset to get the address of the sub array
//ALT = PRI = Address of the 2nd element of the major array
#emit LOAD.I
//ALT = Address of the 2nd element of the major array
//PRI = offset relative to the address stored in the ALT to the 2nd sub-array
#emit ADD
//PRI now has the address of the sub-array
#emit MOVE.alt //Move the address of the first element of the sub-array from PRI to ALT
#emit CONST.pri 4 //We want the 4th element of the sub-array
#emit LIDX//Load the value stored at arr[2][4]
1D Array
Code:
#emit CONST.alt array_address
#emit CONST.pri n
#emit IDXADDR //PRI now has the address of the (n + 1)th element
#emit CONST.alt array_address
#emit CONST.pri n
#emit LIDX //PRI now has the value stored in the (n + 1)th element
This is how arrays are passed
Code:
//Pushing the address of the global string
#emit PUSH.C global_str
//Pushing a local string
#emit PUSH.S cmdtext
Which clearly explains why that works. When you push arrays, you push the address of the array so in your function call you recieve a 1D array. The first part of the 2D array dereference code is essentially skipped in every iteration in this case which makes it a whole lot faster.
Its sad that PAWN doesn't provide pointers.