Raised This Month: $51 Target: $400
 12% 

[EXAMPLE] Optimizing scripts when handling strings or arrays


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
SirLamer
Senior Member
Join Date: Oct 2008
Old 01-06-2009 , 11:48   [EXAMPLE] Optimizing scripts when handling strings or arrays
Reply With Quote #1

Note: The below comments are misguided and should be ignored. They remain for historical purposes only.

I have noticed quite a lot around here, including on the official wiki, significant overuse of array sizing functions to accommodate the array length parameters in many of SourceMod's functions. Of particular concern is how these functions are being used to measure strings and arrays of fixed length as defined during compilation. The sizeof() function must be executed every time it is called, and on a fixed length array it's always going to come up with the same number.

Instead of using this practice, define the array using the #define feature then use the parameter name throughout your code. This allows you to easily change the array length with confidence that the change will propagate through your code. Remember that #define parameters are interpreted by the compiler and are incorporated into the compiled program as though the value were just typed in everywhere.

Here is an example which I pulled straight from the Menu API article on the wiki:
Code:
if (action == MenuAction_Select)
	{
		new String:info[32]
		new bool:found = GetMenuItem(menu, param2, info, sizeof(info))
		PrintToConsole(param1, "You selected item: %d (found? %d info: %s)", param2, found, info)
	}
This would be better as follows:

Code:
if (action == MenuAction_Select)
	{
		#define info_length 32
		new String:info[info_length]
		new bool:found = GetMenuItem(menu, param2, info, info_length)
		PrintToConsole(param1, "You selected item: %d (found? %d info: %s)", param2, found, info)
	}
This will execute in exactly the same way but will run faster. Obviously the performance impact from something like the above is minimal but in other scenarios it can be pretty significant - plus, every little bit helps!

FYI - though I am not 100% certain on this - #define parameters don't have scope but they are read in order from top to bottom while compiling. They have to appear before the parameter name is used in code but where they are in scope is not a factor. The parameter info_length would remain defined for code outside of the if statement and even for subsequent functions - I THINK! However, they can also be re-defined later in the code, though you'll get a compiler warning.

There are many other scenarios where CPU time can be saved by using #define statements or other similar practices instead of using functions like sizeof() all the time. Consider a for loop, where you just have to have the code determine the array length for a good reason.

Many people would code it like this:

Code:
// Array example[] of unknown length was created earlier
for(new i = 0; i < sizeof(example); i++) {
  example[i] *= 2; // Arbitrary in-loop code
}
In this loop, the sizeof() function is called many times - once for each loop. The following optimization is much faster:
Code:
// Array example[] of unknown length was created earlier
example_length = sizeof(example)
for(new i = 0; i < example_length; i++) {
  example[i] *= 2; // Arbitrary in-loop code
}
Remember, fewer lines of code does not necessarily mean faster code!

Anyway, this practice seems rampant so I wanted to comment on it.

Last edited by SirLamer; 01-06-2009 at 12:34.
SirLamer is offline
danielkza
AMX Mod X Plugin Approver
Join Date: May 2007
Location: São Paulo - Brasil
Old 01-06-2009 , 12:14   Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
Reply With Quote #2

sizeof() is a compiler directive, it will never be executed at runtime, it will simply be replaced with the correct number during compilation.
__________________

Community / No support through PM
danielkza is offline
SirLamer
Senior Member
Join Date: Oct 2008
Old 01-06-2009 , 12:33   Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
Reply With Quote #3

Oh... then I am utterly stupid, lol.

Hmm, well I will leave this here for record purposes but leave a big disclaimer up top... embarrassing though it may be!
SirLamer is offline
devicenull
Veteran Member
Join Date: Mar 2004
Location: CT
Old 01-08-2009 , 20:19   Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
Reply With Quote #4

Also, you are talking about optimizing far before it's necessary. With the exception of code running very frequently (GameFrame or 0.1s timers), it's really not necessary to optimize to this level. Who cares if your kick command takes 0.000001s shorter because you used a define?

For the large majority of plugins I've seen, you simply don't need to optimize to this level.
__________________
Various bits of semi-useful code in a bunch of languages: http://code.devicenull.org/
devicenull is offline
Sammy-ROCK!
Senior Member
Join Date: Jun 2008
Location: Near Mrs.Lag
Old 01-09-2009 , 08:47   Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
Reply With Quote #5

Quote:
Originally Posted by devicenull View Post
Also, you are talking about optimizing far before it's necessary. With the exception of code running very frequently (GameFrame or 0.1s timers), it's really not necessary to optimize to this level. Who cares if your kick command takes 0.000001s shorter because you used a define?

For the large majority of plugins I've seen, you simply don't need to optimize to this level.
While peoples think like that something called "Lag" will everlast...
Sammy-ROCK! is offline
SAMURAI16
BANNED
Join Date: Sep 2006
Old 01-09-2009 , 10:28   Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
Reply With Quote #6

on first example, when you used
#define info_length 32
It's stupid to define that there. Could be defined globally e.g. MAX_DATA or something and then used every time when you need
About example #2, danielkza is perfectly right


SAMURAI16 is offline
Send a message via MSN to SAMURAI16
devicenull
Veteran Member
Join Date: Mar 2004
Location: CT
Old 01-09-2009 , 19:38   Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
Reply With Quote #7

Quote:
Originally Posted by Sammy-ROCK! View Post
While peoples think like that something called "Lag" will everlast...
No, not really. Let's take the example of a kick plugin. Kick gets used maybe once an hour at most. Even if your kick function did something very stupid, you would be looking at *one frame* of lag for the server. Given that most servers run at upwards of 250+ FPS, it's just not worth optimizing.

There's tons of information available, just look up "premature optimization" and you will begin to understand.
__________________
Various bits of semi-useful code in a bunch of languages: http://code.devicenull.org/
devicenull is offline
SirLamer
Senior Member
Join Date: Oct 2008
Old 01-12-2009 , 12:33   Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
Reply With Quote #8

It's true that in many contexts there isn't much justification in optimizing, there is never a reason to not optimize, so long as the code remains reasonably easy to understand. So just do it!

Optimization is much more important within looping scripts or scripts that create a session for each client all at once or something like that, but complex structures like these make for very poor and confusing example programs. This simple example could easily be applied to more broad contexts. But remember, I was mistaken in not knowing that the function sizeof() is a compiler directive, hence my surprise to see rampant use all over many programs. For other cases, remember that a function called within the header of a for loop will run not just once but one time for every iteration. So, a 200-cycle loop will call the function 200 times!

Also consider that most game servers are rented and share several machines, which severely restricts available CPU and memory resources as compared to a dedicated or privately owned server machine. If all scripts are CPU and memory-selfish in their design, not considering that they run among several other plugins and even within several other game servers on the same machine, things can get muddled.

I put the #define there just to clearly demonstrate the association as an example, however I disagree with the practice of jamming all the #define parameters at the top of the script as it is much harder then to track relationships should the need arise to edit scripts or move functions around between separate plugins or whatever. I put #define calls up top only when the value is required in more than one place, and otherwise I stack the #define calls at the top of each function. As far as the compiler is concerned, it doesn't matter where the #define calls are as long as they appear in the code before they are put to use (ie. they are not subject to scope). In almost all cases using #define and then applying the parameter name throughout your code is preferred over just manually typing in the values everywhere because it permits rapid refinement and it clearly defines value relationships, which is more more intricate in SourcePawn than in, say, C++ or PHP. For example, defining array lengths with #define parameters avoids the risk of a programmer changing an array length without changing the associated reported "maxlength" in the various functions it is used with.

Last edited by SirLamer; 01-12-2009 at 12:36.
SirLamer is offline
danielkza
AMX Mod X Plugin Approver
Join Date: May 2007
Location: São Paulo - Brasil
Old 01-12-2009 , 15:39   Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
Reply With Quote #9

Quote:
Originally Posted by SirLamer View Post
It's true that in many contexts there isn't much justification in optimizing, there is never a reason to not optimize, so long as the code remains reasonably easy to understand. So just do it!

Optimization is much more important within looping scripts or scripts that create a session for each client all at once or something like that, but complex structures like these make for very poor and confusing example programs. This simple example could easily be applied to more broad contexts. But remember, I was mistaken in not knowing that the function sizeof() is a compiler directive, hence my surprise to see rampant use all over many programs. For other cases, remember that a function called within the header of a for loop will run not just once but one time for every iteration. So, a 200-cycle loop will call the function 200 times!

Also consider that most game servers are rented and share several machines, which severely restricts available CPU and memory resources as compared to a dedicated or privately owned server machine. If all scripts are CPU and memory-selfish in their design, not considering that they run among several other plugins and even within several other game servers on the same machine, things can get muddled.

I put the #define there just to clearly demonstrate the association as an example, however I disagree with the practice of jamming all the #define parameters at the top of the script as it is much harder then to track relationships should the need arise to edit scripts or move functions around between separate plugins or whatever. I put #define calls up top only when the value is required in more than one place, and otherwise I stack the #define calls at the top of each function. As far as the compiler is concerned, it doesn't matter where the #define calls are as long as they appear in the code before they are put to use (ie. they are not subject to scope). In almost all cases using #define and then applying the parameter name throughout your code is preferred over just manually typing in the values everywhere because it permits rapid refinement and it clearly defines value relationships, which is more more intricate in SourcePawn than in, say, C++ or PHP. For example, defining array lengths with #define parameters avoids the risk of a programmer changing an array length without changing the associated reported "maxlength" in the various functions it is used with.
I agree with most of your points, but in regard to your final argument, that was why sizeof() was created, to identify array sizes even if you change them. If you're using a define, you're gonna need to change it anyway,of course doing it once is better than on every reference, but it's even better not to change anything at all. Also, sizeof() has a clear meaning, it clearly identifies what array is being mesured, something not easily discovered just with defines.
__________________

Community / No support through PM

Last edited by danielkza; 01-12-2009 at 15:41.
danielkza is offline
SirLamer
Senior Member
Join Date: Oct 2008
Old 01-12-2009 , 16:06   Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
Reply With Quote #10

Indeed, which is why I put "IGNORE THIS" in bold at the very top of this thread after being advised of that. Computationally, both methods are equivalent while sizeof() is clearer.

There are others similar things, though, like using a function that measures the size of a dynamically sized array or a user-inputted text string in a for loop instead of just storing the array size prior to the loop. I have seen that, too...

Worst of all is typing the array length in manually throughout code, which makes it very laborious to make changes.
SirLamer is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 04:55.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode