23 #include "precompiled.h"
67 for(
size_t node = 0; node <
numNodes; node++)
69 if(nodes[node].processorMask == processorMask)
78 for(
size_t node = 0; node <
numNodes; node++)
80 if(
IsBitSet(nodes[node].processorMask, processor))
95 if(!pGetNumaHighestNodeNumber)
98 ULONG highestNodeNumber;
99 const BOOL ok = pGetNumaHighestNodeNumber(&highestNodeNumber);
101 return (UCHAR)highestNodeNumber;
108 if(!pGetNumaNodeProcessorMask)
111 DWORD_PTR processAffinity, systemAffinity;
113 const BOOL ok = GetProcessAffinityMask(GetCurrentProcess(), &processAffinity, &systemAffinity);
122 const BOOL ok = pGetNumaNodeProcessorMask(nodeNumber, &affinity);
140 #pragma pack(push, 1)
143 struct AffinityHeader
151 static const u8 type = 0;
153 AffinityHeader header;
154 u8 proximityDomainNumber0;
158 u8 proximityDomainNumber123[3];
161 u32 ProximityDomainNumber()
const
164 u32 proximityDomainNumber;
165 memcpy(&proximityDomainNumber, &proximityDomainNumber123[0]-1,
sizeof(proximityDomainNumber));
166 proximityDomainNumber &= ~0xFF;
167 proximityDomainNumber |= proximityDomainNumber0;
168 return proximityDomainNumber;
172 struct AffinityMemory
174 static const u8 type = 1;
176 AffinityHeader header;
177 u32 proximityDomainNumber;
194 AffinityHeader affinities[1];
199 template<
class Affinity>
200 static const Affinity* DynamicCastFromHeader(
const AffinityHeader* header)
202 if(header->type != Affinity::type)
206 ENSURE(header->length ==
sizeof(Affinity));
208 const Affinity* affinity = (
const Affinity*)header;
215 struct ProximityDomain
217 uintptr_t processorMask;
221 typedef std::map<u32, ProximityDomain> ProximityDomains;
223 static ProximityDomains ExtractProximityDomainsFromSRAT(
const SRAT* srat)
225 ProximityDomains proximityDomains;
227 for(
const AffinityHeader* header = srat->affinities;
228 header < (
const AffinityHeader*)(uintptr_t(srat)+srat->header.size);
229 header = (
const AffinityHeader*)(uintptr_t(header) + header->length))
231 const AffinityAPIC* affinityAPIC = DynamicCastFromHeader<AffinityAPIC>(header);
235 const u32 proximityDomainNumber = affinityAPIC->ProximityDomainNumber();
236 ProximityDomain& proximityDomain = proximityDomains[proximityDomainNumber];
237 proximityDomain.processorMask |= Bit<uintptr_t>(processor);
241 return proximityDomains;
244 static void PopulateNodesFromProximityDomains(
const ProximityDomains& proximityDomains)
246 for(ProximityDomains::const_iterator it = proximityDomains.begin(); it != proximityDomains.end(); ++it)
248 const u32 proximityDomainNumber = it->first;
249 const ProximityDomain& proximityDomain = it->second;
260 #endif // #if ARCH_X86_X64
275 const ProximityDomains proximityDomains = ExtractProximityDomainsFromSRAT(srat);
276 PopulateNodesFromProximityDomains(proximityDomains);
331 WUTIL_FUNC(pGetNumaAvailableMemoryNode,
BOOL, (UCHAR, PULONGLONG));
333 if(pGetNumaAvailableMemoryNode)
336 ULONGLONG availableBytes;
337 const BOOL ok = pGetNumaAvailableMemoryNode(nodeNumber, &availableBytes);
339 const size_t availableMiB = size_t(availableBytes /
MiB);
348 #pragma pack(push, 1)
366 for(
size_t i = 0; i < n; i++)
369 return *std::max_element(slit->
entries, slit->
entries+n*n) / 10.0;
376 const size_t size = 32*
MiB;
382 double minTime = 1e10, maxTime = 0.0;
389 memset(mem, 0, size);
390 const double elapsedTime =
timer_Time() - startTime;
392 minTime = std::min(minTime, elapsedTime);
393 maxTime = std::max(maxTime, elapsedTime);
400 return maxTime / minTime;
410 relativeDistance = 1.0;
421 ENSURE(relativeDistance >= 1.0);
422 ENSURE(relativeDistance <= 4.0);
468 static bool VerifyPages(
void* mem,
size_t size,
size_t pageSize,
size_t node)
472 if(!pQueryWorkingSetEx)
477 ENSURE(largePageSize != 0);
480 const size_t numPages = (size + pageSize-1) / pageSize;
481 PSAPI_WORKING_SET_EX_INFORMATION* wsi =
new PSAPI_WORKING_SET_EX_INFORMATION[numPages];
482 for(
size_t i = 0; i < numPages; i++)
483 wsi[i].VirtualAddress = (
u8*)mem + i*
pageSize;
484 pQueryWorkingSetEx(GetCurrentProcess(), wsi,
DWORD(
sizeof(PSAPI_WORKING_SET_EX_INFORMATION)*numPages));
487 for(
size_t i = 0; i < numPages; i++)
489 const PSAPI_WORKING_SET_EX_BLOCK& attributes = wsi[i].VirtualAttributes;
490 if(!attributes.Valid)
492 if((attributes.LargePage != 0) != (pageSize == largePageSize))
497 if(attributes.Node != node)
u32 proximityDomainNumber
bool AreApicIdsReliable()
LIB_API size_t numa_NodeFromProcessor(size_t processor)
static const size_t pageSize
#define WUTIL_FUNC(varName, ret, params)
static const size_t os_cpu_MaxProcessors
maximum number of processors supported by the OS (determined by the number of bits in an affinity mas...
#define ASSUME_ALIGNED(ptr, multiple)
LIB_API size_t numa_AvailableMemory(size_t node)
static Status InitMemoryInterleaved()
static size_t PopulationCount(T x)
static Node nodes[os_cpu_MaxProcessors]
const AcpiTable * acpi_GetTable(const char *signature)
LIB_API double numa_Factor()
static UCHAR HighestNodeNumber()
LIB_API uintptr_t numa_ProcessorMaskFromNode(size_t node)
size_t os_cpu_NumProcessors()
size_t os_cpu_LargePageSize()
size_t ProcessorFromApicId(ApicId apicId)
uintptr_t os_cpu_SetThreadAffinityMask(uintptr_t processorMask)
restrict the current thread to a set of processors.
static UCHAR NodeNumberFromNode(size_t node)
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
#define UNUSED2(param)
mark a function local variable or parameter as unused and avoid the corresponding compiler warning...
intptr_t ModuleInitState
initialization state of a module (class, source file, etc.) must be initialized to zero (e...
static void PopulateNodes()
bool IsBitSet(T value, size_t index)
size_t os_cpu_MemoryAvailable()
uintptr_t wcpu_ProcessorMaskFromAffinity(DWORD_PTR processAffinity, DWORD_PTR affinity)
static Node * FindNodeWithProcessorMask(uintptr_t processorMask)
static double relativeDistance
i64 Status
Error handling system.
static bool IsMemoryInterleaved()
uintptr_t os_cpu_ProcessorMask()
static Node * FindNodeWithProcessor(size_t processor)
static Status InitTopology()
static double MeasureRelativeDistance()
LIB_API size_t numa_NumNodes()
LIB_API bool numa_IsMemoryInterleaved()
static bool isMemoryInterleaved
#define WARN_IF_FALSE(expression)
static const size_t largePageSize
static ModuleInitState initState
void * Allocate(size_t size, PageType pageType, int prot)
reserve address space and commit memory.
static double ReadRelativeDistanceFromSLIT(const SLIT *slit)
Status ModuleInit(volatile ModuleInitState *initState, Status(*init)())
calls a user-defined init function if initState is zero.
void Free(void *p, size_t size)
decommit memory and release address space.
#define WUTIL_IMPORT_KERNEL32(procName, varName)
void debug_printf(const wchar_t *fmt,...)
write a formatted string to the debug channel, subject to filtering (see below).
static Status InitRelativeDistance()