diff options
Diffstat (limited to 'tools/perf/util/sort.c')
-rw-r--r-- | tools/perf/util/sort.c | 139 |
1 files changed, 118 insertions, 21 deletions
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index df622f4e301e..8b327c955a4f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1,12 +1,18 @@ +#include <errno.h> +#include <inttypes.h> +#include <regex.h> #include <sys/mman.h> #include "sort.h" #include "hist.h" #include "comm.h" #include "symbol.h" +#include "thread.h" #include "evsel.h" #include "evlist.h" +#include "strlist.h" #include <traceevent/event-parse.h> #include "mem-events.h" +#include <linux/kernel.h> regex_t parent_regex; const char default_parent_pattern[] = "^sys_|^do_page_fault"; @@ -151,7 +157,7 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) if (!dso_l || !dso_r) return cmp_null(dso_r, dso_l); - if (verbose) { + if (verbose > 0) { dso_name_l = dso_l->long_name; dso_name_r = dso_r->long_name; } else { @@ -172,8 +178,8 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf, size_t size, unsigned int width) { if (map && map->dso) { - const char *dso_name = !verbose ? map->dso->short_name : - map->dso->long_name; + const char *dso_name = verbose > 0 ? map->dso->long_name : + map->dso->short_name; return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name); } @@ -261,7 +267,7 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, { size_t ret = 0; - if (verbose) { + if (verbose > 0) { char o = map ? dso__symtab_origin(map->dso) : '!'; ret += repsep_snprintf(bf, size, "%-#*llx %c ", BITS_PER_LONG / 4 + 2, ip, o); @@ -323,7 +329,7 @@ char *hist_entry__get_srcline(struct hist_entry *he) return SRCLINE_UNKNOWN; return get_srcline(map->dso, map__rip_2objdump(map, he->ip), - he->ms.sym, true); + he->ms.sym, true, true); } static int64_t @@ -366,7 +372,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) left->branch_info->srcline_from = get_srcline(map->dso, map__rip_2objdump(map, left->branch_info->from.al_addr), - left->branch_info->from.sym, true); + left->branch_info->from.sym, + true, true); } if (!right->branch_info->srcline_from) { struct map *map = right->branch_info->from.map; @@ -376,7 +383,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) right->branch_info->srcline_from = get_srcline(map->dso, map__rip_2objdump(map, right->branch_info->from.al_addr), - right->branch_info->from.sym, true); + right->branch_info->from.sym, + true, true); } return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); } @@ -407,7 +415,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) left->branch_info->srcline_to = get_srcline(map->dso, map__rip_2objdump(map, left->branch_info->to.al_addr), - left->branch_info->from.sym, true); + left->branch_info->from.sym, + true, true); } if (!right->branch_info->srcline_to) { struct map *map = right->branch_info->to.map; @@ -417,7 +426,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) right->branch_info->srcline_to = get_srcline(map->dso, map__rip_2objdump(map, right->branch_info->to.al_addr), - right->branch_info->to.sym, true); + right->branch_info->to.sym, + true, true); } return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); } @@ -448,7 +458,7 @@ static char *hist_entry__get_srcfile(struct hist_entry *e) return no_srcfile; sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), - e->ms.sym, false, true); + e->ms.sym, false, true, true); if (!strcmp(sf, SRCLINE_UNKNOWN)) return no_srcfile; p = strchr(sf, ':'); @@ -536,6 +546,46 @@ struct sort_entry sort_cpu = { .se_width_idx = HISTC_CPU, }; +/* --sort cgroup_id */ + +static int64_t _sort__cgroup_dev_cmp(u64 left_dev, u64 right_dev) +{ + return (int64_t)(right_dev - left_dev); +} + +static int64_t _sort__cgroup_inode_cmp(u64 left_ino, u64 right_ino) +{ + return (int64_t)(right_ino - left_ino); +} + +static int64_t +sort__cgroup_id_cmp(struct hist_entry *left, struct hist_entry *right) +{ + int64_t ret; + + ret = _sort__cgroup_dev_cmp(right->cgroup_id.dev, left->cgroup_id.dev); + if (ret != 0) + return ret; + + return _sort__cgroup_inode_cmp(right->cgroup_id.ino, + left->cgroup_id.ino); +} + +static int hist_entry__cgroup_id_snprintf(struct hist_entry *he, + char *bf, size_t size, + unsigned int width __maybe_unused) +{ + return repsep_snprintf(bf, size, "%lu/0x%lx", he->cgroup_id.dev, + he->cgroup_id.ino); +} + +struct sort_entry sort_cgroup_id = { + .se_header = "cgroup id (dev/inode)", + .se_cmp = sort__cgroup_id_cmp, + .se_snprintf = hist_entry__cgroup_id_snprintf, + .se_width_idx = HISTC_CGROUP_ID, +}; + /* --sort socket */ static int64_t @@ -846,6 +896,9 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf, static int64_t sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right) { + if (!left->branch_info || !right->branch_info) + return cmp_null(left->branch_info, right->branch_info); + return left->branch_info->flags.cycles - right->branch_info->flags.cycles; } @@ -853,6 +906,8 @@ sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { + if (!he->branch_info) + return scnprintf(bf, size, "%-.*s", width, "N/A"); if (he->branch_info->flags.cycles == 0) return repsep_snprintf(bf, size, "%-*s", width, "-"); return repsep_snprintf(bf, size, "%-*hd", width, @@ -1396,6 +1451,46 @@ struct sort_entry sort_transaction = { .se_width_idx = HISTC_TRANSACTION, }; +/* --sort symbol_size */ + +static int64_t _sort__sym_size_cmp(struct symbol *sym_l, struct symbol *sym_r) +{ + int64_t size_l = sym_l != NULL ? symbol__size(sym_l) : 0; + int64_t size_r = sym_r != NULL ? symbol__size(sym_r) : 0; + + return size_l < size_r ? -1 : + size_l == size_r ? 0 : 1; +} + +static int64_t +sort__sym_size_cmp(struct hist_entry *left, struct hist_entry *right) +{ + return _sort__sym_size_cmp(right->ms.sym, left->ms.sym); +} + +static int _hist_entry__sym_size_snprintf(struct symbol *sym, char *bf, + size_t bf_size, unsigned int width) +{ + if (sym) + return repsep_snprintf(bf, bf_size, "%*d", width, symbol__size(sym)); + + return repsep_snprintf(bf, bf_size, "%*s", width, "unknown"); +} + +static int hist_entry__sym_size_snprintf(struct hist_entry *he, char *bf, + size_t size, unsigned int width) +{ + return _hist_entry__sym_size_snprintf(he->ms.sym, bf, size, width); +} + +struct sort_entry sort_sym_size = { + .se_header = "Symbol size", + .se_cmp = sort__sym_size_cmp, + .se_snprintf = hist_entry__sym_size_snprintf, + .se_width_idx = HISTC_SYM_SIZE, +}; + + struct sort_dimension { const char *name; struct sort_entry *entry; @@ -1418,6 +1513,8 @@ static struct sort_dimension common_sort_dimensions[] = { DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), DIM(SORT_TRANSACTION, "transaction", sort_transaction), DIM(SORT_TRACE, "trace", sort_trace), + DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size), + DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id), }; #undef DIM @@ -2435,12 +2532,12 @@ static int setup_sort_list(struct perf_hpp_list *list, char *str, ret = sort_dimension__add(list, tok, evlist, level); if (ret == -EINVAL) { if (!cacheline_size && !strncasecmp(tok, "dcacheline", strlen(tok))) - error("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); + pr_err("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); else - error("Invalid --sort key: `%s'", tok); + pr_err("Invalid --sort key: `%s'", tok); break; } else if (ret == -ESRCH) { - error("Unknown --sort key: `%s'", tok); + pr_err("Unknown --sort key: `%s'", tok); break; } } @@ -2497,7 +2594,7 @@ static int setup_sort_order(struct perf_evlist *evlist) return 0; if (sort_order[1] == '\0') { - error("Invalid --sort key: `+'"); + pr_err("Invalid --sort key: `+'"); return -EINVAL; } @@ -2507,7 +2604,7 @@ static int setup_sort_order(struct perf_evlist *evlist) */ if (asprintf(&new_sort_order, "%s,%s", get_default_sort_order(evlist), sort_order + 1) < 0) { - error("Not enough memory to set up --sort"); + pr_err("Not enough memory to set up --sort"); return -ENOMEM; } @@ -2571,7 +2668,7 @@ static int __setup_sorting(struct perf_evlist *evlist) str = strdup(sort_keys); if (str == NULL) { - error("Not enough memory to setup sort keys"); + pr_err("Not enough memory to setup sort keys"); return -ENOMEM; } @@ -2581,7 +2678,7 @@ static int __setup_sorting(struct perf_evlist *evlist) if (!is_strict_order(field_order)) { str = setup_overhead(str); if (str == NULL) { - error("Not enough memory to setup overhead keys"); + pr_err("Not enough memory to setup overhead keys"); return -ENOMEM; } } @@ -2737,10 +2834,10 @@ static int setup_output_list(struct perf_hpp_list *list, char *str) tok; tok = strtok_r(NULL, ", ", &tmp)) { ret = output_field_add(list, tok); if (ret == -EINVAL) { - error("Invalid --fields key: `%s'", tok); + pr_err("Invalid --fields key: `%s'", tok); break; } else if (ret == -ESRCH) { - error("Unknown --fields key: `%s'", tok); + pr_err("Unknown --fields key: `%s'", tok); break; } } @@ -2780,7 +2877,7 @@ static int __setup_output_field(void) strp = str = strdup(field_order); if (str == NULL) { - error("Not enough memory to setup output fields"); + pr_err("Not enough memory to setup output fields"); return -ENOMEM; } @@ -2788,7 +2885,7 @@ static int __setup_output_field(void) strp++; if (!strlen(strp)) { - error("Invalid --fields key: `+'"); + pr_err("Invalid --fields key: `+'"); goto out; } |