Skip to content

Commit 658bce8

Browse files
authored
Introduce MockVM (#1049)
This PR introduces `MockVM`, a type that implements `VMBinding` and allows users to control the behavior of each method for testing. This PR also moves all the tests in the current `DummyVM` to `MockVM`, and removes the current `DummyVM`. This PR closes #99. Note that the current `MockVM` implementation does not allow changing constants or associated types in `VMBinding` -- I would suggest we create another issue to track this problem. Changes: * Introduce `MockVM`, and write all the current `DummyVM` tests with `MockVM`. * Remove `DummyVM`, and remove `./examples` which uses `DummyVM`. * Change CI scripts to run tests with `MockVM`. * Remove `pub` visibility for some modules. Those modules were exposed so we can test them from `DummyVM`. As now `MockVM` is a part of the main crate, we can test private items. We no longer need `pub` for those modules.
1 parent bf1bad3 commit 658bce8

File tree

89 files changed

+3198
-2856
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+3198
-2856
lines changed

.github/scripts/ci-style.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ if [[ $arch == "x86_64" && $os == "linux" ]]; then
2727
cargo clippy --tests --features perf_counter
2828
fi
2929

30+
# mock tests
31+
cargo clippy --features mock_test
32+
cargo clippy --features mock_test --tests
33+
cargo clippy --features mock_test --benches
34+
3035
# --- Check auxiliary crate ---
3136

3237
style_check_auxiliary_crate() {
@@ -37,4 +42,3 @@ style_check_auxiliary_crate() {
3742
}
3843

3944
style_check_auxiliary_crate macros
40-
style_check_auxiliary_crate vmbindings/dummyvm

.github/scripts/ci-test.sh

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,29 @@ if [[ $arch == "x86_64" && $os == "linux" ]]; then
1111
cargo test --features perf_counter
1212
fi
1313

14-
./examples/build.py
15-
1614
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\+')
1715

18-
# Test with DummyVM (each test in a separate run)
19-
cd vmbindings/dummyvm
20-
for fn in $(ls src/tests/*.rs); do
21-
t=$(basename -s .rs $fn)
22-
23-
if [[ $t == "mod" ]]; then
24-
continue
25-
fi
16+
# Test with mock VM:
17+
# - Find all the files that start with mock_test_
18+
# - Run each file separately with cargo test, with the feature 'mock_test'
19+
find ./src ./tests -type f -name "mock_test_*" | while read -r file; do
20+
t=$(basename -s .rs $file)
2621

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

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

4035
# Run the test with each plan it needs.
4136
for MMTK_PLAN in $PLANS; do
42-
env MMTK_PLAN=$MMTK_PLAN cargo test --features "$FEATURES" -- $t;
37+
env MMTK_PLAN=$MMTK_PLAN cargo test --features mock_test,"$FEATURES" -- $t;
4338
done
4439
done
45-

Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,26 @@ sysinfo = "0.29"
5454
[dev-dependencies]
5555
paste = "1.0.8"
5656
rand = "0.8.5"
57+
criterion = "0.4"
5758

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

62+
[[bench]]
63+
name = "main"
64+
harness = false
65+
6166
[features]
6267
default = []
6368

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

73+
# This feature is only used for tests with MockVM.
74+
# CI scripts run those tests with this feature.
75+
mock_test = []
76+
6877
# .github/scripts/ci-common.sh extracts features from the following part (including from comments).
6978
# So be careful when editing or adding stuff to the section below.
7079

benches/alloc.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use criterion::Criterion;
2+
3+
use mmtk::memory_manager;
4+
use mmtk::util::test_util::fixtures::*;
5+
use mmtk::AllocationSemantics;
6+
7+
pub fn bench(c: &mut Criterion) {
8+
// Disable GC so we won't trigger GC
9+
let mut fixture = MutatorFixture::create_with_heapsize(1 << 30);
10+
memory_manager::disable_collection(fixture.mmtk());
11+
c.bench_function("alloc", |b| {
12+
b.iter(|| {
13+
let _addr =
14+
memory_manager::alloc(&mut fixture.mutator, 8, 8, 0, AllocationSemantics::Default);
15+
})
16+
});
17+
}

benches/main.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use criterion::criterion_group;
2+
use criterion::criterion_main;
3+
use criterion::Criterion;
4+
5+
// As we can only initialize one MMTk instance, we have to run each benchmark in a separate process.
6+
// So we only register one benchmark to criterion ('bench_main'), and based on the env var MMTK_BENCH,
7+
// we pick the right benchmark to run.
8+
9+
// The benchmark can be executed with the following command. The feature `mock_test` is required, as the tests use MockVM.
10+
// MMTK_BENCH=alloc cargo bench --features mock_test
11+
// MMTK_BENCH=sft cargo bench --features mock_test
12+
13+
// [Yi] I am not sure if these benchmarks are helpful any more after the MockVM refactoring. MockVM is really slow, as it
14+
// is accessed with a lock, and it dispatches every call to function pointers in a struct. These tests may use MockVM,
15+
// so they become slower as well. And the slowdown
16+
// from MockVM may hide the actual performance difference when we change the functions that are benchmarked.
17+
// We may want to improve the MockVM implementation so we can skip dispatching for benchmarking, or introduce another MockVM
18+
// implementation for benchmarking.
19+
// 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
20+
// them.
21+
22+
mod alloc;
23+
mod sft;
24+
25+
fn bench_main(c: &mut Criterion) {
26+
match std::env::var("MMTK_BENCH") {
27+
Ok(bench) => match bench.as_str() {
28+
"alloc" => alloc::bench(c),
29+
"sft" => sft::bench(c),
30+
_ => panic!("Unknown benchmark {:?}", bench),
31+
},
32+
Err(_) => panic!("Need to name a benchmark by the env var MMTK_BENCH"),
33+
}
34+
}
35+
36+
criterion_group!(benches, bench_main);
37+
criterion_main!(benches);

benches/sft.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use criterion::black_box;
2+
use criterion::Criterion;
3+
4+
use mmtk::memory_manager;
5+
use mmtk::util::test_util::fixtures::*;
6+
use mmtk::util::test_util::mock_vm::*;
7+
use mmtk::vm::ObjectModel;
8+
use mmtk::vm::VMBinding;
9+
use mmtk::AllocationSemantics;
10+
11+
pub fn bench(c: &mut Criterion) {
12+
let mut fixture = MutatorFixture::create();
13+
let addr = memory_manager::alloc(&mut fixture.mutator, 8, 8, 0, AllocationSemantics::Default);
14+
let obj = <MockVM as VMBinding>::VMObjectModel::address_to_ref(addr);
15+
16+
c.bench_function("sft read", |b| {
17+
b.iter(|| memory_manager::is_in_mmtk_spaces::<MockVM>(black_box(obj)))
18+
});
19+
}

docs/userguide/src/portingguide/perf_tuning/alloc.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ If the VM is not implemented in Rust,
3333
the binding needs to turn the boxed pointer into a raw pointer before storing it.
3434

3535
```rust
36-
{{#include ../../../../../vmbindings/dummyvm/src/tests/doc_mutator_storage.rs:mutator_storage_boxed_pointer}}
36+
{{#include ../../../../../src/vm/tests/mock_tests/mock_test_doc_mutator_storage.rs:mutator_storage_boxed_pointer}}
3737
```
3838

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

4646
```rust
47-
{{#include ../../../../../vmbindings/dummyvm/src/tests/doc_mutator_storage.rs:mutator_storage_embed_mutator_struct}}
47+
{{#include ../../../../../src/vm/tests/mock_tests/mock_test_doc_mutator_storage.rs:mutator_storage_embed_mutator_struct}}
4848
```
4949

5050
### Option 3: Embed the fast-path struct
@@ -78,7 +78,7 @@ which includes (but not limited to) `NoGC`, `SemiSpace`, `Immix`, generational p
7878
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`.
7979

8080
```rust
81-
{{#include ../../../../../vmbindings/dummyvm/src/tests/doc_mutator_storage.rs:mutator_storage_embed_fast-path_struct}}
81+
{{#include ../../../../../src/vm/tests/mock_tests/mock_test_doc_mutator_storage.rs:mutator_storage_embed_fastpath_struct}}
8282
```
8383

8484
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.
@@ -120,7 +120,7 @@ Once MMTk is initialized, a binding can get the memory offset for the default al
120120
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.
121121

122122
```rust
123-
{{#include ../../../../../vmbindings/dummyvm/src/tests/doc_avoid_resolving_allocator.rs:avoid_resolving_allocator}}
123+
{{#include ../../../../../src/vm/tests/mock_tests/mock_test_doc_avoid_resolving_allocator.rs:avoid_resolving_allocator}}
124124
```
125125

126126
## Emitting Allocation Sequence in a JIT Compiler

examples/allocation_benchmark.c

Lines changed: 0 additions & 17 deletions
This file was deleted.

examples/bench.sh

Lines changed: 0 additions & 23 deletions
This file was deleted.

examples/build.py

Lines changed: 0 additions & 102 deletions
This file was deleted.

0 commit comments

Comments
 (0)