Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add benchmark for simple transaction #577

Merged
merged 28 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0667acd
feat: add benchmark for default transaction
Fumuran Apr 8, 2024
b63fbf7
refactor: use trace instead of emit, create wrapper for host
Fumuran Apr 10, 2024
d3943e9
refactor: improve cycles print
Fumuran Apr 10, 2024
c823d82
refactor: add inline comments, change trace ids
Fumuran Apr 10, 2024
7e79a5b
chore: ignore the test untill it become a binary
Fumuran Apr 10, 2024
74e99fd
refactor: organise cycles storing, add traces for each note
Fumuran Apr 11, 2024
b7c22b1
feat: create a simple cli for benchmark binary package
Fumuran Apr 11, 2024
4e33ee8
feat: create cargo-make script for benchmarking, move benchmarks back…
Fumuran Apr 12, 2024
cdf40f9
Merge branch 'next' into andrew-tx-execution-bench
Fumuran Apr 12, 2024
b919a14
refactor: move TransactionProgress to the TransactionHost
Fumuran Apr 12, 2024
dd97cb5
feat: implement bench for P2ID note, add NoteId to the output
Fumuran Apr 13, 2024
ff5d2fd
refactor: move last note id obtaining to the separate function
Fumuran Apr 15, 2024
e3bb648
refactor: fix no-std build
Fumuran Apr 15, 2024
0323b67
refactor: update comments in main.masm file to be consistent with api…
Fumuran Apr 17, 2024
118f371
feat: write benchmark results to the json file
Fumuran Apr 18, 2024
f7d446b
Merge branch 'next' into andrew-tx-execution-bench
Fumuran Apr 18, 2024
58e0324
refactor: move benchmarks to their own crate
Fumuran Apr 18, 2024
ea8e5ba
refactor: add ability to run all benches
Fumuran Apr 18, 2024
d2bfbf3
refactor: update bin name, dependencies; remove benches except all
Fumuran Apr 22, 2024
d6a0d9b
Merge branch 'next' into andrew-tx-execution-bench
Fumuran Apr 22, 2024
b9d6473
chore: fix no-std build
Fumuran Apr 22, 2024
1fe5ad2
refactor: rework TransactionProgress serialization
Fumuran Apr 24, 2024
4e284aa
refactor: exclude bench-tx from no-std build, update dependencies
Fumuran Apr 24, 2024
a06ca80
refactor: improve imports formatting
Fumuran Apr 24, 2024
fad7743
refactor: rework writing to json
Fumuran Apr 25, 2024
fc99ee2
chore: change visibility of miden-tx MockDataStore
Fumuran Apr 25, 2024
52d614b
Merge branch 'next' into andrew-tx-execution-bench
Fumuran Apr 25, 2024
4016957
chore: update CHANGELOG, create README for bench-tx
Fumuran Apr 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
resolver = "2"
members = [
members = [
"benchmarks",
bobbinth marked this conversation as resolved.
Show resolved Hide resolved
"miden-lib",
"miden-tx",
"mock",
Expand Down
21 changes: 20 additions & 1 deletion Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,26 @@ description = "Build using no-std"
command = "cargo"
args = ["build", "--no-default-features", "--target", "wasm32-unknown-unknown", "--workspace", "--exclude", "miden-mock"]

# --- utilities ----------------------------------------------------------------------------------------
# --- benchmarking --------------------------------------------------------------------------------
[tasks.bench-all]
description = "Run all available transaction benchmarks"
workspace = false
command = "cargo"
args = ["run", "--bin", "benchmarks", "--features", "executable", "all"]

[tasks.bench-tx]
description = "Run the transaction benchmark with default transaction script and notes"
workspace = false
command = "cargo"
args = ["run", "--bin", "benchmarks", "--features", "executable", "simple"]

[tasks.bench-p2id]
description = "Run the transaction benchmark which consumes a P2ID note into a basic wallet"
workspace = false
command = "cargo"
args = ["run", "--bin", "benchmarks", "--features", "executable", "p2id"]
bobbinth marked this conversation as resolved.
Show resolved Hide resolved

# --- utilities -----------------------------------------------------------------------------------
[tasks.watch]
description = "Watch for changes and rebuild"
workspace = false
Expand Down
29 changes: 29 additions & 0 deletions benchmarks/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "benchmarks"
bobbinth marked this conversation as resolved.
Show resolved Hide resolved
version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
authors.workspace = true
homepage.workspace = true
repository.workspace = true
exclude.workspace = true

[[bin]]
name = "benchmarks"
bobbinth marked this conversation as resolved.
Show resolved Hide resolved
path = "src/main.rs"
required-features = ["executable"]

[features]
default = ["std"]
std = ["miden-lib/std", "miden-objects/std", "miden-tx/std", "vm-processor/std", "mock/std", "serde_json/std"]
executable = ["std"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This crate can be just an executable and so:

  • I don't think we need required-features here.
  • We probably also don't need to support no_std - so, the whole features section can probably go away.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason, if I try to change anything in this setup, the no-std build starts to fail with the same the wasm*-unknown-unknown targets are not supported by default, you may need to enable the "js" error. I still don't understand why it works like that, let me investigate once more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm - I would have thought that something like this should work:

[[bin]]
name = "bench-tx"
path = "src/main.rs"

[dependencies]
miden-lib = { package = "miden-lib", path = "../miden-lib", version = "0.3" }
miden-objects = { package = "miden-objects", path = "../objects", version = "0.3" }
miden-tx = { package = "miden-tx", path = "../miden-tx", version = "0.3" }
mock = { package = "miden-mock", path = "../mock"  }
serde_json = { package = "serde_json", version = "1.0" }
vm-processor = { workspace = true, features = ["std"] }

But I didn't test it.

Either way - I think we should try to figure this out as it may mean that there is something wrong somewhere.


[dependencies]
clap = { version = "4.4", features = ["derive"] }
miden-lib = { package = "miden-lib", path = "../miden-lib", version = "0.3", default-features = false }
miden-objects = { package = "miden-objects", path = "../objects", version = "0.3", default-features = false }
miden-tx = { package = "miden-tx", path = "../miden-tx", version = "0.3", default-features = false }
mock = { package = "miden-mock", path = "../mock", features = ["std"], default-features = false, optional = true}
vm-processor = { workspace = true }
serde_json = { package = "serde_json", version = "1.0", default-features = false, optional = true }
bobbinth marked this conversation as resolved.
Show resolved Hide resolved
140 changes: 140 additions & 0 deletions benchmarks/src/benchmarks.rs
bobbinth marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
use miden_lib::notes::create_p2id_note;
use miden_lib::transaction::ToTransactionKernelInputs;
use miden_lib::utils::Serializable;
use miden_objects::{
accounts::AccountId,
assembly::ProgramAst,
assets::{Asset, FungibleAsset},
crypto::dsa::rpo_falcon512::SecretKey,
crypto::rand::RpoRandomCoin,
notes::NoteType,
transaction::TransactionArgs,
Felt,
};
use miden_tx::{TransactionExecutor, TransactionHost};
use vm_processor::{ExecutionOptions, RecAdviceProvider, Word};

use crate::{
utils::{
get_account_with_default_account_code, write_cycles_to_json, MockDataStore, String,
ToString, Vec, ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN,
ACCOUNT_ID_REGULAR_ACCOUNT_UPDATABLE_CODE_OFF_CHAIN, ACCOUNT_ID_SENDER,
DEFAULT_AUTH_SCRIPT,
},
Path,
};

// BENCHMARKS
// ================================================================================================

/// Runs the default transaction with empty transaction script and two default notes.
pub fn benchmark_default_tx(path: &Path) -> Result<(), String> {
let data_store = MockDataStore::default();
let mut executor = TransactionExecutor::new(data_store.clone()).with_tracing();

let account_id = data_store.account.id();
executor.load_account(account_id).map_err(|e| e.to_string())?;

let block_ref = data_store.block_header.block_num();
let note_ids = data_store.notes.iter().map(|note| note.id()).collect::<Vec<_>>();

let transaction = executor
.prepare_transaction(account_id, block_ref, &note_ids, data_store.tx_args().clone())
.map_err(|e| e.to_string())?;

let (stack_inputs, advice_inputs) = transaction.get_kernel_inputs();
let advice_recorder: RecAdviceProvider = advice_inputs.into();
let mut host = TransactionHost::new(transaction.account().into(), advice_recorder);

vm_processor::execute(
transaction.program(),
stack_inputs,
&mut host,
ExecutionOptions::default().with_tracing(),
)
.map_err(|e| e.to_string())?;

#[cfg(feature = "std")]
write_cycles_to_json(path, crate::Benchmark::Simple, host.tx_progress())?;

Ok(())
}

/// Runs the transaction which consumes a P2ID note into a basic wallet.
pub fn benchmark_p2id(path: &Path) -> Result<(), String> {
// Create assets
let faucet_id = AccountId::try_from(ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN).unwrap();
let fungible_asset: Asset = FungibleAsset::new(faucet_id, 100).unwrap().into();

// Create sender and target account
let sender_account_id = AccountId::try_from(ACCOUNT_ID_SENDER).unwrap();

let target_account_id =
AccountId::try_from(ACCOUNT_ID_REGULAR_ACCOUNT_UPDATABLE_CODE_OFF_CHAIN).unwrap();
let sec_key = SecretKey::new();
let target_pub_key: Word = sec_key.public_key().into();
let mut pk_sk_bytes = sec_key.to_bytes();
pk_sk_bytes.append(&mut target_pub_key.to_bytes());
let target_sk_pk_felt: Vec<Felt> =
pk_sk_bytes.iter().map(|a| Felt::new(*a as u64)).collect::<Vec<Felt>>();
let target_account =
get_account_with_default_account_code(target_account_id, target_pub_key, None);

// Create the note
let note = create_p2id_note(
sender_account_id,
target_account_id,
vec![fungible_asset],
NoteType::Public,
RpoRandomCoin::new([Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]),
)
.unwrap();

let data_store =
MockDataStore::with_existing(Some(target_account.clone()), Some(vec![note.clone()]));

let mut executor = TransactionExecutor::new(data_store.clone()).with_tracing();
executor.load_account(target_account_id).unwrap();

let block_ref = data_store.block_header.block_num();
let note_ids = data_store.notes.iter().map(|note| note.id()).collect::<Vec<_>>();

let tx_script_code = ProgramAst::parse(DEFAULT_AUTH_SCRIPT).unwrap();

let tx_script_target = executor
.compile_tx_script(
tx_script_code.clone(),
vec![(target_pub_key, target_sk_pk_felt)],
vec![],
)
.unwrap();
let tx_args_target = TransactionArgs::with_tx_script(tx_script_target);

// execute transaction
let transaction = executor
.prepare_transaction(target_account_id, block_ref, &note_ids, tx_args_target)
.map_err(|e| e.to_string())?;

let (stack_inputs, advice_inputs) = transaction.get_kernel_inputs();
let advice_recorder: RecAdviceProvider = advice_inputs.into();
let mut host = TransactionHost::new(transaction.account().into(), advice_recorder);

vm_processor::execute(
transaction.program(),
stack_inputs,
&mut host,
ExecutionOptions::default().with_tracing(),
)
.map_err(|e| e.to_string())?;

#[cfg(feature = "std")]
write_cycles_to_json(path, crate::Benchmark::P2ID, host.tx_progress())?;

Ok(())
}

/// Runs all available benchmarks.
pub fn benchmark_all(path: &Path) -> Result<(), String> {
benchmark_default_tx(path)?;
benchmark_p2id(path)
}
78 changes: 78 additions & 0 deletions benchmarks/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use clap::Parser;
use std::{
fs::{read_to_string, write, File},
io::Write,
path::Path,
};

mod benchmarks;
use benchmarks::*;

mod utils;

/// Root CLI struct
#[derive(Debug, Parser)]
#[clap(
name = "Benchmark",
about = "Benchmark execution CLI",
version,
rename_all = "kebab-case"
)]
pub struct Cli {
#[clap(subcommand)]
bench_program: Benchmark,
}

/// CLI actions
#[derive(Debug, Parser)]
pub enum Benchmark {
Simple,
P2ID,
All,
}

impl core::fmt::Display for Benchmark {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Benchmark::Simple => write!(f, "simple"),
Benchmark::P2ID => write!(f, "p2id"),
Benchmark::All => write!(f, "all"),
}
}
}

/// CLI entry point
impl Cli {
pub fn execute(&self) -> Result<(), String> {
match &self.bench_program {
Benchmark::Simple => {
let path = Path::new("benchmarks/src/results/bench_simple.json");
let mut file = File::create(path).map_err(|e| e.to_string())?;
file.write_all(b"{}").map_err(|e| e.to_string())?;
benchmark_default_tx(path)
},
Benchmark::P2ID => {
let path = Path::new("benchmarks/src/results/bench_p2id.json");
let mut file = File::create(path).map_err(|e| e.to_string())?;
file.write_all(b"{}").map_err(|e| e.to_string())?;
benchmark_p2id(path)
},
Benchmark::All => {
let path = Path::new("benchmarks/src/results/bench_all.json");
let mut file = File::create(path).map_err(|e| e.to_string())?;
file.write_all(b"{}").map_err(|e| e.to_string())?;
benchmark_all(path)
},
}
}
}

fn main() {
// read command-line args
let cli = Cli::parse();

// execute cli action
if let Err(error) = cli.execute() {
std::println!("{}", error);
}
}
27 changes: 27 additions & 0 deletions benchmarks/src/results/bench_all.json
bobbinth marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"p2id": {
"epilogue": 270,
"note_execution": [
{
"0xb9fa30eb43d80d579be02dc004338e06b5ad565e81e0bac11a94ab01abfdd40a": 881
}
],
"notes_processing": 918,
"prologue": 2002,
"tx_script_processing": 88207
},
"simple": {
"epilogue": 2220,
"note_execution": [
{
"0x8a55c3531cdd5725aa805475093ed3006c6773b71a008e8ca840da8364a67cd6": 713
},
{
"0xae832786b774651bb0e5b71615fcf9f01427c054a8919cda6d2fd4a0c8948167": 390
}
],
"notes_processing": 1149,
"prologue": 3642,
"tx_script_processing": 30
}
}
13 changes: 13 additions & 0 deletions benchmarks/src/results/bench_p2id.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"p2id": {
"epilogue": 270,
"note_execution": [
{
"0xb9fa30eb43d80d579be02dc004338e06b5ad565e81e0bac11a94ab01abfdd40a": 881
}
],
"notes_processing": 918,
"prologue": 2002,
"tx_script_processing": 88207
}
}
16 changes: 16 additions & 0 deletions benchmarks/src/results/bench_simple.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"simple": {
"epilogue": 2220,
"note_execution": [
{
"0x8a55c3531cdd5725aa805475093ed3006c6773b71a008e8ca840da8364a67cd6": 713
},
{
"0xae832786b774651bb0e5b71615fcf9f01427c054a8919cda6d2fd4a0c8948167": 390
}
],
"notes_processing": 1149,
"prologue": 3642,
"tx_script_processing": 30
}
}
Loading
Loading