diff options
author | Jan Kotas <jkotas@microsoft.com> | 2016-05-17 08:36:57 -0700 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2016-05-17 08:36:57 -0700 |
commit | 0f94239fadf20295b4fc7e8935ffd27a289f9d5e (patch) | |
tree | 25a90f0f9a4ba257bf427398999d2713ee4a4c9a | |
parent | 8162628ae3bcbe805abf9266f67d4c42880bc2e8 (diff) | |
download | coreclr-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.h | 34 | ||||
-rw-r--r-- | src/gc/env/gcenv.structs.h | 14 | ||||
-rw-r--r-- | src/gc/gc.cpp | 59 | ||||
-rw-r--r-- | src/gc/gcpriv.h | 3 | ||||
-rw-r--r-- | src/gc/sample/gcenv.windows.cpp | 46 | ||||
-rw-r--r-- | src/vm/gcenv.os.cpp | 109 |
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); } - |