GetLogicalProcessorInformationEx SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX array size

0

related to: Confusing ReturnLength from Windows GetLogicalProcessorInformationEx function

I have read the documentation for GetLogicalProcessorInformationEx. It states

Buffer [out, optional]

A pointer to a buffer that receives an array of SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX structures. If the function fails, the contents of this buffer are undefined.

Nowhere is the number of elements defined.

I have written a c++ program that uses this and baffled on how to interpret the output. My code makes the assumption that the array size is 1 unless the parameter is

RelationAll

In which case it assumes array size of 4.

Does anyone know the proper way to parse the output of this function?

#include <Windows.h>
#include <memory> 
#include <iterator> 
#include <ostream>
#include <iostream>
#include <iomanip>

using namespace std;

const int FieldOffsetDecWidth = 5;
const int FieldOffsetHexWidth = 4;
const int FieldWidthDec = 4;
const int LableWidth = 25;
const string TabStr = "     ";

const string CacheTypeArray[] =
{
    "CacheUnified",
    "CacheInstruction",
    "CacheData",
    "CacheTrace"
};

string ProcessorCacheTypeToString(PROCESSOR_CACHE_TYPE cacheType)
{
    if (cacheType >= 0 && cacheType <= _countof(CacheTypeArray))
    {
        return CacheTypeArray[static_cast<int>(cacheType)];
    }
    return "unKnown";
}

const string RelationShipArray[] =
{
    "RelationProcessorCore",
    "RelationNumaNode",
    "RelationCache",
    "RelationProcessorPackage",
    "RelationGroup"
};

string ReleationShipToString(LOGICAL_PROCESSOR_RELATIONSHIP relationship)
{
    if (relationship >= 0 && relationship <= _countof(RelationShipArray))
    {
        return RelationShipArray[static_cast<int>(relationship)];
    }
    if (relationship == RelationAll)
    {
        return "RelationAll";
    }
    return "unKnown";
}

void printFieldOffset(size_t offset)
{
    cout    << left << dec << setfill(' ') << setw(FieldOffsetDecWidth) << offset
            << right << " (0x" << hex << setfill('0') << setw(FieldOffsetHexWidth) << offset << ")" << dec;
}

void printField(size_t offset, string name, DWORD value)
{
    printFieldOffset(offset);
    cout    << TabStr.c_str() << left << setfill(' ') << setw(LableWidth)
            << name.c_str() << dec << setw(FieldWidthDec) << value << endl;
}

void printRelationship(size_t offset, string name, LOGICAL_PROCESSOR_RELATIONSHIP relationship)
{
    printFieldOffset(offset);
    cout    << TabStr.c_str() << left << setfill(' ') << setw(LableWidth) << name.c_str() 
            << ReleationShipToString(relationship).c_str() << endl;
}

void printCacheType(size_t offset, string name, PROCESSOR_CACHE_TYPE cacheType)
{
    printFieldOffset(offset);
    cout
        << TabStr.c_str() << left << setfill(' ') << setw(LableWidth) << name.c_str()
        << ProcessorCacheTypeToString(cacheType).c_str() << endl;
}

void printFieldHex(size_t offset, string name, size_t value, int width)
{
    printFieldOffset(offset);
        cout    << TabStr.c_str() << left << setfill(' ') << setw(LableWidth) << name.c_str() 
                << right << "(0x" << hex << setfill('0') << setw(width) << value << ")" << endl;
}

void printHeader(size_t offset, string name, size_t size)
{
    cout << endl;
    printFieldOffset(offset);
    cout    << ' ' << name.c_str() << " [Size " << dec << setfill(' ') << setw(0) << size
            << " (0x" << hex << setfill('0') << setw(FieldOffsetHexWidth) << size << ")]" << endl << dec;
}

void printGROUP_AFFINITY(GROUP_AFFINITY affinity, size_t offset)
{
    printHeader(offset, "GROUP_AFFINITY", sizeof GROUP_AFFINITY);
    offset += offsetof(GROUP_AFFINITY, Mask);
    printFieldHex(offset, "Mask", affinity.Mask, 8);
    offset += offsetof(GROUP_AFFINITY, Group);
    printField(offset, "Group", affinity.Group);
    offset += offsetof(GROUP_AFFINITY, Reserved);
    printFieldOffset(offset);
    cout << TabStr.c_str() << "Reserved" << endl;\
}

void GetLogicalProcessorInformation(LOGICAL_PROCESSOR_RELATIONSHIP relationship)
{
    DWORD returnedLength = 0;
    GetLogicalProcessorInformationEx(relationship, nullptr, &returnedLength);

    auto buffer = make_unique<byte[]>(returnedLength);
    memset(buffer.get(), 0, returnedLength);

    auto result = GetLogicalProcessorInformationEx(relationship, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(buffer.get()), &returnedLength);\
    if (!result)
    {
        cout << "Error  GetLogicalProcessorInformationEx" << endl << "Error " << GetLastError() << endl;
        return;
    }

    cout << "GetLogicalProcessorInformationEx for " << ReleationShipToString(relationship).c_str() << endl << "Size = ";
    printFieldOffset(returnedLength);
    cout << endl;

    auto index = 0;
    size_t base_offset = 0;
    size_t total_size = 0;
    auto basePtr = buffer.get();
    while (total_size < returnedLength)
    {
        auto infoPtr = PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(basePtr);

        cout << endl << "==================================================" << endl;

        auto offset = base_offset;
        printHeader(offset, "SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX", sizeof SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX);
        offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Relationship);
        printRelationship(offset, "Relationship", infoPtr->Relationship);
        offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Size);
        printField(offset, "Size", infoPtr->Size);

        switch (infoPtr->Relationship)
        {
        case RelationProcessorPackage:
        case RelationProcessorCore:
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Processor);
            printHeader(offset, "PROCESSOR_RELATIONSHIP", sizeof PROCESSOR_RELATIONSHIP);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Processor.Flags);
            printFieldHex(offset, "Flags", infoPtr->Processor.Flags, 2);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Processor.Reserved);
            printFieldOffset(offset);
            cout << TabStr.c_str() << "Reserved" << endl;
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Processor.GroupCount);
            printField(offset, "GroupCount", infoPtr->Processor.GroupCount);

            for (auto i = 0; i < infoPtr->Processor.GroupCount; i++)
            {
                printGROUP_AFFINITY(infoPtr->Processor.GroupMask[i], base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Processor.GroupMask[i]));
            }
            break;

        case RelationNumaNode:
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, NumaNode);
            printHeader(offset, "NUMA_NODE_RELATIONSHIP", sizeof NUMA_NODE_RELATIONSHIP);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, NumaNode.NodeNumber);
            printField(offset, "NodeNumber", infoPtr->NumaNode.NodeNumber);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, NumaNode.Reserved);
            printFieldOffset(offset);
            cout << TabStr.c_str() << "Reserved" << endl;

            printGROUP_AFFINITY(infoPtr->NumaNode.GroupMask, base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, NumaNode.GroupMask.Mask));
            break;

        case RelationCache:
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Cache);
            printHeader(offset, "CACHE_RELATIONSHIP", sizeof CACHE_RELATIONSHIP);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Cache.Level);
            printField(offset, "Level", infoPtr->Cache.Level);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Cache.Associativity);
            printField(offset, "Associativity", infoPtr->Cache.Associativity);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Cache.LineSize);
            printField(offset, "LineSize", infoPtr->Cache.LineSize);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Cache.CacheSize);
            printFieldHex(offset, "CacheSize", infoPtr->Cache.CacheSize, 4);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Cache.Type);
            printCacheType(offset, "Type", infoPtr->Cache.Type);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Cache.Reserved);
            printFieldOffset(offset);
            cout << TabStr.c_str() << "Reserved" << endl; 
            printGROUP_AFFINITY(infoPtr->Cache.GroupMask, base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Cache.GroupMask.Mask));
            break;

        case RelationGroup:
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Group);
            printHeader(offset, "GROUP_RELATIONSHIP", sizeof CACHE_RELATIONSHIP);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Group.MaximumGroupCount);
            printField(offset, "MaximumGroupCount", infoPtr->Group.MaximumGroupCount);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Group.ActiveGroupCount);
            printField(offset, "ActiveGroupCount", infoPtr->Group.ActiveGroupCount);
            offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Cache.Reserved);
            printFieldOffset(offset);
            cout << TabStr.c_str() << "Reserved" << endl;

            for (auto i = 0; i < infoPtr->Group.ActiveGroupCount; i++)
            {
                offset = base_offset +  offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Group.GroupInfo[i]);
                printHeader(offset, "PROCESSOR_GROUP_INFO", sizeof PROCESSOR_GROUP_INFO);
                offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Group.GroupInfo[i].MaximumProcessorCount);
                printField(offset, "MaximumProcessorCount", infoPtr->Group.GroupInfo[i].MaximumProcessorCount);
                offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Group.GroupInfo[i].ActiveProcessorCount);
                printField(offset, "ActiveProcessorCount", infoPtr->Group.GroupInfo[i].ActiveProcessorCount);
                printFieldOffset(offset);
                cout << TabStr.c_str() << "Reserved" << endl;
                offset = base_offset + offsetof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, Group.GroupInfo[i].ActiveProcessorMask);
                printFieldHex(offset, "ActiveProcessorMask", infoPtr->Group.GroupInfo[i].ActiveProcessorMask, 8);
            }
            break;

        case RelationAll:
            break;

        default:;
        }
        total_size += infoPtr->Size;
        basePtr += infoPtr->Size;
        base_offset += infoPtr->Size;
        index++;
    }
}

void main(int argc, char* argv[])
{
    if (argc != 2)
    {
        cout
            << "Useage: GetLogicalProcessorInformation relationship" << endl
            << " 0 = RelationProcessorCore" << endl
            << " 1 = RelationNumaNode" << endl
            << " 2 = RelationCache" << endl
            << " 3 = RelationProcessorPackage" << endl
            << " 4 = RelationGroup" << endl
            << "-1 = RelationAll" << endl;
        return;
    }
    auto relationship = LOGICAL_PROCESSOR_RELATIONSHIP(atoi(argv[1]));
    if (relationship == LOGICAL_PROCESSOR_RELATIONSHIP(-1))
    {
        relationship = RelationAll;
    }
    GetLogicalProcessorInformation(relationship); 
}

output

C:\Users\Paul\Perforce\PEB_DEV64\depot\vanguard\RTX\TMManagedProcess\x64\Debug>CoreAndThreadInfoNative.exe 0
GetLogicalProcessorInformationEx for RelationProcessorCore
Size = 384   (0x0180)

==================================================

0     (0x0000) SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX [Size 80 (0x0050)]
0     (0x0000)     Relationship             RelationProcessorCore
4     (0x0004)     Size                     48

8     (0x0008) PROCESSOR_RELATIONSHIP [Size 40 (0x0028)]
8     (0x0008)     Flags                    (0x00)
9     (0x0009)     Reserved
30    (0x001e)     GroupCount               1

32    (0x0020) GROUP_AFFINITY [Size 16 (0x0010)]
32    (0x0020)     Mask                     (0x00000001)
40    (0x0028)     Group                    0
50    (0x0032)     Reserved

==================================================

48    (0x0030) SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX [Size 80 (0x0050)]
48    (0x0030)     Relationship             RelationProcessorCore
52    (0x0034)     Size                     48

56    (0x0038) PROCESSOR_RELATIONSHIP [Size 40 (0x0028)]
56    (0x0038)     Flags                    (0x00)
57    (0x0039)     Reserved
78    (0x004e)     GroupCount               1

80    (0x0050) GROUP_AFFINITY [Size 16 (0x0010)]
80    (0x0050)     Mask                     (0x00000002)
88    (0x0058)     Group                    0
98    (0x0062)     Reserved

==================================================

96    (0x0060) SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX [Size 80 (0x0050)]
96    (0x0060)     Relationship             RelationProcessorCore
100   (0x0064)     Size                     48

104   (0x0068) PROCESSOR_RELATIONSHIP [Size 40 (0x0028)]
104   (0x0068)     Flags                    (0x00)
105   (0x0069)     Reserved
126   (0x007e)     GroupCount               1

128   (0x0080) GROUP_AFFINITY [Size 16 (0x0010)]
128   (0x0080)     Mask                     (0x00000004)
136   (0x0088)     Group                    0
146   (0x0092)     Reserved

==================================================

144   (0x0090) SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX [Size 80 (0x0050)]
144   (0x0090)     Relationship             RelationProcessorCore
148   (0x0094)     Size                     48

152   (0x0098) PROCESSOR_RELATIONSHIP [Size 40 (0x0028)]
152   (0x0098)     Flags                    (0x00)
153   (0x0099)     Reserved
174   (0x00ae)     GroupCount               1

176   (0x00b0) GROUP_AFFINITY [Size 16 (0x0010)]
176   (0x00b0)     Mask                     (0x00000008)
184   (0x00b8)     Group                    0
194   (0x00c2)     Reserved

==================================================

192   (0x00c0) SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX [Size 80 (0x0050)]
192   (0x00c0)     Relationship             RelationProcessorCore
196   (0x00c4)     Size                     48

200   (0x00c8) PROCESSOR_RELATIONSHIP [Size 40 (0x0028)]
200   (0x00c8)     Flags                    (0x00)
201   (0x00c9)     Reserved
222   (0x00de)     GroupCount               1

224   (0x00e0) GROUP_AFFINITY [Size 16 (0x0010)]
224   (0x00e0)     Mask                     (0x00000010)
232   (0x00e8)     Group                    0
242   (0x00f2)     Reserved

==================================================

240   (0x00f0) SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX [Size 80 (0x0050)]
240   (0x00f0)     Relationship             RelationProcessorCore
244   (0x00f4)     Size                     48

248   (0x00f8) PROCESSOR_RELATIONSHIP [Size 40 (0x0028)]
248   (0x00f8)     Flags                    (0x00)
249   (0x00f9)     Reserved
270   (0x010e)     GroupCount               1

272   (0x0110) GROUP_AFFINITY [Size 16 (0x0010)]
272   (0x0110)     Mask                     (0x00000020)
280   (0x0118)     Group                    0
290   (0x0122)     Reserved

==================================================

288   (0x0120) SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX [Size 80 (0x0050)]
288   (0x0120)     Relationship             RelationProcessorCore
292   (0x0124)     Size                     48

296   (0x0128) PROCESSOR_RELATIONSHIP [Size 40 (0x0028)]
296   (0x0128)     Flags                    (0x00)
297   (0x0129)     Reserved
318   (0x013e)     GroupCount               1

320   (0x0140) GROUP_AFFINITY [Size 16 (0x0010)]
320   (0x0140)     Mask                     (0x00000040)
328   (0x0148)     Group                    0
338   (0x0152)     Reserved

==================================================

336   (0x0150) SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX [Size 80 (0x0050)]
336   (0x0150)     Relationship             RelationProcessorCore
340   (0x0154)     Size                     48

344   (0x0158) PROCESSOR_RELATIONSHIP [Size 40 (0x0028)]
344   (0x0158)     Flags                    (0x00)
345   (0x0159)     Reserved
366   (0x016e)     GroupCount               1

368   (0x0170) GROUP_AFFINITY [Size 16 (0x0010)]
368   (0x0170)     Mask                     (0x00000080)
376   (0x0178)     Group                    0
386   (0x0182)     Reserved

C:\Users\Paul\Perforce\PEB_DEV64\depot\vanguard\RTX\TMManagedProcess\x64\Debug>
c++
windows
asked on Stack Overflow Jun 11, 2018 by Paul Baxter • edited Jun 11, 2018 by Paul Baxter

1 Answer

0

Try the following code:

for( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX pProcessor = pProcessorInformation->pProcessorEx;
    (LPBYTE)pProcessor < ((LPBYTE)pProcessorInformation->pProcessorEx) + pProcessorInformation->dwProcessorExSize;
    pProcessor = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)(((LPBYTE)pProcessor) + pProcessor->Size) )
{
    // switch on pProcessor->Relationship for RelationProcessorPackage, RelationProcessorCore, etc...
}

pProcessorInformation is merely a struct that holds my PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX structure that you get back from calling the API.

answered on Stack Overflow Jan 4, 2019 by Stratcat • edited Jan 4, 2019 by ivcubr

User contributions licensed under CC BY-SA 3.0