Skip to content
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

Introduce MockVM #1049

Merged
merged 15 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from 10 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
1 change: 0 additions & 1 deletion .github/scripts/ci-style.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,3 @@ style_check_auxiliary_crate() {
}

style_check_auxiliary_crate macros
style_check_auxiliary_crate vmbindings/dummyvm
22 changes: 8 additions & 14 deletions .github/scripts/ci-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,29 @@ if [[ $arch == "x86_64" && $os == "linux" ]]; then
cargo test --features perf_counter
fi

./examples/build.py

ALL_PLANS=$(sed -n '/enum PlanSelector/,/}/p' src/util/options.rs | sed -e 's;//.*;;g' -e '/^$/d' -e 's/,//g' | xargs | grep -o '{.*}' | grep -o '\w\+')

# Test with DummyVM (each test in a separate run)
cd vmbindings/dummyvm
for fn in $(ls src/tests/*.rs); do
t=$(basename -s .rs $fn)

if [[ $t == "mod" ]]; then
continue
fi
# Test with mock VM:
# - Find all the files that start with mock_test_
# - Run each file separately with cargo test, with the feature 'mock_test'
find ./src ./tests -type f -name "mock_test_*" | while read -r file; do
t=$(basename -s .rs $file)

# Get the required plans.
# Some tests need to be run with multiple plans because
# some bugs can only be reproduced in some plans but not others.
PLANS=$(sed -n 's/^\/\/ *GITHUB-CI: *MMTK_PLAN=//p' $fn)
PLANS=$(sed -n 's/^\/\/ *GITHUB-CI: *MMTK_PLAN=//p' $file)
if [[ $PLANS == 'all' ]]; then
PLANS=$ALL_PLANS
elif [[ -z $PLANS ]]; then
PLANS=NoGC
fi

# Some tests need some features enabled.
FEATURES=$(sed -n 's/^\/\/ *GITHUB-CI: *FEATURES=//p' $fn)
FEATURES=$(sed -n 's/^\/\/ *GITHUB-CI: *FEATURES=//p' $file)

# Run the test with each plan it needs.
for MMTK_PLAN in $PLANS; do
env MMTK_PLAN=$MMTK_PLAN cargo test --features "$FEATURES" -- $t;
env MMTK_PLAN=$MMTK_PLAN cargo test --features mock_test,"$FEATURES" -- $t;
done
done

9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,26 @@ sysinfo = "0.29"
[dev-dependencies]
paste = "1.0.8"
rand = "0.8.5"
criterion = "0.4"

[build-dependencies]
built = { version = "0.7.1", features = ["git2"] }

[[bench]]
name = "main"
harness = false

[features]
default = []

# This feature is only supported on x86-64 for now
# It's manually added to CI scripts
perf_counter = ["pfm"]

# This feature is only used for tests with MockVM.
# CI scripts run those tests with this feature.
mock_test = []

# .github/scripts/ci-common.sh extracts features from the following part (including from comments).
# So be careful when editing or adding stuff to the section below.

Expand Down
18 changes: 18 additions & 0 deletions benches/alloc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use criterion::criterion_group;
qinsoon marked this conversation as resolved.
Show resolved Hide resolved
use criterion::Criterion;

use mmtk::memory_manager;
use mmtk::util::test_util::fixtures::*;
use mmtk::AllocationSemantics;

pub fn bench(c: &mut Criterion) {
// Disable GC so we won't trigger GC
let mut fixture = MutatorFixture::create_with_heapsize(1 << 30);
memory_manager::disable_collection(&mut fixture.mmtk());
c.bench_function("alloc", |b| {
b.iter(|| {
let _addr =
memory_manager::alloc(&mut fixture.mutator, 8, 8, 0, AllocationSemantics::Default);
})
});
}
37 changes: 37 additions & 0 deletions benches/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use criterion::criterion_group;
use criterion::criterion_main;
use criterion::Criterion;

// As we can only initialize one MMTk instance, we have to run each benchmark in a separate process.
// So we only register one benchmark to criterion ('bench_main'), and based on the env var MMTK_BENCH,
// we pick the right benchmark to run.

// The benchmark can be executed with the following command. The feature `mock_test` is required, as the tests use MockVM.
// MMTK_BENCH=alloc cargo bench --features mock_test
// MMTK_BENCH=sft cargo bench --features mock_test

// [Yi] I am not sure if these benchmarks are helpful any more after the MockVM refactoring. MockVM is really slow, as it
// is accessed with a lock, and it dispatches every call to function pointers in a struct. These tests may use MockVM,
// so they become slower as well. And the slowdown
// from MockVM may hide the actual performance difference when we change the functions that are benchmarked.
// We may want to improve the MockVM implementation so we can skip dispatching for benchmarking, or introduce another MockVM
// implementation for benchmarking.
// However, I will just keep these benchmarks here. If we find it not useful, and we do not plan to improve MockVM, we can delete
// them.

mod alloc;
mod sft;

fn bench_main(c: &mut Criterion) {
match std::env::var("MMTK_BENCH") {
Ok(bench) => match bench.as_str() {
"alloc" => alloc::bench(c),
"sft" => sft::bench(c),
_ => panic!("Unknown benchmark {:?}", bench),
},
Err(_) => panic!("Need to name a benchmark by the env var MMTK_BENCH"),
}
}

criterion_group!(benches, bench_main);
criterion_main!(benches);
20 changes: 20 additions & 0 deletions benches/sft.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use criterion::black_box;
use criterion::criterion_group;
qinsoon marked this conversation as resolved.
Show resolved Hide resolved
use criterion::Criterion;

use mmtk::memory_manager;
use mmtk::util::test_util::fixtures::*;
use mmtk::util::test_util::mock_vm::*;
use mmtk::vm::ObjectModel;
use mmtk::vm::VMBinding;
use mmtk::AllocationSemantics;

pub fn bench(c: &mut Criterion) {
let mut fixture = MutatorFixture::create();
let addr = memory_manager::alloc(&mut fixture.mutator, 8, 8, 0, AllocationSemantics::Default);
let obj = <MockVM as VMBinding>::VMObjectModel::address_to_ref(addr);

c.bench_function("sft read", |b| {
b.iter(|| memory_manager::is_in_mmtk_spaces::<MockVM>(black_box(obj)))
});
}
8 changes: 4 additions & 4 deletions docs/userguide/src/portingguide/perf_tuning/alloc.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ If the VM is not implemented in Rust,
the binding needs to turn the boxed pointer into a raw pointer before storing it.

```rust
{{#include ../../../../../vmbindings/dummyvm/src/tests/doc_mutator_storage.rs:mutator_storage_boxed_pointer}}
{{#include ../../../../../src/vm/tests/mock_tests/mock_test_doc_mutator_storage.rs:mutator_storage_boxed_pointer}}
```

### Option 2: Embed the `Mutator` struct
Expand All @@ -44,7 +44,7 @@ If the implementation language is not Rust, the developer needs to create a type
have an assertion to ensure that the native type has the exact same layout as the Rust type `Mutator`.

```rust
{{#include ../../../../../vmbindings/dummyvm/src/tests/doc_mutator_storage.rs:mutator_storage_embed_mutator_struct}}
{{#include ../../../../../src/vm/tests/mock_tests/mock_test_doc_mutator_storage.rs:mutator_storage_embed_mutator_struct}}
```

### Option 3: Embed the fast-path struct
Expand Down Expand Up @@ -78,7 +78,7 @@ which includes (but not limited to) `NoGC`, `SemiSpace`, `Immix`, generational p
If a plan does not do bump-pointer allocation, we may still implement fast-paths, but we need to embed different data structures instead of `BumpPointer`.

```rust
{{#include ../../../../../vmbindings/dummyvm/src/tests/doc_mutator_storage.rs:mutator_storage_embed_fast-path_struct}}
{{#include ../../../../../src/vm/tests/mock_tests/mock_test_doc_mutator_storage.rs:mutator_storage_embed_fast-path_struct}}
wks marked this conversation as resolved.
Show resolved Hide resolved
```

And pseudo-code for how you would reset the `BumpPointer`s for all mutators in `resume_mutators`. Note that these mutators are the runtime's actual mutator threads (i.e. where the cached bump pointers are stored) and are different from MMTk's `Mutator` struct.
Expand Down Expand Up @@ -120,7 +120,7 @@ Once MMTk is initialized, a binding can get the memory offset for the default al
with the default allocation semantics, we can use the offset to get a reference to the actual allocator (with unsafe code), and allocate with the allocator.

```rust
{{#include ../../../../../vmbindings/dummyvm/src/tests/doc_avoid_resolving_allocator.rs:avoid_resolving_allocator}}
{{#include ../../../../../src/vm/tests/mock_tests/mock_test_doc_avoid_resolving_allocator.rs:avoid_resolving_allocator}}
```

## Emitting Allocation Sequence in a JIT Compiler
Expand Down
17 changes: 0 additions & 17 deletions examples/allocation_benchmark.c

This file was deleted.

23 changes: 0 additions & 23 deletions examples/bench.sh

This file was deleted.

102 changes: 0 additions & 102 deletions examples/build.py

This file was deleted.

27 changes: 0 additions & 27 deletions examples/main.c

This file was deleted.

Loading
Loading