1 // SPDX-License-Identifier: GPL-2.0
3 #include <sys/utsname.h>
8 #include <linux/zalloc.h>
9 #include <perf/cpumap.h>
16 #define CORE_SIB_FMT \
17 "%s/devices/system/cpu/cpu%d/topology/core_siblings_list"
19 "%s/devices/system/cpu/cpu%d/topology/die_cpus_list"
20 #define THRD_SIB_FMT \
21 "%s/devices/system/cpu/cpu%d/topology/thread_siblings_list"
22 #define THRD_SIB_FMT_NEW \
23 "%s/devices/system/cpu/cpu%d/topology/core_cpus_list"
24 #define NODE_ONLINE_FMT \
25 "%s/devices/system/node/online"
26 #define NODE_MEMINFO_FMT \
27 "%s/devices/system/node/node%d/meminfo"
28 #define NODE_CPULIST_FMT \
29 "%s/devices/system/node/node%d/cpulist"
31 static int build_cpu_topology(struct cpu_topology *tp, int cpu)
34 char filename[MAXPATHLEN];
41 scnprintf(filename, MAXPATHLEN, CORE_SIB_FMT,
42 sysfs__mountpoint(), cpu);
43 fp = fopen(filename, "r");
47 sret = getline(&buf, &len, fp);
52 p = strchr(buf, '\n');
56 for (i = 0; i < tp->core_sib; i++) {
57 if (!strcmp(buf, tp->core_siblings[i]))
60 if (i == tp->core_sib) {
61 tp->core_siblings[i] = buf;
69 if (!tp->die_siblings)
72 scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
73 sysfs__mountpoint(), cpu);
74 fp = fopen(filename, "r");
78 sret = getline(&buf, &len, fp);
83 p = strchr(buf, '\n');
87 for (i = 0; i < tp->die_sib; i++) {
88 if (!strcmp(buf, tp->die_siblings[i]))
91 if (i == tp->die_sib) {
92 tp->die_siblings[i] = buf;
100 scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT_NEW,
101 sysfs__mountpoint(), cpu);
102 if (access(filename, F_OK) == -1) {
103 scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT,
104 sysfs__mountpoint(), cpu);
106 fp = fopen(filename, "r");
110 if (getline(&buf, &len, fp) <= 0)
113 p = strchr(buf, '\n');
117 for (i = 0; i < tp->thread_sib; i++) {
118 if (!strcmp(buf, tp->thread_siblings[i]))
121 if (i == tp->thread_sib) {
122 tp->thread_siblings[i] = buf;
134 void cpu_topology__delete(struct cpu_topology *tp)
141 for (i = 0 ; i < tp->core_sib; i++)
142 zfree(&tp->core_siblings[i]);
145 for (i = 0 ; i < tp->die_sib; i++)
146 zfree(&tp->die_siblings[i]);
149 for (i = 0 ; i < tp->thread_sib; i++)
150 zfree(&tp->thread_siblings[i]);
155 static bool has_die_topology(void)
157 char filename[MAXPATHLEN];
163 if (strncmp(uts.machine, "x86_64", 6))
166 scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
167 sysfs__mountpoint(), 0);
168 if (access(filename, F_OK) == -1)
174 struct cpu_topology *cpu_topology__new(void)
176 struct cpu_topology *tp = NULL;
182 struct perf_cpu_map *map;
183 bool has_die = has_die_topology();
185 ncpus = cpu__max_present_cpu();
187 /* build online CPU map */
188 map = perf_cpu_map__new(NULL);
190 pr_debug("failed to get system cpumap\n");
194 nr = (u32)(ncpus & UINT_MAX);
196 sz = nr * sizeof(char *);
201 addr = calloc(1, sizeof(*tp) + nr_addr * sz);
207 tp->core_siblings = addr;
210 tp->die_siblings = addr;
213 tp->thread_siblings = addr;
215 for (i = 0; i < nr; i++) {
216 if (!cpu_map__has(map, i))
219 ret = build_cpu_topology(tp, i);
225 perf_cpu_map__put(map);
227 cpu_topology__delete(tp);
233 static int load_numa_node(struct numa_topology_node *node, int nr)
235 char str[MAXPATHLEN];
237 char *buf = NULL, *p;
243 node->node = (u32) nr;
245 scnprintf(str, MAXPATHLEN, NODE_MEMINFO_FMT,
246 sysfs__mountpoint(), nr);
247 fp = fopen(str, "r");
251 while (getline(&buf, &len, fp) > 0) {
252 /* skip over invalid lines */
253 if (!strchr(buf, ':'))
255 if (sscanf(buf, "%*s %*d %31s %"PRIu64, field, &mem) != 2)
257 if (!strcmp(field, "MemTotal:"))
258 node->mem_total = mem;
259 if (!strcmp(field, "MemFree:"))
260 node->mem_free = mem;
261 if (node->mem_total && node->mem_free)
268 scnprintf(str, MAXPATHLEN, NODE_CPULIST_FMT,
269 sysfs__mountpoint(), nr);
271 fp = fopen(str, "r");
275 if (getline(&buf, &len, fp) <= 0)
278 p = strchr(buf, '\n');
293 struct numa_topology *numa_topology__new(void)
295 struct perf_cpu_map *node_map = NULL;
296 struct numa_topology *tp = NULL;
297 char path[MAXPATHLEN];
304 scnprintf(path, MAXPATHLEN, NODE_ONLINE_FMT,
305 sysfs__mountpoint());
307 fp = fopen(path, "r");
311 if (getline(&buf, &len, fp) <= 0)
314 c = strchr(buf, '\n');
318 node_map = perf_cpu_map__new(buf);
322 nr = (u32) node_map->nr;
324 tp = zalloc(sizeof(*tp) + sizeof(tp->nodes[0])*nr);
330 for (i = 0; i < nr; i++) {
331 if (load_numa_node(&tp->nodes[i], node_map->map[i])) {
332 numa_topology__delete(tp);
341 perf_cpu_map__put(node_map);
345 void numa_topology__delete(struct numa_topology *tp)
349 for (i = 0; i < tp->nr; i++)
350 zfree(&tp->nodes[i].cpus);