-
Notifications
You must be signed in to change notification settings - Fork 76
Refactor iterate_meta_bits #1181
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
Conversation
Here are some benchmark results.
The benchmarks can be found in
Note: You need This PR makes But neither master nor this PR is as fast as calling I'll try to rebase #1174 on top of this PR and mark both PRs for review if the refactored code is pleasant for implementing heap traversal with. |
Let's add it back when implementing VO bit scanning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The refactoring looks good to me. I have some comments about exposing private functions for testing/benchmarking.
Cargo.toml
Outdated
@@ -75,6 +75,10 @@ perf_counter = ["pfm"] | |||
# CI scripts run those tests with this feature. | |||
mock_test = [] | |||
|
|||
# This feature is only used for benchmarks. | |||
# It will expose some private functions for benchmarking. | |||
bench = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest renaming this to something like test_private
or test_private_items
. This would be clear for both the function definitions in mmtk-core, and for the bench/test modules outside mmtk-core.
I found the following code confusing: we are in the bench crate, why do we have the bench
feature for some tests but not other tests? A better feature name would make it more clear.
#[cfg(feature = "bench")]
mod bulk_meta;
#[cfg(feature = "mock_test")]
mod mock_bench;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is also posssible to have mock_test = ["test_private_item"]
. In that case, you don't have to change bench_main
and you can simply add your benchmark.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am OK with renaming it to test_private
.
The reason for not requiring the "bench" feature for some test cases is because the current mock tests don't require any of the items exposed from the "bench" feature. But it will probably make things clearer to unconditionally require the "bench" or "test_private" feature when doing benchmarks.
benches/main.rs
Outdated
// Some benchmarks rely on the "bench" feature to expose some private functions. | ||
// Run them with `cargo bench --features bench`. | ||
#[cfg(feature = "bench")] | ||
bulk_meta::bzero_bset::bench(_c); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comments about the features. However, if you do want to separate mock_test
and bench
, you should create a pattern here so others can create new benchmarks with the bench
feature easily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Criterion benchmarks usually don't use the match
statement to select benchmarks. Instead it is similar to running tests. It can be selected on the command line. For example,
cargo bench --features test_private -- bzero
It will select all benchmarks that have "bzero" in the name.
The mock tests are special. Because they rely on a global singleton MockVM
, we can only run one test at a time. Previously, we rely on the environment variable MMTK_BENCH
to ensure only one mock test benchmark is selected at a time.
At the moment, I just isolated the match
statement into the bench_mock
function, and leave everything else in bench_main
. To install more benchmarks, we simply call c.bench_function
, or call functions in other modules (such as bulk_meta::bzero_bset::bench
) to install more benchmarks. In the future, the bench_main
function will simply call more functions, like these lines: https://github.com/mmtk/mmtk-core/pull/1174/files#diff-9ad1cee13898f4e5ac553eb567cd47a8de7d8852bf292c3d8d5991e23677db32R50-R51
In the future, we can refactor the mock_bench
so that we can use the command line to select benchmarks, and as long as we select only one benchmark at a time, they will still be able to run. But if that's impossible, we can still rely on the environment variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have now completely isolated mock benches from other benchmarks. Now regular benchmarks are in a separate module regular_bench
, and each module inside it has its fn bench
method for registering benchmarks. When others add more regular benchmarks, they change the fn bench
in the right module; when adding a mock benchmark, they edit mock_bench::bench
which now holds the match
statement.
pub(super) fn zero_meta_bits( | ||
/// Expose `zero_meta_bits` when running `cargo bench`. | ||
#[cfg(feature = "bench")] | ||
pub fn bench_zero_meta_bits( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may move these functions to a different module, like util::test_util
, so we don't need to worry about duplicate function names. Also they won't appear as a disruption when we read the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to just add a top-level module crate::testing
because they are not really "utilities for testing". They are just the functions to be tested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am slightly concerned that it will appear at the top-level of our docs. But maybe it is okay.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved it to util::test_private
. It does not appear on the first page of the cargo docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This PR refactors the mechanism for visiting (reading and/or updating) side metadata in bulk, specifically the function
SideMetadataSpec::iterate_meta_bits
.The function now uses a single
FnMut
callback instead of twoFn
callbacks. It uses the enum typeBitByteRange
to distinguish whole byte ranges from bit ranges in a byte. This allows the user to capture variables mutably in the callback. This also removes theCell
used infind_prev_non_zero_value_fast
.The function is made non-recursive to improve the performance. Some test cases are added to test for corner cases.
The function is moved to a dedicated
ranges
module and renamed tobreak_bit_range
, for several reasons:SideMetadataSpec
, but it does not access any member ofSideMetadataSpec
.ranges
module in the future.bulk_update_metadata
.