| 35 | |
| 36 | == Low-overhead timer == |
| 37 | |
| 38 | A less fancy way to measure sections of code is: |
| 39 | {{{ |
| 40 | #include "lib/timer.h" |
| 41 | ... |
| 42 | { |
| 43 | TIMER(L"description"); |
| 44 | ... code to measure ... |
| 45 | } |
| 46 | }}} |
| 47 | which will record the time from `TIMER` until the end of the current scope, then immediately print it via `debug_printf` (which goes to `stdout` on Unix, and the debugger Output window on Windows). |
| 48 | |
| 49 | To measure cumulative time spent in a section of code: |
| 50 | {{{ |
| 51 | #include "lib/timer.h" |
| 52 | TIMER_ADD_CLIENT(tc_SomeDescription); |
| 53 | ... |
| 54 | { |
| 55 | TIMER_ACCRUE(tc_SomeDescription); |
| 56 | ... code to measure ... |
| 57 | } |
| 58 | }}} |
| 59 | which will sum the time spent, then print it via `debug_printf` once when the game is shutting down. The output will be like |
| 60 | {{{ |
| 61 | TIMER TOTALS (9 clients) |
| 62 | ----------------------------------------------------- |
| 63 | tc_SomeDescription: 10.265 Mc (12x) |
| 64 | ... |
| 65 | }}} |
| 66 | saying the cumulative time, measured in CPU cycles (kc = kilocycles (10^3^), Mc = megacycles (10^6^), etc). (It measures cycles since that's cheaper and more reliable than converting to seconds, given that clock frequency can change while the game is running. Divide by your CPU frequency manually to get real time). This should have significantly lower overhead than `PROFILE`, so you can use it in functions that get called more often. |
| 67 | |
| 68 | == Simulation replay mode == |
| 69 | |
| 70 | If you're not measuring graphics or GUI code, replay mode lets you run the simulation (the gameplay code and scripts and the AI etc) at maximum speed with all graphics disabled. This should be fully deterministic (i.e. you'll get the same results on each run) and doesn't need user interaction (so you can easily run in Valgrind). |
| 71 | |
| 72 | First, play the game normally, in either single-player or multiplayer. It will generate a file `~/.config/0ad/logs/sim_log/${PID}/commands.txt` (or somewhere in `%APPDATA%\logs\` on Windows) based on the process ID; looking for the newest directory should find it. This contains the map setup data and a list of all players' inputs, so the game can be replayed. You might want to copy the `commands.txt` to somewhere memorable. |
| 73 | |
| 74 | Run the game like |
| 75 | {{{ |
| 76 | ./pyrogenesis -replay=path/to/commands.txt |
| 77 | }}} |
| 78 | (or something equivalent on Windows). It will print its status to `stdout` (or the Output window on Windows). It gives the MD5 checksum of the complete simulation state once it's finished, which is handy if you're changing the code and want to make sure you're not affecting the simulation behaviour. Run in a profiler to measure whatever you want to measure. |
| 79 | |
| 80 | It also stores the in-game profiler state in `profile.txt` every 20 turns. There's a script in `source/tools/replayprofile/` which can plot a graph from that file. |
| 81 | |
| 82 | == Valgrind == |
| 83 | |
| 84 | Callgrind with KCacheGrind is quite nice for detailed (though not hugely accurate) profiling. Valgrind often doesn't like !SpiderMonkey's JITs so you may have to use `valgrind --smc-check=all ...` if it otherwise crashes. |