aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/ktest
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2014-04-23 15:24:04 -0400
committerSteven Rostedt <rostedt@goodmis.org>2014-04-23 23:18:15 -0400
commit6071c22e17552a88562182cd3ad21fcb8bd37130 (patch)
treecc38c426194d10c5a9e5e6999b92d744454ca3d9 /tools/testing/ktest
parent5269faad27f8ed8df1c7ba520a8de628fd248362 (diff)
ktest: Rewrite the config-bisect to actually work
I never liked the way config-bisect worked. I would assume the bad config had some config that broke the system. But it would not work if the bad config just happened to be missing something that the good config had. I rewrote the config-bisect to do this properly. It does a diff of the two configs, and sets half of the configs that are in one and not the other. The way it works is that when it "sets", it really just makes one copy what the other has. That is, a "set" can be setting a: # CONFIG_FOO is not set Basically, it looks at the differences between the two files and makes them similar until it comes down to one config that makes it work or not work depending on if it is set or not. Note, if more than one config change makes the bad config not work, it will only find one of them. But this is true with all bisect logic. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'tools/testing/ktest')
-rwxr-xr-xtools/testing/ktest/ktest.pl452
1 files changed, 226 insertions, 226 deletions
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index c34f0dedad2d..52f558efdb0a 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -2784,12 +2784,17 @@ my %dependency;
2784sub assign_configs { 2784sub assign_configs {
2785 my ($hash, $config) = @_; 2785 my ($hash, $config) = @_;
2786 2786
2787 doprint "Reading configs from $config\n";
2788
2787 open (IN, $config) 2789 open (IN, $config)
2788 or dodie "Failed to read $config"; 2790 or dodie "Failed to read $config";
2789 2791
2790 while (<IN>) { 2792 while (<IN>) {
2793 chomp;
2791 if (/^((CONFIG\S*)=.*)/) { 2794 if (/^((CONFIG\S*)=.*)/) {
2792 ${$hash}{$2} = $1; 2795 ${$hash}{$2} = $1;
2796 } elsif (/^(# (CONFIG\S*) is not set)/) {
2797 ${$hash}{$2} = $1;
2793 } 2798 }
2794 } 2799 }
2795 2800
@@ -2841,53 +2846,97 @@ sub get_dependencies {
2841 return @deps; 2846 return @deps;
2842} 2847}
2843 2848
2849sub save_config {
2850 my ($pc, $file) = @_;
2851
2852 my %configs = %{$pc};
2853
2854 doprint "Saving configs into $file\n";
2855
2856 open(OUT, ">$file") or dodie "Can not write to $file";
2857
2858 foreach my $config (keys %configs) {
2859 print OUT "$configs{$config}\n";
2860 }
2861 close(OUT);
2862}
2863
2844sub create_config { 2864sub create_config {
2845 my @configs = @_; 2865 my ($name, $pc) = @_;
2846 2866
2847 open(OUT, ">$output_config") or dodie "Can not write to $output_config"; 2867 doprint "Creating old config from $name configs\n";
2848 2868
2849 foreach my $config (@configs) { 2869 save_config $pc, $output_config;
2850 print OUT "$config_set{$config}\n"; 2870
2851 my @deps = get_dependencies $config; 2871 make_oldconfig;
2852 foreach my $dep (@deps) { 2872}
2853 print OUT "$config_set{$dep}\n"; 2873
2874# compare two config hashes, and return configs with different vals.
2875# It returns B's config values, but you can use A to see what A was.
2876sub diff_config_vals {
2877 my ($pa, $pb) = @_;
2878
2879 # crappy Perl way to pass in hashes.
2880 my %a = %{$pa};
2881 my %b = %{$pb};
2882
2883 my %ret;
2884
2885 foreach my $item (keys %a) {
2886 if (defined($b{$item}) && $b{$item} ne $a{$item}) {
2887 $ret{$item} = $b{$item};
2854 } 2888 }
2855 } 2889 }
2856 2890
2857 # turn off configs to keep off 2891 return %ret;
2858 foreach my $config (keys %config_off) { 2892}
2859 print OUT "# $config is not set\n";
2860 }
2861 2893
2862 # turn off configs that should be off for now 2894# compare two config hashes and return the configs in B but not A
2863 foreach my $config (@config_off_tmp) { 2895sub diff_configs {
2864 print OUT "# $config is not set\n"; 2896 my ($pa, $pb) = @_;
2865 } 2897
2898 my %ret;
2899
2900 # crappy Perl way to pass in hashes.
2901 my %a = %{$pa};
2902 my %b = %{$pb};
2866 2903
2867 foreach my $config (keys %config_ignore) { 2904 foreach my $item (keys %b) {
2868 print OUT "$config_ignore{$config}\n"; 2905 if (!defined($a{$item})) {
2906 $ret{$item} = $b{$item};
2907 }
2869 } 2908 }
2870 close(OUT);
2871 2909
2872 make_oldconfig; 2910 return %ret;
2873} 2911}
2874 2912
2913# return if two configs are equal or not
2914# 0 is equal +1 b has something a does not
2915# +1 if a and b have a different item.
2916# -1 if a has something b does not
2875sub compare_configs { 2917sub compare_configs {
2876 my (%a, %b) = @_; 2918 my ($pa, $pb) = @_;
2877 2919
2878 foreach my $item (keys %a) { 2920 my %ret;
2879 if (!defined($b{$item})) { 2921
2880 print "diff $item\n"; 2922 # crappy Perl way to pass in hashes.
2923 my %a = %{$pa};
2924 my %b = %{$pb};
2925
2926 foreach my $item (keys %b) {
2927 if (!defined($a{$item})) {
2928 return 1;
2929 }
2930 if ($a{$item} ne $b{$item}) {
2881 return 1; 2931 return 1;
2882 } 2932 }
2883 delete $b{$item};
2884 } 2933 }
2885 2934
2886 my @keys = keys %b; 2935 foreach my $item (keys %a) {
2887 if ($#keys) { 2936 if (!defined($b{$item})) {
2888 print "diff2 $keys[0]\n"; 2937 return -1;
2938 }
2889 } 2939 }
2890 return -1 if ($#keys >= 0);
2891 2940
2892 return 0; 2941 return 0;
2893} 2942}
@@ -2923,253 +2972,204 @@ sub process_failed {
2923 doprint "***************************************\n\n"; 2972 doprint "***************************************\n\n";
2924} 2973}
2925 2974
2926sub run_config_bisect { 2975# used for config bisecting
2976my $good_config;
2977my $bad_config;
2927 2978
2928 my @start_list = keys %config_list; 2979sub process_new_config {
2980 my ($tc, $nc, $gc, $bc) = @_;
2929 2981
2930 if ($#start_list < 0) { 2982 my %tmp_config = %{$tc};
2931 doprint "No more configs to test!!!\n"; 2983 my %good_configs = %{$gc};
2932 return -1; 2984 my %bad_configs = %{$bc};
2933 }
2934 2985
2935 doprint "***** RUN TEST ***\n"; 2986 my %new_configs;
2936 my $type = $config_bisect_type;
2937 my $ret;
2938 my %current_config;
2939 2987
2940 my $count = $#start_list + 1; 2988 my $runtest = 1;
2941 doprint " $count configs to test\n"; 2989 my $ret;
2942 2990
2943 my $half = int($#start_list / 2); 2991 create_config "tmp_configs", \%tmp_config;
2992 assign_configs \%new_configs, $output_config;
2944 2993
2945 do { 2994 $ret = compare_configs \%new_configs, \%bad_configs;
2946 my @tophalf = @start_list[0 .. $half]; 2995 if (!$ret) {
2996 doprint "New config equals bad config, try next test\n";
2997 $runtest = 0;
2998 }
2947 2999
2948 # keep the bottom half off 3000 if ($runtest) {
2949 if ($half < $#start_list) { 3001 $ret = compare_configs \%new_configs, \%good_configs;
2950 @config_off_tmp = @start_list[$half + 1 .. $#start_list]; 3002 if (!$ret) {
2951 } else { 3003 doprint "New config equals good config, try next test\n";
2952 @config_off_tmp = (); 3004 $runtest = 0;
2953 } 3005 }
3006 }
2954 3007
2955 create_config @tophalf; 3008 %{$nc} = %new_configs;
2956 read_current_config \%current_config;
2957
2958 $count = $#tophalf + 1;
2959 doprint "Testing $count configs\n";
2960 my $found = 0;
2961 # make sure we test something
2962 foreach my $config (@tophalf) {
2963 if (defined($current_config{$config})) {
2964 logit " $config\n";
2965 $found = 1;
2966 }
2967 }
2968 if (!$found) {
2969 # try the other half
2970 doprint "Top half produced no set configs, trying bottom half\n";
2971
2972 # keep the top half off
2973 @config_off_tmp = @tophalf;
2974 @tophalf = @start_list[$half + 1 .. $#start_list];
2975
2976 create_config @tophalf;
2977 read_current_config \%current_config;
2978 foreach my $config (@tophalf) {
2979 if (defined($current_config{$config})) {
2980 logit " $config\n";
2981 $found = 1;
2982 }
2983 }
2984 if (!$found) {
2985 doprint "Failed: Can't make new config with current configs\n";
2986 foreach my $config (@start_list) {
2987 doprint " CONFIG: $config\n";
2988 }
2989 return -1;
2990 }
2991 $count = $#tophalf + 1;
2992 doprint "Testing $count configs\n";
2993 }
2994 3009
2995 $ret = run_config_bisect_test $type; 3010 return $runtest;
2996 if ($bisect_manual) { 3011}
2997 $ret = answer_bisect;
2998 }
2999 if ($ret) {
3000 process_passed %current_config;
3001 return 0;
3002 }
3003 3012
3004 doprint "This config had a failure.\n"; 3013sub run_config_bisect {
3005 doprint "Removing these configs that were not set in this config:\n"; 3014 my ($pgood, $pbad) = @_;
3006 doprint "config copied to $outputdir/config_bad\n";
3007 run_command "cp -f $output_config $outputdir/config_bad";
3008 3015
3009 # A config exists in this group that was bad. 3016 my $type = $config_bisect_type;
3010 foreach my $config (keys %config_list) {
3011 if (!defined($current_config{$config})) {
3012 doprint " removing $config\n";
3013 delete $config_list{$config};
3014 }
3015 }
3016 3017
3017 @start_list = @tophalf; 3018 my %good_configs = %{$pgood};
3019 my %bad_configs = %{$pbad};
3018 3020
3019 if ($#start_list == 0) { 3021 my %diff_configs = diff_config_vals \%good_configs, \%bad_configs;
3020 process_failed $start_list[0]; 3022 my %b_configs = diff_configs \%good_configs, \%bad_configs;
3021 return 1; 3023 my %g_configs = diff_configs \%bad_configs, \%good_configs;
3022 }
3023 3024
3024 # remove half the configs we are looking at and see if 3025 my @diff_arr = keys %diff_configs;
3025 # they are good. 3026 my $len_diff = $#diff_arr + 1;
3026 $half = int($#start_list / 2);
3027 } while ($#start_list > 0);
3028 3027
3029 # we found a single config, try it again unless we are running manually 3028 my @b_arr = keys %b_configs;
3029 my $len_b = $#b_arr + 1;
3030 3030
3031 if ($bisect_manual) { 3031 my @g_arr = keys %g_configs;
3032 process_failed $start_list[0]; 3032 my $len_g = $#g_arr + 1;
3033 return 1;
3034 }
3035 3033
3036 my @tophalf = @start_list[0 .. 0]; 3034 my $runtest = 1;
3035 my %new_configs;
3036 my $ret;
3037 3037
3038 $ret = run_config_bisect_test $type; 3038 # First, lets get it down to a single subset.
3039 if ($ret) { 3039 # Is the problem with a difference in values?
3040 process_passed %current_config; 3040 # Is the problem with a missing config?
3041 return 0; 3041 # Is the problem with a config that breaks things?
3042 }
3043 3042
3044 process_failed $start_list[0]; 3043 # Enable all of one set and see if we get a new bad
3045 return 1; 3044 # or good config.
3046}
3047 3045
3048sub config_bisect { 3046 # first set the good config to the bad values.
3049 my ($i) = @_;
3050 3047
3051 my $start_config = $config_bisect; 3048 doprint "d=$len_diff g=$len_g b=$len_b\n";
3052 3049
3053 my $tmpconfig = "$tmpdir/use_config"; 3050 # first lets enable things in bad config that are enabled in good config
3054 3051
3055 if (defined($config_bisect_good)) { 3052 if ($len_diff > 0) {
3056 process_config_ignore $config_bisect_good; 3053 if ($len_b > 0 || $len_g > 0) {
3057 } 3054 my %tmp_config = %bad_configs;
3058 3055
3059 # Make the file with the bad config and the min config 3056 doprint "Set tmp config to be bad config with good config values\n";
3060 if (defined($minconfig)) { 3057 foreach my $item (@diff_arr) {
3061 # read the min config for things to ignore 3058 $tmp_config{$item} = $good_configs{$item};
3062 run_command "cp $minconfig $tmpconfig" or 3059 }
3063 dodie "failed to copy $minconfig to $tmpconfig";
3064 } else {
3065 unlink $tmpconfig;
3066 }
3067 3060
3068 if (-f $tmpconfig) { 3061 $runtest = process_new_config \%tmp_config, \%new_configs,
3069 load_force_config($tmpconfig); 3062 \%good_configs, \%bad_configs;
3070 process_config_ignore $tmpconfig; 3063 }
3071 } 3064 }
3072 3065
3073 # now process the start config 3066 if (!$runtest && $len_diff > 0) {
3074 run_command "cp $start_config $output_config" or
3075 dodie "failed to copy $start_config to $output_config";
3076 3067
3077 # read directly what we want to check 3068 if ($len_diff == 1) {
3078 my %config_check; 3069 doprint "The bad config setting is: $diff_arr[0]\n";
3079 open (IN, $output_config) 3070 return 1;
3080 or dodie "failed to open $output_config"; 3071 }
3072 my %tmp_config = %bad_configs;
3081 3073
3082 while (<IN>) { 3074 my $half = int($#diff_arr / 2);
3083 if (/^((CONFIG\S*)=.*)/) { 3075 my @tophalf = @diff_arr[0 .. $half];
3084 $config_check{$2} = $1; 3076
3077 doprint "Settings bisect with top half:\n";
3078 doprint "Set tmp config to be bad config with some good config values\n";
3079 foreach my $item (@tophalf) {
3080 $tmp_config{$item} = $good_configs{$item};
3085 } 3081 }
3086 }
3087 close(IN);
3088 3082
3089 # Now run oldconfig with the minconfig 3083 $runtest = process_new_config \%tmp_config, \%new_configs,
3090 make_oldconfig; 3084 \%good_configs, \%bad_configs;
3091 3085
3092 # check to see what we lost (or gained) 3086 if (!$runtest) {
3093 open (IN, $output_config) 3087 my %tmp_config = %bad_configs;
3094 or dodie "Failed to read $start_config";
3095 3088
3096 my %removed_configs; 3089 doprint "Try bottom half\n";
3097 my %added_configs;
3098 3090
3099 while (<IN>) { 3091 my @bottomhalf = @diff_arr[$half+1 .. $#diff_arr];
3100 if (/^((CONFIG\S*)=.*)/) { 3092
3101 # save off all options 3093 foreach my $item (@bottomhalf) {
3102 $config_set{$2} = $1; 3094 $tmp_config{$item} = $good_configs{$item};
3103 if (defined($config_check{$2})) {
3104 if (defined($config_ignore{$2})) {
3105 $removed_configs{$2} = $1;
3106 } else {
3107 $config_list{$2} = $1;
3108 }
3109 } elsif (!defined($config_ignore{$2})) {
3110 $added_configs{$2} = $1;
3111 $config_list{$2} = $1;
3112 } 3095 }
3113 } elsif (/^# ((CONFIG\S*).*)/) {
3114 # Keep these configs disabled
3115 $config_set{$2} = $1;
3116 $config_off{$2} = $1;
3117 }
3118 }
3119 close(IN);
3120 3096
3121 my @confs = keys %removed_configs; 3097 $runtest = process_new_config \%tmp_config, \%new_configs,
3122 if ($#confs >= 0) { 3098 \%good_configs, \%bad_configs;
3123 doprint "Configs overridden by default configs and removed from check:\n";
3124 foreach my $config (@confs) {
3125 doprint " $config\n";
3126 } 3099 }
3127 } 3100 }
3128 @confs = keys %added_configs; 3101
3129 if ($#confs >= 0) { 3102 if ($runtest) {
3130 doprint "Configs appearing in make oldconfig and added:\n"; 3103 $ret = run_config_bisect_test $type;
3131 foreach my $config (@confs) { 3104 if ($ret) {
3132 doprint " $config\n"; 3105 doprint "NEW GOOD CONFIG\n";
3106 %good_configs = %new_configs;
3107 run_command "mv $good_config ${good_config}.last";
3108 save_config \%good_configs, $good_config;
3109 %{$pgood} = %good_configs;
3110 } else {
3111 doprint "NEW BAD CONFIG\n";
3112 %bad_configs = %new_configs;
3113 run_command "mv $bad_config ${bad_config}.last";
3114 save_config \%bad_configs, $bad_config;
3115 %{$pbad} = %bad_configs;
3133 } 3116 }
3117 return 0;
3134 } 3118 }
3135 3119
3136 my %config_test; 3120 fail "Hmm, need to do a mix match?\n";
3137 my $once = 0; 3121 return -1;
3122}
3138 3123
3139 @config_off_tmp = (); 3124sub config_bisect {
3125 my ($i) = @_;
3140 3126
3141 # Sometimes kconfig does weird things. We must make sure 3127 my $type = $config_bisect_type;
3142 # that the config we autocreate has everything we need
3143 # to test, otherwise we may miss testing configs, or
3144 # may not be able to create a new config.
3145 # Here we create a config with everything set.
3146 create_config (keys %config_list);
3147 read_current_config \%config_test;
3148 foreach my $config (keys %config_list) {
3149 if (!defined($config_test{$config})) {
3150 if (!$once) {
3151 $once = 1;
3152 doprint "Configs not produced by kconfig (will not be checked):\n";
3153 }
3154 doprint " $config\n";
3155 delete $config_list{$config};
3156 }
3157 }
3158 my $ret;
3159 3128
3160 if (defined($config_bisect_check) && $config_bisect_check) { 3129 $bad_config = $config_bisect;
3161 doprint " Checking to make sure bad config with min config fails\n"; 3130
3162 create_config keys %config_list; 3131 if (defined($config_bisect_good)) {
3163 $ret = run_config_bisect_test $config_bisect_type; 3132 $good_config = $config_bisect_good;
3164 if ($ret) { 3133 } elsif (defined($minconfig)) {
3165 doprint " FAILED! Bad config with min config boots fine\n"; 3134 $good_config = $minconfig;
3166 return -1; 3135 } else {
3136 doprint "No config specified, checking if defconfig works";
3137 my $ret = run_bisect_test $type, "defconfig";
3138 if (!$ret) {
3139 fail "Have no good config to compare with, please set CONFIG_BISECT_GOOD";
3140 return 1;
3167 } 3141 }
3168 doprint " Bad config with min config fails as expected\n"; 3142 $good_config = $output_config;
3169 } 3143 }
3170 3144
3145 # we don't want min configs to cause issues here.
3146 doprint "Disabling 'MIN_CONFIG' for this test\n";
3147 undef $minconfig;
3148
3149 my %good_configs;
3150 my %bad_configs;
3151 my %tmp_configs;
3152
3153 doprint "Run good configs through make oldconfig\n";
3154 assign_configs \%tmp_configs, $good_config;
3155 create_config "$good_config", \%tmp_configs;
3156 assign_configs \%good_configs, $output_config;
3157
3158 doprint "Run bad configs through make oldconfig\n";
3159 assign_configs \%tmp_configs, $bad_config;
3160 create_config "$bad_config", \%tmp_configs;
3161 assign_configs \%bad_configs, $output_config;
3162
3163 $good_config = "$tmpdir/good_config";
3164 $bad_config = "$tmpdir/bad_config";
3165
3166 save_config \%good_configs, $good_config;
3167 save_config \%bad_configs, $bad_config;
3168
3169 my $ret;
3170
3171 do { 3171 do {
3172 $ret = run_config_bisect; 3172 $ret = run_config_bisect \%good_configs, \%bad_configs;
3173 } while (!$ret); 3173 } while (!$ret);
3174 3174
3175 return $ret if ($ret < 0); 3175 return $ret if ($ret < 0);