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
);