High Performance Timers
Profiling Code
Using the SDL_GetTicks() function should be adequate for practically anything that requires timing in games. Chances are if you find you need to measure intervals with precision below 1 ms to get something to work e.g. a phyics effect, you're doing it wrong (or I'm wrong, or both, or neither). Outside of the game but related to it, if you want to profile a part of your code, you have a few options. The first involves the use of low precision timers, such as SDL_GetTicks() or the console command time
, where the code in question is run thousands of times and the time it takes to do these iterations is measured to get the average time of a single run. Another approach is to use a profiling utility such a gprof, however, atleast in the case of gprof it apparently can't profile outside of the main thread without creating a wrapper library for pthreads, and profilers are more useful for showing where your program spends it's time, not for how fast a single piece of code runs.
Then there are high performance counters in SDL, which to use you must have initialised the timer subsystem by setting the flag SDL_INIT_TIMER
when calling SDL_Init
. There are 2 functions involved, Uint64 SDL_GetPerformanceFrequency()
which returns the frequency of the counter e.g. 1000000000 (1 GHz), and Uint64 SDL_GetPerformanceCounter()
, which returns the current time of the counter. To measure a time interval over some code, you need to take the difference in the counter value between the start and end of the code, and then divide that by the frequency:
Uint64 delta = SDL_GetPerfomanceCounter();
/*
(code to be tested here)
*/
delta = SDL_GetPerformanceCounter() - delta;
float pFreq = (float)SDL_GetPerformanceFrequency();
float pDelta = (float)delta;
printf("Time to run code was %e s\n", pDelta/pFreq);
which will give an output like: "Time to run code was 8.763330e-05 s". The calls to SDL_GetPerformanceCounter()
might add a small amount to the count, you can measure it by doing something like:
Uint64 acc = 0;
Uint64 count = 0;
Uint64 delta;
for(i = 0; i < 1000; i++) {
delta = SDL_GetPerformanceCounter();
delta = SDL_GetPerformanceCounter()-delta;
acc += delta;
count++;
}
pdelta = (float)acc;
pdelta /= (float)count;
printf("Delay between calls to getperfcounter: %e s\n", pdelta/pfreq, pfreq);
which for me was 580 ns on average, so it shouldn't really affect your time measurement unless you're only measuring a few lines of code that take less than ~10 us, in which case you should maybe subtract the average time from it.
The time to run a piece of code might change due to different input data or the OS scheduler switching out in the middle of the code. To get around this, you should run the code multiple times and take the average time by calculating the run time delta
as above and then adding it to an accumulator variable and incrementing a counter, so the average can later be calculated. If the code is in another thread, such as the audio callback, you'll need to e.g. lock the audio device if you want to reset this count, and maybe if you want to read it (I don't really understand concurrency). If you do use an accumulator, it should be Uint64, Uint32 could only store ~4.3 s of run time with a 1 GHz counter frequency, which is a lot for small pieces of code but if you have thousands of iterations accumulated it could overflow.
References
- Uses javascript SyntaxHighlighter for syntax highlighting.
- Uses javascript MathJax for LateX rendering.
To the extent possible under law,
Craig Hughes
has waived all copyright and related or neighboring rights to
the text and source code in this example/tutorial.