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 133 134
|
/* Detect and report size of CPU caches
*
* Copyright (C) 2017-2023 by Jody Bruchon <jody@jodybruchon.com>
* Distributed under The MIT License
*
* If an error occurs or a cache is missing, zeroes are returned
* Unified caches populate l1/l2/l3; split caches populate lXi/lXd instead
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "likely_unlikely.h"
#include "libjodycode.h"
/* None of this code is useful outside of Linux */
#ifdef __linux__
static char *pathidx;
static char buf[16];
static char path[64] = "/sys/devices/system/cpu/cpu0/cache/index";
/*** End declarations, begin code ***/
/* Linux sysfs */
static size_t read_procfile(const char * const restrict name)
{
FILE *fp;
size_t i;
if (unlikely(name == NULL)) return 0;
memset(buf, 0, 16);
/* Create path */
*pathidx = '\0';
strcpy(pathidx, name);
fp = fopen(path, "rb");
if (fp == NULL) return 0;
i = fread(buf, 1, 16, fp);
if (ferror(fp)) return 0;
fclose(fp);
return i;
}
extern void jc_get_proc_cacheinfo(struct jc_proc_cacheinfo *pci)
{
char *idx;
size_t i;
size_t size;
int level;
char type;
char index;
if (unlikely(pci == NULL)) return;
memset(pci, 0, sizeof(struct jc_proc_cacheinfo));
i = strlen(path);
if (i > 48) return;
idx = path + i;
pathidx = idx + 1;
*pathidx = '/'; pathidx++;
for (index = '0'; index < '9'; index++) {
*idx = index;
/* Get the level for this index */
if (read_procfile("level") == 0) break;
if (*buf < '1' || *buf > '3') break;
else level = (*buf) + 1 - '1';
/* Get the size */
if (read_procfile("size") == 0) break;
size = (size_t)atoi(buf) * 1024;
if (size == 0) break;
/* Get the type */
if (read_procfile("type") == 0) break;
if (*buf != 'U' && *buf != 'I' && *buf != 'D') break;
type = *buf;
/* Act on it */
switch (type) {
case 'D':
switch (level) {
case 1: pci->l1d = size; break;
case 2: pci->l2d = size; break;
case 3: pci->l3d = size; break;
default: return;
};
break;
case 'I':
switch (level) {
case 1: pci->l1i = size; break;
case 2: pci->l2i = size; break;
case 3: pci->l3i = size; break;
default: return;
};
break;
case 'U':
switch (level) {
case 1: pci->l1 = size; break;
case 2: pci->l2 = size; break;
case 3: pci->l3 = size; break;
default: return;
};
break;
default: return;
}
/* Continue to next index */
}
return;
}
#endif /* __linux__ */
/* This is for testing only */
#ifdef JC_TEST
int main(void)
{
static struct jc_proc_cacheinfo pci;
jc_get_proc_cacheinfo(&pci);
printf("Cache: L1 %d,%d,%d L2 %d,%d,%d L3 %d,%d,%d\n",
pci.l1, pci.l1i, pci.l1d,
pci.l2, pci.l2i, pci.l2d,
pci.l3, pci.l3i, pci.l3d);
return 0;
}
#endif
|