December 22, 2011

How to improve VC++ project build time

How to improve VC++ project build time

Introduction

Microsoft Visual C++ can compile code very quickly, if it is setup properly. There are few basic things to look at:

  • Precompiled headers
  • Pragma once
  • File level parallel building
  • Project level parallel building

Build Statistics

Before we go into the details of each of these items let's see how we can enable some build time statistics. Please note that all my examples and notes are related to Visual Studio 2008 Professional Edition.

Measuring the build time

In VC++ you can get build time by going into Tools > Options > Projects and Solutions > VC++ Project Settings > Build Timing. Set this value to true. This will print the complete build time to the output window. Enable this before you try to improve the build time, then you will be able to measure the performance correctly.

Getting the list of files get included into each compilation unit

In VC++ you can get the list of files gets included into the each compilation unit (CPP) by enabling "Show Includes" in the project properties by going into C/C++ > Advanced > Show Includes. Set this value to true. This will print the included files with the compiler output.

Precompiled Headers

It is often desirable to avoid recompiling a set of header files, especially when they introduce many lines of code and the primary source files that #include them are relatively small. The C++ compiler provides a mechanism for, in effect, taking a snapshot of the state of the compilation at a particular point and writing it to a disk file before completing the compilation; then, when recompiling the same source file or compiling another file with the same set of header files, it can recognize the snapshot point, verify that the corresponding precompiled header (PCH) file is reusable, and read it back in. Under the right circumstances, this can produce a dramatic improvement in compilation time; the trade-off is that PCH files can take a lot of disk space.

Enabling Precompiled Headers

The precompiled-header options are /Yc (Create Precompiled Header File) and /Yu (Use Precompiled Header File). Use /Yc to create a precompiled header. Select /Yu to use an existing precompiled header in the existing compilation. These settings can be changed by going into Project Properties > Configuration Properties > Precompiled Headers.

The idea here is to use one CPP file as the source for creating the pre compiled header and the rest of the CPP files are use the created header file. First you need a header file that every source file in your project will include. In VC++ this is typically called as "stdafx.h". If you do not have one, create it and also the corresponding CPP file which contains a single line to include the "stdafx.h". Change the rest of the CPP files in your project to include the "stdafx.h" file. This include has to be the first include statement (as the first non-comment thing that they do). If you forget to include your precompiled header file then you will get the following error message: "fatal error C1010: unexpected end of file while looking for precompiled header directive."

Now, change the project properties to generate / use pre compiled headers. Make sure you select "All Configurations" so that your fixes will affect both debug and release builds of your project. Select the project properties, go to the C/C++ tab, precompiled headers category. Select "Use precompiled header file" and type in the name of your precompiled header file (stdafx.h). Select "stdafx.cpp" properties, go to the C/C++ tab, precompiled headers category. With "All Configurations" selected, and select "Create precompiled header file", and type in the name of your precompiled header file.

What should be in the stdafx.h?

The precompiled header file should include the big header files which slow down your builds. Possible candidates are STL header files.

The rule of thumb is not to include any header files from your project, since if you modify those header file, the whole project will be rebuilt.

Build with Precompiled Headers

All set now. Try out the build and gather the build statistic and compare with the original.

#pragma once

In the C and C++ programming languages, #pragma once is a non-standard but widely supported preprocessor directive designed to cause the current source file to be included only once in a single compilation. Using #pragma once instead of include guards will typically increase compilation speed since it is a higher-level mechanism; the compiler itself can compare filenames without having to invoke the C preprocessor to scan the header for #ifndef and #endif.

If the header contains only a guard, when compiling the included file (CPP) the included file has to be fully loaded to scan for #ifdef and #endif statements. To improve the time and to support all compilers it is recommended to use both header guards and #pragma once statements in the header files.

For an example, take a header file that you use / include many times form your project. Remove the pragma once from it (if it exists) and compile the project by enabling "Show Includes" discussed previously. Check the number of times the included file gets loaded when the project gets compiled.

File Level Parallel Building

Visual Studio 2008 can take advantage of systems that have multiple processors, or multiple-core processors. A separate build process is created for each available processor. The /MP option can reduce the total time to compile the source files on the command line. The /MP option causes the compiler to create one or more copies of itself, each in a separate process. Then these copies simultaneously compile the source files. Consequently, the total time to build the source files can be significantly reduced. The /MP option can be given to the project settings in the IDE by going into project properties C/C++ > Command Line > Additional Options. The option takes an optional argument to specify the number of processors / cores. If you omit this argument, the compiler retrieves the number of effective processors on your computer from the operating system, and creates a process for each processor. This option does not work with if you have used /Yc (Create Precompiled Header File) or Show Includes. The compiler will warn you, but you can simply ignores it. Otherwise omit the /MP option for /Yc enabled source files (stdafx.cpp) and disable Show Includes option after figuring out the include file fiasco.

With this option along if you are running your compiler on a quad core system, you can gain 3 - 4 times compile time improvement.

Project Level Parallel Building

The number of projects that can build concurrently in the IDE is equal to the value of the Maximum number of parallel project builds property. For example, if you build a solution that comprises several projects while this property is set to 2, then up to two projects will build concurrently at a time. To enable this you need to go into Tools > Options > Projects and Solutions > Build and Run. Set the "maximum number of parallel project to build" to number of processors / cores.

This option only allows you to build non-dependent projects in parallel.

Points of Interest

By doing all of these we were able to improve the build time of a project by 10 times. Hope this article will help you too.