Skip to content
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
2 changes: 1 addition & 1 deletion third_party/move/mono-move/core/src/instruction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ impl std::fmt::Display for DescriptorId {
}
}

#[derive(Debug)]
#[derive(Copy, Clone, Debug)]
pub enum MicroOp {
//======================================================================
// Data movement
Expand Down
13 changes: 13 additions & 0 deletions third_party/move/mono-move/gas/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,19 @@ impl GasMeter for SimpleGasMeter {
}
}

/// A no-op gas meter for testing.
pub struct NoOpGasMeter;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[LOW] NoOpGasMeter is exported as a top-level pub struct with no #[cfg(test)] or feature gate. Since InterpreterContext is generic over G: GasMeter, this type is silently usable in any execution context. The doc comment says "for testing" but there is no compile-time enforcement. Consider #[cfg(any(test, feature = "testing"))], consistent with the pattern already used in programs/src/lib.rs.


impl GasMeter for NoOpGasMeter {
fn charge(&mut self, _amount: u64) -> Result<(), GasExhaustedError> {
Ok(())
}

fn balance(&self) -> u64 {
u64::MAX
}
}

// ---------------------------------------------------------------------------
// Gas schedule
// ---------------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions third_party/move/mono-move/programs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,7 @@ harness = false
[[bench]]
name = "bst"
harness = false

[[bench]]
name = "match_sum"
harness = false
31 changes: 30 additions & 1 deletion third_party/move/mono-move/programs/benches/bst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
// Licensed pursuant to the Innovation-Enabling Source Code License, available at https://github.com/aptos-labs/aptos-core/blob/main/LICENSE

use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion};
use mono_move_gas::NoOpGasMeter;

#[path = "helpers.rs"]
mod helpers;

const N_OPS: u64 = 5000;
const KEY_RANGE: u64 = 2500;
Expand All @@ -28,15 +32,39 @@ fn bench_bst(c: &mut Criterion) {
b.iter(|| native_run_ops(black_box(&ops)));
});

// plain (no gas instrumentation)
let (functions, descriptors, _arena) = micro_op_bst();
// SAFETY: Exclusive access during bench setup; arena is alive.
unsafe { mono_move_core::Function::resolve_calls(&functions) };
group.bench_function("micro_op", |b| {
b.iter_batched(
|| {
let mut ctx = InterpreterContext::new(&descriptors, NoOpGasMeter, unsafe {
functions[6].unwrap().as_ref_unchecked()
});
let vec_ptr = ctx
.alloc_u64_vec(mono_move_core::DescriptorId(0), &ops)
.unwrap();
ctx.set_root_arg(0, &vec_ptr.to_le_bytes());
ctx
},
|mut ctx| ctx.run().unwrap(),
BatchSize::SmallInput,
);
});

// with gas instrumentation
let (functions, _, _arena) = micro_op_bst();
// SAFETY: Exclusive access during bench setup; arena is alive.
let (functions_gas, _arena) = unsafe { helpers::gas_instrument(&functions) };
// SAFETY: Exclusive access during bench setup; arena is alive.
unsafe { mono_move_core::Function::resolve_calls(&functions_gas) };
group.bench_function("micro_op/gas", |b| {
b.iter_batched(
|| {
let gas_meter = SimpleGasMeter::new(u64::MAX);
let mut ctx = InterpreterContext::new(&descriptors, gas_meter, unsafe {
functions[6].unwrap().as_ref_unchecked()
functions_gas[6].unwrap().as_ref_unchecked()
});
let vec_ptr = ctx
.alloc_u64_vec(mono_move_core::DescriptorId(0), &ops)
Expand All @@ -48,6 +76,7 @@ fn bench_bst(c: &mut Criterion) {
BatchSize::SmallInput,
);
});

group.finish();
}

Expand Down
32 changes: 30 additions & 2 deletions third_party/move/mono-move/programs/benches/fib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@

use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion};

#[path = "helpers.rs"]
mod helpers;

const N: u64 = 25;

fn bench_fib(c: &mut Criterion) {
use mono_move_gas::SimpleGasMeter;
use mono_move_gas::{NoOpGasMeter, SimpleGasMeter};
use mono_move_programs::{
fib::{micro_op_fib, move_bytecode_fib, native_fib},
testing,
Expand All @@ -24,15 +27,39 @@ fn bench_fib(c: &mut Criterion) {
b.iter(|| black_box(native_fib(N)));
});

// plain (no gas instrumentation)
let (functions, descriptors, _arena) = micro_op_fib();
// SAFETY: Exclusive access during bench setup; arena is alive.
unsafe { mono_move_core::Function::resolve_calls(&functions) };
group.bench_function("micro_op", |b| {
b.iter_batched(
|| {
let mut ctx = InterpreterContext::new(&descriptors, NoOpGasMeter, unsafe {
functions[0].unwrap().as_ref_unchecked()
});
ctx.set_root_arg(0, &N.to_le_bytes());
ctx
},
|mut ctx| {
ctx.run().unwrap();
black_box(ctx.root_result())
},
BatchSize::SmallInput,
);
});

// with gas instrumentation
let (functions, _, _arena) = micro_op_fib();
// SAFETY: Exclusive access during bench setup; arena is alive.
let (functions_gas, _arena) = unsafe { helpers::gas_instrument(&functions) };
// SAFETY: Exclusive access during bench setup; arena is alive.
unsafe { mono_move_core::Function::resolve_calls(&functions_gas) };
group.bench_function("micro_op/gas", |b| {
b.iter_batched(
|| {
let gas_meter = SimpleGasMeter::new(u64::MAX);
let mut ctx = InterpreterContext::new(&descriptors, gas_meter, unsafe {
functions[0].unwrap().as_ref_unchecked()
functions_gas[0].unwrap().as_ref_unchecked()
});
ctx.set_root_arg(0, &N.to_le_bytes());
ctx
Expand All @@ -44,6 +71,7 @@ fn bench_fib(c: &mut Criterion) {
BatchSize::SmallInput,
);
});

group.finish();
}

Expand Down
54 changes: 54 additions & 0 deletions third_party/move/mono-move/programs/benches/helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) Aptos Foundation
// Licensed pursuant to the Innovation-Enabling Source Code License, available at https://github.com/aptos-labs/aptos-core/blob/main/LICENSE

//! Shared bench helpers. Included via `#[path = "helpers.rs"] mod helpers;`
//! in each bench binary. Not listed as a `[[bench]]` target, so it is never
//! compiled standalone.

use mono_move_alloc::{ExecutableArena, ExecutableArenaPtr};
use mono_move_core::{FrameLayoutInfo, Function, MicroOpGasSchedule, SortedSafePointEntries};
use mono_move_gas::GasInstrumentor;

/// Build a gas-instrumented copy of `func_ptrs`, re-allocated in a fresh arena.
///
/// The caller should build the program fresh (without calling
/// `Function::resolve_calls`) before passing it here, so the code still
/// contains `CallFunc` (index-based) ops. After this call, invoke
/// `Function::resolve_calls` on the returned table to patch those ops to
/// direct pointers into the instrumented arena.
///
/// Frame layouts are re-created as empty; these benchmark programs do not
/// trigger GC, so the omission has no effect on execution.
///
/// # Safety
///
/// Each pointer in `func_ptrs` must be valid (the owning arena must outlive
/// this call).
pub unsafe fn gas_instrument(
func_ptrs: &[Option<ExecutableArenaPtr<Function>>],
) -> (Vec<Option<ExecutableArenaPtr<Function>>>, ExecutableArena) {
let arena = ExecutableArena::new();
let instrumentor = GasInstrumentor::new(MicroOpGasSchedule);
let new_fns = func_ptrs
.iter()
.map(|f| {
let fp = (*f)?;
// SAFETY: caller guarantees the pointer is valid.
let func = unsafe { fp.as_ref_unchecked() };
let raw = unsafe { func.code.as_ref_unchecked() };
let instrumented = instrumentor.run(raw.to_vec());
let code = arena.alloc_slice_copy(&instrumented);
Some(arena.alloc(Function {
name: func.name,
code,
args_size: func.args_size,
args_and_locals_size: func.args_and_locals_size,
extended_frame_size: func.extended_frame_size,
zero_frame: func.zero_frame,
frame_layout: FrameLayoutInfo::empty(&arena),
safe_point_layouts: SortedSafePointEntries::empty(&arena),
}))
})
.collect();
(new_fns, arena)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[LOW] frame_layout and safe_point_layouts are silently dropped (replaced with empty stubs). The doc comment explains this is safe for programs that don't trigger GC, but the function accepts any input without enforcing that precondition. If a future benchmark program has heap-pointer locals, the GC will silently miss those roots. A debug_assert! on func.frame_layout.heap_ptr_offsets being empty, or a note in the # Safety section, would make the precondition explicit.

97 changes: 97 additions & 0 deletions third_party/move/mono-move/programs/benches/match_sum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) Aptos Foundation
// Licensed pursuant to the Innovation-Enabling Source Code License, available at https://github.com/aptos-labs/aptos-core/blob/main/LICENSE

use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion};

#[path = "helpers.rs"]
mod helpers;

const N: u64 = 1_000_000;

fn bench_match_sum(c: &mut Criterion) {
use mono_move_gas::{NoOpGasMeter, SimpleGasMeter};
use mono_move_programs::{
match_sum::{micro_op_match_sum, move_bytecode_match_sum, native_match_sum},
testing,
};
use mono_move_runtime::InterpreterContext;

// -- native & micro_op -------------------------------------------------
{
let mut group = c.benchmark_group("match_sum");
group
.warm_up_time(std::time::Duration::from_secs(1))
.measurement_time(std::time::Duration::from_secs(3));

group.bench_function("native", |b| {
b.iter(|| black_box(native_match_sum(N)));
});

// plain (no gas instrumentation)
let (functions, descriptors, _arena) = micro_op_match_sum();
group.bench_function("micro_op", |b| {
b.iter_batched(
|| {
let mut ctx = InterpreterContext::new(&descriptors, NoOpGasMeter, unsafe {
functions[0].as_ref_unchecked()
});
ctx.set_root_arg(0, &N.to_le_bytes());
ctx
},
|mut ctx| {
ctx.run().unwrap();
black_box(ctx.root_result())
},
BatchSize::SmallInput,
);
});

// with gas instrumentation
let (functions, _, _arena) = micro_op_match_sum();
let wrapped = functions.iter().map(|f| Some(*f)).collect::<Vec<_>>();
// SAFETY: Exclusive access during bench setup; arena is alive.
let (functions_gas, _arena) = unsafe { helpers::gas_instrument(&wrapped) };
group.bench_function("micro_op/gas", |b| {
b.iter_batched(
|| {
let gas_meter = SimpleGasMeter::new(u64::MAX);
let mut ctx = InterpreterContext::new(&descriptors, gas_meter, unsafe {
functions_gas[0].unwrap().as_ref_unchecked()
});
ctx.set_root_arg(0, &N.to_le_bytes());
ctx
},
|mut ctx| {
ctx.run().unwrap();
black_box(ctx.root_result())
},
BatchSize::SmallInput,
);
});

group.finish();
}

// -- move_vm -----------------------------------------------------------
{
let mut group = c.benchmark_group("match_sum");
group
.sample_size(10)
.warm_up_time(std::time::Duration::from_secs(1))
.measurement_time(std::time::Duration::from_secs(3));

let module = move_bytecode_match_sum();
testing::with_loaded_move_function(&module, "match_sum", |env| {
group.bench_function("move_vm", |b| {
b.iter(|| {
let result = env.run(vec![testing::arg_u64(N)]);
black_box(testing::return_u64(&result))
});
});
});
group.finish();
}
}

criterion_group!(benches, bench_match_sum);
criterion_main!(benches);
32 changes: 30 additions & 2 deletions third_party/move/mono-move/programs/benches/merge_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@

use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion};

#[path = "helpers.rs"]
mod helpers;

const N: u64 = 1000;

fn bench_merge_sort(c: &mut Criterion) {
use mono_move_gas::SimpleGasMeter;
use mono_move_gas::{NoOpGasMeter, SimpleGasMeter};
use mono_move_programs::{
merge_sort::{
micro_op_merge_sort, move_bytecode_merge_sort, native_merge_sort, shuffled_range,
Expand Down Expand Up @@ -35,15 +38,39 @@ fn bench_merge_sort(c: &mut Criterion) {
);
});

// plain (no gas instrumentation)
let (functions, descriptors, _arena) = micro_op_merge_sort();
// SAFETY: Exclusive access during bench setup; arena is alive.
unsafe { mono_move_core::Function::resolve_calls(&functions) };
group.bench_function("micro_op", |b| {
b.iter_batched(
|| {
let mut ctx = InterpreterContext::new(&descriptors, NoOpGasMeter, unsafe {
functions[0].unwrap().as_ref_unchecked()
});
let vec_ptr = ctx
.alloc_u64_vec(mono_move_core::DescriptorId(0), &input)
.unwrap();
ctx.set_root_arg(0, &vec_ptr.to_le_bytes());
ctx
},
|mut ctx| ctx.run().unwrap(),
BatchSize::SmallInput,
);
});

// with gas instrumentation
let (functions, _, _arena) = micro_op_merge_sort();
// SAFETY: Exclusive access during bench setup; arena is alive.
let (functions_gas, _arena) = unsafe { helpers::gas_instrument(&functions) };
// SAFETY: Exclusive access during bench setup; arena is alive.
unsafe { mono_move_core::Function::resolve_calls(&functions_gas) };
group.bench_function("micro_op/gas", |b| {
b.iter_batched(
|| {
let gas_meter = SimpleGasMeter::new(u64::MAX);
let mut ctx = InterpreterContext::new(&descriptors, gas_meter, unsafe {
functions[0].unwrap().as_ref_unchecked()
functions_gas[0].unwrap().as_ref_unchecked()
});
let vec_ptr = ctx
.alloc_u64_vec(mono_move_core::DescriptorId(0), &input)
Expand All @@ -55,6 +82,7 @@ fn bench_merge_sort(c: &mut Criterion) {
BatchSize::SmallInput,
);
});

group.finish();
}

Expand Down
Loading
Loading