diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 2dcf38a78f08efce41e28b1fe71e4810ff40a356..fdb97e16a8c31334d93c3423a3a41b3cad11acb4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -997,6 +997,7 @@ void hist_entry__delete(struct hist_entry *he) if (he->srcfile && he->srcfile[0]) free(he->srcfile); free_callchain(he->callchain); + free(he->trace_output); free(he->raw_data); free(he); } diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index cc659ba0e2327bbb5a295b8c144178337f6d95ff..22d28c7e0b0197090e5364b39724247bc82a458e 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1560,6 +1560,62 @@ static int hde_width(struct hpp_dynamic_entry *hde) return hde->hpp.len; } +static char *get_trace_output(struct hist_entry *he) +{ + struct trace_seq seq; + struct perf_evsel *evsel; + struct pevent_record rec = { + .data = he->raw_data, + .size = he->raw_size, + }; + + evsel = hists_to_evsel(he->hists); + + trace_seq_init(&seq); + pevent_event_info(&seq, evsel->tp_format, &rec); + return seq.buffer; +} + +static void update_dynamic_len(struct hpp_dynamic_entry *hde, + struct hist_entry *he) +{ + char *str, *pos; + struct format_field *field = hde->field; + size_t namelen; + bool last = false; + + /* parse pretty print result and update max length */ + if (!he->trace_output) + he->trace_output = get_trace_output(he); + + namelen = strlen(field->name); + str = he->trace_output; + + while (str) { + pos = strchr(str, ' '); + if (pos == NULL) { + last = true; + pos = str + strlen(str); + } + + if (!strncmp(str, field->name, namelen)) { + size_t len; + + str += namelen + 1; + len = pos - str; + + if (len > hde->dynamic_len) + hde->dynamic_len = len; + break; + } + + if (last) + str = NULL; + else + str = pos + 1; + } +} + static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct perf_evsel *evsel __maybe_unused) { @@ -1594,7 +1650,10 @@ static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, { struct hpp_dynamic_entry *hde; size_t len = fmt->user_len; - struct trace_seq seq; + char *str, *pos; + struct format_field *field; + size_t namelen; + bool last = false; int ret; hde = container_of(fmt, struct hpp_dynamic_entry, hpp); @@ -1605,10 +1664,43 @@ static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, if (hists_to_evsel(he->hists) != hde->evsel) return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, "N/A"); - trace_seq_init(&seq); - pevent_print_field(&seq, he->raw_data, hde->field); - ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, seq.buffer); - trace_seq_destroy(&seq); + field = hde->field; + + namelen = strlen(field->name); + str = he->trace_output; + + while (str) { + pos = strchr(str, ' '); + if (pos == NULL) { + last = true; + pos = str + strlen(str); + } + + if (!strncmp(str, field->name, namelen)) { + str += namelen + 1; + str = strndup(str, pos - str); + + if (str == NULL) + return scnprintf(hpp->buf, hpp->size, + "%*.*s", len, len, "ERROR"); + break; + } + + if (last) + str = NULL; + else + str = pos + 1; + } + + if (str == NULL) { + struct trace_seq seq; + trace_seq_init(&seq); + pevent_print_field(&seq, he->raw_data, hde->field); + str = seq.buffer; + } + + ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str); + free(str); return ret; } @@ -1638,6 +1730,9 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt, } else { offset = field->offset; size = field->size; + + update_dynamic_len(hde, a); + update_dynamic_len(hde, b); } return memcmp(a->raw_data + offset, b->raw_data + offset, size); diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 1a00f1eb9d212586541c383db0452b33725c5f63..f6d2a7e3e7f20c6df2ddd985820a13dc483a2684 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -124,6 +124,7 @@ struct hist_entry { struct mem_info *mem_info; void *raw_data; u32 raw_size; + void *trace_output; struct callchain_root callchain[0]; /* must be last member */ };