Get the number of logical CPU cores sharing a cache (L1, L2, L3)

Viewed 1286

Below is some C++ code that detects the size of the L1, L2 and L3 CPU caches on Windows using GetLogicalProcessorInformation:

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;
        }
    }
}

As a next step I would like to get the number of logical CPU cores sharing a cache. On a x64 CPU with hyper-threading two logical CPU cores usually share an L2 cache and all logical CPU cores share the L3 cache.

After reading through MSDN I thought that GetLogicalProcessorInformationEx and CACHE_RELATIONSHIP and GROUP_AFFINITY where the data structures I was looking for but after trying it out these data structures seem useless for my purpose.

Question:

Is there a way to get the number of logical CPU cores sharing a cache on Windows using C/C++? (Ideally without using cpuid directly)


Solution:

The number of logical CPU cores sharing a cache can be obtained using GetLogicalProcessorInformationEx and the CACHE_RELATIONSHIP and GROUP_AFFINITY data structures. The GROUP_AFFINITY.Mask value contains one bit set for each CPU core that shares the current cache (RelationCache). As an example for most Intel CPUs with hyper-threading GROUP_AFFINITY.Mask will contain 2 bits set for the L2 cache and 8 bits set for the L3 cache for a CPU with 4 physical CPU cores and 8 logical CPU cores.

Here is the C++ code:

#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;
}

Caveats:

I have found that when running Windows inside a virtual machine the code above was unable to correctly detect the number of CPU cores sharing the caches, e.g. on a VM with 2 virtual CPU cores the code above reports that each logical CPU core has a private L1, L2 and L3 cache.

3 Answers
Related