|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Uses strict scheduling to run benchmarks in parallel on their own cpus. |
| 3 | +# For benchmarks that can't be parallelized, runs them one at a time to avoid resource contention. |
| 4 | +# Isolates benchmark CPUs from OS and pins all other processes to non-bench CPUs to avoid interference. |
| 5 | +NO_CD=1 source $(git rev-parse --show-toplevel)/ci3/source |
| 6 | + |
| 7 | +bench_cmds_file=$1 |
| 8 | + |
| 9 | +function isolate_bench_cpus { |
| 10 | + [ "$CI" -eq 0 ] && return |
| 11 | + |
| 12 | + # CPU layout assumption: physical cores are 0..N/2-1, hyperthreads are N/2..N-1. |
| 13 | + local total_cpus=$(nproc) |
| 14 | + local total_physical=$((total_cpus / 2)) |
| 15 | + local os_reserve=8 |
| 16 | + local bench_count=$((total_physical - os_reserve)) |
| 17 | + |
| 18 | + # Disable hyperthread siblings of benchmark cores (N/2 .. N/2+bench_count-1). |
| 19 | + # OS cores' hyperthreads (N/2+bench_count .. N-1) stay on for extra OS capacity. |
| 20 | + for cpu in $(seq $total_physical $((total_physical + bench_count - 1))); do |
| 21 | + sudo sh -c "echo 0 > /sys/devices/system/cpu/cpu$cpu/online" 2>/dev/null || true |
| 22 | + done |
| 23 | + |
| 24 | + # Pin all container processes to OS CPUs so they can't land on benchmark cores. |
| 25 | + # exec_test's taskset overrides this for each benchmark with its allocated CPUs. |
| 26 | + local os_cpu_list="$bench_count-$((total_physical - 1)),$((total_physical + bench_count))-$((total_cpus - 1))" |
| 27 | + echo "Pinning container processes to OS CPUs ($os_cpu_list)..." |
| 28 | + for pid in $(ps -eo pid= 2>/dev/null); do |
| 29 | + taskset -apc "$os_cpu_list" $pid &>/dev/null || true |
| 30 | + done |
| 31 | + |
| 32 | + export BENCH_CPU_COUNT=$bench_count |
| 33 | + |
| 34 | + echo "Benchmark CPU isolation: CPUs 0-$((bench_count - 1)) ($bench_count cores, hyperthreads off) for benchmarks." |
| 35 | + echo "OS CPUs: $os_cpu_list." |
| 36 | +} |
| 37 | + |
| 38 | +function unisolate_bench_cpus { |
| 39 | + [ "$CI" -eq 0 ] && return |
| 40 | + |
| 41 | + echo "Re-enabling all CPUs..." |
| 42 | + local total_cpus=$(nproc --all) |
| 43 | + for cpu in $(seq 1 $((total_cpus - 1))); do |
| 44 | + sudo sh -c "echo 1 > /sys/devices/system/cpu/cpu$cpu/online" 2>/dev/null || true |
| 45 | + done |
| 46 | + # Unpin all processes (were pinned to OS CPUs during bench). |
| 47 | + for pid in $(ps -eo pid= 2>/dev/null); do |
| 48 | + taskset -apc 0-$((total_cpus - 1)) $pid &>/dev/null || true |
| 49 | + done |
| 50 | + echo "All CPUs re-enabled. Online CPUs: $(nproc)" |
| 51 | +} |
| 52 | + |
| 53 | +isolate_bench_cpus |
| 54 | + |
| 55 | +# Clean up old benchmark outputs to avoid confusion with new results. |
| 56 | +find . -type d -iname bench-out | xargs rm -rf |
| 57 | + |
| 58 | +# Run parallelizable benchmarks. |
| 59 | +cat $bench_cmds_file | grep -v ':PARALLEL=0' | STRICT_SCHEDULING=1 parallelize |
| 60 | + |
| 61 | +# Run serial benchmarks one at a time (for memory bandwidth / cache isolation). |
| 62 | +serial_cmds=$(cat $bench_cmds_file | grep ':PARALLEL=0' || true) |
| 63 | +if [ -n "$serial_cmds" ]; then |
| 64 | + echo "Running serial benchmarks..." |
| 65 | + while IFS= read -r cmd; do |
| 66 | + [ -z "$cmd" ] && continue |
| 67 | + run_test_cmd "$cmd" |
| 68 | + done <<< "$serial_cmds" |
| 69 | +fi |
| 70 | + |
| 71 | +unisolate_bench_cpus |
0 commit comments