diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-test.c | 9 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 7 | ||||
-rw-r--r-- | tools/perf/util/event.c | 46 | ||||
-rw-r--r-- | tools/perf/util/event.h | 12 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 31 | ||||
-rw-r--r-- | tools/perf/util/evlist.h | 3 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 32 | ||||
-rw-r--r-- | tools/perf/util/header.c | 31 | ||||
-rw-r--r-- | tools/perf/util/header.h | 2 | ||||
-rw-r--r-- | tools/perf/util/include/linux/list.h | 2 | ||||
-rw-r--r-- | tools/perf/util/python.c | 13 | ||||
-rw-r--r-- | tools/perf/util/session.c | 50 | ||||
-rw-r--r-- | tools/perf/util/session.h | 2 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/annotate.c | 1 | ||||
-rw-r--r-- | tools/power/x86/turbostat/turbostat.c | 2 | ||||
-rwxr-xr-x | tools/testing/ktest/ktest.pl | 156 | ||||
-rw-r--r-- | tools/testing/ktest/sample.conf | 93 |
17 files changed, 415 insertions, 77 deletions
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 2f9a337b182..b67186228c8 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -474,6 +474,7 @@ static int test__basic_mmap(void) unsigned int nr_events[nsyscalls], expected_nr_events[nsyscalls], i, j; struct perf_evsel *evsels[nsyscalls], *evsel; + int sample_size = perf_sample_size(attr.sample_type); for (i = 0; i < nsyscalls; ++i) { char name[64]; @@ -558,7 +559,13 @@ static int test__basic_mmap(void) goto out_munmap; } - perf_event__parse_sample(event, attr.sample_type, false, &sample); + err = perf_event__parse_sample(event, attr.sample_type, sample_size, + false, &sample); + if (err) { + pr_err("Can't parse sample, err = %d\n", err); + goto out_munmap; + } + evsel = perf_evlist__id2evsel(evlist, sample.id); if (evsel == NULL) { pr_debug("event with id %" PRIu64 diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ebfc7cf5f63..2d7934e9de3 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -805,9 +805,14 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) { struct perf_sample sample; union perf_event *event; + int ret; while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { - perf_session__parse_sample(self, event, &sample); + ret = perf_session__parse_sample(self, event, &sample); + if (ret) { + pr_err("Can't parse sample, err = %d\n", ret); + continue; + } if (event->header.type == PERF_RECORD_SAMPLE) perf_event__process_sample(event, &sample, self); diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 1023f67633a..6635fcd11ca 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -9,21 +9,21 @@ #include "thread_map.h" static const char *perf_event__names[] = { - [0] = "TOTAL", - [PERF_RECORD_MMAP] = "MMAP", - [PERF_RECORD_LOST] = "LOST", - [PERF_RECORD_COMM] = "COMM", - [PERF_RECORD_EXIT] = "EXIT", - [PERF_RECORD_THROTTLE] = "THROTTLE", - [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE", - [PERF_RECORD_FORK] = "FORK", - [PERF_RECORD_READ] = "READ", - [PERF_RECORD_SAMPLE] = "SAMPLE", - [PERF_RECORD_HEADER_ATTR] = "ATTR", - [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", - [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", - [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", - [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", + [0] = "TOTAL", + [PERF_RECORD_MMAP] = "MMAP", + [PERF_RECORD_LOST] = "LOST", + [PERF_RECORD_COMM] = "COMM", + [PERF_RECORD_EXIT] = "EXIT", + [PERF_RECORD_THROTTLE] = "THROTTLE", + [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE", + [PERF_RECORD_FORK] = "FORK", + [PERF_RECORD_READ] = "READ", + [PERF_RECORD_SAMPLE] = "SAMPLE", + [PERF_RECORD_HEADER_ATTR] = "ATTR", + [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", + [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", + [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", + [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", }; const char *perf_event__name(unsigned int id) @@ -35,6 +35,22 @@ const char *perf_event__name(unsigned int id) return perf_event__names[id]; } +int perf_sample_size(u64 sample_type) +{ + u64 mask = sample_type & PERF_SAMPLE_MASK; + int size = 0; + int i; + + for (i = 0; i < 64; i++) { + if (mask & (1ULL << i)) + size++; + } + + size *= sizeof(u64); + + return size; +} + static struct perf_sample synth_sample = { .pid = -1, .tid = -1, diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 9c35170fb37..c0833287140 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -56,6 +56,13 @@ struct read_event { u64 id; }; + +#define PERF_SAMPLE_MASK \ + (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ + PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ + PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \ + PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) + struct sample_event { struct perf_event_header header; u64 array[]; @@ -75,6 +82,8 @@ struct perf_sample { struct ip_callchain *callchain; }; +int perf_sample_size(u64 sample_type); + #define BUILD_ID_SIZE 20 struct build_id_event { @@ -178,6 +187,7 @@ int perf_event__preprocess_sample(const union perf_event *self, const char *perf_event__name(unsigned int id); int perf_event__parse_sample(const union perf_event *event, u64 type, - bool sample_id_all, struct perf_sample *sample); + int sample_size, bool sample_id_all, + struct perf_sample *sample); #endif /* __PERF_RECORD_H */ diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 23eb22b05d2..50aa34879c3 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -459,3 +459,34 @@ int perf_evlist__set_filters(struct perf_evlist *evlist) return 0; } + +u64 perf_evlist__sample_type(struct perf_evlist *evlist) +{ + struct perf_evsel *pos; + u64 type = 0; + + list_for_each_entry(pos, &evlist->entries, node) { + if (!type) + type = pos->attr.sample_type; + else if (type != pos->attr.sample_type) + die("non matching sample_type"); + } + + return type; +} + +bool perf_evlist__sample_id_all(const struct perf_evlist *evlist) +{ + bool value = false, first = true; + struct perf_evsel *pos; + + list_for_each_entry(pos, &evlist->entries, node) { + if (first) { + value = pos->attr.sample_id_all; + first = false; + } else if (value != pos->attr.sample_id_all) + die("non matching sample_id_all"); + } + + return value; +} diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 7109d7add14..0a1ef1f051f 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -66,4 +66,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, void perf_evlist__delete_maps(struct perf_evlist *evlist); int perf_evlist__set_filters(struct perf_evlist *evlist); +u64 perf_evlist__sample_type(struct perf_evlist *evlist); +bool perf_evlist__sample_id_all(const struct perf_evlist *evlist); + #endif /* __PERF_EVLIST_H */ diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d6fd59beb86..ee0fe0dffa7 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -303,8 +303,20 @@ static int perf_event__parse_id_sample(const union perf_event *event, u64 type, return 0; } +static bool sample_overlap(const union perf_event *event, + const void *offset, u64 size) +{ + const void *base = event; + + if (offset + size > base + event->header.size) + return true; + + return false; +} + int perf_event__parse_sample(const union perf_event *event, u64 type, - bool sample_id_all, struct perf_sample *data) + int sample_size, bool sample_id_all, + struct perf_sample *data) { const u64 *array; @@ -319,6 +331,9 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, array = event->sample.array; + if (sample_size + sizeof(event->header) > event->header.size) + return -EFAULT; + if (type & PERF_SAMPLE_IP) { data->ip = event->ip.ip; array++; @@ -369,14 +384,29 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, } if (type & PERF_SAMPLE_CALLCHAIN) { + if (sample_overlap(event, array, sizeof(data->callchain->nr))) + return -EFAULT; + data->callchain = (struct ip_callchain *)array; + + if (sample_overlap(event, array, data->callchain->nr)) + return -EFAULT; + array += 1 + data->callchain->nr; } if (type & PERF_SAMPLE_RAW) { u32 *p = (u32 *)array; + + if (sample_overlap(event, array, sizeof(u32))) + return -EFAULT; + data->raw_size = *p; p++; + + if (sample_overlap(event, p, data->raw_size)) + return -EFAULT; + data->raw_data = p; } diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 93862a8027e..0717bebc764 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -934,37 +934,6 @@ out_delete_evlist: return -ENOMEM; } -u64 perf_evlist__sample_type(struct perf_evlist *evlist) -{ - struct perf_evsel *pos; - u64 type = 0; - - list_for_each_entry(pos, &evlist->entries, node) { - if (!type) - type = pos->attr.sample_type; - else if (type != pos->attr.sample_type) - die("non matching sample_type"); - } - - return type; -} - -bool perf_evlist__sample_id_all(const struct perf_evlist *evlist) -{ - bool value = false, first = true; - struct perf_evsel *pos; - - list_for_each_entry(pos, &evlist->entries, node) { - if (first) { - value = pos->attr.sample_id_all; - first = false; - } else if (value != pos->attr.sample_id_all) - die("non matching sample_id_all"); - } - - return value; -} - int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, perf_event__handler_t process, struct perf_session *session) diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 456661d7f10..1886256768a 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -64,8 +64,6 @@ int perf_header__write_pipe(int fd); int perf_header__push_event(u64 id, const char *name); char *perf_header__find_event(u64 id); -u64 perf_evlist__sample_type(struct perf_evlist *evlist); -bool perf_evlist__sample_id_all(const struct perf_evlist *evlist); void perf_header__set_feat(struct perf_header *header, int feat); void perf_header__clear_feat(struct perf_header *header, int feat); bool perf_header__has_feat(const struct perf_header *header, int feat); diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h index 99358d61e9a..1d928a0ce99 100644 --- a/tools/perf/util/include/linux/list.h +++ b/tools/perf/util/include/linux/list.h @@ -1,4 +1,6 @@ #include <linux/kernel.h> +#include <linux/prefetch.h> + #include "../../../../include/linux/list.h" #ifndef PERF_LIST_H diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index b5c7d818001..69436b3200a 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -675,6 +675,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, union perf_event *event; int sample_id_all = 1, cpu; static char *kwlist[] = {"sample_id_all", NULL, NULL}; + int err; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist, &cpu, &sample_id_all)) @@ -690,11 +691,17 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, return PyErr_NoMemory(); first = list_entry(evlist->entries.next, struct perf_evsel, node); - perf_event__parse_sample(event, first->attr.sample_type, sample_id_all, - &pevent->sample); + err = perf_event__parse_sample(event, first->attr.sample_type, + perf_sample_size(first->attr.sample_type), + sample_id_all, &pevent->sample); + if (err) { + pr_err("Can't parse sample, err = %d\n", err); + goto end; + } + return pyevent; } - +end: Py_INCREF(Py_None); return Py_None; } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index fff66741f18..64500fc7879 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -97,6 +97,7 @@ out: void perf_session__update_sample_type(struct perf_session *self) { self->sample_type = perf_evlist__sample_type(self->evlist); + self->sample_size = perf_sample_size(self->sample_type); self->sample_id_all = perf_evlist__sample_id_all(self->evlist); perf_session__id_header_size(self); } @@ -479,6 +480,7 @@ static void flush_sample_queue(struct perf_session *s, struct perf_sample sample; u64 limit = os->next_flush; u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; + int ret; if (!ops->ordered_samples || !limit) return; @@ -487,9 +489,12 @@ static void flush_sample_queue(struct perf_session *s, if (iter->timestamp > limit) break; - perf_session__parse_sample(s, iter->event, &sample); - perf_session_deliver_event(s, iter->event, &sample, ops, - iter->file_offset); + ret = perf_session__parse_sample(s, iter->event, &sample); + if (ret) + pr_err("Can't parse sample, err = %d\n", ret); + else + perf_session_deliver_event(s, iter->event, &sample, ops, + iter->file_offset); os->last_flush = iter->timestamp; list_del(&iter->list); @@ -805,7 +810,9 @@ static int perf_session__process_event(struct perf_session *session, /* * For all kernel events we get the sample data */ - perf_session__parse_sample(session, event, &sample); + ret = perf_session__parse_sample(session, event, &sample); + if (ret) + return ret; /* Preprocess sample records - precheck callchains */ if (perf_session__preprocess_sample(session, event, &sample)) @@ -953,6 +960,30 @@ out_err: return err; } +static union perf_event * +fetch_mmaped_event(struct perf_session *session, + u64 head, size_t mmap_size, char *buf) +{ + union perf_event *event; + + /* + * Ensure we have enough space remaining to read + * the size of the event in the headers. + */ + if (head + sizeof(event->header) > mmap_size) + return NULL; + + event = (union perf_event *)(buf + head); + + if (session->header.needs_swap) + perf_event_header__bswap(&event->header); + + if (head + event->header.size > mmap_size) + return NULL; + + return event; +} + int __perf_session__process_events(struct perf_session *session, u64 data_offset, u64 data_size, u64 file_size, struct perf_event_ops *ops) @@ -1007,15 +1038,8 @@ remap: file_pos = file_offset + head; more: - event = (union perf_event *)(buf + head); - - if (session->header.needs_swap) - perf_event_header__bswap(&event->header); - size = event->header.size; - if (size == 0) - size = 8; - - if (head + event->header.size > mmap_size) { + event = fetch_mmaped_event(session, head, mmap_size, buf); + if (!event) { if (mmaps[map_idx]) { munmap(mmaps[map_idx], mmap_size); mmaps[map_idx] = NULL; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 8daaa2d1539..66d4e149087 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -43,6 +43,7 @@ struct perf_session { */ struct hists hists; u64 sample_type; + int sample_size; int fd; bool fd_pipe; bool repipe; @@ -159,6 +160,7 @@ static inline int perf_session__parse_sample(struct perf_session *session, struct perf_sample *sample) { return perf_event__parse_sample(event, session->sample_type, + session->sample_size, session->sample_id_all, sample); } diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 15633d60813..0229723aceb 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -5,7 +5,6 @@ #include "../../hist.h" #include "../../sort.h" #include "../../symbol.h" -#include "../../annotate.h" #include <pthread.h> static void ui__error_window(const char *fmt, ...) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 362a0cb448d..6d8ef4a3a9b 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -990,7 +990,7 @@ int fork_it(char **argv) if (!retval) print_counters(cnt_delta); - fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);; + fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0); return 0; } diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 8ce792ea08e..1fd29b2daa9 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -36,6 +36,7 @@ $default{"REBOOT_ON_SUCCESS"} = 1; $default{"POWEROFF_ON_SUCCESS"} = 0; $default{"BUILD_OPTIONS"} = ""; $default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects +$default{"PATCHCHECK_SLEEP_TIME"} = 60; # sleep time between patch checks $default{"CLEAR_LOG"} = 0; $default{"BISECT_MANUAL"} = 0; $default{"BISECT_SKIP"} = 1; @@ -96,6 +97,7 @@ my $monitor_pid; my $monitor_cnt = 0; my $sleep_time; my $bisect_sleep_time; +my $patchcheck_sleep_time; my $store_failures; my $timeout; my $booted_timeout; @@ -112,6 +114,7 @@ my $successes = 0; my %entered_configs; my %config_help; +my %variable; $config_help{"MACHINE"} = << "EOF" The machine hostname that you will test. @@ -260,6 +263,39 @@ sub get_ktest_configs { } } +sub process_variables { + my ($value) = @_; + my $retval = ""; + + # We want to check for '\', and it is just easier + # to check the previous characet of '$' and not need + # to worry if '$' is the first character. By adding + # a space to $value, we can just check [^\\]\$ and + # it will still work. + $value = " $value"; + + while ($value =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { + my $begin = $1; + my $var = $2; + my $end = $3; + # append beginning of value to retval + $retval = "$retval$begin"; + if (defined($variable{$var})) { + $retval = "$retval$variable{$var}"; + } else { + # put back the origin piece. + $retval = "$retval\$\{$var\}"; + } + $value = $end; + } + $retval = "$retval$value"; + + # remove the space added in the beginning + $retval =~ s/ //; + + return "$retval" +} + sub set_value { my ($lvalue, $rvalue) = @_; @@ -269,10 +305,22 @@ sub set_value { if ($rvalue =~ /^\s*$/) { delete $opt{$lvalue}; } else { + $rvalue = process_variables($rvalue); $opt{$lvalue} = $rvalue; } } +sub set_variable { + my ($lvalue, $rvalue) = @_; + + if ($rvalue =~ /^\s*$/) { + delete $variable{$lvalue}; + } else { + $rvalue = process_variables($rvalue); + $variable{$lvalue} = $rvalue; + } +} + sub read_config { my ($config) = @_; @@ -385,6 +433,22 @@ sub read_config { $repeats{$val} = $repeat; } } + } elsif (/^\s*([A-Z_\[\]\d]+)\s*:=\s*(.*?)\s*$/) { + next if ($skip); + + my $lvalue = $1; + my $rvalue = $2; + + # process config variables. + # Config variables are only active while reading the + # config and can be defined anywhere. They also ignore + # TEST_START and DEFAULTS, but are skipped if they are in + # on of these sections that have SKIP defined. + # The save variable can be + # defined multiple times and the new one simply overrides + # the prevous one. + set_variable($lvalue, $rvalue); + } else { die "$name: $.: Garbage found in config\n$_"; } @@ -838,6 +902,7 @@ sub monitor { if ($stop_test_after > 0 && !$booted && !$bug) { if (time - $monitor_start > $stop_test_after) { + doprint "STOP_TEST_AFTER ($stop_test_after seconds) timed out\n"; $done = 1; } } @@ -907,7 +972,7 @@ sub install { return if (!defined($post_install)); my $cp_post_install = $post_install; - $cp_post_install = s/\$KERNEL_VERSION/$version/g; + $cp_post_install =~ s/\$KERNEL_VERSION/$version/g; run_command "$cp_post_install" or dodie "Failed to run post install"; } @@ -1247,14 +1312,14 @@ sub run_bisect_test { if ($failed) { $result = 0; - - # reboot the box to a good kernel - if ($type ne "build") { - bisect_reboot; - } } else { $result = 1; } + + # reboot the box to a kernel we can ssh to + if ($type ne "build") { + bisect_reboot; + } $in_bisect = 0; return $result; @@ -1763,6 +1828,14 @@ sub config_bisect { success $i; } +sub patchcheck_reboot { + doprint "Reboot and sleep $patchcheck_sleep_time seconds\n"; + reboot; + start_monitor; + wait_for_monitor $patchcheck_sleep_time; + end_monitor; +} + sub patchcheck { my ($i) = @_; @@ -1854,6 +1927,8 @@ sub patchcheck { end_monitor; return 0 if ($failed); + patchcheck_reboot; + } $in_patchcheck = 0; success $i; @@ -1944,7 +2019,7 @@ for (my $i = 0, my $repeat = 1; $i <= $opt{"NUM_TESTS"}; $i += $repeat) { } } -sub set_test_option { +sub __set_test_option { my ($name, $i) = @_; my $option = "$name\[$i\]"; @@ -1970,6 +2045,72 @@ sub set_test_option { return undef; } +sub eval_option { + my ($option, $i) = @_; + + # Add space to evaluate the character before $ + $option = " $option"; + my $retval = ""; + + while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { + my $start = $1; + my $var = $2; + my $end = $3; + + # Append beginning of line + $retval = "$retval$start"; + + # If the iteration option OPT[$i] exists, then use that. + # otherwise see if the default OPT (without [$i]) exists. + + my $o = "$var\[$i\]"; + + if (defined($opt{$o})) { + $o = $opt{$o}; + $retval = "$retval$o"; + } elsif (defined($opt{$var})) { + $o = $opt{$var}; + $retval = "$retval$o"; + } else { + $retval = "$retval\$\{$var\}"; + } + + $option = $end; + } + + $retval = "$retval$option"; + + $retval =~ s/^ //; + + return $retval; +} + +sub set_test_option { + my ($name, $i) = @_; + + my $option = __set_test_option($name, $i); + return $option if (!defined($option)); + + my $prev = ""; + + # Since an option can evaluate to another option, + # keep iterating until we do not evaluate any more + # options. + my $r = 0; + while ($prev ne $option) { + # Check for recursive evaluations. + # 100 deep should be more than enough. + if ($r++ > 100) { + die "Over 100 evaluations accurred with $name\n" . + "Check for recursive variables\n"; + } + $prev = $option; + $option = eval_option($option, $i); + } + + return $option; +} + # First we need to do is the builds for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { @@ -2003,6 +2144,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i); $sleep_time = set_test_option("SLEEP_TIME", $i); $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i); + $patchcheck_sleep_time = set_test_option("PATCHCHECK_SLEEP_TIME", $i); $bisect_manual = set_test_option("BISECT_MANUAL", $i); $bisect_skip = set_test_option("BISECT_SKIP", $i); $store_failures = set_test_option("STORE_FAILURES", $i); diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 4c5d6bd74a0..48cbcc80602 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -73,6 +73,95 @@ # ktest will fail to execute, and no tests will run. # +#### Config variables #### +# +# This config file can also contain "config variables". +# These are assigned with ":=" instead of the ktest option +# assigment "=". +# +# The difference between ktest options and config variables +# is that config variables can be used multiple times, +# where each instance will override the previous instance. +# And that they only live at time of processing this config. +# +# The advantage to config variables are that they can be used +# by any option or any other config variables to define thing +# that you may use over and over again in the options. +# +# For example: +# +# USER := root +# TARGET := mybox +# TEST_CASE := ssh ${USER}@${TARGET} /path/to/my/test +# +# TEST_START +# MIN_CONFIG = config1 +# TEST = ${TEST_CASE} +# +# TEST_START +# MIN_CONFIG = config2 +# TEST = ${TEST_CASE} +# +# TEST_CASE := ssh ${USER}@${TARGET} /path/to/my/test2 +# +# TEST_START +# MIN_CONFIG = config1 +# TEST = ${TEST_CASE} +# +# TEST_START +# MIN_CONFIG = config2 +# TEST = ${TEST_CASE} +# +# TEST_DIR := /home/me/test +# +# BUILD_DIR = ${TEST_DIR}/linux.git +# OUTPUT_DIR = ${TEST_DIR}/test +# +# Note, the config variables are evaluated immediately, thus +# updating TARGET after TEST_CASE has been assigned does nothing +# to TEST_CASE. +# +# As shown in the example, to evaluate a config variable, you +# use the ${X} convention. Simple $X will not work. +# +# If the config variable does not exist, the ${X} will not +# be evaluated. Thus: +# +# MAKE_CMD = PATH=/mypath:${PATH} make +# +# If PATH is not a config variable, then the ${PATH} in +# the MAKE_CMD option will be evaluated by the shell when +# the MAKE_CMD option is passed into shell processing. + +#### Using options in other options #### +# +# Options that are defined in the config file may also be used +# by other options. All options are evaulated at time of +# use (except that config variables are evaluated at config +# processing time). +# +# If an ktest option is used within another option, instead of +# typing it again in that option you can simply use the option +# just like you can config variables. +# +# MACHINE = mybox +# +# TEST = ssh root@${MACHINE} /path/to/test +# +# The option will be used per test case. Thus: +# +# TEST_TYPE = test +# TEST = ssh root@{MACHINE} +# +# TEST_START +# MACHINE = box1 +# +# TEST_START +# MACHINE = box2 +# +# For both test cases, MACHINE will be evaluated at the time +# of the test case. The first test will run ssh root@box1 +# and the second will run ssh root@box2. #### Mandatory Default Options #### @@ -366,6 +455,10 @@ # (default 60) #BISECT_SLEEP_TIME = 60 +# The time in between patch checks to sleep (in seconds) +# (default 60) +#PATCHCHECK_SLEEP_TIME = 60 + # Reboot the target box on error (default 0) #REBOOT_ON_ERROR = 0 |