summaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-record.txt4
-rw-r--r--tools/perf/Documentation/perf-report.txt11
-rw-r--r--tools/perf/builtin-annotate.c2
-rw-r--r--tools/perf/builtin-diff.c3
-rw-r--r--tools/perf/builtin-report.c7
-rw-r--r--tools/perf/builtin-trace.c54
-rw-r--r--tools/perf/tests/hists_cumulate.c4
-rw-r--r--tools/perf/tests/parse-events.c38
-rw-r--r--tools/perf/ui/browser.c17
-rw-r--r--tools/perf/ui/browser.h3
-rw-r--r--tools/perf/ui/browsers/annotate.c43
-rw-r--r--tools/perf/ui/browsers/header.c2
-rw-r--r--tools/perf/ui/browsers/hists.c54
-rw-r--r--tools/perf/ui/browsers/map.c11
-rw-r--r--tools/perf/ui/browsers/scripts.c2
-rw-r--r--tools/perf/ui/libslang.h3
-rw-r--r--tools/perf/ui/tui/util.c2
-rw-r--r--tools/perf/util/dwarf-aux.c18
-rw-r--r--tools/perf/util/evsel.c67
-rw-r--r--tools/perf/util/evsel.h4
-rw-r--r--tools/perf/util/hist.c14
-rw-r--r--tools/perf/util/parse-events.c12
-rw-r--r--tools/perf/util/parse-events.h2
-rw-r--r--tools/perf/util/parse-events.l2
-rw-r--r--tools/perf/util/pmu.c4
-rw-r--r--tools/perf/util/sort.c2
-rw-r--r--tools/perf/util/symbol.h3
27 files changed, 307 insertions, 81 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index afbe45ef7e3e..347a27322ed8 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -53,6 +53,10 @@ OPTIONS
- 'time': Disable/enable time stamping. Acceptable values are 1 for
enabling time stamping. 0 for disabling time stamping.
The default is 1.
+ - 'call-graph': Disable/enable callgraph. Acceptable str are "fp" for
+ FP mode, "dwarf" for DWARF mode, "lbr" for LBR mode and
+ "no" for disable callgraph.
+ - 'stack-size': user stack size for dwarf mode
Note: If user explicitly sets options which conflict with the params,
the value set by the params will be overridden.
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 7b07d19e2d54..a18ba757a0ed 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -359,6 +359,17 @@ OPTIONS
--full-source-path::
Show the full path for source files for srcline output.
+--show-ref-call-graph::
+ When multiple events are sampled, it may not be needed to collect
+ callgraphs for all of them. The sample sites are usually nearby,
+ and it's enough to collect the callgraphs on a reference event.
+ So user can use "call-graph=no" event modifier to disable callgraph
+ for other events to reduce the overhead.
+ However, perf report cannot show callgraphs for the event which
+ disable the callgraph.
+ This option extends the perf report to show reference callgraphs,
+ which collected by reference event, in no callgraph event.
+
include::callchain-overhead-calculation.txt[]
SEE ALSO
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 467a23b14e2f..a32a64ef08e2 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -239,6 +239,8 @@ static int __cmd_annotate(struct perf_annotate *ann)
if (nr_samples > 0) {
total_nr_samples += nr_samples;
hists__collapse_resort(hists, NULL);
+ /* Don't sort callchain */
+ perf_evsel__reset_sample_bit(pos, CALLCHAIN);
hists__output_resort(hists, NULL);
if (symbol_conf.event_group &&
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index daaa7dca9c3b..0b180a885ba3 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -722,6 +722,9 @@ static void data_process(void)
if (verbose || data__files_cnt > 2)
data__fprintf();
+ /* Don't sort callchain for perf diff */
+ perf_evsel__reset_sample_bit(evsel_base, CALLCHAIN);
+
hists__process(hists_base);
}
}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index f301e865001f..62b285e32aa5 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -316,6 +316,11 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
if (evname != NULL)
ret += fprintf(fp, " of event '%s'", evname);
+ if (symbol_conf.show_ref_callgraph &&
+ strstr(evname, "call-graph=no")) {
+ ret += fprintf(fp, ", show reference callgraph");
+ }
+
if (rep->mem_mode) {
ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
ret += fprintf(fp, "\n# Sort order : %s", sort_order ? : default_mem_sort_order);
@@ -740,6 +745,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
itrace_parse_synth_opts),
OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename,
"Show full source file name path for source lines"),
+ OPT_BOOLEAN(0, "show-ref-call-graph", &symbol_conf.show_ref_callgraph,
+ "Show callgraph from reference event"),
OPT_END()
};
struct perf_data_file file = {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index a25048c85b76..489cc118a36a 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -569,6 +569,15 @@ static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
static DEFINE_STRARRAY(itimers);
+static const char *keyctl_options[] = {
+ "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
+ "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
+ "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
+ "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
+ "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
+};
+static DEFINE_STRARRAY(keyctl_options);
+
static const char *whences[] = { "SET", "CUR", "END",
#ifdef SEEK_DATA
"DATA",
@@ -599,7 +608,8 @@ static DEFINE_STRARRAY(sighow);
static const char *clockid[] = {
"REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
- "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
+ "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
+ "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
};
static DEFINE_STRARRAY(clockid);
@@ -1014,7 +1024,8 @@ static struct syscall_fmt {
{ .name = "fchmod", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "fchmodat", .errmsg = true,
- .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
+ .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
+ [1] = SCA_FILENAME, /* filename */ }, },
{ .name = "fchown", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "fchownat", .errmsg = true,
@@ -1045,7 +1056,8 @@ static struct syscall_fmt {
{ .name = "futex", .errmsg = true,
.arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
{ .name = "futimesat", .errmsg = true,
- .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
+ .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
+ [1] = SCA_FILENAME, /* filename */ }, },
{ .name = "getdents", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "getdents64", .errmsg = true,
@@ -1068,6 +1080,7 @@ static struct syscall_fmt {
#else
[2] = SCA_HEX, /* arg */ }, },
#endif
+ { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
{ .name = "kill", .errmsg = true,
.arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
{ .name = "lchown", .errmsg = true,
@@ -1078,13 +1091,18 @@ static struct syscall_fmt {
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
{ .name = "listxattr", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
+ { .name = "llistxattr", .errmsg = true,
+ .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
+ { .name = "lremovexattr", .errmsg = true,
+ .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
{ .name = "lseek", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */
[2] = SCA_STRARRAY, /* whence */ },
.arg_parm = { [2] = &strarray__whences, /* whence */ }, },
{ .name = "lsetxattr", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
- { .name = "lstat", .errmsg = true, .alias = "newlstat", },
+ { .name = "lstat", .errmsg = true, .alias = "newlstat",
+ .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
{ .name = "lsxattr", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
{ .name = "madvise", .errmsg = true,
@@ -1098,7 +1116,8 @@ static struct syscall_fmt {
{ .name = "mknod", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
{ .name = "mknodat", .errmsg = true,
- .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
+ .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
+ [1] = SCA_FILENAME, /* filename */ }, },
{ .name = "mlock", .errmsg = true,
.arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
{ .name = "mlockall", .errmsg = true,
@@ -1111,6 +1130,8 @@ static struct syscall_fmt {
{ .name = "mprotect", .errmsg = true,
.arg_scnprintf = { [0] = SCA_HEX, /* start */
[2] = SCA_MMAP_PROT, /* prot */ }, },
+ { .name = "mq_unlink", .errmsg = true,
+ .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
{ .name = "mremap", .hexret = true,
.arg_scnprintf = { [0] = SCA_HEX, /* addr */
[3] = SCA_MREMAP_FLAGS, /* flags */
@@ -1162,11 +1183,14 @@ static struct syscall_fmt {
{ .name = "readv", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "recvfrom", .errmsg = true,
- .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
+ .arg_scnprintf = { [0] = SCA_FD, /* fd */
+ [3] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "recvmmsg", .errmsg = true,
- .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
+ .arg_scnprintf = { [0] = SCA_FD, /* fd */
+ [3] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "recvmsg", .errmsg = true,
- .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
+ .arg_scnprintf = { [0] = SCA_FD, /* fd */
+ [2] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "removexattr", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
{ .name = "renameat", .errmsg = true,
@@ -1182,11 +1206,14 @@ static struct syscall_fmt {
.arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
{ .name = "select", .errmsg = true, .timeout = true, },
{ .name = "sendmmsg", .errmsg = true,
- .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
+ .arg_scnprintf = { [0] = SCA_FD, /* fd */
+ [3] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "sendmsg", .errmsg = true,
- .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
+ .arg_scnprintf = { [0] = SCA_FD, /* fd */
+ [2] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "sendto", .errmsg = true,
- .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
+ .arg_scnprintf = { [0] = SCA_FD, /* fd */
+ [3] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
{ .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
{ .name = "setxattr", .errmsg = true,
@@ -1201,7 +1228,8 @@ static struct syscall_fmt {
.arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
[1] = SCA_SK_TYPE, /* type */ },
.arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
- { .name = "stat", .errmsg = true, .alias = "newstat", },
+ { .name = "stat", .errmsg = true, .alias = "newstat",
+ .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
{ .name = "statfs", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
{ .name = "swapoff", .errmsg = true,
@@ -1227,6 +1255,8 @@ static struct syscall_fmt {
[1] = SCA_FILENAME, /* filename */ }, },
{ .name = "utimes", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
+ { .name = "vmsplice", .errmsg = true,
+ .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "write", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "writev", .errmsg = true,
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 7d82c8be5e36..7ed737019de7 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -279,6 +279,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
symbol_conf.use_callchain = false;
symbol_conf.cumulate_callchain = false;
+ perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
setup_sorting();
callchain_register_param(&callchain_param);
@@ -425,6 +426,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
symbol_conf.use_callchain = true;
symbol_conf.cumulate_callchain = false;
+ perf_evsel__set_sample_bit(evsel, CALLCHAIN);
setup_sorting();
callchain_register_param(&callchain_param);
@@ -482,6 +484,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
symbol_conf.use_callchain = false;
symbol_conf.cumulate_callchain = true;
+ perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
setup_sorting();
callchain_register_param(&callchain_param);
@@ -665,6 +668,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
symbol_conf.use_callchain = true;
symbol_conf.cumulate_callchain = true;
+ perf_evsel__set_sample_bit(evsel, CALLCHAIN);
setup_sorting();
callchain_register_param(&callchain_param);
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index f65bb89e109e..9b6b2b6324a1 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -479,6 +479,39 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
return 0;
}
+static int test__checkevent_pmu_partial_time_callgraph(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = perf_evlist__first(evlist);
+
+ /* cpu/config=1,call-graph=fp,time,period=100000/ */
+ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+ /*
+ * The period, time and callgraph value gets configured
+ * within perf_evlist__config,
+ * while this test executes only parse events method.
+ */
+ 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 time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type));
+
+ /* cpu/config=2,call-graph=no,time=0,period=2000/ */
+ evsel = perf_evsel__next(evsel);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config);
+ /*
+ * The period, time and callgraph value gets configured
+ * within perf_evlist__config,
+ * while this test executes only parse events method.
+ */
+ 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 time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type));
+
+ return 0;
+}
+
static int test__checkevent_pmu_events(struct perf_evlist *evlist)
{
struct perf_evsel *evsel = perf_evlist__first(evlist);
@@ -1555,6 +1588,11 @@ static struct evlist_test test__events_pmu[] = {
.check = test__checkevent_pmu_name,
.id = 1,
},
+ {
+ .name = "cpu/config=1,call-graph=fp,time,period=100000/,cpu/config=2,call-graph=no,time=0,period=2000/",
+ .check = test__checkevent_pmu_partial_time_callgraph,
+ .id = 2,
+ },
};
struct terms_test {
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 6680fa5cb9dd..c6c7e5189214 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -46,6 +46,21 @@ void ui_browser__gotorc(struct ui_browser *browser, int y, int x)
SLsmg_gotorc(browser->y + y, browser->x + x);
}
+void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg,
+ unsigned int width)
+{
+ slsmg_write_nstring(msg, width);
+}
+
+void ui_browser__printf(struct ui_browser *browser __maybe_unused, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ slsmg_vprintf(fmt, args);
+ va_end(args);
+}
+
static struct list_head *
ui_browser__list_head_filter_entries(struct ui_browser *browser,
struct list_head *pos)
@@ -234,7 +249,7 @@ void __ui_browser__show_title(struct ui_browser *browser, const char *title)
{
SLsmg_gotorc(0, 0);
ui_browser__set_color(browser, HE_COLORSET_ROOT);
- slsmg_write_nstring(title, browser->width + 1);
+ ui_browser__write_nstring(browser, title, browser->width + 1);
}
void ui_browser__show_title(struct ui_browser *browser, const char *title)
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index 92ae72113965..52be87125def 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -37,6 +37,9 @@ void ui_browser__refresh_dimensions(struct ui_browser *browser);
void ui_browser__reset_index(struct ui_browser *browser);
void ui_browser__gotorc(struct ui_browser *browser, int y, int x);
+void ui_browser__write_nstring(struct ui_browser *browser, const char *msg,
+ unsigned int width);
+void ui_browser__printf(struct ui_browser *browser, const char *fmt, ...);
void ui_browser__write_graph(struct ui_browser *browser, int graph);
void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
u64 start, u64 end);
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index b5fc847f9660..29739b347599 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -1,7 +1,6 @@
#include "../../util/util.h"
#include "../browser.h"
#include "../helpline.h"
-#include "../libslang.h"
#include "../ui.h"
#include "../util.h"
#include "../../util/annotate.h"
@@ -134,29 +133,31 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
ui_browser__set_percent_color(browser,
bdl->samples[i].percent,
current_entry);
- if (annotate_browser__opts.show_total_period)
- slsmg_printf("%6" PRIu64 " ",
- bdl->samples[i].nr);
- else
- slsmg_printf("%6.2f ", bdl->samples[i].percent);
+ if (annotate_browser__opts.show_total_period) {
+ ui_browser__printf(browser, "%6" PRIu64 " ",
+ bdl->samples[i].nr);
+ } else {
+ ui_browser__printf(browser, "%6.2f ",
+ bdl->samples[i].percent);
+ }
}
} else {
- slsmg_write_nstring(" ", 7 * ab->nr_events);
+ ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
}
} else {
ui_browser__set_percent_color(browser, 0, current_entry);
- slsmg_write_nstring(" ", 7 * ab->nr_events);
+ ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
}
if (ab->have_cycles) {
if (dl->ipc)
- slsmg_printf("%*.2f ", IPC_WIDTH - 1, dl->ipc);
+ ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
else
- slsmg_write_nstring(" ", IPC_WIDTH);
+ ui_browser__write_nstring(browser, " ", IPC_WIDTH);
if (dl->cycles)
- slsmg_printf("%*" PRIu64 " ",
- CYCLES_WIDTH - 1, dl->cycles);
+ ui_browser__printf(browser, "%*" PRIu64 " ",
+ CYCLES_WIDTH - 1, dl->cycles);
else
- slsmg_write_nstring(" ", CYCLES_WIDTH);
+ ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
}
SLsmg_write_char(' ');
@@ -166,7 +167,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
width += 1;
if (!*dl->line)
- slsmg_write_nstring(" ", width - pcnt_width);
+ ui_browser__write_nstring(browser, " ", width - pcnt_width);
else if (dl->offset == -1) {
if (dl->line_nr && annotate_browser__opts.show_linenr)
printed = scnprintf(bf, sizeof(bf), "%-*d ",
@@ -174,8 +175,8 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
else
printed = scnprintf(bf, sizeof(bf), "%*s ",
ab->addr_width, " ");
- slsmg_write_nstring(bf, printed);
- slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
+ ui_browser__write_nstring(browser, bf, printed);
+ ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1);
} else {
u64 addr = dl->offset;
int color = -1;
@@ -194,7 +195,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
bdl->jump_sources);
prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
current_entry);
- slsmg_write_nstring(bf, printed);
+ ui_browser__write_nstring(browser, bf, printed);
ui_browser__set_color(browser, prev);
}
@@ -208,7 +209,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
if (change_color)
color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
- slsmg_write_nstring(bf, printed);
+ ui_browser__write_nstring(browser, bf, printed);
if (change_color)
ui_browser__set_color(browser, color);
if (dl->ins && dl->ins->ops->scnprintf) {
@@ -222,11 +223,11 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
SLsmg_write_char(' ');
} else {
- slsmg_write_nstring(" ", 2);
+ ui_browser__write_nstring(browser, " ", 2);
}
} else {
if (strcmp(dl->name, "retq")) {
- slsmg_write_nstring(" ", 2);
+ ui_browser__write_nstring(browser, " ", 2);
} else {
ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
SLsmg_write_char(' ');
@@ -234,7 +235,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
}
disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
- slsmg_write_nstring(bf, width - pcnt_width - 3 - printed);
+ ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed);
}
if (current_entry)
diff --git a/tools/perf/ui/browsers/header.c b/tools/perf/ui/browsers/header.c
index e8278c558d4a..f10681717f93 100644
--- a/tools/perf/ui/browsers/header.c
+++ b/tools/perf/ui/browsers/header.c
@@ -25,7 +25,7 @@ static void ui_browser__argv_write(struct ui_browser *browser,
ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
HE_COLORSET_NORMAL);
- slsmg_write_nstring(str, browser->width);
+ ui_browser__write_nstring(browser, str, browser->width);
}
static int list_menu__run(struct ui_browser *menu)
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index fa67613976a8..10c7ec041039 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1,5 +1,4 @@
#include <stdio.h>
-#include "../libslang.h"
#include <stdlib.h>
#include <string.h>
#include <linux/rbtree.h>
@@ -540,10 +539,10 @@ static void hist_browser__show_callchain_entry(struct hist_browser *browser,
ui_browser__set_color(&browser->b, color);
hist_browser__gotorc(browser, row, 0);
- slsmg_write_nstring(" ", offset);
- slsmg_printf("%c", folded_sign);
+ ui_browser__write_nstring(&browser->b, " ", offset);
+ ui_browser__printf(&browser->b, "%c", folded_sign);
ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' ');
- slsmg_write_nstring(str, width);
+ ui_browser__write_nstring(&browser->b, str, width);
}
static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
@@ -680,7 +679,7 @@ static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
- slsmg_printf("%s", hpp->buf);
+ ui_browser__printf(arg->b, "%s", hpp->buf);
advance_hpp(hpp, ret);
return ret;
@@ -713,10 +712,11 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
struct hist_entry *he) \
{ \
if (!symbol_conf.cumulate_callchain) { \
+ struct hpp_arg *arg = hpp->ptr; \
int len = fmt->user_len ?: fmt->len; \
int ret = scnprintf(hpp->buf, hpp->size, \
"%*s", len, "N/A"); \
- slsmg_printf("%s", hpp->buf); \
+ ui_browser__printf(arg->b, "%s", hpp->buf); \
\
return ret; \
} \
@@ -801,12 +801,12 @@ static int hist_browser__show_entry(struct hist_browser *browser,
if (first) {
if (symbol_conf.use_callchain) {
- slsmg_printf("%c ", folded_sign);
+ ui_browser__printf(&browser->b, "%c ", folded_sign);
width -= 2;
}
first = false;
} else {
- slsmg_printf(" ");
+ ui_browser__printf(&browser->b, " ");
width -= 2;
}
@@ -814,7 +814,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
width -= fmt->color(fmt, &hpp, entry);
} else {
width -= fmt->entry(fmt, &hpp, entry);
- slsmg_printf("%s", s);
+ ui_browser__printf(&browser->b, "%s", s);
}
}
@@ -822,7 +822,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
if (!browser->b.navkeypressed)
width += 1;
- slsmg_write_nstring("", width);
+ ui_browser__write_nstring(&browser->b, "", width);
++row;
++printed;
@@ -899,7 +899,7 @@ static void hist_browser__show_headers(struct hist_browser *browser)
hists__scnprintf_headers(headers, sizeof(headers), browser->hists);
ui_browser__gotorc(&browser->b, 0, 0);
ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
- slsmg_write_nstring(headers, browser->b.width + 1);
+ ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
}
static void ui_browser__hists_init_top(struct ui_browser *browser)
@@ -1267,6 +1267,8 @@ static int hists__browser_title(struct hists *hists,
const char *ev_name = perf_evsel__name(evsel);
char buf[512];
size_t buflen = sizeof(buf);
+ char ref[30] = " show reference callgraph, ";
+ bool enable_ref = false;
if (symbol_conf.filter_relative) {
nr_samples = hists->stats.nr_non_filtered_samples;
@@ -1292,10 +1294,13 @@ static int hists__browser_title(struct hists *hists,
}
}
+ if (symbol_conf.show_ref_callgraph &&
+ strstr(ev_name, "call-graph=no"))
+ enable_ref = true;
nr_samples = convert_unit(nr_samples, &unit);
printed = scnprintf(bf, size,
- "Samples: %lu%c of event '%s', Event count (approx.): %" PRIu64,
- nr_samples, unit, ev_name, nr_events);
+ "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64,
+ nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events);
if (hists->uid_filter_str)
@@ -1868,6 +1873,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
case K_RIGHT:
/* menu */
break;
+ case K_ESC:
case K_LEFT: {
const void *top;
@@ -1877,6 +1883,12 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
*/
if (left_exits)
goto out_free_stack;
+
+ if (key == K_ESC &&
+ ui_browser__dialog_yesno(&browser->b,
+ "Do you really want to exit?"))
+ goto out_free_stack;
+
continue;
}
top = pstack__peek(browser->pstack);
@@ -1892,12 +1904,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
do_zoom_thread(browser, actions);
continue;
}
- case K_ESC:
- if (!left_exits &&
- !ui_browser__dialog_yesno(&browser->b,
- "Do you really want to exit?"))
- continue;
- /* Fall thru */
case 'q':
case CTRL('c'):
goto out_free_stack;
@@ -2044,7 +2050,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
nr_events = convert_unit(nr_events, &unit);
printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
unit, unit == ' ' ? "" : " ", ev_name);
- slsmg_printf("%s", bf);
+ ui_browser__printf(browser, "%s", bf);
nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
if (nr_events != 0) {
@@ -2057,7 +2063,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
warn = bf;
}
- slsmg_write_nstring(warn, browser->width - printed);
+ ui_browser__write_nstring(browser, warn, browser->width - printed);
if (current_entry)
menu->selection = evsel;
@@ -2120,15 +2126,11 @@ browse_hists:
else
pos = perf_evsel__prev(pos);
goto browse_hists;
- case K_ESC:
- if (!ui_browser__dialog_yesno(&menu->b,
- "Do you really want to exit?"))
- continue;
- /* Fall thru */
case K_SWITCH_INPUT_DATA:
case 'q':
case CTRL('c'):
goto out;
+ case K_ESC:
default:
continue;
}
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index b11639f33682..8c154c7d4669 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -1,4 +1,3 @@
-#include "../libslang.h"
#include <elf.h>
#include <inttypes.h>
#include <sys/ttydefaults.h>
@@ -26,13 +25,13 @@ static void map_browser__write(struct ui_browser *browser, void *nd, int row)
int width;
ui_browser__set_percent_color(browser, 0, current_entry);
- slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
- mb->addrlen, sym->start, mb->addrlen, sym->end,
- sym->binding == STB_GLOBAL ? 'g' :
- sym->binding == STB_LOCAL ? 'l' : 'w');
+ ui_browser__printf(browser, "%*" PRIx64 " %*" PRIx64 " %c ",
+ mb->addrlen, sym->start, mb->addrlen, sym->end,
+ sym->binding == STB_GLOBAL ? 'g' :
+ sym->binding == STB_LOCAL ? 'l' : 'w');
width = browser->width - ((mb->addrlen * 2) + 4);
if (width > 0)
- slsmg_write_nstring(sym->name, width);
+ ui_browser__write_nstring(browser, sym->name, width);
}
/* FIXME uber-kludgy, see comment on cmd_report... */
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
index 402d2bd30b09..e13b48d705ef 100644
--- a/tools/perf/ui/browsers/scripts.c
+++ b/tools/perf/ui/browsers/scripts.c
@@ -81,7 +81,7 @@ static void script_browser__write(struct ui_browser *browser,
ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
HE_COLORSET_NORMAL);
- slsmg_write_nstring(sline->line, browser->width);
+ ui_browser__write_nstring(browser, sline->line, browser->width);
}
static int script_browser__run(struct perf_script_browser *browser)
diff --git a/tools/perf/ui/libslang.h b/tools/perf/ui/libslang.h
index 4d54b6450f5b..db816695ad97 100644
--- a/tools/perf/ui/libslang.h
+++ b/tools/perf/ui/libslang.h
@@ -14,12 +14,15 @@
#if SLANG_VERSION < 20104
#define slsmg_printf(msg, args...) \
SLsmg_printf((char *)(msg), ##args)
+#define slsmg_vprintf(msg, vargs) \
+ SLsmg_vprintf((char *)(msg), vargs)
#define slsmg_write_nstring(msg, len) \
SLsmg_write_nstring((char *)(msg), len)
#define sltt_set_color(obj, name, fg, bg) \
SLtt_set_color(obj,(char *)(name), (char *)(fg), (char *)(bg))
#else
#define slsmg_printf SLsmg_printf
+#define slsmg_vprintf SLsmg_vprintf
#define slsmg_write_nstring SLsmg_write_nstring
#define sltt_set_color SLtt_set_color
#endif
diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c
index bf890f72fe80..d96ad7c8325d 100644
--- a/tools/perf/ui/tui/util.c
+++ b/tools/perf/ui/tui/util.c
@@ -21,7 +21,7 @@ static void ui_browser__argv_write(struct ui_browser *browser,
ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
HE_COLORSET_NORMAL);
- slsmg_write_nstring(*arg, browser->width);
+ ui_browser__write_nstring(browser, *arg, browser->width);
}
static int popup_menu__run(struct ui_browser *menu)
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 57f3ef41c2bc..445f455dd377 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -734,15 +734,18 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
Dwarf_Lines *lines;
Dwarf_Line *line;
Dwarf_Addr addr;
- const char *fname;
+ const char *fname, *decf = NULL;
int lineno, ret = 0;
+ int decl = 0, inl;
Dwarf_Die die_mem, *cu_die;
size_t nlines, i;
/* Get the CU die */
- if (dwarf_tag(rt_die) != DW_TAG_compile_unit)
+ if (dwarf_tag(rt_die) != DW_TAG_compile_unit) {
cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL);
- else
+ dwarf_decl_line(rt_die, &decl);
+ decf = dwarf_decl_file(rt_die);
+ } else
cu_die = rt_die;
if (!cu_die) {
pr_debug2("Failed to get CU from given DIE.\n");
@@ -773,9 +776,14 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
* The line is included in given function, and
* no inline block includes it.
*/
- if (!dwarf_haspc(rt_die, addr) ||
- die_find_inlinefunc(rt_die, addr, &die_mem))
+ if (!dwarf_haspc(rt_die, addr))
continue;
+ if (die_find_inlinefunc(rt_die, addr, &die_mem)) {
+ dwarf_decl_line(&die_mem, &inl);
+ if (inl != decl ||
+ decf != dwarf_decl_file(&die_mem))
+ continue;
+ }
/* Get source line */
fname = dwarf_linesrc(line, NULL, NULL);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 04fddddc6b6f..b096ef7a240c 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -588,11 +588,36 @@ perf_evsel__config_callgraph(struct perf_evsel *evsel,
}
}
-static void apply_config_terms(struct perf_evsel *evsel)
+static void
+perf_evsel__reset_callgraph(struct perf_evsel *evsel,
+ struct callchain_param *param)
+{
+ struct perf_event_attr *attr = &evsel->attr;
+
+ perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
+ if (param->record_mode == CALLCHAIN_LBR) {
+ perf_evsel__reset_sample_bit(evsel, BRANCH_STACK);
+ attr->branch_sample_type &= ~(PERF_SAMPLE_BRANCH_USER |
+ PERF_SAMPLE_BRANCH_CALL_STACK);
+ }
+ if (param->record_mode == CALLCHAIN_DWARF) {
+ perf_evsel__reset_sample_bit(evsel, REGS_USER);
+ perf_evsel__reset_sample_bit(evsel, STACK_USER);
+ }
+}
+
+static void apply_config_terms(struct perf_evsel *evsel,
+ struct record_opts *opts)
{
struct perf_evsel_config_term *term;
struct list_head *config_terms = &evsel->config_terms;
struct perf_event_attr *attr = &evsel->attr;
+ struct callchain_param param;
+ u32 dump_size = 0;
+ char *callgraph_buf = NULL;
+
+ /* callgraph default */
+ param.record_mode = callchain_param.record_mode;
list_for_each_entry(term, config_terms, list) {
switch (term->type) {
@@ -610,10 +635,48 @@ static void apply_config_terms(struct perf_evsel *evsel)
else
perf_evsel__reset_sample_bit(evsel, TIME);
break;
+ case PERF_EVSEL__CONFIG_TERM_CALLGRAPH:
+ callgraph_buf = term->val.callgraph;
+ break;
+ case PERF_EVSEL__CONFIG_TERM_STACK_USER:
+ dump_size = term->val.stack_user;
+ break;
default:
break;
}
}
+
+ /* User explicitly set per-event callgraph, clear the old setting and reset. */
+ if ((callgraph_buf != NULL) || (dump_size > 0)) {
+
+ /* parse callgraph parameters */
+ if (callgraph_buf != NULL) {
+ if (!strcmp(callgraph_buf, "no")) {
+ param.enabled = false;
+ param.record_mode = CALLCHAIN_NONE;
+ } else {
+ param.enabled = true;
+ if (parse_callchain_record(callgraph_buf, &param)) {
+ pr_err("per-event callgraph setting for %s failed. "
+ "Apply callgraph global setting for it\n",
+ evsel->name);
+ return;
+ }
+ }
+ }
+ if (dump_size > 0) {
+ dump_size = round_up(dump_size, sizeof(u64));
+ param.dump_size = dump_size;
+ }
+
+ /* If global callgraph set, clear it */
+ if (callchain_param.enabled)
+ perf_evsel__reset_callgraph(evsel, &callchain_param);
+
+ /* set perf-event callgraph */
+ if (param.enabled)
+ perf_evsel__config_callgraph(evsel, opts, &param);
+ }
}
/*
@@ -812,7 +875,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
* Apply event specific term settings,
* it overloads any global configuration.
*/
- apply_config_terms(evsel);
+ apply_config_terms(evsel, opts);
}
static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index fdf2674ab339..93ac6b128149 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -41,6 +41,8 @@ enum {
PERF_EVSEL__CONFIG_TERM_PERIOD,
PERF_EVSEL__CONFIG_TERM_FREQ,
PERF_EVSEL__CONFIG_TERM_TIME,
+ PERF_EVSEL__CONFIG_TERM_CALLGRAPH,
+ PERF_EVSEL__CONFIG_TERM_STACK_USER,
PERF_EVSEL__CONFIG_TERM_MAX,
};
@@ -51,6 +53,8 @@ struct perf_evsel_config_term {
u64 period;
u64 freq;
bool time;
+ char *callgraph;
+ u64 stack_user;
} val;
};
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 6bccfae334b1..08b6cd945f1e 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1109,13 +1109,14 @@ void hists__inc_stats(struct hists *hists, struct hist_entry *h)
static void __hists__insert_output_entry(struct rb_root *entries,
struct hist_entry *he,
- u64 min_callchain_hits)
+ u64 min_callchain_hits,
+ bool use_callchain)
{
struct rb_node **p = &entries->rb_node;
struct rb_node *parent = NULL;
struct hist_entry *iter;
- if (symbol_conf.use_callchain)
+ if (use_callchain)
callchain_param.sort(&he->sorted_chain, he->callchain,
min_callchain_hits, &callchain_param);
@@ -1139,6 +1140,13 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
struct rb_node *next;
struct hist_entry *n;
u64 min_callchain_hits;
+ struct perf_evsel *evsel = hists_to_evsel(hists);
+ bool use_callchain;
+
+ if (evsel && !symbol_conf.show_ref_callgraph)
+ use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN;
+ else
+ use_callchain = symbol_conf.use_callchain;
min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
@@ -1157,7 +1165,7 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
n = rb_entry(next, struct hist_entry, rb_node_in);
next = rb_next(&n->rb_node_in);
- __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
+ __hists__insert_output_entry(&hists->entries, n, min_callchain_hits, use_callchain);
hists__inc_stats(hists, n);
if (!n->filtered)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index dbf315df4220..d826e6f515db 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -614,6 +614,12 @@ do { \
return -EINVAL;
}
break;
+ case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
+ CHECK_TYPE_VAL(STR);
+ break;
+ case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
+ CHECK_TYPE_VAL(NUM);
+ break;
case PARSE_EVENTS__TERM_TYPE_NAME:
CHECK_TYPE_VAL(STR);
break;
@@ -668,6 +674,12 @@ do { \
case PARSE_EVENTS__TERM_TYPE_TIME:
ADD_CONFIG_TERM(TIME, time, term->val.num);
break;
+ case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
+ ADD_CONFIG_TERM(CALLGRAPH, callgraph, term->val.str);
+ break;
+ case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
+ ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num);
+ break;
default:
break;
}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index ce2d13a16226..a09b0e210997 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -65,6 +65,8 @@ enum {
PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ,
PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
PARSE_EVENTS__TERM_TYPE_TIME,
+ PARSE_EVENTS__TERM_TYPE_CALLGRAPH,
+ PARSE_EVENTS__TERM_TYPE_STACKSIZE,
};
struct parse_events_term {
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 4306f5ad75c7..936d566f48d8 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -185,6 +185,8 @@ period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
freq { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ); }
branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); }
+call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); }
+stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); }
, { return ','; }
"/" { BEGIN(INITIAL); return '/'; }
{name_minus} { return str(yyscanner, PE_NAME); }
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index d85f11b8cacf..84cad054d6f7 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -634,7 +634,9 @@ static char *formats_error_string(struct list_head *formats)
{
struct perf_pmu_format *format;
char *err, *str;
- static const char *static_terms = "config,config1,config2,name,period,freq,branch_type,time\n";
+ static const char *static_terms = "config,config1,config2,name,"
+ "period,freq,branch_type,time,"
+ "call-graph,stack-size\n";
unsigned i = 0;
if (!asprintf(&str, "valid terms:"))
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index c0c32b050e45..7e3871606df3 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -330,6 +330,8 @@ static char *get_srcfile(struct hist_entry *e)
sf = get_srcline(map->dso, map__rip_2objdump(map, e->ip),
e->ms.sym, true);
+ if (!strcmp(sf, SRCLINE_UNKNOWN))
+ return no_srcfile;
p = strchr(sf, ':');
if (p && *sf) {
*p = 0;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index b98ce51af142..a4cde92afbad 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -106,7 +106,8 @@ struct symbol_conf {
filter_relative,
show_hist_headers,
branch_callstack,
- has_filter;
+ has_filter,
+ show_ref_callgraph;
const char *vmlinux_name,
*kallsyms_name,
*source_prefix,