diff options
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r-- | tools/perf/builtin-report.c | 160 |
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; | |||
46 | static char callchain_default_opt[] = "fractal,0.5"; | 48 | static char callchain_default_opt[] = "fractal,0.5"; |
47 | static symbol_filter_t annotate_init; | 49 | static symbol_filter_t annotate_init; |
48 | 50 | ||
49 | static 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 | |||
82 | static int perf_session__add_hist_entry(struct perf_session *session, | 51 | static 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); | ||
109 | out: | ||
134 | return err; | 110 | return err; |
135 | } | 111 | } |
136 | 112 | ||
137 | static 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 | ||
163 | static int process_sample_event(union perf_event *event, | 114 | static 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 | ||
195 | static int process_read_event(union perf_event *event, | 138 | static 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 | ||
285 | static int hists__tty_browse_tree(struct rb_root *tree, const char *help) | 225 | static 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) | |||
317 | static int __cmd_report(void) | 256 | static 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 | ||
373 | out_delete: | 311 | out_delete: |
374 | /* | 312 | /* |