From aedb37a18a5b12f86db9c6da748168a5bae6263c Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Mon, 4 Sep 2023 12:24:02 +1200 Subject: [PATCH] Benchmark Rust code (#933) This PR allows benchmarking mmtk-core code in DummyVM. It uses `criterion`, which is a popular framework to benchmark with a stable Rust toolchain. This PR just introduces code and two benchmarks that specifically test our allocation code in Rust and our SFT read access. This PR does not include those benchmarks in the CI. --- vmbindings/dummyvm/Cargo.toml | 15 ++++++++++++- vmbindings/dummyvm/benches/bench_alloc.rs | 18 ++++++++++++++++ vmbindings/dummyvm/benches/bench_sft.rs | 20 ++++++++++++++++++ vmbindings/dummyvm/benches/main.rs | 15 +++++++++++++ vmbindings/dummyvm/src/lib.rs | 2 ++ .../fixtures/mod.rs => test_fixtures.rs} | 21 +++++++++++++++++-- .../src/tests/allocate_align_offset.rs | 2 +- .../src/tests/barrier_slow_path_assertion.rs | 4 ++-- vmbindings/dummyvm/src/tests/conservatism.rs | 2 +- vmbindings/dummyvm/src/tests/edges_test.rs | 2 +- .../dummyvm/src/tests/is_in_mmtk_spaces.rs | 2 +- ...7_allocate_unrealistically_large_object.rs | 2 +- .../dummyvm/src/tests/malloc_counted.rs | 2 +- vmbindings/dummyvm/src/tests/mod.rs | 1 - .../dummyvm/src/tests/vm_layout_default.rs | 2 +- 15 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 vmbindings/dummyvm/benches/bench_alloc.rs create mode 100644 vmbindings/dummyvm/benches/bench_sft.rs create mode 100644 vmbindings/dummyvm/benches/main.rs rename vmbindings/dummyvm/src/{tests/fixtures/mod.rs => test_fixtures.rs} (94%) diff --git a/vmbindings/dummyvm/Cargo.toml b/vmbindings/dummyvm/Cargo.toml index 674dff7dc0..a1a3af254b 100644 --- a/vmbindings/dummyvm/Cargo.toml +++ b/vmbindings/dummyvm/Cargo.toml @@ -7,7 +7,9 @@ edition = "2021" [lib] name = "mmtk_dummyvm" # be careful - LTO is only allowed for certain crate types -crate-type = ["cdylib"] +# We know that cdylib should work for LTO. +# We keep rlib here as we need to use the crate from benches. +crate-type = ["cdylib", "rlib"] [profile.release] lto = true @@ -20,6 +22,13 @@ atomic_refcell = "0.1.7" atomic = "0.4.6" log = "0.4" +[dev-dependencies] +criterion = "0.4" + +[[bench]] +name = "main" +harness = false + [features] default = [] is_mmtk_object = ["mmtk/is_mmtk_object"] @@ -27,3 +36,7 @@ malloc_counted_size = ["mmtk/malloc_counted_size"] malloc_mark_sweep = ["mmtk/malloc_mark_sweep"] vo_bit = ["mmtk/vo_bit"] extreme_assertions = ["mmtk/extreme_assertions"] + +# Feature to control which benchmarks to run. See benches/main.rs +bench_sft = [] +bench_alloc = [] diff --git a/vmbindings/dummyvm/benches/bench_alloc.rs b/vmbindings/dummyvm/benches/bench_alloc.rs new file mode 100644 index 0000000000..482cfee33f --- /dev/null +++ b/vmbindings/dummyvm/benches/bench_alloc.rs @@ -0,0 +1,18 @@ +use criterion::{criterion_group, Criterion}; + +use mmtk::plan::AllocationSemantics; +use mmtk_dummyvm::api; +use mmtk_dummyvm::test_fixtures::MutatorFixture; + +fn alloc(c: &mut Criterion) { + println!("Init MMTK in alloc bench"); + // 1GB so we are unlikely to OOM + let fixture = MutatorFixture::create_with_heapsize(1 << 30); + c.bench_function("alloc", |b| { + b.iter(|| { + let _addr = api::mmtk_alloc(fixture.mutator, 8, 8, 0, AllocationSemantics::Default); + }) + }); +} + +criterion_group!(benches, alloc); diff --git a/vmbindings/dummyvm/benches/bench_sft.rs b/vmbindings/dummyvm/benches/bench_sft.rs new file mode 100644 index 0000000000..40ccf01406 --- /dev/null +++ b/vmbindings/dummyvm/benches/bench_sft.rs @@ -0,0 +1,20 @@ +use criterion::{black_box, criterion_group, Criterion}; + +use mmtk::plan::AllocationSemantics; +use mmtk::vm::ObjectModel; +use mmtk_dummyvm::api; +use mmtk_dummyvm::test_fixtures::FixtureContent; +use mmtk_dummyvm::test_fixtures::MutatorFixture; + +fn sft(c: &mut Criterion) { + println!("Init MMTK in sft bench"); + let fixture = MutatorFixture::create(); + let addr = api::mmtk_alloc(fixture.mutator, 8, 8, 0, AllocationSemantics::Default); + let obj = mmtk_dummyvm::object_model::VMObjectModel::address_to_ref(addr); + + c.bench_function("sft read", |b| { + b.iter(|| api::mmtk_is_in_mmtk_spaces(black_box(obj))) + }); +} + +criterion_group!(benches, sft); diff --git a/vmbindings/dummyvm/benches/main.rs b/vmbindings/dummyvm/benches/main.rs new file mode 100644 index 0000000000..804379ee1b --- /dev/null +++ b/vmbindings/dummyvm/benches/main.rs @@ -0,0 +1,15 @@ +use criterion::criterion_main; + +// As we can only initialize one MMTk instance, we have to run each benchmark separately. +// Filtering like `cargo bench -- sft` won't work, as it still evalutes all the benchmark groups (which initialize MMTk). +// We can use conditional compilation, and run with `cargo bench --features bench_sft`. The features are defined in the dummy VM crate. + +#[cfg(feature = "bench_sft")] +mod bench_sft; +#[cfg(feature = "bench_sft")] +criterion_main!(bench_sft::benches); + +#[cfg(feature = "bench_alloc")] +mod bench_alloc; +#[cfg(feature = "bench_alloc")] +criterion_main!(bench_alloc::benches); diff --git a/vmbindings/dummyvm/src/lib.rs b/vmbindings/dummyvm/src/lib.rs index ab13607e24..57e630f222 100644 --- a/vmbindings/dummyvm/src/lib.rs +++ b/vmbindings/dummyvm/src/lib.rs @@ -14,6 +14,8 @@ pub mod object_model; pub mod reference_glue; pub mod scanning; +pub mod test_fixtures; + mod edges; #[cfg(test)] mod tests; diff --git a/vmbindings/dummyvm/src/tests/fixtures/mod.rs b/vmbindings/dummyvm/src/test_fixtures.rs similarity index 94% rename from vmbindings/dummyvm/src/tests/fixtures/mod.rs rename to vmbindings/dummyvm/src/test_fixtures.rs index ccda59970f..4e400bc6d2 100644 --- a/vmbindings/dummyvm/src/tests/fixtures/mod.rs +++ b/vmbindings/dummyvm/src/test_fixtures.rs @@ -43,6 +43,12 @@ impl Fixture { } } +impl Default for Fixture { + fn default() -> Self { + Self::new() + } +} + /// SerialFixture ensures all `with_fixture()` calls will be executed serially. pub struct SerialFixture { content: Mutex>>, @@ -85,6 +91,12 @@ impl SerialFixture { } } +impl Default for SerialFixture { + fn default() -> Self { + Self::new() + } +} + pub struct SingleObject { pub objref: ObjectReference, } @@ -171,8 +183,13 @@ pub struct MutatorFixture { impl FixtureContent for MutatorFixture { fn create() -> Self { const MB: usize = 1024 * 1024; - // 1MB heap - mmtk_init(MB); + Self::create_with_heapsize(MB) + } +} + +impl MutatorFixture { + pub fn create_with_heapsize(size: usize) -> Self { + mmtk_init(size); mmtk_initialize_collection(VMThread::UNINITIALIZED); // Make sure GC does not run during test. mmtk_disable_collection(); diff --git a/vmbindings/dummyvm/src/tests/allocate_align_offset.rs b/vmbindings/dummyvm/src/tests/allocate_align_offset.rs index c68cac7378..ed39c5ce20 100644 --- a/vmbindings/dummyvm/src/tests/allocate_align_offset.rs +++ b/vmbindings/dummyvm/src/tests/allocate_align_offset.rs @@ -1,7 +1,7 @@ // GITHUB-CI: MMTK_PLAN=all use crate::api; -use crate::tests::fixtures::{MutatorFixture, SerialFixture}; +use crate::test_fixtures::{MutatorFixture, SerialFixture}; use crate::DummyVM; use log::info; use mmtk::plan::AllocationSemantics; diff --git a/vmbindings/dummyvm/src/tests/barrier_slow_path_assertion.rs b/vmbindings/dummyvm/src/tests/barrier_slow_path_assertion.rs index f8394a48ab..063c053dcd 100644 --- a/vmbindings/dummyvm/src/tests/barrier_slow_path_assertion.rs +++ b/vmbindings/dummyvm/src/tests/barrier_slow_path_assertion.rs @@ -4,8 +4,8 @@ // Run the test with any plan that uses object barrier, and we also need both VO bit and extreme assertions. use crate::object_model::OBJECT_REF_OFFSET; -use crate::tests::fixtures::FixtureContent; -use crate::tests::fixtures::MMTKSingleton; +use crate::test_fixtures::FixtureContent; +use crate::test_fixtures::MMTKSingleton; use crate::{api::*, edges}; use atomic::Atomic; use mmtk::util::{Address, ObjectReference}; diff --git a/vmbindings/dummyvm/src/tests/conservatism.rs b/vmbindings/dummyvm/src/tests/conservatism.rs index b2ef84c1cf..6262769888 100644 --- a/vmbindings/dummyvm/src/tests/conservatism.rs +++ b/vmbindings/dummyvm/src/tests/conservatism.rs @@ -3,7 +3,7 @@ use crate::api::*; use crate::object_model::OBJECT_REF_OFFSET; -use crate::tests::fixtures::{Fixture, SingleObject}; +use crate::test_fixtures::{Fixture, SingleObject}; use mmtk::util::constants::LOG_BITS_IN_WORD; use mmtk::util::is_mmtk_object::VO_BIT_REGION_SIZE; use mmtk::util::*; diff --git a/vmbindings/dummyvm/src/tests/edges_test.rs b/vmbindings/dummyvm/src/tests/edges_test.rs index 92c50dbbb4..f927e420a6 100644 --- a/vmbindings/dummyvm/src/tests/edges_test.rs +++ b/vmbindings/dummyvm/src/tests/edges_test.rs @@ -8,7 +8,7 @@ use mmtk::{ use crate::{ edges::{DummyVMEdge, OffsetEdge, TaggedEdge}, - tests::fixtures::{Fixture, TwoObjects}, + test_fixtures::{Fixture, TwoObjects}, }; #[cfg(target_pointer_width = "64")] diff --git a/vmbindings/dummyvm/src/tests/is_in_mmtk_spaces.rs b/vmbindings/dummyvm/src/tests/is_in_mmtk_spaces.rs index 7e14fb9bc9..8a41f4116f 100644 --- a/vmbindings/dummyvm/src/tests/is_in_mmtk_spaces.rs +++ b/vmbindings/dummyvm/src/tests/is_in_mmtk_spaces.rs @@ -1,7 +1,7 @@ // GITHUB-CI: MMTK_PLAN=all use crate::api::mmtk_is_in_mmtk_spaces as is_in_mmtk_spaces; -use crate::tests::fixtures::{Fixture, SingleObject}; +use crate::test_fixtures::{Fixture, SingleObject}; use mmtk::util::*; lazy_static! { diff --git a/vmbindings/dummyvm/src/tests/issue867_allocate_unrealistically_large_object.rs b/vmbindings/dummyvm/src/tests/issue867_allocate_unrealistically_large_object.rs index 3cdaf12d8d..8822506413 100644 --- a/vmbindings/dummyvm/src/tests/issue867_allocate_unrealistically_large_object.rs +++ b/vmbindings/dummyvm/src/tests/issue867_allocate_unrealistically_large_object.rs @@ -1,7 +1,7 @@ // GITHUB-CI: MMTK_PLAN=all use crate::api; -use crate::tests::fixtures::{MutatorFixture, SerialFixture}; +use crate::test_fixtures::{MutatorFixture, SerialFixture}; use mmtk::plan::AllocationSemantics; lazy_static! { diff --git a/vmbindings/dummyvm/src/tests/malloc_counted.rs b/vmbindings/dummyvm/src/tests/malloc_counted.rs index d5d8ef678a..c7c6639d0c 100644 --- a/vmbindings/dummyvm/src/tests/malloc_counted.rs +++ b/vmbindings/dummyvm/src/tests/malloc_counted.rs @@ -1,7 +1,7 @@ // GITHUB-CI: FEATURES=malloc_counted_size use crate::api::*; -use crate::tests::fixtures::{MMTKSingleton, SerialFixture}; +use crate::test_fixtures::{MMTKSingleton, SerialFixture}; lazy_static! { static ref MMTK_SINGLETON: SerialFixture = SerialFixture::new(); diff --git a/vmbindings/dummyvm/src/tests/mod.rs b/vmbindings/dummyvm/src/tests/mod.rs index acc48a3eb5..f6eb288ca0 100644 --- a/vmbindings/dummyvm/src/tests/mod.rs +++ b/vmbindings/dummyvm/src/tests/mod.rs @@ -13,7 +13,6 @@ mod barrier_slow_path_assertion; #[cfg(feature = "is_mmtk_object")] mod conservatism; mod edges_test; -mod fixtures; #[cfg(target_os = "linux")] mod handle_mmap_conflict; mod handle_mmap_oom; diff --git a/vmbindings/dummyvm/src/tests/vm_layout_default.rs b/vmbindings/dummyvm/src/tests/vm_layout_default.rs index 9d95c314ca..38fa24a10e 100644 --- a/vmbindings/dummyvm/src/tests/vm_layout_default.rs +++ b/vmbindings/dummyvm/src/tests/vm_layout_default.rs @@ -4,7 +4,7 @@ use mmtk::util::heap::vm_layout::VMLayout; pub fn test_with_vm_layout(layout: Option) { use crate::api; - use crate::tests::fixtures::VMLayoutFixture; + use crate::test_fixtures::VMLayoutFixture; use mmtk::plan::AllocationSemantics; use mmtk::vm::ObjectModel;