Skip to content

Commit a9f68e0

Browse files
authored
feat(test): add execution benchmarks (#1556)
Closes INT-3706 - Moved existing benchmarks to `benchmarks/prove` crate - Added a new `benchmarks/execute` binary crate that runs execution for a list of guest programs - Added programs for benchmarking in `benchmarks/guest` - Added a ci workflow to run execution benchmarks - Note: Timing metrics for summary are currently being parsed from logs. I'll change it to use proper metrics in a follow up
1 parent 51f07d5 commit a9f68e0

File tree

118 files changed

+1118
-95
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

118 files changed

+1118
-95
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
name: "benchmarks-execute"
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
pull_request:
7+
types: [opened, synchronize, reopened, labeled]
8+
branches: ["**"]
9+
paths:
10+
- "benchmarks/execute/**"
11+
- "crates/circuits/**"
12+
- "crates/toolchain/**"
13+
- "crates/prof/**"
14+
- "crates/sdk/**"
15+
- "crates/vm/**"
16+
- "extensions/**"
17+
- "Cargo.toml"
18+
- ".github/workflows/benchmarks-execute.yml"
19+
workflow_dispatch:
20+
21+
env:
22+
CARGO_TERM_COLOR: always
23+
24+
jobs:
25+
execute-benchmarks:
26+
runs-on:
27+
- runs-on=${{ github.run_id }}
28+
- runner=8cpu-linux-x64
29+
steps:
30+
- uses: actions/checkout@v4
31+
32+
- name: Set up Rust
33+
uses: actions-rs/toolchain@v1
34+
with:
35+
profile: minimal
36+
toolchain: stable
37+
override: true
38+
39+
- name: Run execution benchmarks
40+
working-directory: benchmarks/execute
41+
run: cargo run | tee benchmark_output.log
42+
43+
- name: Parse benchmark results
44+
working-directory: benchmarks/execute
45+
run: |
46+
# Determine if running in GitHub Actions environment
47+
if [ -n "$GITHUB_STEP_SUMMARY" ]; then
48+
SUMMARY_FILE="$GITHUB_STEP_SUMMARY"
49+
echo "### Benchmark Results Summary" >> "$SUMMARY_FILE"
50+
else
51+
SUMMARY_FILE="benchmark_summary.md"
52+
echo "### Benchmark Results Summary" > "$SUMMARY_FILE"
53+
echo "Saving summary to $SUMMARY_FILE"
54+
fi
55+
56+
# Set up summary table header
57+
echo "| Program | Total Time (ms) |" >> "$SUMMARY_FILE"
58+
echo "| ------- | --------------- |" >> "$SUMMARY_FILE"
59+
60+
# Variables to track current program and total time
61+
current_program=""
62+
total_time=0
63+
64+
# Process the output file line by line
65+
while IFS= read -r line; do
66+
# Check if line contains "Running program" message
67+
if [[ $line =~ i\ \[info\]:\ Running\ program:\ ([a-zA-Z0-9_-]+) ]]; then
68+
# If we were processing a program, output its results
69+
if [[ -n "$current_program" ]]; then
70+
echo "| $current_program | $total_time |" >> "$SUMMARY_FILE"
71+
fi
72+
73+
# Start tracking new program
74+
current_program="${BASH_REMATCH[1]}"
75+
total_time=0
76+
fi
77+
78+
# Check for program completion to catch programs that might have no execution segments
79+
if [[ $line =~ i\ \[info\]:\ Completed\ program:\ ([a-zA-Z0-9_-]+) ]]; then
80+
completed_program="${BASH_REMATCH[1]}"
81+
# If no segments were found for this program, ensure it's still in the output
82+
if [[ "$current_program" == "$completed_program" && $total_time == 0 ]]; then
83+
echo "| $current_program | 0 |" >> "$SUMMARY_FILE"
84+
current_program=""
85+
fi
86+
fi
87+
88+
# Check if line contains execution time (looking for the format with ms or s)
89+
if [[ $line =~ execute_segment\ \[\ ([0-9.]+)(ms|s)\ \|\ [0-9.]+%\ \]\ segment ]]; then
90+
segment_time="${BASH_REMATCH[1]}"
91+
unit="${BASH_REMATCH[2]}"
92+
93+
# Convert to milliseconds if in seconds
94+
if [[ "$unit" == "s" ]]; then
95+
segment_time=$(echo "scale=6; $segment_time * 1000" | bc)
96+
fi
97+
98+
# Add segment time to total
99+
total_time=$(echo "scale=6; $total_time + $segment_time" | bc)
100+
fi
101+
done < benchmark_output.log
102+
103+
# Output the last program result if there was one
104+
if [[ -n "$current_program" ]]; then
105+
echo "| $current_program | $total_time |" >> "$SUMMARY_FILE"
106+
fi
107+
108+
# If not in GitHub Actions, print the summary to the terminal
109+
if [ -z "$GITHUB_STEP_SUMMARY" ]; then
110+
echo -e "\nBenchmark Summary:"
111+
cat "$SUMMARY_FILE"
112+
fi

.github/workflows/benchmarks.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
types: [opened, synchronize, reopened, labeled]
88
branches: ["**"]
99
paths:
10-
- "benchmarks/**"
10+
- "benchmarks/prove/**"
1111
- "crates/circuits/**"
1212
- "crates/toolchain/**"
1313
- "crates/prof/**"

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ metrics.json
3333
# Profiling
3434
**/flamegraph.svg
3535
**/profile.json
36+
37+
# openvm generated files
38+
crates/cli/openvm/

Cargo.lock

Lines changed: 37 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ license = "MIT"
99

1010
[workspace]
1111
members = [
12-
"benchmarks",
12+
"benchmarks/utils",
13+
"benchmarks/execute",
14+
"benchmarks/prove",
1315
"crates/prof",
1416
"crates/sdk",
1517
"crates/cli",
@@ -127,6 +129,7 @@ openvm-custom-insn = { path = "crates/toolchain/custom_insn", default-features =
127129
openvm-circuit = { path = "crates/vm", default-features = false }
128130
openvm-circuit-derive = { path = "crates/vm/derive", default-features = false }
129131
openvm-continuations = { path = "crates/continuations", default-features = false }
132+
cargo-openvm = { path = "crates/cli", default-features = false }
130133

131134
# Extensions
132135
openvm-rv32im-circuit = { path = "extensions/rv32im/circuit", default-features = false }
@@ -159,6 +162,9 @@ openvm-pairing-circuit = { path = "extensions/pairing/circuit", default-features
159162
openvm-pairing-transpiler = { path = "extensions/pairing/transpiler", default-features = false }
160163
openvm-pairing-guest = { path = "extensions/pairing/guest", default-features = false }
161164

165+
# Benchmarking
166+
openvm-benchmarks-utils = { path = "benchmarks/utils", default-features = false }
167+
162168
# Plonky3
163169
p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "1ba4e5c" }
164170
p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", features = [
@@ -180,6 +186,7 @@ snark-verifier-sdk = { version = "0.2.0", default-features = false, features = [
180186
] }
181187
halo2curves-axiom = "0.7.0"
182188

189+
cargo_metadata = "0.18"
183190
tracing = "0.1.40"
184191
bon = "3.2.0"
185192
serde_json = "1.0.117"

benchmarks/execute/Cargo.toml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
[package]
2+
name = "openvm-benchmarks-execute"
3+
version.workspace = true
4+
authors.workspace = true
5+
edition.workspace = true
6+
homepage.workspace = true
7+
repository.workspace = true
8+
license.workspace = true
9+
10+
[dependencies]
11+
openvm-benchmarks-utils.workspace = true
12+
cargo-openvm.workspace = true
13+
openvm-circuit.workspace = true
14+
openvm-sdk.workspace = true
15+
openvm-stark-sdk.workspace = true
16+
openvm-transpiler.workspace = true
17+
openvm-rv32im-circuit.workspace = true
18+
openvm-rv32im-transpiler.workspace = true
19+
openvm-keccak256-circuit.workspace = true
20+
openvm-keccak256-transpiler.workspace = true
21+
22+
clap = { version = "4.5.9", features = ["derive", "env"] }
23+
eyre.workspace = true
24+
tracing.workspace = true
25+
derive_more = { workspace = true, features = ["from"] }
26+
27+
tracing-subscriber = { version = "0.3.17", features = ["std", "env-filter"] }
28+
29+
[dev-dependencies]
30+
criterion = { version = "0.5", features = ["html_reports"] }
31+
32+
[features]
33+
default = ["mimalloc"]
34+
profiling = ["openvm-sdk/profiling"]
35+
aggregation = []
36+
mimalloc = ["openvm-circuit/mimalloc"]
37+
jemalloc = ["openvm-circuit/jemalloc"]
38+
jemalloc-prof = ["openvm-circuit/jemalloc-prof"]
39+
nightly-features = ["openvm-circuit/nightly-features"]
40+
41+
[[bench]]
42+
name = "fibonacci_execute"
43+
harness = false
44+
45+
[[bench]]
46+
name = "regex_execute"
47+
harness = false
48+
49+
[package.metadata.cargo-shear]
50+
ignored = ["derive_more"]

benchmarks/benches/fibonacci_execute.rs renamed to benchmarks/execute/benches/fibonacci_execute.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use criterion::{criterion_group, criterion_main, Criterion};
2-
use openvm_benchmarks::utils::{build_bench, get_programs_dir};
2+
use openvm_benchmarks_utils::{build_elf, get_programs_dir};
33
use openvm_circuit::arch::{instructions::exe::VmExe, VmExecutor};
44
use openvm_rv32im_circuit::Rv32ImConfig;
55
use openvm_rv32im_transpiler::{
@@ -10,7 +10,9 @@ use openvm_stark_sdk::p3_baby_bear::BabyBear;
1010
use openvm_transpiler::{transpiler::Transpiler, FromElf};
1111

1212
fn benchmark_function(c: &mut Criterion) {
13-
let elf = build_bench(get_programs_dir().join("fibonacci"), "release").unwrap();
13+
let program_dir = get_programs_dir().join("fibonacci");
14+
let elf = build_elf(&program_dir, "release").unwrap();
15+
1416
let exe = VmExe::from_elf(
1517
elf,
1618
Transpiler::<BabyBear>::default()

benchmarks/benches/regex_execute.rs renamed to benchmarks/execute/benches/regex_execute.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use criterion::{black_box, criterion_group, criterion_main, Criterion};
2-
use openvm_benchmarks::utils::{build_bench, get_programs_dir};
2+
use openvm_benchmarks_utils::{build_elf, get_programs_dir};
33
use openvm_circuit::arch::{instructions::exe::VmExe, VmExecutor};
44
use openvm_keccak256_circuit::Keccak256Rv32Config;
55
use openvm_keccak256_transpiler::Keccak256TranspilerExtension;
@@ -11,7 +11,9 @@ use openvm_stark_sdk::p3_baby_bear::BabyBear;
1111
use openvm_transpiler::{transpiler::Transpiler, FromElf};
1212

1313
fn benchmark_function(c: &mut Criterion) {
14-
let elf = build_bench(get_programs_dir().join("regex"), "release").unwrap();
14+
let program_dir = get_programs_dir().join("regex");
15+
let elf = build_elf(&program_dir, "release").unwrap();
16+
1517
let exe = VmExe::from_elf(
1618
elf,
1719
Transpiler::<BabyBear>::default()
@@ -27,7 +29,7 @@ fn benchmark_function(c: &mut Criterion) {
2729
let config = Keccak256Rv32Config::default();
2830
let executor = VmExecutor::<BabyBear, Keccak256Rv32Config>::new(config);
2931

30-
let data = include_str!("../programs/regex/regex_email.txt");
32+
let data = include_str!("../../guest/regex/regex_email.txt");
3133

3234
let fe_bytes = data.to_owned().into_bytes();
3335
group.bench_function("execute", |b| {
File renamed without changes.

benchmarks/examples/regex_execute.rs renamed to benchmarks/execute/examples/regex_execute.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn main() {
2525
let config = Keccak256Rv32Config::default();
2626
let executor = VmExecutor::<BabyBear, Keccak256Rv32Config>::new(config);
2727

28-
let data = include_str!("../programs/regex/regex_email.txt");
28+
let data = include_str!("../../guest/regex/regex_email.txt");
2929

3030
let timer = std::time::Instant::now();
3131
executor

0 commit comments

Comments
 (0)