Skip to content

Commit 263925b

Browse files
namhyungacmel
authored andcommitted
perf annotate: Add --data-type option
Support data type annotation with new --data-type option. It internally uses type sort key to collect sample histogram for the type and display every members like below. $ perf annotate --data-type ... Annotate type: 'struct cfs_rq' in [kernel.kallsyms] (13 samples): ============================================================================ samples offset size field 13 0 640 struct cfs_rq { 2 0 16 struct load_weight load { 2 0 8 unsigned long weight; 0 8 4 u32 inv_weight; }; 0 16 8 unsigned long runnable_weight; 0 24 4 unsigned int nr_running; 1 28 4 unsigned int h_nr_running; ... For simplicity it prints the number of samples per field for now. But it should be easy to show the overhead percentage instead. The number at the outer struct is a sum of the numbers of the inner members. For example, struct cfs_rq got total 13 samples, and 2 came from the load (struct load_weight) and 1 from h_nr_running. Similarly, the struct load_weight got total 2 samples and they all came from the weight field. I've added two new flags in the symbol_conf for this. The annotate_data_member is to get the members of the type. This is also needed for perf report with typeoff sort key. The annotate_data_sample is to update sample stats for each offset and used only in annotate. Currently it only support stdio output mode, TUI support can be added later. Committer testing: With the perf.data from the previous csets, a very simple, short duration one: # perf annotate --data-type Annotate type: 'struct list_head' in [kernel.kallsyms] (1 samples): ============================================================================ samples offset size field 1 0 16 struct list_head { 0 0 8 struct list_head* next; 1 8 8 struct list_head* prev; }; Annotate type: 'char' in [kernel.kallsyms] (1 samples): ============================================================================ samples offset size field 1 0 1 char ; # 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 e2c1c8f commit 263925b

File tree

6 files changed

+118
-11
lines changed

6 files changed

+118
-11
lines changed

tools/perf/Documentation/perf-annotate.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,14 @@ include::itrace.txt[]
155155
stdio or stdio2 (Default: 0). Note that this is about selection of
156156
functions to display, not about lines within the function.
157157

158+
--data-type[=TYPE_NAME]::
159+
Display data type annotation instead of code. It infers data type of
160+
samples (if they are memory accessing instructions) using DWARF debug
161+
information. It can take an optional argument of data type name. In
162+
that case it'd show annotation for the type only, otherwise it'd show
163+
all data types it finds.
164+
165+
158166
SEE ALSO
159167
--------
160168
linkperf:perf-record[1], linkperf:perf-report[1]

tools/perf/builtin-annotate.c

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "util/evlist.h"
2121
#include "util/evsel.h"
2222
#include "util/annotate.h"
23+
#include "util/annotate-data.h"
2324
#include "util/event.h"
2425
#include <subcmd/parse-options.h>
2526
#include "util/parse-events.h"
@@ -55,9 +56,11 @@ struct perf_annotate {
5556
bool skip_missing;
5657
bool has_br_stack;
5758
bool group_set;
59+
bool data_type;
5860
float min_percent;
5961
const char *sym_hist_filter;
6062
const char *cpu_list;
63+
const char *target_data_type;
6164
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
6265
};
6366

@@ -322,6 +325,32 @@ static int hist_entry__tty_annotate(struct hist_entry *he,
322325
return symbol__tty_annotate2(&he->ms, evsel);
323326
}
324327

328+
static void print_annotated_data_type(struct annotated_data_type *mem_type,
329+
struct annotated_member *member,
330+
struct evsel *evsel, int indent)
331+
{
332+
struct annotated_member *child;
333+
struct type_hist *h = mem_type->histograms[evsel->core.idx];
334+
int i, samples = 0;
335+
336+
for (i = 0; i < member->size; i++)
337+
samples += h->addr[member->offset + i].nr_samples;
338+
339+
printf(" %10d %10d %10d %*s%s\t%s",
340+
samples, member->offset, member->size, indent, "", member->type_name,
341+
member->var_name ?: "");
342+
343+
if (!list_empty(&member->children))
344+
printf(" {\n");
345+
346+
list_for_each_entry(child, &member->children, node)
347+
print_annotated_data_type(mem_type, child, evsel, indent + 4);
348+
349+
if (!list_empty(&member->children))
350+
printf("%*s}", 35 + indent, "");
351+
printf(";\n");
352+
}
353+
325354
static void hists__find_annotations(struct hists *hists,
326355
struct evsel *evsel,
327356
struct perf_annotate *ann)
@@ -361,6 +390,40 @@ static void hists__find_annotations(struct hists *hists,
361390
continue;
362391
}
363392

393+
if (ann->data_type) {
394+
struct dso *dso = map__dso(he->ms.map);
395+
396+
/* skip unknown type */
397+
if (he->mem_type->histograms == NULL)
398+
goto find_next;
399+
400+
if (ann->target_data_type) {
401+
const char *type_name = he->mem_type->self.type_name;
402+
403+
/* skip 'struct ' prefix in the type name */
404+
if (strncmp(ann->target_data_type, "struct ", 7) &&
405+
!strncmp(type_name, "struct ", 7))
406+
type_name += 7;
407+
408+
/* skip 'union ' prefix in the type name */
409+
if (strncmp(ann->target_data_type, "union ", 6) &&
410+
!strncmp(type_name, "union ", 6))
411+
type_name += 6;
412+
413+
if (strcmp(ann->target_data_type, type_name))
414+
goto find_next;
415+
}
416+
417+
printf("Annotate type: '%s' in %s (%d samples):\n",
418+
he->mem_type->self.type_name, dso->name, he->stat.nr_events);
419+
printf("============================================================================\n");
420+
printf(" %10s %10s %10s %s\n", "samples", "offset", "size", "field");
421+
422+
print_annotated_data_type(he->mem_type, &he->mem_type->self, evsel, 0);
423+
printf("\n");
424+
goto find_next;
425+
}
426+
364427
if (use_browser == 2) {
365428
int ret;
366429
int (*annotate)(struct hist_entry *he,
@@ -496,6 +559,17 @@ static int parse_percent_limit(const struct option *opt, const char *str,
496559
return 0;
497560
}
498561

562+
static int parse_data_type(const struct option *opt, const char *str, int unset)
563+
{
564+
struct perf_annotate *ann = opt->value;
565+
566+
ann->data_type = !unset;
567+
if (str)
568+
ann->target_data_type = strdup(str);
569+
570+
return 0;
571+
}
572+
499573
static const char * const annotate_usage[] = {
500574
"perf annotate [<options>]",
501575
NULL
@@ -607,6 +681,9 @@ int cmd_annotate(int argc, const char **argv)
607681
OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
608682
"Instruction Tracing options\n" ITRACE_HELP,
609683
itrace_parse_synth_opts),
684+
OPT_CALLBACK_OPTARG(0, "data-type", &annotate, NULL, "name",
685+
"Show data type annotate for the memory accesses",
686+
parse_data_type),
610687

611688
OPT_END()
612689
};
@@ -661,6 +738,13 @@ int cmd_annotate(int argc, const char **argv)
661738
}
662739
#endif
663740

741+
#ifndef HAVE_DWARF_GETLOCATIONS_SUPPORT
742+
if (annotate.data_type) {
743+
pr_err("Error: Data type profiling is disabled due to missing DWARF support\n");
744+
return -ENOTSUP;
745+
}
746+
#endif
747+
664748
ret = symbol__validate_sym_arguments();
665749
if (ret)
666750
return ret;
@@ -703,14 +787,25 @@ int cmd_annotate(int argc, const char **argv)
703787
use_browser = 2;
704788
#endif
705789

790+
/* FIXME: only support stdio for now */
791+
if (annotate.data_type) {
792+
use_browser = 0;
793+
annotate_opts.annotate_src = false;
794+
symbol_conf.annotate_data_member = true;
795+
symbol_conf.annotate_data_sample = true;
796+
}
797+
706798
setup_browser(true);
707799

708800
/*
709801
* Events of different processes may correspond to the same
710802
* symbol, we do not care about the processes in annotate,
711803
* set sort order to avoid repeated output.
712804
*/
713-
sort_order = "dso,symbol";
805+
if (annotate.data_type)
806+
sort_order = "dso,type";
807+
else
808+
sort_order = "dso,symbol";
714809

715810
/*
716811
* Set SORT_MODE__BRANCH so that annotate display IPC/Cycle

tools/perf/util/annotate-data.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "map_symbol.h"
2020
#include "strbuf.h"
2121
#include "symbol.h"
22+
#include "symbol_conf.h"
2223

2324
/*
2425
* Compare type name and size to maintain them in a tree.
@@ -158,11 +159,8 @@ static struct annotated_data_type *dso__findnew_data_type(struct dso *dso,
158159
result->self.size = size;
159160
INIT_LIST_HEAD(&result->self.children);
160161

161-
/*
162-
* Fill member info unconditionally for now,
163-
* later perf annotate would need it.
164-
*/
165-
add_member_types(result, type_die);
162+
if (symbol_conf.annotate_data_member)
163+
add_member_types(result, type_die);
166164

167165
rb_add(&result->node, &dso->data_types, data_type_less);
168166
return result;

tools/perf/util/annotate.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3712,10 +3712,12 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
37123712

37133713
mem_type = find_data_type(ms, ip, op_loc->reg, op_loc->offset);
37143714

3715-
annotated_data_type__update_samples(mem_type, evsel,
3716-
op_loc->offset,
3717-
he->stat.nr_events,
3718-
he->stat.period);
3715+
if (symbol_conf.annotate_data_sample) {
3716+
annotated_data_type__update_samples(mem_type, evsel,
3717+
op_loc->offset,
3718+
he->stat.nr_events,
3719+
he->stat.period);
3720+
}
37193721
he->mem_type_off = op_loc->offset;
37203722
return mem_type;
37213723
}

tools/perf/util/sort.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3401,6 +3401,8 @@ int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
34013401
list->thread = 1;
34023402
} else if (sd->entry == &sort_comm) {
34033403
list->comm = 1;
3404+
} else if (sd->entry == &sort_type_offset) {
3405+
symbol_conf.annotate_data_member = true;
34043406
}
34053407

34063408
return __sort_dimension__add(sd, list, level);

tools/perf/util/symbol_conf.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ struct symbol_conf {
4444
buildid_mmap2,
4545
guest_code,
4646
lazy_load_kernel_maps,
47-
keep_exited_threads;
47+
keep_exited_threads,
48+
annotate_data_member,
49+
annotate_data_sample;
4850
const char *vmlinux_name,
4951
*kallsyms_name,
5052
*source_prefix,

0 commit comments

Comments
 (0)