AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Snippets and Tutorials (https://forums.alliedmods.net/forumdisplay.php?f=112)
-   -   [EXAMPLE] Optimizing scripts when handling strings or arrays (https://forums.alliedmods.net/showthread.php?t=83240)

SirLamer 01-06-2009 11:48

[EXAMPLE] Optimizing scripts when handling strings or arrays
 
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.

danielkza 01-06-2009 12:14

Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
 
sizeof() is a compiler directive, it will never be executed at runtime, it will simply be replaced with the correct number during compilation.

SirLamer 01-06-2009 12:33

Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
 
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!

devicenull 01-08-2009 20:19

Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
 
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.

Sammy-ROCK! 01-09-2009 08:47

Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
 
Quote:

Originally Posted by devicenull (Post 740758)
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...

SAMURAI16 01-09-2009 10:28

Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
 
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



devicenull 01-09-2009 19:38

Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
 
Quote:

Originally Posted by Sammy-ROCK! (Post 740932)
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.

SirLamer 01-12-2009 12:33

Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
 
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.

danielkza 01-12-2009 15:39

Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
 
Quote:

Originally Posted by SirLamer (Post 742907)
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.

SirLamer 01-12-2009 16:06

Re: [EXAMPLE] Optimizing scripts when handling strings or arrays
 
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.


All times are GMT -4. The time now is 00:41.

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