@@ -145,106 +145,32 @@ function bench_cmds {
145145function bench {
146146 rm -rf bench-out && mkdir -p bench-out
147147
148- # Run the gas benchmark to generate the markdown file
148+ # Run the gas benchmark to generate the markdown file and JSON results
149149 gas_benchmark
150150
151- # Extract gas values from gas_benchmark.md and create JSON output
152- awk '
153- function trim(s) {
154- sub(/^[ \t]+/, "", s);
155- sub(/[ \t]+$/, "", s);
156- return s;
157- }
158- BEGIN {
159- print "[";
160- first = 1;
161- }
162- /^[a-zA-Z]/ {
163- if ($1 != "Function" && $1 != "-------------------------") {
164- # Split the line into columns and clean them
165- n = split($0, cols, "|");
166- for (i = 1; i <= n; i++) {
167- cols[i] = trim(cols[i]);
168- }
169-
170- # Only process Max rows
171- if (cols[2] == "Max") {
172- # Get the function name
173- func_name = cols[1];
174-
175- # Define our cases with their column numbers
176- cases["no_validators"] = 3;
177- cases["100_validators"] = 4;
178- cases["100_validators_slashing"] = 5;
179- cases["overhead"] = 6;
180-
181- for (case_name in cases) {
182- col = cases[case_name];
183-
184- # Filter: only include aggregate3 functions with 100_validators_slashing, and vice versa
185- has_aggregate3 = index(tolower(func_name), "aggregate3") > 0;
186- is_slashing_case = (case_name == "100_validators_slashing");
187-
188- # Skip if aggregate3 function but not slashing case, or slashing case but not aggregate3 function
189- if ((has_aggregate3 && !is_slashing_case) || (is_slashing_case && !has_aggregate3)) {
190- continue;
191- }
192-
193-
194- # Rename aggregate3 to proposeAndVote in function name
195- display_func_name = func_name;
196- if (has_aggregate3) {
197- gsub(/aggregate3/, "proposeAndVote", display_func_name);
198- }
199-
200- if (match(cols[col], /([0-9]+)[ ]*\(([0-9.]+)\)/)) {
201- # Extract the raw gas value (first number)
202- match(cols[col], /[0-9]+/);
203- raw_gas = substr(cols[col], RSTART, RLENGTH);
204-
205- # Extract the per tx value
206- match(cols[col], /\(([0-9.]+)\)/);
207- per_tx = substr(cols[col], RSTART+1, RLENGTH-2);
208-
209- if (!first) print ",";
210- first = 0;
211-
212- # Output raw gas value
213- print " {";
214- print " \"name\": \"" display_func_name " (" case_name ")\",";
215- print " \"value\": " raw_gas ",";
216- print " \"unit\": \"gas\"";
217- print " },";
218-
219- # Output per tx value
220- print " {";
221- print " \"name\": \"" display_func_name " (" case_name ") per l2 tx\",";
222- print " \"value\": " per_tx ",";
223- print " \"unit\": \"gas\"";
224- print " }";
225- }
226- }
227- }
228- }
229- }
230- END {
231- print "]";
232- }' gas_benchmark.md > ./bench-out/l1-gas.bench.json
151+ # Use Python script to generate the benchmark JSON from gas_benchmark_results.json
152+ python3 scripts/generate_benchmark_json.py
233153}
234154
235155function gas_benchmark {
236156 check=${1:- " no" }
237157
238- validator_costs
158+ echo_header " l1-contracts gas benchmark"
159+ forge --version
239160
240- diff gas_benchmark.new.md gas_benchmark.md > gas_benchmark.diff || true
161+ # Run the new Python benchmarking script
162+ echo " Running gas benchmarks..."
163+ python3 scripts/gas_benchmarks.py
241164
242- if [ -s gas_benchmark.diff -a " $check " = " check" ]; then
243- cat gas_benchmark.diff
244- echo " Gas benchmark has changed. Please check the diffs above, then run './bootstrap.sh gas_benchmark' to update the gas benchmark."
245- exit 1
165+ # The script generates gas_benchmark.md directly
166+ # Check if it differs from the committed version
167+ if [ " $check " = " check" ]; then
168+ if ! git diff --quiet gas_benchmark.md; then
169+ git diff gas_benchmark.md
170+ echo " Gas benchmark has changed. Please check the diffs above, then run './bootstrap.sh gas_benchmark' to update the gas benchmark."
171+ exit 1
172+ fi
246173 fi
247- mv gas_benchmark.new.md gas_benchmark.md
248174}
249175
250176function validator_costs {
@@ -256,129 +182,30 @@ function validator_costs {
256182 --match-contract " BenchmarkRollupTest" \
257183 --match-test " test_no_validators" \
258184 --fuzz-seed 42 \
259- > no_validators.tmp
185+ --json \
186+ > no_validators.json
260187
261188 # Run test with 100 validators
262189 echo " Running test with 100 validators..."
263190 FORGE_GAS_REPORT=true forge test \
264191 --match-contract " BenchmarkRollupTest" \
265192 --match-test " test_100_validators" \
266193 --fuzz-seed 42 \
267- > with_validators.tmp
194+ --json \
195+ > 100_validators.json
268196
269197 # Run test with 100 validators and slashing
270198 echo " Running test with 100 validators and slashing..."
271199 FORGE_GAS_REPORT=true forge test \
272200 --match-contract " BenchmarkRollupTest" \
273201 --match-test " test_100_slashing_validators" \
274202 --fuzz-seed 42 \
275- > with_slashing_validators.tmp
276-
277- file_no=" no_validators.tmp" # without validators
278- file_yes=" with_validators.tmp" # with validators
279- file_yes_slashing=" with_slashing_validators.tmp" # with validators and slashing
280- report=" gas_benchmark.new.md" # will be overwritten each run
281-
282- # keep ONLY these functions, in this order
283- wanted_funcs=" propose setupEpoch submitEpochRootProof aggregate3"
284-
285- # one label per numeric column (use | to separate)
286- labels=' Min|Avg|Median|Max|# Calls'
287-
288- awk -v keep=" $wanted_funcs " -v lbl=" $labels " \
289- -v f_no=" $file_no " -v f_yes=" $file_yes " -v f_yes_slashing=" $file_yes_slashing " '
290- function trim(s){gsub(/^[[:space:]]+|[[:space:]]+$/,"",s); return s}
291- # cell(raw [, scaled])
292- # If you call it with ONE argument, you get the raw value only.
293- # If you call it with TWO arguments, you get "raw (scaled)" padded to 22.
294- function cell(raw, scaled, s) {
295- # Was a second parameter supplied?
296- if ( scaled == "" ) # argument omitted → print raw only
297- return sprintf("%22d", raw)
298-
299- s = sprintf("%10d (%.2f)", raw, scaled)
300- return sprintf("%-22s", s) # left-pad / truncate to 22 chars
301- }
302-
303- BEGIN{
304- # ---------------- wanted functions & labels (unchanged) ---------------
305- nf = split(keep, F, /[[:space:]]+/)
306- for (i = 1; i <= nf; i++) { order[i] = F[i]; want[F[i]] }
307- split(lbl, L, /\|/); nLab = length(L)
308-
309- # ---------------- fixed-width formats ---------------------------------
310- # header row
311- hdr = "%-24s | %-7s | %22s | %23s | %22s | %12s\n"
312- sep = "-------------------------+---------+------------------------+-------------------------+------------------------+-----------------"
313- # data row (the three %22s will already be fully padded strings)
314- row = "%-24s | %-7s | %22s | %23s | %22s | %10.2f%%\n"
315-
316- printf hdr, "Function", "Metric",
317- "No Validators (gas/tx)", "100 Validators (gas/tx)", "Δ Gas (gas/tx)", "% Overhead"
318- print sep
319-
320- FS="|"; OFS=""
321- }
322- # ---------- first file: without validators ----------------------------------
323- FNR==NR {
324- if($0 !~ /^\|/) next
325- split($0, C) # C[1] "", C[2] fn, C[3..] numbers
326- fn = trim(C[2])
327- if(!(fn in want)) next
328- for(i=3; i<=NF-1; i++) base[fn,i] = trim(C[i]) + 0
329- cols[fn] = NF - 3 # remember how many numeric cols
330- next
331- }
332- # ---------- second file: with validators ------------------------------------
333- {
334- if($0 !~ /^\|/) next
335- split($0, C)
336- fn = trim(C[2])
337- if(!(fn in want)) next
338- for(i=3; i<=NF-1; i++) with[fn,i] = trim(C[i]) + 0
339- cols[fn] = NF - 3
340- }
341- # ---------- third file: with validators and slashing --------------------------
342- {
343- if($0 !~ /^\|/) next
344- split($0, C)
345- fn = trim(C[2])
346- if(!(fn in want)) next
347- for(i=3; i<=NF-1; i++) with_slashing[fn,i] = trim(C[i]) + 0
348- cols[fn] = NF - 3
349- }
350- # ---------- emit table -------------------------------------------------------
351- END{
352- for (k = 1; k <= nf; k++) {
353- fn = order[k]
354- div = (fn == "propose" || fn == "aggregate3" ? 360 : 11520) # change 11520→720 if desired
355-
356- for (j = 1; j <= cols[fn]; j++) {
357- idx = j + 2
358- metric = L[j]
359- a = base[fn,idx] + 0
360- b = with[fn,idx] + 0
361- diff = b - a
362- pct = (a ? diff * 100.0 / a : 0)
363-
364- if (metric == "# Calls") {
365- c1 = cell(a)
366- c2 = cell(b)
367- c3 = cell(diff)
368- } else {
369- c1 = cell(a, a/div)
370- c2 = cell(b, b/div)
371- c3 = cell(diff,diff/div)
372- }
373- printf row, fn, metric, c1, c2, c3, pct
374- }
375- print sep
376- }
377- }
378- ' " $file_no " " $file_yes " " $file_yes_slashing " > " $report "
203+ --json \
204+ > 100_validators_slashing.json
379205
380- # Clean up temporary files
381- rm no_validators.tmp with_validators.tmp with_slashing_validators.tmp
206+ # Use Python script to process the JSON files
207+ echo " Processing gas reports with Python script..."
208+ python3 scripts/process_gas_reports.py no_validators.json 100_validators.json 100_validators_slashing.json
382209}
383210
384211# First argument is a branch name (e.g. master, or the latest version e.g. 1.2.3) to push to the head of.
0 commit comments