summaryrefslogtreecommitdiffstats
path: root/tools/perf/util/sort.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/sort.c')
-rw-r--r--tools/perf/util/sort.c216
1 files changed, 168 insertions, 48 deletions
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 901b9bece2e..14e5a039bc4 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,3 +1,4 @@
+#include <sys/mman.h>
#include "sort.h"
#include "hist.h"
#include "comm.h"
@@ -784,6 +785,104 @@ static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
return repsep_snprintf(bf, size, "%-*s", width, out);
}
+static inline u64 cl_address(u64 address)
+{
+ /* return the cacheline of the address */
+ return (address & ~(cacheline_size - 1));
+}
+
+static int64_t
+sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ u64 l, r;
+ struct map *l_map, *r_map;
+
+ if (!left->mem_info) return -1;
+ if (!right->mem_info) return 1;
+
+ /* group event types together */
+ if (left->cpumode > right->cpumode) return -1;
+ if (left->cpumode < right->cpumode) return 1;
+
+ l_map = left->mem_info->daddr.map;
+ r_map = right->mem_info->daddr.map;
+
+ /* if both are NULL, jump to sort on al_addr instead */
+ if (!l_map && !r_map)
+ goto addr;
+
+ if (!l_map) return -1;
+ if (!r_map) return 1;
+
+ if (l_map->maj > r_map->maj) return -1;
+ if (l_map->maj < r_map->maj) return 1;
+
+ if (l_map->min > r_map->min) return -1;
+ if (l_map->min < r_map->min) return 1;
+
+ if (l_map->ino > r_map->ino) return -1;
+ if (l_map->ino < r_map->ino) return 1;
+
+ if (l_map->ino_generation > r_map->ino_generation) return -1;
+ if (l_map->ino_generation < r_map->ino_generation) return 1;
+
+ /*
+ * Addresses with no major/minor numbers are assumed to be
+ * anonymous in userspace. Sort those on pid then address.
+ *
+ * The kernel and non-zero major/minor mapped areas are
+ * assumed to be unity mapped. Sort those on address.
+ */
+
+ if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
+ (!(l_map->flags & MAP_SHARED)) &&
+ !l_map->maj && !l_map->min && !l_map->ino &&
+ !l_map->ino_generation) {
+ /* userspace anonymous */
+
+ if (left->thread->pid_ > right->thread->pid_) return -1;
+ if (left->thread->pid_ < right->thread->pid_) return 1;
+ }
+
+addr:
+ /* al_addr does all the right addr - start + offset calculations */
+ l = cl_address(left->mem_info->daddr.al_addr);
+ r = cl_address(right->mem_info->daddr.al_addr);
+
+ if (l > r) return -1;
+ if (l < r) return 1;
+
+ return 0;
+}
+
+static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
+ size_t size, unsigned int width)
+{
+
+ uint64_t addr = 0;
+ struct map *map = NULL;
+ struct symbol *sym = NULL;
+ char level = he->level;
+
+ if (he->mem_info) {
+ addr = cl_address(he->mem_info->daddr.al_addr);
+ map = he->mem_info->daddr.map;
+ sym = he->mem_info->daddr.sym;
+
+ /* print [s] for shared data mmaps */
+ if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
+ map && (map->type == MAP__VARIABLE) &&
+ (map->flags & MAP_SHARED) &&
+ (map->maj || map->min || map->ino ||
+ map->ino_generation))
+ level = 's';
+ else if (!map)
+ level = 'X';
+ }
+ return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
+ width);
+}
+
struct sort_entry sort_mispredict = {
.se_header = "Branch Mispredicted",
.se_cmp = sort__mispredict_cmp,
@@ -876,6 +975,13 @@ struct sort_entry sort_mem_snoop = {
.se_width_idx = HISTC_MEM_SNOOP,
};
+struct sort_entry sort_mem_dcacheline = {
+ .se_header = "Data Cacheline",
+ .se_cmp = sort__dcacheline_cmp,
+ .se_snprintf = hist_entry__dcacheline_snprintf,
+ .se_width_idx = HISTC_MEM_DCACHELINE,
+};
+
static int64_t
sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
{
@@ -1043,6 +1149,7 @@ static struct sort_dimension memory_sort_dimensions[] = {
DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
+ DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
};
#undef DIM
@@ -1061,6 +1168,7 @@ static struct hpp_dimension hpp_sort_dimensions[] = {
DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
+ DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
DIM(PERF_HPP__SAMPLES, "sample"),
DIM(PERF_HPP__PERIOD, "period"),
};
@@ -1107,7 +1215,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
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);
+ return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header);
}
static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
@@ -1156,6 +1264,7 @@ __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;
return hse;
}
@@ -1363,27 +1472,64 @@ static int __setup_sorting(void)
return ret;
}
-bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
+void perf_hpp__set_elide(int idx, bool elide)
{
- if (perf_hpp__is_sort_entry(format)) {
- struct hpp_sort_entry *hse;
+ struct perf_hpp_fmt *fmt;
+ struct hpp_sort_entry *hse;
+
+ perf_hpp__for_each_format(fmt) {
+ if (!perf_hpp__is_sort_entry(fmt))
+ continue;
- hse = container_of(format, struct hpp_sort_entry, hpp);
- return hse->se->elide;
+ hse = container_of(fmt, struct hpp_sort_entry, hpp);
+ if (hse->se->se_width_idx == idx) {
+ fmt->elide = elide;
+ break;
+ }
}
- return false;
}
-static void sort_entry__setup_elide(struct sort_entry *se,
- struct strlist *list,
- const char *list_name, FILE *fp)
+static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
{
if (list && strlist__nr_entries(list) == 1) {
if (fp != NULL)
fprintf(fp, "# %s: %s\n", list_name,
strlist__entry(list, 0)->s);
- se->elide = true;
+ return true;
}
+ return false;
+}
+
+static bool get_elide(int idx, FILE *output)
+{
+ switch (idx) {
+ case HISTC_SYMBOL:
+ return __get_elide(symbol_conf.sym_list, "symbol", output);
+ case HISTC_DSO:
+ return __get_elide(symbol_conf.dso_list, "dso", output);
+ case HISTC_COMM:
+ return __get_elide(symbol_conf.comm_list, "comm", output);
+ default:
+ break;
+ }
+
+ if (sort__mode != SORT_MODE__BRANCH)
+ return false;
+
+ switch (idx) {
+ case HISTC_SYMBOL_FROM:
+ return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
+ case HISTC_SYMBOL_TO:
+ return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
+ case HISTC_DSO_FROM:
+ return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
+ case HISTC_DSO_TO:
+ return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
+ default:
+ break;
+ }
+
+ return false;
}
void sort__setup_elide(FILE *output)
@@ -1391,39 +1537,12 @@ void sort__setup_elide(FILE *output)
struct perf_hpp_fmt *fmt;
struct hpp_sort_entry *hse;
- sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
- "dso", output);
- sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
- "comm", output);
- sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
- "symbol", output);
-
- if (sort__mode == SORT_MODE__BRANCH) {
- sort_entry__setup_elide(&sort_dso_from,
- symbol_conf.dso_from_list,
- "dso_from", output);
- sort_entry__setup_elide(&sort_dso_to,
- symbol_conf.dso_to_list,
- "dso_to", output);
- sort_entry__setup_elide(&sort_sym_from,
- symbol_conf.sym_from_list,
- "sym_from", output);
- sort_entry__setup_elide(&sort_sym_to,
- symbol_conf.sym_to_list,
- "sym_to", output);
- } else if (sort__mode == SORT_MODE__MEMORY) {
- sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
- "symbol_daddr", output);
- sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
- "dso_daddr", output);
- sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
- "mem", output);
- sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
- "local_weight", output);
- sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
- "tlb", output);
- sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
- "snoop", output);
+ perf_hpp__for_each_format(fmt) {
+ if (!perf_hpp__is_sort_entry(fmt))
+ continue;
+
+ hse = container_of(fmt, struct hpp_sort_entry, hpp);
+ fmt->elide = get_elide(hse->se->se_width_idx, output);
}
/*
@@ -1434,8 +1553,7 @@ void sort__setup_elide(FILE *output)
if (!perf_hpp__is_sort_entry(fmt))
continue;
- hse = container_of(fmt, struct hpp_sort_entry, hpp);
- if (!hse->se->elide)
+ if (!fmt->elide)
return;
}
@@ -1443,8 +1561,7 @@ void sort__setup_elide(FILE *output)
if (!perf_hpp__is_sort_entry(fmt))
continue;
- hse = container_of(fmt, struct hpp_sort_entry, hpp);
- hse->se->elide = false;
+ fmt->elide = false;
}
}
@@ -1581,6 +1698,9 @@ void reset_output_field(void)
sort__has_sym = 0;
sort__has_dso = 0;
+ field_order = NULL;
+ sort_order = NULL;
+
reset_dimensions();
perf_hpp__reset_output_field();
}