#include "cpucache.h"
#include "common/io/io.h"
#include "util/stringUtils.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");
if (!ffReadFileBuffer(path->chars, buffer))
return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/shared_cpu_list\") == NULL";
ffStrbufTrimRightSpace(buffer);
ffStrbufAppendF(buffer, "_%u_%u_%u_%u\n", 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)
{
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;
}