diff-out revision 2929
12929Sktlim@umich.edu#!/usr/bin/perl 22929Sktlim@umich.edu# Copyright (c) 2001-2005 The Regents of The University of Michigan 32929Sktlim@umich.edu# All rights reserved. 42929Sktlim@umich.edu# 52929Sktlim@umich.edu# Redistribution and use in source and binary forms, with or without 62929Sktlim@umich.edu# modification, are permitted provided that the following conditions are 72929Sktlim@umich.edu# met: redistributions of source code must retain the above copyright 82929Sktlim@umich.edu# notice, this list of conditions and the following disclaimer; 92929Sktlim@umich.edu# redistributions in binary form must reproduce the above copyright 102929Sktlim@umich.edu# notice, this list of conditions and the following disclaimer in the 112929Sktlim@umich.edu# documentation and/or other materials provided with the distribution; 122929Sktlim@umich.edu# neither the name of the copyright holders nor the names of its 132929Sktlim@umich.edu# contributors may be used to endorse or promote products derived from 142929Sktlim@umich.edu# this software without specific prior written permission. 152929Sktlim@umich.edu# 162929Sktlim@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172929Sktlim@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182929Sktlim@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192929Sktlim@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202929Sktlim@umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212929Sktlim@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222929Sktlim@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232929Sktlim@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242929Sktlim@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252929Sktlim@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262929Sktlim@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272929Sktlim@umich.edu# 282929Sktlim@umich.edu# Authors: Steve Reinhardt 292929Sktlim@umich.edu 302929Sktlim@umich.edu# 312929Sktlim@umich.edu# This script diffs two SimpleScalar statistics output files. 322929Sktlim@umich.edu# 332929Sktlim@umich.edu 342929Sktlim@umich.eduuse Getopt::Std; 352929Sktlim@umich.edu 362929Sktlim@umich.edu# 372929Sktlim@umich.edu# -t thresh sets threshold for ignoring differences (in %) 382929Sktlim@umich.edu# -p sorts differences by % chg (default is alphabetic) 392929Sktlim@umich.edu# -f ignores fetch-loss statistics 402929Sktlim@umich.edu# -d ignores all distributions 412929Sktlim@umich.edu# 422929Sktlim@umich.edu 432929Sktlim@umich.edugetopts('dfn:pt:h'); 442929Sktlim@umich.edu 452929Sktlim@umich.eduif ($#ARGV < 1) 462929Sktlim@umich.edu{ 472929Sktlim@umich.edu print "\nError: need two file arguments (<reference> <new>).\n"; 482929Sktlim@umich.edu print " Options: -d = Ignore distributions\n"; 492929Sktlim@umich.edu print " -f = Ignore fetch-loss stats\n"; 502929Sktlim@umich.edu print " -p = Sort errors by percentage\n"; 512929Sktlim@umich.edu print " -h = Diff header info separately from stats\n"; 522929Sktlim@umich.edu print " -n <num> = Print top <num> errors (default 20)\n"; 532929Sktlim@umich.edu print " -t <num> = Error threshold in percent (default 1)\n\n"; 542929Sktlim@umich.edu die -1; 552929Sktlim@umich.edu} 562929Sktlim@umich.edu 572929Sktlim@umich.eduopen(REF, "<$ARGV[0]") or die "Error: can't open $ARGV[0].\n"; 582929Sktlim@umich.eduopen(NEW, "<$ARGV[1]") or die "Error: can't open $ARGV[1].\n"; 592929Sktlim@umich.edu 602929Sktlim@umich.edu 612929Sktlim@umich.edu# 622929Sktlim@umich.edu# Things that really should be adjustable via the command line 632929Sktlim@umich.edu# 642929Sktlim@umich.edu 652929Sktlim@umich.edu# Ignorable error (in percent) 662929Sktlim@umich.edu$err_thresh = ($opt_t) ? $opt_t : 0; 672929Sktlim@umich.edu 682929Sktlim@umich.edu# Number of stats to print before omitting 692929Sktlim@umich.edu$omit_count = ($opt_n) ? $opt_n : 20; 702929Sktlim@umich.edu 712929Sktlim@umich.edu 722929Sktlim@umich.edu# 732929Sktlim@umich.edu# First copy everything up to the simulation statistics to a pair of 742929Sktlim@umich.edu# temporary files, stripping out date-related items, and do a plain 752929Sktlim@umich.edu# diff. Any differences in the arguments are not necessarily an issue; 762929Sktlim@umich.edu# any differences in the program output should be caught by the EIO 772929Sktlim@umich.edu# mechanism if an EIO file is used. 782929Sktlim@umich.edu# 792929Sktlim@umich.edu 802929Sktlim@umich.edu# copy_header takes input filehandle and output filename 812929Sktlim@umich.edu 822929Sktlim@umich.edusub copy_header 832929Sktlim@umich.edu{ 842929Sktlim@umich.edu my ($inhandle, $outname) = @_; 852929Sktlim@umich.edu 862929Sktlim@umich.edu open(OUTPUT, ">$outname") or die "Error: can't open $outname.\n"; 872929Sktlim@umich.edu 882929Sktlim@umich.edu while (<$inhandle>) 892929Sktlim@umich.edu { 902929Sktlim@umich.edu # strip out lines that can vary 912929Sktlim@umich.edu next if /^(command line:|M5 compiled on |M5 simulation started |M5 executing on )/; 922929Sktlim@umich.edu last if /Begin Simulation Statistics/; 932929Sktlim@umich.edu print OUTPUT; 942929Sktlim@umich.edu } 952929Sktlim@umich.edu close OUTPUT; 962929Sktlim@umich.edu} 972929Sktlim@umich.edu 982929Sktlim@umich.eduif ($opt_h) { 992929Sktlim@umich.edu 1002929Sktlim@umich.edu # Diff header separately from stats 1012929Sktlim@umich.edu 1022929Sktlim@umich.edu $refheader = "/tmp/smt-test.refheader.$$"; 1032929Sktlim@umich.edu $newheader = "/tmp/smt-test.newheader.$$"; 1042929Sktlim@umich.edu 1052929Sktlim@umich.edu copy_header(\*REF, $refheader); 1062929Sktlim@umich.edu copy_header(\*NEW, $newheader); 1072929Sktlim@umich.edu 1082929Sktlim@umich.edu print "\n===== Header and program output differences =====\n\n"; 1092929Sktlim@umich.edu 1102929Sktlim@umich.edu print `diff $refheader $newheader`; 1112929Sktlim@umich.edu 1122929Sktlim@umich.edu print "\n===== Statistics differences =====\n\n"; 1132929Sktlim@umich.edu} 1142929Sktlim@umich.edu 1152929Sktlim@umich.edu# 1162929Sktlim@umich.edu# Now parse statistics 1172929Sktlim@umich.edu# 1182929Sktlim@umich.edu 1192929Sktlim@umich.edu# 1202929Sktlim@umich.edu# This function takes an open filehandle and returns a reference to 1212929Sktlim@umich.edu# a hash containing all the statistics variables and their values. 1222929Sktlim@umich.edu# 1232929Sktlim@umich.edusub parse_file 1242929Sktlim@umich.edu{ 1252929Sktlim@umich.edu $stathandle = shift; 1262929Sktlim@umich.edu 1272929Sktlim@umich.edu $in_dist = undef; 1282929Sktlim@umich.edu $hashref = { }; # initialize hash for values 1292929Sktlim@umich.edu 1302929Sktlim@umich.edu while (<$stathandle>) 1312929Sktlim@umich.edu { 1322929Sktlim@umich.edu next if /^\s*$/; # skip blank lines 1332929Sktlim@umich.edu next if /^\*\*Ignore/; # temporary, to make totaling scripts easy for ISCA 03 1342929Sktlim@umich.edu last if /End Simulation Statistics/; 1352929Sktlim@umich.edu 1362929Sktlim@umich.edu s/ *#.*//; # strip comments 1372929Sktlim@umich.edu 1382929Sktlim@umich.edu if (/^Memory usage: (\d+) KBytes/) { 1392929Sktlim@umich.edu $stat = 'memory usage'; 1402929Sktlim@umich.edu $value = $1; 1412929Sktlim@umich.edu } 1422929Sktlim@umich.edu elsif ($in_dist) { 1432929Sktlim@umich.edu if ($in_dist =~ /^fetch_loss_counters/) { 1442929Sktlim@umich.edu if (/^fetch_loss_counters_\d+\.end/) { 1452929Sktlim@umich.edu # end line of distribution: clear $in_dist flag 1462929Sktlim@umich.edu $in_dist = undef; 1472929Sktlim@umich.edu next; 1482929Sktlim@umich.edu } 1492929Sktlim@umich.edu else { 1502929Sktlim@umich.edu next if $opt_f; 1512929Sktlim@umich.edu 1522929Sktlim@umich.edu ($stat, $value) = /^(\S+)\s+(.*)/; 1532929Sktlim@umich.edu } 1542929Sktlim@umich.edu } 1552929Sktlim@umich.edu else { 1562929Sktlim@umich.edu if (/(.*)\.end_dist/) { 1572929Sktlim@umich.edu # end line of distribution: clear $in_dist flag 1582929Sktlim@umich.edu $in_dist = undef; 1592929Sktlim@umich.edu next; 1602929Sktlim@umich.edu } 1612929Sktlim@umich.edu if ($opt_d) { 1622929Sktlim@umich.edu next; # bail out if we are ignoring dists... 1632929Sktlim@umich.edu } 1642929Sktlim@umich.edu elsif (/(.*)\.(min|max)_value/) { 1652929Sktlim@umich.edu # treat these like normal stats 1662929Sktlim@umich.edu ($stat, $value) = /^(\S+)\s+(.*)/; 1672929Sktlim@umich.edu } 1682929Sktlim@umich.edu else { 1692929Sktlim@umich.edu # this is ugly because labels in the distribution 1702929Sktlim@umich.edu # buckets don't start in column 0 and may include 1712929Sktlim@umich.edu # embedded spaces 1722929Sktlim@umich.edu ($stat, $value) = 1732929Sktlim@umich.edu /^\s*(\S+(?:.*\S)?)\s+(\d+)\s+\d+\.\d+%/; 1742929Sktlim@umich.edu $stat = $in_dist . '::' . $stat; 1752929Sktlim@umich.edu } 1762929Sktlim@umich.edu } 1772929Sktlim@umich.edu } 1782929Sktlim@umich.edu else { 1792929Sktlim@umich.edu if (/(.*)\.start_dist/) { 1802929Sktlim@umich.edu # start line of distribution: set $in_dist flag 1812929Sktlim@umich.edu # and save distribution name for future reference 1822929Sktlim@umich.edu $in_dist = $1; 1832929Sktlim@umich.edu $stat = $1; 1842929Sktlim@umich.edu $value = 0; 1852929Sktlim@umich.edu } 1862929Sktlim@umich.edu elsif (/^(fetch_loss_counters_\d+)\.start/) { 1872929Sktlim@umich.edu # treat fetch loss counters like distribution, sort of 1882929Sktlim@umich.edu $in_dist = $1; 1892929Sktlim@umich.edu $stat = $1; 1902929Sktlim@umich.edu $value = 0; 1912929Sktlim@umich.edu } 1922929Sktlim@umich.edu else { 1932929Sktlim@umich.edu ($stat, $value) = /^(\S+)\s+(.*)/; 1942929Sktlim@umich.edu } 1952929Sktlim@umich.edu } 1962929Sktlim@umich.edu 1972929Sktlim@umich.edu $$hashref{$stat} = $value; 1982929Sktlim@umich.edu } 1992929Sktlim@umich.edu 2002929Sktlim@umich.edu close($stathandle); 2012929Sktlim@umich.edu return $hashref; 2022929Sktlim@umich.edu} 2032929Sktlim@umich.edu 2042929Sktlim@umich.edu 2052929Sktlim@umich.edu# 2062929Sktlim@umich.edu# pct_diff($old, $new) returns percent difference from $old to $new. 2072929Sktlim@umich.edu# 2082929Sktlim@umich.edusub pct_diff 2092929Sktlim@umich.edu{ 2102929Sktlim@umich.edu my ($old, $new) = @_; 2112929Sktlim@umich.edu return ($old == 0) ? (($new == 0) ? 0 : 9999) : 100 * ($new - $old) / $old; 2122929Sktlim@umich.edu} 2132929Sktlim@umich.edu 2142929Sktlim@umich.edu 2152929Sktlim@umich.edu# 2162929Sktlim@umich.edu# Statistics to ignore: these relate to simulator performance, not 2172929Sktlim@umich.edu# correctness, so don't fail on changes here. 2182929Sktlim@umich.edu# 2192929Sktlim@umich.edu%ignore = ( 2202929Sktlim@umich.edu 'host_seconds' => 1, 2212929Sktlim@umich.edu 'host_tick_rate' => 1, 2222929Sktlim@umich.edu 'host_inst_rate' => 1, 2232929Sktlim@umich.edu 'host_mem_usage' => 1 2242929Sktlim@umich.edu); 2252929Sktlim@umich.edu 2262929Sktlim@umich.edu# 2272929Sktlim@umich.edu# List of key statistics (always displayed) 2282929Sktlim@umich.edu# ==> list stats here WITHOUT trailing thread ID 2292929Sktlim@umich.edu# 2302929Sktlim@umich.edu@key_stat_list = ( 2312929Sktlim@umich.edu 'COM:IPC', 2322929Sktlim@umich.edu 'ISSUE:MSIPC', 2332929Sktlim@umich.edu 'COM:count', 2342929Sktlim@umich.edu 'host_inst_rate', 2352929Sktlim@umich.edu 'sim_insts', 2362929Sktlim@umich.edu 'sim_ticks', 2372929Sktlim@umich.edu 'host_mem_usage' 2382929Sktlim@umich.edu); 2392929Sktlim@umich.edu 2402929Sktlim@umich.edu$key_stat_pattern = join('|', @key_stat_list); 2412929Sktlim@umich.edu 2422929Sktlim@umich.edu# initialize first statistics from each file 2432929Sktlim@umich.edu 2442929Sktlim@umich.edu$max_err_mag = 0; 2452929Sktlim@umich.edu 2462929Sktlim@umich.edu$refhash = parse_file(\*REF); 2472929Sktlim@umich.edu$newhash = parse_file(\*NEW); 2482929Sktlim@umich.edu 2492929Sktlim@umich.edu# The string sim-smt prints on a divide by zero 2502929Sktlim@umich.edu$divbyzero = '<err: divide by zero>'; 2512929Sktlim@umich.edu 2522929Sktlim@umich.eduforeach $stat (sort keys %$refhash) 2532929Sktlim@umich.edu{ 2542929Sktlim@umich.edu $refvalue = $$refhash{$stat}; 2552929Sktlim@umich.edu $newvalue = $$newhash{$stat}; 2562929Sktlim@umich.edu 2572929Sktlim@umich.edu if (!defined($newvalue)) { 2582929Sktlim@umich.edu # stat missing from new file 2592929Sktlim@umich.edu push @missing_stats, $stat; 2602929Sktlim@umich.edu next; 2612929Sktlim@umich.edu } 2622929Sktlim@umich.edu 2632929Sktlim@umich.edu if ($stat =~ /($key_stat_pattern)/o) { 2642929Sktlim@umich.edu # key statistics: always record & display changes in these 2652929Sktlim@umich.edu push @key_stats, [$stat, $refvalue, $newvalue]; 2662929Sktlim@umich.edu } 2672929Sktlim@umich.edu 2682929Sktlim@umich.edu if ($ignore{$stat} or $refvalue eq $newvalue) { 2692929Sktlim@umich.edu # stat is in "ignore" list, or hasn't changed 2702929Sktlim@umich.edu } 2712929Sktlim@umich.edu else { 2722929Sktlim@umich.edu if ($refvalue eq $divbyzero || $newvalue eq $divbyzero) { 2732929Sktlim@umich.edu # one or the other was a divide by zero: 2742929Sktlim@umich.edu # no point in trying to quantify error 2752929Sktlim@umich.edu print "$stat: $refvalue --> $newvalue\n"; 2762929Sktlim@umich.edu } 2772929Sktlim@umich.edu else { 2782929Sktlim@umich.edu $reldiff = pct_diff($refvalue, $newvalue); 2792929Sktlim@umich.edu $diffmag = abs($reldiff); 2802929Sktlim@umich.edu 2812929Sktlim@umich.edu if ($diffmag > $err_thresh) { 2822929Sktlim@umich.edu push @errs, 2832929Sktlim@umich.edu [$stat, $refvalue, $newvalue, $reldiff]; 2842929Sktlim@umich.edu } 2852929Sktlim@umich.edu 2862929Sktlim@umich.edu if ($diffmag > $max_err_mag) { 2872929Sktlim@umich.edu $max_err_mag = $diffmag; 2882929Sktlim@umich.edu } 2892929Sktlim@umich.edu } 2902929Sktlim@umich.edu } 2912929Sktlim@umich.edu 2922929Sktlim@umich.edu # remove from new hash so we can detect added stats 2932929Sktlim@umich.edu delete $$newhash{$stat}; 2942929Sktlim@umich.edu} 2952929Sktlim@umich.edu 2962929Sktlim@umich.edu 2972929Sktlim@umich.edu# 2982929Sktlim@umich.edu# All done. Print comparison summary. 2992929Sktlim@umich.edu# 3002929Sktlim@umich.edu 3012929Sktlim@umich.eduprintf("Maximum error magnitude: %+f%%\n\n", $max_err_mag); 3022929Sktlim@umich.edu 3032929Sktlim@umich.eduprintf(" %-30s %10s %10s %10s %7s\n", ' ', 'Reference', 'New Value', 'Abs Diff', 'Pct Chg'); 3042929Sktlim@umich.edu 3052929Sktlim@umich.eduprintf("Key statistics:\n\n"); 3062929Sktlim@umich.edu 3072929Sktlim@umich.eduforeach $key_stat (@key_stats) 3082929Sktlim@umich.edu{ 3092929Sktlim@umich.edu ($statname, $refvalue, $newvalue, $reldiff) = @$key_stat; 3102929Sktlim@umich.edu 3112929Sktlim@umich.edu # deduce format from reference value 3122929Sktlim@umich.edu $pointpos = rindex($refvalue, '.'); 3132929Sktlim@umich.edu $digits = ($pointpos < 0) ? 0 :(length($refvalue) - $pointpos - 1); 3142929Sktlim@umich.edu $fmt = "%10.${digits}f"; 3152929Sktlim@umich.edu 3162929Sktlim@umich.edu # print differing values with absolute and relative error 3172929Sktlim@umich.edu printf(" %-30s $fmt $fmt $fmt %+7.2f%%\n", 3182929Sktlim@umich.edu $statname, $refvalue, $newvalue, 3192929Sktlim@umich.edu $newvalue - $refvalue, pct_diff($refvalue, $newvalue)); 3202929Sktlim@umich.edu} 3212929Sktlim@umich.edu 3222929Sktlim@umich.eduprintf("\nLargest $omit_count relative errors (> %d%%):\n\n", $err_thresh); 3232929Sktlim@umich.edu 3242929Sktlim@umich.edu$num_errs = 0; 3252929Sktlim@umich.edu 3262929Sktlim@umich.eduif ($opt_p) 3272929Sktlim@umich.edu{ 3282929Sktlim@umich.edu # sort differences by percent change 3292929Sktlim@umich.edu @errs = sort { abs($$b[3]) <=> abs($$a[3]) } @errs; 3302929Sktlim@umich.edu} 3312929Sktlim@umich.edu 3322929Sktlim@umich.eduforeach $err (@errs) 3332929Sktlim@umich.edu{ 3342929Sktlim@umich.edu ($statname, $refvalue, $newvalue, $reldiff) = @$err; 3352929Sktlim@umich.edu 3362929Sktlim@umich.edu # deduce format from reference value 3372929Sktlim@umich.edu $pointpos1 = rindex($refvalue, '.'); 3382929Sktlim@umich.edu $digits1 = ($pointpos1 < 0) ? 0 :(length($refvalue) - $pointpos1 - 1); 3392929Sktlim@umich.edu $pointpos2 = rindex($newvalue, '.'); 3402929Sktlim@umich.edu $digits2 = ($pointpos2 < 0) ? 0 :(length($newvalue) - $pointpos2 - 1); 3412929Sktlim@umich.edu $digits = ($digits1 > $digits2) ? $digits1 : $digits2; 3422929Sktlim@umich.edu $fmt = "%10.${digits}f"; 3432929Sktlim@umich.edu 3442929Sktlim@umich.edu # print differing values with absolute and relative error 3452929Sktlim@umich.edu printf(" %-30s $fmt $fmt $fmt %+7.2f%%\n", 3462929Sktlim@umich.edu $statname, $refvalue, $newvalue, $newvalue - $refvalue, $reldiff); 3472929Sktlim@umich.edu 3482929Sktlim@umich.edu # only print top N errors 3492929Sktlim@umich.edu if (++$num_errs >= $omit_count) 3502929Sktlim@umich.edu { 3512929Sktlim@umich.edu print "[... additional errors omitted ...]\n"; 3522929Sktlim@umich.edu last; 3532929Sktlim@umich.edu } 3542929Sktlim@umich.edu} 3552929Sktlim@umich.edu 3562929Sktlim@umich.edu# 3572929Sktlim@umich.edu# Report missing stats, but first filter out distribution buckets: 3582929Sktlim@umich.edu# these are mostly noise 3592929Sktlim@umich.edu 3602929Sktlim@umich.edu@missing_stats = grep { !/::(\d+|overflows)?$/ } @missing_stats; 3612929Sktlim@umich.edu 3622929Sktlim@umich.edu# get count 3632929Sktlim@umich.edu$missing_stats = scalar(@missing_stats); 3642929Sktlim@umich.edu 3652929Sktlim@umich.eduif ($missing_stats) 3662929Sktlim@umich.edu{ 3672929Sktlim@umich.edu print "\nMissing $missing_stats reference statistics:\n\n"; 3682929Sktlim@umich.edu foreach $stat (@missing_stats) 3692929Sktlim@umich.edu { 3702929Sktlim@umich.edu# print "\t$stat\n"; 3712929Sktlim@umich.edu printf " %-50s ", $stat; 3722929Sktlim@umich.edu print "$$refhash{$stat}\n"; 3732929Sktlim@umich.edu } 3742929Sktlim@umich.edu} 3752929Sktlim@umich.edu 3762929Sktlim@umich.edu# 3772929Sktlim@umich.edu# Any stats left in newhash are added since the reference file 3782929Sktlim@umich.edu# 3792929Sktlim@umich.edu 3802929Sktlim@umich.edu@added_stats = keys %$newhash; 3812929Sktlim@umich.edu 3822929Sktlim@umich.edu# first filter out distribution buckets: mostly noise 3832929Sktlim@umich.edu 3842929Sktlim@umich.edu@added_stats = grep { !/::(\d+|overflows)?$/ } @added_stats; 3852929Sktlim@umich.edu 3862929Sktlim@umich.edu# get count 3872929Sktlim@umich.edu$added_stats = scalar(@added_stats); 3882929Sktlim@umich.edu 3892929Sktlim@umich.eduif ($added_stats) 3902929Sktlim@umich.edu{ 3912929Sktlim@umich.edu print "\nFound $added_stats new statistics:\n\n"; 3922929Sktlim@umich.edu foreach $stat (sort @added_stats) 3932929Sktlim@umich.edu { 3942929Sktlim@umich.edu# print "\t$stat\n"; 3952929Sktlim@umich.edu printf " %-50s ", $stat; 3962929Sktlim@umich.edu print "$$newhash{$stat}\n"; 3972929Sktlim@umich.edu } 3982929Sktlim@umich.edu} 3992929Sktlim@umich.edu 4002929Sktlim@umich.educleanup(); 4012929Sktlim@umich.edu# Exit code is 0 if no stats error, 1 otherwise 4022929Sktlim@umich.edu$status = ($max_err_mag == 0.0) ? 0 : 1; 4032929Sktlim@umich.eduexit $status; 4042929Sktlim@umich.edu 4052929Sktlim@umich.edusub cleanup 4062929Sktlim@umich.edu{ 4072929Sktlim@umich.edu unlink($refheader) if ($refheader); 4082929Sktlim@umich.edu unlink($newheader) if ($newheader); 4092929Sktlim@umich.edu} 410