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 external-crates/move/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ clap = { version = "4", features = ["derive"] }
codespan = "0.11.1"
codespan-reporting = "0.11.1"
colored = "2.0.0"
criterion = "0.3.4"
criterion = { version = "0.3.4", features = ["html_reports"]}
criterion-cpu-time = "0.1.0"
crossbeam = "0.8"
crossbeam-channel = "0.5.0"
Expand Down
5 changes: 4 additions & 1 deletion external-crates/move/crates/language-benchmarks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ move-binary-format.workspace = true
move-stdlib.workspace = true
move-stdlib-natives.workspace = true

[lib]
bench = false

[[bench]]
name = "vm_benches"
name = "criterion"
harness = false
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) The Diem Core Contributors
// Copyright (c) The Move Contributors
// SPDX-License-Identifier: Apache-2.0

use criterion::{criterion_group, criterion_main, measurement::Measurement, Criterion};
use language_benchmarks::{measurement::cpu_time_measurement, move_vm::bench};

//
// MoveVM benchmarks
//

fn arith<M: Measurement + 'static>(c: &mut Criterion<M>) {
bench(c, "arith.move");
}

fn arith_2<M: Measurement + 'static>(c: &mut Criterion<M>) {
bench(c, "arith_2.move");
}

fn basic_alloc<M: Measurement + 'static>(c: &mut Criterion<M>) {
bench(c, "basic_alloc.move");
}

fn call<M: Measurement + 'static>(c: &mut Criterion<M>) {
bench(c, "call.move");
}

fn call_2<M: Measurement + 'static>(c: &mut Criterion<M>) {
bench(c, "call_2.move");
}

fn natives<M: Measurement + 'static>(c: &mut Criterion<M>) {
bench(c, "natives.move");
}

fn transfers<M: Measurement + 'static>(c: &mut Criterion<M>) {
bench(c, "transfers.move");
}

fn vector<M: Measurement + 'static>(c: &mut Criterion<M>) {
bench(c, "vector.move");
}

criterion_group!(
name = vm_benches;
config = cpu_time_measurement();
targets =
arith,
arith_2,
basic_alloc,
call,
call_2,
natives,
transfers,
vector,
);

criterion_main!(vm_benches);

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@

use criterion::Criterion;
use criterion_cpu_time::PosixTime;
use std::time::Duration;

pub fn cpu_time_measurement() -> Criterion<PosixTime> {
Criterion::default().with_measurement(PosixTime::UserAndSystemTime)
Criterion::default()
.with_measurement(PosixTime::UserAndSystemTime)
.without_plots()
.noise_threshold(0.20)
.confidence_level(0.9)
.warm_up_time(Duration::from_secs(10)) // Warm-up time before measurements start
.measurement_time(Duration::from_secs(30)) // Measurement time of 30 seconds
}

pub fn wall_time_measurement() -> Criterion {
Expand Down
85 changes: 59 additions & 26 deletions external-crates/move/crates/language-benchmarks/src/move_vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,68 @@

use criterion::{measurement::Measurement, Criterion};
use move_binary_format::CompiledModule;
use move_compiler::Compiler;
use move_compiler::{editions::Edition, shared::PackagePaths, Compiler, FullyCompiledProgram};
use move_core_types::{
account_address::AccountAddress,
identifier::{IdentStr, Identifier},
identifier::Identifier,
language_storage::{ModuleId, CORE_CODE_ADDRESS},
};

use move_vm_runtime::move_vm::MoveVM;
use move_vm_test_utils::BlankStorage;
use move_vm_types::gas::UnmeteredGasMeter;
use once_cell::sync::Lazy;
use std::path::PathBuf;
use std::{path::PathBuf, sync::Arc};

static MOVE_BENCH_SRC_PATH: Lazy<PathBuf> = Lazy::new(|| {
vec![env!("CARGO_MANIFEST_DIR"), "src", "bench.move"]
.into_iter()
.collect()
static PRECOMPILED_MOVE_STDLIB: Lazy<FullyCompiledProgram> = Lazy::new(|| {
let program_res = move_compiler::construct_pre_compiled_lib(
vec![PackagePaths {
name: None,
paths: move_stdlib::move_stdlib_files(),
named_address_map: move_stdlib::move_stdlib_named_addresses(),
}],
None,
move_compiler::Flags::empty(),
None,
)
.unwrap();
match program_res {
Ok(stdlib) => stdlib,
Err((files, errors)) => {
eprintln!("!!!Standard library failed to compile!!!");
move_compiler::diagnostics::report_diagnostics(&files, errors)
}
}
});

/// Entry point for the bench, provide a function name to invoke in Module Bench in bench.move.
pub fn bench<M: Measurement + 'static>(c: &mut Criterion<M>, fun: &str) {
let modules = compile_modules();
let move_vm = MoveVM::new(move_stdlib_natives::all_natives(
AccountAddress::from_hex_literal("0x1").unwrap(),
move_stdlib_natives::GasParameters::zeros(),
/* silent debug */ true,
))
.unwrap();
execute(c, &move_vm, modules, fun);
pub fn bench<M: Measurement + 'static>(c: &mut Criterion<M>, filename: &str) {
let modules = compile_modules(filename);
let move_vm = create_vm();
execute(c, &move_vm, modules, filename);
}

fn make_path(file: &str) -> PathBuf {
vec![env!("CARGO_MANIFEST_DIR"), "tests", file]
.into_iter()
.collect()
}

// Compile `bench.move` and its dependencies
fn compile_modules() -> Vec<CompiledModule> {
let mut src_files = move_stdlib::move_stdlib_files();
src_files.push(MOVE_BENCH_SRC_PATH.to_str().unwrap().to_owned());
pub fn compile_modules(filename: &str) -> Vec<CompiledModule> {
let src_files = vec![make_path(filename).to_str().unwrap().to_owned()];
let pkg_config = move_compiler::shared::PackageConfig {
edition: Edition::E2024_BETA,
..Default::default()
};
let (_files, compiled_units) = Compiler::from_files(
None,
src_files,
vec![],
move_stdlib::move_stdlib_named_addresses(),
)
.set_pre_compiled_lib(Arc::new(PRECOMPILED_MOVE_STDLIB.clone()))
.set_default_config(pkg_config)
.build_and_report()
.expect("Error compiling...");
compiled_units
Expand All @@ -52,12 +74,21 @@ fn compile_modules() -> Vec<CompiledModule> {
.collect()
}

fn create_vm() -> MoveVM {
MoveVM::new(move_stdlib_natives::all_natives(
AccountAddress::from_hex_literal("0x1").unwrap(),
move_stdlib_natives::GasParameters::zeros(),
/* silent debug */ true,
))
.unwrap()
}

// execute a given function in the Bench module
fn execute<M: Measurement + 'static>(
c: &mut Criterion<M>,
move_vm: &MoveVM,
modules: Vec<CompiledModule>,
fun: &str,
file: &str,
) {
// establish running context
let storage = BlankStorage::new();
Expand All @@ -77,21 +108,23 @@ fn execute<M: Measurement + 'static>(
}

// module and function to call
let module_id = ModuleId::new(sender, Identifier::new("Bench").unwrap());
let fun_name = IdentStr::new(fun).unwrap_or_else(|_| panic!("Invalid identifier name {}", fun));
let module_id = ModuleId::new(sender, Identifier::new("bench").unwrap());
let fun_name = Identifier::new("bench").unwrap();

// benchmark
c.bench_function(fun, |b| {
b.iter(|| {
c.bench_function(file, |b| {
b.iter_with_large_drop(|| {
session
.execute_function_bypass_visibility(
&module_id,
fun_name,
&fun_name,
vec![],
Vec::<Vec<u8>>::new(),
&mut UnmeteredGasMeter,
)
.unwrap_or_else(|err| panic!("{:?}::{} failed with {:?}", &module_id, fun, err))
.unwrap_or_else(|err| {
panic!("{:?}::bench in {file} failed with {:?}", &module_id, err)
})
})
});
}
22 changes: 22 additions & 0 deletions external-crates/move/crates/language-benchmarks/tests/arith.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module 0x1::bench {
fun check(check: bool, code: u64) {
if (check) () else abort code
}

public fun bench() {
let mut i = 0;
// 10000 is the number of loops to make the benchmark run for a couple of minutes,
// which is an eternity.
// Adjust according to your needs, it's just a reference
while (i < 10000) {
1;
10 + 3;
10;
7 + 5;
let x = 1;
let y = x + 3;
check(x + y == 5, 10);
i = i + 1;
};
}
}
12 changes: 12 additions & 0 deletions external-crates/move/crates/language-benchmarks/tests/arith_2.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module 0x1::bench {
const COUNT: u64 = 10_000u64;

public fun bench() {
let mut sum = 0;
let mut i = 0;
while (i < COUNT) {
sum = sum + i;
i = i + 1;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module 0x1::bench {
const COUNT: u64 = 10_000u64;

public struct LargeStruct has drop {
a: u64, b: u64, c: u64, d: u64, e: u64, f: u64, g: u64, h: u64
}

fun bench_inner(): LargeStruct {
let mut i = 0;
let mut alloc = LargeStruct { a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0 };
while (i < COUNT) {
alloc = LargeStruct { a: i, b: i, c: i, d: i, e: i, f: i, g: i, h: i };
i = i + 1;
};
alloc
}

public fun bench() {
let LargeStruct { a: _, b: _, c: _, d: _, e: _, f: _, g: _, h: i } = bench_inner();
let _i = i;
}
}
47 changes: 47 additions & 0 deletions external-crates/move/crates/language-benchmarks/tests/call.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module 0x1::bench {
//
// Global helpers
//
fun check(check: bool, code: u64) {
if (check) () else abort code
}

public fun bench() {
let mut i = 0;
// 3000 is the number of loops to make the benchmark run for a couple of minutes,
// which is an eternity.
// Adjust according to your needs, it's just a reference
while (i < 3000) {
let b = call_1(@0x0, 128);
call_2(b);
i = i + 1;
};
}

fun call_1(addr: address, val: u64): bool {
let b = call_1_1(&addr);
call_1_2(val, val);
b
}

fun call_1_1(_addr: &address): bool {
true
}

fun call_1_2(val1: u64, val2: u64): bool {
val1 == val2
}

fun call_2(b: bool) {
call_2_1(b);
check(call_2_2() == 400, 200);
}

fun call_2_1(b: bool) {
check(b == b, 100)
}

fun call_2_2(): u64 {
100 + 300
}
}
16 changes: 16 additions & 0 deletions external-crates/move/crates/language-benchmarks/tests/call_2.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module 0x1::bench {

const COUNT: u64 = 10_000u64;

public fun bench(): u64 {
let mut i = 0;
while (i < COUNT) {
i = i + call_empty_function();
};
i
}

public fun call_empty_function(): u64 {
1
}
}
Loading
Loading