Skip to content

Commit

Permalink
feat: Builder pattern for VirtualMachine (#820)
Browse files Browse the repository at this point in the history
  • Loading branch information
zarboq authored Feb 24, 2023
1 parent 763fc5f commit 71e7140
Showing 1 changed file with 217 additions and 0 deletions.
217 changes: 217 additions & 0 deletions src/vm/vm_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,125 @@ impl VirtualMachine {
}
}

pub struct VirtualMachineBuilder {
pub(crate) run_context: RunContext,
pub(crate) builtin_runners: Vec<(&'static str, BuiltinRunner)>,
pub(crate) segments: MemorySegmentManager,
pub(crate) _program_base: Option<MaybeRelocatable>,
pub(crate) accessed_addresses: Option<Vec<Relocatable>>,
pub(crate) trace: Option<Vec<TraceEntry>>,
pub(crate) current_step: usize,
skip_instruction_execution: bool,
run_finished: bool,
#[cfg(feature = "hooks")]
pub(crate) hooks: crate::vm::hooks::Hooks,
}

impl Default for VirtualMachineBuilder {
fn default() -> Self {
let run_context = RunContext {
pc: Relocatable::from((0, 0)),
ap: 0,
fp: 0,
};

VirtualMachineBuilder {
run_context,
builtin_runners: Vec::new(),
_program_base: None,
accessed_addresses: Some(Vec::new()),
trace: None,
current_step: 0,
skip_instruction_execution: false,
segments: MemorySegmentManager::new(),
run_finished: false,
#[cfg(feature = "hooks")]
hooks: Default::default(),
}
}
}

impl VirtualMachineBuilder {
pub fn run_context(mut self, run_context: RunContext) -> VirtualMachineBuilder {
self.run_context = run_context;
self
}

pub fn builtin_runners(
mut self,
builtin_runners: Vec<(&'static str, BuiltinRunner)>,
) -> VirtualMachineBuilder {
self.builtin_runners = builtin_runners;
self
}

pub fn segments(mut self, segments: MemorySegmentManager) -> VirtualMachineBuilder {
self.segments = segments;
self
}

pub fn _program_base(
mut self,
_program_base: Option<MaybeRelocatable>,
) -> VirtualMachineBuilder {
self._program_base = _program_base;
self
}

pub fn accessed_addresses(
mut self,
accessed_addresses: Option<Vec<Relocatable>>,
) -> VirtualMachineBuilder {
self.accessed_addresses = accessed_addresses;
self
}

pub fn trace(mut self, trace: Option<Vec<TraceEntry>>) -> VirtualMachineBuilder {
self.trace = trace;
self
}

pub fn current_step(mut self, current_step: usize) -> VirtualMachineBuilder {
self.current_step = current_step;
self
}

pub fn skip_instruction_execution(
mut self,
skip_instruction_execution: bool,
) -> VirtualMachineBuilder {
self.skip_instruction_execution = skip_instruction_execution;
self
}

pub fn run_finished(mut self, run_finished: bool) -> VirtualMachineBuilder {
self.run_finished = run_finished;
self
}

#[cfg(feature = "hooks")]
pub fn hooks(mut self, hooks: crate::vm::hooks::Hooks) -> VirtualMachineBuilder {
self.hooks = hooks;
self
}

pub fn build(self) -> VirtualMachine {
VirtualMachine {
run_context: self.run_context,
builtin_runners: self.builtin_runners,
_program_base: self._program_base,
accessed_addresses: self.accessed_addresses,
trace: self.trace,
current_step: self.current_step,
skip_instruction_execution: self.skip_instruction_execution,
segments: self.segments,
run_finished: self.run_finished,
#[cfg(feature = "hooks")]
hooks: self.hooks,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -3984,4 +4103,102 @@ mod tests {
let expected_traceback = vec![(Relocatable::from((1, 2)), Relocatable::from((0, 34)))];
assert_eq!(vm.get_traceback_entries(), expected_traceback);
}

#[test]
fn builder_test() {
let virtual_machine_builder: VirtualMachineBuilder = VirtualMachineBuilder::default()
.run_finished(true)
.current_step(12)
._program_base(Some(MaybeRelocatable::from((1, 0))))
.accessed_addresses(Some(vec![Relocatable::from((1, 0))]))
.builtin_runners(vec![(
"string",
BuiltinRunner::from(HashBuiltinRunner::new(12, true)),
)])
.run_context(RunContext {
pc: Relocatable::from((0, 0)),
ap: 18,
fp: 0,
})
.segments(MemorySegmentManager {
segment_sizes: HashMap::new(),
segment_used_sizes: Some(vec![1]),
public_memory_offsets: HashMap::new(),
memory: Memory::new(),
})
.skip_instruction_execution(true)
.trace(Some(vec![TraceEntry {
pc: Relocatable::from((0, 1)),
ap: Relocatable::from((0, 1)),
fp: Relocatable::from((0, 1)),
}]));

#[cfg(feature = "hooks")]
fn before_first_step_hook(
_vm: &mut VirtualMachine,
_runner: &mut CairoRunner,
_hint_data: &HashMap<usize, Vec<Box<dyn Any>>>,
) -> Result<(), VirtualMachineError> {
Err(VirtualMachineError::Unexpected)
}
#[cfg(feature = "hooks")]
let virtual_machine_builder = virtual_machine_builder.hooks(crate::vm::hooks::Hooks::new(
Some(std::sync::Arc::new(before_first_step_hook)),
None,
None,
));

#[allow(unused_mut)]
let mut virtual_machine_from_builder = virtual_machine_builder.build();

assert!(virtual_machine_from_builder.run_finished);
assert_eq!(virtual_machine_from_builder.current_step, 12);
assert_eq!(
virtual_machine_from_builder._program_base,
Some(MaybeRelocatable::from((1, 0)))
);
assert_eq!(
virtual_machine_from_builder.accessed_addresses,
Some(vec![Relocatable::from((1, 0))])
);
assert_eq!(
virtual_machine_from_builder
.builtin_runners
.get(0)
.unwrap()
.0,
"string"
);
assert_eq!(virtual_machine_from_builder.run_context.ap, 18,);
assert_eq!(
virtual_machine_from_builder.segments.segment_used_sizes,
Some(vec![1])
);
assert!(virtual_machine_from_builder.skip_instruction_execution,);
assert_eq!(
virtual_machine_from_builder.trace,
Some(vec![TraceEntry {
pc: Relocatable::from((0, 1)),
ap: Relocatable::from((0, 1)),
fp: Relocatable::from((0, 1)),
}])
);
#[cfg(feature = "hooks")]
{
let program = crate::types::program::Program::from_file(
Path::new("cairo_programs/sqrt.json"),
Some("main"),
)
.expect("Call to `Program::from_file()` failed.");
let mut hint_processor = BuiltinHintProcessor::new_empty();
let mut cairo_runner = cairo_runner!(program);
let end = cairo_runner
.initialize(&mut virtual_machine_from_builder)
.unwrap();

assert!(cairo_runner
.run_until_pc(end, &mut virtual_machine_from_builder, &mut hint_processor)
.is_err());
}
}
}

1 comment on commit 71e7140

@github-actions
Copy link

Choose a reason for hiding this comment

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

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.30.

Benchmark suite Current: 71e7140 Previous: e0da0be Ratio
cairo_run(cairo_programs/benchmarks/compare_arrays_200000.json) 915580407 ns/iter (± 29298847) 679075211 ns/iter (± 4518942) 1.35
cairo_run(cairo_programs/benchmarks/factorial_multirun.json) 362886089 ns/iter (± 7906951) 262715534 ns/iter (± 751131) 1.38
cairo_run(cairo_programs/benchmarks/fibonacci_1000_multirun.json) 169002694 ns/iter (± 5061800) 122743185 ns/iter (± 506308) 1.38
cairo_run(cairo_programs/benchmarks/integration_builtins.json) 568048486 ns/iter (± 12310215) 404425906 ns/iter (± 3085464) 1.40
cairo_run(cairo_programs/benchmarks/linear_search.json) 112784748 ns/iter (± 3573876) 85174238 ns/iter (± 707366) 1.32
cairo_run(cairo_programs/benchmarks/keccak_integration_benchmark.json) 1788646291 ns/iter (± 45209626) 1275722268 ns/iter (± 7596995) 1.40
cairo_run(cairo_programs/benchmarks/secp_integration_benchmark.json) 2079687651 ns/iter (± 44415059) 1388857805 ns/iter (± 5092586) 1.50
cairo_run(cairo_programs/benchmarks/blake2s_integration_benchmark.json) 1620166255 ns/iter (± 44841011) 1119410296 ns/iter (± 5165122) 1.45
cairo_run(cairo_programs/benchmarks/dict_integration_benchmark.json) 1059970270 ns/iter (± 40622492) 791432561 ns/iter (± 3919292) 1.34
cairo_run(cairo_programs/benchmarks/math_integration_benchmark.json) 533005204 ns/iter (± 20954076) 398582202 ns/iter (± 1519462) 1.34
cairo_run(cairo_programs/benchmarks/operations_with_data_structures_benchmarks.json) 2396042184 ns/iter (± 69220520) 1707329950 ns/iter (± 11621990) 1.40
cairo_run(cairo_programs/benchmarks/uint256_integration_benchmark.json) 1610982793 ns/iter (± 70208602) 1141417850 ns/iter (± 7327105) 1.41
cairo_run(cairo_programs/benchmarks/set_integration_benchmark.json) 205146391 ns/iter (± 6480202) 149673105 ns/iter (± 825963) 1.37

This comment was automatically generated by workflow using github-action-benchmark.

CC: @unbalancedparentheses

Please sign in to comment.