aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/builtin-record.c13
-rw-r--r--tools/perf/builtin-stat.c23
-rw-r--r--tools/perf/builtin-test.c6
-rw-r--r--tools/perf/builtin-top.c54
-rw-r--r--tools/perf/util/annotate.c9
-rw-r--r--tools/perf/util/debug.c7
-rw-r--r--tools/perf/util/debug.h17
-rw-r--r--tools/perf/util/evlist.c30
-rw-r--r--tools/perf/util/evlist.h2
-rw-r--r--tools/perf/util/evsel.c53
-rw-r--r--tools/perf/util/evsel.h10
-rw-r--r--tools/perf/util/header.c4
-rw-r--r--tools/perf/util/hist.c13
-rw-r--r--tools/perf/util/hist.h3
-rw-r--r--tools/perf/util/python.c31
-rw-r--r--tools/perf/util/session.c50
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/top.h1
-rw-r--r--tools/perf/util/trace-event-info.c2
-rw-r--r--tools/perf/util/trace-event-parse.c2
-rw-r--r--tools/perf/util/ui/browser.c151
-rw-r--r--tools/perf/util/ui/browser.h9
-rw-r--r--tools/perf/util/ui/browsers/annotate.c14
-rw-r--r--tools/perf/util/ui/browsers/hists.c74
-rw-r--r--tools/perf/util/ui/helpline.c16
-rw-r--r--tools/perf/util/ui/helpline.h2
-rw-r--r--tools/perf/util/ui/progress.c65
-rw-r--r--tools/perf/util/ui/progress.h7
-rw-r--r--tools/perf/util/ui/setup.c83
-rw-r--r--tools/perf/util/ui/ui.h3
-rw-r--r--tools/perf/util/ui/util.c182
-rw-r--r--tools/perf/util/ui/util.h8
-rw-r--r--tools/power/x86/turbostat/turbostat.c28
-rwxr-xr-xtools/testing/ktest/ktest.pl531
-rw-r--r--tools/testing/ktest/sample.conf146
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
263static void open_counters(struct perf_evlist *evlist) 263static 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);
287retry_sample_id: 293retry_sample_id:
288 attr->sample_id_all = sample_id_all_avail ? 1 : 0; 294 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
289try_again: 295try_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];
278struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 278struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
279struct stats walltime_nsecs_stats; 279struct stats walltime_nsecs_stats;
280 280
281static int create_perf_stat_counter(struct perf_evsel *evsel) 281static 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)
396static int run_perf_stat(int argc __used, const char **argv) 402static 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;
89static bool inherit = false; 89static bool inherit = false;
90static int realtime_prio = 0; 90static int realtime_prio = 0;
91static bool group = false; 91static bool group = false;
92static bool sample_id_all_avail = true;
92static unsigned int mmap_pages = 128; 93static unsigned int mmap_pages = 128;
93 94
94static bool dump_symtab = false; 95static 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
567static void *display_thread_tui(void *arg __used) 570static 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
673static void perf_event__process_sample(const union perf_event *event, 676static 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,
807static void perf_session__mmap_read_idx(struct perf_session *self, int idx) 807static 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
835static void start_counters(struct perf_evlist *evlist) 842static 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;
874retry_sample_id:
875 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
861try_again: 876try_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
50void ui__warning(const char *format, ...) 50int 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
60void ui__warning_paranoid(void) 61int 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
22static inline struct ui_progress *ui_progress__new(const char *title __used, 22static 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
28static inline void ui_progress__update(struct ui_progress *self __used,
29 u64 curr __used) {}
30 24
31static inline void ui_progress__delete(struct ui_progress *self __used) {} 25#define ui__error(format, arg...) ui__warning(format, ##arg)
32#else 26#else
33extern char ui_helpline__last_msg[]; 27extern char ui_helpline__last_msg[];
34int ui_helpline__show_help(const char *format, va_list ap); 28int ui_helpline__show_help(const char *format, va_list ap);
35#include "ui/progress.h" 29#include "ui/progress.h"
30int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
36#endif 31#endif
37 32
38void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 33int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
39void ui__warning_paranoid(void); 34int 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
543int 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;
563out_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
51union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 51union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
52 52
53int perf_evlist__open(struct perf_evlist *evlist, bool group);
54
53int perf_evlist__alloc_mmap(struct perf_evlist *evlist); 55int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
54int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); 56int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
55void perf_evlist__munmap(struct perf_evlist *evlist); 57void 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
20int __perf_evsel__sample_size(u64 sample_type) 21int __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
37static 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
36void perf_evsel__init(struct perf_evsel *evsel, 47void 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
206static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 217static 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
269void 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
255static struct { 279static struct {
@@ -269,7 +293,8 @@ static struct {
269}; 293};
270 294
271int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 295int 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
285int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 310int 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
291int perf_evsel__open_per_thread(struct perf_evsel *evsel, 318int 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
297static int perf_event__parse_id_sample(const union perf_event *event, u64 type, 326static 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);
82void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 82void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
83 83
84int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 84int 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);
86int perf_evsel__open_per_thread(struct perf_evsel *evsel, 87int 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);
88int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 90int 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);
93void 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
1216void 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
65void hists__init(struct hists *hists);
66
67struct hist_entry *__hists__add_entry(struct hists *self, 66struct 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
821static 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
817static PyMethodDef pyrf_evlist__methods[] = { 840static 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);
1108out_err: 1131out_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
28struct perf_session { 29struct 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
172void 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
179int 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
205int 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
215bool 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
171void ui_browser__reset_index(struct ui_browser *self) 225void 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
242static int __ui_browser__refresh(struct ui_browser *browser) 298static 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
294static 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
335int ui_browser__run(struct ui_browser *self, int delay_secs) 350int 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
546void 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
563unsigned 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
536void ui_browser__init(void) 587void 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);
43int ui_browser__refresh(struct ui_browser *self); 43int ui_browser__refresh(struct ui_browser *self);
44int ui_browser__run(struct ui_browser *browser, int delay_secs); 44int ui_browser__run(struct ui_browser *browser, int delay_secs);
45void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); 45void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
46void ui_browser__handle_resize(struct ui_browser *browser);
47
48int ui_browser__warning(struct ui_browser *browser, int timeout,
49 const char *format, ...);
50int ui_browser__help_window(struct ui_browser *browser, const char *text);
51bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
52
53void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
54unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
46 55
47void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); 56void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
48unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); 57unsigned 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
11static 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
20struct annotate_browser { 14struct 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
22struct hist_browser { 23struct 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
298static 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
297static int hist_browser__run(struct hist_browser *self, const char *ev_name, 307static 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;
996do_annotate: 1015do_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:
1056struct perf_evsel_menu { 1077struct 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
1061static void perf_evsel_menu__write(struct ui_browser *browser, 1083static 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
10void ui_helpline__pop(void) 11void ui_helpline__pop(void)
11{ 12{
12 newtPopHelpLine();
13} 13}
14 14
15char ui_helpline__current[512];
16
15void ui_helpline__push(const char *msg) 17void 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
20void ui_helpline__vpush(const char *fmt, va_list ap) 28void 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);
11void ui_helpline__fpush(const char *fmt, ...); 11void ui_helpline__fpush(const char *fmt, ...);
12void ui_helpline__puts(const char *msg); 12void ui_helpline__puts(const char *msg);
13 13
14extern 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
6struct ui_progress { 7void ui_progress__update(u64 curr, u64 total, const char *title)
7 newtComponent form, scale;
8};
9
10struct 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
34out_free_form:
35 newtFormDestroy(self->form);
36out_free_self:
37 free(self);
38 return NULL;
39}
40
41void 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
53void 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
4struct ui_progress; 4#include <../types.h>
5 5
6struct ui_progress *ui_progress__new(const char *title, u64 total); 6void ui_progress__update(u64 curr, u64 total, const char *title);
7void ui_progress__delete(struct ui_progress *self);
8
9void 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
12pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; 14pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
13 15
16static volatile int ui__need_resize;
17
18void 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
29static void ui__sigwinch(int sig __used)
30{
31 ui__need_resize = 1;
32}
33
34static 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
46int 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
14static void newt_suspend(void *d __used) 89static void newt_suspend(void *d __used)
15{ 90{
16 newtSuspend(); 91 newtSuspend();
@@ -71,10 +146,10 @@ void setup_browser(bool fallback_to_pager)
71void exit_browser(bool wait_for_ok) 146void 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
6extern pthread_mutex_t ui__lock; 7extern pthread_mutex_t ui__lock;
7 8
9void 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
15static void newt_form__set_exit_keys(newtComponent self) 16static 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
24static 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
32int ui__popup_menu(int argc, char * const argv[]) 27static 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();
61out_destroy_form:
62 newtFormDestroy(form);
63 return rc;
64} 57}
65 58
66int ui__help_window(const char *text) 59int 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
72int 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);
103out_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
108static const char yes[] = "Yes", no[] = "No", 119int 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
111bool ui__dialog_yesno(const char *msg) 124int 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
117void ui__warning(const char *format, ...) 129int __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
148int 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
159int 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
6int ui__getch(int delay_secs);
6int ui__popup_menu(int argc, char * const argv[]); 7int ui__popup_menu(int argc, char * const argv[]);
7int ui__help_window(const char *text); 8int ui__help_window(const char *text);
8bool ui__dialog_yesno(const char *msg); 9int ui__dialog_yesno(const char *msg);
10int ui__question_window(const char *title, const char *text,
11 const char *exit_msg, int delay_secs);
12int __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
163void dump_cnt(struct counters *cnt) 163void 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
180void dump_list(struct counters *cnt) 182void 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;
84my $target; 85my $target;
85my $make; 86my $make;
86my $post_install; 87my $post_install;
88my $no_install;
87my $noclean; 89my $noclean;
88my $minconfig; 90my $minconfig;
89my $start_minconfig; 91my $start_minconfig;
@@ -115,6 +117,7 @@ my $timeout;
115my $booted_timeout; 117my $booted_timeout;
116my $detect_triplefault; 118my $detect_triplefault;
117my $console; 119my $console;
120my $reboot_success_line;
118my $success_line; 121my $success_line;
119my $stop_after_success; 122my $stop_after_success;
120my $stop_after_failure; 123my $stop_after_failure;
@@ -130,6 +133,12 @@ my %config_help;
130my %variable; 133my %variable;
131my %force_config; 134my %force_config;
132 135
136# do not force reboots on config problems
137my $no_reboot = 1;
138
139# default variables that can be used
140chomp ($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.
135EOF 144EOF
@@ -241,6 +250,7 @@ sub read_yn {
241 250
242sub get_ktest_config { 251sub 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
300sub process_variables { 311sub 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
333sub set_value { 348sub 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
358sub read_config { 380sub 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
408sub value_defined {
409 my ($val) = @_;
410
411 return defined($variable{$2}) ||
412 defined($opt{$2});
413}
414
415my $d = 0;
416sub 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
475sub 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
485sub __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
715sub 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
605sub run_command; 844sub run_command;
845sub start_monitor;
846sub end_monitor;
847sub wait_for_monitor;
606 848
607sub reboot { 849sub 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
620sub do_not_reboot { 876sub 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
695sub wait_for_monitor { 951sub 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
903sub reboot_to { 1172sub 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
1084sub install { 1354sub 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
1142sub start_monitor_and_boot { 1414sub 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
1501sub bisect_reboot { 1784sub 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
2067sub patchcheck_reboot { 2347sub 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
2075sub patchcheck { 2352sub patchcheck {
@@ -2178,12 +2455,31 @@ sub patchcheck {
2178} 2455}
2179 2456
2180my %depends; 2457my %depends;
2458my %depcount;
2181my $iflevel = 0; 2459my $iflevel = 0;
2182my @ifdeps; 2460my @ifdeps;
2183 2461
2184# prevent recursion 2462# prevent recursion
2185my %read_kconfigs; 2463my %read_kconfigs;
2186 2464
2465sub 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
2188sub read_kconfig { 2484sub 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
2653sub chomp_config {
2654 my ($config) = @_;
2655
2656 $config =~ s/CONFIG_//;
2657
2658 return $config;
2659}
2660
2368sub get_depends { 2661sub 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
2784for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { 3085for (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