aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/builtin-annotate.c80
-rw-r--r--tools/perf/builtin-report.c160
-rw-r--r--tools/perf/util/evsel.h2
-rw-r--r--tools/perf/util/header.c31
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/hist.c6
-rw-r--r--tools/perf/util/hist.h12
-rw-r--r--tools/perf/util/session.c63
-rw-r--r--tools/perf/util/session.h16
-rw-r--r--tools/perf/util/ui/browsers/hists.c32
10 files changed, 208 insertions, 196 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 427182953fd7..695de4b5ae63 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -19,6 +19,8 @@
19#include "perf.h" 19#include "perf.h"
20#include "util/debug.h" 20#include "util/debug.h"
21 21
22#include "util/evlist.h"
23#include "util/evsel.h"
22#include "util/annotate.h" 24#include "util/annotate.h"
23#include "util/event.h" 25#include "util/event.h"
24#include "util/parse-options.h" 26#include "util/parse-options.h"
@@ -38,9 +40,13 @@ static bool print_line;
38 40
39static const char *sym_hist_filter; 41static const char *sym_hist_filter;
40 42
41static int hists__add_entry(struct hists *self, struct addr_location *al) 43static int perf_evlist__add_sample(struct perf_evlist *evlist,
44 struct perf_sample *sample,
45 struct addr_location *al)
42{ 46{
47 struct perf_evsel *evsel;
43 struct hist_entry *he; 48 struct hist_entry *he;
49 int ret;
44 50
45 if (sym_hist_filter != NULL && 51 if (sym_hist_filter != NULL &&
46 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { 52 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
@@ -53,23 +59,35 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
53 return 0; 59 return 0;
54 } 60 }
55 61
56 he = __hists__add_entry(self, al, NULL, 1); 62 evsel = perf_evlist__id2evsel(evlist, sample->id);
63 if (evsel == NULL) {
64 /*
65 * FIXME: Propagate this back, but at least we're in a builtin,
66 * where exit() is allowed. ;-)
67 */
68 ui__warning("Invalid %s file, contains samples with id not in "
69 "its header!\n", input_name);
70 exit_browser(0);
71 exit(1);
72 }
73
74 he = __hists__add_entry(&evsel->hists, al, NULL, 1);
57 if (he == NULL) 75 if (he == NULL)
58 return -ENOMEM; 76 return -ENOMEM;
59 77
78 ret = 0;
60 if (he->ms.sym != NULL) { 79 if (he->ms.sym != NULL) {
61 /*
62 * All aggregated on the first sym_hist.
63 */
64 struct annotation *notes = symbol__annotation(he->ms.sym); 80 struct annotation *notes = symbol__annotation(he->ms.sym);
65 if (notes->src == NULL && 81 if (notes->src == NULL &&
66 symbol__alloc_hist(he->ms.sym, 1) < 0) 82 symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0)
67 return -ENOMEM; 83 return -ENOMEM;
68 84
69 return hist_entry__inc_addr_samples(he, 0, al->addr); 85 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
70 } 86 }
71 87
72 return 0; 88 evsel->hists.stats.total_period += sample->period;
89 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
90 return ret;
73} 91}
74 92
75static int process_sample_event(union perf_event *event, 93static int process_sample_event(union perf_event *event,
@@ -85,7 +103,7 @@ static int process_sample_event(union perf_event *event,
85 return -1; 103 return -1;
86 } 104 }
87 105
88 if (!al.filtered && hists__add_entry(&session->hists, &al)) { 106 if (!al.filtered && perf_evlist__add_sample(session->evlist, sample, &al)) {
89 pr_warning("problem incrementing symbol count, " 107 pr_warning("problem incrementing symbol count, "
90 "skipping event\n"); 108 "skipping event\n");
91 return -1; 109 return -1;
@@ -100,7 +118,7 @@ static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
100 print_line, full_paths, 0, 0); 118 print_line, full_paths, 0, 0);
101} 119}
102 120
103static void hists__find_annotations(struct hists *self) 121static void hists__find_annotations(struct hists *self, int evidx)
104{ 122{
105 struct rb_node *nd = rb_first(&self->entries), *next; 123 struct rb_node *nd = rb_first(&self->entries), *next;
106 int key = KEY_RIGHT; 124 int key = KEY_RIGHT;
@@ -123,8 +141,7 @@ find_next:
123 } 141 }
124 142
125 if (use_browser > 0) { 143 if (use_browser > 0) {
126 /* For now all is aggregated on the first */ 144 key = hist_entry__tui_annotate(he, evidx);
127 key = hist_entry__tui_annotate(he, 0);
128 switch (key) { 145 switch (key) {
129 case KEY_RIGHT: 146 case KEY_RIGHT:
130 next = rb_next(nd); 147 next = rb_next(nd);
@@ -139,8 +156,7 @@ find_next:
139 if (next != NULL) 156 if (next != NULL)
140 nd = next; 157 nd = next;
141 } else { 158 } else {
142 /* For now all is aggregated on the first */ 159 hist_entry__tty_annotate(he, evidx);
143 hist_entry__tty_annotate(he, 0);
144 nd = rb_next(nd); 160 nd = rb_next(nd);
145 /* 161 /*
146 * Since we have a hist_entry per IP for the same 162 * Since we have a hist_entry per IP for the same
@@ -166,6 +182,8 @@ static int __cmd_annotate(void)
166{ 182{
167 int ret; 183 int ret;
168 struct perf_session *session; 184 struct perf_session *session;
185 struct perf_evsel *pos;
186 u64 total_nr_samples;
169 187
170 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops); 188 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
171 if (session == NULL) 189 if (session == NULL)
@@ -186,12 +204,36 @@ static int __cmd_annotate(void)
186 if (verbose > 2) 204 if (verbose > 2)
187 perf_session__fprintf_dsos(session, stdout); 205 perf_session__fprintf_dsos(session, stdout);
188 206
189 hists__collapse_resort(&session->hists); 207 total_nr_samples = 0;
190 hists__output_resort(&session->hists); 208 list_for_each_entry(pos, &session->evlist->entries, node) {
191 hists__find_annotations(&session->hists); 209 struct hists *hists = &pos->hists;
192out_delete: 210 u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
193 perf_session__delete(session); 211
212 if (nr_samples > 0) {
213 total_nr_samples += nr_samples;
214 hists__collapse_resort(hists);
215 hists__output_resort(hists);
216 hists__find_annotations(hists, pos->idx);
217 }
218 }
194 219
220 if (total_nr_samples == 0) {
221 ui__warning("The %s file has no samples!\n", input_name);
222 goto out_delete;
223 }
224out_delete:
225 /*
226 * Speed up the exit process, for large files this can
227 * take quite a while.
228 *
229 * XXX Enable this when using valgrind or if we ever
230 * librarize this command.
231 *
232 * Also experiment with obstacks to see how much speed
233 * up we'll get here.
234 *
235 * perf_session__delete(session);
236 */
195 return ret; 237 return ret;
196} 238}
197 239
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index dddcc7ea2bec..1c399eae5f7b 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -21,6 +21,8 @@
21 21
22#include "perf.h" 22#include "perf.h"
23#include "util/debug.h" 23#include "util/debug.h"
24#include "util/evlist.h"
25#include "util/evsel.h"
24#include "util/header.h" 26#include "util/header.h"
25#include "util/session.h" 27#include "util/session.h"
26 28
@@ -46,39 +48,6 @@ static const char *pretty_printing_style = default_pretty_printing_style;
46static char callchain_default_opt[] = "fractal,0.5"; 48static char callchain_default_opt[] = "fractal,0.5";
47static symbol_filter_t annotate_init; 49static symbol_filter_t annotate_init;
48 50
49static struct hists *perf_session__hists_findnew(struct perf_session *self,
50 u64 event_stream, u32 type,
51 u64 config)
52{
53 struct rb_node **p = &self->hists_tree.rb_node;
54 struct rb_node *parent = NULL;
55 struct hists *iter, *new;
56
57 while (*p != NULL) {
58 parent = *p;
59 iter = rb_entry(parent, struct hists, rb_node);
60 if (iter->config == config)
61 return iter;
62
63
64 if (config > iter->config)
65 p = &(*p)->rb_right;
66 else
67 p = &(*p)->rb_left;
68 }
69
70 new = malloc(sizeof(struct hists));
71 if (new == NULL)
72 return NULL;
73 memset(new, 0, sizeof(struct hists));
74 new->event_stream = event_stream;
75 new->config = config;
76 new->type = type;
77 rb_link_node(&new->rb_node, parent, p);
78 rb_insert_color(&new->rb_node, &self->hists_tree);
79 return new;
80}
81
82static int perf_session__add_hist_entry(struct perf_session *session, 51static int perf_session__add_hist_entry(struct perf_session *session,
83 struct addr_location *al, 52 struct addr_location *al,
84 struct perf_sample *sample) 53 struct perf_sample *sample)
@@ -86,8 +55,7 @@ static int perf_session__add_hist_entry(struct perf_session *session,
86 struct symbol *parent = NULL; 55 struct symbol *parent = NULL;
87 int err = 0; 56 int err = 0;
88 struct hist_entry *he; 57 struct hist_entry *he;
89 struct hists *hists; 58 struct perf_evsel *evsel;
90 struct perf_event_attr *attr;
91 59
92 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 60 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
93 err = perf_session__resolve_callchain(session, al->thread, 61 err = perf_session__resolve_callchain(session, al->thread,
@@ -96,15 +64,19 @@ static int perf_session__add_hist_entry(struct perf_session *session,
96 return err; 64 return err;
97 } 65 }
98 66
99 attr = perf_header__find_attr(sample->id, &session->header); 67 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
100 if (attr) 68 if (evsel == NULL) {
101 hists = perf_session__hists_findnew(session, sample->id, attr->type, attr->config); 69 /*
102 else 70 * FIXME: Propagate this back, but at least we're in a builtin,
103 hists = perf_session__hists_findnew(session, sample->id, 0, 0); 71 * where exit() is allowed. ;-)
104 if (hists == NULL) 72 */
105 return -ENOMEM; 73 ui__warning("Invalid %s file, contains samples with id not in "
74 "its header!\n", input_name);
75 exit_browser(0);
76 exit(1);
77 }
106 78
107 he = __hists__add_entry(hists, al, parent, sample->period); 79 he = __hists__add_entry(&evsel->hists, al, parent, sample->period);
108 if (he == NULL) 80 if (he == NULL)
109 return -ENOMEM; 81 return -ENOMEM;
110 82
@@ -120,52 +92,30 @@ static int perf_session__add_hist_entry(struct perf_session *session,
120 * code will not use it. 92 * code will not use it.
121 */ 93 */
122 if (al->sym != NULL && use_browser > 0) { 94 if (al->sym != NULL && use_browser > 0) {
123 /*
124 * All aggregated on the first sym_hist.
125 */
126 struct annotation *notes = symbol__annotation(he->ms.sym); 95 struct annotation *notes = symbol__annotation(he->ms.sym);
96
97 assert(evsel != NULL);
98
99 err = -ENOMEM;
127 if (notes->src == NULL && 100 if (notes->src == NULL &&
128 symbol__alloc_hist(he->ms.sym, 1) < 0) 101 symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
129 err = -ENOMEM; 102 goto out;
130 else 103
131 err = hist_entry__inc_addr_samples(he, 0, al->addr); 104 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
132 } 105 }
133 106
107 evsel->hists.stats.total_period += sample->period;
108 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
109out:
134 return err; 110 return err;
135} 111}
136 112
137static int add_event_total(struct perf_session *session,
138 struct perf_sample *sample,
139 struct perf_event_attr *attr)
140{
141 struct hists *hists;
142
143 if (attr)
144 hists = perf_session__hists_findnew(session, sample->id,
145 attr->type, attr->config);
146 else
147 hists = perf_session__hists_findnew(session, sample->id, 0, 0);
148
149 if (!hists)
150 return -ENOMEM;
151
152 hists->stats.total_period += sample->period;
153 /*
154 * FIXME: add_event_total should be moved from here to
155 * perf_session__process_event so that the proper hist is passed to
156 * the event_op methods.
157 */
158 hists__inc_nr_events(hists, PERF_RECORD_SAMPLE);
159 session->hists.stats.total_period += sample->period;
160 return 0;
161}
162 113
163static int process_sample_event(union perf_event *event, 114static int process_sample_event(union perf_event *event,
164 struct perf_sample *sample, 115 struct perf_sample *sample,
165 struct perf_session *session) 116 struct perf_session *session)
166{ 117{
167 struct addr_location al; 118 struct addr_location al;
168 struct perf_event_attr *attr;
169 119
170 if (perf_event__preprocess_sample(event, session, &al, sample, 120 if (perf_event__preprocess_sample(event, session, &al, sample,
171 annotate_init) < 0) { 121 annotate_init) < 0) {
@@ -182,27 +132,17 @@ static int process_sample_event(union perf_event *event,
182 return -1; 132 return -1;
183 } 133 }
184 134
185 attr = perf_header__find_attr(sample->id, &session->header);
186
187 if (add_event_total(session, sample, attr)) {
188 pr_debug("problem adding event period\n");
189 return -1;
190 }
191
192 return 0; 135 return 0;
193} 136}
194 137
195static int process_read_event(union perf_event *event, 138static int process_read_event(union perf_event *event,
196 struct perf_sample *sample __used, 139 struct perf_sample *sample __used,
197 struct perf_session *session __used) 140 struct perf_session *session)
198{ 141{
199 struct perf_event_attr *attr; 142 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
200 143 event->read.id);
201 attr = perf_header__find_attr(event->read.id, &session->header);
202
203 if (show_threads) { 144 if (show_threads) {
204 const char *name = attr ? __event_name(attr->type, attr->config) 145 const char *name = evsel ? event_name(evsel) : "unknown";
205 : "unknown";
206 perf_read_values_add_value(&show_threads_values, 146 perf_read_values_add_value(&show_threads_values,
207 event->read.pid, event->read.tid, 147 event->read.pid, event->read.tid,
208 event->read.id, 148 event->read.id,
@@ -211,7 +151,7 @@ static int process_read_event(union perf_event *event,
211 } 151 }
212 152
213 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid, 153 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
214 attr ? __event_name(attr->type, attr->config) : "FAIL", 154 evsel ? event_name(evsel) : "FAIL",
215 event->read.value); 155 event->read.value);
216 156
217 return 0; 157 return 0;
@@ -282,21 +222,20 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
282 return ret + fprintf(fp, "\n#\n"); 222 return ret + fprintf(fp, "\n#\n");
283} 223}
284 224
285static int hists__tty_browse_tree(struct rb_root *tree, const char *help) 225static int hists__tty_browse_tree(struct perf_evlist *evlist, const char *help)
286{ 226{
287 struct rb_node *next = rb_first(tree); 227 struct perf_evsel *pos;
288 228
289 while (next) { 229 list_for_each_entry(pos, &evlist->entries, node) {
290 struct hists *hists = rb_entry(next, struct hists, rb_node); 230 struct hists *hists = &pos->hists;
291 const char *evname = NULL; 231 const char *evname = NULL;
292 232
293 if (rb_first(&hists->entries) != rb_last(&hists->entries)) 233 if (rb_first(&hists->entries) != rb_last(&hists->entries))
294 evname = __event_name(hists->type, hists->config); 234 evname = event_name(pos);
295 235
296 hists__fprintf_nr_sample_events(hists, evname, stdout); 236 hists__fprintf_nr_sample_events(hists, evname, stdout);
297 hists__fprintf(hists, NULL, false, stdout); 237 hists__fprintf(hists, NULL, false, stdout);
298 fprintf(stdout, "\n\n"); 238 fprintf(stdout, "\n\n");
299 next = rb_next(&hists->rb_node);
300 } 239 }
301 240
302 if (sort_order == default_sort_order && 241 if (sort_order == default_sort_order &&
@@ -317,8 +256,9 @@ static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
317static int __cmd_report(void) 256static int __cmd_report(void)
318{ 257{
319 int ret = -EINVAL; 258 int ret = -EINVAL;
259 u64 nr_samples;
320 struct perf_session *session; 260 struct perf_session *session;
321 struct rb_node *next; 261 struct perf_evsel *pos;
322 const char *help = "For a higher level overview, try: perf report --sort comm,dso"; 262 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
323 263
324 signal(SIGINT, sig_handler); 264 signal(SIGINT, sig_handler);
@@ -349,26 +289,24 @@ static int __cmd_report(void)
349 if (verbose > 2) 289 if (verbose > 2)
350 perf_session__fprintf_dsos(session, stdout); 290 perf_session__fprintf_dsos(session, stdout);
351 291
352 next = rb_first(&session->hists_tree); 292 nr_samples = 0;
353 293 list_for_each_entry(pos, &session->evlist->entries, node) {
354 if (next == NULL) { 294 struct hists *hists = &pos->hists;
355 ui__warning("The %s file has no samples!\n", input_name);
356 goto out_delete;
357 }
358
359 while (next) {
360 struct hists *hists;
361 295
362 hists = rb_entry(next, struct hists, rb_node);
363 hists__collapse_resort(hists); 296 hists__collapse_resort(hists);
364 hists__output_resort(hists); 297 hists__output_resort(hists);
365 next = rb_next(&hists->rb_node); 298 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
299 }
300
301 if (nr_samples == 0) {
302 ui__warning("The %s file has no samples!\n", input_name);
303 goto out_delete;
366 } 304 }
367 305
368 if (use_browser > 0) 306 if (use_browser > 0)
369 hists__tui_browse_tree(&session->hists_tree, help, 0); 307 hists__tui_browse_tree(session->evlist, help);
370 else 308 else
371 hists__tty_browse_tree(&session->hists_tree, help); 309 hists__tty_browse_tree(session->evlist, help);
372 310
373out_delete: 311out_delete:
374 /* 312 /*
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
11struct perf_counts_values { 12struct 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
972struct perf_event_attr *
973perf_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
1003int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 972int 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
86u64 perf_header__sample_type(struct perf_header *header); 86u64 perf_header__sample_type(struct perf_header *header);
87bool perf_header__sample_id_all(const struct perf_header *header); 87bool perf_header__sample_id_all(const struct perf_header *header);
88struct perf_event_attr *
89perf_header__find_attr(u64 id, struct perf_header *header);
90void perf_header__set_feat(struct perf_header *self, int feat); 88void perf_header__set_feat(struct perf_header *self, int feat);
91void perf_header__clear_feat(struct perf_header *self, int feat); 89void perf_header__clear_feat(struct perf_header *self, int feat);
92bool perf_header__has_feat(const struct perf_header *self, int feat); 90bool 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
44struct hists { 44struct 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);
87void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 84void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
88bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); 85bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
89 86
87struct perf_evlist;
88
90#ifdef NO_NEWT_SUPPORT 89#ifdef NO_NEWT_SUPPORT
91static inline int hists__browse(struct hists *self __used, 90static 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
98static inline int hists__tui_browse_tree(struct rb_root *self __used, 97static 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
121int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx); 119int hists__tui_browse_tree(struct perf_evlist *evlist, const char *help);
122#endif 120#endif
123 121
124unsigned int hists__sort_list_width(struct hists *self); 122unsigned 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
16static 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
50out_delete_evlist:
51 perf_evlist__delete(session->evlist);
52 session->evlist = NULL;
53 return -ENOMEM;
54}
55
14static int perf_session__open(struct perf_session *self, bool force) 56static 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
1187size_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);
151size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 151size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
152 FILE *fp, bool with_hits); 152 FILE *fp, bool with_hits);
153 153
154static inline 154size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
155size_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
160static inline int perf_session__parse_sample(struct perf_session *session, 156static 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
990int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx) 992int 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}