From c4341d45acca3ea662cd8d71e7d71094450dd045 Mon Sep 17 00:00:00 2001 From: Manish Godse <61718172+mangod9@users.noreply.github.com> Date: Tue, 25 Oct 2022 13:42:49 -0700 Subject: [PATCH] statically linking GC PAL on linux (#76985) * statically linking GC PAL The GC PAL will be used for both coreclr and standalone GC on linux * fixing arm64 and nativeaot build breaks * macos build break and reducing renaming. * trying to remove numa support from PAL * one more rename to resolve MacOS break * delete pal numa code. * Adding missing madvise in GC PAL * added missing MADV_DONTDUMP calls. * CR feedback * undo (long long) cast in GetMemoryStatus * only invoke madvise on success. --- .../dlls/mscordac/mscordac_unixexports.src | 3 - .../dlls/mscoree/coreclr/CMakeLists.txt | 2 + src/coreclr/gc/CMakeLists.txt | 8 +- src/coreclr/gc/unix/cgroup.cpp | 3 + src/coreclr/gc/unix/gcenv.unix.cpp | 32 +- src/coreclr/pal/src/CMakeLists.txt | 1 - src/coreclr/pal/src/include/pal/palinternal.h | 2 +- src/coreclr/pal/src/init/pal.cpp | 7 - src/coreclr/pal/src/misc/cgroup.cpp | 2 +- src/coreclr/pal/src/misc/sysinfo.cpp | 6 +- src/coreclr/pal/src/numa/numa.cpp | 292 ------------------ src/coreclr/pal/src/numa/numashim.h | 36 --- src/coreclr/utilcode/util.cpp | 5 +- src/coreclr/vm/CMakeLists.txt | 8 +- src/coreclr/vm/ceemain.cpp | 3 +- 15 files changed, 56 insertions(+), 354 deletions(-) delete mode 100644 src/coreclr/pal/src/numa/numa.cpp delete mode 100644 src/coreclr/pal/src/numa/numashim.h diff --git a/src/coreclr/dlls/mscordac/mscordac_unixexports.src b/src/coreclr/dlls/mscordac/mscordac_unixexports.src index ab03a8428ac0c..a6ffa08cb1bcc 100644 --- a/src/coreclr/dlls/mscordac/mscordac_unixexports.src +++ b/src/coreclr/dlls/mscordac/mscordac_unixexports.src @@ -30,7 +30,6 @@ nativeStringResourceTable_mscorrc #PAL_free #PAL_GetLogicalCpuCountFromOS #PAL_GetTotalCpuCount -#PAL_GetNumaProcessorNode #PAL_GetUnwindInfoSize #PAL_get_stdout #PAL_get_stderr @@ -122,7 +121,6 @@ nativeStringResourceTable_mscorrc #GetFullPathNameW #GetLastError #GetModuleFileNameW -#GetNumaHighestNodeNumber #GetProcAddress #GetStdHandle #GetSystemInfo @@ -163,7 +161,6 @@ nativeStringResourceTable_mscorrc #SwitchToThread #TerminateProcess #VirtualAlloc -#VirtualAllocExNuma #VirtualFree #VirtualProtect #VirtualQuery diff --git a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt index 688629d178ddc..6e22bd96f79dc 100644 --- a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt +++ b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt @@ -82,6 +82,7 @@ set_property(TARGET coreclr APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE}) if (CLR_CMAKE_HOST_UNIX) set(LIB_UNWINDER unwinder_wks) + set(GC_PAL gc_unix) endif (CLR_CMAKE_HOST_UNIX) # IMPORTANT! Please do not rearrange the order of the libraries. The linker on Linux is @@ -108,6 +109,7 @@ set(CORECLR_LIBRARIES System.Globalization.Native-Static interop coreclrminipal + ${GC_PAL} ) if(CLR_CMAKE_TARGET_WIN32) diff --git a/src/coreclr/gc/CMakeLists.txt b/src/coreclr/gc/CMakeLists.txt index 9052c4a529f7e..4441c41df36f9 100644 --- a/src/coreclr/gc/CMakeLists.txt +++ b/src/coreclr/gc/CMakeLists.txt @@ -27,12 +27,10 @@ set(GC_SOURCES handletablecache.cpp) if(CLR_CMAKE_HOST_UNIX) + add_subdirectory(unix) include(unix/configure.cmake) set (GC_SOURCES - ${GC_SOURCES} - unix/gcenv.unix.cpp - unix/events.cpp - unix/cgroup.cpp) + ${GC_SOURCES}) else() set (GC_SOURCES ${GC_SOURCES} @@ -101,7 +99,7 @@ if(CLR_CMAKE_HOST_WIN32) kernel32.lib advapi32.lib) else() - set (GC_LINK_LIBRARIES) + set (GC_LINK_LIBRARIES gc_unix) endif(CLR_CMAKE_HOST_WIN32) list(APPEND GC_SOURCES ${GC_HEADERS}) diff --git a/src/coreclr/gc/unix/cgroup.cpp b/src/coreclr/gc/unix/cgroup.cpp index ad2a41284cbbe..136ff3fb19105 100644 --- a/src/coreclr/gc/unix/cgroup.cpp +++ b/src/coreclr/gc/unix/cgroup.cpp @@ -54,6 +54,8 @@ Module Name: extern bool ReadMemoryValueFromFile(const char* filename, uint64_t* val); +namespace +{ class CGroup { // the cgroup version number or 0 to indicate cgroups are not found or not enabled @@ -453,6 +455,7 @@ class CGroup return foundInactiveFileValue; } }; +} int CGroup::s_cgroup_version = 0; char *CGroup::s_memory_cgroup_path = nullptr; diff --git a/src/coreclr/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp index 8037fa084b657..b02f6d29c151b 100644 --- a/src/coreclr/gc/unix/gcenv.unix.cpp +++ b/src/coreclr/gc/unix/gcenv.unix.cpp @@ -659,6 +659,10 @@ static void* VirtualReserveInner(size_t size, size_t alignment, uint32_t flags, } pRetVal = pAlignedRetVal; +#ifdef MADV_DONTDUMP + // Do not include reserved memory in coredump. + madvise(pRetVal, size, MADV_DONTDUMP); +#endif } return pRetVal; @@ -724,6 +728,14 @@ bool GCToOSInterface::VirtualCommit(void* address, size_t size, uint16_t node) { bool success = mprotect(address, size, PROT_WRITE | PROT_READ) == 0; +#ifdef MADV_DODUMP + if (success) + { + // Include committed memory in coredump. + madvise(address, size, MADV_DODUMP); + } +#endif + #if HAVE_NUMA_H if (success && g_numaAvailable && (node != NUMA_NODE_UNDEFINED)) { @@ -760,7 +772,17 @@ bool GCToOSInterface::VirtualDecommit(void* address, size_t size) // that much more clear to the operating system that we no // longer need these pages. Also, GC depends on re-committed pages to // be zeroed-out. - return mmap(address, size, PROT_NONE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0) != NULL; + bool bRetVal = mmap(address, size, PROT_NONE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0) != MAP_FAILED; + +#ifdef MADV_DONTDUMP + if (bRetVal) + { + // Do not include freed memory in coredump. + madvise(address, size, MADV_DONTDUMP); + } +#endif + + return bRetVal; } // Reset virtual memory range. Indicates that data in the memory range specified by address and size is no @@ -791,6 +813,14 @@ bool GCToOSInterface::VirtualReset(void * address, size_t size, bool unlock) #endif } +#ifdef MADV_DONTDUMP + if (st == 0) + { + // Do not include reset memory in coredump. + madvise(address, size, MADV_DONTDUMP); + } +#endif + return (st == 0); } diff --git a/src/coreclr/pal/src/CMakeLists.txt b/src/coreclr/pal/src/CMakeLists.txt index 1315dac0cb1b9..1088bb1791869 100644 --- a/src/coreclr/pal/src/CMakeLists.txt +++ b/src/coreclr/pal/src/CMakeLists.txt @@ -171,7 +171,6 @@ set(SOURCES misc/sysinfo.cpp misc/time.cpp misc/utils.cpp - numa/numa.cpp objmgr/palobjbase.cpp objmgr/shmobject.cpp objmgr/shmobjectmanager.cpp diff --git a/src/coreclr/pal/src/include/pal/palinternal.h b/src/coreclr/pal/src/include/pal/palinternal.h index 89923bf5248e3..cbe75eb2c4ebe 100644 --- a/src/coreclr/pal/src/include/pal/palinternal.h +++ b/src/coreclr/pal/src/include/pal/palinternal.h @@ -648,7 +648,7 @@ typedef enum _TimeConversionConstants } bool -ReadMemoryValueFromFile(const char* filename, uint64_t* val); +PAL_ReadMemoryValueFromFile(const char* filename, uint64_t* val); #ifdef __APPLE__ bool diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp index 72c0ffb9fa6e8..bddda8ceb023b 100644 --- a/src/coreclr/pal/src/init/pal.cpp +++ b/src/coreclr/pal/src/init/pal.cpp @@ -673,13 +673,6 @@ Initialize( goto CLEANUP15; } - if (FALSE == NUMASupportInitialize()) - { - ERROR("Unable to initialize NUMA support\n"); - palError = ERROR_PALINIT_NUMA; - goto CLEANUP15; - } - TRACE("First-time PAL initialization complete.\n"); init_count++; diff --git a/src/coreclr/pal/src/misc/cgroup.cpp b/src/coreclr/pal/src/misc/cgroup.cpp index 6a100d9389c5f..0eae4e8db451d 100644 --- a/src/coreclr/pal/src/misc/cgroup.cpp +++ b/src/coreclr/pal/src/misc/cgroup.cpp @@ -470,7 +470,7 @@ class CGroup static bool ReadMemoryValueFromFile(const char* filename, uint64_t* val) { - return ::ReadMemoryValueFromFile(filename, val); + return ::PAL_ReadMemoryValueFromFile(filename, val); } static bool GetCGroup1CpuLimit(UINT *val) diff --git a/src/coreclr/pal/src/misc/sysinfo.cpp b/src/coreclr/pal/src/misc/sysinfo.cpp index 102a012f76af3..f9731f474586e 100644 --- a/src/coreclr/pal/src/misc/sysinfo.cpp +++ b/src/coreclr/pal/src/misc/sysinfo.cpp @@ -504,7 +504,7 @@ PAL_HasGetCurrentProcessorNumber() } bool -ReadMemoryValueFromFile(const char* filename, uint64_t* val) +PAL_ReadMemoryValueFromFile(const char* filename, uint64_t* val) { bool result = false; char *line = nullptr; @@ -585,11 +585,11 @@ PAL_GetLogicalProcessorCacheSizeFromOS() { path_to_size_file[index] = (char)(48 + i); - if (ReadMemoryValueFromFile(path_to_size_file, &size)) + if (PAL_ReadMemoryValueFromFile(path_to_size_file, &size)) { path_to_level_file[index] = (char)(48 + i); - if (ReadMemoryValueFromFile(path_to_level_file, &level)) + if (PAL_ReadMemoryValueFromFile(path_to_level_file, &level)) { UPDATE_CACHE_SIZE_AND_LEVEL(size, level) } diff --git a/src/coreclr/pal/src/numa/numa.cpp b/src/coreclr/pal/src/numa/numa.cpp deleted file mode 100644 index 676775ca63735..0000000000000 --- a/src/coreclr/pal/src/numa/numa.cpp +++ /dev/null @@ -1,292 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*++ - - - -Module Name: - - numa.cpp - -Abstract: - - Implementation of NUMA related APIs - ---*/ - -#include "pal/dbgmsg.h" -SET_DEFAULT_DEBUG_CHANNEL(NUMA); - -#include "pal/palinternal.h" -#include "pal/dbgmsg.h" -#include "pal/numa.h" -#include "pal/corunix.hpp" -#include "pal/thread.hpp" - -#include -#ifdef __FreeBSD__ -#include -#else -#include -#endif - -#include - -#include "numashim.h" - -using namespace CorUnix; - -// The highest NUMA node available -int g_highestNumaNode = 0; -// Is numa available -bool g_numaAvailable = false; - -void* numaHandle = nullptr; - -#if HAVE_NUMA_H -#include -#include -#include - -#define PER_FUNCTION_BLOCK(fn) decltype(fn)* fn##_ptr; -FOR_ALL_NUMA_FUNCTIONS -#undef PER_FUNCTION_BLOCK - -#if defined(__linux__) -static bool ShouldOpenLibNuma() -{ - // This is a simple heuristic to determine if libnuma.so should be opened. There's - // no point in linking and resolving everything in this library if we're running on - // a system that's not NUMA-capable. - int fd = open("/sys/devices/system/node/possible", O_RDONLY | O_CLOEXEC); - - if (fd == -1) - { - // sysfs might not be mounted, not available, or the interface might have - // changed. Return `true' here so NUMASupportInitialize() can try initializing - // NUMA support with libnuma. - return true; - } - - while (true) - { - char buffer[32]; - ssize_t bytesRead = read(fd, buffer, 32); - - if (bytesRead == -1 && errno == EINTR) - { - continue; - } - - close(fd); - - // If an unknown error happened (bytesRead < 0), or the file was empty - // (bytesRead = 0), let libnuma handle this. Otherwise, if there's just - // one NUMA node, don't bother linking in libnuma. - return (bytesRead <= 0) ? true : strncmp(buffer, "0\n", bytesRead) != 0; - } -} -#else -static bool ShouldOpenLibNuma() -{ - return true; -} -#endif // __linux__ - -#endif // HAVE_NUMA_H - -/*++ -Function: - NUMASupportInitialize - -Initialize data structures for getting and setting thread affinities to processors and -querying NUMA related processor information. -On systems with no NUMA support, it behaves as if there was a single NUMA node with -a single group of processors. ---*/ -BOOL -NUMASupportInitialize() -{ -#if HAVE_NUMA_H - if (!ShouldOpenLibNuma()) - { - g_numaAvailable = false; - g_highestNumaNode = 0; - return TRUE; - } - - numaHandle = dlopen("libnuma.so.1", RTLD_LAZY); - if (numaHandle == 0) - { - numaHandle = dlopen("libnuma.so.1.0.0", RTLD_LAZY); - if (numaHandle == 0) - { - numaHandle = dlopen("libnuma.so", RTLD_LAZY); - } - } - if (numaHandle != 0) - { -#define PER_FUNCTION_BLOCK(fn) \ - fn##_ptr = (decltype(fn)*)dlsym(numaHandle, #fn); \ - if (fn##_ptr == NULL) { fprintf(stderr, "Cannot get symbol " #fn " from libnuma\n"); abort(); } -FOR_ALL_NUMA_FUNCTIONS -#undef PER_FUNCTION_BLOCK - - if (numa_available() == -1) - { - dlclose(numaHandle); - } - else - { - g_numaAvailable = true; - g_highestNumaNode = numa_max_node(); - } - } -#endif // HAVE_NUMA_H - if (!g_numaAvailable) - { - // No NUMA - g_highestNumaNode = 0; - } - - return TRUE; -} - -/*++ -Function: - NUMASupportCleanup - -Cleanup of the NUMA support data structures ---*/ -VOID -NUMASupportCleanup() -{ -#if HAVE_NUMA_H - if (g_numaAvailable) - { - dlclose(numaHandle); - } -#endif // HAVE_NUMA_H -} - -/*++ -Function: - GetNumaHighestNodeNumber - -See MSDN doc. ---*/ -BOOL -PALAPI -GetNumaHighestNodeNumber( - OUT PULONG HighestNodeNumber -) -{ - PERF_ENTRY(GetNumaHighestNodeNumber); - ENTRY("GetNumaHighestNodeNumber(HighestNodeNumber=%p)\n", HighestNodeNumber); - *HighestNodeNumber = (ULONG)g_highestNumaNode; - - BOOL success = TRUE; - - LOGEXIT("GetNumaHighestNodeNumber returns BOOL %d\n", success); - PERF_EXIT(GetNumaHighestNodeNumber); - - return success; -} - -/*++ -Function: - PAL_GetNumaProcessorNode - -Abstract - Get NUMA node of a processor - -Parameters: - procNo - number of the processor to get the NUMA node for - node - the resulting NUMA node - -Return value: - TRUE if the function was able to get the NUMA node, FALSE if it has failed. ---*/ -BOOL -PALAPI -PAL_GetNumaProcessorNode(WORD procNo, WORD* node) -{ -#if HAVE_NUMA_H - if (g_numaAvailable) - { - int result = numa_node_of_cpu(procNo); - if (result >= 0) - { - *node = (WORD)result; - return TRUE; - } - } -#endif // HAVE_NUMA_H - - return FALSE; -} - -/*++ -Function: - VirtualAllocExNuma - -See MSDN doc. ---*/ -LPVOID -PALAPI -VirtualAllocExNuma( - IN HANDLE hProcess, - IN OPTIONAL LPVOID lpAddress, - IN SIZE_T dwSize, - IN DWORD flAllocationType, - IN DWORD flProtect, - IN DWORD nndPreferred -) -{ - PERF_ENTRY(VirtualAllocExNuma); - ENTRY("VirtualAllocExNuma(hProcess=%p, lpAddress=%p, dwSize=%u, flAllocationType=%#x, flProtect=%#x, nndPreferred=%d\n", - hProcess, lpAddress, dwSize, flAllocationType, flProtect, nndPreferred); - - LPVOID result = NULL; - - if (hProcess == GetCurrentProcess()) - { - if ((int)nndPreferred <= g_highestNumaNode) - { - result = VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect); -#if HAVE_NUMA_H - if (result != NULL && g_numaAvailable) - { - int usedNodeMaskBits = g_highestNumaNode + 1; - int nodeMaskLength = (usedNodeMaskBits + sizeof(unsigned long) - 1) / sizeof(unsigned long); - unsigned long nodeMask[nodeMaskLength]; - memset(nodeMask, 0, sizeof(nodeMask)); - - int index = nndPreferred / sizeof(unsigned long); - nodeMask[index] = ((unsigned long)1) << (nndPreferred & (sizeof(unsigned long) - 1)); - - int st = mbind(result, dwSize, MPOL_PREFERRED, nodeMask, usedNodeMaskBits, 0); - - _ASSERTE(st == 0); - // If the mbind fails, we still return the allocated memory since the nndPreferred is just a hint - } -#endif // HAVE_NUMA_H - } - else - { - // The specified node number is larger than the maximum available one - SetLastError(ERROR_INVALID_PARAMETER); - } - } - else - { - // PAL supports allocating from the current process virtual space only - SetLastError(ERROR_INVALID_PARAMETER); - } - - LOGEXIT("VirtualAllocExNuma returns %p\n", result); - PERF_EXIT(VirtualAllocExNuma); - - return result; -} diff --git a/src/coreclr/pal/src/numa/numashim.h b/src/coreclr/pal/src/numa/numashim.h deleted file mode 100644 index c6594b5d06325..0000000000000 --- a/src/coreclr/pal/src/numa/numashim.h +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Enable calling numa functions through shims to make it a soft -// runtime dependency. - -#ifndef __NUMASHIM_H__ -#define __NUMASHIM_H__ - -#if HAVE_NUMA_H - -#include -#include - -// List of all functions from the numa library that are used -#define FOR_ALL_NUMA_FUNCTIONS \ - PER_FUNCTION_BLOCK(numa_available) \ - PER_FUNCTION_BLOCK(mbind) \ - PER_FUNCTION_BLOCK(numa_max_node) \ - PER_FUNCTION_BLOCK(numa_node_of_cpu) - -// Declare pointers to all the used numa functions -#define PER_FUNCTION_BLOCK(fn) extern decltype(fn)* fn##_ptr; -FOR_ALL_NUMA_FUNCTIONS -#undef PER_FUNCTION_BLOCK - -// Redefine all calls to numa functions as calls through pointers that are set -// to the functions of libnuma in the initialization. -#define numa_available() numa_available_ptr() -#define mbind(...) mbind_ptr(__VA_ARGS__) -#define numa_max_node() numa_max_node_ptr() -#define numa_node_of_cpu(...) numa_node_of_cpu_ptr(__VA_ARGS__) - -#endif // HAVE_NUMA_H - -#endif // __NUMASHIM_H__ diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index 1639960a504e0..a331cddf195c9 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -513,6 +513,8 @@ BYTE * ClrVirtualAllocWithinRange(const BYTE *pMinAddr, return pResult; } +#ifdef HOST_WINDOWS + //****************************************************************************** // NumaNodeInfo //****************************************************************************** @@ -524,7 +526,6 @@ BYTE * ClrVirtualAllocWithinRange(const BYTE *pMinAddr, return ::VirtualAllocExNuma(hProc, lpAddr, dwSize, allocType, prot, node); } -#ifdef HOST_WINDOWS /*static*/ BOOL NumaNodeInfo::GetNumaProcessorNodeEx(PPROCESSOR_NUMBER proc_no, PUSHORT node_no) { return ::GetNumaProcessorNodeEx(proc_no, node_no); @@ -566,6 +567,7 @@ BYTE * ClrVirtualAllocWithinRange(const BYTE *pMinAddr, #endif // HOST_WINDOWS #endif +#ifdef HOST_WINDOWS /*static*/ BOOL NumaNodeInfo::m_enableGCNumaAware = FALSE; /*static*/ uint16_t NumaNodeInfo::m_nNodes = 0; /*static*/ BOOL NumaNodeInfo::InitNumaNodeInfoAPI() @@ -599,7 +601,6 @@ BYTE * ClrVirtualAllocWithinRange(const BYTE *pMinAddr, m_enableGCNumaAware = InitNumaNodeInfoAPI(); } -#ifdef HOST_WINDOWS //****************************************************************************** // CPUGroupInfo diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index 153fe06f44f4a..8ac82802a9a41 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -324,7 +324,6 @@ set(VM_SOURCES_WKS gccover.cpp gcenv.ee.static.cpp gcenv.ee.common.cpp - gcenv.os.cpp gchelpers.cpp genanalysis.cpp genmeth.cpp @@ -504,6 +503,13 @@ if (CLR_CMAKE_TARGET_ARCH_AMD64 AND CLR_CMAKE_TARGET_WIN32) ) endif (CLR_CMAKE_TARGET_ARCH_AMD64 AND CLR_CMAKE_TARGET_WIN32) +if (CLR_CMAKE_TARGET_WIN32) + set ( GC_SOURCES_WKS + ${GC_SOURCES_WKS} + gcenv.os.cpp + ) +endif (CLR_CMAKE_TARGET_WIN32) + set(GC_HEADERS_WKS ${GC_HEADERS_DAC_AND_WKS_COMMON} ../gc/gceventstatus.h diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index cb6720645c43f..a2040948c31ec 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -624,12 +624,13 @@ void EEStartupHelper() #ifdef HOST_WINDOWS InitializeCrashDump(); -#endif // HOST_WINDOWS + // Initialize Numa and CPU group information // Need to do this as early as possible. Used by creating object handle // table inside Ref_Initialization() before GC is initialized. NumaNodeInfo::InitNumaNodeInfo(); +#endif // HOST_WINDOWS #ifndef TARGET_UNIX CPUGroupInfo::EnsureInitialized(); #endif // !TARGET_UNIX