aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorEric B Munson <ebmunson@us.ibm.com>2010-03-05 10:51:09 -0500
committerIngo Molnar <mingo@elte.hu>2010-03-10 07:53:50 -0500
commitcbbc79a53278b83bf7f834127751459f9299e402 (patch)
treefe6e2b03671264b68f745329d64e613d71870188 /tools
parenteefc465cdd49cb89a742083fac2807c718ddad31 (diff)
perf report: Add multiple event support
Perf report does not handle multiple events being reported, even though perf record stores them properly on disk. This patch addresses that issue by adding the logic to perf report to use the event stream id that is saved by record and the new data structures to seperate the event streams and report them individually. Signed-off-by: Eric B Munson <ebmunson@us.ibm.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> LKML-Reference: <1267804269-22660-6-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/builtin-report.c115
1 files changed, 100 insertions, 15 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 294b4cf105f2..f815de25d0fc 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -45,29 +45,71 @@ static char *pretty_printing_style = default_pretty_printing_style;
45 45
46static char callchain_default_opt[] = "fractal,0.5"; 46static char callchain_default_opt[] = "fractal,0.5";
47 47
48static struct event_stat_id *get_stats(struct perf_session *self,
49 u64 event_stream, u32 type, u64 config)
50{
51 struct rb_node **p = &self->stats_by_id.rb_node;
52 struct rb_node *parent = NULL;
53 struct event_stat_id *iter, *new;
54
55 while (*p != NULL) {
56 parent = *p;
57 iter = rb_entry(parent, struct event_stat_id, 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 event_stat_id));
69 if (new == NULL)
70 return NULL;
71 memset(new, 0, sizeof(struct event_stat_id));
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->stats_by_id);
77 return new;
78}
79
48static int perf_session__add_hist_entry(struct perf_session *self, 80static int perf_session__add_hist_entry(struct perf_session *self,
49 struct addr_location *al, 81 struct addr_location *al,
50 struct ip_callchain *chain, u64 count) 82 struct sample_data *data)
51{ 83{
52 struct symbol **syms = NULL, *parent = NULL; 84 struct symbol **syms = NULL, *parent = NULL;
53 bool hit; 85 bool hit;
54 struct hist_entry *he; 86 struct hist_entry *he;
87 struct event_stat_id *stats;
88 struct perf_event_attr *attr;
55 89
56 if ((sort__has_parent || symbol_conf.use_callchain) && chain) 90 if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain)
57 syms = perf_session__resolve_callchain(self, al->thread, 91 syms = perf_session__resolve_callchain(self, al->thread,
58 chain, &parent); 92 data->callchain, &parent);
59 he = __perf_session__add_hist_entry(&self->hists, al, parent, 93
60 count, &hit); 94 attr = perf_header__find_attr(data->id, &self->header);
95 if (attr)
96 stats = get_stats(self, data->id, attr->type, attr->config);
97 else
98 stats = get_stats(self, data->id, 0, 0);
99 if (stats == NULL)
100 return -ENOMEM;
101 he = __perf_session__add_hist_entry(&stats->hists, al, parent,
102 data->period, &hit);
61 if (he == NULL) 103 if (he == NULL)
62 return -ENOMEM; 104 return -ENOMEM;
63 105
64 if (hit) 106 if (hit)
65 he->count += count; 107 he->count += data->period;
66 108
67 if (symbol_conf.use_callchain) { 109 if (symbol_conf.use_callchain) {
68 if (!hit) 110 if (!hit)
69 callchain_init(&he->callchain); 111 callchain_init(&he->callchain);
70 append_chain(&he->callchain, chain, syms); 112 append_chain(&he->callchain, data->callchain, syms);
71 free(syms); 113 free(syms);
72 } 114 }
73 115
@@ -87,10 +129,30 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
87 return 0; 129 return 0;
88} 130}
89 131
132static int add_event_total(struct perf_session *session,
133 struct sample_data *data,
134 struct perf_event_attr *attr)
135{
136 struct event_stat_id *stats;
137
138 if (attr)
139 stats = get_stats(session, data->id, attr->type, attr->config);
140 else
141 stats = get_stats(session, data->id, 0, 0);
142
143 if (!stats)
144 return -ENOMEM;
145
146 stats->stats.total += data->period;
147 session->events_stats.total += data->period;
148 return 0;
149}
150
90static int process_sample_event(event_t *event, struct perf_session *session) 151static int process_sample_event(event_t *event, struct perf_session *session)
91{ 152{
92 struct sample_data data = { .period = 1, }; 153 struct sample_data data = { .period = 1, };
93 struct addr_location al; 154 struct addr_location al;
155 struct perf_event_attr *attr;
94 156
95 event__parse_sample(event, session->sample_type, &data); 157 event__parse_sample(event, session->sample_type, &data);
96 158
@@ -124,12 +186,18 @@ static int process_sample_event(event_t *event, struct perf_session *session)
124 if (al.filtered || (hide_unresolved && al.sym == NULL)) 186 if (al.filtered || (hide_unresolved && al.sym == NULL))
125 return 0; 187 return 0;
126 188
127 if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { 189 if (perf_session__add_hist_entry(session, &al, &data)) {
128 pr_debug("problem incrementing symbol count, skipping event\n"); 190 pr_debug("problem incrementing symbol count, skipping event\n");
129 return -1; 191 return -1;
130 } 192 }
131 193
132 session->events_stats.total += data.period; 194 attr = perf_header__find_attr(data.id, &session->header);
195
196 if (add_event_total(session, &data, attr)) {
197 pr_debug("problem adding event count\n");
198 return -1;
199 }
200
133 return 0; 201 return 0;
134} 202}
135 203
@@ -198,6 +266,7 @@ static int __cmd_report(void)
198{ 266{
199 int ret = -EINVAL; 267 int ret = -EINVAL;
200 struct perf_session *session; 268 struct perf_session *session;
269 struct rb_node *next;
201 270
202 session = perf_session__new(input_name, O_RDONLY, force); 271 session = perf_session__new(input_name, O_RDONLY, force);
203 if (session == NULL) 272 if (session == NULL)
@@ -225,12 +294,28 @@ static int __cmd_report(void)
225 if (verbose > 2) 294 if (verbose > 2)
226 dsos__fprintf(stdout); 295 dsos__fprintf(stdout);
227 296
228 perf_session__collapse_resort(&session->hists); 297 next = rb_first(&session->stats_by_id);
229 perf_session__output_resort(&session->hists, 298 while (next) {
230 session->events_stats.total); 299 struct event_stat_id *stats;
231 fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total); 300
232 perf_session__fprintf_hists(&session->hists, NULL, false, stdout, 301 stats = rb_entry(next, struct event_stat_id, rb_node);
233 session->events_stats.total); 302 perf_session__collapse_resort(&stats->hists);
303 perf_session__output_resort(&stats->hists, stats->stats.total);
304 if (rb_first(&session->stats_by_id) ==
305 rb_last(&session->stats_by_id))
306 fprintf(stdout, "# Samples: %Ld\n#\n",
307 stats->stats.total);
308 else
309 fprintf(stdout, "# Samples: %Ld %s\n#\n",
310 stats->stats.total,
311 __event_name(stats->type, stats->config));
312
313 perf_session__fprintf_hists(&stats->hists, NULL, false, stdout,
314 stats->stats.total);
315 fprintf(stdout, "\n\n");
316 next = rb_next(&stats->rb_node);
317 }
318
234 if (sort_order == default_sort_order && 319 if (sort_order == default_sort_order &&
235 parent_pattern == default_parent_pattern) 320 parent_pattern == default_parent_pattern)
236 fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n"); 321 fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n");