@@ -2890,10 +2890,14 @@ bool gc_heap::trigger_initial_gen2_p = false;
28902890
28912891#ifdef BACKGROUND_GC
28922892bool 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
28962899int 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)
3764537725void 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.
3944039535BOOL 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
0 commit comments