diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2013-05-02 11:37:49 -0400 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2013-05-02 11:54:19 -0400 |
commit | c032862fba51a3ca504752d3a25186b324c5ce83 (patch) | |
tree | 955dc2ba4ab3df76ecc2bb780ee84aca04967e8d /tools/perf/util | |
parent | fda76e074c7737fc57855dd17c762e50ed526052 (diff) | |
parent | 8700c95adb033843fc163d112b9d21d4fda78018 (diff) |
Merge commit '8700c95adb03' into timers/nohz
The full dynticks tree needs the latest RCU and sched
upstream updates in order to fix some dependencies.
Merge a common upstream merge point that has these
updates.
Conflicts:
include/linux/perf_event.h
kernel/rcutree.h
kernel/rcutree_plugin.h
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Diffstat (limited to 'tools/perf/util')
35 files changed, 1519 insertions, 805 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index d33fe937e6f1..d102716c43a1 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "symbol.h" | 14 | #include "symbol.h" |
15 | #include "debug.h" | 15 | #include "debug.h" |
16 | #include "annotate.h" | 16 | #include "annotate.h" |
17 | #include "evsel.h" | ||
17 | #include <pthread.h> | 18 | #include <pthread.h> |
18 | #include <linux/bitops.h> | 19 | #include <linux/bitops.h> |
19 | 20 | ||
@@ -602,8 +603,42 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa | |||
602 | return NULL; | 603 | return NULL; |
603 | } | 604 | } |
604 | 605 | ||
606 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | ||
607 | s64 end, const char **path) | ||
608 | { | ||
609 | struct source_line *src_line = notes->src->lines; | ||
610 | double percent = 0.0; | ||
611 | |||
612 | if (src_line) { | ||
613 | size_t sizeof_src_line = sizeof(*src_line) + | ||
614 | sizeof(src_line->p) * (src_line->nr_pcnt - 1); | ||
615 | |||
616 | while (offset < end) { | ||
617 | src_line = (void *)notes->src->lines + | ||
618 | (sizeof_src_line * offset); | ||
619 | |||
620 | if (*path == NULL) | ||
621 | *path = src_line->path; | ||
622 | |||
623 | percent += src_line->p[evidx].percent; | ||
624 | offset++; | ||
625 | } | ||
626 | } else { | ||
627 | struct sym_hist *h = annotation__histogram(notes, evidx); | ||
628 | unsigned int hits = 0; | ||
629 | |||
630 | while (offset < end) | ||
631 | hits += h->addr[offset++]; | ||
632 | |||
633 | if (h->sum) | ||
634 | percent = 100.0 * hits / h->sum; | ||
635 | } | ||
636 | |||
637 | return percent; | ||
638 | } | ||
639 | |||
605 | static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, | 640 | static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, |
606 | int evidx, u64 len, int min_pcnt, int printed, | 641 | struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, |
607 | int max_lines, struct disasm_line *queue) | 642 | int max_lines, struct disasm_line *queue) |
608 | { | 643 | { |
609 | static const char *prev_line; | 644 | static const char *prev_line; |
@@ -611,34 +646,37 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
611 | 646 | ||
612 | if (dl->offset != -1) { | 647 | if (dl->offset != -1) { |
613 | const char *path = NULL; | 648 | const char *path = NULL; |
614 | unsigned int hits = 0; | 649 | double percent, max_percent = 0.0; |
615 | double percent = 0.0; | 650 | double *ppercents = &percent; |
651 | int i, nr_percent = 1; | ||
616 | const char *color; | 652 | const char *color; |
617 | struct annotation *notes = symbol__annotation(sym); | 653 | struct annotation *notes = symbol__annotation(sym); |
618 | struct source_line *src_line = notes->src->lines; | ||
619 | struct sym_hist *h = annotation__histogram(notes, evidx); | ||
620 | s64 offset = dl->offset; | 654 | s64 offset = dl->offset; |
621 | const u64 addr = start + offset; | 655 | const u64 addr = start + offset; |
622 | struct disasm_line *next; | 656 | struct disasm_line *next; |
623 | 657 | ||
624 | next = disasm__get_next_ip_line(¬es->src->source, dl); | 658 | next = disasm__get_next_ip_line(¬es->src->source, dl); |
625 | 659 | ||
626 | while (offset < (s64)len && | 660 | if (perf_evsel__is_group_event(evsel)) { |
627 | (next == NULL || offset < next->offset)) { | 661 | nr_percent = evsel->nr_members; |
628 | if (src_line) { | 662 | ppercents = calloc(nr_percent, sizeof(double)); |
629 | if (path == NULL) | 663 | if (ppercents == NULL) |
630 | path = src_line[offset].path; | 664 | return -1; |
631 | percent += src_line[offset].percent; | ||
632 | } else | ||
633 | hits += h->addr[offset]; | ||
634 | |||
635 | ++offset; | ||
636 | } | 665 | } |
637 | 666 | ||
638 | if (src_line == NULL && h->sum) | 667 | for (i = 0; i < nr_percent; i++) { |
639 | percent = 100.0 * hits / h->sum; | 668 | percent = disasm__calc_percent(notes, |
669 | notes->src->lines ? i : evsel->idx + i, | ||
670 | offset, | ||
671 | next ? next->offset : (s64) len, | ||
672 | &path); | ||
673 | |||
674 | ppercents[i] = percent; | ||
675 | if (percent > max_percent) | ||
676 | max_percent = percent; | ||
677 | } | ||
640 | 678 | ||
641 | if (percent < min_pcnt) | 679 | if (max_percent < min_pcnt) |
642 | return -1; | 680 | return -1; |
643 | 681 | ||
644 | if (max_lines && printed >= max_lines) | 682 | if (max_lines && printed >= max_lines) |
@@ -648,12 +686,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
648 | list_for_each_entry_from(queue, ¬es->src->source, node) { | 686 | list_for_each_entry_from(queue, ¬es->src->source, node) { |
649 | if (queue == dl) | 687 | if (queue == dl) |
650 | break; | 688 | break; |
651 | disasm_line__print(queue, sym, start, evidx, len, | 689 | disasm_line__print(queue, sym, start, evsel, len, |
652 | 0, 0, 1, NULL); | 690 | 0, 0, 1, NULL); |
653 | } | 691 | } |
654 | } | 692 | } |
655 | 693 | ||
656 | color = get_percent_color(percent); | 694 | color = get_percent_color(max_percent); |
657 | 695 | ||
658 | /* | 696 | /* |
659 | * Also color the filename and line if needed, with | 697 | * Also color the filename and line if needed, with |
@@ -669,25 +707,59 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
669 | } | 707 | } |
670 | } | 708 | } |
671 | 709 | ||
672 | color_fprintf(stdout, color, " %7.2f", percent); | 710 | for (i = 0; i < nr_percent; i++) { |
711 | percent = ppercents[i]; | ||
712 | color = get_percent_color(percent); | ||
713 | color_fprintf(stdout, color, " %7.2f", percent); | ||
714 | } | ||
715 | |||
673 | printf(" : "); | 716 | printf(" : "); |
674 | color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); | 717 | color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); |
675 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); | 718 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); |
719 | |||
720 | if (ppercents != &percent) | ||
721 | free(ppercents); | ||
722 | |||
676 | } else if (max_lines && printed >= max_lines) | 723 | } else if (max_lines && printed >= max_lines) |
677 | return 1; | 724 | return 1; |
678 | else { | 725 | else { |
726 | int width = 8; | ||
727 | |||
679 | if (queue) | 728 | if (queue) |
680 | return -1; | 729 | return -1; |
681 | 730 | ||
731 | if (perf_evsel__is_group_event(evsel)) | ||
732 | width *= evsel->nr_members; | ||
733 | |||
682 | if (!*dl->line) | 734 | if (!*dl->line) |
683 | printf(" :\n"); | 735 | printf(" %*s:\n", width, " "); |
684 | else | 736 | else |
685 | printf(" : %s\n", dl->line); | 737 | printf(" %*s: %s\n", width, " ", dl->line); |
686 | } | 738 | } |
687 | 739 | ||
688 | return 0; | 740 | return 0; |
689 | } | 741 | } |
690 | 742 | ||
743 | /* | ||
744 | * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) | ||
745 | * which looks like following | ||
746 | * | ||
747 | * 0000000000415500 <_init>: | ||
748 | * 415500: sub $0x8,%rsp | ||
749 | * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8> | ||
750 | * 41550b: test %rax,%rax | ||
751 | * 41550e: je 415515 <_init+0x15> | ||
752 | * 415510: callq 416e70 <__gmon_start__@plt> | ||
753 | * 415515: add $0x8,%rsp | ||
754 | * 415519: retq | ||
755 | * | ||
756 | * it will be parsed and saved into struct disasm_line as | ||
757 | * <offset> <name> <ops.raw> | ||
758 | * | ||
759 | * The offset will be a relative offset from the start of the symbol and -1 | ||
760 | * means that it's not a disassembly line so should be treated differently. | ||
761 | * The ops.raw part will be parsed further according to type of the instruction. | ||
762 | */ | ||
691 | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | 763 | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, |
692 | FILE *file, size_t privsize) | 764 | FILE *file, size_t privsize) |
693 | { | 765 | { |
@@ -858,7 +930,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin | |||
858 | struct source_line *iter; | 930 | struct source_line *iter; |
859 | struct rb_node **p = &root->rb_node; | 931 | struct rb_node **p = &root->rb_node; |
860 | struct rb_node *parent = NULL; | 932 | struct rb_node *parent = NULL; |
861 | int ret; | 933 | int i, ret; |
862 | 934 | ||
863 | while (*p != NULL) { | 935 | while (*p != NULL) { |
864 | parent = *p; | 936 | parent = *p; |
@@ -866,7 +938,8 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin | |||
866 | 938 | ||
867 | ret = strcmp(iter->path, src_line->path); | 939 | ret = strcmp(iter->path, src_line->path); |
868 | if (ret == 0) { | 940 | if (ret == 0) { |
869 | iter->percent_sum += src_line->percent; | 941 | for (i = 0; i < src_line->nr_pcnt; i++) |
942 | iter->p[i].percent_sum += src_line->p[i].percent; | ||
870 | return; | 943 | return; |
871 | } | 944 | } |
872 | 945 | ||
@@ -876,12 +949,26 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin | |||
876 | p = &(*p)->rb_right; | 949 | p = &(*p)->rb_right; |
877 | } | 950 | } |
878 | 951 | ||
879 | src_line->percent_sum = src_line->percent; | 952 | for (i = 0; i < src_line->nr_pcnt; i++) |
953 | src_line->p[i].percent_sum = src_line->p[i].percent; | ||
880 | 954 | ||
881 | rb_link_node(&src_line->node, parent, p); | 955 | rb_link_node(&src_line->node, parent, p); |
882 | rb_insert_color(&src_line->node, root); | 956 | rb_insert_color(&src_line->node, root); |
883 | } | 957 | } |
884 | 958 | ||
959 | static int cmp_source_line(struct source_line *a, struct source_line *b) | ||
960 | { | ||
961 | int i; | ||
962 | |||
963 | for (i = 0; i < a->nr_pcnt; i++) { | ||
964 | if (a->p[i].percent_sum == b->p[i].percent_sum) | ||
965 | continue; | ||
966 | return a->p[i].percent_sum > b->p[i].percent_sum; | ||
967 | } | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
885 | static void __resort_source_line(struct rb_root *root, struct source_line *src_line) | 972 | static void __resort_source_line(struct rb_root *root, struct source_line *src_line) |
886 | { | 973 | { |
887 | struct source_line *iter; | 974 | struct source_line *iter; |
@@ -892,7 +979,7 @@ static void __resort_source_line(struct rb_root *root, struct source_line *src_l | |||
892 | parent = *p; | 979 | parent = *p; |
893 | iter = rb_entry(parent, struct source_line, node); | 980 | iter = rb_entry(parent, struct source_line, node); |
894 | 981 | ||
895 | if (src_line->percent_sum > iter->percent_sum) | 982 | if (cmp_source_line(src_line, iter)) |
896 | p = &(*p)->rb_left; | 983 | p = &(*p)->rb_left; |
897 | else | 984 | else |
898 | p = &(*p)->rb_right; | 985 | p = &(*p)->rb_right; |
@@ -924,32 +1011,52 @@ static void symbol__free_source_line(struct symbol *sym, int len) | |||
924 | { | 1011 | { |
925 | struct annotation *notes = symbol__annotation(sym); | 1012 | struct annotation *notes = symbol__annotation(sym); |
926 | struct source_line *src_line = notes->src->lines; | 1013 | struct source_line *src_line = notes->src->lines; |
1014 | size_t sizeof_src_line; | ||
927 | int i; | 1015 | int i; |
928 | 1016 | ||
929 | for (i = 0; i < len; i++) | 1017 | sizeof_src_line = sizeof(*src_line) + |
930 | free(src_line[i].path); | 1018 | (sizeof(src_line->p) * (src_line->nr_pcnt - 1)); |
1019 | |||
1020 | for (i = 0; i < len; i++) { | ||
1021 | free(src_line->path); | ||
1022 | src_line = (void *)src_line + sizeof_src_line; | ||
1023 | } | ||
931 | 1024 | ||
932 | free(src_line); | 1025 | free(notes->src->lines); |
933 | notes->src->lines = NULL; | 1026 | notes->src->lines = NULL; |
934 | } | 1027 | } |
935 | 1028 | ||
936 | /* Get the filename:line for the colored entries */ | 1029 | /* Get the filename:line for the colored entries */ |
937 | static int symbol__get_source_line(struct symbol *sym, struct map *map, | 1030 | static int symbol__get_source_line(struct symbol *sym, struct map *map, |
938 | int evidx, struct rb_root *root, int len, | 1031 | struct perf_evsel *evsel, |
1032 | struct rb_root *root, int len, | ||
939 | const char *filename) | 1033 | const char *filename) |
940 | { | 1034 | { |
941 | u64 start; | 1035 | u64 start; |
942 | int i; | 1036 | int i, k; |
1037 | int evidx = evsel->idx; | ||
943 | char cmd[PATH_MAX * 2]; | 1038 | char cmd[PATH_MAX * 2]; |
944 | struct source_line *src_line; | 1039 | struct source_line *src_line; |
945 | struct annotation *notes = symbol__annotation(sym); | 1040 | struct annotation *notes = symbol__annotation(sym); |
946 | struct sym_hist *h = annotation__histogram(notes, evidx); | 1041 | struct sym_hist *h = annotation__histogram(notes, evidx); |
947 | struct rb_root tmp_root = RB_ROOT; | 1042 | struct rb_root tmp_root = RB_ROOT; |
1043 | int nr_pcnt = 1; | ||
1044 | u64 h_sum = h->sum; | ||
1045 | size_t sizeof_src_line = sizeof(struct source_line); | ||
1046 | |||
1047 | if (perf_evsel__is_group_event(evsel)) { | ||
1048 | for (i = 1; i < evsel->nr_members; i++) { | ||
1049 | h = annotation__histogram(notes, evidx + i); | ||
1050 | h_sum += h->sum; | ||
1051 | } | ||
1052 | nr_pcnt = evsel->nr_members; | ||
1053 | sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p); | ||
1054 | } | ||
948 | 1055 | ||
949 | if (!h->sum) | 1056 | if (!h_sum) |
950 | return 0; | 1057 | return 0; |
951 | 1058 | ||
952 | src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); | 1059 | src_line = notes->src->lines = calloc(len, sizeof_src_line); |
953 | if (!notes->src->lines) | 1060 | if (!notes->src->lines) |
954 | return -1; | 1061 | return -1; |
955 | 1062 | ||
@@ -960,29 +1067,41 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, | |||
960 | size_t line_len; | 1067 | size_t line_len; |
961 | u64 offset; | 1068 | u64 offset; |
962 | FILE *fp; | 1069 | FILE *fp; |
1070 | double percent_max = 0.0; | ||
963 | 1071 | ||
964 | src_line[i].percent = 100.0 * h->addr[i] / h->sum; | 1072 | src_line->nr_pcnt = nr_pcnt; |
965 | if (src_line[i].percent <= 0.5) | 1073 | |
966 | continue; | 1074 | for (k = 0; k < nr_pcnt; k++) { |
1075 | h = annotation__histogram(notes, evidx + k); | ||
1076 | src_line->p[k].percent = 100.0 * h->addr[i] / h->sum; | ||
1077 | |||
1078 | if (src_line->p[k].percent > percent_max) | ||
1079 | percent_max = src_line->p[k].percent; | ||
1080 | } | ||
1081 | |||
1082 | if (percent_max <= 0.5) | ||
1083 | goto next; | ||
967 | 1084 | ||
968 | offset = start + i; | 1085 | offset = start + i; |
969 | sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); | 1086 | sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); |
970 | fp = popen(cmd, "r"); | 1087 | fp = popen(cmd, "r"); |
971 | if (!fp) | 1088 | if (!fp) |
972 | continue; | 1089 | goto next; |
973 | 1090 | ||
974 | if (getline(&path, &line_len, fp) < 0 || !line_len) | 1091 | if (getline(&path, &line_len, fp) < 0 || !line_len) |
975 | goto next; | 1092 | goto next_close; |
976 | 1093 | ||
977 | src_line[i].path = malloc(sizeof(char) * line_len + 1); | 1094 | src_line->path = malloc(sizeof(char) * line_len + 1); |
978 | if (!src_line[i].path) | 1095 | if (!src_line->path) |
979 | goto next; | 1096 | goto next_close; |
980 | 1097 | ||
981 | strcpy(src_line[i].path, path); | 1098 | strcpy(src_line->path, path); |
982 | insert_source_line(&tmp_root, &src_line[i]); | 1099 | insert_source_line(&tmp_root, src_line); |
983 | 1100 | ||
984 | next: | 1101 | next_close: |
985 | pclose(fp); | 1102 | pclose(fp); |
1103 | next: | ||
1104 | src_line = (void *)src_line + sizeof_src_line; | ||
986 | } | 1105 | } |
987 | 1106 | ||
988 | resort_source_line(root, &tmp_root); | 1107 | resort_source_line(root, &tmp_root); |
@@ -1004,24 +1123,33 @@ static void print_summary(struct rb_root *root, const char *filename) | |||
1004 | 1123 | ||
1005 | node = rb_first(root); | 1124 | node = rb_first(root); |
1006 | while (node) { | 1125 | while (node) { |
1007 | double percent; | 1126 | double percent, percent_max = 0.0; |
1008 | const char *color; | 1127 | const char *color; |
1009 | char *path; | 1128 | char *path; |
1129 | int i; | ||
1010 | 1130 | ||
1011 | src_line = rb_entry(node, struct source_line, node); | 1131 | src_line = rb_entry(node, struct source_line, node); |
1012 | percent = src_line->percent_sum; | 1132 | for (i = 0; i < src_line->nr_pcnt; i++) { |
1013 | color = get_percent_color(percent); | 1133 | percent = src_line->p[i].percent_sum; |
1134 | color = get_percent_color(percent); | ||
1135 | color_fprintf(stdout, color, " %7.2f", percent); | ||
1136 | |||
1137 | if (percent > percent_max) | ||
1138 | percent_max = percent; | ||
1139 | } | ||
1140 | |||
1014 | path = src_line->path; | 1141 | path = src_line->path; |
1142 | color = get_percent_color(percent_max); | ||
1143 | color_fprintf(stdout, color, " %s", path); | ||
1015 | 1144 | ||
1016 | color_fprintf(stdout, color, " %7.2f %s", percent, path); | ||
1017 | node = rb_next(node); | 1145 | node = rb_next(node); |
1018 | } | 1146 | } |
1019 | } | 1147 | } |
1020 | 1148 | ||
1021 | static void symbol__annotate_hits(struct symbol *sym, int evidx) | 1149 | static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel) |
1022 | { | 1150 | { |
1023 | struct annotation *notes = symbol__annotation(sym); | 1151 | struct annotation *notes = symbol__annotation(sym); |
1024 | struct sym_hist *h = annotation__histogram(notes, evidx); | 1152 | struct sym_hist *h = annotation__histogram(notes, evsel->idx); |
1025 | u64 len = symbol__size(sym), offset; | 1153 | u64 len = symbol__size(sym), offset; |
1026 | 1154 | ||
1027 | for (offset = 0; offset < len; ++offset) | 1155 | for (offset = 0; offset < len; ++offset) |
@@ -1031,9 +1159,9 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx) | |||
1031 | printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); | 1159 | printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); |
1032 | } | 1160 | } |
1033 | 1161 | ||
1034 | int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | 1162 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
1035 | bool full_paths, int min_pcnt, int max_lines, | 1163 | struct perf_evsel *evsel, bool full_paths, |
1036 | int context) | 1164 | int min_pcnt, int max_lines, int context) |
1037 | { | 1165 | { |
1038 | struct dso *dso = map->dso; | 1166 | struct dso *dso = map->dso; |
1039 | char *filename; | 1167 | char *filename; |
@@ -1044,6 +1172,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | |||
1044 | int printed = 2, queue_len = 0; | 1172 | int printed = 2, queue_len = 0; |
1045 | int more = 0; | 1173 | int more = 0; |
1046 | u64 len; | 1174 | u64 len; |
1175 | int width = 8; | ||
1176 | int namelen; | ||
1047 | 1177 | ||
1048 | filename = strdup(dso->long_name); | 1178 | filename = strdup(dso->long_name); |
1049 | if (!filename) | 1179 | if (!filename) |
@@ -1055,12 +1185,18 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | |||
1055 | d_filename = basename(filename); | 1185 | d_filename = basename(filename); |
1056 | 1186 | ||
1057 | len = symbol__size(sym); | 1187 | len = symbol__size(sym); |
1188 | namelen = strlen(d_filename); | ||
1189 | |||
1190 | if (perf_evsel__is_group_event(evsel)) | ||
1191 | width *= evsel->nr_members; | ||
1058 | 1192 | ||
1059 | printf(" Percent | Source code & Disassembly of %s\n", d_filename); | 1193 | printf(" %-*.*s| Source code & Disassembly of %s\n", |
1060 | printf("------------------------------------------------\n"); | 1194 | width, width, "Percent", d_filename); |
1195 | printf("-%-*.*s-------------------------------------\n", | ||
1196 | width+namelen, width+namelen, graph_dotted_line); | ||
1061 | 1197 | ||
1062 | if (verbose) | 1198 | if (verbose) |
1063 | symbol__annotate_hits(sym, evidx); | 1199 | symbol__annotate_hits(sym, evsel); |
1064 | 1200 | ||
1065 | list_for_each_entry(pos, ¬es->src->source, node) { | 1201 | list_for_each_entry(pos, ¬es->src->source, node) { |
1066 | if (context && queue == NULL) { | 1202 | if (context && queue == NULL) { |
@@ -1068,7 +1204,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | |||
1068 | queue_len = 0; | 1204 | queue_len = 0; |
1069 | } | 1205 | } |
1070 | 1206 | ||
1071 | switch (disasm_line__print(pos, sym, start, evidx, len, | 1207 | switch (disasm_line__print(pos, sym, start, evsel, len, |
1072 | min_pcnt, printed, max_lines, | 1208 | min_pcnt, printed, max_lines, |
1073 | queue)) { | 1209 | queue)) { |
1074 | case 0: | 1210 | case 0: |
@@ -1163,9 +1299,9 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp) | |||
1163 | return printed; | 1299 | return printed; |
1164 | } | 1300 | } |
1165 | 1301 | ||
1166 | int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | 1302 | int symbol__tty_annotate(struct symbol *sym, struct map *map, |
1167 | bool print_lines, bool full_paths, int min_pcnt, | 1303 | struct perf_evsel *evsel, bool print_lines, |
1168 | int max_lines) | 1304 | bool full_paths, int min_pcnt, int max_lines) |
1169 | { | 1305 | { |
1170 | struct dso *dso = map->dso; | 1306 | struct dso *dso = map->dso; |
1171 | const char *filename = dso->long_name; | 1307 | const char *filename = dso->long_name; |
@@ -1178,12 +1314,12 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | |||
1178 | len = symbol__size(sym); | 1314 | len = symbol__size(sym); |
1179 | 1315 | ||
1180 | if (print_lines) { | 1316 | if (print_lines) { |
1181 | symbol__get_source_line(sym, map, evidx, &source_line, | 1317 | symbol__get_source_line(sym, map, evsel, &source_line, |
1182 | len, filename); | 1318 | len, filename); |
1183 | print_summary(&source_line, filename); | 1319 | print_summary(&source_line, filename); |
1184 | } | 1320 | } |
1185 | 1321 | ||
1186 | symbol__annotate_printf(sym, map, evidx, full_paths, | 1322 | symbol__annotate_printf(sym, map, evsel, full_paths, |
1187 | min_pcnt, max_lines, 0); | 1323 | min_pcnt, max_lines, 0); |
1188 | if (print_lines) | 1324 | if (print_lines) |
1189 | symbol__free_source_line(sym, len); | 1325 | symbol__free_source_line(sym, len); |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index c422440fe611..af755156d278 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -50,6 +50,8 @@ bool ins__is_jump(const struct ins *ins); | |||
50 | bool ins__is_call(const struct ins *ins); | 50 | bool ins__is_call(const struct ins *ins); |
51 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); | 51 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); |
52 | 52 | ||
53 | struct annotation; | ||
54 | |||
53 | struct disasm_line { | 55 | struct disasm_line { |
54 | struct list_head node; | 56 | struct list_head node; |
55 | s64 offset; | 57 | s64 offset; |
@@ -68,17 +70,24 @@ void disasm_line__free(struct disasm_line *dl); | |||
68 | struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); | 70 | struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); |
69 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); | 71 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); |
70 | size_t disasm__fprintf(struct list_head *head, FILE *fp); | 72 | size_t disasm__fprintf(struct list_head *head, FILE *fp); |
73 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | ||
74 | s64 end, const char **path); | ||
71 | 75 | ||
72 | struct sym_hist { | 76 | struct sym_hist { |
73 | u64 sum; | 77 | u64 sum; |
74 | u64 addr[0]; | 78 | u64 addr[0]; |
75 | }; | 79 | }; |
76 | 80 | ||
77 | struct source_line { | 81 | struct source_line_percent { |
78 | struct rb_node node; | ||
79 | double percent; | 82 | double percent; |
80 | double percent_sum; | 83 | double percent_sum; |
84 | }; | ||
85 | |||
86 | struct source_line { | ||
87 | struct rb_node node; | ||
81 | char *path; | 88 | char *path; |
89 | int nr_pcnt; | ||
90 | struct source_line_percent p[1]; | ||
82 | }; | 91 | }; |
83 | 92 | ||
84 | /** struct annotated_source - symbols with hits have this attached as in sannotation | 93 | /** struct annotated_source - symbols with hits have this attached as in sannotation |
@@ -130,47 +139,49 @@ void symbol__annotate_zero_histograms(struct symbol *sym); | |||
130 | 139 | ||
131 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); | 140 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); |
132 | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); | 141 | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); |
133 | int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | 142 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
134 | bool full_paths, int min_pcnt, int max_lines, | 143 | struct perf_evsel *evsel, bool full_paths, |
135 | int context); | 144 | int min_pcnt, int max_lines, int context); |
136 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); | 145 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); |
137 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); | 146 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); |
138 | void disasm__purge(struct list_head *head); | 147 | void disasm__purge(struct list_head *head); |
139 | 148 | ||
140 | int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | 149 | int symbol__tty_annotate(struct symbol *sym, struct map *map, |
141 | bool print_lines, bool full_paths, int min_pcnt, | 150 | struct perf_evsel *evsel, bool print_lines, |
142 | int max_lines); | 151 | bool full_paths, int min_pcnt, int max_lines); |
143 | 152 | ||
144 | #ifdef NEWT_SUPPORT | 153 | #ifdef SLANG_SUPPORT |
145 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | 154 | int symbol__tui_annotate(struct symbol *sym, struct map *map, |
155 | struct perf_evsel *evsel, | ||
146 | struct hist_browser_timer *hbt); | 156 | struct hist_browser_timer *hbt); |
147 | #else | 157 | #else |
148 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, | 158 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, |
149 | struct map *map __maybe_unused, | 159 | struct map *map __maybe_unused, |
150 | int evidx __maybe_unused, | 160 | struct perf_evsel *evsel __maybe_unused, |
151 | struct hist_browser_timer *hbt | 161 | struct hist_browser_timer *hbt |
152 | __maybe_unused) | 162 | __maybe_unused) |
153 | { | 163 | { |
154 | return 0; | 164 | return 0; |
155 | } | 165 | } |
156 | #endif | 166 | #endif |
157 | 167 | ||
158 | #ifdef GTK2_SUPPORT | 168 | #ifdef GTK2_SUPPORT |
159 | int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, | 169 | int symbol__gtk_annotate(struct symbol *sym, struct map *map, |
170 | struct perf_evsel *evsel, | ||
160 | struct hist_browser_timer *hbt); | 171 | struct hist_browser_timer *hbt); |
161 | 172 | ||
162 | static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx, | 173 | static inline int hist_entry__gtk_annotate(struct hist_entry *he, |
174 | struct perf_evsel *evsel, | ||
163 | struct hist_browser_timer *hbt) | 175 | struct hist_browser_timer *hbt) |
164 | { | 176 | { |
165 | return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt); | 177 | return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt); |
166 | } | 178 | } |
167 | 179 | ||
168 | void perf_gtk__show_annotations(void); | 180 | void perf_gtk__show_annotations(void); |
169 | #else | 181 | #else |
170 | static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused, | 182 | static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused, |
171 | int evidx __maybe_unused, | 183 | struct perf_evsel *evsel __maybe_unused, |
172 | struct hist_browser_timer *hbt | 184 | struct hist_browser_timer *hbt __maybe_unused) |
173 | __maybe_unused) | ||
174 | { | 185 | { |
175 | return 0; | 186 | return 0; |
176 | } | 187 | } |
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index f817046e22b1..beb8cf9f9976 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "cpumap.h" | 4 | #include "cpumap.h" |
5 | #include <assert.h> | 5 | #include <assert.h> |
6 | #include <stdio.h> | 6 | #include <stdio.h> |
7 | #include <stdlib.h> | ||
7 | 8 | ||
8 | static struct cpu_map *cpu_map__default_new(void) | 9 | static struct cpu_map *cpu_map__default_new(void) |
9 | { | 10 | { |
@@ -219,7 +220,7 @@ int cpu_map__get_socket(struct cpu_map *map, int idx) | |||
219 | if (!mnt) | 220 | if (!mnt) |
220 | return -1; | 221 | return -1; |
221 | 222 | ||
222 | sprintf(path, | 223 | snprintf(path, PATH_MAX, |
223 | "%s/devices/system/cpu/cpu%d/topology/physical_package_id", | 224 | "%s/devices/system/cpu/cpu%d/topology/physical_package_id", |
224 | mnt, cpu); | 225 | mnt, cpu); |
225 | 226 | ||
@@ -231,27 +232,88 @@ int cpu_map__get_socket(struct cpu_map *map, int idx) | |||
231 | return ret == 1 ? cpu : -1; | 232 | return ret == 1 ? cpu : -1; |
232 | } | 233 | } |
233 | 234 | ||
234 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) | 235 | static int cmp_ids(const void *a, const void *b) |
235 | { | 236 | { |
236 | struct cpu_map *sock; | 237 | return *(int *)a - *(int *)b; |
238 | } | ||
239 | |||
240 | static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, | ||
241 | int (*f)(struct cpu_map *map, int cpu)) | ||
242 | { | ||
243 | struct cpu_map *c; | ||
237 | int nr = cpus->nr; | 244 | int nr = cpus->nr; |
238 | int cpu, s1, s2; | 245 | int cpu, s1, s2; |
239 | 246 | ||
240 | sock = calloc(1, sizeof(*sock) + nr * sizeof(int)); | 247 | /* allocate as much as possible */ |
241 | if (!sock) | 248 | c = calloc(1, sizeof(*c) + nr * sizeof(int)); |
249 | if (!c) | ||
242 | return -1; | 250 | return -1; |
243 | 251 | ||
244 | for (cpu = 0; cpu < nr; cpu++) { | 252 | for (cpu = 0; cpu < nr; cpu++) { |
245 | s1 = cpu_map__get_socket(cpus, cpu); | 253 | s1 = f(cpus, cpu); |
246 | for (s2 = 0; s2 < sock->nr; s2++) { | 254 | for (s2 = 0; s2 < c->nr; s2++) { |
247 | if (s1 == sock->map[s2]) | 255 | if (s1 == c->map[s2]) |
248 | break; | 256 | break; |
249 | } | 257 | } |
250 | if (s2 == sock->nr) { | 258 | if (s2 == c->nr) { |
251 | sock->map[sock->nr] = s1; | 259 | c->map[c->nr] = s1; |
252 | sock->nr++; | 260 | c->nr++; |
253 | } | 261 | } |
254 | } | 262 | } |
255 | *sockp = sock; | 263 | /* ensure we process id in increasing order */ |
264 | qsort(c->map, c->nr, sizeof(int), cmp_ids); | ||
265 | |||
266 | *res = c; | ||
256 | return 0; | 267 | return 0; |
257 | } | 268 | } |
269 | |||
270 | int cpu_map__get_core(struct cpu_map *map, int idx) | ||
271 | { | ||
272 | FILE *fp; | ||
273 | const char *mnt; | ||
274 | char path[PATH_MAX]; | ||
275 | int cpu, ret, s; | ||
276 | |||
277 | if (idx > map->nr) | ||
278 | return -1; | ||
279 | |||
280 | cpu = map->map[idx]; | ||
281 | |||
282 | mnt = sysfs_find_mountpoint(); | ||
283 | if (!mnt) | ||
284 | return -1; | ||
285 | |||
286 | snprintf(path, PATH_MAX, | ||
287 | "%s/devices/system/cpu/cpu%d/topology/core_id", | ||
288 | mnt, cpu); | ||
289 | |||
290 | fp = fopen(path, "r"); | ||
291 | if (!fp) | ||
292 | return -1; | ||
293 | ret = fscanf(fp, "%d", &cpu); | ||
294 | fclose(fp); | ||
295 | if (ret != 1) | ||
296 | return -1; | ||
297 | |||
298 | s = cpu_map__get_socket(map, idx); | ||
299 | if (s == -1) | ||
300 | return -1; | ||
301 | |||
302 | /* | ||
303 | * encode socket in upper 16 bits | ||
304 | * core_id is relative to socket, and | ||
305 | * we need a global id. So we combine | ||
306 | * socket+ core id | ||
307 | */ | ||
308 | return (s << 16) | (cpu & 0xffff); | ||
309 | } | ||
310 | |||
311 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) | ||
312 | { | ||
313 | return cpu_map__build_map(cpus, sockp, cpu_map__get_socket); | ||
314 | } | ||
315 | |||
316 | int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep) | ||
317 | { | ||
318 | return cpu_map__build_map(cpus, corep, cpu_map__get_core); | ||
319 | } | ||
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 161b00756a12..9bed02e5fb3d 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
@@ -15,7 +15,9 @@ void cpu_map__delete(struct cpu_map *map); | |||
15 | struct cpu_map *cpu_map__read(FILE *file); | 15 | struct cpu_map *cpu_map__read(FILE *file); |
16 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); | 16 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); |
17 | int cpu_map__get_socket(struct cpu_map *map, int idx); | 17 | int cpu_map__get_socket(struct cpu_map *map, int idx); |
18 | int cpu_map__get_core(struct cpu_map *map, int idx); | ||
18 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); | 19 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); |
20 | int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); | ||
19 | 21 | ||
20 | static inline int cpu_map__socket(struct cpu_map *sock, int s) | 22 | static inline int cpu_map__socket(struct cpu_map *sock, int s) |
21 | { | 23 | { |
@@ -24,6 +26,16 @@ static inline int cpu_map__socket(struct cpu_map *sock, int s) | |||
24 | return sock->map[s]; | 26 | return sock->map[s]; |
25 | } | 27 | } |
26 | 28 | ||
29 | static inline int cpu_map__id_to_socket(int id) | ||
30 | { | ||
31 | return id >> 16; | ||
32 | } | ||
33 | |||
34 | static inline int cpu_map__id_to_cpu(int id) | ||
35 | { | ||
36 | return id & 0xffff; | ||
37 | } | ||
38 | |||
27 | static inline int cpu_map__nr(const struct cpu_map *map) | 39 | static inline int cpu_map__nr(const struct cpu_map *map) |
28 | { | 40 | { |
29 | return map ? map->nr : 1; | 41 | return map ? map->nr : 1; |
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c deleted file mode 100644 index dd8b19319c03..000000000000 --- a/tools/perf/util/debugfs.c +++ /dev/null | |||
@@ -1,114 +0,0 @@ | |||
1 | #include "util.h" | ||
2 | #include "debugfs.h" | ||
3 | #include "cache.h" | ||
4 | |||
5 | #include <linux/kernel.h> | ||
6 | #include <sys/mount.h> | ||
7 | |||
8 | static int debugfs_premounted; | ||
9 | char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; | ||
10 | char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; | ||
11 | |||
12 | static const char *debugfs_known_mountpoints[] = { | ||
13 | "/sys/kernel/debug/", | ||
14 | "/debug/", | ||
15 | 0, | ||
16 | }; | ||
17 | |||
18 | static int debugfs_found; | ||
19 | |||
20 | /* find the path to the mounted debugfs */ | ||
21 | const char *debugfs_find_mountpoint(void) | ||
22 | { | ||
23 | const char **ptr; | ||
24 | char type[100]; | ||
25 | FILE *fp; | ||
26 | |||
27 | if (debugfs_found) | ||
28 | return (const char *) debugfs_mountpoint; | ||
29 | |||
30 | ptr = debugfs_known_mountpoints; | ||
31 | while (*ptr) { | ||
32 | if (debugfs_valid_mountpoint(*ptr) == 0) { | ||
33 | debugfs_found = 1; | ||
34 | strcpy(debugfs_mountpoint, *ptr); | ||
35 | return debugfs_mountpoint; | ||
36 | } | ||
37 | ptr++; | ||
38 | } | ||
39 | |||
40 | /* give up and parse /proc/mounts */ | ||
41 | fp = fopen("/proc/mounts", "r"); | ||
42 | if (fp == NULL) | ||
43 | return NULL; | ||
44 | |||
45 | while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", | ||
46 | debugfs_mountpoint, type) == 2) { | ||
47 | if (strcmp(type, "debugfs") == 0) | ||
48 | break; | ||
49 | } | ||
50 | fclose(fp); | ||
51 | |||
52 | if (strcmp(type, "debugfs") != 0) | ||
53 | return NULL; | ||
54 | |||
55 | debugfs_found = 1; | ||
56 | |||
57 | return debugfs_mountpoint; | ||
58 | } | ||
59 | |||
60 | /* verify that a mountpoint is actually a debugfs instance */ | ||
61 | |||
62 | int debugfs_valid_mountpoint(const char *debugfs) | ||
63 | { | ||
64 | struct statfs st_fs; | ||
65 | |||
66 | if (statfs(debugfs, &st_fs) < 0) | ||
67 | return -ENOENT; | ||
68 | else if (st_fs.f_type != (long) DEBUGFS_MAGIC) | ||
69 | return -ENOENT; | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static void debugfs_set_tracing_events_path(const char *mountpoint) | ||
75 | { | ||
76 | snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", | ||
77 | mountpoint, "tracing/events"); | ||
78 | } | ||
79 | |||
80 | /* mount the debugfs somewhere if it's not mounted */ | ||
81 | |||
82 | char *debugfs_mount(const char *mountpoint) | ||
83 | { | ||
84 | /* see if it's already mounted */ | ||
85 | if (debugfs_find_mountpoint()) { | ||
86 | debugfs_premounted = 1; | ||
87 | goto out; | ||
88 | } | ||
89 | |||
90 | /* if not mounted and no argument */ | ||
91 | if (mountpoint == NULL) { | ||
92 | /* see if environment variable set */ | ||
93 | mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT); | ||
94 | /* if no environment variable, use default */ | ||
95 | if (mountpoint == NULL) | ||
96 | mountpoint = "/sys/kernel/debug"; | ||
97 | } | ||
98 | |||
99 | if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0) | ||
100 | return NULL; | ||
101 | |||
102 | /* save the mountpoint */ | ||
103 | debugfs_found = 1; | ||
104 | strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); | ||
105 | out: | ||
106 | debugfs_set_tracing_events_path(debugfs_mountpoint); | ||
107 | return debugfs_mountpoint; | ||
108 | } | ||
109 | |||
110 | void debugfs_set_path(const char *mountpoint) | ||
111 | { | ||
112 | snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint); | ||
113 | debugfs_set_tracing_events_path(mountpoint); | ||
114 | } | ||
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h deleted file mode 100644 index 68f3e87ec57f..000000000000 --- a/tools/perf/util/debugfs.h +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | #ifndef __DEBUGFS_H__ | ||
2 | #define __DEBUGFS_H__ | ||
3 | |||
4 | const char *debugfs_find_mountpoint(void); | ||
5 | int debugfs_valid_mountpoint(const char *debugfs); | ||
6 | char *debugfs_mount(const char *mountpoint); | ||
7 | void debugfs_set_path(const char *mountpoint); | ||
8 | |||
9 | extern char debugfs_mountpoint[]; | ||
10 | extern char tracing_events_path[]; | ||
11 | |||
12 | #endif /* __DEBUGFS_H__ */ | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 0d573ff4771a..181389535c0c 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -88,8 +88,10 @@ struct perf_sample { | |||
88 | u64 id; | 88 | u64 id; |
89 | u64 stream_id; | 89 | u64 stream_id; |
90 | u64 period; | 90 | u64 period; |
91 | u64 weight; | ||
91 | u32 cpu; | 92 | u32 cpu; |
92 | u32 raw_size; | 93 | u32 raw_size; |
94 | u64 data_src; | ||
93 | void *raw_data; | 95 | void *raw_data; |
94 | struct ip_callchain *callchain; | 96 | struct ip_callchain *callchain; |
95 | struct branch_stack *branch_stack; | 97 | struct branch_stack *branch_stack; |
@@ -97,6 +99,13 @@ struct perf_sample { | |||
97 | struct stack_dump user_stack; | 99 | struct stack_dump user_stack; |
98 | }; | 100 | }; |
99 | 101 | ||
102 | #define PERF_MEM_DATA_SRC_NONE \ | ||
103 | (PERF_MEM_S(OP, NA) |\ | ||
104 | PERF_MEM_S(LVL, NA) |\ | ||
105 | PERF_MEM_S(SNOOP, NA) |\ | ||
106 | PERF_MEM_S(LOCK, NA) |\ | ||
107 | PERF_MEM_S(TLB, NA)) | ||
108 | |||
100 | struct build_id_event { | 109 | struct build_id_event { |
101 | struct perf_event_header header; | 110 | struct perf_event_header header; |
102 | pid_t pid; | 111 | pid_t pid; |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c8be0fbc5145..f7c727801aab 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * Released under the GPL v2. (and only v2, not any later version) | 7 | * Released under the GPL v2. (and only v2, not any later version) |
8 | */ | 8 | */ |
9 | #include "util.h" | 9 | #include "util.h" |
10 | #include "debugfs.h" | 10 | #include <lk/debugfs.h> |
11 | #include <poll.h> | 11 | #include <poll.h> |
12 | #include "cpumap.h" | 12 | #include "cpumap.h" |
13 | #include "thread_map.h" | 13 | #include "thread_map.h" |
@@ -38,13 +38,12 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, | |||
38 | evlist->workload.pid = -1; | 38 | evlist->workload.pid = -1; |
39 | } | 39 | } |
40 | 40 | ||
41 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, | 41 | struct perf_evlist *perf_evlist__new(void) |
42 | struct thread_map *threads) | ||
43 | { | 42 | { |
44 | struct perf_evlist *evlist = zalloc(sizeof(*evlist)); | 43 | struct perf_evlist *evlist = zalloc(sizeof(*evlist)); |
45 | 44 | ||
46 | if (evlist != NULL) | 45 | if (evlist != NULL) |
47 | perf_evlist__init(evlist, cpus, threads); | 46 | perf_evlist__init(evlist, NULL, NULL); |
48 | 47 | ||
49 | return evlist; | 48 | return evlist; |
50 | } | 49 | } |
@@ -228,12 +227,14 @@ void perf_evlist__disable(struct perf_evlist *evlist) | |||
228 | { | 227 | { |
229 | int cpu, thread; | 228 | int cpu, thread; |
230 | struct perf_evsel *pos; | 229 | struct perf_evsel *pos; |
230 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
231 | int nr_threads = thread_map__nr(evlist->threads); | ||
231 | 232 | ||
232 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 233 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
233 | list_for_each_entry(pos, &evlist->entries, node) { | 234 | list_for_each_entry(pos, &evlist->entries, node) { |
234 | if (!perf_evsel__is_group_leader(pos)) | 235 | if (!perf_evsel__is_group_leader(pos)) |
235 | continue; | 236 | continue; |
236 | for (thread = 0; thread < evlist->threads->nr; thread++) | 237 | for (thread = 0; thread < nr_threads; thread++) |
237 | ioctl(FD(pos, cpu, thread), | 238 | ioctl(FD(pos, cpu, thread), |
238 | PERF_EVENT_IOC_DISABLE, 0); | 239 | PERF_EVENT_IOC_DISABLE, 0); |
239 | } | 240 | } |
@@ -244,12 +245,14 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
244 | { | 245 | { |
245 | int cpu, thread; | 246 | int cpu, thread; |
246 | struct perf_evsel *pos; | 247 | struct perf_evsel *pos; |
248 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
249 | int nr_threads = thread_map__nr(evlist->threads); | ||
247 | 250 | ||
248 | for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { | 251 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
249 | list_for_each_entry(pos, &evlist->entries, node) { | 252 | list_for_each_entry(pos, &evlist->entries, node) { |
250 | if (!perf_evsel__is_group_leader(pos)) | 253 | if (!perf_evsel__is_group_leader(pos)) |
251 | continue; | 254 | continue; |
252 | for (thread = 0; thread < evlist->threads->nr; thread++) | 255 | for (thread = 0; thread < nr_threads; thread++) |
253 | ioctl(FD(pos, cpu, thread), | 256 | ioctl(FD(pos, cpu, thread), |
254 | PERF_EVENT_IOC_ENABLE, 0); | 257 | PERF_EVENT_IOC_ENABLE, 0); |
255 | } | 258 | } |
@@ -258,7 +261,9 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
258 | 261 | ||
259 | static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | 262 | static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) |
260 | { | 263 | { |
261 | int nfds = cpu_map__nr(evlist->cpus) * evlist->threads->nr * evlist->nr_entries; | 264 | int nr_cpus = cpu_map__nr(evlist->cpus); |
265 | int nr_threads = thread_map__nr(evlist->threads); | ||
266 | int nfds = nr_cpus * nr_threads * evlist->nr_entries; | ||
262 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); | 267 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); |
263 | return evlist->pollfd != NULL ? 0 : -ENOMEM; | 268 | return evlist->pollfd != NULL ? 0 : -ENOMEM; |
264 | } | 269 | } |
@@ -417,7 +422,7 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) | |||
417 | { | 422 | { |
418 | evlist->nr_mmaps = cpu_map__nr(evlist->cpus); | 423 | evlist->nr_mmaps = cpu_map__nr(evlist->cpus); |
419 | if (cpu_map__all(evlist->cpus)) | 424 | if (cpu_map__all(evlist->cpus)) |
420 | evlist->nr_mmaps = evlist->threads->nr; | 425 | evlist->nr_mmaps = thread_map__nr(evlist->threads); |
421 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); | 426 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); |
422 | return evlist->mmap != NULL ? 0 : -ENOMEM; | 427 | return evlist->mmap != NULL ? 0 : -ENOMEM; |
423 | } | 428 | } |
@@ -442,11 +447,13 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m | |||
442 | { | 447 | { |
443 | struct perf_evsel *evsel; | 448 | struct perf_evsel *evsel; |
444 | int cpu, thread; | 449 | int cpu, thread; |
450 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
451 | int nr_threads = thread_map__nr(evlist->threads); | ||
445 | 452 | ||
446 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 453 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
447 | int output = -1; | 454 | int output = -1; |
448 | 455 | ||
449 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 456 | for (thread = 0; thread < nr_threads; thread++) { |
450 | list_for_each_entry(evsel, &evlist->entries, node) { | 457 | list_for_each_entry(evsel, &evlist->entries, node) { |
451 | int fd = FD(evsel, cpu, thread); | 458 | int fd = FD(evsel, cpu, thread); |
452 | 459 | ||
@@ -470,7 +477,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m | |||
470 | return 0; | 477 | return 0; |
471 | 478 | ||
472 | out_unmap: | 479 | out_unmap: |
473 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 480 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
474 | if (evlist->mmap[cpu].base != NULL) { | 481 | if (evlist->mmap[cpu].base != NULL) { |
475 | munmap(evlist->mmap[cpu].base, evlist->mmap_len); | 482 | munmap(evlist->mmap[cpu].base, evlist->mmap_len); |
476 | evlist->mmap[cpu].base = NULL; | 483 | evlist->mmap[cpu].base = NULL; |
@@ -483,8 +490,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in | |||
483 | { | 490 | { |
484 | struct perf_evsel *evsel; | 491 | struct perf_evsel *evsel; |
485 | int thread; | 492 | int thread; |
493 | int nr_threads = thread_map__nr(evlist->threads); | ||
486 | 494 | ||
487 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 495 | for (thread = 0; thread < nr_threads; thread++) { |
488 | int output = -1; | 496 | int output = -1; |
489 | 497 | ||
490 | list_for_each_entry(evsel, &evlist->entries, node) { | 498 | list_for_each_entry(evsel, &evlist->entries, node) { |
@@ -509,7 +517,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in | |||
509 | return 0; | 517 | return 0; |
510 | 518 | ||
511 | out_unmap: | 519 | out_unmap: |
512 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 520 | for (thread = 0; thread < nr_threads; thread++) { |
513 | if (evlist->mmap[thread].base != NULL) { | 521 | if (evlist->mmap[thread].base != NULL) { |
514 | munmap(evlist->mmap[thread].base, evlist->mmap_len); | 522 | munmap(evlist->mmap[thread].base, evlist->mmap_len); |
515 | evlist->mmap[thread].base = NULL; | 523 | evlist->mmap[thread].base = NULL; |
@@ -610,7 +618,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist) | |||
610 | struct perf_evsel *evsel; | 618 | struct perf_evsel *evsel; |
611 | int err = 0; | 619 | int err = 0; |
612 | const int ncpus = cpu_map__nr(evlist->cpus), | 620 | const int ncpus = cpu_map__nr(evlist->cpus), |
613 | nthreads = evlist->threads->nr; | 621 | nthreads = thread_map__nr(evlist->threads); |
614 | 622 | ||
615 | list_for_each_entry(evsel, &evlist->entries, node) { | 623 | list_for_each_entry(evsel, &evlist->entries, node) { |
616 | if (evsel->filter == NULL) | 624 | if (evsel->filter == NULL) |
@@ -629,7 +637,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) | |||
629 | struct perf_evsel *evsel; | 637 | struct perf_evsel *evsel; |
630 | int err = 0; | 638 | int err = 0; |
631 | const int ncpus = cpu_map__nr(evlist->cpus), | 639 | const int ncpus = cpu_map__nr(evlist->cpus), |
632 | nthreads = evlist->threads->nr; | 640 | nthreads = thread_map__nr(evlist->threads); |
633 | 641 | ||
634 | list_for_each_entry(evsel, &evlist->entries, node) { | 642 | list_for_each_entry(evsel, &evlist->entries, node) { |
635 | err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); | 643 | err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); |
@@ -712,10 +720,20 @@ void perf_evlist__set_selected(struct perf_evlist *evlist, | |||
712 | evlist->selected = evsel; | 720 | evlist->selected = evsel; |
713 | } | 721 | } |
714 | 722 | ||
723 | void perf_evlist__close(struct perf_evlist *evlist) | ||
724 | { | ||
725 | struct perf_evsel *evsel; | ||
726 | int ncpus = cpu_map__nr(evlist->cpus); | ||
727 | int nthreads = thread_map__nr(evlist->threads); | ||
728 | |||
729 | list_for_each_entry_reverse(evsel, &evlist->entries, node) | ||
730 | perf_evsel__close(evsel, ncpus, nthreads); | ||
731 | } | ||
732 | |||
715 | int perf_evlist__open(struct perf_evlist *evlist) | 733 | int perf_evlist__open(struct perf_evlist *evlist) |
716 | { | 734 | { |
717 | struct perf_evsel *evsel; | 735 | struct perf_evsel *evsel; |
718 | int err, ncpus, nthreads; | 736 | int err; |
719 | 737 | ||
720 | list_for_each_entry(evsel, &evlist->entries, node) { | 738 | list_for_each_entry(evsel, &evlist->entries, node) { |
721 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); | 739 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); |
@@ -725,19 +743,15 @@ int perf_evlist__open(struct perf_evlist *evlist) | |||
725 | 743 | ||
726 | return 0; | 744 | return 0; |
727 | out_err: | 745 | out_err: |
728 | ncpus = evlist->cpus ? evlist->cpus->nr : 1; | 746 | perf_evlist__close(evlist); |
729 | nthreads = evlist->threads ? evlist->threads->nr : 1; | ||
730 | |||
731 | list_for_each_entry_reverse(evsel, &evlist->entries, node) | ||
732 | perf_evsel__close(evsel, ncpus, nthreads); | ||
733 | |||
734 | errno = -err; | 747 | errno = -err; |
735 | return err; | 748 | return err; |
736 | } | 749 | } |
737 | 750 | ||
738 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 751 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
739 | struct perf_record_opts *opts, | 752 | struct perf_target *target, |
740 | const char *argv[]) | 753 | const char *argv[], bool pipe_output, |
754 | bool want_signal) | ||
741 | { | 755 | { |
742 | int child_ready_pipe[2], go_pipe[2]; | 756 | int child_ready_pipe[2], go_pipe[2]; |
743 | char bf; | 757 | char bf; |
@@ -759,7 +773,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, | |||
759 | } | 773 | } |
760 | 774 | ||
761 | if (!evlist->workload.pid) { | 775 | if (!evlist->workload.pid) { |
762 | if (opts->pipe_output) | 776 | if (pipe_output) |
763 | dup2(2, 1); | 777 | dup2(2, 1); |
764 | 778 | ||
765 | close(child_ready_pipe[0]); | 779 | close(child_ready_pipe[0]); |
@@ -787,11 +801,12 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, | |||
787 | execvp(argv[0], (char **)argv); | 801 | execvp(argv[0], (char **)argv); |
788 | 802 | ||
789 | perror(argv[0]); | 803 | perror(argv[0]); |
790 | kill(getppid(), SIGUSR1); | 804 | if (want_signal) |
805 | kill(getppid(), SIGUSR1); | ||
791 | exit(-1); | 806 | exit(-1); |
792 | } | 807 | } |
793 | 808 | ||
794 | if (perf_target__none(&opts->target)) | 809 | if (perf_target__none(target)) |
795 | evlist->threads->map[0] = evlist->workload.pid; | 810 | evlist->threads->map[0] = evlist->workload.pid; |
796 | 811 | ||
797 | close(child_ready_pipe[1]); | 812 | close(child_ready_pipe[1]); |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 2dd07bd60b4f..0583d36252be 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -49,8 +49,7 @@ struct perf_evsel_str_handler { | |||
49 | void *handler; | 49 | void *handler; |
50 | }; | 50 | }; |
51 | 51 | ||
52 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, | 52 | struct perf_evlist *perf_evlist__new(void); |
53 | struct thread_map *threads); | ||
54 | void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, | 53 | void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, |
55 | struct thread_map *threads); | 54 | struct thread_map *threads); |
56 | void perf_evlist__exit(struct perf_evlist *evlist); | 55 | void perf_evlist__exit(struct perf_evlist *evlist); |
@@ -82,13 +81,15 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); | |||
82 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); | 81 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); |
83 | 82 | ||
84 | int perf_evlist__open(struct perf_evlist *evlist); | 83 | int perf_evlist__open(struct perf_evlist *evlist); |
84 | void perf_evlist__close(struct perf_evlist *evlist); | ||
85 | 85 | ||
86 | void perf_evlist__config(struct perf_evlist *evlist, | 86 | void perf_evlist__config(struct perf_evlist *evlist, |
87 | struct perf_record_opts *opts); | 87 | struct perf_record_opts *opts); |
88 | 88 | ||
89 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 89 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
90 | struct perf_record_opts *opts, | 90 | struct perf_target *target, |
91 | const char *argv[]); | 91 | const char *argv[], bool pipe_output, |
92 | bool want_signal); | ||
92 | int perf_evlist__start_workload(struct perf_evlist *evlist); | 93 | int perf_evlist__start_workload(struct perf_evlist *evlist); |
93 | 94 | ||
94 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | 95 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9c82f98f26de..07b1a3ad3e24 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -10,7 +10,7 @@ | |||
10 | #include <byteswap.h> | 10 | #include <byteswap.h> |
11 | #include <linux/bitops.h> | 11 | #include <linux/bitops.h> |
12 | #include "asm/bug.h" | 12 | #include "asm/bug.h" |
13 | #include "debugfs.h" | 13 | #include <lk/debugfs.h> |
14 | #include "event-parse.h" | 14 | #include "event-parse.h" |
15 | #include "evsel.h" | 15 | #include "evsel.h" |
16 | #include "evlist.h" | 16 | #include "evlist.h" |
@@ -554,6 +554,9 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
554 | perf_evsel__set_sample_bit(evsel, CPU); | 554 | perf_evsel__set_sample_bit(evsel, CPU); |
555 | } | 555 | } |
556 | 556 | ||
557 | if (opts->sample_address) | ||
558 | attr->sample_type |= PERF_SAMPLE_DATA_SRC; | ||
559 | |||
557 | if (opts->no_delay) { | 560 | if (opts->no_delay) { |
558 | attr->watermark = 0; | 561 | attr->watermark = 0; |
559 | attr->wakeup_events = 1; | 562 | attr->wakeup_events = 1; |
@@ -563,6 +566,9 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
563 | attr->branch_sample_type = opts->branch_stack; | 566 | attr->branch_sample_type = opts->branch_stack; |
564 | } | 567 | } |
565 | 568 | ||
569 | if (opts->sample_weight) | ||
570 | attr->sample_type |= PERF_SAMPLE_WEIGHT; | ||
571 | |||
566 | attr->mmap = track; | 572 | attr->mmap = track; |
567 | attr->comm = track; | 573 | attr->comm = track; |
568 | 574 | ||
@@ -633,6 +639,12 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
633 | return 0; | 639 | return 0; |
634 | } | 640 | } |
635 | 641 | ||
642 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) | ||
643 | { | ||
644 | memset(evsel->counts, 0, (sizeof(*evsel->counts) + | ||
645 | (ncpus * sizeof(struct perf_counts_values)))); | ||
646 | } | ||
647 | |||
636 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) | 648 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) |
637 | { | 649 | { |
638 | evsel->counts = zalloc((sizeof(*evsel->counts) + | 650 | evsel->counts = zalloc((sizeof(*evsel->counts) + |
@@ -673,9 +685,8 @@ void perf_evsel__free_counts(struct perf_evsel *evsel) | |||
673 | void perf_evsel__exit(struct perf_evsel *evsel) | 685 | void perf_evsel__exit(struct perf_evsel *evsel) |
674 | { | 686 | { |
675 | assert(list_empty(&evsel->node)); | 687 | assert(list_empty(&evsel->node)); |
676 | xyarray__delete(evsel->fd); | 688 | perf_evsel__free_fd(evsel); |
677 | xyarray__delete(evsel->sample_id); | 689 | perf_evsel__free_id(evsel); |
678 | free(evsel->id); | ||
679 | } | 690 | } |
680 | 691 | ||
681 | void perf_evsel__delete(struct perf_evsel *evsel) | 692 | void perf_evsel__delete(struct perf_evsel *evsel) |
@@ -1012,6 +1023,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | |||
1012 | data->cpu = data->pid = data->tid = -1; | 1023 | data->cpu = data->pid = data->tid = -1; |
1013 | data->stream_id = data->id = data->time = -1ULL; | 1024 | data->stream_id = data->id = data->time = -1ULL; |
1014 | data->period = 1; | 1025 | data->period = 1; |
1026 | data->weight = 0; | ||
1015 | 1027 | ||
1016 | if (event->header.type != PERF_RECORD_SAMPLE) { | 1028 | if (event->header.type != PERF_RECORD_SAMPLE) { |
1017 | if (!evsel->attr.sample_id_all) | 1029 | if (!evsel->attr.sample_id_all) |
@@ -1162,6 +1174,18 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | |||
1162 | } | 1174 | } |
1163 | } | 1175 | } |
1164 | 1176 | ||
1177 | data->weight = 0; | ||
1178 | if (type & PERF_SAMPLE_WEIGHT) { | ||
1179 | data->weight = *array; | ||
1180 | array++; | ||
1181 | } | ||
1182 | |||
1183 | data->data_src = PERF_MEM_DATA_SRC_NONE; | ||
1184 | if (type & PERF_SAMPLE_DATA_SRC) { | ||
1185 | data->data_src = *array; | ||
1186 | array++; | ||
1187 | } | ||
1188 | |||
1165 | return 0; | 1189 | return 0; |
1166 | } | 1190 | } |
1167 | 1191 | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 52021c3087df..3f156ccc1acb 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "xyarray.h" | 9 | #include "xyarray.h" |
10 | #include "cgroup.h" | 10 | #include "cgroup.h" |
11 | #include "hist.h" | 11 | #include "hist.h" |
12 | #include "symbol.h" | ||
12 | 13 | ||
13 | struct perf_counts_values { | 14 | struct perf_counts_values { |
14 | union { | 15 | union { |
@@ -120,6 +121,7 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); | |||
120 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 121 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
121 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); | 122 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); |
122 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); | 123 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); |
124 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); | ||
123 | void perf_evsel__free_fd(struct perf_evsel *evsel); | 125 | void perf_evsel__free_fd(struct perf_evsel *evsel); |
124 | void perf_evsel__free_id(struct perf_evsel *evsel); | 126 | void perf_evsel__free_id(struct perf_evsel *evsel); |
125 | void perf_evsel__free_counts(struct perf_evsel *evsel); | 127 | void perf_evsel__free_counts(struct perf_evsel *evsel); |
@@ -246,11 +248,34 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) | |||
246 | return list_entry(evsel->node.next, struct perf_evsel, node); | 248 | return list_entry(evsel->node.next, struct perf_evsel, node); |
247 | } | 249 | } |
248 | 250 | ||
251 | /** | ||
252 | * perf_evsel__is_group_leader - Return whether given evsel is a leader event | ||
253 | * | ||
254 | * @evsel - evsel selector to be tested | ||
255 | * | ||
256 | * Return %true if @evsel is a group leader or a stand-alone event | ||
257 | */ | ||
249 | static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) | 258 | static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) |
250 | { | 259 | { |
251 | return evsel->leader == evsel; | 260 | return evsel->leader == evsel; |
252 | } | 261 | } |
253 | 262 | ||
263 | /** | ||
264 | * perf_evsel__is_group_event - Return whether given evsel is a group event | ||
265 | * | ||
266 | * @evsel - evsel selector to be tested | ||
267 | * | ||
268 | * Return %true iff event group view is enabled and @evsel is a actual group | ||
269 | * leader which has other members in the group | ||
270 | */ | ||
271 | static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel) | ||
272 | { | ||
273 | if (!symbol_conf.event_group) | ||
274 | return false; | ||
275 | |||
276 | return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1; | ||
277 | } | ||
278 | |||
254 | struct perf_attr_details { | 279 | struct perf_attr_details { |
255 | bool freq; | 280 | bool freq; |
256 | bool verbose; | 281 | bool verbose; |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f4bfd79ef6a7..326068a593a5 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1,5 +1,3 @@ | |||
1 | #define _FILE_OFFSET_BITS 64 | ||
2 | |||
3 | #include "util.h" | 1 | #include "util.h" |
4 | #include <sys/types.h> | 2 | #include <sys/types.h> |
5 | #include <byteswap.h> | 3 | #include <byteswap.h> |
@@ -1672,8 +1670,8 @@ static int process_tracing_data(struct perf_file_section *section __maybe_unused | |||
1672 | struct perf_header *ph __maybe_unused, | 1670 | struct perf_header *ph __maybe_unused, |
1673 | int fd, void *data) | 1671 | int fd, void *data) |
1674 | { | 1672 | { |
1675 | trace_report(fd, data, false); | 1673 | ssize_t ret = trace_report(fd, data, false); |
1676 | return 0; | 1674 | return ret < 0 ? -1 : 0; |
1677 | } | 1675 | } |
1678 | 1676 | ||
1679 | static int process_build_id(struct perf_file_section *section, | 1677 | static int process_build_id(struct perf_file_section *section, |
@@ -2752,6 +2750,11 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, | |||
2752 | if (evsel->tp_format) | 2750 | if (evsel->tp_format) |
2753 | return 0; | 2751 | return 0; |
2754 | 2752 | ||
2753 | if (pevent == NULL) { | ||
2754 | pr_debug("broken or missing trace data\n"); | ||
2755 | return -1; | ||
2756 | } | ||
2757 | |||
2755 | event = pevent_find_event(pevent, evsel->attr.config); | 2758 | event = pevent_find_event(pevent, evsel->attr.config); |
2756 | if (event == NULL) | 2759 | if (event == NULL) |
2757 | return -1; | 2760 | return -1; |
@@ -2789,7 +2792,7 @@ int perf_session__read_header(struct perf_session *session, int fd) | |||
2789 | u64 f_id; | 2792 | u64 f_id; |
2790 | int nr_attrs, nr_ids, i, j; | 2793 | int nr_attrs, nr_ids, i, j; |
2791 | 2794 | ||
2792 | session->evlist = perf_evlist__new(NULL, NULL); | 2795 | session->evlist = perf_evlist__new(); |
2793 | if (session->evlist == NULL) | 2796 | if (session->evlist == NULL) |
2794 | return -ENOMEM; | 2797 | return -ENOMEM; |
2795 | 2798 | ||
@@ -2940,7 +2943,7 @@ int perf_event__process_attr(union perf_event *event, | |||
2940 | struct perf_evlist *evlist = *pevlist; | 2943 | struct perf_evlist *evlist = *pevlist; |
2941 | 2944 | ||
2942 | if (evlist == NULL) { | 2945 | if (evlist == NULL) { |
2943 | *pevlist = evlist = perf_evlist__new(NULL, NULL); | 2946 | *pevlist = evlist = perf_evlist__new(); |
2944 | if (evlist == NULL) | 2947 | if (evlist == NULL) |
2945 | return -ENOMEM; | 2948 | return -ENOMEM; |
2946 | } | 2949 | } |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f855941bebea..6b32721f829a 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -67,12 +67,16 @@ static void hists__set_unres_dso_col_len(struct hists *hists, int dso) | |||
67 | void hists__calc_col_len(struct hists *hists, struct hist_entry *h) | 67 | void hists__calc_col_len(struct hists *hists, struct hist_entry *h) |
68 | { | 68 | { |
69 | const unsigned int unresolved_col_width = BITS_PER_LONG / 4; | 69 | const unsigned int unresolved_col_width = BITS_PER_LONG / 4; |
70 | int symlen; | ||
70 | u16 len; | 71 | u16 len; |
71 | 72 | ||
72 | if (h->ms.sym) | 73 | if (h->ms.sym) |
73 | hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4); | 74 | hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4); |
74 | else | 75 | else { |
76 | symlen = unresolved_col_width + 4 + 2; | ||
77 | hists__new_col_len(hists, HISTC_SYMBOL, symlen); | ||
75 | hists__set_unres_dso_col_len(hists, HISTC_DSO); | 78 | hists__set_unres_dso_col_len(hists, HISTC_DSO); |
79 | } | ||
76 | 80 | ||
77 | len = thread__comm_len(h->thread); | 81 | len = thread__comm_len(h->thread); |
78 | if (hists__new_col_len(hists, HISTC_COMM, len)) | 82 | if (hists__new_col_len(hists, HISTC_COMM, len)) |
@@ -87,7 +91,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) | |||
87 | hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); | 91 | hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); |
88 | 92 | ||
89 | if (h->branch_info) { | 93 | if (h->branch_info) { |
90 | int symlen; | ||
91 | /* | 94 | /* |
92 | * +4 accounts for '[x] ' priv level info | 95 | * +4 accounts for '[x] ' priv level info |
93 | * +2 account of 0x prefix on raw addresses | 96 | * +2 account of 0x prefix on raw addresses |
@@ -116,6 +119,42 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) | |||
116 | hists__set_unres_dso_col_len(hists, HISTC_DSO_TO); | 119 | hists__set_unres_dso_col_len(hists, HISTC_DSO_TO); |
117 | } | 120 | } |
118 | } | 121 | } |
122 | |||
123 | if (h->mem_info) { | ||
124 | /* | ||
125 | * +4 accounts for '[x] ' priv level info | ||
126 | * +2 account of 0x prefix on raw addresses | ||
127 | */ | ||
128 | if (h->mem_info->daddr.sym) { | ||
129 | symlen = (int)h->mem_info->daddr.sym->namelen + 4 | ||
130 | + unresolved_col_width + 2; | ||
131 | hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, | ||
132 | symlen); | ||
133 | } else { | ||
134 | symlen = unresolved_col_width + 4 + 2; | ||
135 | hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, | ||
136 | symlen); | ||
137 | } | ||
138 | if (h->mem_info->daddr.map) { | ||
139 | symlen = dso__name_len(h->mem_info->daddr.map->dso); | ||
140 | hists__new_col_len(hists, HISTC_MEM_DADDR_DSO, | ||
141 | symlen); | ||
142 | } else { | ||
143 | symlen = unresolved_col_width + 4 + 2; | ||
144 | hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); | ||
145 | } | ||
146 | } else { | ||
147 | symlen = unresolved_col_width + 4 + 2; | ||
148 | hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen); | ||
149 | hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); | ||
150 | } | ||
151 | |||
152 | hists__new_col_len(hists, HISTC_MEM_LOCKED, 6); | ||
153 | hists__new_col_len(hists, HISTC_MEM_TLB, 22); | ||
154 | hists__new_col_len(hists, HISTC_MEM_SNOOP, 12); | ||
155 | hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3); | ||
156 | hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); | ||
157 | hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); | ||
119 | } | 158 | } |
120 | 159 | ||
121 | void hists__output_recalc_col_len(struct hists *hists, int max_rows) | 160 | void hists__output_recalc_col_len(struct hists *hists, int max_rows) |
@@ -155,9 +194,12 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he, | |||
155 | } | 194 | } |
156 | } | 195 | } |
157 | 196 | ||
158 | static void he_stat__add_period(struct he_stat *he_stat, u64 period) | 197 | static void he_stat__add_period(struct he_stat *he_stat, u64 period, |
198 | u64 weight) | ||
159 | { | 199 | { |
200 | |||
160 | he_stat->period += period; | 201 | he_stat->period += period; |
202 | he_stat->weight += weight; | ||
161 | he_stat->nr_events += 1; | 203 | he_stat->nr_events += 1; |
162 | } | 204 | } |
163 | 205 | ||
@@ -169,12 +211,14 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src) | |||
169 | dest->period_guest_sys += src->period_guest_sys; | 211 | dest->period_guest_sys += src->period_guest_sys; |
170 | dest->period_guest_us += src->period_guest_us; | 212 | dest->period_guest_us += src->period_guest_us; |
171 | dest->nr_events += src->nr_events; | 213 | dest->nr_events += src->nr_events; |
214 | dest->weight += src->weight; | ||
172 | } | 215 | } |
173 | 216 | ||
174 | static void hist_entry__decay(struct hist_entry *he) | 217 | static void hist_entry__decay(struct hist_entry *he) |
175 | { | 218 | { |
176 | he->stat.period = (he->stat.period * 7) / 8; | 219 | he->stat.period = (he->stat.period * 7) / 8; |
177 | he->stat.nr_events = (he->stat.nr_events * 7) / 8; | 220 | he->stat.nr_events = (he->stat.nr_events * 7) / 8; |
221 | /* XXX need decay for weight too? */ | ||
178 | } | 222 | } |
179 | 223 | ||
180 | static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | 224 | static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) |
@@ -239,7 +283,7 @@ void hists__decay_entries_threaded(struct hists *hists, | |||
239 | static struct hist_entry *hist_entry__new(struct hist_entry *template) | 283 | static struct hist_entry *hist_entry__new(struct hist_entry *template) |
240 | { | 284 | { |
241 | size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; | 285 | size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; |
242 | struct hist_entry *he = malloc(sizeof(*he) + callchain_size); | 286 | struct hist_entry *he = zalloc(sizeof(*he) + callchain_size); |
243 | 287 | ||
244 | if (he != NULL) { | 288 | if (he != NULL) { |
245 | *he = *template; | 289 | *he = *template; |
@@ -254,6 +298,13 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
254 | he->branch_info->to.map->referenced = true; | 298 | he->branch_info->to.map->referenced = true; |
255 | } | 299 | } |
256 | 300 | ||
301 | if (he->mem_info) { | ||
302 | if (he->mem_info->iaddr.map) | ||
303 | he->mem_info->iaddr.map->referenced = true; | ||
304 | if (he->mem_info->daddr.map) | ||
305 | he->mem_info->daddr.map->referenced = true; | ||
306 | } | ||
307 | |||
257 | if (symbol_conf.use_callchain) | 308 | if (symbol_conf.use_callchain) |
258 | callchain_init(he->callchain); | 309 | callchain_init(he->callchain); |
259 | 310 | ||
@@ -282,7 +333,8 @@ static u8 symbol__parent_filter(const struct symbol *parent) | |||
282 | static struct hist_entry *add_hist_entry(struct hists *hists, | 333 | static struct hist_entry *add_hist_entry(struct hists *hists, |
283 | struct hist_entry *entry, | 334 | struct hist_entry *entry, |
284 | struct addr_location *al, | 335 | struct addr_location *al, |
285 | u64 period) | 336 | u64 period, |
337 | u64 weight) | ||
286 | { | 338 | { |
287 | struct rb_node **p; | 339 | struct rb_node **p; |
288 | struct rb_node *parent = NULL; | 340 | struct rb_node *parent = NULL; |
@@ -306,7 +358,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
306 | cmp = hist_entry__cmp(he, entry); | 358 | cmp = hist_entry__cmp(he, entry); |
307 | 359 | ||
308 | if (!cmp) { | 360 | if (!cmp) { |
309 | he_stat__add_period(&he->stat, period); | 361 | he_stat__add_period(&he->stat, period, weight); |
310 | 362 | ||
311 | /* If the map of an existing hist_entry has | 363 | /* If the map of an existing hist_entry has |
312 | * become out-of-date due to an exec() or | 364 | * become out-of-date due to an exec() or |
@@ -341,11 +393,42 @@ out_unlock: | |||
341 | return he; | 393 | return he; |
342 | } | 394 | } |
343 | 395 | ||
396 | struct hist_entry *__hists__add_mem_entry(struct hists *self, | ||
397 | struct addr_location *al, | ||
398 | struct symbol *sym_parent, | ||
399 | struct mem_info *mi, | ||
400 | u64 period, | ||
401 | u64 weight) | ||
402 | { | ||
403 | struct hist_entry entry = { | ||
404 | .thread = al->thread, | ||
405 | .ms = { | ||
406 | .map = al->map, | ||
407 | .sym = al->sym, | ||
408 | }, | ||
409 | .stat = { | ||
410 | .period = period, | ||
411 | .weight = weight, | ||
412 | .nr_events = 1, | ||
413 | }, | ||
414 | .cpu = al->cpu, | ||
415 | .ip = al->addr, | ||
416 | .level = al->level, | ||
417 | .parent = sym_parent, | ||
418 | .filtered = symbol__parent_filter(sym_parent), | ||
419 | .hists = self, | ||
420 | .mem_info = mi, | ||
421 | .branch_info = NULL, | ||
422 | }; | ||
423 | return add_hist_entry(self, &entry, al, period, weight); | ||
424 | } | ||
425 | |||
344 | struct hist_entry *__hists__add_branch_entry(struct hists *self, | 426 | struct hist_entry *__hists__add_branch_entry(struct hists *self, |
345 | struct addr_location *al, | 427 | struct addr_location *al, |
346 | struct symbol *sym_parent, | 428 | struct symbol *sym_parent, |
347 | struct branch_info *bi, | 429 | struct branch_info *bi, |
348 | u64 period) | 430 | u64 period, |
431 | u64 weight) | ||
349 | { | 432 | { |
350 | struct hist_entry entry = { | 433 | struct hist_entry entry = { |
351 | .thread = al->thread, | 434 | .thread = al->thread, |
@@ -359,19 +442,22 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self, | |||
359 | .stat = { | 442 | .stat = { |
360 | .period = period, | 443 | .period = period, |
361 | .nr_events = 1, | 444 | .nr_events = 1, |
445 | .weight = weight, | ||
362 | }, | 446 | }, |
363 | .parent = sym_parent, | 447 | .parent = sym_parent, |
364 | .filtered = symbol__parent_filter(sym_parent), | 448 | .filtered = symbol__parent_filter(sym_parent), |
365 | .branch_info = bi, | 449 | .branch_info = bi, |
366 | .hists = self, | 450 | .hists = self, |
451 | .mem_info = NULL, | ||
367 | }; | 452 | }; |
368 | 453 | ||
369 | return add_hist_entry(self, &entry, al, period); | 454 | return add_hist_entry(self, &entry, al, period, weight); |
370 | } | 455 | } |
371 | 456 | ||
372 | struct hist_entry *__hists__add_entry(struct hists *self, | 457 | struct hist_entry *__hists__add_entry(struct hists *self, |
373 | struct addr_location *al, | 458 | struct addr_location *al, |
374 | struct symbol *sym_parent, u64 period) | 459 | struct symbol *sym_parent, u64 period, |
460 | u64 weight) | ||
375 | { | 461 | { |
376 | struct hist_entry entry = { | 462 | struct hist_entry entry = { |
377 | .thread = al->thread, | 463 | .thread = al->thread, |
@@ -385,13 +471,16 @@ struct hist_entry *__hists__add_entry(struct hists *self, | |||
385 | .stat = { | 471 | .stat = { |
386 | .period = period, | 472 | .period = period, |
387 | .nr_events = 1, | 473 | .nr_events = 1, |
474 | .weight = weight, | ||
388 | }, | 475 | }, |
389 | .parent = sym_parent, | 476 | .parent = sym_parent, |
390 | .filtered = symbol__parent_filter(sym_parent), | 477 | .filtered = symbol__parent_filter(sym_parent), |
391 | .hists = self, | 478 | .hists = self, |
479 | .branch_info = NULL, | ||
480 | .mem_info = NULL, | ||
392 | }; | 481 | }; |
393 | 482 | ||
394 | return add_hist_entry(self, &entry, al, period); | 483 | return add_hist_entry(self, &entry, al, period, weight); |
395 | } | 484 | } |
396 | 485 | ||
397 | int64_t | 486 | int64_t |
@@ -431,6 +520,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
431 | void hist_entry__free(struct hist_entry *he) | 520 | void hist_entry__free(struct hist_entry *he) |
432 | { | 521 | { |
433 | free(he->branch_info); | 522 | free(he->branch_info); |
523 | free(he->mem_info); | ||
434 | free(he); | 524 | free(he); |
435 | } | 525 | } |
436 | 526 | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 38624686ee9a..14c2fe20aa62 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -49,6 +49,14 @@ enum hist_column { | |||
49 | HISTC_DSO_FROM, | 49 | HISTC_DSO_FROM, |
50 | HISTC_DSO_TO, | 50 | HISTC_DSO_TO, |
51 | HISTC_SRCLINE, | 51 | HISTC_SRCLINE, |
52 | HISTC_LOCAL_WEIGHT, | ||
53 | HISTC_GLOBAL_WEIGHT, | ||
54 | HISTC_MEM_DADDR_SYMBOL, | ||
55 | HISTC_MEM_DADDR_DSO, | ||
56 | HISTC_MEM_LOCKED, | ||
57 | HISTC_MEM_TLB, | ||
58 | HISTC_MEM_LVL, | ||
59 | HISTC_MEM_SNOOP, | ||
52 | HISTC_NR_COLS, /* Last entry */ | 60 | HISTC_NR_COLS, /* Last entry */ |
53 | }; | 61 | }; |
54 | 62 | ||
@@ -73,7 +81,8 @@ struct hists { | |||
73 | 81 | ||
74 | struct hist_entry *__hists__add_entry(struct hists *self, | 82 | struct hist_entry *__hists__add_entry(struct hists *self, |
75 | struct addr_location *al, | 83 | struct addr_location *al, |
76 | struct symbol *parent, u64 period); | 84 | struct symbol *parent, u64 period, |
85 | u64 weight); | ||
77 | int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); | 86 | int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); |
78 | int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); | 87 | int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); |
79 | int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, | 88 | int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, |
@@ -84,7 +93,15 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self, | |||
84 | struct addr_location *al, | 93 | struct addr_location *al, |
85 | struct symbol *sym_parent, | 94 | struct symbol *sym_parent, |
86 | struct branch_info *bi, | 95 | struct branch_info *bi, |
87 | u64 period); | 96 | u64 period, |
97 | u64 weight); | ||
98 | |||
99 | struct hist_entry *__hists__add_mem_entry(struct hists *self, | ||
100 | struct addr_location *al, | ||
101 | struct symbol *sym_parent, | ||
102 | struct mem_info *mi, | ||
103 | u64 period, | ||
104 | u64 weight); | ||
88 | 105 | ||
89 | void hists__output_resort(struct hists *self); | 106 | void hists__output_resort(struct hists *self); |
90 | void hists__output_resort_threaded(struct hists *hists); | 107 | void hists__output_resort_threaded(struct hists *hists); |
@@ -175,9 +192,9 @@ struct hist_browser_timer { | |||
175 | int refresh; | 192 | int refresh; |
176 | }; | 193 | }; |
177 | 194 | ||
178 | #ifdef NEWT_SUPPORT | 195 | #ifdef SLANG_SUPPORT |
179 | #include "../ui/keysyms.h" | 196 | #include "../ui/keysyms.h" |
180 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, | 197 | int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, |
181 | struct hist_browser_timer *hbt); | 198 | struct hist_browser_timer *hbt); |
182 | 199 | ||
183 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | 200 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, |
@@ -196,7 +213,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, | |||
196 | 213 | ||
197 | static inline int hist_entry__tui_annotate(struct hist_entry *self | 214 | static inline int hist_entry__tui_annotate(struct hist_entry *self |
198 | __maybe_unused, | 215 | __maybe_unused, |
199 | int evidx __maybe_unused, | 216 | struct perf_evsel *evsel |
217 | __maybe_unused, | ||
200 | struct hist_browser_timer *hbt | 218 | struct hist_browser_timer *hbt |
201 | __maybe_unused) | 219 | __maybe_unused) |
202 | { | 220 | { |
@@ -208,8 +226,9 @@ static inline int script_browse(const char *script_opt __maybe_unused) | |||
208 | return 0; | 226 | return 0; |
209 | } | 227 | } |
210 | 228 | ||
211 | #define K_LEFT -1 | 229 | #define K_LEFT -1000 |
212 | #define K_RIGHT -2 | 230 | #define K_RIGHT -2000 |
231 | #define K_SWITCH_INPUT_DATA -3000 | ||
213 | #endif | 232 | #endif |
214 | 233 | ||
215 | #ifdef GTK2_SUPPORT | 234 | #ifdef GTK2_SUPPORT |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index efdb38e65a92..b2ecad6ec46b 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -955,6 +955,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event | |||
955 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 955 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
956 | struct thread *thread; | 956 | struct thread *thread; |
957 | struct map *map; | 957 | struct map *map; |
958 | enum map_type type; | ||
958 | int ret = 0; | 959 | int ret = 0; |
959 | 960 | ||
960 | if (dump_trace) | 961 | if (dump_trace) |
@@ -971,10 +972,17 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event | |||
971 | thread = machine__findnew_thread(machine, event->mmap.pid); | 972 | thread = machine__findnew_thread(machine, event->mmap.pid); |
972 | if (thread == NULL) | 973 | if (thread == NULL) |
973 | goto out_problem; | 974 | goto out_problem; |
975 | |||
976 | if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) | ||
977 | type = MAP__VARIABLE; | ||
978 | else | ||
979 | type = MAP__FUNCTION; | ||
980 | |||
974 | map = map__new(&machine->user_dsos, event->mmap.start, | 981 | map = map__new(&machine->user_dsos, event->mmap.start, |
975 | event->mmap.len, event->mmap.pgoff, | 982 | event->mmap.len, event->mmap.pgoff, |
976 | event->mmap.pid, event->mmap.filename, | 983 | event->mmap.pid, event->mmap.filename, |
977 | MAP__FUNCTION); | 984 | type); |
985 | |||
978 | if (map == NULL) | 986 | if (map == NULL) |
979 | goto out_problem; | 987 | goto out_problem; |
980 | 988 | ||
@@ -1003,6 +1011,17 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event | |||
1003 | return 0; | 1011 | return 0; |
1004 | } | 1012 | } |
1005 | 1013 | ||
1014 | static void machine__remove_thread(struct machine *machine, struct thread *th) | ||
1015 | { | ||
1016 | machine->last_match = NULL; | ||
1017 | rb_erase(&th->rb_node, &machine->threads); | ||
1018 | /* | ||
1019 | * We may have references to this thread, for instance in some hist_entry | ||
1020 | * instances, so just move them to a separate list. | ||
1021 | */ | ||
1022 | list_add_tail(&th->node, &machine->dead_threads); | ||
1023 | } | ||
1024 | |||
1006 | int machine__process_exit_event(struct machine *machine, union perf_event *event) | 1025 | int machine__process_exit_event(struct machine *machine, union perf_event *event) |
1007 | { | 1026 | { |
1008 | struct thread *thread = machine__find_thread(machine, event->fork.tid); | 1027 | struct thread *thread = machine__find_thread(machine, event->fork.tid); |
@@ -1039,17 +1058,6 @@ int machine__process_event(struct machine *machine, union perf_event *event) | |||
1039 | return ret; | 1058 | return ret; |
1040 | } | 1059 | } |
1041 | 1060 | ||
1042 | void machine__remove_thread(struct machine *machine, struct thread *th) | ||
1043 | { | ||
1044 | machine->last_match = NULL; | ||
1045 | rb_erase(&th->rb_node, &machine->threads); | ||
1046 | /* | ||
1047 | * We may have references to this thread, for instance in some hist_entry | ||
1048 | * instances, so just move them to a separate list. | ||
1049 | */ | ||
1050 | list_add_tail(&th->node, &machine->dead_threads); | ||
1051 | } | ||
1052 | |||
1053 | static bool symbol__match_parent_regex(struct symbol *sym) | 1061 | static bool symbol__match_parent_regex(struct symbol *sym) |
1054 | { | 1062 | { |
1055 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) | 1063 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) |
@@ -1097,6 +1105,38 @@ found: | |||
1097 | ams->map = al.map; | 1105 | ams->map = al.map; |
1098 | } | 1106 | } |
1099 | 1107 | ||
1108 | static void ip__resolve_data(struct machine *machine, struct thread *thread, | ||
1109 | u8 m, struct addr_map_symbol *ams, u64 addr) | ||
1110 | { | ||
1111 | struct addr_location al; | ||
1112 | |||
1113 | memset(&al, 0, sizeof(al)); | ||
1114 | |||
1115 | thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al, | ||
1116 | NULL); | ||
1117 | ams->addr = addr; | ||
1118 | ams->al_addr = al.addr; | ||
1119 | ams->sym = al.sym; | ||
1120 | ams->map = al.map; | ||
1121 | } | ||
1122 | |||
1123 | struct mem_info *machine__resolve_mem(struct machine *machine, | ||
1124 | struct thread *thr, | ||
1125 | struct perf_sample *sample, | ||
1126 | u8 cpumode) | ||
1127 | { | ||
1128 | struct mem_info *mi = zalloc(sizeof(*mi)); | ||
1129 | |||
1130 | if (!mi) | ||
1131 | return NULL; | ||
1132 | |||
1133 | ip__resolve_ams(machine, thr, &mi->iaddr, sample->ip); | ||
1134 | ip__resolve_data(machine, thr, cpumode, &mi->daddr, sample->addr); | ||
1135 | mi->data_src.val = sample->data_src; | ||
1136 | |||
1137 | return mi; | ||
1138 | } | ||
1139 | |||
1100 | struct branch_info *machine__resolve_bstack(struct machine *machine, | 1140 | struct branch_info *machine__resolve_bstack(struct machine *machine, |
1101 | struct thread *thr, | 1141 | struct thread *thr, |
1102 | struct branch_stack *bs) | 1142 | struct branch_stack *bs) |
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 5ac5892f2326..77940680f1fc 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -76,6 +76,9 @@ void machine__delete(struct machine *machine); | |||
76 | struct branch_info *machine__resolve_bstack(struct machine *machine, | 76 | struct branch_info *machine__resolve_bstack(struct machine *machine, |
77 | struct thread *thread, | 77 | struct thread *thread, |
78 | struct branch_stack *bs); | 78 | struct branch_stack *bs); |
79 | struct mem_info *machine__resolve_mem(struct machine *machine, | ||
80 | struct thread *thread, | ||
81 | struct perf_sample *sample, u8 cpumode); | ||
79 | int machine__resolve_callchain(struct machine *machine, | 82 | int machine__resolve_callchain(struct machine *machine, |
80 | struct perf_evsel *evsel, | 83 | struct perf_evsel *evsel, |
81 | struct thread *thread, | 84 | struct thread *thread, |
@@ -97,7 +100,6 @@ static inline bool machine__is_host(struct machine *machine) | |||
97 | } | 100 | } |
98 | 101 | ||
99 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); | 102 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); |
100 | void machine__remove_thread(struct machine *machine, struct thread *th); | ||
101 | 103 | ||
102 | size_t machine__fprintf(struct machine *machine, FILE *fp); | 104 | size_t machine__fprintf(struct machine *machine, FILE *fp); |
103 | 105 | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c84f48cf9678..6c8bb0fb189b 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -10,7 +10,7 @@ | |||
10 | #include "symbol.h" | 10 | #include "symbol.h" |
11 | #include "cache.h" | 11 | #include "cache.h" |
12 | #include "header.h" | 12 | #include "header.h" |
13 | #include "debugfs.h" | 13 | #include <lk/debugfs.h> |
14 | #include "parse-events-bison.h" | 14 | #include "parse-events-bison.h" |
15 | #define YY_EXTRA_TYPE int | 15 | #define YY_EXTRA_TYPE int |
16 | #include "parse-events-flex.h" | 16 | #include "parse-events-flex.h" |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 49a256e6e0a2..aa04bf9c9ad7 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -40,7 +40,7 @@ | |||
40 | #include "color.h" | 40 | #include "color.h" |
41 | #include "symbol.h" | 41 | #include "symbol.h" |
42 | #include "thread.h" | 42 | #include "thread.h" |
43 | #include "debugfs.h" | 43 | #include <lk/debugfs.h> |
44 | #include "trace-event.h" /* For __maybe_unused */ | 44 | #include "trace-event.h" /* For __maybe_unused */ |
45 | #include "probe-event.h" | 45 | #include "probe-event.h" |
46 | #include "probe-finder.h" | 46 | #include "probe-finder.h" |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 64536a993f4a..f75ae1b9900c 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -15,7 +15,6 @@ util/thread_map.c | |||
15 | util/util.c | 15 | util/util.c |
16 | util/xyarray.c | 16 | util/xyarray.c |
17 | util/cgroup.c | 17 | util/cgroup.c |
18 | util/debugfs.c | ||
19 | util/rblist.c | 18 | util/rblist.c |
20 | util/strlist.c | 19 | util/strlist.c |
21 | util/sysfs.c | 20 | util/sysfs.c |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index bd85280bb6e8..cf1fe01b7e89 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1,5 +1,3 @@ | |||
1 | #define _FILE_OFFSET_BITS 64 | ||
2 | |||
3 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
4 | 2 | ||
5 | #include <byteswap.h> | 3 | #include <byteswap.h> |
@@ -800,6 +798,12 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, | |||
800 | 798 | ||
801 | if (sample_type & PERF_SAMPLE_STACK_USER) | 799 | if (sample_type & PERF_SAMPLE_STACK_USER) |
802 | stack_user__printf(&sample->user_stack); | 800 | stack_user__printf(&sample->user_stack); |
801 | |||
802 | if (sample_type & PERF_SAMPLE_WEIGHT) | ||
803 | printf("... weight: %" PRIu64 "\n", sample->weight); | ||
804 | |||
805 | if (sample_type & PERF_SAMPLE_DATA_SRC) | ||
806 | printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); | ||
803 | } | 807 | } |
804 | 808 | ||
805 | static struct machine * | 809 | static struct machine * |
@@ -1365,18 +1369,6 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp) | |||
1365 | return machine__fprintf(&session->machines.host, fp); | 1369 | return machine__fprintf(&session->machines.host, fp); |
1366 | } | 1370 | } |
1367 | 1371 | ||
1368 | void perf_session__remove_thread(struct perf_session *session, | ||
1369 | struct thread *th) | ||
1370 | { | ||
1371 | /* | ||
1372 | * FIXME: This one makes no sense, we need to remove the thread from | ||
1373 | * the machine it belongs to, perf_session can have many machines, so | ||
1374 | * doing it always on ->machines.host is wrong. Fix when auditing all | ||
1375 | * the 'perf kvm' code. | ||
1376 | */ | ||
1377 | machine__remove_thread(&session->machines.host, th); | ||
1378 | } | ||
1379 | |||
1380 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 1372 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
1381 | unsigned int type) | 1373 | unsigned int type) |
1382 | { | 1374 | { |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index b5c0847edfa9..6b51d47acdba 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -72,7 +72,6 @@ void perf_event__attr_swap(struct perf_event_attr *attr); | |||
72 | int perf_session__create_kernel_maps(struct perf_session *self); | 72 | int perf_session__create_kernel_maps(struct perf_session *self); |
73 | 73 | ||
74 | void perf_session__set_id_hdr_size(struct perf_session *session); | 74 | void perf_session__set_id_hdr_size(struct perf_session *session); |
75 | void perf_session__remove_thread(struct perf_session *self, struct thread *th); | ||
76 | 75 | ||
77 | static inline | 76 | static inline |
78 | struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) | 77 | struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 73d510269784..6b0ed322907e 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
@@ -24,6 +24,7 @@ cflags += getenv('CFLAGS', '').split() | |||
24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') | 24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') |
25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') | 25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') |
26 | libtraceevent = getenv('LIBTRACEEVENT') | 26 | libtraceevent = getenv('LIBTRACEEVENT') |
27 | liblk = getenv('LIBLK') | ||
27 | 28 | ||
28 | ext_sources = [f.strip() for f in file('util/python-ext-sources') | 29 | ext_sources = [f.strip() for f in file('util/python-ext-sources') |
29 | if len(f.strip()) > 0 and f[0] != '#'] | 30 | if len(f.strip()) > 0 and f[0] != '#'] |
@@ -32,7 +33,7 @@ perf = Extension('perf', | |||
32 | sources = ext_sources, | 33 | sources = ext_sources, |
33 | include_dirs = ['util/include'], | 34 | include_dirs = ['util/include'], |
34 | extra_compile_args = cflags, | 35 | extra_compile_args = cflags, |
35 | extra_objects = [libtraceevent], | 36 | extra_objects = [libtraceevent, liblk], |
36 | ) | 37 | ) |
37 | 38 | ||
38 | setup(name='perf', | 39 | setup(name='perf', |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index d41926cb9e3f..5f52d492590c 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 - map->unmap_ip(map, 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, |
@@ -464,6 +770,91 @@ struct sort_entry sort_mispredict = { | |||
464 | .se_width_idx = HISTC_MISPREDICT, | 770 | .se_width_idx = HISTC_MISPREDICT, |
465 | }; | 771 | }; |
466 | 772 | ||
773 | static u64 he_weight(struct hist_entry *he) | ||
774 | { | ||
775 | return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0; | ||
776 | } | ||
777 | |||
778 | static int64_t | ||
779 | sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right) | ||
780 | { | ||
781 | return he_weight(left) - he_weight(right); | ||
782 | } | ||
783 | |||
784 | static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf, | ||
785 | size_t size, unsigned int width) | ||
786 | { | ||
787 | return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self)); | ||
788 | } | ||
789 | |||
790 | struct sort_entry sort_local_weight = { | ||
791 | .se_header = "Local Weight", | ||
792 | .se_cmp = sort__local_weight_cmp, | ||
793 | .se_snprintf = hist_entry__local_weight_snprintf, | ||
794 | .se_width_idx = HISTC_LOCAL_WEIGHT, | ||
795 | }; | ||
796 | |||
797 | static int64_t | ||
798 | sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right) | ||
799 | { | ||
800 | return left->stat.weight - right->stat.weight; | ||
801 | } | ||
802 | |||
803 | static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf, | ||
804 | size_t size, unsigned int width) | ||
805 | { | ||
806 | return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight); | ||
807 | } | ||
808 | |||
809 | struct sort_entry sort_global_weight = { | ||
810 | .se_header = "Weight", | ||
811 | .se_cmp = sort__global_weight_cmp, | ||
812 | .se_snprintf = hist_entry__global_weight_snprintf, | ||
813 | .se_width_idx = HISTC_GLOBAL_WEIGHT, | ||
814 | }; | ||
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 | |||
467 | struct sort_dimension { | 858 | struct sort_dimension { |
468 | const char *name; | 859 | const char *name; |
469 | struct sort_entry *entry; | 860 | struct sort_entry *entry; |
@@ -480,6 +871,14 @@ static struct sort_dimension common_sort_dimensions[] = { | |||
480 | DIM(SORT_PARENT, "parent", sort_parent), | 871 | DIM(SORT_PARENT, "parent", sort_parent), |
481 | DIM(SORT_CPU, "cpu", sort_cpu), | 872 | DIM(SORT_CPU, "cpu", sort_cpu), |
482 | DIM(SORT_SRCLINE, "srcline", sort_srcline), | 873 | DIM(SORT_SRCLINE, "srcline", sort_srcline), |
874 | DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_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), | ||
483 | }; | 882 | }; |
484 | 883 | ||
485 | #undef DIM | 884 | #undef DIM |
@@ -516,7 +915,10 @@ int sort_dimension__add(const char *tok) | |||
516 | return -EINVAL; | 915 | return -EINVAL; |
517 | } | 916 | } |
518 | sort__has_parent = 1; | 917 | sort__has_parent = 1; |
519 | } 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) { | ||
520 | sort__has_sym = 1; | 922 | sort__has_sym = 1; |
521 | } | 923 | } |
522 | 924 | ||
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index b13e56f6ccbe..f24bdf64238c 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -49,6 +49,7 @@ struct he_stat { | |||
49 | u64 period_us; | 49 | u64 period_us; |
50 | u64 period_guest_sys; | 50 | u64 period_guest_sys; |
51 | u64 period_guest_us; | 51 | u64 period_guest_us; |
52 | u64 weight; | ||
52 | u32 nr_events; | 53 | u32 nr_events; |
53 | }; | 54 | }; |
54 | 55 | ||
@@ -100,7 +101,8 @@ struct hist_entry { | |||
100 | struct rb_root sorted_chain; | 101 | struct rb_root sorted_chain; |
101 | struct branch_info *branch_info; | 102 | struct branch_info *branch_info; |
102 | struct hists *hists; | 103 | struct hists *hists; |
103 | struct callchain_root callchain[0]; | 104 | struct mem_info *mem_info; |
105 | struct callchain_root callchain[0]; /* must be last member */ | ||
104 | }; | 106 | }; |
105 | 107 | ||
106 | static inline bool hist_entry__has_pairs(struct hist_entry *he) | 108 | static inline bool hist_entry__has_pairs(struct hist_entry *he) |
@@ -130,6 +132,14 @@ enum sort_type { | |||
130 | SORT_PARENT, | 132 | SORT_PARENT, |
131 | SORT_CPU, | 133 | SORT_CPU, |
132 | SORT_SRCLINE, | 134 | SORT_SRCLINE, |
135 | SORT_LOCAL_WEIGHT, | ||
136 | SORT_GLOBAL_WEIGHT, | ||
137 | SORT_MEM_DADDR_SYMBOL, | ||
138 | SORT_MEM_DADDR_DSO, | ||
139 | SORT_MEM_LOCKED, | ||
140 | SORT_MEM_TLB, | ||
141 | SORT_MEM_LVL, | ||
142 | SORT_MEM_SNOOP, | ||
133 | 143 | ||
134 | /* branch stack specific sort keys */ | 144 | /* branch stack specific sort keys */ |
135 | __SORT_BRANCH_STACK, | 145 | __SORT_BRANCH_STACK, |
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index 55433aa42c8f..eabdce0a2daa 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c | |||
@@ -143,7 +143,7 @@ struct strlist *strlist__new(bool dupstr, const char *list) | |||
143 | slist->rblist.node_delete = strlist__node_delete; | 143 | slist->rblist.node_delete = strlist__node_delete; |
144 | 144 | ||
145 | slist->dupstr = dupstr; | 145 | slist->dupstr = dupstr; |
146 | if (slist && strlist__parse_list(slist, list) != 0) | 146 | if (list && strlist__parse_list(slist, list) != 0) |
147 | goto out_error; | 147 | goto out_error; |
148 | } | 148 | } |
149 | 149 | ||
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 54efcb5659ac..4b12bf850325 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -806,9 +806,12 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
806 | * DWARF DW_compile_unit has this, but we don't always have access | 806 | * DWARF DW_compile_unit has this, but we don't always have access |
807 | * to it... | 807 | * to it... |
808 | */ | 808 | */ |
809 | demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); | 809 | if (symbol_conf.demangle) { |
810 | if (demangled != NULL) | 810 | demangled = bfd_demangle(NULL, elf_name, |
811 | elf_name = demangled; | 811 | DMGL_PARAMS | DMGL_ANSI); |
812 | if (demangled != NULL) | ||
813 | elf_name = demangled; | ||
814 | } | ||
812 | new_symbol: | 815 | new_symbol: |
813 | f = symbol__new(sym.st_value, sym.st_size, | 816 | f = symbol__new(sym.st_value, sym.st_size, |
814 | GELF_ST_BIND(sym.st_info), elf_name); | 817 | GELF_ST_BIND(sym.st_info), elf_name); |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e6432d85b43d..8cf3b5426a9a 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -36,6 +36,7 @@ struct symbol_conf symbol_conf = { | |||
36 | .use_modules = true, | 36 | .use_modules = true, |
37 | .try_vmlinux_path = true, | 37 | .try_vmlinux_path = true, |
38 | .annotate_src = true, | 38 | .annotate_src = true, |
39 | .demangle = true, | ||
39 | .symfs = "", | 40 | .symfs = "", |
40 | }; | 41 | }; |
41 | 42 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index b62ca37c4b77..5f720dc076da 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -97,7 +97,8 @@ struct symbol_conf { | |||
97 | kptr_restrict, | 97 | kptr_restrict, |
98 | annotate_asm_raw, | 98 | annotate_asm_raw, |
99 | annotate_src, | 99 | annotate_src, |
100 | event_group; | 100 | event_group, |
101 | demangle; | ||
101 | const char *vmlinux_name, | 102 | const char *vmlinux_name, |
102 | *kallsyms_name, | 103 | *kallsyms_name, |
103 | *source_prefix, | 104 | *source_prefix, |
@@ -155,6 +156,12 @@ struct branch_info { | |||
155 | struct branch_flags flags; | 156 | struct branch_flags flags; |
156 | }; | 157 | }; |
157 | 158 | ||
159 | struct mem_info { | ||
160 | struct addr_map_symbol iaddr; | ||
161 | struct addr_map_symbol daddr; | ||
162 | union perf_mem_data_src data_src; | ||
163 | }; | ||
164 | |||
158 | struct addr_location { | 165 | struct addr_location { |
159 | struct thread *thread; | 166 | struct thread *thread; |
160 | struct map *map; | 167 | struct map *map; |
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index f718df8a3c59..0cd8b3108084 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h | |||
@@ -21,4 +21,9 @@ void thread_map__delete(struct thread_map *threads); | |||
21 | 21 | ||
22 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); | 22 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); |
23 | 23 | ||
24 | static inline int thread_map__nr(struct thread_map *threads) | ||
25 | { | ||
26 | return threads ? threads->nr : 1; | ||
27 | } | ||
28 | |||
24 | #endif /* __PERF_THREAD_MAP_H */ | 29 | #endif /* __PERF_THREAD_MAP_H */ |
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index a8d81c35ef66..3917eb9a8479 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c | |||
@@ -38,52 +38,20 @@ | |||
38 | 38 | ||
39 | #include "../perf.h" | 39 | #include "../perf.h" |
40 | #include "trace-event.h" | 40 | #include "trace-event.h" |
41 | #include "debugfs.h" | 41 | #include <lk/debugfs.h> |
42 | #include "evsel.h" | 42 | #include "evsel.h" |
43 | 43 | ||
44 | #define VERSION "0.5" | 44 | #define VERSION "0.5" |
45 | 45 | ||
46 | #define TRACE_CTRL "tracing_on" | ||
47 | #define TRACE "trace" | ||
48 | #define AVAILABLE "available_tracers" | ||
49 | #define CURRENT "current_tracer" | ||
50 | #define ITER_CTRL "trace_options" | ||
51 | #define MAX_LATENCY "tracing_max_latency" | ||
52 | |||
53 | unsigned int page_size; | ||
54 | |||
55 | static const char *output_file = "trace.info"; | ||
56 | static int output_fd; | 46 | static int output_fd; |
57 | 47 | ||
58 | struct event_list { | ||
59 | struct event_list *next; | ||
60 | const char *event; | ||
61 | }; | ||
62 | |||
63 | struct events { | ||
64 | struct events *sibling; | ||
65 | struct events *children; | ||
66 | struct events *next; | ||
67 | char *name; | ||
68 | }; | ||
69 | |||
70 | |||
71 | static void *malloc_or_die(unsigned int size) | ||
72 | { | ||
73 | void *data; | ||
74 | |||
75 | data = malloc(size); | ||
76 | if (!data) | ||
77 | die("malloc"); | ||
78 | return data; | ||
79 | } | ||
80 | 48 | ||
81 | static const char *find_debugfs(void) | 49 | static const char *find_debugfs(void) |
82 | { | 50 | { |
83 | const char *path = debugfs_mount(NULL); | 51 | const char *path = perf_debugfs_mount(NULL); |
84 | 52 | ||
85 | if (!path) | 53 | if (!path) |
86 | die("Your kernel not support debugfs filesystem"); | 54 | pr_debug("Your kernel does not support the debugfs filesystem"); |
87 | 55 | ||
88 | return path; | 56 | return path; |
89 | } | 57 | } |
@@ -102,8 +70,12 @@ static const char *find_tracing_dir(void) | |||
102 | return tracing; | 70 | return tracing; |
103 | 71 | ||
104 | debugfs = find_debugfs(); | 72 | debugfs = find_debugfs(); |
73 | if (!debugfs) | ||
74 | return NULL; | ||
105 | 75 | ||
106 | tracing = malloc_or_die(strlen(debugfs) + 9); | 76 | tracing = malloc(strlen(debugfs) + 9); |
77 | if (!tracing) | ||
78 | return NULL; | ||
107 | 79 | ||
108 | sprintf(tracing, "%s/tracing", debugfs); | 80 | sprintf(tracing, "%s/tracing", debugfs); |
109 | 81 | ||
@@ -120,7 +92,9 @@ static char *get_tracing_file(const char *name) | |||
120 | if (!tracing) | 92 | if (!tracing) |
121 | return NULL; | 93 | return NULL; |
122 | 94 | ||
123 | file = malloc_or_die(strlen(tracing) + strlen(name) + 2); | 95 | file = malloc(strlen(tracing) + strlen(name) + 2); |
96 | if (!file) | ||
97 | return NULL; | ||
124 | 98 | ||
125 | sprintf(file, "%s/%s", tracing, name); | 99 | sprintf(file, "%s/%s", tracing, name); |
126 | return file; | 100 | return file; |
@@ -131,24 +105,6 @@ static void put_tracing_file(char *file) | |||
131 | free(file); | 105 | free(file); |
132 | } | 106 | } |
133 | 107 | ||
134 | static ssize_t calc_data_size; | ||
135 | |||
136 | static ssize_t write_or_die(const void *buf, size_t len) | ||
137 | { | ||
138 | int ret; | ||
139 | |||
140 | if (calc_data_size) { | ||
141 | calc_data_size += len; | ||
142 | return len; | ||
143 | } | ||
144 | |||
145 | ret = write(output_fd, buf, len); | ||
146 | if (ret < 0) | ||
147 | die("writing to '%s'", output_file); | ||
148 | |||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | int bigendian(void) | 108 | int bigendian(void) |
153 | { | 109 | { |
154 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; | 110 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; |
@@ -159,59 +115,106 @@ int bigendian(void) | |||
159 | } | 115 | } |
160 | 116 | ||
161 | /* unfortunately, you can not stat debugfs or proc files for size */ | 117 | /* unfortunately, you can not stat debugfs or proc files for size */ |
162 | static void record_file(const char *file, size_t hdr_sz) | 118 | static int record_file(const char *file, ssize_t hdr_sz) |
163 | { | 119 | { |
164 | unsigned long long size = 0; | 120 | unsigned long long size = 0; |
165 | char buf[BUFSIZ], *sizep; | 121 | char buf[BUFSIZ], *sizep; |
166 | off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR); | 122 | off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR); |
167 | int r, fd; | 123 | int r, fd; |
124 | int err = -EIO; | ||
168 | 125 | ||
169 | fd = open(file, O_RDONLY); | 126 | fd = open(file, O_RDONLY); |
170 | if (fd < 0) | 127 | if (fd < 0) { |
171 | die("Can't read '%s'", file); | 128 | pr_debug("Can't read '%s'", file); |
129 | return -errno; | ||
130 | } | ||
172 | 131 | ||
173 | /* put in zeros for file size, then fill true size later */ | 132 | /* put in zeros for file size, then fill true size later */ |
174 | if (hdr_sz) | 133 | if (hdr_sz) { |
175 | write_or_die(&size, hdr_sz); | 134 | if (write(output_fd, &size, hdr_sz) != hdr_sz) |
135 | goto out; | ||
136 | } | ||
176 | 137 | ||
177 | do { | 138 | do { |
178 | r = read(fd, buf, BUFSIZ); | 139 | r = read(fd, buf, BUFSIZ); |
179 | if (r > 0) { | 140 | if (r > 0) { |
180 | size += r; | 141 | size += r; |
181 | write_or_die(buf, r); | 142 | if (write(output_fd, buf, r) != r) |
143 | goto out; | ||
182 | } | 144 | } |
183 | } while (r > 0); | 145 | } while (r > 0); |
184 | close(fd); | ||
185 | 146 | ||
186 | /* ugh, handle big-endian hdr_size == 4 */ | 147 | /* ugh, handle big-endian hdr_size == 4 */ |
187 | sizep = (char*)&size; | 148 | sizep = (char*)&size; |
188 | if (bigendian()) | 149 | if (bigendian()) |
189 | sizep += sizeof(u64) - hdr_sz; | 150 | sizep += sizeof(u64) - hdr_sz; |
190 | 151 | ||
191 | if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) | 152 | if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) { |
192 | die("writing to %s", output_file); | 153 | pr_debug("writing file size failed\n"); |
154 | goto out; | ||
155 | } | ||
156 | |||
157 | err = 0; | ||
158 | out: | ||
159 | close(fd); | ||
160 | return err; | ||
193 | } | 161 | } |
194 | 162 | ||
195 | static void read_header_files(void) | 163 | static int read_header_files(void) |
196 | { | 164 | { |
197 | char *path; | 165 | char *path; |
198 | struct stat st; | 166 | struct stat st; |
167 | int err = -EIO; | ||
199 | 168 | ||
200 | path = get_tracing_file("events/header_page"); | 169 | path = get_tracing_file("events/header_page"); |
201 | if (stat(path, &st) < 0) | 170 | if (!path) { |
202 | die("can't read '%s'", path); | 171 | pr_debug("can't get tracing/events/header_page"); |
172 | return -ENOMEM; | ||
173 | } | ||
174 | |||
175 | if (stat(path, &st) < 0) { | ||
176 | pr_debug("can't read '%s'", path); | ||
177 | goto out; | ||
178 | } | ||
179 | |||
180 | if (write(output_fd, "header_page", 12) != 12) { | ||
181 | pr_debug("can't write header_page\n"); | ||
182 | goto out; | ||
183 | } | ||
184 | |||
185 | if (record_file(path, 8) < 0) { | ||
186 | pr_debug("can't record header_page file\n"); | ||
187 | goto out; | ||
188 | } | ||
203 | 189 | ||
204 | write_or_die("header_page", 12); | ||
205 | record_file(path, 8); | ||
206 | put_tracing_file(path); | 190 | put_tracing_file(path); |
207 | 191 | ||
208 | path = get_tracing_file("events/header_event"); | 192 | path = get_tracing_file("events/header_event"); |
209 | if (stat(path, &st) < 0) | 193 | if (!path) { |
210 | die("can't read '%s'", path); | 194 | pr_debug("can't get tracing/events/header_event"); |
195 | err = -ENOMEM; | ||
196 | goto out; | ||
197 | } | ||
198 | |||
199 | if (stat(path, &st) < 0) { | ||
200 | pr_debug("can't read '%s'", path); | ||
201 | goto out; | ||
202 | } | ||
211 | 203 | ||
212 | write_or_die("header_event", 13); | 204 | if (write(output_fd, "header_event", 13) != 13) { |
213 | record_file(path, 8); | 205 | pr_debug("can't write header_event\n"); |
206 | goto out; | ||
207 | } | ||
208 | |||
209 | if (record_file(path, 8) < 0) { | ||
210 | pr_debug("can't record header_event file\n"); | ||
211 | goto out; | ||
212 | } | ||
213 | |||
214 | err = 0; | ||
215 | out: | ||
214 | put_tracing_file(path); | 216 | put_tracing_file(path); |
217 | return err; | ||
215 | } | 218 | } |
216 | 219 | ||
217 | static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) | 220 | static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) |
@@ -225,7 +228,7 @@ static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) | |||
225 | return false; | 228 | return false; |
226 | } | 229 | } |
227 | 230 | ||
228 | static void copy_event_system(const char *sys, struct tracepoint_path *tps) | 231 | static int copy_event_system(const char *sys, struct tracepoint_path *tps) |
229 | { | 232 | { |
230 | struct dirent *dent; | 233 | struct dirent *dent; |
231 | struct stat st; | 234 | struct stat st; |
@@ -233,10 +236,13 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps) | |||
233 | DIR *dir; | 236 | DIR *dir; |
234 | int count = 0; | 237 | int count = 0; |
235 | int ret; | 238 | int ret; |
239 | int err; | ||
236 | 240 | ||
237 | dir = opendir(sys); | 241 | dir = opendir(sys); |
238 | if (!dir) | 242 | if (!dir) { |
239 | die("can't read directory '%s'", sys); | 243 | pr_debug("can't read directory '%s'", sys); |
244 | return -errno; | ||
245 | } | ||
240 | 246 | ||
241 | while ((dent = readdir(dir))) { | 247 | while ((dent = readdir(dir))) { |
242 | if (dent->d_type != DT_DIR || | 248 | if (dent->d_type != DT_DIR || |
@@ -244,7 +250,11 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps) | |||
244 | strcmp(dent->d_name, "..") == 0 || | 250 | strcmp(dent->d_name, "..") == 0 || |
245 | !name_in_tp_list(dent->d_name, tps)) | 251 | !name_in_tp_list(dent->d_name, tps)) |
246 | continue; | 252 | continue; |
247 | format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); | 253 | format = malloc(strlen(sys) + strlen(dent->d_name) + 10); |
254 | if (!format) { | ||
255 | err = -ENOMEM; | ||
256 | goto out; | ||
257 | } | ||
248 | sprintf(format, "%s/%s/format", sys, dent->d_name); | 258 | sprintf(format, "%s/%s/format", sys, dent->d_name); |
249 | ret = stat(format, &st); | 259 | ret = stat(format, &st); |
250 | free(format); | 260 | free(format); |
@@ -253,7 +263,11 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps) | |||
253 | count++; | 263 | count++; |
254 | } | 264 | } |
255 | 265 | ||
256 | write_or_die(&count, 4); | 266 | if (write(output_fd, &count, 4) != 4) { |
267 | err = -EIO; | ||
268 | pr_debug("can't write count\n"); | ||
269 | goto out; | ||
270 | } | ||
257 | 271 | ||
258 | rewinddir(dir); | 272 | rewinddir(dir); |
259 | while ((dent = readdir(dir))) { | 273 | while ((dent = readdir(dir))) { |
@@ -262,27 +276,45 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps) | |||
262 | strcmp(dent->d_name, "..") == 0 || | 276 | strcmp(dent->d_name, "..") == 0 || |
263 | !name_in_tp_list(dent->d_name, tps)) | 277 | !name_in_tp_list(dent->d_name, tps)) |
264 | continue; | 278 | continue; |
265 | format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); | 279 | format = malloc(strlen(sys) + strlen(dent->d_name) + 10); |
280 | if (!format) { | ||
281 | err = -ENOMEM; | ||
282 | goto out; | ||
283 | } | ||
266 | sprintf(format, "%s/%s/format", sys, dent->d_name); | 284 | sprintf(format, "%s/%s/format", sys, dent->d_name); |
267 | ret = stat(format, &st); | 285 | ret = stat(format, &st); |
268 | 286 | ||
269 | if (ret >= 0) | 287 | if (ret >= 0) { |
270 | record_file(format, 8); | 288 | err = record_file(format, 8); |
271 | 289 | if (err) { | |
290 | free(format); | ||
291 | goto out; | ||
292 | } | ||
293 | } | ||
272 | free(format); | 294 | free(format); |
273 | } | 295 | } |
296 | err = 0; | ||
297 | out: | ||
274 | closedir(dir); | 298 | closedir(dir); |
299 | return err; | ||
275 | } | 300 | } |
276 | 301 | ||
277 | static void read_ftrace_files(struct tracepoint_path *tps) | 302 | static int read_ftrace_files(struct tracepoint_path *tps) |
278 | { | 303 | { |
279 | char *path; | 304 | char *path; |
305 | int ret; | ||
280 | 306 | ||
281 | path = get_tracing_file("events/ftrace"); | 307 | path = get_tracing_file("events/ftrace"); |
308 | if (!path) { | ||
309 | pr_debug("can't get tracing/events/ftrace"); | ||
310 | return -ENOMEM; | ||
311 | } | ||
282 | 312 | ||
283 | copy_event_system(path, tps); | 313 | ret = copy_event_system(path, tps); |
284 | 314 | ||
285 | put_tracing_file(path); | 315 | put_tracing_file(path); |
316 | |||
317 | return ret; | ||
286 | } | 318 | } |
287 | 319 | ||
288 | static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) | 320 | static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) |
@@ -296,7 +328,7 @@ static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) | |||
296 | return false; | 328 | return false; |
297 | } | 329 | } |
298 | 330 | ||
299 | static void read_event_files(struct tracepoint_path *tps) | 331 | static int read_event_files(struct tracepoint_path *tps) |
300 | { | 332 | { |
301 | struct dirent *dent; | 333 | struct dirent *dent; |
302 | struct stat st; | 334 | struct stat st; |
@@ -305,12 +337,20 @@ static void read_event_files(struct tracepoint_path *tps) | |||
305 | DIR *dir; | 337 | DIR *dir; |
306 | int count = 0; | 338 | int count = 0; |
307 | int ret; | 339 | int ret; |
340 | int err; | ||
308 | 341 | ||
309 | path = get_tracing_file("events"); | 342 | path = get_tracing_file("events"); |
343 | if (!path) { | ||
344 | pr_debug("can't get tracing/events"); | ||
345 | return -ENOMEM; | ||
346 | } | ||
310 | 347 | ||
311 | dir = opendir(path); | 348 | dir = opendir(path); |
312 | if (!dir) | 349 | if (!dir) { |
313 | die("can't read directory '%s'", path); | 350 | err = -errno; |
351 | pr_debug("can't read directory '%s'", path); | ||
352 | goto out; | ||
353 | } | ||
314 | 354 | ||
315 | while ((dent = readdir(dir))) { | 355 | while ((dent = readdir(dir))) { |
316 | if (dent->d_type != DT_DIR || | 356 | if (dent->d_type != DT_DIR || |
@@ -322,7 +362,11 @@ static void read_event_files(struct tracepoint_path *tps) | |||
322 | count++; | 362 | count++; |
323 | } | 363 | } |
324 | 364 | ||
325 | write_or_die(&count, 4); | 365 | if (write(output_fd, &count, 4) != 4) { |
366 | err = -EIO; | ||
367 | pr_debug("can't write count\n"); | ||
368 | goto out; | ||
369 | } | ||
326 | 370 | ||
327 | rewinddir(dir); | 371 | rewinddir(dir); |
328 | while ((dent = readdir(dir))) { | 372 | while ((dent = readdir(dir))) { |
@@ -332,56 +376,90 @@ static void read_event_files(struct tracepoint_path *tps) | |||
332 | strcmp(dent->d_name, "ftrace") == 0 || | 376 | strcmp(dent->d_name, "ftrace") == 0 || |
333 | !system_in_tp_list(dent->d_name, tps)) | 377 | !system_in_tp_list(dent->d_name, tps)) |
334 | continue; | 378 | continue; |
335 | sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); | 379 | sys = malloc(strlen(path) + strlen(dent->d_name) + 2); |
380 | if (!sys) { | ||
381 | err = -ENOMEM; | ||
382 | goto out; | ||
383 | } | ||
336 | sprintf(sys, "%s/%s", path, dent->d_name); | 384 | sprintf(sys, "%s/%s", path, dent->d_name); |
337 | ret = stat(sys, &st); | 385 | ret = stat(sys, &st); |
338 | if (ret >= 0) { | 386 | if (ret >= 0) { |
339 | write_or_die(dent->d_name, strlen(dent->d_name) + 1); | 387 | ssize_t size = strlen(dent->d_name) + 1; |
340 | copy_event_system(sys, tps); | 388 | |
389 | if (write(output_fd, dent->d_name, size) != size || | ||
390 | copy_event_system(sys, tps) < 0) { | ||
391 | err = -EIO; | ||
392 | free(sys); | ||
393 | goto out; | ||
394 | } | ||
341 | } | 395 | } |
342 | free(sys); | 396 | free(sys); |
343 | } | 397 | } |
344 | 398 | err = 0; | |
399 | out: | ||
345 | closedir(dir); | 400 | closedir(dir); |
346 | put_tracing_file(path); | 401 | put_tracing_file(path); |
402 | |||
403 | return err; | ||
347 | } | 404 | } |
348 | 405 | ||
349 | static void read_proc_kallsyms(void) | 406 | static int read_proc_kallsyms(void) |
350 | { | 407 | { |
351 | unsigned int size; | 408 | unsigned int size; |
352 | const char *path = "/proc/kallsyms"; | 409 | const char *path = "/proc/kallsyms"; |
353 | struct stat st; | 410 | struct stat st; |
354 | int ret; | 411 | int ret, err = 0; |
355 | 412 | ||
356 | ret = stat(path, &st); | 413 | ret = stat(path, &st); |
357 | if (ret < 0) { | 414 | if (ret < 0) { |
358 | /* not found */ | 415 | /* not found */ |
359 | size = 0; | 416 | size = 0; |
360 | write_or_die(&size, 4); | 417 | if (write(output_fd, &size, 4) != 4) |
361 | return; | 418 | err = -EIO; |
419 | return err; | ||
362 | } | 420 | } |
363 | record_file(path, 4); | 421 | return record_file(path, 4); |
364 | } | 422 | } |
365 | 423 | ||
366 | static void read_ftrace_printk(void) | 424 | static int read_ftrace_printk(void) |
367 | { | 425 | { |
368 | unsigned int size; | 426 | unsigned int size; |
369 | char *path; | 427 | char *path; |
370 | struct stat st; | 428 | struct stat st; |
371 | int ret; | 429 | int ret, err = 0; |
372 | 430 | ||
373 | path = get_tracing_file("printk_formats"); | 431 | path = get_tracing_file("printk_formats"); |
432 | if (!path) { | ||
433 | pr_debug("can't get tracing/printk_formats"); | ||
434 | return -ENOMEM; | ||
435 | } | ||
436 | |||
374 | ret = stat(path, &st); | 437 | ret = stat(path, &st); |
375 | if (ret < 0) { | 438 | if (ret < 0) { |
376 | /* not found */ | 439 | /* not found */ |
377 | size = 0; | 440 | size = 0; |
378 | write_or_die(&size, 4); | 441 | if (write(output_fd, &size, 4) != 4) |
442 | err = -EIO; | ||
379 | goto out; | 443 | goto out; |
380 | } | 444 | } |
381 | record_file(path, 4); | 445 | err = record_file(path, 4); |
382 | 446 | ||
383 | out: | 447 | out: |
384 | put_tracing_file(path); | 448 | put_tracing_file(path); |
449 | return err; | ||
450 | } | ||
451 | |||
452 | static void | ||
453 | put_tracepoints_path(struct tracepoint_path *tps) | ||
454 | { | ||
455 | while (tps) { | ||
456 | struct tracepoint_path *t = tps; | ||
457 | |||
458 | tps = tps->next; | ||
459 | free(t->name); | ||
460 | free(t->system); | ||
461 | free(t); | ||
462 | } | ||
385 | } | 463 | } |
386 | 464 | ||
387 | static struct tracepoint_path * | 465 | static struct tracepoint_path * |
@@ -396,27 +474,17 @@ get_tracepoints_path(struct list_head *pattrs) | |||
396 | continue; | 474 | continue; |
397 | ++nr_tracepoints; | 475 | ++nr_tracepoints; |
398 | ppath->next = tracepoint_id_to_path(pos->attr.config); | 476 | ppath->next = tracepoint_id_to_path(pos->attr.config); |
399 | if (!ppath->next) | 477 | if (!ppath->next) { |
400 | die("%s\n", "No memory to alloc tracepoints list"); | 478 | pr_debug("No memory to alloc tracepoints list\n"); |
479 | put_tracepoints_path(&path); | ||
480 | return NULL; | ||
481 | } | ||
401 | ppath = ppath->next; | 482 | ppath = ppath->next; |
402 | } | 483 | } |
403 | 484 | ||
404 | return nr_tracepoints > 0 ? path.next : NULL; | 485 | return nr_tracepoints > 0 ? path.next : NULL; |
405 | } | 486 | } |
406 | 487 | ||
407 | static void | ||
408 | put_tracepoints_path(struct tracepoint_path *tps) | ||
409 | { | ||
410 | while (tps) { | ||
411 | struct tracepoint_path *t = tps; | ||
412 | |||
413 | tps = tps->next; | ||
414 | free(t->name); | ||
415 | free(t->system); | ||
416 | free(t); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | bool have_tracepoints(struct list_head *pattrs) | 488 | bool have_tracepoints(struct list_head *pattrs) |
421 | { | 489 | { |
422 | struct perf_evsel *pos; | 490 | struct perf_evsel *pos; |
@@ -428,9 +496,10 @@ bool have_tracepoints(struct list_head *pattrs) | |||
428 | return false; | 496 | return false; |
429 | } | 497 | } |
430 | 498 | ||
431 | static void tracing_data_header(void) | 499 | static int tracing_data_header(void) |
432 | { | 500 | { |
433 | char buf[20]; | 501 | char buf[20]; |
502 | ssize_t size; | ||
434 | 503 | ||
435 | /* just guessing this is someone's birthday.. ;) */ | 504 | /* just guessing this is someone's birthday.. ;) */ |
436 | buf[0] = 23; | 505 | buf[0] = 23; |
@@ -438,9 +507,12 @@ static void tracing_data_header(void) | |||
438 | buf[2] = 68; | 507 | buf[2] = 68; |
439 | memcpy(buf + 3, "tracing", 7); | 508 | memcpy(buf + 3, "tracing", 7); |
440 | 509 | ||
441 | write_or_die(buf, 10); | 510 | if (write(output_fd, buf, 10) != 10) |
511 | return -1; | ||
442 | 512 | ||
443 | write_or_die(VERSION, strlen(VERSION) + 1); | 513 | size = strlen(VERSION) + 1; |
514 | if (write(output_fd, VERSION, size) != size) | ||
515 | return -1; | ||
444 | 516 | ||
445 | /* save endian */ | 517 | /* save endian */ |
446 | if (bigendian()) | 518 | if (bigendian()) |
@@ -450,15 +522,19 @@ static void tracing_data_header(void) | |||
450 | 522 | ||
451 | read_trace_init(buf[0], buf[0]); | 523 | read_trace_init(buf[0], buf[0]); |
452 | 524 | ||
453 | write_or_die(buf, 1); | 525 | if (write(output_fd, buf, 1) != 1) |
526 | return -1; | ||
454 | 527 | ||
455 | /* save size of long */ | 528 | /* save size of long */ |
456 | buf[0] = sizeof(long); | 529 | buf[0] = sizeof(long); |
457 | write_or_die(buf, 1); | 530 | if (write(output_fd, buf, 1) != 1) |
531 | return -1; | ||
458 | 532 | ||
459 | /* save page_size */ | 533 | /* save page_size */ |
460 | page_size = sysconf(_SC_PAGESIZE); | 534 | if (write(output_fd, &page_size, 4) != 4) |
461 | write_or_die(&page_size, 4); | 535 | return -1; |
536 | |||
537 | return 0; | ||
462 | } | 538 | } |
463 | 539 | ||
464 | struct tracing_data *tracing_data_get(struct list_head *pattrs, | 540 | struct tracing_data *tracing_data_get(struct list_head *pattrs, |
@@ -466,6 +542,7 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, | |||
466 | { | 542 | { |
467 | struct tracepoint_path *tps; | 543 | struct tracepoint_path *tps; |
468 | struct tracing_data *tdata; | 544 | struct tracing_data *tdata; |
545 | int err; | ||
469 | 546 | ||
470 | output_fd = fd; | 547 | output_fd = fd; |
471 | 548 | ||
@@ -473,7 +550,10 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, | |||
473 | if (!tps) | 550 | if (!tps) |
474 | return NULL; | 551 | return NULL; |
475 | 552 | ||
476 | tdata = malloc_or_die(sizeof(*tdata)); | 553 | tdata = malloc(sizeof(*tdata)); |
554 | if (!tdata) | ||
555 | return NULL; | ||
556 | |||
477 | tdata->temp = temp; | 557 | tdata->temp = temp; |
478 | tdata->size = 0; | 558 | tdata->size = 0; |
479 | 559 | ||
@@ -482,12 +562,16 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, | |||
482 | 562 | ||
483 | snprintf(tdata->temp_file, sizeof(tdata->temp_file), | 563 | snprintf(tdata->temp_file, sizeof(tdata->temp_file), |
484 | "/tmp/perf-XXXXXX"); | 564 | "/tmp/perf-XXXXXX"); |
485 | if (!mkstemp(tdata->temp_file)) | 565 | if (!mkstemp(tdata->temp_file)) { |
486 | die("Can't make temp file"); | 566 | pr_debug("Can't make temp file"); |
567 | return NULL; | ||
568 | } | ||
487 | 569 | ||
488 | temp_fd = open(tdata->temp_file, O_RDWR); | 570 | temp_fd = open(tdata->temp_file, O_RDWR); |
489 | if (temp_fd < 0) | 571 | if (temp_fd < 0) { |
490 | die("Can't read '%s'", tdata->temp_file); | 572 | pr_debug("Can't read '%s'", tdata->temp_file); |
573 | return NULL; | ||
574 | } | ||
491 | 575 | ||
492 | /* | 576 | /* |
493 | * Set the temp file the default output, so all the | 577 | * Set the temp file the default output, so all the |
@@ -496,13 +580,24 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, | |||
496 | output_fd = temp_fd; | 580 | output_fd = temp_fd; |
497 | } | 581 | } |
498 | 582 | ||
499 | tracing_data_header(); | 583 | err = tracing_data_header(); |
500 | read_header_files(); | 584 | if (err) |
501 | read_ftrace_files(tps); | 585 | goto out; |
502 | read_event_files(tps); | 586 | err = read_header_files(); |
503 | read_proc_kallsyms(); | 587 | if (err) |
504 | read_ftrace_printk(); | 588 | goto out; |
589 | err = read_ftrace_files(tps); | ||
590 | if (err) | ||
591 | goto out; | ||
592 | err = read_event_files(tps); | ||
593 | if (err) | ||
594 | goto out; | ||
595 | err = read_proc_kallsyms(); | ||
596 | if (err) | ||
597 | goto out; | ||
598 | err = read_ftrace_printk(); | ||
505 | 599 | ||
600 | out: | ||
506 | /* | 601 | /* |
507 | * All tracing data are stored by now, we can restore | 602 | * All tracing data are stored by now, we can restore |
508 | * the default output file in case we used temp file. | 603 | * the default output file in case we used temp file. |
@@ -513,22 +608,31 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, | |||
513 | output_fd = fd; | 608 | output_fd = fd; |
514 | } | 609 | } |
515 | 610 | ||
611 | if (err) { | ||
612 | free(tdata); | ||
613 | tdata = NULL; | ||
614 | } | ||
615 | |||
516 | put_tracepoints_path(tps); | 616 | put_tracepoints_path(tps); |
517 | return tdata; | 617 | return tdata; |
518 | } | 618 | } |
519 | 619 | ||
520 | void tracing_data_put(struct tracing_data *tdata) | 620 | int tracing_data_put(struct tracing_data *tdata) |
521 | { | 621 | { |
622 | int err = 0; | ||
623 | |||
522 | if (tdata->temp) { | 624 | if (tdata->temp) { |
523 | record_file(tdata->temp_file, 0); | 625 | err = record_file(tdata->temp_file, 0); |
524 | unlink(tdata->temp_file); | 626 | unlink(tdata->temp_file); |
525 | } | 627 | } |
526 | 628 | ||
527 | free(tdata); | 629 | free(tdata); |
630 | return err; | ||
528 | } | 631 | } |
529 | 632 | ||
530 | int read_tracing_data(int fd, struct list_head *pattrs) | 633 | int read_tracing_data(int fd, struct list_head *pattrs) |
531 | { | 634 | { |
635 | int err; | ||
532 | struct tracing_data *tdata; | 636 | struct tracing_data *tdata; |
533 | 637 | ||
534 | /* | 638 | /* |
@@ -539,6 +643,6 @@ int read_tracing_data(int fd, struct list_head *pattrs) | |||
539 | if (!tdata) | 643 | if (!tdata) |
540 | return -ENOMEM; | 644 | return -ENOMEM; |
541 | 645 | ||
542 | tracing_data_put(tdata); | 646 | err = tracing_data_put(tdata); |
543 | return 0; | 647 | return err; |
544 | } | 648 | } |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 3aabcd687cd5..4454835a9ebc 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -183,43 +183,6 @@ void event_format__print(struct event_format *event, | |||
183 | trace_seq_do_printf(&s); | 183 | trace_seq_do_printf(&s); |
184 | } | 184 | } |
185 | 185 | ||
186 | void print_trace_event(struct pevent *pevent, int cpu, void *data, int size) | ||
187 | { | ||
188 | int type = trace_parse_common_type(pevent, data); | ||
189 | struct event_format *event = pevent_find_event(pevent, type); | ||
190 | |||
191 | if (!event) { | ||
192 | warning("ug! no event found for type %d", type); | ||
193 | return; | ||
194 | } | ||
195 | |||
196 | event_format__print(event, cpu, data, size); | ||
197 | } | ||
198 | |||
199 | void print_event(struct pevent *pevent, int cpu, void *data, int size, | ||
200 | unsigned long long nsecs, char *comm) | ||
201 | { | ||
202 | struct pevent_record record; | ||
203 | struct trace_seq s; | ||
204 | int pid; | ||
205 | |||
206 | pevent->latency_format = latency_format; | ||
207 | |||
208 | record.ts = nsecs; | ||
209 | record.cpu = cpu; | ||
210 | record.size = size; | ||
211 | record.data = data; | ||
212 | pid = pevent_data_pid(pevent, &record); | ||
213 | |||
214 | if (!pevent_pid_is_registered(pevent, pid)) | ||
215 | pevent_register_comm(pevent, comm, pid); | ||
216 | |||
217 | trace_seq_init(&s); | ||
218 | pevent_print_event(pevent, &s, &record); | ||
219 | trace_seq_do_printf(&s); | ||
220 | printf("\n"); | ||
221 | } | ||
222 | |||
223 | void parse_proc_kallsyms(struct pevent *pevent, | 186 | void parse_proc_kallsyms(struct pevent *pevent, |
224 | char *file, unsigned int size __maybe_unused) | 187 | char *file, unsigned int size __maybe_unused) |
225 | { | 188 | { |
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 3741572696af..af215c0d2379 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -18,8 +18,6 @@ | |||
18 | * | 18 | * |
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
20 | */ | 20 | */ |
21 | #define _FILE_OFFSET_BITS 64 | ||
22 | |||
23 | #include <dirent.h> | 21 | #include <dirent.h> |
24 | #include <stdio.h> | 22 | #include <stdio.h> |
25 | #include <stdlib.h> | 23 | #include <stdlib.h> |
@@ -41,26 +39,14 @@ | |||
41 | 39 | ||
42 | static int input_fd; | 40 | static int input_fd; |
43 | 41 | ||
44 | static int read_page; | ||
45 | |||
46 | int file_bigendian; | 42 | int file_bigendian; |
47 | int host_bigendian; | 43 | int host_bigendian; |
48 | static int long_size; | 44 | static int long_size; |
49 | 45 | ||
50 | static ssize_t calc_data_size; | 46 | static ssize_t trace_data_size; |
51 | static bool repipe; | 47 | static bool repipe; |
52 | 48 | ||
53 | static void *malloc_or_die(int size) | 49 | static int __do_read(int fd, void *buf, int size) |
54 | { | ||
55 | void *ret; | ||
56 | |||
57 | ret = malloc(size); | ||
58 | if (!ret) | ||
59 | die("malloc"); | ||
60 | return ret; | ||
61 | } | ||
62 | |||
63 | static int do_read(int fd, void *buf, int size) | ||
64 | { | 50 | { |
65 | int rsize = size; | 51 | int rsize = size; |
66 | 52 | ||
@@ -73,8 +59,10 @@ static int do_read(int fd, void *buf, int size) | |||
73 | if (repipe) { | 59 | if (repipe) { |
74 | int retw = write(STDOUT_FILENO, buf, ret); | 60 | int retw = write(STDOUT_FILENO, buf, ret); |
75 | 61 | ||
76 | if (retw <= 0 || retw != ret) | 62 | if (retw <= 0 || retw != ret) { |
77 | die("repiping input file"); | 63 | pr_debug("repiping input file"); |
64 | return -1; | ||
65 | } | ||
78 | } | 66 | } |
79 | 67 | ||
80 | size -= ret; | 68 | size -= ret; |
@@ -84,17 +72,18 @@ static int do_read(int fd, void *buf, int size) | |||
84 | return rsize; | 72 | return rsize; |
85 | } | 73 | } |
86 | 74 | ||
87 | static int read_or_die(void *data, int size) | 75 | static int do_read(void *data, int size) |
88 | { | 76 | { |
89 | int r; | 77 | int r; |
90 | 78 | ||
91 | r = do_read(input_fd, data, size); | 79 | r = __do_read(input_fd, data, size); |
92 | if (r <= 0) | 80 | if (r <= 0) { |
93 | die("reading input file (size expected=%d received=%d)", | 81 | pr_debug("reading input file (size expected=%d received=%d)", |
94 | size, r); | 82 | size, r); |
83 | return -1; | ||
84 | } | ||
95 | 85 | ||
96 | if (calc_data_size) | 86 | trace_data_size += r; |
97 | calc_data_size += r; | ||
98 | 87 | ||
99 | return r; | 88 | return r; |
100 | } | 89 | } |
@@ -107,7 +96,7 @@ static void skip(int size) | |||
107 | 96 | ||
108 | while (size) { | 97 | while (size) { |
109 | r = size > BUFSIZ ? BUFSIZ : size; | 98 | r = size > BUFSIZ ? BUFSIZ : size; |
110 | read_or_die(buf, r); | 99 | do_read(buf, r); |
111 | size -= r; | 100 | size -= r; |
112 | }; | 101 | }; |
113 | } | 102 | } |
@@ -116,7 +105,8 @@ static unsigned int read4(struct pevent *pevent) | |||
116 | { | 105 | { |
117 | unsigned int data; | 106 | unsigned int data; |
118 | 107 | ||
119 | read_or_die(&data, 4); | 108 | if (do_read(&data, 4) < 0) |
109 | return 0; | ||
120 | return __data2host4(pevent, data); | 110 | return __data2host4(pevent, data); |
121 | } | 111 | } |
122 | 112 | ||
@@ -124,7 +114,8 @@ static unsigned long long read8(struct pevent *pevent) | |||
124 | { | 114 | { |
125 | unsigned long long data; | 115 | unsigned long long data; |
126 | 116 | ||
127 | read_or_die(&data, 8); | 117 | if (do_read(&data, 8) < 0) |
118 | return 0; | ||
128 | return __data2host8(pevent, data); | 119 | return __data2host8(pevent, data); |
129 | } | 120 | } |
130 | 121 | ||
@@ -138,17 +129,23 @@ static char *read_string(void) | |||
138 | 129 | ||
139 | for (;;) { | 130 | for (;;) { |
140 | r = read(input_fd, &c, 1); | 131 | r = read(input_fd, &c, 1); |
141 | if (r < 0) | 132 | if (r < 0) { |
142 | die("reading input file"); | 133 | pr_debug("reading input file"); |
134 | goto out; | ||
135 | } | ||
143 | 136 | ||
144 | if (!r) | 137 | if (!r) { |
145 | die("no data"); | 138 | pr_debug("no data"); |
139 | goto out; | ||
140 | } | ||
146 | 141 | ||
147 | if (repipe) { | 142 | if (repipe) { |
148 | int retw = write(STDOUT_FILENO, &c, 1); | 143 | int retw = write(STDOUT_FILENO, &c, 1); |
149 | 144 | ||
150 | if (retw <= 0 || retw != r) | 145 | if (retw <= 0 || retw != r) { |
151 | die("repiping input file string"); | 146 | pr_debug("repiping input file string"); |
147 | goto out; | ||
148 | } | ||
152 | } | 149 | } |
153 | 150 | ||
154 | buf[size++] = c; | 151 | buf[size++] = c; |
@@ -157,60 +154,79 @@ static char *read_string(void) | |||
157 | break; | 154 | break; |
158 | } | 155 | } |
159 | 156 | ||
160 | if (calc_data_size) | 157 | trace_data_size += size; |
161 | calc_data_size += size; | ||
162 | |||
163 | str = malloc_or_die(size); | ||
164 | memcpy(str, buf, size); | ||
165 | 158 | ||
159 | str = malloc(size); | ||
160 | if (str) | ||
161 | memcpy(str, buf, size); | ||
162 | out: | ||
166 | return str; | 163 | return str; |
167 | } | 164 | } |
168 | 165 | ||
169 | static void read_proc_kallsyms(struct pevent *pevent) | 166 | static int read_proc_kallsyms(struct pevent *pevent) |
170 | { | 167 | { |
171 | unsigned int size; | 168 | unsigned int size; |
172 | char *buf; | 169 | char *buf; |
173 | 170 | ||
174 | size = read4(pevent); | 171 | size = read4(pevent); |
175 | if (!size) | 172 | if (!size) |
176 | return; | 173 | return 0; |
174 | |||
175 | buf = malloc(size + 1); | ||
176 | if (buf == NULL) | ||
177 | return -1; | ||
177 | 178 | ||
178 | buf = malloc_or_die(size + 1); | 179 | if (do_read(buf, size) < 0) { |
179 | read_or_die(buf, size); | 180 | free(buf); |
181 | return -1; | ||
182 | } | ||
180 | buf[size] = '\0'; | 183 | buf[size] = '\0'; |
181 | 184 | ||
182 | parse_proc_kallsyms(pevent, buf, size); | 185 | parse_proc_kallsyms(pevent, buf, size); |
183 | 186 | ||
184 | free(buf); | 187 | free(buf); |
188 | return 0; | ||
185 | } | 189 | } |
186 | 190 | ||
187 | static void read_ftrace_printk(struct pevent *pevent) | 191 | static int read_ftrace_printk(struct pevent *pevent) |
188 | { | 192 | { |
189 | unsigned int size; | 193 | unsigned int size; |
190 | char *buf; | 194 | char *buf; |
191 | 195 | ||
196 | /* it can have 0 size */ | ||
192 | size = read4(pevent); | 197 | size = read4(pevent); |
193 | if (!size) | 198 | if (!size) |
194 | return; | 199 | return 0; |
200 | |||
201 | buf = malloc(size); | ||
202 | if (buf == NULL) | ||
203 | return -1; | ||
195 | 204 | ||
196 | buf = malloc_or_die(size); | 205 | if (do_read(buf, size) < 0) { |
197 | read_or_die(buf, size); | 206 | free(buf); |
207 | return -1; | ||
208 | } | ||
198 | 209 | ||
199 | parse_ftrace_printk(pevent, buf, size); | 210 | parse_ftrace_printk(pevent, buf, size); |
200 | 211 | ||
201 | free(buf); | 212 | free(buf); |
213 | return 0; | ||
202 | } | 214 | } |
203 | 215 | ||
204 | static void read_header_files(struct pevent *pevent) | 216 | static int read_header_files(struct pevent *pevent) |
205 | { | 217 | { |
206 | unsigned long long size; | 218 | unsigned long long size; |
207 | char *header_event; | 219 | char *header_event; |
208 | char buf[BUFSIZ]; | 220 | char buf[BUFSIZ]; |
221 | int ret = 0; | ||
209 | 222 | ||
210 | read_or_die(buf, 12); | 223 | if (do_read(buf, 12) < 0) |
224 | return -1; | ||
211 | 225 | ||
212 | if (memcmp(buf, "header_page", 12) != 0) | 226 | if (memcmp(buf, "header_page", 12) != 0) { |
213 | die("did not read header page"); | 227 | pr_debug("did not read header page"); |
228 | return -1; | ||
229 | } | ||
214 | 230 | ||
215 | size = read8(pevent); | 231 | size = read8(pevent); |
216 | skip(size); | 232 | skip(size); |
@@ -221,269 +237,107 @@ static void read_header_files(struct pevent *pevent) | |||
221 | */ | 237 | */ |
222 | long_size = header_page_size_size; | 238 | long_size = header_page_size_size; |
223 | 239 | ||
224 | read_or_die(buf, 13); | 240 | if (do_read(buf, 13) < 0) |
225 | if (memcmp(buf, "header_event", 13) != 0) | 241 | return -1; |
226 | die("did not read header event"); | 242 | |
243 | if (memcmp(buf, "header_event", 13) != 0) { | ||
244 | pr_debug("did not read header event"); | ||
245 | return -1; | ||
246 | } | ||
227 | 247 | ||
228 | size = read8(pevent); | 248 | size = read8(pevent); |
229 | header_event = malloc_or_die(size); | 249 | header_event = malloc(size); |
230 | read_or_die(header_event, size); | 250 | if (header_event == NULL) |
251 | return -1; | ||
252 | |||
253 | if (do_read(header_event, size) < 0) | ||
254 | ret = -1; | ||
255 | |||
231 | free(header_event); | 256 | free(header_event); |
257 | return ret; | ||
232 | } | 258 | } |
233 | 259 | ||
234 | static void read_ftrace_file(struct pevent *pevent, unsigned long long size) | 260 | static int read_ftrace_file(struct pevent *pevent, unsigned long long size) |
235 | { | 261 | { |
236 | char *buf; | 262 | char *buf; |
237 | 263 | ||
238 | buf = malloc_or_die(size); | 264 | buf = malloc(size); |
239 | read_or_die(buf, size); | 265 | if (buf == NULL) |
266 | return -1; | ||
267 | |||
268 | if (do_read(buf, size) < 0) { | ||
269 | free(buf); | ||
270 | return -1; | ||
271 | } | ||
272 | |||
240 | parse_ftrace_file(pevent, buf, size); | 273 | parse_ftrace_file(pevent, buf, size); |
241 | free(buf); | 274 | free(buf); |
275 | return 0; | ||
242 | } | 276 | } |
243 | 277 | ||
244 | static void read_event_file(struct pevent *pevent, char *sys, | 278 | static int read_event_file(struct pevent *pevent, char *sys, |
245 | unsigned long long size) | 279 | unsigned long long size) |
246 | { | 280 | { |
247 | char *buf; | 281 | char *buf; |
248 | 282 | ||
249 | buf = malloc_or_die(size); | 283 | buf = malloc(size); |
250 | read_or_die(buf, size); | 284 | if (buf == NULL) |
285 | return -1; | ||
286 | |||
287 | if (do_read(buf, size) < 0) { | ||
288 | free(buf); | ||
289 | return -1; | ||
290 | } | ||
291 | |||
251 | parse_event_file(pevent, buf, size, sys); | 292 | parse_event_file(pevent, buf, size, sys); |
252 | free(buf); | 293 | free(buf); |
294 | return 0; | ||
253 | } | 295 | } |
254 | 296 | ||
255 | static void read_ftrace_files(struct pevent *pevent) | 297 | static int read_ftrace_files(struct pevent *pevent) |
256 | { | 298 | { |
257 | unsigned long long size; | 299 | unsigned long long size; |
258 | int count; | 300 | int count; |
259 | int i; | 301 | int i; |
302 | int ret; | ||
260 | 303 | ||
261 | count = read4(pevent); | 304 | count = read4(pevent); |
262 | 305 | ||
263 | for (i = 0; i < count; i++) { | 306 | for (i = 0; i < count; i++) { |
264 | size = read8(pevent); | 307 | size = read8(pevent); |
265 | read_ftrace_file(pevent, size); | 308 | ret = read_ftrace_file(pevent, size); |
309 | if (ret) | ||
310 | return ret; | ||
266 | } | 311 | } |
312 | return 0; | ||
267 | } | 313 | } |
268 | 314 | ||
269 | static void read_event_files(struct pevent *pevent) | 315 | static int read_event_files(struct pevent *pevent) |
270 | { | 316 | { |
271 | unsigned long long size; | 317 | unsigned long long size; |
272 | char *sys; | 318 | char *sys; |
273 | int systems; | 319 | int systems; |
274 | int count; | 320 | int count; |
275 | int i,x; | 321 | int i,x; |
322 | int ret; | ||
276 | 323 | ||
277 | systems = read4(pevent); | 324 | systems = read4(pevent); |
278 | 325 | ||
279 | for (i = 0; i < systems; i++) { | 326 | for (i = 0; i < systems; i++) { |
280 | sys = read_string(); | 327 | sys = read_string(); |
328 | if (sys == NULL) | ||
329 | return -1; | ||
281 | 330 | ||
282 | count = read4(pevent); | 331 | count = read4(pevent); |
332 | |||
283 | for (x=0; x < count; x++) { | 333 | for (x=0; x < count; x++) { |
284 | size = read8(pevent); | 334 | size = read8(pevent); |
285 | read_event_file(pevent, sys, size); | 335 | ret = read_event_file(pevent, sys, size); |
336 | if (ret) | ||
337 | return ret; | ||
286 | } | 338 | } |
287 | } | 339 | } |
288 | } | 340 | return 0; |
289 | |||
290 | struct cpu_data { | ||
291 | unsigned long long offset; | ||
292 | unsigned long long size; | ||
293 | unsigned long long timestamp; | ||
294 | struct pevent_record *next; | ||
295 | char *page; | ||
296 | int cpu; | ||
297 | int index; | ||
298 | int page_size; | ||
299 | }; | ||
300 | |||
301 | static struct cpu_data *cpu_data; | ||
302 | |||
303 | static void update_cpu_data_index(int cpu) | ||
304 | { | ||
305 | cpu_data[cpu].offset += page_size; | ||
306 | cpu_data[cpu].size -= page_size; | ||
307 | cpu_data[cpu].index = 0; | ||
308 | } | ||
309 | |||
310 | static void get_next_page(int cpu) | ||
311 | { | ||
312 | off_t save_seek; | ||
313 | off_t ret; | ||
314 | |||
315 | if (!cpu_data[cpu].page) | ||
316 | return; | ||
317 | |||
318 | if (read_page) { | ||
319 | if (cpu_data[cpu].size <= page_size) { | ||
320 | free(cpu_data[cpu].page); | ||
321 | cpu_data[cpu].page = NULL; | ||
322 | return; | ||
323 | } | ||
324 | |||
325 | update_cpu_data_index(cpu); | ||
326 | |||
327 | /* other parts of the code may expect the pointer to not move */ | ||
328 | save_seek = lseek(input_fd, 0, SEEK_CUR); | ||
329 | |||
330 | ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET); | ||
331 | if (ret == (off_t)-1) | ||
332 | die("failed to lseek"); | ||
333 | ret = read(input_fd, cpu_data[cpu].page, page_size); | ||
334 | if (ret < 0) | ||
335 | die("failed to read page"); | ||
336 | |||
337 | /* reset the file pointer back */ | ||
338 | lseek(input_fd, save_seek, SEEK_SET); | ||
339 | |||
340 | return; | ||
341 | } | ||
342 | |||
343 | munmap(cpu_data[cpu].page, page_size); | ||
344 | cpu_data[cpu].page = NULL; | ||
345 | |||
346 | if (cpu_data[cpu].size <= page_size) | ||
347 | return; | ||
348 | |||
349 | update_cpu_data_index(cpu); | ||
350 | |||
351 | cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, | ||
352 | input_fd, cpu_data[cpu].offset); | ||
353 | if (cpu_data[cpu].page == MAP_FAILED) | ||
354 | die("failed to mmap cpu %d at offset 0x%llx", | ||
355 | cpu, cpu_data[cpu].offset); | ||
356 | } | ||
357 | |||
358 | static unsigned int type_len4host(unsigned int type_len_ts) | ||
359 | { | ||
360 | if (file_bigendian) | ||
361 | return (type_len_ts >> 27) & ((1 << 5) - 1); | ||
362 | else | ||
363 | return type_len_ts & ((1 << 5) - 1); | ||
364 | } | ||
365 | |||
366 | static unsigned int ts4host(unsigned int type_len_ts) | ||
367 | { | ||
368 | if (file_bigendian) | ||
369 | return type_len_ts & ((1 << 27) - 1); | ||
370 | else | ||
371 | return type_len_ts >> 5; | ||
372 | } | ||
373 | |||
374 | static int calc_index(void *ptr, int cpu) | ||
375 | { | ||
376 | return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; | ||
377 | } | ||
378 | |||
379 | struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu) | ||
380 | { | ||
381 | struct pevent_record *data; | ||
382 | void *page = cpu_data[cpu].page; | ||
383 | int idx = cpu_data[cpu].index; | ||
384 | void *ptr = page + idx; | ||
385 | unsigned long long extend; | ||
386 | unsigned int type_len_ts; | ||
387 | unsigned int type_len; | ||
388 | unsigned int delta; | ||
389 | unsigned int length = 0; | ||
390 | |||
391 | if (cpu_data[cpu].next) | ||
392 | return cpu_data[cpu].next; | ||
393 | |||
394 | if (!page) | ||
395 | return NULL; | ||
396 | |||
397 | if (!idx) { | ||
398 | /* FIXME: handle header page */ | ||
399 | if (header_page_ts_size != 8) | ||
400 | die("expected a long long type for timestamp"); | ||
401 | cpu_data[cpu].timestamp = data2host8(pevent, ptr); | ||
402 | ptr += 8; | ||
403 | switch (header_page_size_size) { | ||
404 | case 4: | ||
405 | cpu_data[cpu].page_size = data2host4(pevent, ptr); | ||
406 | ptr += 4; | ||
407 | break; | ||
408 | case 8: | ||
409 | cpu_data[cpu].page_size = data2host8(pevent, ptr); | ||
410 | ptr += 8; | ||
411 | break; | ||
412 | default: | ||
413 | die("bad long size"); | ||
414 | } | ||
415 | ptr = cpu_data[cpu].page + header_page_data_offset; | ||
416 | } | ||
417 | |||
418 | read_again: | ||
419 | idx = calc_index(ptr, cpu); | ||
420 | |||
421 | if (idx >= cpu_data[cpu].page_size) { | ||
422 | get_next_page(cpu); | ||
423 | return trace_peek_data(pevent, cpu); | ||
424 | } | ||
425 | |||
426 | type_len_ts = data2host4(pevent, ptr); | ||
427 | ptr += 4; | ||
428 | |||
429 | type_len = type_len4host(type_len_ts); | ||
430 | delta = ts4host(type_len_ts); | ||
431 | |||
432 | switch (type_len) { | ||
433 | case RINGBUF_TYPE_PADDING: | ||
434 | if (!delta) | ||
435 | die("error, hit unexpected end of page"); | ||
436 | length = data2host4(pevent, ptr); | ||
437 | ptr += 4; | ||
438 | length *= 4; | ||
439 | ptr += length; | ||
440 | goto read_again; | ||
441 | |||
442 | case RINGBUF_TYPE_TIME_EXTEND: | ||
443 | extend = data2host4(pevent, ptr); | ||
444 | ptr += 4; | ||
445 | extend <<= TS_SHIFT; | ||
446 | extend += delta; | ||
447 | cpu_data[cpu].timestamp += extend; | ||
448 | goto read_again; | ||
449 | |||
450 | case RINGBUF_TYPE_TIME_STAMP: | ||
451 | ptr += 12; | ||
452 | break; | ||
453 | case 0: | ||
454 | length = data2host4(pevent, ptr); | ||
455 | ptr += 4; | ||
456 | die("here! length=%d", length); | ||
457 | break; | ||
458 | default: | ||
459 | length = type_len * 4; | ||
460 | break; | ||
461 | } | ||
462 | |||
463 | cpu_data[cpu].timestamp += delta; | ||
464 | |||
465 | data = malloc_or_die(sizeof(*data)); | ||
466 | memset(data, 0, sizeof(*data)); | ||
467 | |||
468 | data->ts = cpu_data[cpu].timestamp; | ||
469 | data->size = length; | ||
470 | data->data = ptr; | ||
471 | ptr += length; | ||
472 | |||
473 | cpu_data[cpu].index = calc_index(ptr, cpu); | ||
474 | cpu_data[cpu].next = data; | ||
475 | |||
476 | return data; | ||
477 | } | ||
478 | |||
479 | struct pevent_record *trace_read_data(struct pevent *pevent, int cpu) | ||
480 | { | ||
481 | struct pevent_record *data; | ||
482 | |||
483 | data = trace_peek_data(pevent, cpu); | ||
484 | cpu_data[cpu].next = NULL; | ||
485 | |||
486 | return data; | ||
487 | } | 341 | } |
488 | 342 | ||
489 | ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | 343 | ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) |
@@ -494,58 +348,85 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
494 | int show_version = 0; | 348 | int show_version = 0; |
495 | int show_funcs = 0; | 349 | int show_funcs = 0; |
496 | int show_printk = 0; | 350 | int show_printk = 0; |
497 | ssize_t size; | 351 | ssize_t size = -1; |
352 | struct pevent *pevent; | ||
353 | int err; | ||
498 | 354 | ||
499 | calc_data_size = 1; | 355 | *ppevent = NULL; |
500 | repipe = __repipe; | ||
501 | 356 | ||
357 | repipe = __repipe; | ||
502 | input_fd = fd; | 358 | input_fd = fd; |
503 | 359 | ||
504 | read_or_die(buf, 3); | 360 | if (do_read(buf, 3) < 0) |
505 | if (memcmp(buf, test, 3) != 0) | 361 | return -1; |
506 | die("no trace data in the file"); | 362 | if (memcmp(buf, test, 3) != 0) { |
363 | pr_debug("no trace data in the file"); | ||
364 | return -1; | ||
365 | } | ||
507 | 366 | ||
508 | read_or_die(buf, 7); | 367 | if (do_read(buf, 7) < 0) |
509 | if (memcmp(buf, "tracing", 7) != 0) | 368 | return -1; |
510 | die("not a trace file (missing 'tracing' tag)"); | 369 | if (memcmp(buf, "tracing", 7) != 0) { |
370 | pr_debug("not a trace file (missing 'tracing' tag)"); | ||
371 | return -1; | ||
372 | } | ||
511 | 373 | ||
512 | version = read_string(); | 374 | version = read_string(); |
375 | if (version == NULL) | ||
376 | return -1; | ||
513 | if (show_version) | 377 | if (show_version) |
514 | printf("version = %s\n", version); | 378 | printf("version = %s\n", version); |
515 | free(version); | 379 | free(version); |
516 | 380 | ||
517 | read_or_die(buf, 1); | 381 | if (do_read(buf, 1) < 0) |
382 | return -1; | ||
518 | file_bigendian = buf[0]; | 383 | file_bigendian = buf[0]; |
519 | host_bigendian = bigendian(); | 384 | host_bigendian = bigendian(); |
520 | 385 | ||
521 | *ppevent = read_trace_init(file_bigendian, host_bigendian); | 386 | pevent = read_trace_init(file_bigendian, host_bigendian); |
522 | if (*ppevent == NULL) | 387 | if (pevent == NULL) { |
523 | die("read_trace_init failed"); | 388 | pr_debug("read_trace_init failed"); |
389 | goto out; | ||
390 | } | ||
524 | 391 | ||
525 | read_or_die(buf, 1); | 392 | if (do_read(buf, 1) < 0) |
393 | goto out; | ||
526 | long_size = buf[0]; | 394 | long_size = buf[0]; |
527 | 395 | ||
528 | page_size = read4(*ppevent); | 396 | page_size = read4(pevent); |
529 | 397 | if (!page_size) | |
530 | read_header_files(*ppevent); | 398 | goto out; |
531 | 399 | ||
532 | read_ftrace_files(*ppevent); | 400 | err = read_header_files(pevent); |
533 | read_event_files(*ppevent); | 401 | if (err) |
534 | read_proc_kallsyms(*ppevent); | 402 | goto out; |
535 | read_ftrace_printk(*ppevent); | 403 | err = read_ftrace_files(pevent); |
536 | 404 | if (err) | |
537 | size = calc_data_size - 1; | 405 | goto out; |
538 | calc_data_size = 0; | 406 | err = read_event_files(pevent); |
407 | if (err) | ||
408 | goto out; | ||
409 | err = read_proc_kallsyms(pevent); | ||
410 | if (err) | ||
411 | goto out; | ||
412 | err = read_ftrace_printk(pevent); | ||
413 | if (err) | ||
414 | goto out; | ||
415 | |||
416 | size = trace_data_size; | ||
539 | repipe = false; | 417 | repipe = false; |
540 | 418 | ||
541 | if (show_funcs) { | 419 | if (show_funcs) { |
542 | pevent_print_funcs(*ppevent); | 420 | pevent_print_funcs(pevent); |
543 | return size; | 421 | } else if (show_printk) { |
544 | } | 422 | pevent_print_printk(pevent); |
545 | if (show_printk) { | ||
546 | pevent_print_printk(*ppevent); | ||
547 | return size; | ||
548 | } | 423 | } |
549 | 424 | ||
425 | *ppevent = pevent; | ||
426 | pevent = NULL; | ||
427 | |||
428 | out: | ||
429 | if (pevent) | ||
430 | pevent_free(pevent); | ||
550 | return size; | 431 | return size; |
551 | } | 432 | } |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index a55fd37ffea1..1978c398ad87 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -30,13 +30,9 @@ enum { | |||
30 | int bigendian(void); | 30 | int bigendian(void); |
31 | 31 | ||
32 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian); | 32 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian); |
33 | void print_trace_event(struct pevent *pevent, int cpu, void *data, int size); | ||
34 | void event_format__print(struct event_format *event, | 33 | void event_format__print(struct event_format *event, |
35 | int cpu, void *data, int size); | 34 | int cpu, void *data, int size); |
36 | 35 | ||
37 | void print_event(struct pevent *pevent, int cpu, void *data, int size, | ||
38 | unsigned long long nsecs, char *comm); | ||
39 | |||
40 | int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); | 36 | int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); |
41 | int parse_event_file(struct pevent *pevent, | 37 | int parse_event_file(struct pevent *pevent, |
42 | char *buf, unsigned long size, char *sys); | 38 | char *buf, unsigned long size, char *sys); |
@@ -72,7 +68,7 @@ struct tracing_data { | |||
72 | 68 | ||
73 | struct tracing_data *tracing_data_get(struct list_head *pattrs, | 69 | struct tracing_data *tracing_data_get(struct list_head *pattrs, |
74 | int fd, bool temp); | 70 | int fd, bool temp); |
75 | void tracing_data_put(struct tracing_data *tdata); | 71 | int tracing_data_put(struct tracing_data *tdata); |
76 | 72 | ||
77 | 73 | ||
78 | struct addr_location; | 74 | struct addr_location; |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 805d1f52c5b4..59d868add275 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -17,6 +17,8 @@ bool test_attr__enabled; | |||
17 | bool perf_host = true; | 17 | bool perf_host = true; |
18 | bool perf_guest = false; | 18 | bool perf_guest = false; |
19 | 19 | ||
20 | char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; | ||
21 | |||
20 | void event_attr_init(struct perf_event_attr *attr) | 22 | void event_attr_init(struct perf_event_attr *attr) |
21 | { | 23 | { |
22 | if (!perf_host) | 24 | if (!perf_host) |
@@ -242,3 +244,28 @@ void get_term_dimensions(struct winsize *ws) | |||
242 | ws->ws_row = 25; | 244 | ws->ws_row = 25; |
243 | ws->ws_col = 80; | 245 | ws->ws_col = 80; |
244 | } | 246 | } |
247 | |||
248 | static void set_tracing_events_path(const char *mountpoint) | ||
249 | { | ||
250 | snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", | ||
251 | mountpoint, "tracing/events"); | ||
252 | } | ||
253 | |||
254 | const char *perf_debugfs_mount(const char *mountpoint) | ||
255 | { | ||
256 | const char *mnt; | ||
257 | |||
258 | mnt = debugfs_mount(mountpoint); | ||
259 | if (!mnt) | ||
260 | return NULL; | ||
261 | |||
262 | set_tracing_events_path(mnt); | ||
263 | |||
264 | return mnt; | ||
265 | } | ||
266 | |||
267 | void perf_debugfs_set_path(const char *mntpt) | ||
268 | { | ||
269 | snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt); | ||
270 | set_tracing_events_path(mntpt); | ||
271 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 09b4c26b71aa..a45710b70a55 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -1,8 +1,6 @@ | |||
1 | #ifndef GIT_COMPAT_UTIL_H | 1 | #ifndef GIT_COMPAT_UTIL_H |
2 | #define GIT_COMPAT_UTIL_H | 2 | #define GIT_COMPAT_UTIL_H |
3 | 3 | ||
4 | #define _FILE_OFFSET_BITS 64 | ||
5 | |||
6 | #ifndef FLEX_ARRAY | 4 | #ifndef FLEX_ARRAY |
7 | /* | 5 | /* |
8 | * See if our compiler is known to support flexible array members. | 6 | * See if our compiler is known to support flexible array members. |
@@ -73,10 +71,14 @@ | |||
73 | #include <linux/magic.h> | 71 | #include <linux/magic.h> |
74 | #include "types.h" | 72 | #include "types.h" |
75 | #include <sys/ttydefaults.h> | 73 | #include <sys/ttydefaults.h> |
74 | #include <lk/debugfs.h> | ||
76 | 75 | ||
77 | extern const char *graph_line; | 76 | extern const char *graph_line; |
78 | extern const char *graph_dotted_line; | 77 | extern const char *graph_dotted_line; |
79 | extern char buildid_dir[]; | 78 | extern char buildid_dir[]; |
79 | extern char tracing_events_path[]; | ||
80 | extern void perf_debugfs_set_path(const char *mountpoint); | ||
81 | const char *perf_debugfs_mount(const char *mountpoint); | ||
80 | 82 | ||
81 | /* On most systems <limits.h> would have given us this, but | 83 | /* On most systems <limits.h> would have given us this, but |
82 | * not on some systems (e.g. GNU/Hurd). | 84 | * not on some systems (e.g. GNU/Hurd). |
@@ -274,5 +276,4 @@ extern unsigned int page_size; | |||
274 | 276 | ||
275 | struct winsize; | 277 | struct winsize; |
276 | void get_term_dimensions(struct winsize *ws); | 278 | void get_term_dimensions(struct winsize *ws); |
277 | 279 | #endif /* GIT_COMPAT_UTIL_H */ | |
278 | #endif | ||