使用GetLogicalProcessorInformation获取逻辑处理器的详细信息(NUMA节点数、物理CPU数、CPU核心数、逻辑CPU数、各级Cache)

现在多核处理器已经很普及了,市场主流是双核处理器,还有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


三、全部代码

  全部代码——

  1. #include <windows.h>  
  2. #include <malloc.h>      
  3. #include <stdio.h>  
  4. #include <tchar.h>  
  5.   
  6. #if (_WIN32_WINNT < 0x0600)  // [zyl910] 低版本的Windows SDK没有定义 RelationProcessorPackage 等常量  
  7. #define RelationProcessorPackage    3  
  8. #define RelationGroup   4  
  9. #endif  
  10. // [zyl910] LOGICAL_PROCESSOR_RELATIONSHIP枚举的名称  
  11. const LPTSTR Names_LOGICAL_PROCESSOR_RELATIONSHIP[] = {  
  12.     _T("RelationProcessorCore")  
  13.     ,_T("RelationNumaNode")  
  14.     ,_T("RelationCache")  
  15.     ,_T("RelationProcessorPackage")  
  16.     ,_T("RelationGroup")  
  17. };  
  18. // [zyl910] PROCESSOR_CACHE_TYPE枚举的名称  
  19. const LPTSTR Names_PROCESSOR_CACHE_TYPE[] = {  
  20.     _T("CacheUnified")  
  21.     ,_T("CacheInstruction")  
  22.     ,_T("CacheData")  
  23.     ,_T("CacheTrace")  
  24. };  
  25.   
  26. typedef BOOL (WINAPI *LPFN_GLPI)(  
  27.     PSYSTEM_LOGICAL_PROCESSOR_INFORMATION,   
  28.     PDWORD);  
  29.   
  30.   
  31. // Helper function to count set bits in the processor mask.  
  32. DWORD CountSetBits(ULONG_PTR bitMask)  
  33. {  
  34.     DWORD LSHIFT = sizeof(ULONG_PTR)*8 - 1;  
  35.     DWORD bitSetCount = 0;  
  36.     ULONG_PTR bitTest = (ULONG_PTR)1 << LSHIFT;      
  37.     DWORD i;  
  38.       
  39.     for (i = 0; i <= LSHIFT; ++i)  
  40.     {  
  41.         bitSetCount += ((bitMask & bitTest)?1:0);  
  42.         bitTest/=2;  
  43.     }  
  44.   
  45.     return bitSetCount;  
  46. }  
  47.   
  48. int _cdecl _tmain ()  
  49. {  
  50.     LPFN_GLPI glpi;  
  51.     BOOL done = FALSE;  
  52.     PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;  
  53.     PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL;  
  54.     DWORD returnLength = 0;  
  55.     DWORD logicalProcessorCount = 0;  
  56.     DWORD numaNodeCount = 0;  
  57.     DWORD processorCoreCount = 0;  
  58.     DWORD processorL1CacheCount = 0;  
  59.     DWORD processorL2CacheCount = 0;  
  60.     DWORD processorL3CacheCount = 0;  
  61.     DWORD processorPackageCount = 0;  
  62.     DWORD byteOffset = 0;  
  63.     PCACHE_DESCRIPTOR Cache;  
  64.   
  65.     glpi = (LPFN_GLPI) GetProcAddress(  
  66.                             GetModuleHandle(TEXT("kernel32")),  
  67.                             "GetLogicalProcessorInformation");  
  68.     if (NULL == glpi)   
  69.     {  
  70.         _tprintf(TEXT("\nGetLogicalProcessorInformation is not supported.\n"));  
  71.         return (1);  
  72.     }  
  73.   
  74.     while (!done)  
  75.     {  
  76.         DWORD rc = glpi(buffer, &returnLength);  
  77.   
  78.         if (FALSE == rc)   
  79.         {  
  80.             if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)   
  81.             {  
  82.                 if (buffer)   
  83.                     free(buffer);  
  84.   
  85.                 buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(  
  86.                         returnLength);  
  87.   
  88.                 if (NULL == buffer)   
  89.                 {  
  90.                     _tprintf(TEXT("\nError: Allocation failure\n"));  
  91.                     return (2);  
  92.                 }  
  93.             }   
  94.             else   
  95.             {  
  96.                 _tprintf(TEXT("\nError %d\n"), GetLastError());  
  97.                 return (3);  
  98.             }  
  99.         }   
  100.         else  
  101.         {  
  102.             done = TRUE;  
  103.         }  
  104.     }  
  105.   
  106.     ptr = buffer;  
  107.   
  108.     if (true)   // [zyl910] 显示SYSTEM_LOGICAL_PROCESSOR_INFORMATION结构体的详细信息  
  109.     {  
  110.         DWORD cnt = returnLength / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);    // 计算SYSTEM_LOGICAL_PROCESSOR_INFORMATION结构体的数目  
  111.         for(DWORD i=0; i<cnt; ++i)  
  112.         {  
  113.             _tprintf(TEXT("SYSTEM_LOGICAL_PROCESSOR_INFORMATION[%d]\n"), i);  
  114.             _tprintf(TEXT("\t.ProcessorMask:\t0x%.16I64X\t//%I64d\n"), (UINT64)ptr[i].ProcessorMask, (UINT64)ptr[i].ProcessorMask);  
  115.             _tprintf(TEXT("\t.Relationship:\t%d\t//%s\n"), ptr[i].Relationship, Names_LOGICAL_PROCESSOR_RELATIONSHIP[max(0,min(ptr[i].Relationship, RelationGroup))]);  
  116.             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]);  
  117.             if (RelationCache==ptr[i].Relationship)  
  118.             {  
  119.                 _tprintf(TEXT("\t.Cache.Level:\t%u\n"), ptr[i].Cache.Level);  
  120.                 _tprintf(TEXT("\t.Cache.Associativity:\t0x%.2X\t//%u\n"), ptr[i].Cache.Associativity, ptr[i].Cache.Associativity);  
  121.                 _tprintf(TEXT("\t.Cache.LineSize:\t0x%.4X\t//%u\n"), ptr[i].Cache.LineSize, ptr[i].Cache.LineSize);  
  122.                 _tprintf(TEXT("\t.Cache.Size:\t0x%.8X\t//%u\n"), ptr[i].Cache.Size, ptr[i].Cache.Size);  
  123.                 _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))]);  
  124.             }  
  125.         }  
  126.     }  
  127.   
  128.     while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength)   
  129.     {  
  130.         switch (ptr->Relationship)   
  131.         {  
  132.         case RelationNumaNode:  
  133.             // Non-NUMA systems report a single record of this type.  
  134.             numaNodeCount++;  
  135.             break;  
  136.   
  137.         case RelationProcessorCore:  
  138.             processorCoreCount++;  
  139.   
  140.             // A hyperthreaded core supplies more than one logical processor.  
  141.             logicalProcessorCount += CountSetBits(ptr->ProcessorMask);  
  142.             break;  
  143.   
  144.         case RelationCache:  
  145.             // Cache data is in ptr->Cache, one CACHE_DESCRIPTOR structure for each cache.   
  146.             Cache = &ptr->Cache;  
  147.             if (Cache->Level == 1)  
  148.             {  
  149.                 processorL1CacheCount++;  
  150.             }  
  151.             else if (Cache->Level == 2)  
  152.             {  
  153.                 processorL2CacheCount++;  
  154.             }  
  155.             else if (Cache->Level == 3)  
  156.             {  
  157.                 processorL3CacheCount++;  
  158.             }  
  159.             break;  
  160.   
  161.         case RelationProcessorPackage:  
  162.             // Logical processors share a physical package.  
  163.             processorPackageCount++;  
  164.             break;  
  165.   
  166.         default:  
  167.             _tprintf(TEXT("\nError: Unsupported LOGICAL_PROCESSOR_RELATIONSHIP value.\n"));  
  168.             break;  
  169.         }  
  170.         byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);  
  171.         ptr++;  
  172.     }  
  173.   
  174.     _tprintf(TEXT("\nGetLogicalProcessorInformation results:\n"));  
  175.     _tprintf(TEXT("Number of NUMA nodes: %d\n"),   
  176.              numaNodeCount);  
  177.     _tprintf(TEXT("Number of physical processor packages: %d\n"),   
  178.              processorPackageCount);  
  179.     _tprintf(TEXT("Number of processor cores: %d\n"),   
  180.              processorCoreCount);  
  181.     _tprintf(TEXT("Number of logical processors: %d\n"),   
  182.              logicalProcessorCount);  
  183.     _tprintf(TEXT("Number of processor L1/L2/L3 caches: %d/%d/%d\n"),   
  184.              processorL1CacheCount,  
  185.              processorL2CacheCount,  
  186.              processorL3CacheCount);  
  187.       
  188.     free(buffer);  
  189.   
  190.     return 0;  
  191. }  


 

四、输出信息


  例如我的处理器是“Intel Core i3-2310M”,该程序的输出信息为——

[plain] view plaincopy
  1. SYSTEM_LOGICAL_PROCESSOR_INFORMATION[0]  
  2.     .ProcessorMask: 0x0000000000000005  //5  
  3.     .Relationship:  0   //RelationProcessorCore  
  4.     .Reserved[0]:   //0x0000000000000001    1  
  5.     .Reserved[1]:   //0x0000000000000000    0  
  6. SYSTEM_LOGICAL_PROCESSOR_INFORMATION[1]  
  7.     .ProcessorMask: 0x0000000000000005  //5  
  8.     .Relationship:  2   //RelationCache  
  9.     .Reserved[0]:   //0x0000800000400801    140737492551681  
  10.     .Reserved[1]:   //0x0000000000000002    2  
  11.     .Cache.Level:   1  
  12.     .Cache.Associativity:   0x08    //8  
  13.     .Cache.LineSize:    0x0040  //64  
  14.     .Cache.Size:    0x00008000  //32768  
  15.     .Cache.Type:    2   //CacheData  
  16. SYSTEM_LOGICAL_PROCESSOR_INFORMATION[2]  
  17.     .ProcessorMask: 0x0000000000000005  //5  
  18.     .Relationship:  2   //RelationCache  
  19.     .Reserved[0]:   //0x0000800000400801    140737492551681  
  20.     .Reserved[1]:   //0x0000000000000001    1  
  21.     .Cache.Level:   1  
  22.     .Cache.Associativity:   0x08    //8  
  23.     .Cache.LineSize:    0x0040  //64  
  24.     .Cache.Size:    0x00008000  //32768  
  25.     .Cache.Type:    1   //CacheInstruction  
  26. SYSTEM_LOGICAL_PROCESSOR_INFORMATION[3]  
  27.     .ProcessorMask: 0x0000000000000005  //5  
  28.     .Relationship:  2   //RelationCache  
  29.     .Reserved[0]:   //0x0004000000400802    1125899911038978  
  30.     .Reserved[1]:   //0x0000000000000000    0  
  31.     .Cache.Level:   2  
  32.     .Cache.Associativity:   0x08    //8  
  33.     .Cache.LineSize:    0x0040  //64  
  34.     .Cache.Size:    0x00040000  //262144  
  35.     .Cache.Type:    0   //CacheUnified  
  36. SYSTEM_LOGICAL_PROCESSOR_INFORMATION[4]  
  37.     .ProcessorMask: 0x000000000000000F  //15  
  38.     .Relationship:  3   //RelationProcessorPackage  
  39.     .Reserved[0]:   //0x0000000000000000    0  
  40.     .Reserved[1]:   //0x0000000000000000    0  
  41. SYSTEM_LOGICAL_PROCESSOR_INFORMATION[5]  
  42.     .ProcessorMask: 0x000000000000000A  //10  
  43.     .Relationship:  0   //RelationProcessorCore  
  44.     .Reserved[0]:   //0x0000000000000001    1  
  45.     .Reserved[1]:   //0x0000000000000000    0  
  46. SYSTEM_LOGICAL_PROCESSOR_INFORMATION[6]  
  47.     .ProcessorMask: 0x000000000000000A  //10  
  48.     .Relationship:  2   //RelationCache  
  49.     .Reserved[0]:   //0x0000800000400801    140737492551681  
  50.     .Reserved[1]:   //0x0000000000000002    2  
  51.     .Cache.Level:   1  
  52.     .Cache.Associativity:   0x08    //8  
  53.     .Cache.LineSize:    0x0040  //64  
  54.     .Cache.Size:    0x00008000  //32768  
  55.     .Cache.Type:    2   //CacheData  
  56. SYSTEM_LOGICAL_PROCESSOR_INFORMATION[7]  
  57.     .ProcessorMask: 0x000000000000000A  //10  
  58.     .Relationship:  2   //RelationCache  
  59.     .Reserved[0]:   //0x0000800000400801    140737492551681  
  60.     .Reserved[1]:   //0x0000000000000001    1  
  61.     .Cache.Level:   1  
  62.     .Cache.Associativity:   0x08    //8  
  63.     .Cache.LineSize:    0x0040  //64  
  64.     .Cache.Size:    0x00008000  //32768  
  65.     .Cache.Type:    1   //CacheInstruction  
  66. SYSTEM_LOGICAL_PROCESSOR_INFORMATION[8]  
  67.     .ProcessorMask: 0x000000000000000A  //10  
  68.     .Relationship:  2   //RelationCache  
  69.     .Reserved[0]:   //0x0004000000400802    1125899911038978  
  70.     .Reserved[1]:   //0x0000000000000000    0  
  71.     .Cache.Level:   2  
  72.     .Cache.Associativity:   0x08    //8  
  73.     .Cache.LineSize:    0x0040  //64  
  74.     .Cache.Size:    0x00040000  //262144  
  75.     .Cache.Type:    0   //CacheUnified  
  76. SYSTEM_LOGICAL_PROCESSOR_INFORMATION[9]  
  77.     .ProcessorMask: 0x000000000000000F  //15  
  78.     .Relationship:  2   //RelationCache  
  79.     .Reserved[0]:   //0x0030000000400C03    13510798886308867  
  80.     .Reserved[1]:   //0x0000000000000000    0  
  81.     .Cache.Level:   3  
  82.     .Cache.Associativity:   0x0C    //12  
  83.     .Cache.LineSize:    0x0040  //64  
  84.     .Cache.Size:    0x00300000  //3145728  
  85.     .Cache.Type:    0   //CacheUnified  
  86. SYSTEM_LOGICAL_PROCESSOR_INFORMATION[10]  
  87.     .ProcessorMask: 0x000000000000000F  //15  
  88.     .Relationship:  1   //RelationNumaNode  
  89.     .Reserved[0]:   //0x0000000000000000    0  
  90.     .Reserved[1]:   //0x0000000000000000    0  
  91.   
  92. GetLogicalProcessorInformation results:  
  93. Number of NUMA nodes: 1  
  94. Number of physical processor packages: 1  
  95. Number of processor cores: 2  
  96. Number of logical processors: 4  
  97. Number of processor L1/L2/L3 caches: 4/2/1  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值