1 // SPDX-License-Identifier: GPL-2.0
3 #include <sys/utsname.h>
7 #include <linux/zalloc.h>
13 #define CORE_SIB_FMT \
14 "%s/devices/system/cpu/cpu%d/topology/core_siblings_list"
16 "%s/devices/system/cpu/cpu%d/topology/die_cpus_list"
17 #define THRD_SIB_FMT \
18 "%s/devices/system/cpu/cpu%d/topology/thread_siblings_list"
19 #define THRD_SIB_FMT_NEW \
20 "%s/devices/system/cpu/cpu%d/topology/core_cpus_list"
21 #define NODE_ONLINE_FMT \
22 "%s/devices/system/node/online"
23 #define NODE_MEMINFO_FMT \
24 "%s/devices/system/node/node%d/meminfo"
25 #define NODE_CPULIST_FMT \
26 "%s/devices/system/node/node%d/cpulist"
28 static int build_cpu_topology(struct cpu_topology *tp, int cpu)
31 char filename[MAXPATHLEN];
38 scnprintf(filename, MAXPATHLEN, CORE_SIB_FMT,
39 sysfs__mountpoint(), cpu);
40 fp = fopen(filename, "r");
44 sret = getline(&buf, &len, fp);
49 p = strchr(buf, '\n');
53 for (i = 0; i < tp->core_sib; i++) {
54 if (!strcmp(buf, tp->core_siblings[i]))
57 if (i == tp->core_sib) {
58 tp->core_siblings[i] = buf;
66 if (!tp->die_siblings)
69 scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
70 sysfs__mountpoint(), cpu);
71 fp = fopen(filename, "r");
75 sret = getline(&buf, &len, fp);
80 p = strchr(buf, '\n');
84 for (i = 0; i < tp->die_sib; i++) {
85 if (!strcmp(buf, tp->die_siblings[i]))
88 if (i == tp->die_sib) {
89 tp->die_siblings[i] = buf;
97 scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT_NEW,
98 sysfs__mountpoint(), cpu);
99 if (access(filename, F_OK) == -1) {
100 scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT,
101 sysfs__mountpoint(), cpu);
103 fp = fopen(filename, "r");
107 if (getline(&buf, &len, fp) <= 0)
110 p = strchr(buf, '\n');
114 for (i = 0; i < tp->thread_sib; i++) {
115 if (!strcmp(buf, tp->thread_siblings[i]))
118 if (i == tp->thread_sib) {
119 tp->thread_siblings[i] = buf;
131 void cpu_topology__delete(struct cpu_topology *tp)
138 for (i = 0 ; i < tp->core_sib; i++)
139 zfree(&tp->core_siblings[i]);
142 for (i = 0 ; i < tp->die_sib; i++)
143 zfree(&tp->die_siblings[i]);
146 for (i = 0 ; i < tp->thread_sib; i++)
147 zfree(&tp->thread_siblings[i]);
152 static bool has_die_topology(void)
154 char filename[MAXPATHLEN];
160 if (strncmp(uts.machine, "x86_64", 6))
163 scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
164 sysfs__mountpoint(), 0);
165 if (access(filename, F_OK) == -1)
171 struct cpu_topology *cpu_topology__new(void)
173 struct cpu_topology *tp = NULL;
180 bool has_die = has_die_topology();
182 ncpus = cpu__max_present_cpu();
184 /* build online CPU map */
185 map = cpu_map__new(NULL);
187 pr_debug("failed to get system cpumap\n");
191 nr = (u32)(ncpus & UINT_MAX);
193 sz = nr * sizeof(char *);
198 addr = calloc(1, sizeof(*tp) + nr_addr * sz);
204 tp->core_siblings = addr;
207 tp->die_siblings = addr;
210 tp->thread_siblings = addr;
212 for (i = 0; i < nr; i++) {
213 if (!cpu_map__has(map, i))
216 ret = build_cpu_topology(tp, i);
224 cpu_topology__delete(tp);
230 static int load_numa_node(struct numa_topology_node *node, int nr)
232 char str[MAXPATHLEN];
234 char *buf = NULL, *p;
240 node->node = (u32) nr;
242 scnprintf(str, MAXPATHLEN, NODE_MEMINFO_FMT,
243 sysfs__mountpoint(), nr);
244 fp = fopen(str, "r");
248 while (getline(&buf, &len, fp) > 0) {
249 /* skip over invalid lines */
250 if (!strchr(buf, ':'))
252 if (sscanf(buf, "%*s %*d %31s %"PRIu64, field, &mem) != 2)
254 if (!strcmp(field, "MemTotal:"))
255 node->mem_total = mem;
256 if (!strcmp(field, "MemFree:"))
257 node->mem_free = mem;
258 if (node->mem_total && node->mem_free)
265 scnprintf(str, MAXPATHLEN, NODE_CPULIST_FMT,
266 sysfs__mountpoint(), nr);
268 fp = fopen(str, "r");
272 if (getline(&buf, &len, fp) <= 0)
275 p = strchr(buf, '\n');
290 struct numa_topology *numa_topology__new(void)
292 struct cpu_map *node_map = NULL;
293 struct numa_topology *tp = NULL;
294 char path[MAXPATHLEN];
301 scnprintf(path, MAXPATHLEN, NODE_ONLINE_FMT,
302 sysfs__mountpoint());
304 fp = fopen(path, "r");
308 if (getline(&buf, &len, fp) <= 0)
311 c = strchr(buf, '\n');
315 node_map = cpu_map__new(buf);
319 nr = (u32) node_map->nr;
321 tp = zalloc(sizeof(*tp) + sizeof(tp->nodes[0])*nr);
327 for (i = 0; i < nr; i++) {
328 if (load_numa_node(&tp->nodes[i], node_map->map[i])) {
329 numa_topology__delete(tp);
338 cpu_map__put(node_map);
342 void numa_topology__delete(struct numa_topology *tp)
346 for (i = 0; i < tp->nr; i++)
347 free(tp->nodes[i].cpus);