mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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

  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®