aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-10-05 16:50:23 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-10-07 11:12:29 -0400
commit1980c2ebd7020d82c024b8c4046849b38e78e7da (patch)
tree3f2004bffaf6e77b66571e44f8af247ac177d92b /tools
parent3f2728bdb6a4cad0d18b09d03e2008121c902751 (diff)
perf hists: Threaded addition and sorting of entries
By using a mutex just for inserting and rotating two hist_entry rb trees, so that when sorting we can get the last batch of entries created from the ring buffer, merge it with whatever we have processed so far and show the output while new entries are being added. The 'report' tool continues, for now, to do it without threading, but will use this in the future to allow visualization of results in long perf.data sessions while the entries are being processed. The new 'top' tool will be the first user. Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-9b05atsn0q6m7fqgrug8fk2i@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/evsel.c1
-rw-r--r--tools/perf/util/hist.c111
-rw-r--r--tools/perf/util/hist.h9
-rw-r--r--tools/perf/util/sort.h1
4 files changed, 92 insertions, 30 deletions
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index e389815078d3..b46f6e4bff3c 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -39,6 +39,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
39 evsel->idx = idx; 39 evsel->idx = idx;
40 evsel->attr = *attr; 40 evsel->attr = *attr;
41 INIT_LIST_HEAD(&evsel->node); 41 INIT_LIST_HEAD(&evsel->node);
42 hists__init(&evsel->hists);
42} 43}
43 44
44struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 45struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 32c90865940f..80fe30d90d72 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -118,6 +118,7 @@ static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
118 if (!h->filtered) { 118 if (!h->filtered) {
119 hists__calc_col_len(hists, h); 119 hists__calc_col_len(hists, h);
120 ++hists->nr_entries; 120 ++hists->nr_entries;
121 hists->stats.total_period += h->period;
121 } 122 }
122} 123}
123 124
@@ -132,7 +133,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
132 struct addr_location *al, 133 struct addr_location *al,
133 struct symbol *sym_parent, u64 period) 134 struct symbol *sym_parent, u64 period)
134{ 135{
135 struct rb_node **p = &hists->entries.rb_node; 136 struct rb_node **p;
136 struct rb_node *parent = NULL; 137 struct rb_node *parent = NULL;
137 struct hist_entry *he; 138 struct hist_entry *he;
138 struct hist_entry entry = { 139 struct hist_entry entry = {
@@ -150,9 +151,13 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
150 }; 151 };
151 int cmp; 152 int cmp;
152 153
154 pthread_mutex_lock(&hists->lock);
155
156 p = &hists->entries_in->rb_node;
157
153 while (*p != NULL) { 158 while (*p != NULL) {
154 parent = *p; 159 parent = *p;
155 he = rb_entry(parent, struct hist_entry, rb_node); 160 he = rb_entry(parent, struct hist_entry, rb_node_in);
156 161
157 cmp = hist_entry__cmp(&entry, he); 162 cmp = hist_entry__cmp(&entry, he);
158 163
@@ -170,12 +175,14 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
170 175
171 he = hist_entry__new(&entry); 176 he = hist_entry__new(&entry);
172 if (!he) 177 if (!he)
173 return NULL; 178 goto out_unlock;
174 rb_link_node(&he->rb_node, parent, p); 179
175 rb_insert_color(&he->rb_node, &hists->entries); 180 rb_link_node(&he->rb_node_in, parent, p);
176 hists__inc_nr_entries(hists, he); 181 rb_insert_color(&he->rb_node_in, hists->entries_in);
177out: 182out:
178 hist_entry__add_cpumode_period(he, al->cpumode, period); 183 hist_entry__add_cpumode_period(he, al->cpumode, period);
184out_unlock:
185 pthread_mutex_unlock(&hists->lock);
179 return he; 186 return he;
180} 187}
181 188
@@ -233,7 +240,7 @@ static bool hists__collapse_insert_entry(struct hists *hists,
233 240
234 while (*p != NULL) { 241 while (*p != NULL) {
235 parent = *p; 242 parent = *p;
236 iter = rb_entry(parent, struct hist_entry, rb_node); 243 iter = rb_entry(parent, struct hist_entry, rb_node_in);
237 244
238 cmp = hist_entry__collapse(iter, he); 245 cmp = hist_entry__collapse(iter, he);
239 246
@@ -254,35 +261,57 @@ static bool hists__collapse_insert_entry(struct hists *hists,
254 p = &(*p)->rb_right; 261 p = &(*p)->rb_right;
255 } 262 }
256 263
257 rb_link_node(&he->rb_node, parent, p); 264 rb_link_node(&he->rb_node_in, parent, p);
258 rb_insert_color(&he->rb_node, root); 265 rb_insert_color(&he->rb_node_in, root);
259 return true; 266 return true;
260} 267}
261 268
262void hists__collapse_resort(struct hists *hists) 269static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
263{ 270{
264 struct rb_root tmp; 271 struct rb_root *root;
272
273 pthread_mutex_lock(&hists->lock);
274
275 root = hists->entries_in;
276 if (++hists->entries_in > &hists->entries_in_array[1])
277 hists->entries_in = &hists->entries_in_array[0];
278
279 pthread_mutex_unlock(&hists->lock);
280
281 return root;
282}
283
284static void __hists__collapse_resort(struct hists *hists, bool threaded)
285{
286 struct rb_root *root;
265 struct rb_node *next; 287 struct rb_node *next;
266 struct hist_entry *n; 288 struct hist_entry *n;
267 289
268 if (!sort__need_collapse) 290 if (!sort__need_collapse && !threaded)
269 return; 291 return;
270 292
271 tmp = RB_ROOT; 293 root = hists__get_rotate_entries_in(hists);
272 next = rb_first(&hists->entries); 294 next = rb_first(root);
273 hists->nr_entries = 0; 295 hists->stats.total_period = 0;
274 hists__reset_col_len(hists);
275 296
276 while (next) { 297 while (next) {
277 n = rb_entry(next, struct hist_entry, rb_node); 298 n = rb_entry(next, struct hist_entry, rb_node_in);
278 next = rb_next(&n->rb_node); 299 next = rb_next(&n->rb_node_in);
279 300
280 rb_erase(&n->rb_node, &hists->entries); 301 rb_erase(&n->rb_node_in, root);
281 if (hists__collapse_insert_entry(hists, &tmp, n)) 302 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n))
282 hists__inc_nr_entries(hists, n); 303 hists__inc_nr_entries(hists, n);
283 } 304 }
305}
284 306
285 hists->entries = tmp; 307void hists__collapse_resort(struct hists *hists)
308{
309 return __hists__collapse_resort(hists, false);
310}
311
312void hists__collapse_resort_threaded(struct hists *hists)
313{
314 return __hists__collapse_resort(hists, true);
286} 315}
287 316
288/* 317/*
@@ -315,31 +344,43 @@ static void __hists__insert_output_entry(struct rb_root *entries,
315 rb_insert_color(&he->rb_node, entries); 344 rb_insert_color(&he->rb_node, entries);
316} 345}
317 346
318void hists__output_resort(struct hists *hists) 347static void __hists__output_resort(struct hists *hists, bool threaded)
319{ 348{
320 struct rb_root tmp; 349 struct rb_root *root;
321 struct rb_node *next; 350 struct rb_node *next;
322 struct hist_entry *n; 351 struct hist_entry *n;
323 u64 min_callchain_hits; 352 u64 min_callchain_hits;
324 353
325 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); 354 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
326 355
327 tmp = RB_ROOT; 356 if (sort__need_collapse || threaded)
328 next = rb_first(&hists->entries); 357 root = &hists->entries_collapsed;
358 else
359 root = hists->entries_in;
360
361 next = rb_first(root);
362 hists->entries = RB_ROOT;
329 363
330 hists->nr_entries = 0; 364 hists->nr_entries = 0;
331 hists__reset_col_len(hists); 365 hists__reset_col_len(hists);
332 366
333 while (next) { 367 while (next) {
334 n = rb_entry(next, struct hist_entry, rb_node); 368 n = rb_entry(next, struct hist_entry, rb_node_in);
335 next = rb_next(&n->rb_node); 369 next = rb_next(&n->rb_node_in);
336 370
337 rb_erase(&n->rb_node, &hists->entries); 371 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
338 __hists__insert_output_entry(&tmp, n, min_callchain_hits);
339 hists__inc_nr_entries(hists, n); 372 hists__inc_nr_entries(hists, n);
340 } 373 }
374}
341 375
342 hists->entries = tmp; 376void hists__output_resort(struct hists *hists)
377{
378 return __hists__output_resort(hists, false);
379}
380
381void hists__output_resort_threaded(struct hists *hists)
382{
383 return __hists__output_resort(hists, true);
343} 384}
344 385
345static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 386static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -1043,3 +1084,13 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
1043 1084
1044 return ret; 1085 return ret;
1045} 1086}
1087
1088void hists__init(struct hists *hists)
1089{
1090 memset(hists, 0, sizeof(*hists));
1091 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1092 hists->entries_in = &hists->entries_in_array[0];
1093 hists->entries_collapsed = RB_ROOT;
1094 hists->entries = RB_ROOT;
1095 pthread_mutex_init(&hists->lock, NULL);
1096}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 861ffc31db96..d3f976cc7c56 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -2,6 +2,7 @@
2#define __PERF_HIST_H 2#define __PERF_HIST_H
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <pthread.h>
5#include "callchain.h" 6#include "callchain.h"
6 7
7extern struct callchain_param callchain_param; 8extern struct callchain_param callchain_param;
@@ -43,8 +44,12 @@ enum hist_column {
43}; 44};
44 45
45struct hists { 46struct hists {
47 struct rb_root entries_in_array[2];
48 struct rb_root *entries_in;
46 struct rb_root entries; 49 struct rb_root entries;
50 struct rb_root entries_collapsed;
47 u64 nr_entries; 51 u64 nr_entries;
52 pthread_mutex_t lock;
48 struct events_stats stats; 53 struct events_stats stats;
49 u64 event_stream; 54 u64 event_stream;
50 u16 col_len[HISTC_NR_COLS]; 55 u16 col_len[HISTC_NR_COLS];
@@ -52,6 +57,8 @@ struct hists {
52 struct callchain_cursor callchain_cursor; 57 struct callchain_cursor callchain_cursor;
53}; 58};
54 59
60void hists__init(struct hists *hists);
61
55struct hist_entry *__hists__add_entry(struct hists *self, 62struct hist_entry *__hists__add_entry(struct hists *self,
56 struct addr_location *al, 63 struct addr_location *al,
57 struct symbol *parent, u64 period); 64 struct symbol *parent, u64 period);
@@ -67,7 +74,9 @@ int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
67void hist_entry__free(struct hist_entry *); 74void hist_entry__free(struct hist_entry *);
68 75
69void hists__output_resort(struct hists *self); 76void hists__output_resort(struct hists *self);
77void hists__output_resort_threaded(struct hists *hists);
70void hists__collapse_resort(struct hists *self); 78void hists__collapse_resort(struct hists *self);
79void hists__collapse_resort_threaded(struct hists *hists);
71 80
72void hists__inc_nr_events(struct hists *self, u32 type); 81void hists__inc_nr_events(struct hists *self, u32 type);
73size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 82size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 77d0388ad415..03851e301721 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -45,6 +45,7 @@ extern enum sort_type sort__first_dimension;
45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding 45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding
46 */ 46 */
47struct hist_entry { 47struct hist_entry {
48 struct rb_node rb_node_in;
48 struct rb_node rb_node; 49 struct rb_node rb_node;
49 u64 period; 50 u64 period;
50 u64 period_sys; 51 u64 period_sys;