date and time created 81/10/15 13:46:49 by peter
[unix-history] / usr / src / usr.bin / gprof / gprof.c
CommitLineData
3966d652
PK
1#ifndef lint
2 static char *sccsid = "@(#)gprof.c 1.1 (Berkeley) %G%";
3#endif lint
4
5#include "dprof.h"
6
7main(argc, argv)
8 int argc;
9 char **argv;
10{
11
12 --argc;
13 argv++;
14 debug = 0;
15 while ( *argv != 0 && **argv == '-' ) {
16 (*argv)++;
17 if ( **argv == 'd' ) {
18 (*argv)++;
19 debug |= atoi( *argv );
20 debug |= ANYDEBUG;
21# ifdef DEBUG
22 printf( "[main] debug = %d\n" , debug );
23# endif DEBUG
24 } else if ( **argv == 'z' ) {
25 zflg++;
26 }
27 argv++;
28 }
29 if ( *argv != 0 ) {
30 a_outname = *argv;
31 argv++;
32 } else {
33 a_outname = A_OUTNAME;
34 }
35 if ( *argv != 0 ) {
36 dmonname = *argv;
37 argv++;
38 } else {
39 dmonname = DMONNAME;
40 }
41 /*
42 * get information about a.out file.
43 */
44 getnfile();
45 /*
46 * get information about mon.out file(s).
47 */
48 getpfile( dmonname );
49 /*
50 * assign samples to procedures
51 */
52 asgnsamples();
53 /*
54 * print the usual profile
55 */
56 printprof();
57 /*
58 * assemble and print the dynamic profile
59 */
60 doarcs();
61 done();
62}
63
64printprof()
65{
66 register nltype *np;
67 nltype **sortednlp;
68 int index;
69
70 actime = 0.0;
71 putprofheader();
72 /*
73 * Sort the symbol table in by time
74 */
75 sortednlp = (nltype **) calloc( nname , sizeof(nltype *) );
76 if ( sortednlp == (nltype **) 0 ) {
77 fprintf( stderr , "[printprof] ran out of memory for time sorting\n" );
78 }
79 for ( index = 0 ; index < nname ; index += 1 ) {
80 sortednlp[ index ] = &nl[ index ];
81 }
82 qsort( sortednlp , nname , sizeof(nltype *) , timecmp );
83 for ( index = 0 ; index < nname ; index += 1 ) {
84 np = sortednlp[ index ];
85 putprofline( np , 1 );
86 }
87 actime = 0.0;
88 printf( "\ngranularity: each sample hit covers %.1f bytes" , scale );
89 printf( " for %.2f%% of %.2f seconds\n" , 100.0/totime , totime / HZ );
90}
91
92putprofline( np , cumflag )
93 register nltype *np;
94 int cumflag;
95{
96 double time;
97 long calls = np -> ncall + np -> selfcalls;
98
99 if ( zflg == 0 && calls == 0 && np -> time == 0 && np -> childtime == 0 ) {
100 return;
101 }
102 if ( cumflag ) {
103 time = (np->time + np->childtime) / totime;
104 actime += np->time;
105 if ( np -> index != 0 ) {
106 printf( "[%d]" , np -> index );
107 }
108 printf( "\t%5.1f %7.1f" , 100 * time , actime / HZ );
109 } else {
110 printf( "\t%5.5s %7.7s" , "" , "" );
111 }
112 printf( " %7.1f", np -> time / HZ );
113 if ( np -> childtime != 0.0 ) {
114 printf( " %7.1f" , np -> childtime / HZ );
115 } else {
116 printf( " %7.7s" , "" );
117 }
118 if ( calls != 0 ) {
119 printf( " %7d" , np -> ncall );
120 if ( np -> selfcalls != 0 ) {
121 printf( "+%-7d " , np -> selfcalls );
122 } else {
123 printf( " %7.7s " , "" );
124 }
125 } else {
126 printf( " %7.7s %7.7s " , "" , "" );
127 }
128 if ( ! cumflag ) {
129 printf( " " );
130 }
131 printname( np );
132 printf( "\n" );
133}
134
135 /*
136 * header for putprofline
137 */
138putprofheader()
139{
140
141 printf( "\n\t%5.5s %7.7s %-7.7s %-7.7s %7.7s %7.7s %5.5s\n" ,
142 "%time" , "cumsecs" , " self" , " child" , "ncall" , "" , "name" );
143}
144
145/*
146 * Set up string and symbol tables from a.out.
147 * On return symbol table is sorted by value.
148 */
149getnfile()
150{
151 FILE *nfile;
152
153 nfile = fopen( a_outname ,"r");
154 if (nfile == NULL) {
155 perror( a_outname );
156 done();
157 }
158 fread(&xbuf, 1, sizeof(xbuf), nfile);
159 if (N_BADMAG(xbuf)) {
160 fprintf(stderr, "%s: bad format\n", a_outname );
161 done();
162 }
163 getstrtab(nfile);
164 getsymtab(nfile);
165 qsort(nl, nname, sizeof(nltype), valcmp);
166 fclose(nfile);
167# ifdef DEBUG
168 if ( debug & AOUTDEBUG ) {
169 register int j;
170
171 for (j = 0; j < nname; j++){
172 printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
173 }
174 }
175# endif DEBUG
176}
177
178getstrtab(nfile)
179 FILE *nfile;
180{
181
182 fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
183 if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
184 fprintf(stderr, "%s: no string table (old format?)\n", a_outname );
185 done();
186 }
187 strtab = (char *)calloc(ssiz, 1);
188 if (strtab == NULL) {
189 fprintf(stderr, "%s: no room for %d bytes of string table",
190 a_outname , ssiz);
191 done();
192 }
193 if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
194 fprintf(stderr, "%s: error reading string table\n", a_outname );
195 done();
196 }
197}
198
199 /*
200 * Read in symbol table
201 */
202getsymtab(nfile)
203 FILE *nfile;
204{
205 register long i;
206 int askfor;
207 struct nlist nbuf;
208
209 /* pass1 - count symbols */
210 fseek(nfile, (long)N_SYMOFF(xbuf), 0);
211 nname = 0;
212 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
213 fread(&nbuf, sizeof(nbuf), 1, nfile);
214 if ( nbuf.n_type != N_TEXT+N_EXT ) {
215 continue;
216 }
217 nname++;
218 }
219 if (nname == 0) {
220 fprintf(stderr, "%s: no symbols\n", a_outname );
221 done();
222 }
223 /*
224 * ask also for CYCLEFRACTION extra namelist entries for
225 * cycle entries. these hide out at the end of the namelist
226 * and aren't accessed unless the whole namelist (nname+ncycles)
227 * is sorted and searched.
228 */
229 ncycles = nname * CYCLEFRACTION;
230 askfor = nname + 1 + ncycles;
231 nl = (nltype *) calloc( askfor , sizeof(nltype) );
232 if (nl == 0) {
233 fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
234 askfor * sizeof(nltype) );
235 done();
236 }
237
238 /* pass2 - read symbols */
239 fseek(nfile, (long)N_SYMOFF(xbuf), 0);
240 npe = nl;
241 nname = 0;
242 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
243 fread(&nbuf, sizeof(nbuf), 1, nfile);
244 if ( nbuf.n_type != N_TEXT+N_EXT ) {
245 continue;
246 }
247 npe->value = nbuf.n_value;
248 npe->name = strtab+nbuf.n_un.n_strx;
249# ifdef DEBUG
250 if ( debug & AOUTDEBUG ) {
251 printf( "[getsymtab] %d %s 0x%08x\n" ,
252 nname , npe -> name , npe -> value );
253 }
254# endif DEBUG
255 npe++;
256 nname++;
257 }
258 npe->value = -1;
259 npe++;
260}
261
262 /*
263 * information from a dmon.out file is in two parts:
264 * an array of sampling hits within pc ranges,
265 * and the arcs.
266 */
267getpfile(filename)
268 char *filename;
269{
270 FILE *pfile;
271 FILE *openpfile();
272 struct rawarc arc;
273
274 pfile = openpfile(filename);
275 readsamples(pfile);
276 /*
277 * the rest of the file consists of
278 * a bunch of <from,self,count> tuples.
279 */
280 while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
281# ifdef DEBUG
282 if ( debug & SAMPLEDEBUG ) {
283 printf( "[getpfile] frompc %d selfpc %d count %d\n" ,
284 arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
285 }
286# endif DEBUG
287 /*
288 * add this arc
289 */
290 tally( &arc );
291 }
292 fclose(pfile);
293}
294
295FILE *openpfile(filename)
296 char *filename;
297{
298 FILE *pfile;
299
300 if((pfile = fopen(filename, "r")) == NULL) {
301 perror(filename);
302 done();
303 }
304 fread(&h, sizeof(struct hdr), 1, pfile);
305 lowpc = h.lowpc - (UNIT *)0;
306 highpc = h.highpc - (UNIT *)0;
307 sampbytes = h.ncnt - sizeof(struct hdr);
308 nsamples = sampbytes / sizeof (unsigned UNIT);
309 return(pfile);
310}
311
312tally( rawp )
313 struct rawarc *rawp;
314{
315 nltype *parentp;
316 nltype *childp;
317 arctype *arcp;
318 arctype *malloc();
319
320 parentp = nllookup( rawp -> raw_frompc );
321 childp = nllookup( rawp -> raw_selfpc );
322 childp -> ncall += rawp -> raw_count;
323# ifdef DEBUG
324 if ( debug & TALLYDEBUG ) {
325 printf( "[tally] arc from %s to %s traversed %d times\n" ,
326 parentp -> name , childp -> name , rawp -> raw_count );
327 }
328# endif DEBUG
329 arcp = arclookup( parentp , childp );
330 if ( arcp != 0 ) {
331 /*
332 * a hit: just increment the count.
333 */
334# ifdef DEBUG
335 if ( debug & TALLYDEBUG ) {
336 printf( "[tally] hit %d += %d\n" ,
337 arcp -> arc_count , rawp -> raw_count );
338 }
339# endif DEBUG
340 arcp -> arc_count += rawp -> raw_count;
341 return;
342 }
343 arcp = malloc( sizeof *arcp );
344 arcp -> arc_parentp = parentp;
345 arcp -> arc_childp = childp;
346 arcp -> arc_count = rawp -> raw_count;
347 /*
348 * prepend this child to the children of this parent
349 */
350 arcp -> arc_childlist = parentp -> children;
351 parentp -> children = arcp;
352 /*
353 * prepend this parent to the parents of this child
354 */
355 arcp -> arc_parentlist = childp -> parents;
356 childp -> parents = arcp;
357}
358
359valcmp(p1, p2)
360 nltype *p1, *p2;
361{
362 if ( p1 -> value < p2 -> value ) {
363 return LESSTHAN;
364 }
365 if ( p1 -> value > p2 -> value ) {
366 return GREATERTHAN;
367 }
368 return EQUALTO;
369}
370
371readsamples(pfile)
372 FILE *pfile;
373{
374 register i;
375 unsigned UNIT sample;
376
377 if (samples == 0) {
378 samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
379 if (samples == 0) {
380 fprintf( stderr , "prof: No room for %d sample pc's\n",
381 sampbytes / sizeof (unsigned UNIT));
382 done();
383 }
384 }
385 for (i = 0; i < nsamples; i++) {
386 fread(&sample, sizeof (unsigned UNIT), 1, pfile);
387 if (feof(pfile))
388 break;
389 samples[i] += sample;
390 }
391 if (i != nsamples) {
392 fprintf(stderr,
393 "prof: unexpected EOF after reading %d/%d samples\n",
394 --i, nsamples);
395 done();
396 }
397}
398
399/*
400 * Assign samples to the procedures to which they belong.
401 */
402asgnsamples()
403{
404 register int j;
405 unsigned UNIT ccnt;
406 double time;
407 unsigned long pcl, pch;
408 register int i;
409 int overlap;
410 unsigned long svalue0, svalue1;
411
412 /* read samples and assign to namelist symbols */
413 scale = highpc - lowpc;
414 scale /= nsamples;
415 for (i=0; i < nsamples; i++) {
416 ccnt = samples[i];
417 if (ccnt == 0)
418 continue;
419 pcl = lowpc + scale*i;
420 pch = lowpc + scale*(i+1);
421 time = ccnt;
422# ifdef DEBUG
423 if ( debug & SAMPLEDEBUG ) {
424 printf( "[asgnsamples] ccnt %d time %f totime %f\n" ,
425 ccnt , time , totime );
426 }
427# endif DEBUG
428 totime += time;
429 for (j=0; j<nname; j++) {
430 svalue0 = nl[j].value / sizeof(UNIT);
431 svalue1 = nl[j+1].value / sizeof(UNIT);
432 if (pch < svalue0)
433 break;
434 if (pcl >= svalue1)
435 continue;
436 overlap=min(pch,svalue1) - max(pcl,svalue0);
437 if (overlap>0) {
438# ifdef DEBUG
439 if ( debug & SAMPLEDEBUG ) {
440 printf( "[asgnsamples] %s gets %f ticks\n" ,
441 nl[j].name , overlap*time/scale );
442 }
443# endif DEBUG
444 nl[j].time += overlap*time/scale;
445 }
446 }
447 }
448# ifdef DEBUG
449 if ( debug & SAMPLEDEBUG ) {
450 printf( "[asgnsamples] totime %f\n" , totime );
451 }
452# endif DEBUG
453 if (totime==0.0) {
454 fprintf( stderr , "No time accumulated\n" );
455 totime=1.0;
456 }
457}
458
459
460min(a, b)
461 unsigned a,b;
462{
463 if (a<b)
464 return(a);
465 return(b);
466}
467
468max(a, b)
469 unsigned a,b;
470{
471 if (a>b)
472 return(a);
473 return(b);
474}
475
476timecmp( npp1 , npp2 )
477 nltype **npp1, **npp2;
478{
479 double d;
480
481 d = (*npp2)->time - (*npp1)->time;
482 if (d > 0.0)
483 return(1);
484 if (d < 0.0)
485 return(-1);
486 return(strcmp((*npp1)->name,(*npp2)->name));
487}
488
489done()
490{
491
492 exit(0);
493}