1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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;
}
|