Skip to main content
Markdown

Profile-Guided Optimization

Profile-guided optimization (PGO) uses execution counts from representative training runs to inform compiler decisions. Exaloop manages profile collection, candidate builds, and comparison with a normal Exaloop build. Selection depends on the application's configured performance, correctness, and resource criteria. A candidate that fails those checks leaves the baseline selected.

Start with profiling to identify expensive code paths. Once the application is correct and its workload is replayable, use the workflow below to train and evaluate a PGO build.

1. Check the Prerequisites​

This walkthrough assumes a working native application, the Exaloop CLI, and an optimizer SDK matching your Codon compiler and LLVM build. The tuning workflow supports native macOS ARM64 and Linux x86-64/AArch64 executables, not database-hosted modules, JIT, GPU, or cross-compilation. The application runs repeatedly during training and measurement.

An all-SDK distribution provides ext automatically. For an individual SDK, register its installed directory once:

Terminal
OPT_SDK=/path/to/sdk/ext
exaloop plugin add ext --path "$OPT_SDK"

For either installation, check that the complete native PGO path works:

Terminal
exaloop doctor --optimization --json

This checks the complete profile-and-rebuild workflow on a small program before you spend time optimizing your own application.

2. Configure Replayable Inputs​

Add a native target and its optimization inputs to your project's exaloop.toml. This example assumes app.codon accepts a data-file path as its first argument and prints a deterministic result. Replace the filenames with your own inputs.

Input setPurpose
trainCollect execution counts for the compiler
tuneMeasure candidates and choose one for final evaluation
holdoutCheck the choice on separate, representative inputs
exaloop.toml
[targets.analytics]
source = "app.codon"
codon_args = ["-release"]

[targets.analytics.optimize]
train = [["data/train-a.json"], ["data/train-b.json"]]
tune = [["data/tune.json"]]
holdout = [["data/holdout.json"]]
inputs = ["data"]

Each nested list is one set of command-line arguments. In this example, the application runs on two training files, measures candidates with a third file, and checks the choice on a separate holdout file. Use inputs that resemble the workload you expect in production, including its less common cases.

List the data and other external dependencies in inputs so a changed file invalidates cached results. Keep the default PGO-only settings for a first run; the configuration reference covers optional tuning.

Repeated execution

Training and measurement replay the application many times. Read-only inputs or disposable environments prevent those runs from repeating production writes. Session files retain application arguments and output logs.

By default, candidates must produce exactly the same stdout and stderr as the baseline. If the result is a file or another external effect, or requires a numeric tolerance, provide a custom verifier. Matching console output alone cannot prove those results are correct.

3. Run Optimization​

Run from the project directory, or select it with --project DIRECTORY:

Terminal
exaloop --dry-run --target analytics optimize --budget 10m
exaloop --target analytics optimize --budget 10m

The dry run shows the plan without running your application. The second command performs the experiment within the ten-minute budget, using the default Exaloop build without PGO as its baseline. It does not replace your normal build output or deploy the result.

4. Interpret the Result​

Open build/optimize/analytics/session-*/index.html to inspect the result. The dashboard opens automatically in an interactive terminal; use global --no-open to suppress that. The selected executable is program in the same session directory, with machine-readable details in report.json.

The holdout result measures the selected build on inputs that were not used to choose it. Per-case timings, memory measurements, and code size provide context for that result: an aggregate improvement can still include a regression in a case that matters to the application.

A baseline selection means no candidate satisfied every acceptance criterion. The report identifies the checks that prevented selection. Holdout inputs remain reserved for the final evaluation; their results do not drive further search.

Use runs lasting at least roughly 100 ms to reduce startup noise. Timings include process startup and I/O, but exclude compilation and training instrumentation. For the measurement and acceptance rules, see the optimization reference.

5. Resume or Use the Selected Build​

Sessions retain profiles, binaries, coverage, compiler diagnostics, and execution logs. To reuse a completed session's valid build artifacts:

Terminal
exaloop --target analytics optimize --resume build/optimize/analytics/session-EXAMPLE

Resume reuses valid build artifacts but repeats the measurements. Changes to the code, declared inputs, toolchain, or machine can invalidate the cache.

The selected program runs without the training profile, although it still needs its normal native libraries. Treat it as a separate build artifact: ordinary build and package commands do not automatically use the session's selection.

Try a Sample Project​

The event-processing project includes a complete application and configuration, with no input files or services required. Extract the archive, then run:

Terminal
cd optimization
exaloop --target events optimize --budget 10m

The application classifies synthetic events and prints per-category totals. Different seeds provide separate training, tuning, and holdout cases. The sample demonstrates the workflow; its result is not a performance prediction for other applications, and the checks may select the baseline.

Further Reading​

  • Optimization reference: configuration, preset behavior, and advanced compiler controls. Inlining and DFA passes are optional topics, not prerequisites for using PGO.