Reputation: 7895
I wrote this small program to query and display information about my system's information on its cache.
#include <Windows.h>
#include <iostream>
#include <string>
#include <array>
#include <vector>
template<typename T>
auto msg = [](std::string_view label, T value, std::string descriptor = std::string()) {
std::cout << label.data() << ": " << value << descriptor << '\n' ;
};
const static std::array<std::string_view, 4> CacheTypes{
"Unified",
"Instruction",
"Data",
"Trace"
};
void QueryCacheInformation() {
DWORD bufferSize = 0;
GetLogicalProcessorInformation(0, &bufferSize);
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(bufferSize / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
GetLogicalProcessorInformation(buffer.data(), &bufferSize);
auto getCacheType = [](_PROCESSOR_CACHE_TYPE type) {
return std::string(CacheTypes[type]);
};
auto showAll = [&](int i, std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> &buff) {
msg<DWORD>(std::string_view("CPU L" + std::to_string(i) + " cache type"), static_cast<int>(buff[i].Cache.Type), std::string(" " + getCacheType(buff[i].Cache.Type)) );
msg<DWORD>(std::string_view("CPU L" + std::to_string(i) + " cache size"), buff[i].Cache.Size, " bytes");
msg<DWORD>(std::string_view("CPU L" + std::to_string(i) + " cache line size"), buff[i].Cache.LineSize, " bytes");
std::cout << '\n';
};
for (auto& info : buffer) {
switch (info.Cache.Level) {
case 0:
break;
case 1:
case 2:
case 3:
showAll(info.Cache.Level, buffer);
break;
default:
std::cout << "System has no cache!\n";
}
}
}
int main() {
QueryCacheInformation();
system("pause");
return 0;
}
And this is the output when I run this program:
CPU L1 cache type: 2 Data
CPU L1 cache size: 32768 bytes
CPU L1 cache line size: 64 bytes
CPU L1 cache type: 2 Data
CPU L1 cache size: 32768 bytes
CPU L1 cache line size: 64 bytes
CPU L1 cache type: 2 Data
CPU L1 cache size: 32768 bytes
CPU L1 cache line size: 64 bytes
CPU L1 cache type: 2 Data
CPU L1 cache size: 32768 bytes
CPU L1 cache line size: 64 bytes
CPU L2 cache type: 1 Instruction
CPU L2 cache size: 32768 bytes
CPU L2 cache line size: 64 bytes
CPU L1 cache type: 2 Data
CPU L1 cache size: 32768 bytes
CPU L1 cache line size: 64 bytes
CPU L1 cache type: 2 Data
CPU L1 cache size: 32768 bytes
CPU L1 cache line size: 64 bytes
CPU L1 cache type: 2 Data
CPU L1 cache size: 32768 bytes
CPU L1 cache line size: 64 bytes
CPU L1 cache type: 2 Data
CPU L1 cache size: 32768 bytes
CPU L1 cache line size: 64 bytes
CPU L2 cache type: 1 Instruction
CPU L2 cache size: 32768 bytes
CPU L2 cache line size: 64 bytes
Press any key to continue . . .
The program appears to be querying through processor nodes and retrieving information about its caches and displaying the results. However, I'm running this program on my Intel(R) Core(TM)2 Quad CPU Q9650. I'm running this on a Windows 7 64b and I'm compiling this using MS Visual Studio 2017 with the language flag set to ISO C++ Latest Draft Standard (/std:c++latest)
.
According to CPU-World's datasheet pertaining to my specific processor, here is what it is reporting about my system's architecture and its cache:
Cache Level | Cache Properties |
---|---|
Level 1 cache size | 4 x 32 KB 8-way set associative instruction caches |
4 x 32 KB 8-way set associative data caches | |
Level 2 cache size | 2 x 6 MB 24-way set associative caches (each L2 cache is shared between 2 cores) |
Lower on the page, it has these CPU ID tables with more information about its cache:
TLB/Cache details:
- 64-byte Prefetching
- Data TLB: 4-KB Pages, 4-way set associative, 256 entries
- Data TLB: 4-MB Pages, 4-way set associative, 32 entries
- Instruction TLB: 2-MB pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries
- Instruction TLB: 4-KB Pages, 4-way set associative, 128 entries
- L1 Data TLB: 4-KB pages, 4-way set associative, 16 entries
- L1 Data TLB: 4-MB pages, 4-way set associative, 16 entries
Cache: | L1 Data | L1 Instruction | L2 |
---|---|---|---|
Size: | 4 x 32 KB | 4 x 32 KB | 2 x 6 MB |
Associativity: | 8-way set associative | 8-way set associative | 24-way set associative |
Line Size: | 64 bytes | 64 bytes | 64 bytes |
Comments: | Direct-mapped | Direct-mapped | Non-inclusive Direct-Mapped 1 cache per 2 cores |
According to the datasheets, this should be the block diagram of my CPU's architecture.
However, this does not match the printed results from my program. According to the saved data structures from GetLogicalProcessorInformation()
it is claiming that my CPU has 8 L1 Data Caches and 2 L2 Instruction Caches all having the same exact size which is not the case. Now as for the line sizes they are all the same and this information appears to be correct. It's just that the "types" and some of the "sizes" are not. My CPU should have a total of 128KB of L1 Data Cache, 128KB of L1 Instruction Cache, and 12MB of L2 Cache. I'm not sure where I'm going wrong and why I'm not getting matching values and types...
Am I querying and extracting the information correctly? Is it within the for loop, the switch statement, or the lambda's I'm using? Or something else that I'm completely overlooking?
I'm new to this API so any and all help, tips, and suggestions will be useful.
Upvotes: 3
Views: 178
Reputation: 32732
The problem is in your lambda and the data you pass to it. You're using i
(the cache level) to access elements of buff
when you should be passing in the info
value from your loop instead.
Change the lambda and call site to be like this:
auto showAll = [&](int i, SYSTEM_LOGICAL_PROCESSOR_INFORMATION &info) {
msg<DWORD>(std::string_view("CPU L" + std::to_string(i) + " cache type"), static_cast<int>(info.Cache.Type), std::string(" " + getCacheType(info.Cache.Type)) );
msg<DWORD>(std::string_view("CPU L" + std::to_string(i) + " cache size"), info.Cache.Size, " bytes");
msg<DWORD>(std::string_view("CPU L" + std::to_string(i) + " cache line size"), info.Cache.LineSize, " bytes");
std::cout << '\n';
};
// ...
showAll(info.Cache.Level, info);
(replacing buff[i]
with info
in the lambda, and passing in info
instead of the buffer
vector).
Upvotes: 4