diff --git a/src/PerfectHash/BulkCreateBestCsv.h b/src/PerfectHash/BulkCreateBestCsv.h index 6e9bccd7..12d40b89 100644 --- a/src/PerfectHash/BulkCreateBestCsv.h +++ b/src/PerfectHash/BulkCreateBestCsv.h @@ -54,6 +54,55 @@ Module Name: &Context->Rtl->CpuFeatures.Brand, \ OUTPUT_STRING) \ \ + ENTRY(CpuSocketCount, \ + Context->Rtl->CpuFeatures.ProcessorPackageCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuNumaNodeCount, \ + Context->Rtl->CpuFeatures.NumaNodeCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuProcessorCoreCount, \ + Context->Rtl->CpuFeatures.ProcessorCoreCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuLogicalProcessorCount, \ + Context->Rtl->CpuFeatures.LogicalProcessorCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1InstructionSize, \ + Context->Rtl->CpuFeatures.Caches.L1.Instruction.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1DataSize, \ + Context->Rtl->CpuFeatures.Caches.L1.Data.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1Total, \ + ((ULONGLONG)Context->Rtl->CpuFeatures.Caches.L1.Instruction.Size + \ + (ULONGLONG)Context->Rtl->CpuFeatures.Caches.L1.Data.Size), \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL2UnifiedSize, \ + Context->Rtl->CpuFeatures.Caches.L2.Unified.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL3UnifiedSize, \ + Context->Rtl->CpuFeatures.Caches.L3.Unified.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1TraceSize, \ + Context->Rtl->CpuFeatures.Caches.L1.Trace.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL2TraceSize, \ + Context->Rtl->CpuFeatures.Caches.L2.Trace.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL3TraceSize, \ + Context->Rtl->CpuFeatures.Caches.L3.Trace.Size, \ + OUTPUT_INT) \ + \ ENTRY(KeysName, \ &Keys->File->Path->BaseNameA, \ OUTPUT_STRING) \ diff --git a/src/PerfectHash/BulkCreateCsv.h b/src/PerfectHash/BulkCreateCsv.h index 74ff530e..747d843d 100644 --- a/src/PerfectHash/BulkCreateCsv.h +++ b/src/PerfectHash/BulkCreateCsv.h @@ -45,6 +45,63 @@ Module Name: &Context->HexHeaderHash, \ OUTPUT_STRING) \ \ + ENTRY(ComputerName, \ + &Context->ComputerName, \ + OUTPUT_STRING) \ + \ + ENTRY(CpuBrand, \ + &Context->Rtl->CpuFeatures.Brand, \ + OUTPUT_STRING) \ + \ + ENTRY(CpuSocketCount, \ + Context->Rtl->CpuFeatures.ProcessorPackageCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuNumaNodeCount, \ + Context->Rtl->CpuFeatures.NumaNodeCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuProcessorCoreCount, \ + Context->Rtl->CpuFeatures.ProcessorCoreCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuLogicalProcessorCount, \ + Context->Rtl->CpuFeatures.LogicalProcessorCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1InstructionSize, \ + Context->Rtl->CpuFeatures.Caches.L1.Instruction.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1DataSize, \ + Context->Rtl->CpuFeatures.Caches.L1.Data.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1Total, \ + ((ULONGLONG)Context->Rtl->CpuFeatures.Caches.L1.Instruction.Size + \ + (ULONGLONG)Context->Rtl->CpuFeatures.Caches.L1.Data.Size), \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL2UnifiedSize, \ + Context->Rtl->CpuFeatures.Caches.L2.Unified.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL3UnifiedSize, \ + Context->Rtl->CpuFeatures.Caches.L3.Unified.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1TraceSize, \ + Context->Rtl->CpuFeatures.Caches.L1.Trace.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL2TraceSize, \ + Context->Rtl->CpuFeatures.Caches.L2.Trace.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL3TraceSize, \ + Context->Rtl->CpuFeatures.Caches.L3.Trace.Size, \ + OUTPUT_INT) \ + \ ENTRY(KeysName, \ &Keys->File->Path->BaseNameA, \ OUTPUT_STRING) \ diff --git a/src/PerfectHash/PerfectHash.natvis b/src/PerfectHash/PerfectHash.natvis index a6649e72..d4d4eb8c 100644 --- a/src/PerfectHash/PerfectHash.natvis +++ b/src/PerfectHash/PerfectHash.natvis @@ -190,4 +190,19 @@ + + + Count + Size In Bytes + + + + Count + ProcInfo + + + + + + diff --git a/src/PerfectHash/Rtl.c b/src/PerfectHash/Rtl.c index 8e03b498..da23c79e 100644 --- a/src/PerfectHash/Rtl.c +++ b/src/PerfectHash/Rtl.c @@ -234,12 +234,6 @@ RtlInitialize( goto Error; } - Result = RtlInitializeBitManipulationFunctionPointers(Rtl); - if (FAILED(Result)) { - PH_ERROR(RtlInitializeBitManipulationFunctionPointers, Result); - goto Error; - } - Result = RtlInitializeLargePages(Rtl); if (FAILED(Result)) { PH_ERROR(RtlInitializeLargePages, Result); @@ -285,6 +279,7 @@ RtlRundown( { ULONG Index; HMODULE *Module; + PVOID Buffer; if (!ARGUMENT_PRESENT(Rtl)) { return; @@ -297,6 +292,14 @@ RtlRundown( Rtl->CryptProv = 0; } + Buffer = Rtl->CpuFeatures.ProcInfoArray.ProcInfo; + if (Buffer != NULL) { + if (!VirtualFree(Buffer, 0, MEM_RELEASE)) { + SYS_ERROR(VirtualFree); + } + Rtl->CpuFeatures.ProcInfoArray.ProcInfo = NULL; + } + // // Free any loaded modules. // @@ -447,6 +450,165 @@ Return Value: #if defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) +HRESULT +RtlInitializeCpuFeaturesLogicalProcessors( + _In_ PRTL Rtl + ) +/*++ + +Routine Description: + + This routine initializes the logical processor information of the CPU + features structure in the provided Rtl instance. + +Arguments: + + Rtl - Supplies a pointer to an RTL instance. + +Return Value: + + S_OK - Success. + + PH_E_SYSTEM_CALL_FAILED - System call failed. + +--*/ +{ + SIZE_T Index; + BOOL Success; + HRESULT Result; + DWORD LastError; + PVOID ProcInfoBuffer; + DWORD ProcInfoLength; + ULONG ProcessorMaskBits; + PCPU_CACHES Caches; + PCPU_CACHE_LEVEL CacheLevel; + PCACHE_DESCRIPTOR Cache; + PCACHE_DESCRIPTOR CacheDesc; + PRTL_CPU_FEATURES Features; + PSYSTEM_LOGICAL_PROCESSOR_INFO_ARRAY ProcInfoArray; + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ProcInfo; + + Features = &Rtl->CpuFeatures; + + // + // Obtain the processor info. + // + + ProcInfoLength = 0; + Success = GetLogicalProcessorInformation(NULL, &ProcInfoLength); + if (Success) { + PH_RAISE(PH_E_INVARIANT_CHECK_FAILED); + } else { + LastError = GetLastError(); + if (LastError != ERROR_INSUFFICIENT_BUFFER) { + SYS_ERROR(GetLogicalProcessorInformation); + Result = PH_E_SYSTEM_CALL_FAILED; + goto End; + } + } + + ProcInfoBuffer = VirtualAlloc(NULL, + ProcInfoLength, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + + if (!ProcInfoBuffer) { + Result = E_OUTOFMEMORY; + goto End; + } + + Success = GetLogicalProcessorInformation(ProcInfoBuffer, &ProcInfoLength); + if (!Success) { + SYS_ERROR(GetLogicalProcessorInformation); + Result = PH_E_SYSTEM_CALL_FAILED; + goto End; + } + + ProcInfoArray = &Features->ProcInfoArray; + ProcInfoArray->Count = ProcInfoLength / sizeof(*ProcInfo); + ProcInfoArray->SizeInBytes = ProcInfoLength; + + ProcInfoArray->ProcInfo = ( + (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)ProcInfoBuffer + ); + + Caches = &Features->Caches; + + for (Index = 0; Index < ProcInfoArray->Count; Index++) { + + ProcInfo = &ProcInfoArray->ProcInfo[Index]; + + switch (ProcInfo->Relationship) { + case RelationNumaNode: + Features->NumaNodeCount++; + break; + + case RelationProcessorCore: + Features->ProcessorCoreCount++; + + ProcessorMaskBits = (ULONG)( + Rtl->PopulationCountPointer(ProcInfo->ProcessorMask) + ); + Features->LogicalProcessorCount += ProcessorMaskBits; + break; + + case RelationProcessorPackage: + Features->ProcessorPackageCount++; + break; + + case RelationCache: + CacheDesc = &ProcInfo->Cache; + + if (CacheDesc->Level > 4) { + break; + } + + Caches->NumberOfLevels = max(Caches->NumberOfLevels, + CacheDesc->Level); + + CacheLevel = &Caches->Level[CacheDesc->Level-1]; + Cache = &CacheLevel->AsArray[CacheDesc->Type]; + if (Cache->Level == 0) { + CopyMemoryInline(Cache, CacheDesc, sizeof(*Cache)); + } else { + Cache->Size += CacheDesc->Size; + } + break; + + case RelationAll: + break; + + case RelationGroup: + break; + + case RelationNumaNodeEx: + break; + + case RelationProcessorDie: + break; + + case RelationProcessorModule: + break; + + default: + break; + } + + } + + Features->Flags.HasProcessorInformation = TRUE; + Result = S_OK; + + // + // Intentional follow-on. + // + +End: + + return Result; +} + + _Use_decl_annotations_ HRESULT RtlInitializeCpuFeatures( @@ -467,6 +629,8 @@ Return Value: S_OK - Success. + PH_E_SYSTEM_CALL_FAILED - System call failed. + --*/ { HRESULT Result; @@ -602,7 +766,28 @@ Return Value: } - Result = S_OK; + // + // Initialize the bit manipulation features next, then the processor info + // (which needs PopulationCount). + // + + Result = RtlInitializeBitManipulationFunctionPointers(Rtl); + if (FAILED(Result)) { + PH_ERROR(RtlInitializeBitManipulationFunctionPointers, Result); + goto End; + } + + Result = RtlInitializeCpuFeaturesLogicalProcessors(Rtl); + if (FAILED(Result)) { + PH_ERROR(RtlInitializeCpuFeaturesLogicalProcessors, Result); + goto End; + } + + // + // Intentional follow-on. + // + +End: return Result; } diff --git a/src/PerfectHash/Rtl.h b/src/PerfectHash/Rtl.h index 76e8c713..52669214 100644 --- a/src/PerfectHash/Rtl.h +++ b/src/PerfectHash/Rtl.h @@ -928,6 +928,68 @@ typedef union _CPU_VENDOR { typedef CPU_VENDOR *PCPU_VENDOR; C_ASSERT(sizeof(CPU_VENDOR) == sizeof(ULONG)); +// +// Internal CPU feature flags (i.e. not related to the actual CPU, but to the +// structure itself, such as availability of certain data). +// + +typedef union _RTL_CPU_FEATURES_FLAGS { + struct _Struct_size_bytes_(sizeof(ULONG)) { + + // + // When set, indicates the ProcessorInfo structure has been successfully + // initialized and can be used. + // + + ULONG HasProcessorInformation:1; + + // + // Unused bits. + // + + ULONG Unused:31; + }; + + LONG AsLong; + ULONG AsULong; +} RTL_CPU_FEATURES_FLAGS, *PRTL_CPU_FEATURES_FLAGS; +C_ASSERT(sizeof(RTL_CPU_FEATURES_FLAGS) == sizeof(ULONG)); + +typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFO_ARRAY { + SIZE_T Count; + SIZE_T SizeInBytes; + + _Readable_elements_(Count) + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ProcInfo; +} SYSTEM_LOGICAL_PROCESSOR_INFO_ARRAY, *PSYSTEM_LOGICAL_PROCESSOR_INFO_ARRAY; + +typedef union _CPU_CACHE_LEVEL { + struct { + CACHE_DESCRIPTOR Unified; + CACHE_DESCRIPTOR Instruction; + CACHE_DESCRIPTOR Data; + CACHE_DESCRIPTOR Trace; + }; + + CACHE_DESCRIPTOR AsArray[4]; +} CPU_CACHE_LEVEL, *PCPU_CACHE_LEVEL; + +typedef struct _CPU_CACHES { + BYTE NumberOfLevels; + BYTE Padding[3]; + + union { + struct { + CPU_CACHE_LEVEL L1; + CPU_CACHE_LEVEL L2; + CPU_CACHE_LEVEL L3; + CPU_CACHE_LEVEL L4; + }; + + CPU_CACHE_LEVEL Level[4]; + }; +} CPU_CACHES, *PCPU_CACHES; + typedef struct _RTL_CPU_FEATURES { CPU_VENDOR Vendor; @@ -966,7 +1028,7 @@ typedef struct _RTL_CPU_FEATURES { ULONG RDTSCP:1; } Intel; - ULONG Padding; + RTL_CPU_FEATURES_FLAGS Flags; union { @@ -1042,8 +1104,27 @@ typedef struct _RTL_CPU_FEATURES { STRING Brand; CHAR BrandBuffer[48]; + // + // CPU Information. + // + + ULONG LogicalProcessorCount; + ULONG NumaNodeCount; + ULONG ProcessorCoreCount; + ULONG ProcessorL1CacheCount; + ULONG ProcessorL2CacheCount; + ULONG ProcessorL3CacheCount; + ULONG ProcessorPackageCount; + ULONG Padding2; + + CPU_CACHES Caches; + + ULONG Padding3; + SYSTEM_LOGICAL_PROCESSOR_INFO_ARRAY ProcInfoArray; + } RTL_CPU_FEATURES; typedef RTL_CPU_FEATURES *PRTL_CPU_FEATURES; + #endif // defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) //////////////////////////////////////////////////////////////////////////////// diff --git a/src/PerfectHash/TableCreateCsv.h b/src/PerfectHash/TableCreateCsv.h index f4eb81ad..44aecce4 100644 --- a/src/PerfectHash/TableCreateCsv.h +++ b/src/PerfectHash/TableCreateCsv.h @@ -34,6 +34,67 @@ Module Name: &Table->TimestampString, \ OUTPUT_STRING) \ \ + ENTRY(HeaderHash, \ + &Context->HexHeaderHash, \ + OUTPUT_STRING) \ + \ + ENTRY(ComputerName, \ + &Context->ComputerName, \ + OUTPUT_STRING) \ + \ + ENTRY(CpuBrand, \ + &Context->Rtl->CpuFeatures.Brand, \ + OUTPUT_STRING) \ + \ + ENTRY(CpuSocketCount, \ + Context->Rtl->CpuFeatures.ProcessorPackageCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuNumaNodeCount, \ + Context->Rtl->CpuFeatures.NumaNodeCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuProcessorCoreCount, \ + Context->Rtl->CpuFeatures.ProcessorCoreCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuLogicalProcessorCount, \ + Context->Rtl->CpuFeatures.LogicalProcessorCount, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1InstructionSize, \ + Context->Rtl->CpuFeatures.Caches.L1.Instruction.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1DataSize, \ + Context->Rtl->CpuFeatures.Caches.L1.Data.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1Total, \ + ((ULONGLONG)Context->Rtl->CpuFeatures.Caches.L1.Instruction.Size + \ + (ULONGLONG)Context->Rtl->CpuFeatures.Caches.L1.Data.Size), \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL2UnifiedSize, \ + Context->Rtl->CpuFeatures.Caches.L2.Unified.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL3UnifiedSize, \ + Context->Rtl->CpuFeatures.Caches.L3.Unified.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL1TraceSize, \ + Context->Rtl->CpuFeatures.Caches.L1.Trace.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL2TraceSize, \ + Context->Rtl->CpuFeatures.Caches.L2.Trace.Size, \ + OUTPUT_INT) \ + \ + ENTRY(CpuCacheL3TraceSize, \ + Context->Rtl->CpuFeatures.Caches.L3.Trace.Size, \ + OUTPUT_INT) \ + \ ENTRY(KeysName, \ &Keys->File->Path->BaseNameA, \ OUTPUT_STRING) \