1 /* 2 * builtin-annotate.c 3 * 4 * Builtin annotate command: Analyze the perf.data input file, 5 * look up and read DSOs and symbol information and display 6 * a histogram of results, along various sorting keys. 7 */ 8 #include "builtin.h" 9 10 #include "util/util.h" 11 12 #include "util/color.h" 13 #include <linux/list.h> 14 #include "util/cache.h" 15 #include <linux/rbtree.h> 16 #include "util/symbol.h" 17 #include "util/string.h" 18 19 #include "perf.h" 20 #include "util/debug.h" 21 22 #include "util/event.h" 23 #include "util/parse-options.h" 24 #include "util/parse-events.h" 25 #include "util/thread.h" 26 #include "util/sort.h" 27 #include "util/hist.h" 28 #include "util/session.h" 29 30 static char const *input_name = "perf.data"; 31 32 static int force; 33 34 static int full_paths; 35 36 static int print_line; 37 38 struct sym_hist { 39 u64 sum; 40 u64 ip[0]; 41 }; 42 43 struct sym_ext { 44 struct rb_node node; 45 double percent; 46 char *path; 47 }; 48 49 struct sym_priv { 50 struct sym_hist *hist; 51 struct sym_ext *ext; 52 }; 53 54 static const char *sym_hist_filter; 55 56 static int sym__alloc_hist(struct symbol *self) 57 { 58 struct sym_priv *priv = symbol__priv(self); 59 const int size = (sizeof(*priv->hist) + 60 (self->end - self->start) * sizeof(u64)); 61 62 priv->hist = zalloc(size); 63 return priv->hist == NULL ? -1 : 0; 64 } 65 66 /* 67 * collect histogram counts 68 */ 69 static int annotate__hist_hit(struct hist_entry *he, u64 ip) 70 { 71 unsigned int sym_size, offset; 72 struct symbol *sym = he->sym; 73 struct sym_priv *priv; 74 struct sym_hist *h; 75 76 he->count++; 77 78 if (!sym || !he->map) 79 return 0; 80 81 priv = symbol__priv(sym); 82 if (priv->hist == NULL && sym__alloc_hist(sym) < 0) 83 return -ENOMEM; 84 85 sym_size = sym->end - sym->start; 86 offset = ip - sym->start; 87 88 pr_debug3("%s: ip=%#Lx\n", __func__, he->map->unmap_ip(he->map, ip)); 89 90 if (offset >= sym_size) 91 return 0; 92 93 h = priv->hist; 94 h->sum++; 95 h->ip[offset]++; 96 97 pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", he->sym->start, 98 he->sym->name, ip, ip - he->sym->start, h->ip[offset]); 99 return 0; 100 } 101 102 static int perf_session__add_hist_entry(struct perf_session *self, 103 struct addr_location *al, u64 count) 104 { 105 bool hit; 106 struct hist_entry *he; 107 108 if (sym_hist_filter != NULL && 109 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { 110 /* We're only interested in a symbol named sym_hist_filter */ 111 if (al->sym != NULL) { 112 rb_erase(&al->sym->rb_node, 113 &al->map->dso->symbols[al->map->type]); 114 symbol__delete(al->sym); 115 } 116 return 0; 117 } 118 119 he = __perf_session__add_hist_entry(self, al, NULL, count, &hit); 120 if (he == NULL) 121 return -ENOMEM; 122 123 return annotate__hist_hit(he, al->addr); 124 } 125 126 static int process_sample_event(event_t *event, struct perf_session *session) 127 { 128 struct addr_location al; 129 130 dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc, 131 event->ip.pid, event->ip.ip); 132 133 if (event__preprocess_sample(event, session, &al, NULL) < 0) { 134 pr_warning("problem processing %d event, skipping it.\n", 135 event->header.type); 136 return -1; 137 } 138 139 if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) { 140 pr_warning("problem incrementing symbol count, " 141 "skipping event\n"); 142 return -1; 143 } 144 145 return 0; 146 } 147 148 struct objdump_line { 149 struct list_head node; 150 s64 offset; 151 char *line; 152 }; 153 154 static struct objdump_line *objdump_line__new(s64 offset, char *line) 155 { 156 struct objdump_line *self = malloc(sizeof(*self)); 157 158 if (self != NULL) { 159 self->offset = offset; 160 self->line = line; 161 } 162 163 return self; 164 } 165 166 static void objdump_line__free(struct objdump_line *self) 167 { 168 free(self->line); 169 free(self); 170 } 171 172 static void objdump__add_line(struct list_head *head, struct objdump_line *line) 173 { 174 list_add_tail(&line->node, head); 175 } 176 177 static struct objdump_line *objdump__get_next_ip_line(struct list_head *head, 178 struct objdump_line *pos) 179 { 180 list_for_each_entry_continue(pos, head, node) 181 if (pos->offset >= 0) 182 return pos; 183 184 return NULL; 185 } 186 187 static int parse_line(FILE *file, struct hist_entry *he, 188 struct list_head *head) 189 { 190 struct symbol *sym = he->sym; 191 struct objdump_line *objdump_line; 192 char *line = NULL, *tmp, *tmp2; 193 size_t line_len; 194 s64 line_ip, offset = -1; 195 char *c; 196 197 if (getline(&line, &line_len, file) < 0) 198 return -1; 199 200 if (!line) 201 return -1; 202 203 c = strchr(line, '\n'); 204 if (c) 205 *c = 0; 206 207 line_ip = -1; 208 209 /* 210 * Strip leading spaces: 211 */ 212 tmp = line; 213 while (*tmp) { 214 if (*tmp != ' ') 215 break; 216 tmp++; 217 } 218 219 if (*tmp) { 220 /* 221 * Parse hexa addresses followed by ':' 222 */ 223 line_ip = strtoull(tmp, &tmp2, 16); 224 if (*tmp2 != ':') 225 line_ip = -1; 226 } 227 228 if (line_ip != -1) { 229 u64 start = map__rip_2objdump(he->map, sym->start); 230 offset = line_ip - start; 231 } 232 233 objdump_line = objdump_line__new(offset, line); 234 if (objdump_line == NULL) { 235 free(line); 236 return -1; 237 } 238 objdump__add_line(head, objdump_line); 239 240 return 0; 241 } 242 243 static int objdump_line__print(struct objdump_line *self, 244 struct list_head *head, 245 struct hist_entry *he, u64 len) 246 { 247 struct symbol *sym = he->sym; 248 static const char *prev_line; 249 static const char *prev_color; 250 251 if (self->offset != -1) { 252 const char *path = NULL; 253 unsigned int hits = 0; 254 double percent = 0.0; 255 const char *color; 256 struct sym_priv *priv = symbol__priv(sym); 257 struct sym_ext *sym_ext = priv->ext; 258 struct sym_hist *h = priv->hist; 259 s64 offset = self->offset; 260 struct objdump_line *next = objdump__get_next_ip_line(head, self); 261 262 while (offset < (s64)len && 263 (next == NULL || offset < next->offset)) { 264 if (sym_ext) { 265 if (path == NULL) 266 path = sym_ext[offset].path; 267 percent += sym_ext[offset].percent; 268 } else 269 hits += h->ip[offset]; 270 271 ++offset; 272 } 273 274 if (sym_ext == NULL && h->sum) 275 percent = 100.0 * hits / h->sum; 276 277 color = get_percent_color(percent); 278 279 /* 280 * Also color the filename and line if needed, with 281 * the same color than the percentage. Don't print it 282 * twice for close colored ip with the same filename:line 283 */ 284 if (path) { 285 if (!prev_line || strcmp(prev_line, path) 286 || color != prev_color) { 287 color_fprintf(stdout, color, " %s", path); 288 prev_line = path; 289 prev_color = color; 290 } 291 } 292 293 color_fprintf(stdout, color, " %7.2f", percent); 294 printf(" : "); 295 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line); 296 } else { 297 if (!*self->line) 298 printf(" :\n"); 299 else 300 printf(" : %s\n", self->line); 301 } 302 303 return 0; 304 } 305 306 static struct rb_root root_sym_ext; 307 308 static void insert_source_line(struct sym_ext *sym_ext) 309 { 310 struct sym_ext *iter; 311 struct rb_node **p = &root_sym_ext.rb_node; 312 struct rb_node *parent = NULL; 313 314 while (*p != NULL) { 315 parent = *p; 316 iter = rb_entry(parent, struct sym_ext, node); 317 318 if (sym_ext->percent > iter->percent) 319 p = &(*p)->rb_left; 320 else 321 p = &(*p)->rb_right; 322 } 323 324 rb_link_node(&sym_ext->node, parent, p); 325 rb_insert_color(&sym_ext->node, &root_sym_ext); 326 } 327 328 static void free_source_line(struct hist_entry *he, int len) 329 { 330 struct sym_priv *priv = symbol__priv(he->sym); 331 struct sym_ext *sym_ext = priv->ext; 332 int i; 333 334 if (!sym_ext) 335 return; 336 337 for (i = 0; i < len; i++) 338 free(sym_ext[i].path); 339 free(sym_ext); 340 341 priv->ext = NULL; 342 root_sym_ext = RB_ROOT; 343 } 344 345 /* Get the filename:line for the colored entries */ 346 static void 347 get_source_line(struct hist_entry *he, int len, const char *filename) 348 { 349 struct symbol *sym = he->sym; 350 u64 start; 351 int i; 352 char cmd[PATH_MAX * 2]; 353 struct sym_ext *sym_ext; 354 struct sym_priv *priv = symbol__priv(sym); 355 struct sym_hist *h = priv->hist; 356 357 if (!h->sum) 358 return; 359 360 sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext)); 361 if (!priv->ext) 362 return; 363 364 start = he->map->unmap_ip(he->map, sym->start); 365 366 for (i = 0; i < len; i++) { 367 char *path = NULL; 368 size_t line_len; 369 u64 offset; 370 FILE *fp; 371 372 sym_ext[i].percent = 100.0 * h->ip[i] / h->sum; 373 if (sym_ext[i].percent <= 0.5) 374 continue; 375 376 offset = start + i; 377 sprintf(cmd, "addr2line -e %s %016llx", filename, offset); 378 fp = popen(cmd, "r"); 379 if (!fp) 380 continue; 381 382 if (getline(&path, &line_len, fp) < 0 || !line_len) 383 goto next; 384 385 sym_ext[i].path = malloc(sizeof(char) * line_len + 1); 386 if (!sym_ext[i].path) 387 goto next; 388 389 strcpy(sym_ext[i].path, path); 390 insert_source_line(&sym_ext[i]); 391 392 next: 393 pclose(fp); 394 } 395 } 396 397 static void print_summary(const char *filename) 398 { 399 struct sym_ext *sym_ext; 400 struct rb_node *node; 401 402 printf("\nSorted summary for file %s\n", filename); 403 printf("----------------------------------------------\n\n"); 404 405 if (RB_EMPTY_ROOT(&root_sym_ext)) { 406 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); 407 return; 408 } 409 410 node = rb_first(&root_sym_ext); 411 while (node) { 412 double percent; 413 const char *color; 414 char *path; 415 416 sym_ext = rb_entry(node, struct sym_ext, node); 417 percent = sym_ext->percent; 418 color = get_percent_color(percent); 419 path = sym_ext->path; 420 421 color_fprintf(stdout, color, " %7.2f %s", percent, path); 422 node = rb_next(node); 423 } 424 } 425 426 static void hist_entry__print_hits(struct hist_entry *self) 427 { 428 struct symbol *sym = self->sym; 429 struct sym_priv *priv = symbol__priv(sym); 430 struct sym_hist *h = priv->hist; 431 u64 len = sym->end - sym->start, offset; 432 433 for (offset = 0; offset < len; ++offset) 434 if (h->ip[offset] != 0) 435 printf("%*Lx: %Lu\n", BITS_PER_LONG / 2, 436 sym->start + offset, h->ip[offset]); 437 printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum); 438 } 439 440 static void annotate_sym(struct hist_entry *he) 441 { 442 struct map *map = he->map; 443 struct dso *dso = map->dso; 444 struct symbol *sym = he->sym; 445 const char *filename = dso->long_name, *d_filename; 446 u64 len; 447 char command[PATH_MAX*2]; 448 FILE *file; 449 LIST_HEAD(head); 450 struct objdump_line *pos, *n; 451 452 if (!filename) 453 return; 454 455 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__, 456 filename, sym->name, map->unmap_ip(map, sym->start), 457 map->unmap_ip(map, sym->end)); 458 459 if (full_paths) 460 d_filename = filename; 461 else 462 d_filename = basename(filename); 463 464 len = sym->end - sym->start; 465 466 if (print_line) { 467 get_source_line(he, len, filename); 468 print_summary(filename); 469 } 470 471 printf("\n\n------------------------------------------------\n"); 472 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 473 printf("------------------------------------------------\n"); 474 475 if (verbose >= 2) 476 printf("annotating [%p] %30s : [%p] %30s\n", 477 dso, dso->long_name, sym, sym->name); 478 479 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", 480 map__rip_2objdump(map, sym->start), 481 map__rip_2objdump(map, sym->end), 482 filename, filename); 483 484 if (verbose >= 3) 485 printf("doing: %s\n", command); 486 487 file = popen(command, "r"); 488 if (!file) 489 return; 490 491 while (!feof(file)) { 492 if (parse_line(file, he, &head) < 0) 493 break; 494 } 495 496 pclose(file); 497 498 if (verbose) 499 hist_entry__print_hits(he); 500 501 list_for_each_entry_safe(pos, n, &head, node) { 502 objdump_line__print(pos, &head, he, len); 503 list_del(&pos->node); 504 objdump_line__free(pos); 505 } 506 507 if (print_line) 508 free_source_line(he, len); 509 } 510 511 static void perf_session__find_annotations(struct perf_session *self) 512 { 513 struct rb_node *nd; 514 515 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { 516 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 517 struct sym_priv *priv; 518 519 if (he->sym == NULL) 520 continue; 521 522 priv = symbol__priv(he->sym); 523 if (priv->hist == NULL) 524 continue; 525 526 annotate_sym(he); 527 /* 528 * Since we have a hist_entry per IP for the same symbol, free 529 * he->sym->hist to signal we already processed this symbol. 530 */ 531 free(priv->hist); 532 priv->hist = NULL; 533 } 534 } 535 536 static struct perf_event_ops event_ops = { 537 .sample = process_sample_event, 538 .mmap = event__process_mmap, 539 .comm = event__process_comm, 540 .fork = event__process_task, 541 }; 542 543 static int __cmd_annotate(void) 544 { 545 int ret; 546 struct perf_session *session; 547 548 session = perf_session__new(input_name, O_RDONLY, force); 549 if (session == NULL) 550 return -ENOMEM; 551 552 ret = perf_session__process_events(session, &event_ops); 553 if (ret) 554 goto out_delete; 555 556 if (dump_trace) { 557 event__print_totals(); 558 goto out_delete; 559 } 560 561 if (verbose > 3) 562 perf_session__fprintf(session, stdout); 563 564 if (verbose > 2) 565 dsos__fprintf(stdout); 566 567 perf_session__collapse_resort(session); 568 perf_session__output_resort(session, session->event_total[0]); 569 perf_session__find_annotations(session); 570 out_delete: 571 perf_session__delete(session); 572 573 return ret; 574 } 575 576 static const char * const annotate_usage[] = { 577 "perf annotate [<options>] <command>", 578 NULL 579 }; 580 581 static const struct option options[] = { 582 OPT_STRING('i', "input", &input_name, "file", 583 "input file name"), 584 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", 585 "symbol to annotate"), 586 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 587 OPT_BOOLEAN('v', "verbose", &verbose, 588 "be more verbose (show symbol address, etc)"), 589 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 590 "dump raw trace in ASCII"), 591 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 592 "file", "vmlinux pathname"), 593 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 594 "load module symbols - WARNING: use only with -k and LIVE kernel"), 595 OPT_BOOLEAN('l', "print-line", &print_line, 596 "print matching source lines (may be slow)"), 597 OPT_BOOLEAN('P', "full-paths", &full_paths, 598 "Don't shorten the displayed pathnames"), 599 OPT_END() 600 }; 601 602 int cmd_annotate(int argc, const char **argv, const char *prefix __used) 603 { 604 argc = parse_options(argc, argv, options, annotate_usage, 0); 605 606 symbol_conf.priv_size = sizeof(struct sym_priv); 607 symbol_conf.try_vmlinux_path = true; 608 609 if (symbol__init() < 0) 610 return -1; 611 612 setup_sorting(annotate_usage, options); 613 614 if (argc) { 615 /* 616 * Special case: if there's an argument left then assume tha 617 * it's a symbol filter: 618 */ 619 if (argc > 1) 620 usage_with_options(annotate_usage, options); 621 622 sym_hist_filter = argv[0]; 623 } 624 625 setup_pager(); 626 627 if (field_sep && *field_sep == '.') { 628 pr_err("'.' is the only non valid --field-separator argument\n"); 629 return -1; 630 } 631 632 return __cmd_annotate(); 633 } 634