Skip to content

Commit a8805dc

Browse files
added basic benchmarker for the CairoProgramRunner running simple bootloader on cairo pies + script for deploying it
on many pies.
1 parent 0f45006 commit a8805dc

File tree

7 files changed

+277
-0
lines changed

7 files changed

+277
-0
lines changed

Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,12 @@ tempfile = "3.10.1"
3535
thiserror = "1.0.61"
3636
thiserror-no-std = "2.0.2"
3737
tracing = "0.1.40"
38+
39+
[profile.release]
40+
opt-level = 3
41+
lto = true
42+
codegen-units = 1
43+
panic = "abort"
44+
45+
[profile.dev]
46+
opt-level = 3

crates/cairo-program-runner-lib/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ name = "cairo-program-runner-lib"
33
version = "0.1.0"
44
edition = "2021"
55

6+
[[bin]]
7+
name = "benchmark_runner"
8+
path = "scripts/benchmark_runner.rs"
9+
610

711
[dependencies]
812
bincode.workspace = true
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
//! Benchmark Runner for Cairo PIE Files
2+
//!
3+
//! This program measures the performance of loading and executing Cairo PIEs
4+
//! wrapped in simple bootloader and ran by the Cairo Program Runner.
5+
//!
6+
//! Usage:
7+
//! cargo run --bin benchmark_runner <path_to_pie_file> [--show-output]
8+
//!
9+
//! Arguments:
10+
//! <path_to_pie_file> Path to the Cairo PIE file (.zip) to benchmark
11+
//! --show-output Optional flag to display program output
12+
//!
13+
//! Output:
14+
//! - Program load time
15+
//! - Program execution time
16+
//! - Total runtime
17+
//! - Execution resources (steps, memory holes, builtin counters)
18+
//!
19+
//! This binary is typically run through the run_all_pies.sh script, which provides
20+
//! additional features:
21+
//! - Running multiple PIE files
22+
//! - Testing different Rust optimization levels
23+
//! - Aggregating results into a single file
24+
//!
25+
//! Example:
26+
//! Direct usage:
27+
//! cargo run --bin benchmark_runner path/to/program.zip
28+
//! Via script:
29+
//! ./scripts/run_all_pies.sh --opt-levels=3 --pie-dir=path/to/pies
30+
31+
use std::error::Error;
32+
use std::path::PathBuf;
33+
use std::time::Instant;
34+
35+
use cairo_program_runner_lib::cairo_run_program;
36+
use cairo_program_runner_lib::types::RunMode;
37+
use cairo_vm::types::layout_name::LayoutName;
38+
use cairo_vm::types::program::Program;
39+
use cairo_vm::vm::runners::cairo_pie::CairoPie;
40+
41+
fn main() -> Result<(), Box<dyn Error>> {
42+
let project_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
43+
let simple_bootloader_compiled_path =
44+
project_dir.join("resources/compiled_programs/bootloaders/simple_bootloader_compiled.json");
45+
46+
// Parse command line args
47+
let args: Vec<String> = std::env::args().collect();
48+
let mut program_path = String::new();
49+
let mut show_output = false;
50+
51+
// Simple arg parsing
52+
for (i, arg) in args.iter().enumerate() {
53+
if arg == "--show-output" {
54+
show_output = true;
55+
} else if i > 0 && !arg.starts_with("--") {
56+
program_path = arg.clone();
57+
}
58+
}
59+
60+
if program_path.is_empty() {
61+
program_path = project_dir
62+
.join("examples/fibonacci.json")
63+
.display()
64+
.to_string();
65+
}
66+
67+
println!("Loading program from: {}", program_path);
68+
69+
// Try to load as a PIE first, if that fails, try as a regular program
70+
let start_load = Instant::now();
71+
let program_input_contents = if program_path.ends_with(".zip") {
72+
// Load as PIE - we just need to verify it loads
73+
// TODO(idanh): Add an option to configure the hash function
74+
let _cairo_pie = CairoPie::read_zip_file(&PathBuf::from(&program_path))?;
75+
format!(
76+
r#"{{
77+
"tasks": [
78+
{{
79+
"type": "CairoPiePath",
80+
"path": "{}",
81+
"program_hash_function": "pedersen"
82+
}}
83+
],
84+
"single_page": true
85+
}}"#,
86+
program_path
87+
)
88+
} else {
89+
// Load as regular program - we just need to verify it loads
90+
let _program = Program::from_file(PathBuf::from(&program_path).as_path(), Some("main"))?;
91+
format!(
92+
r#"{{
93+
"tasks": [
94+
{{
95+
"path": "{}",
96+
"program_hash_function": "pedersen",
97+
"type": "RunProgramTask"
98+
}}
99+
],
100+
"single_page": true
101+
}}"#,
102+
program_path
103+
)
104+
};
105+
let load_duration = start_load.elapsed();
106+
println!("Program loaded in: {:?}", load_duration);
107+
108+
let simple_bootloader_program =
109+
Program::from_file(simple_bootloader_compiled_path.as_path(), Some("main"))?;
110+
111+
let cairo_run_config = RunMode::Proof {
112+
layout: LayoutName::starknet_with_keccak,
113+
dynamic_layout_params: None,
114+
disable_trace_padding: false,
115+
}
116+
.create_config();
117+
118+
println!("\nExecuting program...");
119+
let start_exec = Instant::now();
120+
let mut runner = cairo_run_program(
121+
&simple_bootloader_program,
122+
Some(program_input_contents),
123+
cairo_run_config,
124+
)?;
125+
let exec_duration = start_exec.elapsed();
126+
println!("Program executed in: {:?}", exec_duration);
127+
128+
// Verify execution by checking outputs
129+
let mut output_buffer = String::new();
130+
runner.vm.write_output(&mut output_buffer)?;
131+
132+
// Print execution verification info
133+
println!("\nProgram Execution Verification:");
134+
println!("Output size: {} bytes", output_buffer.len());
135+
136+
if show_output {
137+
println!("Program output:\n{}", output_buffer);
138+
}
139+
140+
// Print execution resources
141+
println!("\nExecution Resources:");
142+
let resources = runner.get_execution_resources()?;
143+
println!("n_steps: {}", resources.n_steps);
144+
println!("n_memory_holes: {}", resources.n_memory_holes);
145+
println!(
146+
"builtin_instance_counter: {:#?}",
147+
resources.builtin_instance_counter
148+
);
149+
150+
// Check if output is empty - might indicate optimization skip
151+
if output_buffer.trim().is_empty() {
152+
println!("WARNING: Empty output might indicate optimization issues!");
153+
}
154+
155+
println!("\nBenchmark Summary:");
156+
println!("Program load time: {:?}", load_duration);
157+
println!("Program execution time: {:?}", exec_duration);
158+
println!("Total time: {:?}", load_duration + exec_duration);
159+
160+
Ok(())
161+
}
87.5 MB
Binary file not shown.
50.1 MB
Binary file not shown.
Binary file not shown.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/bin/bash
2+
3+
# Script Description:
4+
# This script runs benchmarks of the program runner on the simple bootloader wrapping
5+
# Cairo PIE files with different Rust optimization levels.
6+
# It measures program load time, execution time, and execution resources of the run.
7+
# Results are saved to a file.
8+
#
9+
# Usage:
10+
# ./run_all_pies.sh [--opt-levels=<levels>] [--pie-dir=path/to/pies]
11+
#
12+
# Options:
13+
# --opt-levels=<levels> Specify which Rust optimization levels to run (0-3)
14+
# Examples: --opt-levels=3 (default, runs only level 3)
15+
# --opt-levels=23 (runs levels 2 and 3)
16+
# --opt-levels=013 (runs levels 0, 1, and 3)
17+
# --pie-dir=<path> Path to directory containing PIE files
18+
# Default: ./pies
19+
#
20+
# Output:
21+
# - Shows compilation and execution progress in the terminal
22+
# - Saves detailed benchmark results to benchmark_results.txt in the scripts directory
23+
# - For each PIE file and optimization level, captures:
24+
# * Program load and execution times
25+
# * Number of steps and memory holes
26+
# * Detailed builtin instance counter information
27+
#
28+
# Examples:
29+
# ./run_all_pies.sh # Run with default settings (opt-level 3)
30+
# ./run_all_pies.sh --opt-levels=012 # Run with optimization levels 0, 1, and 2
31+
# ./run_all_pies.sh --pie-dir=/path/to/pies # Use PIE files from custom directory
32+
33+
# Default values
34+
SCRIPT_DIR="$(dirname "$0")"
35+
PIES_DIR="$SCRIPT_DIR/pies"
36+
RESULTS_FILE="$SCRIPT_DIR/benchmark_results.txt"
37+
OPT_LEVELS="3" # Default to only opt level 3
38+
39+
# Parse command line arguments
40+
while [ $# -gt 0 ]; do
41+
case "$1" in
42+
--opt-levels=*)
43+
OPT_LEVELS="${1#*=}"
44+
;;
45+
--pie-dir=*)
46+
PIES_DIR="${1#*=}"
47+
;;
48+
*)
49+
echo "Unknown parameter: $1"
50+
echo "Usage: $0 [--opt-levels=<levels>] [--pie-dir=path/to/pies]"
51+
echo " --opt-levels: Specify which optimization levels to run (0-3)"
52+
echo " Examples: --opt-levels=23 (runs levels 2 and 3)"
53+
echo " --opt-levels=013 (runs levels 0, 1, and 3)"
54+
echo " --pie-dir: Path to directory containing PIE files"
55+
exit 1
56+
;;
57+
esac
58+
shift
59+
done
60+
61+
# Clear previous results
62+
echo "Cairo PIE Benchmark Results" > "$RESULTS_FILE"
63+
date >> "$RESULTS_FILE"
64+
echo "----------------------------------------" >> "$RESULTS_FILE"
65+
66+
# Function to run cargo with specific opt level
67+
run_with_opt_level() {
68+
local pie_file="$1"
69+
local opt_level="$2"
70+
71+
echo "Running ${pie_file} with optimization level ${opt_level}"
72+
echo "Running ${pie_file} with optimization level ${opt_level}" >> "$RESULTS_FILE"
73+
74+
# Run cargo and show compilation/execution stages, but redirect only benchmark results and resources to file
75+
if ! RUSTFLAGS="-C opt-level=${opt_level}" cargo run --bin benchmark_runner "${pie_file}" \
76+
2> >(grep -v "future version of Rust\|future-incompat-report" >&2) | \
77+
tee >(awk '!/Program (load|execution) time:/ && (/Program (loaded|executed)/ || /Execution Resources:/ || /^n_steps:/ || /^n_memory_holes:/ || /^builtin_instance_counter:/ || /^[[:space:]]*[a-z_]+:/ || /^}/ || /Total time:/)' >> "$RESULTS_FILE"); then
78+
echo "Error running benchmark" >> "$RESULTS_FILE"
79+
fi
80+
echo "----------------------------------------" >> "$RESULTS_FILE"
81+
}
82+
83+
# Find all .zip files in pies directory
84+
for pie_file in "$PIES_DIR"/*.zip; do
85+
if [ -f "$pie_file" ]; then
86+
echo "=== Testing $(basename "$pie_file") ==="
87+
echo
88+
89+
# Run with specified optimization levels
90+
# Validate opt levels
91+
for opt_level in $(echo "$OPT_LEVELS" | grep -o .); do
92+
if [[ ! "$opt_level" =~ ^[0-3]$ ]]; then
93+
echo "Error: Invalid optimization level '$opt_level'. Must be one of: 0, 1, 2, 3"
94+
exit 1
95+
fi
96+
run_with_opt_level "$pie_file" "$opt_level"
97+
echo
98+
done
99+
100+
echo "================================================"
101+
echo
102+
fi
103+
done

0 commit comments

Comments
 (0)