Permalink
Browse files

Allow users to specify a no GC region (on behalf of maonis)

This mode lets users to specify an allocation amount for which no GCs would happen. Sometimes during the absolutely performance critical paths users have the desire to allocate without interference from the GC. If there is enough memory, GC will not kick in while this mode is set.

[tfs-changeset: 1421386]
  • Loading branch information...
1 parent d1a4418 commit 4f74a99e296d929945413c5a65d0c61bb7f2c32a @jkotas jkotas committed Feb 26, 2015
View
Oops, something went wrong.
View
@@ -297,6 +297,25 @@ enum wait_full_gc_status
wait_full_gc_na = 4
};
+// !!!!!!!!!!!!!!!!!!!!!!!
+// make sure you change the def in bcl\system\gc.cs
+// if you change this!
+enum start_no_gc_region_status
+{
+ start_no_gc_success = 0,
+ start_no_gc_no_memory = 1,
+ start_no_gc_too_large = 2,
+ start_no_gc_in_progress = 3
+};
+
+enum end_no_gc_region_status
+{
+ end_no_gc_success = 0,
+ end_no_gc_not_in_progress = 1,
+ end_no_gc_induced = 2,
+ end_no_gc_alloc_exceeded = 3
+};
+
enum bgc_state
{
bgc_not_in_process = 0,
@@ -557,6 +576,9 @@ class GCHeap {
virtual int WaitForFullGCApproach(int millisecondsTimeout) = 0;
virtual int WaitForFullGCComplete(int millisecondsTimeout) = 0;
+ virtual int StartNoGCRegion(ULONGLONG totalSize, BOOL lohSizeKnown, ULONGLONG lohSize, BOOL disallowFullBlockingGC) = 0;
+ virtual int EndNoGCRegion() = 0;
+
virtual BOOL IsObjectInFixedHeap(Object *pObj) = 0;
virtual size_t GetTotalBytesInUse () = 0;
virtual size_t GetCurrentObjSize() = 0;
View
@@ -199,6 +199,9 @@ class GCHeap : public ::GCHeap
int WaitForFullGCApproach(int millisecondsTimeout);
int WaitForFullGCComplete(int millisecondsTimeout);
+ int StartNoGCRegion(ULONGLONG totalSize, BOOL lohSizeKnown, ULONGLONG lohSize, BOOL disallowFullBlockingGC);
+ int EndNoGCRegion();
+
PER_HEAP_ISOLATED unsigned GetMaxGeneration();
unsigned GetGcCount();
View
@@ -471,7 +471,8 @@ enum gc_pause_mode
pause_interactive = 1, //We are running an interactive app
pause_low_latency = 2, //short pauses are essential
//avoid long pauses from blocking full GCs unless running out of memory
- pause_sustained_low_latency = 3
+ pause_sustained_low_latency = 3,
+ pause_no_gc = 4
};
enum gc_loh_compaction_mode
@@ -484,7 +485,7 @@ enum gc_loh_compaction_mode
enum set_pause_mode_status
{
set_pause_mode_success = 0,
- // for future error status.
+ set_pause_mode_no_gc = 1 // NoGCRegion is in progress, can't change pause mode.
};
enum gc_tuning_point
@@ -565,6 +566,7 @@ class gc_mechanisms
int gen0_reduction_count;
BOOL should_lock_elevation;
int elevation_locked_count;
+ BOOL minimal_gc;
gc_reason reason;
gc_pause_mode pause_mode;
BOOL found_finalizers;
@@ -1090,6 +1092,20 @@ struct snoop_stats_data
};
#endif //SNOOP_STATS
+struct no_gc_region_info
+{
+ size_t soh_allocation_size;
+ size_t loh_allocation_size;
+ size_t started;
+ size_t num_gcs;
+ size_t num_gcs_induced;
+ start_no_gc_region_status start_status;
+ gc_pause_mode saved_pause_mode;
+ size_t saved_gen0_min_size;
+ size_t saved_gen3_min_size;
+ BOOL minimal_gc_p;
+};
+
//class definition of the internal class
#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
extern void GCProfileWalkHeapWorker(BOOL fProfilerPinned, BOOL fShouldWalkHeapRootsForEtw, BOOL fShouldWalkHeapObjectsForEtw);
@@ -1261,6 +1277,9 @@ class gc_heap
PER_HEAP
void do_post_gc();
+ PER_HEAP
+ BOOL expand_soh_with_minimal_gc();
+
// EE is always suspended when this method is called.
// returning FALSE means we actually didn't do a GC. This happens
// when we figured that we needed to do a BGC.
@@ -1341,6 +1360,72 @@ class gc_heap
PER_HEAP
void gc1();
+ PER_HEAP_ISOLATED
+ void save_data_for_no_gc();
+
+ PER_HEAP_ISOLATED
+ void restore_data_for_no_gc();
+
+ PER_HEAP_ISOLATED
+ void update_collection_counts_for_no_gc();
+
+ PER_HEAP_ISOLATED
+ BOOL should_proceed_with_gc();
+
+ PER_HEAP_ISOLATED
+ void record_gcs_during_no_gc();
+
+ PER_HEAP
+ BOOL find_loh_free_for_no_gc();
+
+ PER_HEAP
+ BOOL find_loh_space_for_no_gc();
+
+ PER_HEAP
+ BOOL commit_loh_for_no_gc (heap_segment* seg);
+
+ PER_HEAP_ISOLATED
+ start_no_gc_region_status prepare_for_no_gc_region (ULONGLONG total_size,
+ BOOL loh_size_known,
+ ULONGLONG loh_size,
+ BOOL disallow_full_blocking);
+
+ PER_HEAP
+ BOOL loh_allocated_for_no_gc();
+
+ PER_HEAP_ISOLATED
+ void release_no_gc_loh_segments();
+
+ PER_HEAP_ISOLATED
+ void thread_no_gc_loh_segments();
+
+ PER_HEAP
+ void allocate_for_no_gc_after_gc();
+
+ PER_HEAP
+ void set_loh_allocations_for_no_gc();
+
+ PER_HEAP
+ void set_soh_allocations_for_no_gc();
+
+ PER_HEAP
+ void prepare_for_no_gc_after_gc();
+
+ PER_HEAP_ISOLATED
+ void set_allocations_for_no_gc();
+
+ PER_HEAP_ISOLATED
+ BOOL should_proceed_for_no_gc();
+
+ PER_HEAP_ISOLATED
+ start_no_gc_region_status get_start_no_gc_region_status();
+
+ PER_HEAP_ISOLATED
+ end_no_gc_region_status end_no_gc_region();
+
+ PER_HEAP_ISOLATED
+ void handle_failure_for_no_gc();
+
PER_HEAP
void fire_etw_allocation_event (size_t allocation_amount, int gen_number, BYTE* object_address);
@@ -2800,6 +2885,11 @@ class gc_heap
PER_HEAP
heap_segment* new_heap_segment;
+
+#define alloc_quantum_balance_units (16)
+
+ PER_HEAP_ISOLATED
+ size_t min_balance_threshold;
#else //MULTIPLE_HEAPS
PER_HEAP
@@ -3204,6 +3294,21 @@ class gc_heap
PER_HEAP
size_t alloc_contexts_used;
+ PER_HEAP_ISOLATED
+ no_gc_region_info current_no_gc_region_info;
+
+ PER_HEAP
+ size_t soh_allocation_no_gc;
+
+ PER_HEAP
+ size_t loh_allocation_no_gc;
+
+ PER_HEAP
+ heap_segment* saved_loh_segment_no_gc;
+
+ PER_HEAP_ISOLATED
+ BOOL proceed_with_gc_p;
+
#define youngest_generation (generation_of (0))
#define large_object_generation (generation_of (max_generation+1))
@@ -71,6 +71,16 @@ public static class GC
internal static extern int SetGCLatencyMode(int newLatencyMode);
[System.Security.SecurityCritical] // auto-generated
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [SuppressUnmanagedCodeSecurity]
+ internal static extern int _StartNoGCRegion(long totalSize, bool lohSizeKnown, long lohSize, bool disallowFullBlockingGC);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [SuppressUnmanagedCodeSecurity]
+ internal static extern int _EndNoGCRegion();
+
+ [System.Security.SecurityCritical] // auto-generated
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern int GetLOHCompactionMode();
@@ -451,6 +461,80 @@ public static GCNotificationStatus WaitForFullGCComplete(int millisecondsTimeout
throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
return (GCNotificationStatus)_WaitForFullGCComplete(millisecondsTimeout);
}
+
+ enum StartNoGCRegionStatus
+ {
+ Succeeded = 0,
+ NotEnoughMemory = 1,
+ AmountTooLarge = 2,
+ AlreadyInProgress = 3
+ }
+
+ enum EndNoGCRegionStatus
+ {
+ Succeeded = 0,
+ NotInProgress = 1,
+ GCInduced = 2,
+ AllocationExceeded = 3
+ }
+
+ [SecurityCritical]
+ static bool StartNoGCRegionWorker(long totalSize, bool hasLohSize, long lohSize, bool disallowFullBlockingGC)
+ {
+ StartNoGCRegionStatus status = (StartNoGCRegionStatus)_StartNoGCRegion(totalSize, hasLohSize, lohSize, disallowFullBlockingGC);
+ if (status == StartNoGCRegionStatus.AmountTooLarge)
+ throw new ArgumentOutOfRangeException("totalSize",
+ "totalSize is too large. For more information about setting the maximum size, see \"Latency Modes\" in http://go.microsoft.com/fwlink/?LinkId=522706");
+ else if (status == StartNoGCRegionStatus.AlreadyInProgress)
+ throw new InvalidOperationException("The NoGCRegion mode was already in progress");
+ else if (status == StartNoGCRegionStatus.NotEnoughMemory)
+ return false;
+ return true;
+ }
+
+ [SecurityCritical]
+ public static bool TryStartNoGCRegion(long totalSize)
+ {
+ return StartNoGCRegionWorker(totalSize, false, 0, false);
+ }
+
+ [SecurityCritical]
+ public static bool TryStartNoGCRegion(long totalSize, long lohSize)
+ {
+ return StartNoGCRegionWorker(totalSize, true, lohSize, false);
+ }
+
+ [SecurityCritical]
+ public static bool TryStartNoGCRegion(long totalSize, bool disallowFullBlockingGC)
+ {
+ return StartNoGCRegionWorker(totalSize, false, 0, disallowFullBlockingGC);
+ }
+
+ [SecurityCritical]
+ public static bool TryStartNoGCRegion(long totalSize, long lohSize, bool disallowFullBlockingGC)
+ {
+ return StartNoGCRegionWorker(totalSize, true, lohSize, disallowFullBlockingGC);
+ }
+
+ [SecurityCritical]
+ static EndNoGCRegionStatus EndNoGCRegionWorker()
+ {
+ EndNoGCRegionStatus status = (EndNoGCRegionStatus)_EndNoGCRegion();
+ if (status == EndNoGCRegionStatus.NotInProgress)
+ throw new InvalidOperationException("NoGCRegion mode must be set");
+ else if (status == EndNoGCRegionStatus.GCInduced)
+ throw new InvalidOperationException("Garbage collection was induced in NoGCRegion mode");
+ else if (status == EndNoGCRegionStatus.AllocationExceeded)
+ throw new InvalidOperationException("Allocated memory exceeds specified memory for NoGCRegion mode");
+
+ return EndNoGCRegionStatus.Succeeded;
+ }
+
+ [SecurityCritical]
+ public static void EndNoGCRegion()
+ {
+ EndNoGCRegionWorker();
+ }
}
#if !FEATURE_CORECLR
@@ -25,11 +25,18 @@ public enum GCLatencyMode
Batch = 0,
Interactive = 1,
LowLatency = 2,
- SustainedLowLatency = 3
+ SustainedLowLatency = 3,
+ NoGCRegion = 4
}
public static class GCSettings
{
+ enum SetLatencyModeStatus
+ {
+ Succeeded = 0,
+ NoGCInProgress = 1 // NoGCRegion is in progress, can't change pause mode.
+ };
+
public static GCLatencyMode LatencyMode
{
[System.Security.SecuritySafeCritical] // auto-generated
@@ -51,7 +58,8 @@ public static GCLatencyMode LatencyMode
}
Contract.EndContractBlock();
- GC.SetGCLatencyMode((int)value);
+ if (GC.SetGCLatencyMode((int)value) == (int)SetLatencyModeStatus.NoGCInProgress)
+ throw new InvalidOperationException("The NoGCRegion mode is in progress. End it and then set a different mode.");
}
}
@@ -1753,6 +1753,41 @@ FCIMPL2(int, GCInterface::CollectionCount, INT32 generation, INT32 getSpecialGCC
}
FCIMPLEND
+int QCALLTYPE GCInterface::StartNoGCRegion(INT64 totalSize, BOOL lohSizeKnown, INT64 lohSize, BOOL disallowFullBlockingGC)
+{
+ QCALL_CONTRACT;
+
+ int retVal = 0;
+
+ BEGIN_QCALL;
+
+ GCX_COOP();
+
+ retVal = GCHeap::GetGCHeap()->StartNoGCRegion((ULONGLONG)totalSize,
+ lohSizeKnown,
+ (ULONGLONG)lohSize,
+ disallowFullBlockingGC);
+
+ END_QCALL;
+
+ return retVal;
+}
+
+int QCALLTYPE GCInterface::EndNoGCRegion()
+{
+ QCALL_CONTRACT;
+
+ int retVal = FALSE;
+
+ BEGIN_QCALL;
+
+ retVal = GCHeap::GetGCHeap()->EndNoGCRegion();
+
+ END_QCALL;
+
+ return retVal;
+}
+
/*===============================GetGenerationWR================================
**Action: Returns the generation in which the object pointed to by a WeakReference is found.
**Returns:
@@ -185,6 +185,12 @@ class GCInterface {
static FCDECL1(void, ReRegisterForFinalize, Object *obj);
static FCDECL2(int, CollectionCount, INT32 generation, INT32 getSpecialGCCount);
+ static
+ int QCALLTYPE StartNoGCRegion(INT64 totalSize, BOOL lohSizeKnown, INT64 lohSize, BOOL disallowFullBlockingGC);
+
+ static
+ int QCALLTYPE EndNoGCRegion();
+
static
void QCALLTYPE _AddMemoryPressure(UINT64 bytesAllocated);
Oops, something went wrong.

0 comments on commit 4f74a99

Please sign in to comment.