~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/ktest/config-bisect.pl

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /tools/testing/ktest/config-bisect.pl (Version linux-6.12-rc7) and /tools/testing/ktest/config-bisect.pl (Version linux-5.12.19)


  1 #!/usr/bin/perl -w                                  1 #!/usr/bin/perl -w
  2 # SPDX-License-Identifier: GPL-2.0-only             2 # SPDX-License-Identifier: GPL-2.0-only
  3 #                                                   3 #
  4 # Copyright 2015 - Steven Rostedt, Red Hat Inc      4 # Copyright 2015 - Steven Rostedt, Red Hat Inc.
  5 # Copyright 2017 - Steven Rostedt, VMware, Inc      5 # Copyright 2017 - Steven Rostedt, VMware, Inc.
  6 #                                                   6 #
  7                                                     7 
  8 # usage:                                            8 # usage:
  9 #  config-bisect.pl [options] good-config bad-      9 #  config-bisect.pl [options] good-config bad-config [good|bad]
 10 #                                                  10 #
 11                                                    11 
 12 # Compares a good config to a bad config, then     12 # Compares a good config to a bad config, then takes half of the diffs
 13 # and produces a config that is somewhere betw     13 # and produces a config that is somewhere between the good config and
 14 # the bad config. That is, the resulting confi     14 # the bad config. That is, the resulting config will start with the
 15 # good config and will try to make half of the     15 # good config and will try to make half of the differences of between
 16 # the good and bad configs match the bad confi     16 # the good and bad configs match the bad config. It tries because of
 17 # dependencies between the two configs it may      17 # dependencies between the two configs it may not be able to change
 18 # exactly half of the configs that are differe     18 # exactly half of the configs that are different between the two config
 19 # files.                                           19 # files.
 20                                                    20 
 21 # Here's a normal way to use it:                   21 # Here's a normal way to use it:
 22 #                                                  22 #
 23 #  $ cd /path/to/linux/kernel                      23 #  $ cd /path/to/linux/kernel
 24 #  $ config-bisect.pl /path/to/good/config /pa     24 #  $ config-bisect.pl /path/to/good/config /path/to/bad/config
 25                                                    25 
 26 # This will now pull in good config (blowing a     26 # This will now pull in good config (blowing away .config in that directory
 27 # so do not make that be one of the good or ba     27 # so do not make that be one of the good or bad configs), and then
 28 # build the config with "make oldconfig" to ma     28 # build the config with "make oldconfig" to make sure it matches the
 29 # current kernel. It will then store the confi     29 # current kernel. It will then store the configs in that result for
 30 # the good config. It does the same for the ba     30 # the good config. It does the same for the bad config as well.
 31 # The algorithm will run, merging half of the      31 # The algorithm will run, merging half of the differences between
 32 # the two configs and building them with "make     32 # the two configs and building them with "make oldconfig" to make sure
 33 # the result changes (dependencies may reset c     33 # the result changes (dependencies may reset changes the tool had made).
 34 # It then copies the result of its good config     34 # It then copies the result of its good config to /path/to/good/config.tmp
 35 # and the bad config to /path/to/bad/config.tm     35 # and the bad config to /path/to/bad/config.tmp (just appends ".tmp" to the
 36 # files passed in). And the ".config" that you     36 # files passed in). And the ".config" that you should test will be in
 37 # directory                                        37 # directory
 38                                                    38 
 39 # After the first run, determine if the result     39 # After the first run, determine if the result is good or bad then
 40 # run the same command appending the result        40 # run the same command appending the result
 41                                                    41 
 42 # For good results:                                42 # For good results:
 43 #  $ config-bisect.pl /path/to/good/config /pa     43 #  $ config-bisect.pl /path/to/good/config /path/to/bad/config good
 44                                                    44 
 45 # For bad results:                                 45 # For bad results:
 46 #  $ config-bisect.pl /path/to/good/config /pa     46 #  $ config-bisect.pl /path/to/good/config /path/to/bad/config bad
 47                                                    47 
 48 # Do not change the good-config or bad-config,     48 # Do not change the good-config or bad-config, config-bisect.pl will
 49 # copy the good-config to a temp file with the     49 # copy the good-config to a temp file with the same name as good-config
 50 # but with a ".tmp" after it. It will do the s     50 # but with a ".tmp" after it. It will do the same with the bad-config.
 51                                                    51 
 52 # If "good" or "bad" is not stated at the end,     52 # If "good" or "bad" is not stated at the end, it will copy the good and
 53 # bad configs to the .tmp versions. If a .tmp      53 # bad configs to the .tmp versions. If a .tmp version already exists, it will
 54 # warn before writing over them (-r will not w     54 # warn before writing over them (-r will not warn, and just write over them).
 55 # If the last config is labeled "good", then i     55 # If the last config is labeled "good", then it will copy it to the good .tmp
 56 # version. If the last config is labeled "bad"     56 # version. If the last config is labeled "bad", it will copy it to the bad
 57 # .tmp version. It will continue this until it     57 # .tmp version. It will continue this until it can not merge the two any more
 58 # without the result being equal to either the     58 # without the result being equal to either the good or bad .tmp configs.
 59                                                    59 
 60 my $start = 0;                                     60 my $start = 0;
 61 my $val = "";                                      61 my $val = "";
 62                                                    62 
 63 my $pwd = `pwd`;                                   63 my $pwd = `pwd`;
 64 chomp $pwd;                                        64 chomp $pwd;
 65 my $tree = $pwd;                                   65 my $tree = $pwd;
 66 my $build;                                         66 my $build;
 67                                                    67 
 68 my $output_config;                                 68 my $output_config;
 69 my $reset_bisect;                                  69 my $reset_bisect;
 70                                                    70 
 71 sub usage {                                        71 sub usage {
 72     print << "EOF"                                 72     print << "EOF"
 73                                                    73 
 74 usage: config-bisect.pl [-l linux-tree][-b bui     74 usage: config-bisect.pl [-l linux-tree][-b build-dir] good-config bad-config [good|bad]
 75   -l [optional] define location of linux-tree      75   -l [optional] define location of linux-tree (default is current directory)
 76   -b [optional] define location to build (O=bu     76   -b [optional] define location to build (O=build-dir) (default is linux-tree)
 77   good-config the config that is considered go     77   good-config the config that is considered good
 78   bad-config the config that does not work         78   bad-config the config that does not work
 79   "good" add this if the last run produced a g     79   "good" add this if the last run produced a good config
 80   "bad" add this if the last run produced a ba     80   "bad" add this if the last run produced a bad config
 81   If "good" or "bad" is not specified, then it     81   If "good" or "bad" is not specified, then it is the start of a new bisect
 82                                                    82 
 83   Note, each run will create copy of good and      83   Note, each run will create copy of good and bad configs with ".tmp" appended.
 84                                                    84 
 85 EOF                                                85 EOF
 86 ;                                                  86 ;
 87                                                    87 
 88     exit(-1);                                      88     exit(-1);
 89 }                                                  89 }
 90                                                    90 
 91 sub doprint {                                      91 sub doprint {
 92     print @_;                                      92     print @_;
 93 }                                                  93 }
 94                                                    94 
 95 sub dodie {                                        95 sub dodie {
 96     doprint "CRITICAL FAILURE... ", @_, "\n";      96     doprint "CRITICAL FAILURE... ", @_, "\n";
 97                                                    97 
 98     die @_, "\n";                                  98     die @_, "\n";
 99 }                                                  99 }
100                                                   100 
101 sub expand_path {                                 101 sub expand_path {
102     my ($file) = @_;                              102     my ($file) = @_;
103                                                   103 
104     if ($file =~ m,^/,) {                         104     if ($file =~ m,^/,) {
105         return $file;                             105         return $file;
106     }                                             106     }
107     return "$pwd/$file";                          107     return "$pwd/$file";
108 }                                                 108 }
109                                                   109 
110 sub read_prompt {                                 110 sub read_prompt {
111     my ($cancel, $prompt) = @_;                   111     my ($cancel, $prompt) = @_;
112                                                   112 
113     my $ans;                                      113     my $ans;
114                                                   114 
115     for (;;) {                                    115     for (;;) {
116         if ($cancel) {                            116         if ($cancel) {
117             print "$prompt [y/n/C] ";             117             print "$prompt [y/n/C] ";
118         } else {                                  118         } else {
119             print "$prompt [y/N] ";               119             print "$prompt [y/N] ";
120         }                                         120         }
121         $ans = <STDIN>;                           121         $ans = <STDIN>;
122         chomp $ans;                               122         chomp $ans;
123         if ($ans =~ /^\s*$/) {                    123         if ($ans =~ /^\s*$/) {
124             if ($cancel) {                        124             if ($cancel) {
125                 $ans = "c";                       125                 $ans = "c";
126             } else {                              126             } else {
127                 $ans = "n";                       127                 $ans = "n";
128             }                                     128             }
129         }                                         129         }
130         last if ($ans =~ /^y$/i || $ans =~ /^n    130         last if ($ans =~ /^y$/i || $ans =~ /^n$/i);
131         if ($cancel) {                            131         if ($cancel) {
132             last if ($ans =~ /^c$/i);             132             last if ($ans =~ /^c$/i);
133             print "Please answer either 'y', '    133             print "Please answer either 'y', 'n' or 'c'.\n";
134         } else {                                  134         } else {
135             print "Please answer either 'y' or    135             print "Please answer either 'y' or 'n'.\n";
136         }                                         136         }
137     }                                             137     }
138     if ($ans =~ /^c/i) {                          138     if ($ans =~ /^c/i) {
139         exit;                                     139         exit;
140     }                                             140     }
141     if ($ans !~ /^y$/i) {                         141     if ($ans !~ /^y$/i) {
142         return 0;                                 142         return 0;
143     }                                             143     }
144     return 1;                                     144     return 1;
145 }                                                 145 }
146                                                   146 
147 sub read_yn {                                     147 sub read_yn {
148     my ($prompt) = @_;                            148     my ($prompt) = @_;
149                                                   149 
150     return read_prompt 0, $prompt;                150     return read_prompt 0, $prompt;
151 }                                                 151 }
152                                                   152 
153 sub read_ync {                                    153 sub read_ync {
154     my ($prompt) = @_;                            154     my ($prompt) = @_;
155                                                   155 
156     return read_prompt 1, $prompt;                156     return read_prompt 1, $prompt;
157 }                                                 157 }
158                                                   158 
159 sub run_command {                                 159 sub run_command {
160     my ($command, $redirect) = @_;                160     my ($command, $redirect) = @_;
161     my $start_time;                               161     my $start_time;
162     my $end_time;                                 162     my $end_time;
163     my $dord = 0;                                 163     my $dord = 0;
164     my $pid;                                      164     my $pid;
165                                                   165 
166     $start_time = time;                           166     $start_time = time;
167                                                   167 
168     doprint("$command ... ");                     168     doprint("$command ... ");
169                                                   169 
170     $pid = open(CMD, "$command 2>&1 |") or        170     $pid = open(CMD, "$command 2>&1 |") or
171         dodie "unable to exec $command";          171         dodie "unable to exec $command";
172                                                   172 
173     if (defined($redirect)) {                     173     if (defined($redirect)) {
174         open (RD, ">$redirect") or                174         open (RD, ">$redirect") or
175             dodie "failed to write to redirect    175             dodie "failed to write to redirect $redirect";
176         $dord = 1;                                176         $dord = 1;
177     }                                             177     }
178                                                   178 
179     while (<CMD>) {                               179     while (<CMD>) {
180         print RD  if ($dord);                     180         print RD  if ($dord);
181     }                                             181     }
182                                                   182 
183     waitpid($pid, 0);                             183     waitpid($pid, 0);
184     my $failed = $?;                              184     my $failed = $?;
185                                                   185 
186     close(CMD);                                   186     close(CMD);
187     close(RD)  if ($dord);                        187     close(RD)  if ($dord);
188                                                   188 
189     $end_time = time;                             189     $end_time = time;
190     my $delta = $end_time - $start_time;          190     my $delta = $end_time - $start_time;
191                                                   191 
192     if ($delta == 1) {                            192     if ($delta == 1) {
193         doprint "[1 second] ";                    193         doprint "[1 second] ";
194     } else {                                      194     } else {
195         doprint "[$delta seconds] ";              195         doprint "[$delta seconds] ";
196     }                                             196     }
197                                                   197 
198     if ($failed) {                                198     if ($failed) {
199         doprint "FAILED!\n";                      199         doprint "FAILED!\n";
200     } else {                                      200     } else {
201         doprint "SUCCESS\n";                      201         doprint "SUCCESS\n";
202     }                                             202     }
203                                                   203 
204     return !$failed;                              204     return !$failed;
205 }                                                 205 }
206                                                   206 
207 ###### CONFIG BISECT ######                       207 ###### CONFIG BISECT ######
208                                                   208 
209 # config_ignore holds the configs that were se    209 # config_ignore holds the configs that were set (or unset) for
210 # a good config and we will ignore these confi    210 # a good config and we will ignore these configs for the rest
211 # of a config bisect. These configs stay as th    211 # of a config bisect. These configs stay as they were.
212 my %config_ignore;                                212 my %config_ignore;
213                                                   213 
214 # config_set holds what all configs were set a    214 # config_set holds what all configs were set as.
215 my %config_set;                                   215 my %config_set;
216                                                   216 
217 # config_off holds the set of configs that the    217 # config_off holds the set of configs that the bad config had disabled.
218 # We need to record them and set them in the .    218 # We need to record them and set them in the .config when running
219 # olddefconfig, because olddefconfig keeps the    219 # olddefconfig, because olddefconfig keeps the defaults.
220 my %config_off;                                   220 my %config_off;
221                                                   221 
222 # config_off_tmp holds a set of configs to tur    222 # config_off_tmp holds a set of configs to turn off for now
223 my @config_off_tmp;                               223 my @config_off_tmp;
224                                                   224 
225 # config_list is the set of configs that are b    225 # config_list is the set of configs that are being tested
226 my %config_list;                                  226 my %config_list;
227 my %null_config;                                  227 my %null_config;
228                                                   228 
229 my %dependency;                                   229 my %dependency;
230                                                   230 
231 my $make;                                         231 my $make;
232                                                   232 
233 sub make_oldconfig {                              233 sub make_oldconfig {
234                                                   234 
235     if (!run_command "$make olddefconfig") {      235     if (!run_command "$make olddefconfig") {
236         # Perhaps olddefconfig doesn't exist i    236         # Perhaps olddefconfig doesn't exist in this version of the kernel
237         # try oldnoconfig                         237         # try oldnoconfig
238         doprint "olddefconfig failed, trying m    238         doprint "olddefconfig failed, trying make oldnoconfig\n";
239         if (!run_command "$make oldnoconfig")     239         if (!run_command "$make oldnoconfig") {
240             doprint "oldnoconfig failed, tryin    240             doprint "oldnoconfig failed, trying yes '' | make oldconfig\n";
241             # try a yes '' | oldconfig            241             # try a yes '' | oldconfig
242             run_command "yes '' | $make oldcon    242             run_command "yes '' | $make oldconfig" or
243                 dodie "failed make config oldc    243                 dodie "failed make config oldconfig";
244         }                                         244         }
245     }                                             245     }
246 }                                                 246 }
247                                                   247 
248 sub assign_configs {                              248 sub assign_configs {
249     my ($hash, $config) = @_;                     249     my ($hash, $config) = @_;
250                                                   250 
251     doprint "Reading configs from $config\n";     251     doprint "Reading configs from $config\n";
252                                                   252 
253     open (IN, $config)                            253     open (IN, $config)
254         or dodie "Failed to read $config";        254         or dodie "Failed to read $config";
255                                                   255 
256     while (<IN>) {                                256     while (<IN>) {
257         chomp;                                    257         chomp;
258         if (/^((CONFIG\S*)=.*)/) {                258         if (/^((CONFIG\S*)=.*)/) {
259             ${$hash}{$2} = $1;                    259             ${$hash}{$2} = $1;
260         } elsif (/^(# (CONFIG\S*) is not set)/    260         } elsif (/^(# (CONFIG\S*) is not set)/) {
261             ${$hash}{$2} = $1;                    261             ${$hash}{$2} = $1;
262         }                                         262         }
263     }                                             263     }
264                                                   264 
265     close(IN);                                    265     close(IN);
266 }                                                 266 }
267                                                   267 
268 sub process_config_ignore {                       268 sub process_config_ignore {
269     my ($config) = @_;                            269     my ($config) = @_;
270                                                   270 
271     assign_configs \%config_ignore, $config;      271     assign_configs \%config_ignore, $config;
272 }                                                 272 }
273                                                   273 
274 sub get_dependencies {                            274 sub get_dependencies {
275     my ($config) = @_;                            275     my ($config) = @_;
276                                                   276 
277     my $arr = $dependency{$config};               277     my $arr = $dependency{$config};
278     if (!defined($arr)) {                         278     if (!defined($arr)) {
279         return ();                                279         return ();
280     }                                             280     }
281                                                   281 
282     my @deps = @{$arr};                           282     my @deps = @{$arr};
283                                                   283 
284     foreach my $dep (@{$arr}) {                   284     foreach my $dep (@{$arr}) {
285         print "ADD DEP $dep\n";                   285         print "ADD DEP $dep\n";
286         @deps = (@deps, get_dependencies $dep)    286         @deps = (@deps, get_dependencies $dep);
287     }                                             287     }
288                                                   288 
289     return @deps;                                 289     return @deps;
290 }                                                 290 }
291                                                   291 
292 sub save_config {                                 292 sub save_config {
293     my ($pc, $file) = @_;                         293     my ($pc, $file) = @_;
294                                                   294 
295     my %configs = %{$pc};                         295     my %configs = %{$pc};
296                                                   296 
297     doprint "Saving configs into $file\n";        297     doprint "Saving configs into $file\n";
298                                                   298 
299     open(OUT, ">$file") or dodie "Can not writ    299     open(OUT, ">$file") or dodie "Can not write to $file";
300                                                   300 
301     foreach my $config (keys %configs) {          301     foreach my $config (keys %configs) {
302         print OUT "$configs{$config}\n";          302         print OUT "$configs{$config}\n";
303     }                                             303     }
304     close(OUT);                                   304     close(OUT);
305 }                                                 305 }
306                                                   306 
307 sub create_config {                               307 sub create_config {
308     my ($name, $pc) = @_;                         308     my ($name, $pc) = @_;
309                                                   309 
310     doprint "Creating old config from $name co    310     doprint "Creating old config from $name configs\n";
311                                                   311 
312     save_config $pc, $output_config;              312     save_config $pc, $output_config;
313                                                   313 
314     make_oldconfig;                               314     make_oldconfig;
315 }                                                 315 }
316                                                   316 
317 # compare two config hashes, and return config    317 # compare two config hashes, and return configs with different vals.
318 # It returns B's config values, but you can us    318 # It returns B's config values, but you can use A to see what A was.
319 sub diff_config_vals {                            319 sub diff_config_vals {
320     my ($pa, $pb) = @_;                           320     my ($pa, $pb) = @_;
321                                                   321 
322     # crappy Perl way to pass in hashes.          322     # crappy Perl way to pass in hashes.
323     my %a = %{$pa};                               323     my %a = %{$pa};
324     my %b = %{$pb};                               324     my %b = %{$pb};
325                                                   325 
326     my %ret;                                      326     my %ret;
327                                                   327 
328     foreach my $item (keys %a) {                  328     foreach my $item (keys %a) {
329         if (defined($b{$item}) && $b{$item} ne    329         if (defined($b{$item}) && $b{$item} ne $a{$item}) {
330             $ret{$item} = $b{$item};              330             $ret{$item} = $b{$item};
331         }                                         331         }
332     }                                             332     }
333                                                   333 
334     return %ret;                                  334     return %ret;
335 }                                                 335 }
336                                                   336 
337 # compare two config hashes and return the con    337 # compare two config hashes and return the configs in B but not A
338 sub diff_configs {                                338 sub diff_configs {
339     my ($pa, $pb) = @_;                           339     my ($pa, $pb) = @_;
340                                                   340 
341     my %ret;                                      341     my %ret;
342                                                   342 
343     # crappy Perl way to pass in hashes.          343     # crappy Perl way to pass in hashes.
344     my %a = %{$pa};                               344     my %a = %{$pa};
345     my %b = %{$pb};                               345     my %b = %{$pb};
346                                                   346 
347     foreach my $item (keys %b) {                  347     foreach my $item (keys %b) {
348         if (!defined($a{$item})) {                348         if (!defined($a{$item})) {
349             $ret{$item} = $b{$item};              349             $ret{$item} = $b{$item};
350         }                                         350         }
351     }                                             351     }
352                                                   352 
353     return %ret;                                  353     return %ret;
354 }                                                 354 }
355                                                   355 
356 # return if two configs are equal or not          356 # return if two configs are equal or not
357 # 0 is equal +1 b has something a does not        357 # 0 is equal +1 b has something a does not
358 # +1 if a and b have a different item.            358 # +1 if a and b have a different item.
359 # -1 if a has something b does not                359 # -1 if a has something b does not
360 sub compare_configs {                             360 sub compare_configs {
361     my ($pa, $pb) = @_;                           361     my ($pa, $pb) = @_;
362                                                   362 
363     my %ret;                                      363     my %ret;
364                                                   364 
365     # crappy Perl way to pass in hashes.          365     # crappy Perl way to pass in hashes.
366     my %a = %{$pa};                               366     my %a = %{$pa};
367     my %b = %{$pb};                               367     my %b = %{$pb};
368                                                   368 
369     foreach my $item (keys %b) {                  369     foreach my $item (keys %b) {
370         if (!defined($a{$item})) {                370         if (!defined($a{$item})) {
371             return 1;                             371             return 1;
372         }                                         372         }
373         if ($a{$item} ne $b{$item}) {             373         if ($a{$item} ne $b{$item}) {
374             return 1;                             374             return 1;
375         }                                         375         }
376     }                                             376     }
377                                                   377 
378     foreach my $item (keys %a) {                  378     foreach my $item (keys %a) {
379         if (!defined($b{$item})) {                379         if (!defined($b{$item})) {
380             return -1;                            380             return -1;
381         }                                         381         }
382     }                                             382     }
383                                                   383 
384     return 0;                                     384     return 0;
385 }                                                 385 }
386                                                   386 
387 sub process_failed {                              387 sub process_failed {
388     my ($config) = @_;                            388     my ($config) = @_;
389                                                   389 
390     doprint "\n\n*****************************    390     doprint "\n\n***************************************\n";
391     doprint "Found bad config: $config\n";        391     doprint "Found bad config: $config\n";
392     doprint "*********************************    392     doprint "***************************************\n\n";
393 }                                                 393 }
394                                                   394 
395 sub process_new_config {                          395 sub process_new_config {
396     my ($tc, $nc, $gc, $bc) = @_;                 396     my ($tc, $nc, $gc, $bc) = @_;
397                                                   397 
398     my %tmp_config = %{$tc};                      398     my %tmp_config = %{$tc};
399     my %good_configs = %{$gc};                    399     my %good_configs = %{$gc};
400     my %bad_configs = %{$bc};                     400     my %bad_configs = %{$bc};
401                                                   401 
402     my %new_configs;                              402     my %new_configs;
403                                                   403 
404     my $runtest = 1;                              404     my $runtest = 1;
405     my $ret;                                      405     my $ret;
406                                                   406 
407     create_config "tmp_configs", \%tmp_config;    407     create_config "tmp_configs", \%tmp_config;
408     assign_configs \%new_configs, $output_conf    408     assign_configs \%new_configs, $output_config;
409                                                   409 
410     $ret = compare_configs \%new_configs, \%ba    410     $ret = compare_configs \%new_configs, \%bad_configs;
411     if (!$ret) {                                  411     if (!$ret) {
412         doprint "New config equals bad config,    412         doprint "New config equals bad config, try next test\n";
413         $runtest = 0;                             413         $runtest = 0;
414     }                                             414     }
415                                                   415 
416     if ($runtest) {                               416     if ($runtest) {
417         $ret = compare_configs \%new_configs,     417         $ret = compare_configs \%new_configs, \%good_configs;
418         if (!$ret) {                              418         if (!$ret) {
419             doprint "New config equals good co    419             doprint "New config equals good config, try next test\n";
420             $runtest = 0;                         420             $runtest = 0;
421         }                                         421         }
422     }                                             422     }
423                                                   423 
424     %{$nc} = %new_configs;                        424     %{$nc} = %new_configs;
425                                                   425 
426     return $runtest;                              426     return $runtest;
427 }                                                 427 }
428                                                   428 
429 sub convert_config {                              429 sub convert_config {
430     my ($config) = @_;                            430     my ($config) = @_;
431                                                   431 
432     if ($config =~ /^# (.*) is not set/) {        432     if ($config =~ /^# (.*) is not set/) {
433         $config = "$1=n";                         433         $config = "$1=n";
434     }                                             434     }
435                                                   435 
436     $config =~ s/^CONFIG_//;                      436     $config =~ s/^CONFIG_//;
437     return $config;                               437     return $config;
438 }                                                 438 }
439                                                   439 
440 sub print_config {                                440 sub print_config {
441     my ($sym, $config) = @_;                      441     my ($sym, $config) = @_;
442                                                   442 
443     $config = convert_config $config;             443     $config = convert_config $config;
444     doprint "$sym$config\n";                      444     doprint "$sym$config\n";
445 }                                                 445 }
446                                                   446 
447 sub print_config_compare {                        447 sub print_config_compare {
448     my ($good_config, $bad_config) = @_;          448     my ($good_config, $bad_config) = @_;
449                                                   449 
450     $good_config = convert_config $good_config    450     $good_config = convert_config $good_config;
451     $bad_config = convert_config $bad_config;     451     $bad_config = convert_config $bad_config;
452                                                   452 
453     my $good_value = $good_config;                453     my $good_value = $good_config;
454     my $bad_value = $bad_config;                  454     my $bad_value = $bad_config;
455     $good_value =~ s/(.*)=//;                     455     $good_value =~ s/(.*)=//;
456     my $config = $1;                              456     my $config = $1;
457                                                   457 
458     $bad_value =~ s/.*=//;                        458     $bad_value =~ s/.*=//;
459                                                   459 
460     doprint " $config $good_value -> $bad_valu    460     doprint " $config $good_value -> $bad_value\n";
461 }                                                 461 }
462                                                   462 
463 # Pass in:                                        463 # Pass in:
464 # $phalf: half of the configs names you want t    464 # $phalf: half of the configs names you want to add
465 # $oconfigs: The orginial configs to start wit    465 # $oconfigs: The orginial configs to start with
466 # $sconfigs: The source to update $oconfigs wi    466 # $sconfigs: The source to update $oconfigs with (from $phalf)
467 # $which: The name of which half that is updat    467 # $which: The name of which half that is updating (top / bottom)
468 # $type: The name of the source type (good / b    468 # $type: The name of the source type (good / bad)
469 sub make_half {                                   469 sub make_half {
470     my ($phalf, $oconfigs, $sconfigs, $which,     470     my ($phalf, $oconfigs, $sconfigs, $which, $type) = @_;
471                                                   471 
472     my @half = @{$phalf};                         472     my @half = @{$phalf};
473     my %orig_configs = %{$oconfigs};              473     my %orig_configs = %{$oconfigs};
474     my %source_configs = %{$sconfigs};            474     my %source_configs = %{$sconfigs};
475                                                   475 
476     my %tmp_config = %orig_configs;               476     my %tmp_config = %orig_configs;
477                                                   477 
478     doprint "Settings bisect with $which half     478     doprint "Settings bisect with $which half of $type configs:\n";
479     foreach my $item (@half) {                    479     foreach my $item (@half) {
480         doprint "Updating $item to $source_con    480         doprint "Updating $item to $source_configs{$item}\n";
481         $tmp_config{$item} = $source_configs{$    481         $tmp_config{$item} = $source_configs{$item};
482     }                                             482     }
483                                                   483 
484     return %tmp_config;                           484     return %tmp_config;
485 }                                                 485 }
486                                                   486 
487 sub run_config_bisect {                           487 sub run_config_bisect {
488     my ($pgood, $pbad) = @_;                      488     my ($pgood, $pbad) = @_;
489                                                   489 
490     my %good_configs = %{$pgood};                 490     my %good_configs = %{$pgood};
491     my %bad_configs = %{$pbad};                   491     my %bad_configs = %{$pbad};
492                                                   492 
493     my %diff_configs = diff_config_vals \%good    493     my %diff_configs = diff_config_vals \%good_configs, \%bad_configs;
494     my %b_configs = diff_configs \%good_config    494     my %b_configs = diff_configs \%good_configs, \%bad_configs;
495     my %g_configs = diff_configs \%bad_configs    495     my %g_configs = diff_configs \%bad_configs, \%good_configs;
496                                                   496 
497     # diff_arr is what is in both good and bad    497     # diff_arr is what is in both good and bad but are different (y->n)
498     my @diff_arr = keys %diff_configs;            498     my @diff_arr = keys %diff_configs;
499     my $len_diff = $#diff_arr + 1;                499     my $len_diff = $#diff_arr + 1;
500                                                   500 
501     # b_arr is what is in bad but not in good     501     # b_arr is what is in bad but not in good (has depends)
502     my @b_arr = keys %b_configs;                  502     my @b_arr = keys %b_configs;
503     my $len_b = $#b_arr + 1;                      503     my $len_b = $#b_arr + 1;
504                                                   504 
505     # g_arr is what is in good but not in bad     505     # g_arr is what is in good but not in bad
506     my @g_arr = keys %g_configs;                  506     my @g_arr = keys %g_configs;
507     my $len_g = $#g_arr + 1;                      507     my $len_g = $#g_arr + 1;
508                                                   508 
509     my $runtest = 0;                              509     my $runtest = 0;
510     my %new_configs;                              510     my %new_configs;
511     my $ret;                                      511     my $ret;
512                                                   512 
513     # Look at the configs that are different b    513     # Look at the configs that are different between good and bad.
514     # This does not include those that depend     514     # This does not include those that depend on other configs
515     #  (configs depending on other configs tha    515     #  (configs depending on other configs that are not set would
516     #   not show up even as a "# CONFIG_FOO is    516     #   not show up even as a "# CONFIG_FOO is not set"
517                                                   517 
518                                                   518 
519     doprint "# of configs to check:               519     doprint "# of configs to check:             $len_diff\n";
520     doprint "# of configs showing only in good    520     doprint "# of configs showing only in good: $len_g\n";
521     doprint "# of configs showing only in bad:    521     doprint "# of configs showing only in bad:  $len_b\n";
522                                                   522 
523     if ($len_diff > 0) {                          523     if ($len_diff > 0) {
524         # Now test for different values           524         # Now test for different values
525                                                   525 
526         doprint "Configs left to check:\n";       526         doprint "Configs left to check:\n";
527         doprint "  Good Config\t\t\tBad Config    527         doprint "  Good Config\t\t\tBad Config\n";
528         doprint "  -----------\t\t\t----------    528         doprint "  -----------\t\t\t----------\n";
529         foreach my $item (@diff_arr) {            529         foreach my $item (@diff_arr) {
530             doprint "  $good_configs{$item}\t$    530             doprint "  $good_configs{$item}\t$bad_configs{$item}\n";
531         }                                         531         }
532                                                   532 
533         my $half = int($#diff_arr / 2);           533         my $half = int($#diff_arr / 2);
534         my @tophalf = @diff_arr[0 .. $half];      534         my @tophalf = @diff_arr[0 .. $half];
535                                                   535 
536         doprint "Set tmp config to be good con    536         doprint "Set tmp config to be good config with some bad config values\n";
537                                                   537 
538         my %tmp_config = make_half \@tophalf,     538         my %tmp_config = make_half \@tophalf, \%good_configs,
539             \%bad_configs, "top", "bad";          539             \%bad_configs, "top", "bad";
540                                                   540 
541         $runtest = process_new_config \%tmp_co    541         $runtest = process_new_config \%tmp_config, \%new_configs,
542                             \%good_configs, \%    542                             \%good_configs, \%bad_configs;
543                                                   543 
544         if (!$runtest) {                          544         if (!$runtest) {
545             doprint "Set tmp config to be bad     545             doprint "Set tmp config to be bad config with some good config values\n";
546                                                   546 
547             my %tmp_config = make_half \@topha    547             my %tmp_config = make_half \@tophalf, \%bad_configs,
548                 \%good_configs, "top", "good";    548                 \%good_configs, "top", "good";
549                                                   549 
550             $runtest = process_new_config \%tm    550             $runtest = process_new_config \%tmp_config, \%new_configs,
551                 \%good_configs, \%bad_configs;    551                 \%good_configs, \%bad_configs;
552         }                                         552         }
553     }                                             553     }
554                                                   554 
555     if (!$runtest && $len_diff > 0) {             555     if (!$runtest && $len_diff > 0) {
556         # do the same thing, but this time wit    556         # do the same thing, but this time with bottom half
557                                                   557 
558         my $half = int($#diff_arr / 2);           558         my $half = int($#diff_arr / 2);
559         my @bottomhalf = @diff_arr[$half+1 ..     559         my @bottomhalf = @diff_arr[$half+1 .. $#diff_arr];
560                                                   560 
561         doprint "Set tmp config to be good con    561         doprint "Set tmp config to be good config with some bad config values\n";
562                                                   562 
563         my %tmp_config = make_half \@bottomhal    563         my %tmp_config = make_half \@bottomhalf, \%good_configs,
564             \%bad_configs, "bottom", "bad";       564             \%bad_configs, "bottom", "bad";
565                                                   565 
566         $runtest = process_new_config \%tmp_co    566         $runtest = process_new_config \%tmp_config, \%new_configs,
567                             \%good_configs, \%    567                             \%good_configs, \%bad_configs;
568                                                   568 
569         if (!$runtest) {                          569         if (!$runtest) {
570             doprint "Set tmp config to be bad     570             doprint "Set tmp config to be bad config with some good config values\n";
571                                                   571 
572             my %tmp_config = make_half \@botto    572             my %tmp_config = make_half \@bottomhalf, \%bad_configs,
573                 \%good_configs, "bottom", "goo    573                 \%good_configs, "bottom", "good";
574                                                   574 
575             $runtest = process_new_config \%tm    575             $runtest = process_new_config \%tmp_config, \%new_configs,
576                 \%good_configs, \%bad_configs;    576                 \%good_configs, \%bad_configs;
577         }                                         577         }
578     }                                             578     }
579                                                   579 
580     if ($runtest) {                               580     if ($runtest) {
581         make_oldconfig;                           581         make_oldconfig;
582         doprint "READY TO TEST .config IN $bui    582         doprint "READY TO TEST .config IN $build\n";
583         return 0;                                 583         return 0;
584     }                                             584     }
585                                                   585 
586     doprint "\n%%%%%%%% FAILED TO FIND SINGLE     586     doprint "\n%%%%%%%% FAILED TO FIND SINGLE BAD CONFIG %%%%%%%%\n";
587     doprint "Hmm, can't make any more changes     587     doprint "Hmm, can't make any more changes without making good == bad?\n";
588     doprint "Difference between good (+) and b    588     doprint "Difference between good (+) and bad (-)\n";
589                                                   589 
590     foreach my $item (keys %bad_configs) {        590     foreach my $item (keys %bad_configs) {
591         if (!defined($good_configs{$item})) {     591         if (!defined($good_configs{$item})) {
592             print_config "-", $bad_configs{$it    592             print_config "-", $bad_configs{$item};
593         }                                         593         }
594     }                                             594     }
595                                                   595 
596     foreach my $item (keys %good_configs) {       596     foreach my $item (keys %good_configs) {
597         next if (!defined($bad_configs{$item})    597         next if (!defined($bad_configs{$item}));
598         if ($good_configs{$item} ne $bad_confi    598         if ($good_configs{$item} ne $bad_configs{$item}) {
599             print_config_compare $good_configs    599             print_config_compare $good_configs{$item}, $bad_configs{$item};
600         }                                         600         }
601     }                                             601     }
602                                                   602 
603     foreach my $item (keys %good_configs) {       603     foreach my $item (keys %good_configs) {
604         if (!defined($bad_configs{$item})) {      604         if (!defined($bad_configs{$item})) {
605             print_config "+", $good_configs{$i    605             print_config "+", $good_configs{$item};
606         }                                         606         }
607     }                                             607     }
608     return -1;                                    608     return -1;
609 }                                                 609 }
610                                                   610 
611 sub config_bisect {                               611 sub config_bisect {
612     my ($good_config, $bad_config) = @_;          612     my ($good_config, $bad_config) = @_;
613     my $ret;                                      613     my $ret;
614                                                   614 
615     my %good_configs;                             615     my %good_configs;
616     my %bad_configs;                              616     my %bad_configs;
617     my %tmp_configs;                              617     my %tmp_configs;
618                                                   618 
619     doprint "Run good configs through make old    619     doprint "Run good configs through make oldconfig\n";
620     assign_configs \%tmp_configs, $good_config    620     assign_configs \%tmp_configs, $good_config;
621     create_config "$good_config", \%tmp_config    621     create_config "$good_config", \%tmp_configs;
622     assign_configs \%good_configs, $output_con    622     assign_configs \%good_configs, $output_config;
623                                                   623 
624     doprint "Run bad configs through make oldc    624     doprint "Run bad configs through make oldconfig\n";
625     assign_configs \%tmp_configs, $bad_config;    625     assign_configs \%tmp_configs, $bad_config;
626     create_config "$bad_config", \%tmp_configs    626     create_config "$bad_config", \%tmp_configs;
627     assign_configs \%bad_configs, $output_conf    627     assign_configs \%bad_configs, $output_config;
628                                                   628 
629     save_config \%good_configs, $good_config;     629     save_config \%good_configs, $good_config;
630     save_config \%bad_configs, $bad_config;       630     save_config \%bad_configs, $bad_config;
631                                                   631 
632     return run_config_bisect \%good_configs, \    632     return run_config_bisect \%good_configs, \%bad_configs;
633 }                                                 633 }
634                                                   634 
635 while ($#ARGV >= 0) {                             635 while ($#ARGV >= 0) {
636     if ($ARGV[0] !~ m/^-/) {                      636     if ($ARGV[0] !~ m/^-/) {
637         last;                                     637         last;
638     }                                             638     }
639     my $opt = shift @ARGV;                        639     my $opt = shift @ARGV;
640                                                   640 
641     if ($opt eq "-b") {                           641     if ($opt eq "-b") {
642         $val = shift @ARGV;                       642         $val = shift @ARGV;
643         if (!defined($val)) {                     643         if (!defined($val)) {
644             die "-b requires value\n";            644             die "-b requires value\n";
645         }                                         645         }
646         $build = $val;                            646         $build = $val;
647     }                                             647     }
648                                                   648 
649     elsif ($opt eq "-l") {                        649     elsif ($opt eq "-l") {
650         $val = shift @ARGV;                       650         $val = shift @ARGV;
651         if (!defined($val)) {                     651         if (!defined($val)) {
652             die "-l requires value\n";            652             die "-l requires value\n";
653         }                                         653         }
654         $tree = $val;                             654         $tree = $val;
655     }                                             655     }
656                                                   656 
657     elsif ($opt eq "-r") {                        657     elsif ($opt eq "-r") {
658         $reset_bisect = 1;                        658         $reset_bisect = 1;
659     }                                             659     }
660                                                   660 
661     elsif ($opt eq "-h") {                        661     elsif ($opt eq "-h") {
662         usage;                                    662         usage;
663     }                                             663     }
664                                                   664 
665     else {                                        665     else {
666         die "Unknown option $opt\n";              666         die "Unknown option $opt\n";
667     }                                             667     }
668 }                                                 668 }
669                                                   669 
670 $build = $tree if (!defined($build));             670 $build = $tree if (!defined($build));
671                                                   671 
672 $tree = expand_path $tree;                        672 $tree = expand_path $tree;
673 $build = expand_path $build;                      673 $build = expand_path $build;
674                                                   674 
675 if ( ! -d $tree ) {                               675 if ( ! -d $tree ) {
676     die "$tree not a directory\n";                676     die "$tree not a directory\n";
677 }                                                 677 }
678                                                   678 
679 if ( ! -d $build ) {                              679 if ( ! -d $build ) {
680     die "$build not a directory\n";               680     die "$build not a directory\n";
681 }                                                 681 }
682                                                   682 
683 usage if $#ARGV < 1;                              683 usage if $#ARGV < 1;
684                                                   684 
685 if ($#ARGV == 1) {                                685 if ($#ARGV == 1) {
686     $start = 1;                                   686     $start = 1;
687 } elsif ($#ARGV == 2) {                           687 } elsif ($#ARGV == 2) {
688     $val = $ARGV[2];                              688     $val = $ARGV[2];
689     if ($val ne "good" && $val ne "bad") {        689     if ($val ne "good" && $val ne "bad") {
690         die "Unknown command '$val', bust be e    690         die "Unknown command '$val', bust be either \"good\" or \"bad\"\n";
691     }                                             691     }
692 } else {                                          692 } else {
693     usage;                                        693     usage;
694 }                                                 694 }
695                                                   695 
696 my $good_start = expand_path $ARGV[0];            696 my $good_start = expand_path $ARGV[0];
697 my $bad_start = expand_path $ARGV[1];             697 my $bad_start = expand_path $ARGV[1];
698                                                   698 
699 my $good = "$good_start.tmp";                     699 my $good = "$good_start.tmp";
700 my $bad = "$bad_start.tmp";                       700 my $bad = "$bad_start.tmp";
701                                                   701 
702 $make = "make";                                   702 $make = "make";
703                                                   703 
704 if ($build ne $tree) {                            704 if ($build ne $tree) {
705     $make = "make O=$build"                       705     $make = "make O=$build"
706 }                                                 706 }
707                                                   707 
708 $output_config = "$build/.config";                708 $output_config = "$build/.config";
709                                                   709 
710 if ($start) {                                     710 if ($start) {
711     if ( ! -f $good_start ) {                     711     if ( ! -f $good_start ) {
712         die "$good_start not found\n";            712         die "$good_start not found\n";
713     }                                             713     }
714     if ( ! -f $bad_start ) {                      714     if ( ! -f $bad_start ) {
715         die "$bad_start not found\n";             715         die "$bad_start not found\n";
716     }                                             716     }
717     if ( -f $good || -f $bad ) {                  717     if ( -f $good || -f $bad ) {
718         my $p = "";                               718         my $p = "";
719                                                   719 
720         if ( -f $good ) {                         720         if ( -f $good ) {
721             $p = "$good exists\n";                721             $p = "$good exists\n";
722         }                                         722         }
723                                                   723 
724         if ( -f $bad ) {                          724         if ( -f $bad ) {
725             $p = "$p$bad exists\n";               725             $p = "$p$bad exists\n";
726         }                                         726         }
727                                                   727 
728         if (!defined($reset_bisect)) {            728         if (!defined($reset_bisect)) {
729             if (!read_yn "${p}Overwrite and st    729             if (!read_yn "${p}Overwrite and start new bisect anyway?") {
730                 exit (-1);                        730                 exit (-1);
731             }                                     731             }
732         }                                         732         }
733     }                                             733     }
734     run_command "cp $good_start $good" or die     734     run_command "cp $good_start $good" or die "failed to copy to $good\n";
735     run_command "cp $bad_start $bad" or die "f    735     run_command "cp $bad_start $bad" or die "failed to copy to $bad\n";
736 } else {                                          736 } else {
737     if ( ! -f $good ) {                           737     if ( ! -f $good ) {
738         die "Can not find file $good\n";          738         die "Can not find file $good\n";
739     }                                             739     }
740     if ( ! -f $bad ) {                            740     if ( ! -f $bad ) {
741         die "Can not find file $bad\n";           741         die "Can not find file $bad\n";
742     }                                             742     }
743     if ($val eq "good") {                         743     if ($val eq "good") {
744         run_command "cp $output_config $good"     744         run_command "cp $output_config $good" or die "failed to copy $config to $good\n";
745     } elsif ($val eq "bad") {                     745     } elsif ($val eq "bad") {
746         run_command "cp $output_config $bad" o    746         run_command "cp $output_config $bad" or die "failed to copy $config to $bad\n";
747     }                                             747     }
748 }                                                 748 }
749                                                   749 
750 chdir $tree || die "can't change directory to     750 chdir $tree || die "can't change directory to $tree";
751                                                   751 
752 my $ret = config_bisect $good, $bad;              752 my $ret = config_bisect $good, $bad;
753                                                   753 
754 if (!$ret) {                                      754 if (!$ret) {
755     exit(0);                                      755     exit(0);
756 }                                                 756 }
757                                                   757 
758 if ($ret > 0) {                                   758 if ($ret > 0) {
759     doprint "Cleaning temp files\n";              759     doprint "Cleaning temp files\n";
760     run_command "rm $good";                       760     run_command "rm $good";
761     run_command "rm $bad";                        761     run_command "rm $bad";
762     exit(1);                                      762     exit(1);
763 } else {                                          763 } else {
764     doprint "See good and bad configs for deta    764     doprint "See good and bad configs for details:\n";
765     doprint "good: $good\n";                      765     doprint "good: $good\n";
766     doprint "bad:  $bad\n";                       766     doprint "bad:  $bad\n";
767     doprint "%%%%%%%% FAILED TO FIND SINGLE BA    767     doprint "%%%%%%%% FAILED TO FIND SINGLE BAD CONFIG %%%%%%%%\n";
768 }                                                 768 }
769 exit(2);                                          769 exit(2);
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php