static Status wvm_Init() { WUTIL_IMPORT_KERNEL32(GetCurrentProcessorNumber, pGetCurrentProcessorNumber); WUTIL_IMPORT_KERNEL32(GetNumaProcessorNode, pGetNumaProcessorNode); WUTIL_IMPORT_KERNEL32(VirtualAllocExNuma, pVirtualAllocExNuma); if(!pGetCurrentProcessorNumber) pGetCurrentProcessorNumber = &EmulateGetCurrentProcessorNumber; if(!pGetNumaProcessorNode) pGetNumaProcessorNode = &EmulateGetNumaProcessorNode; if(!pVirtualAllocExNuma) pVirtualAllocExNuma = &EmulateVirtualAllocExNuma; return INFO::OK; }
static void PopulateNodes() { WUTIL_FUNC(pGetNumaNodeProcessorMask, BOOL, (UCHAR, PULONGLONG)); WUTIL_IMPORT_KERNEL32(GetNumaNodeProcessorMask, pGetNumaNodeProcessorMask); if(!pGetNumaNodeProcessorMask) return; DWORD_PTR processAffinity, systemAffinity; { const BOOL ok = GetProcessAffinityMask(GetCurrentProcess(), &processAffinity, &systemAffinity); WARN_IF_FALSE(ok); } ENSURE(PopulationCount(processAffinity) <= PopulationCount(systemAffinity)); for(UCHAR nodeNumber = 0; nodeNumber <= HighestNodeNumber(); nodeNumber++) { ULONGLONG affinity; { const BOOL ok = pGetNumaNodeProcessorMask(nodeNumber, &affinity); WARN_IF_FALSE(ok); } if(!affinity) continue; // empty node, skip Node* node = AddNode(); node->nodeNumber = nodeNumber; node->processorMask = wcpu_ProcessorMaskFromAffinity(processAffinity, (DWORD_PTR)affinity); } }
static UCHAR HighestNodeNumber() { WUTIL_FUNC(pGetNumaHighestNodeNumber, BOOL, (PULONG)); WUTIL_IMPORT_KERNEL32(GetNumaHighestNodeNumber, pGetNumaHighestNodeNumber); if(!pGetNumaHighestNodeNumber) return 0; // NUMA not supported => only one node ULONG highestNodeNumber; const BOOL ok = pGetNumaHighestNodeNumber(&highestNodeNumber); WARN_IF_FALSE(ok); return (UCHAR)highestNodeNumber; }
static bool VerifyPages(void* mem, size_t size, size_t pageSize, size_t node) { WUTIL_FUNC(pQueryWorkingSetEx, BOOL, (HANDLE, PVOID, DWORD)); WUTIL_IMPORT_KERNEL32(QueryWorkingSetEx, pQueryWorkingSetEx); if(!pQueryWorkingSetEx) return true; // can't do anything #if WINVER >= 0x600 size_t largePageSize = os_cpu_LargePageSize(); ENSURE(largePageSize != 0); // this value is needed for later // retrieve attributes of all pages constituting mem const size_t numPages = (size + pageSize-1) / pageSize; PSAPI_WORKING_SET_EX_INFORMATION* wsi = new PSAPI_WORKING_SET_EX_INFORMATION[numPages]; for(size_t i = 0; i < numPages; i++) wsi[i].VirtualAddress = (u8*)mem + i*pageSize; pQueryWorkingSetEx(GetCurrentProcess(), wsi, DWORD(sizeof(PSAPI_WORKING_SET_EX_INFORMATION)*numPages)); // ensure each is valid and allocated on the correct node for(size_t i = 0; i < numPages; i++) { const PSAPI_WORKING_SET_EX_BLOCK& attributes = wsi[i].VirtualAttributes; if(!attributes.Valid) return false; if((attributes.LargePage != 0) != (pageSize == largePageSize)) { debug_printf("NUMA: is not a large page\n"); return false; } if(attributes.Node != node) { debug_printf("NUMA: allocated from remote node\n"); return false; } } delete[] wsi; #else UNUSED2(mem); UNUSED2(size); UNUSED2(pageSize); UNUSED2(node); #endif return true; }
static void EnableLowFragmentationHeap() { if(IsDebuggerPresent()) { // and the debug heap isn't explicitly disabled, char* var = getenv("_NO_DEBUG_HEAP"); if(!var || var[0] != '1') return; // we can't enable the LFH } #if WINVER >= 0x0501 WUTIL_FUNC(pHeapSetInformation, BOOL, (HANDLE, HEAP_INFORMATION_CLASS, void*, size_t)); WUTIL_IMPORT_KERNEL32(HeapSetInformation, pHeapSetInformation); if(pHeapSetInformation) { ULONG flags = 2; // enable LFH pHeapSetInformation(GetProcessHeap(), HeapCompatibilityInformation, &flags, sizeof(flags)); } #endif // #if WINVER >= 0x0501 }
size_t numa_AvailableMemory(size_t node) { // note: it is said that GetNumaAvailableMemoryNode sometimes incorrectly // reports zero bytes. the actual cause may however be unexpected // RAM configuration, e.g. not all slots filled. WUTIL_FUNC(pGetNumaAvailableMemoryNode, BOOL, (UCHAR, PULONGLONG)); WUTIL_IMPORT_KERNEL32(GetNumaAvailableMemoryNode, pGetNumaAvailableMemoryNode); if(pGetNumaAvailableMemoryNode) { const UCHAR nodeNumber = NodeNumberFromNode(node); ULONGLONG availableBytes; const BOOL ok = pGetNumaAvailableMemoryNode(nodeNumber, &availableBytes); WARN_IF_FALSE(ok); const size_t availableMiB = size_t(availableBytes / MiB); return availableMiB; } // NUMA not supported - return available system memory else return os_cpu_MemoryAvailable(); }
static void ImportWow64Functions() { WUTIL_IMPORT_KERNEL32(IsWow64Process, pIsWow64Process); WUTIL_IMPORT_KERNEL32(Wow64DisableWow64FsRedirection, pWow64DisableWow64FsRedirection); WUTIL_IMPORT_KERNEL32(Wow64RevertWow64FsRedirection, pWow64RevertWow64FsRedirection); }