Inspect and Merge LLVM 20 Profile Data with llvm-profdata

Your profile-guided build is producing worse code than the unoptimised one, and the reason is almost always a bad or stale profile file. llvm-profdata-20 lets you check, merge and compare profiles before you trust them. The examples use llvm-profdata-20 from Debian package llvm-20, version 20.1.8, installed on this machine.

Allow about twenty minutes if you already have raw or indexed profiles. You need a shell, readable profile files, and enough free space for a new output file. This guide reads and creates profile data; it does not alter a compiler, rebuild a program, or require elevated privileges. Use sudo only if ordinary file permissions prevent access to a profile directory.

1. Check the installed tool

Start by confirming the executable and package version. These are ordinary read-only commands:

$ command -v llvm-profdata-20
/usr/bin/llvm-profdata-20
$ llvm-profdata-20 --version
Ubuntu LLVM version 20.1.8
  Optimized build.
$ dpkg-query -W -f='${Package} ${Version}\n' llvm-20
llvm-20 1:20.1.8~++20250804090239+87f0227cb601-1~exp1~20250804210352.139
$ llvm-profdata-20 merge --help
$ llvm-profdata-20 show --help

Checkpoint: if the command is missing, stop here and install or enable the LLVM package through your normal system-management process. Do not copy a profile tool from another LLVM release and assume its file format is interchangeable.

2. Inspect one profile before using it

show reads an instrumentation-based profile by default and writes its report to standard output. Begin with the profile version and a compact report:

$ llvm-profdata-20 show --profile-version ./training.profdata
$ llvm-profdata-20 show --counts --function=main ./training.profdata

The exact report depends on the functions and counts in your file. With --counts, the selected function's counter values are included. The filter is a name substring, so --function=main can match more than one function whose name contains that text.

$ llvm-profdata-20 show --all-functions --counts \
    --output=./training-report.txt ./training.profdata
$ test -s ./training-report.txt && echo 'report written'
report written

Do not confuse show --text with the normal human-readable report. The --text option asks for the parsable text representation of instrumentation profile data. That representation is useful for tooling, but it is not the easiest first report to read.

3. Merge profiles into a new file

Keep the input files intact and write a separate indexed profile. This is the normal instrumentation-profile case:

$ llvm-profdata-20 merge --instr --binary \
    ./run-a.profraw ./run-b.profraw ./run-c.profraw \
    --output=./merged.profdata
$ test -s ./merged.profdata && echo 'merged profile written'
merged profile written

--instr states the profile kind explicitly. --binary states the output encoding explicitly, which makes a script easier to review across installations. The output option cannot be - for merge; an indexed profile must be written to a file.

If the inputs are listed in a file, use newline-separated entries with --input-files. A line can contain just a path or a weight followed by a comma and a path:

$ sed -n '1,5p' profile-inputs.txt
./run-a.profraw
2,./longer-run.profraw
# comments are skipped
./run-c.profraw
$ llvm-profdata-20 merge --instr --binary \
    --input-files=./profile-inputs.txt \
    --output=./merged.profdata

Warning: weights multiply the counts from that input, not a percentage or a duration. An unweighted input has weight 1; a weight of 2 makes that profile contribute twice its recorded counts. Check the list before running it, because a repeated or heavily weighted run changes the result without changing any source profile.

4. Handle invalid inputs deliberately

The installed manual documents --failure-mode=any as the default: the merge fails if any input is invalid. Keep that strict behaviour for release or benchmark data unless you have reviewed the consequences. With all, the merge fails only when every profile is invalid and excludes invalid profiles from the output:

$ llvm-profdata-20 merge --instr --binary \
    --failure-mode=any ./run-a.profraw ./run-b.profraw \
    --output=./merged.profdata
$ printf 'merge status: %s\n' "$?"
merge status: 0

A non-zero status means the command could not complete successfully, for example because it could not read an input or the profile data did not match. Capture the status immediately.

Recovery: do not treat a file left behind after an error as a valid result. Inspect its size and rerun into a new name after fixing the input problem. Profile files are data, not configuration: do not delete raw profiles to save space until the merged file has been inspected and your retention policy permits removal. If you must remove a temporary output, identify the exact path first and use your normal recoverable deletion process.

5. Compare two profiles with overlap

overlap compares the distribution of matching counters between a base profile and a test profile. Its result is a percentage from 0.0% to 100.0%; it is about where counts are concentrated, not whether the total count is the same:

$ llvm-profdata-20 overlap \
    ./baseline.profdata ./candidate.profdata

The report identifies the base and test files, then prints a program-level section containing the number of overlapping functions, an edge-profile overlap percentage, and the count sums for each profile. The exact values come from your files; do not treat a high percentage as proof that the builds are equivalent.

The exact percentage and formatting depend on the files. Use --function=NAME to inspect a matching function, or --value-cutoff=N to suppress functions below a maximum-count threshold. The default cutoff for overlap is the maximum unsigned long long value, so function-level details do not appear unless you lower it or select a function.

Context-sensitive counts are excluded by default. Add --cs when the question is specifically about context-sensitive profile counts. Do not compare unrelated program builds and read a high overlap as proof that their performance is equal; matching names and counter distributions are only one signal.

6. Produce a function order when temporal traces exist

The order subcommand reads temporal profiling traces and emits a function order intended to reduce page faults. Save it as a new text file, then review it before passing it to the linker:

$ llvm-profdata-20 order ./temporal.profdata \
    --output=./function-order.txt
$ test -s ./function-order.txt && sed -n '1,10p' ./function-order.txt

Example: the output can be supplied to lld with --symbol-ordering-file= for ELF or -order-file for Mach-O. It is only useful when the recorded traces represent real startup behaviour. An empty or unhelpful order file is a signal to revisit profile collection, not a reason to reorder functions by hand.

7. Recover from the common traps

Done means