diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/evsel.h | 2 | ||||
-rw-r--r-- | tools/perf/util/header.c | 31 | ||||
-rw-r--r-- | tools/perf/util/header.h | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 6 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 12 | ||||
-rw-r--r-- | tools/perf/util/session.c | 63 | ||||
-rw-r--r-- | tools/perf/util/session.h | 16 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/hists.c | 32 |
8 files changed, 98 insertions, 66 deletions
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index f6fc8f651a25..281b60e5fc7b 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "types.h" | 7 | #include "types.h" |
8 | #include "xyarray.h" | 8 | #include "xyarray.h" |
9 | #include "cgroup.h" | 9 | #include "cgroup.h" |
10 | #include "hist.h" | ||
10 | 11 | ||
11 | struct perf_counts_values { | 12 | struct perf_counts_values { |
12 | union { | 13 | union { |
@@ -51,6 +52,7 @@ struct perf_evsel { | |||
51 | struct xyarray *id; | 52 | struct xyarray *id; |
52 | struct perf_counts *counts; | 53 | struct perf_counts *counts; |
53 | int idx; | 54 | int idx; |
55 | struct hists hists; | ||
54 | char *name; | 56 | char *name; |
55 | void *priv; | 57 | void *priv; |
56 | struct cgroup_sel *cgrp; | 58 | struct cgroup_sel *cgrp; |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 72c124dc5781..108b0db7bbef 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -969,37 +969,6 @@ bool perf_header__sample_id_all(const struct perf_header *header) | |||
969 | return value; | 969 | return value; |
970 | } | 970 | } |
971 | 971 | ||
972 | struct perf_event_attr * | ||
973 | perf_header__find_attr(u64 id, struct perf_header *header) | ||
974 | { | ||
975 | int i; | ||
976 | |||
977 | /* | ||
978 | * We set id to -1 if the data file doesn't contain sample | ||
979 | * ids. This can happen when the data file contains one type | ||
980 | * of event and in that case, the header can still store the | ||
981 | * event attribute information. Check for this and avoid | ||
982 | * walking through the entire list of ids which may be large. | ||
983 | */ | ||
984 | if (id == -1ULL) { | ||
985 | if (header->attrs > 0) | ||
986 | return &header->attr[0]->attr; | ||
987 | return NULL; | ||
988 | } | ||
989 | |||
990 | for (i = 0; i < header->attrs; i++) { | ||
991 | struct perf_header_attr *attr = header->attr[i]; | ||
992 | int j; | ||
993 | |||
994 | for (j = 0; j < attr->ids; j++) { | ||
995 | if (attr->id[j] == id) | ||
996 | return &attr->attr; | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | return NULL; | ||
1001 | } | ||
1002 | |||
1003 | int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | 972 | int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, |
1004 | perf_event__handler_t process, | 973 | perf_event__handler_t process, |
1005 | struct perf_session *session) | 974 | struct perf_session *session) |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index f042cebcec1e..2fab13348aab 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -85,8 +85,6 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id); | |||
85 | 85 | ||
86 | u64 perf_header__sample_type(struct perf_header *header); | 86 | u64 perf_header__sample_type(struct perf_header *header); |
87 | bool perf_header__sample_id_all(const struct perf_header *header); | 87 | bool perf_header__sample_id_all(const struct perf_header *header); |
88 | struct perf_event_attr * | ||
89 | perf_header__find_attr(u64 id, struct perf_header *header); | ||
90 | void perf_header__set_feat(struct perf_header *self, int feat); | 88 | void perf_header__set_feat(struct perf_header *self, int feat); |
91 | void perf_header__clear_feat(struct perf_header *self, int feat); | 89 | void perf_header__clear_feat(struct perf_header *self, int feat); |
92 | bool perf_header__has_feat(const struct perf_header *self, int feat); | 90 | bool perf_header__has_feat(const struct perf_header *self, int feat); |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f7ad6bdbc667..627a02e03c57 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -984,8 +984,12 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) | |||
984 | size_t ret = 0; | 984 | size_t ret = 0; |
985 | 985 | ||
986 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { | 986 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { |
987 | const char *name = perf_event__name(i); | 987 | const char *name; |
988 | 988 | ||
989 | if (self->stats.nr_events[i] == 0) | ||
990 | continue; | ||
991 | |||
992 | name = perf_event__name(i); | ||
989 | if (!strcmp(name, "UNKNOWN")) | 993 | if (!strcmp(name, "UNKNOWN")) |
990 | continue; | 994 | continue; |
991 | 995 | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 37c79089de09..0d38b435827b 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -42,13 +42,10 @@ enum hist_column { | |||
42 | }; | 42 | }; |
43 | 43 | ||
44 | struct hists { | 44 | struct hists { |
45 | struct rb_node rb_node; | ||
46 | struct rb_root entries; | 45 | struct rb_root entries; |
47 | u64 nr_entries; | 46 | u64 nr_entries; |
48 | struct events_stats stats; | 47 | struct events_stats stats; |
49 | u64 config; | ||
50 | u64 event_stream; | 48 | u64 event_stream; |
51 | u32 type; | ||
52 | u16 col_len[HISTC_NR_COLS]; | 49 | u16 col_len[HISTC_NR_COLS]; |
53 | /* Best would be to reuse the session callchain cursor */ | 50 | /* Best would be to reuse the session callchain cursor */ |
54 | struct callchain_cursor callchain_cursor; | 51 | struct callchain_cursor callchain_cursor; |
@@ -87,6 +84,8 @@ u16 hists__col_len(struct hists *self, enum hist_column col); | |||
87 | void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); | 84 | void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); |
88 | bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); | 85 | bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); |
89 | 86 | ||
87 | struct perf_evlist; | ||
88 | |||
90 | #ifdef NO_NEWT_SUPPORT | 89 | #ifdef NO_NEWT_SUPPORT |
91 | static inline int hists__browse(struct hists *self __used, | 90 | static inline int hists__browse(struct hists *self __used, |
92 | const char *helpline __used, | 91 | const char *helpline __used, |
@@ -95,9 +94,8 @@ static inline int hists__browse(struct hists *self __used, | |||
95 | return 0; | 94 | return 0; |
96 | } | 95 | } |
97 | 96 | ||
98 | static inline int hists__tui_browse_tree(struct rb_root *self __used, | 97 | static inline int hists__tui_browse_tree(struct perf_evlist *evlist __used, |
99 | const char *help __used, | 98 | const char *help __used) |
100 | int evidx __used) | ||
101 | { | 99 | { |
102 | return 0; | 100 | return 0; |
103 | } | 101 | } |
@@ -118,7 +116,7 @@ int hist_entry__tui_annotate(struct hist_entry *self, int evidx); | |||
118 | #define KEY_LEFT NEWT_KEY_LEFT | 116 | #define KEY_LEFT NEWT_KEY_LEFT |
119 | #define KEY_RIGHT NEWT_KEY_RIGHT | 117 | #define KEY_RIGHT NEWT_KEY_RIGHT |
120 | 118 | ||
121 | int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx); | 119 | int hists__tui_browse_tree(struct perf_evlist *evlist, const char *help); |
122 | #endif | 120 | #endif |
123 | 121 | ||
124 | unsigned int hists__sort_list_width(struct hists *self); | 122 | unsigned int hists__sort_list_width(struct hists *self); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index a3a871f7bda3..0d414199889d 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -7,10 +7,52 @@ | |||
7 | #include <sys/types.h> | 7 | #include <sys/types.h> |
8 | #include <sys/mman.h> | 8 | #include <sys/mman.h> |
9 | 9 | ||
10 | #include "evlist.h" | ||
11 | #include "evsel.h" | ||
10 | #include "session.h" | 12 | #include "session.h" |
11 | #include "sort.h" | 13 | #include "sort.h" |
12 | #include "util.h" | 14 | #include "util.h" |
13 | 15 | ||
16 | static int perf_session__read_evlist(struct perf_session *session) | ||
17 | { | ||
18 | int i, j; | ||
19 | |||
20 | session->evlist = perf_evlist__new(NULL, NULL); | ||
21 | if (session->evlist == NULL) | ||
22 | return -ENOMEM; | ||
23 | |||
24 | for (i = 0; i < session->header.attrs; ++i) { | ||
25 | struct perf_header_attr *hattr = session->header.attr[i]; | ||
26 | struct perf_evsel *evsel = perf_evsel__new(&hattr->attr, i); | ||
27 | |||
28 | if (evsel == NULL) | ||
29 | goto out_delete_evlist; | ||
30 | /* | ||
31 | * Do it before so that if perf_evsel__alloc_id fails, this | ||
32 | * entry gets purged too at perf_evlist__delete(). | ||
33 | */ | ||
34 | perf_evlist__add(session->evlist, evsel); | ||
35 | /* | ||
36 | * We don't have the cpu and thread maps on the header, so | ||
37 | * for allocating the perf_sample_id table we fake 1 cpu and | ||
38 | * hattr->ids threads. | ||
39 | */ | ||
40 | if (perf_evsel__alloc_id(evsel, 1, hattr->ids)) | ||
41 | goto out_delete_evlist; | ||
42 | |||
43 | for (j = 0; j < hattr->ids; ++j) | ||
44 | perf_evlist__id_hash(session->evlist, evsel, 0, j, | ||
45 | hattr->id[j]); | ||
46 | } | ||
47 | |||
48 | return 0; | ||
49 | |||
50 | out_delete_evlist: | ||
51 | perf_evlist__delete(session->evlist); | ||
52 | session->evlist = NULL; | ||
53 | return -ENOMEM; | ||
54 | } | ||
55 | |||
14 | static int perf_session__open(struct perf_session *self, bool force) | 56 | static int perf_session__open(struct perf_session *self, bool force) |
15 | { | 57 | { |
16 | struct stat input_stat; | 58 | struct stat input_stat; |
@@ -56,6 +98,11 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
56 | goto out_close; | 98 | goto out_close; |
57 | } | 99 | } |
58 | 100 | ||
101 | if (perf_session__read_evlist(self) < 0) { | ||
102 | pr_err("Not enough memory to read the event selector list\n"); | ||
103 | goto out_close; | ||
104 | } | ||
105 | |||
59 | self->size = input_stat.st_size; | 106 | self->size = input_stat.st_size; |
60 | return 0; | 107 | return 0; |
61 | 108 | ||
@@ -141,7 +188,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, | |||
141 | memcpy(self->filename, filename, len); | 188 | memcpy(self->filename, filename, len); |
142 | self->threads = RB_ROOT; | 189 | self->threads = RB_ROOT; |
143 | INIT_LIST_HEAD(&self->dead_threads); | 190 | INIT_LIST_HEAD(&self->dead_threads); |
144 | self->hists_tree = RB_ROOT; | ||
145 | self->last_match = NULL; | 191 | self->last_match = NULL; |
146 | /* | 192 | /* |
147 | * On 64bit we can mmap the data file in one go. No need for tiny mmap | 193 | * On 64bit we can mmap the data file in one go. No need for tiny mmap |
@@ -1137,3 +1183,18 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, | |||
1137 | size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); | 1183 | size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); |
1138 | return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); | 1184 | return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); |
1139 | } | 1185 | } |
1186 | |||
1187 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | ||
1188 | { | ||
1189 | struct perf_evsel *pos; | ||
1190 | size_t ret = fprintf(fp, "Aggregated stats:\n"); | ||
1191 | |||
1192 | ret += hists__fprintf_nr_events(&session->hists, fp); | ||
1193 | |||
1194 | list_for_each_entry(pos, &session->evlist->entries, node) { | ||
1195 | ret += fprintf(fp, "%s stats:\n", event_name(pos)); | ||
1196 | ret += hists__fprintf_nr_events(&pos->hists, fp); | ||
1197 | } | ||
1198 | |||
1199 | return ret; | ||
1200 | } | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 977b3a1b14aa..05dd7bcb9453 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -34,12 +34,12 @@ struct perf_session { | |||
34 | struct thread *last_match; | 34 | struct thread *last_match; |
35 | struct machine host_machine; | 35 | struct machine host_machine; |
36 | struct rb_root machines; | 36 | struct rb_root machines; |
37 | struct rb_root hists_tree; | 37 | struct perf_evlist *evlist; |
38 | /* | 38 | /* |
39 | * FIXME: should point to the first entry in hists_tree and | 39 | * FIXME: Need to split this up further, we need global |
40 | * be a hists instance. Right now its only 'report' | 40 | * stats + per event stats. 'perf diff' also needs |
41 | * that is using ->hists_tree while all the rest use | 41 | * to properly support multiple events in a single |
42 | * ->hists. | 42 | * perf.data file. |
43 | */ | 43 | */ |
44 | struct hists hists; | 44 | struct hists hists; |
45 | u64 sample_type; | 45 | u64 sample_type; |
@@ -151,11 +151,7 @@ size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); | |||
151 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, | 151 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, |
152 | FILE *fp, bool with_hits); | 152 | FILE *fp, bool with_hits); |
153 | 153 | ||
154 | static inline | 154 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); |
155 | size_t perf_session__fprintf_nr_events(struct perf_session *self, FILE *fp) | ||
156 | { | ||
157 | return hists__fprintf_nr_events(&self->hists, fp); | ||
158 | } | ||
159 | 155 | ||
160 | static inline int perf_session__parse_sample(struct perf_session *session, | 156 | static inline int perf_session__parse_sample(struct perf_session *session, |
161 | const union perf_event *event, | 157 | const union perf_event *event, |
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index c98e6f81d285..f3af4fe5cdc4 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c | |||
@@ -7,6 +7,8 @@ | |||
7 | #include <newt.h> | 7 | #include <newt.h> |
8 | #include <linux/rbtree.h> | 8 | #include <linux/rbtree.h> |
9 | 9 | ||
10 | #include "../../evsel.h" | ||
11 | #include "../../evlist.h" | ||
10 | #include "../../hist.h" | 12 | #include "../../hist.h" |
11 | #include "../../pstack.h" | 13 | #include "../../pstack.h" |
12 | #include "../../sort.h" | 14 | #include "../../sort.h" |
@@ -987,31 +989,33 @@ out: | |||
987 | return key; | 989 | return key; |
988 | } | 990 | } |
989 | 991 | ||
990 | int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx) | 992 | int hists__tui_browse_tree(struct perf_evlist *evlist, const char *help) |
991 | { | 993 | { |
992 | struct rb_node *first = rb_first(self), *nd = first, *next; | 994 | struct perf_evsel *pos; |
993 | int key = 0; | ||
994 | 995 | ||
995 | while (nd) { | 996 | pos = list_entry(evlist->entries.next, struct perf_evsel, node); |
996 | struct hists *hists = rb_entry(nd, struct hists, rb_node); | 997 | while (pos) { |
997 | const char *ev_name = __event_name(hists->type, hists->config); | 998 | struct hists *hists = &pos->hists; |
999 | const char *ev_name = event_name(pos); | ||
1000 | int key = hists__browse(hists, help, ev_name, pos->idx); | ||
998 | 1001 | ||
999 | key = hists__browse(hists, help, ev_name, evidx); | ||
1000 | switch (key) { | 1002 | switch (key) { |
1001 | case NEWT_KEY_TAB: | 1003 | case NEWT_KEY_TAB: |
1002 | next = rb_next(nd); | 1004 | if (pos->node.next == &evlist->entries) |
1003 | if (next) | 1005 | pos = list_entry(evlist->entries.next, struct perf_evsel, node); |
1004 | nd = next; | 1006 | else |
1007 | pos = list_entry(pos->node.next, struct perf_evsel, node); | ||
1005 | break; | 1008 | break; |
1006 | case NEWT_KEY_UNTAB: | 1009 | case NEWT_KEY_UNTAB: |
1007 | if (nd == first) | 1010 | if (pos->node.prev == &evlist->entries) |
1008 | continue; | 1011 | pos = list_entry(evlist->entries.prev, struct perf_evsel, node); |
1009 | nd = rb_prev(nd); | 1012 | else |
1013 | pos = list_entry(pos->node.prev, struct perf_evsel, node); | ||
1010 | break; | 1014 | break; |
1011 | default: | 1015 | default: |
1012 | return key; | 1016 | return key; |
1013 | } | 1017 | } |
1014 | } | 1018 | } |
1015 | 1019 | ||
1016 | return key; | 1020 | return 0; |
1017 | } | 1021 | } |