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

Added option to print used resources for tests. #5266

Merged
merged 1 commit into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading