diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-07 15:38:11 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-07 15:38:11 -0500 |
commit | 54a0f91301950af3d6ae2ff2bf710c9c68a9bfea (patch) | |
tree | ffcdf0b916f9c5f805cab347e53b60be17c9aead /tools | |
parent | 94956eed14b4b16d401c8ad36d68df0608f968cb (diff) | |
parent | f9e3d4b1a9c86217655997d3ef109b1eaae967bc (diff) |
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
perf top: Fix live annotation in the --stdio interface
perf top tui: Don't recalc column widths considering just the first page
perf report: Add progress bar when processing time ordered events
perf hists browser: Warn about lost events
perf tools: Fix a typo of command name as trace-cmd
perf hists: Fix recalculation of total_period when sorting entries
perf header: Fix build on old systems
perf ui browser: Handle K_RESIZE in dialog windows
perf ui browser: No need to switch char sets that often
perf hists browser: Use K_TIMER
perf ui: Rename ui__warning_paranoid to ui__error_paranoid
perf ui: Reimplement the popup windows using libslang
perf ui: Reimplement ui__popup_menu using ui__browser
perf ui: Reimplement ui_helpline using libslang
perf ui: Improve handling sigwinch a bit
perf ui progress: Reimplement using slang
perf evlist: Fix grouping of multiple events
Diffstat (limited to 'tools')
31 files changed, 624 insertions, 288 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f82480fa7f27..6ab58cc99d53 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -262,13 +262,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, | |||
262 | 262 | ||
263 | static void open_counters(struct perf_evlist *evlist) | 263 | static void open_counters(struct perf_evlist *evlist) |
264 | { | 264 | { |
265 | struct perf_evsel *pos; | 265 | struct perf_evsel *pos, *first; |
266 | 266 | ||
267 | if (evlist->cpus->map[0] < 0) | 267 | if (evlist->cpus->map[0] < 0) |
268 | no_inherit = true; | 268 | no_inherit = true; |
269 | 269 | ||
270 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
271 | |||
270 | list_for_each_entry(pos, &evlist->entries, node) { | 272 | list_for_each_entry(pos, &evlist->entries, node) { |
271 | struct perf_event_attr *attr = &pos->attr; | 273 | struct perf_event_attr *attr = &pos->attr; |
274 | struct xyarray *group_fd = NULL; | ||
272 | /* | 275 | /* |
273 | * Check if parse_single_tracepoint_event has already asked for | 276 | * Check if parse_single_tracepoint_event has already asked for |
274 | * PERF_SAMPLE_TIME. | 277 | * PERF_SAMPLE_TIME. |
@@ -283,15 +286,19 @@ static void open_counters(struct perf_evlist *evlist) | |||
283 | */ | 286 | */ |
284 | bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; | 287 | bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; |
285 | 288 | ||
289 | if (group && pos != first) | ||
290 | group_fd = first->fd; | ||
291 | |||
286 | config_attr(pos, evlist); | 292 | config_attr(pos, evlist); |
287 | retry_sample_id: | 293 | retry_sample_id: |
288 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | 294 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; |
289 | try_again: | 295 | try_again: |
290 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) { | 296 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, |
297 | group_fd) < 0) { | ||
291 | int err = errno; | 298 | int err = errno; |
292 | 299 | ||
293 | if (err == EPERM || err == EACCES) { | 300 | if (err == EPERM || err == EACCES) { |
294 | ui__warning_paranoid(); | 301 | ui__error_paranoid(); |
295 | exit(EXIT_FAILURE); | 302 | exit(EXIT_FAILURE); |
296 | } else if (err == ENODEV && cpu_list) { | 303 | } else if (err == ENODEV && cpu_list) { |
297 | die("No such device - did you specify" | 304 | die("No such device - did you specify" |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 7ce65f52415e..7d98676808d8 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -278,9 +278,14 @@ struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; | |||
278 | struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; | 278 | struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; |
279 | struct stats walltime_nsecs_stats; | 279 | struct stats walltime_nsecs_stats; |
280 | 280 | ||
281 | static int create_perf_stat_counter(struct perf_evsel *evsel) | 281 | static int create_perf_stat_counter(struct perf_evsel *evsel, |
282 | struct perf_evsel *first) | ||
282 | { | 283 | { |
283 | struct perf_event_attr *attr = &evsel->attr; | 284 | struct perf_event_attr *attr = &evsel->attr; |
285 | struct xyarray *group_fd = NULL; | ||
286 | |||
287 | if (group && evsel != first) | ||
288 | group_fd = first->fd; | ||
284 | 289 | ||
285 | if (scale) | 290 | if (scale) |
286 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 291 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
@@ -289,14 +294,15 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) | |||
289 | attr->inherit = !no_inherit; | 294 | attr->inherit = !no_inherit; |
290 | 295 | ||
291 | if (system_wide) | 296 | if (system_wide) |
292 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group); | 297 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, |
293 | 298 | group, group_fd); | |
294 | if (target_pid == -1 && target_tid == -1) { | 299 | if (target_pid == -1 && target_tid == -1) { |
295 | attr->disabled = 1; | 300 | attr->disabled = 1; |
296 | attr->enable_on_exec = 1; | 301 | attr->enable_on_exec = 1; |
297 | } | 302 | } |
298 | 303 | ||
299 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, group); | 304 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, |
305 | group, group_fd); | ||
300 | } | 306 | } |
301 | 307 | ||
302 | /* | 308 | /* |
@@ -396,7 +402,7 @@ static int read_counter(struct perf_evsel *counter) | |||
396 | static int run_perf_stat(int argc __used, const char **argv) | 402 | static int run_perf_stat(int argc __used, const char **argv) |
397 | { | 403 | { |
398 | unsigned long long t0, t1; | 404 | unsigned long long t0, t1; |
399 | struct perf_evsel *counter; | 405 | struct perf_evsel *counter, *first; |
400 | int status = 0; | 406 | int status = 0; |
401 | int child_ready_pipe[2], go_pipe[2]; | 407 | int child_ready_pipe[2], go_pipe[2]; |
402 | const bool forks = (argc > 0); | 408 | const bool forks = (argc > 0); |
@@ -453,8 +459,10 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
453 | close(child_ready_pipe[0]); | 459 | close(child_ready_pipe[0]); |
454 | } | 460 | } |
455 | 461 | ||
462 | first = list_entry(evsel_list->entries.next, struct perf_evsel, node); | ||
463 | |||
456 | list_for_each_entry(counter, &evsel_list->entries, node) { | 464 | list_for_each_entry(counter, &evsel_list->entries, node) { |
457 | if (create_perf_stat_counter(counter) < 0) { | 465 | if (create_perf_stat_counter(counter, first) < 0) { |
458 | if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) { | 466 | if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) { |
459 | if (verbose) | 467 | if (verbose) |
460 | ui__warning("%s event is not supported by the kernel.\n", | 468 | ui__warning("%s event is not supported by the kernel.\n", |
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index efe696f936e2..831d1baeac37 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
@@ -291,7 +291,7 @@ static int test__open_syscall_event(void) | |||
291 | goto out_thread_map_delete; | 291 | goto out_thread_map_delete; |
292 | } | 292 | } |
293 | 293 | ||
294 | if (perf_evsel__open_per_thread(evsel, threads, false) < 0) { | 294 | if (perf_evsel__open_per_thread(evsel, threads, false, NULL) < 0) { |
295 | pr_debug("failed to open counter: %s, " | 295 | pr_debug("failed to open counter: %s, " |
296 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 296 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
297 | strerror(errno)); | 297 | strerror(errno)); |
@@ -366,7 +366,7 @@ static int test__open_syscall_event_on_all_cpus(void) | |||
366 | goto out_thread_map_delete; | 366 | goto out_thread_map_delete; |
367 | } | 367 | } |
368 | 368 | ||
369 | if (perf_evsel__open(evsel, cpus, threads, false) < 0) { | 369 | if (perf_evsel__open(evsel, cpus, threads, false, NULL) < 0) { |
370 | pr_debug("failed to open counter: %s, " | 370 | pr_debug("failed to open counter: %s, " |
371 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 371 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
372 | strerror(errno)); | 372 | strerror(errno)); |
@@ -531,7 +531,7 @@ static int test__basic_mmap(void) | |||
531 | 531 | ||
532 | perf_evlist__add(evlist, evsels[i]); | 532 | perf_evlist__add(evlist, evsels[i]); |
533 | 533 | ||
534 | if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) { | 534 | if (perf_evsel__open(evsels[i], cpus, threads, false, NULL) < 0) { |
535 | pr_debug("failed to open counter: %s, " | 535 | pr_debug("failed to open counter: %s, " |
536 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 536 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
537 | strerror(errno)); | 537 | strerror(errno)); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7a871714d44e..c9cdedb58134 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -89,6 +89,7 @@ static bool vmlinux_warned; | |||
89 | static bool inherit = false; | 89 | static bool inherit = false; |
90 | static int realtime_prio = 0; | 90 | static int realtime_prio = 0; |
91 | static bool group = false; | 91 | static bool group = false; |
92 | static bool sample_id_all_avail = true; | ||
92 | static unsigned int mmap_pages = 128; | 93 | static unsigned int mmap_pages = 128; |
93 | 94 | ||
94 | static bool dump_symtab = false; | 95 | static bool dump_symtab = false; |
@@ -199,7 +200,8 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) | |||
199 | struct symbol *sym; | 200 | struct symbol *sym; |
200 | 201 | ||
201 | if (he == NULL || he->ms.sym == NULL || | 202 | if (he == NULL || he->ms.sym == NULL || |
202 | (he != top.sym_filter_entry && use_browser != 1)) | 203 | ((top.sym_filter_entry == NULL || |
204 | top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) | ||
203 | return; | 205 | return; |
204 | 206 | ||
205 | sym = he->ms.sym; | 207 | sym = he->ms.sym; |
@@ -289,11 +291,13 @@ static void print_sym_table(void) | |||
289 | 291 | ||
290 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); | 292 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
291 | 293 | ||
292 | if (top.total_lost_warned != top.session->hists.stats.total_lost) { | 294 | if (top.sym_evsel->hists.stats.nr_lost_warned != |
293 | top.total_lost_warned = top.session->hists.stats.total_lost; | 295 | top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { |
294 | color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); | 296 | top.sym_evsel->hists.stats.nr_lost_warned = |
295 | printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", | 297 | top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; |
296 | top.total_lost_warned); | 298 | color_fprintf(stdout, PERF_COLOR_RED, |
299 | "WARNING: LOST %d chunks, Check IO/CPU overload", | ||
300 | top.sym_evsel->hists.stats.nr_lost_warned); | ||
297 | ++printed; | 301 | ++printed; |
298 | } | 302 | } |
299 | 303 | ||
@@ -561,7 +565,6 @@ static void perf_top__sort_new_samples(void *arg) | |||
561 | hists__decay_entries_threaded(&t->sym_evsel->hists, | 565 | hists__decay_entries_threaded(&t->sym_evsel->hists, |
562 | top.hide_user_symbols, | 566 | top.hide_user_symbols, |
563 | top.hide_kernel_symbols); | 567 | top.hide_kernel_symbols); |
564 | hists__output_recalc_col_len(&t->sym_evsel->hists, winsize.ws_row - 3); | ||
565 | } | 568 | } |
566 | 569 | ||
567 | static void *display_thread_tui(void *arg __used) | 570 | static void *display_thread_tui(void *arg __used) |
@@ -671,6 +674,7 @@ static int symbol_filter(struct map *map __used, struct symbol *sym) | |||
671 | } | 674 | } |
672 | 675 | ||
673 | static void perf_event__process_sample(const union perf_event *event, | 676 | static void perf_event__process_sample(const union perf_event *event, |
677 | struct perf_evsel *evsel, | ||
674 | struct perf_sample *sample, | 678 | struct perf_sample *sample, |
675 | struct perf_session *session) | 679 | struct perf_session *session) |
676 | { | 680 | { |
@@ -770,12 +774,8 @@ static void perf_event__process_sample(const union perf_event *event, | |||
770 | } | 774 | } |
771 | 775 | ||
772 | if (al.sym == NULL || !al.sym->ignore) { | 776 | if (al.sym == NULL || !al.sym->ignore) { |
773 | struct perf_evsel *evsel; | ||
774 | struct hist_entry *he; | 777 | struct hist_entry *he; |
775 | 778 | ||
776 | evsel = perf_evlist__id2evsel(top.evlist, sample->id); | ||
777 | assert(evsel != NULL); | ||
778 | |||
779 | if ((sort__has_parent || symbol_conf.use_callchain) && | 779 | if ((sort__has_parent || symbol_conf.use_callchain) && |
780 | sample->callchain) { | 780 | sample->callchain) { |
781 | err = perf_session__resolve_callchain(session, al.thread, | 781 | err = perf_session__resolve_callchain(session, al.thread, |
@@ -807,6 +807,7 @@ static void perf_event__process_sample(const union perf_event *event, | |||
807 | static void perf_session__mmap_read_idx(struct perf_session *self, int idx) | 807 | static void perf_session__mmap_read_idx(struct perf_session *self, int idx) |
808 | { | 808 | { |
809 | struct perf_sample sample; | 809 | struct perf_sample sample; |
810 | struct perf_evsel *evsel; | ||
810 | union perf_event *event; | 811 | union perf_event *event; |
811 | int ret; | 812 | int ret; |
812 | 813 | ||
@@ -817,10 +818,16 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) | |||
817 | continue; | 818 | continue; |
818 | } | 819 | } |
819 | 820 | ||
821 | evsel = perf_evlist__id2evsel(self->evlist, sample.id); | ||
822 | assert(evsel != NULL); | ||
823 | |||
820 | if (event->header.type == PERF_RECORD_SAMPLE) | 824 | if (event->header.type == PERF_RECORD_SAMPLE) |
821 | perf_event__process_sample(event, &sample, self); | 825 | perf_event__process_sample(event, evsel, &sample, self); |
822 | else | 826 | else if (event->header.type < PERF_RECORD_MAX) { |
827 | hists__inc_nr_events(&evsel->hists, event->header.type); | ||
823 | perf_event__process(event, &sample, self); | 828 | perf_event__process(event, &sample, self); |
829 | } else | ||
830 | ++self->hists.stats.nr_unknown_events; | ||
824 | } | 831 | } |
825 | } | 832 | } |
826 | 833 | ||
@@ -834,10 +841,16 @@ static void perf_session__mmap_read(struct perf_session *self) | |||
834 | 841 | ||
835 | static void start_counters(struct perf_evlist *evlist) | 842 | static void start_counters(struct perf_evlist *evlist) |
836 | { | 843 | { |
837 | struct perf_evsel *counter; | 844 | struct perf_evsel *counter, *first; |
845 | |||
846 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
838 | 847 | ||
839 | list_for_each_entry(counter, &evlist->entries, node) { | 848 | list_for_each_entry(counter, &evlist->entries, node) { |
840 | struct perf_event_attr *attr = &counter->attr; | 849 | struct perf_event_attr *attr = &counter->attr; |
850 | struct xyarray *group_fd = NULL; | ||
851 | |||
852 | if (group && counter != first) | ||
853 | group_fd = first->fd; | ||
841 | 854 | ||
842 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 855 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
843 | 856 | ||
@@ -858,14 +871,23 @@ static void start_counters(struct perf_evlist *evlist) | |||
858 | attr->mmap = 1; | 871 | attr->mmap = 1; |
859 | attr->comm = 1; | 872 | attr->comm = 1; |
860 | attr->inherit = inherit; | 873 | attr->inherit = inherit; |
874 | retry_sample_id: | ||
875 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | ||
861 | try_again: | 876 | try_again: |
862 | if (perf_evsel__open(counter, top.evlist->cpus, | 877 | if (perf_evsel__open(counter, top.evlist->cpus, |
863 | top.evlist->threads, group) < 0) { | 878 | top.evlist->threads, group, |
879 | group_fd) < 0) { | ||
864 | int err = errno; | 880 | int err = errno; |
865 | 881 | ||
866 | if (err == EPERM || err == EACCES) { | 882 | if (err == EPERM || err == EACCES) { |
867 | ui__warning_paranoid(); | 883 | ui__error_paranoid(); |
868 | goto out_err; | 884 | goto out_err; |
885 | } else if (err == EINVAL && sample_id_all_avail) { | ||
886 | /* | ||
887 | * Old kernel, no attr->sample_id_type_all field | ||
888 | */ | ||
889 | sample_id_all_avail = false; | ||
890 | goto retry_sample_id; | ||
869 | } | 891 | } |
870 | /* | 892 | /* |
871 | * If it's cycles then fall back to hrtimer | 893 | * If it's cycles then fall back to hrtimer |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index bc8f4773d4d8..119e996035c8 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -310,9 +310,12 @@ fallback: | |||
310 | } | 310 | } |
311 | err = -ENOENT; | 311 | err = -ENOENT; |
312 | dso->annotate_warned = 1; | 312 | dso->annotate_warned = 1; |
313 | pr_err("Can't annotate %s: No vmlinux file%s was found in the " | 313 | pr_err("Can't annotate %s:\n\n" |
314 | "path.\nPlease use 'perf buildid-cache -av vmlinux' or " | 314 | "No vmlinux file%s\nwas found in the path.\n\n" |
315 | "--vmlinux vmlinux.\n", | 315 | "Please use:\n\n" |
316 | " perf buildid-cache -av vmlinux\n\n" | ||
317 | "or:\n\n" | ||
318 | " --vmlinux vmlinux", | ||
316 | sym->name, build_id_msg ?: ""); | 319 | sym->name, build_id_msg ?: ""); |
317 | goto out_free_filename; | 320 | goto out_free_filename; |
318 | } | 321 | } |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 155749d74350..26817daa2961 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -47,19 +47,20 @@ int dump_printf(const char *fmt, ...) | |||
47 | } | 47 | } |
48 | 48 | ||
49 | #ifdef NO_NEWT_SUPPORT | 49 | #ifdef NO_NEWT_SUPPORT |
50 | void ui__warning(const char *format, ...) | 50 | int ui__warning(const char *format, ...) |
51 | { | 51 | { |
52 | va_list args; | 52 | va_list args; |
53 | 53 | ||
54 | va_start(args, format); | 54 | va_start(args, format); |
55 | vfprintf(stderr, format, args); | 55 | vfprintf(stderr, format, args); |
56 | va_end(args); | 56 | va_end(args); |
57 | return 0; | ||
57 | } | 58 | } |
58 | #endif | 59 | #endif |
59 | 60 | ||
60 | void ui__warning_paranoid(void) | 61 | int ui__error_paranoid(void) |
61 | { | 62 | { |
62 | ui__warning("Permission error - are you root?\n" | 63 | return ui__error("Permission error - are you root?\n" |
63 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" | 64 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" |
64 | " -1 - Not paranoid at all\n" | 65 | " -1 - Not paranoid at all\n" |
65 | " 0 - Disallow raw tracepoint access for unpriv\n" | 66 | " 0 - Disallow raw tracepoint access for unpriv\n" |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index fd53db47e3de..f2ce88d04f54 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -19,23 +19,18 @@ static inline int ui_helpline__show_help(const char *format __used, va_list ap _ | |||
19 | return 0; | 19 | return 0; |
20 | } | 20 | } |
21 | 21 | ||
22 | static inline struct ui_progress *ui_progress__new(const char *title __used, | 22 | static inline void ui_progress__update(u64 curr __used, u64 total __used, |
23 | u64 total __used) | 23 | const char *title __used) {} |
24 | { | ||
25 | return (struct ui_progress *)1; | ||
26 | } | ||
27 | |||
28 | static inline void ui_progress__update(struct ui_progress *self __used, | ||
29 | u64 curr __used) {} | ||
30 | 24 | ||
31 | static inline void ui_progress__delete(struct ui_progress *self __used) {} | 25 | #define ui__error(format, arg...) ui__warning(format, ##arg) |
32 | #else | 26 | #else |
33 | extern char ui_helpline__last_msg[]; | 27 | extern char ui_helpline__last_msg[]; |
34 | int ui_helpline__show_help(const char *format, va_list ap); | 28 | int ui_helpline__show_help(const char *format, va_list ap); |
35 | #include "ui/progress.h" | 29 | #include "ui/progress.h" |
30 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | ||
36 | #endif | 31 | #endif |
37 | 32 | ||
38 | void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 33 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
39 | void ui__warning_paranoid(void); | 34 | int ui__error_paranoid(void); |
40 | 35 | ||
41 | #endif /* __PERF_DEBUG_H */ | 36 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 2f6bc89027da..fbb4b4ab9cc6 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -539,3 +539,33 @@ void perf_evlist__set_selected(struct perf_evlist *evlist, | |||
539 | { | 539 | { |
540 | evlist->selected = evsel; | 540 | evlist->selected = evsel; |
541 | } | 541 | } |
542 | |||
543 | int perf_evlist__open(struct perf_evlist *evlist, bool group) | ||
544 | { | ||
545 | struct perf_evsel *evsel, *first; | ||
546 | int err, ncpus, nthreads; | ||
547 | |||
548 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
549 | |||
550 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
551 | struct xyarray *group_fd = NULL; | ||
552 | |||
553 | if (group && evsel != first) | ||
554 | group_fd = first->fd; | ||
555 | |||
556 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads, | ||
557 | group, group_fd); | ||
558 | if (err < 0) | ||
559 | goto out_err; | ||
560 | } | ||
561 | |||
562 | return 0; | ||
563 | out_err: | ||
564 | ncpus = evlist->cpus ? evlist->cpus->nr : 1; | ||
565 | nthreads = evlist->threads ? evlist->threads->nr : 1; | ||
566 | |||
567 | list_for_each_entry_reverse(evsel, &evlist->entries, node) | ||
568 | perf_evsel__close(evsel, ncpus, nthreads); | ||
569 | |||
570 | return err; | ||
571 | } | ||
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 6be71fc57794..1779ffef7828 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -50,6 +50,8 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); | |||
50 | 50 | ||
51 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); | 51 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); |
52 | 52 | ||
53 | int perf_evlist__open(struct perf_evlist *evlist, bool group); | ||
54 | |||
53 | int perf_evlist__alloc_mmap(struct perf_evlist *evlist); | 55 | int perf_evlist__alloc_mmap(struct perf_evlist *evlist); |
54 | int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); | 56 | int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); |
55 | void perf_evlist__munmap(struct perf_evlist *evlist); | 57 | void perf_evlist__munmap(struct perf_evlist *evlist); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index b46f6e4bff3c..e42626422587 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include "thread_map.h" | 16 | #include "thread_map.h" |
17 | 17 | ||
18 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 18 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
19 | #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) | ||
19 | 20 | ||
20 | int __perf_evsel__sample_size(u64 sample_type) | 21 | int __perf_evsel__sample_size(u64 sample_type) |
21 | { | 22 | { |
@@ -204,15 +205,16 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
204 | } | 205 | } |
205 | 206 | ||
206 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 207 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
207 | struct thread_map *threads, bool group) | 208 | struct thread_map *threads, bool group, |
209 | struct xyarray *group_fds) | ||
208 | { | 210 | { |
209 | int cpu, thread; | 211 | int cpu, thread; |
210 | unsigned long flags = 0; | 212 | unsigned long flags = 0; |
211 | int pid = -1; | 213 | int pid = -1, err; |
212 | 214 | ||
213 | if (evsel->fd == NULL && | 215 | if (evsel->fd == NULL && |
214 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) | 216 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) |
215 | return -1; | 217 | return -ENOMEM; |
216 | 218 | ||
217 | if (evsel->cgrp) { | 219 | if (evsel->cgrp) { |
218 | flags = PERF_FLAG_PID_CGROUP; | 220 | flags = PERF_FLAG_PID_CGROUP; |
@@ -220,7 +222,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
220 | } | 222 | } |
221 | 223 | ||
222 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 224 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
223 | int group_fd = -1; | 225 | int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1; |
224 | 226 | ||
225 | for (thread = 0; thread < threads->nr; thread++) { | 227 | for (thread = 0; thread < threads->nr; thread++) { |
226 | 228 | ||
@@ -231,8 +233,10 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
231 | pid, | 233 | pid, |
232 | cpus->map[cpu], | 234 | cpus->map[cpu], |
233 | group_fd, flags); | 235 | group_fd, flags); |
234 | if (FD(evsel, cpu, thread) < 0) | 236 | if (FD(evsel, cpu, thread) < 0) { |
237 | err = -errno; | ||
235 | goto out_close; | 238 | goto out_close; |
239 | } | ||
236 | 240 | ||
237 | if (group && group_fd == -1) | 241 | if (group && group_fd == -1) |
238 | group_fd = FD(evsel, cpu, thread); | 242 | group_fd = FD(evsel, cpu, thread); |
@@ -249,7 +253,17 @@ out_close: | |||
249 | } | 253 | } |
250 | thread = threads->nr; | 254 | thread = threads->nr; |
251 | } while (--cpu >= 0); | 255 | } while (--cpu >= 0); |
252 | return -1; | 256 | return err; |
257 | } | ||
258 | |||
259 | void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads) | ||
260 | { | ||
261 | if (evsel->fd == NULL) | ||
262 | return; | ||
263 | |||
264 | perf_evsel__close_fd(evsel, ncpus, nthreads); | ||
265 | perf_evsel__free_fd(evsel); | ||
266 | evsel->fd = NULL; | ||
253 | } | 267 | } |
254 | 268 | ||
255 | static struct { | 269 | static struct { |
@@ -269,7 +283,8 @@ static struct { | |||
269 | }; | 283 | }; |
270 | 284 | ||
271 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 285 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
272 | struct thread_map *threads, bool group) | 286 | struct thread_map *threads, bool group, |
287 | struct xyarray *group_fd) | ||
273 | { | 288 | { |
274 | if (cpus == NULL) { | 289 | if (cpus == NULL) { |
275 | /* Work around old compiler warnings about strict aliasing */ | 290 | /* Work around old compiler warnings about strict aliasing */ |
@@ -279,19 +294,23 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
279 | if (threads == NULL) | 294 | if (threads == NULL) |
280 | threads = &empty_thread_map.map; | 295 | threads = &empty_thread_map.map; |
281 | 296 | ||
282 | return __perf_evsel__open(evsel, cpus, threads, group); | 297 | return __perf_evsel__open(evsel, cpus, threads, group, group_fd); |
283 | } | 298 | } |
284 | 299 | ||
285 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 300 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
286 | struct cpu_map *cpus, bool group) | 301 | struct cpu_map *cpus, bool group, |
302 | struct xyarray *group_fd) | ||
287 | { | 303 | { |
288 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group); | 304 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, |
305 | group_fd); | ||
289 | } | 306 | } |
290 | 307 | ||
291 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | 308 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, |
292 | struct thread_map *threads, bool group) | 309 | struct thread_map *threads, bool group, |
310 | struct xyarray *group_fd) | ||
293 | { | 311 | { |
294 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group); | 312 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, |
313 | group_fd); | ||
295 | } | 314 | } |
296 | 315 | ||
297 | static int perf_event__parse_id_sample(const union perf_event *event, u64 type, | 316 | static int perf_event__parse_id_sample(const union perf_event *event, u64 type, |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index e9a31554e265..b1d15e6f7ae3 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -82,11 +82,15 @@ void perf_evsel__free_id(struct perf_evsel *evsel); | |||
82 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 82 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
83 | 83 | ||
84 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 84 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
85 | struct cpu_map *cpus, bool group); | 85 | struct cpu_map *cpus, bool group, |
86 | struct xyarray *group_fds); | ||
86 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | 87 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, |
87 | struct thread_map *threads, bool group); | 88 | struct thread_map *threads, bool group, |
89 | struct xyarray *group_fds); | ||
88 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 90 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
89 | struct thread_map *threads, bool group); | 91 | struct thread_map *threads, bool group, |
92 | struct xyarray *group_fds); | ||
93 | void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads); | ||
90 | 94 | ||
91 | #define perf_evsel__match(evsel, t, c) \ | 95 | #define perf_evsel__match(evsel, t, c) \ |
92 | (evsel->attr.type == PERF_TYPE_##t && \ | 96 | (evsel->attr.type == PERF_TYPE_##t && \ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 76c0b2c49eb8..bcd05d05b4f0 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #define _FILE_OFFSET_BITS 64 | 1 | #define _FILE_OFFSET_BITS 64 |
2 | 2 | ||
3 | #include "util.h" | ||
3 | #include <sys/types.h> | 4 | #include <sys/types.h> |
4 | #include <byteswap.h> | 5 | #include <byteswap.h> |
5 | #include <unistd.h> | 6 | #include <unistd.h> |
@@ -11,7 +12,6 @@ | |||
11 | 12 | ||
12 | #include "evlist.h" | 13 | #include "evlist.h" |
13 | #include "evsel.h" | 14 | #include "evsel.h" |
14 | #include "util.h" | ||
15 | #include "header.h" | 15 | #include "header.h" |
16 | #include "../perf.h" | 16 | #include "../perf.h" |
17 | #include "trace-event.h" | 17 | #include "trace-event.h" |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f6a993963a1e..a36a3fa81ffb 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -365,7 +365,6 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded) | |||
365 | 365 | ||
366 | root = hists__get_rotate_entries_in(hists); | 366 | root = hists__get_rotate_entries_in(hists); |
367 | next = rb_first(root); | 367 | next = rb_first(root); |
368 | hists->stats.total_period = 0; | ||
369 | 368 | ||
370 | while (next) { | 369 | while (next) { |
371 | n = rb_entry(next, struct hist_entry, rb_node_in); | 370 | n = rb_entry(next, struct hist_entry, rb_node_in); |
@@ -379,7 +378,6 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded) | |||
379 | * been set by, say, the hist_browser. | 378 | * been set by, say, the hist_browser. |
380 | */ | 379 | */ |
381 | hists__apply_filters(hists, n); | 380 | hists__apply_filters(hists, n); |
382 | hists__inc_nr_entries(hists, n); | ||
383 | } | 381 | } |
384 | } | 382 | } |
385 | } | 383 | } |
@@ -442,6 +440,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded) | |||
442 | hists->entries = RB_ROOT; | 440 | hists->entries = RB_ROOT; |
443 | 441 | ||
444 | hists->nr_entries = 0; | 442 | hists->nr_entries = 0; |
443 | hists->stats.total_period = 0; | ||
445 | hists__reset_col_len(hists); | 444 | hists__reset_col_len(hists); |
446 | 445 | ||
447 | while (next) { | 446 | while (next) { |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ff93ddc91c5c..c86c1d27bd1e 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -28,6 +28,7 @@ struct events_stats { | |||
28 | u64 total_lost; | 28 | u64 total_lost; |
29 | u64 total_invalid_chains; | 29 | u64 total_invalid_chains; |
30 | u32 nr_events[PERF_RECORD_HEADER_MAX]; | 30 | u32 nr_events[PERF_RECORD_HEADER_MAX]; |
31 | u32 nr_lost_warned; | ||
31 | u32 nr_unknown_events; | 32 | u32 nr_unknown_events; |
32 | u32 nr_invalid_chains; | 33 | u32 nr_invalid_chains; |
33 | u32 nr_unknown_id; | 34 | u32 nr_unknown_id; |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 7624324efad4..9dd47a4f2596 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -623,7 +623,11 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, | |||
623 | cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; | 623 | cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; |
624 | 624 | ||
625 | evsel->attr.inherit = inherit; | 625 | evsel->attr.inherit = inherit; |
626 | if (perf_evsel__open(evsel, cpus, threads, group) < 0) { | 626 | /* |
627 | * This will group just the fds for this single evsel, to group | ||
628 | * multiple events, use evlist.open(). | ||
629 | */ | ||
630 | if (perf_evsel__open(evsel, cpus, threads, group, NULL) < 0) { | ||
627 | PyErr_SetFromErrno(PyExc_OSError); | 631 | PyErr_SetFromErrno(PyExc_OSError); |
628 | return NULL; | 632 | return NULL; |
629 | } | 633 | } |
@@ -814,6 +818,25 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, | |||
814 | return Py_None; | 818 | return Py_None; |
815 | } | 819 | } |
816 | 820 | ||
821 | static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, | ||
822 | PyObject *args, PyObject *kwargs) | ||
823 | { | ||
824 | struct perf_evlist *evlist = &pevlist->evlist; | ||
825 | int group = 0; | ||
826 | static char *kwlist[] = { "group", NULL }; | ||
827 | |||
828 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, &group)) | ||
829 | return NULL; | ||
830 | |||
831 | if (perf_evlist__open(evlist, group) < 0) { | ||
832 | PyErr_SetFromErrno(PyExc_OSError); | ||
833 | return NULL; | ||
834 | } | ||
835 | |||
836 | Py_INCREF(Py_None); | ||
837 | return Py_None; | ||
838 | } | ||
839 | |||
817 | static PyMethodDef pyrf_evlist__methods[] = { | 840 | static PyMethodDef pyrf_evlist__methods[] = { |
818 | { | 841 | { |
819 | .ml_name = "mmap", | 842 | .ml_name = "mmap", |
@@ -822,6 +845,12 @@ static PyMethodDef pyrf_evlist__methods[] = { | |||
822 | .ml_doc = PyDoc_STR("mmap the file descriptor table.") | 845 | .ml_doc = PyDoc_STR("mmap the file descriptor table.") |
823 | }, | 846 | }, |
824 | { | 847 | { |
848 | .ml_name = "open", | ||
849 | .ml_meth = (PyCFunction)pyrf_evlist__open, | ||
850 | .ml_flags = METH_VARARGS | METH_KEYWORDS, | ||
851 | .ml_doc = PyDoc_STR("open the file descriptors.") | ||
852 | }, | ||
853 | { | ||
825 | .ml_name = "poll", | 854 | .ml_name = "poll", |
826 | .ml_meth = (PyCFunction)pyrf_evlist__poll, | 855 | .ml_meth = (PyCFunction)pyrf_evlist__poll, |
827 | .ml_flags = METH_VARARGS | METH_KEYWORDS, | 856 | .ml_flags = METH_VARARGS | METH_KEYWORDS, |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 20e011c99a94..85c1e6b76f0a 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -502,6 +502,7 @@ static void flush_sample_queue(struct perf_session *s, | |||
502 | struct perf_sample sample; | 502 | struct perf_sample sample; |
503 | u64 limit = os->next_flush; | 503 | u64 limit = os->next_flush; |
504 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; | 504 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; |
505 | unsigned idx = 0, progress_next = os->nr_samples / 16; | ||
505 | int ret; | 506 | int ret; |
506 | 507 | ||
507 | if (!ops->ordered_samples || !limit) | 508 | if (!ops->ordered_samples || !limit) |
@@ -521,6 +522,11 @@ static void flush_sample_queue(struct perf_session *s, | |||
521 | os->last_flush = iter->timestamp; | 522 | os->last_flush = iter->timestamp; |
522 | list_del(&iter->list); | 523 | list_del(&iter->list); |
523 | list_add(&iter->list, &os->sample_cache); | 524 | list_add(&iter->list, &os->sample_cache); |
525 | if (++idx >= progress_next) { | ||
526 | progress_next += os->nr_samples / 16; | ||
527 | ui_progress__update(idx, os->nr_samples, | ||
528 | "Processing time ordered events..."); | ||
529 | } | ||
524 | } | 530 | } |
525 | 531 | ||
526 | if (list_empty(head)) { | 532 | if (list_empty(head)) { |
@@ -529,6 +535,8 @@ static void flush_sample_queue(struct perf_session *s, | |||
529 | os->last_sample = | 535 | os->last_sample = |
530 | list_entry(head->prev, struct sample_queue, list); | 536 | list_entry(head->prev, struct sample_queue, list); |
531 | } | 537 | } |
538 | |||
539 | os->nr_samples = 0; | ||
532 | } | 540 | } |
533 | 541 | ||
534 | /* | 542 | /* |
@@ -588,6 +596,7 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s) | |||
588 | u64 timestamp = new->timestamp; | 596 | u64 timestamp = new->timestamp; |
589 | struct list_head *p; | 597 | struct list_head *p; |
590 | 598 | ||
599 | ++os->nr_samples; | ||
591 | os->last_sample = new; | 600 | os->last_sample = new; |
592 | 601 | ||
593 | if (!sample) { | 602 | if (!sample) { |
@@ -738,10 +747,27 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
738 | 747 | ||
739 | dump_event(session, event, file_offset, sample); | 748 | dump_event(session, event, file_offset, sample); |
740 | 749 | ||
750 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); | ||
751 | if (evsel != NULL && event->header.type != PERF_RECORD_SAMPLE) { | ||
752 | /* | ||
753 | * XXX We're leaving PERF_RECORD_SAMPLE unnacounted here | ||
754 | * because the tools right now may apply filters, discarding | ||
755 | * some of the samples. For consistency, in the future we | ||
756 | * should have something like nr_filtered_samples and remove | ||
757 | * the sample->period from total_sample_period, etc, KISS for | ||
758 | * now tho. | ||
759 | * | ||
760 | * Also testing against NULL allows us to handle files without | ||
761 | * attr.sample_id_all and/or without PERF_SAMPLE_ID. In the | ||
762 | * future probably it'll be a good idea to restrict event | ||
763 | * processing via perf_session to files with both set. | ||
764 | */ | ||
765 | hists__inc_nr_events(&evsel->hists, event->header.type); | ||
766 | } | ||
767 | |||
741 | switch (event->header.type) { | 768 | switch (event->header.type) { |
742 | case PERF_RECORD_SAMPLE: | 769 | case PERF_RECORD_SAMPLE: |
743 | dump_sample(session, event, sample); | 770 | dump_sample(session, event, sample); |
744 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); | ||
745 | if (evsel == NULL) { | 771 | if (evsel == NULL) { |
746 | ++session->hists.stats.nr_unknown_id; | 772 | ++session->hists.stats.nr_unknown_id; |
747 | return -1; | 773 | return -1; |
@@ -874,11 +900,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
874 | const struct perf_event_ops *ops) | 900 | const struct perf_event_ops *ops) |
875 | { | 901 | { |
876 | if (ops->lost == perf_event__process_lost && | 902 | if (ops->lost == perf_event__process_lost && |
877 | session->hists.stats.total_lost != 0) { | 903 | session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { |
878 | ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64 | 904 | ui__warning("Processed %d events and lost %d chunks!\n\n" |
879 | "!\n\nCheck IO/CPU overload!\n\n", | 905 | "Check IO/CPU overload!\n\n", |
880 | session->hists.stats.total_period, | 906 | session->hists.stats.nr_events[0], |
881 | session->hists.stats.total_lost); | 907 | session->hists.stats.nr_events[PERF_RECORD_LOST]); |
882 | } | 908 | } |
883 | 909 | ||
884 | if (session->hists.stats.nr_unknown_events != 0) { | 910 | if (session->hists.stats.nr_unknown_events != 0) { |
@@ -1012,7 +1038,6 @@ int __perf_session__process_events(struct perf_session *session, | |||
1012 | { | 1038 | { |
1013 | u64 head, page_offset, file_offset, file_pos, progress_next; | 1039 | u64 head, page_offset, file_offset, file_pos, progress_next; |
1014 | int err, mmap_prot, mmap_flags, map_idx = 0; | 1040 | int err, mmap_prot, mmap_flags, map_idx = 0; |
1015 | struct ui_progress *progress; | ||
1016 | size_t page_size, mmap_size; | 1041 | size_t page_size, mmap_size; |
1017 | char *buf, *mmaps[8]; | 1042 | char *buf, *mmaps[8]; |
1018 | union perf_event *event; | 1043 | union perf_event *event; |
@@ -1030,9 +1055,6 @@ int __perf_session__process_events(struct perf_session *session, | |||
1030 | file_size = data_offset + data_size; | 1055 | file_size = data_offset + data_size; |
1031 | 1056 | ||
1032 | progress_next = file_size / 16; | 1057 | progress_next = file_size / 16; |
1033 | progress = ui_progress__new("Processing events...", file_size); | ||
1034 | if (progress == NULL) | ||
1035 | return -1; | ||
1036 | 1058 | ||
1037 | mmap_size = session->mmap_window; | 1059 | mmap_size = session->mmap_window; |
1038 | if (mmap_size > file_size) | 1060 | if (mmap_size > file_size) |
@@ -1095,7 +1117,8 @@ more: | |||
1095 | 1117 | ||
1096 | if (file_pos >= progress_next) { | 1118 | if (file_pos >= progress_next) { |
1097 | progress_next += file_size / 16; | 1119 | progress_next += file_size / 16; |
1098 | ui_progress__update(progress, file_pos); | 1120 | ui_progress__update(file_pos, file_size, |
1121 | "Processing events..."); | ||
1099 | } | 1122 | } |
1100 | 1123 | ||
1101 | if (file_pos < file_size) | 1124 | if (file_pos < file_size) |
@@ -1106,7 +1129,6 @@ more: | |||
1106 | session->ordered_samples.next_flush = ULLONG_MAX; | 1129 | session->ordered_samples.next_flush = ULLONG_MAX; |
1107 | flush_sample_queue(session, ops); | 1130 | flush_sample_queue(session, ops); |
1108 | out_err: | 1131 | out_err: |
1109 | ui_progress__delete(progress); | ||
1110 | perf_session__warn_about_errors(session, ops); | 1132 | perf_session__warn_about_errors(session, ops); |
1111 | perf_session_free_sample_buffers(session); | 1133 | perf_session_free_sample_buffers(session); |
1112 | return err; | 1134 | return err; |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 514b06d41f05..6e393c98eb34 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -23,6 +23,7 @@ struct ordered_samples { | |||
23 | struct sample_queue *sample_buffer; | 23 | struct sample_queue *sample_buffer; |
24 | struct sample_queue *last_sample; | 24 | struct sample_queue *last_sample; |
25 | int sample_buffer_idx; | 25 | int sample_buffer_idx; |
26 | unsigned int nr_samples; | ||
26 | }; | 27 | }; |
27 | 28 | ||
28 | struct perf_session { | 29 | struct perf_session { |
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 01d1057f3074..399650967958 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
@@ -19,7 +19,6 @@ struct perf_top { | |||
19 | u64 kernel_samples, us_samples; | 19 | u64 kernel_samples, us_samples; |
20 | u64 exact_samples; | 20 | u64 exact_samples; |
21 | u64 guest_us_samples, guest_kernel_samples; | 21 | u64 guest_us_samples, guest_kernel_samples; |
22 | u64 total_lost_warned; | ||
23 | int print_entries, count_filter, delay_secs; | 22 | int print_entries, count_filter, delay_secs; |
24 | int freq; | 23 | int freq; |
25 | pid_t target_pid, target_tid; | 24 | pid_t target_pid, target_tid; |
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 2d530cf74f43..d2655f08bcc0 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c | |||
@@ -80,7 +80,7 @@ static void die(const char *fmt, ...) | |||
80 | int ret = errno; | 80 | int ret = errno; |
81 | 81 | ||
82 | if (errno) | 82 | if (errno) |
83 | perror("trace-cmd"); | 83 | perror("perf"); |
84 | else | 84 | else |
85 | ret = -1; | 85 | ret = -1; |
86 | 86 | ||
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 5359f371d30a..556829124b02 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "libslang.h" | 4 | #include "libslang.h" |
5 | #include <newt.h> | 5 | #include <newt.h> |
6 | #include "ui.h" | 6 | #include "ui.h" |
7 | #include "util.h" | ||
7 | #include <linux/compiler.h> | 8 | #include <linux/compiler.h> |
8 | #include <linux/list.h> | 9 | #include <linux/list.h> |
9 | #include <linux/rbtree.h> | 10 | #include <linux/rbtree.h> |
@@ -168,6 +169,59 @@ void ui_browser__refresh_dimensions(struct ui_browser *self) | |||
168 | self->x = 0; | 169 | self->x = 0; |
169 | } | 170 | } |
170 | 171 | ||
172 | void ui_browser__handle_resize(struct ui_browser *browser) | ||
173 | { | ||
174 | ui__refresh_dimensions(false); | ||
175 | ui_browser__show(browser, browser->title, ui_helpline__current); | ||
176 | ui_browser__refresh(browser); | ||
177 | } | ||
178 | |||
179 | int ui_browser__warning(struct ui_browser *browser, int timeout, | ||
180 | const char *format, ...) | ||
181 | { | ||
182 | va_list args; | ||
183 | char *text; | ||
184 | int key = 0, err; | ||
185 | |||
186 | va_start(args, format); | ||
187 | err = vasprintf(&text, format, args); | ||
188 | va_end(args); | ||
189 | |||
190 | if (err < 0) { | ||
191 | va_start(args, format); | ||
192 | ui_helpline__vpush(format, args); | ||
193 | va_end(args); | ||
194 | } else { | ||
195 | while ((key == ui__question_window("Warning!", text, | ||
196 | "Press any key...", | ||
197 | timeout)) == K_RESIZE) | ||
198 | ui_browser__handle_resize(browser); | ||
199 | free(text); | ||
200 | } | ||
201 | |||
202 | return key; | ||
203 | } | ||
204 | |||
205 | int ui_browser__help_window(struct ui_browser *browser, const char *text) | ||
206 | { | ||
207 | int key; | ||
208 | |||
209 | while ((key = ui__help_window(text)) == K_RESIZE) | ||
210 | ui_browser__handle_resize(browser); | ||
211 | |||
212 | return key; | ||
213 | } | ||
214 | |||
215 | bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text) | ||
216 | { | ||
217 | int key; | ||
218 | |||
219 | while ((key = ui__dialog_yesno(text)) == K_RESIZE) | ||
220 | ui_browser__handle_resize(browser); | ||
221 | |||
222 | return key == K_ENTER || toupper(key) == 'Y'; | ||
223 | } | ||
224 | |||
171 | void ui_browser__reset_index(struct ui_browser *self) | 225 | void ui_browser__reset_index(struct ui_browser *self) |
172 | { | 226 | { |
173 | self->index = self->top_idx = 0; | 227 | self->index = self->top_idx = 0; |
@@ -230,13 +284,15 @@ static void ui_browser__scrollbar_set(struct ui_browser *browser) | |||
230 | (browser->nr_entries - 1)); | 284 | (browser->nr_entries - 1)); |
231 | } | 285 | } |
232 | 286 | ||
287 | SLsmg_set_char_set(1); | ||
288 | |||
233 | while (h < height) { | 289 | while (h < height) { |
234 | ui_browser__gotorc(browser, row++, col); | 290 | ui_browser__gotorc(browser, row++, col); |
235 | SLsmg_set_char_set(1); | 291 | SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR); |
236 | SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_BOARD_CHAR); | ||
237 | SLsmg_set_char_set(0); | ||
238 | ++h; | 292 | ++h; |
239 | } | 293 | } |
294 | |||
295 | SLsmg_set_char_set(0); | ||
240 | } | 296 | } |
241 | 297 | ||
242 | static int __ui_browser__refresh(struct ui_browser *browser) | 298 | static int __ui_browser__refresh(struct ui_browser *browser) |
@@ -291,53 +347,10 @@ void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries) | |||
291 | browser->seek(browser, browser->top_idx, SEEK_SET); | 347 | browser->seek(browser, browser->top_idx, SEEK_SET); |
292 | } | 348 | } |
293 | 349 | ||
294 | static int ui__getch(int delay_secs) | ||
295 | { | ||
296 | struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL; | ||
297 | fd_set read_set; | ||
298 | int err, key; | ||
299 | |||
300 | FD_ZERO(&read_set); | ||
301 | FD_SET(0, &read_set); | ||
302 | |||
303 | if (delay_secs) { | ||
304 | timeout.tv_sec = delay_secs; | ||
305 | timeout.tv_usec = 0; | ||
306 | } | ||
307 | |||
308 | err = select(1, &read_set, NULL, NULL, ptimeout); | ||
309 | |||
310 | if (err == 0) | ||
311 | return K_TIMER; | ||
312 | |||
313 | if (err == -1) { | ||
314 | if (errno == EINTR) | ||
315 | return K_RESIZE; | ||
316 | return K_ERROR; | ||
317 | } | ||
318 | |||
319 | key = SLang_getkey(); | ||
320 | if (key != K_ESC) | ||
321 | return key; | ||
322 | |||
323 | FD_ZERO(&read_set); | ||
324 | FD_SET(0, &read_set); | ||
325 | timeout.tv_sec = 0; | ||
326 | timeout.tv_usec = 20; | ||
327 | err = select(1, &read_set, NULL, NULL, &timeout); | ||
328 | if (err == 0) | ||
329 | return K_ESC; | ||
330 | |||
331 | SLang_ungetkey(key); | ||
332 | return SLkp_getkey(); | ||
333 | } | ||
334 | |||
335 | int ui_browser__run(struct ui_browser *self, int delay_secs) | 350 | int ui_browser__run(struct ui_browser *self, int delay_secs) |
336 | { | 351 | { |
337 | int err, key; | 352 | int err, key; |
338 | 353 | ||
339 | pthread__unblock_sigwinch(); | ||
340 | |||
341 | while (1) { | 354 | while (1) { |
342 | off_t offset; | 355 | off_t offset; |
343 | 356 | ||
@@ -351,10 +364,7 @@ int ui_browser__run(struct ui_browser *self, int delay_secs) | |||
351 | key = ui__getch(delay_secs); | 364 | key = ui__getch(delay_secs); |
352 | 365 | ||
353 | if (key == K_RESIZE) { | 366 | if (key == K_RESIZE) { |
354 | pthread_mutex_lock(&ui__lock); | 367 | ui__refresh_dimensions(false); |
355 | SLtt_get_screen_size(); | ||
356 | SLsmg_reinit_smg(); | ||
357 | pthread_mutex_unlock(&ui__lock); | ||
358 | ui_browser__refresh_dimensions(self); | 368 | ui_browser__refresh_dimensions(self); |
359 | __ui_browser__show_title(self, self->title); | 369 | __ui_browser__show_title(self, self->title); |
360 | ui_helpline__puts(self->helpline); | 370 | ui_helpline__puts(self->helpline); |
@@ -533,6 +543,47 @@ static int ui_browser__color_config(const char *var, const char *value, | |||
533 | return -1; | 543 | return -1; |
534 | } | 544 | } |
535 | 545 | ||
546 | void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence) | ||
547 | { | ||
548 | switch (whence) { | ||
549 | case SEEK_SET: | ||
550 | browser->top = browser->entries; | ||
551 | break; | ||
552 | case SEEK_CUR: | ||
553 | browser->top = browser->top + browser->top_idx + offset; | ||
554 | break; | ||
555 | case SEEK_END: | ||
556 | browser->top = browser->top + browser->nr_entries + offset; | ||
557 | break; | ||
558 | default: | ||
559 | return; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | unsigned int ui_browser__argv_refresh(struct ui_browser *browser) | ||
564 | { | ||
565 | unsigned int row = 0, idx = browser->top_idx; | ||
566 | char **pos; | ||
567 | |||
568 | if (browser->top == NULL) | ||
569 | browser->top = browser->entries; | ||
570 | |||
571 | pos = (char **)browser->top; | ||
572 | while (idx < browser->nr_entries) { | ||
573 | if (!browser->filter || !browser->filter(browser, *pos)) { | ||
574 | ui_browser__gotorc(browser, row, 0); | ||
575 | browser->write(browser, pos, row); | ||
576 | if (++row == browser->height) | ||
577 | break; | ||
578 | } | ||
579 | |||
580 | ++idx; | ||
581 | ++pos; | ||
582 | } | ||
583 | |||
584 | return row; | ||
585 | } | ||
586 | |||
536 | void ui_browser__init(void) | 587 | void ui_browser__init(void) |
537 | { | 588 | { |
538 | int i = 0; | 589 | int i = 0; |
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index a2c707d33c5e..84d761b730c1 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h | |||
@@ -43,6 +43,15 @@ void ui_browser__hide(struct ui_browser *self); | |||
43 | int ui_browser__refresh(struct ui_browser *self); | 43 | int ui_browser__refresh(struct ui_browser *self); |
44 | int ui_browser__run(struct ui_browser *browser, int delay_secs); | 44 | int ui_browser__run(struct ui_browser *browser, int delay_secs); |
45 | void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); | 45 | void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); |
46 | void ui_browser__handle_resize(struct ui_browser *browser); | ||
47 | |||
48 | int ui_browser__warning(struct ui_browser *browser, int timeout, | ||
49 | const char *format, ...); | ||
50 | int ui_browser__help_window(struct ui_browser *browser, const char *text); | ||
51 | bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); | ||
52 | |||
53 | void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); | ||
54 | unsigned int ui_browser__argv_refresh(struct ui_browser *browser); | ||
46 | 55 | ||
47 | void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); | 56 | void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); |
48 | unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); | 57 | unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); |
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 4e0cb7fea7d9..0575905d1205 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c | |||
@@ -1,6 +1,9 @@ | |||
1 | #include "../../util.h" | ||
1 | #include "../browser.h" | 2 | #include "../browser.h" |
2 | #include "../helpline.h" | 3 | #include "../helpline.h" |
3 | #include "../libslang.h" | 4 | #include "../libslang.h" |
5 | #include "../ui.h" | ||
6 | #include "../util.h" | ||
4 | #include "../../annotate.h" | 7 | #include "../../annotate.h" |
5 | #include "../../hist.h" | 8 | #include "../../hist.h" |
6 | #include "../../sort.h" | 9 | #include "../../sort.h" |
@@ -8,15 +11,6 @@ | |||
8 | #include <pthread.h> | 11 | #include <pthread.h> |
9 | #include <newt.h> | 12 | #include <newt.h> |
10 | 13 | ||
11 | static void ui__error_window(const char *fmt, ...) | ||
12 | { | ||
13 | va_list ap; | ||
14 | |||
15 | va_start(ap, fmt); | ||
16 | newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap); | ||
17 | va_end(ap); | ||
18 | } | ||
19 | |||
20 | struct annotate_browser { | 14 | struct annotate_browser { |
21 | struct ui_browser b; | 15 | struct ui_browser b; |
22 | struct rb_root entries; | 16 | struct rb_root entries; |
@@ -400,7 +394,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
400 | return -1; | 394 | return -1; |
401 | 395 | ||
402 | if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { | 396 | if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { |
403 | ui__error_window(ui_helpline__last_msg); | 397 | ui__error("%s", ui_helpline__last_msg); |
404 | return -1; | 398 | return -1; |
405 | } | 399 | } |
406 | 400 | ||
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 4663dcb2a19b..d0c94b459685 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "../browser.h" | 17 | #include "../browser.h" |
18 | #include "../helpline.h" | 18 | #include "../helpline.h" |
19 | #include "../util.h" | 19 | #include "../util.h" |
20 | #include "../ui.h" | ||
20 | #include "map.h" | 21 | #include "map.h" |
21 | 22 | ||
22 | struct hist_browser { | 23 | struct hist_browser { |
@@ -294,6 +295,15 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold) | |||
294 | ui_browser__reset_index(&self->b); | 295 | ui_browser__reset_index(&self->b); |
295 | } | 296 | } |
296 | 297 | ||
298 | static void ui_browser__warn_lost_events(struct ui_browser *browser) | ||
299 | { | ||
300 | ui_browser__warning(browser, 4, | ||
301 | "Events are being lost, check IO/CPU overload!\n\n" | ||
302 | "You may want to run 'perf' using a RT scheduler policy:\n\n" | ||
303 | " perf top -r 80\n\n" | ||
304 | "Or reduce the sampling frequency."); | ||
305 | } | ||
306 | |||
297 | static int hist_browser__run(struct hist_browser *self, const char *ev_name, | 307 | static int hist_browser__run(struct hist_browser *self, const char *ev_name, |
298 | void(*timer)(void *arg), void *arg, int delay_secs) | 308 | void(*timer)(void *arg), void *arg, int delay_secs) |
299 | { | 309 | { |
@@ -314,12 +324,18 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, | |||
314 | key = ui_browser__run(&self->b, delay_secs); | 324 | key = ui_browser__run(&self->b, delay_secs); |
315 | 325 | ||
316 | switch (key) { | 326 | switch (key) { |
317 | case -1: | 327 | case K_TIMER: |
318 | /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ | ||
319 | timer(arg); | 328 | timer(arg); |
320 | ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); | 329 | ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); |
321 | hists__browser_title(self->hists, title, sizeof(title), | 330 | |
322 | ev_name); | 331 | if (self->hists->stats.nr_lost_warned != |
332 | self->hists->stats.nr_events[PERF_RECORD_LOST]) { | ||
333 | self->hists->stats.nr_lost_warned = | ||
334 | self->hists->stats.nr_events[PERF_RECORD_LOST]; | ||
335 | ui_browser__warn_lost_events(&self->b); | ||
336 | } | ||
337 | |||
338 | hists__browser_title(self->hists, title, sizeof(title), ev_name); | ||
323 | ui_browser__show_title(&self->b, title); | 339 | ui_browser__show_title(&self->b, title); |
324 | continue; | 340 | continue; |
325 | case 'D': { /* Debug */ | 341 | case 'D': { /* Debug */ |
@@ -883,7 +899,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
883 | goto out_free_stack; | 899 | goto out_free_stack; |
884 | case 'a': | 900 | case 'a': |
885 | if (!browser->has_symbols) { | 901 | if (!browser->has_symbols) { |
886 | ui__warning( | 902 | ui_browser__warning(&browser->b, delay_secs * 2, |
887 | "Annotation is only available for symbolic views, " | 903 | "Annotation is only available for symbolic views, " |
888 | "include \"sym\" in --sort to use it."); | 904 | "include \"sym\" in --sort to use it."); |
889 | continue; | 905 | continue; |
@@ -901,7 +917,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
901 | case K_F1: | 917 | case K_F1: |
902 | case 'h': | 918 | case 'h': |
903 | case '?': | 919 | case '?': |
904 | ui__help_window("h/?/F1 Show this window\n" | 920 | ui_browser__help_window(&browser->b, |
921 | "h/?/F1 Show this window\n" | ||
905 | "UP/DOWN/PGUP\n" | 922 | "UP/DOWN/PGUP\n" |
906 | "PGDN/SPACE Navigate\n" | 923 | "PGDN/SPACE Navigate\n" |
907 | "q/ESC/CTRL+C Exit browser\n\n" | 924 | "q/ESC/CTRL+C Exit browser\n\n" |
@@ -914,7 +931,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
914 | "C Collapse all callchains\n" | 931 | "C Collapse all callchains\n" |
915 | "E Expand all callchains\n" | 932 | "E Expand all callchains\n" |
916 | "d Zoom into current DSO\n" | 933 | "d Zoom into current DSO\n" |
917 | "t Zoom into current Thread\n"); | 934 | "t Zoom into current Thread"); |
918 | continue; | 935 | continue; |
919 | case K_ENTER: | 936 | case K_ENTER: |
920 | case K_RIGHT: | 937 | case K_RIGHT: |
@@ -940,7 +957,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
940 | } | 957 | } |
941 | case K_ESC: | 958 | case K_ESC: |
942 | if (!left_exits && | 959 | if (!left_exits && |
943 | !ui__dialog_yesno("Do you really want to exit?")) | 960 | !ui_browser__dialog_yesno(&browser->b, |
961 | "Do you really want to exit?")) | ||
944 | continue; | 962 | continue; |
945 | /* Fall thru */ | 963 | /* Fall thru */ |
946 | case 'q': | 964 | case 'q': |
@@ -993,6 +1011,7 @@ add_exit_option: | |||
993 | 1011 | ||
994 | if (choice == annotate) { | 1012 | if (choice == annotate) { |
995 | struct hist_entry *he; | 1013 | struct hist_entry *he; |
1014 | int err; | ||
996 | do_annotate: | 1015 | do_annotate: |
997 | he = hist_browser__selected_entry(browser); | 1016 | he = hist_browser__selected_entry(browser); |
998 | if (he == NULL) | 1017 | if (he == NULL) |
@@ -1001,10 +1020,12 @@ do_annotate: | |||
1001 | * Don't let this be freed, say, by hists__decay_entry. | 1020 | * Don't let this be freed, say, by hists__decay_entry. |
1002 | */ | 1021 | */ |
1003 | he->used = true; | 1022 | he->used = true; |
1004 | hist_entry__tui_annotate(he, evsel->idx, nr_events, | 1023 | err = hist_entry__tui_annotate(he, evsel->idx, nr_events, |
1005 | timer, arg, delay_secs); | 1024 | timer, arg, delay_secs); |
1006 | he->used = false; | 1025 | he->used = false; |
1007 | ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); | 1026 | ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); |
1027 | if (err) | ||
1028 | ui_browser__handle_resize(&browser->b); | ||
1008 | } else if (choice == browse_map) | 1029 | } else if (choice == browse_map) |
1009 | map__browse(browser->selection->map); | 1030 | map__browse(browser->selection->map); |
1010 | else if (choice == zoom_dso) { | 1031 | else if (choice == zoom_dso) { |
@@ -1056,6 +1077,7 @@ out: | |||
1056 | struct perf_evsel_menu { | 1077 | struct perf_evsel_menu { |
1057 | struct ui_browser b; | 1078 | struct ui_browser b; |
1058 | struct perf_evsel *selection; | 1079 | struct perf_evsel *selection; |
1080 | bool lost_events, lost_events_warned; | ||
1059 | }; | 1081 | }; |
1060 | 1082 | ||
1061 | static void perf_evsel_menu__write(struct ui_browser *browser, | 1083 | static void perf_evsel_menu__write(struct ui_browser *browser, |
@@ -1068,14 +1090,29 @@ static void perf_evsel_menu__write(struct ui_browser *browser, | |||
1068 | unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; | 1090 | unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; |
1069 | const char *ev_name = event_name(evsel); | 1091 | const char *ev_name = event_name(evsel); |
1070 | char bf[256], unit; | 1092 | char bf[256], unit; |
1093 | const char *warn = " "; | ||
1094 | size_t printed; | ||
1071 | 1095 | ||
1072 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | 1096 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : |
1073 | HE_COLORSET_NORMAL); | 1097 | HE_COLORSET_NORMAL); |
1074 | 1098 | ||
1075 | nr_events = convert_unit(nr_events, &unit); | 1099 | nr_events = convert_unit(nr_events, &unit); |
1076 | snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, | 1100 | printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, |
1077 | unit, unit == ' ' ? "" : " ", ev_name); | 1101 | unit, unit == ' ' ? "" : " ", ev_name); |
1078 | slsmg_write_nstring(bf, browser->width); | 1102 | slsmg_printf("%s", bf); |
1103 | |||
1104 | nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST]; | ||
1105 | if (nr_events != 0) { | ||
1106 | menu->lost_events = true; | ||
1107 | if (!current_entry) | ||
1108 | ui_browser__set_color(browser, HE_COLORSET_TOP); | ||
1109 | nr_events = convert_unit(nr_events, &unit); | ||
1110 | snprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", nr_events, | ||
1111 | unit, unit == ' ' ? "" : " "); | ||
1112 | warn = bf; | ||
1113 | } | ||
1114 | |||
1115 | slsmg_write_nstring(warn, browser->width - printed); | ||
1079 | 1116 | ||
1080 | if (current_entry) | 1117 | if (current_entry) |
1081 | menu->selection = evsel; | 1118 | menu->selection = evsel; |
@@ -1100,6 +1137,11 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, | |||
1100 | switch (key) { | 1137 | switch (key) { |
1101 | case K_TIMER: | 1138 | case K_TIMER: |
1102 | timer(arg); | 1139 | timer(arg); |
1140 | |||
1141 | if (!menu->lost_events_warned && menu->lost_events) { | ||
1142 | ui_browser__warn_lost_events(&menu->b); | ||
1143 | menu->lost_events_warned = true; | ||
1144 | } | ||
1103 | continue; | 1145 | continue; |
1104 | case K_RIGHT: | 1146 | case K_RIGHT: |
1105 | case K_ENTER: | 1147 | case K_ENTER: |
@@ -1133,7 +1175,8 @@ browse_hists: | |||
1133 | pos = list_entry(pos->node.prev, struct perf_evsel, node); | 1175 | pos = list_entry(pos->node.prev, struct perf_evsel, node); |
1134 | goto browse_hists; | 1176 | goto browse_hists; |
1135 | case K_ESC: | 1177 | case K_ESC: |
1136 | if (!ui__dialog_yesno("Do you really want to exit?")) | 1178 | if (!ui_browser__dialog_yesno(&menu->b, |
1179 | "Do you really want to exit?")) | ||
1137 | continue; | 1180 | continue; |
1138 | /* Fall thru */ | 1181 | /* Fall thru */ |
1139 | case 'q': | 1182 | case 'q': |
@@ -1145,7 +1188,8 @@ browse_hists: | |||
1145 | case K_LEFT: | 1188 | case K_LEFT: |
1146 | continue; | 1189 | continue; |
1147 | case K_ESC: | 1190 | case K_ESC: |
1148 | if (!ui__dialog_yesno("Do you really want to exit?")) | 1191 | if (!ui_browser__dialog_yesno(&menu->b, |
1192 | "Do you really want to exit?")) | ||
1149 | continue; | 1193 | continue; |
1150 | /* Fall thru */ | 1194 | /* Fall thru */ |
1151 | case 'q': | 1195 | case 'q': |
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c index f36d2ff509ed..6ef3c5691762 100644 --- a/tools/perf/util/ui/helpline.c +++ b/tools/perf/util/ui/helpline.c | |||
@@ -1,20 +1,28 @@ | |||
1 | #define _GNU_SOURCE | 1 | #define _GNU_SOURCE |
2 | #include <stdio.h> | 2 | #include <stdio.h> |
3 | #include <stdlib.h> | 3 | #include <stdlib.h> |
4 | #include <newt.h> | 4 | #include <string.h> |
5 | 5 | ||
6 | #include "../debug.h" | 6 | #include "../debug.h" |
7 | #include "helpline.h" | 7 | #include "helpline.h" |
8 | #include "ui.h" | 8 | #include "ui.h" |
9 | #include "libslang.h" | ||
9 | 10 | ||
10 | void ui_helpline__pop(void) | 11 | void ui_helpline__pop(void) |
11 | { | 12 | { |
12 | newtPopHelpLine(); | ||
13 | } | 13 | } |
14 | 14 | ||
15 | char ui_helpline__current[512]; | ||
16 | |||
15 | void ui_helpline__push(const char *msg) | 17 | void ui_helpline__push(const char *msg) |
16 | { | 18 | { |
17 | newtPushHelpLine(msg); | 19 | const size_t sz = sizeof(ui_helpline__current); |
20 | |||
21 | SLsmg_gotorc(SLtt_Screen_Rows - 1, 0); | ||
22 | SLsmg_set_color(0); | ||
23 | SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols); | ||
24 | SLsmg_refresh(); | ||
25 | strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; | ||
18 | } | 26 | } |
19 | 27 | ||
20 | void ui_helpline__vpush(const char *fmt, va_list ap) | 28 | void ui_helpline__vpush(const char *fmt, va_list ap) |
@@ -63,7 +71,7 @@ int ui_helpline__show_help(const char *format, va_list ap) | |||
63 | 71 | ||
64 | if (ui_helpline__last_msg[backlog - 1] == '\n') { | 72 | if (ui_helpline__last_msg[backlog - 1] == '\n') { |
65 | ui_helpline__puts(ui_helpline__last_msg); | 73 | ui_helpline__puts(ui_helpline__last_msg); |
66 | newtRefresh(); | 74 | SLsmg_refresh(); |
67 | backlog = 0; | 75 | backlog = 0; |
68 | } | 76 | } |
69 | pthread_mutex_unlock(&ui__lock); | 77 | pthread_mutex_unlock(&ui__lock); |
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h index fdcbc0270acd..7bab6b34e35e 100644 --- a/tools/perf/util/ui/helpline.h +++ b/tools/perf/util/ui/helpline.h | |||
@@ -11,4 +11,6 @@ void ui_helpline__vpush(const char *fmt, va_list ap); | |||
11 | void ui_helpline__fpush(const char *fmt, ...); | 11 | void ui_helpline__fpush(const char *fmt, ...); |
12 | void ui_helpline__puts(const char *msg); | 12 | void ui_helpline__puts(const char *msg); |
13 | 13 | ||
14 | extern char ui_helpline__current[]; | ||
15 | |||
14 | #endif /* _PERF_UI_HELPLINE_H_ */ | 16 | #endif /* _PERF_UI_HELPLINE_H_ */ |
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/util/ui/progress.c index d7fc399d36b3..295e366b6311 100644 --- a/tools/perf/util/ui/progress.c +++ b/tools/perf/util/ui/progress.c | |||
@@ -1,60 +1,29 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include <newt.h> | ||
3 | #include "../cache.h" | 1 | #include "../cache.h" |
4 | #include "progress.h" | 2 | #include "progress.h" |
3 | #include "libslang.h" | ||
4 | #include "ui.h" | ||
5 | #include "browser.h" | ||
5 | 6 | ||
6 | struct ui_progress { | 7 | void ui_progress__update(u64 curr, u64 total, const char *title) |
7 | newtComponent form, scale; | ||
8 | }; | ||
9 | |||
10 | struct ui_progress *ui_progress__new(const char *title, u64 total) | ||
11 | { | ||
12 | struct ui_progress *self = malloc(sizeof(*self)); | ||
13 | |||
14 | if (self != NULL) { | ||
15 | int cols; | ||
16 | |||
17 | if (use_browser <= 0) | ||
18 | return self; | ||
19 | newtGetScreenSize(&cols, NULL); | ||
20 | cols -= 4; | ||
21 | newtCenteredWindow(cols, 1, title); | ||
22 | self->form = newtForm(NULL, NULL, 0); | ||
23 | if (self->form == NULL) | ||
24 | goto out_free_self; | ||
25 | self->scale = newtScale(0, 0, cols, total); | ||
26 | if (self->scale == NULL) | ||
27 | goto out_free_form; | ||
28 | newtFormAddComponent(self->form, self->scale); | ||
29 | newtRefresh(); | ||
30 | } | ||
31 | |||
32 | return self; | ||
33 | |||
34 | out_free_form: | ||
35 | newtFormDestroy(self->form); | ||
36 | out_free_self: | ||
37 | free(self); | ||
38 | return NULL; | ||
39 | } | ||
40 | |||
41 | void ui_progress__update(struct ui_progress *self, u64 curr) | ||
42 | { | 8 | { |
9 | int bar, y; | ||
43 | /* | 10 | /* |
44 | * FIXME: We should have a per UI backend way of showing progress, | 11 | * FIXME: We should have a per UI backend way of showing progress, |
45 | * stdio will just show a percentage as NN%, etc. | 12 | * stdio will just show a percentage as NN%, etc. |
46 | */ | 13 | */ |
47 | if (use_browser <= 0) | 14 | if (use_browser <= 0) |
48 | return; | 15 | return; |
49 | newtScaleSet(self->scale, curr); | ||
50 | newtRefresh(); | ||
51 | } | ||
52 | 16 | ||
53 | void ui_progress__delete(struct ui_progress *self) | 17 | ui__refresh_dimensions(true); |
54 | { | 18 | pthread_mutex_lock(&ui__lock); |
55 | if (use_browser > 0) { | 19 | y = SLtt_Screen_Rows / 2 - 2; |
56 | newtFormDestroy(self->form); | 20 | SLsmg_set_color(0); |
57 | newtPopWindow(); | 21 | SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols); |
58 | } | 22 | SLsmg_gotorc(y++, 1); |
59 | free(self); | 23 | SLsmg_write_string((char *)title); |
24 | SLsmg_set_color(HE_COLORSET_SELECTED); | ||
25 | bar = ((SLtt_Screen_Cols - 2) * curr) / total; | ||
26 | SLsmg_fill_region(y, 1, 1, bar, ' '); | ||
27 | SLsmg_refresh(); | ||
28 | pthread_mutex_unlock(&ui__lock); | ||
60 | } | 29 | } |
diff --git a/tools/perf/util/ui/progress.h b/tools/perf/util/ui/progress.h index a3820a0beb5b..d9c205b59aa1 100644 --- a/tools/perf/util/ui/progress.h +++ b/tools/perf/util/ui/progress.h | |||
@@ -1,11 +1,8 @@ | |||
1 | #ifndef _PERF_UI_PROGRESS_H_ | 1 | #ifndef _PERF_UI_PROGRESS_H_ |
2 | #define _PERF_UI_PROGRESS_H_ 1 | 2 | #define _PERF_UI_PROGRESS_H_ 1 |
3 | 3 | ||
4 | struct ui_progress; | 4 | #include <../types.h> |
5 | 5 | ||
6 | struct ui_progress *ui_progress__new(const char *title, u64 total); | 6 | void ui_progress__update(u64 curr, u64 total, const char *title); |
7 | void ui_progress__delete(struct ui_progress *self); | ||
8 | |||
9 | void ui_progress__update(struct ui_progress *self, u64 curr); | ||
10 | 7 | ||
11 | #endif | 8 | #endif |
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c index 1e6ba06980c4..85a69faa09aa 100644 --- a/tools/perf/util/ui/setup.c +++ b/tools/perf/util/ui/setup.c | |||
@@ -7,10 +7,85 @@ | |||
7 | #include "browser.h" | 7 | #include "browser.h" |
8 | #include "helpline.h" | 8 | #include "helpline.h" |
9 | #include "ui.h" | 9 | #include "ui.h" |
10 | #include "util.h" | ||
10 | #include "libslang.h" | 11 | #include "libslang.h" |
12 | #include "keysyms.h" | ||
11 | 13 | ||
12 | pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; | 14 | pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; |
13 | 15 | ||
16 | static volatile int ui__need_resize; | ||
17 | |||
18 | void ui__refresh_dimensions(bool force) | ||
19 | { | ||
20 | if (force || ui__need_resize) { | ||
21 | ui__need_resize = 0; | ||
22 | pthread_mutex_lock(&ui__lock); | ||
23 | SLtt_get_screen_size(); | ||
24 | SLsmg_reinit_smg(); | ||
25 | pthread_mutex_unlock(&ui__lock); | ||
26 | } | ||
27 | } | ||
28 | |||
29 | static void ui__sigwinch(int sig __used) | ||
30 | { | ||
31 | ui__need_resize = 1; | ||
32 | } | ||
33 | |||
34 | static void ui__setup_sigwinch(void) | ||
35 | { | ||
36 | static bool done; | ||
37 | |||
38 | if (done) | ||
39 | return; | ||
40 | |||
41 | done = true; | ||
42 | pthread__unblock_sigwinch(); | ||
43 | signal(SIGWINCH, ui__sigwinch); | ||
44 | } | ||
45 | |||
46 | int ui__getch(int delay_secs) | ||
47 | { | ||
48 | struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL; | ||
49 | fd_set read_set; | ||
50 | int err, key; | ||
51 | |||
52 | ui__setup_sigwinch(); | ||
53 | |||
54 | FD_ZERO(&read_set); | ||
55 | FD_SET(0, &read_set); | ||
56 | |||
57 | if (delay_secs) { | ||
58 | timeout.tv_sec = delay_secs; | ||
59 | timeout.tv_usec = 0; | ||
60 | } | ||
61 | |||
62 | err = select(1, &read_set, NULL, NULL, ptimeout); | ||
63 | |||
64 | if (err == 0) | ||
65 | return K_TIMER; | ||
66 | |||
67 | if (err == -1) { | ||
68 | if (errno == EINTR) | ||
69 | return K_RESIZE; | ||
70 | return K_ERROR; | ||
71 | } | ||
72 | |||
73 | key = SLang_getkey(); | ||
74 | if (key != K_ESC) | ||
75 | return key; | ||
76 | |||
77 | FD_ZERO(&read_set); | ||
78 | FD_SET(0, &read_set); | ||
79 | timeout.tv_sec = 0; | ||
80 | timeout.tv_usec = 20; | ||
81 | err = select(1, &read_set, NULL, NULL, &timeout); | ||
82 | if (err == 0) | ||
83 | return K_ESC; | ||
84 | |||
85 | SLang_ungetkey(key); | ||
86 | return SLkp_getkey(); | ||
87 | } | ||
88 | |||
14 | static void newt_suspend(void *d __used) | 89 | static void newt_suspend(void *d __used) |
15 | { | 90 | { |
16 | newtSuspend(); | 91 | newtSuspend(); |
@@ -71,10 +146,10 @@ void setup_browser(bool fallback_to_pager) | |||
71 | void exit_browser(bool wait_for_ok) | 146 | void exit_browser(bool wait_for_ok) |
72 | { | 147 | { |
73 | if (use_browser > 0) { | 148 | if (use_browser > 0) { |
74 | if (wait_for_ok) { | 149 | if (wait_for_ok) |
75 | char title[] = "Fatal Error", ok[] = "Ok"; | 150 | ui__question_window("Fatal Error", |
76 | newtWinMessage(title, ok, ui_helpline__last_msg); | 151 | ui_helpline__last_msg, |
77 | } | 152 | "Press any key...", 0); |
78 | ui__exit(); | 153 | ui__exit(); |
79 | } | 154 | } |
80 | } | 155 | } |
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/util/ui/ui.h index d264e059c829..7b67045479f6 100644 --- a/tools/perf/util/ui/ui.h +++ b/tools/perf/util/ui/ui.h | |||
@@ -2,7 +2,10 @@ | |||
2 | #define _PERF_UI_H_ 1 | 2 | #define _PERF_UI_H_ 1 |
3 | 3 | ||
4 | #include <pthread.h> | 4 | #include <pthread.h> |
5 | #include <stdbool.h> | ||
5 | 6 | ||
6 | extern pthread_mutex_t ui__lock; | 7 | extern pthread_mutex_t ui__lock; |
7 | 8 | ||
9 | void ui__refresh_dimensions(bool force); | ||
10 | |||
8 | #endif /* _PERF_UI_H_ */ | 11 | #endif /* _PERF_UI_H_ */ |
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c index fdf1fc8f08bc..45daa7c41dad 100644 --- a/tools/perf/util/ui/util.c +++ b/tools/perf/util/ui/util.c | |||
@@ -1,6 +1,5 @@ | |||
1 | #include <newt.h> | 1 | #include "../util.h" |
2 | #include <signal.h> | 2 | #include <signal.h> |
3 | #include <stdio.h> | ||
4 | #include <stdbool.h> | 3 | #include <stdbool.h> |
5 | #include <string.h> | 4 | #include <string.h> |
6 | #include <sys/ttydefaults.h> | 5 | #include <sys/ttydefaults.h> |
@@ -8,72 +7,75 @@ | |||
8 | #include "../cache.h" | 7 | #include "../cache.h" |
9 | #include "../debug.h" | 8 | #include "../debug.h" |
10 | #include "browser.h" | 9 | #include "browser.h" |
10 | #include "keysyms.h" | ||
11 | #include "helpline.h" | 11 | #include "helpline.h" |
12 | #include "ui.h" | 12 | #include "ui.h" |
13 | #include "util.h" | 13 | #include "util.h" |
14 | #include "libslang.h" | ||
14 | 15 | ||
15 | static void newt_form__set_exit_keys(newtComponent self) | 16 | static void ui_browser__argv_write(struct ui_browser *browser, |
17 | void *entry, int row) | ||
16 | { | 18 | { |
17 | newtFormAddHotKey(self, NEWT_KEY_LEFT); | 19 | char **arg = entry; |
18 | newtFormAddHotKey(self, NEWT_KEY_ESCAPE); | 20 | bool current_entry = ui_browser__is_current_entry(browser, row); |
19 | newtFormAddHotKey(self, 'Q'); | ||
20 | newtFormAddHotKey(self, 'q'); | ||
21 | newtFormAddHotKey(self, CTRL('c')); | ||
22 | } | ||
23 | 21 | ||
24 | static newtComponent newt_form__new(void) | 22 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : |
25 | { | 23 | HE_COLORSET_NORMAL); |
26 | newtComponent self = newtForm(NULL, NULL, 0); | 24 | slsmg_write_nstring(*arg, browser->width); |
27 | if (self) | ||
28 | newt_form__set_exit_keys(self); | ||
29 | return self; | ||
30 | } | 25 | } |
31 | 26 | ||
32 | int ui__popup_menu(int argc, char * const argv[]) | 27 | static int popup_menu__run(struct ui_browser *menu) |
33 | { | 28 | { |
34 | struct newtExitStruct es; | 29 | int key; |
35 | int i, rc = -1, max_len = 5; | ||
36 | newtComponent listbox, form = newt_form__new(); | ||
37 | 30 | ||
38 | if (form == NULL) | 31 | if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0) |
39 | return -1; | 32 | return -1; |
40 | 33 | ||
41 | listbox = newtListbox(0, 0, argc, NEWT_FLAG_RETURNEXIT); | 34 | while (1) { |
42 | if (listbox == NULL) | 35 | key = ui_browser__run(menu, 0); |
43 | goto out_destroy_form; | ||
44 | 36 | ||
45 | newtFormAddComponent(form, listbox); | 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 | } | ||
46 | 51 | ||
47 | for (i = 0; i < argc; ++i) { | 52 | break; |
48 | int len = strlen(argv[i]); | ||
49 | if (len > max_len) | ||
50 | max_len = len; | ||
51 | if (newtListboxAddEntry(listbox, argv[i], (void *)(long)i)) | ||
52 | goto out_destroy_form; | ||
53 | } | 53 | } |
54 | 54 | ||
55 | newtCenteredWindow(max_len, argc, NULL); | 55 | ui_browser__hide(menu); |
56 | newtFormRun(form, &es); | 56 | return key; |
57 | rc = newtListboxGetCurrent(listbox) - NULL; | ||
58 | if (es.reason == NEWT_EXIT_HOTKEY) | ||
59 | rc = -1; | ||
60 | newtPopWindow(); | ||
61 | out_destroy_form: | ||
62 | newtFormDestroy(form); | ||
63 | return rc; | ||
64 | } | 57 | } |
65 | 58 | ||
66 | int ui__help_window(const char *text) | 59 | int ui__popup_menu(int argc, char * const argv[]) |
67 | { | 60 | { |
68 | struct newtExitStruct es; | 61 | struct ui_browser menu = { |
69 | newtComponent tb, form = newt_form__new(); | 62 | .entries = (void *)argv, |
70 | int rc = -1; | 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__question_window(const char *title, const char *text, | ||
73 | const char *exit_msg, int delay_secs) | ||
74 | { | ||
75 | int x, y; | ||
71 | int max_len = 0, nr_lines = 0; | 76 | int max_len = 0, nr_lines = 0; |
72 | const char *t; | 77 | const char *t; |
73 | 78 | ||
74 | if (form == NULL) | ||
75 | return -1; | ||
76 | |||
77 | t = text; | 79 | t = text; |
78 | while (1) { | 80 | while (1) { |
79 | const char *sep = strchr(t, '\n'); | 81 | const char *sep = strchr(t, '\n'); |
@@ -90,41 +92,77 @@ int ui__help_window(const char *text) | |||
90 | t = sep + 1; | 92 | t = sep + 1; |
91 | } | 93 | } |
92 | 94 | ||
93 | tb = newtTextbox(0, 0, max_len, nr_lines, 0); | 95 | max_len += 2; |
94 | if (tb == NULL) | 96 | nr_lines += 4; |
95 | goto out_destroy_form; | 97 | y = SLtt_Screen_Rows / 2 - nr_lines / 2, |
96 | 98 | x = SLtt_Screen_Cols / 2 - max_len / 2; | |
97 | newtTextboxSetText(tb, text); | 99 | |
98 | newtFormAddComponent(form, tb); | 100 | SLsmg_set_color(0); |
99 | newtCenteredWindow(max_len, nr_lines, NULL); | 101 | SLsmg_draw_box(y, x++, nr_lines, max_len); |
100 | newtFormRun(form, &es); | 102 | if (title) { |
101 | newtPopWindow(); | 103 | SLsmg_gotorc(y, x + 1); |
102 | rc = 0; | 104 | SLsmg_write_string((char *)title); |
103 | out_destroy_form: | 105 | } |
104 | newtFormDestroy(form); | 106 | SLsmg_gotorc(++y, x); |
105 | return rc; | 107 | nr_lines -= 2; |
108 | max_len -= 2; | ||
109 | SLsmg_write_wrapped_string((unsigned char *)text, y, x, | ||
110 | nr_lines, max_len, 1); | ||
111 | SLsmg_gotorc(y + nr_lines - 2, x); | ||
112 | SLsmg_write_nstring((char *)" ", max_len); | ||
113 | SLsmg_gotorc(y + nr_lines - 1, x); | ||
114 | SLsmg_write_nstring((char *)exit_msg, max_len); | ||
115 | SLsmg_refresh(); | ||
116 | return ui__getch(delay_secs); | ||
106 | } | 117 | } |
107 | 118 | ||
108 | static const char yes[] = "Yes", no[] = "No", | 119 | int ui__help_window(const char *text) |
109 | warning_str[] = "Warning!", ok[] = "Ok"; | 120 | { |
121 | return ui__question_window("Help", text, "Press any key...", 0); | ||
122 | } | ||
110 | 123 | ||
111 | bool ui__dialog_yesno(const char *msg) | 124 | int ui__dialog_yesno(const char *msg) |
112 | { | 125 | { |
113 | /* newtWinChoice should really be accepting const char pointers... */ | 126 | return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); |
114 | return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1; | ||
115 | } | 127 | } |
116 | 128 | ||
117 | void ui__warning(const char *format, ...) | 129 | int __ui__warning(const char *title, const char *format, va_list args) |
118 | { | 130 | { |
119 | va_list args; | 131 | char *s; |
132 | |||
133 | if (use_browser > 0 && vasprintf(&s, format, args) > 0) { | ||
134 | int key; | ||
120 | 135 | ||
121 | va_start(args, format); | ||
122 | if (use_browser > 0) { | ||
123 | pthread_mutex_lock(&ui__lock); | 136 | pthread_mutex_lock(&ui__lock); |
124 | newtWinMessagev((char *)warning_str, (char *)ok, | 137 | key = ui__question_window(title, s, "Press any key...", 0); |
125 | (char *)format, args); | ||
126 | pthread_mutex_unlock(&ui__lock); | 138 | pthread_mutex_unlock(&ui__lock); |
127 | } else | 139 | free(s); |
128 | vfprintf(stderr, format, args); | 140 | return key; |
141 | } | ||
142 | |||
143 | fprintf(stderr, "%s:\n", title); | ||
144 | vfprintf(stderr, format, args); | ||
145 | return K_ESC; | ||
146 | } | ||
147 | |||
148 | int ui__warning(const char *format, ...) | ||
149 | { | ||
150 | int key; | ||
151 | va_list args; | ||
152 | |||
153 | va_start(args, format); | ||
154 | key = __ui__warning("Warning", format, args); | ||
155 | va_end(args); | ||
156 | return key; | ||
157 | } | ||
158 | |||
159 | int ui__error(const char *format, ...) | ||
160 | { | ||
161 | int key; | ||
162 | va_list args; | ||
163 | |||
164 | va_start(args, format); | ||
165 | key = __ui__warning("Error", format, args); | ||
129 | va_end(args); | 166 | va_end(args); |
167 | return key; | ||
130 | } | 168 | } |
diff --git a/tools/perf/util/ui/util.h b/tools/perf/util/ui/util.h index afcbc1d99531..2d1738bd71c8 100644 --- a/tools/perf/util/ui/util.h +++ b/tools/perf/util/ui/util.h | |||
@@ -1,10 +1,14 @@ | |||
1 | #ifndef _PERF_UI_UTIL_H_ | 1 | #ifndef _PERF_UI_UTIL_H_ |
2 | #define _PERF_UI_UTIL_H_ 1 | 2 | #define _PERF_UI_UTIL_H_ 1 |
3 | 3 | ||
4 | #include <stdbool.h> | 4 | #include <stdarg.h> |
5 | 5 | ||
6 | int ui__getch(int delay_secs); | ||
6 | int ui__popup_menu(int argc, char * const argv[]); | 7 | int ui__popup_menu(int argc, char * const argv[]); |
7 | int ui__help_window(const char *text); | 8 | int ui__help_window(const char *text); |
8 | bool 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, | ||
11 | const char *exit_msg, int delay_secs); | ||
12 | int __ui__warning(const char *title, const char *format, va_list args); | ||
9 | 13 | ||
10 | #endif /* _PERF_UI_UTIL_H_ */ | 14 | #endif /* _PERF_UI_UTIL_H_ */ |