master ohmu/fastfetch-openbsd / src / modules / cpucache / cpucache.c
ohmu  ·  2026-10-15
  1#include "common/printing.h"
  2#include "common/jsonconfig.h"
  3#include "common/size.h"
  4#include "common/strutil.h"
  5#include "detection/cpucache/cpucache.h"
  6#include "modules/cpucache/cpucache.h"
  7
  8static void printCPUCacheNormal(const FFCPUCacheResult* result, FFCPUCacheOptions* options) {
  9    FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
 10    FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
 11
 12    char levelStr[4] = "L";
 13    for (uint32_t i = 0; i < ARRAY_SIZE(result->caches) && result->caches[i].length > 0; i++) {
 14        ffStrbufClear(&key);
 15        levelStr[1] = (char) ('1' + i);
 16        if (options->moduleArgs.key.length == 0) {
 17            ffStrbufAppendF(&key, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(CPUCache), levelStr);
 18        } else {
 19            uint32_t index = i + 1;
 20            FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, ((FFformatarg[]) {
 21                                                                               FF_ARG(index, "index"),
 22                                                                               FF_ARG(levelStr, "level"),
 23                                                                               FF_ARG(options->moduleArgs.keyIcon, "icon"),
 24                                                                               FF_ARG(FF_MODULE_GET_DISPLAY_NAME(CPUCache), "module-name"),
 25                                                                           }));
 26        }
 27
 28        ffStrbufClear(&buffer);
 29
 30        uint32_t sum = 0;
 31        FF_LIST_FOR_EACH (FFCPUCache, src, result->caches[i]) {
 32            char typeStr = '?';
 33            switch (src->type) {
 34                case FF_CPU_CACHE_TYPE_DATA:
 35                    typeStr = 'D';
 36                    break;
 37                case FF_CPU_CACHE_TYPE_INSTRUCTION:
 38                    typeStr = 'I';
 39                    break;
 40                case FF_CPU_CACHE_TYPE_UNIFIED:
 41                    typeStr = 'U';
 42                    break;
 43                case FF_CPU_CACHE_TYPE_TRACE:
 44                    typeStr = 'T';
 45                    break;
 46            }
 47            if (buffer.length) {
 48                ffStrbufAppendS(&buffer, ", ");
 49            }
 50            if (src->num > 1) {
 51                ffStrbufAppendF(&buffer, "%ux", src->num);
 52            }
 53            ffSizeAppendNum(src->size, &buffer);
 54            ffStrbufAppendF(&buffer, " (%c)", typeStr);
 55
 56            sum += src->size * src->num;
 57        }
 58
 59        if (options->moduleArgs.outputFormat.length == 0) {
 60            ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY);
 61            ffStrbufPutTo(&buffer, stdout);
 62        } else {
 63            FF_STRBUF_AUTO_DESTROY buffer2 = ffStrbufCreate();
 64            ffSizeAppendNum(sum, &buffer2);
 65            FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]) {
 66                                                                                                         FF_ARG(buffer, "result"),
 67                                                                                                         FF_ARG(buffer2, "sum"),
 68                                                                                                         FF_ARG(levelStr, "level"),
 69                                                                                                     }));
 70        }
 71    }
 72}
 73
 74static void printCPUCacheCompact(const FFCPUCacheResult* result, FFCPUCacheOptions* options) {
 75    FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
 76    uint64_t sum = 0;
 77    for (uint32_t i = 0; i < ARRAY_SIZE(result->caches) && result->caches[i].length > 0; i++) {
 78        if (buffer.length) {
 79            ffStrbufAppendS(&buffer, ", ");
 80        }
 81        uint32_t value = 0;
 82        FF_LIST_FOR_EACH (FFCPUCache, src, result->caches[i]) {
 83            value += src->size * src->num;
 84        }
 85        ffSizeAppendNum(value, &buffer);
 86        ffStrbufAppendF(&buffer, " (L%u)", i + 1);
 87        sum += value;
 88    }
 89
 90    if (options->moduleArgs.outputFormat.length == 0) {
 91        ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(CPUCache), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
 92        ffStrbufPutTo(&buffer, stdout);
 93    } else {
 94        FF_STRBUF_AUTO_DESTROY buffer2 = ffStrbufCreate();
 95        ffSizeAppendNum(sum, &buffer2);
 96        FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(CPUCache), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
 97                                                                                                              FF_ARG(buffer, "result"),
 98                                                                                                              FF_ARG(buffer2, "sum"),
 99                                                                                                          }));
100    }
101}
102
103bool ffPrintCPUCache(FFCPUCacheOptions* options) {
104    bool success = false;
105    FFCPUCacheResult result = {
106        .caches = {
107            ffListCreate(),
108            ffListCreate(),
109            ffListCreate(),
110            ffListCreate(),
111        },
112    };
113
114    const char* error = ffDetectCPUCache(&result);
115
116    if (error) {
117        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(CPUCache), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
118        goto exit;
119    }
120
121    if (!options->compact) {
122        printCPUCacheNormal(&result, options);
123    } else {
124        printCPUCacheCompact(&result, options);
125    }
126    success = true;
127
128exit:
129    ffListDestroy(&result.caches[0]);
130    ffListDestroy(&result.caches[1]);
131    ffListDestroy(&result.caches[2]);
132    ffListDestroy(&result.caches[3]);
133
134    return success;
135}
136
137void ffParseCPUCacheJsonObject(FFCPUCacheOptions* options, yyjson_val* module) {
138    yyjson_val *key, *val;
139    size_t idx, max;
140    yyjson_obj_foreach (module, idx, max, key, val) {
141        if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) {
142            continue;
143        }
144
145        if (unsafe_yyjson_equals_str(key, "compact")) {
146            options->compact = yyjson_get_bool(val);
147            continue;
148        }
149
150        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(CPUCache), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
151    }
152}
153
154[[gnu::cold]]
155void ffGenerateCPUCacheJsonConfig(FFCPUCacheOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
156    ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
157
158    yyjson_mut_obj_add_bool(doc, module, "compact", options->compact);
159}
160
161bool ffGenerateCPUCacheJsonResult([[maybe_unused]] FFCPUCacheOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
162    bool success = false;
163    FFCPUCacheResult result = {
164        .caches = {
165            ffListCreate(),
166            ffListCreate(),
167            ffListCreate(),
168            ffListCreate(),
169        },
170    };
171
172    const char* error = ffDetectCPUCache(&result);
173
174    if (error) {
175        yyjson_mut_obj_add_str(doc, module, "error", error);
176        goto exit;
177    }
178
179    yyjson_mut_val* caches = yyjson_mut_obj_add_obj(doc, module, "result");
180
181    for (uint32_t i = 0; i < ARRAY_SIZE(result.caches) && result.caches[i].length > 0; i++) {
182        yyjson_mut_val* level = yyjson_mut_obj_add_arr(doc, caches, &"l1\0l2\0l3\0l4\0"[i * 3]);
183        FF_LIST_FOR_EACH (FFCPUCache, src, result.caches[i]) {
184            yyjson_mut_val* item = yyjson_mut_arr_add_obj(doc, level);
185            yyjson_mut_obj_add_uint(doc, item, "size", src->size);
186            yyjson_mut_obj_add_uint(doc, item, "num", src->num);
187            const char* typeStr = "unknown";
188            switch (src->type) {
189                case FF_CPU_CACHE_TYPE_DATA:
190                    typeStr = "data";
191                    break;
192                case FF_CPU_CACHE_TYPE_INSTRUCTION:
193                    typeStr = "instruction";
194                    break;
195                case FF_CPU_CACHE_TYPE_UNIFIED:
196                    typeStr = "unified";
197                    break;
198                case FF_CPU_CACHE_TYPE_TRACE:
199                    typeStr = "trace";
200                    break;
201            }
202            yyjson_mut_obj_add_uint(doc, item, "lineSize", src->lineSize);
203            yyjson_mut_obj_add_str(doc, item, "type", typeStr);
204        }
205    }
206    success = true;
207
208exit:
209    ffListDestroy(&result.caches[0]);
210    ffListDestroy(&result.caches[1]);
211    ffListDestroy(&result.caches[2]);
212    ffListDestroy(&result.caches[3]);
213    return success;
214}
215
216void ffInitCPUCacheOptions(FFCPUCacheOptions* options) {
217    ffOptionInitModuleArg(&options->moduleArgs, "");
218
219    options->compact = false;
220}
221
222void ffDestroyCPUCacheOptions(FFCPUCacheOptions* options) {
223    ffOptionDestroyModuleArg(&options->moduleArgs);
224}
225
226FFModuleBaseInfo ffCPUCacheModuleInfo = {
227    .name = "CPUCache",
228    .description = "Print CPU cache sizes",
229    .displayName = {
230        .en = "CPU Cache",
231        .ar = "ذاكرة المعالج المؤقتة",
232        .cs = "Mezipaměť CPU",
233        .de = "CPU-Cache",
234        .es = "Caché de la CPU",
235        .fi = "Suorittimen Välimuisti",
236        .fr = "Cache CPU",
237        .gl = "Caché da CPU",
238        .he = "מטמון מעבד",
239        .id = "Cache CPU",
240        .it = "Cache CPU",
241        .ja = "CPUキャッシュ",
242        .ko = "CPU 캐시",
243        .pl = "Pamięć podręczna CPU",
244        .pt = "Cache da CPU",
245        .ru = "Кэш процессора",
246        .tr = "CPU Önbelleği",
247        .uk = "Кеш ЦП",
248        .vi = "Bộ nhớ đệm CPU",
249        .zh_CN = "CPU缓存",
250        .zh_TW = "CPU快取記憶體",
251    },
252    .initOptions = (void*) ffInitCPUCacheOptions,
253    .destroyOptions = (void*) ffDestroyCPUCacheOptions,
254    .parseJsonObject = (void*) ffParseCPUCacheJsonObject,
255    .printModule = (void*) ffPrintCPUCache,
256    .generateJsonResult = (void*) ffGenerateCPUCacheJsonResult,
257    .generateJsonConfig = (void*) ffGenerateCPUCacheJsonConfig,
258    .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
259        { "Separate result", "result" },
260        { "Sum result", "sum" },
261        { "Cache level *", "level" },
262    })),
263    .defaultOrder = 34,
264};