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.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 /*