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

Debug mode via cli option #1502

Merged
merged 11 commits into from
Sep 24, 2024
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Added `miden_core::utils::sync::racy_lock` module (#1463).
- Updated `miden_core::utils` to re-export `std::sync::LazyLock` and `racy_lock::RacyLock as LazyLock` for std and no_std environments, respectively (#1463).
- Made the undocumented behavior of the VM with regard to undefined behavior of u32 operations, stricter (#1480)
- Debug instructions can be enabled in the cli `run` command using `--debug` flag
bobbinth marked this conversation as resolved.
Show resolved Hide resolved

#### Fixes

Expand All @@ -25,7 +26,6 @@

- Added `PartialEq`, `Eq`, `Serialize` and `Deserialize` to `AdviceMap` and `AdviceInputs` structs (#1494).


## 0.10.5 (2024-08-21)

#### Enhancements
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ test-skip-proptests: ## Runs all tests, except property-based tests
test-loom: ## Runs all loom-based tests
RUSTFLAGS="--cfg loom" cargo nextest run --cargo-profile test-release --features testing -E 'test(#*loom)'

.PHONY: test-package
test-package: ## Tests specific package: make test-package package=miden-vm
$(DEBUG_ASSERTIONS) cargo nextest run --cargo-profile test-release --features testing -p $(package)
Comment on lines +68 to +70
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice! A question: would we achieve the same result if we add executable feature? e.g.,:

$(DEBUG_ASSERTIONS) cargo nextest run --cargo-profile test-release --features testing,executable

Copy link
Author

Choose a reason for hiding this comment

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

The thing that I added will run the integration tests for just one package as a convenience to avoid having to run all packages. Adding feature "executable" is required to run the unit tests inside the binary crate of miden-vm package. I created issue #1501 with the question regarding whether adding "executable" is the right way fix the problem of unit tests in miden-vm not running when using make tests


# --- checking ------------------------------------------------------------------------------------

.PHONY: check
Expand Down
3 changes: 2 additions & 1 deletion air/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ impl ExecutionOptions {
max_cycles: Option<u32>,
expected_cycles: u32,
enable_tracing: bool,
enable_debugging: bool,
) -> Result<Self, ExecutionOptionsError> {
let max_cycles = max_cycles.unwrap_or(u32::MAX);
if max_cycles < MIN_TRACE_LEN as u32 {
Expand All @@ -209,7 +210,7 @@ impl ExecutionOptions {
max_cycles,
expected_cycles,
enable_tracing,
enable_debugging: false,
enable_debugging,
})
}

Expand Down
28 changes: 24 additions & 4 deletions docs/src/intro/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Internally, Miden VM uses [rayon](https://github.com/rayon-rs/rayon) for paralle

### GPU acceleration

Miden VM proof generation can be accelerated via GPUs. Currently, GPU acceleration is enabled only on Apple silicon hardware (via [Metal](<https://en.wikipedia.org/wiki/Metal_(API)>)). To compile Miden VM with Metal acceleration enabled, you can run the following command:
Miden VM proof generation can be accelerated via GPUs. Currently, GPU acceleration is enabled only on Apple Silicon hardware (via [Metal](<https://en.wikipedia.org/wiki/Metal_(API)>)). To compile Miden VM with Metal acceleration enabled, you can run the following command:

```
make exec-metal
Expand Down Expand Up @@ -85,7 +85,7 @@ Currently, Miden VM can be executed with the following subcommands:
- `debug` - this will instantiate a [Miden debugger](../tools/debugger.md) against the specified Miden assembly program and inputs.
- `analyze` - this will run a Miden assembly program against specific inputs and will output stats about its execution.
- `repl` - this will initiate the [Miden REPL](../tools/repl.md) tool.
- `example` - this will execute a Miden assembly example program, generate a STARK proof of execution and verify it. Currently it is possible to run `blake3` and `fibonacci` examples.
- `example` - this will execute a Miden assembly example program, generate a STARK proof of execution and verify it. Currently, it is possible to run `blake3` and `fibonacci` examples.

All of the above subcommands require various parameters to be provided. To get more detailed help on what is needed for a given subcommand, you can run the following:

Expand All @@ -111,6 +111,14 @@ MIDEN_LOG=trace ./target/optimized/miden [subcommand] [parameters]

If the level is not specified, `warn` level is set as default.

#### Enable Debugging features

You can use the run command with `--debug` parameter to enable debugging with the [debug instruction](../user_docs/assembly/debugging.md) such as `debug.stack`:

```shell
./target/optimized/miden run -a [path_to.masm] --debug
```

### Inputs

As described [here](https://0xpolygonmiden.github.io/miden-vm/intro/overview.html#inputs-and-outputs) the Miden VM can consume public and secret inputs.
Expand All @@ -133,16 +141,28 @@ After a program finishes executing, the elements that remain on the stack become

In the `miden/examples/fib` directory, we provide a very simple Fibonacci calculator example. This example computes the 1001st term of the Fibonacci sequence. You can execute this example on Miden VM like so:

```
```shell
./target/optimized/miden run -a miden/examples/fib/fib.masm -n 1
```

### Capturing Output

This will run the example code to completion and will output the top element remaining on the stack.

If you want the output of the program in a file, you can use the `--output` or `-o` flag and specify the path to the output file. For example:

```
```shell
./target/optimized/miden run -a miden/examples/fib/fib.masm -o fib.out
```

This will dump the output of the program into the `fib.out` file. The output file will contain the state of the stack at the end of the program execution.

### Running with debug instruction enabled

Inside `miden/examples/fib/fib.masm`, insert `debug.stack` instruction anywhere between `begin` and `end`. Then run:

```shell
./target/optimized/miden run -a miden/examples/fib/fib.masm -n 1 --debug
```

You should see output similar to "Stack state before step ..."
26 changes: 26 additions & 0 deletions miden/src/cli/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ impl Debug {
}
}

impl From<bool> for Debug {
fn from(value: bool) -> Self {
match value {
true => Debug::On,
false => Debug::Off,
}
}
}

// MERKLE DATA
// ================================================================================================

Expand Down Expand Up @@ -627,3 +636,20 @@ mod test {
assert!(merkle_store.is_some());
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_debug_from_true() {
let debug_mode: Debug = true.into(); // true.into() will also test Debug.from(true)
assert!(matches!(debug_mode, Debug::On));
}

#[test]
fn test_debug_from_false() {
let debug_mode: Debug = false.into(); // false.into() will also test Debug.from(false)
assert!(matches!(debug_mode, Debug::Off));
}
}
8 changes: 6 additions & 2 deletions miden/src/cli/prove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,12 @@ pub struct ProveCmd {

impl ProveCmd {
pub fn get_proof_options(&self) -> Result<ProvingOptions, ExecutionOptionsError> {
let exec_options =
ExecutionOptions::new(Some(self.max_cycles), self.expected_cycles, self.tracing)?;
let exec_options = ExecutionOptions::new(
Some(self.max_cycles),
self.expected_cycles,
self.tracing,
false,
)?;
Ok(match self.security.as_str() {
"96bits" => {
if self.rpx {
Expand Down
19 changes: 13 additions & 6 deletions miden/src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ pub struct RunCmd {
/// Enable tracing to monitor execution of the VM
#[clap(short = 't', long = "tracing")]
tracing: bool,

/// Enable debug instructions
#[clap(short = 'd', long = "debug")]
debug: bool,
bobbinth marked this conversation as resolved.
Show resolved Hide resolved
}

impl RunCmd {
Expand Down Expand Up @@ -106,16 +110,19 @@ fn run_program(params: &RunCmd) -> Result<(ExecutionTrace, [u8; 32]), Report> {
let libraries = Libraries::new(&params.library_paths)?;

// load program from file and compile
let program =
ProgramFile::read(&params.assembly_file)?.compile(&Debug::Off, &libraries.libraries)?;
let program = ProgramFile::read(&params.assembly_file)?
.compile(&Debug::from(params.debug), &libraries.libraries)?;
bobbinth marked this conversation as resolved.
Show resolved Hide resolved

// load input data from file
let input_data = InputFile::read(&params.input_file, &params.assembly_file)?;

// get execution options
let execution_options =
ExecutionOptions::new(Some(params.max_cycles), params.expected_cycles, params.tracing)
.into_diagnostic()?;
let execution_options = ExecutionOptions::new(
Some(params.max_cycles),
params.expected_cycles,
params.tracing,
params.debug,
)
.into_diagnostic()?;

// fetch the stack and program inputs from the arguments
let stack_inputs = input_data.parse_stack_inputs().map_err(Report::msg)?;
Expand Down
8 changes: 6 additions & 2 deletions miden/src/examples/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,12 @@ pub enum ExampleType {

impl ExampleOptions {
pub fn get_proof_options(&self) -> Result<ProvingOptions, ExecutionOptionsError> {
let exec_options =
ExecutionOptions::new(Some(self.max_cycles), self.expected_cycles, self.tracing)?;
let exec_options = ExecutionOptions::new(
Some(self.max_cycles),
self.expected_cycles,
self.tracing,
false,
)?;
Ok(match self.security.as_str() {
"96bits" => {
if self.rpx {
Expand Down
54 changes: 51 additions & 3 deletions miden/tests/integration/operations/decorators/events.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use assembly::Assembler;
use processor::{ExecutionOptions, Program};
use prover::StackInputs;

use super::TestHost;

Expand All @@ -16,7 +17,8 @@ fn test_event_handling() {
// compile and execute program
let program: Program = Assembler::default().assemble_program(source).unwrap();
let mut host = TestHost::default();
processor::execute(&program, Default::default(), &mut host, Default::default()).unwrap();
processor::execute(&program, StackInputs::default(), &mut host, ExecutionOptions::default())
.unwrap();

// make sure events were handled correctly
let expected = vec![1, 2];
Expand All @@ -38,18 +40,64 @@ fn test_trace_handling() {
let mut host = TestHost::default();

// execute program with disabled tracing
processor::execute(&program, Default::default(), &mut host, Default::default()).unwrap();
processor::execute(&program, StackInputs::default(), &mut host, ExecutionOptions::default())
.unwrap();
let expected = Vec::<u32>::new();
assert_eq!(host.trace_handler, expected);

// execute program with enabled tracing
processor::execute(
&program,
Default::default(),
StackInputs::default(),
&mut host,
ExecutionOptions::default().with_tracing(),
)
.unwrap();
let expected = vec![1, 2];
assert_eq!(host.trace_handler, expected);
}

#[test]
fn test_debug_with_debugging() {
let source: &str = "\
begin
push.1
debug.stack
debug.mem
end";

// compile and execute program
let program: Program = Assembler::default().with_debug_mode(true).assemble_program(source).unwrap();
let mut host = TestHost::default();
processor::execute(
&program,
StackInputs::default(),
&mut host,
ExecutionOptions::default().with_debugging(),
)
.unwrap();

// Expect to see the debug.stack and debug.mem commands
let expected = vec!["stack", "mem"];
assert_eq!(host.debug_handler, expected);
}

#[test]
fn test_debug_without_debugging() {
let source: &str = "\
begin
push.1
debug.stack
debug.mem
end";

// compile and execute program
let program: Program = Assembler::default().assemble_program(source).unwrap();
let mut host = TestHost::default();
processor::execute(&program, StackInputs::default(), &mut host, ExecutionOptions::default())
.unwrap();

// Expect to see no debug commands
let expected: Vec<String> = vec![];
assert_eq!(host.debug_handler, expected);
}
13 changes: 12 additions & 1 deletion miden/tests/integration/operations/decorators/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use processor::{
AdviceExtractor, AdviceProvider, ExecutionError, Host, HostResponse, MastForest,
MemAdviceProvider, ProcessState,
};
use vm_core::AdviceInjector;
use vm_core::{AdviceInjector, DebugOptions};

mod advice;
mod asmop;
Expand All @@ -16,6 +16,7 @@ pub struct TestHost<A> {
pub adv_provider: A,
pub event_handler: Vec<u32>,
pub trace_handler: Vec<u32>,
pub debug_handler: Vec<String>,
}

impl Default for TestHost<MemAdviceProvider> {
Expand All @@ -24,6 +25,7 @@ impl Default for TestHost<MemAdviceProvider> {
adv_provider: MemAdviceProvider::default(),
event_handler: Vec::new(),
trace_handler: Vec::new(),
debug_handler: Vec::new(),
}
}
}
Expand Down Expand Up @@ -63,6 +65,15 @@ impl<A: AdviceProvider> Host for TestHost<A> {
Ok(HostResponse::None)
}

fn on_debug<S: ProcessState>(
&mut self,
_process: &S,
_options: &DebugOptions,
) -> Result<HostResponse, ExecutionError> {
self.debug_handler.push(_options.to_string());
Ok(HostResponse::None)
}

fn get_mast_forest(&self, _node_digest: &prover::Digest) -> Option<Arc<MastForest>> {
// Empty MAST forest store
None
Expand Down
4 changes: 3 additions & 1 deletion processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,9 @@ where
self.host.borrow_mut().set_advice(self, *injector)?;
},
Decorator::Debug(options) => {
self.host.borrow_mut().on_debug(self, options)?;
if self.decoder.in_debug_mode() {
self.host.borrow_mut().on_debug(self, options)?;
}
},
Decorator::AsmOp(assembly_op) => {
if self.decoder.in_debug_mode() {
Expand Down
2 changes: 1 addition & 1 deletion processor/src/system/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn cycles_num_exceeded() {
Kernel::default(),
stack,
host,
ExecutionOptions::new(Some(64), 64, false).unwrap(),
ExecutionOptions::new(Some(64), 64, false, false).unwrap(),
);
for _ in 0..64 {
process.execute_op(Operation::Noop).unwrap();
Expand Down