Skip to content

Instantly share code, notes, and snippets.

@Sc00bz
Created June 3, 2026 01:10
Show Gist options
  • Select an option

  • Save Sc00bz/448af736cc57d1396fcf2538d431739c to your computer and use it in GitHub Desktop.

Select an option

Save Sc00bz/448af736cc57d1396fcf2538d431739c to your computer and use it in GitHub Desktop.
Get CPU cache info for Windows
/*
* The MIT License (MIT)
*
* Copyright (c) 2026 Steve Thomas <steve AT tobtu DOT com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <windows.h>
#include <stdio.h>
#include <inttypes.h>
#define LARGE_ENOUGH(size, start, item) ((size) >= ((char*) &(item)) - ((char*) (start)) + sizeof(item))
const char* getProcessorCacheTypeName(PROCESSOR_CACHE_TYPE type)
{
switch (type)
{
case CacheUnified: return "Unified";
case CacheInstruction: return "Instruction";
case CacheData: return "Data";
case CacheTrace: return "Trace";
case CacheUnknown: return "Unknown";
}
return "Error";
}
int main()
{
char *buffer;
DWORD size = 0;
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX p;
GetLogicalProcessorInformationEx(RelationCache, NULL, &size);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
fprintf(stderr, "Error 1\n");
return 1;
}
buffer = new char[size];
p = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) buffer;
if (GetLogicalProcessorInformationEx(RelationCache, p, &size) == FALSE)
{
fprintf(stderr, "Error 2\n");
return 1;
}
// Find max `p->Cache.GroupCount`
size_t maxGroupCount = 0;
DWORD sizeLeft = size;
while (sizeLeft != 0)
{
if (!LARGE_ENOUGH(sizeLeft, p, p->Size) || sizeLeft < p->Size ||
!LARGE_ENOUGH(p->Size, p, p->Relationship) || p->Relationship != RelationCache ||
!LARGE_ENOUGH(p->Size, p, p->Cache) ||
(p->Cache.GroupCount > 0 && !LARGE_ENOUGH(p->Size, p, p->Cache.GroupMasks[p->Cache.GroupCount - 1])))
{
fprintf(stderr, "Error 3\n");
return 1;
}
if (maxGroupCount < p->Cache.GroupCount)
{
maxGroupCount = p->Cache.GroupCount;
}
// Next
sizeLeft -= p->Size;
p = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) (((uint8_t*) p) + p->Size);
}
// Print table header
if (maxGroupCount == 0)
{
printf(
" Level | Associativity | LineSize | CacheSize | Type | GroupCount | Mask | Group\n"
"-------+---------------+----------+------------+-------------+------------+------------------+-------\n");
}
else
{
printf(" Level | Associativity | LineSize | CacheSize | Type | GroupCount");
for (size_t i = 0; i < maxGroupCount; i++)
{
printf(" | Mask% -12" PRIuPTR " | Group% -5" PRIuPTR, i, i);
}
printf("\n-------+---------------+----------+------------+-------------+------------");
for (size_t i = 0; i < maxGroupCount; i++)
{
printf("+------------------+------------");
}
printf("\n");
}
// Reset
sizeLeft = size;
p = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) buffer;
// Print table
while (sizeLeft != 0)
{
if (!LARGE_ENOUGH(sizeLeft, p, p->Size) || sizeLeft < p->Size ||
!LARGE_ENOUGH(p->Size, p, p->Relationship) || p->Relationship != RelationCache ||
!LARGE_ENOUGH(p->Size, p, p->Cache) ||
(p->Cache.GroupCount > 0 && !LARGE_ENOUGH(p->Size, p, p->Cache.GroupMasks[p->Cache.GroupCount - 1])))
{
fprintf(stderr, "Error 4\n");
return 1;
}
size_t groupCount = p->Cache.GroupCount;
// Print row
printf(
" % 5u | % 13u | % 8u | % 10u | % -11s | % 10" PRIuPTR,
p->Cache.Level,
p->Cache.Associativity,
p->Cache.LineSize,
p->Cache.CacheSize,
getProcessorCacheTypeName(p->Cache.Type),
groupCount);
if (groupCount > 0)
{
for (size_t i = 0; i < groupCount; i++)
{
printf(
" | %016" PRIx64 " | % 10u",
p->Cache.GroupMasks[i].Mask,
p->Cache.GroupMasks[i].Group);
}
}
else if (maxGroupCount > 0)
{
groupCount = 1;
printf(
" | %016" PRIx64 " | % 10u",
p->Cache.GroupMask.Mask,
p->Cache.GroupMask.Group);
}
else
{
printf(
" | %016" PRIx64 " | % 5u",
p->Cache.GroupMask.Mask,
p->Cache.GroupMask.Group);
}
if (groupCount < maxGroupCount)
{
printf(" | |");
for (size_t i = groupCount + 1; i < maxGroupCount; i++)
{
printf(" | |");
}
}
printf("\n");
// Next
sizeLeft -= p->Size;
p = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) (((uint8_t*) p) + p->Size);
}
delete [] buffer;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment