Turn Linux perf Samples into an LLVM Profile with llvm-profgen
Instrumenting a production binary for PGO data is often off the table, but llvm-profgen-18 turns an ordinary perf recording into a profile instead. The local command is LLVM 18.1.3 from Ubuntu package llvm-18. Allow 20 to 30 minutes for a first run, longer if you need to install or configure perf.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need the program you want to profile, a representative workload, its executable binary, llvm-profgen-18, and Linux perf with permission to collect branch-stack samples. The binary must be available to symbolise addresses. Run collection as the same user that can execute the workload; use elevated privileges only when your system's perf policy requires them.
Checkpoint
This workflow creates new trace and profile files. It does not change the executable, compiler flags or system configuration. Keep the trace until you have checked the profile, because the trace is the recovery path if conversion needs to be repeated.
1. Confirm the installed tool
Check the executable and package before preparing data. These are ordinary, read-only commands:
$ command -v llvm-profgen-18
/usr/bin/llvm-profgen-18
$ llvm-profgen-18 --version
Ubuntu LLVM version 18.1.3
Optimized build.
$ dpkg-query -W -f='${Package} ${Version}\n' llvm-18
llvm-18 1:18.1.3-1ubuntu1
The installed manpage calls the tool llvm-profgen and documents --perfscript, --binary, --output and the profile formats. The versioned executable above is the one used in this guide. Ask it for its own help if a distribution update changes the available options:
$ llvm-profgen-18 --help
2. Record a representative workload
Use perf record with branch stacks, as required by the documented llvm-profgen workflow. Replace the two placeholders with a real executable and workload. This command can add system-wide performance overhead while it runs, so collect during a suitable test window.
$ perf record -b -o /tmp/example.perf.data -- /path/to/program --representative-input
The -b option is significant: llvm-profgen needs branch information for this style of sample-based profile. A successful perf record run should leave a non-empty data file. Check it without changing the file:
$ test -s /tmp/example.perf.data && echo 'perf data is non-empty'
perf data is non-empty
If perf reports a permissions error, first check the host's perf policy and whether the workload is allowed to collect samples. Do not weaken kernel security settings blindly. If the command was interrupted, discard only the incomplete trace after checking its path, then collect again.
3. Convert raw perf data to a script trace
Turn the raw recording into the perf-script text that the manpage names as llvm-profgen input. This is a separate, read-only conversion. Keep the output name distinct from any earlier trace:
$ perf script -i /tmp/example.perf.data > /tmp/example.perf.script
$ test -s /tmp/example.perf.script && echo 'perf script is non-empty'
perf script is non-empty
Do not edit the script to make it look plausible. Its event records, mappings and sampled branches have to describe the recording. If the file is empty, stop here and fix collection rather than asking llvm-profgen to guess.
4. Generate a text LLVM sample profile
Pass the script, the exact profiled binary and a new output path. Text is a useful first format because it can be inspected. The command writes the profile file, so avoid a path containing an existing profile unless replacement is deliberate:
$ llvm-profgen-18 \
--perfscript=/tmp/example.perf.script \
--binary=/path/to/program \
--output=/tmp/example.prof \
--format=text
--perfscriptsupplies the samples.--binarysupplies the code and symbols used for address translation.--outputreceives the generated profile.
The binary must correspond to the program that produced the trace. A different build, stripped symbols or moved shared objects can reduce symbolisation quality or make the profile unsuitable for optimisation.
Checkpoint
Verify the conversion created data before opening it:
$ test -s /tmp/example.prof && echo 'LLVM profile is non-empty'
LLVM profile is non-empty
$ sed -n '1,24p' /tmp/example.prof
The exact profile text depends on the workload and binary. It should not be judged by matching a fixed sample output. If llvm-profgen reports that the input file does not exist, check the path first. If it reports missing or unsymbolised addresses, check that the executable and any required debug information match the recording.
5. Use debug information when the executable is not enough
The installed tool accepts --debug-binary for a separate file from which it loads DWARF information. Use it when the executable is stripped but you have the matching debug binary:
$ llvm-profgen-18 \
--perfscript=/tmp/example.perf.script \
--binary=/path/to/stripped-program \
--debug-binary=/path/to/matching/program.debug \
--output=/tmp/example.prof \
--format=text
Matching matters more than merely having a file with debug sections. Do not substitute an arbitrary build. If symbolisation is still incomplete, preserve the profile as diagnostic evidence and compare the executable, libraries and recording environment before changing the command.
6. Choose another format only after inspection
The manpage lists text, binary, extbinary, compbinary and gcc. Text is the easiest format for a first conversion; a consuming LLVM workflow may prefer a binary form. Repeat the conversion to a new file so the checked text profile remains available:
$ llvm-profgen-18 \
--perfscript=/tmp/example.perf.script \
--binary=/path/to/program \
--output=/tmp/example.profdata \
--format=extbinary
$ test -s /tmp/example.profdata && echo 'binary LLVM profile is non-empty'
binary LLVM profile is non-empty
Recovery
Do not infer that a non-zero-size file is a valid optimisation input. Validate it with the LLVM tool that will consume it, and keep the original text output or perf script until that check passes. If you need to abandon the experiment, remove only the explicitly named files in /tmp; the source executable and system configuration are untouched.
7. Avoid common traps
- Missing
-bat collection time. Do not omit it when the trace needs branch stacks; a normal perf recording is not automatically equivalent. - Wrong binary picked for convenience. Do not use a newer or older executable just because its path is convenient. Profile addresses belong to the binary that was actually run.
--formatconfused with input type. It selects the generated profile's encoding;--perfscriptstill points to perf-script text.- Diagnostics mistaken for fixes.
--show-mmap-eventsand--show-disassemblyare for investigating mappings or decoded instructions. Keep normal output separate from the profile file. - Intel syntax used by default. Use
--x86-asm-syntax=intelonly when disassembly is being examined in Intel syntax; the documented default is AT&T syntax.
Done means
- Version confirmed:
llvm-profgen-18 --versionreports the installed LLVM version you intended to use. - Trace validated: the perf recording contains branch information and the generated perf-script file is non-empty.
- Binary matched: the exact profiled binary, or its matching debug binary, was supplied for symbolisation.
- Output checked: a new profile file was generated in the selected format and checked for non-empty output.
- Consumer verified: the profile was inspected or validated by its downstream LLVM consumer before the trace was removed.