at v3.17-rc3 538 lines 9.0 kB view raw
1#include "../perf.h" 2#include "util.h" 3#include "debug.h" 4#include <api/fs/fs.h> 5#include <sys/mman.h> 6#ifdef HAVE_BACKTRACE_SUPPORT 7#include <execinfo.h> 8#endif 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12#include <errno.h> 13#include <limits.h> 14#include <byteswap.h> 15#include <linux/kernel.h> 16 17/* 18 * XXX We need to find a better place for these things... 19 */ 20unsigned int page_size; 21int cacheline_size; 22 23bool test_attr__enabled; 24 25bool perf_host = true; 26bool perf_guest = false; 27 28char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; 29 30void event_attr_init(struct perf_event_attr *attr) 31{ 32 if (!perf_host) 33 attr->exclude_host = 1; 34 if (!perf_guest) 35 attr->exclude_guest = 1; 36 /* to capture ABI version */ 37 attr->size = sizeof(*attr); 38} 39 40int mkdir_p(char *path, mode_t mode) 41{ 42 struct stat st; 43 int err; 44 char *d = path; 45 46 if (*d != '/') 47 return -1; 48 49 if (stat(path, &st) == 0) 50 return 0; 51 52 while (*++d == '/'); 53 54 while ((d = strchr(d, '/'))) { 55 *d = '\0'; 56 err = stat(path, &st) && mkdir(path, mode); 57 *d++ = '/'; 58 if (err) 59 return -1; 60 while (*d == '/') 61 ++d; 62 } 63 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; 64} 65 66static int slow_copyfile(const char *from, const char *to, mode_t mode) 67{ 68 int err = -1; 69 char *line = NULL; 70 size_t n; 71 FILE *from_fp = fopen(from, "r"), *to_fp; 72 mode_t old_umask; 73 74 if (from_fp == NULL) 75 goto out; 76 77 old_umask = umask(mode ^ 0777); 78 to_fp = fopen(to, "w"); 79 umask(old_umask); 80 if (to_fp == NULL) 81 goto out_fclose_from; 82 83 while (getline(&line, &n, from_fp) > 0) 84 if (fputs(line, to_fp) == EOF) 85 goto out_fclose_to; 86 err = 0; 87out_fclose_to: 88 fclose(to_fp); 89 free(line); 90out_fclose_from: 91 fclose(from_fp); 92out: 93 return err; 94} 95 96int copyfile_mode(const char *from, const char *to, mode_t mode) 97{ 98 int fromfd, tofd; 99 struct stat st; 100 void *addr; 101 int err = -1; 102 103 if (stat(from, &st)) 104 goto out; 105 106 if (st.st_size == 0) /* /proc? do it slowly... */ 107 return slow_copyfile(from, to, mode); 108 109 fromfd = open(from, O_RDONLY); 110 if (fromfd < 0) 111 goto out; 112 113 tofd = creat(to, mode); 114 if (tofd < 0) 115 goto out_close_from; 116 117 addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0); 118 if (addr == MAP_FAILED) 119 goto out_close_to; 120 121 if (write(tofd, addr, st.st_size) == st.st_size) 122 err = 0; 123 124 munmap(addr, st.st_size); 125out_close_to: 126 close(tofd); 127 if (err) 128 unlink(to); 129out_close_from: 130 close(fromfd); 131out: 132 return err; 133} 134 135int copyfile(const char *from, const char *to) 136{ 137 return copyfile_mode(from, to, 0755); 138} 139 140unsigned long convert_unit(unsigned long value, char *unit) 141{ 142 *unit = ' '; 143 144 if (value > 1000) { 145 value /= 1000; 146 *unit = 'K'; 147 } 148 149 if (value > 1000) { 150 value /= 1000; 151 *unit = 'M'; 152 } 153 154 if (value > 1000) { 155 value /= 1000; 156 *unit = 'G'; 157 } 158 159 return value; 160} 161 162static ssize_t ion(bool is_read, int fd, void *buf, size_t n) 163{ 164 void *buf_start = buf; 165 size_t left = n; 166 167 while (left) { 168 ssize_t ret = is_read ? read(fd, buf, left) : 169 write(fd, buf, left); 170 171 if (ret < 0 && errno == EINTR) 172 continue; 173 if (ret <= 0) 174 return ret; 175 176 left -= ret; 177 buf += ret; 178 } 179 180 BUG_ON((size_t)(buf - buf_start) != n); 181 return n; 182} 183 184/* 185 * Read exactly 'n' bytes or return an error. 186 */ 187ssize_t readn(int fd, void *buf, size_t n) 188{ 189 return ion(true, fd, buf, n); 190} 191 192/* 193 * Write exactly 'n' bytes or return an error. 194 */ 195ssize_t writen(int fd, void *buf, size_t n) 196{ 197 return ion(false, fd, buf, n); 198} 199 200size_t hex_width(u64 v) 201{ 202 size_t n = 1; 203 204 while ((v >>= 4)) 205 ++n; 206 207 return n; 208} 209 210static int hex(char ch) 211{ 212 if ((ch >= '0') && (ch <= '9')) 213 return ch - '0'; 214 if ((ch >= 'a') && (ch <= 'f')) 215 return ch - 'a' + 10; 216 if ((ch >= 'A') && (ch <= 'F')) 217 return ch - 'A' + 10; 218 return -1; 219} 220 221/* 222 * While we find nice hex chars, build a long_val. 223 * Return number of chars processed. 224 */ 225int hex2u64(const char *ptr, u64 *long_val) 226{ 227 const char *p = ptr; 228 *long_val = 0; 229 230 while (*p) { 231 const int hex_val = hex(*p); 232 233 if (hex_val < 0) 234 break; 235 236 *long_val = (*long_val << 4) | hex_val; 237 p++; 238 } 239 240 return p - ptr; 241} 242 243/* Obtain a backtrace and print it to stdout. */ 244#ifdef HAVE_BACKTRACE_SUPPORT 245void dump_stack(void) 246{ 247 void *array[16]; 248 size_t size = backtrace(array, ARRAY_SIZE(array)); 249 char **strings = backtrace_symbols(array, size); 250 size_t i; 251 252 printf("Obtained %zd stack frames.\n", size); 253 254 for (i = 0; i < size; i++) 255 printf("%s\n", strings[i]); 256 257 free(strings); 258} 259#else 260void dump_stack(void) {} 261#endif 262 263void get_term_dimensions(struct winsize *ws) 264{ 265 char *s = getenv("LINES"); 266 267 if (s != NULL) { 268 ws->ws_row = atoi(s); 269 s = getenv("COLUMNS"); 270 if (s != NULL) { 271 ws->ws_col = atoi(s); 272 if (ws->ws_row && ws->ws_col) 273 return; 274 } 275 } 276#ifdef TIOCGWINSZ 277 if (ioctl(1, TIOCGWINSZ, ws) == 0 && 278 ws->ws_row && ws->ws_col) 279 return; 280#endif 281 ws->ws_row = 25; 282 ws->ws_col = 80; 283} 284 285static void set_tracing_events_path(const char *mountpoint) 286{ 287 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", 288 mountpoint, "tracing/events"); 289} 290 291const char *perf_debugfs_mount(const char *mountpoint) 292{ 293 const char *mnt; 294 295 mnt = debugfs_mount(mountpoint); 296 if (!mnt) 297 return NULL; 298 299 set_tracing_events_path(mnt); 300 301 return mnt; 302} 303 304void perf_debugfs_set_path(const char *mntpt) 305{ 306 snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt); 307 set_tracing_events_path(mntpt); 308} 309 310static const char *find_debugfs(void) 311{ 312 const char *path = perf_debugfs_mount(NULL); 313 314 if (!path) 315 fprintf(stderr, "Your kernel does not support the debugfs filesystem"); 316 317 return path; 318} 319 320/* 321 * Finds the path to the debugfs/tracing 322 * Allocates the string and stores it. 323 */ 324const char *find_tracing_dir(void) 325{ 326 static char *tracing; 327 static int tracing_found; 328 const char *debugfs; 329 330 if (tracing_found) 331 return tracing; 332 333 debugfs = find_debugfs(); 334 if (!debugfs) 335 return NULL; 336 337 if (asprintf(&tracing, "%s/tracing", debugfs) < 0) 338 return NULL; 339 340 tracing_found = 1; 341 return tracing; 342} 343 344char *get_tracing_file(const char *name) 345{ 346 const char *tracing; 347 char *file; 348 349 tracing = find_tracing_dir(); 350 if (!tracing) 351 return NULL; 352 353 if (asprintf(&file, "%s/%s", tracing, name) < 0) 354 return NULL; 355 356 return file; 357} 358 359void put_tracing_file(char *file) 360{ 361 free(file); 362} 363 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} 396 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 413 if (value > ULONG_MAX / i->mult) 414 break; 415 value *= i->mult; 416 return value; 417 } 418 i++; 419 } 420 421 return (unsigned long) -1; 422} 423 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} 440 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} 487 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} 501 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} 518 519void mem_bswap_32(void *src, int byte_size) 520{ 521 u32 *m = src; 522 while (byte_size > 0) { 523 *m = bswap_32(*m); 524 byte_size -= sizeof(u32); 525 ++m; 526 } 527} 528 529void mem_bswap_64(void *src, int byte_size) 530{ 531 u64 *m = src; 532 533 while (byte_size > 0) { 534 *m = bswap_64(*m); 535 byte_size -= sizeof(u64); 536 ++m; 537 } 538}