Skip to content

Commit d538987

Browse files
authored
Remove the immix_stress_copying feature. Replace with separate options. (#1324)
`immix_stress_copying` may cause confusion with the stress GC and the stress factor, as `immix_stress_copying` does not imply stress GCs. This PR removes `immix_stress_copying`, and replaces with separate options to control the specific behavior.
1 parent 9f862ad commit d538987

File tree

8 files changed

+75
-37
lines changed

8 files changed

+75
-37
lines changed

Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,6 @@ immix_non_moving = []
157157
# if `immix_non_moving` is in use.
158158
sticky_immix_non_moving_nursery = []
159159

160-
# Turn on stress copying for Immix. This is a debug feature to test copying for Immix plans.
161-
immix_stress_copying = []
162160
# Reduce block size for ImmixSpace. This mitigates fragmentation when defrag is disabled.
163161
immix_smaller_block = []
164162
# Zero the unmarked lines after a GC cycle in immix. This helps debug untraced objects.

docs/userguide/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
- [Debugging Tips](portingguide/debugging/prefix.md)
3737
- [Enabling Debug Assertions](portingguide/debugging/assertions.md)
3838
- [Print Object Info](portingguide/debugging/print_obj_info.md)
39+
- [Copying in Immix](portingguide/debugging/immix.md)
3940
- [Performance Tuning](portingguide/perf_tuning/prefix.md)
4041
- [Link Time Optimization](portingguide/perf_tuning/lto.md)
4142
- [Optimizing Allocation](portingguide/perf_tuning/alloc.md)

docs/userguide/src/migration/prefix.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,25 @@ API changes:
5353
* This means you can parse a string into `T` when setting an `MMTKOption<T>`. For
5454
example, `options.plan.set(user_input.parse()?);`.
5555

56+
### The feature `immix_stress_copying` is removed.
57+
58+
```admonish tldr
59+
The feature `immix_stress_copying` is removed. Bindings can use MMTk options with the following values
60+
to achieve the same behavior as before: `immix_always_defrag=true,immix_defrag_every_block=true,immix_defrag_headroom_percent=50`
61+
```
62+
63+
API changes:
64+
65+
- The feature `immix_stress_copying` is removed.
66+
- module `util::options`
67+
+ `Options` includes `immix_always_defrag`, which defaults to `false`.
68+
+ `Options` includes `immix_defrag_every_block`, which defaults to `false`.
69+
+ `Options` includes `immix_defrag_headroom_percent`, which defaults to `2`.
70+
71+
See also:
72+
73+
- PR: <https://github.com/mmtk/mmtk-core/pull/1324>
74+
5675
## 0.30.0
5776

5877
### `live_bytes_in_last_gc` becomes a runtime option, and returns a map for live bytes in each space
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Debugging Copying in Immix Plans
2+
3+
Immix uses opportunitic copying, which means it does not always copy objects.
4+
So a bug related with copying may be non-deterministic with Immix plans.
5+
6+
One way to make copying more deterministic is to use the following
7+
[options](https://docs.mmtk.io/api/mmtk/util/options/struct.Options.html) to
8+
change the copying behavior of Immix.
9+
10+
| Option | Default Value | Note |
11+
|---------------------------------|-----------------|-----------------------------------------------------------------------------|
12+
| `immix_always_defrag` | `false` | Immix only does defrag GC when necessary. Set to `true` to make every GC a defrag GC |
13+
| `immix_defrag_every_block` | `false` | Immix only defrags the most heavily fragmented blocks. Set to `true` to make Immix defrag every block with equal chances |
14+
| `immix_defrag_headroom_percent` | `2` | Immix uses 2% of the heap for defraging. We can reserve more headroom to copy more objects. 50% makes Immix behave like SemiSpace. |
15+
16+
A common way to maximumally expose Immix copying bugs is to run with the following values:
17+
```rust
18+
// Set options with MMTkBuilder
19+
builder.options.immix_always_defrag.set(true);
20+
builder.options.immix_defrag_every_block.set(true);
21+
builder.options.immix_defrag_headroom_percent.set(50);
22+
```
23+
24+
These options can also be used along with stress GC options:
25+
```rust
26+
// Do a stress GC for every 10MB allocation
27+
builder.options.stress_factor.set(10485760);
28+
```
29+
30+
Options can also be set using environment variables.
31+
```console
32+
export MMTK_IMMIX_ALWAYS_DEFRAG=true
33+
export MMTK_IMMIX_DEFRAG_EVERY_BLOCK=true
34+
export MMTK_IMMIX_DEFRAG_HEADROOM_PERCENT=50
35+
export MMTK_STRESS_FACTOR=10485760
36+
```
37+

src/policy/immix/defrag.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ impl Defrag {
4545
const NUM_BINS: usize = (Block::LINES >> 1) + 1;
4646
const DEFRAG_LINE_REUSE_RATIO: f32 = 0.99;
4747
const MIN_SPILL_THRESHOLD: usize = 2;
48-
const DEFRAG_HEADROOM_PERCENT: usize = super::DEFRAG_HEADROOM_PERCENT;
4948

5049
/// Allocate a new local histogram.
5150
pub const fn new_histogram(&self) -> Histogram {
@@ -73,12 +72,13 @@ impl Defrag {
7372
user_triggered: bool,
7473
exhausted_reusable_space: bool,
7574
full_heap_system_gc: bool,
75+
stress_defrag: bool,
7676
) {
7777
let in_defrag = defrag_enabled
7878
&& (emergency_collection
7979
|| (collection_attempts > 1)
8080
|| !exhausted_reusable_space
81-
|| super::STRESS_DEFRAG
81+
|| stress_defrag
8282
|| (collect_whole_heap && user_triggered && full_heap_system_gc));
8383
info!("Defrag: {}", in_defrag);
8484
probe!(mmtk, immix_defrag, in_defrag);
@@ -88,7 +88,9 @@ impl Defrag {
8888

8989
/// Get the number of defrag headroom pages.
9090
pub fn defrag_headroom_pages<VM: VMBinding>(&self, space: &ImmixSpace<VM>) -> usize {
91-
space.get_page_resource().reserved_pages() * Self::DEFRAG_HEADROOM_PERCENT / 100
91+
space.get_page_resource().reserved_pages()
92+
* (*space.common().options.immix_defrag_headroom_percent)
93+
/ 100
9294
}
9395

9496
/// Check if the defrag space is exhausted.

src/policy/immix/immixspace.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ impl<VM: VMBinding> ImmixSpace<VM> {
401401
user_triggered_collection,
402402
self.reusable_blocks.len() == 0,
403403
full_heap_system_gc,
404+
*self.common.options.immix_always_defrag,
404405
);
405406
self.defrag.in_defrag()
406407
}
@@ -912,7 +913,7 @@ impl<VM: VMBinding> PrepareBlockState<VM> {
912913
}
913914

914915
impl<VM: VMBinding> GCWork<VM> for PrepareBlockState<VM> {
915-
fn do_work(&mut self, _worker: &mut GCWorker<VM>, _mmtk: &'static MMTK<VM>) {
916+
fn do_work(&mut self, _worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
916917
// Clear object mark table for this chunk
917918
self.reset_object_mark();
918919
// Iterate over all blocks in this chunk
@@ -926,7 +927,7 @@ impl<VM: VMBinding> GCWork<VM> for PrepareBlockState<VM> {
926927
let is_defrag_source = if !self.space.is_defrag_enabled() {
927928
// Do not set any block as defrag source if defrag is disabled.
928929
false
929-
} else if super::DEFRAG_EVERY_BLOCK {
930+
} else if *mmtk.options.immix_defrag_every_block {
930931
// Set every block as defrag source if so desired.
931932
true
932933
} else if let Some(defrag_threshold) = self.defrag_threshold {

src/policy/immix/mod.rs

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,6 @@ pub const MAX_IMMIX_OBJECT_SIZE: usize = Block::BYTES >> 1;
1414
/// Mark/sweep memory for block-level only
1515
pub const BLOCK_ONLY: bool = false;
1616

17-
// STRESS COPYING: Set the feature 'immix_stress_copying' so that Immix will copy as many objects as possible.
18-
// Useful for debugging copying GC if you cannot use SemiSpace.
19-
//
20-
// | constant | when | value | comment |
21-
// |---------------------------|---------|---------|----------------------------------------------------------------------|
22-
// | `STRESS_DEFRAG` | default | `false` | By default, Immix only does defrag GC when necessary. |
23-
// | `STRESS_DEFRAG` | stress | `true` | Set to `true` to force every GC to be defrag GC. |
24-
// | | | | |
25-
// | `DEFRAG_EVERY_BLOCK` | default | `false` | By default, Immix only defrags the most heavily fragmented blocks. |
26-
// | `DEFRAG_EVERY_BLOCK` | stress | `true` | Set to `true` to make every block a defrag source. |
27-
// | | | | |
28-
// | `DEFRAG_HEADROOM_PERCENT` | default | `2` | Immix stops copying when space exhausted. |
29-
// | `DEFRAG_HEADROOM_PERCENT` | stress | `50` | Reserve enough headroom to copy all objects. 50% is like SemiSpace. |
30-
31-
/// Make every GC a defragment GC. (for debugging)
32-
pub const STRESS_DEFRAG: bool = cfg!(feature = "immix_stress_copying");
33-
34-
/// Mark every allocated block as defragmentation source before GC. (for debugging)
35-
pub const DEFRAG_EVERY_BLOCK: bool = cfg!(feature = "immix_stress_copying");
36-
37-
/// Percentage of heap size reserved for defragmentation.
38-
/// According to [this paper](https://doi.org/10.1145/1375581.1375586), Immix works well with
39-
/// headroom between 1% to 3% of the heap size.
40-
pub const DEFRAG_HEADROOM_PERCENT: usize = if cfg!(feature = "immix_stress_copying") {
41-
50
42-
} else {
43-
2
44-
};
45-
4617
/// Mark lines when scanning objects.
4718
/// Otherwise, do it at mark time.
4819
pub const MARK_LINE_AT_SCAN_TIME: bool = true;

src/util/options.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -901,7 +901,16 @@ options! {
901901
/// This only affects the memory for MMTk spaces.
902902
transparent_hugepages: bool [|v: &bool| !v || cfg!(target_os = "linux")] = false,
903903
/// Count live bytes for objects in each space during a GC.
904-
count_live_bytes_in_gc: bool [always_valid] = false
904+
count_live_bytes_in_gc: bool [always_valid] = false,
905+
/// Make every GC a defragment GC. (for debugging)
906+
immix_always_defrag: bool [always_valid] = false,
907+
/// Mark every allocated block as defragmentation source before GC. (for debugging)
908+
/// Depending on the defrag headroom, Immix may not be able to defrag every block even if this option is set to true.
909+
immix_defrag_every_block: bool [always_valid] = false,
910+
/// Percentage of heap size reserved for defragmentation.
911+
/// According to [this paper](https://doi.org/10.1145/1375581.1375586), Immix works well with
912+
/// headroom between 1% to 3% of the heap size.
913+
immix_defrag_headroom_percent: usize [|v: &usize| *v <= 50] = 2
905914
}
906915

907916
#[cfg(test)]

0 commit comments

Comments
 (0)