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