Merge and Rescale GCC Coverage Profiles with gcov-tool
You will finish with a repeatable way to combine GCC .gcda profile directories, adjust their influence with weights, rescale a copy, and compare two runs. The examples use the installed GCC 13.3.0 build on Ubuntu and take about 15 minutes once you have two profile directories.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need a shell, gcov-tool-13, and profile directories produced by an instrumented GCC program. Ordinary user privileges are enough for the commands below. Do not run this against a shared profile directory while another process is writing it.
1. Check the installed tool
Use the versioned command when you want the result tied to GCC 13. This is a read-only check:
$ gcov-tool-13 --version
gcov-tool-13 (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
The unversioned gcov-tool and the target-prefixed x86_64-linux-gnu-gcov-tool-13 are installed here as aliases for the same tool family. Keep the producer and consumer versions aligned where you can. The manpage identifies this interface as an offline processor for GCC's gcda files.
Checkpoint: confirm the subcommands you plan to use before copying a longer command:
$ gcov-tool-13 --help
Usage: gcov-tool-13 [OPTION]... SUB_COMMAND [OPTION]...
2. Put two profile sets in separate directories
A profile set is a directory tree containing the .gcda files from one collection of program runs. The two directories must describe compatible instrumented code. Use descriptive paths such as these in the examples:
$ PROFILE_A=/path/to/profile-baseline
$ PROFILE_B=/path/to/profile-realistic
$ test -d "$PROFILE_A" && test -d "$PROFILE_B"
$ find "$PROFILE_A" "$PROFILE_B" -type f -name '*.gcda' -print
That final command should print the files you intend to process. An empty result means you have directories, but not usable profile data. Preserve the originals before experimenting: merge, rewrite and normalise write new output trees, but a mistaken output path can still make it easy to confuse generated data with source data.
Do not mix profiles from unrelated builds merely because their filenames look similar. Differences in object layout, compiler options or source can make the result misleading or unusable.
3. Merge two profiles with equal weight
Merge the directories into an explicit destination so the result is easy to identify:
$ gcov-tool-13 merge \
--output merged-profile \
"$PROFILE_A" "$PROFILE_B"
$ find merged-profile -type f -name '*.gcda' -print
The two positional directories are required. If you omit --output, GCC 13 uses merged_profile, with an underscore. The default weight is 1 for each input, which is equivalent to:
$ gcov-tool-13 merge --weight 1,1 \
--output merged-profile \
"$PROFILE_A" "$PROFILE_B"
Use --verbose when you need to see which files are being read. It is useful for confirming that a supposedly matching pair of trees actually contains the files you expect.
Checkpoint: the destination should contain .gcda files, and your two input directories should be unchanged:
$ find merged-profile -type f -name '*.gcda' | wc -l
$ git diff --no-index -- /dev/null merged-profile 2>/dev/null || true
The second command is only a rough visual aid for a directory and may return a non-zero status. The important check is that you inspect the destination, not that you treat a diff against /dev/null as a profile validator.
4. Apply weights deliberately
The comma-separated values in --weight belong to the first and second directories respectively. If the second run represents twice as much of the workload, use:
$ gcov-tool-13 merge \
--weight 1,2 \
--output merged-weighted \
"$PROFILE_A" "$PROFILE_B"
Weights change the contribution of counters; they do not turn a profile into a percentage report. Record the reason for the numbers next to the command or in your build notes. A weight of 1,2 means the second input contributes twice the nominal weight of the first, not that every counter is guaranteed to be exactly doubled.
Do not overwrite a previous result while tuning weights. Use a new output directory, inspect it, then replace a downstream input only after your normal backup or artefact-retention policy covers the old data. There is no undo operation inside gcov-tool; recovery means rerunning from the preserved input directories.
5. Rescale or normalise a copy
rewrite reads one profile directory and writes a new one. To multiply its counters by two thirds, use a decimal or a simple fraction:
$ gcov-tool-13 rewrite \
--scale 2/3 \
--output scaled-profile \
"$PROFILE_B"
$ find scaled-profile -type f -name '*.gcda' -print
To normalise instead, specify the maximum counter value for the new profile:
$ gcov-tool-13 rewrite \
--normalize 1000 \
--output normalised-profile \
"$PROFILE_B"
$ find normalised-profile -type f -name '*.gcda' -print
Use one of --scale or --normalize for a given rewrite. Keep the original directory until the rewritten data has been consumed successfully. These operations change counter data in the output and can affect later profile-guided decisions.
6. Measure profile overlap
Use overlap to see how similarly two profiles exercise arc counters. For a compact object-level report:
$ gcov-tool-13 overlap \
--object --fullname \
"$PROFILE_A" "$PROFILE_B"
obj= ./demo.gcda overlap = 0.00%
The exact filenames and percentages depend on the program and runs. Add --function for function-level information, or --hotonly to restrict the report to hot objects and functions. --hot_threshold FLOAT sets the threshold used for that hotness filter.
An overlap score is not a correctness proof. A low score may be expected when the input workloads differ, and a high score does not prove that the test suite covers the behaviour you care about. Treat it as a comparison signal alongside the source-level coverage report and the workload description.
7. Avoid the common traps
merge-stream is a separate workflow for a gcfn and gcda data stream, optionally read from a file or standard input. It is intended for collecting profiles from systems without a normal filesystem. It is not a shorthand for merging two ordinary directories.
Offline merging can differ slightly from online runtime merging. GCC documents three relevant causes: offline histogram recomputation, a different link-list order affecting the CRC32 summary checksum, and runtime-dependent value-profile counters such as heap addresses. Do not reject a merged result solely because those values differ.
If a command reports that it cannot access a directory, stop and check each path, permissions and whether the profile files are still being written. Adding sudo does not repair a wrong path or an incompatible profile. Elevated privileges are not required for normal read and write access to directories you own.
Done means
- You confirmed the installed GCC 13.3.0
gcov-tool-13version. - You kept the original profile directories and wrote results to named destinations.
- You merged two compatible profile sets with explicit weights.
- You know that omitted merge weights are 1,1 and the omitted output is
merged_profile. - You used
rewritefor scaling or normalisation without overwriting the source. - You treated overlap as a workload comparison, not as a coverage or correctness verdict.