Tuning performance

5 minute readScalability

The converter has several methods for improving performance. To determine which is best for your situation, generate an annotation file and open it in Insight.

To generate an annotation file, pass --emake-annodetail=basic,file,lookup,env to your eMake call. By default, the annotation file is named emake.xml.

Improving build time for /Zi + PCH builds (using Electrify)

When using Electrify, you can set ELECTRIFY_FORCE_Z7, ELECTRIFY_SPLIT_PDBS, ELECTRIFY_MAX_SRC_FILES, and ELECTRIFY_EXPAND_INLINE_FILES to improve performance.

The default configuration for VC++ projects is /Zi and using PCH. To parallelize this combination, there are a few Electrify options that can improve performance. To improve build time in these circumstances:

  1. Set ELECTRIFY_FORCE_Z7=true.

    This is the single most effective way to improve build speed. Enabling this setting does not create PDB files and thus overrides ELECTRIFY_SPLIT_PDBS.

  2. Set ELECTRIFY_SPLIT_PBS=true.

    This setting causes unique PDB files to be created for each cl.exe invocation to enable JobCache. (Note that JobCache is incompatible with incremental builds and should be used only for full builds.)

  3. Set ELECTRIFY_MAX_SRC_FILES=<n>.

    This setting ensures cl.exe will build a maximum of <n> files per invocation. Can be used with ELECTRIFY_FORCE_Z7 or ELECTRIFY_SPLIT_PBS to increase parallelism.

  4. Set ELECTRIFY_EXPAND_INLINE_FILES=true.

    This setting expands the inline files of cl.exe to enable JobCache. This needs to be set to enable JobCache. The IDE extension sets this when JobCache is enabled.

Improving build time for /Zi + PCH builds (using ecdevenv)

The default configuration for VC++ projects is /Zi and using PCH. To parallelize this combination, the converter splits PDB and duplicates PCH. However PCH files are usually very large and might negate any improvement parallelization offers.

To improve build time in these circumstances:

  1. Set ECADDIN_FORCE_Z7=true.

    This is the single most effective way to improve build speed. Enabling this setting does not create PDB files and thus overrides ECADDIN_MAX_PDB_FILES.

  2. Set ECADDIN_DISALLOW_PCH.

    This turns off PCH but might result in build failures that can be fixed in code only.

  3. Reduce ECADDIN_MAX_PDB_FILES.

    Reducing this setting reduces parallelism but decreases the time spent copying PCH files. (This setting has no effect if you set ECADDIN_FORCE_Z7=true, which does not create PDB files.)

Improving build time for solutions with many projects

Some very large solutions with few interproject dependencies might benefit from not parsing the project down to the project item level. Follow these steps:

  1. Set ECADDIN_DONT_PARSE_PROJECTS=true.

  2. Clear history.

  3. Rebuild.

Although you lose find-grain parallelism, the reduced overhead might reduce the overall build time.

Many typical solutions have a final link (or lib) that is very large and slow on the cluster. To perform this link locally, set ECADDIN_RUN_LOCAL_LINK=<project>.

Running projects locally with #pragma runlocal might cause other issues. When running with #pragma runlocal, only changes in the current working directory are recognized by EFS, so it is not advised if there are subsequent jobs that use files outside of the CWD.

Improving incremental build time

By default, the converter does not rebuild prebuild events. Instead, the converter first checks whether there is anything out of date. If not, nothing will be built, including the prebuild event.

To always rebuild prebuild events, set ECADDIN_UP_TO_DATE_CHECK=false. Note that when you set this environment variable to false, if you have a prebuild event that touches files, it could potentially rebuild far more than Visual Studio would.

Improving incremental linking time

Improving incremental linking time with the converter

Visual Studio supports incremental linking with the /INCREMENTAL linker option. This does not function in eMake, because eMake updates the time stamp of the exe/dll when it copies it back to the build machine (from the agent) to prevent any problems because of clock skew.

To work around this problem, the converter “touches” the exe after the link with its current time stamp. This explicit modification of the time stamp instructs eMake to preserve the time stamp, which keeps the validity of its incremental status. The converter inserts a call to ectouch.exe, which performs the action stated above. ectouch.exe must be in %PATH%.

To disable this feature with the converter, set ECADDIN_ENABLE_INCREMENTAL_LINK=false.

Improving incremental linking time without the converter

If you are not using the converter, you can still use this feature. You can rename ectouch.exe to eclink.exe and replace occurrences of ` link.exe ` with eclink.exe. eclink.exe should be in %PATH%. Alternatively, you can rename link.exe to link_ec.exe and copy eclink.exe ` to `link.exe. (If you want something other than link_ec.exe, set EC_ORIGINAL_LINK_PATH to the location of the “real” link.exe. )

Optimizing parallelization using PDB splitting

Optimizing parallelization with the converter

By default, Visual Studio puts all debugging information in a centralized database (PDB) called vc80.pdb (this is Visual Studio version-specific). Because each compilation modifies this file, everything in the project is serialized. A workaround is to group debug information into multiple PDB files. You can accomplish this automatically if you use the converter.

ECADDIN_MAX_PDB_FILES is set to 16 by default. You can change this value to be equal to or less than the number of agents, but you might need to increase or decrease this for optimal efficiency. ECADDIN_MAX_PDB_FILES specifies the maximum number of PDB files produced. Each file is placed into a PDB determined by a hash of its filename. This method ensures that a particular file is always placed in the same PDB. This is necessary to ensure eMake’s history file remains valid.

For example, if a project contains 4 files, File1.cpp, File2.cpp, and so on, and they are all serialized on PDB file vc80.pdb. Set ECADDIN_MAX_PDB_FILES=2 will create (at most) 2 PDB files:

File1.cpp --' < ProjectName >_0.pdb File2.cpp --' < ProjectName >_1.pdb File3.cpp --' < ProjectName >_0.pdb File4.cpp --' < ProjectName >_1.pdb

In this example, File1 and File3 will be serialized against each other but will build in parallel from File2 and File4 (which will be serialized against each other).

You can change this variable in the Visual Studio IDE Converter solution settings. Go to the Performance section of the Converter pane.

The history file must be deleted when adding or changing the value of ECADDIN_MAX_PDB_FILES. You can also set --emake-history=create.

Optimizing parallelization without the converter

This technique can be used without using the converter. This distribution contains the application hashstr.exe, which hashes the filename and returns the bucket number. You can use this in your makefile to set the PDB filename (using /fd) in the same manner as above. Precompiled headers must be switched off for this to work.

Usage: hashstr "mystring" [modulus]

Where mystring is the string from which to generate the hash value, and modulus is the number of hash bins you want to use.

You can add this to a pattern rule for builds that suffer from performance degradation due to PDB serialization, with something similar to the following:

%.o: %.c $(CC) /c $(cflags) $(PCH_USE_FLAGS) $(cvars) $(cplus_flags) $(LOCAL_INCLUDE) $(PCB_INCLUDE) $< /Fo$@ /Fd$(shell ${path-to-hashstr}/hashstr.exe "$@" ${hashstr-modulus}).pdb

Troubleshooting

Insight lets you pinpoint performance problems or conflicts in a parallel build. Until now, there has been little visibility into builds to “see” why a build was slow, why a build broke, or which dependencies were involved. Insight® (Insight) removes the “black box” around software product builds and provides easy-to-understand performance data.