Skip to content

Commit a163e80

Browse files
author
Maoni0
committed
manually porting 109804 to 9.0
1 parent 9f23ddb commit a163e80

File tree

3 files changed

+177
-14
lines changed

3 files changed

+177
-14
lines changed

src/coreclr/gc/gc.cpp

Lines changed: 159 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2890,10 +2890,14 @@ bool gc_heap::trigger_initial_gen2_p = false;
28902890

28912891
#ifdef BACKGROUND_GC
28922892
bool gc_heap::trigger_bgc_for_rethreading_p = false;
2893+
int gc_heap::total_bgc_threads = 0;
2894+
int gc_heap::last_bgc_n_heaps = 0;
2895+
int gc_heap::last_total_bgc_threads = 0;
28932896
#endif //BACKGROUND_GC
28942897

28952898
#ifdef STRESS_DYNAMIC_HEAP_COUNT
28962899
int gc_heap::heaps_in_this_gc = 0;
2900+
int gc_heap::bgc_to_ngc2_ratio = 0;
28972901
#endif //STRESS_DYNAMIC_HEAP_COUNT
28982902
#endif // DYNAMIC_HEAP_COUNT
28992903

@@ -14190,6 +14194,11 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size,
1419014194

1419114195
if ((dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes) && (conserve_mem_setting == 0))
1419214196
conserve_mem_setting = 5;
14197+
14198+
#ifdef STRESS_DYNAMIC_HEAP_COUNT
14199+
bgc_to_ngc2_ratio = (int)GCConfig::GetGCDBGCRatio();
14200+
dprintf (1, ("bgc_to_ngc2_ratio is %d", bgc_to_ngc2_ratio));
14201+
#endif
1419314202
#endif //DYNAMIC_HEAP_COUNT
1419414203

1419514204
if (conserve_mem_setting < 0)
@@ -21079,6 +21088,18 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation,
2107921088
if (!((n == max_generation) && *blocking_collection_p))
2108021089
{
2108121090
n = max_generation;
21091+
21092+
#ifdef STRESS_DYNAMIC_HEAP_COUNT
21093+
if (bgc_to_ngc2_ratio)
21094+
{
21095+
int r = (int)gc_rand::get_rand ((bgc_to_ngc2_ratio + 1) * 10);
21096+
dprintf (6666, ("%d - making this full GC %s", r, ((r < 10) ? "NGC2" : "BGC")));
21097+
if (r < 10)
21098+
{
21099+
*blocking_collection_p = TRUE;
21100+
}
21101+
}
21102+
#endif //STRESS_DYNAMIC_HEAP_COUNT
2108221103
}
2108321104
}
2108421105
}
@@ -24340,12 +24361,37 @@ void gc_heap::garbage_collect (int n)
2434024361
size_t saved_bgc_th_count_creation_failed = bgc_th_count_creation_failed;
2434124362
#endif //DYNAMIC_HEAP_COUNT
2434224363

24364+
// This is the count of threads that GCToEEInterface::CreateThread reported successful for.
24365+
int total_bgc_threads_running = 0;
2434324366
for (int i = 0; i < n_heaps; i++)
2434424367
{
24345-
prepare_bgc_thread (g_heaps[i]);
24368+
gc_heap* hp = g_heaps[i];
24369+
if (prepare_bgc_thread (hp))
24370+
{
24371+
assert (hp->bgc_thread_running);
24372+
if (!hp->bgc_thread_running)
24373+
{
24374+
dprintf (6666, ("h%d prepare succeeded but running is still false!", i));
24375+
GCToOSInterface::DebugBreak();
24376+
}
24377+
total_bgc_threads_running++;
24378+
}
24379+
else
24380+
{
24381+
break;
24382+
}
2434624383
}
2434724384

2434824385
#ifdef DYNAMIC_HEAP_COUNT
24386+
// Even if we don't do a BGC, we need to record how many threads were successfully created because those will
24387+
// be running.
24388+
total_bgc_threads = max (total_bgc_threads, total_bgc_threads_running);
24389+
24390+
if (total_bgc_threads_running != n_heaps)
24391+
{
24392+
dprintf (6666, ("wanted to have %d BGC threads but only have %d", n_heaps, total_bgc_threads_running));
24393+
}
24394+
2434924395
add_to_bgc_th_creation_history (current_gc_index,
2435024396
(bgc_th_count_created - saved_bgc_th_count_created),
2435124397
(bgc_th_count_created_th_existed - saved_bgc_th_count_created_th_existed),
@@ -24377,7 +24423,15 @@ void gc_heap::garbage_collect (int n)
2437724423
for (int i = 0; i < n_heaps; i++)
2437824424
{
2437924425
gc_heap* hp = g_heaps[i];
24380-
if (!(hp->bgc_thread) || !hp->commit_mark_array_bgc_init())
24426+
24427+
if (!(hp->bgc_thread_running))
24428+
{
24429+
assert (!(hp->bgc_thread));
24430+
}
24431+
24432+
// In theory we could be in a situation where bgc_thread_running is false but bgc_thread is non NULL. We don't
24433+
// support this scenario so don't do a BGC.
24434+
if (!(hp->bgc_thread_running && hp->bgc_thread && hp->commit_mark_array_bgc_init()))
2438124435
{
2438224436
do_concurrent_p = FALSE;
2438324437
break;
@@ -24397,8 +24451,37 @@ void gc_heap::garbage_collect (int n)
2439724451
}
2439824452
#endif //MULTIPLE_HEAPS
2439924453

24454+
#ifdef DYNAMIC_HEAP_COUNT
24455+
dprintf (6666, ("last BGC saw %d heaps and %d total threads, currently %d heaps and %d total threads, %s BGC",
24456+
last_bgc_n_heaps, last_total_bgc_threads, n_heaps, total_bgc_threads, (do_concurrent_p ? "doing" : "not doing")));
24457+
#endif //DYNAMIC_HEAP_COUNT
24458+
2440024459
if (do_concurrent_p)
2440124460
{
24461+
#ifdef DYNAMIC_HEAP_COUNT
24462+
int diff = n_heaps - last_bgc_n_heaps;
24463+
if (diff > 0)
24464+
{
24465+
int saved_idle_bgc_thread_count = dynamic_heap_count_data.idle_bgc_thread_count;
24466+
int max_idle_event_count = min (n_heaps, last_total_bgc_threads);
24467+
int idle_events_to_set = max_idle_event_count - last_bgc_n_heaps;
24468+
if (idle_events_to_set > 0)
24469+
{
24470+
Interlocked::ExchangeAdd (&dynamic_heap_count_data.idle_bgc_thread_count, -idle_events_to_set);
24471+
dprintf (6666, ("%d BGC threads exist, setting %d idle events for h%d-h%d, total idle %d -> %d",
24472+
total_bgc_threads, idle_events_to_set, last_bgc_n_heaps, (last_bgc_n_heaps + idle_events_to_set - 1),
24473+
saved_idle_bgc_thread_count, VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_bgc_thread_count)));
24474+
for (int heap_idx = last_bgc_n_heaps; heap_idx < max_idle_event_count; heap_idx++)
24475+
{
24476+
g_heaps[heap_idx]->bgc_idle_thread_event.Set();
24477+
}
24478+
}
24479+
}
24480+
24481+
last_bgc_n_heaps = n_heaps;
24482+
last_total_bgc_threads = total_bgc_threads;
24483+
#endif //DYNAMIC_HEAP_COUNT
24484+
2440224485
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
2440324486
SoftwareWriteWatch::EnableForGCHeap();
2440424487
#endif //FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
@@ -25926,9 +26009,6 @@ void gc_heap::check_heap_count ()
2592626009
for (int heap_idx = n_heaps; heap_idx < new_n_heaps; heap_idx++)
2592726010
{
2592826011
g_heaps[heap_idx]->gc_idle_thread_event.Set();
25929-
#ifdef BACKGROUND_GC
25930-
g_heaps[heap_idx]->bgc_idle_thread_event.Set();
25931-
#endif //BACKGROUND_GC
2593226012
}
2593326013
}
2593426014

@@ -37645,6 +37725,19 @@ void gc_heap::gc_thread_stub (void* arg)
3764537725
void gc_heap::bgc_thread_stub (void* arg)
3764637726
{
3764737727
gc_heap* heap = (gc_heap*)arg;
37728+
37729+
#ifdef STRESS_DYNAMIC_HEAP_COUNT
37730+
// We should only do this every so often; otherwise we'll never be able to do a BGC
37731+
int r = (int)gc_rand::get_rand (30);
37732+
bool wait_p = (r < 10);
37733+
37734+
if (wait_p)
37735+
{
37736+
GCToOSInterface::Sleep (100);
37737+
}
37738+
dprintf (6666, ("h%d %s", heap->heap_number, (wait_p ? "waited" : "did not wait")));
37739+
#endif
37740+
3764837741
heap->bgc_thread = GCToEEInterface::GetThread();
3764937742
assert(heap->bgc_thread != nullptr);
3765037743
heap->bgc_thread_function();
@@ -39437,6 +39530,8 @@ void gc_heap::add_to_bgc_th_creation_history (size_t gc_index, size_t count_crea
3943739530
}
3943839531
#endif //DYNAMIC_HEAP_COUNT
3943939532

39533+
// If this returns TRUE, we are saying we expect that thread to be there. However, when that thread is available to work is indeterministic.
39534+
// But when we actually start a BGC, naturally we'll need to wait till it gets to the point it can work.
3944039535
BOOL gc_heap::prepare_bgc_thread(gc_heap* gh)
3944139536
{
3944239537
BOOL success = FALSE;
@@ -39448,7 +39543,19 @@ BOOL gc_heap::prepare_bgc_thread(gc_heap* gh)
3944839543
dprintf (2, ("GC thread not running"));
3944939544
if (gh->bgc_thread == 0)
3945039545
{
39546+
#ifdef STRESS_DYNAMIC_HEAP_COUNT
39547+
// to stress, we just don't actually try to create the thread to simulate a failure
39548+
int r = (int)gc_rand::get_rand (100);
39549+
bool try_to_create_p = (r > 10);
39550+
BOOL thread_created_p = (try_to_create_p ? create_bgc_thread (gh) : FALSE);
39551+
if (!thread_created_p)
39552+
{
39553+
dprintf (6666, ("h%d we failed to create the thread, %s", gh->heap_number, (try_to_create_p ? "tried" : "didn't try")));
39554+
}
39555+
if (thread_created_p)
39556+
#else //STRESS_DYNAMIC_HEAP_COUNT
3945139557
if (create_bgc_thread(gh))
39558+
#endif //STRESS_DYNAMIC_HEAP_COUNT
3945239559
{
3945339560
success = TRUE;
3945439561
thread_created = TRUE;
@@ -39466,8 +39573,11 @@ BOOL gc_heap::prepare_bgc_thread(gc_heap* gh)
3946639573
else
3946739574
{
3946839575
#ifdef DYNAMIC_HEAP_COUNT
39576+
// This would be a very unusual scenario where GCToEEInterface::CreateThread told us it failed yet the thread was created.
3946939577
bgc_th_count_created_th_existed++;
39578+
dprintf (6666, ("h%d we cannot have a thread that runs yet CreateThread reported it failed to create it", gh->heap_number));
3947039579
#endif //DYNAMIC_HEAP_COUNT
39580+
assert (!"GCToEEInterface::CreateThread returned FALSE yet the thread was created!");
3947139581
}
3947239582
}
3947339583
else
@@ -39665,7 +39775,7 @@ void gc_heap::bgc_thread_function()
3966539775
while (1)
3966639776
{
3966739777
// Wait for work to do...
39668-
dprintf (3, ("bgc thread: waiting..."));
39778+
dprintf (6666, ("h%d bgc thread: waiting...", heap_number));
3966939779

3967039780
cooperative_mode = enable_preemptive ();
3967139781
//current_thread->m_fPreemptiveGCDisabled = 0;
@@ -39714,36 +39824,71 @@ void gc_heap::bgc_thread_function()
3971439824
continue;
3971539825
}
3971639826
}
39827+
39828+
#ifdef STRESS_DYNAMIC_HEAP_COUNT
39829+
if (n_heaps <= heap_number)
39830+
{
39831+
uint32_t delay_ms = (uint32_t)gc_rand::get_rand (200);
39832+
GCToOSInterface::Sleep (delay_ms);
39833+
}
39834+
#endif //STRESS_DYNAMIC_HEAP_COUNT
39835+
3971739836
// if we signal the thread with no concurrent work to do -> exit
3971839837
if (!settings.concurrent)
3971939838
{
39720-
dprintf (3, ("no concurrent GC needed, exiting"));
39839+
dprintf (6666, ("h%d no concurrent GC needed, exiting", heap_number));
39840+
39841+
#ifdef STRESS_DYNAMIC_HEAP_COUNT
39842+
flush_gc_log (true);
39843+
GCToOSInterface::DebugBreak();
39844+
#endif
3972139845
break;
3972239846
}
39723-
gc_background_running = TRUE;
39724-
dprintf (2, (ThreadStressLog::gcStartBgcThread(), heap_number,
39725-
generation_free_list_space (generation_of (max_generation)),
39726-
generation_free_obj_space (generation_of (max_generation)),
39727-
dd_fragmentation (dynamic_data_of (max_generation))));
3972839847

3972939848
#ifdef DYNAMIC_HEAP_COUNT
3973039849
if (n_heaps <= heap_number)
3973139850
{
39851+
Interlocked::Increment (&dynamic_heap_count_data.idle_bgc_thread_count);
3973239852
add_to_bgc_hc_history (hc_record_bgc_inactive);
3973339853

3973439854
// this is the case where we have more background GC threads than heaps
3973539855
// - wait until we're told to continue...
39736-
dprintf (9999, ("BGC thread %d idle (%d heaps) (gc%Id)", heap_number, n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index)));
39856+
dprintf (6666, ("BGC%Id h%d going idle (%d heaps), idle count is now %d",
39857+
VolatileLoadWithoutBarrier (&settings.gc_index), heap_number, n_heaps, VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_bgc_thread_count)));
3973739858
bgc_idle_thread_event.Wait(INFINITE, FALSE);
39738-
dprintf (9999, ("BGC thread %d waking from idle (%d heaps) (gc%Id)", heap_number, n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index)));
39859+
dprintf (6666, ("BGC%Id h%d woke from idle (%d heaps), idle count is now %d",
39860+
VolatileLoadWithoutBarrier (&settings.gc_index), heap_number, n_heaps, VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_bgc_thread_count)));
3973939861
continue;
3974039862
}
3974139863
else
3974239864
{
39865+
if (heap_number == 0)
39866+
{
39867+
const int spin_count = 1024;
39868+
int idle_bgc_thread_count = total_bgc_threads - n_heaps;
39869+
dprintf (6666, ("n_heaps %d, total %d bgc threads, bgc idle should be %d and is %d",
39870+
n_heaps, total_bgc_threads, idle_bgc_thread_count, VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_bgc_thread_count)));
39871+
if (idle_bgc_thread_count != dynamic_heap_count_data.idle_bgc_thread_count)
39872+
{
39873+
dprintf (6666, ("current idle is %d, trying to get to %d",
39874+
VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_bgc_thread_count), idle_bgc_thread_count));
39875+
spin_and_wait (spin_count, (idle_bgc_thread_count == dynamic_heap_count_data.idle_bgc_thread_count));
39876+
}
39877+
}
39878+
3974339879
add_to_bgc_hc_history (hc_record_bgc_active);
3974439880
}
3974539881
#endif //DYNAMIC_HEAP_COUNT
3974639882

39883+
if (heap_number == 0)
39884+
{
39885+
gc_background_running = TRUE;
39886+
dprintf (6666, (ThreadStressLog::gcStartBgcThread(), heap_number,
39887+
generation_free_list_space (generation_of (max_generation)),
39888+
generation_free_obj_space (generation_of (max_generation)),
39889+
dd_fragmentation (dynamic_data_of (max_generation))));
39890+
}
39891+
3974739892
gc1();
3974839893

3974939894
#ifndef DOUBLY_LINKED_FL

src/coreclr/gc/gcconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class GCConfigStringHolder
142142
INT_CONFIG (GCSpinCountUnit, "GCSpinCountUnit", NULL, 0, "Specifies the spin count unit used by the GC.") \
143143
INT_CONFIG (GCDynamicAdaptationMode, "GCDynamicAdaptationMode", "System.GC.DynamicAdaptationMode", 1, "Enable the GC to dynamically adapt to application sizes.") \
144144
INT_CONFIG (GCDTargetTCP, "GCDTargetTCP", "System.GC.DTargetTCP", 0, "Specifies the target tcp for DATAS") \
145+
INT_CONFIG (GCDBGCRatio, " GCDBGCRatio", NULL, 0, "Specifies the ratio of BGC to NGC2 for HC change") \
145146
BOOL_CONFIG (GCLogBGCThreadId, "GCLogBGCThreadId", NULL, false, "Specifies if BGC ThreadId should be logged") \
146147
BOOL_CONFIG (GCCacheSizeFromSysConf, "GCCacheSizeFromSysConf", NULL, false, "Specifies using sysconf to retrieve the last level cache size for Unix.")
147148

src/coreclr/gc/gcpriv.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5175,6 +5175,9 @@ class gc_heap
51755175
int last_n_heaps;
51765176
// don't start a GC till we see (n_max_heaps - new_n_heaps) number of threads idling
51775177
VOLATILE(int32_t) idle_thread_count;
5178+
#ifdef BACKGROUND_GC
5179+
VOLATILE(int32_t) idle_bgc_thread_count;
5180+
#endif
51785181
bool init_only_p;
51795182

51805183
bool should_change_heap_count;
@@ -5202,6 +5205,17 @@ class gc_heap
52025205
// This is set when change_heap_count wants the next GC to be a BGC for rethreading gen2 FL
52035206
// and reset during that BGC.
52045207
PER_HEAP_ISOLATED_FIELD_MAINTAINED bool trigger_bgc_for_rethreading_p;
5208+
// BGC threads are created on demand but we don't destroy the ones we created. This
5209+
// is to track how many we've created. They may or may not be active depending on
5210+
// if they are needed.
5211+
PER_HEAP_ISOLATED_FIELD_MAINTAINED int total_bgc_threads;
5212+
5213+
// HC last BGC observed.
5214+
PER_HEAP_ISOLATED_FIELD_MAINTAINED int last_bgc_n_heaps;
5215+
// Number of total BGC threads last BGC observed. This tells us how many new BGC threads have
5216+
// been created since. Note that just because a BGC thread is created doesn't mean it's used.
5217+
// We can fail at committing mark array and not proceed with the BGC.
5218+
PER_HEAP_ISOLATED_FIELD_MAINTAINED int last_total_bgc_threads;
52055219
#endif //BACKGROUND_GC
52065220
#endif //DYNAMIC_HEAP_COUNT
52075221

@@ -5352,6 +5366,9 @@ class gc_heap
53525366

53535367
#ifdef DYNAMIC_HEAP_COUNT
53545368
PER_HEAP_ISOLATED_FIELD_INIT_ONLY int dynamic_adaptation_mode;
5369+
#ifdef STRESS_DYNAMIC_HEAP_COUNT
5370+
PER_HEAP_ISOLATED_FIELD_INIT_ONLY int bgc_to_ngc2_ratio;
5371+
#endif //STRESS_DYNAMIC_HEAP_COUNT
53555372
#endif //DYNAMIC_HEAP_COUNT
53565373

53575374
/********************************************/

0 commit comments

Comments
 (0)