Hi Ingo,
Please consider pulling,
- Arnaldo
The following changes since commit e227051b13956b8f71c0abecc41ad351e64671c8:
uprobes: Remove the unnecessary initialization in add_utask() (2012-06-16 09:10:52 +0200)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux tags/perf-core-for-mingo
for you to fetch changes up to c0a58fb2bdf033df433cad9009c7dac4c6b872b0:
perf annotate: Check null of sym pointer before using it (2012-06-19 14:30:26 -0300)
----------------------------------------------------------------
perf/core improvements and fixes
. Replace event_name with perf_evsel__name, that handles the event modifiers
and doesn't use static variables.
. GTK browser improvements, from Namhyung Kim
. Fix possible NULL pointer deref in the TUI annotate browser, from Samuel Liao
. Add sort by source file:line number, using addr2line.
. Allow printing histogram text snapshots at any point in top/report.
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
----------------------------------------------------------------
Arnaldo Carvalho de Melo (13):
perf tools: Add sort by src line/number
perf lib: Introduce rtrim
perf hists browser: Implement printing snapshots to files
perf evsel: Carve out event modifier formatting
perf tools: Reconstruct hw cache event with modifiers from perf_event_attr
perf tools: Reconstruct sw event with modifiers from perf_event_attr
perf evsel: Handle all event types in perf_evsel__name
perf tools: Move all users of event_name to perf_evsel__name
perf script: Replace __event_name uses with perf_evsel__name
perf tools: Don't access evsel->name directly
perf tools: Remove __event_name
perf evsel: Reconstruct raw event with modifiers from perf_event_attr
perf evsel: Make some methods private
Jiri Olsa (1):
perf tools: Remove unused evsel parameter from machine__resolve_callchain
Namhyung Kim (5):
perf ui: Introduce struct perf_error_ops
perf ui/gtk: Introduce struct perf_gtk_context
perf ui/gtk: Add GTK statusbar widget to browser window
perf ui/gtk: Add GTK info_bar widget to browser window
perf ui/gtk: Use struct perf_error_ops
Samuel Liao (1):
perf annotate: Check null of sym pointer before using it
tools/perf/Documentation/perf-report.txt | 2 +-
tools/perf/Documentation/perf-top.txt | 2 +-
tools/perf/Makefile | 6 +
tools/perf/builtin-evlist.c | 2 +-
tools/perf/builtin-record.c | 4 +-
tools/perf/builtin-report.c | 10 +-
tools/perf/builtin-sched.c | 2 +-
tools/perf/builtin-script.c | 42 ++---
tools/perf/builtin-stat.c | 12 +-
tools/perf/builtin-test.c | 2 +-
tools/perf/builtin-top.c | 12 +-
tools/perf/config/feature-tests.mak | 13 ++
tools/perf/ui/browsers/annotate.c | 4 +-
tools/perf/ui/browsers/hists.c | 210 ++++++++++++++++++++--
tools/perf/ui/gtk/browser.c | 69 +++++++-
tools/perf/ui/gtk/gtk.h | 31 ++++
tools/perf/ui/gtk/setup.c | 5 +
tools/perf/ui/gtk/util.c | 129 ++++++++++++++
tools/perf/ui/tui/setup.c | 6 +
tools/perf/ui/tui/util.c | 243 ++++++++++++++++++++++++++
tools/perf/ui/util.c | 277 ++++++------------------------
tools/perf/ui/util.h | 9 +-
tools/perf/util/debug.c | 2 +-
tools/perf/util/debug.h | 23 ++-
tools/perf/util/evsel.c | 196 ++++++++++++++++++---
tools/perf/util/evsel.h | 15 +-
tools/perf/util/header.c | 2 +-
tools/perf/util/hist.h | 1 +
tools/perf/util/map.h | 2 +-
tools/perf/util/parse-events-test.c | 4 +-
tools/perf/util/parse-events.c | 203 ++--------------------
tools/perf/util/parse-events.h | 2 -
tools/perf/util/session.c | 9 +-
tools/perf/util/session.h | 4 +-
tools/perf/util/sort.c | 49 ++++++
tools/perf/util/sort.h | 2 +
tools/perf/util/string.c | 22 +++
tools/perf/util/top.c | 2 +-
tools/perf/util/util.h | 2 +
39 files changed, 1118 insertions(+), 514 deletions(-)
create mode 100644 tools/perf/ui/gtk/util.c
create mode 100644 tools/perf/ui/tui/util.c
From: Arnaldo Carvalho de Melo <[email protected]>
Remove the trailing whitespaces.
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/string.c | 22 ++++++++++++++++++++++
tools/perf/util/util.h | 2 ++
2 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index d583638..199bc4d 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -313,3 +313,25 @@ int strtailcmp(const char *s1, const char *s2)
return 0;
}
+/**
+ * rtrim - Removes trailing whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Note that the first trailing whitespace is replaced with a %NUL-terminator
+ * in the given string @s. Returns @s.
+ */
+char *rtrim(char *s)
+{
+ size_t size = strlen(s);
+ char *end;
+
+ if (!size)
+ return s;
+
+ end = s + size - 1;
+ while (end >= s && isspace(*end))
+ end--;
+ *(end + 1) = '\0';
+
+ return s;
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 2daaedb..b13c733 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -264,4 +264,6 @@ bool is_power_of_2(unsigned long n)
size_t hex_width(u64 v);
+char *rtrim(char *s);
+
#endif
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
No logic change, just remove one more user of __event_name().
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-script.c | 38 ++++++++++++++++++++------------------
1 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 8e395a5..8f9f9b6 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -137,10 +137,11 @@ static const char *output_field2str(enum perf_output_field field)
#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x)
-static int perf_event_attr__check_stype(struct perf_event_attr *attr,
- u64 sample_type, const char *sample_msg,
- enum perf_output_field field)
+static int perf_evsel__check_stype(struct perf_evsel *evsel,
+ u64 sample_type, const char *sample_msg,
+ enum perf_output_field field)
{
+ struct perf_event_attr *attr = &evsel->attr;
int type = attr->type;
const char *evname;
@@ -148,7 +149,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr,
return 0;
if (output[type].user_set) {
- evname = __event_name(attr->type, attr->config);
+ evname = perf_evsel__name(evsel);
pr_err("Samples for '%s' event do not have %s attribute set. "
"Cannot print '%s' field.\n",
evname, sample_msg, output_field2str(field));
@@ -157,7 +158,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr,
/* user did not ask for it explicitly so remove from the default list */
output[type].fields &= ~field;
- evname = __event_name(attr->type, attr->config);
+ evname = perf_evsel__name(evsel);
pr_debug("Samples for '%s' event do not have %s attribute set. "
"Skipping '%s' field.\n",
evname, sample_msg, output_field2str(field));
@@ -175,8 +176,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
return -EINVAL;
if (PRINT_FIELD(IP)) {
- if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
- PERF_OUTPUT_IP))
+ if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
+ PERF_OUTPUT_IP))
return -EINVAL;
if (!no_callchain &&
@@ -185,8 +186,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
}
if (PRINT_FIELD(ADDR) &&
- perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR",
- PERF_OUTPUT_ADDR))
+ perf_evsel__check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR",
+ PERF_OUTPUT_ADDR))
return -EINVAL;
if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
@@ -208,18 +209,18 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
}
if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
- perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
- PERF_OUTPUT_TID|PERF_OUTPUT_PID))
+ perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID",
+ PERF_OUTPUT_TID|PERF_OUTPUT_PID))
return -EINVAL;
if (PRINT_FIELD(TIME) &&
- perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME",
- PERF_OUTPUT_TIME))
+ perf_evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME",
+ PERF_OUTPUT_TIME))
return -EINVAL;
if (PRINT_FIELD(CPU) &&
- perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU",
- PERF_OUTPUT_CPU))
+ perf_evsel__check_stype(evsel, PERF_SAMPLE_CPU, "CPU",
+ PERF_OUTPUT_CPU))
return -EINVAL;
return 0;
@@ -258,9 +259,10 @@ static int perf_session__check_output_opt(struct perf_session *session)
static void print_sample_start(struct perf_sample *sample,
struct thread *thread,
- struct perf_event_attr *attr)
+ struct perf_evsel *evsel)
{
int type;
+ struct perf_event_attr *attr = &evsel->attr;
struct event_format *event;
const char *evname = NULL;
unsigned long secs;
@@ -305,7 +307,7 @@ static void print_sample_start(struct perf_sample *sample,
if (event)
evname = event->name;
} else
- evname = __event_name(attr->type, attr->config);
+ evname = perf_evsel__name(evsel);
printf("%s: ", evname ? evname : "[unknown]");
}
@@ -412,7 +414,7 @@ static void process_event(union perf_event *event __unused,
if (output[attr->type].fields == 0)
return;
- print_sample_start(sample, thread, attr);
+ print_sample_start(sample, thread, evsel);
if (is_bts_event(attr)) {
print_sample_bts(event, sample, evsel, machine, thread);
--
1.7.1
From: Jiri Olsa <[email protected]>
Removing unused evsel parameter from machine__resolve_callchain
function. Plus related header file and callers changes.
The evsel parameter is unused since following commit:
perf callchain: Make callchain cursors TLS
commit 472606458f3e1ced5fe3cc5f04e90a6b5a4732cf
Author: Namhyung Kim <[email protected]>
Date: Thu May 31 14:43:26 2012 +0900
Signed-off-by: Jiri Olsa <[email protected]>
Cc: Arun Sharma <[email protected]>
Cc: Benjamin Redelings <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Cyrill Gorcunov <[email protected]>
Cc: Frank Ch. Eigler <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Masami Hiramatsu <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Robert Richter <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Tom Zanussi <[email protected]>
Cc: Ulrich Drepper <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-report.c | 4 ++--
tools/perf/builtin-script.c | 4 ++--
tools/perf/builtin-top.c | 2 +-
tools/perf/util/map.h | 2 +-
tools/perf/util/session.c | 7 +++----
tools/perf/util/session.h | 4 ++--
6 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index ea8ce8e..40b0ffc 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -69,7 +69,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
if ((sort__has_parent || symbol_conf.use_callchain)
&& sample->callchain) {
- err = machine__resolve_callchain(machine, evsel, al->thread,
+ err = machine__resolve_callchain(machine, al->thread,
sample->callchain, &parent);
if (err)
return err;
@@ -140,7 +140,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
struct hist_entry *he;
if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
- err = machine__resolve_callchain(machine, evsel, al->thread,
+ err = machine__resolve_callchain(machine, al->thread,
sample->callchain, &parent);
if (err)
return err;
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 8f9f9b6..8fecd3b 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -389,7 +389,7 @@ static void print_sample_bts(union perf_event *event,
printf(" ");
else
printf("\n");
- perf_event__print_ip(event, sample, machine, evsel,
+ perf_event__print_ip(event, sample, machine,
PRINT_FIELD(SYM), PRINT_FIELD(DSO),
PRINT_FIELD(SYMOFFSET));
}
@@ -433,7 +433,7 @@ static void process_event(union perf_event *event __unused,
printf(" ");
else
printf("\n");
- perf_event__print_ip(event, sample, machine, evsel,
+ perf_event__print_ip(event, sample, machine,
PRINT_FIELD(SYM), PRINT_FIELD(DSO),
PRINT_FIELD(SYMOFFSET));
}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 8090a28..e3cab5f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -774,7 +774,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
if ((sort__has_parent || symbol_conf.use_callchain) &&
sample->callchain) {
- err = machine__resolve_callchain(machine, evsel, al.thread,
+ err = machine__resolve_callchain(machine, al.thread,
sample->callchain, &parent);
if (err)
return;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 81371ba..c14c665 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -157,7 +157,7 @@ void machine__exit(struct machine *self);
void machine__delete(struct machine *self);
int machine__resolve_callchain(struct machine *machine,
- struct perf_evsel *evsel, struct thread *thread,
+ struct thread *thread,
struct ip_callchain *chain,
struct symbol **parent);
int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 582ee38..febc0ae 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -289,7 +289,6 @@ struct branch_info *machine__resolve_bstack(struct machine *self,
}
int machine__resolve_callchain(struct machine *self,
- struct perf_evsel *evsel __used,
struct thread *thread,
struct ip_callchain *chain,
struct symbol **parent)
@@ -1480,8 +1479,8 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
}
void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
- struct machine *machine, struct perf_evsel *evsel,
- int print_sym, int print_dso, int print_symoffset)
+ struct machine *machine, int print_sym,
+ int print_dso, int print_symoffset)
{
struct addr_location al;
struct callchain_cursor_node *node;
@@ -1495,7 +1494,7 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
if (symbol_conf.use_callchain && sample->callchain) {
- if (machine__resolve_callchain(machine, evsel, al.thread,
+ if (machine__resolve_callchain(machine, al.thread,
sample->callchain, NULL) != 0) {
if (verbose)
error("Failed to resolve callchain. Skipping\n");
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 7a5434c..877d781 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -150,8 +150,8 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
unsigned int type);
void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
- struct machine *machine, struct perf_evsel *evsel,
- int print_sym, int print_dso, int print_symoffset);
+ struct machine *machine, int print_sym,
+ int print_dso, int print_symoffset);
int perf_session__cpu_bitmap(struct perf_session *session,
const char *cpu_list, unsigned long *cpu_bitmap);
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
[root@sandy ~]# perf record -e task-clock:u -a usleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.482 MB perf.data (~21073 samples) ]
[root@sandy ~]#
Before:
[root@sandy ~]# perf evlist
task-clock
[root@sandy ~]#
After:
[root@sandy ~]# perf evlist
task-clock:u
[root@sandy ~]#
Ditto for other tools.
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/evsel.c | 29 +++++++++++++++++++++++++++++
tools/perf/util/evsel.h | 2 ++
tools/perf/util/parse-events.c | 19 +++----------------
3 files changed, 34 insertions(+), 16 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 47f1fe2..2da0473 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -128,6 +128,31 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
}
+static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
+ "cpu-clock",
+ "task-clock",
+ "page-faults",
+ "context-switches",
+ "CPU-migrations",
+ "minor-faults",
+ "major-faults",
+ "alignment-faults",
+ "emulation-faults",
+};
+
+const char *__perf_evsel__sw_name(u64 config)
+{
+ if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config])
+ return perf_evsel__sw_names[config];
+ return "unknown-software";
+}
+
+static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+ int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config));
+ return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
+}
+
const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
[PERF_EVSEL__MAX_ALIASES] = {
{ "L1-dcache", "l1-d", "l1d", "L1-data", },
@@ -244,6 +269,10 @@ int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
ret = perf_evsel__hw_cache_name(evsel, bf, size);
break;
+ case PERF_TYPE_SOFTWARE:
+ ret = perf_evsel__sw_name(evsel, bf, size);
+ break;
+
default:
/*
* FIXME
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 5bf946a..9ae64d9 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -98,6 +98,8 @@ int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size);
const char *__perf_evsel__hw_name(u64 config);
+const char *__perf_evsel__sw_name(u64 config);
+
int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size);
int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c8f8cf4..641c4ac 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -62,18 +62,6 @@ static struct event_symbol event_symbols[] = {
#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
-static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
- "cpu-clock",
- "task-clock",
- "page-faults",
- "context-switches",
- "CPU-migrations",
- "minor-faults",
- "major-faults",
- "alignment-faults",
- "emulation-faults",
-};
-
#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \
while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
if (sys_dirent.d_type == DT_DIR && \
@@ -218,7 +206,8 @@ const char *event_name(struct perf_evsel *evsel)
u64 config = evsel->attr.config;
int type = evsel->attr.type;
- if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE) {
+ if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE ||
+ type == PERF_TYPE_SOFTWARE || type == PERF_TYPE_HW_CACHE) {
/*
* XXX minimal fix, see comment on perf_evsen__name, this static buffer
* will go away together with event_name in the next devel cycle.
@@ -252,9 +241,7 @@ const char *__event_name(int type, u64 config)
return buf;
case PERF_TYPE_SOFTWARE:
- if (config < PERF_COUNT_SW_MAX && sw_event_names[config])
- return sw_event_names[config];
- return "unknown-software";
+ return __perf_evsel__sw_name(config);
case PERF_TYPE_TRACEPOINT:
return tracepoint_id_to_name(config);
--
1.7.1
From: Samuel Liao <[email protected]>
Sym may be NULL, and that will cause perf to crash.
Signed-off-by: Shan Wei <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/ui/browsers/annotate.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 34b1c46..67a2703 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -814,7 +814,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
{
struct disasm_line *pos, *n;
struct annotation *notes;
- const size_t size = symbol__size(sym);
+ size_t size;
struct map_symbol ms = {
.map = map,
.sym = sym,
@@ -834,6 +834,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
if (sym == NULL)
return -1;
+ size = symbol__size(sym);
+
if (map->dso->annotate_warned)
return -1;
--
1.7.1
From: Namhyung Kim <[email protected]>
The struct perf_gtk_context is for tracking current state of GTK window
and/or other things. This is a preparation of next changes.
Signed-off-by: Namhyung Kim <[email protected]>
Acked-by: Pekka Enberg <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Pekka Enberg <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/ui/gtk/browser.c | 8 +++++++-
tools/perf/ui/gtk/gtk.h | 17 +++++++++++++++++
tools/perf/ui/gtk/util.c | 23 +++++++++++++++++++++++
3 files changed, 47 insertions(+), 1 deletions(-)
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 0656c38..33ab1ae 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -11,8 +11,8 @@
static void perf_gtk__signal(int sig)
{
+ perf_gtk__exit(false);
psignal(sig, "perf");
- gtk_main_quit();
}
static void perf_gtk__resize_window(GtkWidget *window)
@@ -143,6 +143,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
+ pgctx = perf_gtk__activate_context(window);
+ if (!pgctx)
+ return -1;
+
notebook = gtk_notebook_new();
list_for_each_entry(pos, &evlist->entries, node) {
@@ -174,5 +178,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
gtk_main();
+ perf_gtk__deactivate_context(&pgctx);
+
return 0;
}
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 75177ee..34fbca6 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -1,8 +1,25 @@
#ifndef _PERF_GTK_H_
#define _PERF_GTK_H_ 1
+#include <stdbool.h>
+
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#include <gtk/gtk.h>
#pragma GCC diagnostic error "-Wstrict-prototypes"
+
+struct perf_gtk_context {
+ GtkWidget *main_window;
+};
+
+extern struct perf_gtk_context *pgctx;
+
+static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx)
+{
+ return ctx && ctx->main_window;
+}
+
+struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
+int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
+
#endif /* _PERF_GTK_H_ */
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
index a727fe3..6fe13fd 100644
--- a/tools/perf/ui/gtk/util.c
+++ b/tools/perf/ui/gtk/util.c
@@ -3,6 +3,29 @@
#include "gtk.h"
+struct perf_gtk_context *pgctx;
+
+struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window)
+{
+ struct perf_gtk_context *ctx;
+
+ ctx = malloc(sizeof(*pgctx));
+ if (ctx)
+ ctx->main_window = window;
+
+ return ctx;
+}
+
+int perf_gtk__deactivate_context(struct perf_gtk_context **ctx)
+{
+ if (!perf_gtk__is_active_context(*ctx))
+ return -1;
+
+ free(*ctx);
+ *ctx = NULL;
+ return 0;
+}
+
/*
* FIXME: Functions below should be implemented properly.
* For now, just add stubs for NO_NEWT=1 build.
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
So that we don't use global variables that could make us misreport event
names when having a multi window top, for instance.
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-evlist.c | 2 +-
tools/perf/builtin-record.c | 4 ++--
tools/perf/builtin-report.c | 6 +++---
tools/perf/builtin-stat.c | 12 ++++++------
tools/perf/builtin-test.c | 2 +-
tools/perf/builtin-top.c | 10 +++++-----
tools/perf/ui/browsers/hists.c | 15 ++++-----------
tools/perf/ui/gtk/browser.c | 2 +-
tools/perf/util/evsel.c | 26 +++++++++++++-------------
tools/perf/util/evsel.h | 2 +-
tools/perf/util/header.c | 2 +-
tools/perf/util/parse-events.c | 7 -------
tools/perf/util/parse-events.h | 1 -
tools/perf/util/session.c | 2 +-
tools/perf/util/top.c | 2 +-
15 files changed, 40 insertions(+), 55 deletions(-)
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index acd78dc..0dd5a05 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -60,7 +60,7 @@ static int __cmd_evlist(const char *input_name, struct perf_attr_details *detail
list_for_each_entry(pos, &session->evlist->entries, node) {
bool first = true;
- printf("%s", event_name(pos));
+ printf("%s", perf_evsel__name(pos));
if (details->verbose || details->freq) {
comma_printf(&first, " sample_freq=%" PRIu64,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f95840d..f5a6452 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -265,7 +265,7 @@ try_again:
if (err == ENOENT) {
ui__error("The %s event is not supported.\n",
- event_name(pos));
+ perf_evsel__name(pos));
exit(EXIT_FAILURE);
}
@@ -916,7 +916,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
usage_with_options(record_usage, record_options);
list_for_each_entry(pos, &evsel_list->entries, node) {
- if (perf_header__push_event(pos->attr.config, event_name(pos)))
+ if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
goto out_free_fd;
}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 25249f7..ea8ce8e 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -230,7 +230,7 @@ static int process_read_event(struct perf_tool *tool,
struct perf_report *rep = container_of(tool, struct perf_report, tool);
if (rep->show_threads) {
- const char *name = evsel ? event_name(evsel) : "unknown";
+ const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
perf_read_values_add_value(&rep->show_threads_values,
event->read.pid, event->read.tid,
event->read.id,
@@ -239,7 +239,7 @@ static int process_read_event(struct perf_tool *tool,
}
dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
- evsel ? event_name(evsel) : "FAIL",
+ evsel ? perf_evsel__name(evsel) : "FAIL",
event->read.value);
return 0;
@@ -314,7 +314,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
list_for_each_entry(pos, &evlist->entries, node) {
struct hists *hists = &pos->hists;
- const char *evname = event_name(pos);
+ const char *evname = perf_evsel__name(pos);
hists__fprintf_nr_sample_events(hists, evname, stdout);
hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 2625899..875bf26 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -391,7 +391,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
if (verbose) {
fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
- event_name(counter), count[0], count[1], count[2]);
+ perf_evsel__name(counter), count[0], count[1], count[2]);
}
/*
@@ -496,7 +496,7 @@ static int run_perf_stat(int argc __used, const char **argv)
errno == ENXIO) {
if (verbose)
ui__warning("%s event is not supported by the kernel.\n",
- event_name(counter));
+ perf_evsel__name(counter));
counter->supported = false;
continue;
}
@@ -594,7 +594,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
csv_output ? 0 : -4,
evsel_list->cpus->map[cpu], csv_sep);
- fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel));
+ fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel));
if (evsel->cgrp)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -792,7 +792,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
else
cpu = 0;
- fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel));
+ fprintf(output, fmt, cpustr, avg, csv_sep, perf_evsel__name(evsel));
if (evsel->cgrp)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -908,7 +908,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
csv_sep,
csv_output ? 0 : -24,
- event_name(counter));
+ perf_evsel__name(counter));
if (counter->cgrp)
fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
@@ -961,7 +961,7 @@ static void print_counter(struct perf_evsel *counter)
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
csv_sep,
csv_output ? 0 : -24,
- event_name(counter));
+ perf_evsel__name(counter));
if (counter->cgrp)
fprintf(output, "%s%s",
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 5a8727c..5ce3030 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -583,7 +583,7 @@ static int test__basic_mmap(void)
if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
pr_debug("expected %d %s events, got %d\n",
expected_nr_events[evsel->idx],
- event_name(evsel), nr_events[evsel->idx]);
+ perf_evsel__name(evsel), nr_events[evsel->idx]);
goto out_munmap;
}
}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 6bb0277..8090a28 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -245,7 +245,7 @@ static void perf_top__show_details(struct perf_top *top)
if (notes->src == NULL)
goto out_unlock;
- printf("Showing %s for %s\n", event_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);
more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx,
@@ -408,7 +408,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top)
fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries);
if (top->evlist->nr_entries > 1)
- fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top->sym_evsel));
+ fprintf(stdout, "\t[E] active event counter. \t(%s)\n", perf_evsel__name(top->sym_evsel));
fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter);
@@ -503,13 +503,13 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
fprintf(stderr, "\nAvailable events:");
list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
- fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel));
+ fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel));
prompt_integer(&counter, "Enter details event counter");
if (counter >= top->evlist->nr_entries) {
top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
- fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel));
+ fprintf(stderr, "Sorry, no such event, using %s.\n", perf_evsel__name(top->sym_evsel));
sleep(1);
break;
}
@@ -960,7 +960,7 @@ try_again:
if (err == ENOENT) {
ui__error("The %s event is not supported.\n",
- event_name(counter));
+ perf_evsel__name(counter));
goto out_err;
} else if (err == EMFILE) {
ui__error("Too many events are opened.\n"
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index f556e5f..482f051 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1367,7 +1367,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
bool current_entry = ui_browser__is_current_entry(browser, row);
unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
- const char *ev_name = event_name(evsel);
+ const char *ev_name = perf_evsel__name(evsel);
char bf[256], unit;
const char *warn = " ";
size_t printed;
@@ -1435,7 +1435,7 @@ browse_hists:
*/
if (timer)
timer(arg);
- ev_name = event_name(pos);
+ ev_name = perf_evsel__name(pos);
key = perf_evsel__hists_browse(pos, nr_events, help,
ev_name, true, timer,
arg, delay_secs);
@@ -1504,17 +1504,11 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
ui_helpline__push("Press ESC to exit");
list_for_each_entry(pos, &evlist->entries, node) {
- const char *ev_name = event_name(pos);
+ const char *ev_name = perf_evsel__name(pos);
size_t line_len = strlen(ev_name) + 7;
if (menu.b.width < line_len)
menu.b.width = line_len;
- /*
- * Cache the evsel name, tracepoints have a _high_ cost per
- * event_name() call.
- */
- if (pos->name == NULL)
- pos->name = strdup(ev_name);
}
return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
@@ -1525,11 +1519,10 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
void(*timer)(void *arg), void *arg,
int delay_secs)
{
-
if (evlist->nr_entries == 1) {
struct perf_evsel *first = list_entry(evlist->entries.next,
struct perf_evsel, node);
- const char *ev_name = event_name(first);
+ const char *ev_name = perf_evsel__name(first);
return perf_evsel__hists_browse(first, evlist->nr_entries, help,
ev_name, false, timer, arg,
delay_secs);
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index fd41e8d..ec12e0b 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -199,7 +199,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
list_for_each_entry(pos, &evlist->entries, node) {
struct hists *hists = &pos->hists;
- const char *evname = event_name(pos);
+ const char *evname = perf_evsel__name(pos);
GtkWidget *scrolled_window;
GtkWidget *tab_label;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 2ddc812..236bdf2 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -252,42 +252,42 @@ static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t
return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
}
-static int perf_evsel__tracepoint_name(struct perf_evsel *evsel, char *bf, size_t size)
+const char *perf_evsel__name(struct perf_evsel *evsel)
{
- return scnprintf(bf, size, "%s", evsel->name ?: "unknown tracepoint");
-}
+ char bf[128];
-int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
-{
- int ret;
+ if (evsel->name)
+ return evsel->name;
switch (evsel->attr.type) {
case PERF_TYPE_RAW:
- ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
+ scnprintf(bf, sizeof(bf), "raw 0x%" PRIx64, evsel->attr.config);
break;
case PERF_TYPE_HARDWARE:
- ret = perf_evsel__hw_name(evsel, bf, size);
+ perf_evsel__hw_name(evsel, bf, sizeof(bf));
break;
case PERF_TYPE_HW_CACHE:
- ret = perf_evsel__hw_cache_name(evsel, bf, size);
+ perf_evsel__hw_cache_name(evsel, bf, sizeof(bf));
break;
case PERF_TYPE_SOFTWARE:
- ret = perf_evsel__sw_name(evsel, bf, size);
+ perf_evsel__sw_name(evsel, bf, sizeof(bf));
break;
case PERF_TYPE_TRACEPOINT:
- ret = perf_evsel__tracepoint_name(evsel, bf, size);
+ scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint");
break;
default:
- ret = scnprintf(bf, size, "%s", "unknown attr type");
+ scnprintf(bf, sizeof(bf), "%s", "unknown attr type");
break;
}
- return ret;
+ evsel->name = strdup(bf);
+
+ return evsel->name ?: "unknown";
}
void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 9ae64d9..c936feb 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -100,7 +100,7 @@ int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size);
const char *__perf_evsel__hw_name(u64 config);
const char *__perf_evsel__sw_name(u64 config);
-int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size);
+const char *perf_evsel__name(struct perf_evsel *evsel);
int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 2dd5edf..07c8f37 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -641,7 +641,7 @@ static int write_event_desc(int fd, struct perf_header *h __used,
/*
* write event string as passed on cmdline
*/
- ret = do_write_string(fd, event_name(attr));
+ ret = do_write_string(fd, perf_evsel__name(attr));
if (ret < 0)
return ret;
/*
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index d73690b..517e647 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -201,13 +201,6 @@ const char *event_type(int type)
return "unknown";
}
-const char *event_name(struct perf_evsel *evsel)
-{
- static char bf[128];
- perf_evsel__name(evsel, bf, sizeof(bf));
- return bf;
-}
-
const char *__event_name(int type, u64 config)
{
static char buf[32];
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8cac57a..d7eb070 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -26,7 +26,6 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
extern bool have_tracepoints(struct list_head *evlist);
const char *event_type(int type);
-const char *event_name(struct perf_evsel *event);
extern const char *__event_name(int type, u64 config);
extern int parse_events_option(const struct option *opt, const char *str,
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 2600916..582ee38 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1439,7 +1439,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
ret += hists__fprintf_nr_events(&session->hists, fp);
list_for_each_entry(pos, &session->evlist->entries, node) {
- ret += fprintf(fp, "%s stats:\n", event_name(pos));
+ ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
ret += hists__fprintf_nr_events(&pos->hists, fp);
}
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index abe0e8e..7eeebce 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -65,7 +65,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
top->freq ? "Hz" : "");
}
- ret += SNPRINTF(bf + ret, size - ret, "%s", event_name(top->sym_evsel));
+ ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel));
ret += SNPRINTF(bf + ret, size - ret, "], ");
--
1.7.1
From: Namhyung Kim <[email protected]>
Add statusbar widget to display non-critical messages at the bottom of
the window. This can be used for showing a status change, warning or
help message.
Signed-off-by: Namhyung Kim <[email protected]>
Acked-by: Pekka Enberg <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Pekka Enberg <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/ui/gtk/browser.c | 26 +++++++++++++++++++++++++-
tools/perf/ui/gtk/gtk.h | 2 ++
2 files changed, 27 insertions(+), 1 deletions(-)
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 33ab1ae..ece360d 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -122,13 +122,30 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
gtk_container_add(GTK_CONTAINER(window), view);
}
+static GtkWidget *perf_gtk__setup_statusbar(void)
+{
+ GtkWidget *stbar;
+ unsigned ctxid;
+
+ stbar = gtk_statusbar_new();
+
+ ctxid = gtk_statusbar_get_context_id(GTK_STATUSBAR(stbar),
+ "perf report");
+ pgctx->statbar = stbar;
+ pgctx->statbar_ctx_id = ctxid;
+
+ return stbar;
+}
+
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
const char *help __used,
void (*timer) (void *arg)__used,
void *arg __used, int delay_secs __used)
{
struct perf_evsel *pos;
+ GtkWidget *vbox;
GtkWidget *notebook;
+ GtkWidget *statbar;
GtkWidget *window;
signal(SIGSEGV, perf_gtk__signal);
@@ -147,6 +164,8 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
if (!pgctx)
return -1;
+ vbox = gtk_vbox_new(FALSE, 0);
+
notebook = gtk_notebook_new();
list_for_each_entry(pos, &evlist->entries, node) {
@@ -168,7 +187,12 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
}
- gtk_container_add(GTK_CONTAINER(window), notebook);
+ gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+ statbar = perf_gtk__setup_statusbar();
+ gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
+
+ gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show_all(window);
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 34fbca6..2061678 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -10,6 +10,8 @@
struct perf_gtk_context {
GtkWidget *main_window;
+ GtkWidget *statbar;
+ guint statbar_ctx_id;
};
extern struct perf_gtk_context *pgctx;
--
1.7.1
From: Namhyung Kim <[email protected]>
The struct perf_error_ops is for flexible error logging.
We can register appropriate functions based on front-end.
Signed-off-by: Namhyung Kim <[email protected]>
Acked-by: Pekka Enberg <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Pekka Enberg <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Makefile | 3 +
tools/perf/ui/gtk/util.c | 20 ++++
tools/perf/ui/tui/setup.c | 6 +
tools/perf/ui/tui/util.c | 243 +++++++++++++++++++++++++++++++++++++++
tools/perf/ui/util.c | 277 +++++++++------------------------------------
tools/perf/ui/util.h | 9 ++-
tools/perf/util/debug.c | 2 +-
tools/perf/util/debug.h | 23 ++++-
8 files changed, 357 insertions(+), 226 deletions(-)
create mode 100644 tools/perf/ui/gtk/util.c
create mode 100644 tools/perf/ui/tui/util.c
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 0eee64c..c0ee917 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -503,6 +503,7 @@ else
LIB_OBJS += $(OUTPUT)ui/progress.o
LIB_OBJS += $(OUTPUT)ui/util.o
LIB_OBJS += $(OUTPUT)ui/tui/setup.o
+ LIB_OBJS += $(OUTPUT)ui/tui/util.o
LIB_H += ui/browser.h
LIB_H += ui/browsers/map.h
LIB_H += ui/helpline.h
@@ -526,9 +527,11 @@ else
EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
+ LIB_OBJS += $(OUTPUT)ui/gtk/util.o
# Make sure that it'd be included only once.
ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),)
LIB_OBJS += $(OUTPUT)ui/setup.o
+ LIB_OBJS += $(OUTPUT)ui/util.o
endif
endif
endif
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
new file mode 100644
index 0000000..a727fe3
--- /dev/null
+++ b/tools/perf/ui/gtk/util.c
@@ -0,0 +1,20 @@
+#include "../util.h"
+#include "../../util/debug.h"
+#include "gtk.h"
+
+
+/*
+ * FIXME: Functions below should be implemented properly.
+ * For now, just add stubs for NO_NEWT=1 build.
+ */
+#ifdef NO_NEWT_SUPPORT
+int ui_helpline__show_help(const char *format __used, va_list ap __used)
+{
+ return 0;
+}
+
+void ui_progress__update(u64 curr __used, u64 total __used,
+ const char *title __used)
+{
+}
+#endif
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index d33e943..e813c1d 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -15,6 +15,8 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
static volatile int ui__need_resize;
+extern struct perf_error_ops perf_tui_eops;
+
void ui__refresh_dimensions(bool force)
{
if (force || ui__need_resize) {
@@ -122,6 +124,8 @@ int ui__init(void)
signal(SIGINT, ui__signal);
signal(SIGQUIT, ui__signal);
signal(SIGTERM, ui__signal);
+
+ perf_error__register(&perf_tui_eops);
out:
return err;
}
@@ -137,4 +141,6 @@ void ui__exit(bool wait_for_ok)
SLsmg_refresh();
SLsmg_reset_smg();
SLang_reset_tty();
+
+ perf_error__unregister(&perf_tui_eops);
}
diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c
new file mode 100644
index 0000000..092902e
--- /dev/null
+++ b/tools/perf/ui/tui/util.c
@@ -0,0 +1,243 @@
+#include "../../util/util.h"
+#include <signal.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/ttydefaults.h>
+
+#include "../../util/cache.h"
+#include "../../util/debug.h"
+#include "../browser.h"
+#include "../keysyms.h"
+#include "../helpline.h"
+#include "../ui.h"
+#include "../util.h"
+#include "../libslang.h"
+
+static void ui_browser__argv_write(struct ui_browser *browser,
+ void *entry, int row)
+{
+ char **arg = entry;
+ bool current_entry = ui_browser__is_current_entry(browser, row);
+
+ ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
+ HE_COLORSET_NORMAL);
+ slsmg_write_nstring(*arg, browser->width);
+}
+
+static int popup_menu__run(struct ui_browser *menu)
+{
+ int key;
+
+ if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
+ return -1;
+
+ while (1) {
+ key = ui_browser__run(menu, 0);
+
+ switch (key) {
+ case K_RIGHT:
+ case K_ENTER:
+ key = menu->index;
+ break;
+ case K_LEFT:
+ case K_ESC:
+ case 'q':
+ case CTRL('c'):
+ key = -1;
+ break;
+ default:
+ continue;
+ }
+
+ break;
+ }
+
+ ui_browser__hide(menu);
+ return key;
+}
+
+int ui__popup_menu(int argc, char * const argv[])
+{
+ struct ui_browser menu = {
+ .entries = (void *)argv,
+ .refresh = ui_browser__argv_refresh,
+ .seek = ui_browser__argv_seek,
+ .write = ui_browser__argv_write,
+ .nr_entries = argc,
+ };
+
+ return popup_menu__run(&menu);
+}
+
+int ui_browser__input_window(const char *title, const char *text, char *input,
+ const char *exit_msg, int delay_secs)
+{
+ int x, y, len, key;
+ int max_len = 60, nr_lines = 0;
+ static char buf[50];
+ const char *t;
+
+ t = text;
+ while (1) {
+ const char *sep = strchr(t, '\n');
+
+ if (sep == NULL)
+ sep = strchr(t, '\0');
+ len = sep - t;
+ if (max_len < len)
+ max_len = len;
+ ++nr_lines;
+ if (*sep == '\0')
+ break;
+ t = sep + 1;
+ }
+
+ max_len += 2;
+ nr_lines += 8;
+ y = SLtt_Screen_Rows / 2 - nr_lines / 2;
+ x = SLtt_Screen_Cols / 2 - max_len / 2;
+
+ SLsmg_set_color(0);
+ SLsmg_draw_box(y, x++, nr_lines, max_len);
+ if (title) {
+ SLsmg_gotorc(y, x + 1);
+ SLsmg_write_string((char *)title);
+ }
+ SLsmg_gotorc(++y, x);
+ nr_lines -= 7;
+ max_len -= 2;
+ SLsmg_write_wrapped_string((unsigned char *)text, y, x,
+ nr_lines, max_len, 1);
+ y += nr_lines;
+ len = 5;
+ while (len--) {
+ SLsmg_gotorc(y + len - 1, x);
+ SLsmg_write_nstring((char *)" ", max_len);
+ }
+ SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
+
+ SLsmg_gotorc(y + 3, x);
+ SLsmg_write_nstring((char *)exit_msg, max_len);
+ SLsmg_refresh();
+
+ x += 2;
+ len = 0;
+ key = ui__getch(delay_secs);
+ while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
+ if (key == K_BKSPC) {
+ if (len == 0)
+ goto next_key;
+ SLsmg_gotorc(y, x + --len);
+ SLsmg_write_char(' ');
+ } else {
+ buf[len] = key;
+ SLsmg_gotorc(y, x + len++);
+ SLsmg_write_char(key);
+ }
+ SLsmg_refresh();
+
+ /* XXX more graceful overflow handling needed */
+ if (len == sizeof(buf) - 1) {
+ ui_helpline__push("maximum size of symbol name reached!");
+ key = K_ENTER;
+ break;
+ }
+next_key:
+ key = ui__getch(delay_secs);
+ }
+
+ buf[len] = '\0';
+ strncpy(input, buf, len+1);
+ return key;
+}
+
+int ui__question_window(const char *title, const char *text,
+ const char *exit_msg, int delay_secs)
+{
+ int x, y;
+ int max_len = 0, nr_lines = 0;
+ const char *t;
+
+ t = text;
+ while (1) {
+ const char *sep = strchr(t, '\n');
+ int len;
+
+ if (sep == NULL)
+ sep = strchr(t, '\0');
+ len = sep - t;
+ if (max_len < len)
+ max_len = len;
+ ++nr_lines;
+ if (*sep == '\0')
+ break;
+ t = sep + 1;
+ }
+
+ max_len += 2;
+ nr_lines += 4;
+ y = SLtt_Screen_Rows / 2 - nr_lines / 2,
+ x = SLtt_Screen_Cols / 2 - max_len / 2;
+
+ SLsmg_set_color(0);
+ SLsmg_draw_box(y, x++, nr_lines, max_len);
+ if (title) {
+ SLsmg_gotorc(y, x + 1);
+ SLsmg_write_string((char *)title);
+ }
+ SLsmg_gotorc(++y, x);
+ nr_lines -= 2;
+ max_len -= 2;
+ SLsmg_write_wrapped_string((unsigned char *)text, y, x,
+ nr_lines, max_len, 1);
+ SLsmg_gotorc(y + nr_lines - 2, x);
+ SLsmg_write_nstring((char *)" ", max_len);
+ SLsmg_gotorc(y + nr_lines - 1, x);
+ SLsmg_write_nstring((char *)exit_msg, max_len);
+ SLsmg_refresh();
+ return ui__getch(delay_secs);
+}
+
+int ui__help_window(const char *text)
+{
+ return ui__question_window("Help", text, "Press any key...", 0);
+}
+
+int ui__dialog_yesno(const char *msg)
+{
+ return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
+}
+
+static int __ui__warning(const char *title, const char *format, va_list args)
+{
+ char *s;
+
+ if (vasprintf(&s, format, args) > 0) {
+ int key;
+
+ pthread_mutex_lock(&ui__lock);
+ key = ui__question_window(title, s, "Press any key...", 0);
+ pthread_mutex_unlock(&ui__lock);
+ free(s);
+ return key;
+ }
+
+ fprintf(stderr, "%s\n", title);
+ vfprintf(stderr, format, args);
+ return K_ESC;
+}
+
+static int perf_tui__error(const char *format, va_list args)
+{
+ return __ui__warning("Error:", format, args);
+}
+
+static int perf_tui__warning(const char *format, va_list args)
+{
+ return __ui__warning("Warning:", format, args);
+}
+
+struct perf_error_ops perf_tui_eops = {
+ .error = perf_tui__error,
+ .warning = perf_tui__warning,
+};
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c
index ad4374a..4f98977 100644
--- a/tools/perf/ui/util.c
+++ b/tools/perf/ui/util.c
@@ -1,250 +1,85 @@
-#include "../util.h"
-#include <signal.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/ttydefaults.h>
-
-#include "../cache.h"
-#include "../debug.h"
-#include "browser.h"
-#include "keysyms.h"
-#include "helpline.h"
-#include "ui.h"
#include "util.h"
-#include "libslang.h"
-
-static void ui_browser__argv_write(struct ui_browser *browser,
- void *entry, int row)
-{
- char **arg = entry;
- bool current_entry = ui_browser__is_current_entry(browser, row);
-
- ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
- HE_COLORSET_NORMAL);
- slsmg_write_nstring(*arg, browser->width);
-}
-
-static int popup_menu__run(struct ui_browser *menu)
-{
- int key;
-
- if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
- return -1;
+#include "../debug.h"
- while (1) {
- key = ui_browser__run(menu, 0);
-
- switch (key) {
- case K_RIGHT:
- case K_ENTER:
- key = menu->index;
- break;
- case K_LEFT:
- case K_ESC:
- case 'q':
- case CTRL('c'):
- key = -1;
- break;
- default:
- continue;
- }
-
- break;
- }
-
- ui_browser__hide(menu);
- return key;
-}
-int ui__popup_menu(int argc, char * const argv[])
+/*
+ * Default error logging functions
+ */
+static int perf_stdio__error(const char *format, va_list args)
{
- struct ui_browser menu = {
- .entries = (void *)argv,
- .refresh = ui_browser__argv_refresh,
- .seek = ui_browser__argv_seek,
- .write = ui_browser__argv_write,
- .nr_entries = argc,
- };
-
- return popup_menu__run(&menu);
+ fprintf(stderr, "Error:\n");
+ vfprintf(stderr, format, args);
+ return 0;
}
-int ui_browser__input_window(const char *title, const char *text, char *input,
- const char *exit_msg, int delay_secs)
+static int perf_stdio__warning(const char *format, va_list args)
{
- int x, y, len, key;
- int max_len = 60, nr_lines = 0;
- static char buf[50];
- const char *t;
-
- t = text;
- while (1) {
- const char *sep = strchr(t, '\n');
-
- if (sep == NULL)
- sep = strchr(t, '\0');
- len = sep - t;
- if (max_len < len)
- max_len = len;
- ++nr_lines;
- if (*sep == '\0')
- break;
- t = sep + 1;
- }
-
- max_len += 2;
- nr_lines += 8;
- y = SLtt_Screen_Rows / 2 - nr_lines / 2;
- x = SLtt_Screen_Cols / 2 - max_len / 2;
-
- SLsmg_set_color(0);
- SLsmg_draw_box(y, x++, nr_lines, max_len);
- if (title) {
- SLsmg_gotorc(y, x + 1);
- SLsmg_write_string((char *)title);
- }
- SLsmg_gotorc(++y, x);
- nr_lines -= 7;
- max_len -= 2;
- SLsmg_write_wrapped_string((unsigned char *)text, y, x,
- nr_lines, max_len, 1);
- y += nr_lines;
- len = 5;
- while (len--) {
- SLsmg_gotorc(y + len - 1, x);
- SLsmg_write_nstring((char *)" ", max_len);
- }
- SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
-
- SLsmg_gotorc(y + 3, x);
- SLsmg_write_nstring((char *)exit_msg, max_len);
- SLsmg_refresh();
-
- x += 2;
- len = 0;
- key = ui__getch(delay_secs);
- while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
- if (key == K_BKSPC) {
- if (len == 0)
- goto next_key;
- SLsmg_gotorc(y, x + --len);
- SLsmg_write_char(' ');
- } else {
- buf[len] = key;
- SLsmg_gotorc(y, x + len++);
- SLsmg_write_char(key);
- }
- SLsmg_refresh();
-
- /* XXX more graceful overflow handling needed */
- if (len == sizeof(buf) - 1) {
- ui_helpline__push("maximum size of symbol name reached!");
- key = K_ENTER;
- break;
- }
-next_key:
- key = ui__getch(delay_secs);
- }
-
- buf[len] = '\0';
- strncpy(input, buf, len+1);
- return key;
+ fprintf(stderr, "Warning:\n");
+ vfprintf(stderr, format, args);
+ return 0;
}
-int ui__question_window(const char *title, const char *text,
- const char *exit_msg, int delay_secs)
+static struct perf_error_ops default_eops =
{
- int x, y;
- int max_len = 0, nr_lines = 0;
- const char *t;
-
- t = text;
- while (1) {
- const char *sep = strchr(t, '\n');
- int len;
-
- if (sep == NULL)
- sep = strchr(t, '\0');
- len = sep - t;
- if (max_len < len)
- max_len = len;
- ++nr_lines;
- if (*sep == '\0')
- break;
- t = sep + 1;
- }
-
- max_len += 2;
- nr_lines += 4;
- y = SLtt_Screen_Rows / 2 - nr_lines / 2,
- x = SLtt_Screen_Cols / 2 - max_len / 2;
-
- SLsmg_set_color(0);
- SLsmg_draw_box(y, x++, nr_lines, max_len);
- if (title) {
- SLsmg_gotorc(y, x + 1);
- SLsmg_write_string((char *)title);
- }
- SLsmg_gotorc(++y, x);
- nr_lines -= 2;
- max_len -= 2;
- SLsmg_write_wrapped_string((unsigned char *)text, y, x,
- nr_lines, max_len, 1);
- SLsmg_gotorc(y + nr_lines - 2, x);
- SLsmg_write_nstring((char *)" ", max_len);
- SLsmg_gotorc(y + nr_lines - 1, x);
- SLsmg_write_nstring((char *)exit_msg, max_len);
- SLsmg_refresh();
- return ui__getch(delay_secs);
-}
+ .error = perf_stdio__error,
+ .warning = perf_stdio__warning,
+};
-int ui__help_window(const char *text)
-{
- return ui__question_window("Help", text, "Press any key...", 0);
-}
+static struct perf_error_ops *perf_eops = &default_eops;
-int ui__dialog_yesno(const char *msg)
-{
- return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
-}
-int __ui__warning(const char *title, const char *format, va_list args)
+int ui__error(const char *format, ...)
{
- char *s;
-
- if (use_browser > 0 && vasprintf(&s, format, args) > 0) {
- int key;
+ int ret;
+ va_list args;
- pthread_mutex_lock(&ui__lock);
- key = ui__question_window(title, s, "Press any key...", 0);
- pthread_mutex_unlock(&ui__lock);
- free(s);
- return key;
- }
+ va_start(args, format);
+ ret = perf_eops->error(format, args);
+ va_end(args);
- fprintf(stderr, "%s:\n", title);
- vfprintf(stderr, format, args);
- return K_ESC;
+ return ret;
}
int ui__warning(const char *format, ...)
{
- int key;
+ int ret;
va_list args;
va_start(args, format);
- key = __ui__warning("Warning", format, args);
+ ret = perf_eops->warning(format, args);
va_end(args);
- return key;
+
+ return ret;
}
-int ui__error(const char *format, ...)
+
+/**
+ * perf_error__register - Register error logging functions
+ * @eops: The pointer to error logging function struct
+ *
+ * Register UI-specific error logging functions. Before calling this,
+ * other logging functions should be unregistered, if any.
+ */
+int perf_error__register(struct perf_error_ops *eops)
{
- int key;
- va_list args;
+ if (perf_eops != &default_eops)
+ return -1;
- va_start(args, format);
- key = __ui__warning("Error", format, args);
- va_end(args);
- return key;
+ perf_eops = eops;
+ return 0;
+}
+
+/**
+ * perf_error__unregister - Unregister error logging functions
+ * @eops: The pointer to error logging function struct
+ *
+ * Unregister already registered error logging functions.
+ */
+int perf_error__unregister(struct perf_error_ops *eops)
+{
+ if (perf_eops != eops)
+ return -1;
+
+ perf_eops = &default_eops;
+ return 0;
}
diff --git a/tools/perf/ui/util.h b/tools/perf/ui/util.h
index 2d1738b..361f08c 100644
--- a/tools/perf/ui/util.h
+++ b/tools/perf/ui/util.h
@@ -9,6 +9,13 @@ int ui__help_window(const char *text);
int ui__dialog_yesno(const char *msg);
int ui__question_window(const char *title, const char *text,
const char *exit_msg, int delay_secs);
-int __ui__warning(const char *title, const char *format, va_list args);
+
+struct perf_error_ops {
+ int (*error)(const char *format, va_list args);
+ int (*warning)(const char *format, va_list args);
+};
+
+int perf_error__register(struct perf_error_ops *eops);
+int perf_error__unregister(struct perf_error_ops *eops);
#endif /* _PERF_UI_UTIL_H_ */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index efb1fce..4dfe0bb 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -47,7 +47,7 @@ int dump_printf(const char *fmt, ...)
return ret;
}
-#ifdef NO_NEWT_SUPPORT
+#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
int ui__warning(const char *format, ...)
{
va_list args;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 6bebe7f..015c91d 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -12,8 +12,9 @@ int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void trace_event(union perf_event *event);
struct ui_progress;
+struct perf_error_ops;
-#ifdef NO_NEWT_SUPPORT
+#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
static inline int ui_helpline__show_help(const char *format __used, va_list ap __used)
{
return 0;
@@ -23,12 +24,28 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used,
const char *title __used) {}
#define ui__error(format, arg...) ui__warning(format, ##arg)
-#else
+
+static inline int
+perf_error__register(struct perf_error_ops *eops __used)
+{
+ return 0;
+}
+
+static inline int
+perf_error__unregister(struct perf_error_ops *eops __used)
+{
+ return 0;
+}
+
+#else /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
+
extern char ui_helpline__last_msg[];
int ui_helpline__show_help(const char *format, va_list ap);
#include "../ui/progress.h"
int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
-#endif
+#include "../ui/util.h"
+
+#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
int ui__error_paranoid(void);
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
Using addr2line for now, requires debuginfo, needs more work to support
detached debuginfo, aka foo-debuginfo packages.
Example:
[root@sandy ~]# perf record -a sleep 3
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.555 MB perf.data (~24236 samples) ]
[root@sandy ~]# perf report -s dso,srcline 2>&1 | grep -v ^# | head -5
22.41% [kernel.kallsyms] /home/git/linux/drivers/idle/intel_idle.c:280
4.79% [kernel.kallsyms] /home/git/linux/drivers/cpuidle/cpuidle.c:148
4.78% [kernel.kallsyms] /home/git/linux/arch/x86/include/asm/atomic64_64.h:121
4.49% [kernel.kallsyms] /home/git/linux/kernel/sched/core.c:1690
4.30% [kernel.kallsyms] /home/git/linux/include/linux/seqlock.h:90
[root@sandy ~]#
[root@sandy ~]# perf top -U -s dso,symbol,srcline
Samples: 1K of event 'cycles', Event count (approx.): 589617389
18.66% [kernel] [k] copy_user_generic_unrolled /home/git/linux/arch/x86/lib/copy_user_64.S:143
7.83% [kernel] [k] clear_page /home/git/linux/arch/x86/lib/clear_page_64.S:39
6.59% [kernel] [k] clear_page /home/git/linux/arch/x86/lib/clear_page_64.S:38
3.66% [kernel] [k] page_fault /home/git/linux/arch/x86/kernel/entry_64.S:1379
3.25% [kernel] [k] clear_page /home/git/linux/arch/x86/lib/clear_page_64.S:40
3.12% [kernel] [k] clear_page /home/git/linux/arch/x86/lib/clear_page_64.S:37
2.74% [kernel] [k] clear_page /home/git/linux/arch/x86/lib/clear_page_64.S:36
2.39% [kernel] [k] clear_page /home/git/linux/arch/x86/lib/clear_page_64.S:43
2.12% [kernel] [k] ioread32 /home/git/linux/lib/iomap.c:90
1.51% [kernel] [k] copy_user_generic_unrolled /home/git/linux/arch/x86/lib/copy_user_64.S:144
1.19% [kernel] [k] copy_user_generic_unrolled /home/git/linux/arch/x86/lib/copy_user_64.S:154
Suggested-by: Andi Kleen <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Documentation/perf-report.txt | 2 +-
tools/perf/Documentation/perf-top.txt | 2 +-
tools/perf/util/hist.h | 1 +
tools/perf/util/sort.c | 49 ++++++++++++++++++++++++++++++
tools/perf/util/sort.h | 2 +
5 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 2d89f02..495210a 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -57,7 +57,7 @@ OPTIONS
-s::
--sort=::
- Sort by key(s): pid, comm, dso, symbol, parent.
+ Sort by key(s): pid, comm, dso, symbol, parent, srcline.
-p::
--parent=<regex>::
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 4a5680c..5b80d84 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -112,7 +112,7 @@ Default is to monitor all CPUS.
-s::
--sort::
- Sort by key(s): pid, comm, dso, symbol, parent
+ Sort by key(s): pid, comm, dso, symbol, parent, srcline.
-n::
--show-nr-samples::
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 34bb556..0b096c2 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -47,6 +47,7 @@ enum hist_column {
HISTC_SYMBOL_TO,
HISTC_DSO_FROM,
HISTC_DSO_TO,
+ HISTC_SRCLINE,
HISTC_NR_COLS, /* Last entry */
};
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index a272374..0f5a0a4 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -241,6 +241,54 @@ struct sort_entry sort_sym = {
.se_width_idx = HISTC_SYMBOL,
};
+/* --sort srcline */
+
+static int64_t
+sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ return (int64_t)(right->ip - left->ip);
+}
+
+static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
+ size_t size, unsigned int width __used)
+{
+ FILE *fp;
+ char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
+ size_t line_len;
+
+ if (path != NULL)
+ goto out_path;
+
+ snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
+ self->ms.map->dso->long_name, self->ip);
+ fp = popen(cmd, "r");
+ if (!fp)
+ goto out_ip;
+
+ if (getline(&path, &line_len, fp) < 0 || !line_len)
+ goto out_ip;
+ fclose(fp);
+ self->srcline = strdup(path);
+ if (self->srcline == NULL)
+ goto out_ip;
+
+ nl = strchr(self->srcline, '\n');
+ if (nl != NULL)
+ *nl = '\0';
+ path = self->srcline;
+out_path:
+ return repsep_snprintf(bf, size, "%s", path);
+out_ip:
+ return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
+}
+
+struct sort_entry sort_srcline = {
+ .se_header = "Source:Line",
+ .se_cmp = sort__srcline_cmp,
+ .se_snprintf = hist_entry__srcline_snprintf,
+ .se_width_idx = HISTC_SRCLINE,
+};
+
/* --sort parent */
static int64_t
@@ -439,6 +487,7 @@ static struct sort_dimension sort_dimensions[] = {
DIM(SORT_PARENT, "parent", sort_parent),
DIM(SORT_CPU, "cpu", sort_cpu),
DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
+ DIM(SORT_SRCLINE, "srcline", sort_srcline),
};
int sort_dimension__add(const char *tok)
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 472aa5a..e724b26 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -71,6 +71,7 @@ struct hist_entry {
char level;
bool used;
u8 filtered;
+ char *srcline;
struct symbol *parent;
union {
unsigned long position;
@@ -93,6 +94,7 @@ enum sort_type {
SORT_SYM_FROM,
SORT_SYM_TO,
SORT_MISPREDICT,
+ SORT_SRCLINE,
};
/*
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
Now that __event_name is gone, no need to export __perf_evsel__[hs]w_name().
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/evsel.c | 6 +++---
tools/perf/util/evsel.h | 5 -----
2 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8f0e9dd..876f639 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -78,7 +78,7 @@ static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
"ref-cycles",
};
-const char *__perf_evsel__hw_name(u64 config)
+static const char *__perf_evsel__hw_name(u64 config)
{
if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config])
return perf_evsel__hw_names[config];
@@ -140,7 +140,7 @@ static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
"emulation-faults",
};
-const char *__perf_evsel__sw_name(u64 config)
+static const char *__perf_evsel__sw_name(u64 config)
{
if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config])
return perf_evsel__sw_names[config];
@@ -219,7 +219,7 @@ int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
perf_evsel__hw_cache_op[op][1]);
}
-int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size)
+static int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size)
{
u8 op, result, type = (config >> 0) & 0xff;
const char *err = "unknown-ext-hardware-cache-type";
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index c936feb..67cc503 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -95,11 +95,6 @@ const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
[PERF_EVSEL__MAX_ALIASES];
int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
char *bf, size_t size);
-int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size);
-
-const char *__perf_evsel__hw_name(u64 config);
-const char *__perf_evsel__sw_name(u64 config);
-
const char *perf_evsel__name(struct perf_evsel *evsel);
int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
Not needed anymore, the parsing code can just leave evsel->name as NULL
and the first call to perf_evsel__name() will do exactly what was being
pre-cached using __event_name().
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/parse-events.c | 61 ++++------------------------------------
tools/perf/util/parse-events.h | 1 -
2 files changed, 6 insertions(+), 56 deletions(-)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 517e647..eacf932 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -161,24 +161,6 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
return NULL;
}
-#define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1)
-static const char *tracepoint_id_to_name(u64 config)
-{
- static char buf[TP_PATH_LEN];
- struct tracepoint_path *path;
-
- path = tracepoint_id_to_path(config);
- if (path) {
- snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name);
- free(path->name);
- free(path->system);
- free(path);
- } else
- snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown");
-
- return buf;
-}
-
const char *event_type(int type)
{
switch (type) {
@@ -201,36 +183,6 @@ const char *event_type(int type)
return "unknown";
}
-const char *__event_name(int type, u64 config)
-{
- static char buf[32];
-
- if (type == PERF_TYPE_RAW) {
- sprintf(buf, "raw 0x%" PRIx64, config);
- return buf;
- }
-
- switch (type) {
- case PERF_TYPE_HARDWARE:
- return __perf_evsel__hw_name(config);
-
- case PERF_TYPE_HW_CACHE:
- __perf_evsel__hw_cache_name(config, buf, sizeof(buf));
- return buf;
-
- case PERF_TYPE_SOFTWARE:
- return __perf_evsel__sw_name(config);
-
- case PERF_TYPE_TRACEPOINT:
- return tracepoint_id_to_name(config);
-
- default:
- break;
- }
-
- return "unknown";
-}
-
static int add_event(struct list_head **_list, int *idx,
struct perf_event_attr *attr, char *name)
{
@@ -252,7 +204,8 @@ static int add_event(struct list_head **_list, int *idx,
return -ENOMEM;
}
- evsel->name = strdup(name);
+ if (name)
+ evsel->name = strdup(name);
list_add_tail(&evsel->node, list);
*_list = list;
return 0;
@@ -545,8 +498,7 @@ int parse_events_add_numeric(struct list_head **list, int *idx,
config_attr(&attr, head_config, 1))
return -EINVAL;
- return add_event(list, idx, &attr,
- (char *) __event_name(type, config));
+ return add_event(list, idx, &attr, NULL);
}
static int parse_events__is_name_term(struct parse_events__term *term)
@@ -554,8 +506,7 @@ static int parse_events__is_name_term(struct parse_events__term *term)
return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
}
-static char *pmu_event_name(struct perf_event_attr *attr,
- struct list_head *head_terms)
+static char *pmu_event_name(struct list_head *head_terms)
{
struct parse_events__term *term;
@@ -563,7 +514,7 @@ static char *pmu_event_name(struct perf_event_attr *attr,
if (parse_events__is_name_term(term))
return term->val.str;
- return (char *) __event_name(PERF_TYPE_RAW, attr->config);
+ return NULL;
}
int parse_events_add_pmu(struct list_head **list, int *idx,
@@ -588,7 +539,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
return -EINVAL;
return add_event(list, idx, &attr,
- pmu_event_name(&attr, head_config));
+ pmu_event_name(head_config));
}
void parse_events_update_lists(struct list_head *list_event,
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index d7eb070..1784f06 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -26,7 +26,6 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
extern bool have_tracepoints(struct list_head *evlist);
const char *event_type(int type);
-extern const char *__event_name(int type, u64 config);
extern int parse_events_option(const struct option *opt, const char *str,
int unset);
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
To avoid having to resort to --stdio, that expands everything, instead
allow the user to go on expanding the relevant callchains and then press
'P' to print that view.
As the hists browser is used for both static (report) and dynamic (top)
views, it prints to a 'perf.hists.N' sequence, i.e. multiple snapshots
can be taken in report and top.
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/ui/browsers/hists.c | 195 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 195 insertions(+), 0 deletions(-)
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 53f6697..f556e5f 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -23,6 +23,7 @@ struct hist_browser {
struct hists *hists;
struct hist_entry *he_selection;
struct map_symbol *selection;
+ int print_seq;
bool has_symbols;
};
@@ -800,6 +801,196 @@ do_offset:
}
}
+static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
+ struct callchain_node *chain_node,
+ u64 total, int level,
+ FILE *fp)
+{
+ struct rb_node *node;
+ int offset = level * LEVEL_OFFSET_STEP;
+ u64 new_total, remaining;
+ int printed = 0;
+
+ if (callchain_param.mode == CHAIN_GRAPH_REL)
+ new_total = chain_node->children_hit;
+ else
+ new_total = total;
+
+ remaining = new_total;
+ node = rb_first(&chain_node->rb_root);
+ while (node) {
+ struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
+ struct rb_node *next = rb_next(node);
+ u64 cumul = callchain_cumul_hits(child);
+ struct callchain_list *chain;
+ char folded_sign = ' ';
+ int first = true;
+ int extra_offset = 0;
+
+ remaining -= cumul;
+
+ list_for_each_entry(chain, &child->val, list) {
+ char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
+ const char *str;
+ bool was_first = first;
+
+ if (first)
+ first = false;
+ else
+ extra_offset = LEVEL_OFFSET_STEP;
+
+ folded_sign = callchain_list__folded(chain);
+
+ alloc_str = NULL;
+ str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+ if (was_first) {
+ double percent = cumul * 100.0 / new_total;
+
+ if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
+ str = "Not enough memory!";
+ else
+ str = alloc_str;
+ }
+
+ printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
+ free(alloc_str);
+ if (folded_sign == '+')
+ break;
+ }
+
+ if (folded_sign == '-') {
+ const int new_level = level + (extra_offset ? 2 : 1);
+ printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
+ new_level, fp);
+ }
+
+ node = next;
+ }
+
+ return printed;
+}
+
+static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
+ struct callchain_node *node,
+ int level, FILE *fp)
+{
+ struct callchain_list *chain;
+ int offset = level * LEVEL_OFFSET_STEP;
+ char folded_sign = ' ';
+ int printed = 0;
+
+ list_for_each_entry(chain, &node->val, list) {
+ char ipstr[BITS_PER_LONG / 4 + 1], *s;
+
+ folded_sign = callchain_list__folded(chain);
+ s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+ printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
+ }
+
+ if (folded_sign == '-')
+ printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
+ browser->hists->stats.total_period,
+ level + 1, fp);
+ return printed;
+}
+
+static int hist_browser__fprintf_callchain(struct hist_browser *browser,
+ struct rb_root *chain, int level, FILE *fp)
+{
+ struct rb_node *nd;
+ int printed = 0;
+
+ for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+ struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+
+ printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
+ }
+
+ return printed;
+}
+
+static int hist_browser__fprintf_entry(struct hist_browser *browser,
+ struct hist_entry *he, FILE *fp)
+{
+ char s[8192];
+ double percent;
+ int printed = 0;
+ char folded_sign = ' ';
+
+ if (symbol_conf.use_callchain)
+ folded_sign = hist_entry__folded(he);
+
+ hist_entry__snprintf(he, s, sizeof(s), browser->hists);
+ percent = (he->period * 100.0) / browser->hists->stats.total_period;
+
+ if (symbol_conf.use_callchain)
+ printed += fprintf(fp, "%c ", folded_sign);
+
+ printed += fprintf(fp, " %5.2f%%", percent);
+
+ if (symbol_conf.show_nr_samples)
+ printed += fprintf(fp, " %11u", he->nr_events);
+
+ if (symbol_conf.show_total_period)
+ printed += fprintf(fp, " %12" PRIu64, he->period);
+
+ printed += fprintf(fp, "%s\n", rtrim(s));
+
+ if (folded_sign == '-')
+ printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
+
+ return printed;
+}
+
+static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
+{
+ struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries));
+ int printed = 0;
+
+ while (nd) {
+ struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+
+ printed += hist_browser__fprintf_entry(browser, h, fp);
+ nd = hists__filter_entries(rb_next(nd));
+ }
+
+ return printed;
+}
+
+static int hist_browser__dump(struct hist_browser *browser)
+{
+ char filename[64];
+ FILE *fp;
+
+ while (1) {
+ scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
+ if (access(filename, F_OK))
+ break;
+ /*
+ * XXX: Just an arbitrary lazy upper limit
+ */
+ if (++browser->print_seq == 8192) {
+ ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
+ return -1;
+ }
+ }
+
+ fp = fopen(filename, "w");
+ if (fp == NULL) {
+ char bf[64];
+ strerror_r(errno, bf, sizeof(bf));
+ ui_helpline__fpush("Couldn't write to %s: %s", filename, bf);
+ return -1;
+ }
+
+ ++browser->print_seq;
+ hist_browser__fprintf(browser, fp);
+ fclose(fp);
+ ui_helpline__fpush("%s written!", filename);
+
+ return 0;
+}
+
static struct hist_browser *hist_browser__new(struct hists *hists)
{
struct hist_browser *browser = zalloc(sizeof(*browser));
@@ -937,6 +1128,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
browser->selection->map->dso->annotate_warned)
continue;
goto do_annotate;
+ case 'P':
+ hist_browser__dump(browser);
+ continue;
case 'd':
goto zoom_dso;
case 't':
@@ -969,6 +1163,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
"E Expand all callchains\n"
"d Zoom into current DSO\n"
"t Zoom into current Thread\n"
+ "P Print histograms to perf.hist.N\n"
"/ Filter symbol by name");
continue;
case K_ENTER:
--
1.7.1
From: Namhyung Kim <[email protected]>
Define and use perf_gtk_eops to provide a GTK2 message dialog for error
reporting and a info_bar for warning.
As GtkInfoBar requires recent GTK+ libraries, provides a fallback
implementation using statusbar widget too.
Signed-off-by: Namhyung Kim <[email protected]>
Acked-by: Pekka Enberg <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Pekka Enberg <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/ui/gtk/setup.c | 5 +++
tools/perf/ui/gtk/util.c | 86 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 91 insertions(+), 0 deletions(-)
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
index 8295299..92879ce 100644
--- a/tools/perf/ui/gtk/setup.c
+++ b/tools/perf/ui/gtk/setup.c
@@ -1,12 +1,17 @@
#include "gtk.h"
#include "../../util/cache.h"
+#include "../../util/debug.h"
+
+extern struct perf_error_ops perf_gtk_eops;
int perf_gtk__init(void)
{
+ perf_error__register(&perf_gtk_eops);
return gtk_init_check(NULL, NULL) ? 0 : -1;
}
void perf_gtk__exit(bool wait_for_ok __used)
{
+ perf_error__unregister(&perf_gtk_eops);
gtk_main_quit();
}
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
index 6fe13fd..0ead373 100644
--- a/tools/perf/ui/gtk/util.c
+++ b/tools/perf/ui/gtk/util.c
@@ -2,6 +2,8 @@
#include "../../util/debug.h"
#include "gtk.h"
+#include <string.h>
+
struct perf_gtk_context *pgctx;
@@ -26,6 +28,90 @@ int perf_gtk__deactivate_context(struct perf_gtk_context **ctx)
return 0;
}
+static int perf_gtk__error(const char *format, va_list args)
+{
+ char *msg;
+ GtkWidget *dialog;
+
+ if (!perf_gtk__is_active_context(pgctx) ||
+ vasprintf(&msg, format, args) < 0) {
+ fprintf(stderr, "Error:\n");
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ return -1;
+ }
+
+ dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(pgctx->main_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "<b>Error</b>\n\n%s", msg);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+
+ gtk_widget_destroy(dialog);
+ free(msg);
+ return 0;
+}
+
+#ifdef HAVE_GTK_INFO_BAR
+static int perf_gtk__warning_info_bar(const char *format, va_list args)
+{
+ char *msg;
+
+ if (!perf_gtk__is_active_context(pgctx) ||
+ vasprintf(&msg, format, args) < 0) {
+ fprintf(stderr, "Warning:\n");
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ return -1;
+ }
+
+ gtk_label_set_text(GTK_LABEL(pgctx->message_label), msg);
+ gtk_info_bar_set_message_type(GTK_INFO_BAR(pgctx->info_bar),
+ GTK_MESSAGE_WARNING);
+ gtk_widget_show(pgctx->info_bar);
+
+ free(msg);
+ return 0;
+}
+#else
+static int perf_gtk__warning_statusbar(const char *format, va_list args)
+{
+ char *msg, *p;
+
+ if (!perf_gtk__is_active_context(pgctx) ||
+ vasprintf(&msg, format, args) < 0) {
+ fprintf(stderr, "Warning:\n");
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ return -1;
+ }
+
+ gtk_statusbar_pop(GTK_STATUSBAR(pgctx->statbar),
+ pgctx->statbar_ctx_id);
+
+ /* Only first line can be displayed */
+ p = strchr(msg, '\n');
+ if (p)
+ *p = '\0';
+
+ gtk_statusbar_push(GTK_STATUSBAR(pgctx->statbar),
+ pgctx->statbar_ctx_id, msg);
+
+ free(msg);
+ return 0;
+}
+#endif
+
+struct perf_error_ops perf_gtk_eops = {
+ .error = perf_gtk__error,
+#ifdef HAVE_GTK_INFO_BAR
+ .warning = perf_gtk__warning_info_bar,
+#else
+ .warning = perf_gtk__warning_statusbar,
+#endif
+};
+
/*
* FIXME: Functions below should be implemented properly.
* For now, just add stubs for NO_NEWT=1 build.
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
>From perf_evsel__hw_name, so that we can use it for the other kinds of
events (tracepoints, software, hw cache, etc).
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/evsel.c | 17 +++++++++++------
1 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 9f6cebd..dab8938 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -86,16 +86,15 @@ const char *__perf_evsel__hw_name(u64 config)
return "unknown-hardware";
}
-static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
+static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size)
{
- int colon = 0;
+ int colon = 0, r = 0;
struct perf_event_attr *attr = &evsel->attr;
- int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(attr->config));
bool exclude_guest_default = false;
#define MOD_PRINT(context, mod) do { \
if (!attr->exclude_##context) { \
- if (!colon) colon = r++; \
+ if (!colon) colon = ++r; \
r += scnprintf(bf + r, size - r, "%c", mod); \
} } while(0)
@@ -108,7 +107,7 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
if (attr->precise_ip) {
if (!colon)
- colon = r++;
+ colon = ++r;
r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp");
exclude_guest_default = true;
}
@@ -119,10 +118,16 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
}
#undef MOD_PRINT
if (colon)
- bf[colon] = ':';
+ bf[colon - 1] = ':';
return r;
}
+static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+ int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config));
+ return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
+}
+
int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
{
int ret;
--
1.7.1
From: Namhyung Kim <[email protected]>
The GtkInfoBar is a modern UI component to display messages without
bothering the main window. It'll be used for showing a warning message.
As the GtkInfoBar requires 2.18 (or newer) version of GTK+ library, add
availability check to Makefile too.
Suggested-by: Sunjin Yang <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
Acked-by: Pekka Enberg <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Pekka Enberg <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Makefile | 3 +++
tools/perf/config/feature-tests.mak | 13 +++++++++++++
tools/perf/ui/gtk/browser.c | 33 +++++++++++++++++++++++++++++++++
tools/perf/ui/gtk/gtk.h | 12 ++++++++++++
4 files changed, 61 insertions(+), 0 deletions(-)
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index c0ee917..d698c11 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -523,6 +523,9 @@ else
msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
BASIC_CFLAGS += -DNO_GTK2_SUPPORT
else
+ ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y)
+ BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
+ endif
BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index d9084e0..6c18785 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -78,6 +78,19 @@ int main(int argc, char *argv[])
return 0;
}
endef
+
+define SOURCE_GTK2_INFOBAR
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#include <gtk/gtk.h>
+#pragma GCC diagnostic error \"-Wstrict-prototypes\"
+
+int main(void)
+{
+ gtk_info_bar_new();
+
+ return 0;
+}
+endef
endif
ifndef NO_LIBPERL
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index ece360d..fd41e8d 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -122,6 +122,34 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
gtk_container_add(GTK_CONTAINER(window), view);
}
+#ifdef HAVE_GTK_INFO_BAR
+static GtkWidget *perf_gtk__setup_info_bar(void)
+{
+ GtkWidget *info_bar;
+ GtkWidget *label;
+ GtkWidget *content_area;
+
+ info_bar = gtk_info_bar_new();
+ gtk_widget_set_no_show_all(info_bar, TRUE);
+
+ label = gtk_label_new("");
+ gtk_widget_show(label);
+
+ content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(info_bar));
+ gtk_container_add(GTK_CONTAINER(content_area), label);
+
+ gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), GTK_STOCK_OK,
+ GTK_RESPONSE_OK);
+ g_signal_connect(info_bar, "response",
+ G_CALLBACK(gtk_widget_hide), NULL);
+
+ pgctx->info_bar = info_bar;
+ pgctx->message_label = label;
+
+ return info_bar;
+}
+#endif
+
static GtkWidget *perf_gtk__setup_statusbar(void)
{
GtkWidget *stbar;
@@ -145,6 +173,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
struct perf_evsel *pos;
GtkWidget *vbox;
GtkWidget *notebook;
+ GtkWidget *info_bar;
GtkWidget *statbar;
GtkWidget *window;
@@ -189,6 +218,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+ info_bar = perf_gtk__setup_info_bar();
+ if (info_bar)
+ gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
+
statbar = perf_gtk__setup_statusbar();
gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 2061678..a4d0f2b 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -10,6 +10,11 @@
struct perf_gtk_context {
GtkWidget *main_window;
+
+#ifdef HAVE_GTK_INFO_BAR
+ GtkWidget *info_bar;
+ GtkWidget *message_label;
+#endif
GtkWidget *statbar;
guint statbar_ctx_id;
};
@@ -24,4 +29,11 @@ static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx)
struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
+#ifndef HAVE_GTK_INFO_BAR
+static inline GtkWidget *perf_gtk__setup_info_bar(void)
+{
+ return NULL;
+}
+#endif
+
#endif /* _PERF_GTK_H_ */
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
One needs to use perf_evsel__name() so that if needed the name gets
synthesized and stored in evsel->name, from where perf_evsel__name()
will serve from them on.
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-sched.c | 2 +-
tools/perf/util/parse-events-test.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index b125e07..9fe77b1 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1601,7 +1601,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
if (thread == NULL) {
pr_debug("problem processing %s event, skipping it.\n",
- evsel->name);
+ perf_evsel__name(evsel));
return -1;
}
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
index 76b98e2..d0cf7c1 100644
--- a/tools/perf/util/parse-events-test.c
+++ b/tools/perf/util/parse-events-test.c
@@ -418,14 +418,14 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
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);
- TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
+ TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "krava"));
/* cpu/config=2/" */
evsel = list_entry(evsel->node.next, struct perf_evsel, node);
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", 2 == evsel->attr.config);
- TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2"));
+ TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "raw 0x2"));
return 0;
}
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
I forgot to add the modifiers to raw events too, fix it.
Reported-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/evsel.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 236bdf2..8f0e9dd 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -252,6 +252,12 @@ static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t
return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
}
+static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+ int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
+ return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
+}
+
const char *perf_evsel__name(struct perf_evsel *evsel)
{
char bf[128];
@@ -261,7 +267,7 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
switch (evsel->attr.type) {
case PERF_TYPE_RAW:
- scnprintf(bf, sizeof(bf), "raw 0x%" PRIx64, evsel->attr.config);
+ perf_evsel__raw_name(evsel, bf, sizeof(bf));
break;
case PERF_TYPE_HARDWARE:
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
[root@sandy ~]# perf record -a -e dTLB-load-misses:u usleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.486 MB perf.data (~21216 samples) ]
Before:
[root@sandy ~]# perf evlist
dTLB-load-misses
[root@sandy ~]#
After:
[root@sandy ~]# perf evlist
dTLB-load-misses:u
[root@sandy ~]#
Ditto for other tools.
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/evsel.c | 104 ++++++++++++++++++++++++++++++++++++
tools/perf/util/evsel.h | 16 +++++-
tools/perf/util/parse-events.c | 115 +++++----------------------------------
3 files changed, 134 insertions(+), 101 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index dab8938..47f1fe2 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -128,6 +128,105 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
}
+const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
+ [PERF_EVSEL__MAX_ALIASES] = {
+ { "L1-dcache", "l1-d", "l1d", "L1-data", },
+ { "L1-icache", "l1-i", "l1i", "L1-instruction", },
+ { "LLC", "L2", },
+ { "dTLB", "d-tlb", "Data-TLB", },
+ { "iTLB", "i-tlb", "Instruction-TLB", },
+ { "branch", "branches", "bpu", "btb", "bpc", },
+ { "node", },
+};
+
+const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_EVSEL__MAX_ALIASES] = {
+ { "load", "loads", "read", },
+ { "store", "stores", "write", },
+ { "prefetch", "prefetches", "speculative-read", "speculative-load", },
+};
+
+const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
+ [PERF_EVSEL__MAX_ALIASES] = {
+ { "refs", "Reference", "ops", "access", },
+ { "misses", "miss", },
+};
+
+#define C(x) PERF_COUNT_HW_CACHE_##x
+#define CACHE_READ (1 << C(OP_READ))
+#define CACHE_WRITE (1 << C(OP_WRITE))
+#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
+#define COP(x) (1 << x)
+
+/*
+ * cache operartion stat
+ * L1I : Read and prefetch only
+ * ITLB and BPU : Read-only
+ */
+static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = {
+ [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
+ [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(ITLB)] = (CACHE_READ),
+ [C(BPU)] = (CACHE_READ),
+ [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+};
+
+bool perf_evsel__is_cache_op_valid(u8 type, u8 op)
+{
+ if (perf_evsel__hw_cache_stat[type] & COP(op))
+ return true; /* valid */
+ else
+ return false; /* invalid */
+}
+
+int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
+ char *bf, size_t size)
+{
+ if (result) {
+ return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0],
+ perf_evsel__hw_cache_op[op][0],
+ perf_evsel__hw_cache_result[result][0]);
+ }
+
+ return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0],
+ perf_evsel__hw_cache_op[op][1]);
+}
+
+int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size)
+{
+ u8 op, result, type = (config >> 0) & 0xff;
+ const char *err = "unknown-ext-hardware-cache-type";
+
+ if (type > PERF_COUNT_HW_CACHE_MAX)
+ goto out_err;
+
+ op = (config >> 8) & 0xff;
+ err = "unknown-ext-hardware-cache-op";
+ if (op > PERF_COUNT_HW_CACHE_OP_MAX)
+ goto out_err;
+
+ result = (config >> 16) & 0xff;
+ err = "unknown-ext-hardware-cache-result";
+ if (result > PERF_COUNT_HW_CACHE_RESULT_MAX)
+ goto out_err;
+
+ err = "invalid-cache";
+ if (!perf_evsel__is_cache_op_valid(type, op))
+ goto out_err;
+
+ return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size);
+out_err:
+ return scnprintf(bf, size, "%s", err);
+}
+
+static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+ int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size);
+ return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
+}
+
int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
{
int ret;
@@ -140,6 +239,11 @@ int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
case PERF_TYPE_HARDWARE:
ret = perf_evsel__hw_name(evsel, bf, size);
break;
+
+ case PERF_TYPE_HW_CACHE:
+ ret = perf_evsel__hw_cache_name(evsel, bf, size);
+ break;
+
default:
/*
* FIXME
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 4ba8b56..5bf946a 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -83,7 +83,21 @@ void perf_evsel__config(struct perf_evsel *evsel,
struct perf_record_opts *opts,
struct perf_evsel *first);
-const char* __perf_evsel__hw_name(u64 config);
+bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
+
+#define PERF_EVSEL__MAX_ALIASES 8
+
+extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
+ [PERF_EVSEL__MAX_ALIASES];
+extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_EVSEL__MAX_ALIASES];
+const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
+ [PERF_EVSEL__MAX_ALIASES];
+int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
+ char *bf, size_t size);
+int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size);
+
+const char *__perf_evsel__hw_name(u64 config);
int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size);
int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 05dbc8b..c8f8cf4 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -74,51 +74,6 @@ static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
"emulation-faults",
};
-#define MAX_ALIASES 8
-
-static const char *hw_cache[PERF_COUNT_HW_CACHE_MAX][MAX_ALIASES] = {
- { "L1-dcache", "l1-d", "l1d", "L1-data", },
- { "L1-icache", "l1-i", "l1i", "L1-instruction", },
- { "LLC", "L2", },
- { "dTLB", "d-tlb", "Data-TLB", },
- { "iTLB", "i-tlb", "Instruction-TLB", },
- { "branch", "branches", "bpu", "btb", "bpc", },
- { "node", },
-};
-
-static const char *hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][MAX_ALIASES] = {
- { "load", "loads", "read", },
- { "store", "stores", "write", },
- { "prefetch", "prefetches", "speculative-read", "speculative-load", },
-};
-
-static const char *hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
- [MAX_ALIASES] = {
- { "refs", "Reference", "ops", "access", },
- { "misses", "miss", },
-};
-
-#define C(x) PERF_COUNT_HW_CACHE_##x
-#define CACHE_READ (1 << C(OP_READ))
-#define CACHE_WRITE (1 << C(OP_WRITE))
-#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
-#define COP(x) (1 << x)
-
-/*
- * cache operartion stat
- * L1I : Read and prefetch only
- * ITLB and BPU : Read-only
- */
-static unsigned long hw_cache_stat[C(MAX)] = {
- [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
- [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(ITLB)] = (CACHE_READ),
- [C(BPU)] = (CACHE_READ),
- [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
-};
-
#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \
while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
if (sys_dirent.d_type == DT_DIR && \
@@ -236,30 +191,6 @@ static const char *tracepoint_id_to_name(u64 config)
return buf;
}
-static int is_cache_op_valid(u8 cache_type, u8 cache_op)
-{
- if (hw_cache_stat[cache_type] & COP(cache_op))
- return 1; /* valid */
- else
- return 0; /* invalid */
-}
-
-static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
-{
- static char name[50];
-
- if (cache_result) {
- sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
- hw_cache_op[cache_op][0],
- hw_cache_result[cache_result][0]);
- } else {
- sprintf(name, "%s-%s", hw_cache[cache_type][0],
- hw_cache_op[cache_op][1]);
- }
-
- return name;
-}
-
const char *event_type(int type)
{
switch (type) {
@@ -287,7 +218,7 @@ const char *event_name(struct perf_evsel *evsel)
u64 config = evsel->attr.config;
int type = evsel->attr.type;
- if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE) {
+ if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE) {
/*
* XXX minimal fix, see comment on perf_evsen__name, this static buffer
* will go away together with event_name in the next devel cycle.
@@ -316,26 +247,9 @@ const char *__event_name(int type, u64 config)
case PERF_TYPE_HARDWARE:
return __perf_evsel__hw_name(config);
- case PERF_TYPE_HW_CACHE: {
- u8 cache_type, cache_op, cache_result;
-
- cache_type = (config >> 0) & 0xff;
- if (cache_type > PERF_COUNT_HW_CACHE_MAX)
- return "unknown-ext-hardware-cache-type";
-
- cache_op = (config >> 8) & 0xff;
- if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
- return "unknown-ext-hardware-cache-op";
-
- cache_result = (config >> 16) & 0xff;
- if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
- return "unknown-ext-hardware-cache-result";
-
- if (!is_cache_op_valid(cache_type, cache_op))
- return "invalid-cache";
-
- return event_cache_name(cache_type, cache_op, cache_result);
- }
+ case PERF_TYPE_HW_CACHE:
+ __perf_evsel__hw_cache_name(config, buf, sizeof(buf));
+ return buf;
case PERF_TYPE_SOFTWARE:
if (config < PERF_COUNT_SW_MAX && sw_event_names[config])
@@ -379,13 +293,13 @@ static int add_event(struct list_head **_list, int *idx,
return 0;
}
-static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
+static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
{
int i, j;
int n, longest = -1;
for (i = 0; i < size; i++) {
- for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
+ for (j = 0; j < PERF_EVSEL__MAX_ALIASES && names[i][j]; j++) {
n = strlen(names[i][j]);
if (n > longest && !strncasecmp(str, names[i][j], n))
longest = n;
@@ -410,7 +324,7 @@ int parse_events_add_cache(struct list_head **list, int *idx,
* No fallback - if we cannot get a clear cache type
* then bail out:
*/
- cache_type = parse_aliases(type, hw_cache,
+ cache_type = parse_aliases(type, perf_evsel__hw_cache,
PERF_COUNT_HW_CACHE_MAX);
if (cache_type == -1)
return -EINVAL;
@@ -423,18 +337,18 @@ int parse_events_add_cache(struct list_head **list, int *idx,
snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
if (cache_op == -1) {
- cache_op = parse_aliases(str, hw_cache_op,
+ cache_op = parse_aliases(str, perf_evsel__hw_cache_op,
PERF_COUNT_HW_CACHE_OP_MAX);
if (cache_op >= 0) {
- if (!is_cache_op_valid(cache_type, cache_op))
+ if (!perf_evsel__is_cache_op_valid(cache_type, cache_op))
return -EINVAL;
continue;
}
}
if (cache_result == -1) {
- cache_result = parse_aliases(str, hw_cache_result,
- PERF_COUNT_HW_CACHE_RESULT_MAX);
+ cache_result = parse_aliases(str, perf_evsel__hw_cache_result,
+ PERF_COUNT_HW_CACHE_RESULT_MAX);
if (cache_result >= 0)
continue;
}
@@ -970,16 +884,17 @@ void print_events_type(u8 type)
int print_hwcache_events(const char *event_glob)
{
unsigned int type, op, i, printed = 0;
+ char name[64];
for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
/* skip invalid cache type */
- if (!is_cache_op_valid(type, op))
+ if (!perf_evsel__is_cache_op_valid(type, op))
continue;
for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
- char *name = event_cache_name(type, op, i);
-
+ __perf_evsel__hw_cache_type_op_res_name(type, op, i,
+ name, sizeof(name));
if (event_glob != NULL && !strglobmatch(name, event_glob))
continue;
--
1.7.1
From: Arnaldo Carvalho de Melo <[email protected]>
Now to convert all event_name users to perf_evsel__name.
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/evsel.c | 24 +++++++++++-------------
tools/perf/util/parse-events.c | 21 +++------------------
2 files changed, 14 insertions(+), 31 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 2da0473..2ddc812 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -252,6 +252,11 @@ static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t
return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
}
+static int perf_evsel__tracepoint_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+ return scnprintf(bf, size, "%s", evsel->name ?: "unknown tracepoint");
+}
+
int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
{
int ret;
@@ -273,20 +278,13 @@ int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
ret = perf_evsel__sw_name(evsel, bf, size);
break;
+ case PERF_TYPE_TRACEPOINT:
+ ret = perf_evsel__tracepoint_name(evsel, bf, size);
+ break;
+
default:
- /*
- * FIXME
- *
- * This is the minimal perf_evsel__name so that we can
- * reconstruct event names taking into account event modifiers.
- *
- * The old event_name uses it now for raw anr hw events, so that
- * we don't drag all the parsing stuff into the python binding.
- *
- * On the next devel cycle the rest of the event naming will be
- * brought here.
- */
- return 0;
+ ret = scnprintf(bf, size, "%s", "unknown attr type");
+ break;
}
return ret;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 641c4ac..d73690b 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -203,24 +203,9 @@ const char *event_type(int type)
const char *event_name(struct perf_evsel *evsel)
{
- u64 config = evsel->attr.config;
- int type = evsel->attr.type;
-
- if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE ||
- type == PERF_TYPE_SOFTWARE || type == PERF_TYPE_HW_CACHE) {
- /*
- * XXX minimal fix, see comment on perf_evsen__name, this static buffer
- * will go away together with event_name in the next devel cycle.
- */
- static char bf[128];
- perf_evsel__name(evsel, bf, sizeof(bf));
- return bf;
- }
-
- if (evsel->name)
- return evsel->name;
-
- return __event_name(type, config);
+ static char bf[128];
+ perf_evsel__name(evsel, bf, sizeof(bf));
+ return bf;
}
const char *__event_name(int type, u64 config)
--
1.7.1
* Arnaldo Carvalho de Melo <[email protected]> wrote:
> Hi Ingo,
>
> Please consider pulling,
>
> - Arnaldo
>
> The following changes since commit e227051b13956b8f71c0abecc41ad351e64671c8:
>
> uprobes: Remove the unnecessary initialization in add_utask() (2012-06-16 09:10:52 +0200)
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux tags/perf-core-for-mingo
>
> for you to fetch changes up to c0a58fb2bdf033df433cad9009c7dac4c6b872b0:
>
> perf annotate: Check null of sym pointer before using it (2012-06-19 14:30:26 -0300)
>
> ----------------------------------------------------------------
> perf/core improvements and fixes
>
> . Replace event_name with perf_evsel__name, that handles the event modifiers
> and doesn't use static variables.
>
> . GTK browser improvements, from Namhyung Kim
>
> . Fix possible NULL pointer deref in the TUI annotate browser, from Samuel Liao
>
> . Add sort by source file:line number, using addr2line.
>
> . Allow printing histogram text snapshots at any point in top/report.
>
> Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
>
> ----------------------------------------------------------------
> Arnaldo Carvalho de Melo (13):
> perf tools: Add sort by src line/number
> perf lib: Introduce rtrim
> perf hists browser: Implement printing snapshots to files
> perf evsel: Carve out event modifier formatting
> perf tools: Reconstruct hw cache event with modifiers from perf_event_attr
> perf tools: Reconstruct sw event with modifiers from perf_event_attr
> perf evsel: Handle all event types in perf_evsel__name
> perf tools: Move all users of event_name to perf_evsel__name
> perf script: Replace __event_name uses with perf_evsel__name
> perf tools: Don't access evsel->name directly
> perf tools: Remove __event_name
> perf evsel: Reconstruct raw event with modifiers from perf_event_attr
> perf evsel: Make some methods private
>
> Jiri Olsa (1):
> perf tools: Remove unused evsel parameter from machine__resolve_callchain
>
> Namhyung Kim (5):
> perf ui: Introduce struct perf_error_ops
> perf ui/gtk: Introduce struct perf_gtk_context
> perf ui/gtk: Add GTK statusbar widget to browser window
> perf ui/gtk: Add GTK info_bar widget to browser window
> perf ui/gtk: Use struct perf_error_ops
>
> Samuel Liao (1):
> perf annotate: Check null of sym pointer before using it
>
> tools/perf/Documentation/perf-report.txt | 2 +-
> tools/perf/Documentation/perf-top.txt | 2 +-
> tools/perf/Makefile | 6 +
> tools/perf/builtin-evlist.c | 2 +-
> tools/perf/builtin-record.c | 4 +-
> tools/perf/builtin-report.c | 10 +-
> tools/perf/builtin-sched.c | 2 +-
> tools/perf/builtin-script.c | 42 ++---
> tools/perf/builtin-stat.c | 12 +-
> tools/perf/builtin-test.c | 2 +-
> tools/perf/builtin-top.c | 12 +-
> tools/perf/config/feature-tests.mak | 13 ++
> tools/perf/ui/browsers/annotate.c | 4 +-
> tools/perf/ui/browsers/hists.c | 210 ++++++++++++++++++++--
> tools/perf/ui/gtk/browser.c | 69 +++++++-
> tools/perf/ui/gtk/gtk.h | 31 ++++
> tools/perf/ui/gtk/setup.c | 5 +
> tools/perf/ui/gtk/util.c | 129 ++++++++++++++
> tools/perf/ui/tui/setup.c | 6 +
> tools/perf/ui/tui/util.c | 243 ++++++++++++++++++++++++++
> tools/perf/ui/util.c | 277 ++++++------------------------
> tools/perf/ui/util.h | 9 +-
> tools/perf/util/debug.c | 2 +-
> tools/perf/util/debug.h | 23 ++-
> tools/perf/util/evsel.c | 196 ++++++++++++++++++---
> tools/perf/util/evsel.h | 15 +-
> tools/perf/util/header.c | 2 +-
> tools/perf/util/hist.h | 1 +
> tools/perf/util/map.h | 2 +-
> tools/perf/util/parse-events-test.c | 4 +-
> tools/perf/util/parse-events.c | 203 ++--------------------
> tools/perf/util/parse-events.h | 2 -
> tools/perf/util/session.c | 9 +-
> tools/perf/util/session.h | 4 +-
> tools/perf/util/sort.c | 49 ++++++
> tools/perf/util/sort.h | 2 +
> tools/perf/util/string.c | 22 +++
> tools/perf/util/top.c | 2 +-
> tools/perf/util/util.h | 2 +
> 39 files changed, 1118 insertions(+), 514 deletions(-)
> create mode 100644 tools/perf/ui/gtk/util.c
> create mode 100644 tools/perf/ui/tui/util.c
Pulled, thanks Arnaldo!
One Makefile bug I noticed is that lib/tracevents does not clean
out these files:
.event-parse.d
.parse-filter.d
.parse-utils.d
.trace-seq.d
and this can break the build when the libgcc package upgraded:
comet:~/tip/tools/perf> make -j
SUBDIR ../lib/traceevent/
make[1]: *** No rule to make target `/usr/lib/gcc/x86_64-redhat-linux/4.7.0/include/stddef.h',
needed by `event-parse.o'. Stop.
make: *** [../lib/traceevent//libtraceevent.a] Error 2
Thanks,
Ingo
2012-06-20 (수), 14:01 +0200, Ingo Molnar:
> One Makefile bug I noticed is that lib/tracevents does not clean
> out these files:
>
> .event-parse.d
> .parse-filter.d
> .parse-utils.d
> .trace-seq.d
>
> and this can break the build when the libgcc package upgraded:
>
> comet:~/tip/tools/perf> make -j
> SUBDIR ../lib/traceevent/
> make[1]: *** No rule to make target `/usr/lib/gcc/x86_64-redhat-linux/4.7.0/include/stddef.h',
> needed by `event-parse.o'. Stop.
> make: *** [../lib/traceevent//libtraceevent.a] Error 2
>
So how should we deal with it? Just plain 'make clean' should delete *.d
files or add something like 'make distclean' to do that?
--
Regards,
Namhyung Kim
* Namhyung Kim <[email protected]> wrote:
> 2012-06-20 (수), 14:01 +0200, Ingo Molnar:
> > One Makefile bug I noticed is that lib/tracevents does not clean
> > out these files:
> >
> > .event-parse.d
> > .parse-filter.d
> > .parse-utils.d
> > .trace-seq.d
> >
> > and this can break the build when the libgcc package upgraded:
> >
> > comet:~/tip/tools/perf> make -j
> > SUBDIR ../lib/traceevent/
> > make[1]: *** No rule to make target `/usr/lib/gcc/x86_64-redhat-linux/4.7.0/include/stddef.h',
> > needed by `event-parse.o'. Stop.
> > make: *** [../lib/traceevent//libtraceevent.a] Error 2
>
> So how should we deal with it? Just plain 'make clean' should
> delete *.d files or add something like 'make distclean' to do
> that?
Well, 'make' should notice that they are stale or should
regenerate them all the time.
Thanks,
Ingo
Hi, Ingo
On Wed, 20 Jun 2012 16:49:02 +0200, Ingo Molnar wrote:
> Well, 'make' should notice that they are stale or should
> regenerate them all the time.
>
Could you check the patch below does it?
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index 3d69aa9ff51e..42f018e15f36 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -250,8 +250,12 @@ endef
all_objs := $(sort $(ALL_OBJS))
all_deps := $(all_objs:%.o=.%.d)
+# let .d file also depends on the source and header files
define check_deps
- $(CC) -M $(CFLAGS) $< > $@;
+ @set -e; $(RM) $@; \
+ $(CC) -M $(CFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ $(RM) $@.$$$$
endef
$(gui_deps): ks_version.h
* Namhyung Kim <[email protected]> wrote:
> Hi, Ingo
>
> On Wed, 20 Jun 2012 16:49:02 +0200, Ingo Molnar wrote:
> > Well, 'make' should notice that they are stale or should
> > regenerate them all the time.
> >
>
> Could you check the patch below does it?
>
>
> diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
> index 3d69aa9ff51e..42f018e15f36 100644
> --- a/tools/lib/traceevent/Makefile
> +++ b/tools/lib/traceevent/Makefile
> @@ -250,8 +250,12 @@ endef
> all_objs := $(sort $(ALL_OBJS))
> all_deps := $(all_objs:%.o=.%.d)
>
> +# let .d file also depends on the source and header files
> define check_deps
> - $(CC) -M $(CFLAGS) $< > $@;
> + @set -e; $(RM) $@; \
> + $(CC) -M $(CFLAGS) $< > $@.$$$$; \
> + sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
> + $(RM) $@.$$$$
> endef
Yeah, something like this should do the trick.
Thanks,
Ingo