From 43b6a714dd8a674d1ac969015d45b4c43177f146 Mon Sep 17 00:00:00 2001 From: Kamen Mladenov Date: Tue, 29 Apr 2025 16:46:32 +0300 Subject: feat(zkvms_guest_io): Run all operations and output json format Following the new output format, we'll run the guest program for each zkVM, for each operation (execute, prove, verify with --benchmark flag). Then we'll combine the resultant JSON outputs into one big JSON object. For now we're only printing the result object. Later we'll add the ability to write it into any file. --- zkvms_guest_io/Cargo.lock | 7 ++++ zkvms_guest_io/Cargo.toml | 1 + zkvms_guest_io/src/main.rs | 93 ++++++++++++++++++++++++++++++---------------- 3 files changed, 68 insertions(+), 33 deletions(-) diff --git a/zkvms_guest_io/Cargo.lock b/zkvms_guest_io/Cargo.lock index ddfdde7..a602607 100644 --- a/zkvms_guest_io/Cargo.lock +++ b/zkvms_guest_io/Cargo.lock @@ -110,6 +110,12 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + [[package]] name = "once_cell" version = "1.20.3" @@ -241,4 +247,5 @@ name = "zkvms_guest_io" version = "0.1.0" dependencies = [ "clap", + "json", ] diff --git a/zkvms_guest_io/Cargo.toml b/zkvms_guest_io/Cargo.toml index 76ead99..ce255d2 100644 --- a/zkvms_guest_io/Cargo.toml +++ b/zkvms_guest_io/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] clap = { version = "4.5.31", features = ["derive"] } +json = "0.12.4" diff --git a/zkvms_guest_io/src/main.rs b/zkvms_guest_io/src/main.rs index 97cf3fa..4510d34 100644 --- a/zkvms_guest_io/src/main.rs +++ b/zkvms_guest_io/src/main.rs @@ -1,5 +1,6 @@ use clap::Parser; use std::process::{Command, Stdio}; +use json::{object, parse, JsonValue, Null}; /// A CLI tool for running and benchmarking a guest program inside all /// supported zkVMs. @@ -16,59 +17,85 @@ struct Cli { /// Make one failiure stop the entire process #[arg(short, long)] fail_propagation: bool, +} - /// Arguments which are passed to each tool for a single guest and single zkVM - #[arg(trailing_var_arg = true, allow_hyphen_values = true)] - zkvm_args: Vec, +fn run_command(zkvm_guest_command: &str, operation: &str) -> Result { + Command::new(zkvm_guest_command) + .arg(operation) + .arg("--benchmark") + .args([ "--metrics-output", "/tmp/current_metrics" ]) + .stdout(Stdio::piped()) + .output() } fn main() { let cli = Cli::parse(); + // This is set by zkvms_guest_io/default.nix let zkvm_guest_commands: Vec<&str> = env!("PROGRAMS") .split(',') .filter(|x| !x.is_empty()) .collect(); let ignored = cli.ignore.unwrap_or(Vec::new()); - for zkvm_guest_command in zkvm_guest_commands.into_iter() { + let mut runs = object! { + "benchmarking": [] + }; + + 'guest_iter: for zkvm_guest_command in zkvm_guest_commands.into_iter() { if ignored.iter().any(|i| zkvm_guest_command.contains(i)) { continue; } - println!("== Executing {} ==", zkvm_guest_command); + let mut run = JsonValue::new_object(); + run["name"] = zkvm_guest_command.into(); + + for operation in ["execute", "prove", "verify"] { + println!("== {operation} {zkvm_guest_command} =="); - let output = Command::new(zkvm_guest_command) - .args(cli.zkvm_args.clone()) - .stdout(Stdio::piped()) - .output(); + let output = run_command(zkvm_guest_command, operation); - if let Err(msg) = output { - println!("Failed to run command {}!", zkvm_guest_command); - println!("{msg}"); - if cli.fail_propagation { - break; + // Couldn't run the command + if let Err(msg) = output { + println!("Failed to run command!"); + println!("{msg}"); + if cli.fail_propagation { + break 'guest_iter; + } + continue; } - continue; - } - // The if above makes sure this is an Ok - let output = output.unwrap(); - - if !output.stdout.is_empty() { - print!( - "{}", - String::from_utf8(output.stdout).expect("failed to convert stdout to String") - ); - } - if !output.stderr.is_empty() { - print!( - "{}", - String::from_utf8(output.stderr).expect("failed to convert stderr to String") - ); - } - if cli.fail_propagation && !output.status.success() { - break; + // The command ran and therefore produced some output + let output = output.unwrap(); + + // The command ran but exited with non-zero status code + if !output.status.success() { + println!("Command failed!"); + } + + let stdout = String::from_utf8(output.stdout).expect("failed to convert stdout to String"); + println!("{stdout}"); + + if !output.stderr.is_empty() { + print!( + "{}", + String::from_utf8(output.stderr).expect("failed to convert stderr to String") + ); + } + + // The command ran but exited with non-zero status code + if !output.status.success() { + break 'guest_iter; + } + + let raw_data = &read_to_string("/tmp/current_metrics") + .ok() + .unwrap(); + run[operation] = json::parse(raw_data).unwrap(); } + + runs["benchmarking"].push(run); } + + println!("{}", runs.dump()); } -- cgit v1.2.3