Job caching

6 minute read

JobCache is a feature that can substantially reduce compilation time. JobCache lets a build avoid recompiling object files that it previously built, if their inputs have not changed. JobCache works even after you clean the build output tree (for example, by using “make clean”). By caching and reusing object files, JobCache can significantly speed up full builds.

JobCache uses cache “slots.” When JobCache is enabled, eMake maintains a slot for each combination of command line options, relevant environment variable assignments, and current working directory. A slot can be empty or can hold a previously-cached result. If the appropriate slot holds an up-to-date result, a cache “hit” occurs, and compilation is avoided.

A cached result becomes obsolete if eMake detects file system changes that might have caused a different result (with the same command line options, environment variable assignments, and current working directory). Such file system changes include any files that are read during compilation, which means all source files, gcc precompiled headers, and compilation tools included in the eMake root.

CloudBees recommends that all components (Cluster Manager, Electric Agent/EFS, and eMake) on all machines in the cluster are upgraded to the latest version. However, you can still use JobCache with Agents on Electric Agent/EFS machines running versions as old as 7.2, as long as an appropriate backward compatibility package (BCP) is installed on those Electric Agent/EFS machines. For more information, see Installing the Backward-Compatibility Package on Agent Machines.

Benefits

  • Speeds long, full builds (for example, when you do a “make clean” then a “make,” or when you run a build in a new workspace)

  • Builds faster than ccache

  • Avoids certain false cache hits that might occur when you use ccache

  • Uses intelligent hashing for some types of files to avoid spurious cache misses because of changes in unimportant segments of those files.

    For example, JobCache ignores the .NT_GNU_BUILD_ID tag in ELF executables and libraries or input file timestamps in byte-compiled Python scripts.

Limitations

  • JobCache does not cache results from jobs that invoke eMake. JobCache stores results from particular jobs, but if a rule includes an invocation of eMake, (which might spawn other jobs), then that job is not cached, as in the following example:

    gcc -o foo.o foo.c && $(MAKE) -C subdir
  • The date and time in an object file will still reflect the original compilation (not the current date or time) if you use a C preprocessor macro that expands to the date or time when the compiler runs, and CloudBees Build Acceleration re-uses the resulting object file in a subsequent build.

  • Source paths embedded in debugging information in object files will reflect the original compilation (even if you re-use the object file while building in a different workspace).

  • JobCache is incompatible with incremental builds and should be used only for full builds.

Supported tools

JobCache supports the following tools:

Tool Supported Platforms Files Cached Notes

GNU ar or GNU ar-compatible archivers

Linux

All .a and .la

GNU ar-compatible archivers are those that use the same command-line convention and environment variable sensitivity as GNU ar.

cl (Microsoft Visual C/C++)

Windows

All .obj

Should not be used to cache results from linking. The only supported debug option is /Z7.

clang and clang++

Linux and Windows

All .o and .lo

Should not be used to cache results from linking.

gcc and g++

Linux and Windows

All .o and .lo

Should not be used to cache results from linking.

Java Android Compiler Kit (Jack)

Linux

All .jack and .dex

javac

Linux

All .jar

kotlinc and kotlin-jvm

Linux

All .jar

Using javac jobcache will cache kotlinc and kotlin-jvm commands.

GNU ld or GNU ld-compatible linkers

Linux

All .so

GNU ld-compatible archivers are those that use the same command-line convention and environment variable sensitivity as GNU ld.

Metalava

Linux

All .srcjar and .timestamp jobs that run Metalava

When you use --emake-jobcache= to enable JobCache (rather than using #pragma jobcache, eMake ignores trailing digits and version numbers in filename extensions (such as 29 in framework.jar29 and .8.3.0 in libcryptopp.so.8.3.0 ) so that it can use those extensions to try to intelligently determine the type of JobCache to apply to a job.

Running a “learning” build to populate the cache

You must first populate the cache by running a “learning” build with JobCache enabled. For the learning build (because the cache is empty), JobCache saves only a new result to the cache. For subsequent builds, JobCache re-uses cached results and saves a new result to the cache as appropriate. If you do not enable JobCache, then the job cache is not accessed.

Extending JobCache to teams via a shared cache

The Shared JobCache feature extends JobCache to teams of developers by using a shared cache. As with non-shared JobCache, Shared JobCache accelerates builds by reusing outputs from a build in the next build, which avoids costly redundant work across builds. Shared JobCache extends this concept by giving developers read-only access to a cache that was previously populated by another user or process (such as a nightly build). With this feature enabled, only one user must actually run the compilations; other team members simply reuse the output from that “golden” build.

A shared cache gives JobCache two tiers: shared and private (“local”). The shared cache strictly augments the traditional (“local”) cache but does not replace it.

Shared JobCache tries to find matching cache entries in the following order:

  1. During build execution with Shared JobCache enabled, eMake tries to find matching cache entries in the shared asset directory. This directory is specified by the --emake-shared-assetdir option. For example, --emake-shared-assetdir=/net/nightlybuild/.

    Developers can never modify cache entries in the shared asset directory.

  2. If there is no matching slot for a job in the shared asset directory, or if the input files for the job differ, eMake uses the developer’s local cache instead by checking for a hit there. This cache is specified by the --emake-assetdir=<directory> option. For example, --emake-assetdir=/net/home/bob/.

  3. If there is no local cache match, eMake creates a slot in the developer’s local cache if needed. The developer will get a hit in their local cache during the next compilation.

Prerequisites

Shared JobCache requires all participating developers to have access to a shared file system (such as NFS) where the shared asset directory will reside.

Populating the shared cache

For the builds that populate the shared cache, use the following eMake options:

--emake-jobcache=<types> --emake-assetdir=<assetdir>

Using the shared cache

Developer builds use the following eMake options:

--emake-jobcache=<types> --emake-shared-assetdir=<assetdir>

where <assetdir> is the asset directory of the populated cache.

Configuring JobCache

Licensing

JobCache is licensed based on the maximum number of builds that may use it simultaneously. This number is read from the jobcacheMax property in the CloudBees Build Acceleration license file. Simultaneous builds that exceed this number occur without using this feature.

If the JobCache license entry is invalid, or if the number of simultaneous builds has exceeded the license limit, a WARNING EC1181: Your license does not permit object caching message appears when a build tries to use JobCache. eMake will continue to work normally.

Choosing a disk for the job cache

To estimate the disk space required for the job cache, add the sizes of your object files together and multiply by 0.7. A specific example is that the Android KitKat Open Source Project (AOSP) requires about 4 GB. For best performance, choose a disk that is local to the eMake client host. For Shared JobCache, users must have access to a shared file system such as NFS.

You can use the --emake-assetdir= eMake option to specify the directory for your job cache. The default name of this directory is .emake. By default, this directory is in the working directory in which eMake is invoked. (This option also determines the cache location for the parse avoidance feature and the location of the saved dependency information for the dependency optimization feature.)

Building multiple branches

To maximize your cache hits, use the --emake-assetdir= option to specify a separate asset directory for each branch of code that you build.

Setting the eMake root

JobCache does not detect changes to compilation inputs that are not under your eMake root. You must ensure that your eMake root contains all sources and tools that might change.

Job caching for non-cl tools

These tools are: ar, clang, clang-cl, gcc, Jack, javac, ld, and Metalava.

Enabling JobCache for all make invocations in a build

To enable JobCache for all make invocations in a build, use the --emake-jobcache=<types> eMake option, where <types> is a comma-separated list of any combination of ar, clang, clang-cl, gcc, jack, javac, ld, metalava. The list cannot contain spaces. (As an alternative, you can use --emake-jobcache=all as a shortcut to cache all files.) The --emake-jobcache=<type> option works for recursive and nonrecursive builds.

  • --emake-jobcache=clang is an alias for --emake-jobcache=gcc. In the eMake annotation file, the JobCache type appears as jobcache type="gcc".

  • --emake-jobcache=clang-cl is an alias for --emake-jobcache=cl. In the eMake annotation file, the JobCache type appears as jobcache type="cl".