Linux 5.1.15
[linux/fpc-iii.git] / tools / perf / util / cputopo.c
blobece0710249d4c410d2b3a02ed10a2d3cbd37ea42
1 // SPDX-License-Identifier: GPL-2.0
2 #include <sys/param.h>
3 #include <inttypes.h>
4 #include <api/fs/fs.h>
6 #include "cputopo.h"
7 #include "cpumap.h"
8 #include "util.h"
9 #include "env.h"
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"
23 static int build_cpu_topology(struct cpu_topology *tp, int cpu)
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;
33 scnprintf(filename, MAXPATHLEN, CORE_SIB_FMT,
34 sysfs__mountpoint(), cpu);
35 fp = fopen(filename, "r");
36 if (!fp)
37 goto try_threads;
39 sret = getline(&buf, &len, fp);
40 fclose(fp);
41 if (sret <= 0)
42 goto try_threads;
44 p = strchr(buf, '\n');
45 if (p)
46 *p = '\0';
48 for (i = 0; i < tp->core_sib; i++) {
49 if (!strcmp(buf, tp->core_siblings[i]))
50 break;
52 if (i == tp->core_sib) {
53 tp->core_siblings[i] = buf;
54 tp->core_sib++;
55 buf = NULL;
56 len = 0;
58 ret = 0;
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;
67 if (getline(&buf, &len, fp) <= 0)
68 goto done;
70 p = strchr(buf, '\n');
71 if (p)
72 *p = '\0';
74 for (i = 0; i < tp->thread_sib; i++) {
75 if (!strcmp(buf, tp->thread_siblings[i]))
76 break;
78 if (i == tp->thread_sib) {
79 tp->thread_siblings[i] = buf;
80 tp->thread_sib++;
81 buf = NULL;
83 ret = 0;
84 done:
85 if (fp)
86 fclose(fp);
87 free(buf);
88 return ret;
91 void cpu_topology__delete(struct cpu_topology *tp)
93 u32 i;
95 if (!tp)
96 return;
98 for (i = 0 ; i < tp->core_sib; i++)
99 zfree(&tp->core_siblings[i]);
101 for (i = 0 ; i < tp->thread_sib; i++)
102 zfree(&tp->thread_siblings[i]);
104 free(tp);
107 struct cpu_topology *cpu_topology__new(void)
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;
117 ncpus = cpu__max_present_cpu();
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;
126 nr = (u32)(ncpus & UINT_MAX);
128 sz = nr * sizeof(char *);
129 addr = calloc(1, sizeof(*tp) + 2 * sz);
130 if (!addr)
131 goto out_free;
133 tp = addr;
134 addr += sizeof(*tp);
135 tp->core_siblings = addr;
136 addr += sz;
137 tp->thread_siblings = addr;
139 for (i = 0; i < nr; i++) {
140 if (!cpu_map__has(map, i))
141 continue;
143 ret = build_cpu_topology(tp, i);
144 if (ret < 0)
145 break;
148 out_free:
149 cpu_map__put(map);
150 if (ret) {
151 cpu_topology__delete(tp);
152 tp = NULL;
154 return tp;
157 static int load_numa_node(struct numa_topology_node *node, int nr)
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;
167 node->node = (u32) nr;
169 scnprintf(str, MAXPATHLEN, NODE_MEMINFO_FMT,
170 sysfs__mountpoint(), nr);
171 fp = fopen(str, "r");
172 if (!fp)
173 return -1;
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;
189 fclose(fp);
190 fp = NULL;
192 scnprintf(str, MAXPATHLEN, NODE_CPULIST_FMT,
193 sysfs__mountpoint(), nr);
195 fp = fopen(str, "r");
196 if (!fp)
197 return -1;
199 if (getline(&buf, &len, fp) <= 0)
200 goto err;
202 p = strchr(buf, '\n');
203 if (p)
204 *p = '\0';
206 node->cpus = buf;
207 fclose(fp);
208 return 0;
210 err:
211 free(buf);
212 if (fp)
213 fclose(fp);
214 return ret;
217 struct numa_topology *numa_topology__new(void)
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;
228 scnprintf(path, MAXPATHLEN, NODE_ONLINE_FMT,
229 sysfs__mountpoint());
231 fp = fopen(path, "r");
232 if (!fp)
233 return NULL;
235 if (getline(&buf, &len, fp) <= 0)
236 goto out;
238 c = strchr(buf, '\n');
239 if (c)
240 *c = '\0';
242 node_map = cpu_map__new(buf);
243 if (!node_map)
244 goto out;
246 nr = (u32) node_map->nr;
248 tp = zalloc(sizeof(*tp) + sizeof(tp->nodes[0])*nr);
249 if (!tp)
250 goto out;
252 tp->nr = nr;
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;
262 out:
263 free(buf);
264 fclose(fp);
265 cpu_map__put(node_map);
266 return tp;
269 void numa_topology__delete(struct numa_topology *tp)
271 u32 i;
273 for (i = 0; i < tp->nr; i++)
274 free(tp->nodes[i].cpus);
276 free(tp);