blob: 8f63dba212d7f850350d8b2fad95034bad53827b [file] [log] [blame]
Joerg Roedel1aed2672012-01-04 17:54:20 +01001#include "../perf.h"
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02002#include "util.h"
Adrian Hunter1a472452013-12-11 14:36:23 +02003#include "fs.h"
Frederic Weisbecker69e3f522010-01-16 14:21:15 +01004#include <sys/mman.h>
Ingo Molnar89fe8082013-09-30 12:07:11 +02005#ifdef HAVE_BACKTRACE_SUPPORT
Arnaldo Carvalho de Melodc4552b2012-08-07 23:32:05 -03006#include <execinfo.h>
Irina Tirdeac9f08be2012-09-08 03:43:23 +03007#endif
Arnaldo Carvalho de Melodc4552b2012-08-07 23:32:05 -03008#include <stdio.h>
9#include <stdlib.h>
Jiri Olsacef82c92013-12-03 14:09:22 +010010#include <string.h>
11#include <errno.h>
Adrian Hunter1a472452013-12-11 14:36:23 +020012#include <limits.h>
Jiri Olsa838d1452013-11-28 11:30:15 +010013#include <linux/kernel.h>
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -020014
Joerg Roedel1aed2672012-01-04 17:54:20 +010015/*
16 * XXX We need to find a better place for these things...
17 */
Arnaldo Carvalho de Melo0c1fe6b2012-10-06 14:57:10 -030018unsigned int page_size;
19
Arnaldo Carvalho de Melo0c6332e2012-12-13 16:43:04 -030020bool test_attr__enabled;
21
Joerg Roedel1aed2672012-01-04 17:54:20 +010022bool perf_host = true;
Joerg Roedelc4a7dca2012-02-10 18:05:05 +010023bool perf_guest = false;
Joerg Roedel1aed2672012-01-04 17:54:20 +010024
Borislav Petkov13559152013-02-20 16:32:31 +010025char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
26
Joerg Roedel1aed2672012-01-04 17:54:20 +010027void event_attr_init(struct perf_event_attr *attr)
28{
29 if (!perf_host)
30 attr->exclude_host = 1;
31 if (!perf_guest)
32 attr->exclude_guest = 1;
Stephane Eranian7e1ccd32012-02-09 16:12:38 +010033 /* to capture ABI version */
34 attr->size = sizeof(*attr);
Joerg Roedel1aed2672012-01-04 17:54:20 +010035}
36
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -020037int mkdir_p(char *path, mode_t mode)
38{
39 struct stat st;
40 int err;
41 char *d = path;
42
43 if (*d != '/')
44 return -1;
45
46 if (stat(path, &st) == 0)
47 return 0;
48
49 while (*++d == '/');
50
51 while ((d = strchr(d, '/'))) {
52 *d = '\0';
53 err = stat(path, &st) && mkdir(path, mode);
54 *d++ = '/';
55 if (err)
56 return -1;
57 while (*d == '/')
58 ++d;
59 }
60 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
61}
62
Adrian Hunter9a17d722013-10-14 13:43:41 +030063static int slow_copyfile(const char *from, const char *to, mode_t mode)
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -020064{
Adrian Hunter9a17d722013-10-14 13:43:41 +030065 int err = -1;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -020066 char *line = NULL;
67 size_t n;
68 FILE *from_fp = fopen(from, "r"), *to_fp;
Adrian Hunter9a17d722013-10-14 13:43:41 +030069 mode_t old_umask;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -020070
71 if (from_fp == NULL)
72 goto out;
73
Adrian Hunter9a17d722013-10-14 13:43:41 +030074 old_umask = umask(mode ^ 0777);
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -020075 to_fp = fopen(to, "w");
Adrian Hunter9a17d722013-10-14 13:43:41 +030076 umask(old_umask);
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -020077 if (to_fp == NULL)
78 goto out_fclose_from;
79
80 while (getline(&line, &n, from_fp) > 0)
81 if (fputs(line, to_fp) == EOF)
82 goto out_fclose_to;
83 err = 0;
84out_fclose_to:
85 fclose(to_fp);
86 free(line);
87out_fclose_from:
88 fclose(from_fp);
89out:
90 return err;
91}
92
Adrian Hunter9a17d722013-10-14 13:43:41 +030093int copyfile_mode(const char *from, const char *to, mode_t mode)
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -020094{
95 int fromfd, tofd;
96 struct stat st;
97 void *addr;
98 int err = -1;
99
100 if (stat(from, &st))
101 goto out;
102
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200103 if (st.st_size == 0) /* /proc? do it slowly... */
Adrian Hunter9a17d722013-10-14 13:43:41 +0300104 return slow_copyfile(from, to, mode);
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200105
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -0200106 fromfd = open(from, O_RDONLY);
107 if (fromfd < 0)
108 goto out;
109
Adrian Hunter9a17d722013-10-14 13:43:41 +0300110 tofd = creat(to, mode);
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -0200111 if (tofd < 0)
112 goto out_close_from;
113
114 addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
115 if (addr == MAP_FAILED)
116 goto out_close_to;
117
118 if (write(tofd, addr, st.st_size) == st.st_size)
119 err = 0;
120
121 munmap(addr, st.st_size);
122out_close_to:
123 close(tofd);
124 if (err)
125 unlink(to);
126out_close_from:
127 close(fromfd);
128out:
129 return err;
130}
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300131
Adrian Hunter9a17d722013-10-14 13:43:41 +0300132int copyfile(const char *from, const char *to)
133{
134 return copyfile_mode(from, to, 0755);
135}
136
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300137unsigned long convert_unit(unsigned long value, char *unit)
138{
139 *unit = ' ';
140
141 if (value > 1000) {
142 value /= 1000;
143 *unit = 'K';
144 }
145
146 if (value > 1000) {
147 value /= 1000;
148 *unit = 'M';
149 }
150
151 if (value > 1000) {
152 value /= 1000;
153 *unit = 'G';
154 }
155
156 return value;
157}
Arnaldo Carvalho de Melo1e7972c2011-01-03 16:50:55 -0200158
Jiri Olsabc3a5022013-11-28 11:30:16 +0100159static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
Arnaldo Carvalho de Melo1e7972c2011-01-03 16:50:55 -0200160{
161 void *buf_start = buf;
Jiri Olsa838d1452013-11-28 11:30:15 +0100162 size_t left = n;
Arnaldo Carvalho de Melo1e7972c2011-01-03 16:50:55 -0200163
Jiri Olsa838d1452013-11-28 11:30:15 +0100164 while (left) {
Jiri Olsabc3a5022013-11-28 11:30:16 +0100165 ssize_t ret = is_read ? read(fd, buf, left) :
166 write(fd, buf, left);
Arnaldo Carvalho de Melo1e7972c2011-01-03 16:50:55 -0200167
168 if (ret <= 0)
169 return ret;
170
Jiri Olsa838d1452013-11-28 11:30:15 +0100171 left -= ret;
172 buf += ret;
Arnaldo Carvalho de Melo1e7972c2011-01-03 16:50:55 -0200173 }
174
Jiri Olsa838d1452013-11-28 11:30:15 +0100175 BUG_ON((size_t)(buf - buf_start) != n);
176 return n;
Arnaldo Carvalho de Melo1e7972c2011-01-03 16:50:55 -0200177}
Arnaldo Carvalho de Melo61e04b32012-04-19 13:15:24 -0300178
Jiri Olsabc3a5022013-11-28 11:30:16 +0100179/*
180 * Read exactly 'n' bytes or return an error.
181 */
182ssize_t readn(int fd, void *buf, size_t n)
183{
184 return ion(true, fd, buf, n);
185}
186
187/*
188 * Write exactly 'n' bytes or return an error.
189 */
190ssize_t writen(int fd, void *buf, size_t n)
191{
192 return ion(false, fd, buf, n);
193}
194
Arnaldo Carvalho de Melo61e04b32012-04-19 13:15:24 -0300195size_t hex_width(u64 v)
196{
197 size_t n = 1;
198
199 while ((v >>= 4))
200 ++n;
201
202 return n;
203}
Arnaldo Carvalho de Melodc4552b2012-08-07 23:32:05 -0300204
Jiri Olsab2aff5f2012-10-27 23:18:30 +0200205static int hex(char ch)
206{
207 if ((ch >= '0') && (ch <= '9'))
208 return ch - '0';
209 if ((ch >= 'a') && (ch <= 'f'))
210 return ch - 'a' + 10;
211 if ((ch >= 'A') && (ch <= 'F'))
212 return ch - 'A' + 10;
213 return -1;
214}
215
216/*
217 * While we find nice hex chars, build a long_val.
218 * Return number of chars processed.
219 */
220int hex2u64(const char *ptr, u64 *long_val)
221{
222 const char *p = ptr;
223 *long_val = 0;
224
225 while (*p) {
226 const int hex_val = hex(*p);
227
228 if (hex_val < 0)
229 break;
230
231 *long_val = (*long_val << 4) | hex_val;
232 p++;
233 }
234
235 return p - ptr;
236}
237
Arnaldo Carvalho de Melodc4552b2012-08-07 23:32:05 -0300238/* Obtain a backtrace and print it to stdout. */
Ingo Molnar89fe8082013-09-30 12:07:11 +0200239#ifdef HAVE_BACKTRACE_SUPPORT
Arnaldo Carvalho de Melodc4552b2012-08-07 23:32:05 -0300240void dump_stack(void)
241{
242 void *array[16];
243 size_t size = backtrace(array, ARRAY_SIZE(array));
244 char **strings = backtrace_symbols(array, size);
245 size_t i;
246
247 printf("Obtained %zd stack frames.\n", size);
248
249 for (i = 0; i < size; i++)
250 printf("%s\n", strings[i]);
251
252 free(strings);
253}
Irina Tirdeac9f08be2012-09-08 03:43:23 +0300254#else
255void dump_stack(void) {}
256#endif
David Ahern2c803e52013-01-14 10:48:01 -0700257
258void get_term_dimensions(struct winsize *ws)
259{
260 char *s = getenv("LINES");
261
262 if (s != NULL) {
263 ws->ws_row = atoi(s);
264 s = getenv("COLUMNS");
265 if (s != NULL) {
266 ws->ws_col = atoi(s);
267 if (ws->ws_row && ws->ws_col)
268 return;
269 }
270 }
271#ifdef TIOCGWINSZ
272 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
273 ws->ws_row && ws->ws_col)
274 return;
275#endif
276 ws->ws_row = 25;
277 ws->ws_col = 80;
278}
Borislav Petkov13559152013-02-20 16:32:31 +0100279
280static void set_tracing_events_path(const char *mountpoint)
281{
282 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
283 mountpoint, "tracing/events");
284}
285
286const char *perf_debugfs_mount(const char *mountpoint)
287{
288 const char *mnt;
289
290 mnt = debugfs_mount(mountpoint);
291 if (!mnt)
292 return NULL;
293
294 set_tracing_events_path(mnt);
295
296 return mnt;
297}
298
299void perf_debugfs_set_path(const char *mntpt)
300{
301 snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
302 set_tracing_events_path(mntpt);
303}
Namhyung Kim167aedc2013-06-26 16:14:04 +0900304
305static const char *find_debugfs(void)
306{
307 const char *path = perf_debugfs_mount(NULL);
308
309 if (!path)
310 fprintf(stderr, "Your kernel does not support the debugfs filesystem");
311
312 return path;
313}
314
315/*
316 * Finds the path to the debugfs/tracing
317 * Allocates the string and stores it.
318 */
319const char *find_tracing_dir(void)
320{
321 static char *tracing;
322 static int tracing_found;
323 const char *debugfs;
324
325 if (tracing_found)
326 return tracing;
327
328 debugfs = find_debugfs();
329 if (!debugfs)
330 return NULL;
331
332 tracing = malloc(strlen(debugfs) + 9);
333 if (!tracing)
334 return NULL;
335
336 sprintf(tracing, "%s/tracing", debugfs);
337
338 tracing_found = 1;
339 return tracing;
340}
341
342char *get_tracing_file(const char *name)
343{
344 const char *tracing;
345 char *file;
346
347 tracing = find_tracing_dir();
348 if (!tracing)
349 return NULL;
350
351 file = malloc(strlen(tracing) + strlen(name) + 2);
352 if (!file)
353 return NULL;
354
355 sprintf(file, "%s/%s", tracing, name);
356 return file;
357}
358
359void put_tracing_file(char *file)
360{
361 free(file);
362}
Namhyung Kim3b47abe2013-06-04 10:50:29 +0900363
364int parse_nsec_time(const char *str, u64 *ptime)
365{
366 u64 time_sec, time_nsec;
367 char *end;
368
369 time_sec = strtoul(str, &end, 10);
370 if (*end != '.' && *end != '\0')
371 return -1;
372
373 if (*end == '.') {
374 int i;
375 char nsec_buf[10];
376
377 if (strlen(++end) > 9)
378 return -1;
379
380 strncpy(nsec_buf, end, 9);
381 nsec_buf[9] = '\0';
382
383 /* make it nsec precision */
384 for (i = strlen(nsec_buf); i < 9; i++)
385 nsec_buf[i] = '0';
386
387 time_nsec = strtoul(nsec_buf, &end, 10);
388 if (*end != '\0')
389 return -1;
390 } else
391 time_nsec = 0;
392
393 *ptime = time_sec * NSEC_PER_SEC + time_nsec;
394 return 0;
395}
Jiri Olsa27050f52013-09-01 12:36:13 +0200396
397unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
398{
399 struct parse_tag *i = tags;
400
401 while (i->tag) {
402 char *s;
403
404 s = strchr(str, i->tag);
405 if (s) {
406 unsigned long int value;
407 char *endptr;
408
409 value = strtoul(str, &endptr, 10);
410 if (s != endptr)
411 break;
412
Adrian Hunter56921be2013-10-22 10:34:17 +0300413 if (value > ULONG_MAX / i->mult)
414 break;
Jiri Olsa27050f52013-09-01 12:36:13 +0200415 value *= i->mult;
416 return value;
417 }
418 i++;
419 }
420
421 return (unsigned long) -1;
422}
Arnaldo Carvalho de Melo97a07f12013-10-17 16:33:43 -0300423
424int filename__read_int(const char *filename, int *value)
425{
426 char line[64];
427 int fd = open(filename, O_RDONLY), err = -1;
428
429 if (fd < 0)
430 return -1;
431
432 if (read(fd, line, sizeof(line)) > 0) {
433 *value = atoi(line);
434 err = 0;
435 }
436
437 close(fd);
438 return err;
439}
Jiri Olsacef82c92013-12-03 14:09:22 +0100440
441int filename__read_str(const char *filename, char **buf, size_t *sizep)
442{
443 size_t size = 0, alloc_size = 0;
444 void *bf = NULL, *nbf;
445 int fd, n, err = 0;
446
447 fd = open(filename, O_RDONLY);
448 if (fd < 0)
449 return -errno;
450
451 do {
452 if (size == alloc_size) {
453 alloc_size += BUFSIZ;
454 nbf = realloc(bf, alloc_size);
455 if (!nbf) {
456 err = -ENOMEM;
457 break;
458 }
459
460 bf = nbf;
461 }
462
463 n = read(fd, bf + size, alloc_size - size);
464 if (n < 0) {
465 if (size) {
466 pr_warning("read failed %d: %s\n",
467 errno, strerror(errno));
468 err = 0;
469 } else
470 err = -errno;
471
472 break;
473 }
474
475 size += n;
476 } while (n > 0);
477
478 if (!err) {
479 *sizep = size;
480 *buf = bf;
481 } else
482 free(bf);
483
484 close(fd);
485 return err;
486}
Dongsheng Yange1a2b172013-12-06 17:25:51 -0500487
488const char *get_filename_for_perf_kvm(void)
489{
490 const char *filename;
491
492 if (perf_host && !perf_guest)
493 filename = strdup("perf.data.host");
494 else if (!perf_host && perf_guest)
495 filename = strdup("perf.data.guest");
496 else
497 filename = strdup("perf.data.kvm");
498
499 return filename;
500}
Adrian Hunter1a472452013-12-11 14:36:23 +0200501
502int perf_event_paranoid(void)
503{
504 char path[PATH_MAX];
505 const char *procfs = procfs__mountpoint();
506 int value;
507
508 if (!procfs)
509 return INT_MAX;
510
511 scnprintf(path, PATH_MAX, "%s/sys/kernel/perf_event_paranoid", procfs);
512
513 if (filename__read_int(path, &value))
514 return INT_MAX;
515
516 return value;
517}