#!/usr/bin/perl #!/usr/local/bin/perl use Getopt::Std; ####################################################################### # checktrace - trace file consistency checker and balancer. # # Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. # May not be used, modified, or copied without permission. # # This script reads a Malloc Lab trace file, checks it for consistency, # and outputs a balanced version by appending any necessary free requests. # ####################################################################### $| = 1; # autoflush output on every print statement # # void usage(void) - print help message and terminate # sub usage { printf STDERR "$_[0]\n"; printf STDERR "Usage: $0 [-hs]\n"; printf STDERR "Options:\n"; printf STDERR " -h Print this message\n"; printf STDERR " -s Emit only a brief summary\n"; die "\n" ; } ############## # Main routine ############## # # Parse and check the command line arguments # getopts('hs'); if ($opt_h) { usage(""); } $summary = $opt_s; # # HASH keeps a running tally of outstanding alloc/realloc # requests. When a free request is encountered, the corresponding # hash entry is deleted. When we are finished reading the trace, # what is left are the unmatched alloc/realloc requests. # %HASH = (); # Read the trace header values $heap_size = ; chomp($heap_size); $num_blocks = ; chomp($num_blocks); $old_num_ops = ; chomp($old_num_ops); $weight = ; chomp($weight); # # Find any allocate requests that don't have a matching free requests # $linenum = 4; $requestnum = 0; while ($line = ) { chomp($line); $linenum++; ($cmd, $id, $size) = split(" ", $line); # ignore blank lines if (!$cmd) { next; } # save the line for output later $lines[$requestnum++] = $line; #ignore realloc requests, as long as they are preceeded by an alloc request if ($cmd eq "r") { if (!$HASH{$id}) { die "$0: ERROR[$linenum]: realloc without previous alloc\n"; } next; } if ($cmd eq "a" and $HASH{$id} eq "a") { die "$0: ERROR[$linenum]: allocate with no intervening free.\n"; } if ($cmd eq "a" and $HASH{$id} eq "f") { die "$0: ERROR[$linenum]: reused ID $id.\n"; } if ($cmd eq "f" and !exists($HASH{$id})) { die "$0: ERROR[$linenum]: freeing unallocated block.\n"; next; } if ($cmd eq "f" and !$HASH{$id} eq "f") { die "$0: ERROR[$linenum]: freeing already freed block.\n"; next; } if ($cmd eq "f") { delete $HASH{$id}; } else { $HASH{$id} = $cmd; } } # # If called with -s argument , print a brief balance summary and exit # if ($summary) { if (!%HASH) { print "Balanced trace.\n"; } else { print "Unbalanced tree.\n"; } exit; } # # Output a balanced version of the trace # $new_ops = keys %HASH; $new_num_ops = $old_num_ops + $new_ops; print "$heap_size\n"; print "$num_blocks\n"; print "$new_num_ops\n"; print "$weight\n"; # print the old requests foreach $item (@lines) { print "$item\n"; } # print a set of free requests that will balance the trace foreach $key (sort keys %HASH) { if ($HASH{$key} ne "a" and $HASH{$key} ne "r") { die "$0: ERROR: Invalid free request in residue.\n"; } print "f $key\n"; } exit;