Monday, December 7, 2009

Precompiled Headers

Hello, KDE Planet!

Let me insist with another post about time. But in this case about the time spent compiling programs; always too much, because vita brevis est.

I've added to KMid2's build system a CMake script enabling precompiled headers (PCH) for the GCC compiler. It is optionally enabled using a  CMake option "-DWANT_PCH=yes". I've written this script initially for Rosegarden, and later it has been refined and included in several other projects with the goal of reducing the build time.

Enabling PCH for a project is not automatic. You need to write a header file including enough library headers, and give this big header to the ADD_PRECOMPILED_HEADER macro. It is also a good idea to use ADD_DEPENDENCIES in the targets, to ensure that a PCH file is generated before the target components. The macro automatically adds an "-include" argument to each compilation step in the directory,  so PCH can be enabled or disabled for a project without needing to modify the sources.

The trick is creating the big header file with enough #includes to be worth, but not too much. Compiling the PCH file takes not only time, but also many megabytes of disk space. For KMid2 this header is named "qt_kde.h" and includes mostly Qt and KDE headers, and also several Standard Library and ALSA includes.

From my development machine, here are some measures comparing compile times, with and without PCH.

Without PCH
real    1m44.137s (104137 ms)
user    1m25.417s
sys     0m8.149s

With PCH
real    1m21.081s (81081 ms)
user    1m10.732s
sys     0m8.641s

KMid2 is a very small application. For comparison, Rosegarden 1.7 needs between 11 and 15 minutes to build in the same machine. The savings in KMid2 using PCH are 23 seconds, 22.14%. Not too bad! But KDE's build system has another way to save compiling time, and it is ready out of the box for any KDE project using the CMake option   "-DKDE4_ENABLE_FINAL=yes". This setting creates a Single Compilation Unit for each target. Times measured for KMid2:

With ENABLE_FINAL, and without PCH:
real    1m19.808s (79808 ms)
user    1m14.025s
sys     0m4.932s

Savings: 24.329 seconds, 23.36%

Conclusion: ENABLE_FINAL is slightly better than PCH, and it can be  automatically used by all KDE4-based applications. So why bother with PCH? I think that PCH may win if you can use the same PCH file when compiling a whole set of KDE programs at once, but I've not tested this hypothesis yet...