Skip to content

Commit

Permalink
refactor: get trace len info from vmstateiter constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
Fumuran committed Oct 10, 2023
1 parent 2b4b899 commit 72a0a00
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 80 deletions.
118 changes: 43 additions & 75 deletions miden/src/tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::{cli::InputFile, ProgramError};
use clap::Parser;
use core::fmt;
use miden::{utils::collections::Vec, AdviceProvider, Assembler, Operation, StackInputs};
use processor::{AsmOpInfo, ExecutionOptions, TraceLenSummary};
use processor::{AsmOpInfo, TraceLenSummary};
use std::{fs, path::PathBuf};
use stdlib::StdLibrary;

Expand All @@ -19,9 +19,6 @@ pub struct Analyze {
/// Path to .inputs file
#[clap(short = 'i', long = "input", value_parser)]
input_file: Option<PathBuf>,
/// Print extended cycles info
#[clap(short = 'c', long = "cycles")]
cycles_info: bool,
}

/// Implements CLI execution logic
Expand All @@ -38,7 +35,7 @@ impl Analyze {
let advice_provider = input_data.parse_advice_provider()?;

let execution_details: ExecutionDetails =
analyze(program.as_str(), stack_inputs, advice_provider, self.cycles_info)
analyze(program.as_str(), stack_inputs, advice_provider)
.expect("Could not retrieve execution details");

println!("{}", execution_details);
Expand All @@ -53,22 +50,15 @@ impl Analyze {
/// Contains details of executing a program, used for program analysis.
#[derive(Debug, Default, Eq, PartialEq)]
pub struct ExecutionDetails {
/// Number of VM cycles it took to execute the entire program.
total_vm_cycles: u32,
/// Number of noops executed as part of a program.
total_noops: usize,
/// Statistics about individual assembly operations executed by the VM, see [AsmOpStats].
asm_op_stats: Vec<AsmOpStats>,
/// Extended information about cycles of VM components.
extended_cycles_info: Option<TraceLenSummary>,
/// Information about VM components trace lengths.
trace_len_summary: TraceLenSummary,
}

impl ExecutionDetails {
/// Returns total vm cycles to execute a program
pub fn total_vm_cycles(&self) -> u32 {
self.total_vm_cycles
}

/// Returns total noops executed as part of a program
pub fn total_noops(&self) -> usize {
self.total_noops
Expand All @@ -81,8 +71,8 @@ impl ExecutionDetails {
}

/// Returns [TraceLenSummary] that contains the data about lengths of the trace parts.
pub fn extended_cycles_info(&self) -> Option<TraceLenSummary> {
self.extended_cycles_info
pub fn trace_len_summary(&self) -> TraceLenSummary {
self.trace_len_summary
}

// STATE MUTATORS
Expand All @@ -93,11 +83,6 @@ impl ExecutionDetails {
self.total_noops += 1;
}

/// Sets the total vm cycles to the provided value
pub fn set_total_vm_cycles(&mut self, total_vm_cycles: u32) {
self.total_vm_cycles = total_vm_cycles;
}

/// Records a new occurrence of asmop in the sorted asmop stats vector of this program info.
/// If the asmop is already in the list, increments its frequency by one.
/// If the asmop is not already in the list, add it at the appropriate index to keep the
Expand Down Expand Up @@ -128,45 +113,40 @@ impl ExecutionDetails {
}

/// Sets the information about lengths of the trace parts.
pub fn set_extended_cycle_info(&mut self, extended_cycles_info: &TraceLenSummary) {
self.extended_cycles_info = Some(*extended_cycles_info);
pub fn set_trace_len_summary(&mut self, extended_cycles_info: &TraceLenSummary) {
self.trace_len_summary = *extended_cycles_info;
}
}

impl fmt::Display for ExecutionDetails {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// if the extended information about VM cycles is provided, print it instead of concise
// variant
if let Some(extended_cycles_info) = self.extended_cycles_info() {
// calculate the percentage of padded rows
let padding_percentage =
(extended_cycles_info.padded_trace_len() - extended_cycles_info.trace_len()) * 100
/ extended_cycles_info.padded_trace_len();
// calculate the percentage of padded rows
let padding_percentage = (self.trace_len_summary().padded_trace_len()
- self.trace_len_summary().trace_len())
* 100
/ self.trace_len_summary().padded_trace_len();

writeln!(
f,
"\nVM cycles: {} extended to {} steps ({}% padding).
├── Stack rows: {}
├── Range checker rows: {}
└── Chiplets rows: {}
├── Hash chiplet rows: {}
├── Bitwise chiplet rows: {}
├── Memory chiplet rows: {}
└── Kernel ROM rows: {}",
extended_cycles_info.trace_len(),
extended_cycles_info.padded_trace_len(),
padding_percentage,
extended_cycles_info.main_trace_len(),
extended_cycles_info.range_trace_len(),
extended_cycles_info.chiplets_trace_len().trace_len(),
extended_cycles_info.chiplets_trace_len().hash_chiplet_len(),
extended_cycles_info.chiplets_trace_len().bitwise_chiplet_len(),
extended_cycles_info.chiplets_trace_len().memory_chiplet_len(),
extended_cycles_info.chiplets_trace_len().kernel_rom_len(),
)?;
} else {
writeln!(f, "\nTotal Number of VM Cycles: {}", self.total_vm_cycles())?;
}
writeln!(
f,
"\nVM cycles: {} extended to {} steps ({}% padding).
├── Stack rows: {}
├── Range checker rows: {}
└── Chiplets rows: {}
├── Hash chiplet rows: {}
├── Bitwise chiplet rows: {}
├── Memory chiplet rows: {}
└── Kernel ROM rows: {}",
self.trace_len_summary().trace_len(),
self.trace_len_summary().padded_trace_len(),
padding_percentage,
self.trace_len_summary().main_trace_len(),
self.trace_len_summary().range_trace_len(),
self.trace_len_summary().chiplets_trace_len().trace_len(),
self.trace_len_summary().chiplets_trace_len().hash_chiplet_len(),
self.trace_len_summary().chiplets_trace_len().bitwise_chiplet_len(),
self.trace_len_summary().chiplets_trace_len().memory_chiplet_len(),
self.trace_len_summary().chiplets_trace_len().kernel_rom_len(),
)?;
let total_noops = self.total_noops();
let asm_op_stats = self.asm_op_stats();
writeln!(f, "Total Number of NOOPs executed: {}\n", total_noops)?;
Expand Down Expand Up @@ -208,7 +188,6 @@ pub fn analyze<A>(
program: &str,
stack_inputs: StackInputs,
advice_provider: A,
cycles_info: bool,
) -> Result<ExecutionDetails, ProgramError>
where
A: AdviceProvider + Clone,
Expand All @@ -222,19 +201,9 @@ where

let mut execution_details = ExecutionDetails::default();

// if the `cycles_info` flag is true, get the program execution trace to obtain the trace length summary
if cycles_info {
let trace = processor::execute(
&program,
stack_inputs.clone(),
advice_provider.clone(),
ExecutionOptions::default(),
)
.map_err(|err| ProgramError::ExecutionError(err))?;
execution_details.set_extended_cycle_info(trace.trace_len_summary());
}

let vm_state_iterator = processor::execute_iter(&program, stack_inputs, advice_provider);
let (vm_state_iterator, trace_len_summary) =
processor::execute_iter_with_trace_len(&program, stack_inputs, advice_provider);
execution_details.set_trace_len_summary(&trace_len_summary);

for state in vm_state_iterator {
let vm_state = state.map_err(ProgramError::ExecutionError)?;
Expand All @@ -244,7 +213,6 @@ where
if let Some(asmop_info) = vm_state.asmop {
execution_details.record_asmop(asmop_info);
}
execution_details.set_total_vm_cycles(vm_state.clk);
}

Ok(execution_details)
Expand Down Expand Up @@ -308,26 +276,26 @@ impl AsmOpStats {
mod tests {
use super::{AsmOpStats, ExecutionDetails, StackInputs};
use miden::MemAdviceProvider;
use processor::{ChipletsLengths, TraceLenSummary};

#[test]
fn analyze_test() {
let source =
"proc.foo.1 loc_store.0 end begin mem_storew.1 dropw push.17 push.1 movdn.2 exec.foo end";
let stack_inputs = StackInputs::default();
let advice_provider = MemAdviceProvider::default();
let execution_details = super::analyze(source, stack_inputs, advice_provider, false)
let execution_details = super::analyze(source, stack_inputs, advice_provider)
.expect("analyze_test: Unexpected Error");
let expected_details = ExecutionDetails {
total_vm_cycles: 23,
total_noops: 2,
asm_op_stats: vec![
AsmOpStats::new("dropw".to_string(), 1, 4),
AsmOpStats::new("loc_store".to_string(), 1, 4),
AsmOpStats::new("mem_storew".to_string(), 1, 3),
AsmOpStats::new("movdn2".to_string(), 1, 1),
AsmOpStats::new("movdn.2".to_string(), 1, 1),
AsmOpStats::new("push".to_string(), 2, 3),
],
extended_cycles_info: None,
trace_len_summary: TraceLenSummary::new(23, 39, ChipletsLengths::new_debug(8, 0, 2, 0)),
};
assert_eq!(execution_details, expected_details);
}
Expand All @@ -338,7 +306,7 @@ mod tests {
let stack_inputs = vec![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let stack_inputs = StackInputs::try_from_values(stack_inputs).unwrap();
let advice_provider = MemAdviceProvider::default();
let execution_details = super::analyze(source, stack_inputs, advice_provider, false);
let execution_details = super::analyze(source, stack_inputs, advice_provider);
let expected_error = "Execution Error: DivideByZero(1)";
assert_eq!(execution_details.err().unwrap().to_string(), expected_error);
}
Expand All @@ -348,7 +316,7 @@ mod tests {
let source = "proc.foo.1 loc_store.0 end mem_storew.1 dropw push.17 exec.foo end";
let stack_inputs = StackInputs::default();
let advice_provider = MemAdviceProvider::default();
let execution_details = super::analyze(source, stack_inputs, advice_provider, false);
let execution_details = super::analyze(source, stack_inputs, advice_provider);
let expected_error = "Assembly Error: ParsingError(\"unexpected token: expected 'begin' but was 'mem_storew.1'\")";
assert_eq!(execution_details.err().unwrap().to_string(), expected_error);
}
Expand Down
35 changes: 33 additions & 2 deletions processor/src/debug.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
advice::AdviceProvider, Chiplets, Decoder, ExecutionError, Felt, Process, Stack, StarkField,
System, Vec,
advice::AdviceProvider, trace::ChipletsLengths, Chiplets, Decoder, ExecutionError, Felt,
Process, Stack, StarkField, System, TraceLenSummary, Vec,
};
use core::fmt;
use vm_core::{
Expand Down Expand Up @@ -76,6 +76,37 @@ impl VmStateIterator {
}
}

/// Returns a new instance of [VmStateIterator] together with [TraceLenSummary].
pub(super) fn new_with_trace_len<A>(
process: Process<A>,
result: Result<StackOutputs, ExecutionError>,
) -> (Self, TraceLenSummary)
where
A: AdviceProvider,
{
let (system, decoder, stack, mut range, chiplets, _) = process.into_parts();

let clk = system.clk();
let range_table_len = range.get_number_range_checker_rows();
chiplets.append_range_checks(&mut range);

let trace_len_summary =
TraceLenSummary::new(clk as usize, range_table_len, ChipletsLengths::new(&chiplets));

let state_iterator = Self {
chiplets,
decoder,
stack,
system,
error: result.err(),
clk: 0,
asmop_idx: 0,
forward: true,
};

(state_iterator, trace_len_summary)
}

/// Returns the asm op info corresponding to this vm state and whether this is the start of
/// operation sequence corresponding to current assembly instruction.
fn get_asmop(&self) -> (Option<AsmOpInfo>, bool) {
Expand Down
26 changes: 25 additions & 1 deletion processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ use chiplets::Chiplets;

mod trace;
use trace::TraceFragment;
pub use trace::{ExecutionTrace, TraceLenSummary};
pub use trace::{ChipletsLengths, ExecutionTrace, TraceLenSummary};

mod errors;
pub use errors::{ExecutionError, Ext2InttError};
Expand Down Expand Up @@ -151,6 +151,30 @@ where
VmStateIterator::new(process, result)
}

/// Returns a tuple with VM state iterator and trace lengths summary.
pub fn execute_iter_with_trace_len<A>(
program: &Program,
stack_inputs: StackInputs,
advice_provider: A,
) -> (VmStateIterator, TraceLenSummary)
where
A: AdviceProvider + Clone,
{
let mut process = Process::new_debug(program.kernel().clone(), stack_inputs, advice_provider);
let stack_outputs = process.execute(program);
if stack_outputs.is_ok() {
assert_eq!(
program.hash(),
process.decoder.program_hash().into(),
"inconsistent program hash"
);
}
let (state_iterator, trace_len_summary) =
VmStateIterator::new_with_trace_len(process, stack_outputs);

(state_iterator, trace_len_summary)
}

// PROCESS
// ================================================================================================

Expand Down
18 changes: 16 additions & 2 deletions processor/src/trace/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ impl HintCycle for u64 {
/// - `range_trace_len` contains the length of the range checker trace.
/// - `chiplets_trace_len` contains the trace lengths of the all chiplets (hash, bitwise, memory,
/// kernel ROM)
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
pub struct TraceLenSummary {
main_trace_len: usize,
range_trace_len: usize,
Expand Down Expand Up @@ -297,7 +297,7 @@ impl TraceLenSummary {

/// Contains trace lengths of all chilplets: hash, bitwise, memory and kernel ROM trace
/// lengths.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
pub struct ChipletsLengths {
hash_chiplet_len: usize,
bitwise_chiplet_len: usize,
Expand All @@ -315,6 +315,20 @@ impl ChipletsLengths {
}
}

pub fn new_debug(
hash_len: usize,
bitwise_len: usize,
memory_len: usize,
kernel_len: usize,
) -> Self {
ChipletsLengths {
hash_chiplet_len: hash_len,
bitwise_chiplet_len: bitwise_len,
memory_chiplet_len: memory_len,
kernel_rom_len: kernel_len,
}
}

/// Returns the length of the hash chiplet trace
pub fn hash_chiplet_len(&self) -> usize {
self.hash_chiplet_len
Expand Down

0 comments on commit 72a0a00

Please sign in to comment.