| #! /usr/bin/perl |
| # Script to find regressions by binary-searching a time interval in the |
| # CVS tree. Written by Brian Gaeke on 2-Mar-2004. |
| # |
| |
| require 5.6.0; # NOTE: This script not tested with earlier versions. |
| use Getopt::Std; |
| use POSIX; |
| use Time::Local; |
| use IO::Handle; |
| |
| sub usage { |
| print STDERR <<END; |
| findRegression [-I] -w WTIME -d DTIME -t TOOLS -c SCRIPT |
| |
| The -w, -d, -t, and -c options are required. |
| Run findRegression in the top level of an LLVM tree. |
| WTIME is a time when you are sure the regression does NOT exist ("Works"). |
| DTIME is a time when you are sure the regression DOES exist ("Doesntwork"). |
| WTIME and DTIME are both in the format: "YYYY/MM/DD HH:MM". |
| -I means run builds at WTIME and DTIME first to make sure. |
| TOOLS is a comma separated list of tools to rebuild before running SCRIPT. |
| SCRIPT exits 1 if the regression is present in TOOLS; 0 otherwise. |
| END |
| exit 1; |
| } |
| |
| sub timeAsSeconds { |
| my ($timestr) = @_; |
| |
| if ( $timestr =~ /(\d\d\d\d)\/(\d\d)\/(\d\d) (\d\d):(\d\d)/ ) { |
| my ( $year, $mon, $mday, $hour, $min ) = ( $1, $2, $3, $4, $5 ); |
| return timegm( 0, $min, $hour, $mday, $mon - 1, $year ); |
| } |
| else { |
| die "** Can't parse date + time: $timestr\n"; |
| } |
| } |
| |
| sub timeAsString { |
| my ($secs) = @_; |
| return strftime( "%Y/%m/%d %H:%M", gmtime($secs) ); |
| } |
| |
| sub run { |
| my ($cmdline) = @_; |
| print LOG "** Running: $cmdline\n"; |
| return system($cmdline); |
| } |
| |
| sub buildLibrariesAndTools { |
| run("sh /home/vadve/gaeke/scripts/run-configure"); |
| run("$MAKE -C lib/Support"); |
| run("$MAKE -C utils"); |
| run("$MAKE -C lib"); |
| foreach my $tool (@TOOLS) { run("$MAKE -C tools/$tool"); } |
| } |
| |
| sub contains { |
| my ( $file, $regex ) = @_; |
| local (*FILE); |
| open( FILE, "<$file" ) or die "** can't read $file: $!\n"; |
| while (<FILE>) { |
| if (/$regex/) { |
| close FILE; |
| return 1; |
| } |
| } |
| close FILE; |
| return 0; |
| } |
| |
| sub updateSources { |
| my ($time) = @_; |
| my $inst = "include/llvm/Instruction.h"; |
| unlink($inst); |
| run( "cvs update -D'" . timeAsString($time) . "'" ); |
| if ( !contains( $inst, 'class Instruction.*Annotable' ) ) { |
| run("patch -F100 -p0 < makeInstructionAnnotable.patch"); |
| } |
| } |
| |
| sub regressionPresentAt { |
| my ($time) = @_; |
| |
| updateSources($time); |
| buildLibrariesAndTools(); |
| my $rc = run($SCRIPT); |
| if ($rc) { |
| print LOG "** Found that regression was PRESENT at " |
| . timeAsString($time) . "\n"; |
| return 1; |
| } |
| else { |
| print LOG "** Found that regression was ABSENT at " |
| . timeAsString($time) . "\n"; |
| return 0; |
| } |
| } |
| |
| sub regressionAbsentAt { |
| my ($time) = @_; |
| return !regressionPresentAt($time); |
| } |
| |
| sub closeTo { |
| my ( $time1, $time2 ) = @_; |
| return abs( $time1 - $time2 ) < 600; # 10 minutes seems reasonable. |
| } |
| |
| sub halfWayPoint { |
| my ( $time1, $time2 ) = @_; |
| my $halfSpan = int( abs( $time1 - $time2 ) / 2 ); |
| if ( $time1 < $time2 ) { |
| return $time1 + $halfSpan; |
| } |
| else { |
| return $time2 + $halfSpan; |
| } |
| } |
| |
| sub checkBoundaryConditions { |
| print LOG "** Checking for presence of regression at ", timeAsString($DTIME), |
| "\n"; |
| if ( !regressionPresentAt($DTIME) ) { |
| die ( "** Can't help you; $SCRIPT says regression absent at dtime: " |
| . timeAsString($DTIME) |
| . "\n" ); |
| } |
| print LOG "** Checking for absence of regression at ", timeAsString($WTIME), |
| "\n"; |
| if ( !regressionAbsentAt($WTIME) ) { |
| die ( "** Can't help you; $SCRIPT says regression present at wtime: " |
| . timeAsString($WTIME) |
| . "\n" ); |
| } |
| } |
| |
| ############################################################################## |
| |
| # Set up log files |
| open (STDERR, ">&STDOUT") || die "** Can't redirect std.err: $!\n"; |
| autoflush STDOUT 1; |
| autoflush STDERR 1; |
| open (LOG, ">RegFinder.log") || die "** can't write RegFinder.log: $!\n"; |
| autoflush LOG 1; |
| # Check command line arguments and environment variables |
| getopts('Iw:d:t:c:'); |
| if ( !( $opt_w && $opt_d && $opt_t && $opt_c ) ) { |
| usage; |
| } |
| $MAKE = $ENV{'MAKE'}; |
| $MAKE = 'gmake' unless $MAKE; |
| $WTIME = timeAsSeconds($opt_w); |
| print LOG "** Assuming worked at ", timeAsString($WTIME), "\n"; |
| $DTIME = timeAsSeconds($opt_d); |
| print LOG "** Assuming didn't work at ", timeAsString($DTIME), "\n"; |
| $opt_t =~ s/\s*//g; |
| $SCRIPT = $opt_c; |
| die "** $SCRIPT is not executable or not found\n" unless -x $SCRIPT; |
| print LOG "** Checking for the regression using $SCRIPT\n"; |
| @TOOLS = split ( /,/, $opt_t ); |
| print LOG ( |
| "** Going to rebuild: ", |
| ( join ", ", @TOOLS ), |
| " before each $SCRIPT run\n" |
| ); |
| if ($opt_I) { checkBoundaryConditions(); } |
| # do the dirty work: |
| while ( !closeTo( $DTIME, $WTIME ) ) { |
| my $halfPt = halfWayPoint( $DTIME, $WTIME ); |
| print LOG "** Checking whether regression is present at ", |
| timeAsString($halfPt), "\n"; |
| if ( regressionPresentAt($halfPt) ) { |
| $DTIME = $halfPt; |
| } |
| else { |
| $WTIME = $halfPt; |
| } |
| } |
| # Tell them what we found |
| print LOG "** Narrowed it down to:\n"; |
| print LOG "** Worked at: ", timeAsString($WTIME), "\n"; |
| print LOG "** Did not work at: ", timeAsString($DTIME), "\n"; |
| close LOG; |
| exit 0; |