diff options
Diffstat (limited to 'src/detection/cpucache/cpucache_linux.c')
| -rw-r--r-- | src/detection/cpucache/cpucache_linux.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/detection/cpucache/cpucache_linux.c b/src/detection/cpucache/cpucache_linux.c new file mode 100644 index 0000000..0657c84 --- /dev/null +++ b/src/detection/cpucache/cpucache_linux.c @@ -0,0 +1,132 @@ +#include "cpucache.h" +#include "common/io.h" +#include "common/strutil.h" + +static const char* parseCpuCacheIndex(FFstrbuf* path, FFCPUCacheResult* result, FFstrbuf* buffer, FFstrbuf* added) { + uint32_t baseLen = path->length; + ffStrbufAppendS(path, "/level"); + if (!ffReadFileBuffer(path->chars, buffer)) { + return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/level\") == NULL"; + } + + uint32_t level = (uint32_t) ffStrbufToUInt(buffer, 0); + if (level < 1 || level > 4) { + return "level < 1 || level > 4"; + } + + ffStrbufSubstrBefore(path, baseLen); + ffStrbufAppendS(path, "/size"); + if (!ffReadFileBuffer(path->chars, buffer)) { + return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/size\") == NULL"; + } + + uint32_t sizeKb = (uint32_t) ffStrbufToUInt(buffer, 0); + if (sizeKb == 0) { + return "size == 0"; + } + + ffStrbufSubstrBefore(path, baseLen); + ffStrbufAppendS(path, "/type"); + if (!ffReadFileBuffer(path->chars, buffer)) { + return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/type\") == NULL"; + } + ffStrbufTrimRightSpace(buffer); + + FFCPUCacheType cacheType = 0; + switch (buffer->chars[0]) { + case 'I': + cacheType = FF_CPU_CACHE_TYPE_INSTRUCTION; + break; + case 'D': + cacheType = FF_CPU_CACHE_TYPE_DATA; + break; + case 'U': + cacheType = FF_CPU_CACHE_TYPE_UNIFIED; + break; + case 'T': + cacheType = FF_CPU_CACHE_TYPE_TRACE; + break; + default: + return "unknown cache type"; + } + + uint32_t lineSize = 0; + ffStrbufSubstrBefore(path, baseLen); + ffStrbufAppendS(path, "/coherency_line_size"); + if (ffReadFileBuffer(path->chars, buffer)) { + lineSize = (uint32_t) ffStrbufToUInt(buffer, 0); + } + + ffStrbufSubstrBefore(path, baseLen); + ffStrbufAppendS(path, "/shared_cpu_list"); + ffStrbufClear(buffer); + ffStrbufAppendC(buffer, '['); + if (!ffAppendFileBuffer(path->chars, buffer)) { + return "ffAppendFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/shared_cpu_list\") == NULL"; + } + ffStrbufTrimRightSpace(buffer); + + // deduplicate shared caches + ffStrbufAppendF(buffer, "_%u_%u_%u_%u]", level, sizeKb, lineSize, cacheType); + + if (ffStrbufContain(added, buffer)) { + return NULL; + } + ffStrbufAppend(added, buffer); + ffCPUCacheAddItem(result, level, sizeKb * 1024, lineSize, cacheType); + return NULL; +} + +static const char* parseCpuCache(FFstrbuf* path, FFCPUCacheResult* result, FFstrbuf* buffer, FFstrbuf* added) { + ffStrbufAppendS(path, "/cache/"); + uint32_t baseLen = path->length; + FF_AUTO_CLOSE_DIR DIR* pathCacheDir = opendir(path->chars); + if (!pathCacheDir) { + return "opendir(\"/sys/devices/system/cpu/cpuX/cache/\") == NULL"; + } + + struct dirent* pathCacheEntry; + while ((pathCacheEntry = readdir(pathCacheDir)) != NULL) { + if (!ffStrStartsWith(pathCacheEntry->d_name, "index") || !ffCharIsDigit(pathCacheEntry->d_name[strlen("index")])) { + continue; + } + + ffStrbufAppendS(path, pathCacheEntry->d_name); + const char* error = parseCpuCacheIndex(path, result, buffer, added); + if (error) { + return error; + } + ffStrbufSubstrBefore(path, baseLen); + } + + return NULL; +} + +const char* ffDetectCPUCache(FFCPUCacheResult* result) { + // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu + FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateS("/sys/devices/system/cpu/"); + uint32_t baseLen = path.length; + FF_AUTO_CLOSE_DIR DIR* pathCpuDir = opendir(path.chars); + if (!pathCpuDir) { + return "opendir(\"/sys/devices/system/cpu/\") == NULL"; + } + + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + FF_STRBUF_AUTO_DESTROY added = ffStrbufCreate(); + + struct dirent* pathCpuEntry; + while ((pathCpuEntry = readdir(pathCpuDir)) != NULL) { + if (!ffStrStartsWith(pathCpuEntry->d_name, "cpu") || + !ffCharIsDigit(pathCpuEntry->d_name[strlen("cpu")])) { + continue; + } + + ffStrbufAppendS(&path, pathCpuEntry->d_name); + const char* error = parseCpuCache(&path, result, &buffer, &added); + if (error) { + return error; + } + ffStrbufSubstrBefore(&path, baseLen); + } + return NULL; +} |