Skip to content

Commit

Permalink
Support NoGC for regions (dotnet#54085)
Browse files Browse the repository at this point in the history
  • Loading branch information
cshung authored Aug 11, 2021
1 parent a33dbf3 commit 2fabfc0
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 30 deletions.
115 changes: 87 additions & 28 deletions src/coreclr/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14973,7 +14973,6 @@ size_t gc_heap::new_allocation_limit (size_t size, size_t physical_limit, int ge
ptrdiff_t logical_limit = max (new_alloc, (ptrdiff_t)size);
size_t limit = min (logical_limit, (ptrdiff_t)physical_limit);
assert (limit == Align (limit, get_alignment_constant (gen_number <= max_generation)));
dd_new_allocation (dd) = (new_alloc - limit);

return limit;
}
Expand Down Expand Up @@ -15354,6 +15353,7 @@ BOOL gc_heap::a_fit_free_list_p (int gen_number,
// to make sure that we can insert a free object
// in adjust_limit will set the limit lower
size_t limit = limit_from_size (size, flags, free_list_size, gen_number, align_const);
dd_new_allocation (dynamic_data_of (gen_number)) -= limit;

uint8_t* remain = (free_list + limit);
size_t remain_size = (free_list_size - limit);
Expand Down Expand Up @@ -15540,6 +15540,7 @@ BOOL gc_heap::a_fit_free_list_uoh_p (size_t size,
// Substract min obj size because limit_from_size adds it. Not needed for LOH
size_t limit = limit_from_size (size - Align(min_obj_size, align_const), flags, free_list_size,
gen_number, align_const);
dd_new_allocation (dynamic_data_of (gen_number)) -= limit;

#ifdef FEATURE_LOH_COMPACTION
if (loh_pad)
Expand Down Expand Up @@ -15644,7 +15645,7 @@ BOOL gc_heap::a_fit_segment_end_p (int gen_number,

end = heap_segment_reserved (seg) - pad;

if (a_size_fit_p (size, allocated, end, align_const))
if ((heap_segment_reserved (seg) != heap_segment_committed (seg)) && (a_size_fit_p (size, allocated, end, align_const)))
{
limit = limit_from_size (size,
flags,
Expand Down Expand Up @@ -15672,6 +15673,7 @@ BOOL gc_heap::a_fit_segment_end_p (int gen_number,
goto found_no_fit;

found_fit:
dd_new_allocation (dynamic_data_of (gen_number)) -= limit;

#ifdef BACKGROUND_GC
if (gen_number != 0)
Expand Down Expand Up @@ -20536,7 +20538,11 @@ start_no_gc_region_status gc_heap::prepare_for_no_gc_region (uint64_t total_size
}

int soh_align_const = get_alignment_constant (TRUE);
#ifdef USE_REGIONS
size_t max_soh_allocated = SIZE_T_MAX;
#else
size_t max_soh_allocated = soh_segment_size - segment_info_size - eph_gen_starts_size;
#endif
size_t size_per_heap = 0;
const double scale_factor = 1.05;

Expand Down Expand Up @@ -20783,40 +20789,64 @@ BOOL gc_heap::should_proceed_for_no_gc()
BOOL no_gc_requested = FALSE;
BOOL get_new_loh_segments = FALSE;

gc_heap* hp = nullptr;
if (current_no_gc_region_info.soh_allocation_size)
{
#ifdef USE_REGIONS
#ifdef MULTIPLE_HEAPS
for (int i = 0; i < n_heaps; i++)
{
gc_heap* hp = g_heaps[i];
if ((size_t)(heap_segment_reserved (hp->ephemeral_heap_segment) - hp->alloc_allocated) < hp->soh_allocation_no_gc)
hp = g_heaps[i];
#else
{
hp = pGenGCHeap;
#endif //MULTIPLE_HEAPS
if (!hp->extend_soh_for_no_gc())
{
gc_requested = TRUE;
soh_full_gc_requested = TRUE;
#ifdef MULTIPLE_HEAPS
break;
#endif //MULTIPLE_HEAPS
}
}
#else //USE_REGIONS
#ifdef MULTIPLE_HEAPS
for (int i = 0; i < n_heaps; i++)
{
hp = g_heaps[i];
#else //MULTIPLE_HEAPS
if ((size_t)(heap_segment_reserved (ephemeral_heap_segment) - alloc_allocated) < soh_allocation_no_gc)
gc_requested = TRUE;
{
hp = pGenGCHeap;
#endif //MULTIPLE_HEAPS

size_t reserved_space = heap_segment_reserved (hp->ephemeral_heap_segment) - hp->alloc_allocated;
if (reserved_space < hp->soh_allocation_no_gc)
{
gc_requested = TRUE;
#ifdef MULTIPLE_HEAPS
break;
#endif //MULTIPLE_HEAPS
}
}
if (!gc_requested)
{
#ifdef MULTIPLE_HEAPS
for (int i = 0; i < n_heaps; i++)
{
gc_heap* hp = g_heaps[i];
hp = g_heaps[i];
#else //MULTIPLE_HEAPS
{
hp = pGenGCHeap;
#endif //MULTIPLE_HEAPS
if (!(hp->grow_heap_segment (hp->ephemeral_heap_segment, (hp->alloc_allocated + hp->soh_allocation_no_gc))))
{
soh_full_gc_requested = TRUE;
#ifdef MULTIPLE_HEAPS
break;
#endif //MULTIPLE_HEAPS
}
}
#else //MULTIPLE_HEAPS
if (!grow_heap_segment (ephemeral_heap_segment, (alloc_allocated + soh_allocation_no_gc)))
soh_full_gc_requested = TRUE;
#endif //MULTIPLE_HEAPS
}
#endif //USE_REGIONS
}

if (!current_no_gc_region_info.minimal_gc_p && gc_requested)
Expand Down Expand Up @@ -20943,12 +20973,45 @@ void gc_heap::update_collection_counts ()
}
}

BOOL gc_heap::expand_soh_with_minimal_gc()
{
#ifdef USE_REGIONS
assert (!"NoGC region mode is not implemented yet for regions");
return FALSE;
bool gc_heap::extend_soh_for_no_gc()
{
size_t required = soh_allocation_no_gc;
heap_segment* region = ephemeral_heap_segment;

while (true)
{
uint8_t* allocated = (region == ephemeral_heap_segment) ?
alloc_allocated :
heap_segment_allocated (region);
size_t available = heap_segment_reserved (region) - allocated;
size_t commit = min (available, required);

if (grow_heap_segment (region, allocated + commit))
{
required -= commit;
if (required == 0)
{
break;
}

region = heap_segment_next (region);
if ((region == nullptr) && !(region = get_new_region (0)))
{
break;
}
}
else
{
break;
}
}

return (required == 0);
}
#else
BOOL gc_heap::expand_soh_with_minimal_gc()
{
if ((size_t)(heap_segment_reserved (ephemeral_heap_segment) - heap_segment_allocated (ephemeral_heap_segment)) >= soh_allocation_no_gc)
return TRUE;

Expand Down Expand Up @@ -21014,8 +21077,8 @@ BOOL gc_heap::expand_soh_with_minimal_gc()
{
return FALSE;
}
#endif //USE_REGIONS
}
#endif //USE_REGIONS

// Only to be done on the thread that calls restart in a join for server GC
// and reset the oom status per heap.
Expand Down Expand Up @@ -21051,11 +21114,15 @@ void gc_heap::allocate_for_no_gc_after_gc()
{
if (current_no_gc_region_info.soh_allocation_size != 0)
{
#ifdef USE_REGIONS
no_gc_oom_p = !extend_soh_for_no_gc();
#else
if (((size_t)(heap_segment_reserved (ephemeral_heap_segment) - heap_segment_allocated (ephemeral_heap_segment)) < soh_allocation_no_gc) ||
(!grow_heap_segment (ephemeral_heap_segment, (heap_segment_allocated (ephemeral_heap_segment) + soh_allocation_no_gc))))
{
no_gc_oom_p = true;
}
#endif //USE_REGIONS

#ifdef MULTIPLE_HEAPS
gc_t_join.join(this, gc_join_after_commit_soh_no_gc);
Expand Down Expand Up @@ -21270,6 +21337,7 @@ void gc_heap::garbage_collect (int n)
if (gc_t_join.joined())
#endif //MULTIPLE_HEAPS
{
#ifndef USE_REGIONS
#ifdef MULTIPLE_HEAPS
// this is serialized because we need to get a segment
for (int i = 0; i < n_heaps; i++)
Expand All @@ -21281,6 +21349,7 @@ void gc_heap::garbage_collect (int n)
if (!expand_soh_with_minimal_gc())
current_no_gc_region_info.start_status = start_no_gc_no_memory;
#endif //MULTIPLE_HEAPS
#endif //!USE_REGIONS

update_collection_counts_for_no_gc();

Expand Down Expand Up @@ -44920,11 +44989,6 @@ int GCHeap::WaitForFullGCComplete(int millisecondsTimeout)

int GCHeap::StartNoGCRegion(uint64_t totalSize, bool lohSizeKnown, uint64_t lohSize, bool disallowFullBlockingGC)
{
#ifdef USE_REGIONS
assert (!"not impl!");
return -1;
#endif //USE_REGIONS

NoGCRegionLockHolder lh;

dprintf (1, ("begin no gc called"));
Expand All @@ -44943,11 +45007,6 @@ int GCHeap::StartNoGCRegion(uint64_t totalSize, bool lohSizeKnown, uint64_t lohS

int GCHeap::EndNoGCRegion()
{
#ifdef USE_REGIONS
assert (!"not impl!");
return -1;
#endif //USE_REGIONS

NoGCRegionLockHolder lh;
return (int)gc_heap::end_no_gc_region();
}
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/gc/gcpriv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1535,8 +1535,10 @@ class gc_heap
void get_and_reset_loh_alloc_info();
#endif //BGC_SERVO_TUNING

#ifndef USE_REGIONS
PER_HEAP
BOOL expand_soh_with_minimal_gc();
#endif //!USE_REGIONS

// EE is always suspended when this method is called.
// returning FALSE means we actually didn't do a GC. This happens
Expand Down Expand Up @@ -1704,6 +1706,11 @@ class gc_heap
PER_HEAP
void allocate_for_no_gc_after_gc();

#ifdef USE_REGIONS
PER_HEAP
bool extend_soh_for_no_gc();
#endif //USE_REGIONS

PER_HEAP
void set_loh_allocations_for_no_gc();

Expand Down
4 changes: 2 additions & 2 deletions src/tests/GC/API/NoGCRegion/NoGC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ static void DoAllocWithNoGC(long size, bool fLOH)
static bool TestAllocInNoGCRegion(int sizeMB, int sizeMBLOH, bool disallowFullBlockingGC)
{
bool isCurrentTestPassed = false;
Console.WriteLine("=====allocating {0}mb {1} full blocking GC first=====",
sizeMB, (disallowFullBlockingGC ? "disallowing" : "allowing"));
Console.WriteLine("=====allocating {0}mb/{1}mb {2} full blocking GC first=====",
sizeMB, sizeMBLOH, (disallowFullBlockingGC ? "disallowing" : "allowing"));

DoAlloc();

Expand Down

0 comments on commit 2fabfc0

Please sign in to comment.