From 2583ce936776a0eac31df904e41d5119840c203b Mon Sep 17 00:00:00 2001 From: Maoni Stephens Date: Mon, 2 Apr 2018 11:10:48 -0700 Subject: [PATCH] Added a new API to provide memory information that GC records. This (#17326) is to be used by BCL for deciding when to trim memory usage in pooling code --- src/gc/gc.cpp | 66 ++++++++++++++++++++++++++++++++++++++----- src/gc/gcimpl.h | 6 ++++ src/gc/gcinterface.h | 14 +++++++++ src/gc/gcpriv.h | 13 +++++++++ src/mscorlib/src/System/GC.cs | 8 ++++++ src/vm/comutilnative.cpp | 12 ++++++++ src/vm/comutilnative.h | 1 + src/vm/ecalllist.h | 1 + 8 files changed, 114 insertions(+), 7 deletions(-) diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp index a23edb9..ef9058e 100644 --- a/src/gc/gc.cpp +++ b/src/gc/gc.cpp @@ -2467,13 +2467,19 @@ double gc_heap::short_plugs_pad_ratio = 0; size_t gc_heap::youngest_gen_desired_th; #endif //BIT64 -uint64_t gc_heap::mem_one_percent; +uint32_t gc_heap::last_gc_memory_load = 0; -uint32_t gc_heap::high_memory_load_th; +size_t gc_heap::last_gc_heap_size = 0; -uint64_t gc_heap::total_physical_mem; +size_t gc_heap::last_gc_fragmentation = 0; -uint64_t gc_heap::entry_available_physical_mem; +uint64_t gc_heap::mem_one_percent = 0; + +uint32_t gc_heap::high_memory_load_th = 0; + +uint64_t gc_heap::total_physical_mem = 0; + +uint64_t gc_heap::entry_available_physical_mem = 0; #ifdef BACKGROUND_GC GCEvent gc_heap::bgc_start_event; @@ -5755,9 +5761,8 @@ void gc_mechanisms::init_mechanisms() allocations_allowed = TRUE; #endif //BACKGROUND_GC -#ifdef BIT64 entry_memory_load = 0; -#endif // BIT64 + exit_memory_load = 0; #ifdef STRESS_HEAP stress_induced = FALSE; @@ -19096,6 +19101,28 @@ size_t gc_heap::get_total_heap_size() return total_heap_size; } +size_t gc_heap::get_total_fragmentation() +{ + size_t total_fragmentation = 0; + +#ifdef MULTIPLE_HEAPS + for (int i = 0; i < gc_heap::n_heaps; i++) + { + gc_heap* hp = gc_heap::g_heaps[i]; +#else //MULTIPLE_HEAPS + { + gc_heap* hp = pGenGCHeap; +#endif //MULTIPLE_HEAPS + for (int i = 0; i <= (max_generation + 1); i++) + { + generation* gen = hp->generation_of (i); + total_fragmentation += (generation_free_list_space (gen) + generation_free_obj_space (gen)); + } + } + + return total_fragmentation; +} + size_t gc_heap::committed_size() { generation* gen = generation_of (max_generation); @@ -29663,8 +29690,11 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd, } else //large object heap { + uint32_t memory_load = 0; uint64_t available_physical = 0; - get_memory_info (NULL, &available_physical); + get_memory_info (&memory_load, &available_physical); + if (heap_number == 0) + settings.exit_memory_load = memory_load; if (available_physical > 1024*1024) available_physical -= 1024*1024; @@ -29899,6 +29929,7 @@ size_t gc_heap::joined_youngest_desired (size_t new_allocation) { uint32_t memory_load = 0; get_memory_info (&memory_load); + settings.exit_memory_load = memory_load; dprintf (2, ("Current emory load: %d", memory_load)); size_t final_total = @@ -34882,6 +34913,14 @@ void gc_heap::do_post_gc() settings.condemned_generation, (settings.concurrent ? "BGC" : "GC"))); + if (settings.exit_memory_load != 0) + last_gc_memory_load = settings.exit_memory_load; + else if (settings.entry_memory_load != 0) + last_gc_memory_load = settings.entry_memory_load; + + last_gc_heap_size = get_total_heap_size(); + last_gc_fragmentation = get_total_fragmentation(); + GCHeap::UpdatePostGCCounters(); #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING //if (g_fEnableARM) @@ -35266,6 +35305,19 @@ unsigned int GCHeap::GetCondemnedGeneration() return gc_heap::settings.condemned_generation; } +void GCHeap::GetMemoryInfo(uint32_t* highMemLoadThreshold, + uint64_t* totalPhysicalMem, + uint32_t* lastRecordedMemLoad, + size_t* lastRecordedHeapSize, + size_t* lastRecordedFragmentation) +{ + *highMemLoadThreshold = gc_heap::high_memory_load_th; + *totalPhysicalMem = gc_heap::total_physical_mem; + *lastRecordedMemLoad = gc_heap::last_gc_memory_load; + *lastRecordedHeapSize = gc_heap::last_gc_heap_size; + *lastRecordedFragmentation = gc_heap::last_gc_fragmentation; +} + int GCHeap::GetGcLatencyMode() { return (int)(pGenGCHeap->settings.pause_mode); diff --git a/src/gc/gcimpl.h b/src/gc/gcimpl.h index 261e26e..54aee1a 100644 --- a/src/gc/gcimpl.h +++ b/src/gc/gcimpl.h @@ -168,6 +168,12 @@ public: unsigned GetCondemnedGeneration(); + void GetMemoryInfo(uint32_t* highMemLoadThreshold, + uint64_t* totalPhysicalMem, + uint32_t* lastRecordedMemLoad, + size_t* lastRecordedHeapSize, + size_t* lastRecordedFragmentation); + int GetGcLatencyMode(); int SetGcLatencyMode(int newLatencyMode); diff --git a/src/gc/gcinterface.h b/src/gc/gcinterface.h index c7c6424..d532c8a 100644 --- a/src/gc/gcinterface.h +++ b/src/gc/gcinterface.h @@ -608,6 +608,20 @@ public: =========================================================================== */ + // Gets memory related information - + // highMemLoadThreshold - physical memory load (in percentage) when GC will start to + // react aggressively to reclaim memory. + // totalPhysicalMem - the total amount of phyiscal memory available on the machine and the memory + // limit set on the container if running in a container. + // lastRecordedMemLoad - physical memory load in percentage recorded in the last GC + // lastRecordedHeapSize - total managed heap size recorded in the last GC + // lastRecordedFragmentation - total fragmentation in the managed heap recorded in the last GC + virtual void GetMemoryInfo(uint32_t* highMemLoadThreshold, + uint64_t* totalPhysicalMem, + uint32_t* lastRecordedMemLoad, + size_t* lastRecordedHeapSize, + size_t* lastRecordedFragmentation) = 0; + // Gets the current GC latency mode. virtual int GetGcLatencyMode() = 0; diff --git a/src/gc/gcpriv.h b/src/gc/gcpriv.h index 2c66ace..9071742 100644 --- a/src/gc/gcpriv.h +++ b/src/gc/gcpriv.h @@ -489,7 +489,9 @@ public: BOOL stress_induced; #endif // STRESS_HEAP + // These are opportunistically set uint32_t entry_memory_load; + uint32_t exit_memory_load; void init_mechanisms(); //for each GC void first_init(); // for the life of the EE @@ -2479,6 +2481,8 @@ protected: size_t get_total_heap_size (); PER_HEAP_ISOLATED size_t get_total_committed_size(); + PER_HEAP_ISOLATED + size_t get_total_fragmentation(); PER_HEAP_ISOLATED void get_memory_info (uint32_t* memory_load, @@ -2969,6 +2973,15 @@ public: #endif //BIT64 PER_HEAP_ISOLATED + uint32_t last_gc_memory_load; + + PER_HEAP_ISOLATED + size_t last_gc_heap_size; + + PER_HEAP_ISOLATED + size_t last_gc_fragmentation; + + PER_HEAP_ISOLATED uint32_t high_memory_load_th; PER_HEAP_ISOLATED diff --git a/src/mscorlib/src/System/GC.cs b/src/mscorlib/src/System/GC.cs index 7119302..848141f 100644 --- a/src/mscorlib/src/System/GC.cs +++ b/src/mscorlib/src/System/GC.cs @@ -66,6 +66,14 @@ namespace System [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern int SetGCLatencyMode(int newLatencyMode); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void GetMemoryInfo(out uint highMemLoadThreshold, + out ulong totalPhysicalMem, + out uint lastRecordedMemLoad, + // The next two are size_t + out UIntPtr lastRecordedHeapSize, + out UIntPtr lastRecordedFragmentation); + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] internal static extern int _StartNoGCRegion(long totalSize, bool lohSizeKnown, long lohSize, bool disallowFullBlockingGC); diff --git a/src/vm/comutilnative.cpp b/src/vm/comutilnative.cpp index 48efc11..d564f9a 100644 --- a/src/vm/comutilnative.cpp +++ b/src/vm/comutilnative.cpp @@ -922,6 +922,18 @@ UINT64 GCInterface::m_remPressure[NEW_PRESSURE_COUNT] = {0, 0, 0, 0}; // his // (m_iteration % NEW_PRESSURE_COUNT) is used as an index into m_addPressure and m_remPressure UINT GCInterface::m_iteration = 0; +FCIMPL5(void, GCInterface::GetMemoryInfo, UINT32* highMemLoadThreshold, UINT64* totalPhysicalMem, UINT32* lastRecordedMemLoad, size_t* lastRecordedHeapSize, size_t* lastRecordedFragmentation) +{ + FCALL_CONTRACT; + + FC_GC_POLL_NOT_NEEDED(); + + return GCHeapUtilities::GetGCHeap()->GetMemoryInfo(highMemLoadThreshold, totalPhysicalMem, + lastRecordedMemLoad, + lastRecordedHeapSize, lastRecordedFragmentation); +} +FCIMPLEND + FCIMPL0(int, GCInterface::GetGcLatencyMode) { FCALL_CONTRACT; diff --git a/src/vm/comutilnative.h b/src/vm/comutilnative.h index 3e63a04..c604811 100644 --- a/src/vm/comutilnative.h +++ b/src/vm/comutilnative.h @@ -111,6 +111,7 @@ public: static FORCEINLINE UINT64 InterlockedAdd(UINT64 *pAugend, UINT64 addend); static FORCEINLINE UINT64 InterlockedSub(UINT64 *pMinuend, UINT64 subtrahend); + static FCDECL5(void, GetMemoryInfo, UINT32* highMemLoadThreshold, UINT64* totalPhysicalMem, UINT32* lastRecordedMemLoad, size_t* lastRecordedHeapSize, size_t* lastRecordedFragmentation); static FCDECL0(int, GetGcLatencyMode); static FCDECL1(int, SetGcLatencyMode, int newLatencyMode); static FCDECL0(int, GetLOHCompactionMode); diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h index 92d75e3..998f62b 100644 --- a/src/vm/ecalllist.h +++ b/src/vm/ecalllist.h @@ -840,6 +840,7 @@ FCFuncStart(gGCInterfaceFuncs) FCFuncElement("_WaitForFullGCApproach", GCInterface::WaitForFullGCApproach) FCFuncElement("_WaitForFullGCComplete", GCInterface::WaitForFullGCComplete) FCFuncElement("_CollectionCount", GCInterface::CollectionCount) + FCFuncElement("GetMemoryInfo", GCInterface::GetMemoryInfo) FCFuncElement("GetGCLatencyMode", GCInterface::GetGcLatencyMode) FCFuncElement("SetGCLatencyMode", GCInterface::SetGcLatencyMode) FCFuncElement("GetLOHCompactionMode", GCInterface::GetLOHCompactionMode) -- 2.7.4