# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Nathan Binkert
+# Steve Reinhardt
# Diff two streams.
#
# "filename" is a pipe (|). Thus to compare the instruction traces
# from two versions of m5 (m5a and m5b), you can do this:
#
-# rundiff 'm5a --trace:flags=InstExec |' 'm5b --trace:flags=InstExec |'
+# rundiff 'm5a --traceflags=InstExec |' 'm5b --traceflags=InstExec |'
#
use strict;
+use FileHandle;
+use Getopt::Std;
+
+#
+# Options:
+# -c <n> : print n lines of context before & after changes
+# -l <n> : use n lines of lookahead
+# -x : use "complex" diff from Algorithm::Diff (see below)
+#
+our ($opt_c, $opt_l, $opt_x);
+getopts('c:l:x');
#
# For the highest-quality (minimal) diffs, we can use the
-# Algorithm::Diff package. If you don't have this installed, or want
-# the script to run faster (like 3-4x faster, based on informal
-# observation), set $use_complexdiff to 0; then a built-in, simple,
-# and generally quite adequate algorithm will be used instead.
-my $use_complexdiff = 0;
+# Algorithm::Diff package. By default, a built-in, simple, and
+# generally quite adequate algorithm will be used. If you have
+# Algorithm::Diff installed on your system, and don't mind having the
+# script go slower (like 3-4x slower, based on informal observation),
+# then specify '-x' on the command line to use it.
+my $use_complexdiff = defined($opt_x);
if ($use_complexdiff) {
- use Algorithm::Diff qw(traverse_sequences);
+ # Don't use 'use', as that's a compile-time option and will fail
+ # on systems that don't have Algorithm::Diff installed even if
+ # $use_complexdiff is false. 'require' is evaluated at runtime,
+ # so it's OK.
+ require Algorithm::Diff;
+ import Algorithm::Diff qw(traverse_sequences);
};
-my $lookahead_lines = 200;
-my $precontext_lines = 3;
-my $postcontext_lines = 3;
+my $lookahead_lines = $opt_l || 200;
+
+# in theory you could have different amounts of context before and
+# after a diff, but until someone needs that there's only one arg to
+# set both.
+my $precontext_lines = $opt_c || 3;
+my $postcontext_lines = $precontext_lines;
my $file1 = $ARGV[0];
my $file2 = $ARGV[1];
open($fh1, $file1) or die "Can't open $file1";
open($fh2, $file2) or die "Can't open $file2";
+# print files to output so we know which is which
+print "-$file1\n";
+print "+$file2\n";
+
# buffer of matching lines for pre-diff context
my @precontext = ();
# number of post-diff matching lines remaining to print
# Set $postcontext to print the next $postcontext_lines matching lines.
$postcontext = $postcontext_lines;
+
+ # Normally we flush after the postcontext lines are printed, but if
+ # the user has decreed that there aren't any we need to flush now
+ if ($postcontext == 0) {
+ STDOUT->flush();
+ }
}
DISCARD_A => \&discard1,
DISCARD_B => \&discard2 });
- die "Lost sync!" if (!$match_found);
+ if (!$match_found) {
+ printdiff(scalar(@lines1), scalar(@lines2));
+ die "Lost sync!";
+ }
# Since we shouldn't get here unless the first lines of the
# buffers are different, then we must discard some lines off
# treated as common; if that bugs you, use Algorithm::Diff.
if ($lines1[$n1] eq $lines2[$n2] && $lines1[$n1+1] eq $lines2[$n2+1]) {
printdiff($n1, $n2);
+ return 1;
}
+
+ return 0;
}
sub simple_diff
return if checkmatch($cnt, $n);
}
}
+
+ printdiff(scalar(@lines1), scalar(@lines2));
die "Lost sync!";
}
# figure out what to do with this line
if ($postcontext > 0) {
# we're in the post-context of a diff: print it
- $postcontext--;
print ' ', $l1;
$lineno1++;
$lineno2++;
+ if (--$postcontext == 0) {
+ STDOUT->flush();
+ }
}
else {
# we're in the middle of a matching region... save this