mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-06-20 05:59:29 +00:00
refactor(cycle_bench): split into lib + binary, drop hand-rolled verify timing
This commit is contained in:
parent
b608d10ca1
commit
fb89e7549b
@ -16,6 +16,7 @@ ppe = ["prove"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
nssa = { workspace = true }
|
nssa = { workspace = true }
|
||||||
nssa_core = { workspace = true, features = ["host"] }
|
nssa_core = { workspace = true, features = ["host"] }
|
||||||
|
authenticated_transfer_core.workspace = true
|
||||||
clock_core.workspace = true
|
clock_core.workspace = true
|
||||||
token_core.workspace = true
|
token_core.workspace = true
|
||||||
amm_core.workspace = true
|
amm_core.workspace = true
|
||||||
|
|||||||
23
tools/cycle_bench/src/lib.rs
Normal file
23
tools/cycle_bench/src/lib.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//! `cycle_bench` library: per-program executor/prover cycle measurement helpers
|
||||||
|
//! shared between the `cycle_bench` binary and the `verify` criterion bench.
|
||||||
|
|
||||||
|
#![expect(
|
||||||
|
clippy::arithmetic_side_effects,
|
||||||
|
clippy::as_conversions,
|
||||||
|
clippy::cast_precision_loss,
|
||||||
|
clippy::float_arithmetic,
|
||||||
|
clippy::print_literal,
|
||||||
|
clippy::print_stdout,
|
||||||
|
reason = "Bench library: stats arithmetic and table printing are bench-style"
|
||||||
|
)]
|
||||||
|
#![cfg_attr(
|
||||||
|
feature = "ppe",
|
||||||
|
expect(
|
||||||
|
clippy::arbitrary_source_item_ordering,
|
||||||
|
clippy::print_stderr,
|
||||||
|
reason = "PPE module: re-export ordering and eprintln progress trip strict lints"
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
|
||||||
|
pub mod ppe;
|
||||||
|
pub mod stats;
|
||||||
@ -9,15 +9,11 @@
|
|||||||
|
|
||||||
#![expect(
|
#![expect(
|
||||||
clippy::arithmetic_side_effects,
|
clippy::arithmetic_side_effects,
|
||||||
clippy::as_conversions,
|
|
||||||
clippy::cast_precision_loss,
|
|
||||||
clippy::float_arithmetic,
|
clippy::float_arithmetic,
|
||||||
clippy::missing_const_for_fn,
|
clippy::missing_const_for_fn,
|
||||||
clippy::non_ascii_literal,
|
clippy::non_ascii_literal,
|
||||||
clippy::print_literal,
|
|
||||||
clippy::print_stderr,
|
clippy::print_stderr,
|
||||||
clippy::print_stdout,
|
clippy::print_stdout,
|
||||||
clippy::ref_patterns,
|
|
||||||
reason = "Bench tool: matches test-style fixture code"
|
reason = "Bench tool: matches test-style fixture code"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
@ -31,6 +27,7 @@ use clock_core::{
|
|||||||
CLOCK_01_PROGRAM_ACCOUNT_ID, CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID,
|
CLOCK_01_PROGRAM_ACCOUNT_ID, CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID,
|
||||||
ClockAccountData,
|
ClockAccountData,
|
||||||
};
|
};
|
||||||
|
use cycle_bench::{ppe, stats::Stats};
|
||||||
use nssa::program_methods::{
|
use nssa::program_methods::{
|
||||||
AMM_ELF, AMM_ID, ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID,
|
AMM_ELF, AMM_ID, ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID,
|
||||||
AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, CLOCK_ELF, CLOCK_ID, TOKEN_ELF,
|
AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, CLOCK_ELF, CLOCK_ID, TOKEN_ELF,
|
||||||
@ -43,12 +40,8 @@ use nssa_core::{
|
|||||||
};
|
};
|
||||||
use risc0_zkvm::{ExecutorEnv, default_executor, default_prover};
|
use risc0_zkvm::{ExecutorEnv, default_executor, default_prover};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use stats::Stats;
|
|
||||||
use token_core::{TokenDefinition, TokenHolding};
|
use token_core::{TokenDefinition, TokenHolding};
|
||||||
|
|
||||||
mod ppe;
|
|
||||||
mod stats;
|
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(about = "Per-program executor and (optionally) prover cycle measurements")]
|
#[command(about = "Per-program executor and (optionally) prover cycle measurements")]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
@ -62,16 +55,6 @@ struct Cli {
|
|||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
ppe: bool,
|
ppe: bool,
|
||||||
|
|
||||||
/// After running --ppe-style proving once for auth_transfer-in-PPE, time
|
|
||||||
/// `receipt.verify(PRIVACY_PRESERVING_CIRCUIT_ID)` over many iterations.
|
|
||||||
/// Produces `G_verify` for the fee model. Requires --features ppe.
|
|
||||||
#[arg(long)]
|
|
||||||
verify: bool,
|
|
||||||
|
|
||||||
/// Iterations for --verify. Default matches the fee-model handoff target.
|
|
||||||
#[arg(long, default_value_t = 1000)]
|
|
||||||
verify_iters: usize,
|
|
||||||
|
|
||||||
/// Iterations for executor wall-time sampling per case. First iter is
|
/// Iterations for executor wall-time sampling per case. First iter is
|
||||||
/// discarded as warmup, remaining N feed the stats.
|
/// discarded as warmup, remaining N feed the stats.
|
||||||
#[arg(long, default_value_t = 5)]
|
#[arg(long, default_value_t = 5)]
|
||||||
@ -428,7 +411,7 @@ fn main() -> Result<()> {
|
|||||||
AUTHENTICATED_TRANSFER_ELF,
|
AUTHENTICATED_TRANSFER_ELF,
|
||||||
AUTHENTICATED_TRANSFER_ID,
|
AUTHENTICATED_TRANSFER_ID,
|
||||||
authenticated_transfer_transfer(),
|
authenticated_transfer_transfer(),
|
||||||
&5_000_u128,
|
&authenticated_transfer_core::Instruction::Transfer { amount: 5_000 },
|
||||||
)?,
|
)?,
|
||||||
Case::new(
|
Case::new(
|
||||||
"authenticated_transfer",
|
"authenticated_transfer",
|
||||||
@ -436,7 +419,7 @@ fn main() -> Result<()> {
|
|||||||
AUTHENTICATED_TRANSFER_ELF,
|
AUTHENTICATED_TRANSFER_ELF,
|
||||||
AUTHENTICATED_TRANSFER_ID,
|
AUTHENTICATED_TRANSFER_ID,
|
||||||
authenticated_transfer_init(),
|
authenticated_transfer_init(),
|
||||||
&0_u128,
|
&authenticated_transfer_core::Instruction::Initialize,
|
||||||
)?,
|
)?,
|
||||||
Case::new(
|
Case::new(
|
||||||
"token",
|
"token",
|
||||||
@ -532,23 +515,6 @@ fn main() -> Result<()> {
|
|||||||
ppe::print_table(&ppe_results);
|
ppe::print_table(&ppe_results);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ppe")]
|
|
||||||
let verify_result = if cli.verify {
|
|
||||||
Some(ppe::run_verify(cli.verify_iters)?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
#[cfg(not(feature = "ppe"))]
|
|
||||||
let verify_result: Option<ppe::VerifyBenchResult> = {
|
|
||||||
if cli.verify {
|
|
||||||
eprintln!("cycle_bench: --verify requires --features ppe at build time. Ignoring.");
|
|
||||||
}
|
|
||||||
None
|
|
||||||
};
|
|
||||||
if let Some(ref vr) = verify_result {
|
|
||||||
ppe::print_verify(vr);
|
|
||||||
}
|
|
||||||
|
|
||||||
let workspace_root = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
let workspace_root = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||||
.join("..")
|
.join("..")
|
||||||
.join("..")
|
.join("..")
|
||||||
@ -560,7 +526,6 @@ fn main() -> Result<()> {
|
|||||||
let combined = serde_json::json!({
|
let combined = serde_json::json!({
|
||||||
"standalone": results,
|
"standalone": results,
|
||||||
"ppe": ppe_results,
|
"ppe": ppe_results,
|
||||||
"verify": verify_result,
|
|
||||||
});
|
});
|
||||||
std::fs::write(&out_path, serde_json::to_string_pretty(&combined)?)?;
|
std::fs::write(&out_path, serde_json::to_string_pretty(&combined)?)?;
|
||||||
println!("\nJSON written to {}", out_path.display());
|
println!("\nJSON written to {}", out_path.display());
|
||||||
|
|||||||
@ -5,24 +5,23 @@
|
|||||||
//! that wraps the same program in the privacy circuit. Chained-call depth sweep
|
//! that wraps the same program in the privacy circuit. Chained-call depth sweep
|
||||||
//! uses the `chain_caller` test program (loaded from artifacts/) with N=1, 3, 5, 9.
|
//! uses the `chain_caller` test program (loaded from artifacts/) with N=1, 3, 5, 9.
|
||||||
//!
|
//!
|
||||||
//! `run_verify` produces `G_verify` for the fee model: it generates one PPE
|
//! `Receipt::verify(PRIVACY_PRESERVING_CIRCUIT_ID)` timings (the `G_verify` fee-model
|
||||||
//! receipt (`auth_transfer` Transfer in PPE) and times `Receipt::verify` over
|
//! parameter) are measured by the `verify` criterion bench under `benches/verify.rs`,
|
||||||
//! `iters` iterations. The proof bytes captured here are also the on-wire
|
//! which reuses the `prove_auth_transfer_in_ppe` setup helper re-exported below.
|
||||||
//! "outer proof" payload (`S_agg` in the fee model).
|
|
||||||
|
|
||||||
#![allow(
|
#![allow(
|
||||||
dead_code,
|
dead_code,
|
||||||
reason = "Stubs are used when the `ppe` feature is disabled."
|
reason = "Stubs are used when the `ppe` feature is disabled."
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::stats::Stats;
|
|
||||||
|
|
||||||
#[cfg(feature = "ppe")]
|
#[cfg(feature = "ppe")]
|
||||||
mod ppe_impl;
|
mod ppe_impl;
|
||||||
|
|
||||||
|
#[cfg(feature = "ppe")]
|
||||||
|
pub use ppe_impl::prove_auth_transfer_in_ppe;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
pub struct PpeBenchResult {
|
pub struct PpeBenchResult {
|
||||||
pub label: String,
|
pub label: String,
|
||||||
@ -33,20 +32,14 @@ pub struct PpeBenchResult {
|
|||||||
pub error: Option<String>,
|
pub error: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
|
||||||
pub struct VerifyBenchResult {
|
|
||||||
pub label: String,
|
|
||||||
pub stats: Stats,
|
|
||||||
pub proof_bytes: usize,
|
|
||||||
pub journal_bytes: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "ppe"))]
|
#[cfg(not(feature = "ppe"))]
|
||||||
pub fn run_all() -> Vec<PpeBenchResult> {
|
#[must_use]
|
||||||
|
pub const fn run_all() -> Vec<PpeBenchResult> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ppe")]
|
#[cfg(feature = "ppe")]
|
||||||
|
#[must_use]
|
||||||
pub fn run_all() -> Vec<PpeBenchResult> {
|
pub fn run_all() -> Vec<PpeBenchResult> {
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
|
|
||||||
@ -61,16 +54,6 @@ pub fn run_all() -> Vec<PpeBenchResult> {
|
|||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "ppe"))]
|
|
||||||
pub fn run_verify(_iters: usize) -> Result<VerifyBenchResult> {
|
|
||||||
anyhow::bail!("--verify requires --features ppe at build time")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ppe")]
|
|
||||||
pub fn run_verify(iters: usize) -> Result<VerifyBenchResult> {
|
|
||||||
ppe_impl::run_verify(iters)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print_table(results: &[PpeBenchResult]) {
|
pub fn print_table(results: &[PpeBenchResult]) {
|
||||||
let lw = results
|
let lw = results
|
||||||
.iter()
|
.iter()
|
||||||
@ -109,14 +92,3 @@ pub fn print_table(results: &[PpeBenchResult]) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_verify(r: &VerifyBenchResult) {
|
|
||||||
println!("\nVerify (G_verify):");
|
|
||||||
println!(" case : {}", r.label);
|
|
||||||
println!(
|
|
||||||
" proof_bytes : {} (borsh InnerReceipt, S_agg)",
|
|
||||||
r.proof_bytes
|
|
||||||
);
|
|
||||||
println!(" journal_bytes : {}", r.journal_bytes);
|
|
||||||
println!(" verify_ms : {}", r.stats);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
//! Feature-gated implementation of PPE composition and verify benches.
|
//! Feature-gated implementation of PPE composition benches.
|
||||||
|
//!
|
||||||
|
//! `prove_auth_transfer_in_ppe` is reused by the `verify` criterion bench under
|
||||||
|
//! `benches/verify.rs` (re-exported via `super::prove_auth_transfer_in_ppe`).
|
||||||
|
|
||||||
use std::{collections::HashMap, time::Instant};
|
use std::{collections::HashMap, time::Instant};
|
||||||
|
|
||||||
@ -6,17 +9,15 @@ use nssa::{
|
|||||||
execute_and_prove,
|
execute_and_prove,
|
||||||
privacy_preserving_transaction::circuit::{ProgramWithDependencies, Proof},
|
privacy_preserving_transaction::circuit::{ProgramWithDependencies, Proof},
|
||||||
program::Program,
|
program::Program,
|
||||||
program_methods::PRIVACY_PRESERVING_CIRCUIT_ID,
|
|
||||||
};
|
};
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
InputAccountIdentity, PrivacyPreservingCircuitOutput,
|
InputAccountIdentity, PrivacyPreservingCircuitOutput,
|
||||||
account::{Account, AccountId, AccountWithMetadata},
|
account::{Account, AccountId, AccountWithMetadata},
|
||||||
program::ProgramId,
|
program::ProgramId,
|
||||||
};
|
};
|
||||||
use risc0_zkvm::{InnerReceipt, Receipt, serde::to_vec};
|
use risc0_zkvm::serde::to_vec;
|
||||||
|
|
||||||
use super::{PpeBenchResult, VerifyBenchResult};
|
use super::PpeBenchResult;
|
||||||
use crate::stats::Stats;
|
|
||||||
|
|
||||||
const AUTH_TRANSFER_ID: ProgramId = nssa::program_methods::AUTHENTICATED_TRANSFER_ID;
|
const AUTH_TRANSFER_ID: ProgramId = nssa::program_methods::AUTHENTICATED_TRANSFER_ID;
|
||||||
const AUTH_TRANSFER_ELF: &[u8] = nssa::program_methods::AUTHENTICATED_TRANSFER_ELF;
|
const AUTH_TRANSFER_ELF: &[u8] = nssa::program_methods::AUTHENTICATED_TRANSFER_ELF;
|
||||||
@ -50,7 +51,7 @@ pub fn run_auth_transfer_in_ppe() -> PpeBenchResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prove_auth_transfer_in_ppe() -> anyhow::Result<(PrivacyPreservingCircuitOutput, Proof)> {
|
pub fn prove_auth_transfer_in_ppe() -> anyhow::Result<(PrivacyPreservingCircuitOutput, Proof)> {
|
||||||
let program = Program::new(AUTH_TRANSFER_ELF.to_vec())?;
|
let program = Program::new(AUTH_TRANSFER_ELF.to_vec())?;
|
||||||
let pwd = ProgramWithDependencies::from(program);
|
let pwd = ProgramWithDependencies::from(program);
|
||||||
|
|
||||||
@ -73,8 +74,8 @@ fn prove_auth_transfer_in_ppe() -> anyhow::Result<(PrivacyPreservingCircuitOutpu
|
|||||||
};
|
};
|
||||||
let pre_states = vec![sender, recipient];
|
let pre_states = vec![sender, recipient];
|
||||||
|
|
||||||
let balance_to_move: u128 = 5_000;
|
let instruction = authenticated_transfer_core::Instruction::Transfer { amount: 5_000 };
|
||||||
let instruction_data = to_vec(&balance_to_move)?;
|
let instruction_data = to_vec(&instruction)?;
|
||||||
|
|
||||||
let account_identities = vec![InputAccountIdentity::Public; pre_states.len()];
|
let account_identities = vec![InputAccountIdentity::Public; pre_states.len()];
|
||||||
|
|
||||||
@ -156,39 +157,3 @@ fn prove_chain_caller(
|
|||||||
&pwd,
|
&pwd,
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_verify(iters: usize) -> anyhow::Result<VerifyBenchResult> {
|
|
||||||
eprintln!("verify: generating PPE receipt for auth_transfer Transfer (~1 prove)");
|
|
||||||
let (output, proof) = prove_auth_transfer_in_ppe()?;
|
|
||||||
let journal = output.to_bytes();
|
|
||||||
let journal_bytes = journal.len();
|
|
||||||
let proof_bytes_vec = proof.into_inner();
|
|
||||||
let proof_bytes = proof_bytes_vec.len();
|
|
||||||
|
|
||||||
let inner: InnerReceipt = borsh::from_slice(&proof_bytes_vec)
|
|
||||||
.map_err(|e| anyhow::anyhow!("InnerReceipt deserialize: {e}"))?;
|
|
||||||
let receipt = Receipt::new(inner, journal);
|
|
||||||
|
|
||||||
// Sanity-check before the timing loop so we don't measure 1000 failures.
|
|
||||||
receipt
|
|
||||||
.verify(PRIVACY_PRESERVING_CIRCUIT_ID)
|
|
||||||
.map_err(|e| anyhow::anyhow!("verify sanity check failed: {e}"))?;
|
|
||||||
|
|
||||||
eprintln!("verify: timing {iters} iters of receipt.verify(...)");
|
|
||||||
let mut samples = Vec::with_capacity(iters);
|
|
||||||
for _ in 0..iters {
|
|
||||||
let started = Instant::now();
|
|
||||||
receipt
|
|
||||||
.verify(PRIVACY_PRESERVING_CIRCUIT_ID)
|
|
||||||
.map_err(|e| anyhow::anyhow!("verify failed mid-loop: {e}"))?;
|
|
||||||
samples.push(started.elapsed().as_secs_f64() * 1_000.0);
|
|
||||||
}
|
|
||||||
let stats = Stats::from_samples(&samples);
|
|
||||||
|
|
||||||
Ok(VerifyBenchResult {
|
|
||||||
label: "auth_transfer Transfer in PPE".to_owned(),
|
|
||||||
stats,
|
|
||||||
proof_bytes,
|
|
||||||
journal_bytes,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user