By Paul Dreik 2023-10-15

Measuring build performance

I use the defacto standard cmake for building C++. Build times in C++ is one of the pain points.

One thing I do often is to verify all commits build and pass unit test properly. A full build (including configure, build and running the unit test) must therefore be as fast as possible.

I use ccache and other tricks, I strongly recommend checking out this excellent 2023 talk by Vittorio Romeo.

Measure what cmake is doing during configure

Cmake has profiling capability built in.

cmake -B /tmp/blah -S /path/to/source --profiling-output blaha.json --profiling-format=google-trace

Then I used chrome (not Debian chromium, it does not work) to display the file, using the chrome://tracing/ feature.

Action taken to improve cmake

I immediately found that I used check_cxx_source_compiles to check for the existence of a specific boost feature. The particular header is very heavy. I tried using CHECK_INCLUDE_FILE_CXX to save time, but no significant improvement.

I instead used the following trick:

check_cxx_source_compiles(
    "#if __has_include(<boost/x/y/z.hpp>)
    int main() { }
    #endif" HAS_BOOST_FEATURE)

This trick requires the C++17 feature __has_include. Luckily, I have a pretty high minimum compiler version in this project.

This saved two seconds from the configure time.

Visualizing the build

This is based on the information from this Craig Scott blog entry.

I use the excellent ninja build tool. It generates a log, which can be used to understand the build process.

cmake -B /tmp/blah -S /path/to/source -GNinja
cmake --build /tmp/blah

There is now a .ninja_log file to work with. For some reason, it has an extra newline at the end which must be removed before fed to the next tool.

Get the tool from here.

Then just run

./ninjatracing.py .ninja_log >cmake_build_trace_full.json

and open the json file in chrome. I could verify that there are no significant bottlenecks in my build, but there are some heavy files.

Idea: build scheduling

One thing I noticed is that the end of my build was blocked on a single item. If the builder had known the compile/link time for each step, it could have planned better and started the long running things first. It would be a cool thing if the build could take timings from it’s last build (which often is pretty accurate prediction) and optimize the build order.