From 87313f9f78e486d7343c9d3ca670b27f6bd4d4e2 Mon Sep 17 00:00:00 2001
From: taynpg <taynpg@163.com>
Date: Fri, 8 Mar 2024 14:15:01 +0800
Subject: [PATCH] =?UTF-8?q?windows=E4=B8=8B=E8=8E=B7=E5=8F=96CPU=E6=A0=B8?=
 =?UTF-8?q?=E5=BF=83=E6=95=B0=EF=BC=88=E4=BB=85=E5=8F=82=E8=80=83=E4=B8=8D?=
 =?UTF-8?q?=E8=83=BD=E7=9B=B4=E6=8E=A5=E4=BD=BF=E7=94=A8=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 cpp/common/win_getcpu_corenum.cpp | 158 ++++++++++++++++++++++++++++++
 1 file changed, 158 insertions(+)
 create mode 100644 cpp/common/win_getcpu_corenum.cpp

diff --git a/cpp/common/win_getcpu_corenum.cpp b/cpp/common/win_getcpu_corenum.cpp
new file mode 100644
index 0000000..bb31df7
--- /dev/null
+++ b/cpp/common/win_getcpu_corenum.cpp
@@ -0,0 +1,158 @@
+#include <windows.h>
+#include <malloc.h>    
+#include <stdio.h>
+#include <tchar.h>
+
+// LINK: https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformation?redirectedfrom=MSDN
+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;
+
+    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;
+}
+
+SYSTEM_INFO sysInfo;
+GetSystemInfo(&sysInfo);
+int numCores = sysInfo.dwNumberOfProcessors;
+int numPhysicalCores = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
+std::cout << "Number of CPU cores: " << numCores << std::endl;
\ No newline at end of file