aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2012-06-20 07:41:42 -0400
committerIngo Molnar <mingo@kernel.org>2012-06-20 07:41:53 -0400
commit32c46e579b68c7ac0cd19d0803898a841d99833d (patch)
tree64a15c3b6eca5b302ef5aff0e045f52035c33eb7
parent2992c542fcd40777ed253f57362c65711fb8acaf (diff)
parentc0a58fb2bdf033df433cad9009c7dac4c6b872b0 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf improvements from Arnaldo Carvalho de Melo: * 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 <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/perf/Documentation/perf-report.txt2
-rw-r--r--tools/perf/Documentation/perf-top.txt2
-rw-r--r--tools/perf/Makefile6
-rw-r--r--tools/perf/builtin-evlist.c2
-rw-r--r--tools/perf/builtin-record.c4
-rw-r--r--tools/perf/builtin-report.c10
-rw-r--r--tools/perf/builtin-sched.c2
-rw-r--r--tools/perf/builtin-script.c42
-rw-r--r--tools/perf/builtin-stat.c12
-rw-r--r--tools/perf/builtin-test.c2
-rw-r--r--tools/perf/builtin-top.c12
-rw-r--r--tools/perf/config/feature-tests.mak13
-rw-r--r--tools/perf/ui/browsers/annotate.c4
-rw-r--r--tools/perf/ui/browsers/hists.c210
-rw-r--r--tools/perf/ui/gtk/browser.c69
-rw-r--r--tools/perf/ui/gtk/gtk.h31
-rw-r--r--tools/perf/ui/gtk/setup.c5
-rw-r--r--tools/perf/ui/gtk/util.c129
-rw-r--r--tools/perf/ui/tui/setup.c6
-rw-r--r--tools/perf/ui/tui/util.c243
-rw-r--r--tools/perf/ui/util.c277
-rw-r--r--tools/perf/ui/util.h9
-rw-r--r--tools/perf/util/debug.c2
-rw-r--r--tools/perf/util/debug.h23
-rw-r--r--tools/perf/util/evsel.c196
-rw-r--r--tools/perf/util/evsel.h15
-rw-r--r--tools/perf/util/header.c2
-rw-r--r--tools/perf/util/hist.h1
-rw-r--r--tools/perf/util/map.h2
-rw-r--r--tools/perf/util/parse-events-test.c4
-rw-r--r--tools/perf/util/parse-events.c203
-rw-r--r--tools/perf/util/parse-events.h2
-rw-r--r--tools/perf/util/session.c9
-rw-r--r--tools/perf/util/session.h4
-rw-r--r--tools/perf/util/sort.c49
-rw-r--r--tools/perf/util/sort.h2
-rw-r--r--tools/perf/util/string.c22
-rw-r--r--tools/perf/util/top.c2
-rw-r--r--tools/perf/util/util.h2
39 files changed, 1118 insertions, 514 deletions
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 2d89f02719b5..495210a612c4 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -57,7 +57,7 @@ OPTIONS
57 57
58-s:: 58-s::
59--sort=:: 59--sort=::
60 Sort by key(s): pid, comm, dso, symbol, parent. 60 Sort by key(s): pid, comm, dso, symbol, parent, srcline.
61 61
62-p:: 62-p::
63--parent=<regex>:: 63--parent=<regex>::
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 4a5680cb242e..5b80d84d6b4a 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.
112 112
113-s:: 113-s::
114--sort:: 114--sort::
115 Sort by key(s): pid, comm, dso, symbol, parent 115 Sort by key(s): pid, comm, dso, symbol, parent, srcline.
116 116
117-n:: 117-n::
118--show-nr-samples:: 118--show-nr-samples::
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 0eee64cfe9a0..d698c118a602 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -503,6 +503,7 @@ else
503 LIB_OBJS += $(OUTPUT)ui/progress.o 503 LIB_OBJS += $(OUTPUT)ui/progress.o
504 LIB_OBJS += $(OUTPUT)ui/util.o 504 LIB_OBJS += $(OUTPUT)ui/util.o
505 LIB_OBJS += $(OUTPUT)ui/tui/setup.o 505 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
506 LIB_OBJS += $(OUTPUT)ui/tui/util.o
506 LIB_H += ui/browser.h 507 LIB_H += ui/browser.h
507 LIB_H += ui/browsers/map.h 508 LIB_H += ui/browsers/map.h
508 LIB_H += ui/helpline.h 509 LIB_H += ui/helpline.h
@@ -522,13 +523,18 @@ else
522 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); 523 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
523 BASIC_CFLAGS += -DNO_GTK2_SUPPORT 524 BASIC_CFLAGS += -DNO_GTK2_SUPPORT
524 else 525 else
526 ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y)
527 BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
528 endif
525 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0) 529 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
526 EXTLIBS += $(shell pkg-config --libs gtk+-2.0) 530 EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
527 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o 531 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
528 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o 532 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
533 LIB_OBJS += $(OUTPUT)ui/gtk/util.o
529 # Make sure that it'd be included only once. 534 # Make sure that it'd be included only once.
530 ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),) 535 ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),)
531 LIB_OBJS += $(OUTPUT)ui/setup.o 536 LIB_OBJS += $(OUTPUT)ui/setup.o
537 LIB_OBJS += $(OUTPUT)ui/util.o
532 endif 538 endif
533 endif 539 endif
534endif 540endif
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index acd78dc28341..0dd5a058f766 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
60 list_for_each_entry(pos, &session->evlist->entries, node) { 60 list_for_each_entry(pos, &session->evlist->entries, node) {
61 bool first = true; 61 bool first = true;
62 62
63 printf("%s", event_name(pos)); 63 printf("%s", perf_evsel__name(pos));
64 64
65 if (details->verbose || details->freq) { 65 if (details->verbose || details->freq) {
66 comma_printf(&first, " sample_freq=%" PRIu64, 66 comma_printf(&first, " sample_freq=%" PRIu64,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f95840d04e4c..f5a6452931e6 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -265,7 +265,7 @@ try_again:
265 265
266 if (err == ENOENT) { 266 if (err == ENOENT) {
267 ui__error("The %s event is not supported.\n", 267 ui__error("The %s event is not supported.\n",
268 event_name(pos)); 268 perf_evsel__name(pos));
269 exit(EXIT_FAILURE); 269 exit(EXIT_FAILURE);
270 } 270 }
271 271
@@ -916,7 +916,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
916 usage_with_options(record_usage, record_options); 916 usage_with_options(record_usage, record_options);
917 917
918 list_for_each_entry(pos, &evsel_list->entries, node) { 918 list_for_each_entry(pos, &evsel_list->entries, node) {
919 if (perf_header__push_event(pos->attr.config, event_name(pos))) 919 if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
920 goto out_free_fd; 920 goto out_free_fd;
921 } 921 }
922 922
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 25249f76329d..40b0ffc3ad3b 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,
69 69
70 if ((sort__has_parent || symbol_conf.use_callchain) 70 if ((sort__has_parent || symbol_conf.use_callchain)
71 && sample->callchain) { 71 && sample->callchain) {
72 err = machine__resolve_callchain(machine, evsel, al->thread, 72 err = machine__resolve_callchain(machine, al->thread,
73 sample->callchain, &parent); 73 sample->callchain, &parent);
74 if (err) 74 if (err)
75 return err; 75 return err;
@@ -140,7 +140,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
140 struct hist_entry *he; 140 struct hist_entry *he;
141 141
142 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 142 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
143 err = machine__resolve_callchain(machine, evsel, al->thread, 143 err = machine__resolve_callchain(machine, al->thread,
144 sample->callchain, &parent); 144 sample->callchain, &parent);
145 if (err) 145 if (err)
146 return err; 146 return err;
@@ -230,7 +230,7 @@ static int process_read_event(struct perf_tool *tool,
230 struct perf_report *rep = container_of(tool, struct perf_report, tool); 230 struct perf_report *rep = container_of(tool, struct perf_report, tool);
231 231
232 if (rep->show_threads) { 232 if (rep->show_threads) {
233 const char *name = evsel ? event_name(evsel) : "unknown"; 233 const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
234 perf_read_values_add_value(&rep->show_threads_values, 234 perf_read_values_add_value(&rep->show_threads_values,
235 event->read.pid, event->read.tid, 235 event->read.pid, event->read.tid,
236 event->read.id, 236 event->read.id,
@@ -239,7 +239,7 @@ static int process_read_event(struct perf_tool *tool,
239 } 239 }
240 240
241 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid, 241 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
242 evsel ? event_name(evsel) : "FAIL", 242 evsel ? perf_evsel__name(evsel) : "FAIL",
243 event->read.value); 243 event->read.value);
244 244
245 return 0; 245 return 0;
@@ -314,7 +314,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
314 314
315 list_for_each_entry(pos, &evlist->entries, node) { 315 list_for_each_entry(pos, &evlist->entries, node) {
316 struct hists *hists = &pos->hists; 316 struct hists *hists = &pos->hists;
317 const char *evname = event_name(pos); 317 const char *evname = perf_evsel__name(pos);
318 318
319 hists__fprintf_nr_sample_events(hists, evname, stdout); 319 hists__fprintf_nr_sample_events(hists, evname, stdout);
320 hists__fprintf(hists, NULL, false, true, 0, 0, stdout); 320 hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index b125e07eb399..9fe77b185338 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,
1601 1601
1602 if (thread == NULL) { 1602 if (thread == NULL) {
1603 pr_debug("problem processing %s event, skipping it.\n", 1603 pr_debug("problem processing %s event, skipping it.\n",
1604 evsel->name); 1604 perf_evsel__name(evsel));
1605 return -1; 1605 return -1;
1606 } 1606 }
1607 1607
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 8e395a538eb9..8fecd3b8130a 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)
137 137
138#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) 138#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x)
139 139
140static int perf_event_attr__check_stype(struct perf_event_attr *attr, 140static int perf_evsel__check_stype(struct perf_evsel *evsel,
141 u64 sample_type, const char *sample_msg, 141 u64 sample_type, const char *sample_msg,
142 enum perf_output_field field) 142 enum perf_output_field field)
143{ 143{
144 struct perf_event_attr *attr = &evsel->attr;
144 int type = attr->type; 145 int type = attr->type;
145 const char *evname; 146 const char *evname;
146 147
@@ -148,7 +149,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr,
148 return 0; 149 return 0;
149 150
150 if (output[type].user_set) { 151 if (output[type].user_set) {
151 evname = __event_name(attr->type, attr->config); 152 evname = perf_evsel__name(evsel);
152 pr_err("Samples for '%s' event do not have %s attribute set. " 153 pr_err("Samples for '%s' event do not have %s attribute set. "
153 "Cannot print '%s' field.\n", 154 "Cannot print '%s' field.\n",
154 evname, sample_msg, output_field2str(field)); 155 evname, sample_msg, output_field2str(field));
@@ -157,7 +158,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr,
157 158
158 /* user did not ask for it explicitly so remove from the default list */ 159 /* user did not ask for it explicitly so remove from the default list */
159 output[type].fields &= ~field; 160 output[type].fields &= ~field;
160 evname = __event_name(attr->type, attr->config); 161 evname = perf_evsel__name(evsel);
161 pr_debug("Samples for '%s' event do not have %s attribute set. " 162 pr_debug("Samples for '%s' event do not have %s attribute set. "
162 "Skipping '%s' field.\n", 163 "Skipping '%s' field.\n",
163 evname, sample_msg, output_field2str(field)); 164 evname, sample_msg, output_field2str(field));
@@ -175,8 +176,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
175 return -EINVAL; 176 return -EINVAL;
176 177
177 if (PRINT_FIELD(IP)) { 178 if (PRINT_FIELD(IP)) {
178 if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP", 179 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
179 PERF_OUTPUT_IP)) 180 PERF_OUTPUT_IP))
180 return -EINVAL; 181 return -EINVAL;
181 182
182 if (!no_callchain && 183 if (!no_callchain &&
@@ -185,8 +186,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
185 } 186 }
186 187
187 if (PRINT_FIELD(ADDR) && 188 if (PRINT_FIELD(ADDR) &&
188 perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR", 189 perf_evsel__check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR",
189 PERF_OUTPUT_ADDR)) 190 PERF_OUTPUT_ADDR))
190 return -EINVAL; 191 return -EINVAL;
191 192
192 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { 193 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
@@ -208,18 +209,18 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
208 } 209 }
209 210
210 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && 211 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
211 perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID", 212 perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID",
212 PERF_OUTPUT_TID|PERF_OUTPUT_PID)) 213 PERF_OUTPUT_TID|PERF_OUTPUT_PID))
213 return -EINVAL; 214 return -EINVAL;
214 215
215 if (PRINT_FIELD(TIME) && 216 if (PRINT_FIELD(TIME) &&
216 perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME", 217 perf_evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME",
217 PERF_OUTPUT_TIME)) 218 PERF_OUTPUT_TIME))
218 return -EINVAL; 219 return -EINVAL;
219 220
220 if (PRINT_FIELD(CPU) && 221 if (PRINT_FIELD(CPU) &&
221 perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU", 222 perf_evsel__check_stype(evsel, PERF_SAMPLE_CPU, "CPU",
222 PERF_OUTPUT_CPU)) 223 PERF_OUTPUT_CPU))
223 return -EINVAL; 224 return -EINVAL;
224 225
225 return 0; 226 return 0;
@@ -258,9 +259,10 @@ static int perf_session__check_output_opt(struct perf_session *session)
258 259
259static void print_sample_start(struct perf_sample *sample, 260static void print_sample_start(struct perf_sample *sample,
260 struct thread *thread, 261 struct thread *thread,
261 struct perf_event_attr *attr) 262 struct perf_evsel *evsel)
262{ 263{
263 int type; 264 int type;
265 struct perf_event_attr *attr = &evsel->attr;
264 struct event_format *event; 266 struct event_format *event;
265 const char *evname = NULL; 267 const char *evname = NULL;
266 unsigned long secs; 268 unsigned long secs;
@@ -305,7 +307,7 @@ static void print_sample_start(struct perf_sample *sample,
305 if (event) 307 if (event)
306 evname = event->name; 308 evname = event->name;
307 } else 309 } else
308 evname = __event_name(attr->type, attr->config); 310 evname = perf_evsel__name(evsel);
309 311
310 printf("%s: ", evname ? evname : "[unknown]"); 312 printf("%s: ", evname ? evname : "[unknown]");
311 } 313 }
@@ -387,7 +389,7 @@ static void print_sample_bts(union perf_event *event,
387 printf(" "); 389 printf(" ");
388 else 390 else
389 printf("\n"); 391 printf("\n");
390 perf_event__print_ip(event, sample, machine, evsel, 392 perf_event__print_ip(event, sample, machine,
391 PRINT_FIELD(SYM), PRINT_FIELD(DSO), 393 PRINT_FIELD(SYM), PRINT_FIELD(DSO),
392 PRINT_FIELD(SYMOFFSET)); 394 PRINT_FIELD(SYMOFFSET));
393 } 395 }
@@ -412,7 +414,7 @@ static void process_event(union perf_event *event __unused,
412 if (output[attr->type].fields == 0) 414 if (output[attr->type].fields == 0)
413 return; 415 return;
414 416
415 print_sample_start(sample, thread, attr); 417 print_sample_start(sample, thread, evsel);
416 418
417 if (is_bts_event(attr)) { 419 if (is_bts_event(attr)) {
418 print_sample_bts(event, sample, evsel, machine, thread); 420 print_sample_bts(event, sample, evsel, machine, thread);
@@ -431,7 +433,7 @@ static void process_event(union perf_event *event __unused,
431 printf(" "); 433 printf(" ");
432 else 434 else
433 printf("\n"); 435 printf("\n");
434 perf_event__print_ip(event, sample, machine, evsel, 436 perf_event__print_ip(event, sample, machine,
435 PRINT_FIELD(SYM), PRINT_FIELD(DSO), 437 PRINT_FIELD(SYM), PRINT_FIELD(DSO),
436 PRINT_FIELD(SYMOFFSET)); 438 PRINT_FIELD(SYMOFFSET));
437 } 439 }
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 07b5c7703dd1..861f0aec77ae 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)
391 391
392 if (verbose) { 392 if (verbose) {
393 fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", 393 fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
394 event_name(counter), count[0], count[1], count[2]); 394 perf_evsel__name(counter), count[0], count[1], count[2]);
395 } 395 }
396 396
397 /* 397 /*
@@ -496,7 +496,7 @@ static int run_perf_stat(int argc __used, const char **argv)
496 errno == ENXIO) { 496 errno == ENXIO) {
497 if (verbose) 497 if (verbose)
498 ui__warning("%s event is not supported by the kernel.\n", 498 ui__warning("%s event is not supported by the kernel.\n",
499 event_name(counter)); 499 perf_evsel__name(counter));
500 counter->supported = false; 500 counter->supported = false;
501 continue; 501 continue;
502 } 502 }
@@ -594,7 +594,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
594 csv_output ? 0 : -4, 594 csv_output ? 0 : -4,
595 evsel_list->cpus->map[cpu], csv_sep); 595 evsel_list->cpus->map[cpu], csv_sep);
596 596
597 fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel)); 597 fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel));
598 598
599 if (evsel->cgrp) 599 if (evsel->cgrp)
600 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 600 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)
792 else 792 else
793 cpu = 0; 793 cpu = 0;
794 794
795 fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel)); 795 fprintf(output, fmt, cpustr, avg, csv_sep, perf_evsel__name(evsel));
796 796
797 if (evsel->cgrp) 797 if (evsel->cgrp)
798 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 798 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -908,7 +908,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
908 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 908 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
909 csv_sep, 909 csv_sep,
910 csv_output ? 0 : -24, 910 csv_output ? 0 : -24,
911 event_name(counter)); 911 perf_evsel__name(counter));
912 912
913 if (counter->cgrp) 913 if (counter->cgrp)
914 fprintf(output, "%s%s", csv_sep, counter->cgrp->name); 914 fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
@@ -961,7 +961,7 @@ static void print_counter(struct perf_evsel *counter)
961 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 961 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
962 csv_sep, 962 csv_sep,
963 csv_output ? 0 : -24, 963 csv_output ? 0 : -24,
964 event_name(counter)); 964 perf_evsel__name(counter));
965 965
966 if (counter->cgrp) 966 if (counter->cgrp)
967 fprintf(output, "%s%s", 967 fprintf(output, "%s%s",
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 5a8727c08757..5ce30305462b 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -583,7 +583,7 @@ static int test__basic_mmap(void)
583 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { 583 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
584 pr_debug("expected %d %s events, got %d\n", 584 pr_debug("expected %d %s events, got %d\n",
585 expected_nr_events[evsel->idx], 585 expected_nr_events[evsel->idx],
586 event_name(evsel), nr_events[evsel->idx]); 586 perf_evsel__name(evsel), nr_events[evsel->idx]);
587 goto out_munmap; 587 goto out_munmap;
588 } 588 }
589 } 589 }
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 6bb0277b7dfe..e3cab5f088f8 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)
245 if (notes->src == NULL) 245 if (notes->src == NULL)
246 goto out_unlock; 246 goto out_unlock;
247 247
248 printf("Showing %s for %s\n", event_name(top->sym_evsel), symbol->name); 248 printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name);
249 printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); 249 printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter);
250 250
251 more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx, 251 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)
408 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries); 408 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries);
409 409
410 if (top->evlist->nr_entries > 1) 410 if (top->evlist->nr_entries > 1)
411 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top->sym_evsel)); 411 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", perf_evsel__name(top->sym_evsel));
412 412
413 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); 413 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter);
414 414
@@ -503,13 +503,13 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
503 fprintf(stderr, "\nAvailable events:"); 503 fprintf(stderr, "\nAvailable events:");
504 504
505 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) 505 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
506 fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel)); 506 fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel));
507 507
508 prompt_integer(&counter, "Enter details event counter"); 508 prompt_integer(&counter, "Enter details event counter");
509 509
510 if (counter >= top->evlist->nr_entries) { 510 if (counter >= top->evlist->nr_entries) {
511 top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node); 511 top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
512 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel)); 512 fprintf(stderr, "Sorry, no such event, using %s.\n", perf_evsel__name(top->sym_evsel));
513 sleep(1); 513 sleep(1);
514 break; 514 break;
515 } 515 }
@@ -774,7 +774,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
774 774
775 if ((sort__has_parent || symbol_conf.use_callchain) && 775 if ((sort__has_parent || symbol_conf.use_callchain) &&
776 sample->callchain) { 776 sample->callchain) {
777 err = machine__resolve_callchain(machine, evsel, al.thread, 777 err = machine__resolve_callchain(machine, al.thread,
778 sample->callchain, &parent); 778 sample->callchain, &parent);
779 if (err) 779 if (err)
780 return; 780 return;
@@ -960,7 +960,7 @@ try_again:
960 960
961 if (err == ENOENT) { 961 if (err == ENOENT) {
962 ui__error("The %s event is not supported.\n", 962 ui__error("The %s event is not supported.\n",
963 event_name(counter)); 963 perf_evsel__name(counter));
964 goto out_err; 964 goto out_err;
965 } else if (err == EMFILE) { 965 } else if (err == EMFILE) {
966 ui__error("Too many events are opened.\n" 966 ui__error("Too many events are opened.\n"
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index d9084e03ce56..6c18785a6417 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[])
78 return 0; 78 return 0;
79} 79}
80endef 80endef
81
82define SOURCE_GTK2_INFOBAR
83#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
84#include <gtk/gtk.h>
85#pragma GCC diagnostic error \"-Wstrict-prototypes\"
86
87int main(void)
88{
89 gtk_info_bar_new();
90
91 return 0;
92}
93endef
81endif 94endif
82 95
83ifndef NO_LIBPERL 96ifndef NO_LIBPERL
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 34b1c46eaf42..67a2703e666a 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,
814{ 814{
815 struct disasm_line *pos, *n; 815 struct disasm_line *pos, *n;
816 struct annotation *notes; 816 struct annotation *notes;
817 const size_t size = symbol__size(sym); 817 size_t size;
818 struct map_symbol ms = { 818 struct map_symbol ms = {
819 .map = map, 819 .map = map,
820 .sym = sym, 820 .sym = sym,
@@ -834,6 +834,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
834 if (sym == NULL) 834 if (sym == NULL)
835 return -1; 835 return -1;
836 836
837 size = symbol__size(sym);
838
837 if (map->dso->annotate_warned) 839 if (map->dso->annotate_warned)
838 return -1; 840 return -1;
839 841
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 53f6697d014e..482f0517b61e 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -23,6 +23,7 @@ struct hist_browser {
23 struct hists *hists; 23 struct hists *hists;
24 struct hist_entry *he_selection; 24 struct hist_entry *he_selection;
25 struct map_symbol *selection; 25 struct map_symbol *selection;
26 int print_seq;
26 bool has_symbols; 27 bool has_symbols;
27}; 28};
28 29
@@ -800,6 +801,196 @@ do_offset:
800 } 801 }
801} 802}
802 803
804static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
805 struct callchain_node *chain_node,
806 u64 total, int level,
807 FILE *fp)
808{
809 struct rb_node *node;
810 int offset = level * LEVEL_OFFSET_STEP;
811 u64 new_total, remaining;
812 int printed = 0;
813
814 if (callchain_param.mode == CHAIN_GRAPH_REL)
815 new_total = chain_node->children_hit;
816 else
817 new_total = total;
818
819 remaining = new_total;
820 node = rb_first(&chain_node->rb_root);
821 while (node) {
822 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
823 struct rb_node *next = rb_next(node);
824 u64 cumul = callchain_cumul_hits(child);
825 struct callchain_list *chain;
826 char folded_sign = ' ';
827 int first = true;
828 int extra_offset = 0;
829
830 remaining -= cumul;
831
832 list_for_each_entry(chain, &child->val, list) {
833 char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
834 const char *str;
835 bool was_first = first;
836
837 if (first)
838 first = false;
839 else
840 extra_offset = LEVEL_OFFSET_STEP;
841
842 folded_sign = callchain_list__folded(chain);
843
844 alloc_str = NULL;
845 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
846 if (was_first) {
847 double percent = cumul * 100.0 / new_total;
848
849 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
850 str = "Not enough memory!";
851 else
852 str = alloc_str;
853 }
854
855 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
856 free(alloc_str);
857 if (folded_sign == '+')
858 break;
859 }
860
861 if (folded_sign == '-') {
862 const int new_level = level + (extra_offset ? 2 : 1);
863 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
864 new_level, fp);
865 }
866
867 node = next;
868 }
869
870 return printed;
871}
872
873static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
874 struct callchain_node *node,
875 int level, FILE *fp)
876{
877 struct callchain_list *chain;
878 int offset = level * LEVEL_OFFSET_STEP;
879 char folded_sign = ' ';
880 int printed = 0;
881
882 list_for_each_entry(chain, &node->val, list) {
883 char ipstr[BITS_PER_LONG / 4 + 1], *s;
884
885 folded_sign = callchain_list__folded(chain);
886 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
887 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
888 }
889
890 if (folded_sign == '-')
891 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
892 browser->hists->stats.total_period,
893 level + 1, fp);
894 return printed;
895}
896
897static int hist_browser__fprintf_callchain(struct hist_browser *browser,
898 struct rb_root *chain, int level, FILE *fp)
899{
900 struct rb_node *nd;
901 int printed = 0;
902
903 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
904 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
905
906 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
907 }
908
909 return printed;
910}
911
912static int hist_browser__fprintf_entry(struct hist_browser *browser,
913 struct hist_entry *he, FILE *fp)
914{
915 char s[8192];
916 double percent;
917 int printed = 0;
918 char folded_sign = ' ';
919
920 if (symbol_conf.use_callchain)
921 folded_sign = hist_entry__folded(he);
922
923 hist_entry__snprintf(he, s, sizeof(s), browser->hists);
924 percent = (he->period * 100.0) / browser->hists->stats.total_period;
925
926 if (symbol_conf.use_callchain)
927 printed += fprintf(fp, "%c ", folded_sign);
928
929 printed += fprintf(fp, " %5.2f%%", percent);
930
931 if (symbol_conf.show_nr_samples)
932 printed += fprintf(fp, " %11u", he->nr_events);
933
934 if (symbol_conf.show_total_period)
935 printed += fprintf(fp, " %12" PRIu64, he->period);
936
937 printed += fprintf(fp, "%s\n", rtrim(s));
938
939 if (folded_sign == '-')
940 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
941
942 return printed;
943}
944
945static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
946{
947 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries));
948 int printed = 0;
949
950 while (nd) {
951 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
952
953 printed += hist_browser__fprintf_entry(browser, h, fp);
954 nd = hists__filter_entries(rb_next(nd));
955 }
956
957 return printed;
958}
959
960static int hist_browser__dump(struct hist_browser *browser)
961{
962 char filename[64];
963 FILE *fp;
964
965 while (1) {
966 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
967 if (access(filename, F_OK))
968 break;
969 /*
970 * XXX: Just an arbitrary lazy upper limit
971 */
972 if (++browser->print_seq == 8192) {
973 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
974 return -1;
975 }
976 }
977
978 fp = fopen(filename, "w");
979 if (fp == NULL) {
980 char bf[64];
981 strerror_r(errno, bf, sizeof(bf));
982 ui_helpline__fpush("Couldn't write to %s: %s", filename, bf);
983 return -1;
984 }
985
986 ++browser->print_seq;
987 hist_browser__fprintf(browser, fp);
988 fclose(fp);
989 ui_helpline__fpush("%s written!", filename);
990
991 return 0;
992}
993
803static struct hist_browser *hist_browser__new(struct hists *hists) 994static struct hist_browser *hist_browser__new(struct hists *hists)
804{ 995{
805 struct hist_browser *browser = zalloc(sizeof(*browser)); 996 struct hist_browser *browser = zalloc(sizeof(*browser));
@@ -937,6 +1128,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
937 browser->selection->map->dso->annotate_warned) 1128 browser->selection->map->dso->annotate_warned)
938 continue; 1129 continue;
939 goto do_annotate; 1130 goto do_annotate;
1131 case 'P':
1132 hist_browser__dump(browser);
1133 continue;
940 case 'd': 1134 case 'd':
941 goto zoom_dso; 1135 goto zoom_dso;
942 case 't': 1136 case 't':
@@ -969,6 +1163,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
969 "E Expand all callchains\n" 1163 "E Expand all callchains\n"
970 "d Zoom into current DSO\n" 1164 "d Zoom into current DSO\n"
971 "t Zoom into current Thread\n" 1165 "t Zoom into current Thread\n"
1166 "P Print histograms to perf.hist.N\n"
972 "/ Filter symbol by name"); 1167 "/ Filter symbol by name");
973 continue; 1168 continue;
974 case K_ENTER: 1169 case K_ENTER:
@@ -1172,7 +1367,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1172 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 1367 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1173 bool current_entry = ui_browser__is_current_entry(browser, row); 1368 bool current_entry = ui_browser__is_current_entry(browser, row);
1174 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1369 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1175 const char *ev_name = event_name(evsel); 1370 const char *ev_name = perf_evsel__name(evsel);
1176 char bf[256], unit; 1371 char bf[256], unit;
1177 const char *warn = " "; 1372 const char *warn = " ";
1178 size_t printed; 1373 size_t printed;
@@ -1240,7 +1435,7 @@ browse_hists:
1240 */ 1435 */
1241 if (timer) 1436 if (timer)
1242 timer(arg); 1437 timer(arg);
1243 ev_name = event_name(pos); 1438 ev_name = perf_evsel__name(pos);
1244 key = perf_evsel__hists_browse(pos, nr_events, help, 1439 key = perf_evsel__hists_browse(pos, nr_events, help,
1245 ev_name, true, timer, 1440 ev_name, true, timer,
1246 arg, delay_secs); 1441 arg, delay_secs);
@@ -1309,17 +1504,11 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1309 ui_helpline__push("Press ESC to exit"); 1504 ui_helpline__push("Press ESC to exit");
1310 1505
1311 list_for_each_entry(pos, &evlist->entries, node) { 1506 list_for_each_entry(pos, &evlist->entries, node) {
1312 const char *ev_name = event_name(pos); 1507 const char *ev_name = perf_evsel__name(pos);
1313 size_t line_len = strlen(ev_name) + 7; 1508 size_t line_len = strlen(ev_name) + 7;
1314 1509
1315 if (menu.b.width < line_len) 1510 if (menu.b.width < line_len)
1316 menu.b.width = line_len; 1511 menu.b.width = line_len;
1317 /*
1318 * Cache the evsel name, tracepoints have a _high_ cost per
1319 * event_name() call.
1320 */
1321 if (pos->name == NULL)
1322 pos->name = strdup(ev_name);
1323 } 1512 }
1324 1513
1325 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer, 1514 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
@@ -1330,11 +1519,10 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1330 void(*timer)(void *arg), void *arg, 1519 void(*timer)(void *arg), void *arg,
1331 int delay_secs) 1520 int delay_secs)
1332{ 1521{
1333
1334 if (evlist->nr_entries == 1) { 1522 if (evlist->nr_entries == 1) {
1335 struct perf_evsel *first = list_entry(evlist->entries.next, 1523 struct perf_evsel *first = list_entry(evlist->entries.next,
1336 struct perf_evsel, node); 1524 struct perf_evsel, node);
1337 const char *ev_name = event_name(first); 1525 const char *ev_name = perf_evsel__name(first);
1338 return perf_evsel__hists_browse(first, evlist->nr_entries, help, 1526 return perf_evsel__hists_browse(first, evlist->nr_entries, help,
1339 ev_name, false, timer, arg, 1527 ev_name, false, timer, arg,
1340 delay_secs); 1528 delay_secs);
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 0656c381a89c..ec12e0b4ded6 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -11,8 +11,8 @@
11 11
12static void perf_gtk__signal(int sig) 12static void perf_gtk__signal(int sig)
13{ 13{
14 perf_gtk__exit(false);
14 psignal(sig, "perf"); 15 psignal(sig, "perf");
15 gtk_main_quit();
16} 16}
17 17
18static void perf_gtk__resize_window(GtkWidget *window) 18static void perf_gtk__resize_window(GtkWidget *window)
@@ -122,13 +122,59 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
122 gtk_container_add(GTK_CONTAINER(window), view); 122 gtk_container_add(GTK_CONTAINER(window), view);
123} 123}
124 124
125#ifdef HAVE_GTK_INFO_BAR
126static GtkWidget *perf_gtk__setup_info_bar(void)
127{
128 GtkWidget *info_bar;
129 GtkWidget *label;
130 GtkWidget *content_area;
131
132 info_bar = gtk_info_bar_new();
133 gtk_widget_set_no_show_all(info_bar, TRUE);
134
135 label = gtk_label_new("");
136 gtk_widget_show(label);
137
138 content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(info_bar));
139 gtk_container_add(GTK_CONTAINER(content_area), label);
140
141 gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), GTK_STOCK_OK,
142 GTK_RESPONSE_OK);
143 g_signal_connect(info_bar, "response",
144 G_CALLBACK(gtk_widget_hide), NULL);
145
146 pgctx->info_bar = info_bar;
147 pgctx->message_label = label;
148
149 return info_bar;
150}
151#endif
152
153static GtkWidget *perf_gtk__setup_statusbar(void)
154{
155 GtkWidget *stbar;
156 unsigned ctxid;
157
158 stbar = gtk_statusbar_new();
159
160 ctxid = gtk_statusbar_get_context_id(GTK_STATUSBAR(stbar),
161 "perf report");
162 pgctx->statbar = stbar;
163 pgctx->statbar_ctx_id = ctxid;
164
165 return stbar;
166}
167
125int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, 168int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
126 const char *help __used, 169 const char *help __used,
127 void (*timer) (void *arg)__used, 170 void (*timer) (void *arg)__used,
128 void *arg __used, int delay_secs __used) 171 void *arg __used, int delay_secs __used)
129{ 172{
130 struct perf_evsel *pos; 173 struct perf_evsel *pos;
174 GtkWidget *vbox;
131 GtkWidget *notebook; 175 GtkWidget *notebook;
176 GtkWidget *info_bar;
177 GtkWidget *statbar;
132 GtkWidget *window; 178 GtkWidget *window;
133 179
134 signal(SIGSEGV, perf_gtk__signal); 180 signal(SIGSEGV, perf_gtk__signal);
@@ -143,11 +189,17 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
143 189
144 g_signal_connect(window, "delete_event", gtk_main_quit, NULL); 190 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
145 191
192 pgctx = perf_gtk__activate_context(window);
193 if (!pgctx)
194 return -1;
195
196 vbox = gtk_vbox_new(FALSE, 0);
197
146 notebook = gtk_notebook_new(); 198 notebook = gtk_notebook_new();
147 199
148 list_for_each_entry(pos, &evlist->entries, node) { 200 list_for_each_entry(pos, &evlist->entries, node) {
149 struct hists *hists = &pos->hists; 201 struct hists *hists = &pos->hists;
150 const char *evname = event_name(pos); 202 const char *evname = perf_evsel__name(pos);
151 GtkWidget *scrolled_window; 203 GtkWidget *scrolled_window;
152 GtkWidget *tab_label; 204 GtkWidget *tab_label;
153 205
@@ -164,7 +216,16 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
164 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); 216 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
165 } 217 }
166 218
167 gtk_container_add(GTK_CONTAINER(window), notebook); 219 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
220
221 info_bar = perf_gtk__setup_info_bar();
222 if (info_bar)
223 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
224
225 statbar = perf_gtk__setup_statusbar();
226 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
227
228 gtk_container_add(GTK_CONTAINER(window), vbox);
168 229
169 gtk_widget_show_all(window); 230 gtk_widget_show_all(window);
170 231
@@ -174,5 +235,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
174 235
175 gtk_main(); 236 gtk_main();
176 237
238 perf_gtk__deactivate_context(&pgctx);
239
177 return 0; 240 return 0;
178} 241}
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 75177ee04032..a4d0f2b4a2dc 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -1,8 +1,39 @@
1#ifndef _PERF_GTK_H_ 1#ifndef _PERF_GTK_H_
2#define _PERF_GTK_H_ 1 2#define _PERF_GTK_H_ 1
3 3
4#include <stdbool.h>
5
4#pragma GCC diagnostic ignored "-Wstrict-prototypes" 6#pragma GCC diagnostic ignored "-Wstrict-prototypes"
5#include <gtk/gtk.h> 7#include <gtk/gtk.h>
6#pragma GCC diagnostic error "-Wstrict-prototypes" 8#pragma GCC diagnostic error "-Wstrict-prototypes"
7 9
10
11struct perf_gtk_context {
12 GtkWidget *main_window;
13
14#ifdef HAVE_GTK_INFO_BAR
15 GtkWidget *info_bar;
16 GtkWidget *message_label;
17#endif
18 GtkWidget *statbar;
19 guint statbar_ctx_id;
20};
21
22extern struct perf_gtk_context *pgctx;
23
24static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx)
25{
26 return ctx && ctx->main_window;
27}
28
29struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
30int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
31
32#ifndef HAVE_GTK_INFO_BAR
33static inline GtkWidget *perf_gtk__setup_info_bar(void)
34{
35 return NULL;
36}
37#endif
38
8#endif /* _PERF_GTK_H_ */ 39#endif /* _PERF_GTK_H_ */
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
index 829529957766..92879ce61e2f 100644
--- a/tools/perf/ui/gtk/setup.c
+++ b/tools/perf/ui/gtk/setup.c
@@ -1,12 +1,17 @@
1#include "gtk.h" 1#include "gtk.h"
2#include "../../util/cache.h" 2#include "../../util/cache.h"
3#include "../../util/debug.h"
4
5extern struct perf_error_ops perf_gtk_eops;
3 6
4int perf_gtk__init(void) 7int perf_gtk__init(void)
5{ 8{
9 perf_error__register(&perf_gtk_eops);
6 return gtk_init_check(NULL, NULL) ? 0 : -1; 10 return gtk_init_check(NULL, NULL) ? 0 : -1;
7} 11}
8 12
9void perf_gtk__exit(bool wait_for_ok __used) 13void perf_gtk__exit(bool wait_for_ok __used)
10{ 14{
15 perf_error__unregister(&perf_gtk_eops);
11 gtk_main_quit(); 16 gtk_main_quit();
12} 17}
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
new file mode 100644
index 000000000000..0ead373c0dfb
--- /dev/null
+++ b/tools/perf/ui/gtk/util.c
@@ -0,0 +1,129 @@
1#include "../util.h"
2#include "../../util/debug.h"
3#include "gtk.h"
4
5#include <string.h>
6
7
8struct perf_gtk_context *pgctx;
9
10struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window)
11{
12 struct perf_gtk_context *ctx;
13
14 ctx = malloc(sizeof(*pgctx));
15 if (ctx)
16 ctx->main_window = window;
17
18 return ctx;
19}
20
21int perf_gtk__deactivate_context(struct perf_gtk_context **ctx)
22{
23 if (!perf_gtk__is_active_context(*ctx))
24 return -1;
25
26 free(*ctx);
27 *ctx = NULL;
28 return 0;
29}
30
31static int perf_gtk__error(const char *format, va_list args)
32{
33 char *msg;
34 GtkWidget *dialog;
35
36 if (!perf_gtk__is_active_context(pgctx) ||
37 vasprintf(&msg, format, args) < 0) {
38 fprintf(stderr, "Error:\n");
39 vfprintf(stderr, format, args);
40 fprintf(stderr, "\n");
41 return -1;
42 }
43
44 dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(pgctx->main_window),
45 GTK_DIALOG_DESTROY_WITH_PARENT,
46 GTK_MESSAGE_ERROR,
47 GTK_BUTTONS_CLOSE,
48 "<b>Error</b>\n\n%s", msg);
49 gtk_dialog_run(GTK_DIALOG(dialog));
50
51 gtk_widget_destroy(dialog);
52 free(msg);
53 return 0;
54}
55
56#ifdef HAVE_GTK_INFO_BAR
57static int perf_gtk__warning_info_bar(const char *format, va_list args)
58{
59 char *msg;
60
61 if (!perf_gtk__is_active_context(pgctx) ||
62 vasprintf(&msg, format, args) < 0) {
63 fprintf(stderr, "Warning:\n");
64 vfprintf(stderr, format, args);
65 fprintf(stderr, "\n");
66 return -1;
67 }
68
69 gtk_label_set_text(GTK_LABEL(pgctx->message_label), msg);
70 gtk_info_bar_set_message_type(GTK_INFO_BAR(pgctx->info_bar),
71 GTK_MESSAGE_WARNING);
72 gtk_widget_show(pgctx->info_bar);
73
74 free(msg);
75 return 0;
76}
77#else
78static int perf_gtk__warning_statusbar(const char *format, va_list args)
79{
80 char *msg, *p;
81
82 if (!perf_gtk__is_active_context(pgctx) ||
83 vasprintf(&msg, format, args) < 0) {
84 fprintf(stderr, "Warning:\n");
85 vfprintf(stderr, format, args);
86 fprintf(stderr, "\n");
87 return -1;
88 }
89
90 gtk_statusbar_pop(GTK_STATUSBAR(pgctx->statbar),
91 pgctx->statbar_ctx_id);
92
93 /* Only first line can be displayed */
94 p = strchr(msg, '\n');
95 if (p)
96 *p = '\0';
97
98 gtk_statusbar_push(GTK_STATUSBAR(pgctx->statbar),
99 pgctx->statbar_ctx_id, msg);
100
101 free(msg);
102 return 0;
103}
104#endif
105
106struct perf_error_ops perf_gtk_eops = {
107 .error = perf_gtk__error,
108#ifdef HAVE_GTK_INFO_BAR
109 .warning = perf_gtk__warning_info_bar,
110#else
111 .warning = perf_gtk__warning_statusbar,
112#endif
113};
114
115/*
116 * FIXME: Functions below should be implemented properly.
117 * For now, just add stubs for NO_NEWT=1 build.
118 */
119#ifdef NO_NEWT_SUPPORT
120int ui_helpline__show_help(const char *format __used, va_list ap __used)
121{
122 return 0;
123}
124
125void ui_progress__update(u64 curr __used, u64 total __used,
126 const char *title __used)
127{
128}
129#endif
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index d33e943ac434..e813c1d17346 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;
15 15
16static volatile int ui__need_resize; 16static volatile int ui__need_resize;
17 17
18extern struct perf_error_ops perf_tui_eops;
19
18void ui__refresh_dimensions(bool force) 20void ui__refresh_dimensions(bool force)
19{ 21{
20 if (force || ui__need_resize) { 22 if (force || ui__need_resize) {
@@ -122,6 +124,8 @@ int ui__init(void)
122 signal(SIGINT, ui__signal); 124 signal(SIGINT, ui__signal);
123 signal(SIGQUIT, ui__signal); 125 signal(SIGQUIT, ui__signal);
124 signal(SIGTERM, ui__signal); 126 signal(SIGTERM, ui__signal);
127
128 perf_error__register(&perf_tui_eops);
125out: 129out:
126 return err; 130 return err;
127} 131}
@@ -137,4 +141,6 @@ void ui__exit(bool wait_for_ok)
137 SLsmg_refresh(); 141 SLsmg_refresh();
138 SLsmg_reset_smg(); 142 SLsmg_reset_smg();
139 SLang_reset_tty(); 143 SLang_reset_tty();
144
145 perf_error__unregister(&perf_tui_eops);
140} 146}
diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c
new file mode 100644
index 000000000000..092902e30cee
--- /dev/null
+++ b/tools/perf/ui/tui/util.c
@@ -0,0 +1,243 @@
1#include "../../util/util.h"
2#include <signal.h>
3#include <stdbool.h>
4#include <string.h>
5#include <sys/ttydefaults.h>
6
7#include "../../util/cache.h"
8#include "../../util/debug.h"
9#include "../browser.h"
10#include "../keysyms.h"
11#include "../helpline.h"
12#include "../ui.h"
13#include "../util.h"
14#include "../libslang.h"
15
16static void ui_browser__argv_write(struct ui_browser *browser,
17 void *entry, int row)
18{
19 char **arg = entry;
20 bool current_entry = ui_browser__is_current_entry(browser, row);
21
22 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
23 HE_COLORSET_NORMAL);
24 slsmg_write_nstring(*arg, browser->width);
25}
26
27static int popup_menu__run(struct ui_browser *menu)
28{
29 int key;
30
31 if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
32 return -1;
33
34 while (1) {
35 key = ui_browser__run(menu, 0);
36
37 switch (key) {
38 case K_RIGHT:
39 case K_ENTER:
40 key = menu->index;
41 break;
42 case K_LEFT:
43 case K_ESC:
44 case 'q':
45 case CTRL('c'):
46 key = -1;
47 break;
48 default:
49 continue;
50 }
51
52 break;
53 }
54
55 ui_browser__hide(menu);
56 return key;
57}
58
59int ui__popup_menu(int argc, char * const argv[])
60{
61 struct ui_browser menu = {
62 .entries = (void *)argv,
63 .refresh = ui_browser__argv_refresh,
64 .seek = ui_browser__argv_seek,
65 .write = ui_browser__argv_write,
66 .nr_entries = argc,
67 };
68
69 return popup_menu__run(&menu);
70}
71
72int ui_browser__input_window(const char *title, const char *text, char *input,
73 const char *exit_msg, int delay_secs)
74{
75 int x, y, len, key;
76 int max_len = 60, nr_lines = 0;
77 static char buf[50];
78 const char *t;
79
80 t = text;
81 while (1) {
82 const char *sep = strchr(t, '\n');
83
84 if (sep == NULL)
85 sep = strchr(t, '\0');
86 len = sep - t;
87 if (max_len < len)
88 max_len = len;
89 ++nr_lines;
90 if (*sep == '\0')
91 break;
92 t = sep + 1;
93 }
94
95 max_len += 2;
96 nr_lines += 8;
97 y = SLtt_Screen_Rows / 2 - nr_lines / 2;
98 x = SLtt_Screen_Cols / 2 - max_len / 2;
99
100 SLsmg_set_color(0);
101 SLsmg_draw_box(y, x++, nr_lines, max_len);
102 if (title) {
103 SLsmg_gotorc(y, x + 1);
104 SLsmg_write_string((char *)title);
105 }
106 SLsmg_gotorc(++y, x);
107 nr_lines -= 7;
108 max_len -= 2;
109 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
110 nr_lines, max_len, 1);
111 y += nr_lines;
112 len = 5;
113 while (len--) {
114 SLsmg_gotorc(y + len - 1, x);
115 SLsmg_write_nstring((char *)" ", max_len);
116 }
117 SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
118
119 SLsmg_gotorc(y + 3, x);
120 SLsmg_write_nstring((char *)exit_msg, max_len);
121 SLsmg_refresh();
122
123 x += 2;
124 len = 0;
125 key = ui__getch(delay_secs);
126 while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
127 if (key == K_BKSPC) {
128 if (len == 0)
129 goto next_key;
130 SLsmg_gotorc(y, x + --len);
131 SLsmg_write_char(' ');
132 } else {
133 buf[len] = key;
134 SLsmg_gotorc(y, x + len++);
135 SLsmg_write_char(key);
136 }
137 SLsmg_refresh();
138
139 /* XXX more graceful overflow handling needed */
140 if (len == sizeof(buf) - 1) {
141 ui_helpline__push("maximum size of symbol name reached!");
142 key = K_ENTER;
143 break;
144 }
145next_key:
146 key = ui__getch(delay_secs);
147 }
148
149 buf[len] = '\0';
150 strncpy(input, buf, len+1);
151 return key;
152}
153
154int ui__question_window(const char *title, const char *text,
155 const char *exit_msg, int delay_secs)
156{
157 int x, y;
158 int max_len = 0, nr_lines = 0;
159 const char *t;
160
161 t = text;
162 while (1) {
163 const char *sep = strchr(t, '\n');
164 int len;
165
166 if (sep == NULL)
167 sep = strchr(t, '\0');
168 len = sep - t;
169 if (max_len < len)
170 max_len = len;
171 ++nr_lines;
172 if (*sep == '\0')
173 break;
174 t = sep + 1;
175 }
176
177 max_len += 2;
178 nr_lines += 4;
179 y = SLtt_Screen_Rows / 2 - nr_lines / 2,
180 x = SLtt_Screen_Cols / 2 - max_len / 2;
181
182 SLsmg_set_color(0);
183 SLsmg_draw_box(y, x++, nr_lines, max_len);
184 if (title) {
185 SLsmg_gotorc(y, x + 1);
186 SLsmg_write_string((char *)title);
187 }
188 SLsmg_gotorc(++y, x);
189 nr_lines -= 2;
190 max_len -= 2;
191 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
192 nr_lines, max_len, 1);
193 SLsmg_gotorc(y + nr_lines - 2, x);
194 SLsmg_write_nstring((char *)" ", max_len);
195 SLsmg_gotorc(y + nr_lines - 1, x);
196 SLsmg_write_nstring((char *)exit_msg, max_len);
197 SLsmg_refresh();
198 return ui__getch(delay_secs);
199}
200
201int ui__help_window(const char *text)
202{
203 return ui__question_window("Help", text, "Press any key...", 0);
204}
205
206int ui__dialog_yesno(const char *msg)
207{
208 return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
209}
210
211static int __ui__warning(const char *title, const char *format, va_list args)
212{
213 char *s;
214
215 if (vasprintf(&s, format, args) > 0) {
216 int key;
217
218 pthread_mutex_lock(&ui__lock);
219 key = ui__question_window(title, s, "Press any key...", 0);
220 pthread_mutex_unlock(&ui__lock);
221 free(s);
222 return key;
223 }
224
225 fprintf(stderr, "%s\n", title);
226 vfprintf(stderr, format, args);
227 return K_ESC;
228}
229
230static int perf_tui__error(const char *format, va_list args)
231{
232 return __ui__warning("Error:", format, args);
233}
234
235static int perf_tui__warning(const char *format, va_list args)
236{
237 return __ui__warning("Warning:", format, args);
238}
239
240struct perf_error_ops perf_tui_eops = {
241 .error = perf_tui__error,
242 .warning = perf_tui__warning,
243};
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c
index ad4374a16bb0..4f989774c8c6 100644
--- a/tools/perf/ui/util.c
+++ b/tools/perf/ui/util.c
@@ -1,250 +1,85 @@
1#include "../util.h"
2#include <signal.h>
3#include <stdbool.h>
4#include <string.h>
5#include <sys/ttydefaults.h>
6
7#include "../cache.h"
8#include "../debug.h"
9#include "browser.h"
10#include "keysyms.h"
11#include "helpline.h"
12#include "ui.h"
13#include "util.h" 1#include "util.h"
14#include "libslang.h" 2#include "../debug.h"
15
16static void ui_browser__argv_write(struct ui_browser *browser,
17 void *entry, int row)
18{
19 char **arg = entry;
20 bool current_entry = ui_browser__is_current_entry(browser, row);
21
22 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
23 HE_COLORSET_NORMAL);
24 slsmg_write_nstring(*arg, browser->width);
25}
26
27static int popup_menu__run(struct ui_browser *menu)
28{
29 int key;
30
31 if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
32 return -1;
33 3
34 while (1) {
35 key = ui_browser__run(menu, 0);
36
37 switch (key) {
38 case K_RIGHT:
39 case K_ENTER:
40 key = menu->index;
41 break;
42 case K_LEFT:
43 case K_ESC:
44 case 'q':
45 case CTRL('c'):
46 key = -1;
47 break;
48 default:
49 continue;
50 }
51
52 break;
53 }
54
55 ui_browser__hide(menu);
56 return key;
57}
58 4
59int ui__popup_menu(int argc, char * const argv[]) 5/*
6 * Default error logging functions
7 */
8static int perf_stdio__error(const char *format, va_list args)
60{ 9{
61 struct ui_browser menu = { 10 fprintf(stderr, "Error:\n");
62 .entries = (void *)argv, 11 vfprintf(stderr, format, args);
63 .refresh = ui_browser__argv_refresh, 12 return 0;
64 .seek = ui_browser__argv_seek,
65 .write = ui_browser__argv_write,
66 .nr_entries = argc,
67 };
68
69 return popup_menu__run(&menu);
70} 13}
71 14
72int ui_browser__input_window(const char *title, const char *text, char *input, 15static int perf_stdio__warning(const char *format, va_list args)
73 const char *exit_msg, int delay_secs)
74{ 16{
75 int x, y, len, key; 17 fprintf(stderr, "Warning:\n");
76 int max_len = 60, nr_lines = 0; 18 vfprintf(stderr, format, args);
77 static char buf[50]; 19 return 0;
78 const char *t;
79
80 t = text;
81 while (1) {
82 const char *sep = strchr(t, '\n');
83
84 if (sep == NULL)
85 sep = strchr(t, '\0');
86 len = sep - t;
87 if (max_len < len)
88 max_len = len;
89 ++nr_lines;
90 if (*sep == '\0')
91 break;
92 t = sep + 1;
93 }
94
95 max_len += 2;
96 nr_lines += 8;
97 y = SLtt_Screen_Rows / 2 - nr_lines / 2;
98 x = SLtt_Screen_Cols / 2 - max_len / 2;
99
100 SLsmg_set_color(0);
101 SLsmg_draw_box(y, x++, nr_lines, max_len);
102 if (title) {
103 SLsmg_gotorc(y, x + 1);
104 SLsmg_write_string((char *)title);
105 }
106 SLsmg_gotorc(++y, x);
107 nr_lines -= 7;
108 max_len -= 2;
109 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
110 nr_lines, max_len, 1);
111 y += nr_lines;
112 len = 5;
113 while (len--) {
114 SLsmg_gotorc(y + len - 1, x);
115 SLsmg_write_nstring((char *)" ", max_len);
116 }
117 SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
118
119 SLsmg_gotorc(y + 3, x);
120 SLsmg_write_nstring((char *)exit_msg, max_len);
121 SLsmg_refresh();
122
123 x += 2;
124 len = 0;
125 key = ui__getch(delay_secs);
126 while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
127 if (key == K_BKSPC) {
128 if (len == 0)
129 goto next_key;
130 SLsmg_gotorc(y, x + --len);
131 SLsmg_write_char(' ');
132 } else {
133 buf[len] = key;
134 SLsmg_gotorc(y, x + len++);
135 SLsmg_write_char(key);
136 }
137 SLsmg_refresh();
138
139 /* XXX more graceful overflow handling needed */
140 if (len == sizeof(buf) - 1) {
141 ui_helpline__push("maximum size of symbol name reached!");
142 key = K_ENTER;
143 break;
144 }
145next_key:
146 key = ui__getch(delay_secs);
147 }
148
149 buf[len] = '\0';
150 strncpy(input, buf, len+1);
151 return key;
152} 20}
153 21
154int ui__question_window(const char *title, const char *text, 22static struct perf_error_ops default_eops =
155 const char *exit_msg, int delay_secs)
156{ 23{
157 int x, y; 24 .error = perf_stdio__error,
158 int max_len = 0, nr_lines = 0; 25 .warning = perf_stdio__warning,
159 const char *t; 26};
160
161 t = text;
162 while (1) {
163 const char *sep = strchr(t, '\n');
164 int len;
165
166 if (sep == NULL)
167 sep = strchr(t, '\0');
168 len = sep - t;
169 if (max_len < len)
170 max_len = len;
171 ++nr_lines;
172 if (*sep == '\0')
173 break;
174 t = sep + 1;
175 }
176
177 max_len += 2;
178 nr_lines += 4;
179 y = SLtt_Screen_Rows / 2 - nr_lines / 2,
180 x = SLtt_Screen_Cols / 2 - max_len / 2;
181
182 SLsmg_set_color(0);
183 SLsmg_draw_box(y, x++, nr_lines, max_len);
184 if (title) {
185 SLsmg_gotorc(y, x + 1);
186 SLsmg_write_string((char *)title);
187 }
188 SLsmg_gotorc(++y, x);
189 nr_lines -= 2;
190 max_len -= 2;
191 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
192 nr_lines, max_len, 1);
193 SLsmg_gotorc(y + nr_lines - 2, x);
194 SLsmg_write_nstring((char *)" ", max_len);
195 SLsmg_gotorc(y + nr_lines - 1, x);
196 SLsmg_write_nstring((char *)exit_msg, max_len);
197 SLsmg_refresh();
198 return ui__getch(delay_secs);
199}
200 27
201int ui__help_window(const char *text) 28static struct perf_error_ops *perf_eops = &default_eops;
202{
203 return ui__question_window("Help", text, "Press any key...", 0);
204}
205 29
206int ui__dialog_yesno(const char *msg)
207{
208 return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
209}
210 30
211int __ui__warning(const char *title, const char *format, va_list args) 31int ui__error(const char *format, ...)
212{ 32{
213 char *s; 33 int ret;
214 34 va_list args;
215 if (use_browser > 0 && vasprintf(&s, format, args) > 0) {
216 int key;
217 35
218 pthread_mutex_lock(&ui__lock); 36 va_start(args, format);
219 key = ui__question_window(title, s, "Press any key...", 0); 37 ret = perf_eops->error(format, args);
220 pthread_mutex_unlock(&ui__lock); 38 va_end(args);
221 free(s);
222 return key;
223 }
224 39
225 fprintf(stderr, "%s:\n", title); 40 return ret;
226 vfprintf(stderr, format, args);
227 return K_ESC;
228} 41}
229 42
230int ui__warning(const char *format, ...) 43int ui__warning(const char *format, ...)
231{ 44{
232 int key; 45 int ret;
233 va_list args; 46 va_list args;
234 47
235 va_start(args, format); 48 va_start(args, format);
236 key = __ui__warning("Warning", format, args); 49 ret = perf_eops->warning(format, args);
237 va_end(args); 50 va_end(args);
238 return key; 51
52 return ret;
239} 53}
240 54
241int ui__error(const char *format, ...) 55
56/**
57 * perf_error__register - Register error logging functions
58 * @eops: The pointer to error logging function struct
59 *
60 * Register UI-specific error logging functions. Before calling this,
61 * other logging functions should be unregistered, if any.
62 */
63int perf_error__register(struct perf_error_ops *eops)
242{ 64{
243 int key; 65 if (perf_eops != &default_eops)
244 va_list args; 66 return -1;
245 67
246 va_start(args, format); 68 perf_eops = eops;
247 key = __ui__warning("Error", format, args); 69 return 0;
248 va_end(args); 70}
249 return key; 71
72/**
73 * perf_error__unregister - Unregister error logging functions
74 * @eops: The pointer to error logging function struct
75 *
76 * Unregister already registered error logging functions.
77 */
78int perf_error__unregister(struct perf_error_ops *eops)
79{
80 if (perf_eops != eops)
81 return -1;
82
83 perf_eops = &default_eops;
84 return 0;
250} 85}
diff --git a/tools/perf/ui/util.h b/tools/perf/ui/util.h
index 2d1738bd71c8..361f08c52d37 100644
--- a/tools/perf/ui/util.h
+++ b/tools/perf/ui/util.h
@@ -9,6 +9,13 @@ int ui__help_window(const char *text);
9int ui__dialog_yesno(const char *msg); 9int ui__dialog_yesno(const char *msg);
10int ui__question_window(const char *title, const char *text, 10int ui__question_window(const char *title, const char *text,
11 const char *exit_msg, int delay_secs); 11 const char *exit_msg, int delay_secs);
12int __ui__warning(const char *title, const char *format, va_list args); 12
13struct perf_error_ops {
14 int (*error)(const char *format, va_list args);
15 int (*warning)(const char *format, va_list args);
16};
17
18int perf_error__register(struct perf_error_ops *eops);
19int perf_error__unregister(struct perf_error_ops *eops);
13 20
14#endif /* _PERF_UI_UTIL_H_ */ 21#endif /* _PERF_UI_UTIL_H_ */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index efb1fce259a4..4dfe0bb3c322 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -47,7 +47,7 @@ int dump_printf(const char *fmt, ...)
47 return ret; 47 return ret;
48} 48}
49 49
50#ifdef NO_NEWT_SUPPORT 50#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
51int ui__warning(const char *format, ...) 51int ui__warning(const char *format, ...)
52{ 52{
53 va_list args; 53 va_list args;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 6bebe7f0a20c..015c91dbc096 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)));
12void trace_event(union perf_event *event); 12void trace_event(union perf_event *event);
13 13
14struct ui_progress; 14struct ui_progress;
15struct perf_error_ops;
15 16
16#ifdef NO_NEWT_SUPPORT 17#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
17static inline int ui_helpline__show_help(const char *format __used, va_list ap __used) 18static inline int ui_helpline__show_help(const char *format __used, va_list ap __used)
18{ 19{
19 return 0; 20 return 0;
@@ -23,12 +24,28 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used,
23 const char *title __used) {} 24 const char *title __used) {}
24 25
25#define ui__error(format, arg...) ui__warning(format, ##arg) 26#define ui__error(format, arg...) ui__warning(format, ##arg)
26#else 27
28static inline int
29perf_error__register(struct perf_error_ops *eops __used)
30{
31 return 0;
32}
33
34static inline int
35perf_error__unregister(struct perf_error_ops *eops __used)
36{
37 return 0;
38}
39
40#else /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
41
27extern char ui_helpline__last_msg[]; 42extern char ui_helpline__last_msg[];
28int ui_helpline__show_help(const char *format, va_list ap); 43int ui_helpline__show_help(const char *format, va_list ap);
29#include "../ui/progress.h" 44#include "../ui/progress.h"
30int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); 45int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
31#endif 46#include "../ui/util.h"
47
48#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
32 49
33int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 50int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
34int ui__error_paranoid(void); 51int ui__error_paranoid(void);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 9f6cebd798ee..876f639d69ed 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] = {
78 "ref-cycles", 78 "ref-cycles",
79}; 79};
80 80
81const char *__perf_evsel__hw_name(u64 config) 81static const char *__perf_evsel__hw_name(u64 config)
82{ 82{
83 if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config]) 83 if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config])
84 return perf_evsel__hw_names[config]; 84 return perf_evsel__hw_names[config];
@@ -86,16 +86,15 @@ const char *__perf_evsel__hw_name(u64 config)
86 return "unknown-hardware"; 86 return "unknown-hardware";
87} 87}
88 88
89static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) 89static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size)
90{ 90{
91 int colon = 0; 91 int colon = 0, r = 0;
92 struct perf_event_attr *attr = &evsel->attr; 92 struct perf_event_attr *attr = &evsel->attr;
93 int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(attr->config));
94 bool exclude_guest_default = false; 93 bool exclude_guest_default = false;
95 94
96#define MOD_PRINT(context, mod) do { \ 95#define MOD_PRINT(context, mod) do { \
97 if (!attr->exclude_##context) { \ 96 if (!attr->exclude_##context) { \
98 if (!colon) colon = r++; \ 97 if (!colon) colon = ++r; \
99 r += scnprintf(bf + r, size - r, "%c", mod); \ 98 r += scnprintf(bf + r, size - r, "%c", mod); \
100 } } while(0) 99 } } while(0)
101 100
@@ -108,7 +107,7 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
108 107
109 if (attr->precise_ip) { 108 if (attr->precise_ip) {
110 if (!colon) 109 if (!colon)
111 colon = r++; 110 colon = ++r;
112 r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp"); 111 r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp");
113 exclude_guest_default = true; 112 exclude_guest_default = true;
114 } 113 }
@@ -119,39 +118,182 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
119 } 118 }
120#undef MOD_PRINT 119#undef MOD_PRINT
121 if (colon) 120 if (colon)
122 bf[colon] = ':'; 121 bf[colon - 1] = ':';
123 return r; 122 return r;
124} 123}
125 124
126int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size) 125static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
126{
127 int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config));
128 return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
129}
130
131static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
132 "cpu-clock",
133 "task-clock",
134 "page-faults",
135 "context-switches",
136 "CPU-migrations",
137 "minor-faults",
138 "major-faults",
139 "alignment-faults",
140 "emulation-faults",
141};
142
143static const char *__perf_evsel__sw_name(u64 config)
144{
145 if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config])
146 return perf_evsel__sw_names[config];
147 return "unknown-software";
148}
149
150static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size)
151{
152 int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config));
153 return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
154}
155
156const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
157 [PERF_EVSEL__MAX_ALIASES] = {
158 { "L1-dcache", "l1-d", "l1d", "L1-data", },
159 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
160 { "LLC", "L2", },
161 { "dTLB", "d-tlb", "Data-TLB", },
162 { "iTLB", "i-tlb", "Instruction-TLB", },
163 { "branch", "branches", "bpu", "btb", "bpc", },
164 { "node", },
165};
166
167const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
168 [PERF_EVSEL__MAX_ALIASES] = {
169 { "load", "loads", "read", },
170 { "store", "stores", "write", },
171 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
172};
173
174const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
175 [PERF_EVSEL__MAX_ALIASES] = {
176 { "refs", "Reference", "ops", "access", },
177 { "misses", "miss", },
178};
179
180#define C(x) PERF_COUNT_HW_CACHE_##x
181#define CACHE_READ (1 << C(OP_READ))
182#define CACHE_WRITE (1 << C(OP_WRITE))
183#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
184#define COP(x) (1 << x)
185
186/*
187 * cache operartion stat
188 * L1I : Read and prefetch only
189 * ITLB and BPU : Read-only
190 */
191static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = {
192 [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
193 [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
194 [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
195 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
196 [C(ITLB)] = (CACHE_READ),
197 [C(BPU)] = (CACHE_READ),
198 [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
199};
200
201bool perf_evsel__is_cache_op_valid(u8 type, u8 op)
202{
203 if (perf_evsel__hw_cache_stat[type] & COP(op))
204 return true; /* valid */
205 else
206 return false; /* invalid */
207}
208
209int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
210 char *bf, size_t size)
211{
212 if (result) {
213 return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0],
214 perf_evsel__hw_cache_op[op][0],
215 perf_evsel__hw_cache_result[result][0]);
216 }
217
218 return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0],
219 perf_evsel__hw_cache_op[op][1]);
220}
221
222static int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size)
127{ 223{
128 int ret; 224 u8 op, result, type = (config >> 0) & 0xff;
225 const char *err = "unknown-ext-hardware-cache-type";
226
227 if (type > PERF_COUNT_HW_CACHE_MAX)
228 goto out_err;
229
230 op = (config >> 8) & 0xff;
231 err = "unknown-ext-hardware-cache-op";
232 if (op > PERF_COUNT_HW_CACHE_OP_MAX)
233 goto out_err;
234
235 result = (config >> 16) & 0xff;
236 err = "unknown-ext-hardware-cache-result";
237 if (result > PERF_COUNT_HW_CACHE_RESULT_MAX)
238 goto out_err;
239
240 err = "invalid-cache";
241 if (!perf_evsel__is_cache_op_valid(type, op))
242 goto out_err;
243
244 return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size);
245out_err:
246 return scnprintf(bf, size, "%s", err);
247}
248
249static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size)
250{
251 int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size);
252 return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
253}
254
255static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size)
256{
257 int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
258 return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
259}
260
261const char *perf_evsel__name(struct perf_evsel *evsel)
262{
263 char bf[128];
264
265 if (evsel->name)
266 return evsel->name;
129 267
130 switch (evsel->attr.type) { 268 switch (evsel->attr.type) {
131 case PERF_TYPE_RAW: 269 case PERF_TYPE_RAW:
132 ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config); 270 perf_evsel__raw_name(evsel, bf, sizeof(bf));
133 break; 271 break;
134 272
135 case PERF_TYPE_HARDWARE: 273 case PERF_TYPE_HARDWARE:
136 ret = perf_evsel__hw_name(evsel, bf, size); 274 perf_evsel__hw_name(evsel, bf, sizeof(bf));
275 break;
276
277 case PERF_TYPE_HW_CACHE:
278 perf_evsel__hw_cache_name(evsel, bf, sizeof(bf));
279 break;
280
281 case PERF_TYPE_SOFTWARE:
282 perf_evsel__sw_name(evsel, bf, sizeof(bf));
137 break; 283 break;
284
285 case PERF_TYPE_TRACEPOINT:
286 scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint");
287 break;
288
138 default: 289 default:
139 /* 290 scnprintf(bf, sizeof(bf), "%s", "unknown attr type");
140 * FIXME 291 break;
141 * 292 }
142 * This is the minimal perf_evsel__name so that we can 293
143 * reconstruct event names taking into account event modifiers. 294 evsel->name = strdup(bf);
144 * 295
145 * The old event_name uses it now for raw anr hw events, so that 296 return evsel->name ?: "unknown";
146 * we don't drag all the parsing stuff into the python binding.
147 *
148 * On the next devel cycle the rest of the event naming will be
149 * brought here.
150 */
151 return 0;
152 }
153
154 return ret;
155} 297}
156 298
157void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, 299void 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 4ba8b564e6f4..67cc5033d192 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -83,8 +83,19 @@ void perf_evsel__config(struct perf_evsel *evsel,
83 struct perf_record_opts *opts, 83 struct perf_record_opts *opts,
84 struct perf_evsel *first); 84 struct perf_evsel *first);
85 85
86const char* __perf_evsel__hw_name(u64 config); 86bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
87int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size); 87
88#define PERF_EVSEL__MAX_ALIASES 8
89
90extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
91 [PERF_EVSEL__MAX_ALIASES];
92extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
93 [PERF_EVSEL__MAX_ALIASES];
94const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
95 [PERF_EVSEL__MAX_ALIASES];
96int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
97 char *bf, size_t size);
98const char *perf_evsel__name(struct perf_evsel *evsel);
88 99
89int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 100int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
90int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 101int 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 e909d43cf542..a5e2015319ee 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,
641 /* 641 /*
642 * write event string as passed on cmdline 642 * write event string as passed on cmdline
643 */ 643 */
644 ret = do_write_string(fd, event_name(attr)); 644 ret = do_write_string(fd, perf_evsel__name(attr));
645 if (ret < 0) 645 if (ret < 0)
646 return ret; 646 return ret;
647 /* 647 /*
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 34bb556d6219..0b096c27a419 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -47,6 +47,7 @@ enum hist_column {
47 HISTC_SYMBOL_TO, 47 HISTC_SYMBOL_TO,
48 HISTC_DSO_FROM, 48 HISTC_DSO_FROM,
49 HISTC_DSO_TO, 49 HISTC_DSO_TO,
50 HISTC_SRCLINE,
50 HISTC_NR_COLS, /* Last entry */ 51 HISTC_NR_COLS, /* Last entry */
51}; 52};
52 53
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 81371bad4ef0..c14c665d9a25 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -157,7 +157,7 @@ void machine__exit(struct machine *self);
157void machine__delete(struct machine *self); 157void machine__delete(struct machine *self);
158 158
159int machine__resolve_callchain(struct machine *machine, 159int machine__resolve_callchain(struct machine *machine,
160 struct perf_evsel *evsel, struct thread *thread, 160 struct thread *thread,
161 struct ip_callchain *chain, 161 struct ip_callchain *chain,
162 struct symbol **parent); 162 struct symbol **parent);
163int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, 163int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
index af1039cdb853..229af6da33a2 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)
418 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); 418 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
419 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); 419 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
420 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); 420 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
421 TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava")); 421 TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "krava"));
422 422
423 /* cpu/config=2/" */ 423 /* cpu/config=2/" */
424 evsel = list_entry(evsel->node.next, struct perf_evsel, node); 424 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
425 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); 425 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
426 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); 426 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
427 TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config); 427 TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config);
428 TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2")); 428 TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "raw 0x2"));
429 429
430 return 0; 430 return 0;
431} 431}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 3339424cc421..0cc27da30ddb 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -64,63 +64,6 @@ static struct event_symbol event_symbols[] = {
64#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) 64#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
65#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) 65#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
66 66
67static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
68 "cpu-clock",
69 "task-clock",
70 "page-faults",
71 "context-switches",
72 "CPU-migrations",
73 "minor-faults",
74 "major-faults",
75 "alignment-faults",
76 "emulation-faults",
77};
78
79#define MAX_ALIASES 8
80
81static const char *hw_cache[PERF_COUNT_HW_CACHE_MAX][MAX_ALIASES] = {
82 { "L1-dcache", "l1-d", "l1d", "L1-data", },
83 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
84 { "LLC", "L2", },
85 { "dTLB", "d-tlb", "Data-TLB", },
86 { "iTLB", "i-tlb", "Instruction-TLB", },
87 { "branch", "branches", "bpu", "btb", "bpc", },
88 { "node", },
89};
90
91static const char *hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][MAX_ALIASES] = {
92 { "load", "loads", "read", },
93 { "store", "stores", "write", },
94 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
95};
96
97static const char *hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
98 [MAX_ALIASES] = {
99 { "refs", "Reference", "ops", "access", },
100 { "misses", "miss", },
101};
102
103#define C(x) PERF_COUNT_HW_CACHE_##x
104#define CACHE_READ (1 << C(OP_READ))
105#define CACHE_WRITE (1 << C(OP_WRITE))
106#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
107#define COP(x) (1 << x)
108
109/*
110 * cache operartion stat
111 * L1I : Read and prefetch only
112 * ITLB and BPU : Read-only
113 */
114static unsigned long hw_cache_stat[C(MAX)] = {
115 [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
116 [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
117 [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
118 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
119 [C(ITLB)] = (CACHE_READ),
120 [C(BPU)] = (CACHE_READ),
121 [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
122};
123
124#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ 67#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \
125 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ 68 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
126 if (sys_dirent.d_type == DT_DIR && \ 69 if (sys_dirent.d_type == DT_DIR && \
@@ -220,48 +163,6 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
220 return NULL; 163 return NULL;
221} 164}
222 165
223#define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1)
224static const char *tracepoint_id_to_name(u64 config)
225{
226 static char buf[TP_PATH_LEN];
227 struct tracepoint_path *path;
228
229 path = tracepoint_id_to_path(config);
230 if (path) {
231 snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name);
232 free(path->name);
233 free(path->system);
234 free(path);
235 } else
236 snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown");
237
238 return buf;
239}
240
241static int is_cache_op_valid(u8 cache_type, u8 cache_op)
242{
243 if (hw_cache_stat[cache_type] & COP(cache_op))
244 return 1; /* valid */
245 else
246 return 0; /* invalid */
247}
248
249static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
250{
251 static char name[50];
252
253 if (cache_result) {
254 sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
255 hw_cache_op[cache_op][0],
256 hw_cache_result[cache_result][0]);
257 } else {
258 sprintf(name, "%s-%s", hw_cache[cache_type][0],
259 hw_cache_op[cache_op][1]);
260 }
261
262 return name;
263}
264
265const char *event_type(int type) 166const char *event_type(int type)
266{ 167{
267 switch (type) { 168 switch (type) {
@@ -284,76 +185,6 @@ const char *event_type(int type)
284 return "unknown"; 185 return "unknown";
285} 186}
286 187
287const char *event_name(struct perf_evsel *evsel)
288{
289 u64 config = evsel->attr.config;
290 int type = evsel->attr.type;
291
292 if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE) {
293 /*
294 * XXX minimal fix, see comment on perf_evsen__name, this static buffer
295 * will go away together with event_name in the next devel cycle.
296 */
297 static char bf[128];
298 perf_evsel__name(evsel, bf, sizeof(bf));
299 return bf;
300 }
301
302 if (evsel->name)
303 return evsel->name;
304
305 return __event_name(type, config);
306}
307
308const char *__event_name(int type, u64 config)
309{
310 static char buf[32];
311
312 if (type == PERF_TYPE_RAW) {
313 sprintf(buf, "raw 0x%" PRIx64, config);
314 return buf;
315 }
316
317 switch (type) {
318 case PERF_TYPE_HARDWARE:
319 return __perf_evsel__hw_name(config);
320
321 case PERF_TYPE_HW_CACHE: {
322 u8 cache_type, cache_op, cache_result;
323
324 cache_type = (config >> 0) & 0xff;
325 if (cache_type > PERF_COUNT_HW_CACHE_MAX)
326 return "unknown-ext-hardware-cache-type";
327
328 cache_op = (config >> 8) & 0xff;
329 if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
330 return "unknown-ext-hardware-cache-op";
331
332 cache_result = (config >> 16) & 0xff;
333 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
334 return "unknown-ext-hardware-cache-result";
335
336 if (!is_cache_op_valid(cache_type, cache_op))
337 return "invalid-cache";
338
339 return event_cache_name(cache_type, cache_op, cache_result);
340 }
341
342 case PERF_TYPE_SOFTWARE:
343 if (config < PERF_COUNT_SW_MAX && sw_event_names[config])
344 return sw_event_names[config];
345 return "unknown-software";
346
347 case PERF_TYPE_TRACEPOINT:
348 return tracepoint_id_to_name(config);
349
350 default:
351 break;
352 }
353
354 return "unknown";
355}
356
357static int add_event(struct list_head **_list, int *idx, 188static int add_event(struct list_head **_list, int *idx,
358 struct perf_event_attr *attr, char *name) 189 struct perf_event_attr *attr, char *name)
359{ 190{
@@ -375,19 +206,20 @@ static int add_event(struct list_head **_list, int *idx,
375 return -ENOMEM; 206 return -ENOMEM;
376 } 207 }
377 208
378 evsel->name = strdup(name); 209 if (name)
210 evsel->name = strdup(name);
379 list_add_tail(&evsel->node, list); 211 list_add_tail(&evsel->node, list);
380 *_list = list; 212 *_list = list;
381 return 0; 213 return 0;
382} 214}
383 215
384static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size) 216static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
385{ 217{
386 int i, j; 218 int i, j;
387 int n, longest = -1; 219 int n, longest = -1;
388 220
389 for (i = 0; i < size; i++) { 221 for (i = 0; i < size; i++) {
390 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) { 222 for (j = 0; j < PERF_EVSEL__MAX_ALIASES && names[i][j]; j++) {
391 n = strlen(names[i][j]); 223 n = strlen(names[i][j]);
392 if (n > longest && !strncasecmp(str, names[i][j], n)) 224 if (n > longest && !strncasecmp(str, names[i][j], n))
393 longest = n; 225 longest = n;
@@ -412,7 +244,7 @@ int parse_events_add_cache(struct list_head **list, int *idx,
412 * No fallback - if we cannot get a clear cache type 244 * No fallback - if we cannot get a clear cache type
413 * then bail out: 245 * then bail out:
414 */ 246 */
415 cache_type = parse_aliases(type, hw_cache, 247 cache_type = parse_aliases(type, perf_evsel__hw_cache,
416 PERF_COUNT_HW_CACHE_MAX); 248 PERF_COUNT_HW_CACHE_MAX);
417 if (cache_type == -1) 249 if (cache_type == -1)
418 return -EINVAL; 250 return -EINVAL;
@@ -425,18 +257,18 @@ int parse_events_add_cache(struct list_head **list, int *idx,
425 snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str); 257 snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
426 258
427 if (cache_op == -1) { 259 if (cache_op == -1) {
428 cache_op = parse_aliases(str, hw_cache_op, 260 cache_op = parse_aliases(str, perf_evsel__hw_cache_op,
429 PERF_COUNT_HW_CACHE_OP_MAX); 261 PERF_COUNT_HW_CACHE_OP_MAX);
430 if (cache_op >= 0) { 262 if (cache_op >= 0) {
431 if (!is_cache_op_valid(cache_type, cache_op)) 263 if (!perf_evsel__is_cache_op_valid(cache_type, cache_op))
432 return -EINVAL; 264 return -EINVAL;
433 continue; 265 continue;
434 } 266 }
435 } 267 }
436 268
437 if (cache_result == -1) { 269 if (cache_result == -1) {
438 cache_result = parse_aliases(str, hw_cache_result, 270 cache_result = parse_aliases(str, perf_evsel__hw_cache_result,
439 PERF_COUNT_HW_CACHE_RESULT_MAX); 271 PERF_COUNT_HW_CACHE_RESULT_MAX);
440 if (cache_result >= 0) 272 if (cache_result >= 0)
441 continue; 273 continue;
442 } 274 }
@@ -668,8 +500,7 @@ int parse_events_add_numeric(struct list_head **list, int *idx,
668 config_attr(&attr, head_config, 1)) 500 config_attr(&attr, head_config, 1))
669 return -EINVAL; 501 return -EINVAL;
670 502
671 return add_event(list, idx, &attr, 503 return add_event(list, idx, &attr, NULL);
672 (char *) __event_name(type, config));
673} 504}
674 505
675static int parse_events__is_name_term(struct parse_events__term *term) 506static int parse_events__is_name_term(struct parse_events__term *term)
@@ -677,8 +508,7 @@ static int parse_events__is_name_term(struct parse_events__term *term)
677 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; 508 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
678} 509}
679 510
680static char *pmu_event_name(struct perf_event_attr *attr, 511static char *pmu_event_name(struct list_head *head_terms)
681 struct list_head *head_terms)
682{ 512{
683 struct parse_events__term *term; 513 struct parse_events__term *term;
684 514
@@ -686,7 +516,7 @@ static char *pmu_event_name(struct perf_event_attr *attr,
686 if (parse_events__is_name_term(term)) 516 if (parse_events__is_name_term(term))
687 return term->val.str; 517 return term->val.str;
688 518
689 return (char *) __event_name(PERF_TYPE_RAW, attr->config); 519 return NULL;
690} 520}
691 521
692int parse_events_add_pmu(struct list_head **list, int *idx, 522int parse_events_add_pmu(struct list_head **list, int *idx,
@@ -714,7 +544,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
714 return -EINVAL; 544 return -EINVAL;
715 545
716 return add_event(list, idx, &attr, 546 return add_event(list, idx, &attr,
717 pmu_event_name(&attr, head_config)); 547 pmu_event_name(head_config));
718} 548}
719 549
720void parse_events_update_lists(struct list_head *list_event, 550void parse_events_update_lists(struct list_head *list_event,
@@ -1010,16 +840,17 @@ void print_events_type(u8 type)
1010int print_hwcache_events(const char *event_glob) 840int print_hwcache_events(const char *event_glob)
1011{ 841{
1012 unsigned int type, op, i, printed = 0; 842 unsigned int type, op, i, printed = 0;
843 char name[64];
1013 844
1014 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 845 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
1015 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 846 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
1016 /* skip invalid cache type */ 847 /* skip invalid cache type */
1017 if (!is_cache_op_valid(type, op)) 848 if (!perf_evsel__is_cache_op_valid(type, op))
1018 continue; 849 continue;
1019 850
1020 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 851 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
1021 char *name = event_cache_name(type, op, i); 852 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
1022 853 name, sizeof(name));
1023 if (event_glob != NULL && !strglobmatch(name, event_glob)) 854 if (event_glob != NULL && !strglobmatch(name, event_glob))
1024 continue; 855 continue;
1025 856
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index a2c71684f6a4..ee9c218a193c 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -26,8 +26,6 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
26extern bool have_tracepoints(struct list_head *evlist); 26extern bool have_tracepoints(struct list_head *evlist);
27 27
28const char *event_type(int type); 28const char *event_type(int type);
29const char *event_name(struct perf_evsel *event);
30extern const char *__event_name(int type, u64 config);
31 29
32extern int parse_events_option(const struct option *opt, const char *str, 30extern int parse_events_option(const struct option *opt, const char *str,
33 int unset); 31 int unset);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index c3e399bcf18d..6b305fbcc986 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,
289} 289}
290 290
291int machine__resolve_callchain(struct machine *self, 291int machine__resolve_callchain(struct machine *self,
292 struct perf_evsel *evsel __used,
293 struct thread *thread, 292 struct thread *thread,
294 struct ip_callchain *chain, 293 struct ip_callchain *chain,
295 struct symbol **parent) 294 struct symbol **parent)
@@ -1449,7 +1448,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1449 ret += hists__fprintf_nr_events(&session->hists, fp); 1448 ret += hists__fprintf_nr_events(&session->hists, fp);
1450 1449
1451 list_for_each_entry(pos, &session->evlist->entries, node) { 1450 list_for_each_entry(pos, &session->evlist->entries, node) {
1452 ret += fprintf(fp, "%s stats:\n", event_name(pos)); 1451 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
1453 ret += hists__fprintf_nr_events(&pos->hists, fp); 1452 ret += hists__fprintf_nr_events(&pos->hists, fp);
1454 } 1453 }
1455 1454
@@ -1490,8 +1489,8 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1490} 1489}
1491 1490
1492void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, 1491void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1493 struct machine *machine, struct perf_evsel *evsel, 1492 struct machine *machine, int print_sym,
1494 int print_sym, int print_dso, int print_symoffset) 1493 int print_dso, int print_symoffset)
1495{ 1494{
1496 struct addr_location al; 1495 struct addr_location al;
1497 struct callchain_cursor_node *node; 1496 struct callchain_cursor_node *node;
@@ -1505,7 +1504,7 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1505 1504
1506 if (symbol_conf.use_callchain && sample->callchain) { 1505 if (symbol_conf.use_callchain && sample->callchain) {
1507 1506
1508 if (machine__resolve_callchain(machine, evsel, al.thread, 1507 if (machine__resolve_callchain(machine, al.thread,
1509 sample->callchain, NULL) != 0) { 1508 sample->callchain, NULL) != 0) {
1510 if (verbose) 1509 if (verbose)
1511 error("Failed to resolve callchain. Skipping\n"); 1510 error("Failed to resolve callchain. Skipping\n");
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 0c702e3f0a36..c71a1a7b05ed 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -151,8 +151,8 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
151 unsigned int type); 151 unsigned int type);
152 152
153void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, 153void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
154 struct machine *machine, struct perf_evsel *evsel, 154 struct machine *machine, int print_sym,
155 int print_sym, int print_dso, int print_symoffset); 155 int print_dso, int print_symoffset);
156 156
157int perf_session__cpu_bitmap(struct perf_session *session, 157int perf_session__cpu_bitmap(struct perf_session *session,
158 const char *cpu_list, unsigned long *cpu_bitmap); 158 const char *cpu_list, unsigned long *cpu_bitmap);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index a27237430c5f..0f5a0a496bc4 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -241,6 +241,54 @@ struct sort_entry sort_sym = {
241 .se_width_idx = HISTC_SYMBOL, 241 .se_width_idx = HISTC_SYMBOL,
242}; 242};
243 243
244/* --sort srcline */
245
246static int64_t
247sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
248{
249 return (int64_t)(right->ip - left->ip);
250}
251
252static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
253 size_t size, unsigned int width __used)
254{
255 FILE *fp;
256 char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
257 size_t line_len;
258
259 if (path != NULL)
260 goto out_path;
261
262 snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
263 self->ms.map->dso->long_name, self->ip);
264 fp = popen(cmd, "r");
265 if (!fp)
266 goto out_ip;
267
268 if (getline(&path, &line_len, fp) < 0 || !line_len)
269 goto out_ip;
270 fclose(fp);
271 self->srcline = strdup(path);
272 if (self->srcline == NULL)
273 goto out_ip;
274
275 nl = strchr(self->srcline, '\n');
276 if (nl != NULL)
277 *nl = '\0';
278 path = self->srcline;
279out_path:
280 return repsep_snprintf(bf, size, "%s", path);
281out_ip:
282 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
283}
284
285struct sort_entry sort_srcline = {
286 .se_header = "Source:Line",
287 .se_cmp = sort__srcline_cmp,
288 .se_snprintf = hist_entry__srcline_snprintf,
289 .se_width_idx = HISTC_SRCLINE,
290};
291
244/* --sort parent */ 292/* --sort parent */
245 293
246static int64_t 294static int64_t
@@ -439,6 +487,7 @@ static struct sort_dimension sort_dimensions[] = {
439 DIM(SORT_PARENT, "parent", sort_parent), 487 DIM(SORT_PARENT, "parent", sort_parent),
440 DIM(SORT_CPU, "cpu", sort_cpu), 488 DIM(SORT_CPU, "cpu", sort_cpu),
441 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), 489 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
490 DIM(SORT_SRCLINE, "srcline", sort_srcline),
442}; 491};
443 492
444int sort_dimension__add(const char *tok) 493int sort_dimension__add(const char *tok)
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 472aa5a63a58..e724b26acd51 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -71,6 +71,7 @@ struct hist_entry {
71 char level; 71 char level;
72 bool used; 72 bool used;
73 u8 filtered; 73 u8 filtered;
74 char *srcline;
74 struct symbol *parent; 75 struct symbol *parent;
75 union { 76 union {
76 unsigned long position; 77 unsigned long position;
@@ -93,6 +94,7 @@ enum sort_type {
93 SORT_SYM_FROM, 94 SORT_SYM_FROM,
94 SORT_SYM_TO, 95 SORT_SYM_TO,
95 SORT_MISPREDICT, 96 SORT_MISPREDICT,
97 SORT_SRCLINE,
96}; 98};
97 99
98/* 100/*
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index d5836382ff2c..199bc4d8905d 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)
313 return 0; 313 return 0;
314} 314}
315 315
316/**
317 * rtrim - Removes trailing whitespace from @s.
318 * @s: The string to be stripped.
319 *
320 * Note that the first trailing whitespace is replaced with a %NUL-terminator
321 * in the given string @s. Returns @s.
322 */
323char *rtrim(char *s)
324{
325 size_t size = strlen(s);
326 char *end;
327
328 if (!size)
329 return s;
330
331 end = s + size - 1;
332 while (end >= s && isspace(*end))
333 end--;
334 *(end + 1) = '\0';
335
336 return s;
337}
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index abe0e8e95068..7eeebcee291c 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)
65 top->freq ? "Hz" : ""); 65 top->freq ? "Hz" : "");
66 } 66 }
67 67
68 ret += SNPRINTF(bf + ret, size - ret, "%s", event_name(top->sym_evsel)); 68 ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel));
69 69
70 ret += SNPRINTF(bf + ret, size - ret, "], "); 70 ret += SNPRINTF(bf + ret, size - ret, "], ");
71 71
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 2daaedb83d84..b13c7331eaf8 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)
264 264
265size_t hex_width(u64 v); 265size_t hex_width(u64 v);
266 266
267char *rtrim(char *s);
268
267#endif 269#endif