-
-
Save giovannicuccu/b3f56321c929e37b6e758fcd1f601554 to your computer and use it in GitHub Desktop.
Bash script to run a benchmark under decent conditons.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # | |
| # this is a modified copy of https://gist.github.com/grahamking/9c8c91b871843a9a6ce2bec428b8f48d | |
| # the differences are AMD cpu detection and the ability to run this script via sudo | |
| # Usage: runperf ./my-benchmark-binary | |
| # | |
| # Script to run a benchmark / performance test in decent conditions. Based on: | |
| # - https://www.llvm.org/docs/Benchmarking.html | |
| # - "Performance Analysis and Tuning on Modern CPU" by Denis Bakhvalov, Appendix A. | |
| # - https://github.com/andikleen/pmu-tools | |
| # | |
| # Note that this doesn't do any actual benchmarking, your binary must be able to do that all by itself. | |
| # Instead, this sets up the machine to make your benchmarks reliable. | |
| # | |
| # Usage with rust/cargo criterion (https://github.com/bheisler/cargo-criterion): | |
| # Build the binary: `cargo criterion --bench my-bench --no-run` | |
| # Run it: `runperf ./target/release/deps/my-bench-<hex-string> --bench` | |
| # | |
| # Setup | |
| # | |
| # Detect CPU vendor for appropriate turbo mode handling, default to intel when unable to identify the cpu | |
| detect_cpu_vendor() { | |
| if [ -f /proc/cpuinfo ]; then | |
| local vendor=$(grep -m 1 "vendor_id" /proc/cpuinfo | awk '{print $3}') | |
| case "$vendor" in | |
| "GenuineIntel") | |
| echo "intel" | |
| ;; | |
| "AuthenticAMD") | |
| echo "amd" | |
| ;; | |
| *) | |
| echo "intel" | |
| ;; | |
| esac | |
| else | |
| echo "intel" | |
| fi | |
| } | |
| CPU_VENDOR=$(detect_cpu_vendor) | |
| echo "Detected CPU vendor: $CPU_VENDOR" | |
| # (optional) mount input / output files in ramdisk to eliminate disk access variability | |
| # mount -t tmpfs -o size=<XX>g none dir_to_mount | |
| echo "Disable address space randomization" | |
| echo 0 | sudo tee /proc/sys/kernel/randomize_va_space > /dev/null | |
| echo "Disable kernel NMI watchdog" | |
| sudo sysctl -q -w kernel.nmi_watchdog=0 | |
| echo "Allow access to perf events" | |
| # Sometimes we run as ./runperf perf stat <the-binary> | |
| echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid > /dev/null | |
| echo "Set scaling governor to performance" | |
| # If you don't have `cpupower`: | |
| # for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor | |
| # do | |
| # echo performance > /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor | |
| # done | |
| sudo cpupower frequency-set -g performance > /dev/null | |
| echo "Disable turbo mode (short-term higher freq)" | |
| # This is the biggest source of variability. For short runs the CPU can go much faster but it heats | |
| # up and cannot sustain the boost, so later runs will be slower. | |
| disable_turbo_mode() { | |
| case "$CPU_VENDOR" in | |
| "intel") | |
| if [ -f /sys/devices/system/cpu/intel_pstate/no_turbo ]; then | |
| echo 1 | sudo tee /sys/devices/system/cpu/intel_pstate/no_turbo > /dev/null | |
| echo "Intel turbo mode disabled" | |
| else | |
| echo "Warning: Intel turbo control not available" | |
| fi | |
| ;; | |
| "amd") | |
| if [ -f /sys/devices/system/cpu/cpufreq/boost ]; then | |
| echo 0 | sudo tee /sys/devices/system/cpu/cpufreq/boost > /dev/null 2>&1 | |
| echo "AMD boost disabled" | |
| fi | |
| ;; | |
| *) | |
| ;; | |
| esac | |
| } | |
| disable_turbo_mode | |
| echo "Move system processes to second two cores (and their hyper-threaded pairs)" | |
| # Adjust this if your topology is different. I have four cores / eight threads. | |
| # | |
| # This only moves system stuff not user stuff, so your terminal/browser/Gnome are all still using the shared CPU. | |
| # Ideally we would also do the same for `user.slice`, but then `taskset` later can't use the reserved CPUs. | |
| # To mitigate we use `nice` to make our job higher priority. | |
| sudo systemctl set-property --runtime system.slice AllowedCPUs=2,3,6,7 | |
| echo "Disable the hyper-threading pair of the reserved CPUs" | |
| # Find the pair: cat /sys/devices/system/cpu/cpuN/topology/thread_siblings_list | |
| echo 0 | sudo tee /sys/devices/system/cpu/cpu4/online > /dev/null | |
| echo 0 | sudo tee /sys/devices/system/cpu/cpu5/online > /dev/null | |
| # | |
| # Run the script | |
| # . on our reserved CPUs so it doesn't migrate | |
| # . re-niced so it doesn't get context switched | |
| # | |
| echo "params full $@" | |
| ORIGINAL_USER=${SUDO_USER:-$USER} | |
| taskset -c 0,1 sudo nice -n -5 runuser -u $ORIGINAL_USER -- $@ | |
| # Monitor cpu-migrations and context-switches. They should both be 0. perf must come before nice to make the benchmark higher priority. | |
| #taskset -c 0,1 perf stat -e context-switches,cpu-migrations sudo nice -n -5 $@ | |
| # | |
| # Restore | |
| # | |
| echo "Restoring to non-perf settings" | |
| echo 1 | sudo tee /sys/devices/system/cpu/cpu4/online > /dev/null | |
| echo 1 | sudo tee /sys/devices/system/cpu/cpu5/online > /dev/null | |
| sudo systemctl set-property --runtime system.slice AllowedCPUs=0-7 | |
| enable_turbo_mode() { | |
| case "$CPU_VENDOR" in | |
| "intel") | |
| if [ -f /sys/devices/system/cpu/intel_pstate/no_turbo ]; then | |
| echo 0 | sudo tee /sys/devices/system/cpu/intel_pstate/no_turbo > /dev/null | |
| echo "Intel turbo mode re-enabled" | |
| fi | |
| ;; | |
| "amd") | |
| # Re-enable AMD boost | |
| if [ -f /sys/devices/system/cpu/cpufreq/boost ]; then | |
| echo 1 | sudo tee /sys/devices/system/cpu/cpufreq/boost > /dev/null 2>&1 | |
| echo "AMD boost re-enabled" | |
| fi | |
| ;; | |
| *) | |
| ;; | |
| esac | |
| } | |
| enable_turbo_mode | |
| sudo cpupower frequency-set -g powersave > /dev/null | |
| echo 0 | sudo tee /proc/sys/kernel/perf_event_paranoid | |
| sudo sudo sysctl -q -w kernel.nmi_watchdog=1 | |
| echo 2 | sudo tee /proc/sys/kernel/randomize_va_space > /dev/null |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment