|
Packit |
0848f5 |
#! /usr/bin/env perl
|
|
Packit |
0848f5 |
# -*- Mode: perl; -*-
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# This script extracts information from files produced by gcov showing what
|
|
Packit |
0848f5 |
# parts of each file have *not* been executed by the test programs.
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# Normally, this script should *not* be used directly; instead, use
|
|
Packit |
0848f5 |
# maint/createcoverage
|
|
Packit |
0848f5 |
# The createcoverave script uses this (getcoverage) script to create the
|
|
Packit |
0848f5 |
# coverage information.
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# To create a coverage report using this script, use the following steps:
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# configure --enable-coverage <other options>
|
|
Packit |
0848f5 |
# make
|
|
Packit |
0848f5 |
# make install
|
|
Packit |
0848f5 |
# make testing
|
|
Packit |
0848f5 |
# < run other tests, such as the Intel, MPICH1, and C++ tests >
|
|
Packit |
0848f5 |
# make coverage
|
|
Packit |
0848f5 |
# maint/getcoverage src/mpi src/util > coverage.txt
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# The script in mpich-tests/getcoverage will perform all of these steps
|
|
Packit |
0848f5 |
# (this script is not yet included with the MPICH distribution)
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# As an option, create HTML versions of the files with the uncovered code
|
|
Packit |
0848f5 |
# highlighted with a different background color (e.g., pale red). These
|
|
Packit |
0848f5 |
# should be placed into the same directory structure as the original source
|
|
Packit |
0848f5 |
# files, but with a different root ($annoteSrcDir)
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# ToDo:
|
|
Packit |
0848f5 |
# Another useful option for graphical output would be to keep track of the
|
|
Packit |
0848f5 |
# percentage of covered lines and produce an "xdu"-style map of the
|
|
Packit |
0848f5 |
# coverage, with color indicating the fraction of coverage.
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# The GNU tools sometimes incorrectly mark "break" statements within a
|
|
Packit |
0848f5 |
# case statement as not executed. As break can also be used in a loop, where
|
|
Packit |
0848f5 |
# it is an executable statement, we can't just ignore breaks, and we can't
|
|
Packit |
0848f5 |
# determine which type the break is without parsing the program :(.
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
use warnings;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
$includeFileInOutput = 0;
|
|
Packit |
0848f5 |
$skipErrExits = 1;
|
|
Packit |
0848f5 |
$outputUncovered = 1;
|
|
Packit |
0848f5 |
@UnCalled = ();
|
|
Packit |
0848f5 |
@TopFilenames = (); # Array of files and directories provided on the
|
|
Packit |
0848f5 |
# command line
|
|
Packit |
0848f5 |
@CoveredFiles = (); # Array of files that are ok
|
|
Packit |
0848f5 |
# annoteSrcDir is where the annotation files are placed,
|
|
Packit |
0848f5 |
# annoteBaseDir is the base file name that is stripped from the
|
|
Packit |
0848f5 |
# file names
|
|
Packit |
0848f5 |
$annoteSrcDir = "";
|
|
Packit |
0848f5 |
$annoteWebPrefix = "";
|
|
Packit |
0848f5 |
$CoverageMessage = ""; # Extra message for the coverage index file
|
|
Packit |
0848f5 |
$indexfile = ""; # File to contain the index of files
|
|
Packit |
0848f5 |
$annoteFiles = 0;
|
|
Packit |
0848f5 |
$annoteBaseDir = "";
|
|
Packit |
0848f5 |
%AnnoteFilesMap = (); # Clear the list of files
|
|
Packit |
0848f5 |
%AnnoteMissed = (); # Clear the mapping of filenames to "missed;total" lines
|
|
Packit |
0848f5 |
%AnnoteFilesToOrig = (); # Map from annoted file key to original name (used for
|
|
Packit |
0848f5 |
# indexing into AnnoteMissed)
|
|
Packit |
0848f5 |
$gDebug = 0;
|
|
Packit |
0848f5 |
$gDebugDetail = 0;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# The line leaders are used to provide a common set of expressions to match
|
|
Packit |
0848f5 |
# the begining of a line. This matches the output from the gcov tools.
|
|
Packit |
0848f5 |
# There are two of these because the output from the tools associtated with
|
|
Packit |
0848f5 |
# gcc version 2.x and 3.x are different.
|
|
Packit |
0848f5 |
# As, apparently is 4.x.
|
|
Packit |
0848f5 |
# We also permit an isolated open or close brace on the line (a non-executable
|
|
Packit |
0848f5 |
# statement)
|
|
Packit |
0848f5 |
$lineLeader2 = '^\s*[\{\}]?\s*';
|
|
Packit |
0848f5 |
$lineLeader3 = '^\s*-:\s*\d+:\s*[\{\}]?\s*';
|
|
Packit |
0848f5 |
$lineLeader4 = '^\s*[0-9-]+:\s*\d+:\s*[\{\}]?\s*';
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# This is the list of known block names. They represent several types of
|
|
Packit |
0848f5 |
# code for which it may be desirable not to count in coverage analysis.
|
|
Packit |
0848f5 |
# Code that normally should not be executed:
|
|
Packit |
0848f5 |
# DEBUG - Code for debugging
|
|
Packit |
0848f5 |
# EXPERIMENTAL - Experimental code that will normally not be executed
|
|
Packit |
0848f5 |
# Code that may be executed, but for which it is difficult to write
|
|
Packit |
0848f5 |
# coverage tests
|
|
Packit |
0848f5 |
# USEREXTENSION - Code that provides for user extensions, particularly
|
|
Packit |
0848f5 |
# through places where user-provided functions may be called
|
|
Packit |
0848f5 |
# OPTIONALINIT - Code that provides for lazy initialization of
|
|
Packit |
0848f5 |
# datastructures, particularly function tables.
|
|
Packit |
0848f5 |
# HETEROGENEOUS - Code that provides for heterogenous data representations
|
|
Packit |
0848f5 |
# Note that MPICH current does not support such code, and it is
|
|
Packit |
0848f5 |
# more correct for any such experimental code to be ifdef'ed out
|
|
Packit |
0848f5 |
# the the #ifdef MPID_HAS_HETERO ... #endif
|
|
Packit |
0848f5 |
# Code that is executed only with erroneous input (e.g., user errors) or
|
|
Packit |
0848f5 |
# exceptional events (e.g., socket unexpectedly closes).
|
|
Packit |
0848f5 |
# ERROR HANDLING - Code for handling or reporting errors
|
|
Packit |
0848f5 |
@BlockNames = ( "DEBUG", "ERROR HANDLING", "EXPERIMENTAL", "USEREXTENSION",
|
|
Packit |
0848f5 |
"OPTIONALINIT", "HETEROGENEOUS" );
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# Keep track of coverage amounts
|
|
Packit |
0848f5 |
$GrandTotal = 0;
|
|
Packit |
0848f5 |
$GrandTotalMissed = 0;
|
|
Packit |
0848f5 |
$GrandTotalExec = 0;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# gfilename is used to hold the current open file for READING, so
|
|
Packit |
0848f5 |
# that error messages can be more specific
|
|
Packit |
0848f5 |
$gFilename = "";
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# ----------------------------------------------------------------------------
|
|
Packit |
0848f5 |
for (@ARGV) {
|
|
Packit |
0848f5 |
if (/-webpages=(.*)/) {
|
|
Packit |
0848f5 |
# Create the coverage in default web pages for the device
|
|
Packit |
0848f5 |
# named as an argument (e.g., maint/getcoverage -webpages=ch3:sock)
|
|
Packit |
0848f5 |
my $device = $1;
|
|
Packit |
0848f5 |
my $weblocbase = "/tmp/_HMuTRgPPE/mpich-3.2.1/www/coverage";
|
|
Packit |
0848f5 |
my $webloc = $weblocbase . "/$device";
|
|
Packit |
0848f5 |
$annoteSrcDir = $webloc;
|
|
Packit |
0848f5 |
$annoteFiles = 1;
|
|
Packit |
0848f5 |
$annoteWebPrefix = "";
|
|
Packit |
0848f5 |
$indexdir = $webloc;
|
|
Packit |
0848f5 |
$indexfile = "$indexdir/index.htm";
|
|
Packit |
0848f5 |
$coveredindexfile = "$indexdir/covered.htm";
|
|
Packit |
0848f5 |
if (! -d $indexdir) { &MakeDirs( $indexfile ); }
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (/-annote=(.*)/) {
|
|
Packit |
0848f5 |
# Create an annotation of the source data in the specified root
|
|
Packit |
0848f5 |
# directory
|
|
Packit |
0848f5 |
$annoteSrcDir = $1;
|
|
Packit |
0848f5 |
$annoteFiles = 1;
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (/-annoteweb=(.*)/) {
|
|
Packit |
0848f5 |
# annoteweb gives the URL that matches the annoteSrcDir.
|
|
Packit |
0848f5 |
$annoteWebPrefix = $1;
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (/-index=(.*)/) {
|
|
Packit |
0848f5 |
$indexfile = $1;
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (/-indexdir=(.*)/) {
|
|
Packit |
0848f5 |
# This target sets the directory for the index file, along with
|
|
Packit |
0848f5 |
# the file that contains the names of the files that are
|
|
Packit |
0848f5 |
# considered completely covered.
|
|
Packit |
0848f5 |
my $indexdir = $1;
|
|
Packit |
0848f5 |
$indexfile = "$indexdir/index.htm";
|
|
Packit |
0848f5 |
$coveredindexfile = "$indexdir/covered.htm";
|
|
Packit |
0848f5 |
if (! -d $indexdir) { &MakeDirs( $indexfile ); }
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (/-coveredmsg=(.*)/) {
|
|
Packit |
0848f5 |
$CoverageMessage = $1;
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (/-debugall/) {
|
|
Packit |
0848f5 |
$gDebugDetail = 1;
|
|
Packit |
0848f5 |
$gDebug = 1;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (/-debug/) {
|
|
Packit |
0848f5 |
$gDebug = 1;
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
$TopFilenames[$#TopFilenames + 1] = $_;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
# ----------------------------------------------------------------------------
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# ----------------------------------------------------------------------------
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
for my $filename (@TopFilenames) {
|
|
Packit |
0848f5 |
if (-d $filename) {
|
|
Packit |
0848f5 |
# Check for a "pmpi" directory - one that was used to merge
|
|
Packit |
0848f5 |
# PMPI and MPI outputs. If found, we skip to the next directory
|
|
Packit |
0848f5 |
if ($filename =~ /\-pmpi$/) { next; }
|
|
Packit |
0848f5 |
# Added to handle a change in the naming convention for object files
|
|
Packit |
0848f5 |
# in MPICH, which now needs a -mpi directory as well as the -pmpi
|
|
Packit |
0848f5 |
# directory needed to handle the pmpi object files.
|
|
Packit |
0848f5 |
if ($filename =~ /\-mpi$/) { next; }
|
|
Packit |
0848f5 |
# Expand the directory into a list of files. If there are
|
|
Packit |
0848f5 |
# subdirectories, expand them too (e.g., get a list of
|
|
Packit |
0848f5 |
# *every* file within the directory tree.
|
|
Packit |
0848f5 |
@files = &ExpandDir( $filename );
|
|
Packit |
0848f5 |
foreach my $file (@files) {
|
|
Packit |
0848f5 |
($missed_lines,$total_lines,$execLines) =
|
|
Packit |
0848f5 |
&CountUncoveredLines( $file );
|
|
Packit |
0848f5 |
$GrandTotal += $total_lines;
|
|
Packit |
0848f5 |
$GrandTotalMissed += $missed_lines;
|
|
Packit |
0848f5 |
$GrandTotalExec += $execLines;
|
|
Packit |
0848f5 |
$AnnoteMissed{$file} = "$missed_lines;$total_lines;$execLines";
|
|
Packit |
0848f5 |
if ($missed_lines) {
|
|
Packit |
0848f5 |
print "$missed_lines line(s) not covered by tests in $file\n";
|
|
Packit |
0848f5 |
&WriteAnnoteFile( $file, $total_lines, $execLines, $missed_lines );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
print "All code covered by tests in $file\n";
|
|
Packit |
0848f5 |
$CoveredFiles[$#CoveredFiles+1] = $file;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (-s $filename) {
|
|
Packit |
0848f5 |
($missed_lines,$total_lines,$execLines) =
|
|
Packit |
0848f5 |
&CountUncoveredLines( $filename );
|
|
Packit |
0848f5 |
$GrandTotal += $total_lines;
|
|
Packit |
0848f5 |
$GrandTotalMissed += $missed_lines;
|
|
Packit |
0848f5 |
$GrandTotalExec += $execLines;
|
|
Packit |
0848f5 |
$AnnoteMissed{$filename} = "$missed_lines;$total_lines;$execLines";
|
|
Packit |
0848f5 |
print "$filename - $missed_lines missed lines\n" if $gDebug;
|
|
Packit |
0848f5 |
if ($missed_lines) {
|
|
Packit |
0848f5 |
print "$missed_lines line(s) not covered by tests in $filename\n";
|
|
Packit |
0848f5 |
&WriteAnnoteFile( $filename, $total_lines, $execLines, $missed_lines );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
print "All code covered by tests in $filename\n";
|
|
Packit |
0848f5 |
$CoveredFiles[$#CoveredFiles+1] = $filename;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
print "Cannot open $filename\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
for $routine (@UnCalled) {
|
|
Packit |
0848f5 |
print STDERR "$routine never called\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
if ($annoteFiles && $indexfile ne "") {
|
|
Packit |
0848f5 |
# Here is where we could process the list of files that were annotated
|
|
Packit |
0848f5 |
&WriteAnnoteFileMap( $indexfile );
|
|
Packit |
0848f5 |
if ($coveredindexfile ne "") {
|
|
Packit |
0848f5 |
WriteCoveredFileMap( $coveredindexfile );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# ----------------------------------------------------------------------------
|
|
Packit |
0848f5 |
# Here begin the support routines
|
|
Packit |
0848f5 |
# ----------------------------------------------------------------------------
|
|
Packit |
0848f5 |
# ?Count the number of uncovered lines, and return that number.
|
|
Packit |
0848f5 |
sub CountUncoveredLines {
|
|
Packit |
0848f5 |
my $filename = $_[0];
|
|
Packit |
0848f5 |
my $missed_lines = 0;
|
|
Packit |
0848f5 |
my $headerOutput = 0;
|
|
Packit |
0848f5 |
my $linecount = 0; # Line in the coverage file
|
|
Packit |
0848f5 |
my $fileline = 0; # Line in the original file
|
|
Packit |
0848f5 |
my $executableLines = 0; # Number of lines that could be executed
|
|
Packit |
0848f5 |
my $lastLineOut = -1;
|
|
Packit |
0848f5 |
my ($lineincr, $filelineincr); # Used to update linecount,fileline
|
|
Packit |
0848f5 |
my $oldLine;
|
|
Packit |
0848f5 |
my $lastLine;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
open( FD, "<$filename" ) || die "Could not open $filename\n";
|
|
Packit |
0848f5 |
$gFilename = $filename; # Export filename for error reporting
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Note that linecount is relative to the foo.c.gcov file, not the
|
|
Packit |
0848f5 |
# original foo.c file.
|
|
Packit |
0848f5 |
# Gcc 3.x changed the output format (including a line number and
|
|
Packit |
0848f5 |
# a - for unexecuted lines, i.e.,
|
|
Packit |
0848f5 |
# ^\s*-:\s*\d+:original-text-line
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
L: while (<FD>) {
|
|
Packit |
0848f5 |
$linecount++;
|
|
Packit |
0848f5 |
# Coverage messages appear to always begin in the first column.
|
|
Packit |
0848f5 |
if (/^\s/) { $fileline++; }
|
|
Packit |
0848f5 |
# Skip any error checking block
|
|
Packit |
0848f5 |
if (/^\s*#\s*ifdef\s+HAVE_ERROR_CHECKING/ ||
|
|
Packit |
0848f5 |
/^\s*-:\s*\d+:\s*#\s*ifdef\s+HAVE_ERROR_CHECKING/) {
|
|
Packit |
0848f5 |
while (<FD>) {
|
|
Packit |
0848f5 |
$linecount++;
|
|
Packit |
0848f5 |
if (/^\s/) { $fileline++; }
|
|
Packit |
0848f5 |
if (/^\s+#\s*endif/ || /^\s*#\s*els/ ||
|
|
Packit |
0848f5 |
/^\s*-:\s*\d+:\s*#\s*endif/ || /^\s*-:\s*\d+:\s*#\s*els/) {
|
|
Packit |
0848f5 |
last;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Skip any blocks marked as debugging or unavoidable error checking
|
|
Packit |
0848f5 |
# code
|
|
Packit |
0848f5 |
foreach my $name (@BlockNames) {
|
|
Packit |
0848f5 |
if (/$lineLeader2\/\*\s+--BEGIN $name--\s+\*\// ||
|
|
Packit |
0848f5 |
/$lineLeader3\/\*\s+--BEGIN $name--\s+\*\// ||
|
|
Packit |
0848f5 |
/$lineLeader4\/\*\s+--BEGIN $name--\s+\*\//) {
|
|
Packit |
0848f5 |
# It is usually an error to encounter a block begin
|
|
Packit |
0848f5 |
# within another block. The exception is the
|
|
Packit |
0848f5 |
# EXPERIMENTAL block, which may contain ERROR HANDLING blocks
|
|
Packit |
0848f5 |
my $allowNest = 0;
|
|
Packit |
0848f5 |
if ($name eq "EXPERIMENTAL") { $allowNest = 1; }
|
|
Packit |
0848f5 |
($lineincr,$filelineincr) =
|
|
Packit |
0848f5 |
&skipBlock( $name, $allowNest, $linecount );
|
|
Packit |
0848f5 |
$linecount += $lineincr;
|
|
Packit |
0848f5 |
$fileline += $filelineincr;
|
|
Packit |
0848f5 |
next L;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# If requested, skip obvious error checking lines
|
|
Packit |
0848f5 |
# The errflag set should really be an MPIR_ERR macro; the
|
|
Packit |
0848f5 |
# test is designed to accept only lines that set that flag
|
|
Packit |
0848f5 |
# and nothing else.
|
|
Packit |
0848f5 |
if ($skipErrExits &&
|
|
Packit |
0848f5 |
(/FUNC_EXIT.*STATE/ || /MPIR_Err_return_/ ||
|
|
Packit |
0848f5 |
/MPIR_ERR_SET/ || /MPIR_ERR_POP/ || /goto\s+fn_fail/ ||
|
|
Packit |
0848f5 |
/MPIR_ERR_ADD/ || /\*errflag\s*=\s*[^;]*;\s*$/ ||
|
|
Packit |
0848f5 |
/fn_fail:/ || /MPIR_Err_create_code/)) {
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Gcc 3.3 generates a different output form (!) with only
|
|
Packit |
0848f5 |
# 5 sharps instead of 6. It does mark lines that are not
|
|
Packit |
0848f5 |
# executable with a -, which is an improvement
|
|
Packit |
0848f5 |
if (/^\s*######?/) {
|
|
Packit |
0848f5 |
# First, ignore a few odd markings by gcov
|
|
Packit |
0848f5 |
if (/^\s*######?\s*\}\s*$/ || /^\s*######?\s*:\s*\d+:\s*\}\s*$/) {
|
|
Packit |
0848f5 |
# Ignore a closed brace
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
$missed_lines++;
|
|
Packit |
0848f5 |
$executableLines++; # This missed line is executable
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# The char\s+.* allows char or const char (or other
|
|
Packit |
0848f5 |
# things, but nothing else should use FCNAME).
|
|
Packit |
0848f5 |
if (/static\s+char\s+.*FCNAME\[\]\s*=\s*\"(.*)\"/) {
|
|
Packit |
0848f5 |
# Add this to a list of functions never called.
|
|
Packit |
0848f5 |
$UnCalled[$#UnCalled + 1] = $1;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($outputUncovered) {
|
|
Packit |
0848f5 |
if (!$headerOutput) {
|
|
Packit |
0848f5 |
print "\nUncovered lines in $filename\n";
|
|
Packit |
0848f5 |
$headerOutput = 1;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($lastLineOut < $linecount - 2) {
|
|
Packit |
0848f5 |
my $ll = $linecount - 2;
|
|
Packit |
0848f5 |
print "$ll:\t$oldLine";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($lastLineOut < $linecount - 1) {
|
|
Packit |
0848f5 |
my $ll = $linecount - 1;
|
|
Packit |
0848f5 |
print "$ll:\t$lastLine";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print "$linecount:\t$_";
|
|
Packit |
0848f5 |
$lastLineOut = $linecount;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (/^\s*-:/) {
|
|
Packit |
0848f5 |
;
|
|
Packit |
0848f5 |
# Not (at least to gcov) an executable line
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (/^\s*\d+:/) {
|
|
Packit |
0848f5 |
# A line that was executed at least once
|
|
Packit |
0848f5 |
$executableLines++;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($includeFileInOutput) {
|
|
Packit |
0848f5 |
print $_;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
$oldLine = $lastLine;
|
|
Packit |
0848f5 |
$lastLine = $_;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
close (FD);
|
|
Packit |
0848f5 |
return ($missed_lines,$fileline,$executableLines);
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# ----------------------------------------------------------------------------
|
|
Packit |
0848f5 |
# ?Annotate a file by placing the uncovered lines in bgcolor
|
|
Packit |
0848f5 |
# AnnotateUncoveredLines( coveragefile, bgcolor, filenhandle )
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# This uses a state machine to move between the states of:
|
|
Packit |
0848f5 |
# init - beginning (top of file)
|
|
Packit |
0848f5 |
# unex - within unexecuted code
|
|
Packit |
0848f5 |
# exec - within executed code
|
|
Packit |
0848f5 |
# skip - within skipped code (code that we don't care whether it is
|
|
Packit |
0848f5 |
# executed). Currently contains 3 sub states:
|
|
Packit |
0848f5 |
# errcheck (error checking code)
|
|
Packit |
0848f5 |
# ERROR HANDLING (error handling code)
|
|
Packit |
0848f5 |
# DEBUG (debug code)
|
|
Packit |
0848f5 |
# EXPERIMENTAL (experimental)
|
|
Packit |
0848f5 |
# USEREXTENSION (code to enable user extensions)
|
|
Packit |
0848f5 |
# The uppercase names are the same as the @BlockNames.
|
|
Packit |
0848f5 |
# Currently, the skipcolors are all lightblue
|
|
Packit |
0848f5 |
sub AnnotateUncoveredLines {
|
|
Packit |
0848f5 |
my $filename = $_[0];
|
|
Packit |
0848f5 |
my $bgcolor = $_[1];
|
|
Packit |
0848f5 |
my %skipcolors = ( "errcheck" => "lightblue",
|
|
Packit |
0848f5 |
"ERROR HANDLING" => "lightblue",
|
|
Packit |
0848f5 |
"DEBUG" => "lightblue",
|
|
Packit |
0848f5 |
"EXPERIMENTAL" => "lightblue",
|
|
Packit |
0848f5 |
"USEREXTENSION" => "lightyellow",
|
|
Packit |
0848f5 |
"HETEROGENEOUS" => "lightgreen",
|
|
Packit |
0848f5 |
"OPTIONALINIT" => "lightgreen",
|
|
Packit |
0848f5 |
);
|
|
Packit |
0848f5 |
my $outfile = $_[2];
|
|
Packit |
0848f5 |
my $curstate = "init"; # Current state
|
|
Packit |
0848f5 |
my $newstate; # New state implied by the last line read
|
|
Packit |
0848f5 |
my $substate; # Used for substates within a state (skip only)
|
|
Packit |
0848f5 |
my $newline = "\r\n";
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
open( FD, "<$filename" ) || die "Could not open $filename\n";
|
|
Packit |
0848f5 |
$gFilename = $filename;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
print $outfile "$newline";
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Note that linecount is relative to the foo.c.gcov file, not the
|
|
Packit |
0848f5 |
# original foo.c file.
|
|
Packit |
0848f5 |
L2: while (<FD>) {
|
|
Packit |
0848f5 |
# Skip coverage messages (always start in the first column)
|
|
Packit |
0848f5 |
if (! /^\s/) { next; }
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# TODO:
|
|
Packit |
0848f5 |
# If there is neither a "######" nor a count in front of the
|
|
Packit |
0848f5 |
# line, and it is not a comment or blank space, it has
|
|
Packit |
0848f5 |
# the same state as currently in (e.g., it is probably a
|
|
Packit |
0848f5 |
# continuation line).
|
|
Packit |
0848f5 |
# Determine what state this line is in
|
|
Packit |
0848f5 |
# (gcc 3.3 only outputs 5 sharps, earlier versions use 6)
|
|
Packit |
0848f5 |
# The format of the line also changed
|
|
Packit |
0848f5 |
if ($skipErrExits &&
|
|
Packit |
0848f5 |
(/FUNC_EXIT.*STATE/ || /MPIR_Err_return_/ ||
|
|
Packit |
0848f5 |
/MPIR_ERR_SET/ || /MPIR_ERR_POP/ || /goto\s+fn_fail/ ||
|
|
Packit |
0848f5 |
/MPIR_ERR_ADD/ || /\*errflag\s*=\s*[^;]*;\s*$/ ||
|
|
Packit |
0848f5 |
/fn_fail:/ || /MPIR_Err_create_code/)) {
|
|
Packit |
0848f5 |
# If requested, skip obvious error checking lines
|
|
Packit |
0848f5 |
$newstate = "skip";
|
|
Packit |
0848f5 |
$substate = "errcheck";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (/^\s*######?/) {
|
|
Packit |
0848f5 |
$newstate = "unex";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (/^\s*\d+\s/ ||
|
|
Packit |
0848f5 |
/^\s*\d+:\s*\d+:/) {
|
|
Packit |
0848f5 |
# Also had /^\s*-:\s*\d+:/, but this should really be "same state"
|
|
Packit |
0848f5 |
# to avoid flipping in and out of a state.
|
|
Packit |
0848f5 |
$newstate = "exec";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
# Keep the same state...
|
|
Packit |
0848f5 |
if ($curstate eq "init") {
|
|
Packit |
0848f5 |
$newstate = "exec";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
$newstate = $curstate;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Special cases for blocks that we skip (mark them as executed)
|
|
Packit |
0848f5 |
if (/^\s*#\s*ifdef\s+HAVE_ERROR_CHECKING/ ||
|
|
Packit |
0848f5 |
/^\s*-:\s*\d+:\s*#\s*ifdef\s+HAVE_ERROR_CHECKING/) {
|
|
Packit |
0848f5 |
$newstate = "skip";
|
|
Packit |
0848f5 |
$substate = "errcheck";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
foreach my $name (@BlockNames) {
|
|
Packit |
0848f5 |
if (/$lineLeader2\/\*\s+--BEGIN $name--\s+\*\// ||
|
|
Packit |
0848f5 |
/$lineLeader3\/\*\s+--BEGIN $name--\s+\*\// ||
|
|
Packit |
0848f5 |
/$lineLeader4\/\*\s+--BEGIN $name--\s+\*\//) {
|
|
Packit |
0848f5 |
$newstate = "skip";
|
|
Packit |
0848f5 |
$substate = $name;
|
|
Packit |
0848f5 |
last;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# If there is a change in state, generate the correct code
|
|
Packit |
0848f5 |
if ($newstate ne $curstate) {
|
|
Packit |
0848f5 |
print STDERR "Newstate = $newstate\n" if $gDebugDetail;
|
|
Packit |
0848f5 |
if ($curstate ne "init") {
|
|
Packit |
0848f5 |
# Finish off the current state
|
|
Packit |
0848f5 |
print $outfile "$newline";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($newstate eq "exec") { $bgcolor = "white"; }
|
|
Packit |
0848f5 |
elsif ($newstate eq "unex") { $bgcolor = "red"; }
|
|
Packit |
0848f5 |
elsif ($newstate eq "skip") {
|
|
Packit |
0848f5 |
$bgcolor = $skipcolors{$substate};
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
print STDERR "Internal error: unrecognized state $newstate\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print $outfile "$newline";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
$curstate = $newstate;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Add this line
|
|
Packit |
0848f5 |
print $outfile &HTMLify($_);
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Now, for the blocks that we skip, read them until we reach the
|
|
Packit |
0848f5 |
# end of the block
|
|
Packit |
0848f5 |
# Skip any error checking block
|
|
Packit |
0848f5 |
if (/^\s*#\s*ifdef\s+HAVE_ERROR_CHECKING/ ||
|
|
Packit |
0848f5 |
/^\s*-:\s*\d+:\s*#\s*ifdef\s+HAVE_ERROR_CHECKING/) {
|
|
Packit |
0848f5 |
my $sawend = 0;
|
|
Packit |
0848f5 |
print STDERR "Skipping HAVE_ERROR_CHECKING\n" if $gDebugDetail;
|
|
Packit |
0848f5 |
while (<FD>) {
|
|
Packit |
0848f5 |
if (!/^\s/) { next; }
|
|
Packit |
0848f5 |
print $outfile &HTMLify($_);
|
|
Packit |
0848f5 |
if (/^\s+#\s*endif/ || /^\s*#\s*els/ ||
|
|
Packit |
0848f5 |
/^\s*-:\s*\d+:\s*#\s*endif/ ||
|
|
Packit |
0848f5 |
/^\s*-:\s*\d+:\s*#\s*els/) {
|
|
Packit |
0848f5 |
$sawend = 1;
|
|
Packit |
0848f5 |
last;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if (!$sawend) {
|
|
Packit |
0848f5 |
print STDERR "File $gFilename ended in HAVE ERROR CHECKING block\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
# Skip any blocks marked as debugging or unavoidable error checking
|
|
Packit |
0848f5 |
# code
|
|
Packit |
0848f5 |
foreach my $name (@BlockNames) {
|
|
Packit |
0848f5 |
if (/$lineLeader2\/\*\s+--BEGIN $name--\s+\*\// ||
|
|
Packit |
0848f5 |
/$lineLeader3\/\*\s+--BEGIN $name--\s+\*\// ||
|
|
Packit |
0848f5 |
/$lineLeader4\/\*\s+--BEGIN $name--\s+\*\//) {
|
|
Packit |
0848f5 |
&skipBlockAndAnnotate( $outfile, $name );
|
|
Packit |
0848f5 |
next L2;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
close (FD);
|
|
Packit |
0848f5 |
print $outfile "$newline$newline";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Write the annotation file as a simple HTML file
|
|
Packit |
0848f5 |
# (returns immediately if annotations are not requested)
|
|
Packit |
0848f5 |
# To aid in navigating the annotation pages
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# WriteAnnoteFile( filename, total_lines, exec_lines, missed_lines )
|
|
Packit |
0848f5 |
# Also inserts the generated filename to the hash %AnnoteFilesMap
|
|
Packit |
0848f5 |
# with key the base filename (e.g., foo.c) and the value the
|
|
Packit |
0848f5 |
# full directory path (e.g., $annoteSrcDir/foo.c.htm)
|
|
Packit |
0848f5 |
sub WriteAnnoteFile {
|
|
Packit |
0848f5 |
my $filename = $_[0];
|
|
Packit |
0848f5 |
my $totalLines = $_[1];
|
|
Packit |
0848f5 |
my $execLines = $_[2];
|
|
Packit |
0848f5 |
my $missedLines = $_[3];
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
print "Writing (if $annoteFiles) annotated file $filename\n" if $gDebug;
|
|
Packit |
0848f5 |
if ($annoteFiles) {
|
|
Packit |
0848f5 |
# Make a file name
|
|
Packit |
0848f5 |
my $basefile = $filename;
|
|
Packit |
0848f5 |
$basefile =~ s/\.merge$//; # Remove "merge" from filename
|
|
Packit |
0848f5 |
$basefile =~ s/\.gcov//;
|
|
Packit |
0848f5 |
$basefile =~ s/$annoteBaseDir//;
|
|
Packit |
0848f5 |
my $OUTFD = OUTFD;
|
|
Packit |
0848f5 |
my $rc = &MakeDirs( "$annoteSrcDir/$basefile" );
|
|
Packit |
0848f5 |
if ($rc == 0) {
|
|
Packit |
0848f5 |
print STDERR "Could not create directories $annoteSrcDir/$basefile\n";
|
|
Packit |
0848f5 |
return;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print STDERR "Opening $annoteSrcDir/$basefile.htm\n" if $gDebug;
|
|
Packit |
0848f5 |
$rc = open( $OUTFD, ">$annoteSrcDir/$basefile.htm" );
|
|
Packit |
0848f5 |
if ($rc != 0) {
|
|
Packit |
0848f5 |
$AnnoteFilesMap{$basefile} = "$annoteSrcDir/$basefile.htm";
|
|
Packit |
0848f5 |
$AnnoteFilesToOrig{$basefile} = $filename;
|
|
Packit |
0848f5 |
print STDERR "Saving $filename as AnnoteFilesToOrig{$basefile}\n" if $gDebug;
|
|
Packit |
0848f5 |
$newline = "\r\n";
|
|
Packit |
0848f5 |
print $OUTFD "<HTML><HEAD>$newline" || die "writing header";
|
|
Packit |
0848f5 |
print $OUTFD "<TITLE>Coverage for $filename</TITLE>$newline";
|
|
Packit |
0848f5 |
print $OUTFD "</HEAD>$newline";
|
|
Packit |
0848f5 |
print $OUTFD "<BODY BGCOLOR=\"FFFFFF\">$newline";
|
|
Packit |
0848f5 |
my $percent = sprintf( "%2d", 100 * $missedLines / $execLines );
|
|
Packit |
0848f5 |
print $OUTFD "For $filename, $missedLines lines of code out of $execLines executable lines were not executed ($percent\% missed)$newline";
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
&AnnotateUncoveredLines( $filename, "red", $OUTFD );
|
|
Packit |
0848f5 |
print $OUTFD "</BODY></HTML>$newline";
|
|
Packit |
0848f5 |
close( $OUTFD );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
print STDERR "Cannot open $annoteSrcDir/$basefile\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# TODO: Create a map of the annotated files by using AnnoteFilesMap
|
|
Packit |
0848f5 |
# We need a better framework for this. Perhaps a table with multiple
|
|
Packit |
0848f5 |
# columns. We could also arrange in groups by directory names
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# WriteAnnoteFileMap( name-fo-file-to-write )
|
|
Packit |
0848f5 |
sub WriteAnnoteFileMap {
|
|
Packit |
0848f5 |
my @names = sort(keys(%AnnoteFilesMap));
|
|
Packit |
0848f5 |
my $indexfile = $_[0];
|
|
Packit |
0848f5 |
#my $date = `date "+%Y-%m-%d-%H-%M"`;
|
|
Packit |
0848f5 |
my $date = `date`;
|
|
Packit |
0848f5 |
# FilesByMissed is a semicolon separated list of files, indexed by the
|
|
Packit |
0848f5 |
# number of lines missed. This will allow us to list the top problems
|
|
Packit |
0848f5 |
# in terms of the number of uncovered lines.
|
|
Packit |
0848f5 |
my %FilesByMissed = ();
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
open (IFD, ">$indexfile" ) || die "Could not open $indexfile\n";
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
print IFD "<HTML><HEAD><TITLE>Index to coverage analysis</TITLE></HEAD>\n";
|
|
Packit |
0848f5 |
print IFD "<BODY BGCOLOR=\"FFFFFF\">\n";
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Create the heading
|
|
Packit |
0848f5 |
if ($GrandTotal > 0 && $GrandTotalMissed > 0) {
|
|
Packit |
0848f5 |
print IFD "Summary of Coverage Testing\n";
|
|
Packit |
0848f5 |
print IFD "Of $GrandTotal lines in code, $GrandTotalMissed lines were not covered\n";
|
|
Packit |
0848f5 |
my $percent = (100 * $GrandTotalMissed) / $GrandTotal;
|
|
Packit |
0848f5 |
my $covered = 100 - $percent;
|
|
Packit |
0848f5 |
# convert to strings
|
|
Packit |
0848f5 |
$percent = sprintf( "%.2f", $percent );
|
|
Packit |
0848f5 |
$covered = sprintf( "%.2f", $covered );
|
|
Packit |
0848f5 |
print IFD "or $percent% missed ($covered% covered)\n";
|
|
Packit |
0848f5 |
# Do the same, but for the executable lines
|
|
Packit |
0848f5 |
print IFD " Of $GrandTotalExec executable lines in code, $GrandTotalMissed lines were not covered\n";
|
|
Packit |
0848f5 |
$percent = (100 * $GrandTotalMissed) / $GrandTotalExec;
|
|
Packit |
0848f5 |
$covered = 100 - $percent;
|
|
Packit |
0848f5 |
# convert to strings
|
|
Packit |
0848f5 |
$percent = sprintf( "%.2f", $percent );
|
|
Packit |
0848f5 |
$covered = sprintf( "%.2f", $covered );
|
|
Packit |
0848f5 |
print IFD "or $percent% missed ($covered% covered)\n";
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
my $date = `date "+%Y-%m-%d-%H-%M"`;
|
|
Packit |
0848f5 |
print IFD " This index created on $date\n";
|
|
Packit |
0848f5 |
if ($CoverageMessage ne "") {
|
|
Packit |
0848f5 |
print IFD " $CoverageMessage \n"
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print IFD "\n";
|
|
Packit |
0848f5 |
print IFD "The following files contained some code that was not executed. Files in which all non-error-handling, non-debug code was executed are not shown\n"
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
my $col = 1;
|
|
Packit |
0848f5 |
my $maxcol = 4;
|
|
Packit |
0848f5 |
my $curprefix = "--NONE--";
|
|
Packit |
0848f5 |
for ($i=0; $i<=$#names; $i++) {
|
|
Packit |
0848f5 |
my $file = $names[$i];
|
|
Packit |
0848f5 |
my $target = $AnnoteFilesMap{$file};
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Clean up filename
|
|
Packit |
0848f5 |
$file =~ s/^\.\///;
|
|
Packit |
0848f5 |
if ($file =~ /(.*)\/([^\/]*)/) {
|
|
Packit |
0848f5 |
$dirname = $1;
|
|
Packit |
0848f5 |
$basename = $2;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
$dirname = "";
|
|
Packit |
0848f5 |
$basename = $file;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Clean up target
|
|
Packit |
0848f5 |
if ($annoteWebPrefix ne "") {
|
|
Packit |
0848f5 |
$target =~ s/$annoteSrcDir/$annoteWebPrefix/;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
# make the reference relative
|
|
Packit |
0848f5 |
$target =~ s/$annoteSrcDir\///;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Compare dirname to curprefix; start a new table if
|
|
Packit |
0848f5 |
# necessary
|
|
Packit |
0848f5 |
if ($dirname ne $curprefix) {
|
|
Packit |
0848f5 |
if ($curprefix ne "--NONE--") {
|
|
Packit |
0848f5 |
for (my $j=$col-1; $j<=$maxcol; $j++) {
|
|
Packit |
0848f5 |
print IFD "";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print IFD "\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
$curprefix = $dirname;
|
|
Packit |
0848f5 |
print IFD "$dirname\n";
|
|
Packit |
0848f5 |
print IFD "\n";
|
|
Packit |
0848f5 |
$col = 1;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($col == 1) {
|
|
Packit |
0848f5 |
print IFD "\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
my $label = $basename;
|
|
Packit |
0848f5 |
my $origFileName = $AnnoteFilesToOrig{$names[$i]};
|
|
Packit |
0848f5 |
my $missed;
|
|
Packit |
0848f5 |
my $total;
|
|
Packit |
0848f5 |
if (defined($AnnoteMissed{$origFileName})) {
|
|
Packit |
0848f5 |
($missed,$total) = split(/;/,$AnnoteMissed{$origFileName});
|
|
Packit |
0848f5 |
$label = "$label ($missed)";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
# FIXME:
|
|
Packit |
0848f5 |
# Allow relative rather than absolute targets
|
|
Packit |
0848f5 |
print IFD "$label\n";
|
|
Packit |
0848f5 |
if ($col++ == $maxcol) {
|
|
Packit |
0848f5 |
print IFD "\n";
|
|
Packit |
0848f5 |
$col = 1;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if (defined($FilesByMissed{$missed})) {
|
|
Packit |
0848f5 |
$FilesByMissed{$missed} .= ";$dirname/$basename($target)";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
$FilesByMissed{$missed} = "$dirname/$basename($target)";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Flush the final table
|
|
Packit |
0848f5 |
if ($curprefix ne "--NONE--") {
|
|
Packit |
0848f5 |
# In case the page is empty
|
|
Packit |
0848f5 |
if ($col > 1) {
|
|
Packit |
0848f5 |
for (my $i=$col-1; $i<=$maxcol; $i++) {
|
|
Packit |
0848f5 |
print IFD "";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print IFD "\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print IFD "\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
print IFD " \nFiles with the most coverage gaps\n";
|
|
Packit |
0848f5 |
foreach my $key (sort {$b <=> $a} keys(%FilesByMissed)) {
|
|
Packit |
0848f5 |
if ($key < 10) { last; }
|
|
Packit |
0848f5 |
print IFD "($key): ";
|
|
Packit |
0848f5 |
foreach my $file (split(/;/,$FilesByMissed{$key})) {
|
|
Packit |
0848f5 |
if ($file =~ /(.*)\((.*)\)/) {
|
|
Packit |
0848f5 |
print IFD "$1\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
print IFD "$file\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print IFD " \n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
print IFD " \nGenerated on $date\n";
|
|
Packit |
0848f5 |
print IFD "</BODY></HTML>\n";
|
|
Packit |
0848f5 |
close IFD;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# -
|
|
Packit |
0848f5 |
# ( $coveredindexfile );
|
|
Packit |
0848f5 |
# This needs to be updated
|
|
Packit |
0848f5 |
sub WriteCoveredFileMap {
|
|
Packit |
0848f5 |
my $filename = $_[0];
|
|
Packit |
0848f5 |
my $newline = "\r\n";
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
open ( IFD, ">$filename" ) || die "Cannot open $filename\n";
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
print IFD "<HTML><HEAD>$newline";
|
|
Packit |
0848f5 |
print IFD "<TITLE>List of fully covered files</TITLE>$newline";
|
|
Packit |
0848f5 |
print IFD "</HEAD>$newline";
|
|
Packit |
0848f5 |
print IFD "<BODY BGCOLOR=\"FFFFFF\">$newline";
|
|
Packit |
0848f5 |
@sortedfiles = sort ( @CoveredFiles );
|
|
Packit |
0848f5 |
# for (my $i = 0; $i <= $#sortedfiles; $i ++ ) {
|
|
Packit |
0848f5 |
# my $file = $sortedfiles[$i];
|
|
Packit |
0848f5 |
# print IFD "$file\n";
|
|
Packit |
0848f5 |
# }
|
|
Packit |
0848f5 |
# This both avoids calling OutputFileTable if the array is empty
|
|
Packit |
0848f5 |
# and keeps Perl from issuing a warning about sortedfiles having
|
|
Packit |
0848f5 |
# only one use.
|
|
Packit |
0848f5 |
if ($#sortedfiles >= 0) {
|
|
Packit |
0848f5 |
&OutputFileTable( IFD, "sortedfiles", "" );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print IFD "</BODY></HTML>$newline";
|
|
Packit |
0848f5 |
close( IFD );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# -
|
|
Packit |
0848f5 |
# Make all of the directories in filename (which may include a
|
|
Packit |
0848f5 |
# final file). If it contains only directories, make sure that
|
|
Packit |
0848f5 |
# the name ends in a /
|
|
Packit |
0848f5 |
sub MakeDirs {
|
|
Packit |
0848f5 |
my $filename = $_[0];
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
my @subdirs = split(/\//, $filename );
|
|
Packit |
0848f5 |
print STDERR "Size of subdirs is $#subdirs\n" if $gDebugDetail;
|
|
Packit |
0848f5 |
my $curdir = $subdirs[0];
|
|
Packit |
0848f5 |
if ($curdir eq "") { $curdir = "/"; }
|
|
Packit |
0848f5 |
my $rc = 0;
|
|
Packit |
0848f5 |
for($i=1; $i<=$#subdirs; $i++) {
|
|
Packit |
0848f5 |
print STDERR "Making $curdir\n" if $gDebugDetail;
|
|
Packit |
0848f5 |
if (! -d $curdir) {
|
|
Packit |
0848f5 |
$rc = mkdir $curdir;
|
|
Packit |
0848f5 |
if (!$rc) {
|
|
Packit |
0848f5 |
print STDERR "Could not make directory $curdir\n";
|
|
Packit |
0848f5 |
return $rc;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if (! ($curdir =~ /\/$/)) { $curdir .= "/"; }
|
|
Packit |
0848f5 |
$curdir .= "$subdirs[$i]";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
return 1;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
# Get all of the .gcov files from the named directory, including any subdirs
|
|
Packit |
0848f5 |
# If there is a "merge" version of the gcov file, prefer that. These are
|
|
Packit |
0848f5 |
# used when the same source file is compiled for both the MPI and PMPI
|
|
Packit |
0848f5 |
# interfaces,
|
|
Packit |
0848f5 |
sub ExpandDir {
|
|
Packit |
0848f5 |
my $dir = $_[0];
|
|
Packit |
0848f5 |
my @otherdirs = ();
|
|
Packit |
0848f5 |
my @files = ();
|
|
Packit |
0848f5 |
opendir DIR, "$dir";
|
|
Packit |
0848f5 |
while ($filename = readdir DIR) {
|
|
Packit |
0848f5 |
if ($filename =~ /^\./ || $filename eq ".svn") {
|
|
Packit |
0848f5 |
next;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif (-d "$dir/$filename") {
|
|
Packit |
0848f5 |
# Skip pmpi directories used for merging gcov output
|
|
Packit |
0848f5 |
if ($filename =~ /\-pmpi$/) { next; }
|
|
Packit |
0848f5 |
# Skip mpi directories used for handling name-mangled files
|
|
Packit |
0848f5 |
if ($filename =~ /\-mpi$/) { next; }
|
|
Packit |
0848f5 |
$otherdirs[$#otherdirs+1] = "$dir/$filename";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
elsif ($filename =~ /(.*\.gcov)$/) {
|
|
Packit |
0848f5 |
# Check for the presense of a "merged" gcov file and use instead
|
|
Packit |
0848f5 |
if (-f "$dir/$filename.merge") {
|
|
Packit |
0848f5 |
$files[$#files + 1] = "$dir/$filename.merge";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
$files[$#files + 1] = "$dir/$filename";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
closedir DIR;
|
|
Packit |
0848f5 |
# (almost) tail recurse on otherdirs (we've closed the directory handle,
|
|
Packit |
0848f5 |
# so we don't need to worry about it anymore)
|
|
Packit |
0848f5 |
foreach $dir (@otherdirs) {
|
|
Packit |
0848f5 |
@files = (@files, &ExpandDir( $dir ) );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
return @files;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# --------------------------------------------------------------------------
|
|
Packit |
0848f5 |
# HTMLify
|
|
Packit |
0848f5 |
# Take an input line and make it value HTML
|
|
Packit |
0848f5 |
sub HTMLify {
|
|
Packit |
0848f5 |
my $line = $_[0];
|
|
Packit |
0848f5 |
$line =~ s/\&/--AMP--/g;
|
|
Packit |
0848f5 |
$line =~ s/>/>/g;
|
|
Packit |
0848f5 |
$line =~ s/</</g;
|
|
Packit |
0848f5 |
$line =~ s/--AMP--/&/g;
|
|
Packit |
0848f5 |
return $line;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# Output a table of file names
|
|
Packit |
0848f5 |
# OutputFileTable( FD, array-of-names, targethash )
|
|
Packit |
0848f5 |
sub OutputFileTable {
|
|
Packit |
0848f5 |
my $IFD = $_[0];
|
|
Packit |
0848f5 |
my $arrayname = $_[1];
|
|
Packit |
0848f5 |
my $targethashname = $_[2];
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
my $col = 1;
|
|
Packit |
0848f5 |
my $maxcol = 4;
|
|
Packit |
0848f5 |
my $curprefix = "--NONE--";
|
|
Packit |
0848f5 |
for ($i=0; $i<=$#$arrayname; $i++) {
|
|
Packit |
0848f5 |
my $file = $$arrayname[$i];
|
|
Packit |
0848f5 |
my $target = "";
|
|
Packit |
0848f5 |
if ($targethashname ne "") {
|
|
Packit |
0848f5 |
$target = $$targethashname{$file};
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Clean up filename
|
|
Packit |
0848f5 |
$file =~ s/^\.\///;
|
|
Packit |
0848f5 |
if ($file =~ /(.*)\/([^\/]*)/) {
|
|
Packit |
0848f5 |
$dirname = $1;
|
|
Packit |
0848f5 |
$basename = $2;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
$dirname = "";
|
|
Packit |
0848f5 |
$basename = $file;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Clean up target
|
|
Packit |
0848f5 |
if (defined($target) && $target ne "") {
|
|
Packit |
0848f5 |
if ($annoteWebPrefix ne "") {
|
|
Packit |
0848f5 |
$target =~ s/$annoteSrcDir/$annoteWebPrefix/;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
# make the reference relative
|
|
Packit |
0848f5 |
$target =~ s/$annoteSrcDir\///;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Compare dirname to curprefix; start a new table if
|
|
Packit |
0848f5 |
# necessary
|
|
Packit |
0848f5 |
if ($dirname ne $curprefix) {
|
|
Packit |
0848f5 |
if ($curprefix ne "--NONE--") {
|
|
Packit |
0848f5 |
for (my $j=$col-1; $j<=$maxcol; $j++) {
|
|
Packit |
0848f5 |
print $IFD "";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print $IFD "\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
$curprefix = $dirname;
|
|
Packit |
0848f5 |
print $IFD "$dirname\n";
|
|
Packit |
0848f5 |
print $IFD "\n";
|
|
Packit |
0848f5 |
$col = 1;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($col == 1) {
|
|
Packit |
0848f5 |
print $IFD "\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
my $label = $basename;
|
|
Packit |
0848f5 |
# my $origFileName = $AnnoteFilesToOrig{$names[$i]};
|
|
Packit |
0848f5 |
my $origFileName = $AnnoteFilesToOrig{$file};
|
|
Packit |
0848f5 |
if (defined($origFileName)) {
|
|
Packit |
0848f5 |
if (defined($AnnoteMissed{$origFileName})) {
|
|
Packit |
0848f5 |
my ($missed,$total) = split(/;/,$AnnoteMissed{$origFileName});
|
|
Packit |
0848f5 |
$label = "$label ($missed)";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($target ne "") {
|
|
Packit |
0848f5 |
print $IFD "$label\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
print $IFD "$label\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($col++ == $maxcol) {
|
|
Packit |
0848f5 |
print $IFD "\n";
|
|
Packit |
0848f5 |
$col = 1;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
# Flush the final table
|
|
Packit |
0848f5 |
if ($curprefix ne "--NONE--") {
|
|
Packit |
0848f5 |
# In case the page is empty
|
|
Packit |
0848f5 |
if ($col > 1) {
|
|
Packit |
0848f5 |
for (my $i=$col-1; $i<=$maxcol; $i++) {
|
|
Packit |
0848f5 |
print $IFD "";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print $IFD "\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print $IFD "\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# To generate a summary
|
|
Packit |
0848f5 |
# cd mpich/src
|
|
Packit |
0848f5 |
# ~/projects/mpich/maint/getcoverage mpi/*/*.gcov mpi/romio/mpi-io/*.gcov \
|
|
Packit |
0848f5 |
# mpi/romio/adio/ad_nfs/*.gcov mpi/romio/adio/ad_ufs/*.gcov \
|
|
Packit |
0848f5 |
# util/info/*.gcov \
|
|
Packit |
0848f5 |
# mpid/ch3/src/*.gcov mpid/ch3/channels/sock/src/*.gcov > coverage.txt
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Now can use
|
|
Packit |
0848f5 |
# maint/getcoverage src/mpi src/util/info >coveragebase.txt
|
|
Packit |
0848f5 |
# maint/getcoverage src/mpid/ch3/src/*.gcov \
|
|
Packit |
0848f5 |
# src/mpid/ch3/channels/sock/src/*.gcov > coveragempid.txt
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# Skip over a named block (while writing it to the annotation file)
|
|
Packit |
0848f5 |
# Usage:
|
|
Packit |
0848f5 |
# skipBlockAndAnnotate( outfd, blockname );
|
|
Packit |
0848f5 |
# e.g.,
|
|
Packit |
0848f5 |
# skipBlockAndAnnotate( $outfile, "DEBUG" );
|
|
Packit |
0848f5 |
sub skipBlockAndAnnotate {
|
|
Packit |
0848f5 |
my ($outfile,$blockName) = @_;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
my $sawend=0;
|
|
Packit |
0848f5 |
print STDERR "Skipping BEGIN $blockName\n" if $gDebugDetail;
|
|
Packit |
0848f5 |
while (<FD>) {
|
|
Packit |
0848f5 |
if (/^\s/) { print $outfile &HTMLify($_); }
|
|
Packit |
0848f5 |
if (/^$lineLeader2\/\*\s+--END $blockName--\s+\*\// ||
|
|
Packit |
0848f5 |
/^$lineLeader3\/\*\s+--END $blockName--\s+\*\// ||
|
|
Packit |
0848f5 |
/^$lineLeader4\/\*\s+--END $blockName--\s+\*\//) {
|
|
Packit |
0848f5 |
$sawend = 1;
|
|
Packit |
0848f5 |
last;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if (!$sawend) {
|
|
Packit |
0848f5 |
print STDERR "File $gFilename ended in --BEGIN $blockName-- block\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Skip over a named block. Return the number of lines skipped
|
|
Packit |
0848f5 |
# Usage:
|
|
Packit |
0848f5 |
# skipBlock( blockname, allowNested, linecount )
|
|
Packit |
0848f5 |
# e.g.,
|
|
Packit |
0848f5 |
# skipBlock( "DEBUG", 0, linecount );
|
|
Packit |
0848f5 |
sub skipBlock {
|
|
Packit |
0848f5 |
my ($blockName,$allowNested,$linecount) = @_;
|
|
Packit |
0848f5 |
my $fileline = 0;
|
|
Packit |
0848f5 |
my $lineincr = 0;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
while (<FD>) {
|
|
Packit |
0848f5 |
$lineincr++;
|
|
Packit |
0848f5 |
if (/^\s/) { $fileline++; }
|
|
Packit |
0848f5 |
if (! $allowNested) {
|
|
Packit |
0848f5 |
if (/^$lineLeader2\/\*\s+--BEGIN/ ||
|
|
Packit |
0848f5 |
/^$lineLeader3\/\*\s+--BEGIN/ ||
|
|
Packit |
0848f5 |
/^$lineLeader4\/\*\s+--BEGIN/) {
|
|
Packit |
0848f5 |
my $cleanline = $_;
|
|
Packit |
0848f5 |
$cleanline =~ s/^\s*//;
|
|
Packit |
0848f5 |
chop $cleanline;
|
|
Packit |
0848f5 |
my $curlinecount = $linecount + $lineincr;
|
|
Packit |
0848f5 |
print STDERR "Possible missing END $blockName in $gFilename at $curlinecount; saw $cleanline\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
# else {
|
|
Packit |
0848f5 |
# if (/^\s*\/\*\s*--\s*END\s+$blockName\s*--\s*\*\/\s*/ ||
|
|
Packit |
0848f5 |
# /^\s*-:\s*\d+:\s*\/\*\s*--\s*END\s+$blockName\s*--\s*\*\/\s*/) {
|
|
Packit |
0848f5 |
# # FIXME: Why is this a mangled line? Should some of the \s* be
|
|
Packit |
0848f5 |
# # \s+? (e.g., --\s+END)
|
|
Packit |
0848f5 |
# my $curlinecount = $linecount + $lineincr;
|
|
Packit |
0848f5 |
# print STDERR "Mangled line in $gFilename at $curlinecount: $_";
|
|
Packit |
0848f5 |
# last;
|
|
Packit |
0848f5 |
# }
|
|
Packit |
0848f5 |
# }
|
|
Packit |
0848f5 |
if (/^$lineLeader2\/\*\s+--END $blockName--\s+\*\// ||
|
|
Packit |
0848f5 |
/^$lineLeader3\/\*\s+--END $blockName--\s+\*\// ||
|
|
Packit |
0848f5 |
/^$lineLeader4\/\*\s+--END $blockName--\s+\*\//) {
|
|
Packit |
0848f5 |
last;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
# If we match the following but not the preceeding, there are extra
|
|
Packit |
0848f5 |
# spaces in the comment
|
|
Packit |
0848f5 |
if (/^\s*\/\*\s*--\s*END\s+$blockName\s*--\s*\*\/\s*/ ||
|
|
Packit |
0848f5 |
/^\s*-:\s*\d+:\s*\/\*\s*--\s*END\s+$blockName\s*--\s*\*\/\s*/) {
|
|
Packit |
0848f5 |
my $curlinecount = $linecount + $lineincr;
|
|
Packit |
0848f5 |
print STDERR "Mangled line in $gFilename at $curlinecount: $_";
|
|
Packit |
0848f5 |
last;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
return ($lineincr,$fileline);
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# skipIfdefBlock
|
|
Packit |
0848f5 |
# (ToDo)
|