aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/annotate.c
diff options
context:
space:
mode:
authorAndi Kleen <ak@linux.intel.com>2015-07-18 11:24:48 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-08-06 15:32:45 -0400
commitd4957633bf9dab70e566e7dbb2b8d0c61c3a2f1e (patch)
tree2dcf2a678a146eb1dc533921521d73ecd91f8b29 /tools/perf/util/annotate.c
parent98df858ed46ddaaf9be3573eb2b63b57a68c6af7 (diff)
perf report: Add infrastructure for a cycles histogram
This adds the basic infrastructure to keep track of cycle counts per basic block for annotate. We allocate an array similar to the normal accounting, and then account branch cycles there. We handle two cases: cycles per basic block with start and cycles per branch (these are later used for either IPC or just cycles per BB) In the start case we cannot handle overlaps, so always the longest basic block wins. For the cycles per branch case everything is accurately accounted. v2: Remove unnecessary checks. Slight restructure. Move symbol__get_annotation to another patch. Move histogram allocation. v3: Merged with current tree Signed-off-by: Andi Kleen <ak@linux.intel.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Link: http://lkml.kernel.org/r/1437233094-12844-4-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r--tools/perf/util/annotate.c127
1 files changed, 124 insertions, 3 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 03b7bc70eb66..e0b614648044 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -473,17 +473,73 @@ int symbol__alloc_hist(struct symbol *sym)
473 return 0; 473 return 0;
474} 474}
475 475
476/* The cycles histogram is lazily allocated. */
477static int symbol__alloc_hist_cycles(struct symbol *sym)
478{
479 struct annotation *notes = symbol__annotation(sym);
480 const size_t size = symbol__size(sym);
481
482 notes->src->cycles_hist = calloc(size, sizeof(struct cyc_hist));
483 if (notes->src->cycles_hist == NULL)
484 return -1;
485 return 0;
486}
487
476void symbol__annotate_zero_histograms(struct symbol *sym) 488void symbol__annotate_zero_histograms(struct symbol *sym)
477{ 489{
478 struct annotation *notes = symbol__annotation(sym); 490 struct annotation *notes = symbol__annotation(sym);
479 491
480 pthread_mutex_lock(&notes->lock); 492 pthread_mutex_lock(&notes->lock);
481 if (notes->src != NULL) 493 if (notes->src != NULL) {
482 memset(notes->src->histograms, 0, 494 memset(notes->src->histograms, 0,
483 notes->src->nr_histograms * notes->src->sizeof_sym_hist); 495 notes->src->nr_histograms * notes->src->sizeof_sym_hist);
496 if (notes->src->cycles_hist)
497 memset(notes->src->cycles_hist, 0,
498 symbol__size(sym) * sizeof(struct cyc_hist));
499 }
484 pthread_mutex_unlock(&notes->lock); 500 pthread_mutex_unlock(&notes->lock);
485} 501}
486 502
503static int __symbol__account_cycles(struct annotation *notes,
504 u64 start,
505 unsigned offset, unsigned cycles,
506 unsigned have_start)
507{
508 struct cyc_hist *ch;
509
510 ch = notes->src->cycles_hist;
511 /*
512 * For now we can only account one basic block per
513 * final jump. But multiple could be overlapping.
514 * Always account the longest one. So when
515 * a shorter one has been already seen throw it away.
516 *
517 * We separately always account the full cycles.
518 */
519 ch[offset].num_aggr++;
520 ch[offset].cycles_aggr += cycles;
521
522 if (!have_start && ch[offset].have_start)
523 return 0;
524 if (ch[offset].num) {
525 if (have_start && (!ch[offset].have_start ||
526 ch[offset].start > start)) {
527 ch[offset].have_start = 0;
528 ch[offset].cycles = 0;
529 ch[offset].num = 0;
530 if (ch[offset].reset < 0xffff)
531 ch[offset].reset++;
532 } else if (have_start &&
533 ch[offset].start < start)
534 return 0;
535 }
536 ch[offset].have_start = have_start;
537 ch[offset].start = start;
538 ch[offset].cycles += cycles;
539 ch[offset].num++;
540 return 0;
541}
542
487static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, 543static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
488 struct annotation *notes, int evidx, u64 addr) 544 struct annotation *notes, int evidx, u64 addr)
489{ 545{
@@ -506,7 +562,7 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
506 return 0; 562 return 0;
507} 563}
508 564
509static struct annotation *symbol__get_annotation(struct symbol *sym) 565static struct annotation *symbol__get_annotation(struct symbol *sym, bool cycles)
510{ 566{
511 struct annotation *notes = symbol__annotation(sym); 567 struct annotation *notes = symbol__annotation(sym);
512 568
@@ -514,6 +570,10 @@ static struct annotation *symbol__get_annotation(struct symbol *sym)
514 if (symbol__alloc_hist(sym) < 0) 570 if (symbol__alloc_hist(sym) < 0)
515 return NULL; 571 return NULL;
516 } 572 }
573 if (!notes->src->cycles_hist && cycles) {
574 if (symbol__alloc_hist_cycles(sym) < 0)
575 return NULL;
576 }
517 return notes; 577 return notes;
518} 578}
519 579
@@ -524,12 +584,73 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
524 584
525 if (sym == NULL) 585 if (sym == NULL)
526 return 0; 586 return 0;
527 notes = symbol__get_annotation(sym); 587 notes = symbol__get_annotation(sym, false);
528 if (notes == NULL) 588 if (notes == NULL)
529 return -ENOMEM; 589 return -ENOMEM;
530 return __symbol__inc_addr_samples(sym, map, notes, evidx, addr); 590 return __symbol__inc_addr_samples(sym, map, notes, evidx, addr);
531} 591}
532 592
593static int symbol__account_cycles(u64 addr, u64 start,
594 struct symbol *sym, unsigned cycles)
595{
596 struct annotation *notes;
597 unsigned offset;
598
599 if (sym == NULL)
600 return 0;
601 notes = symbol__get_annotation(sym, true);
602 if (notes == NULL)
603 return -ENOMEM;
604 if (addr < sym->start || addr >= sym->end)
605 return -ERANGE;
606
607 if (start) {
608 if (start < sym->start || start >= sym->end)
609 return -ERANGE;
610 if (start >= addr)
611 start = 0;
612 }
613 offset = addr - sym->start;
614 return __symbol__account_cycles(notes,
615 start ? start - sym->start : 0,
616 offset, cycles,
617 !!start);
618}
619
620int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
621 struct addr_map_symbol *start,
622 unsigned cycles)
623{
624 unsigned long saddr = 0;
625 int err;
626
627 if (!cycles)
628 return 0;
629
630 /*
631 * Only set start when IPC can be computed. We can only
632 * compute it when the basic block is completely in a single
633 * function.
634 * Special case the case when the jump is elsewhere, but
635 * it starts on the function start.
636 */
637 if (start &&
638 (start->sym == ams->sym ||
639 (ams->sym &&
640 start->addr == ams->sym->start + ams->map->start)))
641 saddr = start->al_addr;
642 if (saddr == 0)
643 pr_debug2("BB with bad start: addr %lx start %lx sym %lx saddr %lx\n",
644 ams->addr,
645 start ? start->addr : 0,
646 ams->sym ? ams->sym->start + ams->map->start : 0,
647 saddr);
648 err = symbol__account_cycles(ams->al_addr, saddr, ams->sym, cycles);
649 if (err)
650 pr_debug2("account_cycles failed %d\n", err);
651 return err;
652}
653
533int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx) 654int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx)
534{ 655{
535 return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr); 656 return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr);