xref: /openbmc/linux/tools/perf/util/util.c (revision db181ce0)
1 #include "../perf.h"
2 #include "util.h"
3 #include <api/fs/fs.h>
4 #include <sys/mman.h>
5 #ifdef HAVE_BACKTRACE_SUPPORT
6 #include <execinfo.h>
7 #endif
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <errno.h>
12 #include <limits.h>
13 #include <byteswap.h>
14 #include <linux/kernel.h>
15 
16 /*
17  * XXX We need to find a better place for these things...
18  */
19 unsigned int page_size;
20 int cacheline_size;
21 
22 bool test_attr__enabled;
23 
24 bool perf_host  = true;
25 bool perf_guest = false;
26 
27 char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
28 
29 void event_attr_init(struct perf_event_attr *attr)
30 {
31 	if (!perf_host)
32 		attr->exclude_host  = 1;
33 	if (!perf_guest)
34 		attr->exclude_guest = 1;
35 	/* to capture ABI version */
36 	attr->size = sizeof(*attr);
37 }
38 
39 int mkdir_p(char *path, mode_t mode)
40 {
41 	struct stat st;
42 	int err;
43 	char *d = path;
44 
45 	if (*d != '/')
46 		return -1;
47 
48 	if (stat(path, &st) == 0)
49 		return 0;
50 
51 	while (*++d == '/');
52 
53 	while ((d = strchr(d, '/'))) {
54 		*d = '\0';
55 		err = stat(path, &st) && mkdir(path, mode);
56 		*d++ = '/';
57 		if (err)
58 			return -1;
59 		while (*d == '/')
60 			++d;
61 	}
62 	return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
63 }
64 
65 static int slow_copyfile(const char *from, const char *to, mode_t mode)
66 {
67 	int err = -1;
68 	char *line = NULL;
69 	size_t n;
70 	FILE *from_fp = fopen(from, "r"), *to_fp;
71 	mode_t old_umask;
72 
73 	if (from_fp == NULL)
74 		goto out;
75 
76 	old_umask = umask(mode ^ 0777);
77 	to_fp = fopen(to, "w");
78 	umask(old_umask);
79 	if (to_fp == NULL)
80 		goto out_fclose_from;
81 
82 	while (getline(&line, &n, from_fp) > 0)
83 		if (fputs(line, to_fp) == EOF)
84 			goto out_fclose_to;
85 	err = 0;
86 out_fclose_to:
87 	fclose(to_fp);
88 	free(line);
89 out_fclose_from:
90 	fclose(from_fp);
91 out:
92 	return err;
93 }
94 
95 int copyfile_mode(const char *from, const char *to, mode_t mode)
96 {
97 	int fromfd, tofd;
98 	struct stat st;
99 	void *addr;
100 	int err = -1;
101 
102 	if (stat(from, &st))
103 		goto out;
104 
105 	if (st.st_size == 0) /* /proc? do it slowly... */
106 		return slow_copyfile(from, to, mode);
107 
108 	fromfd = open(from, O_RDONLY);
109 	if (fromfd < 0)
110 		goto out;
111 
112 	tofd = creat(to, mode);
113 	if (tofd < 0)
114 		goto out_close_from;
115 
116 	addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
117 	if (addr == MAP_FAILED)
118 		goto out_close_to;
119 
120 	if (write(tofd, addr, st.st_size) == st.st_size)
121 		err = 0;
122 
123 	munmap(addr, st.st_size);
124 out_close_to:
125 	close(tofd);
126 	if (err)
127 		unlink(to);
128 out_close_from:
129 	close(fromfd);
130 out:
131 	return err;
132 }
133 
134 int copyfile(const char *from, const char *to)
135 {
136 	return copyfile_mode(from, to, 0755);
137 }
138 
139 unsigned long convert_unit(unsigned long value, char *unit)
140 {
141 	*unit = ' ';
142 
143 	if (value > 1000) {
144 		value /= 1000;
145 		*unit = 'K';
146 	}
147 
148 	if (value > 1000) {
149 		value /= 1000;
150 		*unit = 'M';
151 	}
152 
153 	if (value > 1000) {
154 		value /= 1000;
155 		*unit = 'G';
156 	}
157 
158 	return value;
159 }
160 
161 static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
162 {
163 	void *buf_start = buf;
164 	size_t left = n;
165 
166 	while (left) {
167 		ssize_t ret = is_read ? read(fd, buf, left) :
168 					write(fd, buf, left);
169 
170 		if (ret < 0 && errno == EINTR)
171 			continue;
172 		if (ret <= 0)
173 			return ret;
174 
175 		left -= ret;
176 		buf  += ret;
177 	}
178 
179 	BUG_ON((size_t)(buf - buf_start) != n);
180 	return n;
181 }
182 
183 /*
184  * Read exactly 'n' bytes or return an error.
185  */
186 ssize_t readn(int fd, void *buf, size_t n)
187 {
188 	return ion(true, fd, buf, n);
189 }
190 
191 /*
192  * Write exactly 'n' bytes or return an error.
193  */
194 ssize_t writen(int fd, void *buf, size_t n)
195 {
196 	return ion(false, fd, buf, n);
197 }
198 
199 size_t hex_width(u64 v)
200 {
201 	size_t n = 1;
202 
203 	while ((v >>= 4))
204 		++n;
205 
206 	return n;
207 }
208 
209 static int hex(char ch)
210 {
211 	if ((ch >= '0') && (ch <= '9'))
212 		return ch - '0';
213 	if ((ch >= 'a') && (ch <= 'f'))
214 		return ch - 'a' + 10;
215 	if ((ch >= 'A') && (ch <= 'F'))
216 		return ch - 'A' + 10;
217 	return -1;
218 }
219 
220 /*
221  * While we find nice hex chars, build a long_val.
222  * Return number of chars processed.
223  */
224 int hex2u64(const char *ptr, u64 *long_val)
225 {
226 	const char *p = ptr;
227 	*long_val = 0;
228 
229 	while (*p) {
230 		const int hex_val = hex(*p);
231 
232 		if (hex_val < 0)
233 			break;
234 
235 		*long_val = (*long_val << 4) | hex_val;
236 		p++;
237 	}
238 
239 	return p - ptr;
240 }
241 
242 /* Obtain a backtrace and print it to stdout. */
243 #ifdef HAVE_BACKTRACE_SUPPORT
244 void dump_stack(void)
245 {
246 	void *array[16];
247 	size_t size = backtrace(array, ARRAY_SIZE(array));
248 	char **strings = backtrace_symbols(array, size);
249 	size_t i;
250 
251 	printf("Obtained %zd stack frames.\n", size);
252 
253 	for (i = 0; i < size; i++)
254 		printf("%s\n", strings[i]);
255 
256 	free(strings);
257 }
258 #else
259 void dump_stack(void) {}
260 #endif
261 
262 void get_term_dimensions(struct winsize *ws)
263 {
264 	char *s = getenv("LINES");
265 
266 	if (s != NULL) {
267 		ws->ws_row = atoi(s);
268 		s = getenv("COLUMNS");
269 		if (s != NULL) {
270 			ws->ws_col = atoi(s);
271 			if (ws->ws_row && ws->ws_col)
272 				return;
273 		}
274 	}
275 #ifdef TIOCGWINSZ
276 	if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
277 	    ws->ws_row && ws->ws_col)
278 		return;
279 #endif
280 	ws->ws_row = 25;
281 	ws->ws_col = 80;
282 }
283 
284 static void set_tracing_events_path(const char *mountpoint)
285 {
286 	snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
287 		 mountpoint, "tracing/events");
288 }
289 
290 const char *perf_debugfs_mount(const char *mountpoint)
291 {
292 	const char *mnt;
293 
294 	mnt = debugfs_mount(mountpoint);
295 	if (!mnt)
296 		return NULL;
297 
298 	set_tracing_events_path(mnt);
299 
300 	return mnt;
301 }
302 
303 void perf_debugfs_set_path(const char *mntpt)
304 {
305 	snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
306 	set_tracing_events_path(mntpt);
307 }
308 
309 static const char *find_debugfs(void)
310 {
311 	const char *path = perf_debugfs_mount(NULL);
312 
313 	if (!path)
314 		fprintf(stderr, "Your kernel does not support the debugfs filesystem");
315 
316 	return path;
317 }
318 
319 /*
320  * Finds the path to the debugfs/tracing
321  * Allocates the string and stores it.
322  */
323 const char *find_tracing_dir(void)
324 {
325 	static char *tracing;
326 	static int tracing_found;
327 	const char *debugfs;
328 
329 	if (tracing_found)
330 		return tracing;
331 
332 	debugfs = find_debugfs();
333 	if (!debugfs)
334 		return NULL;
335 
336 	tracing = malloc(strlen(debugfs) + 9);
337 	if (!tracing)
338 		return NULL;
339 
340 	sprintf(tracing, "%s/tracing", debugfs);
341 
342 	tracing_found = 1;
343 	return tracing;
344 }
345 
346 char *get_tracing_file(const char *name)
347 {
348 	const char *tracing;
349 	char *file;
350 
351 	tracing = find_tracing_dir();
352 	if (!tracing)
353 		return NULL;
354 
355 	file = malloc(strlen(tracing) + strlen(name) + 2);
356 	if (!file)
357 		return NULL;
358 
359 	sprintf(file, "%s/%s", tracing, name);
360 	return file;
361 }
362 
363 void put_tracing_file(char *file)
364 {
365 	free(file);
366 }
367 
368 int parse_nsec_time(const char *str, u64 *ptime)
369 {
370 	u64 time_sec, time_nsec;
371 	char *end;
372 
373 	time_sec = strtoul(str, &end, 10);
374 	if (*end != '.' && *end != '\0')
375 		return -1;
376 
377 	if (*end == '.') {
378 		int i;
379 		char nsec_buf[10];
380 
381 		if (strlen(++end) > 9)
382 			return -1;
383 
384 		strncpy(nsec_buf, end, 9);
385 		nsec_buf[9] = '\0';
386 
387 		/* make it nsec precision */
388 		for (i = strlen(nsec_buf); i < 9; i++)
389 			nsec_buf[i] = '0';
390 
391 		time_nsec = strtoul(nsec_buf, &end, 10);
392 		if (*end != '\0')
393 			return -1;
394 	} else
395 		time_nsec = 0;
396 
397 	*ptime = time_sec * NSEC_PER_SEC + time_nsec;
398 	return 0;
399 }
400 
401 unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
402 {
403 	struct parse_tag *i = tags;
404 
405 	while (i->tag) {
406 		char *s;
407 
408 		s = strchr(str, i->tag);
409 		if (s) {
410 			unsigned long int value;
411 			char *endptr;
412 
413 			value = strtoul(str, &endptr, 10);
414 			if (s != endptr)
415 				break;
416 
417 			if (value > ULONG_MAX / i->mult)
418 				break;
419 			value *= i->mult;
420 			return value;
421 		}
422 		i++;
423 	}
424 
425 	return (unsigned long) -1;
426 }
427 
428 int filename__read_int(const char *filename, int *value)
429 {
430 	char line[64];
431 	int fd = open(filename, O_RDONLY), err = -1;
432 
433 	if (fd < 0)
434 		return -1;
435 
436 	if (read(fd, line, sizeof(line)) > 0) {
437 		*value = atoi(line);
438 		err = 0;
439 	}
440 
441 	close(fd);
442 	return err;
443 }
444 
445 int filename__read_str(const char *filename, char **buf, size_t *sizep)
446 {
447 	size_t size = 0, alloc_size = 0;
448 	void *bf = NULL, *nbf;
449 	int fd, n, err = 0;
450 
451 	fd = open(filename, O_RDONLY);
452 	if (fd < 0)
453 		return -errno;
454 
455 	do {
456 		if (size == alloc_size) {
457 			alloc_size += BUFSIZ;
458 			nbf = realloc(bf, alloc_size);
459 			if (!nbf) {
460 				err = -ENOMEM;
461 				break;
462 			}
463 
464 			bf = nbf;
465 		}
466 
467 		n = read(fd, bf + size, alloc_size - size);
468 		if (n < 0) {
469 			if (size) {
470 				pr_warning("read failed %d: %s\n",
471 					   errno, strerror(errno));
472 				err = 0;
473 			} else
474 				err = -errno;
475 
476 			break;
477 		}
478 
479 		size += n;
480 	} while (n > 0);
481 
482 	if (!err) {
483 		*sizep = size;
484 		*buf   = bf;
485 	} else
486 		free(bf);
487 
488 	close(fd);
489 	return err;
490 }
491 
492 const char *get_filename_for_perf_kvm(void)
493 {
494 	const char *filename;
495 
496 	if (perf_host && !perf_guest)
497 		filename = strdup("perf.data.host");
498 	else if (!perf_host && perf_guest)
499 		filename = strdup("perf.data.guest");
500 	else
501 		filename = strdup("perf.data.kvm");
502 
503 	return filename;
504 }
505 
506 int perf_event_paranoid(void)
507 {
508 	char path[PATH_MAX];
509 	const char *procfs = procfs__mountpoint();
510 	int value;
511 
512 	if (!procfs)
513 		return INT_MAX;
514 
515 	scnprintf(path, PATH_MAX, "%s/sys/kernel/perf_event_paranoid", procfs);
516 
517 	if (filename__read_int(path, &value))
518 		return INT_MAX;
519 
520 	return value;
521 }
522 
523 void mem_bswap_32(void *src, int byte_size)
524 {
525 	u32 *m = src;
526 	while (byte_size > 0) {
527 		*m = bswap_32(*m);
528 		byte_size -= sizeof(u32);
529 		++m;
530 	}
531 }
532 
533 void mem_bswap_64(void *src, int byte_size)
534 {
535 	u64 *m = src;
536 
537 	while (byte_size > 0) {
538 		*m = bswap_64(*m);
539 		byte_size -= sizeof(u64);
540 		++m;
541 	}
542 }
543