perf/core improvements and fixes:

perf stat:
 
 . Display user and system time for workload targets (Jiri Olsa)
 
 perf record:
 
 . Enable arbitrary event names thru name= modifier (Alexey Budankov)
 
 PowerPC:
 
 . Add a python script for hypervisor call statistics (Ravi Bangoria)
 
 Intel PT: (Adrian Hunter)
 
 . Fix sync_switch INTEL_PT_SS_NOT_TRACING
 
 . Fix decoding to accept CBR between FUP and corresponding TIP
 
 . Fix MTC timing after overflow
 
 . Fix "Unexpected indirect branch" error
 
 perf test:
 
 . record+probe_libc_inet_pton:
 
   .  To get the symbol table for dynamic
      shared objects on ubuntu we need to pass the -D/--dynamic command line
      option, unlike with the fedora distros (Arnaldo Carvalho de Melo)
 
 . code-reading:
 
   . Fix perf_env setup for PTI entry trampolines (Adrian Hunter)
 
 . kmod-path:
 
   . Add tests for vdso32 and vdsox32 (Adrian Hunter)
 
 . Use header file util/debug.h (Thomas Richter)
 
 perf annotate:
 
 . Make the various UI backends (stdio, TUI, gtk) use more consistently
   structs with annotation options as specified by the user (Arnaldo Carvalho de Melo)
 
 . Move annotation specific knobs from the symbol_conf global kitchen
   sink to the annotation option structs (Arnaldo Carvalho de Melo)
 
 perf script:
 
 . Add more PMU fields to python scripts event handler dict (Jin Yao)
 
 Core:
 
 . Fix misleading error for some unparsable events mentioning PMUs when
   those are not involved in the problem (Jiri Olsa)
 
 . Consider BSS symbols when processing /proc/kallsyms ('B' and 'b')
   (Arnaldo Carvalho de Melo)
 
 - Be more robust when trying to use per-symbol histograms, checking for
   unlikely but possible cases where the space for the histograms wasn't
   allocated, print a debug message for such cases (Arnaldo Carvalho de Melo)
 
 - Fix symbol and object code resolution for vdso32 and vdsox32 (Adrian Hunter)
 
 . No need to check for null when passing pointers to foo__get() style
   refcount grabbing helpers, just like in the kernel and with free(),
   its safe to pass a NULL pointer to avoid having to check it before
   each and every foo__get() call (Arnaldo Carvalho de Melo)
 
 . Remove some dead code (quote.[ch]) (Arnaldo Carvalho de Melo)
 
 . Remove some needless globals, making them local (Arnaldo Carvalho de Melo)
 
 . Reduce usage of symbol_conf.use_callchain, using other means of
   finding out if callchains are in use or available for specific events,
   as we evolved this codebase to allow requesting callchains for just
   a subset of the monitored events. In time it will help polish
   recording and showing mixed sets accross the various tools:
 
     perf record -e cycles/call-graph=fp/,cache-misses/call-graph=dwarf/,instructions'
 
   (Arnaldo Carvalho de Melo)
 
 . Consider PTI entry trampolines in map__rip_2objdump() (Adrian Hunter)
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEELb9bqkb7Te0zijNb1lAW81NSqkAFAlsYQTAACgkQ1lAW81NS
 qkCjoA//WKjqox7hb4JZiSwvOulA8REs1UvTHzusm48spNRXUXezFWBRgQrvuh3E
 4C5DUnhOC4Tonm/Je4xzu80xB4w4yjd6QTXicQ0sajEEZXSoBS5XtjhWdZCpXb/v
 cIBY+7wEHkMZE3p89rUKih1tbBrKkjLD1QykD5QoNOB/HsektBbDTsmsI2kgBetg
 jjwhkh1CJqBEvd9rDeMyWTDHI5EUruINVzqIoF4U8gUu/TaowWF5d+byEM5x0JLC
 yRB3mIfyWxQug+VONjvs4Z/f/LhRuLbayz0l4lhqmfqta0b7aDl+VMdcwXcFQMeS
 wotXPu9fJKQmXVtGMqoLRHWDBDDtpHPGZb2F+cHDNsskzMtPiGmjH+YW1tant0Q8
 5c4ZqJvkxViED1Xmn6dWgqYwc3hjxVvZ1pEu3hR9/GWdrfwq/4NXaumGmf1BVILf
 +IACKOjb6XdSxo9BXgdQb5a5uxcZqF41vrJJqfZE7jtEvSkVZrewX7ugbX5c+ANX
 BWGrXOZx4aT4W4qSWjSYk36mQ60gXeB8G238xnlzV36UY9/svF9eLtXa9joq1Xaq
 2DQ3abA0iw9Mv1eh4ZAkYZo69Iy9zgZKJ+yDJt96UCQqz88lFirYRdda7XTf6WFR
 wWAfrhTgAuVTmC/aksQvIu3G23lQkgdVhT3SaXD+/QVs9B2c90Y=
 =9fWW
 -----END PGP SIGNATURE-----

Merge tag 'perf-core-for-mingo-4.18-20180606' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

perf stat:

 - Display user and system time for workload targets (Jiri Olsa)

perf record:

 - Enable arbitrary event names thru name= modifier (Alexey Budankov)

PowerPC:

 - Add a python script for hypervisor call statistics (Ravi Bangoria)

Intel PT: (Adrian Hunter)

 - Fix sync_switch INTEL_PT_SS_NOT_TRACING

 - Fix decoding to accept CBR between FUP and corresponding TIP

 - Fix MTC timing after overflow

 - Fix "Unexpected indirect branch" error

perf test:

 - record+probe_libc_inet_pton:

  -  To get the symbol table for dynamic
     shared objects on ubuntu we need to pass the -D/--dynamic command line
     option, unlike with the fedora distros (Arnaldo Carvalho de Melo)

 - code-reading:

  - Fix perf_env setup for PTI entry trampolines (Adrian Hunter)

 - kmod-path:

  - Add tests for vdso32 and vdsox32 (Adrian Hunter)

 - Use header file util/debug.h (Thomas Richter)

perf annotate:

 - Make the various UI backends (stdio, TUI, gtk) use more consistently
  structs with annotation options as specified by the user (Arnaldo Carvalho de Melo)

 - Move annotation specific knobs from the symbol_conf global kitchen
  sink to the annotation option structs (Arnaldo Carvalho de Melo)

perf script:

 - Add more PMU fields to python scripts event handler dict (Jin Yao)

Core:

 - Fix misleading error for some unparsable events mentioning PMUs when
  those are not involved in the problem (Jiri Olsa)

 - Consider BSS symbols when processing /proc/kallsyms ('B' and 'b')
  (Arnaldo Carvalho de Melo)

- Be more robust when trying to use per-symbol histograms, checking for
  unlikely but possible cases where the space for the histograms wasn't
  allocated, print a debug message for such cases (Arnaldo Carvalho de Melo)

- Fix symbol and object code resolution for vdso32 and vdsox32 (Adrian Hunter)

 - No need to check for null when passing pointers to foo__get() style
  refcount grabbing helpers, just like in the kernel and with free(),
  its safe to pass a NULL pointer to avoid having to check it before
  each and every foo__get() call (Arnaldo Carvalho de Melo)

 - Remove some dead code (quote.[ch]) (Arnaldo Carvalho de Melo)

 - Remove some needless globals, making them local (Arnaldo Carvalho de Melo)

 - Reduce usage of symbol_conf.use_callchain, using other means of
  finding out if callchains are in use or available for specific events,
  as we evolved this codebase to allow requesting callchains for just
  a subset of the monitored events. In time it will help polish
  recording and showing mixed sets accross the various tools:

    perf record -e cycles/call-graph=fp/,cache-misses/call-graph=dwarf/,instructions'

  (Arnaldo Carvalho de Melo)

 - Consider PTI entry trampolines in map__rip_2objdump() (Adrian Hunter)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2018-06-07 07:18:51 +02:00
commit 2696ec4566
59 changed files with 998 additions and 427 deletions

View File

@ -124,7 +124,11 @@ The available PMUs and their raw parameters can be listed with
For example the raw event "LSD.UOPS" core pmu event above could For example the raw event "LSD.UOPS" core pmu event above could
be specified as be specified as
perf stat -e cpu/event=0xa8,umask=0x1,name=LSD.UOPS_CYCLES,cmask=1/ ... perf stat -e cpu/event=0xa8,umask=0x1,name=LSD.UOPS_CYCLES,cmask=0x1/ ...
or using extended name syntax
perf stat -e cpu/event=0xa8,umask=0x1,cmask=0x1,name=\'LSD.UOPS_CYCLES:cmask=0x1\'/ ...
PER SOCKET PMUS PER SOCKET PMUS
--------------- ---------------

View File

@ -57,6 +57,9 @@ OPTIONS
FP mode, "dwarf" for DWARF mode, "lbr" for LBR mode and FP mode, "dwarf" for DWARF mode, "lbr" for LBR mode and
"no" for disable callgraph. "no" for disable callgraph.
- 'stack-size': user stack size for dwarf mode - 'stack-size': user stack size for dwarf mode
- 'name' : User defined event name. Single quotes (') may be used to
escape symbols in the name from parsing by shell and tool
like this: name=\'CPU_CLK_UNHALTED.THREAD:cmask=0x1\'.
See the linkperf:perf-list[1] man page for more parameters. See the linkperf:perf-list[1] man page for more parameters.

View File

@ -610,6 +610,32 @@ Various utility functions for use with perf script:
nsecs_str(nsecs) - returns printable string in the form secs.nsecs nsecs_str(nsecs) - returns printable string in the form secs.nsecs
avg(total, n) - returns average given a sum and a total number of values avg(total, n) - returns average given a sum and a total number of values
SUPPORTED FIELDS
----------------
Currently supported fields:
ev_name, comm, pid, tid, cpu, ip, time, period, phys_addr, addr,
symbol, dso, time_enabled, time_running, values, callchain,
brstack, brstacksym, datasrc, datasrc_decode, iregs, uregs,
weight, transaction, raw_buf, attr.
Some fields have sub items:
brstack:
from, to, from_dsoname, to_dsoname, mispred,
predicted, in_tx, abort, cycles.
brstacksym:
items: from, to, pred, in_tx, abort (converted string)
For example,
We can use this code to print brstack "from", "to", "cycles".
if 'brstack' in dict:
for entry in dict['brstack']:
print "from %s, to %s, cycles %s" % (entry["from"], entry["to"], entry["cycles"])
SEE ALSO SEE ALSO
-------- --------
linkperf:perf-script[1] linkperf:perf-script[1]

View File

@ -310,20 +310,38 @@ Users who wants to get the actual value can apply --no-metric-only.
EXAMPLES EXAMPLES
-------- --------
$ perf stat -- make -j $ perf stat -- make
Performance counter stats for 'make -j': Performance counter stats for 'make':
8117.370256 task clock ticks # 11.281 CPU utilization factor 83723.452481 task-clock:u (msec) # 1.004 CPUs utilized
678 context switches # 0.000 M/sec 0 context-switches:u # 0.000 K/sec
133 CPU migrations # 0.000 M/sec 0 cpu-migrations:u # 0.000 K/sec
235724 pagefaults # 0.029 M/sec 3,228,188 page-faults:u # 0.039 M/sec
24821162526 CPU cycles # 3057.784 M/sec 229,570,665,834 cycles:u # 2.742 GHz
18687303457 instructions # 2302.138 M/sec 313,163,853,778 instructions:u # 1.36 insn per cycle
172158895 cache references # 21.209 M/sec 69,704,684,856 branches:u # 832.559 M/sec
27075259 cache misses # 3.335 M/sec 2,078,861,393 branch-misses:u # 2.98% of all branches
Wall-clock time elapsed: 719.554352 msecs 83.409183620 seconds time elapsed
74.684747000 seconds user
8.739217000 seconds sys
TIMINGS
-------
As displayed in the example above we can display 3 types of timings.
We always display the time the counters were enabled/alive:
83.409183620 seconds time elapsed
For workload sessions we also display time the workloads spent in
user/system lands:
74.684747000 seconds user
8.739217000 seconds sys
Those times are the very same as displayed by the 'time' tool.
CSV FORMAT CSV FORMAT
---------- ----------

View File

@ -189,7 +189,7 @@ out_error:
return -1; return -1;
} }
int perf_env__lookup_objdump(struct perf_env *env) int perf_env__lookup_objdump(struct perf_env *env, const char **path)
{ {
/* /*
* For live mode, env->arch will be NULL and we can use * For live mode, env->arch will be NULL and we can use
@ -198,5 +198,5 @@ int perf_env__lookup_objdump(struct perf_env *env)
if (env->arch == NULL) if (env->arch == NULL)
return 0; return 0;
return perf_env__lookup_binutils_path(env, "objdump", &objdump_path); return perf_env__lookup_binutils_path(env, "objdump", path);
} }

View File

@ -4,8 +4,6 @@
#include "../util/env.h" #include "../util/env.h"
extern const char *objdump_path; int perf_env__lookup_objdump(struct perf_env *env, const char **path);
int perf_env__lookup_objdump(struct perf_env *env);
#endif /* ARCH_PERF_COMMON_H */ #endif /* ARCH_PERF_COMMON_H */

View File

@ -40,9 +40,8 @@
struct perf_annotate { struct perf_annotate {
struct perf_tool tool; struct perf_tool tool;
struct perf_session *session; struct perf_session *session;
struct annotation_options opts;
bool use_tui, use_stdio, use_stdio2, use_gtk; bool use_tui, use_stdio, use_stdio2, use_gtk;
bool full_paths;
bool print_line;
bool skip_missing; bool skip_missing;
bool has_br_stack; bool has_br_stack;
bool group_set; bool group_set;
@ -162,12 +161,12 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter,
hist__account_cycles(sample->branch_stack, al, sample, false); hist__account_cycles(sample->branch_stack, al, sample, false);
bi = he->branch_info; bi = he->branch_info;
err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); err = addr_map_symbol__inc_samples(&bi->from, sample, evsel);
if (err) if (err)
goto out; goto out;
err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); err = addr_map_symbol__inc_samples(&bi->to, sample, evsel);
out: out:
return err; return err;
@ -249,7 +248,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
if (he == NULL) if (he == NULL)
return -ENOMEM; return -ENOMEM;
ret = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); ret = hist_entry__inc_addr_samples(he, sample, evsel, al->addr);
hists__inc_nr_samples(hists, true); hists__inc_nr_samples(hists, true);
return ret; return ret;
} }
@ -289,10 +288,9 @@ static int hist_entry__tty_annotate(struct hist_entry *he,
struct perf_annotate *ann) struct perf_annotate *ann)
{ {
if (!ann->use_stdio2) if (!ann->use_stdio2)
return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, &ann->opts);
ann->print_line, ann->full_paths, 0, 0);
return symbol__tty_annotate2(he->ms.sym, he->ms.map, evsel, return symbol__tty_annotate2(he->ms.sym, he->ms.map, evsel, &ann->opts);
ann->print_line, ann->full_paths);
} }
static void hists__find_annotations(struct hists *hists, static void hists__find_annotations(struct hists *hists,
@ -343,7 +341,7 @@ find_next:
/* skip missing symbols */ /* skip missing symbols */
nd = rb_next(nd); nd = rb_next(nd);
} else if (use_browser == 1) { } else if (use_browser == 1) {
key = hist_entry__tui_annotate(he, evsel, NULL); key = hist_entry__tui_annotate(he, evsel, NULL, &ann->opts);
switch (key) { switch (key) {
case -1: case -1:
@ -390,8 +388,9 @@ static int __cmd_annotate(struct perf_annotate *ann)
goto out; goto out;
} }
if (!objdump_path) { if (!ann->opts.objdump_path) {
ret = perf_env__lookup_objdump(&session->header.env); ret = perf_env__lookup_objdump(&session->header.env,
&ann->opts.objdump_path);
if (ret) if (ret)
goto out; goto out;
} }
@ -476,6 +475,7 @@ int cmd_annotate(int argc, const char **argv)
.ordered_events = true, .ordered_events = true,
.ordering_requires_timestamps = true, .ordering_requires_timestamps = true,
}, },
.opts = annotation__default_options,
}; };
struct perf_data data = { struct perf_data data = {
.mode = PERF_DATA_MODE_READ, .mode = PERF_DATA_MODE_READ,
@ -503,9 +503,9 @@ int cmd_annotate(int argc, const char **argv)
"file", "vmlinux pathname"), "file", "vmlinux pathname"),
OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
"load module symbols - WARNING: use only with -k and LIVE kernel"), "load module symbols - WARNING: use only with -k and LIVE kernel"),
OPT_BOOLEAN('l', "print-line", &annotate.print_line, OPT_BOOLEAN('l', "print-line", &annotate.opts.print_lines,
"print matching source lines (may be slow)"), "print matching source lines (may be slow)"),
OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, OPT_BOOLEAN('P', "full-paths", &annotate.opts.full_path,
"Don't shorten the displayed pathnames"), "Don't shorten the displayed pathnames"),
OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing, OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing,
"Skip symbols that cannot be annotated"), "Skip symbols that cannot be annotated"),
@ -516,13 +516,13 @@ int cmd_annotate(int argc, const char **argv)
OPT_CALLBACK(0, "symfs", NULL, "directory", OPT_CALLBACK(0, "symfs", NULL, "directory",
"Look for files with symbols relative to this directory", "Look for files with symbols relative to this directory",
symbol__config_symfs), symbol__config_symfs),
OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, OPT_BOOLEAN(0, "source", &annotate.opts.annotate_src,
"Interleave source code with assembly code (default)"), "Interleave source code with assembly code (default)"),
OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, OPT_BOOLEAN(0, "asm-raw", &annotate.opts.show_asm_raw,
"Display raw encoding of assembly instructions (default)"), "Display raw encoding of assembly instructions (default)"),
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", OPT_STRING('M', "disassembler-style", &annotate.opts.disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"), "Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING(0, "objdump", &objdump_path, "path", OPT_STRING(0, "objdump", &annotate.opts.objdump_path, "path",
"objdump binary to use for disassembly and annotations"), "objdump binary to use for disassembly and annotations"),
OPT_BOOLEAN(0, "group", &symbol_conf.event_group, OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
"Show event group information together"), "Show event group information together"),

View File

@ -1976,7 +1976,7 @@ static int filter_cb(struct hist_entry *he)
c2c_he = container_of(he, struct c2c_hist_entry, he); c2c_he = container_of(he, struct c2c_hist_entry, he);
if (c2c.show_src && !he->srcline) if (c2c.show_src && !he->srcline)
he->srcline = hist_entry__get_srcline(he); he->srcline = hist_entry__srcline(he);
calc_width(c2c_he); calc_width(c2c_he);

View File

@ -1438,8 +1438,6 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
goto out; goto out;
} }
symbol_conf.nr_events = kvm->evlist->nr_entries;
if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0) if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0)
usage_with_options(live_usage, live_options); usage_with_options(live_usage, live_options);

View File

@ -81,8 +81,7 @@ static int parse_probe_event(const char *str)
params.target_used = true; params.target_used = true;
} }
if (params.nsi) pev->nsi = nsinfo__get(params.nsi);
pev->nsi = nsinfo__get(params.nsi);
/* Parse a perf-probe command into event */ /* Parse a perf-probe command into event */
ret = parse_perf_probe_command(str, pev); ret = parse_perf_probe_command(str, pev);

View File

@ -71,6 +71,7 @@ struct report {
bool group_set; bool group_set;
int max_stack; int max_stack;
struct perf_read_values show_threads_values; struct perf_read_values show_threads_values;
struct annotation_options annotation_opts;
const char *pretty_printing_style; const char *pretty_printing_style;
const char *cpu_list; const char *cpu_list;
const char *symbol_filter_str; const char *symbol_filter_str;
@ -136,26 +137,25 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter,
if (sort__mode == SORT_MODE__BRANCH) { if (sort__mode == SORT_MODE__BRANCH) {
bi = he->branch_info; bi = he->branch_info;
err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); err = addr_map_symbol__inc_samples(&bi->from, sample, evsel);
if (err) if (err)
goto out; goto out;
err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); err = addr_map_symbol__inc_samples(&bi->to, sample, evsel);
} else if (rep->mem_mode) { } else if (rep->mem_mode) {
mi = he->mem_info; mi = he->mem_info;
err = addr_map_symbol__inc_samples(&mi->daddr, sample, evsel->idx); err = addr_map_symbol__inc_samples(&mi->daddr, sample, evsel);
if (err) if (err)
goto out; goto out;
err = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr);
} else if (symbol_conf.cumulate_callchain) { } else if (symbol_conf.cumulate_callchain) {
if (single) if (single)
err = hist_entry__inc_addr_samples(he, sample, evsel->idx, err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr);
al->addr);
} else { } else {
err = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr);
} }
out: out:
@ -181,11 +181,11 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter,
rep->nonany_branch_mode); rep->nonany_branch_mode);
bi = he->branch_info; bi = he->branch_info;
err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); err = addr_map_symbol__inc_samples(&bi->from, sample, evsel);
if (err) if (err)
goto out; goto out;
err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); err = addr_map_symbol__inc_samples(&bi->to, sample, evsel);
branch_type_count(&rep->brtype_stat, &bi->flags, branch_type_count(&rep->brtype_stat, &bi->flags,
bi->from.addr, bi->to.addr); bi->from.addr, bi->to.addr);
@ -561,7 +561,7 @@ static int report__browse_hists(struct report *rep)
ret = perf_evlist__tui_browse_hists(evlist, help, NULL, ret = perf_evlist__tui_browse_hists(evlist, help, NULL,
rep->min_percent, rep->min_percent,
&session->header.env, &session->header.env,
true); true, &rep->annotation_opts);
/* /*
* Usually "ret" is the last pressed key, and we only * Usually "ret" is the last pressed key, and we only
* care if the key notifies us to switch data file. * care if the key notifies us to switch data file.
@ -946,12 +946,6 @@ parse_percent_limit(const struct option *opt, const char *str,
return 0; return 0;
} }
#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
CALLCHAIN_REPORT_HELP
"\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
int cmd_report(int argc, const char **argv) int cmd_report(int argc, const char **argv)
{ {
struct perf_session *session; struct perf_session *session;
@ -960,6 +954,10 @@ int cmd_report(int argc, const char **argv)
bool has_br_stack = false; bool has_br_stack = false;
int branch_mode = -1; int branch_mode = -1;
bool branch_call_mode = false; bool branch_call_mode = false;
#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
CALLCHAIN_REPORT_HELP
"\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT; char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
const char * const report_usage[] = { const char * const report_usage[] = {
"perf report [<options>]", "perf report [<options>]",
@ -989,6 +987,7 @@ int cmd_report(int argc, const char **argv)
.max_stack = PERF_MAX_STACK_DEPTH, .max_stack = PERF_MAX_STACK_DEPTH,
.pretty_printing_style = "normal", .pretty_printing_style = "normal",
.socket_filter = -1, .socket_filter = -1,
.annotation_opts = annotation__default_options,
}; };
const struct option options[] = { const struct option options[] = {
OPT_STRING('i', "input", &input_name, "file", OPT_STRING('i', "input", &input_name, "file",
@ -1078,11 +1077,11 @@ int cmd_report(int argc, const char **argv)
"list of cpus to profile"), "list of cpus to profile"),
OPT_BOOLEAN('I', "show-info", &report.show_full_info, OPT_BOOLEAN('I', "show-info", &report.show_full_info,
"Display extended information about perf.data file"), "Display extended information about perf.data file"),
OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, OPT_BOOLEAN(0, "source", &report.annotation_opts.annotate_src,
"Interleave source code with assembly code (default)"), "Interleave source code with assembly code (default)"),
OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, OPT_BOOLEAN(0, "asm-raw", &report.annotation_opts.show_asm_raw,
"Display raw encoding of assembly instructions (default)"), "Display raw encoding of assembly instructions (default)"),
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", OPT_STRING('M', "disassembler-style", &report.annotation_opts.disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"), "Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
"Show a column with the sum of periods"), "Show a column with the sum of periods"),
@ -1093,7 +1092,7 @@ int cmd_report(int argc, const char **argv)
parse_branch_mode), parse_branch_mode),
OPT_BOOLEAN(0, "branch-history", &branch_call_mode, OPT_BOOLEAN(0, "branch-history", &branch_call_mode,
"add last branch records to call history"), "add last branch records to call history"),
OPT_STRING(0, "objdump", &objdump_path, "path", OPT_STRING(0, "objdump", &report.annotation_opts.objdump_path, "path",
"objdump binary to use for disassembly and annotations"), "objdump binary to use for disassembly and annotations"),
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
"Disable symbol demangling"), "Disable symbol demangling"),

View File

@ -2143,7 +2143,7 @@ static void save_task_callchain(struct perf_sched *sched,
return; return;
} }
if (!symbol_conf.use_callchain || sample->callchain == NULL) if (!sched->show_callchain || sample->callchain == NULL)
return; return;
if (thread__resolve_callchain(thread, cursor, evsel, sample, if (thread__resolve_callchain(thread, cursor, evsel, sample,
@ -2271,10 +2271,11 @@ static struct thread *get_idle_thread(int cpu)
return idle_threads[cpu]; return idle_threads[cpu];
} }
static void save_idle_callchain(struct idle_thread_runtime *itr, static void save_idle_callchain(struct perf_sched *sched,
struct idle_thread_runtime *itr,
struct perf_sample *sample) struct perf_sample *sample)
{ {
if (!symbol_conf.use_callchain || sample->callchain == NULL) if (!sched->show_callchain || sample->callchain == NULL)
return; return;
callchain_cursor__copy(&itr->cursor, &callchain_cursor); callchain_cursor__copy(&itr->cursor, &callchain_cursor);
@ -2320,7 +2321,7 @@ static struct thread *timehist_get_thread(struct perf_sched *sched,
/* copy task callchain when entering to idle */ /* copy task callchain when entering to idle */
if (perf_evsel__intval(evsel, sample, "next_pid") == 0) if (perf_evsel__intval(evsel, sample, "next_pid") == 0)
save_idle_callchain(itr, sample); save_idle_callchain(sched, itr, sample);
} }
} }
@ -2849,7 +2850,7 @@ static void timehist_print_summary(struct perf_sched *sched,
printf(" CPU %2d idle entire time window\n", i); printf(" CPU %2d idle entire time window\n", i);
} }
if (sched->idle_hist && symbol_conf.use_callchain) { if (sched->idle_hist && sched->show_callchain) {
callchain_param.mode = CHAIN_FOLDED; callchain_param.mode = CHAIN_FOLDED;
callchain_param.value = CCVAL_PERIOD; callchain_param.value = CCVAL_PERIOD;
@ -2933,8 +2934,7 @@ static int timehist_check_attr(struct perf_sched *sched,
return -1; return -1;
} }
if (sched->show_callchain && if (sched->show_callchain && !evsel__has_callchain(evsel)) {
!(evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN)) {
pr_info("Samples do not have callchains.\n"); pr_info("Samples do not have callchains.\n");
sched->show_callchain = 0; sched->show_callchain = 0;
symbol_conf.use_callchain = 0; symbol_conf.use_callchain = 0;

View File

@ -517,7 +517,7 @@ static int perf_session__check_output_opt(struct perf_session *session)
evlist__for_each_entry(session->evlist, evsel) { evlist__for_each_entry(session->evlist, evsel) {
not_pipe = true; not_pipe = true;
if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { if (evsel__has_callchain(evsel)) {
use_callchain = true; use_callchain = true;
break; break;
} }
@ -532,22 +532,18 @@ static int perf_session__check_output_opt(struct perf_session *session)
*/ */
if (symbol_conf.use_callchain && if (symbol_conf.use_callchain &&
!output[PERF_TYPE_TRACEPOINT].user_set) { !output[PERF_TYPE_TRACEPOINT].user_set) {
struct perf_event_attr *attr;
j = PERF_TYPE_TRACEPOINT; j = PERF_TYPE_TRACEPOINT;
evlist__for_each_entry(session->evlist, evsel) { evlist__for_each_entry(session->evlist, evsel) {
if (evsel->attr.type != j) if (evsel->attr.type != j)
continue; continue;
attr = &evsel->attr; if (evsel__has_callchain(evsel)) {
if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) {
output[j].fields |= PERF_OUTPUT_IP; output[j].fields |= PERF_OUTPUT_IP;
output[j].fields |= PERF_OUTPUT_SYM; output[j].fields |= PERF_OUTPUT_SYM;
output[j].fields |= PERF_OUTPUT_SYMOFFSET; output[j].fields |= PERF_OUTPUT_SYMOFFSET;
output[j].fields |= PERF_OUTPUT_DSO; output[j].fields |= PERF_OUTPUT_DSO;
set_print_ip_opts(attr); set_print_ip_opts(&evsel->attr);
goto out; goto out;
} }
} }
@ -610,7 +606,7 @@ static int perf_sample__fprintf_start(struct perf_sample *sample,
if (PRINT_FIELD(COMM)) { if (PRINT_FIELD(COMM)) {
if (latency_format) if (latency_format)
printed += fprintf(fp, "%8.8s ", thread__comm_str(thread)); printed += fprintf(fp, "%8.8s ", thread__comm_str(thread));
else if (PRINT_FIELD(IP) && symbol_conf.use_callchain) else if (PRINT_FIELD(IP) && evsel__has_callchain(evsel) && symbol_conf.use_callchain)
printed += fprintf(fp, "%s ", thread__comm_str(thread)); printed += fprintf(fp, "%s ", thread__comm_str(thread));
else else
printed += fprintf(fp, "%16s ", thread__comm_str(thread)); printed += fprintf(fp, "%16s ", thread__comm_str(thread));

View File

@ -80,6 +80,9 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include "sane_ctype.h" #include "sane_ctype.h"
@ -175,6 +178,8 @@ static int output_fd;
static int print_free_counters_hint; static int print_free_counters_hint;
static int print_mixed_hw_group_error; static int print_mixed_hw_group_error;
static u64 *walltime_run; static u64 *walltime_run;
static bool ru_display = false;
static struct rusage ru_data;
struct perf_stat { struct perf_stat {
bool record; bool record;
@ -726,7 +731,7 @@ try_again:
break; break;
} }
} }
waitpid(child_pid, &status, 0); wait4(child_pid, &status, 0, &ru_data);
if (workload_exec_errno) { if (workload_exec_errno) {
const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg));
@ -1804,6 +1809,11 @@ static void print_table(FILE *output, int precision, double avg)
fprintf(output, "\n%*s# Final result:\n", indent, ""); fprintf(output, "\n%*s# Final result:\n", indent, "");
} }
static double timeval2double(struct timeval *t)
{
return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC;
}
static void print_footer(void) static void print_footer(void)
{ {
double avg = avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC; double avg = avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC;
@ -1815,6 +1825,15 @@ static void print_footer(void)
if (run_count == 1) { if (run_count == 1) {
fprintf(output, " %17.9f seconds time elapsed", avg); fprintf(output, " %17.9f seconds time elapsed", avg);
if (ru_display) {
double ru_utime = timeval2double(&ru_data.ru_utime);
double ru_stime = timeval2double(&ru_data.ru_stime);
fprintf(output, "\n\n");
fprintf(output, " %17.9f seconds user\n", ru_utime);
fprintf(output, " %17.9f seconds sys\n", ru_stime);
}
} else { } else {
double sd = stddev_stats(&walltime_nsecs_stats) / NSEC_PER_SEC; double sd = stddev_stats(&walltime_nsecs_stats) / NSEC_PER_SEC;
/* /*
@ -2950,6 +2969,13 @@ int cmd_stat(int argc, const char **argv)
setup_system_wide(argc); setup_system_wide(argc);
/*
* Display user/system times only for single
* run and when there's specified tracee.
*/
if ((run_count == 1) && target__none(&target))
ru_display = true;
if (run_count < 0) { if (run_count < 0) {
pr_err("Run count must be a positive number\n"); pr_err("Run count must be a positive number\n");
parse_options_usage(stat_usage, stat_options, "r", 1); parse_options_usage(stat_usage, stat_options, "r", 1);

View File

@ -123,14 +123,9 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
} }
notes = symbol__annotation(sym); notes = symbol__annotation(sym);
if (notes->src != NULL) {
pthread_mutex_lock(&notes->lock);
goto out_assign;
}
pthread_mutex_lock(&notes->lock); pthread_mutex_lock(&notes->lock);
if (symbol__alloc_hist(sym) < 0) { if (!symbol__hists(sym, top->evlist->nr_entries)) {
pthread_mutex_unlock(&notes->lock); pthread_mutex_unlock(&notes->lock);
pr_err("Not enough memory for annotating '%s' symbol!\n", pr_err("Not enough memory for annotating '%s' symbol!\n",
sym->name); sym->name);
@ -138,9 +133,8 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
return err; return err;
} }
err = symbol__annotate(sym, map, evsel, 0, NULL); err = symbol__annotate(sym, map, evsel, 0, &top->annotation_opts, NULL);
if (err == 0) { if (err == 0) {
out_assign:
top->sym_filter_entry = he; top->sym_filter_entry = he;
} else { } else {
char msg[BUFSIZ]; char msg[BUFSIZ];
@ -188,7 +182,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip)
static void perf_top__record_precise_ip(struct perf_top *top, static void perf_top__record_precise_ip(struct perf_top *top,
struct hist_entry *he, struct hist_entry *he,
struct perf_sample *sample, struct perf_sample *sample,
int counter, u64 ip) struct perf_evsel *evsel, u64 ip)
{ {
struct annotation *notes; struct annotation *notes;
struct symbol *sym = he->ms.sym; struct symbol *sym = he->ms.sym;
@ -204,7 +198,7 @@ static void perf_top__record_precise_ip(struct perf_top *top,
if (pthread_mutex_trylock(&notes->lock)) if (pthread_mutex_trylock(&notes->lock))
return; return;
err = hist_entry__inc_addr_samples(he, sample, counter, ip); err = hist_entry__inc_addr_samples(he, sample, evsel, ip);
pthread_mutex_unlock(&notes->lock); pthread_mutex_unlock(&notes->lock);
@ -249,10 +243,9 @@ static void perf_top__show_details(struct perf_top *top)
goto out_unlock; goto out_unlock;
printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name);
printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); printf(" Events Pcnt (>=%d%%)\n", top->annotation_opts.min_pcnt);
more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, &top->annotation_opts);
0, top->sym_pcnt_filter, top->print_entries, 4);
if (top->evlist->enabled) { if (top->evlist->enabled) {
if (top->zero) if (top->zero)
@ -412,7 +405,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top)
fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter);
fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter); fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->annotation_opts.min_pcnt);
fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
fprintf(stdout, "\t[S] stop annotation.\n"); fprintf(stdout, "\t[S] stop annotation.\n");
@ -515,7 +508,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
prompt_integer(&top->count_filter, "Enter display event count filter"); prompt_integer(&top->count_filter, "Enter display event count filter");
break; break;
case 'F': case 'F':
prompt_percent(&top->sym_pcnt_filter, prompt_percent(&top->annotation_opts.min_pcnt,
"Enter details display event filter (percent)"); "Enter details display event filter (percent)");
break; break;
case 'K': case 'K':
@ -613,7 +606,8 @@ static void *display_thread_tui(void *arg)
perf_evlist__tui_browse_hists(top->evlist, help, &hbt, perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
top->min_percent, top->min_percent,
&top->session->header.env, &top->session->header.env,
!top->record_opts.overwrite); !top->record_opts.overwrite,
&top->annotation_opts);
done = 1; done = 1;
return NULL; return NULL;
@ -691,7 +685,7 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter,
struct perf_evsel *evsel = iter->evsel; struct perf_evsel *evsel = iter->evsel;
if (perf_hpp_list.sym && single) if (perf_hpp_list.sym && single)
perf_top__record_precise_ip(top, he, iter->sample, evsel->idx, al->addr); perf_top__record_precise_ip(top, he, iter->sample, evsel, al->addr);
hist__account_cycles(iter->sample->branch_stack, al, iter->sample, hist__account_cycles(iter->sample->branch_stack, al, iter->sample,
!(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY));
@ -1083,8 +1077,9 @@ static int __cmd_top(struct perf_top *top)
if (top->session == NULL) if (top->session == NULL)
return -1; return -1;
if (!objdump_path) { if (!top->annotation_opts.objdump_path) {
ret = perf_env__lookup_objdump(&top->session->header.env); ret = perf_env__lookup_objdump(&top->session->header.env,
&top->annotation_opts.objdump_path);
if (ret) if (ret)
goto out_delete; goto out_delete;
} }
@ -1265,7 +1260,7 @@ int cmd_top(int argc, const char **argv)
.overwrite = 1, .overwrite = 1,
}, },
.max_stack = sysctl__max_stack(), .max_stack = sysctl__max_stack(),
.sym_pcnt_filter = 5, .annotation_opts = annotation__default_options,
.nr_threads_synthesize = UINT_MAX, .nr_threads_synthesize = UINT_MAX,
}; };
struct record_opts *opts = &top.record_opts; struct record_opts *opts = &top.record_opts;
@ -1347,15 +1342,15 @@ int cmd_top(int argc, const char **argv)
"only consider symbols in these comms"), "only consider symbols in these comms"),
OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
"only consider these symbols"), "only consider these symbols"),
OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, OPT_BOOLEAN(0, "source", &top.annotation_opts.annotate_src,
"Interleave source code with assembly code (default)"), "Interleave source code with assembly code (default)"),
OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, OPT_BOOLEAN(0, "asm-raw", &top.annotation_opts.show_asm_raw,
"Display raw encoding of assembly instructions (default)"), "Display raw encoding of assembly instructions (default)"),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
"Enable kernel symbol demangling"), "Enable kernel symbol demangling"),
OPT_STRING(0, "objdump", &objdump_path, "path", OPT_STRING(0, "objdump", &top.annotation_opts.objdump_path, "path",
"objdump binary to use for disassembly and annotations"), "objdump binary to use for disassembly and annotations"),
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"), "Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
OPT_CALLBACK(0, "percent-limit", &top, "percent", OPT_CALLBACK(0, "percent-limit", &top, "percent",
@ -1391,6 +1386,9 @@ int cmd_top(int argc, const char **argv)
if (status < 0) if (status < 0)
return status; return status;
top.annotation_opts.min_pcnt = 5;
top.annotation_opts.context = 4;
top.evlist = perf_evlist__new(); top.evlist = perf_evlist__new();
if (top.evlist == NULL) if (top.evlist == NULL)
return -ENOMEM; return -ENOMEM;
@ -1468,8 +1466,6 @@ int cmd_top(int argc, const char **argv)
goto out_delete_evlist; goto out_delete_evlist;
} }
symbol_conf.nr_events = top.evlist->nr_entries;
if (top.delay_secs < 1) if (top.delay_secs < 1)
top.delay_secs = 1; top.delay_secs = 1;

View File

@ -2491,7 +2491,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
* to override an explicitely set --max-stack global setting. * to override an explicitely set --max-stack global setting.
*/ */
evlist__for_each_entry(evlist, evsel) { evlist__for_each_entry(evlist, evsel) {
if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) && if (evsel__has_callchain(evsel) &&
evsel->attr.sample_max_stack == 0) evsel->attr.sample_max_stack == 0)
evsel->attr.sample_max_stack = trace->max_stack; evsel->attr.sample_max_stack = trace->max_stack;
} }

View File

@ -12,7 +12,6 @@
#include "util/env.h" #include "util/env.h"
#include <subcmd/exec-cmd.h> #include <subcmd/exec-cmd.h>
#include "util/config.h" #include "util/config.h"
#include "util/quote.h"
#include <subcmd/run-command.h> #include <subcmd/run-command.h>
#include "util/parse-events.h" #include "util/parse-events.h"
#include <subcmd/parse-options.h> #include <subcmd/parse-options.h>

View File

@ -0,0 +1,2 @@
#!/bin/bash
perf record -e "{powerpc:hcall_entry,powerpc:hcall_exit}" $@

View File

@ -0,0 +1,2 @@
#!/bin/bash
perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/powerpc-hcalls.py

View File

@ -0,0 +1,200 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2018 Ravi Bangoria, IBM Corporation
#
# Hypervisor call statisics
import os
import sys
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
from perf_trace_context import *
from Core import *
from Util import *
# output: {
# opcode: {
# 'min': minimum time nsec
# 'max': maximum time nsec
# 'time': average time nsec
# 'cnt': counter
# } ...
# }
output = {}
# d_enter: {
# cpu: {
# opcode: nsec
# } ...
# }
d_enter = {}
hcall_table = {
4: 'H_REMOVE',
8: 'H_ENTER',
12: 'H_READ',
16: 'H_CLEAR_MOD',
20: 'H_CLEAR_REF',
24: 'H_PROTECT',
28: 'H_GET_TCE',
32: 'H_PUT_TCE',
36: 'H_SET_SPRG0',
40: 'H_SET_DABR',
44: 'H_PAGE_INIT',
48: 'H_SET_ASR',
52: 'H_ASR_ON',
56: 'H_ASR_OFF',
60: 'H_LOGICAL_CI_LOAD',
64: 'H_LOGICAL_CI_STORE',
68: 'H_LOGICAL_CACHE_LOAD',
72: 'H_LOGICAL_CACHE_STORE',
76: 'H_LOGICAL_ICBI',
80: 'H_LOGICAL_DCBF',
84: 'H_GET_TERM_CHAR',
88: 'H_PUT_TERM_CHAR',
92: 'H_REAL_TO_LOGICAL',
96: 'H_HYPERVISOR_DATA',
100: 'H_EOI',
104: 'H_CPPR',
108: 'H_IPI',
112: 'H_IPOLL',
116: 'H_XIRR',
120: 'H_MIGRATE_DMA',
124: 'H_PERFMON',
220: 'H_REGISTER_VPA',
224: 'H_CEDE',
228: 'H_CONFER',
232: 'H_PROD',
236: 'H_GET_PPP',
240: 'H_SET_PPP',
244: 'H_PURR',
248: 'H_PIC',
252: 'H_REG_CRQ',
256: 'H_FREE_CRQ',
260: 'H_VIO_SIGNAL',
264: 'H_SEND_CRQ',
272: 'H_COPY_RDMA',
276: 'H_REGISTER_LOGICAL_LAN',
280: 'H_FREE_LOGICAL_LAN',
284: 'H_ADD_LOGICAL_LAN_BUFFER',
288: 'H_SEND_LOGICAL_LAN',
292: 'H_BULK_REMOVE',
304: 'H_MULTICAST_CTRL',
308: 'H_SET_XDABR',
312: 'H_STUFF_TCE',
316: 'H_PUT_TCE_INDIRECT',
332: 'H_CHANGE_LOGICAL_LAN_MAC',
336: 'H_VTERM_PARTNER_INFO',
340: 'H_REGISTER_VTERM',
344: 'H_FREE_VTERM',
348: 'H_RESET_EVENTS',
352: 'H_ALLOC_RESOURCE',
356: 'H_FREE_RESOURCE',
360: 'H_MODIFY_QP',
364: 'H_QUERY_QP',
368: 'H_REREGISTER_PMR',
372: 'H_REGISTER_SMR',
376: 'H_QUERY_MR',
380: 'H_QUERY_MW',
384: 'H_QUERY_HCA',
388: 'H_QUERY_PORT',
392: 'H_MODIFY_PORT',
396: 'H_DEFINE_AQP1',
400: 'H_GET_TRACE_BUFFER',
404: 'H_DEFINE_AQP0',
408: 'H_RESIZE_MR',
412: 'H_ATTACH_MCQP',
416: 'H_DETACH_MCQP',
420: 'H_CREATE_RPT',
424: 'H_REMOVE_RPT',
428: 'H_REGISTER_RPAGES',
432: 'H_DISABLE_AND_GETC',
436: 'H_ERROR_DATA',
440: 'H_GET_HCA_INFO',
444: 'H_GET_PERF_COUNT',
448: 'H_MANAGE_TRACE',
468: 'H_FREE_LOGICAL_LAN_BUFFER',
472: 'H_POLL_PENDING',
484: 'H_QUERY_INT_STATE',
580: 'H_ILLAN_ATTRIBUTES',
592: 'H_MODIFY_HEA_QP',
596: 'H_QUERY_HEA_QP',
600: 'H_QUERY_HEA',
604: 'H_QUERY_HEA_PORT',
608: 'H_MODIFY_HEA_PORT',
612: 'H_REG_BCMC',
616: 'H_DEREG_BCMC',
620: 'H_REGISTER_HEA_RPAGES',
624: 'H_DISABLE_AND_GET_HEA',
628: 'H_GET_HEA_INFO',
632: 'H_ALLOC_HEA_RESOURCE',
644: 'H_ADD_CONN',
648: 'H_DEL_CONN',
664: 'H_JOIN',
676: 'H_VASI_STATE',
688: 'H_ENABLE_CRQ',
696: 'H_GET_EM_PARMS',
720: 'H_SET_MPP',
724: 'H_GET_MPP',
748: 'H_HOME_NODE_ASSOCIATIVITY',
756: 'H_BEST_ENERGY',
764: 'H_XIRR_X',
768: 'H_RANDOM',
772: 'H_COP',
788: 'H_GET_MPP_X',
796: 'H_SET_MODE',
61440: 'H_RTAS',
}
def hcall_table_lookup(opcode):
if (hcall_table.has_key(opcode)):
return hcall_table[opcode]
else:
return opcode
print_ptrn = '%-28s%10s%10s%10s%10s'
def trace_end():
print print_ptrn % ('hcall', 'count', 'min(ns)', 'max(ns)', 'avg(ns)')
print '-' * 68
for opcode in output:
h_name = hcall_table_lookup(opcode)
time = output[opcode]['time']
cnt = output[opcode]['cnt']
min_t = output[opcode]['min']
max_t = output[opcode]['max']
print print_ptrn % (h_name, cnt, min_t, max_t, time/cnt)
def powerpc__hcall_exit(name, context, cpu, sec, nsec, pid, comm, callchain,
opcode, retval):
if (d_enter.has_key(cpu) and d_enter[cpu].has_key(opcode)):
diff = nsecs(sec, nsec) - d_enter[cpu][opcode]
if (output.has_key(opcode)):
output[opcode]['time'] += diff
output[opcode]['cnt'] += 1
if (output[opcode]['min'] > diff):
output[opcode]['min'] = diff
if (output[opcode]['max'] < diff):
output[opcode]['max'] = diff
else:
output[opcode] = {
'time': diff,
'cnt': 1,
'min': diff,
'max': diff,
}
del d_enter[cpu][opcode]
# else:
# print "Can't find matching hcall_enter event. Ignoring sample"
def powerpc__hcall_entry(event_name, context, cpu, sec, nsec, pid, comm,
callchain, opcode):
if (d_enter.has_key(cpu)):
d_enter[cpu][opcode] = nsecs(sec, nsec)
else:
d_enter[cpu] = {opcode: nsecs(sec, nsec)}

View File

@ -560,6 +560,7 @@ static int do_test_code_reading(bool try_kcore)
pid = getpid(); pid = getpid();
machine = machine__new_host(); machine = machine__new_host();
machine->env = &perf_env;
ret = machine__create_kernel_maps(machine); ret = machine__create_kernel_maps(machine);
if (ret < 0) { if (ret < 0) {

View File

@ -127,6 +127,22 @@ int test__kmod_path__parse(struct test *t __maybe_unused, int subtest __maybe_un
M("[vdso]", PERF_RECORD_MISC_KERNEL, false); M("[vdso]", PERF_RECORD_MISC_KERNEL, false);
M("[vdso]", PERF_RECORD_MISC_USER, false); M("[vdso]", PERF_RECORD_MISC_USER, false);
T("[vdso32]", true , true , false, false, "[vdso32]", NULL);
T("[vdso32]", false , true , false, false, NULL , NULL);
T("[vdso32]", true , false , false, false, "[vdso32]", NULL);
T("[vdso32]", false , false , false, false, NULL , NULL);
M("[vdso32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
M("[vdso32]", PERF_RECORD_MISC_KERNEL, false);
M("[vdso32]", PERF_RECORD_MISC_USER, false);
T("[vdsox32]", true , true , false, false, "[vdsox32]", NULL);
T("[vdsox32]", false , true , false, false, NULL , NULL);
T("[vdsox32]", true , false , false, false, "[vdsox32]", NULL);
T("[vdsox32]", false , false , false, false, NULL , NULL);
M("[vdsox32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false);
M("[vdsox32]", PERF_RECORD_MISC_KERNEL, false);
M("[vdsox32]", PERF_RECORD_MISC_USER, false);
/* path alloc_name alloc_ext kmod comp name ext */ /* path alloc_name alloc_ext kmod comp name ext */
T("[vsyscall]", true , true , false, false, "[vsyscall]", NULL); T("[vsyscall]", true , true , false, false, "[vsyscall]", NULL);
T("[vsyscall]", false , true , false, false, NULL , NULL); T("[vsyscall]", false , true , false, false, NULL , NULL);

View File

@ -499,7 +499,7 @@ static int test__checkevent_pmu_partial_time_callgraph(struct perf_evlist *evlis
* while this test executes only parse events method. * while this test executes only parse events method.
*/ */
TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period);
TEST_ASSERT_VAL("wrong callgraph", !(PERF_SAMPLE_CALLCHAIN & evsel->attr.sample_type)); TEST_ASSERT_VAL("wrong callgraph", !evsel__has_callchain(evsel));
TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type)); TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type));
/* cpu/config=2,call-graph=no,time=0,period=2000/ */ /* cpu/config=2,call-graph=no,time=0,period=2000/ */
@ -512,7 +512,7 @@ static int test__checkevent_pmu_partial_time_callgraph(struct perf_evlist *evlis
* while this test executes only parse events method. * while this test executes only parse events method.
*/ */
TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period);
TEST_ASSERT_VAL("wrong callgraph", !(PERF_SAMPLE_CALLCHAIN & evsel->attr.sample_type)); TEST_ASSERT_VAL("wrong callgraph", !evsel__has_callchain(evsel));
TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type)); TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type));
return 0; return 0;

View File

@ -7,8 +7,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include "tests.h" #include "tests.h"
#include "util/debug.h"
extern int verbose;
int test__python_use(struct test *test __maybe_unused, int subtest __maybe_unused) int test__python_use(struct test *test __maybe_unused, int subtest __maybe_unused)
{ {

View File

@ -11,7 +11,7 @@
. $(dirname $0)/lib/probe.sh . $(dirname $0)/lib/probe.sh
libc=$(grep -w libc /proc/self/maps | head -1 | sed -r 's/.*[[:space:]](\/.*)/\1/g') libc=$(grep -w libc /proc/self/maps | head -1 | sed -r 's/.*[[:space:]](\/.*)/\1/g')
nm -g $libc 2>/dev/null | fgrep -q inet_pton || exit 254 nm -Dg $libc 2>/dev/null | fgrep -q inet_pton || exit 254
trace_libc_inet_pton_backtrace() { trace_libc_inet_pton_backtrace() {
idx=0 idx=0

View File

@ -29,6 +29,7 @@ struct annotate_browser {
struct rb_node *curr_hot; struct rb_node *curr_hot;
struct annotation_line *selection; struct annotation_line *selection;
struct arch *arch; struct arch *arch;
struct annotation_options *opts;
bool searching_backwards; bool searching_backwards;
char search_bf[128]; char search_bf[128];
}; };
@ -410,7 +411,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
notes = symbol__annotation(dl->ops.target.sym); notes = symbol__annotation(dl->ops.target.sym);
pthread_mutex_lock(&notes->lock); pthread_mutex_lock(&notes->lock);
if (notes->src == NULL && symbol__alloc_hist(dl->ops.target.sym) < 0) { if (!symbol__hists(dl->ops.target.sym, evsel->evlist->nr_entries)) {
pthread_mutex_unlock(&notes->lock); pthread_mutex_unlock(&notes->lock);
ui__warning("Not enough memory for annotating '%s' symbol!\n", ui__warning("Not enough memory for annotating '%s' symbol!\n",
dl->ops.target.sym->name); dl->ops.target.sym->name);
@ -418,7 +419,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
} }
pthread_mutex_unlock(&notes->lock); pthread_mutex_unlock(&notes->lock);
symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt); symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts);
sym_title(ms->sym, ms->map, title, sizeof(title)); sym_title(ms->sym, ms->map, title, sizeof(title));
ui_browser__show_title(&browser->b, title); ui_browser__show_title(&browser->b, title);
return true; return true;
@ -817,24 +818,27 @@ out:
} }
int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
struct hist_browser_timer *hbt) struct hist_browser_timer *hbt,
struct annotation_options *opts)
{ {
return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt); return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt, opts);
} }
int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
struct hist_browser_timer *hbt) struct hist_browser_timer *hbt,
struct annotation_options *opts)
{ {
/* reset abort key so that it can get Ctrl-C as a key */ /* reset abort key so that it can get Ctrl-C as a key */
SLang_reset_tty(); SLang_reset_tty();
SLang_init_tty(0, 0, 0); SLang_init_tty(0, 0, 0);
return map_symbol__tui_annotate(&he->ms, evsel, hbt); return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
} }
int symbol__tui_annotate(struct symbol *sym, struct map *map, int symbol__tui_annotate(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct hist_browser_timer *hbt) struct hist_browser_timer *hbt,
struct annotation_options *opts)
{ {
struct annotation *notes = symbol__annotation(sym); struct annotation *notes = symbol__annotation(sym);
struct map_symbol ms = { struct map_symbol ms = {
@ -851,6 +855,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
.priv = &ms, .priv = &ms,
.use_navkeypressed = true, .use_navkeypressed = true,
}, },
.opts = opts,
}; };
int ret = -1, err; int ret = -1, err;
@ -860,7 +865,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
if (map->dso->annotate_warned) if (map->dso->annotate_warned)
return -1; return -1;
err = symbol__annotate2(sym, map, evsel, &annotation__default_options, &browser.arch); err = symbol__annotate2(sym, map, evsel, opts, &browser.arch);
if (err) { if (err) {
char msg[BUFSIZ]; char msg[BUFSIZ];
symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));

View File

@ -1231,6 +1231,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
int width = browser->b.width; int width = browser->b.width;
char folded_sign = ' '; char folded_sign = ' ';
bool current_entry = ui_browser__is_current_entry(&browser->b, row); bool current_entry = ui_browser__is_current_entry(&browser->b, row);
bool use_callchain = hist_entry__has_callchains(entry) && symbol_conf.use_callchain;
off_t row_offset = entry->row_offset; off_t row_offset = entry->row_offset;
bool first = true; bool first = true;
struct perf_hpp_fmt *fmt; struct perf_hpp_fmt *fmt;
@ -1240,7 +1241,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
browser->selection = &entry->ms; browser->selection = &entry->ms;
} }
if (symbol_conf.use_callchain) { if (use_callchain) {
hist_entry__init_have_children(entry); hist_entry__init_have_children(entry);
folded_sign = hist_entry__folded(entry); folded_sign = hist_entry__folded(entry);
} }
@ -1276,7 +1277,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
} }
if (first) { if (first) {
if (symbol_conf.use_callchain) { if (use_callchain) {
ui_browser__printf(&browser->b, "%c ", folded_sign); ui_browser__printf(&browser->b, "%c ", folded_sign);
width -= 2; width -= 2;
} }
@ -1583,7 +1584,7 @@ hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
int column = 0; int column = 0;
int span = 0; int span = 0;
if (symbol_conf.use_callchain) { if (hists__has_callchains(hists) && symbol_conf.use_callchain) {
ret = scnprintf(buf, size, " "); ret = scnprintf(buf, size, " ");
if (advance_hpp_check(&dummy_hpp, ret)) if (advance_hpp_check(&dummy_hpp, ret))
return ret; return ret;
@ -1987,7 +1988,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
bool first = true; bool first = true;
int ret; int ret;
if (symbol_conf.use_callchain) { if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
folded_sign = hist_entry__folded(he); folded_sign = hist_entry__folded(he);
printed += fprintf(fp, "%c ", folded_sign); printed += fprintf(fp, "%c ", folded_sign);
} }
@ -2175,7 +2176,8 @@ struct hist_browser *hist_browser__new(struct hists *hists)
static struct hist_browser * static struct hist_browser *
perf_evsel_browser__new(struct perf_evsel *evsel, perf_evsel_browser__new(struct perf_evsel *evsel,
struct hist_browser_timer *hbt, struct hist_browser_timer *hbt,
struct perf_env *env) struct perf_env *env,
struct annotation_options *annotation_opts)
{ {
struct hist_browser *browser = hist_browser__new(evsel__hists(evsel)); struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
@ -2183,6 +2185,7 @@ perf_evsel_browser__new(struct perf_evsel *evsel,
browser->hbt = hbt; browser->hbt = hbt;
browser->env = env; browser->env = env;
browser->title = hists_browser__scnprintf_title; browser->title = hists_browser__scnprintf_title;
browser->annotation_opts = annotation_opts;
} }
return browser; return browser;
} }
@ -2336,7 +2339,8 @@ do_annotate(struct hist_browser *browser, struct popup_action *act)
struct hist_entry *he; struct hist_entry *he;
int err; int err;
if (!objdump_path && perf_env__lookup_objdump(browser->env)) if (!browser->annotation_opts->objdump_path &&
perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path))
return 0; return 0;
notes = symbol__annotation(act->ms.sym); notes = symbol__annotation(act->ms.sym);
@ -2344,7 +2348,8 @@ do_annotate(struct hist_browser *browser, struct popup_action *act)
return 0; return 0;
evsel = hists_to_evsel(browser->hists); evsel = hists_to_evsel(browser->hists);
err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt); err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt,
browser->annotation_opts);
he = hist_browser__selected_entry(browser); he = hist_browser__selected_entry(browser);
/* /*
* offer option to annotate the other branch source or target * offer option to annotate the other branch source or target
@ -2667,7 +2672,7 @@ static void hist_browser__update_percent_limit(struct hist_browser *hb,
he->nr_rows = 0; he->nr_rows = 0;
} }
if (!he->leaf || !symbol_conf.use_callchain) if (!he->leaf || !hist_entry__has_callchains(he) || !symbol_conf.use_callchain)
goto next; goto next;
if (callchain_param.mode == CHAIN_GRAPH_REL) { if (callchain_param.mode == CHAIN_GRAPH_REL) {
@ -2697,10 +2702,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
struct hist_browser_timer *hbt, struct hist_browser_timer *hbt,
float min_pcnt, float min_pcnt,
struct perf_env *env, struct perf_env *env,
bool warn_lost_event) bool warn_lost_event,
struct annotation_options *annotation_opts)
{ {
struct hists *hists = evsel__hists(evsel); struct hists *hists = evsel__hists(evsel);
struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env); struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts);
struct branch_info *bi; struct branch_info *bi;
#define MAX_OPTIONS 16 #define MAX_OPTIONS 16
char *options[MAX_OPTIONS]; char *options[MAX_OPTIONS];
@ -3062,6 +3068,7 @@ out:
struct perf_evsel_menu { struct perf_evsel_menu {
struct ui_browser b; struct ui_browser b;
struct perf_evsel *selection; struct perf_evsel *selection;
struct annotation_options *annotation_opts;
bool lost_events, lost_events_warned; bool lost_events, lost_events_warned;
float min_pcnt; float min_pcnt;
struct perf_env *env; struct perf_env *env;
@ -3163,7 +3170,8 @@ browse_hists:
true, hbt, true, hbt,
menu->min_pcnt, menu->min_pcnt,
menu->env, menu->env,
warn_lost_event); warn_lost_event,
menu->annotation_opts);
ui_browser__show_title(&menu->b, title); ui_browser__show_title(&menu->b, title);
switch (key) { switch (key) {
case K_TAB: case K_TAB:
@ -3222,7 +3230,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
struct hist_browser_timer *hbt, struct hist_browser_timer *hbt,
float min_pcnt, float min_pcnt,
struct perf_env *env, struct perf_env *env,
bool warn_lost_event) bool warn_lost_event,
struct annotation_options *annotation_opts)
{ {
struct perf_evsel *pos; struct perf_evsel *pos;
struct perf_evsel_menu menu = { struct perf_evsel_menu menu = {
@ -3237,6 +3246,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
}, },
.min_pcnt = min_pcnt, .min_pcnt = min_pcnt,
.env = env, .env = env,
.annotation_opts = annotation_opts,
}; };
ui_helpline__push("Press ESC to exit"); ui_helpline__push("Press ESC to exit");
@ -3257,7 +3267,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
struct hist_browser_timer *hbt, struct hist_browser_timer *hbt,
float min_pcnt, float min_pcnt,
struct perf_env *env, struct perf_env *env,
bool warn_lost_event) bool warn_lost_event,
struct annotation_options *annotation_opts)
{ {
int nr_entries = evlist->nr_entries; int nr_entries = evlist->nr_entries;
@ -3267,7 +3278,8 @@ single_entry:
return perf_evsel__hists_browse(first, nr_entries, help, return perf_evsel__hists_browse(first, nr_entries, help,
false, hbt, min_pcnt, false, hbt, min_pcnt,
env, warn_lost_event); env, warn_lost_event,
annotation_opts);
} }
if (symbol_conf.event_group) { if (symbol_conf.event_group) {
@ -3285,5 +3297,6 @@ single_entry:
return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
hbt, min_pcnt, env, hbt, min_pcnt, env,
warn_lost_event); warn_lost_event,
annotation_opts);
} }

View File

@ -4,6 +4,8 @@
#include "ui/browser.h" #include "ui/browser.h"
struct annotation_options;
struct hist_browser { struct hist_browser {
struct ui_browser b; struct ui_browser b;
struct hists *hists; struct hists *hists;
@ -12,6 +14,7 @@ struct hist_browser {
struct hist_browser_timer *hbt; struct hist_browser_timer *hbt;
struct pstack *pstack; struct pstack *pstack;
struct perf_env *env; struct perf_env *env;
struct annotation_options *annotation_opts;
int print_seq; int print_seq;
bool show_dso; bool show_dso;
bool show_headers; bool show_headers;

View File

@ -169,7 +169,7 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map,
if (map->dso->annotate_warned) if (map->dso->annotate_warned)
return -1; return -1;
err = symbol__annotate(sym, map, evsel, 0, NULL); err = symbol__annotate(sym, map, evsel, 0, &annotation__default_options, NULL);
if (err) { if (err) {
char msg[BUFSIZ]; char msg[BUFSIZ];
symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));

View File

@ -382,7 +382,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
gtk_tree_store_set(store, &iter, col_idx++, s, -1); gtk_tree_store_set(store, &iter, col_idx++, s, -1);
} }
if (symbol_conf.use_callchain && hists__has(hists, sym)) { if (hists__has_callchains(hists) &&
symbol_conf.use_callchain && hists__has(hists, sym)) {
if (callchain_param.mode == CHAIN_GRAPH_REL) if (callchain_param.mode == CHAIN_GRAPH_REL)
total = symbol_conf.cumulate_callchain ? total = symbol_conf.cumulate_callchain ?
h->stat_acc->period : h->stat.period; h->stat_acc->period : h->stat.period;
@ -479,7 +480,7 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists,
} }
} }
if (symbol_conf.use_callchain && he->leaf) { if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
if (callchain_param.mode == CHAIN_GRAPH_REL) if (callchain_param.mode == CHAIN_GRAPH_REL)
total = symbol_conf.cumulate_callchain ? total = symbol_conf.cumulate_callchain ?
he->stat_acc->period : he->stat.period; he->stat_acc->period : he->stat.period;

View File

@ -207,7 +207,7 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
if (ret) if (ret)
return ret; return ret;
if (a->thread != b->thread || !symbol_conf.use_callchain) if (a->thread != b->thread || !hist_entry__has_callchains(a) || !symbol_conf.use_callchain)
return 0; return 0;
ret = b->callchain->max_depth - a->callchain->max_depth; ret = b->callchain->max_depth - a->callchain->max_depth;

View File

@ -516,7 +516,7 @@ static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
} }
printed += putc('\n', fp); printed += putc('\n', fp);
if (symbol_conf.use_callchain && he->leaf) { if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
u64 total = hists__total_period(hists); u64 total = hists__total_period(hists);
printed += hist_entry_callchain__fprintf(he, total, 0, fp); printed += hist_entry_callchain__fprintf(he, total, 0, fp);
@ -550,7 +550,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
ret = fprintf(fp, "%s\n", bf); ret = fprintf(fp, "%s\n", bf);
if (use_callchain) if (hist_entry__has_callchains(he) && use_callchain)
callchain_ret = hist_entry_callchain__fprintf(he, total_period, callchain_ret = hist_entry_callchain__fprintf(he, total_period,
0, fp); 0, fp);

View File

@ -24,7 +24,6 @@ libperf-y += libstring.o
libperf-y += bitmap.o libperf-y += bitmap.o
libperf-y += hweight.o libperf-y += hweight.o
libperf-y += smt.o libperf-y += smt.o
libperf-y += quote.o
libperf-y += strbuf.o libperf-y += strbuf.o
libperf-y += string.o libperf-y += string.o
libperf-y += strlist.o libperf-y += strlist.o

View File

@ -21,6 +21,7 @@
#include "debug.h" #include "debug.h"
#include "annotate.h" #include "annotate.h"
#include "evsel.h" #include "evsel.h"
#include "evlist.h"
#include "block-range.h" #include "block-range.h"
#include "string2.h" #include "string2.h"
#include "arch/common.h" #include "arch/common.h"
@ -46,11 +47,10 @@
struct annotation_options annotation__default_options = { struct annotation_options annotation__default_options = {
.use_offset = true, .use_offset = true,
.jump_arrows = true, .jump_arrows = true,
.annotate_src = true,
.offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS,
}; };
const char *disassembler_style;
const char *objdump_path;
static regex_t file_lineno; static regex_t file_lineno;
static struct ins_ops *ins__find(struct arch *arch, const char *name); static struct ins_ops *ins__find(struct arch *arch, const char *name);
@ -678,10 +678,28 @@ static struct arch *arch__find(const char *name)
return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp); return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp);
} }
int symbol__alloc_hist(struct symbol *sym) static struct annotated_source *annotated_source__new(void)
{
struct annotated_source *src = zalloc(sizeof(*src));
if (src != NULL)
INIT_LIST_HEAD(&src->source);
return src;
}
static __maybe_unused void annotated_source__delete(struct annotated_source *src)
{
if (src == NULL)
return;
zfree(&src->histograms);
zfree(&src->cycles_hist);
free(src);
}
static int annotated_source__alloc_histograms(struct annotated_source *src,
size_t size, int nr_hists)
{ {
struct annotation *notes = symbol__annotation(sym);
size_t size = symbol__size(sym);
size_t sizeof_sym_hist; size_t sizeof_sym_hist;
/* /*
@ -701,17 +719,13 @@ int symbol__alloc_hist(struct symbol *sym)
sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(struct sym_hist_entry)); sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(struct sym_hist_entry));
/* Check for overflow in zalloc argument */ /* Check for overflow in zalloc argument */
if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src)) if (sizeof_sym_hist > SIZE_MAX / nr_hists)
/ symbol_conf.nr_events)
return -1; return -1;
notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); src->sizeof_sym_hist = sizeof_sym_hist;
if (notes->src == NULL) src->nr_histograms = nr_hists;
return -1; src->histograms = calloc(nr_hists, sizeof_sym_hist) ;
notes->src->sizeof_sym_hist = sizeof_sym_hist; return src->histograms ? 0 : -1;
notes->src->nr_histograms = symbol_conf.nr_events;
INIT_LIST_HEAD(&notes->src->source);
return 0;
} }
/* The cycles histogram is lazily allocated. */ /* The cycles histogram is lazily allocated. */
@ -741,14 +755,11 @@ void symbol__annotate_zero_histograms(struct symbol *sym)
pthread_mutex_unlock(&notes->lock); pthread_mutex_unlock(&notes->lock);
} }
static int __symbol__account_cycles(struct annotation *notes, static int __symbol__account_cycles(struct cyc_hist *ch,
u64 start, u64 start,
unsigned offset, unsigned cycles, unsigned offset, unsigned cycles,
unsigned have_start) unsigned have_start)
{ {
struct cyc_hist *ch;
ch = notes->src->cycles_hist;
/* /*
* For now we can only account one basic block per * For now we can only account one basic block per
* final jump. But multiple could be overlapping. * final jump. But multiple could be overlapping.
@ -791,7 +802,7 @@ static int __symbol__account_cycles(struct annotation *notes,
} }
static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
struct annotation *notes, int evidx, u64 addr, struct annotated_source *src, int evidx, u64 addr,
struct perf_sample *sample) struct perf_sample *sample)
{ {
unsigned offset; unsigned offset;
@ -807,7 +818,12 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
} }
offset = addr - sym->start; offset = addr - sym->start;
h = annotation__histogram(notes, evidx); h = annotated_source__histogram(src, evidx);
if (h == NULL) {
pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n",
__func__, __LINE__, sym->name, sym->start, addr, sym->end, sym->type == STT_FUNC);
return -ENOMEM;
}
h->nr_samples++; h->nr_samples++;
h->addr[offset].nr_samples++; h->addr[offset].nr_samples++;
h->period += sample->period; h->period += sample->period;
@ -820,45 +836,69 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
return 0; return 0;
} }
static struct annotation *symbol__get_annotation(struct symbol *sym, bool cycles) static struct cyc_hist *symbol__cycles_hist(struct symbol *sym)
{ {
struct annotation *notes = symbol__annotation(sym); struct annotation *notes = symbol__annotation(sym);
if (notes->src == NULL) { if (notes->src == NULL) {
if (symbol__alloc_hist(sym) < 0) notes->src = annotated_source__new();
if (notes->src == NULL)
return NULL; return NULL;
goto alloc_cycles_hist;
} }
if (!notes->src->cycles_hist && cycles) {
if (symbol__alloc_hist_cycles(sym) < 0) if (!notes->src->cycles_hist) {
alloc_cycles_hist:
symbol__alloc_hist_cycles(sym);
}
return notes->src->cycles_hist;
}
struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists)
{
struct annotation *notes = symbol__annotation(sym);
if (notes->src == NULL) {
notes->src = annotated_source__new();
if (notes->src == NULL)
return NULL; return NULL;
goto alloc_histograms;
} }
return notes;
if (notes->src->histograms == NULL) {
alloc_histograms:
annotated_source__alloc_histograms(notes->src, symbol__size(sym),
nr_hists);
}
return notes->src;
} }
static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
int evidx, u64 addr, struct perf_evsel *evsel, u64 addr,
struct perf_sample *sample) struct perf_sample *sample)
{ {
struct annotation *notes; struct annotated_source *src;
if (sym == NULL) if (sym == NULL)
return 0; return 0;
notes = symbol__get_annotation(sym, false); src = symbol__hists(sym, evsel->evlist->nr_entries);
if (notes == NULL) if (src == NULL)
return -ENOMEM; return -ENOMEM;
return __symbol__inc_addr_samples(sym, map, notes, evidx, addr, sample); return __symbol__inc_addr_samples(sym, map, src, evsel->idx, addr, sample);
} }
static int symbol__account_cycles(u64 addr, u64 start, static int symbol__account_cycles(u64 addr, u64 start,
struct symbol *sym, unsigned cycles) struct symbol *sym, unsigned cycles)
{ {
struct annotation *notes; struct cyc_hist *cycles_hist;
unsigned offset; unsigned offset;
if (sym == NULL) if (sym == NULL)
return 0; return 0;
notes = symbol__get_annotation(sym, true); cycles_hist = symbol__cycles_hist(sym);
if (notes == NULL) if (cycles_hist == NULL)
return -ENOMEM; return -ENOMEM;
if (addr < sym->start || addr >= sym->end) if (addr < sym->start || addr >= sym->end)
return -ERANGE; return -ERANGE;
@ -870,7 +910,7 @@ static int symbol__account_cycles(u64 addr, u64 start,
start = 0; start = 0;
} }
offset = addr - sym->start; offset = addr - sym->start;
return __symbol__account_cycles(notes, return __symbol__account_cycles(cycles_hist,
start ? start - sym->start : 0, start ? start - sym->start : 0,
offset, cycles, offset, cycles,
!!start); !!start);
@ -974,15 +1014,15 @@ void annotation__compute_ipc(struct annotation *notes, size_t size)
} }
int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,
int evidx) struct perf_evsel *evsel)
{ {
return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr, sample); return symbol__inc_addr_samples(ams->sym, ams->map, evsel, ams->al_addr, sample);
} }
int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample,
int evidx, u64 ip) struct perf_evsel *evsel, u64 ip)
{ {
return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip, sample); return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evsel, ip, sample);
} }
static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms) static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms)
@ -1031,6 +1071,7 @@ struct annotate_args {
struct arch *arch; struct arch *arch;
struct map_symbol ms; struct map_symbol ms;
struct perf_evsel *evsel; struct perf_evsel *evsel;
struct annotation_options *options;
s64 offset; s64 offset;
char *line; char *line;
int line_nr; int line_nr;
@ -1572,6 +1613,7 @@ fallback:
static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
{ {
struct annotation_options *opts = args->options;
struct map *map = args->ms.map; struct map *map = args->ms.map;
struct dso *dso = map->dso; struct dso *dso = map->dso;
char *command; char *command;
@ -1619,13 +1661,13 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
"%s %s%s --start-address=0x%016" PRIx64 "%s %s%s --start-address=0x%016" PRIx64
" --stop-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64
" -l -d %s %s -C \"%s\" 2>/dev/null|grep -v \"%s:\"|expand", " -l -d %s %s -C \"%s\" 2>/dev/null|grep -v \"%s:\"|expand",
objdump_path ? objdump_path : "objdump", opts->objdump_path ?: "objdump",
disassembler_style ? "-M " : "", opts->disassembler_style ? "-M " : "",
disassembler_style ? disassembler_style : "", opts->disassembler_style ?: "",
map__rip_2objdump(map, sym->start), map__rip_2objdump(map, sym->start),
map__rip_2objdump(map, sym->end), map__rip_2objdump(map, sym->end),
symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", opts->show_asm_raw ? "" : "--no-show-raw",
symbol_conf.annotate_src ? "-S" : "", opts->annotate_src ? "-S" : "",
symfs_filename, symfs_filename); symfs_filename, symfs_filename);
if (err < 0) { if (err < 0) {
@ -1767,11 +1809,13 @@ void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel)
int symbol__annotate(struct symbol *sym, struct map *map, int symbol__annotate(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, size_t privsize, struct perf_evsel *evsel, size_t privsize,
struct annotation_options *options,
struct arch **parch) struct arch **parch)
{ {
struct annotate_args args = { struct annotate_args args = {
.privsize = privsize, .privsize = privsize,
.evsel = evsel, .evsel = evsel,
.options = options,
}; };
struct perf_env *env = perf_evsel__env(evsel); struct perf_env *env = perf_evsel__env(evsel);
const char *arch_name = perf_env__arch(env); const char *arch_name = perf_env__arch(env);
@ -1949,8 +1993,8 @@ static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start)
} }
int symbol__annotate_printf(struct symbol *sym, struct map *map, int symbol__annotate_printf(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, bool full_paths, struct perf_evsel *evsel,
int min_pcnt, int max_lines, int context) struct annotation_options *opts)
{ {
struct dso *dso = map->dso; struct dso *dso = map->dso;
char *filename; char *filename;
@ -1962,6 +2006,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
u64 start = map__rip_2objdump(map, sym->start); u64 start = map__rip_2objdump(map, sym->start);
int printed = 2, queue_len = 0, addr_fmt_width; int printed = 2, queue_len = 0, addr_fmt_width;
int more = 0; int more = 0;
bool context = opts->context;
u64 len; u64 len;
int width = symbol_conf.show_total_period ? 12 : 8; int width = symbol_conf.show_total_period ? 12 : 8;
int graph_dotted_len; int graph_dotted_len;
@ -1971,7 +2016,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
if (!filename) if (!filename)
return -ENOMEM; return -ENOMEM;
if (full_paths) if (opts->full_path)
d_filename = filename; d_filename = filename;
else else
d_filename = basename(filename); d_filename = basename(filename);
@ -2006,7 +2051,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
} }
err = annotation_line__print(pos, sym, start, evsel, len, err = annotation_line__print(pos, sym, start, evsel, len,
min_pcnt, printed, max_lines, opts->min_pcnt, printed, opts->max_lines,
queue, addr_fmt_width); queue, addr_fmt_width);
switch (err) { switch (err) {
@ -2339,20 +2384,19 @@ static void symbol__calc_lines(struct symbol *sym, struct map *map,
} }
int symbol__tty_annotate2(struct symbol *sym, struct map *map, int symbol__tty_annotate2(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, bool print_lines, struct perf_evsel *evsel,
bool full_paths) struct annotation_options *opts)
{ {
struct dso *dso = map->dso; struct dso *dso = map->dso;
struct rb_root source_line = RB_ROOT; struct rb_root source_line = RB_ROOT;
struct annotation_options opts = annotation__default_options;
struct annotation *notes = symbol__annotation(sym); struct annotation *notes = symbol__annotation(sym);
char buf[1024]; char buf[1024];
if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0)
return -1; return -1;
if (print_lines) { if (opts->print_lines) {
srcline_full_filename = full_paths; srcline_full_filename = opts->full_path;
symbol__calc_lines(sym, map, &source_line); symbol__calc_lines(sym, map, &source_line);
print_summary(&source_line, dso->long_name); print_summary(&source_line, dso->long_name);
} }
@ -2367,25 +2411,24 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map,
} }
int symbol__tty_annotate(struct symbol *sym, struct map *map, int symbol__tty_annotate(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, bool print_lines, struct perf_evsel *evsel,
bool full_paths, int min_pcnt, int max_lines) struct annotation_options *opts)
{ {
struct dso *dso = map->dso; struct dso *dso = map->dso;
struct rb_root source_line = RB_ROOT; struct rb_root source_line = RB_ROOT;
if (symbol__annotate(sym, map, evsel, 0, NULL) < 0) if (symbol__annotate(sym, map, evsel, 0, opts, NULL) < 0)
return -1; return -1;
symbol__calc_percent(sym, evsel); symbol__calc_percent(sym, evsel);
if (print_lines) { if (opts->print_lines) {
srcline_full_filename = full_paths; srcline_full_filename = opts->full_path;
symbol__calc_lines(sym, map, &source_line); symbol__calc_lines(sym, map, &source_line);
print_summary(&source_line, dso->long_name); print_summary(&source_line, dso->long_name);
} }
symbol__annotate_printf(sym, map, evsel, full_paths, symbol__annotate_printf(sym, map, evsel, opts);
min_pcnt, max_lines, 0);
annotated_source__purge(symbol__annotation(sym)->src); annotated_source__purge(symbol__annotation(sym)->src);
@ -2620,7 +2663,7 @@ int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *ev
if (perf_evsel__is_group_event(evsel)) if (perf_evsel__is_group_event(evsel))
nr_pcnt = evsel->nr_members; nr_pcnt = evsel->nr_members;
err = symbol__annotate(sym, map, evsel, 0, parch); err = symbol__annotate(sym, map, evsel, 0, options, parch);
if (err) if (err)
goto out_free_offsets; goto out_free_offsets;

View File

@ -67,12 +67,21 @@ struct annotation_options {
bool hide_src_code, bool hide_src_code,
use_offset, use_offset,
jump_arrows, jump_arrows,
print_lines,
full_path,
show_linenr, show_linenr,
show_nr_jumps, show_nr_jumps,
show_nr_samples, show_nr_samples,
show_total_period, show_total_period,
show_minmax_cycle; show_minmax_cycle,
show_asm_raw,
annotate_src;
u8 offset_level; u8 offset_level;
int min_pcnt;
int max_lines;
int context;
const char *objdump_path;
const char *disassembler_style;
}; };
enum { enum {
@ -201,7 +210,11 @@ struct cyc_hist {
/** struct annotated_source - symbols with hits have this attached as in sannotation /** struct annotated_source - symbols with hits have this attached as in sannotation
* *
* @histogram: Array of addr hit histograms per event being monitored * @histograms: Array of addr hit histograms per event being monitored
* nr_histograms: This may not be the same as evsel->evlist->nr_entries if
* we have more than a group in a evlist, where we will want
* to see each group separately, that is why symbol__annotate2()
* sets src->nr_histograms to evsel->nr_members.
* @lines: If 'print_lines' is specified, per source code line percentages * @lines: If 'print_lines' is specified, per source code line percentages
* @source: source parsed from a disassembler like objdump -dS * @source: source parsed from a disassembler like objdump -dS
* @cyc_hist: Average cycles per basic block * @cyc_hist: Average cycles per basic block
@ -217,7 +230,7 @@ struct annotated_source {
int nr_histograms; int nr_histograms;
size_t sizeof_sym_hist; size_t sizeof_sym_hist;
struct cyc_hist *cycles_hist; struct cyc_hist *cycles_hist;
struct sym_hist histograms[0]; struct sym_hist *histograms;
}; };
struct annotation { struct annotation {
@ -267,10 +280,14 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym)
void annotation__update_column_widths(struct annotation *notes); void annotation__update_column_widths(struct annotation *notes);
void annotation__init_column_widths(struct annotation *notes, struct symbol *sym); void annotation__init_column_widths(struct annotation *notes, struct symbol *sym);
static inline struct sym_hist *annotated_source__histogram(struct annotated_source *src, int idx)
{
return ((void *)src->histograms) + (src->sizeof_sym_hist * idx);
}
static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx)
{ {
return (((void *)&notes->src->histograms) + return annotated_source__histogram(notes->src, idx);
(notes->src->sizeof_sym_hist * idx));
} }
static inline struct annotation *symbol__annotation(struct symbol *sym) static inline struct annotation *symbol__annotation(struct symbol *sym)
@ -279,20 +296,21 @@ static inline struct annotation *symbol__annotation(struct symbol *sym)
} }
int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,
int evidx); struct perf_evsel *evsel);
int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
struct addr_map_symbol *start, struct addr_map_symbol *start,
unsigned cycles); unsigned cycles);
int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample,
int evidx, u64 addr); struct perf_evsel *evsel, u64 addr);
int symbol__alloc_hist(struct symbol *sym); struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists);
void symbol__annotate_zero_histograms(struct symbol *sym); void symbol__annotate_zero_histograms(struct symbol *sym);
int symbol__annotate(struct symbol *sym, struct map *map, int symbol__annotate(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, size_t privsize, struct perf_evsel *evsel, size_t privsize,
struct annotation_options *options,
struct arch **parch); struct arch **parch);
int symbol__annotate2(struct symbol *sym, struct map *map, int symbol__annotate2(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, struct perf_evsel *evsel,
@ -320,8 +338,8 @@ int symbol__strerror_disassemble(struct symbol *sym, struct map *map,
int errnum, char *buf, size_t buflen); int errnum, char *buf, size_t buflen);
int symbol__annotate_printf(struct symbol *sym, struct map *map, int symbol__annotate_printf(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, bool full_paths, struct perf_evsel *evsel,
int min_pcnt, int max_lines, int context); struct annotation_options *options);
int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp); int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp);
void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
@ -332,30 +350,27 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel)
bool ui__has_annotation(void); bool ui__has_annotation(void);
int symbol__tty_annotate(struct symbol *sym, struct map *map, int symbol__tty_annotate(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, bool print_lines, struct perf_evsel *evsel, struct annotation_options *opts);
bool full_paths, int min_pcnt, int max_lines);
int symbol__tty_annotate2(struct symbol *sym, struct map *map, int symbol__tty_annotate2(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, bool print_lines, struct perf_evsel *evsel, struct annotation_options *opts);
bool full_paths);
#ifdef HAVE_SLANG_SUPPORT #ifdef HAVE_SLANG_SUPPORT
int symbol__tui_annotate(struct symbol *sym, struct map *map, int symbol__tui_annotate(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct hist_browser_timer *hbt); struct hist_browser_timer *hbt,
struct annotation_options *opts);
#else #else
static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
struct map *map __maybe_unused, struct map *map __maybe_unused,
struct perf_evsel *evsel __maybe_unused, struct perf_evsel *evsel __maybe_unused,
struct hist_browser_timer *hbt struct hist_browser_timer *hbt __maybe_unused,
__maybe_unused) struct annotation_options *opts __maybe_unused)
{ {
return 0; return 0;
} }
#endif #endif
extern const char *disassembler_style;
void annotation_config__init(void); void annotation_config__init(void);
#endif /* __PERF_ANNOTATE_H */ #endif /* __PERF_ANNOTATE_H */

View File

@ -93,20 +93,17 @@ static int open_cgroup(const char *name)
static struct cgroup *evlist__find_cgroup(struct perf_evlist *evlist, const char *str) static struct cgroup *evlist__find_cgroup(struct perf_evlist *evlist, const char *str)
{ {
struct perf_evsel *counter; struct perf_evsel *counter;
struct cgroup *cgrp = NULL;
/* /*
* check if cgrp is already defined, if so we reuse it * check if cgrp is already defined, if so we reuse it
*/ */
evlist__for_each_entry(evlist, counter) { evlist__for_each_entry(evlist, counter) {
if (!counter->cgrp) if (!counter->cgrp)
continue; continue;
if (!strcmp(counter->cgrp->name, str)) { if (!strcmp(counter->cgrp->name, str))
cgrp = cgroup__get(counter->cgrp); return cgroup__get(counter->cgrp);
break;
}
} }
return cgrp; return NULL;
} }
static struct cgroup *cgroup__new(const char *name) static struct cgroup *cgroup__new(const char *name)

View File

@ -354,6 +354,8 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) || if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) ||
(strncmp(name, "[guest.kernel.kallsyms", 22) == 0) || (strncmp(name, "[guest.kernel.kallsyms", 22) == 0) ||
(strncmp(name, "[vdso]", 6) == 0) || (strncmp(name, "[vdso]", 6) == 0) ||
(strncmp(name, "[vdso32]", 8) == 0) ||
(strncmp(name, "[vdsox32]", 9) == 0) ||
(strncmp(name, "[vsyscall]", 10) == 0)) { (strncmp(name, "[vsyscall]", 10) == 0)) {
m->kmod = false; m->kmod = false;

View File

@ -2197,7 +2197,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
} }
} }
if (type & PERF_SAMPLE_CALLCHAIN) { if (evsel__has_callchain(evsel)) {
const u64 max_callchain_nr = UINT64_MAX / sizeof(u64); const u64 max_callchain_nr = UINT64_MAX / sizeof(u64);
OVERFLOW_CHECK_u64(array); OVERFLOW_CHECK_u64(array);
@ -2857,7 +2857,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
"Hint: Try again after reducing the number of events.\n" "Hint: Try again after reducing the number of events.\n"
"Hint: Try increasing the limit with 'ulimit -n <limit>'"); "Hint: Try increasing the limit with 'ulimit -n <limit>'");
case ENOMEM: case ENOMEM:
if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0 && if (evsel__has_callchain(evsel) &&
access("/proc/sys/kernel/perf_event_max_stack", F_OK) == 0) access("/proc/sys/kernel/perf_event_max_stack", F_OK) == 0)
return scnprintf(msg, size, return scnprintf(msg, size,
"Not enough memory to setup event with callchain.\n" "Not enough memory to setup event with callchain.\n"

View File

@ -459,6 +459,11 @@ static inline bool perf_evsel__has_branch_callstack(const struct perf_evsel *evs
return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK;
} }
static inline bool evsel__has_callchain(const struct perf_evsel *evsel)
{
return (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0;
}
typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *);
int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr,

View File

@ -1459,8 +1459,24 @@ static void print_cmdline(struct feat_fd *ff, FILE *fp)
fprintf(fp, "# cmdline : "); fprintf(fp, "# cmdline : ");
for (i = 0; i < nr; i++) for (i = 0; i < nr; i++) {
fprintf(fp, "%s ", ff->ph->env.cmdline_argv[i]); char *argv_i = strdup(ff->ph->env.cmdline_argv[i]);
if (!argv_i) {
fprintf(fp, "%s ", ff->ph->env.cmdline_argv[i]);
} else {
char *mem = argv_i;
do {
char *quote = strchr(argv_i, '\'');
if (!quote)
break;
*quote++ = '\0';
fprintf(fp, "%s\\\'", argv_i);
argv_i = quote;
} while (1);
fprintf(fp, "%s ", argv_i);
free(mem);
}
}
fputc('\n', fp); fputc('\n', fp);
} }
@ -3312,8 +3328,6 @@ int perf_session__read_header(struct perf_session *session)
lseek(fd, tmp, SEEK_SET); lseek(fd, tmp, SEEK_SET);
} }
symbol_conf.nr_events = nr_attrs;
perf_header__process_sections(header, fd, &session->tevent, perf_header__process_sections(header, fd, &session->tevent,
perf_file_section__process); perf_file_section__process);
@ -3739,8 +3753,6 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]); perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]);
} }
symbol_conf.nr_events = evlist->nr_entries;
return 0; return 0;
} }

View File

@ -410,7 +410,7 @@ static int hist_entry__init(struct hist_entry *he,
map__get(he->mem_info->daddr.map); map__get(he->mem_info->daddr.map);
} }
if (symbol_conf.use_callchain) if (hist_entry__has_callchains(he) && symbol_conf.use_callchain)
callchain_init(he->callchain); callchain_init(he->callchain);
if (he->raw_data) { if (he->raw_data) {
@ -492,7 +492,7 @@ static u8 symbol__parent_filter(const struct symbol *parent)
static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period) static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period)
{ {
if (!symbol_conf.use_callchain) if (!hist_entry__has_callchains(he) || !symbol_conf.use_callchain)
return; return;
he->hists->callchain_period += period; he->hists->callchain_period += period;
@ -986,7 +986,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
iter->he = he; iter->he = he;
he_cache[iter->curr++] = he; he_cache[iter->curr++] = he;
if (symbol_conf.use_callchain) if (hist_entry__has_callchains(he) && symbol_conf.use_callchain)
callchain_append(he->callchain, &cursor, sample->period); callchain_append(he->callchain, &cursor, sample->period);
return 0; return 0;
} }
@ -1039,7 +1039,7 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
int err, err2; int err, err2;
struct map *alm = NULL; struct map *alm = NULL;
if (al && al->map) if (al)
alm = map__get(al->map); alm = map__get(al->map);
err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent,
@ -1373,7 +1373,8 @@ static int hists__hierarchy_insert_entry(struct hists *hists,
if (new_he) { if (new_he) {
new_he->leaf = true; new_he->leaf = true;
if (symbol_conf.use_callchain) { if (hist_entry__has_callchains(new_he) &&
symbol_conf.use_callchain) {
callchain_cursor_reset(&callchain_cursor); callchain_cursor_reset(&callchain_cursor);
if (callchain_merge(&callchain_cursor, if (callchain_merge(&callchain_cursor,
new_he->callchain, new_he->callchain,
@ -1414,7 +1415,7 @@ static int hists__collapse_insert_entry(struct hists *hists,
if (symbol_conf.cumulate_callchain) if (symbol_conf.cumulate_callchain)
he_stat__add_stat(iter->stat_acc, he->stat_acc); he_stat__add_stat(iter->stat_acc, he->stat_acc);
if (symbol_conf.use_callchain) { if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
callchain_cursor_reset(&callchain_cursor); callchain_cursor_reset(&callchain_cursor);
if (callchain_merge(&callchain_cursor, if (callchain_merge(&callchain_cursor,
iter->callchain, iter->callchain,
@ -1757,7 +1758,7 @@ void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *pro
bool use_callchain; bool use_callchain;
if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph) if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph)
use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN; use_callchain = evsel__has_callchain(evsel);
else else
use_callchain = symbol_conf.use_callchain; use_callchain = symbol_conf.use_callchain;

View File

@ -220,6 +220,12 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel)
return &hevsel->hists; return &hevsel->hists;
} }
static __pure inline bool hists__has_callchains(struct hists *hists)
{
const struct perf_evsel *evsel = hists_to_evsel(hists);
return evsel__has_callchain(evsel);
}
int hists__init(void); int hists__init(void);
int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list); int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list);
@ -419,19 +425,24 @@ struct hist_browser_timer {
int refresh; int refresh;
}; };
struct annotation_options;
#ifdef HAVE_SLANG_SUPPORT #ifdef HAVE_SLANG_SUPPORT
#include "../ui/keysyms.h" #include "../ui/keysyms.h"
int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
struct hist_browser_timer *hbt); struct hist_browser_timer *hbt,
struct annotation_options *annotation_opts);
int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
struct hist_browser_timer *hbt); struct hist_browser_timer *hbt,
struct annotation_options *annotation_opts);
int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
struct hist_browser_timer *hbt, struct hist_browser_timer *hbt,
float min_pcnt, float min_pcnt,
struct perf_env *env, struct perf_env *env,
bool warn_lost_event); bool warn_lost_event,
struct annotation_options *annotation_options);
int script_browse(const char *script_opt); int script_browse(const char *script_opt);
#else #else
static inline static inline
@ -440,20 +451,23 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
struct hist_browser_timer *hbt __maybe_unused, struct hist_browser_timer *hbt __maybe_unused,
float min_pcnt __maybe_unused, float min_pcnt __maybe_unused,
struct perf_env *env __maybe_unused, struct perf_env *env __maybe_unused,
bool warn_lost_event __maybe_unused) bool warn_lost_event __maybe_unused,
struct annotation_options *annotation_options __maybe_unused)
{ {
return 0; return 0;
} }
static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused, static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused,
struct perf_evsel *evsel __maybe_unused, struct perf_evsel *evsel __maybe_unused,
struct hist_browser_timer *hbt __maybe_unused) struct hist_browser_timer *hbt __maybe_unused,
struct annotation_options *annotation_options __maybe_unused)
{ {
return 0; return 0;
} }
static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused,
struct perf_evsel *evsel __maybe_unused, struct perf_evsel *evsel __maybe_unused,
struct hist_browser_timer *hbt __maybe_unused) struct hist_browser_timer *hbt __maybe_unused,
struct annotation_options *annotation_opts __maybe_unused)
{ {
return 0; return 0;
} }

View File

@ -113,6 +113,7 @@ struct intel_pt_decoder {
bool have_cyc; bool have_cyc;
bool fixup_last_mtc; bool fixup_last_mtc;
bool have_last_ip; bool have_last_ip;
enum intel_pt_param_flags flags;
uint64_t pos; uint64_t pos;
uint64_t last_ip; uint64_t last_ip;
uint64_t ip; uint64_t ip;
@ -226,6 +227,8 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params)
decoder->return_compression = params->return_compression; decoder->return_compression = params->return_compression;
decoder->branch_enable = params->branch_enable; decoder->branch_enable = params->branch_enable;
decoder->flags = params->flags;
decoder->period = params->period; decoder->period = params->period;
decoder->period_type = params->period_type; decoder->period_type = params->period_type;
@ -1097,6 +1100,15 @@ static bool intel_pt_fup_event(struct intel_pt_decoder *decoder)
return ret; return ret;
} }
static inline bool intel_pt_fup_with_nlip(struct intel_pt_decoder *decoder,
struct intel_pt_insn *intel_pt_insn,
uint64_t ip, int err)
{
return decoder->flags & INTEL_PT_FUP_WITH_NLIP && !err &&
intel_pt_insn->branch == INTEL_PT_BR_INDIRECT &&
ip == decoder->ip + intel_pt_insn->length;
}
static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) static int intel_pt_walk_fup(struct intel_pt_decoder *decoder)
{ {
struct intel_pt_insn intel_pt_insn; struct intel_pt_insn intel_pt_insn;
@ -1109,10 +1121,11 @@ static int intel_pt_walk_fup(struct intel_pt_decoder *decoder)
err = intel_pt_walk_insn(decoder, &intel_pt_insn, ip); err = intel_pt_walk_insn(decoder, &intel_pt_insn, ip);
if (err == INTEL_PT_RETURN) if (err == INTEL_PT_RETURN)
return 0; return 0;
if (err == -EAGAIN) { if (err == -EAGAIN ||
intel_pt_fup_with_nlip(decoder, &intel_pt_insn, ip, err)) {
if (intel_pt_fup_event(decoder)) if (intel_pt_fup_event(decoder))
return 0; return 0;
return err; return -EAGAIN;
} }
decoder->set_fup_tx_flags = false; decoder->set_fup_tx_flags = false;
if (err) if (err)
@ -1376,7 +1389,6 @@ static int intel_pt_overflow(struct intel_pt_decoder *decoder)
{ {
intel_pt_log("ERROR: Buffer overflow\n"); intel_pt_log("ERROR: Buffer overflow\n");
intel_pt_clear_tx_flags(decoder); intel_pt_clear_tx_flags(decoder);
decoder->have_tma = false;
decoder->cbr = 0; decoder->cbr = 0;
decoder->timestamp_insn_cnt = 0; decoder->timestamp_insn_cnt = 0;
decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC;
@ -1604,7 +1616,6 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder)
case INTEL_PT_PSB: case INTEL_PT_PSB:
case INTEL_PT_TSC: case INTEL_PT_TSC:
case INTEL_PT_TMA: case INTEL_PT_TMA:
case INTEL_PT_CBR:
case INTEL_PT_MODE_TSX: case INTEL_PT_MODE_TSX:
case INTEL_PT_BAD: case INTEL_PT_BAD:
case INTEL_PT_PSBEND: case INTEL_PT_PSBEND:
@ -1620,6 +1631,10 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder)
decoder->pkt_step = 0; decoder->pkt_step = 0;
return -ENOENT; return -ENOENT;
case INTEL_PT_CBR:
intel_pt_calc_cbr(decoder);
break;
case INTEL_PT_OVF: case INTEL_PT_OVF:
return intel_pt_overflow(decoder); return intel_pt_overflow(decoder);

View File

@ -60,6 +60,14 @@ enum {
INTEL_PT_ERR_MAX, INTEL_PT_ERR_MAX,
}; };
enum intel_pt_param_flags {
/*
* FUP packet can contain next linear instruction pointer instead of
* current linear instruction pointer.
*/
INTEL_PT_FUP_WITH_NLIP = 1 << 0,
};
struct intel_pt_state { struct intel_pt_state {
enum intel_pt_sample_type type; enum intel_pt_sample_type type;
int err; int err;
@ -106,6 +114,7 @@ struct intel_pt_params {
unsigned int mtc_period; unsigned int mtc_period;
uint32_t tsc_ctc_ratio_n; uint32_t tsc_ctc_ratio_n;
uint32_t tsc_ctc_ratio_d; uint32_t tsc_ctc_ratio_d;
enum intel_pt_param_flags flags;
}; };
struct intel_pt_decoder; struct intel_pt_decoder;

View File

@ -749,6 +749,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt,
unsigned int queue_nr) unsigned int queue_nr)
{ {
struct intel_pt_params params = { .get_trace = 0, }; struct intel_pt_params params = { .get_trace = 0, };
struct perf_env *env = pt->machine->env;
struct intel_pt_queue *ptq; struct intel_pt_queue *ptq;
ptq = zalloc(sizeof(struct intel_pt_queue)); ptq = zalloc(sizeof(struct intel_pt_queue));
@ -830,6 +831,9 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt,
} }
} }
if (env->cpuid && !strncmp(env->cpuid, "GenuineIntel,6,92,", 18))
params.flags |= INTEL_PT_FUP_WITH_NLIP;
ptq->decoder = intel_pt_decoder_new(&params); ptq->decoder = intel_pt_decoder_new(&params);
if (!ptq->decoder) if (!ptq->decoder)
goto out_free; goto out_free;
@ -1521,6 +1525,7 @@ static int intel_pt_sample(struct intel_pt_queue *ptq)
if (intel_pt_is_switch_ip(ptq, state->to_ip)) { if (intel_pt_is_switch_ip(ptq, state->to_ip)) {
switch (ptq->switch_state) { switch (ptq->switch_state) {
case INTEL_PT_SS_NOT_TRACING:
case INTEL_PT_SS_UNKNOWN: case INTEL_PT_SS_UNKNOWN:
case INTEL_PT_SS_EXPECTING_SWITCH_IP: case INTEL_PT_SS_EXPECTING_SWITCH_IP:
err = intel_pt_next_tid(pt, ptq); err = intel_pt_next_tid(pt, ptq);

View File

@ -415,16 +415,20 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
return fprintf(fp, "%s", dsoname); return fprintf(fp, "%s", dsoname);
} }
char *map__srcline(struct map *map, u64 addr, struct symbol *sym)
{
if (map == NULL)
return SRCLINE_UNKNOWN;
return get_srcline(map->dso, map__rip_2objdump(map, addr), sym, true, true, addr);
}
int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
FILE *fp) FILE *fp)
{ {
char *srcline;
int ret = 0; int ret = 0;
if (map && map->dso) { if (map && map->dso) {
srcline = get_srcline(map->dso, char *srcline = map__srcline(map, addr, NULL);
map__rip_2objdump(map, addr), NULL,
true, true, addr);
if (srcline != SRCLINE_UNKNOWN) if (srcline != SRCLINE_UNKNOWN)
ret = fprintf(fp, "%s%s", prefix, srcline); ret = fprintf(fp, "%s%s", prefix, srcline);
free_srcline(srcline); free_srcline(srcline);
@ -445,6 +449,20 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
*/ */
u64 map__rip_2objdump(struct map *map, u64 rip) u64 map__rip_2objdump(struct map *map, u64 rip)
{ {
struct kmap *kmap = __map__kmap(map);
/*
* vmlinux does not have program headers for PTI entry trampolines and
* kcore may not either. However the trampoline object code is on the
* main kernel map, so just use that instead.
*/
if (kmap && is_entry_trampoline(kmap->name) && kmap->kmaps && kmap->kmaps->machine) {
struct map *kernel_map = machine__kernel_map(kmap->kmaps->machine);
if (kernel_map)
map = kernel_map;
}
if (!map->dso->adjust_symbols) if (!map->dso->adjust_symbols)
return rip; return rip;

View File

@ -169,6 +169,7 @@ static inline void __map__zput(struct map **map)
int map__overlap(struct map *l, struct map *r); int map__overlap(struct map *l, struct map *r);
size_t map__fprintf(struct map *map, FILE *fp); size_t map__fprintf(struct map *map, FILE *fp);
size_t map__fprintf_dsoname(struct map *map, FILE *fp); size_t map__fprintf_dsoname(struct map *map, FILE *fp);
char *map__srcline(struct map *map, u64 addr, struct symbol *sym);
int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
FILE *fp); FILE *fp);

View File

@ -53,7 +53,21 @@ static int str(yyscan_t scanner, int token)
YYSTYPE *yylval = parse_events_get_lval(scanner); YYSTYPE *yylval = parse_events_get_lval(scanner);
char *text = parse_events_get_text(scanner); char *text = parse_events_get_text(scanner);
yylval->str = strdup(text); if (text[0] != '\'') {
yylval->str = strdup(text);
} else {
/*
* If a text tag specified on the command line
* contains opening single quite ' then it is
* expected that the tag ends with single quote
* as well, like this:
* name=\'CPU_CLK_UNHALTED.THREAD:cmask=1\'
* quotes need to be escaped to bypass shell
* processing.
*/
yylval->str = strndup(&text[1], strlen(text) - 2);
}
return token; return token;
} }
@ -176,6 +190,7 @@ num_dec [0-9]+
num_hex 0x[a-fA-F0-9]+ num_hex 0x[a-fA-F0-9]+
num_raw_hex [a-fA-F0-9]+ num_raw_hex [a-fA-F0-9]+
name [a-zA-Z_*?\[\]][a-zA-Z0-9_*?.\[\]]* name [a-zA-Z_*?\[\]][a-zA-Z0-9_*?.\[\]]*
name_tag [\'][a-zA-Z_*?\[\]][a-zA-Z0-9_*?\-,\.\[\]:=]*[\']
name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]* name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]*
drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)? drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)?
/* If you add a modifier you need to update check_modifier() */ /* If you add a modifier you need to update check_modifier() */
@ -344,6 +359,7 @@ r{num_raw_hex} { return raw(yyscanner); }
{bpf_object} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_OBJECT); } {bpf_object} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_OBJECT); }
{bpf_source} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_SOURCE); } {bpf_source} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_SOURCE); }
{name} { return pmu_str_check(yyscanner); } {name} { return pmu_str_check(yyscanner); }
{name_tag} { return str(yyscanner, PE_NAME); }
"/" { BEGIN(config); return '/'; } "/" { BEGIN(config); return '/'; }
- { return '-'; } - { return '-'; }
, { BEGIN(event); return ','; } , { BEGIN(event); return ','; }

View File

@ -73,6 +73,7 @@ static void inc_group_count(struct list_head *list,
%type <num> value_sym %type <num> value_sym
%type <head> event_config %type <head> event_config
%type <head> opt_event_config %type <head> opt_event_config
%type <head> opt_pmu_config
%type <term> event_term %type <term> event_term
%type <head> event_pmu %type <head> event_pmu
%type <head> event_legacy_symbol %type <head> event_legacy_symbol
@ -224,7 +225,7 @@ event_def: event_pmu |
event_bpf_file event_bpf_file
event_pmu: event_pmu:
PE_NAME opt_event_config PE_NAME opt_pmu_config
{ {
struct list_head *list, *orig_terms, *terms; struct list_head *list, *orig_terms, *terms;
@ -496,6 +497,17 @@ opt_event_config:
$$ = NULL; $$ = NULL;
} }
opt_pmu_config:
'/' event_config '/'
{
$$ = $2;
}
|
'/' '/'
{
$$ = NULL;
}
start_terms: event_config start_terms: event_config
{ {
struct parse_events_state *parse_state = _parse_state; struct parse_events_state *parse_state = _parse_state;

View File

@ -165,8 +165,7 @@ static struct map *kernel_get_module_map(const char *module)
if (strncmp(pos->dso->short_name + 1, module, if (strncmp(pos->dso->short_name + 1, module,
pos->dso->short_name_len - 2) == 0 && pos->dso->short_name_len - 2) == 0 &&
module[pos->dso->short_name_len - 2] == '\0') { module[pos->dso->short_name_len - 2] == '\0') {
map__get(pos); return map__get(pos);
return pos;
} }
} }
return NULL; return NULL;

View File

@ -1,62 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <stdlib.h>
#include "strbuf.h"
#include "quote.h"
#include "util.h"
/* Help to copy the thing properly quoted for the shell safety.
* any single quote is replaced with '\'', any exclamation point
* is replaced with '\!', and the whole thing is enclosed in a
*
* E.g.
* original sq_quote result
* name ==> name ==> 'name'
* a b ==> a b ==> 'a b'
* a'b ==> a'\''b ==> 'a'\''b'
* a!b ==> a'\!'b ==> 'a'\!'b'
*/
static inline int need_bs_quote(char c)
{
return (c == '\'' || c == '!');
}
static int sq_quote_buf(struct strbuf *dst, const char *src)
{
char *to_free = NULL;
int ret;
if (dst->buf == src)
to_free = strbuf_detach(dst, NULL);
ret = strbuf_addch(dst, '\'');
while (!ret && *src) {
size_t len = strcspn(src, "'!");
ret = strbuf_add(dst, src, len);
src += len;
while (!ret && need_bs_quote(*src))
ret = strbuf_addf(dst, "'\\%c\'", *src++);
}
if (!ret)
ret = strbuf_addch(dst, '\'');
free(to_free);
return ret;
}
int sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
{
int i, ret;
/* Copy into destination buffer. */
ret = strbuf_grow(dst, 255);
for (i = 0; !ret && argv[i]; ++i) {
ret = strbuf_addch(dst, ' ');
if (ret)
break;
ret = sq_quote_buf(dst, argv[i]);
if (maxlen && dst->len > maxlen)
return -ENOSPC;
}
return ret;
}

View File

@ -1,31 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PERF_QUOTE_H
#define __PERF_QUOTE_H
#include <stddef.h>
/* Help to copy the thing properly quoted for the shell safety.
* any single quote is replaced with '\'', any exclamation point
* is replaced with '\!', and the whole thing is enclosed in a
* single quote pair.
*
* For example, if you are passing the result to system() as an
* argument:
*
* sprintf(cmd, "foobar %s %s", sq_quote(arg0), sq_quote(arg1))
*
* would be appropriate. If the system() is going to call ssh to
* run the command on the other side:
*
* sprintf(cmd, "git-diff-tree %s %s", sq_quote(arg0), sq_quote(arg1));
* sprintf(rcmd, "ssh %s %s", sq_util/quote.host), sq_quote(cmd));
*
* Note that the above examples leak memory! Remember to free result from
* sq_quote() in a real application.
*/
struct strbuf;
int sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen);
#endif /* __PERF_QUOTE_H */

View File

@ -48,6 +48,7 @@
#include "cpumap.h" #include "cpumap.h"
#include "print_binary.h" #include "print_binary.h"
#include "stat.h" #include "stat.h"
#include "mem-events.h"
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
#define _PyUnicode_FromString(arg) \ #define _PyUnicode_FromString(arg) \
@ -372,6 +373,19 @@ static PyObject *get_field_numeric_entry(struct event_format *event,
return obj; return obj;
} }
static const char *get_dsoname(struct map *map)
{
const char *dsoname = "[unknown]";
if (map && map->dso) {
if (symbol_conf.show_kernel_path && map->dso->long_name)
dsoname = map->dso->long_name;
else
dsoname = map->dso->name;
}
return dsoname;
}
static PyObject *python_process_callchain(struct perf_sample *sample, static PyObject *python_process_callchain(struct perf_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
@ -427,14 +441,8 @@ static PyObject *python_process_callchain(struct perf_sample *sample,
} }
if (node->map) { if (node->map) {
struct map *map = node->map; const char *dsoname = get_dsoname(node->map);
const char *dsoname = "[unknown]";
if (map && map->dso) {
if (symbol_conf.show_kernel_path && map->dso->long_name)
dsoname = map->dso->long_name;
else
dsoname = map->dso->name;
}
pydict_set_item_string_decref(pyelem, "dso", pydict_set_item_string_decref(pyelem, "dso",
_PyUnicode_FromString(dsoname)); _PyUnicode_FromString(dsoname));
} }
@ -448,6 +456,166 @@ exit:
return pylist; return pylist;
} }
static PyObject *python_process_brstack(struct perf_sample *sample,
struct thread *thread)
{
struct branch_stack *br = sample->branch_stack;
PyObject *pylist;
u64 i;
pylist = PyList_New(0);
if (!pylist)
Py_FatalError("couldn't create Python list");
if (!(br && br->nr))
goto exit;
for (i = 0; i < br->nr; i++) {
PyObject *pyelem;
struct addr_location al;
const char *dsoname;
pyelem = PyDict_New();
if (!pyelem)
Py_FatalError("couldn't create Python dictionary");
pydict_set_item_string_decref(pyelem, "from",
PyLong_FromUnsignedLongLong(br->entries[i].from));
pydict_set_item_string_decref(pyelem, "to",
PyLong_FromUnsignedLongLong(br->entries[i].to));
pydict_set_item_string_decref(pyelem, "mispred",
PyBool_FromLong(br->entries[i].flags.mispred));
pydict_set_item_string_decref(pyelem, "predicted",
PyBool_FromLong(br->entries[i].flags.predicted));
pydict_set_item_string_decref(pyelem, "in_tx",
PyBool_FromLong(br->entries[i].flags.in_tx));
pydict_set_item_string_decref(pyelem, "abort",
PyBool_FromLong(br->entries[i].flags.abort));
pydict_set_item_string_decref(pyelem, "cycles",
PyLong_FromUnsignedLongLong(br->entries[i].flags.cycles));
thread__find_map(thread, sample->cpumode,
br->entries[i].from, &al);
dsoname = get_dsoname(al.map);
pydict_set_item_string_decref(pyelem, "from_dsoname",
_PyUnicode_FromString(dsoname));
thread__find_map(thread, sample->cpumode,
br->entries[i].to, &al);
dsoname = get_dsoname(al.map);
pydict_set_item_string_decref(pyelem, "to_dsoname",
_PyUnicode_FromString(dsoname));
PyList_Append(pylist, pyelem);
Py_DECREF(pyelem);
}
exit:
return pylist;
}
static unsigned long get_offset(struct symbol *sym, struct addr_location *al)
{
unsigned long offset;
if (al->addr < sym->end)
offset = al->addr - sym->start;
else
offset = al->addr - al->map->start - sym->start;
return offset;
}
static int get_symoff(struct symbol *sym, struct addr_location *al,
bool print_off, char *bf, int size)
{
unsigned long offset;
if (!sym || !sym->name[0])
return scnprintf(bf, size, "%s", "[unknown]");
if (!print_off)
return scnprintf(bf, size, "%s", sym->name);
offset = get_offset(sym, al);
return scnprintf(bf, size, "%s+0x%x", sym->name, offset);
}
static int get_br_mspred(struct branch_flags *flags, char *bf, int size)
{
if (!flags->mispred && !flags->predicted)
return scnprintf(bf, size, "%s", "-");
if (flags->mispred)
return scnprintf(bf, size, "%s", "M");
return scnprintf(bf, size, "%s", "P");
}
static PyObject *python_process_brstacksym(struct perf_sample *sample,
struct thread *thread)
{
struct branch_stack *br = sample->branch_stack;
PyObject *pylist;
u64 i;
char bf[512];
struct addr_location al;
pylist = PyList_New(0);
if (!pylist)
Py_FatalError("couldn't create Python list");
if (!(br && br->nr))
goto exit;
for (i = 0; i < br->nr; i++) {
PyObject *pyelem;
pyelem = PyDict_New();
if (!pyelem)
Py_FatalError("couldn't create Python dictionary");
thread__find_symbol(thread, sample->cpumode,
br->entries[i].from, &al);
get_symoff(al.sym, &al, true, bf, sizeof(bf));
pydict_set_item_string_decref(pyelem, "from",
_PyUnicode_FromString(bf));
thread__find_symbol(thread, sample->cpumode,
br->entries[i].to, &al);
get_symoff(al.sym, &al, true, bf, sizeof(bf));
pydict_set_item_string_decref(pyelem, "to",
_PyUnicode_FromString(bf));
get_br_mspred(&br->entries[i].flags, bf, sizeof(bf));
pydict_set_item_string_decref(pyelem, "pred",
_PyUnicode_FromString(bf));
if (br->entries[i].flags.in_tx) {
pydict_set_item_string_decref(pyelem, "in_tx",
_PyUnicode_FromString("X"));
} else {
pydict_set_item_string_decref(pyelem, "in_tx",
_PyUnicode_FromString("-"));
}
if (br->entries[i].flags.abort) {
pydict_set_item_string_decref(pyelem, "abort",
_PyUnicode_FromString("A"));
} else {
pydict_set_item_string_decref(pyelem, "abort",
_PyUnicode_FromString("-"));
}
PyList_Append(pylist, pyelem);
Py_DECREF(pyelem);
}
exit:
return pylist;
}
static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) static PyObject *get_sample_value_as_tuple(struct sample_read_value *value)
{ {
PyObject *t; PyObject *t;
@ -498,12 +666,63 @@ static void set_sample_read_in_dict(PyObject *dict_sample,
pydict_set_item_string_decref(dict_sample, "values", values); pydict_set_item_string_decref(dict_sample, "values", values);
} }
static void set_sample_datasrc_in_dict(PyObject *dict,
struct perf_sample *sample)
{
struct mem_info mi = { .data_src.val = sample->data_src };
char decode[100];
pydict_set_item_string_decref(dict, "datasrc",
PyLong_FromUnsignedLongLong(sample->data_src));
perf_script__meminfo_scnprintf(decode, 100, &mi);
pydict_set_item_string_decref(dict, "datasrc_decode",
_PyUnicode_FromString(decode));
}
static int regs_map(struct regs_dump *regs, uint64_t mask, char *bf, int size)
{
unsigned int i = 0, r;
int printed = 0;
bf[0] = 0;
for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) {
u64 val = regs->regs[i++];
printed += scnprintf(bf + printed, size - printed,
"%5s:0x%" PRIx64 " ",
perf_reg_name(r), val);
}
return printed;
}
static void set_regs_in_dict(PyObject *dict,
struct perf_sample *sample,
struct perf_evsel *evsel)
{
struct perf_event_attr *attr = &evsel->attr;
char bf[512];
regs_map(&sample->intr_regs, attr->sample_regs_intr, bf, sizeof(bf));
pydict_set_item_string_decref(dict, "iregs",
_PyUnicode_FromString(bf));
regs_map(&sample->user_regs, attr->sample_regs_user, bf, sizeof(bf));
pydict_set_item_string_decref(dict, "uregs",
_PyUnicode_FromString(bf));
}
static PyObject *get_perf_sample_dict(struct perf_sample *sample, static PyObject *get_perf_sample_dict(struct perf_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct addr_location *al, struct addr_location *al,
PyObject *callchain) PyObject *callchain)
{ {
PyObject *dict, *dict_sample; PyObject *dict, *dict_sample, *brstack, *brstacksym;
dict = PyDict_New(); dict = PyDict_New();
if (!dict) if (!dict)
@ -534,6 +753,11 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample,
pydict_set_item_string_decref(dict_sample, "addr", pydict_set_item_string_decref(dict_sample, "addr",
PyLong_FromUnsignedLongLong(sample->addr)); PyLong_FromUnsignedLongLong(sample->addr));
set_sample_read_in_dict(dict_sample, sample, evsel); set_sample_read_in_dict(dict_sample, sample, evsel);
pydict_set_item_string_decref(dict_sample, "weight",
PyLong_FromUnsignedLongLong(sample->weight));
pydict_set_item_string_decref(dict_sample, "transaction",
PyLong_FromUnsignedLongLong(sample->transaction));
set_sample_datasrc_in_dict(dict_sample, sample);
pydict_set_item_string_decref(dict, "sample", dict_sample); pydict_set_item_string_decref(dict, "sample", dict_sample);
pydict_set_item_string_decref(dict, "raw_buf", _PyBytes_FromStringAndSize( pydict_set_item_string_decref(dict, "raw_buf", _PyBytes_FromStringAndSize(
@ -551,6 +775,14 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample,
pydict_set_item_string_decref(dict, "callchain", callchain); pydict_set_item_string_decref(dict, "callchain", callchain);
brstack = python_process_brstack(sample, al->thread);
pydict_set_item_string_decref(dict, "brstack", brstack);
brstacksym = python_process_brstacksym(sample, al->thread);
pydict_set_item_string_decref(dict, "brstacksym", brstacksym);
set_regs_in_dict(dict, sample, evsel);
return dict; return dict;
} }

View File

@ -1094,7 +1094,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
sample_type = evsel->attr.sample_type; sample_type = evsel->attr.sample_type;
if (sample_type & PERF_SAMPLE_CALLCHAIN) if (evsel__has_callchain(evsel))
callchain__printf(evsel, sample); callchain__printf(evsel, sample);
if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !perf_evsel__has_branch_callstack(evsel)) if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !perf_evsel__has_branch_callstack(evsel))

View File

@ -331,24 +331,18 @@ struct sort_entry sort_sym = {
/* --sort srcline */ /* --sort srcline */
char *hist_entry__get_srcline(struct hist_entry *he) char *hist_entry__srcline(struct hist_entry *he)
{ {
struct map *map = he->ms.map; return map__srcline(he->ms.map, he->ip, he->ms.sym);
if (!map)
return SRCLINE_UNKNOWN;
return get_srcline(map->dso, map__rip_2objdump(map, he->ip),
he->ms.sym, true, true, he->ip);
} }
static int64_t static int64_t
sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
{ {
if (!left->srcline) if (!left->srcline)
left->srcline = hist_entry__get_srcline(left); left->srcline = hist_entry__srcline(left);
if (!right->srcline) if (!right->srcline)
right->srcline = hist_entry__get_srcline(right); right->srcline = hist_entry__srcline(right);
return strcmp(right->srcline, left->srcline); return strcmp(right->srcline, left->srcline);
} }
@ -357,7 +351,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
if (!he->srcline) if (!he->srcline)
he->srcline = hist_entry__get_srcline(he); he->srcline = hist_entry__srcline(he);
return repsep_snprintf(bf, size, "%-.*s", width, he->srcline); return repsep_snprintf(bf, size, "%-.*s", width, he->srcline);
} }
@ -371,33 +365,20 @@ struct sort_entry sort_srcline = {
/* --sort srcline_from */ /* --sort srcline_from */
static char *addr_map_symbol__srcline(struct addr_map_symbol *ams)
{
return map__srcline(ams->map, ams->al_addr, ams->sym);
}
static int64_t static int64_t
sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
{ {
if (!left->branch_info->srcline_from) { if (!left->branch_info->srcline_from)
struct map *map = left->branch_info->from.map; left->branch_info->srcline_from = addr_map_symbol__srcline(&left->branch_info->from);
if (!map)
left->branch_info->srcline_from = SRCLINE_UNKNOWN; if (!right->branch_info->srcline_from)
else right->branch_info->srcline_from = addr_map_symbol__srcline(&right->branch_info->from);
left->branch_info->srcline_from = get_srcline(map->dso,
map__rip_2objdump(map,
left->branch_info->from.al_addr),
left->branch_info->from.sym,
true, true,
left->branch_info->from.al_addr);
}
if (!right->branch_info->srcline_from) {
struct map *map = right->branch_info->from.map;
if (!map)
right->branch_info->srcline_from = SRCLINE_UNKNOWN;
else
right->branch_info->srcline_from = get_srcline(map->dso,
map__rip_2objdump(map,
right->branch_info->from.al_addr),
right->branch_info->from.sym,
true, true,
right->branch_info->from.al_addr);
}
return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from);
} }
@ -419,30 +400,12 @@ struct sort_entry sort_srcline_from = {
static int64_t static int64_t
sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
{ {
if (!left->branch_info->srcline_to) { if (!left->branch_info->srcline_to)
struct map *map = left->branch_info->to.map; left->branch_info->srcline_to = addr_map_symbol__srcline(&left->branch_info->to);
if (!map)
left->branch_info->srcline_to = SRCLINE_UNKNOWN; if (!right->branch_info->srcline_to)
else right->branch_info->srcline_to = addr_map_symbol__srcline(&right->branch_info->to);
left->branch_info->srcline_to = get_srcline(map->dso,
map__rip_2objdump(map,
left->branch_info->to.al_addr),
left->branch_info->from.sym,
true, true,
left->branch_info->to.al_addr);
}
if (!right->branch_info->srcline_to) {
struct map *map = right->branch_info->to.map;
if (!map)
right->branch_info->srcline_to = SRCLINE_UNKNOWN;
else
right->branch_info->srcline_to = get_srcline(map->dso,
map__rip_2objdump(map,
right->branch_info->to.al_addr),
right->branch_info->to.sym,
true, true,
right->branch_info->to.al_addr);
}
return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to);
} }

View File

@ -151,6 +151,11 @@ struct hist_entry {
struct callchain_root callchain[0]; /* must be last member */ struct callchain_root callchain[0]; /* must be last member */
}; };
static __pure inline bool hist_entry__has_callchains(struct hist_entry *he)
{
return hists__has_callchains(he->hists);
}
static inline bool hist_entry__has_pairs(struct hist_entry *he) static inline bool hist_entry__has_pairs(struct hist_entry *he)
{ {
return !list_empty(&he->pairs.node); return !list_empty(&he->pairs.node);
@ -292,5 +297,5 @@ int64_t
sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right); sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right);
int64_t int64_t
sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right); sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right);
char *hist_entry__get_srcline(struct hist_entry *he); char *hist_entry__srcline(struct hist_entry *he);
#endif /* __PERF_SORT_H */ #endif /* __PERF_SORT_H */

View File

@ -40,7 +40,6 @@ char **vmlinux_path;
struct symbol_conf symbol_conf = { struct symbol_conf symbol_conf = {
.use_modules = true, .use_modules = true,
.try_vmlinux_path = true, .try_vmlinux_path = true,
.annotate_src = true,
.demangle = true, .demangle = true,
.demangle_kernel = false, .demangle_kernel = false,
.cumulate_callchain = true, .cumulate_callchain = true,
@ -74,7 +73,7 @@ static enum dso_binary_type binary_type_symtab[] = {
static bool symbol_type__filter(char symbol_type) static bool symbol_type__filter(char symbol_type)
{ {
symbol_type = toupper(symbol_type); symbol_type = toupper(symbol_type);
return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D'; return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D' || symbol_type == 'B';
} }
static int prefix_underscores_count(const char *str) static int prefix_underscores_count(const char *str)

View File

@ -90,7 +90,6 @@ struct intlist;
struct symbol_conf { struct symbol_conf {
unsigned short priv_size; unsigned short priv_size;
unsigned short nr_events;
bool try_vmlinux_path, bool try_vmlinux_path,
init_annotation, init_annotation,
force, force,
@ -109,8 +108,6 @@ struct symbol_conf {
show_cpu_utilization, show_cpu_utilization,
initialized, initialized,
kptr_restrict, kptr_restrict,
annotate_asm_raw,
annotate_src,
event_group, event_group,
demangle, demangle,
demangle_kernel, demangle_kernel,

View File

@ -3,6 +3,7 @@
#define __PERF_TOP_H 1 #define __PERF_TOP_H 1
#include "tool.h" #include "tool.h"
#include "annotate.h"
#include <linux/types.h> #include <linux/types.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
@ -16,6 +17,7 @@ struct perf_top {
struct perf_tool tool; struct perf_tool tool;
struct perf_evlist *evlist; struct perf_evlist *evlist;
struct record_opts record_opts; struct record_opts record_opts;
struct annotation_options annotation_opts;
/* /*
* Symbols will be added here in perf_event__process_sample and will * Symbols will be added here in perf_event__process_sample and will
* get out after decayed. * get out after decayed.
@ -35,7 +37,6 @@ struct perf_top {
struct perf_session *session; struct perf_session *session;
struct winsize winsize; struct winsize winsize;
int realtime_prio; int realtime_prio;
int sym_pcnt_filter;
const char *sym_filter; const char *sym_filter;
float min_percent; float min_percent;
unsigned int nr_threads_synthesize; unsigned int nr_threads_synthesize;