Skip to content

Commit 871304a

Browse files
namhyungacmel
authored andcommitted
perf report: Add 'typeoff' sort key
The typeoff sort key shows the data type name, offset and the name of the field. This is useful to see which field in the struct is accessed most frequently. $ perf report -s type,typeoff --hierarchy --stdio ... # Overhead Data Type / Data Type Offset # ............ ............................ # ... 1.23% struct cfs_rq 0.19% struct cfs_rq +404 (throttle_count) 0.19% struct cfs_rq +0 (load.weight) 0.19% struct cfs_rq +336 (leaf_cfs_rq_list.next) 0.09% struct cfs_rq +272 (propagate) 0.09% struct cfs_rq +196 (removed.nr) 0.09% struct cfs_rq +80 (curr) 0.09% struct cfs_rq +544 (lt_b_children_throttled) 0.06% struct cfs_rq +320 (rq) Committer testing: Again with the perf.data from the previous csets: # perf report --stdio -s type,typeoff # To display the perf.data header info, please use --header/--header-only options. # # # Total Lost Samples: 0 # # Samples: 4 of event 'cpu_atom/mem-loads,ldlat=30/P' # Event count (approx.): 7 # # Overhead Data Type Data Type Offset # ........ ......... ................ # 42.86% struct list_head struct list_head +8 (prev) 42.86% (unknown) (unknown) +0 (no field) 14.29% char char +0 (no field) # # (Tip: To see callchains in a more compact form: perf report -g folded) # # perf report --stdio -s dso,type,typeoff # To display the perf.data header info, please use --header/--header-only options. # # # Total Lost Samples: 0 # # Samples: 4 of event 'cpu_atom/mem-loads,ldlat=30/P' # Event count (approx.): 7 # # Overhead Shared Object Data Type Data Type Offset # ........ .................... ......... ................ # 42.86% [kernel.kallsyms] struct list_head struct list_head +8 (prev) 28.57% libc.so.6 (unknown) (unknown) +0 (no field) 14.29% [kernel.kallsyms] char char +0 (no field) 14.29% ld-linux-x86-64.so.2 (unknown) (unknown) +0 (no field) # # (Tip: If you have debuginfo enabled, try: perf report -s sym,srcline) # # Signed-off-by: Namhyung Kim <[email protected]> Tested-by: Arnaldo Carvalho de Melo <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Ian Rogers <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Masami Hiramatsu <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stephane Eranian <[email protected]> Cc: [email protected] Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 9bd7ddd commit 871304a

File tree

5 files changed

+87
-1
lines changed

5 files changed

+87
-1
lines changed

tools/perf/Documentation/perf-report.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ OPTIONS
119119
to the previous instruction in cycles. And currently supported only on X86
120120
- simd: Flags describing a SIMD operation. "e" for empty Arm SVE predicate. "p" for partial Arm SVE predicate
121121
- type: Data type of sample memory access.
122+
- typeoff: Offset in the data type of sample memory access.
122123

123124
By default, comm, dso and symbol keys are used.
124125
(i.e. --sort comm,dso,symbol)

tools/perf/util/annotate.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3716,6 +3716,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
37163716
op_loc->offset,
37173717
he->stat.nr_events,
37183718
he->stat.period);
3719+
he->mem_type_off = op_loc->offset;
37193720
return mem_type;
37203721
}
37213722
return NULL;

tools/perf/util/hist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ enum hist_column {
8383
HISTC_ADDR,
8484
HISTC_SIMD,
8585
HISTC_TYPE,
86+
HISTC_TYPE_OFFSET,
8687
HISTC_NR_COLS, /* Last entry */
8788
};
8889

tools/perf/util/sort.c

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2153,8 +2153,10 @@ static void sort__type_init(struct hist_entry *he)
21532153
return;
21542154

21552155
he->mem_type = hist_entry__get_data_type(he);
2156-
if (he->mem_type == NULL)
2156+
if (he->mem_type == NULL) {
21572157
he->mem_type = &unknown_type;
2158+
he->mem_type_off = 0;
2159+
}
21582160
}
21592161

21602162
static int64_t
@@ -2198,6 +2200,84 @@ struct sort_entry sort_type = {
21982200
.se_width_idx = HISTC_TYPE,
21992201
};
22002202

2203+
/* --sort typeoff */
2204+
2205+
static int64_t
2206+
sort__typeoff_sort(struct hist_entry *left, struct hist_entry *right)
2207+
{
2208+
struct annotated_data_type *left_type = left->mem_type;
2209+
struct annotated_data_type *right_type = right->mem_type;
2210+
int64_t ret;
2211+
2212+
if (!left_type) {
2213+
sort__type_init(left);
2214+
left_type = left->mem_type;
2215+
}
2216+
2217+
if (!right_type) {
2218+
sort__type_init(right);
2219+
right_type = right->mem_type;
2220+
}
2221+
2222+
ret = strcmp(left_type->self.type_name, right_type->self.type_name);
2223+
if (ret)
2224+
return ret;
2225+
return left->mem_type_off - right->mem_type_off;
2226+
}
2227+
2228+
static void fill_member_name(char *buf, size_t sz, struct annotated_member *m,
2229+
int offset, bool first)
2230+
{
2231+
struct annotated_member *child;
2232+
2233+
if (list_empty(&m->children))
2234+
return;
2235+
2236+
list_for_each_entry(child, &m->children, node) {
2237+
if (child->offset <= offset && offset < child->offset + child->size) {
2238+
int len = 0;
2239+
2240+
/* It can have anonymous struct/union members */
2241+
if (child->var_name) {
2242+
len = scnprintf(buf, sz, "%s%s",
2243+
first ? "" : ".", child->var_name);
2244+
first = false;
2245+
}
2246+
2247+
fill_member_name(buf + len, sz - len, child, offset, first);
2248+
return;
2249+
}
2250+
}
2251+
}
2252+
2253+
static int hist_entry__typeoff_snprintf(struct hist_entry *he, char *bf,
2254+
size_t size, unsigned int width __maybe_unused)
2255+
{
2256+
struct annotated_data_type *he_type = he->mem_type;
2257+
char buf[4096];
2258+
2259+
buf[0] = '\0';
2260+
if (list_empty(&he_type->self.children))
2261+
snprintf(buf, sizeof(buf), "no field");
2262+
else
2263+
fill_member_name(buf, sizeof(buf), &he_type->self,
2264+
he->mem_type_off, true);
2265+
buf[4095] = '\0';
2266+
2267+
return repsep_snprintf(bf, size, "%s %+d (%s)", he_type->self.type_name,
2268+
he->mem_type_off, buf);
2269+
}
2270+
2271+
struct sort_entry sort_type_offset = {
2272+
.se_header = "Data Type Offset",
2273+
.se_cmp = sort__type_cmp,
2274+
.se_collapse = sort__typeoff_sort,
2275+
.se_sort = sort__typeoff_sort,
2276+
.se_init = sort__type_init,
2277+
.se_snprintf = hist_entry__typeoff_snprintf,
2278+
.se_width_idx = HISTC_TYPE_OFFSET,
2279+
};
2280+
22012281

22022282
struct sort_dimension {
22032283
const char *name;
@@ -2254,6 +2334,7 @@ static struct sort_dimension common_sort_dimensions[] = {
22542334
DIM(SORT_GLOBAL_RETIRE_LAT, "retire_lat", sort_global_p_stage_cyc),
22552335
DIM(SORT_SIMD, "simd", sort_simd),
22562336
DIM(SORT_ANNOTATE_DATA_TYPE, "type", sort_type),
2337+
DIM(SORT_ANNOTATE_DATA_TYPE_OFFSET, "typeoff", sort_type_offset),
22572338
};
22582339

22592340
#undef DIM

tools/perf/util/sort.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ struct hist_entry {
113113
u64 p_stage_cyc;
114114
u8 cpumode;
115115
u8 depth;
116+
int mem_type_off;
116117
struct simd_flags simd_flags;
117118

118119
/* We are added by hists__add_dummy_entry. */
@@ -247,6 +248,7 @@ enum sort_type {
247248
SORT_GLOBAL_RETIRE_LAT,
248249
SORT_SIMD,
249250
SORT_ANNOTATE_DATA_TYPE,
251+
SORT_ANNOTATE_DATA_TYPE_OFFSET,
250252

251253
/* branch stack specific sort keys */
252254
__SORT_BRANCH_STACK,

0 commit comments

Comments
 (0)