aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-04-30 10:41:01 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-30 10:41:01 -0400
commite0972916e8fe943f342b0dd1c9d43dbf5bc261c2 (patch)
tree690c436f1f9b839c4ba34d17ab3efa63b97a2dce /tools/perf/util
parent1f889ec62c3f0d8913f3c32f9aff2a1e15099346 (diff)
parent5ac2b5c2721501a8f5c5e1cd4116cbc31ace6886 (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar: "Features: - Add "uretprobes" - an optimization to uprobes, like kretprobes are an optimization to kprobes. "perf probe -x file sym%return" now works like kretprobes. By Oleg Nesterov. - Introduce per core aggregation in 'perf stat', from Stephane Eranian. - Add memory profiling via PEBS, from Stephane Eranian. - Event group view for 'annotate' in --stdio, --tui and --gtk, from Namhyung Kim. - Add support for AMD NB and L2I "uncore" counters, by Jacob Shin. - Add Ivy Bridge-EP uncore support, by Zheng Yan - IBM zEnterprise EC12 oprofile support patchlet from Robert Richter. - Add perf test entries for checking breakpoint overflow signal handler issues, from Jiri Olsa. - Add perf test entry for for checking number of EXIT events, from Namhyung Kim. - Add perf test entries for checking --cpu in record and stat, from Jiri Olsa. - Introduce perf stat --repeat forever, from Frederik Deweerdt. - Add --no-demangle to report/top, from Namhyung Kim. - PowerPC fixes plus a couple of cleanups/optimizations in uprobes and trace_uprobes, by Oleg Nesterov. Various fixes and refactorings: - Fix dependency of the python binding wrt libtraceevent, from Naohiro Aota. - Simplify some perf_evlist methods and to allow 'stat' to share code with 'record' and 'trace', by Arnaldo Carvalho de Melo. - Remove dead code in related to libtraceevent integration, from Namhyung Kim. - Revert "perf sched: Handle PERF_RECORD_EXIT events" to get 'perf sched lat' back working, by Arnaldo Carvalho de Melo - We don't use Newt anymore, just plain libslang, by Arnaldo Carvalho de Melo. - Kill a bunch of die() calls, from Namhyung Kim. - Fix build on non-glibc systems due to libio.h absence, from Cody P Schafer. - Remove some perf_session and tracing dead code, from David Ahern. - Honor parallel jobs, fix from Borislav Petkov - Introduce tools/lib/lk library, initially just removing duplication among tools/perf and tools/vm. from Borislav Petkov ... and many more I missed to list, see the shortlog and git log for more details." * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (136 commits) perf/x86/intel/P4: Robistify P4 PMU types perf/x86/amd: Fix AMD NB and L2I "uncore" support perf/x86/amd: Remove old-style NB counter support from perf_event_amd.c perf/x86: Check all MSRs before passing hw check perf/x86/amd: Add support for AMD NB and L2I "uncore" counters perf/x86/intel: Add Ivy Bridge-EP uncore support perf/x86/intel: Fix SNB-EP CBO and PCU uncore PMU filter management perf/x86: Avoid kfree() in CPU_{STARTING,DYING} uprobes/perf: Avoid perf_trace_buf_prepare/submit if ->perf_events is empty uprobes/tracing: Don't pass addr=ip to perf_trace_buf_submit() uprobes/tracing: Change create_trace_uprobe() to support uretprobes uprobes/tracing: Make seq_printf() code uretprobe-friendly uprobes/tracing: Make register_uprobe_event() paths uretprobe-friendly uprobes/tracing: Make uprobe_{trace,perf}_print() uretprobe-friendly uprobes/tracing: Introduce is_ret_probe() and uretprobe_dispatcher() uprobes/tracing: Introduce uprobe_{trace,perf}_print() helpers uprobes/tracing: Generalize struct uprobe_trace_entry_head uprobes/tracing: Kill the pointless local_save_flags/preempt_count calls uprobes/tracing: Kill the pointless seq_print_ip_sym() call uprobes/tracing: Kill the pointless task_pt_regs() calls ...
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/annotate.c262
-rw-r--r--tools/perf/util/annotate.h51
-rw-r--r--tools/perf/util/cpumap.c86
-rw-r--r--tools/perf/util/cpumap.h12
-rw-r--r--tools/perf/util/debugfs.c114
-rw-r--r--tools/perf/util/debugfs.h12
-rw-r--r--tools/perf/util/event.h9
-rw-r--r--tools/perf/util/evlist.c73
-rw-r--r--tools/perf/util/evlist.h9
-rw-r--r--tools/perf/util/evsel.c32
-rw-r--r--tools/perf/util/evsel.h25
-rw-r--r--tools/perf/util/header.c15
-rw-r--r--tools/perf/util/hist.c110
-rw-r--r--tools/perf/util/hist.h28
-rw-r--r--tools/perf/util/machine.c64
-rw-r--r--tools/perf/util/machine.h4
-rw-r--r--tools/perf/util/parse-events.c2
-rw-r--r--tools/perf/util/probe-event.c2
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/session.c20
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/setup.py3
-rw-r--r--tools/perf/util/sort.c414
-rw-r--r--tools/perf/util/sort.h12
-rw-r--r--tools/perf/util/symbol-elf.c9
-rw-r--r--tools/perf/util/symbol.c1
-rw-r--r--tools/perf/util/symbol.h9
-rw-r--r--tools/perf/util/thread_map.h5
-rw-r--r--tools/perf/util/trace-event-info.c380
-rw-r--r--tools/perf/util/trace-event-parse.c37
-rw-r--r--tools/perf/util/trace-event-read.c473
-rw-r--r--tools/perf/util/trace-event.h6
-rw-r--r--tools/perf/util/util.c27
-rw-r--r--tools/perf/util/util.h9
34 files changed, 1515 insertions, 802 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
606double 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
605static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, 640static 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(&notes->src->source, dl); 658 next = disasm__get_next_ip_line(&notes->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, &notes->src->source, node) { 686 list_for_each_entry_from(queue, &notes->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 */
691static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, 763static 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
959static 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
885static void __resort_source_line(struct rb_root *root, struct source_line *src_line) 972static 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 */
937static int symbol__get_source_line(struct symbol *sym, struct map *map, 1030static 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
1021static void symbol__annotate_hits(struct symbol *sym, int evidx) 1149static 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
1034int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 1162int 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, &notes->src->source, node) { 1201 list_for_each_entry(pos, &notes->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
1166int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 1302int 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);
50bool ins__is_call(const struct ins *ins); 50bool ins__is_call(const struct ins *ins);
51int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); 51int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
52 52
53struct annotation;
54
53struct disasm_line { 55struct 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);
68struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); 70struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
69int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); 71int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
70size_t disasm__fprintf(struct list_head *head, FILE *fp); 72size_t disasm__fprintf(struct list_head *head, FILE *fp);
73double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
74 s64 end, const char **path);
71 75
72struct sym_hist { 76struct sym_hist {
73 u64 sum; 77 u64 sum;
74 u64 addr[0]; 78 u64 addr[0];
75}; 79};
76 80
77struct source_line { 81struct source_line_percent {
78 struct rb_node node;
79 double percent; 82 double percent;
80 double percent_sum; 83 double percent_sum;
84};
85
86struct 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
131int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); 140int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
132int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); 141int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym);
133int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 142int 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);
136void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 145void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
137void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 146void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
138void disasm__purge(struct list_head *head); 147void disasm__purge(struct list_head *head);
139 148
140int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 149int 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
145int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 154int 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
148static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, 158static 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
159int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, 169int 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
162static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx, 173static 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
168void perf_gtk__show_annotations(void); 180void perf_gtk__show_annotations(void);
169#else 181#else
170static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused, 182static 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
8static struct cpu_map *cpu_map__default_new(void) 9static 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
234int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) 235static int cmp_ids(const void *a, const void *b)
235{ 236{
236 struct cpu_map *sock; 237 return *(int *)a - *(int *)b;
238}
239
240static 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
270int 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
311int 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
316int 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);
15struct cpu_map *cpu_map__read(FILE *file); 15struct cpu_map *cpu_map__read(FILE *file);
16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
17int cpu_map__get_socket(struct cpu_map *map, int idx); 17int cpu_map__get_socket(struct cpu_map *map, int idx);
18int cpu_map__get_core(struct cpu_map *map, int idx);
18int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); 19int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
20int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep);
19 21
20static inline int cpu_map__socket(struct cpu_map *sock, int s) 22static 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
29static inline int cpu_map__id_to_socket(int id)
30{
31 return id >> 16;
32}
33
34static inline int cpu_map__id_to_cpu(int id)
35{
36 return id & 0xffff;
37}
38
27static inline int cpu_map__nr(const struct cpu_map *map) 39static 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
8static int debugfs_premounted;
9char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug";
10char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
11
12static const char *debugfs_known_mountpoints[] = {
13 "/sys/kernel/debug/",
14 "/debug/",
15 0,
16};
17
18static int debugfs_found;
19
20/* find the path to the mounted debugfs */
21const 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
62int 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
74static 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
82char *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));
105out:
106 debugfs_set_tracing_events_path(debugfs_mountpoint);
107 return debugfs_mountpoint;
108}
109
110void 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
4const char *debugfs_find_mountpoint(void);
5int debugfs_valid_mountpoint(const char *debugfs);
6char *debugfs_mount(const char *mountpoint);
7void debugfs_set_path(const char *mountpoint);
8
9extern char debugfs_mountpoint[];
10extern 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
100struct build_id_event { 109struct 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
41struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 41struct 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
259static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 262static 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
472out_unmap: 479out_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
511out_unmap: 519out_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
723void 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
715int perf_evlist__open(struct perf_evlist *evlist) 733int 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;
727out_err: 745out_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
738int perf_evlist__prepare_workload(struct perf_evlist *evlist, 751int 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
52struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 52struct perf_evlist *perf_evlist__new(void);
53 struct thread_map *threads);
54void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, 53void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
55 struct thread_map *threads); 54 struct thread_map *threads);
56void perf_evlist__exit(struct perf_evlist *evlist); 55void perf_evlist__exit(struct perf_evlist *evlist);
@@ -82,13 +81,15 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
82union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 81union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
83 82
84int perf_evlist__open(struct perf_evlist *evlist); 83int perf_evlist__open(struct perf_evlist *evlist);
84void perf_evlist__close(struct perf_evlist *evlist);
85 85
86void perf_evlist__config(struct perf_evlist *evlist, 86void perf_evlist__config(struct perf_evlist *evlist,
87 struct perf_record_opts *opts); 87 struct perf_record_opts *opts);
88 88
89int perf_evlist__prepare_workload(struct perf_evlist *evlist, 89int 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);
92int perf_evlist__start_workload(struct perf_evlist *evlist); 93int perf_evlist__start_workload(struct perf_evlist *evlist);
93 94
94int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 95int 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
642void 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
636int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 648int 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)
673void perf_evsel__exit(struct perf_evsel *evsel) 685void 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
681void perf_evsel__delete(struct perf_evsel *evsel) 692void 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
13struct perf_counts_values { 14struct 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);
120int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 121int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
121int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 122int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
122int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 123int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
124void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus);
123void perf_evsel__free_fd(struct perf_evsel *evsel); 125void perf_evsel__free_fd(struct perf_evsel *evsel);
124void perf_evsel__free_id(struct perf_evsel *evsel); 126void perf_evsel__free_id(struct perf_evsel *evsel);
125void perf_evsel__free_counts(struct perf_evsel *evsel); 127void 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 */
249static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) 258static 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 */
271static 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
254struct perf_attr_details { 279struct 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
1679static int process_build_id(struct perf_file_section *section, 1677static 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)
67void hists__calc_col_len(struct hists *hists, struct hist_entry *h) 67void 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
121void hists__output_recalc_col_len(struct hists *hists, int max_rows) 160void 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
158static void he_stat__add_period(struct he_stat *he_stat, u64 period) 197static 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
174static void hist_entry__decay(struct hist_entry *he) 217static 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
180static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 224static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
@@ -239,7 +283,7 @@ void hists__decay_entries_threaded(struct hists *hists,
239static struct hist_entry *hist_entry__new(struct hist_entry *template) 283static 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)
282static struct hist_entry *add_hist_entry(struct hists *hists, 333static 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
396struct 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
344struct hist_entry *__hists__add_branch_entry(struct hists *self, 426struct 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
372struct hist_entry *__hists__add_entry(struct hists *self, 457struct 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
397int64_t 486int64_t
@@ -431,6 +520,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
431void hist_entry__free(struct hist_entry *he) 520void 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 226a4ae2f936..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
74struct hist_entry *__hists__add_entry(struct hists *self, 82struct 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);
77int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 86int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
78int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 87int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
79int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, 88int 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
99struct 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
89void hists__output_resort(struct hists *self); 106void hists__output_resort(struct hists *self);
90void hists__output_resort_threaded(struct hists *hists); 107void 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"
180int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 197int 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
183int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 200int 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
197static inline int hist_entry__tui_annotate(struct hist_entry *self 214static 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{
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
1014static 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
1006int machine__process_exit_event(struct machine *machine, union perf_event *event) 1025int 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
1042void 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
1053static bool symbol__match_parent_regex(struct symbol *sym) 1061static 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
1108static 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
1123struct 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
1100struct branch_info *machine__resolve_bstack(struct machine *machine, 1140struct 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);
76struct branch_info *machine__resolve_bstack(struct machine *machine, 76struct 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);
79struct mem_info *machine__resolve_mem(struct machine *machine,
80 struct thread *thread,
81 struct perf_sample *sample, u8 cpumode);
79int machine__resolve_callchain(struct machine *machine, 82int 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
99struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); 102struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
100void machine__remove_thread(struct machine *machine, struct thread *th);
101 103
102size_t machine__fprintf(struct machine *machine, FILE *fp); 104size_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
15util/util.c 15util/util.c
16util/xyarray.c 16util/xyarray.c
17util/cgroup.c 17util/cgroup.c
18util/debugfs.c
19util/rblist.c 18util/rblist.c
20util/strlist.c 19util/strlist.c
21util/sysfs.c 20util/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
805static struct machine * 809static 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
1368void 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
1380struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 1372struct 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);
72int perf_session__create_kernel_maps(struct perf_session *self); 72int perf_session__create_kernel_maps(struct perf_session *self);
73 73
74void perf_session__set_id_hdr_size(struct perf_session *session); 74void perf_session__set_id_hdr_size(struct perf_session *session);
75void perf_session__remove_thread(struct perf_session *self, struct thread *th);
76 75
77static inline 76static inline
78struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) 77struct 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()
24build_lib = getenv('PYTHON_EXTBUILD_LIB') 24build_lib = getenv('PYTHON_EXTBUILD_LIB')
25build_tmp = getenv('PYTHON_EXTBUILD_TMP') 25build_tmp = getenv('PYTHON_EXTBUILD_TMP')
26libtraceevent = getenv('LIBTRACEEVENT') 26libtraceevent = getenv('LIBTRACEEVENT')
27liblk = getenv('LIBLK')
27 28
28ext_sources = [f.strip() for f in file('util/python-ext-sources') 29ext_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
38setup(name='perf', 39setup(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 */
469static int64_t
470sort__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
482static 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
498static int64_t
499sort__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
512static 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
523static int64_t
524sort__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
542static 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
561static int64_t
562sort__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
580static 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
591static 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
631static int64_t
632sort__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
650static 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
668static 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
708static int64_t
709sort__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
727static 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
736static 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
460struct sort_entry sort_mispredict = { 766struct 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
773static u64 he_weight(struct hist_entry *he)
774{
775 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
776}
777
778static int64_t
779sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
780{
781 return he_weight(left) - he_weight(right);
782}
783
784static 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
790struct 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
797static int64_t
798sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
799{
800 return left->stat.weight - right->stat.weight;
801}
802
803static 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
809struct 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
816struct 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
823struct 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
830struct 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
837struct 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
844struct 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
851struct 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
467struct sort_dimension { 858struct 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
106static inline bool hist_entry__has_pairs(struct hist_entry *he) 108static 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/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 }
812new_symbol: 815new_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
159struct mem_info {
160 struct addr_map_symbol iaddr;
161 struct addr_map_symbol daddr;
162 union perf_mem_data_src data_src;
163};
164
158struct addr_location { 165struct 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
22size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); 22size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
23 23
24static 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
53unsigned int page_size;
54
55static const char *output_file = "trace.info";
56static int output_fd; 46static int output_fd;
57 47
58struct event_list {
59 struct event_list *next;
60 const char *event;
61};
62
63struct events {
64 struct events *sibling;
65 struct events *children;
66 struct events *next;
67 char *name;
68};
69
70
71static 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
81static const char *find_debugfs(void) 49static 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
134static ssize_t calc_data_size;
135
136static 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
152int bigendian(void) 108int 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 */
162static void record_file(const char *file, size_t hdr_sz) 118static 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;
158out:
159 close(fd);
160 return err;
193} 161}
194 162
195static void read_header_files(void) 163static 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;
215out:
214 put_tracing_file(path); 216 put_tracing_file(path);
217 return err;
215} 218}
216 219
217static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 220static 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
228static void copy_event_system(const char *sys, struct tracepoint_path *tps) 231static 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;
297out:
274 closedir(dir); 298 closedir(dir);
299 return err;
275} 300}
276 301
277static void read_ftrace_files(struct tracepoint_path *tps) 302static 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
288static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) 320static 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
299static void read_event_files(struct tracepoint_path *tps) 331static 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;
399out:
345 closedir(dir); 400 closedir(dir);
346 put_tracing_file(path); 401 put_tracing_file(path);
402
403 return err;
347} 404}
348 405
349static void read_proc_kallsyms(void) 406static 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
366static void read_ftrace_printk(void) 424static 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
383out: 447out:
384 put_tracing_file(path); 448 put_tracing_file(path);
449 return err;
450}
451
452static void
453put_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
387static struct tracepoint_path * 465static 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
407static void
408put_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
420bool have_tracepoints(struct list_head *pattrs) 488bool 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
431static void tracing_data_header(void) 499static 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
464struct tracing_data *tracing_data_get(struct list_head *pattrs, 540struct 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
600out:
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
520void tracing_data_put(struct tracing_data *tdata) 620int 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
530int read_tracing_data(int fd, struct list_head *pattrs) 633int 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
186void 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
199void 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
223void parse_proc_kallsyms(struct pevent *pevent, 186void 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
42static int input_fd; 40static int input_fd;
43 41
44static int read_page;
45
46int file_bigendian; 42int file_bigendian;
47int host_bigendian; 43int host_bigendian;
48static int long_size; 44static int long_size;
49 45
50static ssize_t calc_data_size; 46static ssize_t trace_data_size;
51static bool repipe; 47static bool repipe;
52 48
53static void *malloc_or_die(int size) 49static 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
63static 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
87static int read_or_die(void *data, int size) 75static 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);
162out:
166 return str; 163 return str;
167} 164}
168 165
169static void read_proc_kallsyms(struct pevent *pevent) 166static 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
187static void read_ftrace_printk(struct pevent *pevent) 191static 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
204static void read_header_files(struct pevent *pevent) 216static 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
234static void read_ftrace_file(struct pevent *pevent, unsigned long long size) 260static 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
244static void read_event_file(struct pevent *pevent, char *sys, 278static 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
255static void read_ftrace_files(struct pevent *pevent) 297static 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
269static void read_event_files(struct pevent *pevent) 315static 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
290struct 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
301static struct cpu_data *cpu_data;
302
303static 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
310static 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
358static 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
366static 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
374static int calc_index(void *ptr, int cpu)
375{
376 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
377}
378
379struct 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
418read_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
479struct 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
489ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) 343ssize_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
428out:
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 {
30int bigendian(void); 30int bigendian(void);
31 31
32struct pevent *read_trace_init(int file_bigendian, int host_bigendian); 32struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
33void print_trace_event(struct pevent *pevent, int cpu, void *data, int size);
34void event_format__print(struct event_format *event, 33void event_format__print(struct event_format *event,
35 int cpu, void *data, int size); 34 int cpu, void *data, int size);
36 35
37void print_event(struct pevent *pevent, int cpu, void *data, int size,
38 unsigned long long nsecs, char *comm);
39
40int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); 36int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size);
41int parse_event_file(struct pevent *pevent, 37int 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
73struct tracing_data *tracing_data_get(struct list_head *pattrs, 69struct tracing_data *tracing_data_get(struct list_head *pattrs,
74 int fd, bool temp); 70 int fd, bool temp);
75void tracing_data_put(struct tracing_data *tdata); 71int tracing_data_put(struct tracing_data *tdata);
76 72
77 73
78struct addr_location; 74struct 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;
17bool perf_host = true; 17bool perf_host = true;
18bool perf_guest = false; 18bool perf_guest = false;
19 19
20char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
21
20void event_attr_init(struct perf_event_attr *attr) 22void 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
248static 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
254const 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
267void 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
77extern const char *graph_line; 76extern const char *graph_line;
78extern const char *graph_dotted_line; 77extern const char *graph_dotted_line;
79extern char buildid_dir[]; 78extern char buildid_dir[];
79extern char tracing_events_path[];
80extern void perf_debugfs_set_path(const char *mountpoint);
81const 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
275struct winsize; 277struct winsize;
276void get_term_dimensions(struct winsize *ws); 278void get_term_dimensions(struct winsize *ws);
277 279#endif /* GIT_COMPAT_UTIL_H */
278#endif