1 /*
2 * Copyright (C) by Argonne National Laboratory
3 * See COPYRIGHT in top-level directory
4 */
5
6 /*
7 * This is a *very* simple tool for basic coverage analysis.
8 * This is intended as a stop-gap until gcov works with the C++ files
9 * used in the MPICH binding of C++ (as of 2/23/2004, gcov aborts when
10 * processing the coverage files produced by g++ for the MPICH C++
11 * binding).
12 */
13
14 #include <iostream.h>
15 #include <fstream.h>
16 #include <string.h>
17
18 #include "mpicovsimple.h"
19
20 /* For remove */
21 #include <stdio.h>
22
23 // Find the matching entry or insert and initialize a new one
findOrInsert(const char name[],int argcount)24 covinfo * MPIX_Coverage::findOrInsert( const char name[], int argcount )
25 {
26 covinfo *p = head, *newp;
27 int cmp;
28 static covinfo *lastp = 0; // We use lastp to start where we
29 // left off if we can; this speeds
30 // sorted inserts
31
32 // See if we can skip ahead...
33 if (lastp) {
34 cmp = strcmp( lastp->name, name );
35 if (cmp < 0 || (cmp == 0 && lastp->argcount <= argcount )) p = lastp;
36 }
37
38 while (p) {
39 cmp = strcmp( p->name, name );
40 if (cmp == 0) {
41 cmp = p->argcount - argcount;
42 if (cmp == 0) {
43 // If still 0, we've found our match.
44 lastp = p;
45 return p;
46 }
47 }
48
49 if (cmp > 0) {
50 // If we got here, backup and exit to perform the insert
51 p = p->bLink;
52 break;
53 }
54 // If we're at the end of the list, this p is the last element,
55 // so we exit now
56 if (!p->fLink) break;
57
58 p = p->fLink;
59 }
60
61 // If we got here, we need to insert after p
62 newp = new covinfo;
63 newp->name = new char [strlen(name)+1];
64 strcpy( newp->name, name );
65 newp->argcount = argcount;
66 newp->count = 0;
67 newp->sourceFile = 0;
68 newp->firstLine = -1;
69 newp->lastLine = -1;
70 newp->bLink = p;
71 if (p) {
72 // insert after p
73 newp->fLink = p->fLink;
74 p->fLink = newp;
75 if (newp->fLink) {
76 newp->fLink->bLink = newp;
77 }
78 }
79 else {
80 // insert at the head of the list
81 newp->fLink = head;
82 if (head) {
83 head->bLink = newp;
84 }
85 head = newp;
86 }
87
88 lastp = newp;
89 return newp;
90 }
91
92 // Add an item to the coverage list, including the first line
Add(const char name[],int argcnt,const char file[],int line)93 void MPIX_Coverage::Add( const char name[], int argcnt,
94 const char file[], int line )
95 {
96 covinfo *p = findOrInsert( name, argcnt );
97
98 p->count ++;
99 if (!p->sourceFile) {
100 p->sourceFile = new char [strlen(file)+1];
101 strcpy( p->sourceFile, file );
102 p->firstLine = line;
103 }
104 }
105
106 // Add the last line value to an item in the coverage list
AddEnd(const char name[],int argcnt,const char file[],int line)107 void MPIX_Coverage::AddEnd( const char name[], int argcnt,
108 const char file[], int line )
109 {
110 covinfo *p = findOrInsert( name, argcnt );
111
112 if (p->lastLine < 0)
113 p->lastLine = line;
114 }
115
116 //
117 // Merge the coverage data with the data in the file
118 // The directory for the coverage file is defined by the
119 // cpp value COVERAGE_DIR
FileMerge(const char filename[])120 int MPIX_Coverage::FileMerge( const char filename[] )
121 {
122 ifstream infile;
123 ofstream outfile;
124 covinfo *p;
125 covinfo fp;
126 char *infilename, *tmpfilename;
127
128 // Try to open the input file.
129 {
130 #ifdef COVERAGE_DIR
131 infilename = new char [strlen(filename) + strlen(COVERAGE_DIR) + 2 ];
132 strcpy( infilename, COVERAGE_DIR );
133 strcat( infilename, "/" );
134 strcat( infilename, filename );
135 #else
136 infilename = (char *)filename;
137 #endif
138 infile.open( infilename );
139
140 // Create a place in which to read the data
141 fp.name = new char [1024];
142 fp.sourceFile = new char [1024];
143
144 // Add the contents of the file to the internal list
145 // This is easy but not the most memory efficient.
146 // If this becomes a problem, we can merge the two
147 // into a single output
148 while (infile) {
149 fp.count = -1; // Set a sentinal on eof in infile
150 infile >> fp.name >> fp.argcount >> fp.count >> fp.sourceFile >>
151 fp.firstLine >> fp.lastLine;
152 if (fp.count == -1) break;
153 p = findOrInsert( fp.name, fp.argcount );
154 if (!p->sourceFile) {
155 p->sourceFile = strdup( fp.sourceFile );
156 p->firstLine = fp.firstLine;
157 p->lastLine = fp.lastLine;
158 }
159 p->count += fp.count;
160 }
161 infile.close();
162 // Recover new storage
163 delete fp.name;
164 delete fp.sourceFile;
165 }
166
167 // Try to open the output file
168 #ifdef COVERAGE_DIR
169 tmpfilename = new char [strlen(".covtmp") + strlen(COVERAGE_DIR) + 2 ];
170 strcpy( tmpfilename, COVERAGE_DIR );
171 strcat( tmpfilename, "/" );
172 strcat( tmpfilename, ".covtmp" );
173 #else
174 tmpfilename = ".covtmp";
175 #endif
176 outfile.open( tmpfilename );
177
178 p = head;
179 while (p) {
180 outfile << p->name << '\t' << p->argcount << '\t' <<
181 p->count << '\t' << p->sourceFile << '\t' <<
182 p->firstLine << '\t' << p->lastLine << '\n';
183 p = p->fLink;
184 }
185
186 outfile.close();
187
188 // Now, remove the old file and move the new file over it
189 remove( infilename );
190 rename( tmpfilename, infilename );
191
192 return 0;
193 }
194
195 #if 0
196 // This is partial and incomplete code for an alternative version of
197 // FileMerge that avoids reading the entire file into memory
198 // This was a early version that was lost in a terrible keyboarding
199 // accident just after it was debugged :)
200 // This predates the current form of the coverage file and contains
201 // a number of bugs, but it would be a reasonable starting point
202 // if it is desired to avoid reading the entire file into memory.
203 int MPIX_Ooverage::FileMerge( const char filename[] )
204 {
205 covinfo *p, *fp=0;
206 ifstream infile;
207 ofstream outfile;
208 char *tmpfile;
209
210 infile.open( filename, ios::in );
211
212 tmpfile = new char [ strlen(filename) + 5 ];
213 strcpy( tmpfile, filename );
214 strcat( tmpfile, ".tmp" );
215 outfile.open( tmpfile );
216 if (!outfile) {
217 cerr << "Unable to open " << tmpfile << "\n";
218 }
219 p = head;
220 if (infile) {
221 fp = new covinfo;
222 fp->name = new char [1024];
223 infile >> fp->name >> fp->argcount >> fp->count;
224 }
225 while (p) {
226 int cmp = 0;
227 if (fp) {
228 cmp = strcmp( fp->name, p->name );
229 if (cmp == 0) {
230 cmp = fp->argcount - p->argcount;
231 }
232 if (cmp < 0) {
233 // output the file entry
234 outfile << fp->name << '\t' << fp->argcount << '\t' <<
235 fp->count << '\n';
236 infile >> fp->name >> fp->argcount >> fp->count;
237 if (infile.eof()) break;
238 continue;
239 }
240 else if (cmp == 0) {
241 // Increment the p entry
242 p->count += fp->count;
243 infile >> fp->name >> fp->argcount >> fp->count;
244 if (infile.eof()) break;
245 }
246 // else keep this entry
247 }
248 outfile << p->name << '\t' << p->argcount << '\t' << p->count << '\n';
249 p = p->fLink;
250 }
251 // Read the rest of the file, if any
252 while (infile && !infile.eof()) {
253 infile >> fp->name >> fp->argcount fp->count;
254 outfile << fp->name << '\t' << fp->argcount << '\t' <<
255 fp->count << '\n';
256 }
257 // Output the rest of the list
258 while (p) {
259 outfile << p->name << '\t' << p->argcount << '\t' << p->count << '\n';
260 p = p->fLink;
261 }
262 // Close the input file if we opened it...
263 if (fp) {
264 infile.close();
265 ... remove code as above
266 }
267
268 }
269 #endif
270
271 MPIX_Coverage MPIR_Cov;
272
273 //#define TEST_PROGRAM
274 #ifdef TEST_PROGRAM
main(int argc,char ** argv)275 int main( int argc, char **argv )
276 {
277 MPIR_Cov.Add( "foo", 2, __FILE__, __LINE__ );
278 MPIR_Cov.Add( "foo", 1, __FILE__, __LINE__ );
279 MPIR_Cov.Add( "bar", 2, __FILE__, __LINE__ );
280
281 MPIR_Cov.FileMerge( "covtest.dat" );
282 return 0;
283 }
284 #endif
285