A build claims to be optimised, but you want proof, so this guide merges raw counters into indexed data and reads them with llvm-profdata-18. Along the way you compile an instrumented program, collect a raw profile, merge it, and inspect the recorded function counts. You will also see how weighting changes those counts and why a failed merge should stop a profile-guided optimisation run.
Allow about fifteen minutes. You need the llvm-18 package, clang-18, a writable working directory, and a program that can be exercised safely. The installed command here is LLVM 18.1.3 on Ubuntu. The examples use llvm-profdata-18, not the unversioned name. They do not require elevated privileges.
Start by confirming the binary and its version. This is a read-only check:
$ command -v llvm-profdata-18
/usr/bin/llvm-profdata-18
$ llvm-profdata-18 --version
Ubuntu LLVM version 18.1.3
Optimized build.
The manpage shipped with this package documents merge, show, overlap and order. This guide concentrates on the first two. The command returns status 1 when a subcommand is missing or invalid, an input cannot be read, or profile data does not match.
Checkpoint: confirm the option spelling on the machine where the job will run:
$ llvm-profdata-18 merge --help
$ llvm-profdata-18 show --help
LLVM tools can expose more options in their built-in help than an older installed manpage. Use the local help and the local executable as the final authority for an automated build.
The profile tool does not collect execution data by itself. A compiler-instrumented executable writes raw data when it runs. Create a temporary workspace and a deliberately small program:
$ workdir="$(mktemp -d /tmp/llvm-profdata-demo.XXXXXX)"
$ printf '%s\n' '#include <stdio.h>' \
'int main(void) { puts("profile-ok"); return 0; }' > "$workdir/main.c"
$ clang-18 -fprofile-instr-generate -fcoverage-mapping \
"$workdir/main.c" -o "$workdir/main"
workdir is a placeholder for a temporary directory. Keep it separate from a source tree or a directory containing profiles that matter. The compiler flags create instrumentation and coverage metadata; they do not alter the system or need root access.
Checkpoint: confirm that the executable exists before collecting data:
$ test -x "$workdir/main" && printf '%s\n' 'instrumented executable ready'
instrumented executable ready
Set LLVM_PROFILE_FILE for the instrumented process, then run the program:
$ LLVM_PROFILE_FILE="$workdir/run.profraw" "$workdir/main"
profile-ok
$ test -s "$workdir/run.profraw" && printf '%s\n' 'raw profile written'
raw profile written
The raw file is produced by the instrumented program, not by llvm-profdata-18. In a real test suite, use a pattern such as run-%p.profraw when several processes may write at once, so separate processes do not trample the same file.
Do not treat an empty or missing raw file as a successful test. Check the program's exit status and investigate its runtime environment first. A profile that does not describe the intended run can still be syntactically valid.
Merge one or more raw profiles and choose an output path with -o:
$ llvm-profdata-18 merge "$workdir/run.profraw" \
-o "$workdir/merged.profdata"
$ test -s "$workdir/merged.profdata" && printf '%s\n' 'indexed profile ready'
indexed profile ready
For multiple runs, list each input before the output option:
$ llvm-profdata-18 merge \
"$workdir/run-1.profraw" "$workdir/run-2.profraw" \
-o "$workdir/merged.profdata"
By default, an instrumentation profile is merged without changing the relative contribution of its inputs. The counts from a longer or more frequently repeated run therefore carry more weight. The output must be a file. This command cannot write an indexed profile to standard output with -o -.
Checkpoint: a successful merge produces no required summary text. Use the file test above, then inspect the result rather than relying on silence.
Use show for a human-readable summary. --counts includes counter values and --all-functions removes the default function filtering:
$ llvm-profdata-18 show --counts --all-functions \
"$workdir/merged.profdata"
Counters:
main:
...
Function count: 1
Functions shown: 1
Total functions: 1
Hashes and detailed fields vary with the compiler and source. The useful checks are that the expected functions appear, the total is plausible, and the function count is not zero when the program ran. To focus on one name, use --function:
$ llvm-profdata-18 show --counts --function=main \
"$workdir/merged.profdata"
Ask for the profile version when diagnosing a toolchain mismatch:
$ llvm-profdata-18 show --profile-version "$workdir/merged.profdata"
Profile version: 11
The exact surrounding summary depends on the profile. A version mismatch, unreadable input or incompatible data is a merge or show failure, not a reason to guess at a flag.
--weighted-input=<weight,filename> multiplies the counts from that input by an integer weight of at least 1. This is useful when a run represents a deliberately larger training population, but it is also an easy way to distort PGO decisions:
$ llvm-profdata-18 merge \
--weighted-input="2,$workdir/run.profraw" \
"$workdir/run.profraw" \
-o "$workdir/weighted.profdata"
$ llvm-profdata-18 show --counts --function=main \
"$workdir/weighted.profdata"
Function count: 3
The same raw profile is included once with weight 2 and once with the default weight 1, so a count of 1 becomes 3. The weight is not a percentage and it does not normalise the other inputs. Record why each weight was chosen, and keep the unweighted merged profile until the result has been reviewed.
The default failure mode is any: the merge fails if any profile is invalid. The installed LLVM 18 help also exposes --failure-mode=all, which permits a merge when at least one profile is usable, and --failure-mode=warn, which reports warnings without failing. These modes can intentionally exclude or tolerate bad input, so do not use them to make a broken collection look healthy. Keep the default for CI and investigate the offending file.
Common traps are pointing at a raw file that was never written, mixing profiles from incompatible instrumented binaries, overwriting a valuable output file, and assuming that a successful merge proves representative training. Write to a new output path, compare the reported functions and counts, and only then hand the indexed file to the compiler's PGO step.
These examples change only the temporary workspace. After checking its path, remove it if it contains no profile you need:
$ case "$workdir" in
/tmp/llvm-profdata-demo.*) rm -rf -- "$workdir" ;;
*) printf '%s\n' 'refusing to remove an unexpected path' >&2; exit 1 ;;
esac
There is no undo for deletion, so inspect printf '%s\n' "$workdir" first and copy any required .profraw or .profdata files elsewhere.
llvm-profdata-18 --version reports the expected LLVM 18 installation.merge produced a new indexed .profdata file.show --counts reports plausible functions and counts.