diff options
author | Ingo Molnar <mingo@kernel.org> | 2012-06-20 07:41:42 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-06-20 07:41:53 -0400 |
commit | 32c46e579b68c7ac0cd19d0803898a841d99833d (patch) | |
tree | 64a15c3b6eca5b302ef5aff0e045f52035c33eb7 | |
parent | 2992c542fcd40777ed253f57362c65711fb8acaf (diff) | |
parent | c0a58fb2bdf033df433cad9009c7dac4c6b872b0 (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>
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 |
534 | endif | 540 | endif |
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 | ||
140 | static int perf_event_attr__check_stype(struct perf_event_attr *attr, | 140 | static 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 | ||
259 | static void print_sample_start(struct perf_sample *sample, | 260 | static 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 | } |
80 | endef | 80 | endef |
81 | |||
82 | define SOURCE_GTK2_INFOBAR | ||
83 | #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" | ||
84 | #include <gtk/gtk.h> | ||
85 | #pragma GCC diagnostic error \"-Wstrict-prototypes\" | ||
86 | |||
87 | int main(void) | ||
88 | { | ||
89 | gtk_info_bar_new(); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | endef | ||
81 | endif | 94 | endif |
82 | 95 | ||
83 | ifndef NO_LIBPERL | 96 | ifndef 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 | ||
804 | static 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 | |||
873 | static 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 | |||
897 | static 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 | |||
912 | static 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 | |||
945 | static 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 | |||
960 | static 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 | |||
803 | static struct hist_browser *hist_browser__new(struct hists *hists) | 994 | static 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 | ||
12 | static void perf_gtk__signal(int sig) | 12 | static 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 | ||
18 | static void perf_gtk__resize_window(GtkWidget *window) | 18 | static 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 | ||
126 | static 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 | |||
153 | static 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 | |||
125 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | 168 | int 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 | |||
11 | struct 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 | |||
22 | extern struct perf_gtk_context *pgctx; | ||
23 | |||
24 | static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx) | ||
25 | { | ||
26 | return ctx && ctx->main_window; | ||
27 | } | ||
28 | |||
29 | struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window); | ||
30 | int perf_gtk__deactivate_context(struct perf_gtk_context **ctx); | ||
31 | |||
32 | #ifndef HAVE_GTK_INFO_BAR | ||
33 | static 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 | |||
5 | extern struct perf_error_ops perf_gtk_eops; | ||
3 | 6 | ||
4 | int perf_gtk__init(void) | 7 | int 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 | ||
9 | void perf_gtk__exit(bool wait_for_ok __used) | 13 | void 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 | |||
8 | struct perf_gtk_context *pgctx; | ||
9 | |||
10 | struct 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 | |||
21 | int 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 | |||
31 | static 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 | ||
57 | static 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 | ||
78 | static 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 | |||
106 | struct 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 | ||
120 | int ui_helpline__show_help(const char *format __used, va_list ap __used) | ||
121 | { | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | void 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 | ||
16 | static volatile int ui__need_resize; | 16 | static volatile int ui__need_resize; |
17 | 17 | ||
18 | extern struct perf_error_ops perf_tui_eops; | ||
19 | |||
18 | void ui__refresh_dimensions(bool force) | 20 | void 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); | ||
125 | out: | 129 | out: |
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 | |||
16 | static 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 | |||
27 | static 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 | |||
59 | int 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 | |||
72 | int 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 | } | ||
145 | next_key: | ||
146 | key = ui__getch(delay_secs); | ||
147 | } | ||
148 | |||
149 | buf[len] = '\0'; | ||
150 | strncpy(input, buf, len+1); | ||
151 | return key; | ||
152 | } | ||
153 | |||
154 | int 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 | |||
201 | int ui__help_window(const char *text) | ||
202 | { | ||
203 | return ui__question_window("Help", text, "Press any key...", 0); | ||
204 | } | ||
205 | |||
206 | int ui__dialog_yesno(const char *msg) | ||
207 | { | ||
208 | return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); | ||
209 | } | ||
210 | |||
211 | static 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 | |||
230 | static int perf_tui__error(const char *format, va_list args) | ||
231 | { | ||
232 | return __ui__warning("Error:", format, args); | ||
233 | } | ||
234 | |||
235 | static int perf_tui__warning(const char *format, va_list args) | ||
236 | { | ||
237 | return __ui__warning("Warning:", format, args); | ||
238 | } | ||
239 | |||
240 | struct 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 | |||
16 | static 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 | |||
27 | static 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 | ||
59 | int ui__popup_menu(int argc, char * const argv[]) | 5 | /* |
6 | * Default error logging functions | ||
7 | */ | ||
8 | static 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 | ||
72 | int ui_browser__input_window(const char *title, const char *text, char *input, | 15 | static 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 | } | ||
145 | next_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 | ||
154 | int ui__question_window(const char *title, const char *text, | 22 | static 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 | ||
201 | int ui__help_window(const char *text) | 28 | static struct perf_error_ops *perf_eops = &default_eops; |
202 | { | ||
203 | return ui__question_window("Help", text, "Press any key...", 0); | ||
204 | } | ||
205 | 29 | ||
206 | int ui__dialog_yesno(const char *msg) | ||
207 | { | ||
208 | return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); | ||
209 | } | ||
210 | 30 | ||
211 | int __ui__warning(const char *title, const char *format, va_list args) | 31 | int 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 | ||
230 | int ui__warning(const char *format, ...) | 43 | int 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 | ||
241 | int 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 | */ | ||
63 | int 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 | */ | ||
78 | int 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); | |||
9 | int ui__dialog_yesno(const char *msg); | 9 | int ui__dialog_yesno(const char *msg); |
10 | int ui__question_window(const char *title, const char *text, | 10 | int 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); |
12 | int __ui__warning(const char *title, const char *format, va_list args); | 12 | |
13 | struct perf_error_ops { | ||
14 | int (*error)(const char *format, va_list args); | ||
15 | int (*warning)(const char *format, va_list args); | ||
16 | }; | ||
17 | |||
18 | int perf_error__register(struct perf_error_ops *eops); | ||
19 | int 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) |
51 | int ui__warning(const char *format, ...) | 51 | int 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))); | |||
12 | void trace_event(union perf_event *event); | 12 | void trace_event(union perf_event *event); |
13 | 13 | ||
14 | struct ui_progress; | 14 | struct ui_progress; |
15 | struct perf_error_ops; | ||
15 | 16 | ||
16 | #ifdef NO_NEWT_SUPPORT | 17 | #if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) |
17 | static inline int ui_helpline__show_help(const char *format __used, va_list ap __used) | 18 | static 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 | |
28 | static inline int | ||
29 | perf_error__register(struct perf_error_ops *eops __used) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | static inline int | ||
35 | perf_error__unregister(struct perf_error_ops *eops __used) | ||
36 | { | ||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | #else /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ | ||
41 | |||
27 | extern char ui_helpline__last_msg[]; | 42 | extern char ui_helpline__last_msg[]; |
28 | int ui_helpline__show_help(const char *format, va_list ap); | 43 | int ui_helpline__show_help(const char *format, va_list ap); |
29 | #include "../ui/progress.h" | 44 | #include "../ui/progress.h" |
30 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | 45 | int 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 | ||
33 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 50 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
34 | int ui__error_paranoid(void); | 51 | int 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 | ||
81 | const char *__perf_evsel__hw_name(u64 config) | 81 | static 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 | ||
89 | static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) | 89 | static 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 | ||
126 | int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size) | 125 | static 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 | |||
131 | static 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 | |||
143 | static 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 | |||
150 | static 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 | |||
156 | const 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 | |||
167 | const 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 | |||
174 | const 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 | */ | ||
191 | static 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 | |||
201 | bool 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 | |||
209 | int __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 | |||
222 | static 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); | ||
245 | out_err: | ||
246 | return scnprintf(bf, size, "%s", err); | ||
247 | } | ||
248 | |||
249 | static 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 | |||
255 | static 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 | |||
261 | const 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 | ||
157 | void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, | 299 | void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 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 | ||
86 | const char* __perf_evsel__hw_name(u64 config); | 86 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op); |
87 | int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size); | 87 | |
88 | #define PERF_EVSEL__MAX_ALIASES 8 | ||
89 | |||
90 | extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] | ||
91 | [PERF_EVSEL__MAX_ALIASES]; | ||
92 | extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] | ||
93 | [PERF_EVSEL__MAX_ALIASES]; | ||
94 | const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] | ||
95 | [PERF_EVSEL__MAX_ALIASES]; | ||
96 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, | ||
97 | char *bf, size_t size); | ||
98 | const char *perf_evsel__name(struct perf_evsel *evsel); | ||
88 | 99 | ||
89 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 100 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
90 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); | 101 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 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); | |||
157 | void machine__delete(struct machine *self); | 157 | void machine__delete(struct machine *self); |
158 | 158 | ||
159 | int machine__resolve_callchain(struct machine *machine, | 159 | int 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); |
163 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, | 163 | int 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 | ||
67 | static 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 | |||
81 | static 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 | |||
91 | static 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 | |||
97 | static 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 | */ | ||
114 | static 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) | ||
224 | static 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 | |||
241 | static 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 | |||
249 | static 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 | |||
265 | const char *event_type(int type) | 166 | const 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 | ||
287 | const 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 | |||
308 | const 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 | |||
357 | static int add_event(struct list_head **_list, int *idx, | 188 | static 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 | ||
384 | static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size) | 216 | static 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 | ||
675 | static int parse_events__is_name_term(struct parse_events__term *term) | 506 | static 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 | ||
680 | static char *pmu_event_name(struct perf_event_attr *attr, | 511 | static 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 | ||
692 | int parse_events_add_pmu(struct list_head **list, int *idx, | 522 | int 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 | ||
720 | void parse_events_update_lists(struct list_head *list_event, | 550 | void parse_events_update_lists(struct list_head *list_event, |
@@ -1010,16 +840,17 @@ void print_events_type(u8 type) | |||
1010 | int print_hwcache_events(const char *event_glob) | 840 | int 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); | |||
26 | extern bool have_tracepoints(struct list_head *evlist); | 26 | extern bool have_tracepoints(struct list_head *evlist); |
27 | 27 | ||
28 | const char *event_type(int type); | 28 | const char *event_type(int type); |
29 | const char *event_name(struct perf_evsel *event); | ||
30 | extern const char *__event_name(int type, u64 config); | ||
31 | 29 | ||
32 | extern int parse_events_option(const struct option *opt, const char *str, | 30 | extern 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 | ||
291 | int machine__resolve_callchain(struct machine *self, | 291 | int 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 | ||
1492 | void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, | 1491 | void 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 | ||
153 | void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, | 153 | void 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 | ||
157 | int perf_session__cpu_bitmap(struct perf_session *session, | 157 | int 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 | |||
246 | static int64_t | ||
247 | sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) | ||
248 | { | ||
249 | return (int64_t)(right->ip - left->ip); | ||
250 | } | ||
251 | |||
252 | static 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; | ||
279 | out_path: | ||
280 | return repsep_snprintf(bf, size, "%s", path); | ||
281 | out_ip: | ||
282 | return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip); | ||
283 | } | ||
284 | |||
285 | struct 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 | ||
246 | static int64_t | 294 | static 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 | ||
444 | int sort_dimension__add(const char *tok) | 493 | int 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 | */ | ||
323 | char *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 | ||
265 | size_t hex_width(u64 v); | 265 | size_t hex_width(u64 v); |
266 | 266 | ||
267 | char *rtrim(char *s); | ||
268 | |||
267 | #endif | 269 | #endif |