Skip to content

Commit

Permalink
feat: impl cycle limit and expected memory consumption
Browse files Browse the repository at this point in the history
  • Loading branch information
Fumuran committed Jul 18, 2023
1 parent f2d9e8f commit c7bfa70
Show file tree
Hide file tree
Showing 12 changed files with 96 additions and 31 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#### VM Internals
- Simplified range checker and removed 1 main and 1 auxiliary trace column (#949).
- Added `get_mapped_values()` and `get_store_subset()` methods to the `AdviceProvider` trait (#987).
- Added options to specify maximum number of cycles and expected number of cycles for a program (#998).

## 0.6.1 (2023-06-29)

Expand Down
10 changes: 10 additions & 0 deletions air/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,14 @@ impl ExecutionOptions {
expected_cycles,
})
}

/// Returns maximum number of cycles
pub fn max_cycles(&self) -> Option<u32> {
self.max_cycles
}

/// Returns number of the expected cycles
pub fn expected_cycles(&self) -> u32 {
self.expected_cycles
}
}
2 changes: 1 addition & 1 deletion miden/src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl RunCmd {

// execute program and generate outputs
let trace = processor::execute(&program, stack_inputs, advice_provider, execution_options)
.map_err(|err| format!("Failed to generate exection trace = {:?}", err))?;
.map_err(|err| format!("Failed to generate exection trace = {:?}", err.to_string()))?;

println!("done ({} steps in {} ms)", trace.get_trace_len(), now.elapsed().as_millis());

Expand Down
7 changes: 4 additions & 3 deletions processor/src/chiplets/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
utils::get_trace_len, CodeBlock, ExecutionTrace, Kernel, MemAdviceProvider, Operation, Process,
StackInputs, Vec,
utils::get_trace_len, CodeBlock, ExecutionOptions, ExecutionTrace, Kernel, MemAdviceProvider,
Operation, Process, StackInputs, Vec,
};
use miden_air::trace::{
chiplets::{
Expand Down Expand Up @@ -112,7 +112,8 @@ fn build_trace(
) -> (ChipletsTrace, usize) {
let stack_inputs = StackInputs::try_from_values(stack_inputs.iter().copied()).unwrap();
let advice_provider = MemAdviceProvider::default();
let mut process = Process::new(kernel, stack_inputs, advice_provider);
let mut process =
Process::new(kernel, stack_inputs, advice_provider, ExecutionOptions::default());
let program = CodeBlock::new_span(operations);
process.execute_code_block(&program, &CodeBlockTable::default()).unwrap();

Expand Down
10 changes: 6 additions & 4 deletions processor/src/decoder/tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{
super::{
utils::get_trace_len, ExecutionTrace, Felt, Kernel, MemAdviceProvider, Operation, Process,
StackInputs, Word,
utils::get_trace_len, ExecutionOptions, ExecutionTrace, Felt, Kernel, MemAdviceProvider,
Operation, Process, StackInputs, Word,
},
build_op_group, AuxTraceHints, BlockHashTableRow, BlockStackTableRow, BlockTableUpdate,
ExecutionContextInfo, OpGroupTableRow, OpGroupTableUpdate,
Expand Down Expand Up @@ -1500,7 +1500,8 @@ fn set_user_op_helpers_many() {
fn build_trace(stack_inputs: &[u64], program: &CodeBlock) -> (DecoderTrace, AuxTraceHints, usize) {
let stack_inputs = StackInputs::try_from_values(stack_inputs.iter().copied()).unwrap();
let advice_provider = MemAdviceProvider::default();
let mut process = Process::new(Kernel::default(), stack_inputs, advice_provider);
let mut process =
Process::new(Kernel::default(), stack_inputs, advice_provider, ExecutionOptions::default());
process.execute_code_block(program, &CodeBlockTable::default()).unwrap();

let (trace, aux_hints) = ExecutionTrace::test_finalize_trace(process);
Expand All @@ -1527,7 +1528,8 @@ fn build_call_trace(
};
let advice_provider = MemAdviceProvider::default();
let stack_inputs = crate::StackInputs::default();
let mut process = Process::new(kernel, stack_inputs, advice_provider);
let mut process =
Process::new(kernel, stack_inputs, advice_provider, ExecutionOptions::default());

// build code block table
let mut cb_table = CodeBlockTable::default();
Expand Down
8 changes: 5 additions & 3 deletions processor/src/decorators/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{
super::{AdviceInputs, Felt, FieldElement, Kernel, Operation, StarkField},
super::{AdviceInputs, ExecutionOptions, Felt, FieldElement, Kernel, Operation, StarkField},
Process,
};
use crate::{MemAdviceProvider, StackInputs, Word};
Expand Down Expand Up @@ -30,7 +30,8 @@ fn push_merkle_node() {
let stack_inputs = StackInputs::try_from_values(stack_inputs).unwrap();
let advice_inputs = AdviceInputs::default().with_merkle_store(store);
let advice_provider = MemAdviceProvider::from(advice_inputs);
let mut process = Process::new(Kernel::default(), stack_inputs, advice_provider);
let mut process =
Process::new(Kernel::default(), stack_inputs, advice_provider, ExecutionOptions::default());
process.execute_op(Operation::Noop).unwrap();

// push the node onto the advice stack
Expand Down Expand Up @@ -185,7 +186,8 @@ fn assert_case_smtget(
.with_merkle_store(store)
.with_map([(node.into_bytes(), mapped)]);
let advice_provider = MemAdviceProvider::from(advice_inputs);
let mut process = Process::new(Kernel::default(), stack_inputs, advice_provider);
let mut process =
Process::new(Kernel::default(), stack_inputs, advice_provider, ExecutionOptions::default());

// call the injector and clear the stack
process.execute_op(Operation::Noop).unwrap();
Expand Down
4 changes: 4 additions & 0 deletions processor/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub enum ExecutionError {
AdviceStackReadFailed(u32),
CallerNotInSyscall,
CodeBlockNotFound(Digest),
CycleLimitExceeded(u32),
DivideByZero(u32),
Ext2InttError(Ext2InttError),
FailedAssertion(u32),
Expand Down Expand Up @@ -61,6 +62,9 @@ impl Display for ExecutionError {
"Failed to execute code block with root {hex}; the block could not be found"
)
}
CycleLimitExceeded(max_cycles) => {
write!(f, "Exceeded the allowed number of cycles which equals {max_cycles}")
}
DivideByZero(clk) => write!(f, "Division by zero at clock cycle {clk}"),
Ext2InttError(err) => write!(f, "Failed to execute Ext2Intt operation: {err}"),
FailedAssertion(clk) => write!(f, "Assertion failed at clock cycle {clk}"),
Expand Down
35 changes: 27 additions & 8 deletions processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,13 @@ pub fn execute<A>(
program: &Program,
stack_inputs: StackInputs,
advice_provider: A,
_options: ExecutionOptions,
options: ExecutionOptions,
) -> Result<ExecutionTrace, ExecutionError>
where
A: AdviceProvider,
{
let mut process = Process::new(program.kernel().clone(), stack_inputs, advice_provider);
// TODO: use ExecutionOptions to limit program execution
let mut process =
Process::new(program.kernel().clone(), stack_inputs, advice_provider, options);
let stack_outputs = process.execute(program)?;
let trace = ExecutionTrace::new(process, stack_outputs);
assert_eq!(&program.hash(), trace.program_hash(), "inconsistent program hash");
Expand Down Expand Up @@ -161,6 +161,7 @@ where
range: RangeChecker,
chiplets: Chiplets,
advice_provider: A,
max_cycles: Option<u32>,
}

impl<A> Process<A>
Expand All @@ -170,28 +171,35 @@ where
// CONSTRUCTORS
// --------------------------------------------------------------------------------------------
/// Creates a new process with the provided inputs.
pub fn new(kernel: Kernel, stack_inputs: StackInputs, advice_provider: A) -> Self {
Self::initialize(kernel, stack_inputs, advice_provider, false)
pub fn new(
kernel: Kernel,
stack_inputs: StackInputs,
advice_provider: A,
execution_options: ExecutionOptions,
) -> Self {
Self::initialize(kernel, stack_inputs, advice_provider, false, execution_options)
}

/// Creates a new process with provided inputs and debug options enabled.
pub fn new_debug(kernel: Kernel, stack_inputs: StackInputs, advice_provider: A) -> Self {
Self::initialize(kernel, stack_inputs, advice_provider, true)
Self::initialize(kernel, stack_inputs, advice_provider, true, ExecutionOptions::default())
}

fn initialize(
kernel: Kernel,
stack: StackInputs,
advice_provider: A,
in_debug_mode: bool,
execution_options: ExecutionOptions,
) -> Self {
Self {
system: System::new(MIN_TRACE_LEN),
system: System::new(execution_options.expected_cycles() as usize),
decoder: Decoder::new(in_debug_mode),
stack: Stack::new(&stack, MIN_TRACE_LEN, in_debug_mode),
stack: Stack::new(&stack, execution_options.expected_cycles() as usize, in_debug_mode),
range: RangeChecker::new(),
chiplets: Chiplets::new(kernel),
advice_provider,
max_cycles: execution_options.max_cycles(),
}
}

Expand All @@ -218,6 +226,7 @@ where
block: &CodeBlock,
cb_table: &CodeBlockTable,
) -> Result<(), ExecutionError> {
self.check_cycles_limit()?;
match block {
CodeBlock::Join(block) => self.execute_join_block(block, cb_table),
CodeBlock::Split(block) => self.execute_split_block(block, cb_table),
Expand Down Expand Up @@ -346,6 +355,7 @@ where
op_offset += op_batch.ops().len();
}

self.check_cycles_limit()?;
self.end_span_block(block)
}

Expand Down Expand Up @@ -436,6 +446,14 @@ where
Ok(())
}

fn check_cycles_limit(&self) -> Result<(), ExecutionError> {
if self.max_cycles.is_some_and(|max_cycles| self.system.clk() > max_cycles) {
Err(ExecutionError::CycleLimitExceeded(self.max_cycles.unwrap()))
} else {
Ok(())
}
}

// PUBLIC ACCESSORS
// --------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -473,4 +491,5 @@ where
pub range: RangeChecker,
pub chiplets: Chiplets,
pub advice_provider: A,
pub max_cycles: Option<u32>,
}
21 changes: 18 additions & 3 deletions processor/src/operations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,12 @@ impl Process<super::MemAdviceProvider> {
/// initialized with the provided values.
fn new_dummy(stack_inputs: super::StackInputs) -> Self {
let advice_provider = super::MemAdviceProvider::default();
let mut process = Self::new(Kernel::default(), stack_inputs, advice_provider);
let mut process = Self::new(
Kernel::default(),
stack_inputs,
advice_provider,
super::ExecutionOptions::default(),
);
process.execute_op(Operation::Noop).unwrap();
process
}
Expand All @@ -196,7 +201,12 @@ impl Process<super::MemAdviceProvider> {
.with_stack_values(advice_stack.iter().copied())
.unwrap();
let advice_provider = super::MemAdviceProvider::from(advice_inputs);
let mut process = Self::new(Kernel::default(), stack_inputs, advice_provider);
let mut process = Self::new(
Kernel::default(),
stack_inputs,
advice_provider,
super::ExecutionOptions::default(),
);
process.execute_op(Operation::Noop).unwrap();
process
}
Expand Down Expand Up @@ -224,7 +234,12 @@ impl Process<super::MemAdviceProvider> {
advice_inputs: super::AdviceInputs,
) -> Self {
let advice_provider = super::MemAdviceProvider::from(advice_inputs);
let mut process = Self::new(Kernel::default(), stack_inputs, advice_provider);
let mut process = Self::new(
Kernel::default(),
stack_inputs,
advice_provider,
super::ExecutionOptions::default(),
);
process.decoder.add_dummy_trace_row();
process.execute_op(Operation::Noop).unwrap();
process
Expand Down
8 changes: 5 additions & 3 deletions processor/src/trace/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::{
super::chiplets::init_state_from_words, ExecutionTrace, Felt, FieldElement, LookupTableRow,
Process, Trace, Vec, NUM_RAND_ROWS,
};
use crate::{AdviceInputs, MemAdviceProvider, StackInputs};
use crate::{AdviceInputs, ExecutionOptions, MemAdviceProvider, StackInputs};
use rand_utils::rand_array;
use vm_core::{
code_blocks::CodeBlock, CodeBlockTable, Kernel, Operation, StackOutputs, Word, ONE, ZERO,
Expand All @@ -20,7 +20,8 @@ mod stack;
pub fn build_trace_from_block(program: &CodeBlock, stack_inputs: &[u64]) -> ExecutionTrace {
let stack_inputs = StackInputs::try_from_values(stack_inputs.iter().copied()).unwrap();
let advice_provider = MemAdviceProvider::default();
let mut process = Process::new(Kernel::default(), stack_inputs, advice_provider);
let mut process =
Process::new(Kernel::default(), stack_inputs, advice_provider, ExecutionOptions::default());
process.execute_code_block(program, &CodeBlockTable::default()).unwrap();
ExecutionTrace::new(process, StackOutputs::default())
}
Expand All @@ -41,7 +42,8 @@ pub fn build_trace_from_ops_with_inputs(
advice_inputs: AdviceInputs,
) -> ExecutionTrace {
let advice_provider = MemAdviceProvider::from(advice_inputs);
let mut process = Process::new(Kernel::default(), stack_inputs, advice_provider);
let mut process =
Process::new(Kernel::default(), stack_inputs, advice_provider, ExecutionOptions::default());
let program = CodeBlock::new_span(operations);
process.execute_code_block(&program, &CodeBlockTable::default()).unwrap();
ExecutionTrace::new(process, StackOutputs::default())
Expand Down
5 changes: 3 additions & 2 deletions stdlib/tests/mem/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use test_utils::{
build_expected_hash, build_expected_perm, stack_to_ints, AdviceInputs, MemAdviceProvider,
Process, StackInputs, ONE, ZERO,
build_expected_hash, build_expected_perm, stack_to_ints, AdviceInputs, ExecutionOptions,
MemAdviceProvider, Process, StackInputs, ONE, ZERO,
};

#[test]
Expand Down Expand Up @@ -31,6 +31,7 @@ fn test_memcopy() {
program.kernel().clone(),
StackInputs::default(),
MemAdviceProvider::from(AdviceInputs::default()),
ExecutionOptions::default(),
);
process.execute(&program).unwrap();

Expand Down
16 changes: 12 additions & 4 deletions test-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,12 @@ impl Test {
let advice_provider = MemAdviceProvider::from(self.advice_inputs.clone());

// execute the test
let mut process =
Process::new(program.kernel().clone(), self.stack_inputs.clone(), advice_provider);
let mut process = Process::new(
program.kernel().clone(),
self.stack_inputs.clone(),
advice_provider,
ExecutionOptions::default(),
);
process.execute(&program).unwrap();

// validate the memory state
Expand Down Expand Up @@ -236,8 +240,12 @@ impl Test {
pub fn execute_process(&self) -> Result<Process<MemAdviceProvider>, ExecutionError> {
let program = self.compile();
let advice_provider = MemAdviceProvider::from(self.advice_inputs.clone());
let mut process =
Process::new(program.kernel().clone(), self.stack_inputs.clone(), advice_provider);
let mut process = Process::new(
program.kernel().clone(),
self.stack_inputs.clone(),
advice_provider,
ExecutionOptions::default(),
);
process.execute(&program)?;
Ok(process)
}
Expand Down

0 comments on commit c7bfa70

Please sign in to comment.