diff options
| -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 */ |
