//-*- Mode: C++; c-basic-offset:4 ; -*- */ // // Copyright (C) 2004 by Argonne National Laboratory. // See COPYRIGHT in top-level directory. // // This is a *very* simple tool for basic coverage analysis. // This is intended as a stop-gap until gcov works with the C++ files // used in the MPICH binding of C++ (as of 2/23/2004, gcov aborts when // processing the coverage files produced by g++ for the MPICH C++ // binding). // #include #include #include #include "mpicovsimple.h" /* For remove */ #include // Find the matching entry or insert and initialize a new one covinfo * MPIX_Coverage::findOrInsert( const char name[], int argcount ) { covinfo *p = head, *newp; int cmp; static covinfo *lastp = 0; // We use lastp to start where we // left off if we can; this speeds // sorted inserts // See if we can skip ahead... if (lastp) { cmp = strcmp( lastp->name, name ); if (cmp < 0 || (cmp == 0 && lastp->argcount <= argcount )) p = lastp; } while (p) { cmp = strcmp( p->name, name ); if (cmp == 0) { cmp = p->argcount - argcount; if (cmp == 0) { // If still 0, we've found our match. lastp = p; return p; } } if (cmp > 0) { // If we got here, backup and exit to perform the insert p = p->bLink; break; } // If we're at the end of the list, this p is the last element, // so we exit now if (!p->fLink) break; p = p->fLink; } // If we got here, we need to insert after p newp = new covinfo; newp->name = new char [strlen(name)+1]; strcpy( newp->name, name ); newp->argcount = argcount; newp->count = 0; newp->sourceFile = 0; newp->firstLine = -1; newp->lastLine = -1; newp->bLink = p; if (p) { // insert after p newp->fLink = p->fLink; p->fLink = newp; if (newp->fLink) { newp->fLink->bLink = newp; } } else { // insert at the head of the list newp->fLink = head; if (head) { head->bLink = newp; } head = newp; } lastp = newp; return newp; } // Add an item to the coverage list, including the first line void MPIX_Coverage::Add( const char name[], int argcnt, const char file[], int line ) { covinfo *p = findOrInsert( name, argcnt ); p->count ++; if (!p->sourceFile) { p->sourceFile = new char [strlen(file)+1]; strcpy( p->sourceFile, file ); p->firstLine = line; } } // Add the last line value to an item in the coverage list void MPIX_Coverage::AddEnd( const char name[], int argcnt, const char file[], int line ) { covinfo *p = findOrInsert( name, argcnt ); if (p->lastLine < 0) p->lastLine = line; } // // Merge the coverage data with the data in the file // The directory for the coverage file is defined by the // cpp value COVERAGE_DIR int MPIX_Coverage::FileMerge( const char filename[] ) { ifstream infile; ofstream outfile; covinfo *p; covinfo fp; char *infilename, *tmpfilename; // Try to open the input file. { #ifdef COVERAGE_DIR infilename = new char [strlen(filename) + strlen(COVERAGE_DIR) + 2 ]; strcpy( infilename, COVERAGE_DIR ); strcat( infilename, "/" ); strcat( infilename, filename ); #else infilename = (char *)filename; #endif infile.open( infilename ); // Create a place in which to read the data fp.name = new char [1024]; fp.sourceFile = new char [1024]; // Add the contents of the file to the internal list // This is easy but not the most memory efficient. // If this becomes a problem, we can merge the two // into a single output while (infile) { fp.count = -1; // Set a sentinal on eof in infile infile >> fp.name >> fp.argcount >> fp.count >> fp.sourceFile >> fp.firstLine >> fp.lastLine; if (fp.count == -1) break; p = findOrInsert( fp.name, fp.argcount ); if (!p->sourceFile) { p->sourceFile = strdup( fp.sourceFile ); p->firstLine = fp.firstLine; p->lastLine = fp.lastLine; } p->count += fp.count; } infile.close(); // Recover new storage delete fp.name; delete fp.sourceFile; } // Try to open the output file #ifdef COVERAGE_DIR tmpfilename = new char [strlen(".covtmp") + strlen(COVERAGE_DIR) + 2 ]; strcpy( tmpfilename, COVERAGE_DIR ); strcat( tmpfilename, "/" ); strcat( tmpfilename, ".covtmp" ); #else tmpfilename = ".covtmp"; #endif outfile.open( tmpfilename ); p = head; while (p) { outfile << p->name << '\t' << p->argcount << '\t' << p->count << '\t' << p->sourceFile << '\t' << p->firstLine << '\t' << p->lastLine << '\n'; p = p->fLink; } outfile.close(); // Now, remove the old file and move the new file over it remove( infilename ); rename( tmpfilename, infilename ); return 0; } #if 0 // This is partial and incomplete code for an alternative version of // FileMerge that avoids reading the entire file into memory // This was a early version that was lost in a terrible keyboarding // accident just after it was debugged :) // This predates the current form of the coverage file and contains // a number of bugs, but it would be a reasonable starting point // if it is desired to avoid reading the entire file into memory. int MPIX_Ooverage::FileMerge( const char filename[] ) { covinfo *p, *fp=0; ifstream infile; ofstream outfile; char *tmpfile; infile.open( filename, ios::in ); tmpfile = new char [ strlen(filename) + 5 ]; strcpy( tmpfile, filename ); strcat( tmpfile, ".tmp" ); outfile.open( tmpfile ); if (!outfile) { cerr << "Unable to open " << tmpfile << "\n"; } p = head; if (infile) { fp = new covinfo; fp->name = new char [1024]; infile >> fp->name >> fp->argcount >> fp->count; } while (p) { int cmp = 0; if (fp) { cmp = strcmp( fp->name, p->name ); if (cmp == 0) { cmp = fp->argcount - p->argcount; } if (cmp < 0) { // output the file entry outfile << fp->name << '\t' << fp->argcount << '\t' << fp->count << '\n'; infile >> fp->name >> fp->argcount >> fp->count; if (infile.eof()) break; continue; } else if (cmp == 0) { // Increment the p entry p->count += fp->count; infile >> fp->name >> fp->argcount >> fp->count; if (infile.eof()) break; } // else keep this entry } outfile << p->name << '\t' << p->argcount << '\t' << p->count << '\n'; p = p->fLink; } // Read the rest of the file, if any while (infile && !infile.eof()) { infile >> fp->name >> fp->argcount fp->count; outfile << fp->name << '\t' << fp->argcount << '\t' << fp->count << '\n'; } // Output the rest of the list while (p) { outfile << p->name << '\t' << p->argcount << '\t' << p->count << '\n'; p = p->fLink; } // Close the input file if we opened it... if (fp) { infile.close(); ... remove code as above } } #endif MPIX_Coverage MPIR_Cov; //#define TEST_PROGRAM #ifdef TEST_PROGRAM int main( int argc, char **argv ) { MPIR_Cov.Add( "foo", 2, __FILE__, __LINE__ ); MPIR_Cov.Add( "foo", 1, __FILE__, __LINE__ ); MPIR_Cov.Add( "bar", 2, __FILE__, __LINE__ ); MPIR_Cov.FileMerge( "covtest.dat" ); return 0; } #endif