Skip to content

Commit

Permalink
fix: restore instruction count functionality (#3081)
Browse files Browse the repository at this point in the history
Brings back instruction counts that show that bytecode has changed
rather than VM performance. They were previously disabled because vm2
didn't support tracers.
  • Loading branch information
joonazan authored Oct 15, 2024
1 parent c60a348 commit 6159f75
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 31 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions core/tests/vm-benchmark/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ zksync_multivm.workspace = true
zksync_types.workspace = true
zksync_utils.workspace = true
zksync_vlog.workspace = true
zksync_vm2.workspace = true

criterion.workspace = true
once_cell.workspace = true
Expand Down
1 change: 1 addition & 0 deletions core/tests/vm-benchmark/benches/iai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ make_functions_and_main!(
write_and_decode => write_and_decode_legacy,
event_spam => event_spam_legacy,
slot_hash_collision => slot_hash_collision_legacy,
heap_read_write => heap_read_write_legacy,
);
31 changes: 16 additions & 15 deletions core/tests/vm-benchmark/src/bin/compare_iai_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,7 @@ fn main() {
.keys()
.collect::<HashSet<_>>()
.intersection(&iai_after.keys().collect())
.filter_map(|&name| {
let diff = percent_difference(iai_before[name], iai_after[name]);
if diff.abs() > 2. {
Some((name, format!("{:+.1}%", diff)))
} else {
None
}
})
.map(|&name| (name, percent_difference(iai_before[name], iai_after[name])))
.collect::<HashMap<_, _>>();

let duration_changes = opcodes_before
Expand All @@ -47,12 +40,17 @@ fn main() {

let mut nonzero_diff = false;

for name in perf_changes.keys().collect::<HashSet<_>>().union(
&duration_changes
.iter()
.filter_map(|(key, value)| (*value != 0).then_some(key))
.collect(),
) {
for name in perf_changes
.iter()
.filter_map(|(key, value)| (value.abs() > 2.).then_some(key))
.collect::<HashSet<_>>()
.union(
&duration_changes
.iter()
.filter_map(|(key, value)| (*value != 0).then_some(key))
.collect(),
)
{
// write the header before writing the first line of diff
if !nonzero_diff {
println!("Benchmark name | change in estimated runtime | change in number of opcodes executed \n--- | --- | ---");
Expand All @@ -63,7 +61,10 @@ fn main() {
println!(
"{} | {} | {}",
name,
perf_changes.get(**name).unwrap_or(&n_a.clone()),
perf_changes
.get(**name)
.map(|percent| format!("{:+.1}%", percent))
.unwrap_or(n_a.clone()),
duration_changes
.get(**name)
.map(|abs_diff| format!(
Expand Down
9 changes: 7 additions & 2 deletions core/tests/vm-benchmark/src/bin/instruction_counts.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
//! Runs all benchmarks and prints out the number of zkEVM opcodes each one executed.
use vm_benchmark::{BenchmarkingVm, BYTECODES};
use vm_benchmark::{BenchmarkingVmFactory, Fast, Legacy, BYTECODES};

fn main() {
for bytecode in BYTECODES {
let tx = bytecode.deploy_tx();
let name = bytecode.name;
println!("{name} {}", BenchmarkingVm::new().instruction_count(&tx));
println!("{name} {}", Fast::<()>::count_instructions(&tx));
println!(
"{} {}",
name.to_string() + "_legacy",
Legacy::count_instructions(&tx)
);
}
}
1 change: 0 additions & 1 deletion core/tests/vm-benchmark/src/instruction_counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ pub struct InstructionCounter {

/// A tracer that counts the number of instructions executed by the VM.
impl InstructionCounter {
#[allow(dead_code)] // FIXME: re-enable instruction counting once new tracers are merged
pub fn new(output: Rc<RefCell<usize>>) -> Self {
Self { count: 0, output }
}
Expand Down
58 changes: 45 additions & 13 deletions core/tests/vm-benchmark/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use zksync_multivm::{
VmExecutionResultAndLogs, VmFactory, VmInterface, VmInterfaceExt,
VmInterfaceHistoryEnabled,
},
vm_fast, vm_latest,
vm_latest::{constants::BATCH_COMPUTATIONAL_GAS_LIMIT, HistoryEnabled},
vm_fast,
vm_latest::{self, constants::BATCH_COMPUTATIONAL_GAS_LIMIT, HistoryEnabled, ToTracerPointer},
zk_evm_latest::ethereum_types::{Address, U256},
};
use zksync_types::{
Expand All @@ -20,7 +20,7 @@ use zksync_types::{
};
use zksync_utils::bytecode::hash_bytecode;

use crate::transaction::PRIVATE_KEY;
use crate::{instruction_counter::InstructionCounter, transaction::PRIVATE_KEY};

static SYSTEM_CONTRACTS: Lazy<BaseSystemContracts> = Lazy::new(BaseSystemContracts::load_from_disk);

Expand Down Expand Up @@ -72,16 +72,19 @@ pub trait BenchmarkingVmFactory {
system_env: SystemEnv,
storage: &'static InMemoryStorage,
) -> Self::Instance;

/// Counts instructions executed by the VM while processing the transaction.
fn count_instructions(tx: &Transaction) -> usize;
}

/// Factory for the new / fast VM.
#[derive(Debug)]
pub struct Fast(());
pub struct Fast<Tr = ()>(Tr);

impl BenchmarkingVmFactory for Fast {
impl<Tr: vm_fast::Tracer + Default + 'static> BenchmarkingVmFactory for Fast<Tr> {
const LABEL: VmLabel = VmLabel::Fast;

type Instance = vm_fast::Vm<&'static InMemoryStorage>;
type Instance = vm_fast::Vm<&'static InMemoryStorage, Tr>;

fn create(
batch_env: L1BatchEnv,
Expand All @@ -90,6 +93,29 @@ impl BenchmarkingVmFactory for Fast {
) -> Self::Instance {
vm_fast::Vm::custom(batch_env, system_env, storage)
}

fn count_instructions(tx: &Transaction) -> usize {
let mut vm = BenchmarkingVm::<Fast<InstructionCount>>::default();
vm.0.push_transaction(tx.clone());

#[derive(Default)]
struct InstructionCount(usize);
impl vm_fast::Tracer for InstructionCount {
fn before_instruction<
OP: zksync_vm2::interface::OpcodeType,
S: zksync_vm2::interface::StateInterface,
>(
&mut self,
_: &mut S,
) {
self.0 += 1;
}
}
let mut tracer = InstructionCount(0);

vm.0.inspect(&mut tracer, VmExecutionMode::OneTx);
tracer.0
}
}

/// Factory for the legacy VM (latest version).
Expand All @@ -109,6 +135,19 @@ impl BenchmarkingVmFactory for Legacy {
let storage = StorageView::new(storage).to_rc_ptr();
vm_latest::Vm::new(batch_env, system_env, storage)
}

fn count_instructions(tx: &Transaction) -> usize {
let mut vm = BenchmarkingVm::<Self>::default();
vm.0.push_transaction(tx.clone());
let count = Rc::new(RefCell::new(0));
vm.0.inspect(
&mut InstructionCounter::new(count.clone())
.into_tracer_pointer()
.into(),
VmExecutionMode::OneTx,
);
count.take()
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -169,13 +208,6 @@ impl<VM: BenchmarkingVmFactory> BenchmarkingVm<VM> {
}
tx_result
}

pub fn instruction_count(&mut self, tx: &Transaction) -> usize {
self.0.push_transaction(tx.clone());
let count = Rc::new(RefCell::new(0));
self.0.execute(VmExecutionMode::OneTx); // FIXME: re-enable instruction counting once new tracers are merged
count.take()
}
}

impl BenchmarkingVm<Fast> {
Expand Down

0 comments on commit 6159f75

Please sign in to comment.