1 // SPDX-License-Identifier: GPL-2.0
3 #include <sys/utsname.h>
8 #include <linux/zalloc.h>
9 #include <perf/cpumap.h>
15 #include "pmu-hybrid.h"
17 #define CORE_SIB_FMT \
18 "%s/devices/system/cpu/cpu%d/topology/core_siblings_list"
20 "%s/devices/system/cpu/cpu%d/topology/die_cpus_list"
21 #define THRD_SIB_FMT \
22 "%s/devices/system/cpu/cpu%d/topology/thread_siblings_list"
23 #define THRD_SIB_FMT_NEW \
24 "%s/devices/system/cpu/cpu%d/topology/core_cpus_list"
25 #define NODE_ONLINE_FMT \
26 "%s/devices/system/node/online"
27 #define NODE_MEMINFO_FMT \
28 "%s/devices/system/node/node%d/meminfo"
29 #define NODE_CPULIST_FMT \
30 "%s/devices/system/node/node%d/cpulist"
32 static int build_cpu_topology(struct cpu_topology *tp, int cpu)
35 char filename[MAXPATHLEN];
42 scnprintf(filename, MAXPATHLEN, CORE_SIB_FMT,
43 sysfs__mountpoint(), cpu);
44 fp = fopen(filename, "r");
48 sret = getline(&buf, &len, fp);
53 p = strchr(buf, '\n');
57 for (i = 0; i < tp->core_sib; i++) {
58 if (!strcmp(buf, tp->core_siblings[i]))
61 if (i == tp->core_sib) {
62 tp->core_siblings[i] = buf;
70 if (!tp->die_siblings)
73 scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
74 sysfs__mountpoint(), cpu);
75 fp = fopen(filename, "r");
79 sret = getline(&buf, &len, fp);
84 p = strchr(buf, '\n');
88 for (i = 0; i < tp->die_sib; i++) {
89 if (!strcmp(buf, tp->die_siblings[i]))
92 if (i == tp->die_sib) {
93 tp->die_siblings[i] = buf;
101 scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT_NEW,
102 sysfs__mountpoint(), cpu);
103 if (access(filename, F_OK) == -1) {
104 scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT,
105 sysfs__mountpoint(), cpu);
107 fp = fopen(filename, "r");
111 if (getline(&buf, &len, fp) <= 0)
114 p = strchr(buf, '\n');
118 for (i = 0; i < tp->thread_sib; i++) {
119 if (!strcmp(buf, tp->thread_siblings[i]))
122 if (i == tp->thread_sib) {
123 tp->thread_siblings[i] = buf;
135 void cpu_topology__delete(struct cpu_topology *tp)
142 for (i = 0 ; i < tp->core_sib; i++)
143 zfree(&tp->core_siblings[i]);
146 for (i = 0 ; i < tp->die_sib; i++)
147 zfree(&tp->die_siblings[i]);
150 for (i = 0 ; i < tp->thread_sib; i++)
151 zfree(&tp->thread_siblings[i]);
156 static bool has_die_topology(void)
158 char filename[MAXPATHLEN];
164 if (strncmp(uts.machine, "x86_64", 6))
167 scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
168 sysfs__mountpoint(), 0);
169 if (access(filename, F_OK) == -1)
175 struct cpu_topology *cpu_topology__new(void)
177 struct cpu_topology *tp = NULL;
183 struct perf_cpu_map *map;
184 bool has_die = has_die_topology();
186 ncpus = cpu__max_present_cpu();
188 /* build online CPU map */
189 map = perf_cpu_map__new(NULL);
191 pr_debug("failed to get system cpumap\n");
195 nr = (u32)(ncpus & UINT_MAX);
197 sz = nr * sizeof(char *);
202 addr = calloc(1, sizeof(*tp) + nr_addr * sz);
208 tp->core_siblings = addr;
211 tp->die_siblings = addr;
214 tp->thread_siblings = addr;
216 for (i = 0; i < nr; i++) {
217 if (!cpu_map__has(map, i))
220 ret = build_cpu_topology(tp, i);
226 perf_cpu_map__put(map);
228 cpu_topology__delete(tp);
234 static int load_numa_node(struct numa_topology_node *node, int nr)
236 char str[MAXPATHLEN];
238 char *buf = NULL, *p;
244 node->node = (u32) nr;
246 scnprintf(str, MAXPATHLEN, NODE_MEMINFO_FMT,
247 sysfs__mountpoint(), nr);
248 fp = fopen(str, "r");
252 while (getline(&buf, &len, fp) > 0) {
253 /* skip over invalid lines */
254 if (!strchr(buf, ':'))
256 if (sscanf(buf, "%*s %*d %31s %"PRIu64, field, &mem) != 2)
258 if (!strcmp(field, "MemTotal:"))
259 node->mem_total = mem;
260 if (!strcmp(field, "MemFree:"))
261 node->mem_free = mem;
262 if (node->mem_total && node->mem_free)
269 scnprintf(str, MAXPATHLEN, NODE_CPULIST_FMT,
270 sysfs__mountpoint(), nr);
272 fp = fopen(str, "r");
276 if (getline(&buf, &len, fp) <= 0)
279 p = strchr(buf, '\n');
294 struct numa_topology *numa_topology__new(void)
296 struct perf_cpu_map *node_map = NULL;
297 struct numa_topology *tp = NULL;
298 char path[MAXPATHLEN];
305 scnprintf(path, MAXPATHLEN, NODE_ONLINE_FMT,
306 sysfs__mountpoint());
308 fp = fopen(path, "r");
312 if (getline(&buf, &len, fp) <= 0)
315 c = strchr(buf, '\n');
319 node_map = perf_cpu_map__new(buf);
323 nr = (u32) node_map->nr;
325 tp = zalloc(sizeof(*tp) + sizeof(tp->nodes[0])*nr);
331 for (i = 0; i < nr; i++) {
332 if (load_numa_node(&tp->nodes[i], node_map->map[i])) {
333 numa_topology__delete(tp);
342 perf_cpu_map__put(node_map);
346 void numa_topology__delete(struct numa_topology *tp)
350 for (i = 0; i < tp->nr; i++)
351 zfree(&tp->nodes[i].cpus);
356 static int load_hybrid_node(struct hybrid_topology_node *node,
357 struct perf_pmu *pmu)
361 char *buf = NULL, *p;
365 node->pmu_name = strdup(pmu->name);
369 sysfs = sysfs__mountpoint();
373 snprintf(path, PATH_MAX, CPUS_TEMPLATE_CPU, sysfs, pmu->name);
374 fp = fopen(path, "r");
378 if (getline(&buf, &len, fp) <= 0) {
383 p = strchr(buf, '\n');
392 zfree(&node->pmu_name);
397 struct hybrid_topology *hybrid_topology__new(void)
399 struct perf_pmu *pmu;
400 struct hybrid_topology *tp = NULL;
403 nr = perf_pmu__hybrid_pmu_num();
407 tp = zalloc(sizeof(*tp) + sizeof(tp->nodes[0]) * nr);
412 perf_pmu__for_each_hybrid_pmu(pmu) {
413 if (load_hybrid_node(&tp->nodes[i], pmu)) {
414 hybrid_topology__delete(tp);
423 void hybrid_topology__delete(struct hybrid_topology *tp)
427 for (i = 0; i < tp->nr; i++) {
428 zfree(&tp->nodes[i].pmu_name);
429 zfree(&tp->nodes[i].cpus);