{"id":13429247,"url":"https://github.com/Kobzol/cargo-pgo","last_synced_at":"2025-03-16T03:31:12.922Z","repository":{"id":52679547,"uuid":"513542067","full_name":"Kobzol/cargo-pgo","owner":"Kobzol","description":"Cargo subcommand for optimizing Rust binaries/libraries with PGO and BOLT.","archived":false,"fork":false,"pushed_at":"2025-02-20T08:02:05.000Z","size":279,"stargazers_count":615,"open_issues_count":7,"forks_count":12,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-03-08T07:15:39.545Z","etag":null,"topics":["bolt","cargo","pgo","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Kobzol.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-13T13:56:50.000Z","updated_at":"2025-03-08T05:23:18.000Z","dependencies_parsed_at":"2024-02-15T10:25:14.899Z","dependency_job_id":"11015ef8-457a-41f0-bc9f-96b79a2f11ab","html_url":"https://github.com/Kobzol/cargo-pgo","commit_stats":{"total_commits":117,"total_committers":5,"mean_commits":23.4,"dds":0.07692307692307687,"last_synced_commit":"71de65734bb4ae0a44542cdbe7780e0a1316f402"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kobzol%2Fcargo-pgo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kobzol%2Fcargo-pgo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kobzol%2Fcargo-pgo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kobzol%2Fcargo-pgo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kobzol","download_url":"https://codeload.github.com/Kobzol/cargo-pgo/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243732285,"owners_count":20338835,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bolt","cargo","pgo","rust"],"created_at":"2024-07-31T02:00:31.907Z","updated_at":"2025-03-16T03:31:12.917Z","avatar_url":"https://github.com/Kobzol.png","language":"Rust","funding_links":[],"categories":["PGO support in programming languages and compilers","Rust"],"sub_categories":["PGO support in build systems"],"readme":"# `cargo-pgo` [![Build Status]][actions] [![Latest Version]][crates.io]\n\n[Build Status]: https://github.com/kobzol/cargo-pgo/actions/workflows/check.yml/badge.svg\n[actions]: https://github.com/kobzol/cargo-pgo/actions?query=branch%3Amain\n[Latest Version]: https://img.shields.io/crates/v/cargo-pgo.svg\n[crates.io]: https://crates.io/crates/cargo-pgo\n\n**Cargo subcommand that makes it easier to use [PGO](https://doc.rust-lang.org/rustc/profile-guided-optimization.html)\nand [BOLT](https://github.com/llvm/llvm-project/tree/main/bolt) to optimize Rust binaries.**\n\nFor an example on how to use `cargo-pgo` to optimize a binary on GitHub Actions CI, see [this workflow](ci/pgo.yml).\n\n## Installation\n\n```bash\n$ cargo install cargo-pgo\n```\n\nYou will also need the `llvm-profdata` binary for PGO and `llvm-bolt` and `merge-fdata`\nbinaries for BOLT.\n\nYou can install the PGO helper binary by adding the `llvm-tools-preview` component to your toolchain\nwith `rustup`:\n```bash\n$ rustup component add llvm-tools-preview\n```\n\nFor BOLT, it is highly recommended to use [Docker](#docker).\nSee [below](#bolt-installation) for BOLT installation guide.\n\n\u003e BOLT and Docker support is currently *experimental*.\n\n## Docker\n\nTo use latest `cargo-pgo` with Docker, you need to build the image first:\n\n```bash\ngit clone https://github.com/Kobzol/cargo-pgo.git \u0026\u0026 cd cargo-pgo\ndocker build -t cargo-pgo .\n```\n\nThen run this in your project directory to create a container:\n\n```bash\ndocker run -v $(pwd):/workdir --rm -it cargo-pgo\n```\n\nIn the container, you can run `cargo-pgo` as you would on your system.\n\nNote that with `--rm` argument, the container will be removed after you exit.\n\n## PGO/BOLT workflow\nIt is important to understand the workflow of using feedback-directed optimizations. Put simply, it\nconsists of three general steps:\n\n1) **Build binary with instrumentation**\n    - Perform a special build of your executable which will add additional instrumentation code to it.\n2) **Gather performance profiles**\n    - Run your instrumented binary on representative workloads. The binary will generate profile files\n    on disk which will be then used to optimize the binary.\n    - Try to gather as much data as possible. Ideally, exercise all the important parts of the codebase (in the coverage sense).\n3) **Build an optimized binary using generated profiles**\n    - The compiler will use the generated profiles to build an optimized version of your binary.\n    - The binary will be optimized with respect to the profiled workloads. If you execute it on a\n    substantially different workload, the optimizations might not work (or they might even make your\n    binary slower!).\n\n## Example\n![Example usage of the tool](docs/terminal.gif)\n\n# **Usage**\nBefore you start to optimize your binaries, you should first check if your environment is set up\ncorrectly, at least for PGO (BOLT is more complicated). You can do that using the `info` command:\n```bash\n$ cargo pgo info\n```\n\n## PGO\n`cargo-pgo` provides subcommands that wrap common Cargo commands. It will automatically add\n`--release` to wrapped commands where it is applicable, since it doesn't really make sense to perform\nPGO on debug builds.\n\n### Generating the profiles\nFirst, you need to generate the PGO profiles by performing an *instrumented* build.\nYou can currently do that in several ways. The most generic command for creating an instrumented\nartifact is `cargo pgo instrument`:\n\n```bash\n$ cargo pgo instrument [\u003ccommand\u003e] -- [cargo-args]\n```\n\nThe `command` specifies what command will be executed by `cargo`. It is optional and by default it\nis set to `build`. You can pass additional arguments for `cargo` after `--`.\n\nThere are several ways of producing the profiles:\n\n- **Building a binary**\n    ```bash\n    $ cargo pgo build\n    # or\n    $ cargo pgo instrument build\n    ```\n\n    This is the simplest and recommended approach. You build an instrumented binary and then run it\n    on some workloads. Note that the binary will be located at `\u003ctarget-dir\u003e/\u003ctarget-triple\u003e/release/\u003cbinary-name\u003e`.\n\n- **Running an instrumented program**\n    ```bash\n    $ cargo pgo run\n    # or\n    $ cargo pgo instrument run\n    ```\n\n    You can also directly execute an instrumented binary with the `cargo pgo run` command,\n    which is a shortcut for `cargo pgo instrument run`. This command will instrument the binary and\n    then execute it right away.\n\n- **Run instrumented tests**\n    ```bash\n    $ cargo pgo test\n    # or\n    $ cargo pgo instrument test\n    ```\n    This command will generate profiles by executing tests. Note that unless your test suite\n    is really comprehensive, it might be better to create a binary and run it on some specific\n    workloads instead.\n\n- **Run instrumented benchmarks**\n    ```bash\n    $ cargo pgo bench\n    # or\n    $ cargo pgo instrument bench\n    ```\n    This command will generate profiles by executing benchmarks.\n\n### Building an optimized binary\nOnce you have generated some profiles, you can execute `cargo pgo optimize` to build an optimized\nversion of your binary.\n\nIf you want, you can also pass a command to `cargo pgo optimize` to e.g. run PGO-optimized benchmarks\nor tests:\n\n```bash\n$ cargo pgo optimize bench\n$ cargo pgo optimize test\n```\n\n### Analyzing PGO profiles\nYou can analyze gathered PGO profiles using the `llvm-profdata` binary:\n```console\n$ llvm-profdata show \u003cprofile\u003e.profdata\n```\n\n## BOLT\nUsing BOLT with `cargo-pgo` is similar to using PGO, however you either have to [build](#bolt-installation)\nBOLT manually or download it from the GitHub releases archive (for LLVM 16+). Support for BOLT is currently in an\nexperimental stage.\n\nBOLT is not supported directly by `rustc`, so the instrumentation and optimization commands are not\ndirectly applied to binaries built by `rustc`. Instead, `cargo-pgo` creates additional binaries that\nyou have to use for gathering profiles and executing the optimized code.\n\n### Generating the profiles\nFirst, you need to generate the BOLT profiles. To do that, execute the following command:\n```bash\n$ cargo pgo bolt build\n```\nThe instrumented binary will be located at `\u003ctarget-dir\u003e/\u003ctarget-triple\u003e/release/\u003cbinary-name\u003e-bolt-instrumented`.\nExecute it on several workloads to gather as much data as possible.\n\nNote that for BOLT, the profile gathering step is optional. You can also simply run the optimization\nstep (see below) without any profiles, although it will probably not have a large effect.\n\n### Building an optimized binary\nOnce you have generated some profiles, you can execute `cargo pgo bolt optimize` to build an\noptimized version of your binary. The optimized binary will be named `\u003cbinary-name\u003e-bolt-optimized`.\n\n## BOLT + PGO\nYes, BOLT and PGO can even be combined :) To do that, you should first generate PGO profiles and\nthen use BOLT on already PGO optimized binaries. You can do that using the `--with-pgo` flag:\n\n```bash\n# Build PGO instrumented binary\n$ cargo pgo build\n# Run binary to gather PGO profiles\n$ ./target/.../\u003cbinary\u003e\n# Build BOLT instrumented binary using PGO profiles\n$ cargo pgo bolt build --with-pgo\n# Run binary to gather BOLT profiles\n$ ./target/.../\u003cbinary\u003e-bolt-instrumented\n# Optimize a PGO-optimized binary with BOLT\n$ cargo pgo bolt optimize --with-pgo\n```\n\n\u003e Do not strip symbols from your release binary when using BOLT! If you do it, you might encounter\n\u003e linker errors.\n\n### BOLT installation\nHere's a short guide how to compile LLVM with BOLT manually. You will need a recent compiler, `CMake` and\n`ninja`.\n\n\u003e Note: LLVM BOLT is slowly getting into package repositories, although it's not fully working out of the box yet.\n\u003e You can find more details [here](https://github.com/Kobzol/cargo-pgo/issues/31) if you're interested.\n\n1) Download LLVM\n    ```bash\n    $ git clone https://github.com/llvm/llvm-project\n    $ cd llvm-project \n    ```\n2) (Optional) Checkout a stable version, at least 14.0.0\n    ```bash\n    $ git checkout llvmorg-14.0.5\n    ```\n   Note that BOLT is being actively fixed, so a `trunk` version of LLVM might actually work better.\n3) Prepare the build\n    ```bash\n    $ cmake -S llvm -B build -G Ninja \\\n      -DCMAKE_BUILD_TYPE=Release \\\n      -DCMAKE_INSTALL_PREFIX=${PWD}/llvm-install \\\n      -DLLVM_ENABLE_PROJECTS=\"clang;lld;compiler-rt;bolt\"\n    ```\n4) Compile LLVM with BOLT\n    ```bash\n    $ cd build\n    $ ninja\n    $ ninja install \n    ```\n    The built files should be located at `\u003cllvm-dir\u003e/llvm-install/bin`. You should add this directory\n    to `$PATH` to make BOLT usable with `cargo-pgo`.\n\n## Caveats\n- `cargo-pgo` needs to set RUSTFLAGS for the crate being compiled. If you pass your own RUSTFLAGS using `config.toml` file, please make sure to use the `[target.\u003c...\u003e] rustflags = ...` section, instead of the `[build] rustflags = ...` section. With `target`, your flags will be combined with the PGO flags. If you use `build`, your flags will be overridden instead. See [#49](https://github.com/Kobzol/cargo-pgo/issues/49) for more context.\n\n# Related work\n- [cargo-pgo](https://github.com/vadimcn/cargo-pgo) I basically independently reimplemented this\ncrate. It uses an almost identical approach, but doesn't support BOLT. It's not maintained\nanymore, I got a permission from its author to (re)use its name.\n\n# License\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKobzol%2Fcargo-pgo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FKobzol%2Fcargo-pgo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKobzol%2Fcargo-pgo/lists"}