[SOLVED] Variable Performance


photo

Recommended Posts

Typically I would store certain types of information in const variables, since it gives type safety as well as letting the compiler know that it wont change, but since there appears to not be const nor type safety in unigen, I was wondering if it would simply be more performant to put this type of data in #defines?  

 

Another question I have is local variables vs member data vs globals.   Typically it would be more performant to copy a variable into a local on the stack before doing operations with it, as apposed to constantly referencing the global variable that could cause more memory instructions and cache misses.  Does such a notion exist in Unigen?

Link to post

Brian, usage of #define for some constants can improve performance, as script compiler has some more optimization options.

 

Constructs that should always be used are the foreach/forloop statements instead of classical for( int i=0; i<..; i++) as these are significantly faster (and also provider cleaner code).

 

Also excessive function calls can have significant performance impact (though UNIGINE compiler can inline automatically simple getter function)

 

Nevertheless I have the feeling, that you are thinking far too much about lowest-level optimizations (variable access, function invocation by index,...).

 

My experience: think and optimize high-level, only do it were neccessary !

 

I would always recommend to implement a "clean" initial code solution and then use excellent UNIGINE profiling (e.g world_analyse,..) to identify real overall performance hot-spots and than only optimize these on-demand

 

Very often one will realize that most of the code does not need any optimization at all and the real performance hot-spot is a different one than previously expected.

 

In addition most of the time "pre-optimized for speed" code also leads to over-complex, error-prone and hard-to-maintain implementations (Which should be avoided due to minimal UNIGINE debugging support).

 

Especially in a scripting environment the general algorithm and design has much more impact on overall performance.

 

Depending on the actual problem caching of objects for avoiding constant rebuild, spatial indexing for faster data search/access, pre-calculated look-up tables for avoiding complex calculations are classical optimization techniques based on trading memory for speed.

 

In a real-time environment with 30+ render frames per second a lot of calculations/updates often can be done at a much lower frequency (e.g. only each 10th frame). UNIGINE provides powerful instructions for spread calculation over frames and cooperative threading (yield/thread/wait).

 

Another often overlooked UNIGINE capability is usage of world script flush() function to implement processor-intensive calculations on the CPU in parallel to the GPU rendering process (which takes huge amounts of the frame time). This can give you a lot of extra CPU-side data processing-time for free and without any negative impact on frame rate (as otherwise the CPU just would wait for GPU render termination).

 

If there are still some low-level code sequences that kill performance (e.g. dynamic texture image manipulations required each frame) than such code should be place in a C++ plugin for gaining maximum low-level performance. Of course here all your above mentinoned thought can be used to optimize such critical code parts.

  • Like 1
Link to post

Ulf, thanks for the so detailed explanation.

 

Declaring constant variables via enum or #define is a preferable way.

Because in that case compiler can calculate constant expression on compilation step.

 

For example to two following scripts are compiled into single constant string:

#define A 10
printf("%s\n",string(vec3(sin(A))));
enum { A = 10 };
printf("%s\n",string(vec3(sin(A))));
0x00000002: pushcc     string: "-0.544021 -0.544021 -0.544021" string: "%s\n"
0x00000005: callefv    printf
 

In same time declaring A as a variable:

int A = 10;
printf("%s\n",string(vec3(sin(A))));
0x00000002: setvc      A = int: 10
0x00000005: pushv      A
0x00000007: callef     sin
0x00000009: callef     vec3
0x0000000b: callef     string
0x0000000d: pushc      string: "%s\n"
0x0000000f: callefv    printf
Link to post

@UNIGINE: as this topic is quite general it might be a good idea to include the explanations/hints somewhere in the documentation.

Link to post

Very interesting topic !!!

i agree with @ulf to add in the documentation 

Link to post