diff options
Diffstat (limited to 'tools/perf/ui/hist.c')
-rw-r--r-- | tools/perf/ui/hist.c | 424 |
1 files changed, 374 insertions, 50 deletions
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index e5491995adf0..b085eb0de849 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -11,6 +11,8 @@ #include "../util/sort.h" #include "../util/evsel.h" #include "../util/evlist.h" +#include "../util/mem-events.h" +#include "../util/string2.h" #include "../util/thread.h" #include "../util/util.h" @@ -27,9 +29,10 @@ static int __hpp__fmt_print(struct perf_hpp *hpp, struct hists *hists, u64 val, int nr_samples, const char *fmt, int len, hpp_snprint_fn print_fn, enum perf_hpp_fmt_type fmtype) { - if (fmtype == PERF_HPP_FMT_TYPE__PERCENT) { + if (fmtype == PERF_HPP_FMT_TYPE__PERCENT || fmtype == PERF_HPP_FMT_TYPE__LATENCY) { double percent = 0.0; - u64 total = hists__total_period(hists); + u64 total = fmtype == PERF_HPP_FMT_TYPE__PERCENT ? hists__total_period(hists) : + hists__total_latency(hists); if (total) percent = 100.0 * val / total; @@ -121,14 +124,14 @@ int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, const char *fmtstr, hpp_snprint_fn print_fn, enum perf_hpp_fmt_type fmtype) { - int len = fmt->user_len ?: fmt->len; + int len = max(fmt->user_len ?: fmt->len, (int)strlen(fmt->name)); if (symbol_conf.field_sep) { return __hpp__fmt(hpp, he, get_field, fmtstr, 1, print_fn, fmtype); } - if (fmtype == PERF_HPP_FMT_TYPE__PERCENT) + if (fmtype == PERF_HPP_FMT_TYPE__PERCENT || fmtype == PERF_HPP_FMT_TYPE__LATENCY) len -= 2; /* 2 for a space and a % sign */ else len -= 1; @@ -149,6 +152,48 @@ int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmtype); } +int hpp__fmt_mem_stat(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, + struct hist_entry *he, enum mem_stat_type mst, + const char *fmtstr, hpp_snprint_fn print_fn) +{ + struct hists *hists = he->hists; + int mem_stat_idx = -1; + char *buf = hpp->buf; + size_t size = hpp->size; + u64 total = 0; + int ret = 0; + + for (int i = 0; i < hists->nr_mem_stats; i++) { + if (hists->mem_stat_types[i] == mst) { + mem_stat_idx = i; + break; + } + } + assert(mem_stat_idx != -1); + + for (int i = 0; i < MEM_STAT_LEN; i++) + total += hists->mem_stat_total[mem_stat_idx].entries[i]; + assert(total != 0); + + for (int i = 0; i < MEM_STAT_LEN; i++) { + u64 val = he->mem_stat[mem_stat_idx].entries[i]; + + if (hists->mem_stat_total[mem_stat_idx].entries[i] == 0) + continue; + + ret += hpp__call_print_fn(hpp, print_fn, fmtstr, 100.0 * val / total); + } + + /* + * Restore original buf and size as it's where caller expects + * the result will be saved. + */ + hpp->buf = buf; + hpp->size = size; + + return ret; +} + static int field_cmp(u64 field_a, u64 field_b) { if (field_a > field_b) @@ -293,6 +338,37 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, return ret; } +static bool perf_hpp__is_mem_stat_entry(struct perf_hpp_fmt *fmt); + +static enum mem_stat_type hpp__mem_stat_type(struct perf_hpp_fmt *fmt) +{ + if (!perf_hpp__is_mem_stat_entry(fmt)) + return -1; + + switch (fmt->idx) { + case PERF_HPP__MEM_STAT_OP: + return PERF_MEM_STAT_OP; + case PERF_HPP__MEM_STAT_CACHE: + return PERF_MEM_STAT_CACHE; + case PERF_HPP__MEM_STAT_MEMORY: + return PERF_MEM_STAT_MEMORY; + case PERF_HPP__MEM_STAT_SNOOP: + return PERF_MEM_STAT_SNOOP; + case PERF_HPP__MEM_STAT_DTLB: + return PERF_MEM_STAT_DTLB; + default: + break; + } + pr_debug("Should not reach here\n"); + return -1; +} + +static int64_t hpp__sort_mem_stat(struct perf_hpp_fmt *fmt __maybe_unused, + struct hist_entry *a, struct hist_entry *b) +{ + return a->stat.period - b->stat.period; +} + static int hpp__width_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp __maybe_unused, struct hists *hists) @@ -320,11 +396,78 @@ static int hpp__width_fn(struct perf_hpp_fmt *fmt, } static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct hists *hists, int line __maybe_unused, + struct hists *hists, int line, int *span __maybe_unused) { int len = hpp__width_fn(fmt, hpp, hists); - return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); + const char *hdr = ""; + + if (line == hists->hpp_list->nr_header_lines - 1) + hdr = fmt->name; + + return scnprintf(hpp->buf, hpp->size, "%*s", len, hdr); +} + +static int hpp__header_mem_stat_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hists *hists, int line, + int *span __maybe_unused) +{ + char *buf = hpp->buf; + int ret = 0; + int len; + enum mem_stat_type mst = hpp__mem_stat_type(fmt); + int mem_stat_idx = -1; + + for (int i = 0; i < hists->nr_mem_stats; i++) { + if (hists->mem_stat_types[i] == mst) { + mem_stat_idx = i; + break; + } + } + assert(mem_stat_idx != -1); + + if (line == 0) { + int left, right; + + len = 0; + /* update fmt->len for acutally used columns only */ + for (int i = 0; i < MEM_STAT_LEN; i++) { + if (hists->mem_stat_total[mem_stat_idx].entries[i]) + len += MEM_STAT_PRINT_LEN; + } + fmt->len = len; + + /* print header directly if single column only */ + if (len == MEM_STAT_PRINT_LEN) + return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); + + left = (len - strlen(fmt->name)) / 2 - 1; + right = len - left - strlen(fmt->name) - 2; + + if (left < 0) + left = 0; + if (right < 0) + right = 0; + + return scnprintf(hpp->buf, hpp->size, "%.*s %s %.*s", + left, graph_dotted_line, fmt->name, right, graph_dotted_line); + } + + + len = hpp->size; + for (int i = 0; i < MEM_STAT_LEN; i++) { + int printed; + + if (hists->mem_stat_total[mem_stat_idx].entries[i] == 0) + continue; + + printed = scnprintf(buf, len, "%*s", MEM_STAT_PRINT_LEN, + mem_stat_name(mst, i)); + ret += printed; + buf += printed; + len -= printed; + } + return ret; } int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) @@ -356,7 +499,7 @@ static int hpp_entry_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) return (ret >= ssize) ? (ssize - 1) : ret; } -#define __HPP_COLOR_PERCENT_FN(_type, _field) \ +#define __HPP_COLOR_PERCENT_FN(_type, _field, _fmttype) \ static u64 he_get_##_field(struct hist_entry *he) \ { \ return he->stat._field; \ @@ -366,15 +509,15 @@ static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ - hpp_color_scnprintf, PERF_HPP_FMT_TYPE__PERCENT); \ + hpp_color_scnprintf, _fmttype); \ } -#define __HPP_ENTRY_PERCENT_FN(_type, _field) \ +#define __HPP_ENTRY_PERCENT_FN(_type, _field, _fmttype) \ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ - hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__PERCENT); \ + hpp_entry_scnprintf, _fmttype); \ } #define __HPP_SORT_FN(_type, _field) \ @@ -384,7 +527,7 @@ static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ return __hpp__sort(a, b, he_get_##_field); \ } -#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ +#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field, _fmttype) \ static u64 he_get_acc_##_field(struct hist_entry *he) \ { \ return he->stat_acc->_field; \ @@ -394,15 +537,15 @@ static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ - hpp_color_scnprintf, PERF_HPP_FMT_TYPE__PERCENT); \ + hpp_color_scnprintf, _fmttype); \ } -#define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ +#define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field, _fmttype) \ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ - hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__PERCENT); \ + hpp_entry_scnprintf, _fmttype); \ } #define __HPP_SORT_ACC_FN(_type, _field) \ @@ -452,15 +595,32 @@ static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ return __hpp__sort(a, b, he_get_##_field); \ } +#define __HPP_COLOR_MEM_STAT_FN(_name, _type) \ +static int hpp__color_mem_stat_##_name(struct perf_hpp_fmt *fmt, \ + struct perf_hpp *hpp, \ + struct hist_entry *he) \ +{ \ + return hpp__fmt_mem_stat(fmt, hpp, he, PERF_MEM_STAT_##_type, \ + " %5.1f%%", hpp_color_scnprintf); \ +} -#define HPP_PERCENT_FNS(_type, _field) \ -__HPP_COLOR_PERCENT_FN(_type, _field) \ -__HPP_ENTRY_PERCENT_FN(_type, _field) \ +#define __HPP_ENTRY_MEM_STAT_FN(_name, _type) \ +static int hpp__entry_mem_stat_##_name(struct perf_hpp_fmt *fmt, \ + struct perf_hpp *hpp, \ + struct hist_entry *he) \ +{ \ + return hpp__fmt_mem_stat(fmt, hpp, he, PERF_MEM_STAT_##_type, \ + " %5.1f%%", hpp_entry_scnprintf); \ +} + +#define HPP_PERCENT_FNS(_type, _field, _fmttype) \ +__HPP_COLOR_PERCENT_FN(_type, _field, _fmttype) \ +__HPP_ENTRY_PERCENT_FN(_type, _field, _fmttype) \ __HPP_SORT_FN(_type, _field) -#define HPP_PERCENT_ACC_FNS(_type, _field) \ -__HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ -__HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ +#define HPP_PERCENT_ACC_FNS(_type, _field, _fmttype) \ +__HPP_COLOR_ACC_PERCENT_FN(_type, _field, _fmttype) \ +__HPP_ENTRY_ACC_PERCENT_FN(_type, _field, _fmttype) \ __HPP_SORT_ACC_FN(_type, _field) #define HPP_RAW_FNS(_type, _field) \ @@ -471,12 +631,18 @@ __HPP_SORT_RAW_FN(_type, _field) __HPP_ENTRY_AVERAGE_FN(_type, _field) \ __HPP_SORT_AVERAGE_FN(_type, _field) -HPP_PERCENT_FNS(overhead, period) -HPP_PERCENT_FNS(overhead_sys, period_sys) -HPP_PERCENT_FNS(overhead_us, period_us) -HPP_PERCENT_FNS(overhead_guest_sys, period_guest_sys) -HPP_PERCENT_FNS(overhead_guest_us, period_guest_us) -HPP_PERCENT_ACC_FNS(overhead_acc, period) +#define HPP_MEM_STAT_FNS(_name, _type) \ +__HPP_COLOR_MEM_STAT_FN(_name, _type) \ +__HPP_ENTRY_MEM_STAT_FN(_name, _type) + +HPP_PERCENT_FNS(overhead, period, PERF_HPP_FMT_TYPE__PERCENT) +HPP_PERCENT_FNS(latency, latency, PERF_HPP_FMT_TYPE__LATENCY) +HPP_PERCENT_FNS(overhead_sys, period_sys, PERF_HPP_FMT_TYPE__PERCENT) +HPP_PERCENT_FNS(overhead_us, period_us, PERF_HPP_FMT_TYPE__PERCENT) +HPP_PERCENT_FNS(overhead_guest_sys, period_guest_sys, PERF_HPP_FMT_TYPE__PERCENT) +HPP_PERCENT_FNS(overhead_guest_us, period_guest_us, PERF_HPP_FMT_TYPE__PERCENT) +HPP_PERCENT_ACC_FNS(overhead_acc, period, PERF_HPP_FMT_TYPE__PERCENT) +HPP_PERCENT_ACC_FNS(latency_acc, latency, PERF_HPP_FMT_TYPE__LATENCY) HPP_RAW_FNS(samples, nr_events) HPP_RAW_FNS(period, period) @@ -485,6 +651,12 @@ HPP_AVERAGE_FNS(weight1, weight1) HPP_AVERAGE_FNS(weight2, weight2) HPP_AVERAGE_FNS(weight3, weight3) +HPP_MEM_STAT_FNS(op, OP) +HPP_MEM_STAT_FNS(cache, CACHE) +HPP_MEM_STAT_FNS(memory, MEMORY) +HPP_MEM_STAT_FNS(snoop, SNOOP) +HPP_MEM_STAT_FNS(dtlb, DTLB) + static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *a __maybe_unused, struct hist_entry *b __maybe_unused) @@ -492,6 +664,11 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused, return 0; } +static bool perf_hpp__is_mem_stat_entry(struct perf_hpp_fmt *fmt) +{ + return fmt->sort == hpp__sort_mem_stat; +} + static bool perf_hpp__is_hpp_entry(struct perf_hpp_fmt *a) { return a->header == hpp__header_fn; @@ -505,6 +682,14 @@ static bool hpp__equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) return a->idx == b->idx; } +static bool hpp__equal_mem_stat(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) +{ + if (!perf_hpp__is_mem_stat_entry(a) || !perf_hpp__is_mem_stat_entry(b)) + return false; + + return a->entry == b->entry; +} + #define HPP__COLOR_PRINT_FNS(_name, _fn, _idx) \ { \ .name = _name, \ @@ -546,18 +731,39 @@ static bool hpp__equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) .equal = hpp__equal, \ } +#define HPP__MEM_STAT_PRINT_FNS(_name, _fn, _type) \ + { \ + .name = _name, \ + .header = hpp__header_mem_stat_fn, \ + .width = hpp__width_fn, \ + .color = hpp__color_mem_stat_ ## _fn, \ + .entry = hpp__entry_mem_stat_ ## _fn, \ + .cmp = hpp__nop_cmp, \ + .collapse = hpp__nop_cmp, \ + .sort = hpp__sort_mem_stat, \ + .idx = PERF_HPP__MEM_STAT_ ## _type, \ + .equal = hpp__equal_mem_stat, \ + } + struct perf_hpp_fmt perf_hpp__format[] = { HPP__COLOR_PRINT_FNS("Overhead", overhead, OVERHEAD), + HPP__COLOR_PRINT_FNS("Latency", latency, LATENCY), HPP__COLOR_PRINT_FNS("sys", overhead_sys, OVERHEAD_SYS), HPP__COLOR_PRINT_FNS("usr", overhead_us, OVERHEAD_US), HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys, OVERHEAD_GUEST_SYS), HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us, OVERHEAD_GUEST_US), HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc, OVERHEAD_ACC), + HPP__COLOR_ACC_PRINT_FNS("Latency", latency_acc, LATENCY_ACC), HPP__PRINT_FNS("Samples", samples, SAMPLES), HPP__PRINT_FNS("Period", period, PERIOD), HPP__PRINT_FNS("Weight1", weight1, WEIGHT1), HPP__PRINT_FNS("Weight2", weight2, WEIGHT2), HPP__PRINT_FNS("Weight3", weight3, WEIGHT3), + HPP__MEM_STAT_PRINT_FNS("Mem Op", op, OP), + HPP__MEM_STAT_PRINT_FNS("Cache", cache, CACHE), + HPP__MEM_STAT_PRINT_FNS("Memory", memory, MEMORY), + HPP__MEM_STAT_PRINT_FNS("Snoop", snoop, SNOOP), + HPP__MEM_STAT_PRINT_FNS("D-TLB", dtlb, DTLB), }; struct perf_hpp_list perf_hpp_list = { @@ -569,11 +775,13 @@ struct perf_hpp_list perf_hpp_list = { #undef HPP__COLOR_PRINT_FNS #undef HPP__COLOR_ACC_PRINT_FNS #undef HPP__PRINT_FNS +#undef HPP__MEM_STAT_PRINT_FNS #undef HPP_PERCENT_FNS #undef HPP_PERCENT_ACC_FNS #undef HPP_RAW_FNS #undef HPP_AVERAGE_FNS +#undef HPP_MEM_STAT_FNS #undef __HPP_HEADER_FN #undef __HPP_WIDTH_FN @@ -583,6 +791,9 @@ struct perf_hpp_list perf_hpp_list = { #undef __HPP_ENTRY_ACC_PERCENT_FN #undef __HPP_ENTRY_RAW_FN #undef __HPP_ENTRY_AVERAGE_FN +#undef __HPP_COLOR_MEM_STAT_FN +#undef __HPP_ENTRY_MEM_STAT_FN + #undef __HPP_SORT_FN #undef __HPP_SORT_ACC_FN #undef __HPP_SORT_RAW_FN @@ -601,6 +812,11 @@ static void fmt_free(struct perf_hpp_fmt *fmt) fmt->free(fmt); } +static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) +{ + return a->equal && a->equal(a, b); +} + void perf_hpp__init(void) { int i; @@ -621,28 +837,48 @@ void perf_hpp__init(void) if (is_strict_order(field_order)) return; + /* + * Overhead and latency columns are added in setup_overhead(), + * so they are added implicitly here only if they were added + * by setup_overhead() before (have was_taken flag set). + * This is required because setup_overhead() has more complex + * logic, in particular it does not add "overhead" if user + * specified "latency" in sort order, and vise versa. + */ if (symbol_conf.cumulate_callchain) { - hpp_dimension__add_output(PERF_HPP__OVERHEAD_ACC); + /* + * Addition of fields is idempotent, so we add latency + * column twice to get desired order with simpler logic. + */ + if (symbol_conf.prefer_latency) + hpp_dimension__add_output(PERF_HPP__LATENCY_ACC, true); + hpp_dimension__add_output(PERF_HPP__OVERHEAD_ACC, true); + if (symbol_conf.enable_latency) + hpp_dimension__add_output(PERF_HPP__LATENCY_ACC, true); perf_hpp__format[PERF_HPP__OVERHEAD].name = "Self"; } - hpp_dimension__add_output(PERF_HPP__OVERHEAD); + if (symbol_conf.prefer_latency) + hpp_dimension__add_output(PERF_HPP__LATENCY, true); + hpp_dimension__add_output(PERF_HPP__OVERHEAD, true); + if (symbol_conf.enable_latency) + hpp_dimension__add_output(PERF_HPP__LATENCY, true); if (symbol_conf.show_cpu_utilization) { - hpp_dimension__add_output(PERF_HPP__OVERHEAD_SYS); - hpp_dimension__add_output(PERF_HPP__OVERHEAD_US); + hpp_dimension__add_output(PERF_HPP__OVERHEAD_SYS, false); + hpp_dimension__add_output(PERF_HPP__OVERHEAD_US, false); if (perf_guest) { - hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_SYS); - hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_US); + hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_SYS, false); + hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_US, false); } } if (symbol_conf.show_nr_samples) - hpp_dimension__add_output(PERF_HPP__SAMPLES); + hpp_dimension__add_output(PERF_HPP__SAMPLES, false); if (symbol_conf.show_total_period) - hpp_dimension__add_output(PERF_HPP__PERIOD); + hpp_dimension__add_output(PERF_HPP__PERIOD, false); } void perf_hpp_list__column_register(struct perf_hpp_list *list, @@ -666,33 +902,79 @@ void perf_hpp_list__prepend_sort_field(struct perf_hpp_list *list, static void perf_hpp__column_unregister(struct perf_hpp_fmt *format) { list_del_init(&format->list); + list_del_init(&format->sort_list); fmt_free(format); } -void perf_hpp__cancel_cumulate(void) +void perf_hpp__cancel_cumulate(struct evlist *evlist) { - struct perf_hpp_fmt *fmt, *acc, *ovh, *tmp; + struct perf_hpp_fmt *fmt, *acc, *ovh, *acc_lat, *tmp; + struct evsel *evsel; if (is_strict_order(field_order)) return; ovh = &perf_hpp__format[PERF_HPP__OVERHEAD]; acc = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC]; + acc_lat = &perf_hpp__format[PERF_HPP__LATENCY_ACC]; perf_hpp_list__for_each_format_safe(&perf_hpp_list, fmt, tmp) { - if (acc->equal(acc, fmt)) { + if (fmt_equal(acc, fmt) || fmt_equal(acc_lat, fmt)) { perf_hpp__column_unregister(fmt); continue; } - if (ovh->equal(ovh, fmt)) + if (fmt_equal(ovh, fmt)) fmt->name = "Overhead"; } + + evlist__for_each_entry(evlist, evsel) { + struct hists *hists = evsel__hists(evsel); + struct perf_hpp_list_node *node; + + list_for_each_entry(node, &hists->hpp_formats, list) { + perf_hpp_list__for_each_format_safe(&node->hpp, fmt, tmp) { + if (fmt_equal(acc, fmt) || fmt_equal(acc_lat, fmt)) { + perf_hpp__column_unregister(fmt); + continue; + } + + if (fmt_equal(ovh, fmt)) + fmt->name = "Overhead"; + } + } + } } -static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) +void perf_hpp__cancel_latency(struct evlist *evlist) { - return a->equal && a->equal(a, b); + struct perf_hpp_fmt *fmt, *lat, *acc, *tmp; + struct evsel *evsel; + + if (is_strict_order(field_order)) + return; + if (sort_order && strstr(sort_order, "latency")) + return; + + lat = &perf_hpp__format[PERF_HPP__LATENCY]; + acc = &perf_hpp__format[PERF_HPP__LATENCY_ACC]; + + perf_hpp_list__for_each_format_safe(&perf_hpp_list, fmt, tmp) { + if (fmt_equal(lat, fmt) || fmt_equal(acc, fmt)) + perf_hpp__column_unregister(fmt); + } + + evlist__for_each_entry(evlist, evsel) { + struct hists *hists = evsel__hists(evsel); + struct perf_hpp_list_node *node; + + list_for_each_entry(node, &hists->hpp_formats, list) { + perf_hpp_list__for_each_format_safe(&node->hpp, fmt, tmp) { + if (fmt_equal(lat, fmt) || fmt_equal(acc, fmt)) + perf_hpp__column_unregister(fmt); + } + } + } } void perf_hpp__setup_output_field(struct perf_hpp_list *list) @@ -743,18 +1025,12 @@ void perf_hpp__reset_output_field(struct perf_hpp_list *list) struct perf_hpp_fmt *fmt, *tmp; /* reset output fields */ - perf_hpp_list__for_each_format_safe(list, fmt, tmp) { - list_del_init(&fmt->list); - list_del_init(&fmt->sort_list); - fmt_free(fmt); - } + perf_hpp_list__for_each_format_safe(list, fmt, tmp) + perf_hpp__column_unregister(fmt); /* reset sort keys */ - perf_hpp_list__for_each_sort_list_safe(list, fmt, tmp) { - list_del_init(&fmt->list); - list_del_init(&fmt->sort_list); - fmt_free(fmt); - } + perf_hpp_list__for_each_sort_list_safe(list, fmt, tmp) + perf_hpp__column_unregister(fmt); } /* @@ -819,6 +1095,7 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) switch (fmt->idx) { case PERF_HPP__OVERHEAD: + case PERF_HPP__LATENCY: case PERF_HPP__OVERHEAD_SYS: case PERF_HPP__OVERHEAD_US: case PERF_HPP__OVERHEAD_ACC: @@ -841,6 +1118,14 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) fmt->len = 8; break; + case PERF_HPP__MEM_STAT_OP: + case PERF_HPP__MEM_STAT_CACHE: + case PERF_HPP__MEM_STAT_MEMORY: + case PERF_HPP__MEM_STAT_SNOOP: + case PERF_HPP__MEM_STAT_DTLB: + fmt->len = MEM_STAT_LEN * MEM_STAT_PRINT_LEN; + break; + default: break; } @@ -946,3 +1231,42 @@ int perf_hpp__setup_hists_formats(struct perf_hpp_list *list, return 0; } + +int perf_hpp__alloc_mem_stats(struct perf_hpp_list *list, struct evlist *evlist) +{ + struct perf_hpp_fmt *fmt; + struct evsel *evsel; + enum mem_stat_type mst[16]; + unsigned nr_mem_stats = 0; + + perf_hpp_list__for_each_format(list, fmt) { + if (!perf_hpp__is_mem_stat_entry(fmt)) + continue; + + assert(nr_mem_stats < ARRAY_SIZE(mst)); + mst[nr_mem_stats++] = hpp__mem_stat_type(fmt); + } + + if (nr_mem_stats == 0) + return 0; + + list->nr_header_lines = 2; + + evlist__for_each_entry(evlist, evsel) { + struct hists *hists = evsel__hists(evsel); + + hists->mem_stat_types = calloc(nr_mem_stats, + sizeof(*hists->mem_stat_types)); + if (hists->mem_stat_types == NULL) + return -ENOMEM; + + hists->mem_stat_total = calloc(nr_mem_stats, + sizeof(*hists->mem_stat_total)); + if (hists->mem_stat_total == NULL) + return -ENOMEM; + + memcpy(hists->mem_stat_types, mst, nr_mem_stats * sizeof(*mst)); + hists->nr_mem_stats = nr_mem_stats; + } + return 0; +} |