zoukankan      html  css  js  c++  java
  • 使用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


    三、全部代码

      全部代码——

    #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

  • 相关阅读:
    Java异步消息平台
    spring mvc绑定对象String转Date解决入参不能是Date的问题
    <welcome-file-list>标签的控制作用以及在springmvc中此标签的的配置方式
    第一篇
    Struts2学习笔记《二》
    java的事务处理
    Java Statement和PreparedStatement性能测试(转)
    JAVA上百实例源码网站
    Java程序优化的一些最佳实践(转)
    Struts2学习笔记《一》
  • 原文地址:https://www.cnblogs.com/zyl910/p/showGetLogicalProcessorInformation.html
Copyright © 2011-2022 走看看