From f1eaeddfe1ce8a7743615d1ac55c27d947b54210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 4 Jun 2024 23:56:00 +0800 Subject: [PATCH] CPU (Windows): detect CPU caches --- src/detection/cpu/cpu.h | 16 +++++++++++++ src/detection/cpu/cpu_windows.c | 40 ++++++++++++++++++++++++++++++-- src/modules/cpu/cpu.c | 41 +++++++++++++++++++++++++++++++-- 3 files changed, 93 insertions(+), 4 deletions(-) diff --git a/src/detection/cpu/cpu.h b/src/detection/cpu/cpu.h index fc9b7e080..7c8c4facd 100644 --- a/src/detection/cpu/cpu.h +++ b/src/detection/cpu/cpu.h @@ -10,6 +10,21 @@ typedef struct FFCPUCore uint32_t count; } FFCPUCore; +typedef enum FFCPUCacheType +{ + FF_CPU_CACHE_TYPE_UNIFIED = 0, + FF_CPU_CACHE_TYPE_INSTRUCTION = 1, + FF_CPU_CACHE_TYPE_DATA = 2, + FF_CPU_CACHE_TYPE_TRACE = 3, +} FFCPUCacheType; + +typedef struct FFCPUCache +{ + uint32_t size; + uint32_t num; + FFCPUCacheType type; +} FFCPUCache; + typedef struct FFCPUResult { FFstrbuf name; @@ -25,6 +40,7 @@ typedef struct FFCPUResult double frequencyBiosLimit; // GHz FFCPUCore coreTypes[16]; // number of P cores, E cores, etc. + FFlist caches[3]; // L1, L2, L3 double temperature; } FFCPUResult; diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index e0904ac07..c0a82252e 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -126,9 +126,9 @@ static const char* detectNCores(FFCPUResult* cpu) ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size) ) { - if(ptr->Relationship == RelationProcessorCore) + if (ptr->Relationship == RelationProcessorCore) ++cpu->coresPhysical; - else if(ptr->Relationship == RelationGroup) + else if (ptr->Relationship == RelationGroup) { for (uint32_t index = 0; index < ptr->Group.ActiveGroupCount; ++index) { @@ -136,6 +136,42 @@ static const char* detectNCores(FFCPUResult* cpu) cpu->coresLogical += ptr->Group.GroupInfo[index].MaximumProcessorCount; } } + else if(ptr->Relationship == RelationCache) + { + if (__builtin_expect(ptr->Cache.Level <= 3, true)) + { + FFCPUCacheType cacheType = 0; + switch (ptr->Cache.Type) + { + case CacheUnified: cacheType = FF_CPU_CACHE_TYPE_UNIFIED; break; + case CacheInstruction: cacheType = FF_CPU_CACHE_TYPE_INSTRUCTION; break; + case CacheData: cacheType = FF_CPU_CACHE_TYPE_DATA; break; + case CacheTrace: cacheType = FF_CPU_CACHE_TYPE_TRACE; break; + default: __builtin_unreachable(); break; + } + + FFlist* cacheLevel = &cpu->caches[ptr->Cache.Level - 1]; + FFCPUCache* found = NULL; + FF_LIST_FOR_EACH(FFCPUCache, item, *cacheLevel) + { + if (item->type == cacheType && item->size == ptr->Cache.CacheSize) + { + found = item; + break; + } + } + if (found) + found->num++; + else + { + *(FFCPUCache*) ffListAdd(cacheLevel) = (FFCPUCache) { + .size = ptr->Cache.CacheSize, + .num = 1, + .type = cacheType, + }; + } + } + } } return NULL; diff --git a/src/modules/cpu/cpu.c b/src/modules/cpu/cpu.c index ed21740e4..39e96ce15 100644 --- a/src/modules/cpu/cpu.c +++ b/src/modules/cpu/cpu.c @@ -22,7 +22,12 @@ void ffPrintCPU(FFCPUOptions* options) .frequencyBase = 0.0/0.0, .frequencyBiosLimit = 0.0/0.0, .name = ffStrbufCreate(), - .vendor = ffStrbufCreate() + .vendor = ffStrbufCreate(), + .caches = { + ffListCreate(sizeof (FFCPUCache)), + ffListCreate(sizeof (FFCPUCache)), + ffListCreate(sizeof (FFCPUCache)), + }, }; const char* error = ffDetectCPU(options, &cpu); @@ -123,6 +128,9 @@ void ffPrintCPU(FFCPUOptions* options) ffStrbufDestroy(&cpu.name); ffStrbufDestroy(&cpu.vendor); + ffListDestroy(&cpu.caches[0]); + ffListDestroy(&cpu.caches[1]); + ffListDestroy(&cpu.caches[2]); } bool ffParseCPUCommandOptions(FFCPUOptions* options, const char* key, const char* value) @@ -207,7 +215,12 @@ void ffGenerateCPUJsonResult(FFCPUOptions* options, yyjson_mut_doc* doc, yyjson_ .frequencyBase = 0.0/0.0, .frequencyBiosLimit = 0.0/0.0, .name = ffStrbufCreate(), - .vendor = ffStrbufCreate() + .vendor = ffStrbufCreate(), + .caches = { + ffListCreate(sizeof (FFCPUCache)), + ffListCreate(sizeof (FFCPUCache)), + ffListCreate(sizeof (FFCPUCache)), + }, }; const char* error = ffDetectCPU(options, &cpu); @@ -237,6 +250,27 @@ void ffGenerateCPUJsonResult(FFCPUOptions* options, yyjson_mut_doc* doc, yyjson_ yyjson_mut_obj_add_real(doc, frequency, "min", cpu.frequencyMin); yyjson_mut_obj_add_real(doc, frequency, "biosLimit", cpu.frequencyBiosLimit); + yyjson_mut_val* caches = yyjson_mut_obj_add_obj(doc, obj, "cache"); + for (uint32_t i = 0; i < sizeof (cpu.caches) / sizeof (cpu.caches[0]) && cpu.caches[i].length > 0; i++) + { + yyjson_mut_val* level = yyjson_mut_obj_add_arr(doc, caches, i == 0 ? "L1" : (i == 1 ? "L2" : "L3")); + FF_LIST_FOR_EACH(FFCPUCache, src, cpu.caches[i]) + { + yyjson_mut_val* item = yyjson_mut_arr_add_obj(doc, level); + yyjson_mut_obj_add_uint(doc, item, "size", src->size); + yyjson_mut_obj_add_uint(doc, item, "num", src->num); + const char* typeStr = "unknown"; + switch (src->type) + { + case FF_CPU_CACHE_TYPE_DATA: typeStr = "data"; break; + case FF_CPU_CACHE_TYPE_INSTRUCTION: typeStr = "instruction"; break; + case FF_CPU_CACHE_TYPE_UNIFIED: typeStr = "unified"; break; + case FF_CPU_CACHE_TYPE_TRACE: typeStr = "trace"; break; + } + yyjson_mut_obj_add_str(doc, item, "type", typeStr); + } + } + yyjson_mut_val* coreTypes = yyjson_mut_obj_add_arr(doc, obj, "coreTypes"); for (uint32_t i = 0; i < sizeof (cpu.coreTypes) / sizeof (cpu.coreTypes[0]) && cpu.coreTypes[i].count > 0; i++) { @@ -250,6 +284,9 @@ void ffGenerateCPUJsonResult(FFCPUOptions* options, yyjson_mut_doc* doc, yyjson_ ffStrbufDestroy(&cpu.name); ffStrbufDestroy(&cpu.vendor); + ffListDestroy(&cpu.caches[0]); + ffListDestroy(&cpu.caches[1]); + ffListDestroy(&cpu.caches[2]); } void ffPrintCPUHelpFormat(void)