Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

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