现在多核处理器已经很普及了,市场主流是双核处理器,还有4核、8核等高端产品。而且Intel推广了超线程技术(Hyper-Threading Technology, HTT),可以将一个物理核心模拟为两个逻辑处理器。这一切使得“CPU数量”这一概念变得复杂起来,对于软件开发人员来说,希望能获得物理CPU数、CPU核心数、逻辑CPU数等详细信息。
在Windows平台,可以调用GetLogicalProcessorInformation函数来获取它们的详细信息。
一、背景知识
先来明确一下名词——
physical processor packages:物理处理器封装个数,即俗称的“物理CPU数”。例如一块“Intel Core i3-2310M”只有1个“物理处理器封装个数”。若对于有多个处理器插槽的服务器,“物理处理器封装个数”很可能会大于1。
processor cores:处理器核心数,即俗称的“CPU核心数”。例如“Intel Core i3-2310M”是双核处理器,它有2个“处理器核心数”。
logical processors:逻辑处理器数,即俗称的“逻辑CPU数”。例如“Intel Core i3-2310M”支持超线程,一个物理核心能模拟为两个逻辑处理器,即一块“Intel Core i3-2310M”有4个“逻辑处理器数”。
再来看看2个大家可能不太熟悉的名词——
SMP:Symmetrical Multi-Processing,对称多处理机。
NUMA:Non Uniform Memory Access,非均匀访存模型。http://msdn.microsoft.com/en-us/library/aa363804(v=vs.85).aspx
这个两个名词牵涉到很多专业知识,这里不做详细介绍,感兴趣的同学可以自行翻阅相关资料。
老版本的Windows系统(例如Windows XP)采用的是SMP模型。但后来因多核处理器及异构计算的发展,从Windows Server 2003开始使用NUMA模型,系统中支持多个NUMA节点。对于开发人员来说,当只有1个NUMA节点时,与SMP模型是差不多的。
对于 Windows XP,在打上SP3补丁后,也可以利用GetLogicalProcessorInformation函数获得NUMA等信息。
二、GetLogicalProcessorInformation函数的使用心得
在MSDN上我们可以查到GetLogicalProcessorInformation函数的帮助——
http://msdn.microsoft.com/en-us/library/ms683194(v=vs.85).aspx
GetLogicalProcessorInformation function
GetLogicalProcessorInformation函数还牵涉到一些结构体和枚举——
http://msdn.microsoft.com/en-us/library/ms686694(v=vs.85).aspx
SYSTEM_LOGICAL_PROCESSOR_INFORMATION structure
http://msdn.microsoft.com/en-us/library/ms684197(v=vs.85).aspx
LOGICAL_PROCESSOR_RELATIONSHIP enumeration
http://msdn.microsoft.com/en-us/library/ms681979(v=vs.85).aspx
CACHE_DESCRIPTOR structure
http://msdn.microsoft.com/en-us/library/ms684844(v=vs.85).aspx
PROCESSOR_CACHE_TYPE enumeration
GetLogicalProcessorInformation函数用起来是有一定复杂性的。因为它返回的是SYSTEM_LOGICAL_PROCESSOR_INFORMATION数组,数组中的每一项分别描述了不同的信息,学习曲线较陡峭。
虽然MSDN上有该函数的范例代码,但是它屏蔽了很多细节,对我们的帮助有限。于是我将该范例程序作了改进,显示了SYSTEM_LOGICAL_PROCESSOR_INFORMATION数组中每一项的详细信息。
心得——
1.SYSTEM_LOGICAL_PROCESSOR_INFORMATION结构ProcessorMask是ULONG_PTR类型的。在32位系统上是32位,64位系统上是64位。为了简化代码,建议强制转型为UINT64类型,调用printf等输出函数时使用“I64”格式码。
2.ProcessorMask是处理器掩码,每一位代表一个逻辑处理器。所以一般来说,32位系统最多支持32个逻辑处理器,64位系统最多支持64个逻辑处理器。
3.对于Windows 7和Windows Server 2008 R2来说,能突破64个逻辑处理器限制,最高支持256个逻辑处理器。新加了 处理器组(Processor Groups)概念,详见:http://msdn.microsoft.com/en-us/library/dd405503(v=vs.85).aspx。
三、全部代码
全部代码——
#include <windows.h> #include <malloc.h> #include <stdio.h> #include <tchar.h> #if (_WIN32_WINNT < 0x0600) // [zyl910] 低版本的Windows SDK没有定义 RelationProcessorPackage 等常量 #define RelationProcessorPackage 3 #define RelationGroup 4 #endif // [zyl910] LOGICAL_PROCESSOR_RELATIONSHIP枚举的名称 const LPTSTR Names_LOGICAL_PROCESSOR_RELATIONSHIP[] = { _T("RelationProcessorCore") ,_T("RelationNumaNode") ,_T("RelationCache") ,_T("RelationProcessorPackage") ,_T("RelationGroup") }; // [zyl910] PROCESSOR_CACHE_TYPE枚举的名称 const LPTSTR Names_PROCESSOR_CACHE_TYPE[] = { _T("CacheUnified") ,_T("CacheInstruction") ,_T("CacheData") ,_T("CacheTrace") }; typedef BOOL (WINAPI *LPFN_GLPI)( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); // Helper function to count set bits in the processor mask. DWORD CountSetBits(ULONG_PTR bitMask) { DWORD LSHIFT = sizeof(ULONG_PTR)*8 - 1; DWORD bitSetCount = 0; ULONG_PTR bitTest = (ULONG_PTR)1 << LSHIFT; DWORD i; for (i = 0; i <= LSHIFT; ++i) { bitSetCount += ((bitMask & bitTest)?1:0); bitTest/=2; } return bitSetCount; } int _cdecl _tmain () { LPFN_GLPI glpi; BOOL done = FALSE; PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL; PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL; DWORD returnLength = 0; DWORD logicalProcessorCount = 0; DWORD numaNodeCount = 0; DWORD processorCoreCount = 0; DWORD processorL1CacheCount = 0; DWORD processorL2CacheCount = 0; DWORD processorL3CacheCount = 0; DWORD processorPackageCount = 0; DWORD byteOffset = 0; PCACHE_DESCRIPTOR Cache; glpi = (LPFN_GLPI) GetProcAddress( GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation"); if (NULL == glpi) { _tprintf(TEXT("\nGetLogicalProcessorInformation is not supported.\n")); return (1); } while (!done) { DWORD rc = glpi(buffer, &returnLength); if (FALSE == rc) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { if (buffer) free(buffer); buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc( returnLength); if (NULL == buffer) { _tprintf(TEXT("\nError: Allocation failure\n")); return (2); } } else { _tprintf(TEXT("\nError %d\n"), GetLastError()); return (3); } } else { done = TRUE; } } ptr = buffer; if (true) // [zyl910] 显示SYSTEM_LOGICAL_PROCESSOR_INFORMATION结构体的详细信息 { DWORD cnt = returnLength / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); // 计算SYSTEM_LOGICAL_PROCESSOR_INFORMATION结构体的数目 for(DWORD i=0; i<cnt; ++i) { _tprintf(TEXT("SYSTEM_LOGICAL_PROCESSOR_INFORMATION[%d]\n"), i); _tprintf(TEXT("\t.ProcessorMask:\t0x%.16I64X\t//%I64d\n"), (UINT64)ptr[i].ProcessorMask, (UINT64)ptr[i].ProcessorMask); _tprintf(TEXT("\t.Relationship:\t%d\t//%s\n"), ptr[i].Relationship, Names_LOGICAL_PROCESSOR_RELATIONSHIP[max(0,min(ptr[i].Relationship, RelationGroup))]); for(int j=0; j<2; ++j) _tprintf(TEXT("\t.Reserved[%d]:\t//0x%.16I64X\t%I64d\n"), j, (UINT64)ptr[i].Reserved[j], (UINT64)ptr[i].Reserved[j]); if (RelationCache==ptr[i].Relationship) { _tprintf(TEXT("\t.Cache.Level:\t%u\n"), ptr[i].Cache.Level); _tprintf(TEXT("\t.Cache.Associativity:\t0x%.2X\t//%u\n"), ptr[i].Cache.Associativity, ptr[i].Cache.Associativity); _tprintf(TEXT("\t.Cache.LineSize:\t0x%.4X\t//%u\n"), ptr[i].Cache.LineSize, ptr[i].Cache.LineSize); _tprintf(TEXT("\t.Cache.Size:\t0x%.8X\t//%u\n"), ptr[i].Cache.Size, ptr[i].Cache.Size); _tprintf(TEXT("\t.Cache.Type:\t%d\t//%s\n"), ptr[i].Cache.Type, Names_PROCESSOR_CACHE_TYPE[max(0,min(ptr[i].Cache.Type, CacheTrace))]); } } } while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) { switch (ptr->Relationship) { case RelationNumaNode: // Non-NUMA systems report a single record of this type. numaNodeCount++; break; case RelationProcessorCore: processorCoreCount++; // A hyperthreaded core supplies more than one logical processor. logicalProcessorCount += CountSetBits(ptr->ProcessorMask); break; case RelationCache: // Cache data is in ptr->Cache, one CACHE_DESCRIPTOR structure for each cache. Cache = &ptr->Cache; if (Cache->Level == 1) { processorL1CacheCount++; } else if (Cache->Level == 2) { processorL2CacheCount++; } else if (Cache->Level == 3) { processorL3CacheCount++; } break; case RelationProcessorPackage: // Logical processors share a physical package. processorPackageCount++; break; default: _tprintf(TEXT("\nError: Unsupported LOGICAL_PROCESSOR_RELATIONSHIP value.\n")); break; } byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ptr++; } _tprintf(TEXT("\nGetLogicalProcessorInformation results:\n")); _tprintf(TEXT("Number of NUMA nodes: %d\n"), numaNodeCount); _tprintf(TEXT("Number of physical processor packages: %d\n"), processorPackageCount); _tprintf(TEXT("Number of processor cores: %d\n"), processorCoreCount); _tprintf(TEXT("Number of logical processors: %d\n"), logicalProcessorCount); _tprintf(TEXT("Number of processor L1/L2/L3 caches: %d/%d/%d\n"), processorL1CacheCount, processorL2CacheCount, processorL3CacheCount); free(buffer); return 0; }
四、输出信息
例如我的处理器是“Intel Core i3-2310M”,该程序的输出信息为——
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[0] .ProcessorMask: 0x0000000000000005 //5 .Relationship: 0 //RelationProcessorCore .Reserved[0]: //0x0000000000000001 1 .Reserved[1]: //0x0000000000000000 0 SYSTEM_LOGICAL_PROCESSOR_INFORMATION[1] .ProcessorMask: 0x0000000000000005 //5 .Relationship: 2 //RelationCache .Reserved[0]: //0x0000800000400801 140737492551681 .Reserved[1]: //0x0000000000000002 2 .Cache.Level: 1 .Cache.Associativity: 0x08 //8 .Cache.LineSize: 0x0040 //64 .Cache.Size: 0x00008000 //32768 .Cache.Type: 2 //CacheData SYSTEM_LOGICAL_PROCESSOR_INFORMATION[2] .ProcessorMask: 0x0000000000000005 //5 .Relationship: 2 //RelationCache .Reserved[0]: //0x0000800000400801 140737492551681 .Reserved[1]: //0x0000000000000001 1 .Cache.Level: 1 .Cache.Associativity: 0x08 //8 .Cache.LineSize: 0x0040 //64 .Cache.Size: 0x00008000 //32768 .Cache.Type: 1 //CacheInstruction SYSTEM_LOGICAL_PROCESSOR_INFORMATION[3] .ProcessorMask: 0x0000000000000005 //5 .Relationship: 2 //RelationCache .Reserved[0]: //0x0004000000400802 1125899911038978 .Reserved[1]: //0x0000000000000000 0 .Cache.Level: 2 .Cache.Associativity: 0x08 //8 .Cache.LineSize: 0x0040 //64 .Cache.Size: 0x00040000 //262144 .Cache.Type: 0 //CacheUnified SYSTEM_LOGICAL_PROCESSOR_INFORMATION[4] .ProcessorMask: 0x000000000000000F //15 .Relationship: 3 //RelationProcessorPackage .Reserved[0]: //0x0000000000000000 0 .Reserved[1]: //0x0000000000000000 0 SYSTEM_LOGICAL_PROCESSOR_INFORMATION[5] .ProcessorMask: 0x000000000000000A //10 .Relationship: 0 //RelationProcessorCore .Reserved[0]: //0x0000000000000001 1 .Reserved[1]: //0x0000000000000000 0 SYSTEM_LOGICAL_PROCESSOR_INFORMATION[6] .ProcessorMask: 0x000000000000000A //10 .Relationship: 2 //RelationCache .Reserved[0]: //0x0000800000400801 140737492551681 .Reserved[1]: //0x0000000000000002 2 .Cache.Level: 1 .Cache.Associativity: 0x08 //8 .Cache.LineSize: 0x0040 //64 .Cache.Size: 0x00008000 //32768 .Cache.Type: 2 //CacheData SYSTEM_LOGICAL_PROCESSOR_INFORMATION[7] .ProcessorMask: 0x000000000000000A //10 .Relationship: 2 //RelationCache .Reserved[0]: //0x0000800000400801 140737492551681 .Reserved[1]: //0x0000000000000001 1 .Cache.Level: 1 .Cache.Associativity: 0x08 //8 .Cache.LineSize: 0x0040 //64 .Cache.Size: 0x00008000 //32768 .Cache.Type: 1 //CacheInstruction SYSTEM_LOGICAL_PROCESSOR_INFORMATION[8] .ProcessorMask: 0x000000000000000A //10 .Relationship: 2 //RelationCache .Reserved[0]: //0x0004000000400802 1125899911038978 .Reserved[1]: //0x0000000000000000 0 .Cache.Level: 2 .Cache.Associativity: 0x08 //8 .Cache.LineSize: 0x0040 //64 .Cache.Size: 0x00040000 //262144 .Cache.Type: 0 //CacheUnified SYSTEM_LOGICAL_PROCESSOR_INFORMATION[9] .ProcessorMask: 0x000000000000000F //15 .Relationship: 2 //RelationCache .Reserved[0]: //0x0030000000400C03 13510798886308867 .Reserved[1]: //0x0000000000000000 0 .Cache.Level: 3 .Cache.Associativity: 0x0C //12 .Cache.LineSize: 0x0040 //64 .Cache.Size: 0x00300000 //3145728 .Cache.Type: 0 //CacheUnified SYSTEM_LOGICAL_PROCESSOR_INFORMATION[10] .ProcessorMask: 0x000000000000000F //15 .Relationship: 1 //RelationNumaNode .Reserved[0]: //0x0000000000000000 0 .Reserved[1]: //0x0000000000000000 0 GetLogicalProcessorInformation results: Number of NUMA nodes: 1 Number of physical processor packages: 1 Number of processor cores: 2 Number of logical processors: 4 Number of processor L1/L2/L3 caches: 4/2/1
源码下载——
https://files.cnblogs.com/zyl910/showGetLogicalProcessorInformation.rar