openvm_benchmarks_execute/
main.rs

1use cargo_openvm::{default::DEFAULT_APP_CONFIG_PATH, util::read_config_toml_or_default};
2use clap::{Parser, ValueEnum};
3use eyre::Result;
4use openvm_benchmarks_utils::{get_elf_path, get_programs_dir, read_elf_file};
5use openvm_circuit::arch::{instructions::exe::VmExe, VmExecutor};
6use openvm_sdk::StdIn;
7use openvm_stark_sdk::bench::run_with_metric_collection;
8use openvm_transpiler::FromElf;
9
10#[derive(Debug, Clone, ValueEnum)]
11enum BuildProfile {
12    Debug,
13    Release,
14}
15
16static AVAILABLE_PROGRAMS: &[&str] = &[
17    "fibonacci_recursive",
18    "fibonacci_iterative",
19    "quicksort",
20    "bubblesort",
21    "pairing",
22    "keccak256",
23    "keccak256_iter",
24    "sha256",
25    "sha256_iter",
26    "revm_transfer",
27    "revm_snailtracer",
28];
29
30#[derive(Parser)]
31#[command(author, version, about = "OpenVM Benchmark CLI", long_about = None)]
32struct Cli {
33    /// Programs to benchmark (if not specified, all programs will be run)
34    #[arg(short, long)]
35    programs: Vec<String>,
36
37    /// Programs to skip from benchmarking
38    #[arg(short, long)]
39    skip: Vec<String>,
40
41    /// Output path for benchmark results
42    #[arg(short, long, default_value = "OUTPUT_PATH")]
43    output: String,
44
45    /// List available benchmark programs and exit
46    #[arg(short, long)]
47    list: bool,
48
49    /// Verbose output
50    #[arg(short, long)]
51    verbose: bool,
52}
53
54fn main() -> Result<()> {
55    let cli = Cli::parse();
56
57    if cli.list {
58        println!("Available benchmark programs:");
59        for program in AVAILABLE_PROGRAMS {
60            println!("  {}", program);
61        }
62        return Ok(());
63    }
64
65    // Set up logging based on verbosity
66    if cli.verbose {
67        tracing_subscriber::fmt::init();
68    }
69
70    let mut programs_to_run = if cli.programs.is_empty() {
71        AVAILABLE_PROGRAMS.to_vec()
72    } else {
73        // Validate provided programs
74        for program in &cli.programs {
75            if !AVAILABLE_PROGRAMS.contains(&program.as_str()) {
76                eprintln!("Unknown program: {}", program);
77                eprintln!("Use --list to see available programs");
78                std::process::exit(1);
79            }
80        }
81        cli.programs.iter().map(|s| s.as_str()).collect()
82    };
83
84    // Remove programs that should be skipped
85    if !cli.skip.is_empty() {
86        // Validate skipped programs
87        for program in &cli.skip {
88            if !AVAILABLE_PROGRAMS.contains(&program.as_str()) {
89                eprintln!("Unknown program to skip: {}", program);
90                eprintln!("Use --list to see available programs");
91                std::process::exit(1);
92            }
93        }
94
95        let skip_set: Vec<&str> = cli.skip.iter().map(|s| s.as_str()).collect();
96        programs_to_run.retain(|&program| !skip_set.contains(&program));
97    }
98
99    tracing::info!("Starting benchmarks with metric collection");
100
101    run_with_metric_collection(&cli.output, || -> Result<()> {
102        for program in &programs_to_run {
103            tracing::info!("Running program: {}", program);
104
105            let program_dir = get_programs_dir().join(program);
106            let elf_path = get_elf_path(&program_dir);
107            let elf = read_elf_file(&elf_path)?;
108
109            let config_path = program_dir.join(DEFAULT_APP_CONFIG_PATH);
110            let vm_config = read_config_toml_or_default(&config_path)?.app_vm_config;
111
112            let exe = VmExe::from_elf(elf, vm_config.transpiler())?;
113
114            let executor = VmExecutor::new(vm_config);
115            executor.execute(exe, StdIn::default())?;
116            tracing::info!("Completed program: {}", program);
117        }
118        tracing::info!("All programs executed successfully");
119        Ok(())
120    })
121}