diff options
Diffstat (limited to 'Documentation/perf_counter')
-rw-r--r-- | Documentation/perf_counter/builtin-report.c | 178 |
1 files changed, 75 insertions, 103 deletions
diff --git a/Documentation/perf_counter/builtin-report.c b/Documentation/perf_counter/builtin-report.c index f63057fe2cd2..e857201e1e0f 100644 --- a/Documentation/perf_counter/builtin-report.c +++ b/Documentation/perf_counter/builtin-report.c | |||
@@ -479,23 +479,25 @@ static size_t map__fprintf(struct map *self, FILE *fp) | |||
479 | } | 479 | } |
480 | 480 | ||
481 | struct symhist { | 481 | struct symhist { |
482 | struct list_head node; | 482 | struct rb_node rb_node; |
483 | struct dso *dso; | 483 | struct dso *dso; |
484 | struct symbol *sym; | 484 | struct symbol *sym; |
485 | uint64_t ip; | ||
485 | uint32_t count; | 486 | uint32_t count; |
486 | char level; | 487 | char level; |
487 | }; | 488 | }; |
488 | 489 | ||
489 | static struct symhist *symhist__new(struct symbol *sym, struct dso *dso, | 490 | static struct symhist *symhist__new(struct symbol *sym, uint64_t ip, |
490 | char level) | 491 | struct dso *dso, char level) |
491 | { | 492 | { |
492 | struct symhist *self = malloc(sizeof(*self)); | 493 | struct symhist *self = malloc(sizeof(*self)); |
493 | 494 | ||
494 | if (self != NULL) { | 495 | if (self != NULL) { |
495 | self->sym = sym; | 496 | self->sym = sym; |
497 | self->ip = ip; | ||
496 | self->dso = dso; | 498 | self->dso = dso; |
497 | self->level = level; | 499 | self->level = level; |
498 | self->count = 0; | 500 | self->count = 1; |
499 | } | 501 | } |
500 | 502 | ||
501 | return self; | 503 | return self; |
@@ -506,12 +508,6 @@ static void symhist__delete(struct symhist *self) | |||
506 | free(self); | 508 | free(self); |
507 | } | 509 | } |
508 | 510 | ||
509 | static bool symhist__equal(struct symhist *self, struct symbol *sym, | ||
510 | struct dso *dso, char level) | ||
511 | { | ||
512 | return self->level == level && self->sym == sym && self->dso == dso; | ||
513 | } | ||
514 | |||
515 | static void symhist__inc(struct symhist *self) | 511 | static void symhist__inc(struct symhist *self) |
516 | { | 512 | { |
517 | ++self->count; | 513 | ++self->count; |
@@ -519,7 +515,7 @@ static void symhist__inc(struct symhist *self) | |||
519 | 515 | ||
520 | static size_t symhist__fprintf(struct symhist *self, FILE *fp) | 516 | static size_t symhist__fprintf(struct symhist *self, FILE *fp) |
521 | { | 517 | { |
522 | size_t ret = fprintf(fp, "[%c] ", self->level); | 518 | size_t ret = fprintf(fp, "%#llx [%c] ", (unsigned long long)self->ip, self->level); |
523 | 519 | ||
524 | if (self->level != '.') | 520 | if (self->level != '.') |
525 | ret += fprintf(fp, "%s", self->sym->name); | 521 | ret += fprintf(fp, "%s", self->sym->name); |
@@ -531,9 +527,9 @@ static size_t symhist__fprintf(struct symhist *self, FILE *fp) | |||
531 | } | 527 | } |
532 | 528 | ||
533 | struct thread { | 529 | struct thread { |
534 | struct list_head node; | 530 | struct rb_node rb_node; |
535 | struct list_head maps; | 531 | struct list_head maps; |
536 | struct list_head symhists; | 532 | struct rb_root symhists; |
537 | pid_t pid; | 533 | pid_t pid; |
538 | char *comm; | 534 | char *comm; |
539 | }; | 535 | }; |
@@ -546,47 +542,43 @@ static struct thread *thread__new(pid_t pid) | |||
546 | self->pid = pid; | 542 | self->pid = pid; |
547 | self->comm = NULL; | 543 | self->comm = NULL; |
548 | INIT_LIST_HEAD(&self->maps); | 544 | INIT_LIST_HEAD(&self->maps); |
549 | INIT_LIST_HEAD(&self->symhists); | 545 | self->symhists = RB_ROOT; |
550 | } | 546 | } |
551 | 547 | ||
552 | return self; | 548 | return self; |
553 | } | 549 | } |
554 | 550 | ||
555 | static void thread__insert_symhist(struct thread *self, | 551 | static int thread__symbol_incnew(struct thread *self, struct symbol *sym, |
556 | struct symhist *symhist) | 552 | uint64_t ip, struct dso *dso, char level) |
557 | { | ||
558 | list_add_tail(&symhist->node, &self->symhists); | ||
559 | } | ||
560 | |||
561 | static struct symhist *thread__symhists_find(struct thread *self, | ||
562 | struct symbol *sym, | ||
563 | struct dso *dso, char level) | ||
564 | { | 553 | { |
565 | struct symhist *pos; | 554 | struct rb_node **p = &self->symhists.rb_node; |
555 | struct rb_node *parent = NULL; | ||
556 | struct symhist *sh; | ||
566 | 557 | ||
567 | list_for_each_entry(pos, &self->symhists, node) | 558 | while (*p != NULL) { |
568 | if (symhist__equal(pos, sym, dso, level)) | 559 | parent = *p; |
569 | return pos; | 560 | sh = rb_entry(parent, struct symhist, rb_node); |
570 | 561 | ||
571 | return NULL; | 562 | if (sh->sym == sym || ip == sh->ip) { |
572 | } | 563 | symhist__inc(sh); |
564 | return 0; | ||
565 | } | ||
573 | 566 | ||
574 | static int thread__symbol_incnew(struct thread *self, struct symbol *sym, | 567 | /* Handle unresolved symbols too */ |
575 | struct dso *dso, char level) | 568 | const uint64_t start = !sh->sym ? sh->ip : sh->sym->start; |
576 | { | ||
577 | struct symhist *symhist = thread__symhists_find(self, sym, dso, level); | ||
578 | 569 | ||
579 | if (symhist == NULL) { | 570 | if (ip < start) |
580 | symhist = symhist__new(sym, dso, level); | 571 | p = &(*p)->rb_left; |
581 | if (symhist == NULL) | 572 | else |
582 | goto out_error; | 573 | p = &(*p)->rb_right; |
583 | thread__insert_symhist(self, symhist); | ||
584 | } | 574 | } |
585 | 575 | ||
586 | symhist__inc(symhist); | 576 | sh = symhist__new(sym, ip, dso, level); |
577 | if (sh == NULL) | ||
578 | return -ENOMEM; | ||
579 | rb_link_node(&sh->rb_node, parent, p); | ||
580 | rb_insert_color(&sh->rb_node, &self->symhists); | ||
587 | return 0; | 581 | return 0; |
588 | out_error: | ||
589 | return -ENOMEM; | ||
590 | } | 582 | } |
591 | 583 | ||
592 | static int thread__set_comm(struct thread *self, const char *comm) | 584 | static int thread__set_comm(struct thread *self, const char *comm) |
@@ -608,43 +600,44 @@ static size_t thread__maps_fprintf(struct thread *self, FILE *fp) | |||
608 | 600 | ||
609 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 601 | static size_t thread__fprintf(struct thread *self, FILE *fp) |
610 | { | 602 | { |
611 | struct symhist *pos; | ||
612 | int ret = fprintf(fp, "thread: %d %s\n", self->pid, self->comm); | 603 | int ret = fprintf(fp, "thread: %d %s\n", self->pid, self->comm); |
604 | struct rb_node *nd; | ||
613 | 605 | ||
614 | list_for_each_entry(pos, &self->symhists, node) | 606 | for (nd = rb_first(&self->symhists); nd; nd = rb_next(nd)) { |
607 | struct symhist *pos = rb_entry(nd, struct symhist, rb_node); | ||
615 | ret += symhist__fprintf(pos, fp); | 608 | ret += symhist__fprintf(pos, fp); |
609 | } | ||
616 | 610 | ||
617 | return ret; | 611 | return ret; |
618 | } | 612 | } |
619 | 613 | ||
620 | static LIST_HEAD(threads); | 614 | static struct rb_root threads = RB_ROOT; |
621 | 615 | ||
622 | static void threads__add(struct thread *thread) | 616 | static struct thread *threads__findnew(pid_t pid) |
623 | { | ||
624 | list_add_tail(&thread->node, &threads); | ||
625 | } | ||
626 | |||
627 | static struct thread *threads__find(pid_t pid) | ||
628 | { | 617 | { |
629 | struct thread *pos; | 618 | struct rb_node **p = &threads.rb_node; |
619 | struct rb_node *parent = NULL; | ||
620 | struct thread *th; | ||
630 | 621 | ||
631 | list_for_each_entry(pos, &threads, node) | 622 | while (*p != NULL) { |
632 | if (pos->pid == pid) | 623 | parent = *p; |
633 | return pos; | 624 | th = rb_entry(parent, struct thread, rb_node); |
634 | return NULL; | ||
635 | } | ||
636 | 625 | ||
637 | static struct thread *threads__findnew(pid_t pid) | 626 | if (th->pid == pid) |
638 | { | 627 | return th; |
639 | struct thread *thread = threads__find(pid); | ||
640 | 628 | ||
641 | if (thread == NULL) { | 629 | if (pid < th->pid) |
642 | thread = thread__new(pid); | 630 | p = &(*p)->rb_left; |
643 | if (thread != NULL) | 631 | else |
644 | threads__add(thread); | 632 | p = &(*p)->rb_right; |
645 | } | 633 | } |
646 | 634 | ||
647 | return thread; | 635 | th = thread__new(pid); |
636 | if (th != NULL) { | ||
637 | rb_link_node(&th->rb_node, parent, p); | ||
638 | rb_insert_color(&th->rb_node, &threads); | ||
639 | } | ||
640 | return th; | ||
648 | } | 641 | } |
649 | 642 | ||
650 | static void thread__insert_map(struct thread *self, struct map *map) | 643 | static void thread__insert_map(struct thread *self, struct map *map) |
@@ -668,44 +661,13 @@ static struct map *thread__find_map(struct thread *self, uint64_t ip) | |||
668 | 661 | ||
669 | static void threads__fprintf(FILE *fp) | 662 | static void threads__fprintf(FILE *fp) |
670 | { | 663 | { |
671 | struct thread *pos; | 664 | struct rb_node *nd; |
672 | 665 | for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { | |
673 | list_for_each_entry(pos, &threads, node) | 666 | struct thread *pos = rb_entry(nd, struct thread, rb_node); |
674 | thread__fprintf(pos, fp); | 667 | thread__fprintf(pos, fp); |
668 | } | ||
675 | } | 669 | } |
676 | 670 | ||
677 | #if 0 | ||
678 | static std::string resolve_user_symbol(int pid, uint64_t ip) | ||
679 | { | ||
680 | std::string sym = "<unknown>"; | ||
681 | |||
682 | maps_t &m = maps[pid]; | ||
683 | maps_t::const_iterator mi = m.upper_bound(map(ip)); | ||
684 | if (mi == m.end()) | ||
685 | return sym; | ||
686 | |||
687 | ip -= mi->start + mi->pgoff; | ||
688 | |||
689 | symbols_t &s = dsos[mi->dso].syms; | ||
690 | symbols_t::const_iterator si = s.upper_bound(symbol(ip)); | ||
691 | |||
692 | sym = mi->dso + ": <unknown>"; | ||
693 | |||
694 | if (si == s.begin()) | ||
695 | return sym; | ||
696 | si--; | ||
697 | |||
698 | if (si->start <= ip && ip < si->end) | ||
699 | sym = mi->dso + ": " + si->name; | ||
700 | #if 0 | ||
701 | else if (si->start <= ip) | ||
702 | sym = mi->dso + ": ?" + si->name; | ||
703 | #endif | ||
704 | |||
705 | return sym; | ||
706 | } | ||
707 | #endif | ||
708 | |||
709 | static void display_help(void) | 671 | static void display_help(void) |
710 | { | 672 | { |
711 | printf( | 673 | printf( |
@@ -824,8 +786,11 @@ more: | |||
824 | struct dso *dso = NULL; | 786 | struct dso *dso = NULL; |
825 | struct thread *thread = threads__findnew(event->ip.pid); | 787 | struct thread *thread = threads__findnew(event->ip.pid); |
826 | 788 | ||
827 | if (thread == NULL) | 789 | if (thread == NULL) { |
790 | fprintf(stderr, "problem processing %d event, bailing out\n", | ||
791 | event->header.type); | ||
828 | goto done; | 792 | goto done; |
793 | } | ||
829 | 794 | ||
830 | if (event->header.misc & PERF_EVENT_MISC_KERNEL) { | 795 | if (event->header.misc & PERF_EVENT_MISC_KERNEL) { |
831 | show = SHOW_KERNEL; | 796 | show = SHOW_KERNEL; |
@@ -845,8 +810,11 @@ more: | |||
845 | if (show & show_mask) { | 810 | if (show & show_mask) { |
846 | struct symbol *sym = dso__find_symbol(dso, event->ip.ip); | 811 | struct symbol *sym = dso__find_symbol(dso, event->ip.ip); |
847 | 812 | ||
848 | if (thread__symbol_incnew(thread, sym, dso, level)) | 813 | if (thread__symbol_incnew(thread, sym, event->ip.ip, |
814 | dso, level)) { | ||
815 | fprintf(stderr, "problem incrementing symbol count, bailing out\n"); | ||
849 | goto done; | 816 | goto done; |
817 | } | ||
850 | } | 818 | } |
851 | total++; | 819 | total++; |
852 | } else switch (event->header.type) { | 820 | } else switch (event->header.type) { |
@@ -854,8 +822,10 @@ more: | |||
854 | struct thread *thread = threads__findnew(event->mmap.pid); | 822 | struct thread *thread = threads__findnew(event->mmap.pid); |
855 | struct map *map = map__new(&event->mmap); | 823 | struct map *map = map__new(&event->mmap); |
856 | 824 | ||
857 | if (thread == NULL || map == NULL ) | 825 | if (thread == NULL || map == NULL) { |
826 | fprintf(stderr, "problem processing PERF_EVENT_MMAP, bailing out\n"); | ||
858 | goto done; | 827 | goto done; |
828 | } | ||
859 | thread__insert_map(thread, map); | 829 | thread__insert_map(thread, map); |
860 | break; | 830 | break; |
861 | } | 831 | } |
@@ -863,8 +833,10 @@ more: | |||
863 | struct thread *thread = threads__findnew(event->comm.pid); | 833 | struct thread *thread = threads__findnew(event->comm.pid); |
864 | 834 | ||
865 | if (thread == NULL || | 835 | if (thread == NULL || |
866 | thread__set_comm(thread, event->comm.comm)) | 836 | thread__set_comm(thread, event->comm.comm)) { |
837 | fprintf(stderr, "problem processing PERF_EVENT_COMM, bailing out\n"); | ||
867 | goto done; | 838 | goto done; |
839 | } | ||
868 | break; | 840 | break; |
869 | } | 841 | } |
870 | } | 842 | } |