summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/builtin-annotate.c18
-rw-r--r--tools/perf/builtin-diff.c1
-rw-r--r--tools/perf/builtin-inject.c11
-rw-r--r--tools/perf/builtin-kmem.c1
-rw-r--r--tools/perf/builtin-lock.c4
-rw-r--r--tools/perf/builtin-report.c19
-rw-r--r--tools/perf/builtin-sched.c1
-rw-r--r--tools/perf/builtin-script.c15
-rw-r--r--tools/perf/builtin-timechart.c11
-rw-r--r--tools/perf/builtin-top.c4
-rw-r--r--tools/perf/util/build-id.c1
-rw-r--r--tools/perf/util/header.c57
-rw-r--r--tools/perf/util/hist.h1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c1
-rw-r--r--tools/perf/util/session.c25
-rw-r--r--tools/perf/util/session.h7
-rw-r--r--tools/perf/util/symbol.c25
-rw-r--r--tools/perf/util/trace-event-scripting.c1
-rw-r--r--tools/perf/util/trace-event.h1
-rwxr-xr-xtools/testing/ktest/ktest.pl139
-rw-r--r--tools/testing/ktest/sample.conf42
22 files changed, 306 insertions, 80 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 695de4b5ae63..e18eb7ed30ae 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -42,9 +42,9 @@ static const char *sym_hist_filter;
static int perf_evlist__add_sample(struct perf_evlist *evlist,
struct perf_sample *sample,
+ struct perf_evsel *evsel,
struct addr_location *al)
{
- struct perf_evsel *evsel;
struct hist_entry *he;
int ret;
@@ -59,18 +59,6 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist,
return 0;
}
- evsel = perf_evlist__id2evsel(evlist, sample->id);
- if (evsel == NULL) {
- /*
- * FIXME: Propagate this back, but at least we're in a builtin,
- * where exit() is allowed. ;-)
- */
- ui__warning("Invalid %s file, contains samples with id not in "
- "its header!\n", input_name);
- exit_browser(0);
- exit(1);
- }
-
he = __hists__add_entry(&evsel->hists, al, NULL, 1);
if (he == NULL)
return -ENOMEM;
@@ -92,6 +80,7 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist,
static int process_sample_event(union perf_event *event,
struct perf_sample *sample,
+ struct perf_evsel *evsel,
struct perf_session *session)
{
struct addr_location al;
@@ -103,7 +92,8 @@ static int process_sample_event(union perf_event *event,
return -1;
}
- if (!al.filtered && perf_evlist__add_sample(session->evlist, sample, &al)) {
+ if (!al.filtered &&
+ perf_evlist__add_sample(session->evlist, sample, evsel, &al)) {
pr_warning("problem incrementing symbol count, "
"skipping event\n");
return -1;
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 6b7d91160ecb..e8219990f8b8 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -32,6 +32,7 @@ static int hists__add_entry(struct hists *self,
static int diff__process_sample_event(union perf_event *event,
struct perf_sample *sample,
+ struct perf_evsel *evsel __used,
struct perf_session *session)
{
struct addr_location al;
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index e29f04ed3396..8dfc12bb119b 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -43,6 +43,14 @@ static int perf_event__repipe(union perf_event *event,
return perf_event__repipe_synth(event, session);
}
+static int perf_event__repipe_sample(union perf_event *event,
+ struct perf_sample *sample __used,
+ struct perf_evsel *evsel __used,
+ struct perf_session *session)
+{
+ return perf_event__repipe_synth(event, session);
+}
+
static int perf_event__repipe_mmap(union perf_event *event,
struct perf_sample *sample,
struct perf_session *session)
@@ -124,6 +132,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
static int perf_event__inject_buildid(union perf_event *event,
struct perf_sample *sample,
+ struct perf_evsel *evsel __used,
struct perf_session *session)
{
struct addr_location al;
@@ -164,7 +173,7 @@ repipe:
}
struct perf_event_ops inject_ops = {
- .sample = perf_event__repipe,
+ .sample = perf_event__repipe_sample,
.mmap = perf_event__repipe,
.comm = perf_event__repipe,
.fork = perf_event__repipe,
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 7f618f4e7b79..225e963df105 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -305,6 +305,7 @@ static void process_raw_event(union perf_event *raw_event __used, void *data,
static int process_sample_event(union perf_event *event,
struct perf_sample *sample,
+ struct perf_evsel *evsel __used,
struct perf_session *session)
{
struct thread *thread = perf_session__findnew(session, event->ip.pid);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 7a2a79d2cf2c..9ac05aafd9b2 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -845,7 +845,9 @@ static void dump_info(void)
die("Unknown type of information\n");
}
-static int process_sample_event(union perf_event *event, struct perf_sample *sample,
+static int process_sample_event(union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_evsel *evsel __used,
struct perf_session *s)
{
struct thread *thread = perf_session__findnew(s, sample->tid);
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index b1b82009ab9b..498c6f70a747 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -50,12 +50,12 @@ static symbol_filter_t annotate_init;
static int perf_session__add_hist_entry(struct perf_session *session,
struct addr_location *al,
- struct perf_sample *sample)
+ struct perf_sample *sample,
+ struct perf_evsel *evsel)
{
struct symbol *parent = NULL;
int err = 0;
struct hist_entry *he;
- struct perf_evsel *evsel;
if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
err = perf_session__resolve_callchain(session, al->thread,
@@ -64,18 +64,6 @@ static int perf_session__add_hist_entry(struct perf_session *session,
return err;
}
- evsel = perf_evlist__id2evsel(session->evlist, sample->id);
- if (evsel == NULL) {
- /*
- * FIXME: Propagate this back, but at least we're in a builtin,
- * where exit() is allowed. ;-)
- */
- ui__warning("Invalid %s file, contains samples with id %" PRIu64 " not in "
- "its header!\n", input_name, sample->id);
- exit_browser(0);
- exit(1);
- }
-
he = __hists__add_entry(&evsel->hists, al, parent, sample->period);
if (he == NULL)
return -ENOMEM;
@@ -113,6 +101,7 @@ out:
static int process_sample_event(union perf_event *event,
struct perf_sample *sample,
+ struct perf_evsel *evsel,
struct perf_session *session)
{
struct addr_location al;
@@ -127,7 +116,7 @@ static int process_sample_event(union perf_event *event,
if (al.filtered || (hide_unresolved && al.sym == NULL))
return 0;
- if (perf_session__add_hist_entry(session, &al, sample)) {
+ if (perf_session__add_hist_entry(session, &al, sample, evsel)) {
pr_debug("problem incrementing symbol period, skipping event\n");
return -1;
}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index a32f411faeac..dcfe8873c9a1 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1603,6 +1603,7 @@ static void process_raw_event(union perf_event *raw_event __used,
static int process_sample_event(union perf_event *event,
struct perf_sample *sample,
+ struct perf_evsel *evsel __used,
struct perf_session *session)
{
struct thread *thread;
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 9f5fc5492141..ac574ea23917 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -162,19 +162,11 @@ static void print_sample_start(struct perf_sample *sample,
static void process_event(union perf_event *event __unused,
struct perf_sample *sample,
+ struct perf_evsel *evsel,
struct perf_session *session,
struct thread *thread)
{
- struct perf_event_attr *attr;
- struct perf_evsel *evsel;
-
- evsel = perf_evlist__id2evsel(session->evlist, sample->id);
- if (evsel == NULL) {
- pr_err("Invalid data. Contains samples with id not in "
- "its header!\n");
- return;
- }
- attr = &evsel->attr;
+ struct perf_event_attr *attr = &evsel->attr;
if (output_fields[attr->type] == 0)
return;
@@ -244,6 +236,7 @@ static char const *input_name = "perf.data";
static int process_sample_event(union perf_event *event,
struct perf_sample *sample,
+ struct perf_evsel *evsel,
struct perf_session *session)
{
struct thread *thread = perf_session__findnew(session, event->ip.pid);
@@ -264,7 +257,7 @@ static int process_sample_event(union perf_event *event,
last_timestamp = sample->time;
return 0;
}
- scripting_ops->process_event(event, sample, session, thread);
+ scripting_ops->process_event(event, sample, evsel, session, thread);
session->hists.stats.total_period += sample->period;
return 0;
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 67c0459dc325..aa26f4d66d10 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -488,6 +488,7 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
static int process_sample_event(union perf_event *event __used,
struct perf_sample *sample,
+ struct perf_evsel *evsel __used,
struct perf_session *session)
{
struct trace_entry *te;
@@ -506,6 +507,16 @@ static int process_sample_event(union perf_event *event __used,
struct power_entry_old *peo;
peo = (void *)te;
#endif
+ /*
+ * FIXME: use evsel, its already mapped from id to perf_evsel,
+ * remove perf_header__find_event infrastructure bits.
+ * Mapping all these "power:cpu_idle" strings to the tracepoint
+ * ID and then just comparing against evsel->attr.config.
+ *
+ * e.g.:
+ *
+ * if (evsel->attr.config == power_cpu_idle_id)
+ */
event_str = perf_header__find_event(te->type);
if (!event_str)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 70f1075cc5b0..676b4fb0070f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -515,7 +515,9 @@ static void handle_keypress(struct perf_session *session, int c)
break;
case 'E':
if (top.evlist->nr_entries > 1) {
- int counter;
+ /* Select 0 as the default event: */
+ int counter = 0;
+
fprintf(stderr, "\nAvailable events:");
list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 31f934af9861..a91cd99f26ea 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -16,6 +16,7 @@
static int build_id__mark_dso_hit(union perf_event *event,
struct perf_sample *sample __used,
+ struct perf_evsel *evsel __used,
struct perf_session *session)
{
struct addr_location al;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index e5230c0ef95b..93862a8027ea 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -695,13 +695,50 @@ out:
return err;
}
+static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
+ int input, u64 offset, u64 size)
+{
+ struct perf_session *session = container_of(header, struct perf_session, header);
+ struct {
+ struct perf_event_header header;
+ u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
+ char filename[0];
+ } old_bev;
+ struct build_id_event bev;
+ char filename[PATH_MAX];
+ u64 limit = offset + size;
+
+ while (offset < limit) {
+ ssize_t len;
+
+ if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
+ return -1;
+
+ if (header->needs_swap)
+ perf_event_header__bswap(&old_bev.header);
+
+ len = old_bev.header.size - sizeof(old_bev);
+ if (read(input, filename, len) != len)
+ return -1;
+
+ bev.header = old_bev.header;
+ bev.pid = 0;
+ memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
+ __event_process_build_id(&bev, filename, session);
+
+ offset += bev.header.size;
+ }
+
+ return 0;
+}
+
static int perf_header__read_build_ids(struct perf_header *header,
int input, u64 offset, u64 size)
{
struct perf_session *session = container_of(header, struct perf_session, header);
struct build_id_event bev;
char filename[PATH_MAX];
- u64 limit = offset + size;
+ u64 limit = offset + size, orig_offset = offset;
int err = -1;
while (offset < limit) {
@@ -716,6 +753,24 @@ static int perf_header__read_build_ids(struct perf_header *header,
len = bev.header.size - sizeof(bev);
if (read(input, filename, len) != len)
goto out;
+ /*
+ * The a1645ce1 changeset:
+ *
+ * "perf: 'perf kvm' tool for monitoring guest performance from host"
+ *
+ * Added a field to struct build_id_event that broke the file
+ * format.
+ *
+ * Since the kernel build-id is the first entry, process the
+ * table using the old format if the well known
+ * '[kernel.kallsyms]' string for the kernel build-id has the
+ * first 4 characters chopped off (where the pid_t sits).
+ */
+ if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
+ if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
+ return -1;
+ return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
+ }
__event_process_build_id(&bev, filename, session);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index cb6858a2f9a3..3beb97c4d822 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -29,6 +29,7 @@ struct events_stats {
u32 nr_events[PERF_RECORD_HEADER_MAX];
u32 nr_unknown_events;
u32 nr_invalid_chains;
+ u32 nr_unknown_id;
};
enum hist_column {
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 621427212e86..74350ffb57fe 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -247,6 +247,7 @@ static inline struct event *find_cache_event(int type)
static void perl_process_event(union perf_event *pevent __unused,
struct perf_sample *sample,
+ struct perf_evsel *evsel,
struct perf_session *session __unused,
struct thread *thread)
{
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 1b85d6055159..6ccf70e8d8f2 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -206,6 +206,7 @@ static inline struct event *find_cache_event(int type)
static void python_process_event(union perf_event *pevent __unused,
struct perf_sample *sample,
+ struct perf_evsel *evsel __unused,
struct perf_session *session __unused,
struct thread *thread)
{
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index c68cf40764f9..caa224522fea 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -280,6 +280,15 @@ static int process_event_synth_stub(union perf_event *event __used,
return 0;
}
+static int process_event_sample_stub(union perf_event *event __used,
+ struct perf_sample *sample __used,
+ struct perf_evsel *evsel __used,
+ struct perf_session *session __used)
+{
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
static int process_event_stub(union perf_event *event __used,
struct perf_sample *sample __used,
struct perf_session *session __used)
@@ -303,7 +312,7 @@ static int process_finished_round(union perf_event *event,
static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
{
if (handler->sample == NULL)
- handler->sample = process_event_stub;
+ handler->sample = process_event_sample_stub;
if (handler->mmap == NULL)
handler->mmap = process_event_stub;
if (handler->comm == NULL)
@@ -698,12 +707,19 @@ static int perf_session_deliver_event(struct perf_session *session,
struct perf_event_ops *ops,
u64 file_offset)
{
+ struct perf_evsel *evsel;
+
dump_event(session, event, file_offset, sample);
switch (event->header.type) {
case PERF_RECORD_SAMPLE:
dump_sample(session, event, sample);
- return ops->sample(event, sample, session);
+ evsel = perf_evlist__id2evsel(session->evlist, sample->id);
+ if (evsel == NULL) {
+ ++session->hists.stats.nr_unknown_id;
+ return -1;
+ }
+ return ops->sample(event, sample, evsel, session);
case PERF_RECORD_MMAP:
return ops->mmap(event, sample, session);
case PERF_RECORD_COMM:
@@ -845,6 +861,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
session->hists.stats.nr_unknown_events);
}
+ if (session->hists.stats.nr_unknown_id != 0) {
+ ui__warning("%u samples with id not present in the header\n",
+ session->hists.stats.nr_unknown_id);
+ }
+
if (session->hists.stats.nr_invalid_chains != 0) {
ui__warning("Found invalid callchains!\n\n"
"%u out of %u events were discarded for this reason.\n\n"
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 0b3c9afecaa9..1ac481fc1100 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -55,8 +55,11 @@ struct perf_session {
char filename[0];
};
+struct perf_evsel;
struct perf_event_ops;
+typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample,
+ struct perf_evsel *evsel, struct perf_session *session);
typedef int (*event_op)(union perf_event *self, struct perf_sample *sample,
struct perf_session *session);
typedef int (*event_synth_op)(union perf_event *self,
@@ -65,8 +68,8 @@ typedef int (*event_op2)(union perf_event *self, struct perf_session *session,
struct perf_event_ops *ops);
struct perf_event_ops {
- event_op sample,
- mmap,
+ event_sample sample;
+ event_op mmap,
comm,
fork,
exit,
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 651dbfe7f4f3..17df793c8924 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1486,7 +1486,9 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
* On the first pass, only load images if they have a full symtab.
* Failing that, do a second pass where we accept .dynsym also
*/
- for (self->symtab_type = SYMTAB__BUILD_ID_CACHE, want_symtab = 1;
+ want_symtab = 1;
+restart:
+ for (self->symtab_type = SYMTAB__BUILD_ID_CACHE;
self->symtab_type != SYMTAB__NOT_FOUND;
self->symtab_type++) {
switch (self->symtab_type) {
@@ -1536,17 +1538,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
snprintf(name, size, "%s%s", symbol_conf.symfs,
self->long_name);
break;
-
- default:
- /*
- * If we wanted a full symtab but no image had one,
- * relax our requirements and repeat the search.
- */
- if (want_symtab) {
- want_symtab = 0;
- self->symtab_type = SYMTAB__BUILD_ID_CACHE;
- } else
- continue;
+ default:;
}
/* Name is now the name of the next image to try */
@@ -1573,6 +1565,15 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
}
}
+ /*
+ * If we wanted a full symtab but no image had one,
+ * relax our requirements and repeat the search.
+ */
+ if (ret <= 0 && want_symtab) {
+ want_symtab = 0;
+ goto restart;
+ }
+
free(name);
if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
return 0;
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index 66f4b78737ab..c9dcbec7d800 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -38,6 +38,7 @@ static int stop_script_unsupported(void)
static void process_event_unsupported(union perf_event *event __unused,
struct perf_sample *sample __unused,
+ struct perf_evsel *evsel __unused,
struct perf_session *session __unused,
struct thread *thread __unused)
{
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index b04da5722437..f674dda3363b 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -280,6 +280,7 @@ struct scripting_ops {
int (*stop_script) (void);
void (*process_event) (union perf_event *event,
struct perf_sample *sample,
+ struct perf_evsel *evsel,
struct perf_session *session,
struct thread *thread);
int (*generate_script) (const char *outfile);
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index ba7c63af6f3b..8ce792ea08e9 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -37,6 +37,8 @@ $default{"POWEROFF_ON_SUCCESS"} = 0;
$default{"BUILD_OPTIONS"} = "";
$default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects
$default{"CLEAR_LOG"} = 0;
+$default{"BISECT_MANUAL"} = 0;
+$default{"BISECT_SKIP"} = 1;
$default{"SUCCESS_LINE"} = "login:";
$default{"BOOTED_TIMEOUT"} = 1;
$default{"DIE_ON_FAILURE"} = 1;
@@ -45,6 +47,7 @@ $default{"SCP_TO_TARGET"} = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE";
$default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot";
$default{"STOP_AFTER_SUCCESS"} = 10;
$default{"STOP_AFTER_FAILURE"} = 60;
+$default{"STOP_TEST_AFTER"} = 600;
$default{"LOCALVERSION"} = "-test";
my $ktest_config;
@@ -81,6 +84,8 @@ my $addconfig;
my $in_bisect = 0;
my $bisect_bad = "";
my $reverse_bisect;
+my $bisect_manual;
+my $bisect_skip;
my $in_patchcheck = 0;
my $run_test;
my $redirect;
@@ -98,6 +103,7 @@ my $console;
my $success_line;
my $stop_after_success;
my $stop_after_failure;
+my $stop_test_after;
my $build_target;
my $target_image;
my $localversion;
@@ -462,6 +468,10 @@ sub dodie {
`$power_off`;
}
+ if (defined($opt{"LOG_FILE"})) {
+ print " See $opt{LOG_FILE} for more info.\n";
+ }
+
die @_, "\n";
}
@@ -760,8 +770,10 @@ sub monitor {
my $success_start;
my $failure_start;
+ my $monitor_start = time;
+ my $done = 0;
- for (;;) {
+ while (!$done) {
if ($booted) {
$line = wait_for_input($monitor_fp, $booted_timeout);
@@ -796,7 +808,7 @@ sub monitor {
}
if ($full_line =~ /call trace:/i) {
- if (!$skip_call_trace) {
+ if (!$bug && !$skip_call_trace) {
$bug = 1;
$failure_start = time;
}
@@ -816,12 +828,19 @@ sub monitor {
}
if ($full_line =~ /Kernel panic -/) {
+ $failure_start = time;
$bug = 1;
}
if ($line =~ /\n/) {
$full_line = "";
}
+
+ if ($stop_test_after > 0 && !$booted && !$bug) {
+ if (time - $monitor_start > $stop_test_after) {
+ $done = 1;
+ }
+ }
}
close(DMESG);
@@ -925,6 +944,18 @@ sub check_buildlog {
return 1;
}
+sub make_oldconfig {
+ my ($defconfig) = @_;
+
+ if (!run_command "$defconfig $make oldnoconfig") {
+ # Perhaps oldnoconfig doesn't exist in this version of the kernel
+ # try a yes '' | oldconfig
+ doprint "oldnoconfig failed, trying yes '' | make oldconfig\n";
+ run_command "yes '' | $defconfig $make oldconfig" or
+ dodie "failed make config oldconfig";
+ }
+}
+
sub build {
my ($type) = @_;
my $defconfig = "";
@@ -970,8 +1001,12 @@ sub build {
$defconfig = "KCONFIG_ALLCONFIG=$minconfig";
}
- run_command "$defconfig $make $type" or
- dodie "failed make config";
+ if ($type eq "oldnoconfig") {
+ make_oldconfig $defconfig;
+ } else {
+ run_command "$defconfig $make $type" or
+ dodie "failed make config";
+ }
$redirect = "$buildlog";
if (!run_command "$make $build_options") {
@@ -1025,6 +1060,21 @@ sub get_version {
doprint "$version\n";
}
+sub answer_bisect {
+ for (;;) {
+ doprint "Pass or fail? [p/f]";
+ my $ans = <STDIN>;
+ chomp $ans;
+ if ($ans eq "p" || $ans eq "P") {
+ return 1;
+ } elsif ($ans eq "f" || $ans eq "F") {
+ return 0;
+ } else {
+ print "Please answer 'P' or 'F'\n";
+ }
+ }
+}
+
sub child_run_test {
my $failed = 0;
@@ -1070,6 +1120,7 @@ sub do_run_test {
# we are not guaranteed to get a full line
$full_line .= $line;
+ doprint $line;
if ($full_line =~ /call trace:/i) {
$bug = 1;
@@ -1086,6 +1137,19 @@ sub do_run_test {
} while (!$child_done && !$bug);
if ($bug) {
+ my $failure_start = time;
+ my $now;
+ do {
+ $line = wait_for_input($monitor_fp, 1);
+ if (defined($line)) {
+ doprint $line;
+ }
+ $now = time;
+ if ($now - $failure_start >= $stop_after_failure) {
+ last;
+ }
+ } while (defined($line));
+
doprint "Detected kernel crash!\n";
# kill the child with extreme prejudice
kill 9, $child_pid;
@@ -1131,7 +1195,15 @@ sub run_git_bisect {
return 1;
}
-# returns 1 on success, 0 on failure
+sub bisect_reboot {
+ doprint "Reboot and sleep $bisect_sleep_time seconds\n";
+ reboot;
+ start_monitor;
+ wait_for_monitor $bisect_sleep_time;
+ end_monitor;
+}
+
+# returns 1 on success, 0 on failure, -1 on skip
sub run_bisect_test {
my ($type, $buildtype) = @_;
@@ -1145,6 +1217,10 @@ sub run_bisect_test {
build $buildtype or $failed = 1;
if ($type ne "build") {
+ if ($failed && $bisect_skip) {
+ $in_bisect = 0;
+ return -1;
+ }
dodie "Failed on build" if $failed;
# Now boot the box
@@ -1156,6 +1232,12 @@ sub run_bisect_test {
monitor or $failed = 1;
if ($type ne "boot") {
+ if ($failed && $bisect_skip) {
+ end_monitor;
+ bisect_reboot;
+ $in_bisect = 0;
+ return -1;
+ }
dodie "Failed on boot" if $failed;
do_run_test or $failed = 1;
@@ -1168,11 +1250,7 @@ sub run_bisect_test {
# reboot the box to a good kernel
if ($type ne "build") {
- doprint "Reboot and sleep $bisect_sleep_time seconds\n";
- reboot;
- start_monitor;
- wait_for_monitor $bisect_sleep_time;
- end_monitor;
+ bisect_reboot;
}
} else {
$result = 1;
@@ -1193,16 +1271,22 @@ sub run_bisect {
my $ret = run_bisect_test $type, $buildtype;
+ if ($bisect_manual) {
+ $ret = answer_bisect;
+ }
# Are we looking for where it worked, not failed?
if ($reverse_bisect) {
$ret = !$ret;
}
- if ($ret) {
+ if ($ret > 0) {
return "good";
- } else {
+ } elsif ($ret == 0) {
return "bad";
+ } elsif ($bisect_skip) {
+ doprint "HIT A BAD COMMIT ... SKIPPING\n";
+ return "skip";
}
}
@@ -1220,6 +1304,13 @@ sub bisect {
my $type = $opt{"BISECT_TYPE[$i]"};
my $start = $opt{"BISECT_START[$i]"};
my $replay = $opt{"BISECT_REPLAY[$i]"};
+ my $start_files = $opt{"BISECT_FILES[$i]"};
+
+ if (defined($start_files)) {
+ $start_files = " -- " . $start_files;
+ } else {
+ $start_files = "";
+ }
# convert to true sha1's
$good = get_sha1($good);
@@ -1273,7 +1364,7 @@ sub bisect {
die "Failed to checkout $head";
}
- run_command "git bisect start" or
+ run_command "git bisect start$start_files" or
dodie "could not start bisect";
run_command "git bisect good $good" or
@@ -1390,9 +1481,7 @@ sub create_config {
close(OUT);
# exit;
- run_command "$make oldnoconfig" or
- dodie "failed make config oldconfig";
-
+ make_oldconfig "";
}
sub compare_configs {
@@ -1505,7 +1594,9 @@ sub run_config_bisect {
}
$ret = run_config_bisect_test $type;
-
+ if ($bisect_manual) {
+ $ret = answer_bisect;
+ }
if ($ret) {
process_passed %current_config;
return 0;
@@ -1536,7 +1627,13 @@ sub run_config_bisect {
$half = int($#start_list / 2);
} while ($half > 0);
- # we found a single config, try it again
+ # we found a single config, try it again unless we are running manually
+
+ if ($bisect_manual) {
+ process_failed $start_list[0];
+ return 1;
+ }
+
my @tophalf = @start_list[0 .. 0];
$ret = run_config_bisect_test $type;
@@ -1594,8 +1691,7 @@ sub config_bisect {
close(IN);
# Now run oldconfig with the minconfig (and addconfigs)
- run_command "$defconfig $make oldnoconfig" or
- dodie "failed make config oldconfig";
+ make_oldconfig $defconfig;
# check to see what we lost (or gained)
open (IN, $output_config)
@@ -1907,6 +2003,8 @@ 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);
+ $bisect_manual = set_test_option("BISECT_MANUAL", $i);
+ $bisect_skip = set_test_option("BISECT_SKIP", $i);
$store_failures = set_test_option("STORE_FAILURES", $i);
$timeout = set_test_option("TIMEOUT", $i);
$booted_timeout = set_test_option("BOOTED_TIMEOUT", $i);
@@ -1914,6 +2012,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
$success_line = set_test_option("SUCCESS_LINE", $i);
$stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i);
$stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i);
+ $stop_test_after = set_test_option("STOP_TEST_AFTER", $i);
$build_target = set_test_option("BUILD_TARGET", $i);
$ssh_exec = set_test_option("SSH_EXEC", $i);
$scp_to_target = set_test_option("SCP_TO_TARGET", $i);
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index 3408c594b2de..4c5d6bd74a02 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -306,6 +306,14 @@
# (default 60)
#STOP_AFTER_FAILURE = 60
+# In case the console constantly fills the screen, having
+# a specified time to stop the test if it never succeeds nor fails
+# is recommended.
+# Note: this is ignored if a success or failure is detected.
+# (in seconds)
+# (default 600, -1 is to never stop)
+#STOP_TEST_AFTER = 600
+
# Stop testing if a build fails. If set, the script will end if
# a failure is detected, otherwise it will save off the .config,
# dmesg and bootlog in a directory called
@@ -519,6 +527,24 @@
# git bisect good, git bisect bad, and running the git bisect replay
# if the BISECT_REPLAY is set.
#
+# BISECT_SKIP = 1 (optional, default 0)
+#
+# If BISECT_TYPE is set to test but the build fails, ktest will
+# simply fail the test and end their. You could use BISECT_REPLAY
+# and BISECT_START to resume after you found a new starting point,
+# or you could set BISECT_SKIP to 1. If BISECT_SKIP is set to 1,
+# when something other than the BISECT_TYPE fails, ktest.pl will
+# run "git bisect skip" and try again.
+#
+# BISECT_FILES = <path> (optional, default undefined)
+#
+# To just run the git bisect on a specific path, set BISECT_FILES.
+# For example:
+#
+# BISECT_FILES = arch/x86 kernel/time
+#
+# Will run the bisect with "git bisect start -- arch/x86 kernel/time"
+#
# BISECT_REVERSE = 1 (optional, default 0)
#
# In those strange instances where it was broken forever
@@ -528,6 +554,15 @@
# With BISECT_REVERSE = 1, The test will consider failures as
# good, and success as bad.
#
+# BISECT_MANUAL = 1 (optional, default 0)
+#
+# In case there's a problem with automating the bisect for
+# whatever reason. (Can't reboot, want to inspect each iteration)
+# Doing a BISECT_MANUAL will have the test wait for you to
+# tell it if the test passed or failed after each iteration.
+# This is basicall the same as running git bisect yourself
+# but ktest will rebuild and install the kernel for you.
+#
# BISECT_CHECK = 1 (optional, default 0)
#
# Just to be sure the good is good and bad is bad, setting
@@ -613,10 +648,17 @@
#
# CONFIG_BISECT is the config that failed to boot
#
+# If BISECT_MANUAL is set, it will pause between iterations.
+# This is useful to use just ktest.pl just for the config bisect.
+# If you set it to build, it will run the bisect and you can
+# control what happens in between iterations. It will ask you if
+# the test succeeded or not and continue the config bisect.
+#
# Example:
# TEST_START
# TEST_TYPE = config_bisect
# CONFIG_BISECT_TYPE = build
# CONFIG_BISECT = /home/test/˘onfig-bad
# MIN_CONFIG = /home/test/config-min
+# BISECT_MANUAL = 1
#
OpenPOWER on IntegriCloud