Skip to content

Commit

Permalink
Added option to print used resources for tests.
Browse files Browse the repository at this point in the history
commit-id:008454fd

fixup! Added option to print used resources for tests.
  • Loading branch information
orizi committed Mar 21, 2024
1 parent 6dd3b32 commit ffc962c
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 64 deletions.
4 changes: 4 additions & 0 deletions crates/bin/cairo-test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ struct Args {
/// Should disable gas calculation.
#[arg(long)]
gas_disabled: bool,
/// Whether to print resource usage after each test.
#[arg(long, default_value_t = false)]
print_resource_usage: bool,
}

fn main() -> anyhow::Result<()> {
Expand All @@ -73,6 +76,7 @@ fn main() -> anyhow::Result<()> {
include_ignored: args.include_ignored,
run_profiler: args.run_profiler.into(),
gas_enabled: !args.gas_disabled,
print_resource_usage: args.print_resource_usage,
};

let runner = TestRunner::new(&args.path, args.starknet, args.allow_warnings, config)?;
Expand Down
49 changes: 34 additions & 15 deletions crates/cairo-lang-runner/src/casm_run/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ use cairo_vm::vm::errors::cairo_run_errors::CairoRunError;
use cairo_vm::vm::errors::hint_errors::HintError;
use cairo_vm::vm::errors::memory_errors::MemoryError;
use cairo_vm::vm::errors::vm_errors::VirtualMachineError;
use cairo_vm::vm::runners::cairo_runner::{CairoRunner, ResourceTracker, RunResources};
use cairo_vm::vm::runners::cairo_runner::{
CairoRunner, ExecutionResources, ResourceTracker, RunResources,
};
use cairo_vm::vm::vm_core::VirtualMachine;
use dict_manager::DictManagerExecScope;
use itertools::Itertools;
Expand All @@ -41,7 +43,7 @@ use {ark_secp256k1 as secp256k1, ark_secp256r1 as secp256r1};
use self::contract_address::calculate_contract_address;
use self::dict_manager::DictSquashExecScope;
use crate::short_string::{as_cairo_short_string, as_cairo_short_string_ex};
use crate::{Arg, RunResultValue, SierraCasmRunner};
use crate::{Arg, RunResultValue, SierraCasmRunner, StarknetExecutionResources};

#[cfg(test)]
mod test;
Expand Down Expand Up @@ -92,14 +94,16 @@ struct Secp256r1ExecutionScope {
/// HintProcessor for Cairo compiler hints.
pub struct CairoHintProcessor<'a> {
/// The Cairo runner.
#[allow(dead_code)]
pub runner: Option<&'a SierraCasmRunner>,
// A mapping from a string that represents a hint to the hint object.
/// A mapping from a string that represents a hint to the hint object.
pub string_to_hint: HashMap<String, Hint>,
// The starknet state.
/// The starknet state.
pub starknet_state: StarknetState,
// Maintains the resources of the run.
/// Maintains the resources of the run.
pub run_resources: RunResources,
/// Resources used during syscalls - does not include resources used during the current VM run.
/// At the end of the run - adding both would result in the actual expected resource usage.
pub syscalls_used_resources: StarknetExecutionResources,
}

pub fn cell_ref_to_relocatable(cell_ref: &CellRef, vm: &VirtualMachine) -> Relocatable {
Expand Down Expand Up @@ -131,7 +135,6 @@ pub struct StarknetState {
/// The values of addresses in the simulated storage per contract.
storage: HashMap<Felt252, HashMap<Felt252, Felt252>>,
/// A mapping from contract address to class hash.
#[allow(dead_code)]
deployed_contracts: HashMap<Felt252, Felt252>,
/// A mapping from contract address to logs.
logs: HashMap<Felt252, ContractLogs>,
Expand Down Expand Up @@ -651,7 +654,9 @@ impl<'a> CairoHintProcessor<'a> {
}
Ok(())
};
match std::str::from_utf8(&selector).unwrap() {
let selector = std::str::from_utf8(&selector).unwrap();
*self.syscalls_used_resources.syscalls.entry(selector.into()).or_default() += 1;
match selector {
"StorageWrite" => execute_handle_helper(&mut |system_buffer, gas_counter| {
self.storage_write(
gas_counter,
Expand Down Expand Up @@ -1117,7 +1122,7 @@ impl<'a> CairoHintProcessor<'a> {
self.starknet_state.clone(),
)
.expect("Internal runner error.");

self.syscalls_used_resources += res.used_resources;
*gas_counter = res.gas_counter.unwrap().to_usize().unwrap();
match res.value {
RunResultValue::Success(value) => {
Expand Down Expand Up @@ -2085,8 +2090,6 @@ pub struct RunFunctionContext<'a> {
pub data_len: usize,
}

type RunFunctionRes = (Vec<Option<Felt252>>, usize);

/// Runs CairoRunner on layout with prime.
/// Allows injecting custom CairoRunner.
pub fn run_function_with_runner(
Expand Down Expand Up @@ -2128,7 +2131,17 @@ pub fn build_cairo_runner(
CairoRunner::new(&program, "all_cairo", false).map_err(CairoRunError::from).map_err(Box::new)
}

/// Runs `bytecode` on layout with prime, and returns the memory layout and ap value.
/// The result of [run_function].
pub struct RunFunctionResult {
/// The memory layout after the run.
pub memory: Vec<Option<Felt252>>,
/// The ap value after the run.
pub ap: usize,
/// The used resources after the run.
pub used_resources: ExecutionResources,
}

/// Runs `bytecode` on layout with prime, and returns the matching [RunFunctionResult].
/// Allows injecting custom HintProcessor.
pub fn run_function<'a, 'b: 'a>(
vm: &mut VirtualMachine,
Expand All @@ -2139,15 +2152,21 @@ pub fn run_function<'a, 'b: 'a>(
) -> Result<(), Box<CairoRunError>>,
hint_processor: &mut dyn HintProcessor,
hints_dict: HashMap<usize, Vec<HintParams>>,
) -> Result<RunFunctionRes, Box<CairoRunError>> {
) -> Result<RunFunctionResult, Box<CairoRunError>> {
let data: Vec<MaybeRelocatable> =
bytecode.map(Felt252::from).map(MaybeRelocatable::from).collect();
let data_len = data.len();
let mut runner = build_cairo_runner(data, builtins, hints_dict)?;

run_function_with_runner(vm, data_len, additional_initialization, hint_processor, &mut runner)?;

Ok((runner.relocated_memory, vm.get_relocated_trace().unwrap().last().unwrap().ap))
let used_resources = runner
.get_execution_resources(vm)
.expect("Failed to get execution resources, but the run was successful.");
Ok(RunFunctionResult {
memory: runner.relocated_memory,
ap: vm.get_relocated_trace().unwrap().last().unwrap().ap,
used_resources,
})
}

/// Formats the given felts as a debug string.
Expand Down
12 changes: 7 additions & 5 deletions crates/cairo-lang-runner/src/casm_run/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use test_case::test_case;

use super::format_for_debug;
use crate::casm_run::contract_address::calculate_contract_address;
use crate::casm_run::run_function;
use crate::casm_run::{run_function, RunFunctionResult};
use crate::short_string::{as_cairo_short_string, as_cairo_short_string_ex};
use crate::{build_hints_dict, CairoHintProcessor, StarknetState};

Expand Down Expand Up @@ -116,14 +116,15 @@ fn test_runner(function: CasmContext, n_returns: usize, expected: &[i128]) {
string_to_hint,
starknet_state: StarknetState::default(),
run_resources: RunResources::default(),
syscalls_used_resources: Default::default(),
};
let bytecode: Vec<BigInt> = function
.instructions
.iter()
.flat_map(|instruction| instruction.assemble().encode())
.collect();

let (cells, ap) = run_function(
let RunFunctionResult { memory, ap, .. } = run_function(
&mut VirtualMachine::new(true),
bytecode.iter(),
vec![],
Expand All @@ -132,9 +133,9 @@ fn test_runner(function: CasmContext, n_returns: usize, expected: &[i128]) {
hints_dict,
)
.expect("Running code failed.");
let cells = cells.into_iter().skip(ap - n_returns);
let ret_memory = memory.into_iter().skip(ap - n_returns);
assert_eq!(
cells.take(n_returns).map(|cell| cell.unwrap()).collect_vec(),
ret_memory.take(n_returns).map(|cell| cell.unwrap()).collect_vec(),
expected.iter().copied().map(Felt252::from).collect_vec()
);
}
Expand All @@ -154,11 +155,12 @@ fn test_allocate_segment() {
string_to_hint,
starknet_state: StarknetState::default(),
run_resources: RunResources::default(),
syscalls_used_resources: Default::default(),
};
let bytecode: Vec<BigInt> =
casm.instructions.iter().flat_map(|instruction| instruction.assemble().encode()).collect();

let (memory, ap) = run_function(
let RunFunctionResult { memory, ap, .. } = run_function(
&mut VirtualMachine::new(true),
bytecode.iter(),
vec![],
Expand Down
53 changes: 40 additions & 13 deletions crates/cairo-lang-runner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use cairo_lang_utils::unordered_hash_map::UnorderedHashMap;
use cairo_vm::hint_processor::hint_processor_definition::HintProcessor;
use cairo_vm::serde::deserialize_program::{BuiltinName, HintParams};
use cairo_vm::vm::errors::cairo_run_errors::CairoRunError;
use cairo_vm::vm::runners::cairo_runner::RunResources;
use cairo_vm::vm::runners::cairo_runner::{ExecutionResources, RunResources};
use cairo_vm::vm::trace::trace_entry::TraceEntry;
use cairo_vm::vm::vm_core::VirtualMachine;
use casm_run::hint_to_hint_params;
Expand All @@ -45,7 +45,7 @@ use num_traits::ToPrimitive;
use profiling::{user_function_idx_by_sierra_statement_idx, ProfilingInfo};
use thiserror::Error;

use crate::casm_run::RunFunctionContext;
use crate::casm_run::{RunFunctionContext, RunFunctionResult};

pub mod casm_run;
pub mod profiling;
Expand Down Expand Up @@ -85,6 +85,7 @@ pub struct RunResultStarknet {
pub memory: Vec<Option<Felt252>>,
pub value: RunResultValue,
pub starknet_state: StarknetState,
pub used_resources: StarknetExecutionResources,
/// The profiling info of the run, if requested.
pub profiling_info: Option<ProfilingInfo>,
}
Expand All @@ -95,10 +96,31 @@ pub struct RunResult {
pub gas_counter: Option<Felt252>,
pub memory: Vec<Option<Felt252>>,
pub value: RunResultValue,
pub used_resources: ExecutionResources,
/// The profiling info of the run, if requested.
pub profiling_info: Option<ProfilingInfo>,
}

/// The execution resources in a run.
/// Extends [ExecutionResources] by including the used syscalls for starknet.
#[derive(Debug, Eq, PartialEq, Clone, Default)]
pub struct StarknetExecutionResources {
/// The basic execution resources.
pub basic_resources: ExecutionResources,
/// The used syscalls.
pub syscalls: HashMap<String, usize>,
}

impl std::ops::AddAssign<StarknetExecutionResources> for StarknetExecutionResources {
/// Adds the resources of `other` to `self`.
fn add_assign(&mut self, other: Self) {
self.basic_resources += &other.basic_resources;
for (k, v) in other.syscalls {
*self.syscalls.entry(k).or_default() += v;
}
}
}

/// The ran function return value.
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum RunResultValue {
Expand Down Expand Up @@ -226,19 +248,24 @@ impl SierraCasmRunner {
starknet_state,
string_to_hint,
run_resources: RunResources::default(),
syscalls_used_resources: Default::default(),
};
let RunResult { gas_counter, memory, value, profiling_info } = self.run_function(
func,
&mut hint_processor,
hints_dict,
assembled_program.bytecode.iter(),
builtins,
)?;
let RunResult { gas_counter, memory, value, used_resources, profiling_info } = self
.run_function(
func,
&mut hint_processor,
hints_dict,
assembled_program.bytecode.iter(),
builtins,
)?;
let mut all_used_resources = hint_processor.syscalls_used_resources;
all_used_resources.basic_resources += &used_resources;
Ok(RunResultStarknet {
gas_counter,
memory,
value,
starknet_state: hint_processor.starknet_state,
used_resources: all_used_resources,
profiling_info,
})
}
Expand All @@ -262,15 +289,15 @@ impl SierraCasmRunner {
{
let return_types = self.generic_id_and_size_from_concrete(&func.signature.ret_types);

let (cells, ap) = casm_run::run_function(
let RunFunctionResult { memory, ap, used_resources } = casm_run::run_function(
vm,
bytecode,
builtins,
initialize_vm,
hint_processor,
hints_dict,
)?;
let (results_data, gas_counter) = Self::get_results_data(&return_types, &cells, ap);
let (results_data, gas_counter) = Self::get_results_data(&return_types, &memory, ap);
assert!(results_data.len() <= 1);

let value = if results_data.is_empty() {
Expand All @@ -280,14 +307,14 @@ impl SierraCasmRunner {
let (ty, values) = results_data[0].clone();
let inner_ty =
self.inner_type_from_panic_wrapper(&ty, func).map(|it| self.type_sizes[&it]);
Self::handle_main_return_value(inner_ty, values, &cells)
Self::handle_main_return_value(inner_ty, values, &memory)
};

let profiling_info = self.run_profiler.as_ref().map(|config| {
self.collect_profiling_info(vm.get_relocated_trace().unwrap(), config.clone())
});

Ok(RunResult { gas_counter, memory: cells, value, profiling_info })
Ok(RunResult { gas_counter, memory, value, used_resources, profiling_info })
}

/// Collects profiling info of the current run using the trace.
Expand Down
Loading

0 comments on commit ffc962c

Please sign in to comment.