aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c225
1 files changed, 92 insertions, 133 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index c27e31f289e6..b1b82009ab9b 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -9,6 +9,7 @@
9 9
10#include "util/util.h" 10#include "util/util.h"
11 11
12#include "util/annotate.h"
12#include "util/color.h" 13#include "util/color.h"
13#include <linux/list.h> 14#include <linux/list.h>
14#include "util/cache.h" 15#include "util/cache.h"
@@ -20,6 +21,8 @@
20 21
21#include "perf.h" 22#include "perf.h"
22#include "util/debug.h" 23#include "util/debug.h"
24#include "util/evlist.h"
25#include "util/evsel.h"
23#include "util/header.h" 26#include "util/header.h"
24#include "util/session.h" 27#include "util/session.h"
25 28
@@ -43,120 +46,79 @@ static const char default_pretty_printing_style[] = "normal";
43static const char *pretty_printing_style = default_pretty_printing_style; 46static const char *pretty_printing_style = default_pretty_printing_style;
44 47
45static char callchain_default_opt[] = "fractal,0.5"; 48static char callchain_default_opt[] = "fractal,0.5";
49static symbol_filter_t annotate_init;
46 50
47static struct hists *perf_session__hists_findnew(struct perf_session *self, 51static int perf_session__add_hist_entry(struct perf_session *session,
48 u64 event_stream, u32 type,
49 u64 config)
50{
51 struct rb_node **p = &self->hists_tree.rb_node;
52 struct rb_node *parent = NULL;
53 struct hists *iter, *new;
54
55 while (*p != NULL) {
56 parent = *p;
57 iter = rb_entry(parent, struct hists, rb_node);
58 if (iter->config == config)
59 return iter;
60
61
62 if (config > iter->config)
63 p = &(*p)->rb_right;
64 else
65 p = &(*p)->rb_left;
66 }
67
68 new = malloc(sizeof(struct hists));
69 if (new == NULL)
70 return NULL;
71 memset(new, 0, sizeof(struct hists));
72 new->event_stream = event_stream;
73 new->config = config;
74 new->type = type;
75 rb_link_node(&new->rb_node, parent, p);
76 rb_insert_color(&new->rb_node, &self->hists_tree);
77 return new;
78}
79
80static int perf_session__add_hist_entry(struct perf_session *self,
81 struct addr_location *al, 52 struct addr_location *al,
82 struct sample_data *data) 53 struct perf_sample *sample)
83{ 54{
84 struct map_symbol *syms = NULL;
85 struct symbol *parent = NULL; 55 struct symbol *parent = NULL;
86 int err = -ENOMEM; 56 int err = 0;
87 struct hist_entry *he; 57 struct hist_entry *he;
88 struct hists *hists; 58 struct perf_evsel *evsel;
89 struct perf_event_attr *attr; 59
90 60 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
91 if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) { 61 err = perf_session__resolve_callchain(session, al->thread,
92 syms = perf_session__resolve_callchain(self, al->thread, 62 sample->callchain, &parent);
93 data->callchain, &parent); 63 if (err)
94 if (syms == NULL) 64 return err;
95 return -ENOMEM;
96 } 65 }
97 66
98 attr = perf_header__find_attr(data->id, &self->header); 67 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
99 if (attr) 68 if (evsel == NULL) {
100 hists = perf_session__hists_findnew(self, data->id, attr->type, attr->config); 69 /*
101 else 70 * FIXME: Propagate this back, but at least we're in a builtin,
102 hists = perf_session__hists_findnew(self, data->id, 0, 0); 71 * where exit() is allowed. ;-)
103 if (hists == NULL) 72 */
104 goto out_free_syms; 73 ui__warning("Invalid %s file, contains samples with id %" PRIu64 " not in "
105 he = __hists__add_entry(hists, al, parent, data->period); 74 "its header!\n", input_name, sample->id);
75 exit_browser(0);
76 exit(1);
77 }
78
79 he = __hists__add_entry(&evsel->hists, al, parent, sample->period);
106 if (he == NULL) 80 if (he == NULL)
107 goto out_free_syms; 81 return -ENOMEM;
108 err = 0; 82
109 if (symbol_conf.use_callchain) { 83 if (symbol_conf.use_callchain) {
110 err = callchain_append(he->callchain, data->callchain, syms, 84 err = callchain_append(he->callchain, &session->callchain_cursor,
111 data->period); 85 sample->period);
112 if (err) 86 if (err)
113 goto out_free_syms; 87 return err;
114 } 88 }
115 /* 89 /*
116 * Only in the newt browser we are doing integrated annotation, 90 * Only in the newt browser we are doing integrated annotation,
117 * so we don't allocated the extra space needed because the stdio 91 * so we don't allocated the extra space needed because the stdio
118 * code will not use it. 92 * code will not use it.
119 */ 93 */
120 if (use_browser > 0) 94 if (al->sym != NULL && use_browser > 0) {
121 err = hist_entry__inc_addr_samples(he, al->addr); 95 struct annotation *notes = symbol__annotation(he->ms.sym);
122out_free_syms:
123 free(syms);
124 return err;
125}
126 96
127static int add_event_total(struct perf_session *session, 97 assert(evsel != NULL);
128 struct sample_data *data,
129 struct perf_event_attr *attr)
130{
131 struct hists *hists;
132 98
133 if (attr) 99 err = -ENOMEM;
134 hists = perf_session__hists_findnew(session, data->id, 100 if (notes->src == NULL &&
135 attr->type, attr->config); 101 symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
136 else 102 goto out;
137 hists = perf_session__hists_findnew(session, data->id, 0, 0);
138 103
139 if (!hists) 104 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
140 return -ENOMEM; 105 }
141 106
142 hists->stats.total_period += data->period; 107 evsel->hists.stats.total_period += sample->period;
143 /* 108 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
144 * FIXME: add_event_total should be moved from here to 109out:
145 * perf_session__process_event so that the proper hist is passed to 110 return err;
146 * the event_op methods.
147 */
148 hists__inc_nr_events(hists, PERF_RECORD_SAMPLE);
149 session->hists.stats.total_period += data->period;
150 return 0;
151} 111}
152 112
153static int process_sample_event(event_t *event, struct sample_data *sample, 113
114static int process_sample_event(union perf_event *event,
115 struct perf_sample *sample,
154 struct perf_session *session) 116 struct perf_session *session)
155{ 117{
156 struct addr_location al; 118 struct addr_location al;
157 struct perf_event_attr *attr;
158 119
159 if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { 120 if (perf_event__preprocess_sample(event, session, &al, sample,
121 annotate_init) < 0) {
160 fprintf(stderr, "problem processing %d event, skipping it.\n", 122 fprintf(stderr, "problem processing %d event, skipping it.\n",
161 event->header.type); 123 event->header.type);
162 return -1; 124 return -1;
@@ -170,26 +132,17 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
170 return -1; 132 return -1;
171 } 133 }
172 134
173 attr = perf_header__find_attr(sample->id, &session->header);
174
175 if (add_event_total(session, sample, attr)) {
176 pr_debug("problem adding event period\n");
177 return -1;
178 }
179
180 return 0; 135 return 0;
181} 136}
182 137
183static int process_read_event(event_t *event, struct sample_data *sample __used, 138static int process_read_event(union perf_event *event,
184 struct perf_session *session __used) 139 struct perf_sample *sample __used,
140 struct perf_session *session)
185{ 141{
186 struct perf_event_attr *attr; 142 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
187 143 event->read.id);
188 attr = perf_header__find_attr(event->read.id, &session->header);
189
190 if (show_threads) { 144 if (show_threads) {
191 const char *name = attr ? __event_name(attr->type, attr->config) 145 const char *name = evsel ? event_name(evsel) : "unknown";
192 : "unknown";
193 perf_read_values_add_value(&show_threads_values, 146 perf_read_values_add_value(&show_threads_values,
194 event->read.pid, event->read.tid, 147 event->read.pid, event->read.tid,
195 event->read.id, 148 event->read.id,
@@ -198,7 +151,7 @@ static int process_read_event(event_t *event, struct sample_data *sample __used,
198 } 151 }
199 152
200 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,
201 attr ? __event_name(attr->type, attr->config) : "FAIL", 154 evsel ? event_name(evsel) : "FAIL",
202 event->read.value); 155 event->read.value);
203 156
204 return 0; 157 return 0;
@@ -222,7 +175,7 @@ static int perf_session__setup_sample_type(struct perf_session *self)
222 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && 175 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
223 !symbol_conf.use_callchain) { 176 !symbol_conf.use_callchain) {
224 symbol_conf.use_callchain = true; 177 symbol_conf.use_callchain = true;
225 if (register_callchain_param(&callchain_param) < 0) { 178 if (callchain_register_param(&callchain_param) < 0) {
226 fprintf(stderr, "Can't register callchain" 179 fprintf(stderr, "Can't register callchain"
227 " params\n"); 180 " params\n");
228 return -EINVAL; 181 return -EINVAL;
@@ -233,17 +186,17 @@ static int perf_session__setup_sample_type(struct perf_session *self)
233} 186}
234 187
235static struct perf_event_ops event_ops = { 188static struct perf_event_ops event_ops = {
236 .sample = process_sample_event, 189 .sample = process_sample_event,
237 .mmap = event__process_mmap, 190 .mmap = perf_event__process_mmap,
238 .comm = event__process_comm, 191 .comm = perf_event__process_comm,
239 .exit = event__process_task, 192 .exit = perf_event__process_task,
240 .fork = event__process_task, 193 .fork = perf_event__process_task,
241 .lost = event__process_lost, 194 .lost = perf_event__process_lost,
242 .read = process_read_event, 195 .read = process_read_event,
243 .attr = event__process_attr, 196 .attr = perf_event__process_attr,
244 .event_type = event__process_event_type, 197 .event_type = perf_event__process_event_type,
245 .tracing_data = event__process_tracing_data, 198 .tracing_data = perf_event__process_tracing_data,
246 .build_id = event__process_build_id, 199 .build_id = perf_event__process_build_id,
247 .ordered_samples = true, 200 .ordered_samples = true,
248 .ordering_requires_timestamps = true, 201 .ordering_requires_timestamps = true,
249}; 202};
@@ -269,21 +222,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
269 return ret + fprintf(fp, "\n#\n"); 222 return ret + fprintf(fp, "\n#\n");
270} 223}
271 224
272static int hists__tty_browse_tree(struct rb_root *tree, const char *help) 225static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
226 const char *help)
273{ 227{
274 struct rb_node *next = rb_first(tree); 228 struct perf_evsel *pos;
275 229
276 while (next) { 230 list_for_each_entry(pos, &evlist->entries, node) {
277 struct hists *hists = rb_entry(next, struct hists, rb_node); 231 struct hists *hists = &pos->hists;
278 const char *evname = NULL; 232 const char *evname = NULL;
279 233
280 if (rb_first(&hists->entries) != rb_last(&hists->entries)) 234 if (rb_first(&hists->entries) != rb_last(&hists->entries))
281 evname = __event_name(hists->type, hists->config); 235 evname = event_name(pos);
282 236
283 hists__fprintf_nr_sample_events(hists, evname, stdout); 237 hists__fprintf_nr_sample_events(hists, evname, stdout);
284 hists__fprintf(hists, NULL, false, stdout); 238 hists__fprintf(hists, NULL, false, stdout);
285 fprintf(stdout, "\n\n"); 239 fprintf(stdout, "\n\n");
286 next = rb_next(&hists->rb_node);
287 } 240 }
288 241
289 if (sort_order == default_sort_order && 242 if (sort_order == default_sort_order &&
@@ -304,8 +257,9 @@ static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
304static int __cmd_report(void) 257static int __cmd_report(void)
305{ 258{
306 int ret = -EINVAL; 259 int ret = -EINVAL;
260 u64 nr_samples;
307 struct perf_session *session; 261 struct perf_session *session;
308 struct rb_node *next; 262 struct perf_evsel *pos;
309 const char *help = "For a higher level overview, try: perf report --sort comm,dso"; 263 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
310 264
311 signal(SIGINT, sig_handler); 265 signal(SIGINT, sig_handler);
@@ -336,20 +290,24 @@ static int __cmd_report(void)
336 if (verbose > 2) 290 if (verbose > 2)
337 perf_session__fprintf_dsos(session, stdout); 291 perf_session__fprintf_dsos(session, stdout);
338 292
339 next = rb_first(&session->hists_tree); 293 nr_samples = 0;
340 while (next) { 294 list_for_each_entry(pos, &session->evlist->entries, node) {
341 struct hists *hists; 295 struct hists *hists = &pos->hists;
342 296
343 hists = rb_entry(next, struct hists, rb_node);
344 hists__collapse_resort(hists); 297 hists__collapse_resort(hists);
345 hists__output_resort(hists); 298 hists__output_resort(hists);
346 next = rb_next(&hists->rb_node); 299 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
300 }
301
302 if (nr_samples == 0) {
303 ui__warning("The %s file has no samples!\n", input_name);
304 goto out_delete;
347 } 305 }
348 306
349 if (use_browser > 0) 307 if (use_browser > 0)
350 hists__tui_browse_tree(&session->hists_tree, help); 308 perf_evlist__tui_browse_hists(session->evlist, help);
351 else 309 else
352 hists__tty_browse_tree(&session->hists_tree, help); 310 perf_evlist__tty_browse_hists(session->evlist, help);
353 311
354out_delete: 312out_delete:
355 /* 313 /*
@@ -424,7 +382,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
424 if (tok2) 382 if (tok2)
425 callchain_param.print_limit = strtod(tok2, &endptr); 383 callchain_param.print_limit = strtod(tok2, &endptr);
426setup: 384setup:
427 if (register_callchain_param(&callchain_param) < 0) { 385 if (callchain_register_param(&callchain_param) < 0) {
428 fprintf(stderr, "Can't register callchain params\n"); 386 fprintf(stderr, "Can't register callchain params\n");
429 return -1; 387 return -1;
430 } 388 }
@@ -498,7 +456,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
498 use_browser = 1; 456 use_browser = 1;
499 457
500 if (strcmp(input_name, "-") != 0) 458 if (strcmp(input_name, "-") != 0)
501 setup_browser(); 459 setup_browser(true);
502 else 460 else
503 use_browser = 0; 461 use_browser = 0;
504 /* 462 /*
@@ -507,7 +465,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
507 * implementation. 465 * implementation.
508 */ 466 */
509 if (use_browser > 0) { 467 if (use_browser > 0) {
510 symbol_conf.priv_size = sizeof(struct sym_priv); 468 symbol_conf.priv_size = sizeof(struct annotation);
469 annotate_init = symbol__annotate_init;
511 /* 470 /*
512 * For searching by name on the "Browse map details". 471 * For searching by name on the "Browse map details".
513 * providing it only in verbose mode not to bloat too 472 * providing it only in verbose mode not to bloat too