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

Conversation

Fumuran
Copy link
Contributor

@Fumuran Fumuran commented Apr 8, 2024

This PR implements the benchmark of the default transaction with default (mock) notes and with P2ID note.
This benchmark prints the number of cycles required to execute each stage of the transaction.

@Fumuran Fumuran force-pushed the andrew-tx-execution-bench branch from cd6f639 to 27d78ba Compare April 8, 2024 16:28
@Fumuran
Copy link
Contributor Author

Fumuran commented Apr 8, 2024

Although this solution works, there are some things which I don't like. Namely:

  1. I don't like the fact that I need to modify the "core" main.masm just for the benchmark. And not only just with harmless emit instructions: the problem with decorators being used in an empty span is appeared again, so I have to add some kind of push.0 drop instructions just to put something to the span block. I thought that I can use the modified copy of the main.masm file in the test, but it seems that we are using this file too early in the pipeline to be able to change it during the test.
  2. It is a little bit strange for me to implement benchmark as a test. It doesn't really test anything and it requires additional time and resources while testing the whole project. Looks like it is better to make it as an "example", although I'm not sure how can we do that in this repo.
  3. For now I just print the current cycle to the stdout using println!, which I have to import from the standard library. I tried to avoid using std, but didn't find a way to output some data without it. Probably we can use some logger? But it looks like an overkill for the miden-base to have it. But maybe I'm wrong.
  4. Probably I should make the output message more useful: now I am printing only the cycle count and a context, but since we have access to the Host, we could print something more meaningful, I just not sure what information could be useful.

@Fumuran Fumuran force-pushed the andrew-tx-execution-bench branch from 27d78ba to 0667acd Compare April 9, 2024 11:29
@bobbinth
Copy link
Contributor

Without having looked at the code too much, a few thoughts:

  1. I don't like the fact that I need to modify the "core" main.masm just for the benchmark. And not only just with harmless emit instructions: the problem with decorators being used in an empty span is appeared again, so I have to add some kind of push.0 drop instructions just to put something to the span block. I thought that I can use the modified copy of the main.masm file in the test, but it seems that we are using this file too early in the pipeline to be able to change it during the test.

I don't think that's an issue. The need for push.0 drop is indeed annoying but that's a separate problem, and hopefully, we'll find a solution soon.

  1. It is a little bit strange for me to implement benchmark as a test. It doesn't really test anything and it requires additional time and resources while testing the whole project. Looks like it is better to make it as an "example", although I'm not sure how can we do that in this repo.

I probably wouldn't implement them as a test (especially since tests are usually not run in release mode). One other option is to write this as a small binary program which one can run via one of the cargo make commands. But maybe others have other suggestions too.

  1. For now I just print the current cycle to the stdout using println!, which I have to import from the standard library. I tried to avoid using std, but didn't find a way to output some data without it. Probably we can use some logger? But it looks like an overkill for the miden-base to have it. But maybe I'm wrong.

I don't think usage of std for benchmark purposes is an issue - but I'd tried to avoid using it inside TransactionHost. I'm not sure what's the best solution here, but you can try to wrap TransactionHost in a new host which overrides the relevant functions and prints to stdout. Another option is to collect benchmarking info in some struct of transaction host, and fill this struct only if some flag in the host is set. But the wrapper approach would be preferred if it works.

  1. Probably I should make the output message more useful: now I am printing only the cycle count and a context, but since we have access to the Host, we could print something more meaningful, I just not sure what information could be useful.

Why aren't we using trace instruction for this (instead of emit)? I would use it and instead of having a single new event would have trace events for every stage we are trying to benchmark.

Comment on lines 13 to 16
const END_OF_PROLOGUE: u8 = 0;
const END_OF_NODE_PROCESSING: u8 = 1;
const END_OF_TX_SCRIPT_PROCESSING: u8 = 2;
const END_OF_EPILOGUE: u8 = 3;
Copy link
Contributor

Choose a reason for hiding this comment

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

I would use the same scheme here as we do for events and error codes - i.e., the first 16 bits are set to 2 and the remaining 16 bits is a counter that increments (0, 1, 2 etc.).

@Fumuran Fumuran marked this pull request as ready for review April 10, 2024 21:20
@Fumuran Fumuran requested a review from bobbinth April 10, 2024 21:20
@Fumuran
Copy link
Contributor Author

Fumuran commented Apr 10, 2024

I didn't manage to create a binary program from this test. Is there a way to do that without additional libraries?

Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you! I added some comments inline. One thing I'm starting to think is that maybe we should move capturing of the tracing info into the main TransactionHost and bench host would be responsible only for printing it out.

miden-lib/asm/kernels/transaction/main.masm Outdated Show resolved Hide resolved
miden-tx/tests/integration/bench/tx_benchmark.rs Outdated Show resolved Hide resolved
miden-tx/tests/integration/bench/tx_benchmark.rs Outdated Show resolved Hide resolved
miden-lib/asm/kernels/transaction/main.masm Outdated Show resolved Hide resolved
@bobbinth
Copy link
Contributor

I didn't manage to create a binary program from this test. Is there a way to do that without additional libraries?

We don't need a new library, but we would need to create a new binary (a Rust project can have many binaries).

Btw, what are the cycle counts look like for some simple transaction?

@Fumuran
Copy link
Contributor Author

Fumuran commented Apr 10, 2024

Currently for the default empty transaction we have this result:

  • Number of cycles it takes to execute the prologue: 3642
  • Number of cycles it takes to execute the note processing: 1141
  • Number of cycles it takes to execute the transaction script processing: 30
  • Number of cycles it takes to execute the epilogue: 2230

Cargo.toml Outdated Show resolved Hide resolved
@Fumuran
Copy link
Contributor Author

Fumuran commented Apr 12, 2024

The benchmark could be ran with this command:

cargo make bench-simple

Currently the output looks like so:

Number of cycles it takes to execule:
- Prologue: 3642,
- Notes processing: 1149,
--- Note #0: 713
--- Note #1: 390
- Transaction script processing: 30,
- Epilogue: 2230

@bobbinth
Copy link
Contributor

Currently the output looks like so:

Number of cycles it takes to execule:
- Prologue: 3642,
- Notes processing: 1149,
--- Note #0: 713
--- Note #1: 390
- Transaction script processing: 30,
- Epilogue: 2230

Could we do this as a transaction which consumes a P2ID note into a basic wallet? The main difference would be is that transaction script would need to include a signature and would probably take about 80K cycles.

Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Thank you! Looks good! Not a full review - but I left some more comments inline.

Makefile.toml Outdated Show resolved Hide resolved
miden-tx/src/tx_benches/utils.rs Outdated Show resolved Hide resolved
miden-tx/src/tx_benches/utils.rs Outdated Show resolved Hide resolved
miden-tx/src/tx_benches/utils.rs Outdated Show resolved Hide resolved
@Fumuran
Copy link
Contributor Author

Fumuran commented Apr 13, 2024

Benchmarks could be executed with these commands:

  • Default notes:
    cargo make bench-tx
    
    Result of this benchmark:
    Number of cycles it takes to execule:
    - Prologue: 3642,
    - Notes processing: 1149,
    --- Note 0x8a55c3531cdd5725aa805475093ed3006c6773b71a008e8ca840da8364a67cd6: 713
    --- Note 0xae832786b774651bb0e5b71615fcf9f01427c054a8919cda6d2fd4a0c8948167: 390
    - Transaction script processing: 30,
    - Epilogue: 2230
    
  • P2ID note:
    cargo make bench-p2id
    
    Result of this benchmark:
    Number of cycles it takes to execule:
    - Prologue: 2002,
    - Notes processing: 918,
    --- Note 0xb9fa30eb43d80d579be02dc004338e06b5ad565e81e0bac11a94ab01abfdd40a: 881
    - Transaction script processing: 88207,
    - Epilogue: 280
    

@Fumuran Fumuran requested a review from bobbinth April 13, 2024 17:31
@Fumuran Fumuran force-pushed the andrew-tx-execution-bench branch 2 times, most recently from bcd898c to f26171d Compare April 22, 2024 21:36
@Fumuran Fumuran force-pushed the andrew-tx-execution-bench branch from aa1de52 to b9d6473 Compare April 22, 2024 22:40
Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Thank you! Looks good! I left a few more comments inline.

bench-tx/src/bench-tx.json Outdated Show resolved Hide resolved
Comment on lines 246 to 255
/// Returns the ID of the consumed note being executed.
fn get_current_note_id<S: ProcessState>(process: &S) -> Result<Option<NoteId>, ExecutionError> {
let note_address_felt = process
.get_mem_value(process.ctx(), CURRENT_CONSUMED_NOTE_PTR)
.expect("current consumed note pointer invalid")[0];
let note_address: u32 = note_address_felt
.try_into()
.map_err(|_| ExecutionError::MemoryAddressOutOfBounds(note_address_felt.as_int()))?;
Ok(process.get_mem_value(process.ctx(), note_address).map(NoteId::from))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

In case we haven't start executing any note, expect will panic.

What about after note execution is done? In general, I still think it would be better to check the value of the current note pointer.

I wanted to return an ExecutionError, but looks like we don't have an error for the cases when the memory segment wasn't initialized. I can implement it, but I'm not sure that it is worth it since it is used only here.

I think returning Option (the way you have it now) is fine.

Comment on lines 15 to 20
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.

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.

// DATA PRINT
// --------------------------------------------------------------------------------------------

pub fn to_json_string(&self) -> String {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the struct could look something like:

pub struct TransactionBenchmark {
    prologue: u32,
    notes_processing: u32,
    note_execution: Vec<(String, u32)>,
    tx_script_processing: u32,
    epilogue: u32,
}

And then we can implement TryFrom<TransactionProgress> for TransactionBenchmark. This conversion should be pretty straight-forward.

miden-tx/src/host/tx_progress.rs Outdated Show resolved Hide resolved
@Fumuran
Copy link
Contributor Author

Fumuran commented Apr 24, 2024

@bobbinth @hackaugusto Yesterday I spent the whole day trying to reconstruct the JSON file to be able to track the changes commit by commit and create readable plots with this data. I came to the conclusion, that it is quite difficult to create few informative plots with this large amount of data: we have $4 + n$ values (where $n$ is number of notes being executed) for each of $m$ benchmarks for each of $k$ commits. I can create plots based only on the overall number of cycles for each benchmark, but in that case we will loose valuable data.
I think one of the solutions could be printing both: for example, plots with total number of cycles for each benchmark at the top of the README, and beneath collapsed tabs for each benchmark containing plots for each parameter. But it still looks like a bulky solution for me, IMO it will be difficult to track the performance using that many plots.

So, the general question sounds like: how do we want to show the benchmarking data? Do you know any solutions being able to track and aggregate a lot of data to compare effectiveness? (github-action-benchmark is a good solution, but it doesn't really suit us: it works with the output of actual cargo bench in specific format, and also is able to create plots based on the only one value).

@bobbinth
Copy link
Contributor

I would move the plotting part into a separate issue. For this PR, just committing the JSON file (as you have now), is fine.

@Fumuran Fumuran force-pushed the andrew-tx-execution-bench branch from 6c109f8 to 6c5b84b Compare April 24, 2024 19:23
@Fumuran Fumuran force-pushed the andrew-tx-execution-bench branch from 6c5b84b to 499ddc5 Compare April 24, 2024 19:28
@Fumuran Fumuran force-pushed the andrew-tx-execution-bench branch from 499ddc5 to 4e284aa Compare April 24, 2024 19:55
@Fumuran Fumuran requested a review from bobbinth April 24, 2024 20:16
Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you! I left some small nits inline - once these are addressed, we can merge.

Makefile.toml Show resolved Hide resolved
Makefile.toml Outdated Show resolved Hide resolved
bench-tx/bench-tx.json Outdated Show resolved Hide resolved
miden-tx/src/host/mod.rs Outdated Show resolved Hide resolved
miden-tx/src/host/mod.rs Outdated Show resolved Hide resolved
bench-tx/src/utils.rs Outdated Show resolved Hide resolved
bench-tx/src/main.rs Outdated Show resolved Hide resolved
@Fumuran Fumuran requested a review from bobbinth April 25, 2024 08:46
Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

All looks good! Thank you! Let's update changelog and merge.

Also, you may want to rebase from the latest next as the changelog was updated there.

@Fumuran Fumuran merged commit 50c42e7 into next Apr 25, 2024
9 checks passed
@Fumuran Fumuran deleted the andrew-tx-execution-bench branch April 25, 2024 10:10
bobbinth pushed a commit that referenced this pull request Apr 25, 2024
* feat: add benchmark for default transaction

* refactor: use trace instead of emit, create wrapper for host

* refactor: improve cycles print

* refactor: add inline comments, change trace ids

* chore: ignore the test untill it become a binary

* refactor: organise cycles storing, add traces for each note

* feat: create a simple cli for benchmark binary package

* feat: create cargo-make script for benchmarking, move benchmarks back to the miden-tx

* refactor: move TransactionProgress to the TransactionHost

* feat: implement bench for P2ID note, add NoteId to the output

* refactor: move last note id obtaining to the separate function

* refactor: fix no-std build

* refactor: update comments in main.masm file to be consistent with api.masm

* feat: write benchmark results to the json file

* refactor: move benchmarks to their own crate

* refactor: add ability to run all benches

* refactor: update bin name, dependencies; remove benches except all

* chore: fix no-std build

* refactor: rework TransactionProgress serialization

* refactor: exclude bench-tx from no-std build, update dependencies

* refactor: improve imports formatting

* refactor: rework writing to json

* chore: change visibility of miden-tx MockDataStore

* chore: update CHANGELOG, create README for bench-tx
bobbinth pushed a commit that referenced this pull request Apr 26, 2024
* feat: add benchmark for default transaction

* refactor: use trace instead of emit, create wrapper for host

* refactor: improve cycles print

* refactor: add inline comments, change trace ids

* chore: ignore the test untill it become a binary

* refactor: organise cycles storing, add traces for each note

* feat: create a simple cli for benchmark binary package

* feat: create cargo-make script for benchmarking, move benchmarks back to the miden-tx

* refactor: move TransactionProgress to the TransactionHost

* feat: implement bench for P2ID note, add NoteId to the output

* refactor: move last note id obtaining to the separate function

* refactor: fix no-std build

* refactor: update comments in main.masm file to be consistent with api.masm

* feat: write benchmark results to the json file

* refactor: move benchmarks to their own crate

* refactor: add ability to run all benches

* refactor: update bin name, dependencies; remove benches except all

* chore: fix no-std build

* refactor: rework TransactionProgress serialization

* refactor: exclude bench-tx from no-std build, update dependencies

* refactor: improve imports formatting

* refactor: rework writing to json

* chore: change visibility of miden-tx MockDataStore

* chore: update CHANGELOG, create README for bench-tx
Dominik1999 pushed a commit that referenced this pull request Apr 26, 2024
* feat: add benchmark for default transaction

* refactor: use trace instead of emit, create wrapper for host

* refactor: improve cycles print

* refactor: add inline comments, change trace ids

* chore: ignore the test untill it become a binary

* refactor: organise cycles storing, add traces for each note

* feat: create a simple cli for benchmark binary package

* feat: create cargo-make script for benchmarking, move benchmarks back to the miden-tx

* refactor: move TransactionProgress to the TransactionHost

* feat: implement bench for P2ID note, add NoteId to the output

* refactor: move last note id obtaining to the separate function

* refactor: fix no-std build

* refactor: update comments in main.masm file to be consistent with api.masm

* feat: write benchmark results to the json file

* refactor: move benchmarks to their own crate

* refactor: add ability to run all benches

* refactor: update bin name, dependencies; remove benches except all

* chore: fix no-std build

* refactor: rework TransactionProgress serialization

* refactor: exclude bench-tx from no-std build, update dependencies

* refactor: improve imports formatting

* refactor: rework writing to json

* chore: change visibility of miden-tx MockDataStore

* chore: update CHANGELOG, create README for bench-tx
bobbinth pushed a commit that referenced this pull request May 13, 2024
* feat: add benchmark for default transaction

* refactor: use trace instead of emit, create wrapper for host

* refactor: improve cycles print

* refactor: add inline comments, change trace ids

* chore: ignore the test untill it become a binary

* refactor: organise cycles storing, add traces for each note

* feat: create a simple cli for benchmark binary package

* feat: create cargo-make script for benchmarking, move benchmarks back to the miden-tx

* refactor: move TransactionProgress to the TransactionHost

* feat: implement bench for P2ID note, add NoteId to the output

* refactor: move last note id obtaining to the separate function

* refactor: fix no-std build

* refactor: update comments in main.masm file to be consistent with api.masm

* feat: write benchmark results to the json file

* refactor: move benchmarks to their own crate

* refactor: add ability to run all benches

* refactor: update bin name, dependencies; remove benches except all

* chore: fix no-std build

* refactor: rework TransactionProgress serialization

* refactor: exclude bench-tx from no-std build, update dependencies

* refactor: improve imports formatting

* refactor: rework writing to json

* chore: change visibility of miden-tx MockDataStore

* chore: update CHANGELOG, create README for bench-tx
bobbinth pushed a commit that referenced this pull request May 14, 2024
* feat: add benchmark for default transaction

* refactor: use trace instead of emit, create wrapper for host

* refactor: improve cycles print

* refactor: add inline comments, change trace ids

* chore: ignore the test untill it become a binary

* refactor: organise cycles storing, add traces for each note

* feat: create a simple cli for benchmark binary package

* feat: create cargo-make script for benchmarking, move benchmarks back to the miden-tx

* refactor: move TransactionProgress to the TransactionHost

* feat: implement bench for P2ID note, add NoteId to the output

* refactor: move last note id obtaining to the separate function

* refactor: fix no-std build

* refactor: update comments in main.masm file to be consistent with api.masm

* feat: write benchmark results to the json file

* refactor: move benchmarks to their own crate

* refactor: add ability to run all benches

* refactor: update bin name, dependencies; remove benches except all

* chore: fix no-std build

* refactor: rework TransactionProgress serialization

* refactor: exclude bench-tx from no-std build, update dependencies

* refactor: improve imports formatting

* refactor: rework writing to json

* chore: change visibility of miden-tx MockDataStore

* chore: update CHANGELOG, create README for bench-tx
Fumuran added a commit that referenced this pull request May 23, 2024
* feat: add benchmark for default transaction

* refactor: use trace instead of emit, create wrapper for host

* refactor: improve cycles print

* refactor: add inline comments, change trace ids

* chore: ignore the test untill it become a binary

* refactor: organise cycles storing, add traces for each note

* feat: create a simple cli for benchmark binary package

* feat: create cargo-make script for benchmarking, move benchmarks back to the miden-tx

* refactor: move TransactionProgress to the TransactionHost

* feat: implement bench for P2ID note, add NoteId to the output

* refactor: move last note id obtaining to the separate function

* refactor: fix no-std build

* refactor: update comments in main.masm file to be consistent with api.masm

* feat: write benchmark results to the json file

* refactor: move benchmarks to their own crate

* refactor: add ability to run all benches

* refactor: update bin name, dependencies; remove benches except all

* chore: fix no-std build

* refactor: rework TransactionProgress serialization

* refactor: exclude bench-tx from no-std build, update dependencies

* refactor: improve imports formatting

* refactor: rework writing to json

* chore: change visibility of miden-tx MockDataStore

* chore: update CHANGELOG, create README for bench-tx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants