diff options
Diffstat (limited to 'tools/perf/util')
28 files changed, 575 insertions, 272 deletions
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..d7915d4e77cb 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 | { |
| @@ -33,6 +34,16 @@ int __perf_evsel__sample_size(u64 sample_type) | |||
| 33 | return size; | 34 | return size; |
| 34 | } | 35 | } |
| 35 | 36 | ||
| 37 | static void hists__init(struct hists *hists) | ||
| 38 | { | ||
| 39 | memset(hists, 0, sizeof(*hists)); | ||
| 40 | hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; | ||
| 41 | hists->entries_in = &hists->entries_in_array[0]; | ||
| 42 | hists->entries_collapsed = RB_ROOT; | ||
| 43 | hists->entries = RB_ROOT; | ||
| 44 | pthread_mutex_init(&hists->lock, NULL); | ||
| 45 | } | ||
| 46 | |||
| 36 | void perf_evsel__init(struct perf_evsel *evsel, | 47 | void perf_evsel__init(struct perf_evsel *evsel, |
| 37 | struct perf_event_attr *attr, int idx) | 48 | struct perf_event_attr *attr, int idx) |
| 38 | { | 49 | { |
| @@ -204,15 +215,16 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
| 204 | } | 215 | } |
| 205 | 216 | ||
| 206 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 217 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
| 207 | struct thread_map *threads, bool group) | 218 | struct thread_map *threads, bool group, |
| 219 | struct xyarray *group_fds) | ||
| 208 | { | 220 | { |
| 209 | int cpu, thread; | 221 | int cpu, thread; |
| 210 | unsigned long flags = 0; | 222 | unsigned long flags = 0; |
| 211 | int pid = -1; | 223 | int pid = -1, err; |
| 212 | 224 | ||
| 213 | if (evsel->fd == NULL && | 225 | if (evsel->fd == NULL && |
| 214 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) | 226 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) |
| 215 | return -1; | 227 | return -ENOMEM; |
| 216 | 228 | ||
| 217 | if (evsel->cgrp) { | 229 | if (evsel->cgrp) { |
| 218 | flags = PERF_FLAG_PID_CGROUP; | 230 | flags = PERF_FLAG_PID_CGROUP; |
| @@ -220,7 +232,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
| 220 | } | 232 | } |
| 221 | 233 | ||
| 222 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 234 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
| 223 | int group_fd = -1; | 235 | int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1; |
| 224 | 236 | ||
| 225 | for (thread = 0; thread < threads->nr; thread++) { | 237 | for (thread = 0; thread < threads->nr; thread++) { |
| 226 | 238 | ||
| @@ -231,8 +243,10 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
| 231 | pid, | 243 | pid, |
| 232 | cpus->map[cpu], | 244 | cpus->map[cpu], |
| 233 | group_fd, flags); | 245 | group_fd, flags); |
| 234 | if (FD(evsel, cpu, thread) < 0) | 246 | if (FD(evsel, cpu, thread) < 0) { |
| 247 | err = -errno; | ||
| 235 | goto out_close; | 248 | goto out_close; |
| 249 | } | ||
| 236 | 250 | ||
| 237 | if (group && group_fd == -1) | 251 | if (group && group_fd == -1) |
| 238 | group_fd = FD(evsel, cpu, thread); | 252 | group_fd = FD(evsel, cpu, thread); |
| @@ -249,7 +263,17 @@ out_close: | |||
| 249 | } | 263 | } |
| 250 | thread = threads->nr; | 264 | thread = threads->nr; |
| 251 | } while (--cpu >= 0); | 265 | } while (--cpu >= 0); |
| 252 | return -1; | 266 | return err; |
| 267 | } | ||
| 268 | |||
| 269 | void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads) | ||
| 270 | { | ||
| 271 | if (evsel->fd == NULL) | ||
| 272 | return; | ||
| 273 | |||
| 274 | perf_evsel__close_fd(evsel, ncpus, nthreads); | ||
| 275 | perf_evsel__free_fd(evsel); | ||
| 276 | evsel->fd = NULL; | ||
| 253 | } | 277 | } |
| 254 | 278 | ||
| 255 | static struct { | 279 | static struct { |
| @@ -269,7 +293,8 @@ static struct { | |||
| 269 | }; | 293 | }; |
| 270 | 294 | ||
| 271 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 295 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
| 272 | struct thread_map *threads, bool group) | 296 | struct thread_map *threads, bool group, |
| 297 | struct xyarray *group_fd) | ||
| 273 | { | 298 | { |
| 274 | if (cpus == NULL) { | 299 | if (cpus == NULL) { |
| 275 | /* Work around old compiler warnings about strict aliasing */ | 300 | /* Work around old compiler warnings about strict aliasing */ |
| @@ -279,19 +304,23 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
| 279 | if (threads == NULL) | 304 | if (threads == NULL) |
| 280 | threads = &empty_thread_map.map; | 305 | threads = &empty_thread_map.map; |
| 281 | 306 | ||
| 282 | return __perf_evsel__open(evsel, cpus, threads, group); | 307 | return __perf_evsel__open(evsel, cpus, threads, group, group_fd); |
| 283 | } | 308 | } |
| 284 | 309 | ||
| 285 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 310 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
| 286 | struct cpu_map *cpus, bool group) | 311 | struct cpu_map *cpus, bool group, |
| 312 | struct xyarray *group_fd) | ||
| 287 | { | 313 | { |
| 288 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group); | 314 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, |
| 315 | group_fd); | ||
| 289 | } | 316 | } |
| 290 | 317 | ||
| 291 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | 318 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, |
| 292 | struct thread_map *threads, bool group) | 319 | struct thread_map *threads, bool group, |
| 320 | struct xyarray *group_fd) | ||
| 293 | { | 321 | { |
| 294 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group); | 322 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, |
| 323 | group_fd); | ||
| 295 | } | 324 | } |
| 296 | 325 | ||
| 297 | static int perf_event__parse_id_sample(const union perf_event *event, u64 type, | 326 | 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..abef2703cd24 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) { |
| @@ -1212,13 +1211,3 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) | |||
| 1212 | 1211 | ||
| 1213 | return ret; | 1212 | return ret; |
| 1214 | } | 1213 | } |
| 1215 | |||
| 1216 | void hists__init(struct hists *hists) | ||
| 1217 | { | ||
| 1218 | memset(hists, 0, sizeof(*hists)); | ||
| 1219 | hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; | ||
| 1220 | hists->entries_in = &hists->entries_in_array[0]; | ||
| 1221 | hists->entries_collapsed = RB_ROOT; | ||
| 1222 | hists->entries = RB_ROOT; | ||
| 1223 | pthread_mutex_init(&hists->lock, NULL); | ||
| 1224 | } | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ff93ddc91c5c..89289c8e935e 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; |
| @@ -62,8 +63,6 @@ struct hists { | |||
| 62 | struct callchain_cursor callchain_cursor; | 63 | struct callchain_cursor callchain_cursor; |
| 63 | }; | 64 | }; |
| 64 | 65 | ||
| 65 | void hists__init(struct hists *hists); | ||
| 66 | |||
| 67 | struct hist_entry *__hists__add_entry(struct hists *self, | 66 | struct hist_entry *__hists__add_entry(struct hists *self, |
| 68 | struct addr_location *al, | 67 | struct addr_location *al, |
| 69 | struct symbol *parent, u64 period); | 68 | struct symbol *parent, u64 period); |
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..0f4555ce9063 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; |
| @@ -1311,6 +1333,10 @@ int perf_session__cpu_bitmap(struct perf_session *session, | |||
| 1311 | } | 1333 | } |
| 1312 | 1334 | ||
| 1313 | map = cpu_map__new(cpu_list); | 1335 | map = cpu_map__new(cpu_list); |
| 1336 | if (map == NULL) { | ||
| 1337 | pr_err("Invalid cpu_list\n"); | ||
| 1338 | return -1; | ||
| 1339 | } | ||
| 1314 | 1340 | ||
| 1315 | for (i = 0; i < map->nr; i++) { | 1341 | for (i = 0; i < map->nr; i++) { |
| 1316 | int cpu = map->map[i]; | 1342 | int cpu = map->map[i]; |
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/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 0a7ed5b5e281..6c164dc9ee95 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
| @@ -1537,6 +1537,8 @@ process_flags(struct event *event, struct print_arg *arg, char **tok) | |||
| 1537 | field = malloc_or_die(sizeof(*field)); | 1537 | field = malloc_or_die(sizeof(*field)); |
| 1538 | 1538 | ||
| 1539 | type = process_arg(event, field, &token); | 1539 | type = process_arg(event, field, &token); |
| 1540 | while (type == EVENT_OP) | ||
| 1541 | type = process_op(event, field, &token); | ||
| 1540 | if (test_type_token(type, token, EVENT_DELIM, ",")) | 1542 | if (test_type_token(type, token, EVENT_DELIM, ",")) |
| 1541 | goto out_free; | 1543 | goto out_free; |
| 1542 | 1544 | ||
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_ */ |
