By Michael Hahsler
Looks like you want to improve the runtime of your code. Before you resort to a profiler you should:
- Turn on compiler optimization.
Compilers use code optimization (GCC optimizations).
In VS Code, compile the code using in the bottom bar
CMake:[Release](i.e., with speed optimization) instead ofCMake: [Debug](optimizer disabled). - Use appropriate data structures and algorithms. Determine what you need (fast lookup or fast insertion) and then choose each data structure based on the Big-O notation and experiments. It is highly recommended to use standard library implementations.
- Copying objects. Assigning objects happen in many algorithms. Assigning larger objects by copying is expensive. Make sure you implement move semantics for these objects.
- Avoid recursion and nested loops. Recursions can be replaced by iteration. Often, better algorithms can be used to avoid nested loops.
Profiling Software measures the space (memory) or time used by a program, the usage of particular instructions, or the frequency and duration of function calls. Most commonly, profiling information serves to aid program optimization by pointing the developer to the part of the code that is the slowest or consumes the most memory.
Several open-source and commercial profilers are available (see List of performance analysis tools). Here I use
callgrind and KCachegrind. Alternatives are perf for Linux and WSL2, and Dtrace for MacOS.
Details on callgrind can be found in the callgrind manual. callgrind records each function call and how many machine code instructions were fetched. It can also calculate approximate run time by translating the instructions into cycle estimates.
Installation: You need to install valgrind and KCachgrind on your machine (Linux, WSL2; not available for Mac). If you use a remote Linux servers (e.g., SMU's genuse machines) or WSL2, then you need
to install the X server software on your computer (e.g., Xming or
XQuarz) and start the X server. Now you log into the server using ssh -X username@server in your shell. This will forward the window of kcachegrind from the server to your local desktop.
-
Compile your program with optimization on and debug information included (in VSCode:
[RelWithDebInfo]) -
Run your executable with
valgrind:valgrind --tool=callgrind --dump-instr=yes --simulate-cache=yes --collect-jumps=yes ./<executable> [args...] -
This will produce a
callgrind.out.xxxxxfile. Open the file with:kcachegrind callgrind.out.xxxxxHere is short document on Profiling with Valgrind and visualization with KCachegrind.
-
Find the file/class you are interested in (e.g.,
main.cpp), click on the function below and chooseCall Graphin the bottom right window. You should now see what gets called, how often, and how long it takes (in % of the caller). By default only calls that take long are shown. You can change his by right-click on the graphGraph > Min. Node Cost. -
Identify the functions that takes the most time and are called often. Optimize the code (loops, used algorithms, and data structure) there and profile again to se if and by how much you have improved the runtime (this can be judged by the number of instructions fetched).
All code and documents in this repository are provided under Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) License.
