Skip to content

Commit cfabadb

Browse files
EgorBoMaoni0jkotas
authored
GC: Mark all the in-range ro segments (#76251)
+ we need to proactively go mark all the in range ro segs because these objects' life time isn't accurately expressed. The expectation is all objects on ro segs are reported as marked. + fixed an existing bug - for full blocking GCs it's not enough to handle ro segs when gen start seg is not ephemeral, it needs to be checking for condemned gen because you can still have ro segs in range even with one segment per heap. + got rid of some unnecessary checks. + I do make the assumption that ro segs are always threaded at the beginning of gen2 so we can exit as soon as we see an rw seg. we actually always thread these into heap 0's gen2 seg list but I can see a chance of that changing, if we want a better balancing of work done for ro segs. + a bit of code refactoring since now we have more code related to ro segs. Co-authored-by: Maoni0 <[email protected]> Co-authored-by: Jan Kotas <[email protected]>
1 parent dd6696a commit cfabadb

File tree

5 files changed

+244
-89
lines changed

5 files changed

+244
-89
lines changed

src/coreclr/gc/gc.cpp

Lines changed: 160 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -8460,19 +8460,13 @@ uint32_t* translate_mark_array (uint32_t* ma)
84608460
return (uint32_t*)((uint8_t*)ma - size_mark_array_of (0, g_gc_lowest_address));
84618461
}
84628462

8463-
// from and end must be page aligned addresses.
8464-
void gc_heap::clear_mark_array (uint8_t* from, uint8_t* end, BOOL check_only/*=TRUE*/
84658463
#ifdef FEATURE_BASICFREEZE
8466-
, BOOL read_only/*=FALSE*/
8467-
#endif // FEATURE_BASICFREEZE
8468-
)
8464+
// end must be page aligned addresses.
8465+
void gc_heap::clear_mark_array (uint8_t* from, uint8_t* end, BOOL read_only/*=FALSE*/)
84698466
{
8470-
if(!gc_can_use_concurrent)
8471-
return;
8467+
assert (gc_can_use_concurrent);
84728468

8473-
#ifdef FEATURE_BASICFREEZE
84748469
if (!read_only)
8475-
#endif // FEATURE_BASICFREEZE
84768470
{
84778471
assert (from == align_on_mark_word (from));
84788472
}
@@ -8489,45 +8483,41 @@ void gc_heap::clear_mark_array (uint8_t* from, uint8_t* end, BOOL check_only/*=T
84898483
size_t beg_word = mark_word_of (align_on_mark_word (from));
84908484
//align end word to make sure to cover the address
84918485
size_t end_word = mark_word_of (align_on_mark_word (end));
8492-
dprintf (3, ("Calling clearing mark array [%Ix, %Ix[ for addresses [%Ix, %Ix[(%s)",
8486+
dprintf (3, ("Calling clearing mark array [%Ix, %Ix[ for addresses [%Ix, %Ix[",
84938487
(size_t)mark_word_address (beg_word),
84948488
(size_t)mark_word_address (end_word),
8495-
(size_t)from, (size_t)end,
8496-
(check_only ? "check_only" : "clear")));
8497-
if (!check_only)
8498-
{
8499-
uint8_t* op = from;
8500-
while (op < mark_word_address (beg_word))
8501-
{
8502-
mark_array_clear_marked (op);
8503-
op += mark_bit_pitch;
8504-
}
8489+
(size_t)from, (size_t)end));
85058490

8506-
memset (&mark_array[beg_word], 0, (end_word - beg_word)*sizeof (uint32_t));
8491+
uint8_t* op = from;
8492+
while (op < mark_word_address (beg_word))
8493+
{
8494+
mark_array_clear_marked (op);
8495+
op += mark_bit_pitch;
85078496
}
8497+
8498+
memset (&mark_array[beg_word], 0, (end_word - beg_word)*sizeof (uint32_t));
8499+
85088500
#ifdef _DEBUG
8509-
else
8501+
//Beware, it is assumed that the mark array word straddling
8502+
//start has been cleared before
8503+
//verify that the array is empty.
8504+
size_t markw = mark_word_of (align_on_mark_word (from));
8505+
size_t markw_end = mark_word_of (align_on_mark_word (end));
8506+
while (markw < markw_end)
85108507
{
8511-
//Beware, it is assumed that the mark array word straddling
8512-
//start has been cleared before
8513-
//verify that the array is empty.
8514-
size_t markw = mark_word_of (align_on_mark_word (from));
8515-
size_t markw_end = mark_word_of (align_on_mark_word (end));
8516-
while (markw < markw_end)
8517-
{
8518-
assert (!(mark_array [markw]));
8519-
markw++;
8520-
}
8521-
uint8_t* p = mark_word_address (markw_end);
8522-
while (p < end)
8523-
{
8524-
assert (!(mark_array_marked (p)));
8525-
p++;
8526-
}
8508+
assert (!(mark_array [markw]));
8509+
markw++;
8510+
}
8511+
uint8_t* p = mark_word_address (markw_end);
8512+
while (p < end)
8513+
{
8514+
assert (!(mark_array_marked (p)));
8515+
p++;
85278516
}
85288517
#endif //_DEBUG
85298518
}
85308519
}
8520+
#endif // FEATURE_BASICFREEZE
85318521
#endif //BACKGROUND_GC
85328522

85338523
//These work on untranslated card tables
@@ -9458,6 +9448,7 @@ void gc_heap::copy_brick_card_table()
94589448
}
94599449

94609450
#ifdef FEATURE_BASICFREEZE
9451+
// Note that we always insert at the head of the max_generation segment list.
94619452
BOOL gc_heap::insert_ro_segment (heap_segment* seg)
94629453
{
94639454
#ifdef FEATURE_EVENT_TRACE
@@ -9477,7 +9468,6 @@ BOOL gc_heap::insert_ro_segment (heap_segment* seg)
94779468
return FALSE;
94789469
}
94799470

9480-
//insert at the head of the segment list
94819471
generation* gen2 = generation_of (max_generation);
94829472
heap_segment* oldhead = generation_start_segment (gen2);
94839473
heap_segment_next (seg) = oldhead;
@@ -9515,13 +9505,12 @@ BOOL gc_heap::insert_ro_segment (heap_segment* seg)
95159505
// which portion of the mark array was committed and only decommit that.
95169506
void gc_heap::remove_ro_segment (heap_segment* seg)
95179507
{
9518-
//clear the mark bits so a new segment allocated in its place will have a clear mark bits
9508+
//clear the mark bits so a new segment allocated in its place will have a clear mark bits
95199509
#ifdef BACKGROUND_GC
95209510
if (gc_can_use_concurrent)
95219511
{
95229512
clear_mark_array (align_lower_mark_word (max (heap_segment_mem (seg), lowest_address)),
9523-
align_on_card_word (min (heap_segment_allocated (seg), highest_address)),
9524-
false); // read_only segments need the mark clear
9513+
align_on_card_word (min (heap_segment_allocated (seg), highest_address)));
95259514
}
95269515
#endif //BACKGROUND_GC
95279516

@@ -11000,20 +10989,39 @@ inline size_t my_get_size (Object* ob)
1100010989
#endif //COLLECTIBLE_CLASS
1100110990

1100210991
#ifdef BACKGROUND_GC
10992+
#ifdef FEATURE_BASICFREEZE
1100310993
inline
1100410994
void gc_heap::seg_clear_mark_array_bits_soh (heap_segment* seg)
1100510995
{
1100610996
uint8_t* range_beg = 0;
1100710997
uint8_t* range_end = 0;
1100810998
if (bgc_mark_array_range (seg, FALSE, &range_beg, &range_end))
1100910999
{
11010-
clear_mark_array (range_beg, align_on_mark_word (range_end), FALSE
11011-
#ifdef FEATURE_BASICFREEZE
11012-
, TRUE
11013-
#endif // FEATURE_BASICFREEZE
11014-
);
11000+
clear_mark_array (range_beg, align_on_mark_word (range_end), TRUE);
11001+
}
11002+
}
11003+
11004+
inline
11005+
void gc_heap::seg_set_mark_array_bits_soh (heap_segment* seg)
11006+
{
11007+
uint8_t* range_beg = 0;
11008+
uint8_t* range_end = 0;
11009+
if (bgc_mark_array_range (seg, FALSE, &range_beg, &range_end))
11010+
{
11011+
size_t beg_word = mark_word_of (align_on_mark_word (range_beg));
11012+
size_t end_word = mark_word_of (align_on_mark_word (range_end));
11013+
11014+
uint8_t* op = range_beg;
11015+
while (op < mark_word_address (beg_word))
11016+
{
11017+
mark_array_set_marked (op);
11018+
op += mark_bit_pitch;
11019+
}
11020+
11021+
memset (&mark_array[beg_word], 0xFF, (end_word - beg_word)*sizeof (uint32_t));
1101511022
}
1101611023
}
11024+
#endif //FEATURE_BASICFREEZE
1101711025

1101811026
void gc_heap::bgc_clear_batch_mark_array_bits (uint8_t* start, uint8_t* end)
1101911027
{
@@ -26493,6 +26501,19 @@ void gc_heap::mark_phase (int condemned_gen_number, BOOL mark_only_p)
2649326501
}
2649426502
}
2649526503

26504+
#ifdef FEATURE_BASICFREEZE
26505+
#ifdef USE_REGIONS
26506+
assert (!ro_segments_in_range);
26507+
#else //USE_REGIONS
26508+
if (ro_segments_in_range)
26509+
{
26510+
dprintf(3,("Marking in range ro segments"));
26511+
mark_ro_segments();
26512+
// Should fire an ETW event here.
26513+
}
26514+
#endif //USE_REGIONS
26515+
#endif //FEATURE_BASICFREEZE
26516+
2649626517
dprintf(3,("Marking Roots"));
2649726518

2649826519
GCScan::GcScanRoots(GCHeap::Promote,
@@ -27538,6 +27559,18 @@ void gc_heap::process_ephemeral_boundaries (uint8_t* x,
2753827559
}
2753927560
#endif //!USE_REGIONS
2754027561

27562+
#ifdef FEATURE_BASICFREEZE
27563+
inline
27564+
void gc_heap::seg_set_mark_bits (heap_segment* seg)
27565+
{
27566+
uint8_t* o = heap_segment_mem (seg);
27567+
while (o < heap_segment_allocated (seg))
27568+
{
27569+
set_marked (o);
27570+
o = o + Align (size(o));
27571+
}
27572+
}
27573+
2754127574
inline
2754227575
void gc_heap::seg_clear_mark_bits (heap_segment* seg)
2754327576
{
@@ -27548,36 +27581,77 @@ void gc_heap::seg_clear_mark_bits (heap_segment* seg)
2754827581
{
2754927582
clear_marked (o);
2755027583
}
27551-
o = o + Align (size (o));
27584+
o = o + Align (size (o));
2755227585
}
2755327586
}
2755427587

27555-
#ifdef FEATURE_BASICFREEZE
27556-
void gc_heap::sweep_ro_segments (heap_segment* start_seg)
27588+
// We have to do this for in range ro segments because these objects' life time isn't accurately
27589+
// expressed. The expectation is all objects on ro segs are live. So we just artifically mark
27590+
// all of them on the in range ro segs.
27591+
void gc_heap::mark_ro_segments()
2755727592
{
27558-
//go through all of the segment in range and reset the mark bit
27559-
heap_segment* seg = start_seg;
27560-
27561-
while (seg)
27593+
#ifdef USE_REGIONS
27594+
assert (!ro_segments_in_range);
27595+
#else //USE_REGIONS
27596+
if ((settings.condemned_generation == max_generation) && ro_segments_in_range)
2756227597
{
27563-
if (heap_segment_read_only_p (seg) &&
27564-
heap_segment_in_range_p (seg))
27598+
heap_segment* seg = generation_start_segment (generation_of (max_generation));
27599+
27600+
while (seg)
2756527601
{
27566-
#ifdef BACKGROUND_GC
27567-
if (settings.concurrent)
27602+
if (!heap_segment_read_only_p (seg))
27603+
break;
27604+
27605+
if (heap_segment_in_range_p (seg))
2756827606
{
27569-
seg_clear_mark_array_bits_soh (seg);
27607+
#ifdef BACKGROUND_GC
27608+
if (settings.concurrent)
27609+
{
27610+
seg_set_mark_array_bits_soh (seg);
27611+
}
27612+
else
27613+
#endif //BACKGROUND_GC
27614+
{
27615+
seg_set_mark_bits (seg);
27616+
}
2757027617
}
27571-
else
27618+
seg = heap_segment_next (seg);
27619+
}
27620+
}
27621+
#endif //USE_REGIONS
27622+
}
27623+
27624+
void gc_heap::sweep_ro_segments()
27625+
{
27626+
#ifdef USE_REGIONS
27627+
assert (!ro_segments_in_range);
27628+
#else //USE_REGIONS
27629+
if ((settings.condemned_generation == max_generation) && ro_segments_in_range)
27630+
{
27631+
heap_segment* seg = generation_start_segment (generation_of (max_generation));;
27632+
27633+
while (seg)
27634+
{
27635+
if (!heap_segment_read_only_p (seg))
27636+
break;
27637+
27638+
if (heap_segment_in_range_p (seg))
2757227639
{
27573-
seg_clear_mark_bits (seg);
27574-
}
27575-
#else //BACKGROUND_GC
27576-
seg_clear_mark_bits (seg);
27640+
#ifdef BACKGROUND_GC
27641+
if (settings.concurrent)
27642+
{
27643+
seg_clear_mark_array_bits_soh (seg);
27644+
}
27645+
else
2757727646
#endif //BACKGROUND_GC
27647+
{
27648+
seg_clear_mark_bits (seg);
27649+
}
27650+
}
27651+
seg = heap_segment_next (seg);
2757827652
}
27579-
seg = heap_segment_next (seg);
2758027653
}
27654+
#endif //USE_REGIONS
2758127655
}
2758227656
#endif // FEATURE_BASICFREEZE
2758327657

@@ -28956,16 +29030,8 @@ void gc_heap::plan_phase (int condemned_gen_number)
2895629030
}
2895729031

2895829032
#ifdef FEATURE_BASICFREEZE
28959-
#ifdef USE_REGIONS
28960-
assert (!ro_segments_in_range);
28961-
#else //USE_REGIONS
28962-
if ((generation_start_segment (condemned_gen1) != ephemeral_heap_segment) &&
28963-
ro_segments_in_range)
28964-
{
28965-
sweep_ro_segments (generation_start_segment (condemned_gen1));
28966-
}
28967-
#endif //USE_REGIONS
28968-
#endif // FEATURE_BASICFREEZE
29033+
sweep_ro_segments();
29034+
#endif //FEATURE_BASICFREEZE
2896929035

2897029036
#ifndef MULTIPLE_HEAPS
2897129037
int condemned_gen_index = get_stop_generation_index (condemned_gen_number);
@@ -35007,6 +35073,20 @@ void gc_heap::background_mark_phase ()
3500735073

3500835074
dprintf (GTC_LOG, ("FM: h%d: loh: %Id, soh: %Id, poh: %Id", heap_number, total_loh_size, total_soh_size, total_poh_size));
3500935075

35076+
#ifdef FEATURE_BASICFREEZE
35077+
#ifdef USE_REGIONS
35078+
assert (!ro_segments_in_range);
35079+
#else //USE_REGIONS
35080+
if (ro_segments_in_range)
35081+
{
35082+
dprintf (2, ("nonconcurrent marking in range ro segments"));
35083+
mark_ro_segments();
35084+
//concurrent_print_time_delta ("nonconcurrent marking in range ro segments");
35085+
concurrent_print_time_delta ("NRRO");
35086+
}
35087+
#endif //USE_REGIONS
35088+
#endif //FEATURE_BASICFREEZE
35089+
3501035090
dprintf (2, ("nonconcurrent marking stack roots"));
3501135091
GCScan::GcScanRoots(background_promote,
3501235092
max_generation, max_generation,
@@ -42364,13 +42444,8 @@ void gc_heap::background_sweep()
4236442444
#endif //DOUBLY_LINKED_FL
4236542445

4236642446
#ifdef FEATURE_BASICFREEZE
42367-
generation* max_gen = generation_of (max_generation);
42368-
if ((generation_start_segment (max_gen) != ephemeral_heap_segment) &&
42369-
ro_segments_in_range)
42370-
{
42371-
sweep_ro_segments (generation_start_segment (max_gen));
42372-
}
42373-
#endif // FEATURE_BASICFREEZE
42447+
sweep_ro_segments();
42448+
#endif //FEATURE_BASICFREEZE
4237442449

4237542450
if (current_c_gc_state != c_gc_state_planning)
4237642451
{
@@ -45350,6 +45425,9 @@ bool GCHeap::IsPromoted(Object* object)
4535045425
if (o)
4535145426
{
4535245427
((CObjectHeader*)o)->Validate(TRUE, TRUE, is_marked);
45428+
45429+
// Frozen objects aren't expected to be "not promoted" here
45430+
assert(is_marked || !IsInFrozenSegment(object));
4535345431
}
4535445432
#endif //_DEBUG
4535545433

0 commit comments

Comments
 (0)