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_ */ |
