Make vs Ninja Performance Comparison
Ever since I started using CMake to handle generating my build files I have relied on Makefiles. Most linux distributions come with the make command so getting up and running doesn’t require too much effort. Make and its derivatives been around for almost 40 years and it’s an extremely powerful tool that can do many things beyond simply compiling code. There are cases where the flexibility and power of make are overkill in terms of compiling code and if you are willing to trade them with improved performance Ninja might be what you are looking for.
Ninja, written by Evan Martin is a build system that is focused on performance. It was designed for fast incremental builds and large projects in general. To quote the chromium project “Ninja is a build system written with the specific goal of improving the edit-compile cycle time”.
Ninja does not output information about the current progress of the build on more than one line. Warnings and Errors are output like normal. Make on the other hand will output a line for every single cpp file that was compiled and linked. So beyond the performance improvements Ninja has a higher signal to noise ratio than Make.
I wanted to measure the performance of Make and Ninja for several projects, namely chrono and ogre.
- Chrono 383 files
- Ogre 495 files
Compilation will be performed on an Intel Haswell i7-4770K CPU with 32GB of ram. The host OS is Arch Linux and the compiler used is GCC 4.9.2.
To generate files for Ninja use the -G flag in cmake to specify the generator type.
cmake -G Ninja
Commands used for timing
Timing was performed using the linux “time” command and all builds were done in memory and all output was redirected to /dev/null. Redirecting to dev null was performed so that only the timing output would be written to standard out. In practice > /dev/null 2>&1 should not be used.
Results:
Performance for increasing threads, all times are in seconds
Chrono
Threads | Make | Ninja | Speedup |
---|---|---|---|
1 | 73.862 | 71.884 | 1.028 |
2 | 38.065 | 37.007 | 1.029 |
3 | 26.45 | 25.849 | 1.023 |
4 | 21.469 | 20.358 | 1.055 |
5 | 20.13 | 19.503 | 1.032 |
6 | 19.272 | 18.91 | 1.019 |
7 | 18.349 | 18.035 | 1.017 |
8 | 17.898 | 17.407 | 1.028 |
Compiling an already compiled project, compiling after touching a single file. (picked at random)
Touched | Make | Ninja |
---|---|---|
Nothing | 0.22 | 0.008 |
ChSystem.cpp | 2.288 | 2.005 |
Ogre
Threads | Make | Ninja | Speedup |
---|---|---|---|
1 | 644.983 | 641.365 | 1.006 |
2 | 335.196 | 336.222 | 0.997 |
3 | 233.126 | 233.597 | 0.998 |
4 | 182.641 | 184.452 | 0.990 |
5 | 175.907 | 174.221 | 1.010 |
6 | 166.511 | 167.086 | 0.997 |
7 | 159.870 | 158.142 | 1.011 |
8 | 153.529 | 153.901 | 0.998 |
Compiling an already compiled project, compiling after touching a single file. (picked at random)
Touched | Make | Ninja |
---|---|---|
Nothing | 0.465 | 0.035 |
OgrePose.cpp | 5.462 | 4.699 |
Ninja and Make are very close in terms of performance. It has less overhead when performing incremental builds but for full builds any performance gains would be negligible.