From: Scott Wood <swood@redhat.com>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: linux-kernel@vger.kernel.org, Scott Wood <swood@redhat.com>
Subject: [PATCH 4/8] ktest: Separate out config bisect logic
Date: Sun, 16 Jul 2017 19:16:26 -0500 [thread overview]
Message-ID: <20170717001630.10518-4-swood@redhat.com> (raw)
In-Reply-To: <20170717001630.10518-1-swood@redhat.com>
From: Scott Wood <oss@buserror.net>
This allows config bisecting to be performed when building on the machine
being tested -- all required state is saved in the filesystem rather than
requiring one script instance to run for the duration of the bisecting.
Plus, while ktest appears very featureful, it is also a bit complicated
to set up, which can be a barrier to accessing the config bisect
functionality. Separating it is more in line with traditional Unix
philosophy of small tools working together rather than a big monolith.
Signed-off-by: Scott Wood <swood@redhat.com>
---
tools/testing/ktest/config-bisect.pl | 280 +++++++++++++++++++++++++++++++++++
1 file changed, 280 insertions(+)
create mode 100755 tools/testing/ktest/config-bisect.pl
diff --git a/tools/testing/ktest/config-bisect.pl b/tools/testing/ktest/config-bisect.pl
new file mode 100755
index 000000000000..1768d145ced8
--- /dev/null
+++ b/tools/testing/ktest/config-bisect.pl
@@ -0,0 +1,280 @@
+#!/usr/bin/perl -w
+#
+# Copyright 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
+# Licensed under the terms of the GNU GPL License version 2
+#
+
+use strict;
+
+my $outputdir;
+
+sub make_oldconfig {
+ if (system "\$MAKE O=$outputdir olddefconfig") {
+ # Perhaps olddefconfig doesn't exist in this version of
+ # the kernel; try oldnoconfig
+ print "olddefconfig failed, trying make oldnoconfig\n";
+ if (system "\$MAKE O=$outputdir oldnoconfig") {
+ print "oldnoconfig failed, trying yes '' | make oldconfig\n";
+ # try a yes '' | oldconfig
+ system "yes '' | \$MAKE O=$outputdir oldconfig" == 0 or
+ die "failed make config oldconfig";
+ }
+ }
+}
+
+sub assign_configs {
+ my ($hash, $config) = @_;
+
+ print "Reading configs from $config\n";
+
+ open (IN, $config)
+ or die "Failed to read $config";
+
+ while (<IN>) {
+ chomp;
+ if (/^((CONFIG\S*)=.*)/) {
+ ${$hash}{$2} = $1;
+ } elsif (/^(# (CONFIG\S*) is not set)/) {
+ ${$hash}{$2} = $1;
+ }
+ }
+
+ close(IN);
+}
+
+sub save_config {
+ my ($pc, $file) = @_;
+
+ my %configs = %{$pc};
+
+ print "Saving configs into $file\n";
+
+ open(OUT, ">$file") or die "Can not write to $file";
+
+ foreach my $config (keys %configs) {
+ print OUT "$configs{$config}\n";
+ }
+ close(OUT);
+
+ make_oldconfig;
+}
+
+# compare two config hashes, and return configs with different vals.
+# It returns B's config values, but you can use A to see what A was.
+sub diff_config_vals {
+ my ($pa, $pb) = @_;
+
+ # crappy Perl way to pass in hashes.
+ my %a = %{$pa};
+ my %b = %{$pb};
+
+ my %ret;
+
+ foreach my $item (keys %a) {
+ if (defined($b{$item}) && $b{$item} ne $a{$item}) {
+ $ret{$item} = $b{$item};
+ }
+ }
+
+ return %ret;
+}
+
+# compare two config hashes and return the configs in B but not A
+sub diff_configs {
+ my ($pa, $pb) = @_;
+
+ my %ret;
+
+ # crappy Perl way to pass in hashes.
+ my %a = %{$pa};
+ my %b = %{$pb};
+
+ foreach my $item (keys %b) {
+ if (!defined($a{$item})) {
+ $ret{$item} = $b{$item};
+ }
+ }
+
+ return %ret;
+}
+
+# return if two configs are equal or not
+# 0 is equal +1 b has something a does not
+# +1 if a and b have a different item.
+# -1 if a has something b does not
+sub compare_configs {
+ my ($pa, $pb) = @_;
+
+ my %ret;
+
+ # crappy Perl way to pass in hashes.
+ my %a = %{$pa};
+ my %b = %{$pb};
+
+ foreach my $item (keys %b) {
+ if (!defined($a{$item})) {
+ return 1;
+ }
+ if ($a{$item} ne $b{$item}) {
+ return 1;
+ }
+ }
+
+ foreach my $item (keys %a) {
+ if (!defined($b{$item})) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+sub process_new_config {
+ my ($tc, $nc, $gc, $bc, $ofile) = @_;
+
+ my %tmp_config = %{$tc};
+ my %good_configs = %{$gc};
+ my %bad_configs = %{$bc};
+
+ my %new_configs;
+
+ my $runtest = 1;
+ my $ret;
+
+ save_config \%tmp_config, $ofile;
+ assign_configs \%new_configs, $ofile;
+
+ $ret = compare_configs \%new_configs, \%bad_configs;
+ if (!$ret) {
+ print "New config equals bad config, try next test\n";
+ $runtest = 0;
+ }
+
+ if ($runtest) {
+ $ret = compare_configs \%new_configs, \%good_configs;
+ if (!$ret) {
+ print "New config equals good config, try next test\n";
+ $runtest = 0;
+ }
+ }
+
+ %{$nc} = %new_configs;
+
+ return $runtest;
+}
+
+sub run_config_bisect {
+ my ($outfile, $pgood, $pbad) = @_;
+
+ my %good_configs = %{$pgood};
+ my %bad_configs = %{$pbad};
+
+ my %diff_configs = diff_config_vals \%good_configs, \%bad_configs;
+ my %b_configs = diff_configs \%good_configs, \%bad_configs;
+ my %g_configs = diff_configs \%bad_configs, \%good_configs;
+
+ my @diff_arr = keys %diff_configs;
+ my $len_diff = $#diff_arr + 1;
+
+ my @b_arr = keys %b_configs;
+ my $len_b = $#b_arr + 1;
+
+ my @g_arr = keys %g_configs;
+ my $len_g = $#g_arr + 1;
+
+ my $runtest = 1;
+ my %new_configs;
+ my $ret;
+
+ # First, lets get it down to a single subset.
+ # Is the problem with a difference in values?
+ # Is the problem with a missing config?
+ # Is the problem with a config that breaks things?
+
+ # Enable all of one set and see if we get a new bad
+ # or good config.
+
+ # first set the good config to the bad values.
+
+ print "d=$len_diff g=$len_g b=$len_b\n";
+
+ # first lets enable things in bad config that are enabled in good config
+
+ if ($len_diff > 0) {
+ if ($len_b > 0 || $len_g > 0) {
+ my %tmp_config = %bad_configs;
+
+ print "Set tmp config to be bad config with good config values\n";
+ foreach my $item (@diff_arr) {
+ $tmp_config{$item} = $good_configs{$item};
+ }
+
+ $runtest = process_new_config \%tmp_config,
+ \%new_configs, \%good_configs,
+ \%bad_configs, $outfile;
+ }
+ }
+
+ if (!$runtest && $len_diff > 0) {
+
+ if ($len_diff == 1) {
+ process_failed $diff_arr[0];
+ return 1;
+ }
+ my %tmp_config = %bad_configs;
+
+ my $half = int($#diff_arr / 2);
+ my @tophalf = @diff_arr[0 .. $half];
+
+ print "Settings bisect with top half:\n";
+ print "Set tmp config to be bad config with some good config values\n";
+ foreach my $item (@tophalf) {
+ $tmp_config{$item} = $good_configs{$item};
+ }
+
+ $runtest = process_new_config \%tmp_config, \%new_configs,
+ \%good_configs, \%bad_configs, $outfile;
+
+ if (!$runtest) {
+ my %tmp_config = %bad_configs;
+
+ print "Try bottom half\n";
+
+ my @bottomhalf = @diff_arr[$half+1 .. $#diff_arr];
+
+ foreach my $item (@bottomhalf) {
+ $tmp_config{$item} = $good_configs{$item};
+ }
+
+ $runtest = process_new_config \%tmp_config,
+ \%new_configs, \%good_configs,
+ \%bad_configs, $outfile;
+ }
+ }
+
+}
+
+sub cb_by_file {
+ my ($outfile, $goodfile, $badfile) = @_;
+ my (%good, %bad);
+
+ assign_configs \%good, $goodfile;
+ assign_configs \%bad, $badfile;
+
+ run_config_bisect $outfile, \%good, \%bad;
+}
+
+if (!defined($ARGV[2])) {
+ print "Usage: $0 <outputdir> <good> <bad>\n";
+ exit 1;
+}
+
+if (!defined($ENV{MAKE})) {
+ $ENV{MAKE} = "make";
+}
+
+$outputdir = $ARGV[0];
+
+cb_by_file("${outputdir}/.config", $ARGV[1], $ARGV[2]);
+exit 0;
--
2.9.4
next prev parent reply other threads:[~2017-07-17 0:17 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-07-17 0:16 [PATCH 1/8] ktest: Clarify config file usage Scott Wood
2017-07-17 0:16 ` [PATCH 2/8] ktest: Set buildonly=1 for CONFIG_BISECT_TYPE=build Scott Wood
2017-07-17 0:16 ` [PATCH 3/8] ktest: Set do_not_reboot=y " Scott Wood
2017-07-17 0:16 ` Scott Wood [this message]
2017-07-17 0:16 ` [PATCH 5/8] ktest/config_bisect: Simplify bisect logic Scott Wood
2017-07-17 0:16 ` [PATCH 6/8] ktest/config-bisect: Try harder to find a new config Scott Wood
2017-07-17 0:16 ` [PATCH 7/8] ktest: Add simple config-bisect frontend Scott Wood
2017-07-17 0:16 ` [PATCH 8/8] ktest: Use config-bisect.pl in ktest.pl Scott Wood
2017-09-14 21:41 ` Scott Wood
2017-10-04 19:17 ` Steven Rostedt
2017-10-04 19:18 ` Steven Rostedt
2017-10-04 20:24 ` Scott Wood
2017-10-05 12:50 ` Steven Rostedt
2017-10-05 23:18 ` Scott Wood
2017-10-05 19:43 ` Steven Rostedt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170717001630.10518-4-swood@redhat.com \
--to=swood@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=rostedt@goodmis.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®