Skip to content

Benchmark Rust code #933

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

Merged
merged 3 commits into from
Sep 4, 2023
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
15 changes: 14 additions & 1 deletion vmbindings/dummyvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -20,10 +22,21 @@ 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"]
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 = []
18 changes: 18 additions & 0 deletions vmbindings/dummyvm/benches/bench_alloc.rs
Original file line number Diff line number Diff line change
@@ -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);
20 changes: 20 additions & 0 deletions vmbindings/dummyvm/benches/bench_sft.rs
Original file line number Diff line number Diff line change
@@ -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)))
Copy link
Collaborator

Choose a reason for hiding this comment

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

This test is accessing the SFT entry of the same object again and again. The cache will always hit in this case. I recommend adding a test case where we access the SFT randomly. To make the performance comparison fair and stable, we can use a pseudo random number generator so that we always access the objects in the same "random" order.

Copy link
Member Author

Choose a reason for hiding this comment

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

It is possible. We could control what we want to benchmark. criterion provides an approach that allows us to microbenchmark short running functions. It is useful when we can isolate one function and check the performance of the function so that we can make changes to it with more confidence. It is a complement to what we usually do for benchmarking.

Though we can control what we want to benchmark, I am not convinced if we would like to use micro benchmarks to mimic a real situation. Using a larger benchmark or real workload is usually a better option.

Also for this case, I don't think we want to take cache locality into consideration. For SFT access, I would like to measure the performance impact of the code change for #931. Cache locality is not what I am trying to measure, and randomly accessing memory would just add more noise to the result.

});
}

criterion_group!(benches, sft);
15 changes: 15 additions & 0 deletions vmbindings/dummyvm/benches/main.rs
Original file line number Diff line number Diff line change
@@ -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);
2 changes: 2 additions & 0 deletions vmbindings/dummyvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ impl<T: FixtureContent> Fixture<T> {
}
}

impl<T: FixtureContent> Default for Fixture<T> {
fn default() -> Self {
Self::new()
}
}

/// SerialFixture ensures all `with_fixture()` calls will be executed serially.
pub struct SerialFixture<T: FixtureContent> {
content: Mutex<Option<Box<T>>>,
Expand Down Expand Up @@ -85,6 +91,12 @@ impl<T: FixtureContent> SerialFixture<T> {
}
}

impl<T: FixtureContent> Default for SerialFixture<T> {
fn default() -> Self {
Self::new()
}
}

pub struct SingleObject {
pub objref: ObjectReference,
}
Expand Down Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion vmbindings/dummyvm/src/tests/allocate_align_offset.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
4 changes: 2 additions & 2 deletions vmbindings/dummyvm/src/tests/barrier_slow_path_assertion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
2 changes: 1 addition & 1 deletion vmbindings/dummyvm/src/tests/conservatism.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down
2 changes: 1 addition & 1 deletion vmbindings/dummyvm/src/tests/edges_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
2 changes: 1 addition & 1 deletion vmbindings/dummyvm/src/tests/is_in_mmtk_spaces.rs
Original file line number Diff line number Diff line change
@@ -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! {
Expand Down
Original file line number Diff line number Diff line change
@@ -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! {
Expand Down
2 changes: 1 addition & 1 deletion vmbindings/dummyvm/src/tests/malloc_counted.rs
Original file line number Diff line number Diff line change
@@ -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<MMTKSingleton> = SerialFixture::new();
Expand Down
1 change: 0 additions & 1 deletion vmbindings/dummyvm/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion vmbindings/dummyvm/src/tests/vm_layout_default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use mmtk::util::heap::vm_layout::VMLayout;

pub fn test_with_vm_layout(layout: Option<VMLayout>) {
use crate::api;
use crate::tests::fixtures::VMLayoutFixture;
use crate::test_fixtures::VMLayoutFixture;
use mmtk::plan::AllocationSemantics;
use mmtk::vm::ObjectModel;

Expand Down