c++ - 获取共享缓存的逻辑 CPU 内核数(L1、L2、L3)

标签 c++ windows visual-c++

下面是一些 C++ 代码,使用 GetLogicalProcessorInformation 检测 Windows 上 L1、L2 和 L3 CPU 缓存的大小。 :

typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);

LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(
    GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");

if (glpi)
{
    DWORD bytes = 0;
    glpi(0, &bytes);
    size_t size = bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
    vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> info(size);
    glpi(info.data(), &bytes);

    for (size_t i = 0; i < size; i++)
    {
        if (info[i].Relationship == RelationCache)
        {
            if (info[i].Cache.Level == 1)
              l1_cache_Size = info[i].Cache.Size;
            if (info[i].Cache.Level == 2)
              l2_cache_Size = info[i].Cache.Size;
            if (info[i].Cache.Level == 3)
              l3_cache_Size = info[i].Cache.Size;
        }
    }
}

作为下一步,我想获得共享高速缓存的逻辑 CPU 内核的数量。在具有超线程的 x64 CPU 上,两个逻辑 CPU 内核通常共享一个 L2 缓存,所有逻辑 CPU 内核共享 L3 缓存。

阅读 MSDN 后,我认为 GetLogicalProcessorInformationExCACHE_RELATIONSHIPGROUP_AFFINITY我正在寻找的数据结构在哪里,但在尝试之后,这些数据结构似乎对我的目的毫无用处。

问题:

有没有办法使用 C/C++ 在 Windows 上获取共享缓存的逻辑 CPU 核心数? (最好不要直接使用 cpuid)


解决方案:

可以使用 GetLogicalProcessorInformationExCACHE_RELATIONSHIP 获取共享缓存的逻辑 CPU 内核数。和 GROUP_AFFINITY数据结构。 GROUP_AFFINITY.Mask 值包含为共享当前缓存 (RelationCache) 的每个 CPU 内核设置的一位。例如,对于具有超线程的大多数 Intel CPU,GROUP_AFFINITY.Mask 将包含为 L2 缓存设置的 2 位和为具有 4 个物理 CPU 内核和 8 个逻辑 CPU 的 CPU 设置的 8 位 L3 缓存核心。

C++代码如下:

#include <windows.h>
#include <vector>
#include <iostream>

using namespace std;

typedef BOOL (WINAPI *LPFN_GLPI)(LOGICAL_PROCESSOR_RELATIONSHIP,
    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD);

int main()
{
    LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(
        GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformationEx");

    if (!glpi)
        return 1;

    DWORD bytes = 0;
    glpi(RelationAll, 0, &bytes);
    vector<char> buffer(bytes);
    SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* info;

    if (!glpi(RelationAll, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) &buffer[0], &bytes))
        return 1;

    for (size_t i = 0; i < bytes; i += info->Size)
    {
        info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) &buffer[i];

        if (info->Relationship == RelationCache &&
            (info->Cache.Type == CacheData ||
             info->Cache.Type == CacheUnified))
        {
            cout << "info->Cache.Level: " << (int) info->Cache.Level << endl;
            cout << "info->Cache.CacheSize: " << (int) info->Cache.CacheSize << endl;
            cout << "info->Cache.GroupMask.Group: " << info->Cache.GroupMask.Group << endl;
            cout << "info->Cache.GroupMask.Mask: " << info->Cache.GroupMask.Mask << endl << endl;
        }
    }

    return 0;
}

注意事项:

我发现当在虚拟机中运行 Windows 时,上面的代码无法正确检测共享缓存的 CPU 内核数量,例如在具有 2 个虚拟 CPU 核心的 VM 上,上面的代码报告每个逻辑 CPU 核心都有一个私有(private)的 L1、L2 和 L3 缓存。

最佳答案

@RbMm: but CACHE_RELATIONSHIP contains all info needed. number of logical CPU cores = number of bits set in Cache->GroupMask.Mask

我已经在 AppVeyor CI 上对此进行了测试(甚至在发布到 stackoverflow 之前)。这是 x64 CPU 的输出:

info->Cache.Level: 1
info->Cache.CacheSize: 32768
info->Cache.GroupMask.Group: 0
info->Cache.GroupMask.Mask: 1

info->Cache.Level: 1
info->Cache.CacheSize: 32768
info->Cache.GroupMask.Group: 0
info->Cache.GroupMask.Mask: 1

info->Cache.Level: 2
info->Cache.CacheSize: 262144
info->Cache.GroupMask.Group: 0
info->Cache.GroupMask.Mask: 1

info->Cache.Level: 3
info->Cache.CacheSize: 31457280
info->Cache.GroupMask.Group: 0
info->Cache.GroupMask.Mask: 1

info->Cache.Level: 1
info->Cache.CacheSize: 32768
info->Cache.GroupMask.Group: 0
info->Cache.GroupMask.Mask: 2

info->Cache.Level: 1
info->Cache.CacheSize: 32768
info->Cache.GroupMask.Group: 0
info->Cache.GroupMask.Mask: 2

info->Cache.Level: 2
info->Cache.CacheSize: 262144
info->Cache.GroupMask.Group: 0
info->Cache.GroupMask.Mask: 2

info->Cache.Level: 3
info->Cache.CacheSize: 31457280
info->Cache.GroupMask.Group: 0
info->Cache.GroupMask.Mask: 2

或者:

| Cache Level |    Processor 1     |    Processor 2     |
|-------------|--------------------|--------------------|
| L1          |  32 KB Data        |  32 KB Data        |
|             |  32 KB Instruction |  32 KB Instruction |
|-------------|--------------------|--------------------|
| L2          | 256 KB Unified     | 256 KB Unified     |
|-------------|--------------------|--------------------|
| L3          |  30 MB Unified     |  30 MB Unified     |

根据 MSDN 文档:

GroupMask.Mask - A bitmap that specifies the affinity for zero or more processors within the specified group.

根据此文档,我期望 L3 缓存有不同的 GroupMask.Mask,但上面的输出没有显示这一点。对我来说,GroupMask.Mask 中的数据毫无意义!

这是一个link to the code产生上面的数据

关于c++ - 获取共享缓存的逻辑 CPU 内核数(L1、L2、L3),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45444041/

相关文章:

java - 如何检查是否有默认打印机 (Windows)?

c++ - 如何在 WINAPI 中忽略 HttpPOST 请求中的证书

visual-c++ - 新显卡上的 nvoglv32.dll 中的绘制调用崩溃

c++ - 重载用户定义类型的全局交换

c++ - C++类构造函数中的内存泄漏

windows - Windows 上的 Rsync : wrong permissions for created directories

c++ - OpenCV 在 Windows 和 Linux 上的不同结果

c++ - 即使包含头文件,程序也会出现 LNK2019 错误

c++ - 该片段在 Coliru 中编译时带有警告,但在 Ideone 中编译正常。哪一个是正确的?

c++ - 硬件断点 EXCEPTION_SINGLE_STEP 始终