Merge tag 'for-5.1-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[linux-2.6-microblaze.git] / tools / perf / util / cputopo.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <sys/param.h>
3 #include <inttypes.h>
4 #include <api/fs/fs.h>
5
6 #include "cputopo.h"
7 #include "cpumap.h"
8 #include "util.h"
9 #include "env.h"
10
11
12 #define CORE_SIB_FMT \
13         "%s/devices/system/cpu/cpu%d/topology/core_siblings_list"
14 #define THRD_SIB_FMT \
15         "%s/devices/system/cpu/cpu%d/topology/thread_siblings_list"
16 #define NODE_ONLINE_FMT \
17         "%s/devices/system/node/online"
18 #define NODE_MEMINFO_FMT \
19         "%s/devices/system/node/node%d/meminfo"
20 #define NODE_CPULIST_FMT \
21         "%s/devices/system/node/node%d/cpulist"
22
23 static int build_cpu_topology(struct cpu_topology *tp, int cpu)
24 {
25         FILE *fp;
26         char filename[MAXPATHLEN];
27         char *buf = NULL, *p;
28         size_t len = 0;
29         ssize_t sret;
30         u32 i = 0;
31         int ret = -1;
32
33         scnprintf(filename, MAXPATHLEN, CORE_SIB_FMT,
34                   sysfs__mountpoint(), cpu);
35         fp = fopen(filename, "r");
36         if (!fp)
37                 goto try_threads;
38
39         sret = getline(&buf, &len, fp);
40         fclose(fp);
41         if (sret <= 0)
42                 goto try_threads;
43
44         p = strchr(buf, '\n');
45         if (p)
46                 *p = '\0';
47
48         for (i = 0; i < tp->core_sib; i++) {
49                 if (!strcmp(buf, tp->core_siblings[i]))
50                         break;
51         }
52         if (i == tp->core_sib) {
53                 tp->core_siblings[i] = buf;
54                 tp->core_sib++;
55                 buf = NULL;
56                 len = 0;
57         }
58         ret = 0;
59
60 try_threads:
61         scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT,
62                   sysfs__mountpoint(), cpu);
63         fp = fopen(filename, "r");
64         if (!fp)
65                 goto done;
66
67         if (getline(&buf, &len, fp) <= 0)
68                 goto done;
69
70         p = strchr(buf, '\n');
71         if (p)
72                 *p = '\0';
73
74         for (i = 0; i < tp->thread_sib; i++) {
75                 if (!strcmp(buf, tp->thread_siblings[i]))
76                         break;
77         }
78         if (i == tp->thread_sib) {
79                 tp->thread_siblings[i] = buf;
80                 tp->thread_sib++;
81                 buf = NULL;
82         }
83         ret = 0;
84 done:
85         if (fp)
86                 fclose(fp);
87         free(buf);
88         return ret;
89 }
90
91 void cpu_topology__delete(struct cpu_topology *tp)
92 {
93         u32 i;
94
95         if (!tp)
96                 return;
97
98         for (i = 0 ; i < tp->core_sib; i++)
99                 zfree(&tp->core_siblings[i]);
100
101         for (i = 0 ; i < tp->thread_sib; i++)
102                 zfree(&tp->thread_siblings[i]);
103
104         free(tp);
105 }
106
107 struct cpu_topology *cpu_topology__new(void)
108 {
109         struct cpu_topology *tp = NULL;
110         void *addr;
111         u32 nr, i;
112         size_t sz;
113         long ncpus;
114         int ret = -1;
115         struct cpu_map *map;
116
117         ncpus = cpu__max_present_cpu();
118
119         /* build online CPU map */
120         map = cpu_map__new(NULL);
121         if (map == NULL) {
122                 pr_debug("failed to get system cpumap\n");
123                 return NULL;
124         }
125
126         nr = (u32)(ncpus & UINT_MAX);
127
128         sz = nr * sizeof(char *);
129         addr = calloc(1, sizeof(*tp) + 2 * sz);
130         if (!addr)
131                 goto out_free;
132
133         tp = addr;
134         addr += sizeof(*tp);
135         tp->core_siblings = addr;
136         addr += sz;
137         tp->thread_siblings = addr;
138
139         for (i = 0; i < nr; i++) {
140                 if (!cpu_map__has(map, i))
141                         continue;
142
143                 ret = build_cpu_topology(tp, i);
144                 if (ret < 0)
145                         break;
146         }
147
148 out_free:
149         cpu_map__put(map);
150         if (ret) {
151                 cpu_topology__delete(tp);
152                 tp = NULL;
153         }
154         return tp;
155 }
156
157 static int load_numa_node(struct numa_topology_node *node, int nr)
158 {
159         char str[MAXPATHLEN];
160         char field[32];
161         char *buf = NULL, *p;
162         size_t len = 0;
163         int ret = -1;
164         FILE *fp;
165         u64 mem;
166
167         node->node = (u32) nr;
168
169         scnprintf(str, MAXPATHLEN, NODE_MEMINFO_FMT,
170                   sysfs__mountpoint(), nr);
171         fp = fopen(str, "r");
172         if (!fp)
173                 return -1;
174
175         while (getline(&buf, &len, fp) > 0) {
176                 /* skip over invalid lines */
177                 if (!strchr(buf, ':'))
178                         continue;
179                 if (sscanf(buf, "%*s %*d %31s %"PRIu64, field, &mem) != 2)
180                         goto err;
181                 if (!strcmp(field, "MemTotal:"))
182                         node->mem_total = mem;
183                 if (!strcmp(field, "MemFree:"))
184                         node->mem_free = mem;
185                 if (node->mem_total && node->mem_free)
186                         break;
187         }
188
189         fclose(fp);
190         fp = NULL;
191
192         scnprintf(str, MAXPATHLEN, NODE_CPULIST_FMT,
193                   sysfs__mountpoint(), nr);
194
195         fp = fopen(str, "r");
196         if (!fp)
197                 return -1;
198
199         if (getline(&buf, &len, fp) <= 0)
200                 goto err;
201
202         p = strchr(buf, '\n');
203         if (p)
204                 *p = '\0';
205
206         node->cpus = buf;
207         fclose(fp);
208         return 0;
209
210 err:
211         free(buf);
212         if (fp)
213                 fclose(fp);
214         return ret;
215 }
216
217 struct numa_topology *numa_topology__new(void)
218 {
219         struct cpu_map *node_map = NULL;
220         struct numa_topology *tp = NULL;
221         char path[MAXPATHLEN];
222         char *buf = NULL;
223         size_t len = 0;
224         u32 nr, i;
225         FILE *fp;
226         char *c;
227
228         scnprintf(path, MAXPATHLEN, NODE_ONLINE_FMT,
229                   sysfs__mountpoint());
230
231         fp = fopen(path, "r");
232         if (!fp)
233                 return NULL;
234
235         if (getline(&buf, &len, fp) <= 0)
236                 goto out;
237
238         c = strchr(buf, '\n');
239         if (c)
240                 *c = '\0';
241
242         node_map = cpu_map__new(buf);
243         if (!node_map)
244                 goto out;
245
246         nr = (u32) node_map->nr;
247
248         tp = zalloc(sizeof(*tp) + sizeof(tp->nodes[0])*nr);
249         if (!tp)
250                 goto out;
251
252         tp->nr = nr;
253
254         for (i = 0; i < nr; i++) {
255                 if (load_numa_node(&tp->nodes[i], node_map->map[i])) {
256                         numa_topology__delete(tp);
257                         tp = NULL;
258                         break;
259                 }
260         }
261
262 out:
263         free(buf);
264         fclose(fp);
265         cpu_map__put(node_map);
266         return tp;
267 }
268
269 void numa_topology__delete(struct numa_topology *tp)
270 {
271         u32 i;
272
273         for (i = 0; i < tp->nr; i++)
274                 free(tp->nodes[i].cpus);
275
276         free(tp);
277 }