@@ -5,7 +5,6 @@ use crate::plan::Plan;
5
5
use crate :: policy:: copyspace:: CopySpace ;
6
6
use crate :: policy:: space:: Space ;
7
7
use crate :: scheduler:: * ;
8
- use crate :: util:: conversions;
9
8
use crate :: util:: copy:: CopySemantics ;
10
9
use crate :: util:: heap:: VMRequest ;
11
10
use crate :: util:: metadata:: side_metadata:: SideMetadataSanity ;
@@ -22,7 +21,7 @@ use mmtk_macros::PlanTraceObject;
22
21
/// Common implementation for generational plans. Each generational plan
23
22
/// should include this type, and forward calls to it where possible.
24
23
#[ derive( PlanTraceObject ) ]
25
- pub struct Gen < VM : VMBinding > {
24
+ pub struct CommonGenPlan < VM : VMBinding > {
26
25
/// The nursery space.
27
26
#[ trace( CopySemantics :: PromoteToMature ) ]
28
27
pub nursery : CopySpace < VM > ,
@@ -36,21 +35,21 @@ pub struct Gen<VM: VMBinding> {
36
35
pub full_heap_gc_count : Arc < Mutex < EventCounter > > ,
37
36
}
38
37
39
- impl < VM : VMBinding > Gen < VM > {
38
+ impl < VM : VMBinding > CommonGenPlan < VM > {
40
39
pub fn new ( mut args : CreateSpecificPlanArgs < VM > ) -> Self {
41
40
let nursery = CopySpace :: new (
42
41
args. get_space_args (
43
42
"nursery" ,
44
43
true ,
45
- VMRequest :: fixed_extent ( args. global_args . options . get_max_nursery ( ) , false ) ,
44
+ VMRequest :: fixed_extent ( args. global_args . options . get_max_nursery_bytes ( ) , false ) ,
46
45
) ,
47
46
true ,
48
47
) ;
49
48
let common = CommonPlan :: new ( args) ;
50
49
51
50
let full_heap_gc_count = common. base . stats . new_event_counter ( "majorGC" , true , true ) ;
52
51
53
- Gen {
52
+ CommonGenPlan {
54
53
nursery,
55
54
common,
56
55
gc_full_heap : AtomicBool :: default ( ) ,
@@ -97,28 +96,35 @@ impl<VM: VMBinding> Gen<VM> {
97
96
///
98
97
/// Returns `true` if the nursery has grown to the extent that it may not be able to be copied
99
98
/// into the mature space.
100
- fn virtual_memory_exhausted < P : Plan > ( & self , plan : & P ) -> bool {
99
+ fn virtual_memory_exhausted ( plan : & dyn GenerationalPlan < VM = VM > ) -> bool {
101
100
( ( plan. get_collection_reserved_pages ( ) as f64
102
101
* VM :: VMObjectModel :: VM_WORST_CASE_COPY_EXPANSION ) as usize )
103
102
> plan. get_mature_physical_pages_available ( )
104
103
}
105
104
106
105
/// Check if we need a GC based on the nursery space usage. This method may mark
107
106
/// the following GC as a full heap GC.
108
- pub fn collection_required < P : Plan > (
107
+ pub fn collection_required < P : Plan < VM = VM > > (
109
108
& self ,
110
109
plan : & P ,
111
110
space_full : bool ,
112
111
space : Option < & dyn Space < VM > > ,
113
112
) -> bool {
114
- let nursery_full = self . nursery . reserved_pages ( )
115
- >= ( conversions:: bytes_to_pages_up ( self . common . base . options . get_max_nursery ( ) ) ) ;
113
+ let cur_nursery = self . nursery . reserved_pages ( ) ;
114
+ let max_nursery = self . common . base . options . get_max_nursery_pages ( ) ;
115
+ let nursery_full = cur_nursery >= max_nursery;
116
+ trace ! (
117
+ "nursery_full = {:?} (nursery = {}, max_nursery = {})" ,
118
+ nursery_full,
119
+ cur_nursery,
120
+ max_nursery,
121
+ ) ;
116
122
117
123
if nursery_full {
118
124
return true ;
119
125
}
120
126
121
- if self . virtual_memory_exhausted ( plan) {
127
+ if Self :: virtual_memory_exhausted ( plan. generational ( ) . unwrap ( ) ) {
122
128
return true ;
123
129
}
124
130
@@ -146,11 +152,12 @@ impl<VM: VMBinding> Gen<VM> {
146
152
147
153
/// Check if we should do a full heap GC. It returns true if we should have a full heap GC.
148
154
/// It also sets gc_full_heap based on the result.
149
- pub fn requires_full_heap_collection < P : Plan > ( & self , plan : & P ) -> bool {
155
+ pub fn requires_full_heap_collection < P : Plan < VM = VM > > ( & self , plan : & P ) -> bool {
150
156
// Allow the same 'true' block for if-else.
151
157
// The conditions are complex, and it is easier to read if we put them to separate if blocks.
152
158
#[ allow( clippy:: if_same_then_else, clippy:: needless_bool) ]
153
159
let is_full_heap = if crate :: plan:: generational:: FULL_NURSERY_GC {
160
+ trace ! ( "full heap: forced full heap" ) ;
154
161
// For barrier overhead measurements, we always do full gc in nursery collections.
155
162
true
156
163
} else if self
@@ -160,6 +167,7 @@ impl<VM: VMBinding> Gen<VM> {
160
167
. load ( Ordering :: SeqCst )
161
168
&& * self . common . base . options . full_heap_system_gc
162
169
{
170
+ trace ! ( "full heap: user triggered" ) ;
163
171
// User triggered collection, and we force full heap for user triggered collection
164
172
true
165
173
} else if self . next_gc_full_heap . load ( Ordering :: SeqCst )
@@ -170,9 +178,18 @@ impl<VM: VMBinding> Gen<VM> {
170
178
. load ( Ordering :: SeqCst )
171
179
> 1
172
180
{
181
+ trace ! (
182
+ "full heap: next_gc_full_heap = {}, cur_collection_attempts = {}" ,
183
+ self . next_gc_full_heap. load( Ordering :: SeqCst ) ,
184
+ self . common
185
+ . base
186
+ . cur_collection_attempts
187
+ . load( Ordering :: SeqCst )
188
+ ) ;
173
189
// Forces full heap collection
174
190
true
175
- } else if self . virtual_memory_exhausted ( plan) {
191
+ } else if Self :: virtual_memory_exhausted ( plan. generational ( ) . unwrap ( ) ) {
192
+ trace ! ( "full heap: virtual memory exhausted" ) ;
176
193
true
177
194
} else {
178
195
// We use an Appel-style nursery. The default GC (even for a "heap-full" collection)
@@ -250,8 +267,16 @@ impl<VM: VMBinding> Gen<VM> {
250
267
/// [`get_available_pages`](crate::plan::Plan::get_available_pages)
251
268
/// whose value depends on which spaces have been released.
252
269
pub fn should_next_gc_be_full_heap ( plan : & dyn Plan < VM = VM > ) -> bool {
253
- plan. get_available_pages ( )
254
- < conversions:: bytes_to_pages_up ( plan. base ( ) . options . get_min_nursery ( ) )
270
+ let available = plan. get_available_pages ( ) ;
271
+ let min_nursery = plan. base ( ) . options . get_min_nursery_pages ( ) ;
272
+ let next_gc_full_heap = available < min_nursery;
273
+ trace ! (
274
+ "next gc will be full heap? {}, availabe pages = {}, min nursery = {}" ,
275
+ next_gc_full_heap,
276
+ available,
277
+ min_nursery
278
+ ) ;
279
+ next_gc_full_heap
255
280
}
256
281
257
282
/// Set next_gc_full_heap to the given value.
@@ -272,3 +297,22 @@ impl<VM: VMBinding> Gen<VM> {
272
297
self . nursery . reserved_pages ( ) + self . common . get_used_pages ( )
273
298
}
274
299
}
300
+
301
+ /// This trait include methods that are specific to generational plans.
302
+ pub trait GenerationalPlan : Plan {
303
+ /// Return the common generational implementation [`crate::plan::generational::global::CommonGenPlan`].
304
+ fn common_gen ( & self ) -> & CommonGenPlan < Self :: VM > ;
305
+
306
+ /// Return the number of pages available for allocation into the mature space.
307
+ fn get_mature_physical_pages_available ( & self ) -> usize ;
308
+
309
+ /// Return the number of used pages in the mature space.
310
+ fn get_mature_reserved_pages ( & self ) -> usize ;
311
+ }
312
+
313
+ /// Is current GC only collecting objects allocated since last GC? This method can be called
314
+ /// with any plan (generational or not). For non generational plans, it will always return false.
315
+ pub fn is_nursery_gc < VM : VMBinding > ( plan : & dyn Plan < VM = VM > ) -> bool {
316
+ plan. generational ( )
317
+ . map_or ( false , |plan| plan. common_gen ( ) . is_current_gc_nursery ( ) )
318
+ }
0 commit comments