diff options
Diffstat (limited to 'tools/perf/util/sort.c')
-rw-r--r-- | tools/perf/util/sort.c | 119 |
1 files changed, 91 insertions, 28 deletions
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 14e5a039bc45..289df9d1e65a 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -70,12 +70,14 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { const char *comm = thread__comm_str(he->thread); - return repsep_snprintf(bf, size, "%*s:%5d", width - 6, - comm ?: "", he->thread->tid); + + width = max(7U, width) - 6; + return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid, + width, width, comm ?: ""); } struct sort_entry sort_thread = { - .se_header = "Command: Pid", + .se_header = " Pid:Command", .se_cmp = sort__thread_cmp, .se_snprintf = hist_entry__thread_snprintf, .se_width_idx = HISTC_THREAD, @@ -106,7 +108,7 @@ sort__comm_sort(struct hist_entry *left, struct hist_entry *right) static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { - return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm)); + return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm)); } struct sort_entry sort_comm = { @@ -152,10 +154,10 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf, if (map && map->dso) { const char *dso_name = !verbose ? map->dso->short_name : map->dso->long_name; - return repsep_snprintf(bf, size, "%-*s", width, dso_name); + return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name); } - return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); + return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]"); } static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf, @@ -257,7 +259,10 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, width - ret, ""); } - return ret; + if (ret > width) + bf[width] = '\0'; + + return width; } static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, @@ -302,10 +307,9 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) } static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, - size_t size, - unsigned int width __maybe_unused) + size_t size, unsigned int width) { - return repsep_snprintf(bf, size, "%s", he->srcline); + return repsep_snprintf(bf, size, "%*.*-s", width, width, he->srcline); } struct sort_entry sort_srcline = { @@ -332,7 +336,7 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { - return repsep_snprintf(bf, size, "%-*s", width, + return repsep_snprintf(bf, size, "%-*.*s", width, width, he->parent ? he->parent->name : "[other]"); } @@ -354,7 +358,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { - return repsep_snprintf(bf, size, "%*d", width, he->cpu); + return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu); } struct sort_entry sort_cpu = { @@ -484,7 +488,7 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf, else if (he->branch_info->flags.mispred) out = "Y"; - return repsep_snprintf(bf, size, "%-*s", width, out); + return repsep_snprintf(bf, size, "%-*.*s", width, width, out); } /* --sort daddr_sym */ @@ -1194,7 +1198,7 @@ bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) return hse_a->se == hse_b->se; } -void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) +void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) { struct hpp_sort_entry *hse; @@ -1202,20 +1206,21 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) return; hse = container_of(fmt, struct hpp_sort_entry, hpp); - hists__new_col_len(hists, hse->se->se_width_idx, - strlen(hse->se->se_header)); + hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name)); } static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct perf_evsel *evsel) { struct hpp_sort_entry *hse; - size_t len; + size_t len = fmt->user_len; hse = container_of(fmt, struct hpp_sort_entry, hpp); - len = hists__col_len(&evsel->hists, hse->se->se_width_idx); - return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header); + if (!len) + len = hists__col_len(&evsel->hists, hse->se->se_width_idx); + + return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name); } static int __sort__hpp_width(struct perf_hpp_fmt *fmt, @@ -1223,20 +1228,26 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt, struct perf_evsel *evsel) { struct hpp_sort_entry *hse; + size_t len = fmt->user_len; hse = container_of(fmt, struct hpp_sort_entry, hpp); - return hists__col_len(&evsel->hists, hse->se->se_width_idx); + if (!len) + len = hists__col_len(&evsel->hists, hse->se->se_width_idx); + + return len; } static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { struct hpp_sort_entry *hse; - size_t len; + size_t len = fmt->user_len; hse = container_of(fmt, struct hpp_sort_entry, hpp); - len = hists__col_len(he->hists, hse->se->se_width_idx); + + if (!len) + len = hists__col_len(he->hists, hse->se->se_width_idx); return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); } @@ -1253,6 +1264,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd) } hse->se = sd->entry; + hse->hpp.name = sd->entry->se_header; hse->hpp.header = __sort__hpp_header; hse->hpp.width = __sort__hpp_width; hse->hpp.entry = __sort__hpp_entry; @@ -1265,6 +1277,8 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd) INIT_LIST_HEAD(&hse->hpp.list); INIT_LIST_HEAD(&hse->hpp.sort_list); hse->hpp.elide = false; + hse->hpp.len = 0; + hse->hpp.user_len = 0; return hse; } @@ -1432,14 +1446,49 @@ static const char *get_default_sort_order(void) return default_sort_orders[sort__mode]; } +static int setup_sort_order(void) +{ + char *new_sort_order; + + /* + * Append '+'-prefixed sort order to the default sort + * order string. + */ + if (!sort_order || is_strict_order(sort_order)) + return 0; + + if (sort_order[1] == '\0') { + error("Invalid --sort key: `+'"); + return -EINVAL; + } + + /* + * We allocate new sort_order string, but we never free it, + * because it's checked over the rest of the code. + */ + if (asprintf(&new_sort_order, "%s,%s", + get_default_sort_order(), sort_order + 1) < 0) { + error("Not enough memory to set up --sort"); + return -ENOMEM; + } + + sort_order = new_sort_order; + return 0; +} + static int __setup_sorting(void) { char *tmp, *tok, *str; - const char *sort_keys = sort_order; + const char *sort_keys; int ret = 0; + ret = setup_sort_order(); + if (ret) + return ret; + + sort_keys = sort_order; if (sort_keys == NULL) { - if (field_order) { + if (is_strict_order(field_order)) { /* * If user specified field order but no sort order, * we'll honor it and not add default sort orders. @@ -1625,23 +1674,36 @@ static void reset_dimensions(void) memory_sort_dimensions[i].taken = 0; } +bool is_strict_order(const char *order) +{ + return order && (*order != '+'); +} + static int __setup_output_field(void) { - char *tmp, *tok, *str; - int ret = 0; + char *tmp, *tok, *str, *strp; + int ret = -EINVAL; if (field_order == NULL) return 0; reset_dimensions(); - str = strdup(field_order); + strp = str = strdup(field_order); if (str == NULL) { error("Not enough memory to setup output fields"); return -ENOMEM; } - for (tok = strtok_r(str, ", ", &tmp); + if (!is_strict_order(field_order)) + strp++; + + if (!strlen(strp)) { + error("Invalid --fields key: `+'"); + goto out; + } + + for (tok = strtok_r(strp, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) { ret = output_field_add(tok); if (ret == -EINVAL) { @@ -1653,6 +1715,7 @@ static int __setup_output_field(void) } } +out: free(str); return ret; } |