|
| 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 | +} |
0 commit comments