aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-03-05 19:40:06 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-03-06 11:13:40 -0500
commite248de331a452f8771eda6ed4bb30d92c82df28b (patch)
tree7ef04743a7bf7a1da354a3b82536ef32504823d9 /tools/perf/builtin-report.c
parent3d3b5e95997208067c963923db90ed1517565d14 (diff)
perf tools: Improve support for sessions with multiple events
By creating an perf_evlist out of the attributes in the perf.data file header, so that we can use evlists and evsels when reading recorded sessions in addition to when we record sessions. More work is needed to allow tools to allow the user to select which events are wanted when browsing sessions, be it just one or a subset of them, aggregated or showed at the same time but with different indications on the UI to allow seeing workloads thru different views at the same time. But the overall goal/trend is to more uniformly use evsels and evlists. Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c160
1 files changed, 49 insertions, 111 deletions
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 /*