diff options
Diffstat (limited to 'tools/perf/util/sort.c')
-rw-r--r-- | tools/perf/util/sort.c | 369 |
1 files changed, 363 insertions, 6 deletions
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index d66bcd33248c..32a1ef15912c 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -198,11 +198,19 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, | |||
198 | } | 198 | } |
199 | 199 | ||
200 | ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); | 200 | ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); |
201 | if (sym) | 201 | if (sym && map) { |
202 | ret += repsep_snprintf(bf + ret, size - ret, "%-*s", | 202 | if (map->type == MAP__VARIABLE) { |
203 | width - ret, | 203 | ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); |
204 | sym->name); | 204 | ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", |
205 | else { | 205 | ip - sym->start); |
206 | ret += repsep_snprintf(bf + ret, size - ret, "%-*s", | ||
207 | width - ret, ""); | ||
208 | } else { | ||
209 | ret += repsep_snprintf(bf + ret, size - ret, "%-*s", | ||
210 | width - ret, | ||
211 | sym->name); | ||
212 | } | ||
213 | } else { | ||
206 | size_t len = BITS_PER_LONG / 4; | 214 | size_t len = BITS_PER_LONG / 4; |
207 | ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", | 215 | ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", |
208 | len, ip); | 216 | len, ip); |
@@ -457,6 +465,304 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf, | |||
457 | return repsep_snprintf(bf, size, "%-*s", width, out); | 465 | return repsep_snprintf(bf, size, "%-*s", width, out); |
458 | } | 466 | } |
459 | 467 | ||
468 | /* --sort daddr_sym */ | ||
469 | static int64_t | ||
470 | sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right) | ||
471 | { | ||
472 | uint64_t l = 0, r = 0; | ||
473 | |||
474 | if (left->mem_info) | ||
475 | l = left->mem_info->daddr.addr; | ||
476 | if (right->mem_info) | ||
477 | r = right->mem_info->daddr.addr; | ||
478 | |||
479 | return (int64_t)(r - l); | ||
480 | } | ||
481 | |||
482 | static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf, | ||
483 | size_t size, unsigned int width) | ||
484 | { | ||
485 | uint64_t addr = 0; | ||
486 | struct map *map = NULL; | ||
487 | struct symbol *sym = NULL; | ||
488 | |||
489 | if (self->mem_info) { | ||
490 | addr = self->mem_info->daddr.addr; | ||
491 | map = self->mem_info->daddr.map; | ||
492 | sym = self->mem_info->daddr.sym; | ||
493 | } | ||
494 | return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size, | ||
495 | width); | ||
496 | } | ||
497 | |||
498 | static int64_t | ||
499 | sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right) | ||
500 | { | ||
501 | struct map *map_l = NULL; | ||
502 | struct map *map_r = NULL; | ||
503 | |||
504 | if (left->mem_info) | ||
505 | map_l = left->mem_info->daddr.map; | ||
506 | if (right->mem_info) | ||
507 | map_r = right->mem_info->daddr.map; | ||
508 | |||
509 | return _sort__dso_cmp(map_l, map_r); | ||
510 | } | ||
511 | |||
512 | static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf, | ||
513 | size_t size, unsigned int width) | ||
514 | { | ||
515 | struct map *map = NULL; | ||
516 | |||
517 | if (self->mem_info) | ||
518 | map = self->mem_info->daddr.map; | ||
519 | |||
520 | return _hist_entry__dso_snprintf(map, bf, size, width); | ||
521 | } | ||
522 | |||
523 | static int64_t | ||
524 | sort__locked_cmp(struct hist_entry *left, struct hist_entry *right) | ||
525 | { | ||
526 | union perf_mem_data_src data_src_l; | ||
527 | union perf_mem_data_src data_src_r; | ||
528 | |||
529 | if (left->mem_info) | ||
530 | data_src_l = left->mem_info->data_src; | ||
531 | else | ||
532 | data_src_l.mem_lock = PERF_MEM_LOCK_NA; | ||
533 | |||
534 | if (right->mem_info) | ||
535 | data_src_r = right->mem_info->data_src; | ||
536 | else | ||
537 | data_src_r.mem_lock = PERF_MEM_LOCK_NA; | ||
538 | |||
539 | return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock); | ||
540 | } | ||
541 | |||
542 | static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf, | ||
543 | size_t size, unsigned int width) | ||
544 | { | ||
545 | const char *out; | ||
546 | u64 mask = PERF_MEM_LOCK_NA; | ||
547 | |||
548 | if (self->mem_info) | ||
549 | mask = self->mem_info->data_src.mem_lock; | ||
550 | |||
551 | if (mask & PERF_MEM_LOCK_NA) | ||
552 | out = "N/A"; | ||
553 | else if (mask & PERF_MEM_LOCK_LOCKED) | ||
554 | out = "Yes"; | ||
555 | else | ||
556 | out = "No"; | ||
557 | |||
558 | return repsep_snprintf(bf, size, "%-*s", width, out); | ||
559 | } | ||
560 | |||
561 | static int64_t | ||
562 | sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right) | ||
563 | { | ||
564 | union perf_mem_data_src data_src_l; | ||
565 | union perf_mem_data_src data_src_r; | ||
566 | |||
567 | if (left->mem_info) | ||
568 | data_src_l = left->mem_info->data_src; | ||
569 | else | ||
570 | data_src_l.mem_dtlb = PERF_MEM_TLB_NA; | ||
571 | |||
572 | if (right->mem_info) | ||
573 | data_src_r = right->mem_info->data_src; | ||
574 | else | ||
575 | data_src_r.mem_dtlb = PERF_MEM_TLB_NA; | ||
576 | |||
577 | return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb); | ||
578 | } | ||
579 | |||
580 | static const char * const tlb_access[] = { | ||
581 | "N/A", | ||
582 | "HIT", | ||
583 | "MISS", | ||
584 | "L1", | ||
585 | "L2", | ||
586 | "Walker", | ||
587 | "Fault", | ||
588 | }; | ||
589 | #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *)) | ||
590 | |||
591 | static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf, | ||
592 | size_t size, unsigned int width) | ||
593 | { | ||
594 | char out[64]; | ||
595 | size_t sz = sizeof(out) - 1; /* -1 for null termination */ | ||
596 | size_t l = 0, i; | ||
597 | u64 m = PERF_MEM_TLB_NA; | ||
598 | u64 hit, miss; | ||
599 | |||
600 | out[0] = '\0'; | ||
601 | |||
602 | if (self->mem_info) | ||
603 | m = self->mem_info->data_src.mem_dtlb; | ||
604 | |||
605 | hit = m & PERF_MEM_TLB_HIT; | ||
606 | miss = m & PERF_MEM_TLB_MISS; | ||
607 | |||
608 | /* already taken care of */ | ||
609 | m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS); | ||
610 | |||
611 | for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) { | ||
612 | if (!(m & 0x1)) | ||
613 | continue; | ||
614 | if (l) { | ||
615 | strcat(out, " or "); | ||
616 | l += 4; | ||
617 | } | ||
618 | strncat(out, tlb_access[i], sz - l); | ||
619 | l += strlen(tlb_access[i]); | ||
620 | } | ||
621 | if (*out == '\0') | ||
622 | strcpy(out, "N/A"); | ||
623 | if (hit) | ||
624 | strncat(out, " hit", sz - l); | ||
625 | if (miss) | ||
626 | strncat(out, " miss", sz - l); | ||
627 | |||
628 | return repsep_snprintf(bf, size, "%-*s", width, out); | ||
629 | } | ||
630 | |||
631 | static int64_t | ||
632 | sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right) | ||
633 | { | ||
634 | union perf_mem_data_src data_src_l; | ||
635 | union perf_mem_data_src data_src_r; | ||
636 | |||
637 | if (left->mem_info) | ||
638 | data_src_l = left->mem_info->data_src; | ||
639 | else | ||
640 | data_src_l.mem_lvl = PERF_MEM_LVL_NA; | ||
641 | |||
642 | if (right->mem_info) | ||
643 | data_src_r = right->mem_info->data_src; | ||
644 | else | ||
645 | data_src_r.mem_lvl = PERF_MEM_LVL_NA; | ||
646 | |||
647 | return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl); | ||
648 | } | ||
649 | |||
650 | static const char * const mem_lvl[] = { | ||
651 | "N/A", | ||
652 | "HIT", | ||
653 | "MISS", | ||
654 | "L1", | ||
655 | "LFB", | ||
656 | "L2", | ||
657 | "L3", | ||
658 | "Local RAM", | ||
659 | "Remote RAM (1 hop)", | ||
660 | "Remote RAM (2 hops)", | ||
661 | "Remote Cache (1 hop)", | ||
662 | "Remote Cache (2 hops)", | ||
663 | "I/O", | ||
664 | "Uncached", | ||
665 | }; | ||
666 | #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *)) | ||
667 | |||
668 | static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf, | ||
669 | size_t size, unsigned int width) | ||
670 | { | ||
671 | char out[64]; | ||
672 | size_t sz = sizeof(out) - 1; /* -1 for null termination */ | ||
673 | size_t i, l = 0; | ||
674 | u64 m = PERF_MEM_LVL_NA; | ||
675 | u64 hit, miss; | ||
676 | |||
677 | if (self->mem_info) | ||
678 | m = self->mem_info->data_src.mem_lvl; | ||
679 | |||
680 | out[0] = '\0'; | ||
681 | |||
682 | hit = m & PERF_MEM_LVL_HIT; | ||
683 | miss = m & PERF_MEM_LVL_MISS; | ||
684 | |||
685 | /* already taken care of */ | ||
686 | m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS); | ||
687 | |||
688 | for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) { | ||
689 | if (!(m & 0x1)) | ||
690 | continue; | ||
691 | if (l) { | ||
692 | strcat(out, " or "); | ||
693 | l += 4; | ||
694 | } | ||
695 | strncat(out, mem_lvl[i], sz - l); | ||
696 | l += strlen(mem_lvl[i]); | ||
697 | } | ||
698 | if (*out == '\0') | ||
699 | strcpy(out, "N/A"); | ||
700 | if (hit) | ||
701 | strncat(out, " hit", sz - l); | ||
702 | if (miss) | ||
703 | strncat(out, " miss", sz - l); | ||
704 | |||
705 | return repsep_snprintf(bf, size, "%-*s", width, out); | ||
706 | } | ||
707 | |||
708 | static int64_t | ||
709 | sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right) | ||
710 | { | ||
711 | union perf_mem_data_src data_src_l; | ||
712 | union perf_mem_data_src data_src_r; | ||
713 | |||
714 | if (left->mem_info) | ||
715 | data_src_l = left->mem_info->data_src; | ||
716 | else | ||
717 | data_src_l.mem_snoop = PERF_MEM_SNOOP_NA; | ||
718 | |||
719 | if (right->mem_info) | ||
720 | data_src_r = right->mem_info->data_src; | ||
721 | else | ||
722 | data_src_r.mem_snoop = PERF_MEM_SNOOP_NA; | ||
723 | |||
724 | return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop); | ||
725 | } | ||
726 | |||
727 | static const char * const snoop_access[] = { | ||
728 | "N/A", | ||
729 | "None", | ||
730 | "Miss", | ||
731 | "Hit", | ||
732 | "HitM", | ||
733 | }; | ||
734 | #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *)) | ||
735 | |||
736 | static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf, | ||
737 | size_t size, unsigned int width) | ||
738 | { | ||
739 | char out[64]; | ||
740 | size_t sz = sizeof(out) - 1; /* -1 for null termination */ | ||
741 | size_t i, l = 0; | ||
742 | u64 m = PERF_MEM_SNOOP_NA; | ||
743 | |||
744 | out[0] = '\0'; | ||
745 | |||
746 | if (self->mem_info) | ||
747 | m = self->mem_info->data_src.mem_snoop; | ||
748 | |||
749 | for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) { | ||
750 | if (!(m & 0x1)) | ||
751 | continue; | ||
752 | if (l) { | ||
753 | strcat(out, " or "); | ||
754 | l += 4; | ||
755 | } | ||
756 | strncat(out, snoop_access[i], sz - l); | ||
757 | l += strlen(snoop_access[i]); | ||
758 | } | ||
759 | |||
760 | if (*out == '\0') | ||
761 | strcpy(out, "N/A"); | ||
762 | |||
763 | return repsep_snprintf(bf, size, "%-*s", width, out); | ||
764 | } | ||
765 | |||
460 | struct sort_entry sort_mispredict = { | 766 | struct sort_entry sort_mispredict = { |
461 | .se_header = "Branch Mispredicted", | 767 | .se_header = "Branch Mispredicted", |
462 | .se_cmp = sort__mispredict_cmp, | 768 | .se_cmp = sort__mispredict_cmp, |
@@ -507,6 +813,48 @@ struct sort_entry sort_global_weight = { | |||
507 | .se_width_idx = HISTC_GLOBAL_WEIGHT, | 813 | .se_width_idx = HISTC_GLOBAL_WEIGHT, |
508 | }; | 814 | }; |
509 | 815 | ||
816 | struct sort_entry sort_mem_daddr_sym = { | ||
817 | .se_header = "Data Symbol", | ||
818 | .se_cmp = sort__daddr_cmp, | ||
819 | .se_snprintf = hist_entry__daddr_snprintf, | ||
820 | .se_width_idx = HISTC_MEM_DADDR_SYMBOL, | ||
821 | }; | ||
822 | |||
823 | struct sort_entry sort_mem_daddr_dso = { | ||
824 | .se_header = "Data Object", | ||
825 | .se_cmp = sort__dso_daddr_cmp, | ||
826 | .se_snprintf = hist_entry__dso_daddr_snprintf, | ||
827 | .se_width_idx = HISTC_MEM_DADDR_SYMBOL, | ||
828 | }; | ||
829 | |||
830 | struct sort_entry sort_mem_locked = { | ||
831 | .se_header = "Locked", | ||
832 | .se_cmp = sort__locked_cmp, | ||
833 | .se_snprintf = hist_entry__locked_snprintf, | ||
834 | .se_width_idx = HISTC_MEM_LOCKED, | ||
835 | }; | ||
836 | |||
837 | struct sort_entry sort_mem_tlb = { | ||
838 | .se_header = "TLB access", | ||
839 | .se_cmp = sort__tlb_cmp, | ||
840 | .se_snprintf = hist_entry__tlb_snprintf, | ||
841 | .se_width_idx = HISTC_MEM_TLB, | ||
842 | }; | ||
843 | |||
844 | struct sort_entry sort_mem_lvl = { | ||
845 | .se_header = "Memory access", | ||
846 | .se_cmp = sort__lvl_cmp, | ||
847 | .se_snprintf = hist_entry__lvl_snprintf, | ||
848 | .se_width_idx = HISTC_MEM_LVL, | ||
849 | }; | ||
850 | |||
851 | struct sort_entry sort_mem_snoop = { | ||
852 | .se_header = "Snoop", | ||
853 | .se_cmp = sort__snoop_cmp, | ||
854 | .se_snprintf = hist_entry__snoop_snprintf, | ||
855 | .se_width_idx = HISTC_MEM_SNOOP, | ||
856 | }; | ||
857 | |||
510 | struct sort_dimension { | 858 | struct sort_dimension { |
511 | const char *name; | 859 | const char *name; |
512 | struct sort_entry *entry; | 860 | struct sort_entry *entry; |
@@ -525,6 +873,12 @@ static struct sort_dimension common_sort_dimensions[] = { | |||
525 | DIM(SORT_SRCLINE, "srcline", sort_srcline), | 873 | DIM(SORT_SRCLINE, "srcline", sort_srcline), |
526 | DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), | 874 | DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), |
527 | DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), | 875 | DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), |
876 | DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym), | ||
877 | DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso), | ||
878 | DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked), | ||
879 | DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), | ||
880 | DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), | ||
881 | DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), | ||
528 | }; | 882 | }; |
529 | 883 | ||
530 | #undef DIM | 884 | #undef DIM |
@@ -561,7 +915,10 @@ int sort_dimension__add(const char *tok) | |||
561 | return -EINVAL; | 915 | return -EINVAL; |
562 | } | 916 | } |
563 | sort__has_parent = 1; | 917 | sort__has_parent = 1; |
564 | } else if (sd->entry == &sort_sym) { | 918 | } else if (sd->entry == &sort_sym || |
919 | sd->entry == &sort_sym_from || | ||
920 | sd->entry == &sort_sym_to || | ||
921 | sd->entry == &sort_mem_daddr_sym) { | ||
565 | sort__has_sym = 1; | 922 | sort__has_sym = 1; |
566 | } | 923 | } |
567 | 924 | ||