Linux Audio

Check our new training course

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