diff options
Diffstat (limited to 'tools')
35 files changed, 1227 insertions, 423 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f82480fa7f27..6ab58cc99d53 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -262,13 +262,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, | |||
262 | 262 | ||
263 | static void open_counters(struct perf_evlist *evlist) | 263 | static void open_counters(struct perf_evlist *evlist) |
264 | { | 264 | { |
265 | struct perf_evsel *pos; | 265 | struct perf_evsel *pos, *first; |
266 | 266 | ||
267 | if (evlist->cpus->map[0] < 0) | 267 | if (evlist->cpus->map[0] < 0) |
268 | no_inherit = true; | 268 | no_inherit = true; |
269 | 269 | ||
270 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
271 | |||
270 | list_for_each_entry(pos, &evlist->entries, node) { | 272 | list_for_each_entry(pos, &evlist->entries, node) { |
271 | struct perf_event_attr *attr = &pos->attr; | 273 | struct perf_event_attr *attr = &pos->attr; |
274 | struct xyarray *group_fd = NULL; | ||
272 | /* | 275 | /* |
273 | * Check if parse_single_tracepoint_event has already asked for | 276 | * Check if parse_single_tracepoint_event has already asked for |
274 | * PERF_SAMPLE_TIME. | 277 | * PERF_SAMPLE_TIME. |
@@ -283,15 +286,19 @@ static void open_counters(struct perf_evlist *evlist) | |||
283 | */ | 286 | */ |
284 | bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; | 287 | bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; |
285 | 288 | ||
289 | if (group && pos != first) | ||
290 | group_fd = first->fd; | ||
291 | |||
286 | config_attr(pos, evlist); | 292 | config_attr(pos, evlist); |
287 | retry_sample_id: | 293 | retry_sample_id: |
288 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | 294 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; |
289 | try_again: | 295 | try_again: |
290 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) { | 296 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, |
297 | group_fd) < 0) { | ||
291 | int err = errno; | 298 | int err = errno; |
292 | 299 | ||
293 | if (err == EPERM || err == EACCES) { | 300 | if (err == EPERM || err == EACCES) { |
294 | ui__warning_paranoid(); | 301 | ui__error_paranoid(); |
295 | exit(EXIT_FAILURE); | 302 | exit(EXIT_FAILURE); |
296 | } else if (err == ENODEV && cpu_list) { | 303 | } else if (err == ENODEV && cpu_list) { |
297 | die("No such device - did you specify" | 304 | die("No such device - did you specify" |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 7ce65f52415e..955930e0a5c3 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -278,9 +278,14 @@ struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; | |||
278 | struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; | 278 | struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; |
279 | struct stats walltime_nsecs_stats; | 279 | struct stats walltime_nsecs_stats; |
280 | 280 | ||
281 | static int create_perf_stat_counter(struct perf_evsel *evsel) | 281 | static int create_perf_stat_counter(struct perf_evsel *evsel, |
282 | struct perf_evsel *first) | ||
282 | { | 283 | { |
283 | struct perf_event_attr *attr = &evsel->attr; | 284 | struct perf_event_attr *attr = &evsel->attr; |
285 | struct xyarray *group_fd = NULL; | ||
286 | |||
287 | if (group && evsel != first) | ||
288 | group_fd = first->fd; | ||
284 | 289 | ||
285 | if (scale) | 290 | if (scale) |
286 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 291 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
@@ -289,14 +294,15 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) | |||
289 | attr->inherit = !no_inherit; | 294 | attr->inherit = !no_inherit; |
290 | 295 | ||
291 | if (system_wide) | 296 | if (system_wide) |
292 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group); | 297 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, |
293 | 298 | group, group_fd); | |
294 | if (target_pid == -1 && target_tid == -1) { | 299 | if (target_pid == -1 && target_tid == -1) { |
295 | attr->disabled = 1; | 300 | attr->disabled = 1; |
296 | attr->enable_on_exec = 1; | 301 | attr->enable_on_exec = 1; |
297 | } | 302 | } |
298 | 303 | ||
299 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, group); | 304 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, |
305 | group, group_fd); | ||
300 | } | 306 | } |
301 | 307 | ||
302 | /* | 308 | /* |
@@ -396,7 +402,7 @@ static int read_counter(struct perf_evsel *counter) | |||
396 | static int run_perf_stat(int argc __used, const char **argv) | 402 | static int run_perf_stat(int argc __used, const char **argv) |
397 | { | 403 | { |
398 | unsigned long long t0, t1; | 404 | unsigned long long t0, t1; |
399 | struct perf_evsel *counter; | 405 | struct perf_evsel *counter, *first; |
400 | int status = 0; | 406 | int status = 0; |
401 | int child_ready_pipe[2], go_pipe[2]; | 407 | int child_ready_pipe[2], go_pipe[2]; |
402 | const bool forks = (argc > 0); | 408 | const bool forks = (argc > 0); |
@@ -453,9 +459,12 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
453 | close(child_ready_pipe[0]); | 459 | close(child_ready_pipe[0]); |
454 | } | 460 | } |
455 | 461 | ||
462 | first = list_entry(evsel_list->entries.next, struct perf_evsel, node); | ||
463 | |||
456 | list_for_each_entry(counter, &evsel_list->entries, node) { | 464 | list_for_each_entry(counter, &evsel_list->entries, node) { |
457 | if (create_perf_stat_counter(counter) < 0) { | 465 | if (create_perf_stat_counter(counter, first) < 0) { |
458 | if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) { | 466 | if (errno == EINVAL || errno == ENOSYS || |
467 | errno == ENOENT || errno == EOPNOTSUPP) { | ||
459 | if (verbose) | 468 | if (verbose) |
460 | ui__warning("%s event is not supported by the kernel.\n", | 469 | ui__warning("%s event is not supported by the kernel.\n", |
461 | event_name(counter)); | 470 | event_name(counter)); |
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index efe696f936e2..831d1baeac37 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
@@ -291,7 +291,7 @@ static int test__open_syscall_event(void) | |||
291 | goto out_thread_map_delete; | 291 | goto out_thread_map_delete; |
292 | } | 292 | } |
293 | 293 | ||
294 | if (perf_evsel__open_per_thread(evsel, threads, false) < 0) { | 294 | if (perf_evsel__open_per_thread(evsel, threads, false, NULL) < 0) { |
295 | pr_debug("failed to open counter: %s, " | 295 | pr_debug("failed to open counter: %s, " |
296 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 296 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
297 | strerror(errno)); | 297 | strerror(errno)); |
@@ -366,7 +366,7 @@ static int test__open_syscall_event_on_all_cpus(void) | |||
366 | goto out_thread_map_delete; | 366 | goto out_thread_map_delete; |
367 | } | 367 | } |
368 | 368 | ||
369 | if (perf_evsel__open(evsel, cpus, threads, false) < 0) { | 369 | if (perf_evsel__open(evsel, cpus, threads, false, NULL) < 0) { |
370 | pr_debug("failed to open counter: %s, " | 370 | pr_debug("failed to open counter: %s, " |
371 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 371 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
372 | strerror(errno)); | 372 | strerror(errno)); |
@@ -531,7 +531,7 @@ static int test__basic_mmap(void) | |||
531 | 531 | ||
532 | perf_evlist__add(evlist, evsels[i]); | 532 | perf_evlist__add(evlist, evsels[i]); |
533 | 533 | ||
534 | if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) { | 534 | if (perf_evsel__open(evsels[i], cpus, threads, false, NULL) < 0) { |
535 | pr_debug("failed to open counter: %s, " | 535 | pr_debug("failed to open counter: %s, " |
536 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 536 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
537 | strerror(errno)); | 537 | strerror(errno)); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7a871714d44e..c9cdedb58134 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -89,6 +89,7 @@ static bool vmlinux_warned; | |||
89 | static bool inherit = false; | 89 | static bool inherit = false; |
90 | static int realtime_prio = 0; | 90 | static int realtime_prio = 0; |
91 | static bool group = false; | 91 | static bool group = false; |
92 | static bool sample_id_all_avail = true; | ||
92 | static unsigned int mmap_pages = 128; | 93 | static unsigned int mmap_pages = 128; |
93 | 94 | ||
94 | static bool dump_symtab = false; | 95 | static bool dump_symtab = false; |
@@ -199,7 +200,8 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) | |||
199 | struct symbol *sym; | 200 | struct symbol *sym; |
200 | 201 | ||
201 | if (he == NULL || he->ms.sym == NULL || | 202 | if (he == NULL || he->ms.sym == NULL || |
202 | (he != top.sym_filter_entry && use_browser != 1)) | 203 | ((top.sym_filter_entry == NULL || |
204 | top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) | ||
203 | return; | 205 | return; |
204 | 206 | ||
205 | sym = he->ms.sym; | 207 | sym = he->ms.sym; |
@@ -289,11 +291,13 @@ static void print_sym_table(void) | |||
289 | 291 | ||
290 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); | 292 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
291 | 293 | ||
292 | if (top.total_lost_warned != top.session->hists.stats.total_lost) { | 294 | if (top.sym_evsel->hists.stats.nr_lost_warned != |
293 | top.total_lost_warned = top.session->hists.stats.total_lost; | 295 | top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { |
294 | color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); | 296 | top.sym_evsel->hists.stats.nr_lost_warned = |
295 | printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", | 297 | top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; |
296 | top.total_lost_warned); | 298 | color_fprintf(stdout, PERF_COLOR_RED, |
299 | "WARNING: LOST %d chunks, Check IO/CPU overload", | ||
300 | top.sym_evsel->hists.stats.nr_lost_warned); | ||
297 | ++printed; | 301 | ++printed; |
298 | } | 302 | } |
299 | 303 | ||
@@ -561,7 +565,6 @@ static void perf_top__sort_new_samples(void *arg) | |||
561 | hists__decay_entries_threaded(&t->sym_evsel->hists, | 565 | hists__decay_entries_threaded(&t->sym_evsel->hists, |
562 | top.hide_user_symbols, | 566 | top.hide_user_symbols, |
563 | top.hide_kernel_symbols); | 567 | top.hide_kernel_symbols); |
564 | hists__output_recalc_col_len(&t->sym_evsel->hists, winsize.ws_row - 3); | ||
565 | } | 568 | } |
566 | 569 | ||
567 | static void *display_thread_tui(void *arg __used) | 570 | static void *display_thread_tui(void *arg __used) |
@@ -671,6 +674,7 @@ static int symbol_filter(struct map *map __used, struct symbol *sym) | |||
671 | } | 674 | } |
672 | 675 | ||
673 | static void perf_event__process_sample(const union perf_event *event, | 676 | static void perf_event__process_sample(const union perf_event *event, |
677 | struct perf_evsel *evsel, | ||
674 | struct perf_sample *sample, | 678 | struct perf_sample *sample, |
675 | struct perf_session *session) | 679 | struct perf_session *session) |
676 | { | 680 | { |
@@ -770,12 +774,8 @@ static void perf_event__process_sample(const union perf_event *event, | |||
770 | } | 774 | } |
771 | 775 | ||
772 | if (al.sym == NULL || !al.sym->ignore) { | 776 | if (al.sym == NULL || !al.sym->ignore) { |
773 | struct perf_evsel *evsel; | ||
774 | struct hist_entry *he; | 777 | struct hist_entry *he; |
775 | 778 | ||
776 | evsel = perf_evlist__id2evsel(top.evlist, sample->id); | ||
777 | assert(evsel != NULL); | ||
778 | |||
779 | if ((sort__has_parent || symbol_conf.use_callchain) && | 779 | if ((sort__has_parent || symbol_conf.use_callchain) && |
780 | sample->callchain) { | 780 | sample->callchain) { |
781 | err = perf_session__resolve_callchain(session, al.thread, | 781 | err = perf_session__resolve_callchain(session, al.thread, |
@@ -807,6 +807,7 @@ static void perf_event__process_sample(const union perf_event *event, | |||
807 | static void perf_session__mmap_read_idx(struct perf_session *self, int idx) | 807 | static void perf_session__mmap_read_idx(struct perf_session *self, int idx) |
808 | { | 808 | { |
809 | struct perf_sample sample; | 809 | struct perf_sample sample; |
810 | struct perf_evsel *evsel; | ||
810 | union perf_event *event; | 811 | union perf_event *event; |
811 | int ret; | 812 | int ret; |
812 | 813 | ||
@@ -817,10 +818,16 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) | |||
817 | continue; | 818 | continue; |
818 | } | 819 | } |
819 | 820 | ||
821 | evsel = perf_evlist__id2evsel(self->evlist, sample.id); | ||
822 | assert(evsel != NULL); | ||
823 | |||
820 | if (event->header.type == PERF_RECORD_SAMPLE) | 824 | if (event->header.type == PERF_RECORD_SAMPLE) |
821 | perf_event__process_sample(event, &sample, self); | 825 | perf_event__process_sample(event, evsel, &sample, self); |
822 | else | 826 | else if (event->header.type < PERF_RECORD_MAX) { |
827 | hists__inc_nr_events(&evsel->hists, event->header.type); | ||
823 | perf_event__process(event, &sample, self); | 828 | perf_event__process(event, &sample, self); |
829 | } else | ||
830 | ++self->hists.stats.nr_unknown_events; | ||
824 | } | 831 | } |
825 | } | 832 | } |
826 | 833 | ||
@@ -834,10 +841,16 @@ static void perf_session__mmap_read(struct perf_session *self) | |||
834 | 841 | ||
835 | static void start_counters(struct perf_evlist *evlist) | 842 | static void start_counters(struct perf_evlist *evlist) |
836 | { | 843 | { |
837 | struct perf_evsel *counter; | 844 | struct perf_evsel *counter, *first; |
845 | |||
846 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
838 | 847 | ||
839 | list_for_each_entry(counter, &evlist->entries, node) { | 848 | list_for_each_entry(counter, &evlist->entries, node) { |
840 | struct perf_event_attr *attr = &counter->attr; | 849 | struct perf_event_attr *attr = &counter->attr; |
850 | struct xyarray *group_fd = NULL; | ||
851 | |||
852 | if (group && counter != first) | ||
853 | group_fd = first->fd; | ||
841 | 854 | ||
842 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 855 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
843 | 856 | ||
@@ -858,14 +871,23 @@ static void start_counters(struct perf_evlist *evlist) | |||
858 | attr->mmap = 1; | 871 | attr->mmap = 1; |
859 | attr->comm = 1; | 872 | attr->comm = 1; |
860 | attr->inherit = inherit; | 873 | attr->inherit = inherit; |
874 | retry_sample_id: | ||
875 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | ||
861 | try_again: | 876 | try_again: |
862 | if (perf_evsel__open(counter, top.evlist->cpus, | 877 | if (perf_evsel__open(counter, top.evlist->cpus, |
863 | top.evlist->threads, group) < 0) { | 878 | top.evlist->threads, group, |
879 | group_fd) < 0) { | ||
864 | int err = errno; | 880 | int err = errno; |
865 | 881 | ||
866 | if (err == EPERM || err == EACCES) { | 882 | if (err == EPERM || err == EACCES) { |
867 | ui__warning_paranoid(); | 883 | ui__error_paranoid(); |
868 | goto out_err; | 884 | goto out_err; |
885 | } else if (err == EINVAL && sample_id_all_avail) { | ||
886 | /* | ||
887 | * Old kernel, no attr->sample_id_type_all field | ||
888 | */ | ||
889 | sample_id_all_avail = false; | ||
890 | goto retry_sample_id; | ||
869 | } | 891 | } |
870 | /* | 892 | /* |
871 | * If it's cycles then fall back to hrtimer | 893 | * If it's cycles then fall back to hrtimer |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index bc8f4773d4d8..119e996035c8 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -310,9 +310,12 @@ fallback: | |||
310 | } | 310 | } |
311 | err = -ENOENT; | 311 | err = -ENOENT; |
312 | dso->annotate_warned = 1; | 312 | dso->annotate_warned = 1; |
313 | pr_err("Can't annotate %s: No vmlinux file%s was found in the " | 313 | pr_err("Can't annotate %s:\n\n" |
314 | "path.\nPlease use 'perf buildid-cache -av vmlinux' or " | 314 | "No vmlinux file%s\nwas found in the path.\n\n" |
315 | "--vmlinux vmlinux.\n", | 315 | "Please use:\n\n" |
316 | " perf buildid-cache -av vmlinux\n\n" | ||
317 | "or:\n\n" | ||
318 | " --vmlinux vmlinux", | ||
316 | sym->name, build_id_msg ?: ""); | 319 | sym->name, build_id_msg ?: ""); |
317 | goto out_free_filename; | 320 | goto out_free_filename; |
318 | } | 321 | } |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 155749d74350..26817daa2961 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -47,19 +47,20 @@ int dump_printf(const char *fmt, ...) | |||
47 | } | 47 | } |
48 | 48 | ||
49 | #ifdef NO_NEWT_SUPPORT | 49 | #ifdef NO_NEWT_SUPPORT |
50 | void ui__warning(const char *format, ...) | 50 | int ui__warning(const char *format, ...) |
51 | { | 51 | { |
52 | va_list args; | 52 | va_list args; |
53 | 53 | ||
54 | va_start(args, format); | 54 | va_start(args, format); |
55 | vfprintf(stderr, format, args); | 55 | vfprintf(stderr, format, args); |
56 | va_end(args); | 56 | va_end(args); |
57 | return 0; | ||
57 | } | 58 | } |
58 | #endif | 59 | #endif |
59 | 60 | ||
60 | void ui__warning_paranoid(void) | 61 | int ui__error_paranoid(void) |
61 | { | 62 | { |
62 | ui__warning("Permission error - are you root?\n" | 63 | return ui__error("Permission error - are you root?\n" |
63 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" | 64 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" |
64 | " -1 - Not paranoid at all\n" | 65 | " -1 - Not paranoid at all\n" |
65 | " 0 - Disallow raw tracepoint access for unpriv\n" | 66 | " 0 - Disallow raw tracepoint access for unpriv\n" |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index fd53db47e3de..f2ce88d04f54 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -19,23 +19,18 @@ static inline int ui_helpline__show_help(const char *format __used, va_list ap _ | |||
19 | return 0; | 19 | return 0; |
20 | } | 20 | } |
21 | 21 | ||
22 | static inline struct ui_progress *ui_progress__new(const char *title __used, | 22 | static inline void ui_progress__update(u64 curr __used, u64 total __used, |
23 | u64 total __used) | 23 | const char *title __used) {} |
24 | { | ||
25 | return (struct ui_progress *)1; | ||
26 | } | ||
27 | |||
28 | static inline void ui_progress__update(struct ui_progress *self __used, | ||
29 | u64 curr __used) {} | ||
30 | 24 | ||
31 | static inline void ui_progress__delete(struct ui_progress *self __used) {} | 25 | #define ui__error(format, arg...) ui__warning(format, ##arg) |
32 | #else | 26 | #else |
33 | extern char ui_helpline__last_msg[]; | 27 | extern char ui_helpline__last_msg[]; |
34 | int ui_helpline__show_help(const char *format, va_list ap); | 28 | int ui_helpline__show_help(const char *format, va_list ap); |
35 | #include "ui/progress.h" | 29 | #include "ui/progress.h" |
30 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | ||
36 | #endif | 31 | #endif |
37 | 32 | ||
38 | void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 33 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
39 | void ui__warning_paranoid(void); | 34 | int ui__error_paranoid(void); |
40 | 35 | ||
41 | #endif /* __PERF_DEBUG_H */ | 36 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 2f6bc89027da..fbb4b4ab9cc6 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -539,3 +539,33 @@ void perf_evlist__set_selected(struct perf_evlist *evlist, | |||
539 | { | 539 | { |
540 | evlist->selected = evsel; | 540 | evlist->selected = evsel; |
541 | } | 541 | } |
542 | |||
543 | int perf_evlist__open(struct perf_evlist *evlist, bool group) | ||
544 | { | ||
545 | struct perf_evsel *evsel, *first; | ||
546 | int err, ncpus, nthreads; | ||
547 | |||
548 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
549 | |||
550 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
551 | struct xyarray *group_fd = NULL; | ||
552 | |||
553 | if (group && evsel != first) | ||
554 | group_fd = first->fd; | ||
555 | |||
556 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads, | ||
557 | group, group_fd); | ||
558 | if (err < 0) | ||
559 | goto out_err; | ||
560 | } | ||
561 | |||
562 | return 0; | ||
563 | out_err: | ||
564 | ncpus = evlist->cpus ? evlist->cpus->nr : 1; | ||
565 | nthreads = evlist->threads ? evlist->threads->nr : 1; | ||
566 | |||
567 | list_for_each_entry_reverse(evsel, &evlist->entries, node) | ||
568 | perf_evsel__close(evsel, ncpus, nthreads); | ||
569 | |||
570 | return err; | ||
571 | } | ||
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 6be71fc57794..1779ffef7828 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -50,6 +50,8 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); | |||
50 | 50 | ||
51 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); | 51 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); |
52 | 52 | ||
53 | int perf_evlist__open(struct perf_evlist *evlist, bool group); | ||
54 | |||
53 | int perf_evlist__alloc_mmap(struct perf_evlist *evlist); | 55 | int perf_evlist__alloc_mmap(struct perf_evlist *evlist); |
54 | int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); | 56 | int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); |
55 | void perf_evlist__munmap(struct perf_evlist *evlist); | 57 | void perf_evlist__munmap(struct perf_evlist *evlist); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index b46f6e4bff3c..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..33c17a2b2a81 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" |
@@ -388,7 +388,7 @@ static int write_event_desc(int fd, struct perf_header *h __used, | |||
388 | /* | 388 | /* |
389 | * write event string as passed on cmdline | 389 | * write event string as passed on cmdline |
390 | */ | 390 | */ |
391 | ret = do_write_string(fd, attr->name); | 391 | ret = do_write_string(fd, event_name(attr)); |
392 | if (ret < 0) | 392 | if (ret < 0) |
393 | return ret; | 393 | return ret; |
394 | /* | 394 | /* |
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_ */ |
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 4b05b445969e..310d3dd5e547 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c | |||
@@ -162,19 +162,21 @@ void print_header(void) | |||
162 | 162 | ||
163 | void dump_cnt(struct counters *cnt) | 163 | void dump_cnt(struct counters *cnt) |
164 | { | 164 | { |
165 | fprintf(stderr, "package: %d ", cnt->pkg); | 165 | if (!cnt) |
166 | fprintf(stderr, "core:: %d ", cnt->core); | 166 | return; |
167 | fprintf(stderr, "CPU: %d ", cnt->cpu); | 167 | if (cnt->pkg) fprintf(stderr, "package: %d ", cnt->pkg); |
168 | fprintf(stderr, "TSC: %016llX\n", cnt->tsc); | 168 | if (cnt->core) fprintf(stderr, "core:: %d ", cnt->core); |
169 | fprintf(stderr, "c3: %016llX\n", cnt->c3); | 169 | if (cnt->cpu) fprintf(stderr, "CPU: %d ", cnt->cpu); |
170 | fprintf(stderr, "c6: %016llX\n", cnt->c6); | 170 | if (cnt->tsc) fprintf(stderr, "TSC: %016llX\n", cnt->tsc); |
171 | fprintf(stderr, "c7: %016llX\n", cnt->c7); | 171 | if (cnt->c3) fprintf(stderr, "c3: %016llX\n", cnt->c3); |
172 | fprintf(stderr, "aperf: %016llX\n", cnt->aperf); | 172 | if (cnt->c6) fprintf(stderr, "c6: %016llX\n", cnt->c6); |
173 | fprintf(stderr, "pc2: %016llX\n", cnt->pc2); | 173 | if (cnt->c7) fprintf(stderr, "c7: %016llX\n", cnt->c7); |
174 | fprintf(stderr, "pc3: %016llX\n", cnt->pc3); | 174 | if (cnt->aperf) fprintf(stderr, "aperf: %016llX\n", cnt->aperf); |
175 | fprintf(stderr, "pc6: %016llX\n", cnt->pc6); | 175 | if (cnt->pc2) fprintf(stderr, "pc2: %016llX\n", cnt->pc2); |
176 | fprintf(stderr, "pc7: %016llX\n", cnt->pc7); | 176 | if (cnt->pc3) fprintf(stderr, "pc3: %016llX\n", cnt->pc3); |
177 | fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr); | 177 | if (cnt->pc6) fprintf(stderr, "pc6: %016llX\n", cnt->pc6); |
178 | if (cnt->pc7) fprintf(stderr, "pc7: %016llX\n", cnt->pc7); | ||
179 | if (cnt->extra_msr) fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr); | ||
178 | } | 180 | } |
179 | 181 | ||
180 | void dump_list(struct counters *cnt) | 182 | void dump_list(struct counters *cnt) |
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 8d02ccb10c59..8b4c2535b266 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl | |||
@@ -42,6 +42,7 @@ $default{"BISECT_MANUAL"} = 0; | |||
42 | $default{"BISECT_SKIP"} = 1; | 42 | $default{"BISECT_SKIP"} = 1; |
43 | $default{"SUCCESS_LINE"} = "login:"; | 43 | $default{"SUCCESS_LINE"} = "login:"; |
44 | $default{"DETECT_TRIPLE_FAULT"} = 1; | 44 | $default{"DETECT_TRIPLE_FAULT"} = 1; |
45 | $default{"NO_INSTALL"} = 0; | ||
45 | $default{"BOOTED_TIMEOUT"} = 1; | 46 | $default{"BOOTED_TIMEOUT"} = 1; |
46 | $default{"DIE_ON_FAILURE"} = 1; | 47 | $default{"DIE_ON_FAILURE"} = 1; |
47 | $default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND"; | 48 | $default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND"; |
@@ -84,6 +85,7 @@ my $grub_number; | |||
84 | my $target; | 85 | my $target; |
85 | my $make; | 86 | my $make; |
86 | my $post_install; | 87 | my $post_install; |
88 | my $no_install; | ||
87 | my $noclean; | 89 | my $noclean; |
88 | my $minconfig; | 90 | my $minconfig; |
89 | my $start_minconfig; | 91 | my $start_minconfig; |
@@ -115,6 +117,7 @@ my $timeout; | |||
115 | my $booted_timeout; | 117 | my $booted_timeout; |
116 | my $detect_triplefault; | 118 | my $detect_triplefault; |
117 | my $console; | 119 | my $console; |
120 | my $reboot_success_line; | ||
118 | my $success_line; | 121 | my $success_line; |
119 | my $stop_after_success; | 122 | my $stop_after_success; |
120 | my $stop_after_failure; | 123 | my $stop_after_failure; |
@@ -130,6 +133,12 @@ my %config_help; | |||
130 | my %variable; | 133 | my %variable; |
131 | my %force_config; | 134 | my %force_config; |
132 | 135 | ||
136 | # do not force reboots on config problems | ||
137 | my $no_reboot = 1; | ||
138 | |||
139 | # default variables that can be used | ||
140 | chomp ($variable{"PWD"} = `pwd`); | ||
141 | |||
133 | $config_help{"MACHINE"} = << "EOF" | 142 | $config_help{"MACHINE"} = << "EOF" |
134 | The machine hostname that you will test. | 143 | The machine hostname that you will test. |
135 | EOF | 144 | EOF |
@@ -241,6 +250,7 @@ sub read_yn { | |||
241 | 250 | ||
242 | sub get_ktest_config { | 251 | sub get_ktest_config { |
243 | my ($config) = @_; | 252 | my ($config) = @_; |
253 | my $ans; | ||
244 | 254 | ||
245 | return if (defined($opt{$config})); | 255 | return if (defined($opt{$config})); |
246 | 256 | ||
@@ -254,16 +264,17 @@ sub get_ktest_config { | |||
254 | if (defined($default{$config})) { | 264 | if (defined($default{$config})) { |
255 | print "\[$default{$config}\] "; | 265 | print "\[$default{$config}\] "; |
256 | } | 266 | } |
257 | $entered_configs{$config} = <STDIN>; | 267 | $ans = <STDIN>; |
258 | $entered_configs{$config} =~ s/^\s*(.*\S)\s*$/$1/; | 268 | $ans =~ s/^\s*(.*\S)\s*$/$1/; |
259 | if ($entered_configs{$config} =~ /^\s*$/) { | 269 | if ($ans =~ /^\s*$/) { |
260 | if ($default{$config}) { | 270 | if ($default{$config}) { |
261 | $entered_configs{$config} = $default{$config}; | 271 | $ans = $default{$config}; |
262 | } else { | 272 | } else { |
263 | print "Your answer can not be blank\n"; | 273 | print "Your answer can not be blank\n"; |
264 | next; | 274 | next; |
265 | } | 275 | } |
266 | } | 276 | } |
277 | $entered_configs{$config} = process_variables($ans); | ||
267 | last; | 278 | last; |
268 | } | 279 | } |
269 | } | 280 | } |
@@ -298,7 +309,7 @@ sub get_ktest_configs { | |||
298 | } | 309 | } |
299 | 310 | ||
300 | sub process_variables { | 311 | sub process_variables { |
301 | my ($value) = @_; | 312 | my ($value, $remove_undef) = @_; |
302 | my $retval = ""; | 313 | my $retval = ""; |
303 | 314 | ||
304 | # We want to check for '\', and it is just easier | 315 | # We want to check for '\', and it is just easier |
@@ -316,6 +327,10 @@ sub process_variables { | |||
316 | $retval = "$retval$begin"; | 327 | $retval = "$retval$begin"; |
317 | if (defined($variable{$var})) { | 328 | if (defined($variable{$var})) { |
318 | $retval = "$retval$variable{$var}"; | 329 | $retval = "$retval$variable{$var}"; |
330 | } elsif (defined($remove_undef) && $remove_undef) { | ||
331 | # for if statements, any variable that is not defined, | ||
332 | # we simple convert to 0 | ||
333 | $retval = "${retval}0"; | ||
319 | } else { | 334 | } else { |
320 | # put back the origin piece. | 335 | # put back the origin piece. |
321 | $retval = "$retval\$\{$var\}"; | 336 | $retval = "$retval\$\{$var\}"; |
@@ -331,10 +346,17 @@ sub process_variables { | |||
331 | } | 346 | } |
332 | 347 | ||
333 | sub set_value { | 348 | sub set_value { |
334 | my ($lvalue, $rvalue) = @_; | 349 | my ($lvalue, $rvalue, $override, $overrides, $name) = @_; |
335 | 350 | ||
336 | if (defined($opt{$lvalue})) { | 351 | if (defined($opt{$lvalue})) { |
337 | die "Error: Option $lvalue defined more than once!\n"; | 352 | if (!$override || defined(${$overrides}{$lvalue})) { |
353 | my $extra = ""; | ||
354 | if ($override) { | ||
355 | $extra = "In the same override section!\n"; | ||
356 | } | ||
357 | die "$name: $.: Option $lvalue defined more than once!\n$extra"; | ||
358 | } | ||
359 | ${$overrides}{$lvalue} = $rvalue; | ||
338 | } | 360 | } |
339 | if ($rvalue =~ /^\s*$/) { | 361 | if ($rvalue =~ /^\s*$/) { |
340 | delete $opt{$lvalue}; | 362 | delete $opt{$lvalue}; |
@@ -355,86 +377,274 @@ sub set_variable { | |||
355 | } | 377 | } |
356 | } | 378 | } |
357 | 379 | ||
358 | sub read_config { | 380 | sub process_compare { |
359 | my ($config) = @_; | 381 | my ($lval, $cmp, $rval) = @_; |
382 | |||
383 | # remove whitespace | ||
384 | |||
385 | $lval =~ s/^\s*//; | ||
386 | $lval =~ s/\s*$//; | ||
387 | |||
388 | $rval =~ s/^\s*//; | ||
389 | $rval =~ s/\s*$//; | ||
390 | |||
391 | if ($cmp eq "==") { | ||
392 | return $lval eq $rval; | ||
393 | } elsif ($cmp eq "!=") { | ||
394 | return $lval ne $rval; | ||
395 | } | ||
396 | |||
397 | my $statement = "$lval $cmp $rval"; | ||
398 | my $ret = eval $statement; | ||
399 | |||
400 | # $@ stores error of eval | ||
401 | if ($@) { | ||
402 | return -1; | ||
403 | } | ||
404 | |||
405 | return $ret; | ||
406 | } | ||
407 | |||
408 | sub value_defined { | ||
409 | my ($val) = @_; | ||
410 | |||
411 | return defined($variable{$2}) || | ||
412 | defined($opt{$2}); | ||
413 | } | ||
414 | |||
415 | my $d = 0; | ||
416 | sub process_expression { | ||
417 | my ($name, $val) = @_; | ||
418 | |||
419 | my $c = $d++; | ||
420 | |||
421 | while ($val =~ s/\(([^\(]*?)\)/\&\&\&\&VAL\&\&\&\&/) { | ||
422 | my $express = $1; | ||
423 | |||
424 | if (process_expression($name, $express)) { | ||
425 | $val =~ s/\&\&\&\&VAL\&\&\&\&/ 1 /; | ||
426 | } else { | ||
427 | $val =~ s/\&\&\&\&VAL\&\&\&\&/ 0 /; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | $d--; | ||
432 | my $OR = "\\|\\|"; | ||
433 | my $AND = "\\&\\&"; | ||
434 | |||
435 | while ($val =~ s/^(.*?)($OR|$AND)//) { | ||
436 | my $express = $1; | ||
437 | my $op = $2; | ||
438 | |||
439 | if (process_expression($name, $express)) { | ||
440 | if ($op eq "||") { | ||
441 | return 1; | ||
442 | } | ||
443 | } else { | ||
444 | if ($op eq "&&") { | ||
445 | return 0; | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | |||
450 | if ($val =~ /(.*)(==|\!=|>=|<=|>|<)(.*)/) { | ||
451 | my $ret = process_compare($1, $2, $3); | ||
452 | if ($ret < 0) { | ||
453 | die "$name: $.: Unable to process comparison\n"; | ||
454 | } | ||
455 | return $ret; | ||
456 | } | ||
457 | |||
458 | if ($val =~ /^\s*(NOT\s*)?DEFINED\s+(\S+)\s*$/) { | ||
459 | if (defined $1) { | ||
460 | return !value_defined($2); | ||
461 | } else { | ||
462 | return value_defined($2); | ||
463 | } | ||
464 | } | ||
465 | |||
466 | if ($val =~ /^\s*0\s*$/) { | ||
467 | return 0; | ||
468 | } elsif ($val =~ /^\s*\d+\s*$/) { | ||
469 | return 1; | ||
470 | } | ||
471 | |||
472 | die ("$name: $.: Undefined content $val in if statement\n"); | ||
473 | } | ||
474 | |||
475 | sub process_if { | ||
476 | my ($name, $value) = @_; | ||
360 | 477 | ||
361 | open(IN, $config) || die "can't read file $config"; | 478 | # Convert variables and replace undefined ones with 0 |
479 | my $val = process_variables($value, 1); | ||
480 | my $ret = process_expression $name, $val; | ||
481 | |||
482 | return $ret; | ||
483 | } | ||
484 | |||
485 | sub __read_config { | ||
486 | my ($config, $current_test_num) = @_; | ||
487 | |||
488 | my $in; | ||
489 | open($in, $config) || die "can't read file $config"; | ||
362 | 490 | ||
363 | my $name = $config; | 491 | my $name = $config; |
364 | $name =~ s,.*/(.*),$1,; | 492 | $name =~ s,.*/(.*),$1,; |
365 | 493 | ||
366 | my $test_num = 0; | 494 | my $test_num = $$current_test_num; |
367 | my $default = 1; | 495 | my $default = 1; |
368 | my $repeat = 1; | 496 | my $repeat = 1; |
369 | my $num_tests_set = 0; | 497 | my $num_tests_set = 0; |
370 | my $skip = 0; | 498 | my $skip = 0; |
371 | my $rest; | 499 | my $rest; |
500 | my $line; | ||
372 | my $test_case = 0; | 501 | my $test_case = 0; |
502 | my $if = 0; | ||
503 | my $if_set = 0; | ||
504 | my $override = 0; | ||
373 | 505 | ||
374 | while (<IN>) { | 506 | my %overrides; |
507 | |||
508 | while (<$in>) { | ||
375 | 509 | ||
376 | # ignore blank lines and comments | 510 | # ignore blank lines and comments |
377 | next if (/^\s*$/ || /\s*\#/); | 511 | next if (/^\s*$/ || /\s*\#/); |
378 | 512 | ||
379 | if (/^\s*TEST_START(.*)/) { | 513 | if (/^\s*(TEST_START|DEFAULTS)\b(.*)/) { |
380 | 514 | ||
381 | $rest = $1; | 515 | my $type = $1; |
516 | $rest = $2; | ||
517 | $line = $2; | ||
382 | 518 | ||
383 | if ($num_tests_set) { | 519 | my $old_test_num; |
384 | die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n"; | 520 | my $old_repeat; |
385 | } | 521 | $override = 0; |
522 | |||
523 | if ($type eq "TEST_START") { | ||
386 | 524 | ||
387 | my $old_test_num = $test_num; | 525 | if ($num_tests_set) { |
388 | my $old_repeat = $repeat; | 526 | die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n"; |
527 | } | ||
389 | 528 | ||
390 | $test_num += $repeat; | 529 | $old_test_num = $test_num; |
391 | $default = 0; | 530 | $old_repeat = $repeat; |
392 | $repeat = 1; | ||
393 | 531 | ||
394 | if ($rest =~ /\s+SKIP(.*)/) { | 532 | $test_num += $repeat; |
395 | $rest = $1; | 533 | $default = 0; |
534 | $repeat = 1; | ||
535 | } else { | ||
536 | $default = 1; | ||
537 | } | ||
538 | |||
539 | # If SKIP is anywhere in the line, the command will be skipped | ||
540 | if ($rest =~ s/\s+SKIP\b//) { | ||
396 | $skip = 1; | 541 | $skip = 1; |
397 | } else { | 542 | } else { |
398 | $test_case = 1; | 543 | $test_case = 1; |
399 | $skip = 0; | 544 | $skip = 0; |
400 | } | 545 | } |
401 | 546 | ||
402 | if ($rest =~ /\s+ITERATE\s+(\d+)(.*)$/) { | 547 | if ($rest =~ s/\sELSE\b//) { |
403 | $repeat = $1; | 548 | if (!$if) { |
404 | $rest = $2; | 549 | die "$name: $.: ELSE found with out matching IF section\n$_"; |
405 | $repeat_tests{"$test_num"} = $repeat; | 550 | } |
551 | $if = 0; | ||
552 | |||
553 | if ($if_set) { | ||
554 | $skip = 1; | ||
555 | } else { | ||
556 | $skip = 0; | ||
557 | } | ||
406 | } | 558 | } |
407 | 559 | ||
408 | if ($rest =~ /\s+SKIP(.*)/) { | 560 | if ($rest =~ s/\sIF\s+(.*)//) { |
409 | $rest = $1; | 561 | if (process_if($name, $1)) { |
410 | $skip = 1; | 562 | $if_set = 1; |
563 | } else { | ||
564 | $skip = 1; | ||
565 | } | ||
566 | $if = 1; | ||
567 | } else { | ||
568 | $if = 0; | ||
569 | $if_set = 0; | ||
411 | } | 570 | } |
412 | 571 | ||
413 | if ($rest !~ /^\s*$/) { | 572 | if (!$skip) { |
414 | die "$name: $.: Gargbage found after TEST_START\n$_"; | 573 | if ($type eq "TEST_START") { |
574 | if ($rest =~ s/\s+ITERATE\s+(\d+)//) { | ||
575 | $repeat = $1; | ||
576 | $repeat_tests{"$test_num"} = $repeat; | ||
577 | } | ||
578 | } elsif ($rest =~ s/\sOVERRIDE\b//) { | ||
579 | # DEFAULT only | ||
580 | $override = 1; | ||
581 | # Clear previous overrides | ||
582 | %overrides = (); | ||
583 | } | ||
584 | } | ||
585 | |||
586 | if (!$skip && $rest !~ /^\s*$/) { | ||
587 | die "$name: $.: Gargbage found after $type\n$_"; | ||
415 | } | 588 | } |
416 | 589 | ||
417 | if ($skip) { | 590 | if ($skip && $type eq "TEST_START") { |
418 | $test_num = $old_test_num; | 591 | $test_num = $old_test_num; |
419 | $repeat = $old_repeat; | 592 | $repeat = $old_repeat; |
420 | } | 593 | } |
421 | 594 | ||
422 | } elsif (/^\s*DEFAULTS(.*)$/) { | 595 | } elsif (/^\s*ELSE\b(.*)$/) { |
423 | $default = 1; | 596 | if (!$if) { |
424 | 597 | die "$name: $.: ELSE found with out matching IF section\n$_"; | |
598 | } | ||
425 | $rest = $1; | 599 | $rest = $1; |
426 | 600 | if ($if_set) { | |
427 | if ($rest =~ /\s+SKIP(.*)/) { | ||
428 | $rest = $1; | ||
429 | $skip = 1; | 601 | $skip = 1; |
602 | $rest = ""; | ||
430 | } else { | 603 | } else { |
431 | $skip = 0; | 604 | $skip = 0; |
605 | |||
606 | if ($rest =~ /\sIF\s+(.*)/) { | ||
607 | # May be a ELSE IF section. | ||
608 | if (!process_if($name, $1)) { | ||
609 | $skip = 1; | ||
610 | } | ||
611 | $rest = ""; | ||
612 | } else { | ||
613 | $if = 0; | ||
614 | } | ||
432 | } | 615 | } |
433 | 616 | ||
434 | if ($rest !~ /^\s*$/) { | 617 | if ($rest !~ /^\s*$/) { |
435 | die "$name: $.: Gargbage found after DEFAULTS\n$_"; | 618 | die "$name: $.: Gargbage found after DEFAULTS\n$_"; |
436 | } | 619 | } |
437 | 620 | ||
621 | } elsif (/^\s*INCLUDE\s+(\S+)/) { | ||
622 | |||
623 | next if ($skip); | ||
624 | |||
625 | if (!$default) { | ||
626 | die "$name: $.: INCLUDE can only be done in default sections\n$_"; | ||
627 | } | ||
628 | |||
629 | my $file = process_variables($1); | ||
630 | |||
631 | if ($file !~ m,^/,) { | ||
632 | # check the path of the config file first | ||
633 | if ($config =~ m,(.*)/,) { | ||
634 | if (-f "$1/$file") { | ||
635 | $file = "$1/$file"; | ||
636 | } | ||
637 | } | ||
638 | } | ||
639 | |||
640 | if ( ! -r $file ) { | ||
641 | die "$name: $.: Can't read file $file\n$_"; | ||
642 | } | ||
643 | |||
644 | if (__read_config($file, \$test_num)) { | ||
645 | $test_case = 1; | ||
646 | } | ||
647 | |||
438 | } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) { | 648 | } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) { |
439 | 649 | ||
440 | next if ($skip); | 650 | next if ($skip); |
@@ -460,10 +670,10 @@ sub read_config { | |||
460 | } | 670 | } |
461 | 671 | ||
462 | if ($default || $lvalue =~ /\[\d+\]$/) { | 672 | if ($default || $lvalue =~ /\[\d+\]$/) { |
463 | set_value($lvalue, $rvalue); | 673 | set_value($lvalue, $rvalue, $override, \%overrides, $name); |
464 | } else { | 674 | } else { |
465 | my $val = "$lvalue\[$test_num\]"; | 675 | my $val = "$lvalue\[$test_num\]"; |
466 | set_value($val, $rvalue); | 676 | set_value($val, $rvalue, $override, \%overrides, $name); |
467 | 677 | ||
468 | if ($repeat > 1) { | 678 | if ($repeat > 1) { |
469 | $repeats{$val} = $repeat; | 679 | $repeats{$val} = $repeat; |
@@ -490,13 +700,26 @@ sub read_config { | |||
490 | } | 700 | } |
491 | } | 701 | } |
492 | 702 | ||
493 | close(IN); | ||
494 | |||
495 | if ($test_num) { | 703 | if ($test_num) { |
496 | $test_num += $repeat - 1; | 704 | $test_num += $repeat - 1; |
497 | $opt{"NUM_TESTS"} = $test_num; | 705 | $opt{"NUM_TESTS"} = $test_num; |
498 | } | 706 | } |
499 | 707 | ||
708 | close($in); | ||
709 | |||
710 | $$current_test_num = $test_num; | ||
711 | |||
712 | return $test_case; | ||
713 | } | ||
714 | |||
715 | sub read_config { | ||
716 | my ($config) = @_; | ||
717 | |||
718 | my $test_case; | ||
719 | my $test_num = 0; | ||
720 | |||
721 | $test_case = __read_config $config, \$test_num; | ||
722 | |||
500 | # make sure we have all mandatory configs | 723 | # make sure we have all mandatory configs |
501 | get_ktest_configs; | 724 | get_ktest_configs; |
502 | 725 | ||
@@ -524,6 +747,18 @@ sub __eval_option { | |||
524 | # Add space to evaluate the character before $ | 747 | # Add space to evaluate the character before $ |
525 | $option = " $option"; | 748 | $option = " $option"; |
526 | my $retval = ""; | 749 | my $retval = ""; |
750 | my $repeated = 0; | ||
751 | my $parent = 0; | ||
752 | |||
753 | foreach my $test (keys %repeat_tests) { | ||
754 | if ($i >= $test && | ||
755 | $i < $test + $repeat_tests{$test}) { | ||
756 | |||
757 | $repeated = 1; | ||
758 | $parent = $test; | ||
759 | last; | ||
760 | } | ||
761 | } | ||
527 | 762 | ||
528 | while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { | 763 | while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { |
529 | my $start = $1; | 764 | my $start = $1; |
@@ -537,10 +772,14 @@ sub __eval_option { | |||
537 | # otherwise see if the default OPT (without [$i]) exists. | 772 | # otherwise see if the default OPT (without [$i]) exists. |
538 | 773 | ||
539 | my $o = "$var\[$i\]"; | 774 | my $o = "$var\[$i\]"; |
775 | my $parento = "$var\[$parent\]"; | ||
540 | 776 | ||
541 | if (defined($opt{$o})) { | 777 | if (defined($opt{$o})) { |
542 | $o = $opt{$o}; | 778 | $o = $opt{$o}; |
543 | $retval = "$retval$o"; | 779 | $retval = "$retval$o"; |
780 | } elsif ($repeated && defined($opt{$parento})) { | ||
781 | $o = $opt{$parento}; | ||
782 | $retval = "$retval$o"; | ||
544 | } elsif (defined($opt{$var})) { | 783 | } elsif (defined($opt{$var})) { |
545 | $o = $opt{$var}; | 784 | $o = $opt{$var}; |
546 | $retval = "$retval$o"; | 785 | $retval = "$retval$o"; |
@@ -603,8 +842,20 @@ sub doprint { | |||
603 | } | 842 | } |
604 | 843 | ||
605 | sub run_command; | 844 | sub run_command; |
845 | sub start_monitor; | ||
846 | sub end_monitor; | ||
847 | sub wait_for_monitor; | ||
606 | 848 | ||
607 | sub reboot { | 849 | sub reboot { |
850 | my ($time) = @_; | ||
851 | |||
852 | if (defined($time)) { | ||
853 | start_monitor; | ||
854 | # flush out current monitor | ||
855 | # May contain the reboot success line | ||
856 | wait_for_monitor 1; | ||
857 | } | ||
858 | |||
608 | # try to reboot normally | 859 | # try to reboot normally |
609 | if (run_command $reboot) { | 860 | if (run_command $reboot) { |
610 | if (defined($powercycle_after_reboot)) { | 861 | if (defined($powercycle_after_reboot)) { |
@@ -615,12 +866,17 @@ sub reboot { | |||
615 | # nope? power cycle it. | 866 | # nope? power cycle it. |
616 | run_command "$power_cycle"; | 867 | run_command "$power_cycle"; |
617 | } | 868 | } |
869 | |||
870 | if (defined($time)) { | ||
871 | wait_for_monitor($time, $reboot_success_line); | ||
872 | end_monitor; | ||
873 | } | ||
618 | } | 874 | } |
619 | 875 | ||
620 | sub do_not_reboot { | 876 | sub do_not_reboot { |
621 | my $i = $iteration; | 877 | my $i = $iteration; |
622 | 878 | ||
623 | return $test_type eq "build" || | 879 | return $test_type eq "build" || $no_reboot || |
624 | ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") || | 880 | ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") || |
625 | ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build"); | 881 | ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build"); |
626 | } | 882 | } |
@@ -693,16 +949,29 @@ sub end_monitor { | |||
693 | } | 949 | } |
694 | 950 | ||
695 | sub wait_for_monitor { | 951 | sub wait_for_monitor { |
696 | my ($time) = @_; | 952 | my ($time, $stop) = @_; |
953 | my $full_line = ""; | ||
697 | my $line; | 954 | my $line; |
955 | my $booted = 0; | ||
698 | 956 | ||
699 | doprint "** Wait for monitor to settle down **\n"; | 957 | doprint "** Wait for monitor to settle down **\n"; |
700 | 958 | ||
701 | # read the monitor and wait for the system to calm down | 959 | # read the monitor and wait for the system to calm down |
702 | do { | 960 | while (!$booted) { |
703 | $line = wait_for_input($monitor_fp, $time); | 961 | $line = wait_for_input($monitor_fp, $time); |
704 | print "$line" if (defined($line)); | 962 | last if (!defined($line)); |
705 | } while (defined($line)); | 963 | print "$line"; |
964 | $full_line .= $line; | ||
965 | |||
966 | if (defined($stop) && $full_line =~ /$stop/) { | ||
967 | doprint "wait for monitor detected $stop\n"; | ||
968 | $booted = 1; | ||
969 | } | ||
970 | |||
971 | if ($line =~ /\n/) { | ||
972 | $full_line = ""; | ||
973 | } | ||
974 | } | ||
706 | print "** Monitor flushed **\n"; | 975 | print "** Monitor flushed **\n"; |
707 | } | 976 | } |
708 | 977 | ||
@@ -719,10 +988,7 @@ sub fail { | |||
719 | # no need to reboot for just building. | 988 | # no need to reboot for just building. |
720 | if (!do_not_reboot) { | 989 | if (!do_not_reboot) { |
721 | doprint "REBOOTING\n"; | 990 | doprint "REBOOTING\n"; |
722 | reboot; | 991 | reboot $sleep_time; |
723 | start_monitor; | ||
724 | wait_for_monitor $sleep_time; | ||
725 | end_monitor; | ||
726 | } | 992 | } |
727 | 993 | ||
728 | my $name = ""; | 994 | my $name = ""; |
@@ -854,9 +1120,12 @@ sub get_grub_index { | |||
854 | open(IN, "$ssh_grub |") | 1120 | open(IN, "$ssh_grub |") |
855 | or die "unable to get menu.lst"; | 1121 | or die "unable to get menu.lst"; |
856 | 1122 | ||
1123 | my $found = 0; | ||
1124 | |||
857 | while (<IN>) { | 1125 | while (<IN>) { |
858 | if (/^\s*title\s+$grub_menu\s*$/) { | 1126 | if (/^\s*title\s+$grub_menu\s*$/) { |
859 | $grub_number++; | 1127 | $grub_number++; |
1128 | $found = 1; | ||
860 | last; | 1129 | last; |
861 | } elsif (/^\s*title\s/) { | 1130 | } elsif (/^\s*title\s/) { |
862 | $grub_number++; | 1131 | $grub_number++; |
@@ -865,7 +1134,7 @@ sub get_grub_index { | |||
865 | close(IN); | 1134 | close(IN); |
866 | 1135 | ||
867 | die "Could not find '$grub_menu' in /boot/grub/menu on $machine" | 1136 | die "Could not find '$grub_menu' in /boot/grub/menu on $machine" |
868 | if ($grub_number < 0); | 1137 | if (!$found); |
869 | doprint "$grub_number\n"; | 1138 | doprint "$grub_number\n"; |
870 | } | 1139 | } |
871 | 1140 | ||
@@ -902,7 +1171,8 @@ sub wait_for_input | |||
902 | 1171 | ||
903 | sub reboot_to { | 1172 | sub reboot_to { |
904 | if ($reboot_type eq "grub") { | 1173 | if ($reboot_type eq "grub") { |
905 | run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch && reboot)'"; | 1174 | run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'"; |
1175 | reboot; | ||
906 | return; | 1176 | return; |
907 | } | 1177 | } |
908 | 1178 | ||
@@ -1083,6 +1353,8 @@ sub do_post_install { | |||
1083 | 1353 | ||
1084 | sub install { | 1354 | sub install { |
1085 | 1355 | ||
1356 | return if ($no_install); | ||
1357 | |||
1086 | run_scp "$outputdir/$build_target", "$target_image" or | 1358 | run_scp "$outputdir/$build_target", "$target_image" or |
1087 | dodie "failed to copy image"; | 1359 | dodie "failed to copy image"; |
1088 | 1360 | ||
@@ -1140,6 +1412,11 @@ sub get_version { | |||
1140 | } | 1412 | } |
1141 | 1413 | ||
1142 | sub start_monitor_and_boot { | 1414 | sub start_monitor_and_boot { |
1415 | # Make sure the stable kernel has finished booting | ||
1416 | start_monitor; | ||
1417 | wait_for_monitor 5; | ||
1418 | end_monitor; | ||
1419 | |||
1143 | get_grub_index; | 1420 | get_grub_index; |
1144 | get_version; | 1421 | get_version; |
1145 | install; | 1422 | install; |
@@ -1250,6 +1527,10 @@ sub build { | |||
1250 | 1527 | ||
1251 | unlink $buildlog; | 1528 | unlink $buildlog; |
1252 | 1529 | ||
1530 | # Failed builds should not reboot the target | ||
1531 | my $save_no_reboot = $no_reboot; | ||
1532 | $no_reboot = 1; | ||
1533 | |||
1253 | if (defined($pre_build)) { | 1534 | if (defined($pre_build)) { |
1254 | my $ret = run_command $pre_build; | 1535 | my $ret = run_command $pre_build; |
1255 | if (!$ret && defined($pre_build_die) && | 1536 | if (!$ret && defined($pre_build_die) && |
@@ -1272,15 +1553,15 @@ sub build { | |||
1272 | # allow for empty configs | 1553 | # allow for empty configs |
1273 | run_command "touch $output_config"; | 1554 | run_command "touch $output_config"; |
1274 | 1555 | ||
1275 | run_command "mv $output_config $outputdir/config_temp" or | 1556 | if (!$noclean) { |
1276 | dodie "moving .config"; | 1557 | run_command "mv $output_config $outputdir/config_temp" or |
1558 | dodie "moving .config"; | ||
1277 | 1559 | ||
1278 | if (!$noclean && !run_command "$make mrproper") { | 1560 | run_command "$make mrproper" or dodie "make mrproper"; |
1279 | dodie "make mrproper"; | ||
1280 | } | ||
1281 | 1561 | ||
1282 | run_command "mv $outputdir/config_temp $output_config" or | 1562 | run_command "mv $outputdir/config_temp $output_config" or |
1283 | dodie "moving config_temp"; | 1563 | dodie "moving config_temp"; |
1564 | } | ||
1284 | 1565 | ||
1285 | } elsif (!$noclean) { | 1566 | } elsif (!$noclean) { |
1286 | unlink "$output_config"; | 1567 | unlink "$output_config"; |
@@ -1318,10 +1599,15 @@ sub build { | |||
1318 | 1599 | ||
1319 | if (!$build_ret) { | 1600 | if (!$build_ret) { |
1320 | # bisect may need this to pass | 1601 | # bisect may need this to pass |
1321 | return 0 if ($in_bisect); | 1602 | if ($in_bisect) { |
1603 | $no_reboot = $save_no_reboot; | ||
1604 | return 0; | ||
1605 | } | ||
1322 | fail "failed build" and return 0; | 1606 | fail "failed build" and return 0; |
1323 | } | 1607 | } |
1324 | 1608 | ||
1609 | $no_reboot = $save_no_reboot; | ||
1610 | |||
1325 | return 1; | 1611 | return 1; |
1326 | } | 1612 | } |
1327 | 1613 | ||
@@ -1356,10 +1642,7 @@ sub success { | |||
1356 | 1642 | ||
1357 | if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) { | 1643 | if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) { |
1358 | doprint "Reboot and wait $sleep_time seconds\n"; | 1644 | doprint "Reboot and wait $sleep_time seconds\n"; |
1359 | reboot; | 1645 | reboot $sleep_time; |
1360 | start_monitor; | ||
1361 | wait_for_monitor $sleep_time; | ||
1362 | end_monitor; | ||
1363 | } | 1646 | } |
1364 | } | 1647 | } |
1365 | 1648 | ||
@@ -1500,10 +1783,7 @@ sub run_git_bisect { | |||
1500 | 1783 | ||
1501 | sub bisect_reboot { | 1784 | sub bisect_reboot { |
1502 | doprint "Reboot and sleep $bisect_sleep_time seconds\n"; | 1785 | doprint "Reboot and sleep $bisect_sleep_time seconds\n"; |
1503 | reboot; | 1786 | reboot $bisect_sleep_time; |
1504 | start_monitor; | ||
1505 | wait_for_monitor $bisect_sleep_time; | ||
1506 | end_monitor; | ||
1507 | } | 1787 | } |
1508 | 1788 | ||
1509 | # returns 1 on success, 0 on failure, -1 on skip | 1789 | # returns 1 on success, 0 on failure, -1 on skip |
@@ -2066,10 +2346,7 @@ sub config_bisect { | |||
2066 | 2346 | ||
2067 | sub patchcheck_reboot { | 2347 | sub patchcheck_reboot { |
2068 | doprint "Reboot and sleep $patchcheck_sleep_time seconds\n"; | 2348 | doprint "Reboot and sleep $patchcheck_sleep_time seconds\n"; |
2069 | reboot; | 2349 | reboot $patchcheck_sleep_time; |
2070 | start_monitor; | ||
2071 | wait_for_monitor $patchcheck_sleep_time; | ||
2072 | end_monitor; | ||
2073 | } | 2350 | } |
2074 | 2351 | ||
2075 | sub patchcheck { | 2352 | sub patchcheck { |
@@ -2178,12 +2455,31 @@ sub patchcheck { | |||
2178 | } | 2455 | } |
2179 | 2456 | ||
2180 | my %depends; | 2457 | my %depends; |
2458 | my %depcount; | ||
2181 | my $iflevel = 0; | 2459 | my $iflevel = 0; |
2182 | my @ifdeps; | 2460 | my @ifdeps; |
2183 | 2461 | ||
2184 | # prevent recursion | 2462 | # prevent recursion |
2185 | my %read_kconfigs; | 2463 | my %read_kconfigs; |
2186 | 2464 | ||
2465 | sub add_dep { | ||
2466 | # $config depends on $dep | ||
2467 | my ($config, $dep) = @_; | ||
2468 | |||
2469 | if (defined($depends{$config})) { | ||
2470 | $depends{$config} .= " " . $dep; | ||
2471 | } else { | ||
2472 | $depends{$config} = $dep; | ||
2473 | } | ||
2474 | |||
2475 | # record the number of configs depending on $dep | ||
2476 | if (defined $depcount{$dep}) { | ||
2477 | $depcount{$dep}++; | ||
2478 | } else { | ||
2479 | $depcount{$dep} = 1; | ||
2480 | } | ||
2481 | } | ||
2482 | |||
2187 | # taken from streamline_config.pl | 2483 | # taken from streamline_config.pl |
2188 | sub read_kconfig { | 2484 | sub read_kconfig { |
2189 | my ($kconfig) = @_; | 2485 | my ($kconfig) = @_; |
@@ -2230,30 +2526,19 @@ sub read_kconfig { | |||
2230 | $config = $2; | 2526 | $config = $2; |
2231 | 2527 | ||
2232 | for (my $i = 0; $i < $iflevel; $i++) { | 2528 | for (my $i = 0; $i < $iflevel; $i++) { |
2233 | if ($i) { | 2529 | add_dep $config, $ifdeps[$i]; |
2234 | $depends{$config} .= " " . $ifdeps[$i]; | ||
2235 | } else { | ||
2236 | $depends{$config} = $ifdeps[$i]; | ||
2237 | } | ||
2238 | $state = "DEP"; | ||
2239 | } | 2530 | } |
2240 | 2531 | ||
2241 | # collect the depends for the config | 2532 | # collect the depends for the config |
2242 | } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) { | 2533 | } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) { |
2243 | 2534 | ||
2244 | if (defined($depends{$1})) { | 2535 | add_dep $config, $1; |
2245 | $depends{$config} .= " " . $1; | ||
2246 | } else { | ||
2247 | $depends{$config} = $1; | ||
2248 | } | ||
2249 | 2536 | ||
2250 | # Get the configs that select this config | 2537 | # Get the configs that select this config |
2251 | } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) { | 2538 | } elsif ($state eq "NEW" && /^\s*select\s+(\S+)/) { |
2252 | if (defined($depends{$1})) { | 2539 | |
2253 | $depends{$1} .= " " . $config; | 2540 | # selected by depends on config |
2254 | } else { | 2541 | add_dep $1, $config; |
2255 | $depends{$1} = $config; | ||
2256 | } | ||
2257 | 2542 | ||
2258 | # Check for if statements | 2543 | # Check for if statements |
2259 | } elsif (/^if\s+(.*\S)\s*$/) { | 2544 | } elsif (/^if\s+(.*\S)\s*$/) { |
@@ -2365,11 +2650,18 @@ sub make_new_config { | |||
2365 | close OUT; | 2650 | close OUT; |
2366 | } | 2651 | } |
2367 | 2652 | ||
2653 | sub chomp_config { | ||
2654 | my ($config) = @_; | ||
2655 | |||
2656 | $config =~ s/CONFIG_//; | ||
2657 | |||
2658 | return $config; | ||
2659 | } | ||
2660 | |||
2368 | sub get_depends { | 2661 | sub get_depends { |
2369 | my ($dep) = @_; | 2662 | my ($dep) = @_; |
2370 | 2663 | ||
2371 | my $kconfig = $dep; | 2664 | my $kconfig = chomp_config $dep; |
2372 | $kconfig =~ s/CONFIG_//; | ||
2373 | 2665 | ||
2374 | $dep = $depends{"$kconfig"}; | 2666 | $dep = $depends{"$kconfig"}; |
2375 | 2667 | ||
@@ -2419,8 +2711,7 @@ sub test_this_config { | |||
2419 | return undef; | 2711 | return undef; |
2420 | } | 2712 | } |
2421 | 2713 | ||
2422 | my $kconfig = $config; | 2714 | my $kconfig = chomp_config $config; |
2423 | $kconfig =~ s/CONFIG_//; | ||
2424 | 2715 | ||
2425 | # Test dependencies first | 2716 | # Test dependencies first |
2426 | if (defined($depends{"$kconfig"})) { | 2717 | if (defined($depends{"$kconfig"})) { |
@@ -2510,6 +2801,14 @@ sub make_min_config { | |||
2510 | 2801 | ||
2511 | my @config_keys = keys %min_configs; | 2802 | my @config_keys = keys %min_configs; |
2512 | 2803 | ||
2804 | # All configs need a depcount | ||
2805 | foreach my $config (@config_keys) { | ||
2806 | my $kconfig = chomp_config $config; | ||
2807 | if (!defined $depcount{$kconfig}) { | ||
2808 | $depcount{$kconfig} = 0; | ||
2809 | } | ||
2810 | } | ||
2811 | |||
2513 | # Remove anything that was set by the make allnoconfig | 2812 | # Remove anything that was set by the make allnoconfig |
2514 | # we shouldn't need them as they get set for us anyway. | 2813 | # we shouldn't need them as they get set for us anyway. |
2515 | foreach my $config (@config_keys) { | 2814 | foreach my $config (@config_keys) { |
@@ -2548,8 +2847,13 @@ sub make_min_config { | |||
2548 | # Now disable each config one by one and do a make oldconfig | 2847 | # Now disable each config one by one and do a make oldconfig |
2549 | # till we find a config that changes our list. | 2848 | # till we find a config that changes our list. |
2550 | 2849 | ||
2551 | # Put configs that did not modify the config at the end. | ||
2552 | my @test_configs = keys %min_configs; | 2850 | my @test_configs = keys %min_configs; |
2851 | |||
2852 | # Sort keys by who is most dependent on | ||
2853 | @test_configs = sort { $depcount{chomp_config($b)} <=> $depcount{chomp_config($a)} } | ||
2854 | @test_configs ; | ||
2855 | |||
2856 | # Put configs that did not modify the config at the end. | ||
2553 | my $reset = 1; | 2857 | my $reset = 1; |
2554 | for (my $i = 0; $i < $#test_configs; $i++) { | 2858 | for (my $i = 0; $i < $#test_configs; $i++) { |
2555 | if (!defined($nochange_config{$test_configs[0]})) { | 2859 | if (!defined($nochange_config{$test_configs[0]})) { |
@@ -2659,10 +2963,7 @@ sub make_min_config { | |||
2659 | } | 2963 | } |
2660 | 2964 | ||
2661 | doprint "Reboot and wait $sleep_time seconds\n"; | 2965 | doprint "Reboot and wait $sleep_time seconds\n"; |
2662 | reboot; | 2966 | reboot $sleep_time; |
2663 | start_monitor; | ||
2664 | wait_for_monitor $sleep_time; | ||
2665 | end_monitor; | ||
2666 | } | 2967 | } |
2667 | 2968 | ||
2668 | success $i; | 2969 | success $i; |
@@ -2783,6 +3084,9 @@ sub set_test_option { | |||
2783 | # First we need to do is the builds | 3084 | # First we need to do is the builds |
2784 | for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | 3085 | for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { |
2785 | 3086 | ||
3087 | # Do not reboot on failing test options | ||
3088 | $no_reboot = 1; | ||
3089 | |||
2786 | $iteration = $i; | 3090 | $iteration = $i; |
2787 | 3091 | ||
2788 | my $makecmd = set_test_option("MAKE_CMD", $i); | 3092 | my $makecmd = set_test_option("MAKE_CMD", $i); |
@@ -2811,6 +3115,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2811 | $reboot_type = set_test_option("REBOOT_TYPE", $i); | 3115 | $reboot_type = set_test_option("REBOOT_TYPE", $i); |
2812 | $grub_menu = set_test_option("GRUB_MENU", $i); | 3116 | $grub_menu = set_test_option("GRUB_MENU", $i); |
2813 | $post_install = set_test_option("POST_INSTALL", $i); | 3117 | $post_install = set_test_option("POST_INSTALL", $i); |
3118 | $no_install = set_test_option("NO_INSTALL", $i); | ||
2814 | $reboot_script = set_test_option("REBOOT_SCRIPT", $i); | 3119 | $reboot_script = set_test_option("REBOOT_SCRIPT", $i); |
2815 | $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i); | 3120 | $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i); |
2816 | $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i); | 3121 | $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i); |
@@ -2832,6 +3137,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2832 | $console = set_test_option("CONSOLE", $i); | 3137 | $console = set_test_option("CONSOLE", $i); |
2833 | $detect_triplefault = set_test_option("DETECT_TRIPLE_FAULT", $i); | 3138 | $detect_triplefault = set_test_option("DETECT_TRIPLE_FAULT", $i); |
2834 | $success_line = set_test_option("SUCCESS_LINE", $i); | 3139 | $success_line = set_test_option("SUCCESS_LINE", $i); |
3140 | $reboot_success_line = set_test_option("REBOOT_SUCCESS_LINE", $i); | ||
2835 | $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i); | 3141 | $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i); |
2836 | $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i); | 3142 | $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i); |
2837 | $stop_test_after = set_test_option("STOP_TEST_AFTER", $i); | 3143 | $stop_test_after = set_test_option("STOP_TEST_AFTER", $i); |
@@ -2850,9 +3156,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2850 | 3156 | ||
2851 | chdir $builddir || die "can't change directory to $builddir"; | 3157 | chdir $builddir || die "can't change directory to $builddir"; |
2852 | 3158 | ||
2853 | if (!-d $tmpdir) { | 3159 | foreach my $dir ($tmpdir, $outputdir) { |
2854 | mkpath($tmpdir) or | 3160 | if (!-d $dir) { |
2855 | die "can't create $tmpdir"; | 3161 | mkpath($dir) or |
3162 | die "can't create $dir"; | ||
3163 | } | ||
2856 | } | 3164 | } |
2857 | 3165 | ||
2858 | $ENV{"SSH_USER"} = $ssh_user; | 3166 | $ENV{"SSH_USER"} = $ssh_user; |
@@ -2889,8 +3197,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2889 | $run_type = "ERROR"; | 3197 | $run_type = "ERROR"; |
2890 | } | 3198 | } |
2891 | 3199 | ||
3200 | my $installme = ""; | ||
3201 | $installme = " no_install" if ($no_install); | ||
3202 | |||
2892 | doprint "\n\n"; | 3203 | doprint "\n\n"; |
2893 | doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n"; | 3204 | doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type$installme\n\n"; |
2894 | 3205 | ||
2895 | unlink $dmesg; | 3206 | unlink $dmesg; |
2896 | unlink $buildlog; | 3207 | unlink $buildlog; |
@@ -2911,6 +3222,9 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2911 | die "failed to checkout $checkout"; | 3222 | die "failed to checkout $checkout"; |
2912 | } | 3223 | } |
2913 | 3224 | ||
3225 | $no_reboot = 0; | ||
3226 | |||
3227 | |||
2914 | if ($test_type eq "bisect") { | 3228 | if ($test_type eq "bisect") { |
2915 | bisect $i; | 3229 | bisect $i; |
2916 | next; | 3230 | next; |
@@ -2929,6 +3243,13 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2929 | build $build_type or next; | 3243 | build $build_type or next; |
2930 | } | 3244 | } |
2931 | 3245 | ||
3246 | if ($test_type eq "install") { | ||
3247 | get_version; | ||
3248 | install; | ||
3249 | success $i; | ||
3250 | next; | ||
3251 | } | ||
3252 | |||
2932 | if ($test_type ne "build") { | 3253 | if ($test_type ne "build") { |
2933 | my $failed = 0; | 3254 | my $failed = 0; |
2934 | start_monitor_and_boot or $failed = 1; | 3255 | start_monitor_and_boot or $failed = 1; |
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index b8bcd14b5a4d..dbedfa196727 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf | |||
@@ -72,6 +72,128 @@ | |||
72 | # the same option name under the same test or as default | 72 | # the same option name under the same test or as default |
73 | # ktest will fail to execute, and no tests will run. | 73 | # ktest will fail to execute, and no tests will run. |
74 | # | 74 | # |
75 | # DEFAULTS OVERRIDE | ||
76 | # | ||
77 | # Options defined in the DEFAULTS section can not be duplicated | ||
78 | # even if they are defined in two different DEFAULT sections. | ||
79 | # This is done to catch mistakes where an option is added but | ||
80 | # the previous option was forgotten about and not commented. | ||
81 | # | ||
82 | # The OVERRIDE keyword can be added to a section to allow this | ||
83 | # section to override other DEFAULT sections values that have | ||
84 | # been defined previously. It will only override options that | ||
85 | # have been defined before its use. Options defined later | ||
86 | # in a non override section will still error. The same option | ||
87 | # can not be defined in the same section even if that section | ||
88 | # is marked OVERRIDE. | ||
89 | # | ||
90 | # | ||
91 | # | ||
92 | # Both TEST_START and DEFAULTS sections can also have the IF keyword | ||
93 | # The value after the IF must evaluate into a 0 or non 0 positive | ||
94 | # integer, and can use the config variables (explained below). | ||
95 | # | ||
96 | # DEFAULTS IF ${IS_X86_32} | ||
97 | # | ||
98 | # The above will process the DEFAULTS section if the config | ||
99 | # variable IS_X86_32 evaluates to a non zero positive integer | ||
100 | # otherwise if it evaluates to zero, it will act the same | ||
101 | # as if the SKIP keyword was used. | ||
102 | # | ||
103 | # The ELSE keyword can be used directly after a section with | ||
104 | # a IF statement. | ||
105 | # | ||
106 | # TEST_START IF ${RUN_NET_TESTS} | ||
107 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network | ||
108 | # | ||
109 | # ELSE | ||
110 | # | ||
111 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-normal | ||
112 | # | ||
113 | # | ||
114 | # The ELSE keyword can also contain an IF statement to allow multiple | ||
115 | # if then else sections. But all the sections must be either | ||
116 | # DEFAULT or TEST_START, they can not be a mixture. | ||
117 | # | ||
118 | # TEST_START IF ${RUN_NET_TESTS} | ||
119 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network | ||
120 | # | ||
121 | # ELSE IF ${RUN_DISK_TESTS} | ||
122 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-tests | ||
123 | # | ||
124 | # ELSE IF ${RUN_CPU_TESTS} | ||
125 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-cpu | ||
126 | # | ||
127 | # ELSE | ||
128 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network | ||
129 | # | ||
130 | # The if statement may also have comparisons that will and for | ||
131 | # == and !=, strings may be used for both sides. | ||
132 | # | ||
133 | # BOX_TYPE := x86_32 | ||
134 | # | ||
135 | # DEFAULTS IF ${BOX_TYPE} == x86_32 | ||
136 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-32 | ||
137 | # ELSE | ||
138 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-64 | ||
139 | # | ||
140 | # The DEFINED keyword can be used by the IF statements too. | ||
141 | # It returns true if the given config variable or option has been defined | ||
142 | # or false otherwise. | ||
143 | # | ||
144 | # | ||
145 | # DEFAULTS IF DEFINED USE_CC | ||
146 | # CC := ${USE_CC} | ||
147 | # ELSE | ||
148 | # CC := gcc | ||
149 | # | ||
150 | # | ||
151 | # As well as NOT DEFINED. | ||
152 | # | ||
153 | # DEFAULTS IF NOT DEFINED MAKE_CMD | ||
154 | # MAKE_CMD := make ARCH=x86 | ||
155 | # | ||
156 | # | ||
157 | # And/or ops (&&,||) may also be used to make complex conditionals. | ||
158 | # | ||
159 | # TEST_START IF (DEFINED ALL_TESTS || ${MYTEST} == boottest) && ${MACHINE} == gandalf | ||
160 | # | ||
161 | # Notice the use of paranthesis. Without any paranthesis the above would be | ||
162 | # processed the same as: | ||
163 | # | ||
164 | # TEST_START IF DEFINED ALL_TESTS || (${MYTEST} == boottest && ${MACHINE} == gandalf) | ||
165 | # | ||
166 | # | ||
167 | # | ||
168 | # INCLUDE file | ||
169 | # | ||
170 | # The INCLUDE keyword may be used in DEFAULT sections. This will | ||
171 | # read another config file and process that file as well. The included | ||
172 | # file can include other files, add new test cases or default | ||
173 | # statements. Config variables will be passed to these files and changes | ||
174 | # to config variables will be seen by top level config files. Including | ||
175 | # a file is processed just like the contents of the file was cut and pasted | ||
176 | # into the top level file, except, that include files that end with | ||
177 | # TEST_START sections will have that section ended at the end of | ||
178 | # the include file. That is, an included file is included followed | ||
179 | # by another DEFAULT keyword. | ||
180 | # | ||
181 | # Unlike other files referenced in this config, the file path does not need | ||
182 | # to be absolute. If the file does not start with '/', then the directory | ||
183 | # that the current config file was located in is used. If no config by the | ||
184 | # given name is found there, then the current directory is searched. | ||
185 | # | ||
186 | # INCLUDE myfile | ||
187 | # DEFAULT | ||
188 | # | ||
189 | # is the same as: | ||
190 | # | ||
191 | # INCLUDE myfile | ||
192 | # | ||
193 | # Note, if the include file does not contain a full path, the file is | ||
194 | # searched first by the location of the original include file, and then | ||
195 | # by the location that ktest.pl was executed in. | ||
196 | # | ||
75 | 197 | ||
76 | #### Config variables #### | 198 | #### Config variables #### |
77 | # | 199 | # |
@@ -253,9 +375,10 @@ | |||
253 | 375 | ||
254 | # The default test type (default test) | 376 | # The default test type (default test) |
255 | # The test types may be: | 377 | # The test types may be: |
256 | # build - only build the kernel, do nothing else | 378 | # build - only build the kernel, do nothing else |
257 | # boot - build and boot the kernel | 379 | # install - build and install, but do nothing else (does not reboot) |
258 | # test - build, boot and if TEST is set, run the test script | 380 | # boot - build, install, and boot the kernel |
381 | # test - build, boot and if TEST is set, run the test script | ||
259 | # (If TEST is not set, it defaults back to boot) | 382 | # (If TEST is not set, it defaults back to boot) |
260 | # bisect - Perform a bisect on the kernel (see BISECT_TYPE below) | 383 | # bisect - Perform a bisect on the kernel (see BISECT_TYPE below) |
261 | # patchcheck - Do a test on a series of commits in git (see PATCHCHECK below) | 384 | # patchcheck - Do a test on a series of commits in git (see PATCHCHECK below) |
@@ -293,6 +416,13 @@ | |||
293 | # or on some systems: | 416 | # or on some systems: |
294 | #POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION | 417 | #POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION |
295 | 418 | ||
419 | # If for some reason you just want to boot the kernel and you do not | ||
420 | # want the test to install anything new. For example, you may just want | ||
421 | # to boot test the same kernel over and over and do not want to go through | ||
422 | # the hassle of installing anything, you can set this option to 1 | ||
423 | # (default 0) | ||
424 | #NO_INSTALL = 1 | ||
425 | |||
296 | # If there is a script that you require to run before the build is done | 426 | # If there is a script that you require to run before the build is done |
297 | # you can specify it with PRE_BUILD. | 427 | # you can specify it with PRE_BUILD. |
298 | # | 428 | # |
@@ -415,6 +545,14 @@ | |||
415 | # (default "login:") | 545 | # (default "login:") |
416 | #SUCCESS_LINE = login: | 546 | #SUCCESS_LINE = login: |
417 | 547 | ||
548 | # To speed up between reboots, defining a line that the | ||
549 | # default kernel produces that represents that the default | ||
550 | # kernel has successfully booted and can be used to pass | ||
551 | # a new test kernel to it. Otherwise ktest.pl will wait till | ||
552 | # SLEEP_TIME to continue. | ||
553 | # (default undefined) | ||
554 | #REBOOT_SUCCESS_LINE = login: | ||
555 | |||
418 | # In case the console constantly fills the screen, having | 556 | # In case the console constantly fills the screen, having |
419 | # a specified time to stop the test after success is recommended. | 557 | # a specified time to stop the test after success is recommended. |
420 | # (in seconds) | 558 | # (in seconds) |
@@ -480,6 +618,8 @@ | |||
480 | # another test. If a reboot to the reliable kernel happens, | 618 | # another test. If a reboot to the reliable kernel happens, |
481 | # we wait SLEEP_TIME for the console to stop producing output | 619 | # we wait SLEEP_TIME for the console to stop producing output |
482 | # before starting the next test. | 620 | # before starting the next test. |
621 | # | ||
622 | # You can speed up reboot times even more by setting REBOOT_SUCCESS_LINE. | ||
483 | # (default 60) | 623 | # (default 60) |
484 | #SLEEP_TIME = 60 | 624 | #SLEEP_TIME = 60 |
485 | 625 | ||