diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-12-16 10:49:27 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-16 10:53:37 -0500 |
commit | c351c2816177eb7d2979ec874b9b895abe9d6e5c (patch) | |
tree | b6dd7fb4a5e048168319111e18082025c2e93f1b /tools | |
parent | 125c4fad1e60751ceaab1ee2a73bddf31213e5ca (diff) |
perf diff: Use perf_session__fprintf_hists just like 'perf record'
That means that almost everything you can do with 'perf report'
can be done with 'perf diff', for instance:
$ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2699
samples) ] $ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2687
samples) ] perf diff | head -8
9.02% +1.00% find libc-2.10.1.so [.] _IO_vfprintf_internal
2.91% -1.00% find [kernel] [k] __kmalloc
2.85% -1.00% find [kernel] [k] ext4_htree_store_dirent
1.99% -1.00% find [kernel] [k] _atomic_dec_and_lock
2.44% find [kernel] [k] half_md4_transform
$
So if you want to zoom into libc:
$ perf diff --dsos libc-2.10.1.so | head -8
37.34% find [.] _IO_vfprintf_internal
10.34% find [.] __GI_memmove
8.25% +2.00% find [.] _int_malloc
5.07% -1.00% find [.] __GI_mempcpy
7.62% +2.00% find [.] _int_free
$
And if there were multiple commands using libc, it is also
possible to aggregate them all by using --sort symbol:
$ perf diff --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% [.] __GI_mempcpy
7.62% +2.00% [.] _int_free
$
The displacement column now is off by default, to use it:
perf diff -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% +2 [.] __GI_mempcpy
7.62% +2.00% -1 [.] _int_free
$
Using -t/--field-separator can be used for scripting:
$ perf diff -t, -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34, , ,[.] _IO_vfprintf_internal
10.34, , ,[.] __GI_memmove
8.25,+2.00%, ,[.] _int_malloc
5.07,-1.00%, +2,[.] __GI_mempcpy
7.62,+2.00%, -1,[.] _int_free
6.99,+1.00%, -1,[.] _IO_new_file_xsputn
1.89,-2.00%, +4,[.] __readdir64
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260978567-550-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Documentation/perf-diff.txt | 29 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-report.txt | 4 | ||||
-rw-r--r-- | tools/perf/builtin-diff.c | 90 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 12 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 126 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 5 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 11 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 2 |
8 files changed, 169 insertions, 110 deletions
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 6936fdb6d472..8974e208cba6 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt | |||
@@ -19,9 +19,32 @@ If no parameters are passed it will assume perf.data.old and perf.data. | |||
19 | 19 | ||
20 | OPTIONS | 20 | OPTIONS |
21 | ------- | 21 | ------- |
22 | -p:: | 22 | -d:: |
23 | --percentage:: | 23 | --dsos=:: |
24 | Show percentages instead of raw counts | 24 | Only consider symbols in these dsos. CSV that understands |
25 | file://filename entries. | ||
26 | |||
27 | -C:: | ||
28 | --comms=:: | ||
29 | Only consider symbols in these comms. CSV that understands | ||
30 | file://filename entries. | ||
31 | |||
32 | -S:: | ||
33 | --symbols=:: | ||
34 | Only consider these symbols. CSV that understands | ||
35 | file://filename entries. | ||
36 | |||
37 | -s:: | ||
38 | --sort=:: | ||
39 | Sort by key(s): pid, comm, dso, symbol. | ||
40 | |||
41 | -t:: | ||
42 | --field-separator=:: | ||
43 | |||
44 | Use a special separator character and don't pad with spaces, replacing | ||
45 | all occurances of this separator in symbol names (and other output) | ||
46 | with a '.' character, that thus it's the only non valid separator. | ||
47 | |||
25 | -v:: | 48 | -v:: |
26 | --verbose:: | 49 | --verbose:: |
27 | Be verbose, for instance, show the raw counts in addition to the | 50 | Be verbose, for instance, show the raw counts in addition to the |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 9dccb180b7af..abfabe9147a4 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -39,6 +39,10 @@ OPTIONS | |||
39 | Only consider these symbols. CSV that understands | 39 | Only consider these symbols. CSV that understands |
40 | file://filename entries. | 40 | file://filename entries. |
41 | 41 | ||
42 | -s:: | ||
43 | --sort=:: | ||
44 | Sort by key(s): pid, comm, dso, symbol, parent. | ||
45 | |||
42 | -w:: | 46 | -w:: |
43 | --field-width=:: | 47 | --field-width=:: |
44 | Force each column width to the provided list, for large terminal | 48 | Force each column width to the provided list, for large terminal |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index ff91e9c291bb..66f100d249a8 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -16,10 +16,10 @@ | |||
16 | 16 | ||
17 | #include <stdlib.h> | 17 | #include <stdlib.h> |
18 | 18 | ||
19 | static char const *input_old = "perf.data.old", | 19 | static char const *input_old = "perf.data.old", |
20 | *input_new = "perf.data"; | 20 | *input_new = "perf.data"; |
21 | static int force; | 21 | static int force; |
22 | static bool show_percent; | 22 | static bool show_displacement; |
23 | 23 | ||
24 | static int perf_session__add_hist_entry(struct perf_session *self, | 24 | static int perf_session__add_hist_entry(struct perf_session *self, |
25 | struct addr_location *al, u64 count) | 25 | struct addr_location *al, u64 count) |
@@ -162,70 +162,6 @@ static void perf_session__match_hists(struct perf_session *old_session, | |||
162 | } | 162 | } |
163 | } | 163 | } |
164 | 164 | ||
165 | static size_t hist_entry__fprintf_matched(struct hist_entry *self, | ||
166 | unsigned long pos, | ||
167 | struct perf_session *session, | ||
168 | struct perf_session *pair_session, | ||
169 | FILE *fp) | ||
170 | { | ||
171 | u64 old_count = 0; | ||
172 | char displacement[16]; | ||
173 | size_t printed; | ||
174 | |||
175 | if (self->pair != NULL) { | ||
176 | long pdiff = (long)self->pair->position - (long)pos; | ||
177 | old_count = self->pair->count; | ||
178 | if (pdiff == 0) | ||
179 | goto blank; | ||
180 | snprintf(displacement, sizeof(displacement), "%+4ld", pdiff); | ||
181 | } else { | ||
182 | blank: memset(displacement, ' ', sizeof(displacement)); | ||
183 | } | ||
184 | |||
185 | printed = fprintf(fp, "%4lu %5.5s ", pos, displacement); | ||
186 | |||
187 | if (show_percent) { | ||
188 | double old_percent = 0, new_percent = 0, diff; | ||
189 | |||
190 | if (pair_session->events_stats.total > 0) | ||
191 | old_percent = (old_count * 100) / pair_session->events_stats.total; | ||
192 | if (session->events_stats.total > 0) | ||
193 | new_percent = (self->count * 100) / session->events_stats.total; | ||
194 | |||
195 | diff = old_percent - new_percent; | ||
196 | if (verbose) | ||
197 | printed += fprintf(fp, " %3.2f%% %3.2f%%", old_percent, new_percent); | ||
198 | |||
199 | if ((u64)diff != 0) | ||
200 | printed += fprintf(fp, " %+4.2F%%", diff); | ||
201 | else | ||
202 | printed += fprintf(fp, " "); | ||
203 | } else { | ||
204 | if (verbose) | ||
205 | printed += fprintf(fp, " %9Lu %9Lu", old_count, self->count); | ||
206 | printed += fprintf(fp, " %+9Ld", (s64)self->count - (s64)old_count); | ||
207 | } | ||
208 | |||
209 | return printed + fprintf(fp, " %25.25s %s\n", | ||
210 | self->map->dso->name, self->sym->name); | ||
211 | } | ||
212 | |||
213 | static size_t perf_session__fprintf_matched_hists(struct perf_session *self, | ||
214 | struct perf_session *pair, | ||
215 | FILE *fp) | ||
216 | { | ||
217 | struct rb_node *nd; | ||
218 | size_t printed = 0; | ||
219 | unsigned long pos = 1; | ||
220 | |||
221 | for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { | ||
222 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); | ||
223 | printed += hist_entry__fprintf_matched(he, pos++, self, pair, fp); | ||
224 | } | ||
225 | |||
226 | return printed; | ||
227 | } | ||
228 | |||
229 | static int __cmd_diff(void) | 165 | static int __cmd_diff(void) |
230 | { | 166 | { |
231 | int ret, i; | 167 | int ret, i; |
@@ -244,7 +180,8 @@ static int __cmd_diff(void) | |||
244 | } | 180 | } |
245 | 181 | ||
246 | perf_session__match_hists(session[0], session[1]); | 182 | perf_session__match_hists(session[0], session[1]); |
247 | perf_session__fprintf_matched_hists(session[1], session[0], stdout); | 183 | perf_session__fprintf_hists(session[1], session[0], |
184 | show_displacement, stdout); | ||
248 | out_delete: | 185 | out_delete: |
249 | for (i = 0; i < 2; ++i) | 186 | for (i = 0; i < 2; ++i) |
250 | perf_session__delete(session[i]); | 187 | perf_session__delete(session[i]); |
@@ -258,13 +195,13 @@ static const char *const diff_usage[] = { | |||
258 | static const struct option options[] = { | 195 | static const struct option options[] = { |
259 | OPT_BOOLEAN('v', "verbose", &verbose, | 196 | OPT_BOOLEAN('v', "verbose", &verbose, |
260 | "be more verbose (show symbol address, etc)"), | 197 | "be more verbose (show symbol address, etc)"), |
198 | OPT_BOOLEAN('m', "displacement", &show_displacement, | ||
199 | "Show position displacement relative to baseline"), | ||
261 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 200 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
262 | "dump raw trace in ASCII"), | 201 | "dump raw trace in ASCII"), |
263 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | 202 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), |
264 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, | 203 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, |
265 | "load module symbols - WARNING: use only with -k and LIVE kernel"), | 204 | "load module symbols - WARNING: use only with -k and LIVE kernel"), |
266 | OPT_BOOLEAN('p', "percentages", &show_percent, | ||
267 | "Don't shorten the pathnames taking into account the cwd"), | ||
268 | OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, | 205 | OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, |
269 | "Don't shorten the pathnames taking into account the cwd"), | 206 | "Don't shorten the pathnames taking into account the cwd"), |
270 | OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", | 207 | OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", |
@@ -273,6 +210,11 @@ static const struct option options[] = { | |||
273 | "only consider symbols in these comms"), | 210 | "only consider symbols in these comms"), |
274 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | 211 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", |
275 | "only consider these symbols"), | 212 | "only consider these symbols"), |
213 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | ||
214 | "sort by key(s): pid, comm, dso, symbol, parent"), | ||
215 | OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", | ||
216 | "separator for columns, no spaces will be added between " | ||
217 | "columns '.' is reserved."), | ||
276 | OPT_END() | 218 | OPT_END() |
277 | }; | 219 | }; |
278 | 220 | ||
@@ -289,10 +231,16 @@ int cmd_diff(int argc, const char **argv, const char *prefix __used) | |||
289 | input_new = argv[0]; | 231 | input_new = argv[0]; |
290 | } | 232 | } |
291 | 233 | ||
234 | symbol_conf.exclude_other = false; | ||
292 | if (symbol__init() < 0) | 235 | if (symbol__init() < 0) |
293 | return -1; | 236 | return -1; |
294 | 237 | ||
295 | setup_sorting(diff_usage, options); | 238 | setup_sorting(diff_usage, options); |
296 | setup_pager(); | 239 | setup_pager(); |
240 | |||
241 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); | ||
242 | sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL); | ||
243 | sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL); | ||
244 | |||
297 | return __cmd_diff(); | 245 | return __cmd_diff(); |
298 | } | 246 | } |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index cf1d370f51cb..e50a6b10ee6f 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -225,7 +225,7 @@ static int __cmd_report(void) | |||
225 | perf_session__collapse_resort(session); | 225 | perf_session__collapse_resort(session); |
226 | perf_session__output_resort(session, session->events_stats.total); | 226 | perf_session__output_resort(session, session->events_stats.total); |
227 | fprintf(stdout, "# Samples: %ld\n#\n", session->events_stats.total); | 227 | fprintf(stdout, "# Samples: %ld\n#\n", session->events_stats.total); |
228 | perf_session__fprintf_hists(session, stdout); | 228 | perf_session__fprintf_hists(session, NULL, false, stdout); |
229 | if (sort_order == default_sort_order && | 229 | if (sort_order == default_sort_order && |
230 | parent_pattern == default_parent_pattern) | 230 | parent_pattern == default_parent_pattern) |
231 | fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n"); | 231 | fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n"); |
@@ -344,16 +344,6 @@ static const struct option options[] = { | |||
344 | OPT_END() | 344 | OPT_END() |
345 | }; | 345 | }; |
346 | 346 | ||
347 | static void sort_entry__setup_elide(struct sort_entry *self, | ||
348 | struct strlist *list, | ||
349 | const char *list_name, FILE *fp) | ||
350 | { | ||
351 | if (list && strlist__nr_entries(list) == 1) { | ||
352 | fprintf(fp, "# %s: %s\n", list_name, strlist__entry(list, 0)->s); | ||
353 | self->elide = true; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | int cmd_report(int argc, const char **argv, const char *prefix __used) | 347 | int cmd_report(int argc, const char **argv, const char *prefix __used) |
358 | { | 348 | { |
359 | argc = parse_options(argc, argv, options, report_usage, 0); | 349 | argc = parse_options(argc, argv, options, report_usage, 0); |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 6e416a62e0d6..ecf853cdc0bf 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -454,34 +454,80 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, | |||
454 | return ret; | 454 | return ret; |
455 | } | 455 | } |
456 | 456 | ||
457 | static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self, | 457 | static size_t hist_entry__fprintf(struct hist_entry *self, |
458 | struct perf_session *session) | 458 | struct perf_session *session, |
459 | struct perf_session *pair_session, | ||
460 | bool show_displacement, | ||
461 | long displacement, FILE *fp) | ||
459 | { | 462 | { |
460 | struct sort_entry *se; | 463 | struct sort_entry *se; |
464 | u64 count, total; | ||
465 | const char *sep = symbol_conf.field_sep; | ||
461 | size_t ret; | 466 | size_t ret; |
462 | 467 | ||
463 | if (symbol_conf.exclude_other && !self->parent) | 468 | if (symbol_conf.exclude_other && !self->parent) |
464 | return 0; | 469 | return 0; |
465 | 470 | ||
466 | if (session->events_stats.total) | 471 | if (pair_session) { |
467 | ret = percent_color_fprintf(fp, | 472 | count = self->pair ? self->pair->count : 0; |
468 | symbol_conf.field_sep ? "%.2f" : " %6.2f%%", | 473 | total = pair_session->events_stats.total; |
469 | (self->count * 100.0) / session->events_stats.total); | 474 | } else { |
475 | count = self->count; | ||
476 | total = session->events_stats.total; | ||
477 | } | ||
478 | |||
479 | if (total) | ||
480 | ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%", | ||
481 | (count * 100.0) / total); | ||
470 | else | 482 | else |
471 | ret = fprintf(fp, symbol_conf.field_sep ? "%lld" : "%12lld ", self->count); | 483 | ret = fprintf(fp, sep ? "%lld" : "%12lld ", count); |
472 | 484 | ||
473 | if (symbol_conf.show_nr_samples) { | 485 | if (symbol_conf.show_nr_samples) { |
474 | if (symbol_conf.field_sep) | 486 | if (sep) |
475 | fprintf(fp, "%c%lld", *symbol_conf.field_sep, self->count); | 487 | fprintf(fp, "%c%lld", *sep, count); |
476 | else | 488 | else |
477 | fprintf(fp, "%11lld", self->count); | 489 | fprintf(fp, "%11lld", count); |
490 | } | ||
491 | |||
492 | if (pair_session) { | ||
493 | char bf[32]; | ||
494 | double old_percent = 0, new_percent = 0, diff; | ||
495 | |||
496 | if (total > 0) | ||
497 | old_percent = (count * 100) / total; | ||
498 | if (session->events_stats.total > 0) | ||
499 | new_percent = (self->count * 100) / session->events_stats.total; | ||
500 | |||
501 | diff = old_percent - new_percent; | ||
502 | |||
503 | if ((u64)diff != 0) | ||
504 | snprintf(bf, sizeof(bf), "%+4.2F%%", diff); | ||
505 | else | ||
506 | snprintf(bf, sizeof(bf), " "); | ||
507 | |||
508 | if (sep) | ||
509 | ret += fprintf(fp, "%c%s", *sep, bf); | ||
510 | else | ||
511 | ret += fprintf(fp, "%11.11s", bf); | ||
512 | |||
513 | if (show_displacement) { | ||
514 | if (displacement) | ||
515 | snprintf(bf, sizeof(bf), "%+4ld", displacement); | ||
516 | else | ||
517 | snprintf(bf, sizeof(bf), " "); | ||
518 | |||
519 | if (sep) | ||
520 | fprintf(fp, "%c%s", *sep, bf); | ||
521 | else | ||
522 | fprintf(fp, "%6.6s", bf); | ||
523 | } | ||
478 | } | 524 | } |
479 | 525 | ||
480 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 526 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
481 | if (se->elide) | 527 | if (se->elide) |
482 | continue; | 528 | continue; |
483 | 529 | ||
484 | fprintf(fp, "%s", symbol_conf.field_sep ?: " "); | 530 | fprintf(fp, "%s", sep ?: " "); |
485 | ret += se->print(fp, self, se->width ? *se->width : 0); | 531 | ret += se->print(fp, self, se->width ? *se->width : 0); |
486 | } | 532 | } |
487 | 533 | ||
@@ -504,29 +550,49 @@ static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self, | |||
504 | return ret; | 550 | return ret; |
505 | } | 551 | } |
506 | 552 | ||
507 | size_t perf_session__fprintf_hists(struct perf_session *self, FILE *fp) | 553 | size_t perf_session__fprintf_hists(struct perf_session *self, |
554 | struct perf_session *pair, | ||
555 | bool show_displacement, FILE *fp) | ||
508 | { | 556 | { |
509 | struct hist_entry *pos; | ||
510 | struct sort_entry *se; | 557 | struct sort_entry *se; |
511 | struct rb_node *nd; | 558 | struct rb_node *nd; |
512 | size_t ret = 0; | 559 | size_t ret = 0; |
560 | unsigned long position = 1; | ||
561 | long displacement = 0; | ||
513 | unsigned int width; | 562 | unsigned int width; |
563 | const char *sep = symbol_conf.field_sep; | ||
514 | char *col_width = symbol_conf.col_width_list_str; | 564 | char *col_width = symbol_conf.col_width_list_str; |
515 | 565 | ||
516 | init_rem_hits(); | 566 | init_rem_hits(); |
517 | 567 | ||
518 | fprintf(fp, "# Overhead"); | 568 | fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); |
569 | |||
519 | if (symbol_conf.show_nr_samples) { | 570 | if (symbol_conf.show_nr_samples) { |
520 | if (symbol_conf.field_sep) | 571 | if (sep) |
521 | fprintf(fp, "%cSamples", *symbol_conf.field_sep); | 572 | fprintf(fp, "%cSamples", *sep); |
522 | else | 573 | else |
523 | fputs(" Samples ", fp); | 574 | fputs(" Samples ", fp); |
524 | } | 575 | } |
576 | |||
577 | if (pair) { | ||
578 | if (sep) | ||
579 | ret += fprintf(fp, "%cDelta", *sep); | ||
580 | else | ||
581 | ret += fprintf(fp, " Delta "); | ||
582 | |||
583 | if (show_displacement) { | ||
584 | if (sep) | ||
585 | ret += fprintf(fp, "%cDisplacement", *sep); | ||
586 | else | ||
587 | ret += fprintf(fp, " Displ"); | ||
588 | } | ||
589 | } | ||
590 | |||
525 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 591 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
526 | if (se->elide) | 592 | if (se->elide) |
527 | continue; | 593 | continue; |
528 | if (symbol_conf.field_sep) { | 594 | if (sep) { |
529 | fprintf(fp, "%c%s", *symbol_conf.field_sep, se->header); | 595 | fprintf(fp, "%c%s", *sep, se->header); |
530 | continue; | 596 | continue; |
531 | } | 597 | } |
532 | width = strlen(se->header); | 598 | width = strlen(se->header); |
@@ -545,12 +611,17 @@ size_t perf_session__fprintf_hists(struct perf_session *self, FILE *fp) | |||
545 | } | 611 | } |
546 | fprintf(fp, "\n"); | 612 | fprintf(fp, "\n"); |
547 | 613 | ||
548 | if (symbol_conf.field_sep) | 614 | if (sep) |
549 | goto print_entries; | 615 | goto print_entries; |
550 | 616 | ||
551 | fprintf(fp, "# ........"); | 617 | fprintf(fp, "# ........"); |
552 | if (symbol_conf.show_nr_samples) | 618 | if (symbol_conf.show_nr_samples) |
553 | fprintf(fp, " .........."); | 619 | fprintf(fp, " .........."); |
620 | if (pair) { | ||
621 | fprintf(fp, " .........."); | ||
622 | if (show_displacement) | ||
623 | fprintf(fp, " ....."); | ||
624 | } | ||
554 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 625 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
555 | unsigned int i; | 626 | unsigned int i; |
556 | 627 | ||
@@ -565,14 +636,23 @@ size_t perf_session__fprintf_hists(struct perf_session *self, FILE *fp) | |||
565 | for (i = 0; i < width; i++) | 636 | for (i = 0; i < width; i++) |
566 | fprintf(fp, "."); | 637 | fprintf(fp, "."); |
567 | } | 638 | } |
568 | fprintf(fp, "\n"); | ||
569 | 639 | ||
570 | fprintf(fp, "#\n"); | 640 | fprintf(fp, "\n#\n"); |
571 | 641 | ||
572 | print_entries: | 642 | print_entries: |
573 | for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { | 643 | for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { |
574 | pos = rb_entry(nd, struct hist_entry, rb_node); | 644 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
575 | ret += hist_entry__fprintf(fp, pos, self); | 645 | |
646 | if (show_displacement) { | ||
647 | if (h->pair != NULL) | ||
648 | displacement = ((long)h->pair->position - | ||
649 | (long)position); | ||
650 | else | ||
651 | displacement = 0; | ||
652 | ++position; | ||
653 | } | ||
654 | ret += hist_entry__fprintf(h, self, pair, show_displacement, | ||
655 | displacement, fp); | ||
576 | } | 656 | } |
577 | 657 | ||
578 | free(rem_sq_bracket); | 658 | free(rem_sq_bracket); |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index c7ac78d93b0c..e5f99b24048b 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -21,6 +21,7 @@ void hist_entry__free(struct hist_entry *); | |||
21 | 21 | ||
22 | void perf_session__output_resort(struct perf_session *self, u64 total_samples); | 22 | void perf_session__output_resort(struct perf_session *self, u64 total_samples); |
23 | void perf_session__collapse_resort(struct perf_session *self); | 23 | void perf_session__collapse_resort(struct perf_session *self); |
24 | size_t perf_session__fprintf_hists(struct perf_session *self, FILE *fp); | 24 | size_t perf_session__fprintf_hists(struct perf_session *self, |
25 | 25 | struct perf_session *pair, | |
26 | bool show_displacement, FILE *fp); | ||
26 | #endif /* __PERF_HIST_H */ | 27 | #endif /* __PERF_HIST_H */ |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index cff1c316fa91..cb0f327de9e8 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -303,3 +303,14 @@ void setup_sorting(const char * const usagestr[], const struct option *opts) | |||
303 | 303 | ||
304 | free(str); | 304 | free(str); |
305 | } | 305 | } |
306 | |||
307 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, | ||
308 | const char *list_name, FILE *fp) | ||
309 | { | ||
310 | if (list && strlist__nr_entries(list) == 1) { | ||
311 | if (fp != NULL) | ||
312 | fprintf(fp, "# %s: %s\n", list_name, | ||
313 | strlist__entry(list, 0)->s); | ||
314 | self->elide = true; | ||
315 | } | ||
316 | } | ||
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 925f083e1eee..753f9ea99fb0 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -101,5 +101,7 @@ extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *); | |||
101 | extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); | 101 | extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); |
102 | extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); | 102 | extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); |
103 | extern int sort_dimension__add(const char *); | 103 | extern int sort_dimension__add(const char *); |
104 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, | ||
105 | const char *list_name, FILE *fp); | ||
104 | 106 | ||
105 | #endif /* __PERF_SORT_H */ | 107 | #endif /* __PERF_SORT_H */ |