# [cargo-]cbench Environment control for benchmarks on Linux/systemd, reducing external noise from benchmark results. `cbench` can be used to run any programs. `cargo-cbench` is a wrapper giving a `cargo bench`-like interface for running [cargo benches][cargo-bench] conveniently. ## Installation `cargo install cbench` ## Usage For Rust projects with cargo benches, simply replace `cargo bench` with `cargo cbench`: `cargo cbench` This will setup the environment and tweak system configurables (see [the next section](#what-it-does)), run all cargo benchmarks in the current project, and finally revert changes to the original state. It will only allocate a single *exclusive* CPU for the benchmark. If your program is multi-threaded, you can allocate more by: `cargo cbench --cpus=1-2` Cargo flags and bench program flags can be passed using the same syntax: `cargo cbench --bench=bench1 --features=feat1 -- --exact foo` For other benchmarking frameworks, run `cbench` following by the command: `cbench hyperfine /some/benchee` By default, the target command will be run inside a systemd unit named 'cbench.service' as the current user. It will be in a clean environment without inheriting from the current shell. If your command relies on some environment variables, you need to pass them explicitly via `--setenv=ENV` or `--setenv=ENV=VALUE`. More control arguments can be seen in `cbench --help`. ## What it does - `noaslr`: Disable [Address Space Layout Randomization (ASLR)][aslr] via [`/proc/sys/kernel/randomize_va_space`][randomize_va_space] - `cpuset`: Pin the target process' cgroup on specific CPU(s) for exclusive use via [cgroup cpuset][cpuset]. - `noht`: Disable (set offline) CPU thread siblings of the CPU(s) used if hyper-threading is enabled, via [CPU hotplug][cpu-hotplug]. - `cpufreq`: Set power governor of target CPU(s) to 'performance' and disable adaptive turbo/boost, via [CPU Performance Scaling][cpufreq]. - `noirq`: Mask used CPU(s) from [IRQ affinity][irq-affinity]. These control modules can be enabled or disabled individually via `--with=` or `--without=`. ## What it does NOT - We don't do benchmarks, but we setup environment and tunables for benchmark programs to do benchmarks more reliably. It's expected to be used together with benchmark frameworks/programs like [`criterion`][criterion] or [`hyperfine`][hyperfine]. - Environment control does not make programs run faster, but typically in opposite, because we disable frequency boost by default. Our goal is consistency rather than performance. - We reduce external noise from tainting the benchmark results. But we cannot magically stabilize it from internal biases. Benchee may still be unstable under different memory (heap and stack) layout caused by environment variables or "being lucky" on program initialization, producing a seemingly random systemic bias through multiple runs. You need to carefully write your benchee program to reduce this effect. See [stabilizer] for more information. ## Privileged operations All settings mentioned above are privileged and machine global. To minimize the impact and security risks, we leverage `systemd-run` privileged `ExecStartPre=`/`ExecStopPost=` commands, thus only the environment setup and reset will be executed with root privileges. Authentication is done by `systemd-run` itself by default (via PolKit), or you can use `--use-sudo` to use `sudo` instead. Note that no matter whether `--use-sudo` is used, the program compilation (via `cargo build`) and benchmark processes are always running as the current user. Never add `sudo` to `cargo cbench` itself! Even if you really want to run the target artifact/command as `root` because, say you are running `perf stat --all-kernel`, use the option `--root` for it. Environment modifications will be reverted after the program exits via systemd `ExecStopPost=` command, which will do the clean up even if the target process aborted unexpectedly (eg. by Ctrl-C). If they do not, please report a bug. ## Credit - Heavily motivated by [LLVM benchmarking tips][llvm-tips]. - Thank [QuarticCat@github](https://github.com/QuarticCat) for turbo/boost control tips. - Thank [PeterCxy@github](https://github.com/PeterCxy) for IRQ control tips. [cargo-bench]: https://doc.rust-lang.org/cargo/reference/profiles.html#bench [criterion]: https://github.com/bheisler/criterion.rs [hyperfine]: https://github.com/sharkdp/hyperfine [aslr]: https://en.wikipedia.org/wiki/Address_space_layout_randomization [randomize_va_space]: https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html#randomize-va-space [cpuset]: https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#cpuset-interface-files [cpu-hotplug]: https://www.kernel.org/doc/html/latest/core-api/cpu_hotplug.html#using-cpu-hotplug [cpufreq]: https://www.kernel.org/doc/html/latest/admin-guide/pm/cpufreq.html#policy-interface-in-sysfs [irq-affinity]: https://www.kernel.org/doc/html/latest/core-api/irq/irq-affinity.html [stabilizer]: https://github.com/ccurtsinger/stabilizer [llvm-tips]: https://llvm.org/docs/Benchmarking.html