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 program analysis tool #198

Merged
merged 4 commits into from Jun 20, 2022

Conversation

tohrnii
Copy link
Contributor

@tohrnii tohrnii commented May 12, 2022

Partly addresses #138

Adds a utility package to analyse any given script. Takes a source script as a file input and prints the following information.

  • Number of VM cycles it takes to execute the script
  • Number of NOOPs executed as part of a program

Input:
proc.foo.1 pop.local.0 end begin popw.mem.1 push.17 exec.foo end

Output:

Total Number of VM Cycles: 24
Total Number of NOOPs: 1

@bobbinth
Copy link
Contributor

@tohrnii - thank you for working on this! A few preliminary thoughts:

  1. I'd like to make the structure a bit more generic. For example:
  • Let's return something like ProgramInfo struct from the analyze() function. For now, this could contain just a single field and we can expand it later to contain more fields.
  • I'd like the structure to be generic so that we could use it, for example, from WASM. This way, we'll be able to have a webpage where you could paste in a script and get the stats back.
  1. I'd probably prefer tools rather than analysis crate. And the package name itself could be miden-vm-tools.
  2. I'm not sure what's the right place to put the code is. On the one hand, it would be nice to have miden-vm-tools compile into a binary (so that we could run it from the command line). On the other hand, I'd like to be able to compile it as a WASM-compliant library. Any suggestions are welcome here.

@grjte
Copy link
Collaborator

grjte commented May 14, 2022

3. I'm not sure what's the right place to put the code is. On the one hand, it would be nice to have `miden-vm-tools` compile into a binary (so that we could run it from the command line). On the other hand, I'd like to be able to compile it as a WASM-compliant library. Any suggestions are welcome here.

I think it should probably be a library which could then be used for front-end tooling or as a dependency for a binary

@bobbinth
Copy link
Contributor

I think it should probably be a library which could then be used for front-end tooling or as a dependency for a binary

I guess the question is where to put the library portion of the code and where to put the binaries. For example, we could put the actual code into the miden crate and then create tools crate to contain binaries.

Another option is for tools crate be a library crate and come up with some other crate to contain binaries.

@tohrnii
Copy link
Contributor Author

tohrnii commented May 15, 2022

we could put the actual code into the miden crate and then create tools crate to contain binaries.

This seems like the best way to go to me.

@tohrnii
Copy link
Contributor Author

tohrnii commented May 15, 2022

Moved the library to miden::utils and binary to tools crate. Does this structure make sense?

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! I left a few comments inline.

tools/Cargo.toml Outdated Show resolved Hide resolved
tools/Cargo.toml Outdated Show resolved Hide resolved
tools/Cargo.toml Outdated Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
miden/src/lib.rs Outdated Show resolved Hide resolved
miden/src/utils/mod.rs Outdated Show resolved Hide resolved
miden/src/utils/mod.rs Outdated Show resolved Hide resolved
.gitignore Outdated Show resolved Hide resolved
@tohrnii tohrnii force-pushed the feat/program-analysis-tool branch from dda81c8 to 9212b46 Compare May 23, 2022 09:45
@tohrnii
Copy link
Contributor Author

tohrnii commented May 23, 2022

Thank you so much @bobbinth for the review. Made suggested changes. Please let me know if we should add rest of the analysis to the same pr or open another one.

@tohrnii tohrnii marked this pull request as ready for review May 23, 2022 09:48
@tohrnii tohrnii requested a review from bobbinth May 23, 2022 09:48
@tohrnii tohrnii force-pushed the feat/program-analysis-tool branch 3 times, most recently from 4987c10 to 945e478 Compare May 23, 2022 13:52
@tohrnii
Copy link
Contributor Author

tohrnii commented May 23, 2022

On rebasing to latest next branch, the total number of vm cycles have changed. This seems to be related to PR #212 . For example for script use.std::sys begin exec.sys::finalize_stack end, the total number of vm cycles changed from 69 to 72.
Similarly, for script proc.foo.1 pop.local.0 end begin popw.mem.1 push.17 exec.foo end, the total number of vm cycles changed from 23 to 24. @bobbinth Does this look like an intended side effect of PR 212 or should this be investigated further?

@bobbinth
Copy link
Contributor

bobbinth commented May 23, 2022

@tohrnii - yes, this is mostly likely due to #212. The difference in count should come primarily form more NOOP operations executed. We need to execute NOOPs in a few cases, for example:

  1. If a number of operation groups in a batch is not a power of two, we execute NOOPs for each missing group (e.g., if there are 3 groups in a batch, we put a single NOOP into the 4th group).
  2. If a PUSH operation is the last one in a group, we need to execute a NOOP operation after it.

By the way, it may be a good metric to track: number of NOOPs executed as a part of a program. This could be a good efficiency metric.

tools/Cargo.toml Outdated Show resolved Hide resolved
@tohrnii
Copy link
Contributor Author

tohrnii commented May 23, 2022

Thanks for the explanation on PR 212. I'll add NOOPs metric to be added as part of the program analysis tool to issue #138 as a comment.

@bobbinth
Copy link
Contributor

@tohrnii - let's add NOOP tracking in this PR (since I think it should be fairly simple), and then we can do the rest in subsequent PRs. What do you think?

@tohrnii
Copy link
Contributor Author

tohrnii commented May 24, 2022

@bobbinth - Sounds good!

@bobbinth
Copy link
Contributor

Actually, I should say that counting NOOPs would be pretty difficult right now, but will become very easy once #195 is merges. So, let's wait until I'm done with decoder trace, and then we can finish this PR.

@tohrnii tohrnii marked this pull request as draft May 24, 2022 14:44
@tohrnii tohrnii force-pushed the feat/program-analysis-tool branch from 79363c2 to 30285ed Compare June 4, 2022 02:07
cleanup

print number of program blocks in the script

change path to string

refactor

refactor

more refactor based on review

remove debug

rebase next

rename binary to mvt
@tohrnii tohrnii marked this pull request as ready for review June 17, 2022 17:14
@tohrnii tohrnii requested a review from bobbinth June 17, 2022 17:14
@tohrnii
Copy link
Contributor Author

tohrnii commented Jun 17, 2022

@bobbinth - I've added total noops executed as part of the analysis. Also added None operation as part of this PR. VmState at the first row contains the None operation based on your suggestion.

Two pending analysis left to be addressed are:

  • Number of program blocks in the script (for each block type)
  • Number of cycles per assembly instruction. E.g., a program executed u32add.full operation x times, and this translated to y VM cycles.

I will address these in a separate PR after completing #226.

@tohrnii tohrnii force-pushed the feat/program-analysis-tool branch from 6366068 to 16b3527 Compare June 17, 2022 17: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! I left a few more comments inline.

processor/src/decoder/mod.rs Outdated Show resolved Hide resolved
core/src/operations/mod.rs Outdated Show resolved Hide resolved
processor/src/operations/mod.rs Outdated Show resolved Hide resolved
miden/src/tools/mod.rs Outdated Show resolved Hide resolved
@tohrnii tohrnii force-pushed the feat/program-analysis-tool branch from a11b9d9 to c3407d4 Compare June 18, 2022 10:43
feat(core): add None operation

feat(tools): add total noops to program analysis

fix(processor): change operation type to Option<Operation>
@tohrnii tohrnii force-pushed the feat/program-analysis-tool branch from c3407d4 to 4d9fa2c Compare June 18, 2022 11:00
@tohrnii tohrnii requested a review from bobbinth June 18, 2022 11:22
@tohrnii tohrnii force-pushed the feat/program-analysis-tool branch from 4d9fa2c to 4d46d39 Compare June 18, 2022 13:50
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! A few more comments inline.

processor/src/debug.rs Outdated Show resolved Hide resolved
processor/src/decoder/mod.rs Outdated Show resolved Hide resolved
miden/src/tools/mod.rs Outdated Show resolved Hide resolved
miden/src/tools/mod.rs Outdated Show resolved Hide resolved
miden/src/tools/mod.rs Outdated Show resolved Hide resolved
miden/src/tools/mod.rs Outdated Show resolved Hide resolved
tools/src/main.rs Outdated Show resolved Hide resolved
@tohrnii tohrnii force-pushed the feat/program-analysis-tool branch from 4d46d39 to bb2133b Compare June 18, 2022 20:42
@tohrnii
Copy link
Contributor Author

tohrnii commented Jun 18, 2022

@bobbinth - Thank you for the review. Made suggested changes.

@tohrnii tohrnii requested a review from bobbinth June 18, 2022 20:47
let mut noop_count = 0;

for vm_state in vm_state_iterator {
if matches!(vm_state.as_ref().unwrap().op, Some(Operation::Noop)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you need the unwrap() here? Would something like this work: matches!(vm_state.op, Some(Operation::Noop))?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh - I think it won't. I'm trying to think of a way to get rid of the unwrap's here - ideally, we shouldn't have them in production code.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess one thing that this doesn't account for is when a program terminates with an error. We should probably change the return type of analyze() to return a Result<ProgramInfo, ExecutionError> and then if we encounter an error it would be just returned instead of ProgramInfo. What do you think?

Copy link
Contributor Author

@tohrnii tohrnii Jun 19, 2022

Choose a reason for hiding this comment

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

I'm trying to think of a way to get rid of the unwrap's here - ideally, we shouldn't have them in production code.

Just to clarify, the reason is proper error propagation right?
Can we use something like:

for state in vm_state_iterator {
    let vm_state = match state {
        Ok(vm_state) => vm_state,
        Err(err) => return Err(err)
    };
    if matches!(vm_state.op, Some(Operation::Noop)) {
        noop_count += 1;
    }
    total_vm_cycles = vm_state.clk;
}

Copy link
Contributor Author

@tohrnii tohrnii Jun 19, 2022

Choose a reason for hiding this comment

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

I guess one thing that this doesn't account for is when a program terminates with an error. We should probably change the return type of analyze() to return a Result<ProgramInfo, ExecutionError> and then if we encounter an error it would be just returned instead of ProgramInfo. What do you think?

Makes sense to propagate error here. Since there are two possible errors here, AssemblyError while compiling the script and ExecutionError while executing the script, should we add a new enum called AnalysisError with those two variants and return that instead? That doesn't look very clean though. Is there a better (more idiomatic) way to handle that? Thanks.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes - the reason is proper error propagation, but also, as a general rule, I try not to have unwrap's in non-test code.

Yes, let's add a new enum. We did something like this here. Though I don't love the name AnalysisError. One other option that came to mind is MidenError - but I don't love this one too much either.

The code snippet above looks right - though, I'd prefer to use map_err() instead of match. For example, something like:

for state in vm_state_iterator {
    let vm_state = state.map_err(...)?;
    if matches!(vm_state.op, Some(Operation::Noop)) {
        noop_count += 1;
    }
    total_vm_cycles = vm_state.clk;
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe ProgramError is better than the other options?

Copy link
Contributor Author

@tohrnii tohrnii Jun 20, 2022

Choose a reason for hiding this comment

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

@bobbinth - ProgramError sounds good to me. For future, in general should we lean more towards verbosity or succinctness in naming things?

@tohrnii tohrnii force-pushed the feat/program-analysis-tool branch 3 times, most recently from 2025f59 to 8058c72 Compare June 20, 2022 07:34
@tohrnii
Copy link
Contributor Author

tohrnii commented Jun 20, 2022

@bobbinth - Thank you for the review. Made suggested changes.
ProgramError enum variants take error as argument instead of string. The thinking is that this would allow access to properties of the error in case this enum was to be used outside of program analysis and in general to avoid loss of information. Please let me know if this should take a string instead.

@tohrnii tohrnii force-pushed the feat/program-analysis-tool branch from 8058c72 to 3de91a7 Compare June 20, 2022 08:04
cargo fix

change string to str

fix comment

fixes

change analyze function return type to result

remove std

remove std

add comments
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!

@bobbinth bobbinth merged commit 1f07ac9 into 0xPolygonMiden:next Jun 20, 2022
@tohrnii tohrnii deleted the feat/program-analysis-tool branch July 30, 2022 09:13
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.

None yet

3 participants