From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751382AbdGQARb (ORCPT ); Sun, 16 Jul 2017 20:17:31 -0400 Received: from mx1.redhat.com ([209.132.183.28]:43804 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751269AbdGQAQg (ORCPT ); Sun, 16 Jul 2017 20:16:36 -0400 DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 05FC966861 Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=swood@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 05FC966861 From: Scott Wood To: Steven Rostedt Cc: linux-kernel@vger.kernel.org, Scott Wood Subject: [PATCH 4/8] ktest: Separate out config bisect logic Date: Sun, 16 Jul 2017 19:16:26 -0500 Message-Id: <20170717001630.10518-4-swood@redhat.com> In-Reply-To: <20170717001630.10518-1-swood@redhat.com> References: <20170717001630.10518-1-swood@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Mon, 17 Jul 2017 00:16:36 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Scott Wood 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 --- 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 , 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 () { + 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 \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