diff options
author | Namhyung Kim <namhyung@kernel.org> | 2014-03-04 10:46:34 +0900 |
---|---|---|
committer | Jiri Olsa <jolsa@kernel.org> | 2014-05-21 11:45:35 +0200 |
commit | a7d945bc91602f916d2d0c794c179d9a784859e7 (patch) | |
tree | 40b0b84ec5ec0a624cbad51b7342a6ae44903def /tools/perf/util/sort.c | |
parent | 22af969e8cfc6ea46d3e1a774a16d7e19b8cf4db (diff) | |
download | linux-a7d945bc91602f916d2d0c794c179d9a784859e7.tar.bz2 |
perf report: Add -F option to specify output fields
The -F/--fields option is to allow user setup output field in any
order. It can receive any sort keys and following (hpp) fields:
overhead, overhead_sys, overhead_us, sample and period
If guest profiling is enabled, overhead_guest_{sys,us} will be
available too.
The output fields also affect sort order unless you give -s/--sort
option. And any keys specified on -s option, will also be added to
the output field list automatically.
$ perf report -F sym,sample,overhead
...
# Symbol Samples Overhead
# .......................... ............ ........
#
[.] __cxa_atexit 2 2.50%
[.] __libc_csu_init 4 5.00%
[.] __new_exitfn 3 3.75%
[.] _dl_check_map_versions 1 1.25%
[.] _dl_name_match_p 4 5.00%
[.] _dl_setup_hash 1 1.25%
[.] _dl_sysdep_start 1 1.25%
[.] _init 5 6.25%
[.] _setjmp 6 7.50%
[.] a 8 10.00%
[.] b 8 10.00%
[.] brk 1 1.25%
[.] c 8 10.00%
Note that, the example output above is captured after applying next
patch which fixes sort/comparing behavior.
Requested-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
Link: http://lkml.kernel.org/r/1400480762-22852-12-git-send-email-namhyung@kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Diffstat (limited to 'tools/perf/util/sort.c')
-rw-r--r-- | tools/perf/util/sort.c | 209 |
1 files changed, 204 insertions, 5 deletions
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index d64c1e58f1b1..b748b02fcb78 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -13,6 +13,7 @@ const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso const char default_top_sort_order[] = "dso,symbol"; const char default_diff_sort_order[] = "dso,symbol"; const char *sort_order; +const char *field_order; regex_t ignore_callees_regex; int have_ignore_callees = 0; int sort__need_collapse = 0; @@ -1057,6 +1058,20 @@ struct hpp_sort_entry { struct sort_entry *se; }; +bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) +{ + struct hpp_sort_entry *hse_a; + struct hpp_sort_entry *hse_b; + + if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b)) + return false; + + hse_a = container_of(a, struct hpp_sort_entry, hpp); + hse_b = container_of(b, struct hpp_sort_entry, hpp); + + return hse_a->se == hse_b->se; +} + static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct perf_evsel *evsel) { @@ -1092,14 +1107,15 @@ static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); } -static int __sort_dimension__add_hpp(struct sort_dimension *sd) +static struct hpp_sort_entry * +__sort_dimension__alloc_hpp(struct sort_dimension *sd) { struct hpp_sort_entry *hse; hse = malloc(sizeof(*hse)); if (hse == NULL) { pr_err("Memory allocation failed\n"); - return -1; + return NULL; } hse->se = sd->entry; @@ -1115,16 +1131,42 @@ static int __sort_dimension__add_hpp(struct sort_dimension *sd) INIT_LIST_HEAD(&hse->hpp.list); INIT_LIST_HEAD(&hse->hpp.sort_list); + return hse; +} + +bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format) +{ + return format->header == __sort__hpp_header; +} + +static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd) +{ + struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); + + if (hse == NULL) + return -1; + perf_hpp__register_sort_field(&hse->hpp); return 0; } +static int __sort_dimension__add_hpp_output(struct sort_dimension *sd) +{ + struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); + + if (hse == NULL) + return -1; + + perf_hpp__column_register(&hse->hpp); + return 0; +} + static int __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx) { if (sd->taken) return 0; - if (__sort_dimension__add_hpp(sd) < 0) + if (__sort_dimension__add_hpp_sort(sd) < 0) return -1; if (sd->entry->se_collapse) @@ -1149,6 +1191,28 @@ static int __hpp_dimension__add(struct hpp_dimension *hd) return 0; } +static int __sort_dimension__add_output(struct sort_dimension *sd) +{ + if (sd->taken) + return 0; + + if (__sort_dimension__add_hpp_output(sd) < 0) + return -1; + + sd->taken = 1; + return 0; +} + +static int __hpp_dimension__add_output(struct hpp_dimension *hd) +{ + if (!hd->taken) { + hd->taken = 1; + + perf_hpp__column_register(hd->fmt); + } + return 0; +} + int sort_dimension__add(const char *tok) { unsigned int i; @@ -1237,14 +1301,23 @@ static const char *get_default_sort_order(void) return default_sort_orders[sort__mode]; } -int setup_sorting(void) +static int __setup_sorting(void) { char *tmp, *tok, *str; const char *sort_keys = sort_order; int ret = 0; - if (sort_keys == NULL) + if (sort_keys == NULL) { + if (field_order) { + /* + * If user specified field order but no sort order, + * we'll honor it and not add default sort orders. + */ + return 0; + } + sort_keys = get_default_sort_order(); + } str = strdup(sort_keys); if (str == NULL) { @@ -1331,3 +1404,129 @@ void sort__setup_elide(FILE *output) list_for_each_entry(se, &hist_entry__sort_list, list) se->elide = false; } + +static int output_field_add(char *tok) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { + struct sort_dimension *sd = &common_sort_dimensions[i]; + + if (strncasecmp(tok, sd->name, strlen(tok))) + continue; + + return __sort_dimension__add_output(sd); + } + + for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { + struct hpp_dimension *hd = &hpp_sort_dimensions[i]; + + if (strncasecmp(tok, hd->name, strlen(tok))) + continue; + + return __hpp_dimension__add_output(hd); + } + + for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { + struct sort_dimension *sd = &bstack_sort_dimensions[i]; + + if (strncasecmp(tok, sd->name, strlen(tok))) + continue; + + return __sort_dimension__add_output(sd); + } + + for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { + struct sort_dimension *sd = &memory_sort_dimensions[i]; + + if (strncasecmp(tok, sd->name, strlen(tok))) + continue; + + return __sort_dimension__add_output(sd); + } + + return -ESRCH; +} + +static void reset_dimensions(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) + common_sort_dimensions[i].taken = 0; + + for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) + hpp_sort_dimensions[i].taken = 0; + + for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) + bstack_sort_dimensions[i].taken = 0; + + for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) + memory_sort_dimensions[i].taken = 0; +} + +static int __setup_output_field(void) +{ + char *tmp, *tok, *str; + int ret = 0; + + if (field_order == NULL) + return 0; + + reset_dimensions(); + + str = strdup(field_order); + if (str == NULL) { + error("Not enough memory to setup output fields"); + return -ENOMEM; + } + + for (tok = strtok_r(str, ", ", &tmp); + tok; tok = strtok_r(NULL, ", ", &tmp)) { + ret = output_field_add(tok); + if (ret == -EINVAL) { + error("Invalid --fields key: `%s'", tok); + break; + } else if (ret == -ESRCH) { + error("Unknown --fields key: `%s'", tok); + break; + } + } + + free(str); + return ret; +} + +int setup_sorting(void) +{ + int err; + + err = __setup_sorting(); + if (err < 0) + return err; + + if (parent_pattern != default_parent_pattern) { + err = sort_dimension__add("parent"); + if (err < 0) + return err; + } + + reset_dimensions(); + + /* + * perf diff doesn't use default hpp output fields. + */ + if (sort__mode != SORT_MODE__DIFF) + perf_hpp__init(); + + err = __setup_output_field(); + if (err < 0) + return err; + + /* copy sort keys to output fields */ + perf_hpp__setup_output_field(); + /* and then copy output fields to sort keys */ + perf_hpp__append_sort_keys(); + + return 0; +} |