]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/perf/util/cputopo.c
perf tools: Add missing headers, mostly stdlib.h
[linux.git] / tools / perf / util / cputopo.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <sys/param.h>
3 #include <sys/utsname.h>
4 #include <inttypes.h>
5 #include <stdlib.h>
6 #include <api/fs/fs.h>
7
8 #include "cputopo.h"
9 #include "cpumap.h"
10 #include "util.h"
11 #include "env.h"
12
13 #define CORE_SIB_FMT \
14         "%s/devices/system/cpu/cpu%d/topology/core_siblings_list"
15 #define DIE_SIB_FMT \
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"
27
28 static int build_cpu_topology(struct cpu_topology *tp, int cpu)
29 {
30         FILE *fp;
31         char filename[MAXPATHLEN];
32         char *buf = NULL, *p;
33         size_t len = 0;
34         ssize_t sret;
35         u32 i = 0;
36         int ret = -1;
37
38         scnprintf(filename, MAXPATHLEN, CORE_SIB_FMT,
39                   sysfs__mountpoint(), cpu);
40         fp = fopen(filename, "r");
41         if (!fp)
42                 goto try_dies;
43
44         sret = getline(&buf, &len, fp);
45         fclose(fp);
46         if (sret <= 0)
47                 goto try_dies;
48
49         p = strchr(buf, '\n');
50         if (p)
51                 *p = '\0';
52
53         for (i = 0; i < tp->core_sib; i++) {
54                 if (!strcmp(buf, tp->core_siblings[i]))
55                         break;
56         }
57         if (i == tp->core_sib) {
58                 tp->core_siblings[i] = buf;
59                 tp->core_sib++;
60                 buf = NULL;
61                 len = 0;
62         }
63         ret = 0;
64
65 try_dies:
66         if (!tp->die_siblings)
67                 goto try_threads;
68
69         scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
70                   sysfs__mountpoint(), cpu);
71         fp = fopen(filename, "r");
72         if (!fp)
73                 goto try_threads;
74
75         sret = getline(&buf, &len, fp);
76         fclose(fp);
77         if (sret <= 0)
78                 goto try_threads;
79
80         p = strchr(buf, '\n');
81         if (p)
82                 *p = '\0';
83
84         for (i = 0; i < tp->die_sib; i++) {
85                 if (!strcmp(buf, tp->die_siblings[i]))
86                         break;
87         }
88         if (i == tp->die_sib) {
89                 tp->die_siblings[i] = buf;
90                 tp->die_sib++;
91                 buf = NULL;
92                 len = 0;
93         }
94         ret = 0;
95
96 try_threads:
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);
102         }
103         fp = fopen(filename, "r");
104         if (!fp)
105                 goto done;
106
107         if (getline(&buf, &len, fp) <= 0)
108                 goto done;
109
110         p = strchr(buf, '\n');
111         if (p)
112                 *p = '\0';
113
114         for (i = 0; i < tp->thread_sib; i++) {
115                 if (!strcmp(buf, tp->thread_siblings[i]))
116                         break;
117         }
118         if (i == tp->thread_sib) {
119                 tp->thread_siblings[i] = buf;
120                 tp->thread_sib++;
121                 buf = NULL;
122         }
123         ret = 0;
124 done:
125         if (fp)
126                 fclose(fp);
127         free(buf);
128         return ret;
129 }
130
131 void cpu_topology__delete(struct cpu_topology *tp)
132 {
133         u32 i;
134
135         if (!tp)
136                 return;
137
138         for (i = 0 ; i < tp->core_sib; i++)
139                 zfree(&tp->core_siblings[i]);
140
141         if (tp->die_sib) {
142                 for (i = 0 ; i < tp->die_sib; i++)
143                         zfree(&tp->die_siblings[i]);
144         }
145
146         for (i = 0 ; i < tp->thread_sib; i++)
147                 zfree(&tp->thread_siblings[i]);
148
149         free(tp);
150 }
151
152 static bool has_die_topology(void)
153 {
154         char filename[MAXPATHLEN];
155         struct utsname uts;
156
157         if (uname(&uts) < 0)
158                 return false;
159
160         if (strncmp(uts.machine, "x86_64", 6))
161                 return false;
162
163         scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
164                   sysfs__mountpoint(), 0);
165         if (access(filename, F_OK) == -1)
166                 return false;
167
168         return true;
169 }
170
171 struct cpu_topology *cpu_topology__new(void)
172 {
173         struct cpu_topology *tp = NULL;
174         void *addr;
175         u32 nr, i, nr_addr;
176         size_t sz;
177         long ncpus;
178         int ret = -1;
179         struct cpu_map *map;
180         bool has_die = has_die_topology();
181
182         ncpus = cpu__max_present_cpu();
183
184         /* build online CPU map */
185         map = cpu_map__new(NULL);
186         if (map == NULL) {
187                 pr_debug("failed to get system cpumap\n");
188                 return NULL;
189         }
190
191         nr = (u32)(ncpus & UINT_MAX);
192
193         sz = nr * sizeof(char *);
194         if (has_die)
195                 nr_addr = 3;
196         else
197                 nr_addr = 2;
198         addr = calloc(1, sizeof(*tp) + nr_addr * sz);
199         if (!addr)
200                 goto out_free;
201
202         tp = addr;
203         addr += sizeof(*tp);
204         tp->core_siblings = addr;
205         addr += sz;
206         if (has_die) {
207                 tp->die_siblings = addr;
208                 addr += sz;
209         }
210         tp->thread_siblings = addr;
211
212         for (i = 0; i < nr; i++) {
213                 if (!cpu_map__has(map, i))
214                         continue;
215
216                 ret = build_cpu_topology(tp, i);
217                 if (ret < 0)
218                         break;
219         }
220
221 out_free:
222         cpu_map__put(map);
223         if (ret) {
224                 cpu_topology__delete(tp);
225                 tp = NULL;
226         }
227         return tp;
228 }
229
230 static int load_numa_node(struct numa_topology_node *node, int nr)
231 {
232         char str[MAXPATHLEN];
233         char field[32];
234         char *buf = NULL, *p;
235         size_t len = 0;
236         int ret = -1;
237         FILE *fp;
238         u64 mem;
239
240         node->node = (u32) nr;
241
242         scnprintf(str, MAXPATHLEN, NODE_MEMINFO_FMT,
243                   sysfs__mountpoint(), nr);
244         fp = fopen(str, "r");
245         if (!fp)
246                 return -1;
247
248         while (getline(&buf, &len, fp) > 0) {
249                 /* skip over invalid lines */
250                 if (!strchr(buf, ':'))
251                         continue;
252                 if (sscanf(buf, "%*s %*d %31s %"PRIu64, field, &mem) != 2)
253                         goto err;
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)
259                         break;
260         }
261
262         fclose(fp);
263         fp = NULL;
264
265         scnprintf(str, MAXPATHLEN, NODE_CPULIST_FMT,
266                   sysfs__mountpoint(), nr);
267
268         fp = fopen(str, "r");
269         if (!fp)
270                 return -1;
271
272         if (getline(&buf, &len, fp) <= 0)
273                 goto err;
274
275         p = strchr(buf, '\n');
276         if (p)
277                 *p = '\0';
278
279         node->cpus = buf;
280         fclose(fp);
281         return 0;
282
283 err:
284         free(buf);
285         if (fp)
286                 fclose(fp);
287         return ret;
288 }
289
290 struct numa_topology *numa_topology__new(void)
291 {
292         struct cpu_map *node_map = NULL;
293         struct numa_topology *tp = NULL;
294         char path[MAXPATHLEN];
295         char *buf = NULL;
296         size_t len = 0;
297         u32 nr, i;
298         FILE *fp;
299         char *c;
300
301         scnprintf(path, MAXPATHLEN, NODE_ONLINE_FMT,
302                   sysfs__mountpoint());
303
304         fp = fopen(path, "r");
305         if (!fp)
306                 return NULL;
307
308         if (getline(&buf, &len, fp) <= 0)
309                 goto out;
310
311         c = strchr(buf, '\n');
312         if (c)
313                 *c = '\0';
314
315         node_map = cpu_map__new(buf);
316         if (!node_map)
317                 goto out;
318
319         nr = (u32) node_map->nr;
320
321         tp = zalloc(sizeof(*tp) + sizeof(tp->nodes[0])*nr);
322         if (!tp)
323                 goto out;
324
325         tp->nr = nr;
326
327         for (i = 0; i < nr; i++) {
328                 if (load_numa_node(&tp->nodes[i], node_map->map[i])) {
329                         numa_topology__delete(tp);
330                         tp = NULL;
331                         break;
332                 }
333         }
334
335 out:
336         free(buf);
337         fclose(fp);
338         cpu_map__put(node_map);
339         return tp;
340 }
341
342 void numa_topology__delete(struct numa_topology *tp)
343 {
344         u32 i;
345
346         for (i = 0; i < tp->nr; i++)
347                 free(tp->nodes[i].cpus);
348
349         free(tp);
350 }