$Verbose = 0;
$SaveStderr = 0;
$SaveStdout = 0;
+$StdoutBinary = 0;
+$StderrBinary = 0;
$Status = 0;
@PgmArgs = ();
$PgmFail=0;
@PgmStderrFile = ();
$PreScript = '';
$PostScript = '';
-$TimeCmd = '';
+$TimeCmd = 'time';
$StatsFile = "$TmpPrefix/stats$$";
$CachegrindStats = "cachegrind.out.summary";
$SysSpecificTiming = '';
+$SysCPUCounting = 0; # Use CPU counters
$Cachegrind = 'no';
+$Counters = "";
die "$Pgm: program to run not given as first argument\n" if $#ARGV < 0;
$ToRun = $ARGV[0]; shift(@ARGV);
/^-accept-output-stdout$/ && do { $SaveStdout = 1; next arg; };
/^-accept-output$/ && do { $SaveStdout = 1; $SaveStderr = 1; next arg; };
+ /^-stdout-binary/ && do { $StdoutBinary=1; next arg; };
+ /^-stderr-binary/ && do { $StderrBinary=1; next arg; };
+
/^-O(.*)/ && do { push(@PgmArgs, &grab_arg_arg('-O',$1)); next arg; };
/^-i(.*)/ && do { $PgmStdinFile = &grab_arg_arg('-i',$1);
$Status++,
next arg; };
/^-(ghc|hbc)-timing$/ && do { $SysSpecificTiming = $1;
next arg; };
+ /^-cpu-counting-(.)$/ && do { $SysCPUCounting = "$1";
+ next arg; };
/^-cachegrind$/ && do { $SysSpecificTiming = 'ghc-instrs';
$Cachegrind = 'yes';
next arg };
# deal with system-specific timing options
$TimingMagic = '';
if ( $SysSpecificTiming =~ /^ghc/ ) {
- $TimingMagic = "+RTS -S$StatsFile -RTS"
+ if ($SysCPUCounting) {
+ # Count specified CPU events
+ $cpu_counting_ghc = "-a$SysCPUCounting";
+ } else {
+ $cpu_counting_ghc = "";
+ }
+ $TimingMagic = "+RTS -S$StatsFile $cpu_counting_ghc -RTS"
} elsif ( $SysSpecificTiming eq 'hbc' ) {
$TimingMagic = "-S$StatsFile";
}
local($to_do);
$PostScriptLines = `cat $PostScript`;
$PostScriptLines =~ s/\r//g;
- $* = 1;
- $PostScriptLines =~ s#\$o1#$TmpPrefix/runtest$$.1#g;
- $PostScriptLines =~ s#\$o2#$TmpPrefix/runtest$$.2#g;
+ $PostScriptLines =~ s#\$o1#$TmpPrefix/runtest$$.1#gm;
+ $PostScriptLines =~ s#\$o2#$TmpPrefix/runtest$$.2#gm;
+# The postfix 'm' deals with recent versions of
+# Perl that removed the $* feature
} else {
$PostScriptLines = '';
}
cat /dev/null > $DefaultStderrFile
$PreScriptLines
$SpixifyLine1
-echo $TimeCmd /bin/sh -c \'$CachegrindPrefix $ToRun $TimingMagic @PgmArgs < $PgmStdinFile 1> $TmpPrefix/runtest$$.1 2> $TmpPrefix/runtest$$.2 3> $TmpPrefix/runtest$$.3\'
-$TimeCmd /bin/sh -c \'$CachegrindPrefix $ToRun $TimingMagic @PgmArgs < $PgmStdinFile 1> $TmpPrefix/runtest$$.1 2> $TmpPrefix/runtest$$.2 3> $TmpPrefix/runtest$$.3\'
+$TimeCmd /bin/sh -c \'$CachegrindPrefix $ToRun $TimingMagic @PgmArgs < $PgmStdinFile 1> $TmpPrefix/runtest$$.1.raw 2> $TmpPrefix/runtest$$.2.raw 3> $TmpPrefix/runtest$$.3.raw\'
progexit=\$?
+if [ "$StdoutBinary" = "0" ]; then
+ dos2unix < $TmpPrefix/runtest$$.1.raw > $TmpPrefix/runtest$$.1
+else
+ cp $TmpPrefix/runtest$$.1.raw $TmpPrefix/runtest$$.1
+fi
+if [ "$StderrBinary" = "0" ]; then
+ dos2unix < $TmpPrefix/runtest$$.2.raw > $TmpPrefix/runtest$$.2
+else
+ cp $TmpPrefix/runtest$$.2.raw $TmpPrefix/runtest$$.2
+fi
+dos2unix < $TmpPrefix/runtest$$.3.raw > $TmpPrefix/runtest$$.3
if [ \$progexit -eq 0 ] && [ $PgmFail -ne 0 ]; then
echo $ToRun @PgmArgs \\< $PgmStdinFile
echo "****" expected a failure, but was successful
$PostScriptLines
hit='NO'
for out_file in @PgmStdoutFile ; do
- if diff --strip-trailing-cr \$out_file $TmpPrefix/runtest$$.1 > /dev/null 2>&1 ; then
+ if sed "s/\r\$//" $TmpPrefix/runtest$$.1 | cmp -s \$out_file - ; then
hit='YES'
fi
done
hit='NO'
for out_file in @PgmStderrFile ; do
- if diff --strip-trailing-cr \$out_file $TmpPrefix/runtest$$.2 > /dev/null 2>&1 ; then
+ if sed "s/\r\$//" $TmpPrefix/runtest$$.2 | cmp -s \$out_file - ; then
hit='YES'
fi
done
cp $TmpPrefix/runtest$$.2 $PgmStderrFile[0]
fi
-${RM} core $ToRunOrig.spix $DefaultStdoutFile $DefaultStderrFile $TmpPrefix/runtest$$.1 $TmpPrefix/runtest$$.2 $TmpPrefix/runtest$$.3
+${RM} core $ToRunOrig.spix $DefaultStdoutFile $DefaultStderrFile $TmpPrefix/runtest$$.1 $TmpPrefix/runtest$$.2 $TmpPrefix/runtest$$.3 $TmpPrefix/runtest$$.1.raw $TmpPrefix/runtest$$.2.raw $TmpPrefix/runtest$$.3.raw
exit \$myexit
EOSCRIPT
# print out what we found
print STDERR "<<$SysSpecificTiming: ";
if ( $Cachegrind ne 'yes') {
- print STDERR "$BytesAlloc bytes, $GCs GCs, $AvgResidency/$MaxResidency avg/max bytes residency ($ResidencySamples samples), $GCWork bytes GC work, ${TotMem}M in use, $InitTime INIT ($InitElapsed elapsed), $MutTime MUT ($MutElapsed elapsed), $GcTime GC ($GcElapsed elapsed)";
+ print STDERR "$BytesAlloc bytes, $GCs GCs, $AvgResidency/$MaxResidency avg/max bytes residency ($ResidencySamples samples), $GCWork bytes GC work, ${TotMem}M in use, $InitTime INIT ($InitElapsed elapsed), $MutTime MUT ($MutElapsed elapsed), $GcTime GC ($GcElapsed elapsed), $Gc0Time GC(0) ($Gc0Elapsed elapsed), $Gc1Time GC(1) ($Gc1Elapsed elapsed), $Balance balance$Counters";
} else {
- print STDERR "$BytesAlloc bytes, $GCs GCs, $AvgResidency/$MaxResidency avg/max bytes residency ($ResidencySamples samples), $GCWork bytes GC work, ${TotMem}M in use, $InitTime INIT ($InitElapsed elapsed), $MutTime MUT ($MutElapsed elapsed), $GcTime GC ($GcElapsed elapsed), $TotInstrs instructions, $TotReads memory reads, $TotWrites memory writes, $TotMisses L2 cache misses";
+ print STDERR "$BytesAlloc bytes, $GCs GCs, $AvgResidency/$MaxResidency avg/max bytes residency ($ResidencySamples samples), $GCWork bytes GC work, ${TotMem}M in use, $InitTime INIT ($InitElapsed elapsed), $MutTime MUT ($MutElapsed elapsed), $GcTime GC ($GcElapsed elapsed), $Gc0Time GC(0) ($Gc0Elapsed elapsed), $Gc1Time GC(1) ($Gc1Elapsed elapsed), $Balance balance, $TotInstrs instructions, $TotReads memory reads, $TotWrites memory writes, $TotMisses L2 cache misses";
};
print STDERR " :$SysSpecificTiming>>\n";
local($max_live) = 0;
local($tot_live) = 0; # for calculating residency stuff
local($tot_samples) = 0;
+ local($into_gc_counters) = 0; # once we reach into the GC counters part
+ local($counters) = "";
+ local($counter) = "";
+ local($count) = 0;
$GCWork = 0;
+ $GCs = 0;
+ $Balance = 1;
while (<STATS>) {
if (! /Gen:\s+0/ && /^\s*\d+\s+\d+\s+(\d+)\s+\d+\.\d+/ ) {
$max_live = $1 if $max_live < $1;
}
$BytesAlloc = $1 if /^\s*([0-9,]+) bytes allocated in the heap/;
- $GCWork += $1 if /^\s*([0-9,]+) bytes copied during GC/;
+
+ if (/^\s*([0-9,]+) bytes copied during GC/) {
+ $tmp = $1;
+ $tmp =~ s/,//g;
+ $GCWork += $tmp;
+ }
# if ( /^\s*([0-9,]+) bytes maximum residency .* (\d+) sample/ ) {
# $MaxResidency = $1; $ResidencySamples = $2;
# }
- $GCs = $1 if /^\s*([0-9,]+) collections? in generation 0/;
+ $GCs += $1 if /^\s*Generation\s*\d+:\s*([0-9,]+) collections/;
- if ( /^\s+([0-9]+)\s+Mb total memory/ ) {
+ if ( /^\s+([0-9]+)\s+M[Bb] total memory/ ) {
$TotMem = $1;
}
} elsif ( /^\s*GC\s+time\s*(-*\d+\.\d\d)s\s*\(\s*(-*\d+\.\d\d)s elapsed\)/ ) {
$GcTime = $1; $GcElapsed = $2;
}
+
+ if (/Generation (\d+):\s*\d+ collections,\s*\d+ parallel,\s*(-*\d+\.\d\d)s\s*,\s*(-*\d+\.\d\d)s elapsed/) {
+ if ($1 == 0) {
+ $Gc0Time = $2; $Gc0Elapsed = $3;
+ } elsif ($1 == 1) {
+ $Gc1Time = $2; $Gc1Elapsed = $3;
+ }
+ }
+
+ if (/work balance: ([0-9.]+)/) {
+ $Balance = $1;
+ }
+
+
+ if ( /CPU GC counters/ ) {
+ # Counters that follow correspond to GC
+ $into_gc_counters = 1;
+ }
+
+ if ( /^\s+\(([A-Z_0-9]+)\)\s+:\s+([0-9,]+)/ ) {
+ $counter = $1;
+ $count = $2;
+ $count =~ s/,//g; # Remove commas in numbers
+ # Pretty printing elements of a list with type [(String,[Float])]
+ # It's a bit lame for passing values but it works.
+ if($into_gc_counters) {
+ $counters = "$counters(\"GC:$counter\",[$count]),";
+ } else {
+ $counters = "$counters(\"$counter\",[$count]),";
+ }
+ }
+
+ if ( /^\s+\(([A-Z_0-9]+)\)\s+\%\s+of\s+\(([A-Z_0-9]+)\)\s+:\s+([0-9.]+)/ ) {
+ $counter = "$1/$2"; # Relative quantity
+ $count = $3;
+ # Pretty printing elements of a list with type [(String,[Float])]
+ # It's a bit lame for passing values but it works.
+ if($into_gc_counters) {
+ $counters = "$counters(\"GC:$counter\",[$count]),";
+ } else {
+ $counters = "$counters(\"$counter\",[$count]),";
+ }
+ }
+
}
close(STATS) || die "Failed when closing $StatsFile\n";
if ( $tot_samples > 0 ) {
$AvgResidency = int ($tot_live / $tot_samples) ;
}
+ if ( length($counters) == 0 ) {
+ $Counters = "";
+ } else {
+ chop($counters); # remove trailing comma from the last entry
+ $Counters = " [$counters]";
+ }
+
} elsif ( $SysSpecificTiming eq 'hbc' ) {
open(STATS, $StatsFile) || die "Failed when opening $StatsFile\n";
print STDERR "Warning: GcElapsed not found in stats file\n" unless defined($GcElapsed);
print STDERR "Warning: total memory not found in stats file\n" unless defined($TotMem);
print STDERR "Warning: GC work not found in stats file\n" unless defined($GCWork);
+ print STDERR "Warning: Gc0Time not found in stats file\n" unless defined($Gc0Time);
+ print STDERR "Warning: Gc0Elapsed not found in stats file\n" unless defined($Gc0Elapsed);
+ print STDERR "Warning: Gc1Time not found in stats file\n" unless defined($Gc1Time);
+ print STDERR "Warning: Gc1Elapsed not found in stats file\n" unless defined($Gc1Elapsed);
+ print STDERR "Warning: Balance not found in stats file\n" unless defined($Gc1Elapsed);
# things we didn't necessarily expect to find
$MaxResidency = 0 unless defined($MaxResidency);
$AvgResidency = 0 unless defined($AvgResidency);
$ResidencySamples = 0 unless defined($ResidencySamples);
+ $Gc0Time = 0.0 unless defined($Gc0Time);
+ $Gc0Elapsed = 0.0 unless defined($Gc0Elapsed);
+ $Gc1Time = 0.0 unless defined($Gc1Time);
+ $Gc1Elapsed = 0.0 unless defined($Gc1Elapsed);
# a bit of tidying
$BytesAlloc =~ s/,//g;
- $GCWork =~ s/,//g;
$MaxResidency =~ s/,//g;
$GCs =~ s/,//g;
$InitTime =~ s/,//g;