Skip to content

Commit 59a51b9

Browse files
committed
Add bench_prover_scaling.sh
1 parent 2cc03aa commit 59a51b9

1 file changed

Lines changed: 262 additions & 0 deletions

File tree

scripts/bench_prover_scaling.sh

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
#!/bin/bash
2+
# Prover scaling benchmark across fib_iterative sizes.
3+
# Shows how per-phase timing and heap grow with program size, plus linear regression.
4+
#
5+
# Usage: bench_prover_scaling.sh [--sizes "500k 1M 2M 4M"] [--runs N]
6+
#
7+
# Requires: instruments + jemalloc-stats features.
8+
9+
set -euo pipefail
10+
11+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12+
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
13+
TMP_DIR="/tmp/bench_prover_scaling"
14+
ELF_DIR="$ROOT_DIR/executor/program_artifacts/asm"
15+
16+
GREEN='\033[0;32m'
17+
BOLD='\033[1m'
18+
NC='\033[0m'
19+
20+
SIZES="500k 1M 2M 4M"
21+
RUNS=1
22+
23+
while [[ $# -gt 0 ]]; do
24+
case $1 in
25+
--sizes) SIZES="$2"; shift 2 ;;
26+
--runs) RUNS="$2"; shift 2 ;;
27+
*) echo "Unknown arg: $1"; exit 1 ;;
28+
esac
29+
done
30+
31+
suffix_to_steps() {
32+
case $1 in
33+
160k) echo 160000 ;; 250k) echo 250000 ;; 372k) echo 372000 ;;
34+
500k) echo 500000 ;; 1M) echo 1000000 ;; 1200k) echo 1200000 ;;
35+
2M) echo 2000000 ;; 4M) echo 4000000 ;; 8M) echo 8000000 ;;
36+
16M) echo 16000000 ;; 32M) echo 32000000 ;; 64M) echo 64000000 ;; 128M) echo 128000000 ;;
37+
*) echo "Unknown size: $1" >&2; exit 1 ;;
38+
esac
39+
}
40+
41+
rm -rf "$TMP_DIR" && mkdir -p "$TMP_DIR"
42+
43+
echo -e "${GREEN}Building CLI with jemalloc-stats + instruments...${NC}"
44+
cargo build --release -p cli --features jemalloc-stats,instruments \
45+
--manifest-path "$ROOT_DIR/Cargo.toml" 2>&1 | tail -1
46+
CLI="$ROOT_DIR/target/release/cli"
47+
48+
# Parse timing (seconds) and heap (MB) from one run's stdout + stderr.
49+
# Emits key=value lines to stdout.
50+
parse_run() {
51+
local stdout=$1 stderr=$2
52+
awk '
53+
function secs( s) {
54+
if (match($0, /[0-9]+\.?[0-9]*s/)) {
55+
s = substr($0, RSTART, RLENGTH - 1)
56+
return s
57+
}
58+
return ""
59+
}
60+
/^ Execute / { v = secs(); if (v) print "t_execute=" v }
61+
/^ Trace build/ { v = secs(); if (v) print "t_trace_build=" v }
62+
/^ AIR construction/ { v = secs(); if (v) print "t_air=" v }
63+
/^ Pre-pass/ { v = secs(); if (v) print "t_prepass=" v }
64+
/^ Round 1 / { v = secs(); if (v) print "t_round1=" v }
65+
/Main trace commits/ { v = secs(); if (v) print "t_main_commits="v }
66+
/Aux trace build/ { v = secs(); if (v) print "t_aux_build=" v }
67+
/Aux trace commit/ { v = secs(); if (v) print "t_aux_commit=" v }
68+
/Rounds 2/ { v = secs(); if (v) print "t_rounds24=" v }
69+
/Main expand_pool_to_lde/{ v = secs(); if (v) print "t_main_lde=" v }
70+
/Aux expand_pool_to_lde/ { v = secs(); if (v) print "t_aux_lde=" v }
71+
/Main commit \(Merkle\)/ { v = secs(); if (v) print "t_main_merkle=" v }
72+
/Aux commit \(Merkle\)/ { v = secs(); if (v) print "t_aux_merkle=" v }
73+
/^ Total FFT/ { v = secs(); if (v) print "t_total_fft=" v }
74+
/^ Total Merkle/ { v = secs(); if (v) print "t_total_merkle="v }
75+
/^ TOTAL / { v = secs(); if (v) print "t_total=" v }
76+
/After execute/ { print "h_execute=" $(NF-1) }
77+
/After trace build/ { print "h_trace_build=" $(NF-1) }
78+
/After AIR/ { print "h_air=" $(NF-1) }
79+
/after pool alloc/ { print "h_pool_alloc=" $(NF-1) }
80+
/after main commits/ { print "h_main_commits=" $(NF-1) }
81+
/after aux build/ { print "h_aux_build=" $(NF-1) }
82+
/after aux commit/ { print "h_aux_commit=" $(NF-1) }
83+
' "$stderr"
84+
85+
grep -o 'Peak heap: [0-9]*' "$stdout" | awk '{print "peak=" $3}'
86+
grep -o 'Proving time: [0-9.]*' "$stdout" | awk '{print "wall=" $3}'
87+
}
88+
89+
get_val() {
90+
awk -F= -v k="$2" '$1==k {print $2; exit}' "$1" 2>/dev/null
91+
}
92+
93+
# Pick the run whose wall-clock is the median across RUNS; copy its data file.
94+
# Writes final per-size data to ${size}_data.txt.
95+
select_median_run() {
96+
local size=$1
97+
if [ "$RUNS" -eq 1 ]; then
98+
cp "$TMP_DIR/${size}_run_1.txt" "$TMP_DIR/${size}_data.txt"
99+
return
100+
fi
101+
# Collect (wall, run_index), sort by wall, pick middle
102+
local pairs=""
103+
for i in $(seq 1 "$RUNS"); do
104+
local w
105+
w=$(get_val "$TMP_DIR/${size}_run_${i}.txt" wall)
106+
pairs+=" $w $i"
107+
done
108+
local median_idx
109+
median_idx=$(echo "$pairs" | tr ' ' '\n' | awk 'NF' | paste -d' ' - - | \
110+
sort -n | awk -v n="$RUNS" 'NR == int((n+1)/2) {print $2}')
111+
cp "$TMP_DIR/${size}_run_${median_idx}.txt" "$TMP_DIR/${size}_data.txt"
112+
}
113+
114+
for size in $SIZES; do
115+
ELF="$ELF_DIR/fib_iterative_${size}.elf"
116+
[ -f "$ELF" ] || { echo "Missing: $ELF"; continue; }
117+
steps=$(suffix_to_steps "$size")
118+
echo -e "${GREEN}Running fib_iterative_${size} (${RUNS} runs)...${NC}"
119+
120+
for i in $(seq 1 "$RUNS"); do
121+
STDOUT="$TMP_DIR/${size}_run_${i}_stdout.txt"
122+
STDERR="$TMP_DIR/${size}_run_${i}_stderr.txt"
123+
"$CLI" prove "$ELF" -o "$TMP_DIR/proof.bin" --time >"$STDOUT" 2>"$STDERR"
124+
rm -f "$TMP_DIR/proof.bin"
125+
{
126+
echo "steps=$steps"
127+
parse_run "$STDOUT" "$STDERR"
128+
} > "$TMP_DIR/${size}_run_${i}.txt"
129+
done
130+
select_median_run "$size"
131+
done
132+
133+
# ---------------------------------------------------------------------------
134+
# Rendering
135+
# ---------------------------------------------------------------------------
136+
137+
print_row() {
138+
local label=$1 key=$2 unit=$3
139+
printf " %-26s" "$label"
140+
for size in $SIZES; do
141+
local data="$TMP_DIR/${size}_data.txt"
142+
if [ ! -f "$data" ]; then
143+
printf " %10s" "-"; continue
144+
fi
145+
local v
146+
v=$(get_val "$data" "$key")
147+
if [ -z "$v" ]; then
148+
printf " %10s" "-"
149+
elif [ "$unit" = "s" ]; then
150+
printf " %9.2fs" "$v"
151+
else
152+
printf " %10d" "$v"
153+
fi
154+
done
155+
echo ""
156+
}
157+
158+
print_header() {
159+
printf " %-26s" ""
160+
for size in $SIZES; do printf " %10s" "$size"; done
161+
echo ""
162+
printf " %-26s" ""
163+
for size in $SIZES; do printf " %10s" "──────────"; done
164+
echo ""
165+
}
166+
167+
echo ""
168+
echo -e "${BOLD}=== TIMING (seconds) ===${NC}"
169+
print_header
170+
print_row "Execute" t_execute s
171+
print_row "Trace build" t_trace_build s
172+
print_row "AIR construction" t_air s
173+
print_row "Pre-pass" t_prepass s
174+
print_row "Round 1" t_round1 s
175+
print_row " Main trace commits" t_main_commits s
176+
print_row " Main LDE" t_main_lde s
177+
print_row " Main Merkle" t_main_merkle s
178+
print_row " Aux trace build" t_aux_build s
179+
print_row " Aux trace commit" t_aux_commit s
180+
print_row " Aux LDE" t_aux_lde s
181+
print_row " Aux Merkle" t_aux_merkle s
182+
print_row "Rounds 2-4" t_rounds24 s
183+
print_row "Total FFT (all rounds)" t_total_fft s
184+
print_row "Total Merkle" t_total_merkle s
185+
print_row "TOTAL" t_total s
186+
187+
echo ""
188+
echo -e "${BOLD}=== HEAP (MB absolute) ===${NC}"
189+
print_header
190+
print_row "After execute" h_execute mb
191+
print_row "After trace build" h_trace_build mb
192+
print_row "After AIR construction" h_air mb
193+
print_row "After pool alloc" h_pool_alloc mb
194+
print_row "After main commits" h_main_commits mb
195+
print_row "After aux build" h_aux_build mb
196+
print_row "After aux commit" h_aux_commit mb
197+
print_row "Peak heap" peak mb
198+
199+
# ---------------------------------------------------------------------------
200+
# Linear regression per metric: y = a + b * (steps / 1M)
201+
# ---------------------------------------------------------------------------
202+
203+
regress() {
204+
local label=$1 key=$2 unit=$3
205+
local pairs=""
206+
for size in $SIZES; do
207+
local data="$TMP_DIR/${size}_data.txt"
208+
[ -f "$data" ] || continue
209+
local steps v
210+
steps=$(get_val "$data" steps)
211+
v=$(get_val "$data" "$key")
212+
[ -z "$v" ] && continue
213+
[ -z "$steps" ] && continue
214+
local steps_m
215+
steps_m=$(awk -v s="$steps" 'BEGIN {printf "%.6f", s / 1000000}')
216+
pairs+=" $steps_m $v"
217+
done
218+
echo "$pairs" | awk -v label="$label" -v unit="$unit" '{
219+
n = NF / 2
220+
if (n < 2) { printf " %-26s (insufficient data)\n", label; next }
221+
for (i = 0; i < n; i++) { x[i] = $(2*i+1); y[i] = $(2*i+2) }
222+
sx=0; sy=0; sxx=0; sxy=0
223+
for (i=0;i<n;i++) { sx+=x[i]; sy+=y[i]; sxx+=x[i]*x[i]; sxy+=x[i]*y[i] }
224+
d = n*sxx - sx*sx
225+
if (d == 0) { printf " %-26s (constant)\n", label; next }
226+
b = (n*sxy - sx*sy) / d
227+
a = (sy - b*sx) / n
228+
ym = sy/n; ss_tot=0; ss_res=0
229+
for (i=0;i<n;i++) { p=a+b*x[i]; ss_res+=(y[i]-p)^2; ss_tot+=(y[i]-ym)^2 }
230+
r2 = (ss_tot>0) ? 1 - ss_res/ss_tot : 1
231+
if (unit == "s")
232+
printf " %-26s %+7.2fs/M (base %6.2fs, R\xc2\xb2=%.3f)\n", label, b, a, r2
233+
else
234+
printf " %-26s %+7.0f MB/M (base %6.0f MB, R\xc2\xb2=%.3f)\n", label, b, a, r2
235+
}'
236+
}
237+
238+
echo ""
239+
echo -e "${BOLD}=== TIMING GROWTH (per 1M steps) ===${NC}"
240+
regress "Execute" t_execute s
241+
regress "Trace build" t_trace_build s
242+
regress "AIR construction" t_air s
243+
regress "Pre-pass" t_prepass s
244+
regress "Round 1" t_round1 s
245+
regress "Rounds 2-4" t_rounds24 s
246+
regress "Total FFT" t_total_fft s
247+
regress "Total Merkle" t_total_merkle s
248+
regress "TOTAL" t_total s
249+
250+
echo ""
251+
echo -e "${BOLD}=== HEAP GROWTH (per 1M steps) ===${NC}"
252+
regress "After execute" h_execute mb
253+
regress "After trace build" h_trace_build mb
254+
regress "After AIR construction" h_air mb
255+
regress "After pool alloc" h_pool_alloc mb
256+
regress "After main commits" h_main_commits mb
257+
regress "After aux build" h_aux_build mb
258+
regress "After aux commit" h_aux_commit mb
259+
regress "Peak heap" peak mb
260+
261+
echo ""
262+
echo "Raw data: $TMP_DIR/"

0 commit comments

Comments
 (0)