summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kotas <jkotas@microsoft.com>2016-05-17 08:36:57 -0700
committerJan Kotas <jkotas@microsoft.com>2016-05-17 08:36:57 -0700
commit0f94239fadf20295b4fc7e8935ffd27a289f9d5e (patch)
tree25a90f0f9a4ba257bf427398999d2713ee4a4c9a
parent8162628ae3bcbe805abf9266f67d4c42880bc2e8 (diff)
downloadcoreclr-0f94239fadf20295b4fc7e8935ffd27a289f9d5e.tar.gz
coreclr-0f94239fadf20295b4fc7e8935ffd27a289f9d5e.tar.bz2
coreclr-0f94239fadf20295b4fc7e8935ffd27a289f9d5e.zip
Move notion of restricted physical memory behind the GCToOSInterface (#5007)
-rw-r--r--src/gc/env/gcenv.os.h34
-rw-r--r--src/gc/env/gcenv.structs.h14
-rw-r--r--src/gc/gc.cpp59
-rw-r--r--src/gc/gcpriv.h3
-rw-r--r--src/gc/sample/gcenv.windows.cpp46
-rw-r--r--src/vm/gcenv.os.cpp109
6 files changed, 124 insertions, 141 deletions
diff --git a/src/gc/env/gcenv.os.h b/src/gc/env/gcenv.os.h
index 007b57f3bc..45b958c32e 100644
--- a/src/gc/env/gcenv.os.h
+++ b/src/gc/env/gcenv.os.h
@@ -224,31 +224,35 @@ public:
static bool GetCurrentProcessAffinityMask(uintptr_t *processMask, uintptr_t *systemMask);
//
- // Support for acting on memory limit imposed on this process, eg, running in a job object on Windows.
+ // Global memory info
//
- // If the process's memory is restricted (ie, beyond what's available on the machine), return that limit.
+ // Return the size of the user-mode portion of the virtual address space of this process.
// Return:
// non zero if it has succeeded, 0 if it has failed
- // Remarks:
- // If a process runs with a restricted memory limit, and we are successful at getting
- // that limit, it returns the limit. If there's no limit specified, or there's an error
- // at getting that limit, it returns 0.
- static uint64_t GetRestrictedPhysicalMemoryLimit();
+ static size_t GetVirtualMemoryLimit();
- // Get the current physical memory this process is using.
+ // Get the physical memory that this process can use.
// Return:
// non zero if it has succeeded, 0 if it has failed
- static size_t GetCurrentPhysicalMemory();
-
- //
- // Misc
- //
+ // Remarks:
+ // If a process runs with a restricted memory limit, it returns the limit. If there's no limit
+ // specified, it returns amount of actual physical memory.
+ static uint64_t GetPhysicalMemoryLimit();
// Get global memory status
// Parameters:
- // ms - pointer to the structure that will be filled in with the memory status
- static void GetMemoryStatus(GCMemoryStatus* ms);
+ // memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory
+ // that is in use (0 indicates no memory use and 100 indicates full memory use).
+ // available_physical - The amount of physical memory currently available, in bytes.
+ // available_page_file - The maximum amount of memory the current process can commit, in bytes.
+ // Remarks:
+ // Any parameter can be null.
+ static void GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file);
+
+ //
+ // Misc
+ //
// Flush write buffers of processors that are executing threads of the current process
static void FlushProcessWriteBuffers();
diff --git a/src/gc/env/gcenv.structs.h b/src/gc/env/gcenv.structs.h
index ef6ec595aa..5887dd7852 100644
--- a/src/gc/env/gcenv.structs.h
+++ b/src/gc/env/gcenv.structs.h
@@ -14,20 +14,6 @@ struct GCSystemInfo
uint32_t dwAllocationGranularity;
};
-// An 'abstract' definition of Windows MEMORYSTATUSEX. In practice, the only difference is the missing struct size
-// field and one field that Windows documents to always be 0. If additional information is available on other OSes,
-// this information should be surfaced through this structure as additional fields that the GC may optionally depend on.
-struct GCMemoryStatus
-{
- uint32_t dwMemoryLoad;
- uint64_t ullTotalPhys;
- uint64_t ullAvailPhys;
- uint64_t ullTotalPageFile;
- uint64_t ullAvailPageFile;
- uint64_t ullTotalVirtual;
- uint64_t ullAvailVirtual;
-};
-
typedef void * HANDLE;
#ifdef PLATFORM_UNIX
diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp
index 62ebc16b57..904f9497f4 100644
--- a/src/gc/gc.cpp
+++ b/src/gc/gc.cpp
@@ -2330,8 +2330,6 @@ uint64_t gc_heap::total_physical_mem;
uint64_t gc_heap::entry_available_physical_mem;
-bool gc_heap::restricted_physical_memory_p = false;
-
#ifdef BACKGROUND_GC
CLREvent gc_heap::bgc_start_event;
@@ -7017,11 +7015,9 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
{
//modify the higest address so the span covered
//is twice the previous one.
- GCMemoryStatus st;
- GCToOSInterface::GetMemoryStatus (&st);
- uint8_t* top = (uint8_t*)0 + Align ((size_t)(st.ullTotalVirtual));
- // On non-Windows systems, we get only an approximate ullTotalVirtual
- // value that can possibly be slightly lower than the saved_g_highest_address.
+ uint8_t* top = (uint8_t*)0 + Align (GCToOSInterface::GetVirtualMemoryLimit());
+ // On non-Windows systems, we get only an approximate value that can possibly be
+ // slightly lower than the saved_g_highest_address.
// In such case, we set the top to the saved_g_highest_address so that the
// card and brick tables always cover the whole new range.
if (top < saved_g_highest_address)
@@ -19046,33 +19042,7 @@ void gc_heap::get_memory_info (uint32_t* memory_load,
uint64_t* available_physical,
uint64_t* available_page_file)
{
- if (restricted_physical_memory_p)
- {
- size_t working_set_size = GCToOSInterface::GetCurrentPhysicalMemory();
- if (working_set_size)
- {
- if (memory_load)
- *memory_load = (uint32_t)((float)working_set_size * 100.0 / (float)total_physical_mem);
- if (available_physical)
- *available_physical = total_physical_mem - working_set_size;
- // Available page file doesn't mean much when physical memory is restricted since
- // we don't know how much of it is available to this process so we are not going to
- // bother to make another OS call for it.
- if (available_page_file)
- *available_page_file = 0;
-
- return;
- }
- }
-
- GCMemoryStatus ms;
- GCToOSInterface::GetMemoryStatus(&ms);
- if (memory_load)
- *memory_load = ms.dwMemoryLoad;
- if (available_physical)
- *available_physical = ms.ullAvailPhys;
- if (available_page_file)
- *available_page_file = ms.ullAvailPageFile;
+ GCToOSInterface::GetMemoryStatus(memory_load, available_physical, available_page_file);
}
void fire_mark_event (int heap_num, int root_type, size_t bytes_marked)
@@ -33714,22 +33684,7 @@ HRESULT GCHeap::Initialize ()
if (hr != S_OK)
return hr;
- // If there's a physical memory limit set on this process, it needs to be checked very early on,
- // before we set various memory info.
- uint64_t physical_memory_limit = GCToOSInterface::GetRestrictedPhysicalMemoryLimit();
-
- if (physical_memory_limit)
- gc_heap::restricted_physical_memory_p = true;
-
- GCMemoryStatus ms;
- GCToOSInterface::GetMemoryStatus (&ms);
- gc_heap::total_physical_mem = ms.ullTotalPhys;
-
- if (gc_heap::restricted_physical_memory_p)
- {
- // A sanity check in case someone set a larger limit than there is actual physical memory.
- gc_heap::total_physical_mem = min (gc_heap::total_physical_mem, physical_memory_limit);
- }
+ gc_heap::total_physical_mem = GCToOSInterface::GetPhysicalMemoryLimit();
gc_heap::mem_one_percent = gc_heap::total_physical_mem / 100;
#ifndef MULTIPLE_HEAPS
@@ -35903,11 +35858,9 @@ size_t GCHeap::GetValidGen0MaxSize(size_t seg_size)
GCToOSInterface::GetLargestOnDieCacheSize(TRUE),
GCToOSInterface::GetLogicalCpuCount()));
- GCMemoryStatus ms;
- GCToOSInterface::GetMemoryStatus (&ms);
// if the total min GC across heaps will exceed 1/6th of available memory,
// then reduce the min GC size until it either fits or has been reduced to cache size.
- while ((gen0size * gc_heap::n_heaps) > (ms.ullAvailPhys / 6))
+ while ((gen0size * gc_heap::n_heaps) > GCToOSInterface::GetPhysicalMemoryLimit() / 6)
{
gen0size = gen0size / 2;
if (gen0size <= trueSize)
diff --git a/src/gc/gcpriv.h b/src/gc/gcpriv.h
index e14cab4c62..9f6abe40d4 100644
--- a/src/gc/gcpriv.h
+++ b/src/gc/gcpriv.h
@@ -2959,9 +2959,6 @@ public:
uint64_t entry_available_physical_mem;
PER_HEAP_ISOLATED
- bool restricted_physical_memory_p;
-
- PER_HEAP_ISOLATED
size_t last_gc_index;
PER_HEAP_ISOLATED
diff --git a/src/gc/sample/gcenv.windows.cpp b/src/gc/sample/gcenv.windows.cpp
index 7e6641e010..64faa322a1 100644
--- a/src/gc/sample/gcenv.windows.cpp
+++ b/src/gc/sample/gcenv.windows.cpp
@@ -282,30 +282,38 @@ uint32_t GCToOSInterface::GetCurrentProcessCpuCount()
return g_SystemInfo.dwNumberOfProcessors;
}
-// If the process's memory is restricted (ie, beyond what's available on the machine), return that limit.
+// Return the size of the user-mode portion of the virtual address space of this process.
// Return:
// non zero if it has succeeded, 0 if it has failed
-// Remarks:
-// If a process runs with a restricted memory limit, and we are successful at getting
-// that limit, it returns the limit. If there's no limit specified, or there's an error
-// at getting that limit, it returns 0.
-uint64_t GCToOSInterface::GetRestrictedPhysicalMemoryLimit()
+size_t GCToOSInterface::GetVirtualMemoryLimit()
{
- return 0;
+ MEMORYSTATUSEX memStatus;
+
+ memStatus.dwLength = sizeof(MEMORYSTATUSEX);
+ BOOL fRet = GlobalMemoryStatusEx(&memStatus);
+ _ASSERTE(fRet);
+
+ return (size_t)memStatus.ullTotalVirtual;
}
-// Get the current physical memory this process is using.
+// Get the physical memory that this process can use.
// Return:
// non zero if it has succeeded, 0 if it has failed
-size_t GCToOSInterface::GetCurrentPhysicalMemory()
+uint64_t GCToOSInterface::GetPhysicalMemoryLimit()
{
- return 0;
+ MEMORYSTATUSEX memStatus;
+
+ memStatus.dwLength = sizeof(MEMORYSTATUSEX);
+ BOOL fRet = GlobalMemoryStatusEx(&memStatus);
+ _ASSERTE(fRet);
+
+ return memStatus.ullTotalPhys;
}
// Get global memory status
// Parameters:
// ms - pointer to the structure that will be filled in with the memory status
-void GCToOSInterface::GetMemoryStatus(GCMemoryStatus* ms)
+void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file)
{
CONTRACTL
{
@@ -321,20 +329,18 @@ void GCToOSInterface::GetMemoryStatus(GCMemoryStatus* ms)
_ASSERTE (fRet);
// If the machine has more RAM than virtual address limit, let us cap it.
- // Our GC can never use more than virtual address limit.
+ // The GC can never use more than virtual address limit.
if (memStatus.ullAvailPhys > memStatus.ullTotalVirtual)
{
memStatus.ullAvailPhys = memStatus.ullAvailVirtual;
}
- // Convert Windows struct to abstract struct
- ms->dwMemoryLoad = memStatus.dwMemoryLoad ;
- ms->ullTotalPhys = memStatus.ullTotalPhys ;
- ms->ullAvailPhys = memStatus.ullAvailPhys ;
- ms->ullTotalPageFile = memStatus.ullTotalPageFile ;
- ms->ullAvailPageFile = memStatus.ullAvailPageFile ;
- ms->ullTotalVirtual = memStatus.ullTotalVirtual ;
- ms->ullAvailVirtual = memStatus.ullAvailVirtual ;
+ if (memory_load != NULL)
+ *memory_load = memStatus.dwMemoryLoad;
+ if (available_physical != NULL)
+ *available_physical = memStatus.ullAvailPhys;
+ if (available_page_file != NULL)
+ *available_page_file = memStatus.ullAvailPageFile;
}
// Get a high precision performance counter
diff --git a/src/vm/gcenv.os.cpp b/src/vm/gcenv.os.cpp
index 5580ae0c03..de87e05c19 100644
--- a/src/vm/gcenv.os.cpp
+++ b/src/vm/gcenv.os.cpp
@@ -340,15 +340,29 @@ uint32_t GCToOSInterface::GetCurrentProcessCpuCount()
return ::GetCurrentProcessCpuCount();
}
+// Return the size of the user-mode portion of the virtual address space of this process.
+// Return:
+// non zero if it has succeeded, 0 if it has failed
+size_t GCToOSInterface::GetVirtualMemoryLimit()
+{
+ MEMORYSTATUSEX memStatus;
+ ::GetProcessMemoryLoad(&memStatus);
+
+ return (size_t)memStatus.ullTotalVirtual;
+}
+
+
#ifndef FEATURE_PAL
+
typedef BOOL (WINAPI *PGET_PROCESS_MEMORY_INFO)(HANDLE handle, PROCESS_MEMORY_COUNTERS* memCounters, uint32_t cb);
static PGET_PROCESS_MEMORY_INFO GCGetProcessMemoryInfo = 0;
+static size_t g_RestrictedPhysicalMemoryLimit = (size_t)MAX_PTR;
+
typedef BOOL (WINAPI *PIS_PROCESS_IN_JOB)(HANDLE processHandle, HANDLE jobHandle, BOOL* result);
typedef BOOL (WINAPI *PQUERY_INFORMATION_JOB_OBJECT)(HANDLE jobHandle, JOBOBJECTINFOCLASS jobObjectInfoClass, void* lpJobObjectInfo, DWORD cbJobObjectInfoLength, LPDWORD lpReturnLength);
-#endif
-#if defined(FEATURE_CORECLR) && !defined(FEATURE_PAL)
+#ifdef FEATURE_CORECLR
// For coresys we need to look for an API in some apiset dll on win8 if we can't find it
// in the traditional dll.
HINSTANCE LoadDllForAPI(WCHAR* dllTraditional, WCHAR* dllApiSet)
@@ -365,20 +379,14 @@ HINSTANCE LoadDllForAPI(WCHAR* dllTraditional, WCHAR* dllApiSet)
}
#endif
-// If the process's memory is restricted (ie, beyond what's available on the machine), return that limit.
-// Return:
-// 0 if it has failed for some reason, the real value if it has succeeded
-// Remarks:
-// If a process runs with a restricted memory limit, and we are successful at getting
-// that limit, it returns the limit. If there's no limit specified, or there's an error
-// at getting that limit, it returns 0.
-uint64_t GCToOSInterface::GetRestrictedPhysicalMemoryLimit()
+static size_t GetRestrictedPhysicalMemoryLimit()
{
LIMITED_METHOD_CONTRACT;
-#ifdef FEATURE_PAL
- return 0;
-#else
+ // The limit was cached already
+ if (g_RestrictedPhysicalMemoryLimit != (size_t)MAX_PTR)
+ return g_RestrictedPhysicalMemoryLimit;
+
size_t job_physical_memory_limit = (size_t)MAX_PTR;
BOOL in_job_p = FALSE;
#ifdef FEATURE_CORECLR
@@ -470,6 +478,12 @@ uint64_t GCToOSInterface::GetRestrictedPhysicalMemoryLimit()
job_physical_memory_limit = min (job_memory_limit, job_process_memory_limit);
job_physical_memory_limit = min (job_physical_memory_limit, job_workingset_limit);
+
+ MEMORYSTATUSEX ms;
+ ::GetProcessMemoryLoad(&ms);
+
+ // A sanity check in case someone set a larger limit than there is actual physical memory.
+ job_physical_memory_limit = (size_t) min (job_physical_memory_limit, ms.ullTotalPhys);
}
}
@@ -492,46 +506,70 @@ exit:
#endif
}
- return job_physical_memory_limit;
-#endif
+ VolatileStore(&g_RestrictedPhysicalMemoryLimit, job_physical_memory_limit);
+ return g_RestrictedPhysicalMemoryLimit;
}
-// Get the current physical memory this process is using.
+#endif // FEATURE_PAL
+
+
+// Get the physical memory that this process can use.
// Return:
-// 0 if it has failed, the real value if it has succeeded
-size_t GCToOSInterface::GetCurrentPhysicalMemory()
+// non zero if it has succeeded, 0 if it has failed
+uint64_t GCToOSInterface::GetPhysicalMemoryLimit()
{
LIMITED_METHOD_CONTRACT;
#ifndef FEATURE_PAL
- PROCESS_MEMORY_COUNTERS pmc;
- if (GCGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
- return pmc.WorkingSetSize;
-#endif
+ size_t restricted_limit = GetRestrictedPhysicalMemoryLimit();
+ if (restricted_limit != 0)
+ return restricted_limit;
+#endif
- return 0;
+ MEMORYSTATUSEX memStatus;
+ ::GetProcessMemoryLoad(&memStatus);
+
+ return memStatus.ullTotalPhys;
}
// Get global memory status
// Parameters:
// ms - pointer to the structure that will be filled in with the memory status
-void GCToOSInterface::GetMemoryStatus(GCMemoryStatus* ms)
+void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file)
{
LIMITED_METHOD_CONTRACT;
- MEMORYSTATUSEX msEx;
- msEx.dwLength = sizeof(MEMORYSTATUSEX);
+#ifndef FEATURE_PAL
+ uint64_t restricted_limit = GetRestrictedPhysicalMemoryLimit();
+ if (restricted_limit != 0)
+ {
+ PROCESS_MEMORY_COUNTERS pmc;
+ if (GCGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
+ {
+ if (memory_load)
+ *memory_load = (uint32_t)((float)pmc.WorkingSetSize * 100.0 / (float)restricted_limit);
+ if (available_physical)
+ *available_physical = restricted_limit - pmc.WorkingSetSize;
+ // Available page file doesn't mean much when physical memory is restricted since
+ // we don't know how much of it is available to this process so we are not going to
+ // bother to make another OS call for it.
+ if (available_page_file)
+ *available_page_file = 0;
+
+ return;
+ }
+ }
+#endif
- ::GetProcessMemoryLoad(&msEx);
+ MEMORYSTATUSEX ms;
+ ::GetProcessMemoryLoad(&ms);
- // Convert Windows struct to abstract struct
- ms->dwMemoryLoad = msEx.dwMemoryLoad;
- ms->ullTotalPhys = msEx.ullTotalPhys;
- ms->ullAvailPhys = msEx.ullAvailPhys;
- ms->ullTotalPageFile = msEx.ullTotalPageFile;
- ms->ullAvailPageFile = msEx.ullAvailPageFile;
- ms->ullTotalVirtual = msEx.ullTotalVirtual;
- ms->ullAvailVirtual = msEx.ullAvailVirtual;
+ if (memory_load != NULL)
+ *memory_load = ms.dwMemoryLoad;
+ if (available_physical != NULL)
+ *available_physical = ms.ullAvailPhys;
+ if (available_page_file != NULL)
+ *available_page_file = ms.ullAvailPageFile;
}
// Get a high precision performance counter
@@ -688,4 +726,3 @@ void CLRCriticalSection::Leave()
WRAPPER_NO_CONTRACT;
UnsafeLeaveCriticalSection(&m_cs);
}
-