diff options
-rw-r--r-- | tools/perf/util/evsel.c | 1 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 111 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 9 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 1 |
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 | ||
44 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) | 45 | struct 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); |
177 | out: | 182 | out: |
178 | hist_entry__add_cpumode_period(he, al->cpumode, period); | 183 | hist_entry__add_cpumode_period(he, al->cpumode, period); |
184 | out_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 | ||
262 | void hists__collapse_resort(struct hists *hists) | 269 | static 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 | |||
284 | static 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; | 307 | void hists__collapse_resort(struct hists *hists) |
308 | { | ||
309 | return __hists__collapse_resort(hists, false); | ||
310 | } | ||
311 | |||
312 | void 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 | ||
318 | void hists__output_resort(struct hists *hists) | 347 | static 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; | 376 | void hists__output_resort(struct hists *hists) |
377 | { | ||
378 | return __hists__output_resort(hists, false); | ||
379 | } | ||
380 | |||
381 | void hists__output_resort_threaded(struct hists *hists) | ||
382 | { | ||
383 | return __hists__output_resort(hists, true); | ||
343 | } | 384 | } |
344 | 385 | ||
345 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) | 386 | static 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 | |||
1088 | void 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 | ||
7 | extern struct callchain_param callchain_param; | 8 | extern struct callchain_param callchain_param; |
@@ -43,8 +44,12 @@ enum hist_column { | |||
43 | }; | 44 | }; |
44 | 45 | ||
45 | struct hists { | 46 | struct 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 | ||
60 | void hists__init(struct hists *hists); | ||
61 | |||
55 | struct hist_entry *__hists__add_entry(struct hists *self, | 62 | struct 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, | |||
67 | void hist_entry__free(struct hist_entry *); | 74 | void hist_entry__free(struct hist_entry *); |
68 | 75 | ||
69 | void hists__output_resort(struct hists *self); | 76 | void hists__output_resort(struct hists *self); |
77 | void hists__output_resort_threaded(struct hists *hists); | ||
70 | void hists__collapse_resort(struct hists *self); | 78 | void hists__collapse_resort(struct hists *self); |
79 | void hists__collapse_resort_threaded(struct hists *hists); | ||
71 | 80 | ||
72 | void hists__inc_nr_events(struct hists *self, u32 type); | 81 | void hists__inc_nr_events(struct hists *self, u32 type); |
73 | size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); | 82 | size_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 | */ |
47 | struct hist_entry { | 47 | struct 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; |