date and time created 83/02/24 12:56:06 by mckusick
[unix-history] / usr / src / usr.bin / gprof / gprof.c
CommitLineData
3966d652 1#ifndef lint
89bcca98 2 static char *sccsid = "@(#)gprof.c 1.19 (Berkeley) %G%";
3966d652
PK
3#endif lint
4
31f0a970 5#include "gprof.h"
3966d652 6
ad3b82ad
PK
7char *whoami = "gprof";
8
a441395b
PK
9 /*
10 * things which get -E excluded by default.
11 */
12char *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
7ec9eedc 13
3966d652 14main(argc, argv)
7ec9eedc
PK
15 int argc;
16 char **argv;
3966d652 17{
7ec9eedc 18 char **sp;
3966d652
PK
19
20 --argc;
21 argv++;
22 debug = 0;
23 while ( *argv != 0 && **argv == '-' ) {
24 (*argv)++;
0c0ac747 25 switch ( **argv ) {
7ec9eedc
PK
26 case 'a':
27 aflag = TRUE;
28 break;
29 case 'b':
30 bflag = TRUE;
31 break;
32 case 'c':
33 cflag = TRUE;
34 break;
0c0ac747 35 case 'd':
7ec9eedc 36 dflag = TRUE;
3966d652
PK
37 (*argv)++;
38 debug |= atoi( *argv );
39 debug |= ANYDEBUG;
40# ifdef DEBUG
41 printf( "[main] debug = %d\n" , debug );
42# endif DEBUG
0c0ac747 43 break;
a441395b
PK
44 case 'E':
45 ++argv;
46 addlist( Elist , *argv );
47 Eflag = TRUE;
48 addlist( elist , *argv );
49 eflag = TRUE;
50 break;
7ec9eedc 51 case 'e':
a441395b 52 addlist( elist , *++argv );
7ec9eedc 53 eflag = TRUE;
a441395b
PK
54 break;
55 case 'F':
56 ++argv;
57 addlist( Flist , *argv );
58 Fflag = TRUE;
59 addlist( flist , *argv );
60 fflag = TRUE;
0c0ac747 61 break;
7ec9eedc 62 case 'f':
a441395b 63 addlist( flist , *++argv );
7ec9eedc 64 fflag = TRUE;
0c0ac747
KM
65 break;
66 case 's':
7ec9eedc 67 sflag = TRUE;
0c0ac747
KM
68 break;
69 case 'z':
7ec9eedc 70 zflag = TRUE;
0c0ac747 71 break;
3966d652
PK
72 }
73 argv++;
74 }
75 if ( *argv != 0 ) {
76 a_outname = *argv;
77 argv++;
78 } else {
79 a_outname = A_OUTNAME;
80 }
81 if ( *argv != 0 ) {
31f0a970 82 gmonname = *argv;
3966d652
PK
83 argv++;
84 } else {
31f0a970 85 gmonname = GMONNAME;
7ec9eedc
PK
86 }
87 /*
88 * turn off default functions
89 */
a441395b
PK
90 for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
91 Eflag = TRUE;
92 addlist( Elist , *sp );
7ec9eedc 93 eflag = TRUE;
a441395b 94 addlist( elist , *sp );
3966d652 95 }
89bcca98
PK
96 /*
97 * how long is a clock tick?
98 */
99 hz = hertz();
3966d652
PK
100 /*
101 * get information about a.out file.
102 */
103 getnfile();
104 /*
105 * get information about mon.out file(s).
106 */
0c0ac747
KM
107 do {
108 getpfile( gmonname );
109 if ( *argv != 0 ) {
110 gmonname = *argv;
111 }
ad3b82ad 112 } while ( *argv++ != 0 );
0c0ac747
KM
113 /*
114 * dump out a gmon.sum file if requested
115 */
ad3b82ad
PK
116 if ( sflag ) {
117 dumpsum( GMONSUM );
118 }
3966d652
PK
119 /*
120 * assign samples to procedures
121 */
122 asgnsamples();
123 /*
124 * print the usual profile
125 */
126 printprof();
127 /*
128 * assemble and print the dynamic profile
129 */
130 doarcs();
131 done();
132}
133
ad3b82ad
PK
134 /*
135 * Set up string and symbol tables from a.out.
136 * and optionally the text space.
137 * On return symbol table is sorted by value.
138 */
3966d652
PK
139getnfile()
140{
141 FILE *nfile;
142
143 nfile = fopen( a_outname ,"r");
144 if (nfile == NULL) {
145 perror( a_outname );
146 done();
147 }
148 fread(&xbuf, 1, sizeof(xbuf), nfile);
149 if (N_BADMAG(xbuf)) {
ad3b82ad 150 fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname );
3966d652
PK
151 done();
152 }
153 getstrtab(nfile);
154 getsymtab(nfile);
29da1d26 155 gettextspace( nfile );
3966d652
PK
156 qsort(nl, nname, sizeof(nltype), valcmp);
157 fclose(nfile);
158# ifdef DEBUG
159 if ( debug & AOUTDEBUG ) {
160 register int j;
161
162 for (j = 0; j < nname; j++){
163 printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
164 }
165 }
166# endif DEBUG
167}
168
169getstrtab(nfile)
170 FILE *nfile;
171{
172
173 fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
174 if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
ad3b82ad
PK
175 fprintf(stderr, "%s: %s: no string table (old format?)\n" ,
176 whoami , a_outname );
3966d652
PK
177 done();
178 }
179 strtab = (char *)calloc(ssiz, 1);
180 if (strtab == NULL) {
ad3b82ad
PK
181 fprintf(stderr, "%s: %s: no room for %d bytes of string table",
182 whoami , a_outname , ssiz);
3966d652
PK
183 done();
184 }
185 if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
ad3b82ad
PK
186 fprintf(stderr, "%s: %s: error reading string table\n",
187 whoami , a_outname );
3966d652
PK
188 done();
189 }
190}
191
192 /*
193 * Read in symbol table
194 */
195getsymtab(nfile)
196 FILE *nfile;
197{
198 register long i;
199 int askfor;
200 struct nlist nbuf;
201
202 /* pass1 - count symbols */
203 fseek(nfile, (long)N_SYMOFF(xbuf), 0);
204 nname = 0;
205 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
206 fread(&nbuf, sizeof(nbuf), 1, nfile);
3f722622 207 if ( ! funcsymbol( &nbuf ) ) {
3966d652
PK
208 continue;
209 }
210 nname++;
211 }
212 if (nname == 0) {
ad3b82ad 213 fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
3966d652
PK
214 done();
215 }
ad3b82ad 216 askfor = nname + 1;
3966d652
PK
217 nl = (nltype *) calloc( askfor , sizeof(nltype) );
218 if (nl == 0) {
ad3b82ad
PK
219 fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
220 whoami, askfor * sizeof(nltype) );
3966d652
PK
221 done();
222 }
223
224 /* pass2 - read symbols */
225 fseek(nfile, (long)N_SYMOFF(xbuf), 0);
226 npe = nl;
227 nname = 0;
228 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
229 fread(&nbuf, sizeof(nbuf), 1, nfile);
3f722622
PK
230 if ( ! funcsymbol( &nbuf ) ) {
231# ifdef DEBUG
232 if ( debug & AOUTDEBUG ) {
233 printf( "[getsymtab] rejecting: 0x%x %s\n" ,
234 nbuf.n_type , strtab + nbuf.n_un.n_strx );
235 }
236# endif DEBUG
3966d652
PK
237 continue;
238 }
239 npe->value = nbuf.n_value;
240 npe->name = strtab+nbuf.n_un.n_strx;
241# ifdef DEBUG
242 if ( debug & AOUTDEBUG ) {
243 printf( "[getsymtab] %d %s 0x%08x\n" ,
244 nname , npe -> name , npe -> value );
245 }
246# endif DEBUG
247 npe++;
248 nname++;
249 }
250 npe->value = -1;
251 npe++;
252}
253
29da1d26
PK
254 /*
255 * read in the text space of an a.out file
256 */
257gettextspace( nfile )
258 FILE *nfile;
259{
260 unsigned char *malloc();
261
262 if ( cflag == 0 ) {
263 return;
264 }
265 textspace = malloc( xbuf.a_text );
266 if ( textspace == 0 ) {
ad3b82ad
PK
267 fprintf( stderr , "%s: ran out room for %d bytes of text space: " ,
268 whoami , xbuf.a_text );
269 fprintf( stderr , "can't do -c\n" );
29da1d26
PK
270 return;
271 }
272 (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
273 if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
ad3b82ad
PK
274 fprintf( stderr , "%s: couldn't read text space: " , whoami );
275 fprintf( stderr , "can't do -c\n" );
29da1d26
PK
276 free( textspace );
277 textspace = 0;
278 return;
279 }
280}
3966d652 281 /*
31f0a970 282 * information from a gmon.out file is in two parts:
3966d652
PK
283 * an array of sampling hits within pc ranges,
284 * and the arcs.
285 */
286getpfile(filename)
287 char *filename;
288{
289 FILE *pfile;
290 FILE *openpfile();
291 struct rawarc arc;
292
293 pfile = openpfile(filename);
294 readsamples(pfile);
295 /*
296 * the rest of the file consists of
297 * a bunch of <from,self,count> tuples.
298 */
299 while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
300# ifdef DEBUG
301 if ( debug & SAMPLEDEBUG ) {
06ac0fb1 302 printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
3966d652
PK
303 arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
304 }
305# endif DEBUG
306 /*
307 * add this arc
308 */
309 tally( &arc );
310 }
311 fclose(pfile);
312}
313
35e3e365
PK
314FILE *
315openpfile(filename)
3966d652
PK
316 char *filename;
317{
0c0ac747 318 struct hdr tmp;
3966d652
PK
319 FILE *pfile;
320
321 if((pfile = fopen(filename, "r")) == NULL) {
322 perror(filename);
323 done();
324 }
0c0ac747
KM
325 fread(&tmp, sizeof(struct hdr), 1, pfile);
326 if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc ||
327 tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) {
328 fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
329 done();
330 }
331 h = tmp;
06ac0fb1
PK
332 s_lowpc = (unsigned long) h.lowpc;
333 s_highpc = (unsigned long) h.highpc;
6d94fded
KM
334 lowpc = (unsigned long)h.lowpc / sizeof(UNIT);
335 highpc = (unsigned long)h.highpc / sizeof(UNIT);
3966d652
PK
336 sampbytes = h.ncnt - sizeof(struct hdr);
337 nsamples = sampbytes / sizeof (unsigned UNIT);
33e41a83
PK
338# ifdef DEBUG
339 if ( debug & SAMPLEDEBUG ) {
340 printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
341 h.lowpc , h.highpc , h.ncnt );
342 printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" ,
343 s_lowpc , s_highpc );
344 printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" ,
345 lowpc , highpc );
346 printf( "[openpfile] sampbytes %d nsamples %d\n" ,
347 sampbytes , nsamples );
348 }
349# endif DEBUG
3966d652
PK
350 return(pfile);
351}
352
353tally( rawp )
354 struct rawarc *rawp;
355{
356 nltype *parentp;
357 nltype *childp;
3966d652
PK
358
359 parentp = nllookup( rawp -> raw_frompc );
360 childp = nllookup( rawp -> raw_selfpc );
361 childp -> ncall += rawp -> raw_count;
362# ifdef DEBUG
363 if ( debug & TALLYDEBUG ) {
364 printf( "[tally] arc from %s to %s traversed %d times\n" ,
365 parentp -> name , childp -> name , rawp -> raw_count );
366 }
367# endif DEBUG
29da1d26 368 addarc( parentp , childp , rawp -> raw_count );
3966d652
PK
369}
370
0c0ac747
KM
371/*
372 * dump out the gmon.sum file
373 */
374dumpsum( sumfile )
375 char *sumfile;
376{
377 register nltype *nlp;
378 register arctype *arcp;
379 struct rawarc arc;
380 FILE *sfile;
381
382 if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
383 perror( sumfile );
384 done();
385 }
386 /*
387 * dump the header; use the last header read in
388 */
389 if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) {
390 perror( sumfile );
391 done();
392 }
393 /*
394 * dump the samples
395 */
396 if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) {
397 perror( sumfile );
398 done();
399 }
400 /*
401 * dump the normalized raw arc information
402 */
403 for ( nlp = nl ; nlp < npe - 1 ; nlp++ ) {
404 for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
405 arc.raw_frompc = arcp -> arc_parentp -> value;
406 arc.raw_selfpc = arcp -> arc_childp -> value;
407 arc.raw_count = arcp -> arc_count;
408 if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
409 perror( sumfile );
410 done();
411 }
412# ifdef DEBUG
413 if ( debug & SAMPLEDEBUG ) {
414 printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
415 arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
416 }
417# endif DEBUG
418 }
419 }
420 fclose( sfile );
421}
422
3966d652
PK
423valcmp(p1, p2)
424 nltype *p1, *p2;
425{
426 if ( p1 -> value < p2 -> value ) {
427 return LESSTHAN;
428 }
429 if ( p1 -> value > p2 -> value ) {
430 return GREATERTHAN;
431 }
432 return EQUALTO;
433}
434
435readsamples(pfile)
436 FILE *pfile;
437{
438 register i;
439 unsigned UNIT sample;
440
441 if (samples == 0) {
442 samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
443 if (samples == 0) {
ad3b82ad
PK
444 fprintf( stderr , "%s: No room for %d sample pc's\n",
445 whoami , sampbytes / sizeof (unsigned UNIT));
3966d652
PK
446 done();
447 }
448 }
449 for (i = 0; i < nsamples; i++) {
450 fread(&sample, sizeof (unsigned UNIT), 1, pfile);
451 if (feof(pfile))
452 break;
453 samples[i] += sample;
454 }
455 if (i != nsamples) {
456 fprintf(stderr,
ad3b82ad
PK
457 "%s: unexpected EOF after reading %d/%d samples\n",
458 whoami , --i , nsamples );
3966d652
PK
459 done();
460 }
461}
462
463/*
464 * Assign samples to the procedures to which they belong.
465 */
466asgnsamples()
467{
468 register int j;
469 unsigned UNIT ccnt;
470 double time;
471 unsigned long pcl, pch;
472 register int i;
35e3e365 473 unsigned long overlap;
3966d652
PK
474 unsigned long svalue0, svalue1;
475
476 /* read samples and assign to namelist symbols */
477 scale = highpc - lowpc;
478 scale /= nsamples;
0fcb1e15 479 for (i = 0, j = 1; i < nsamples; i++) {
3966d652
PK
480 ccnt = samples[i];
481 if (ccnt == 0)
482 continue;
483 pcl = lowpc + scale*i;
484 pch = lowpc + scale*(i+1);
485 time = ccnt;
486# ifdef DEBUG
487 if ( debug & SAMPLEDEBUG ) {
eb6d6a16
KM
488 printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
489 pcl , pch , ccnt );
3966d652
PK
490 }
491# endif DEBUG
492 totime += time;
16051da5 493 for (j = j - 1; j < nname; j++) {
3966d652
PK
494 svalue0 = nl[j].value / sizeof(UNIT);
495 svalue1 = nl[j+1].value / sizeof(UNIT);
496 if (pch < svalue0)
497 break;
498 if (pcl >= svalue1)
499 continue;
500 overlap=min(pch,svalue1) - max(pcl,svalue0);
501 if (overlap>0) {
502# ifdef DEBUG
503 if ( debug & SAMPLEDEBUG ) {
eb6d6a16
KM
504 printf( "[asgnsamples] (0x%x-0x%x) %s gets %f ticks\n" ,
505 svalue0 , svalue1 , nl[j].name ,
506 overlap*time/scale );
3966d652
PK
507 }
508# endif DEBUG
509 nl[j].time += overlap*time/scale;
510 }
511 }
512 }
513# ifdef DEBUG
514 if ( debug & SAMPLEDEBUG ) {
515 printf( "[asgnsamples] totime %f\n" , totime );
516 }
517# endif DEBUG
3966d652
PK
518}
519
520
35e3e365 521unsigned long
3966d652 522min(a, b)
35e3e365 523 unsigned long a,b;
3966d652
PK
524{
525 if (a<b)
526 return(a);
527 return(b);
528}
529
35e3e365 530unsigned long
3966d652 531max(a, b)
35e3e365 532 unsigned long a,b;
3966d652
PK
533{
534 if (a>b)
535 return(a);
536 return(b);
537}
538
3f722622
PK
539bool
540funcsymbol( nlistp )
541 struct nlist *nlistp;
542{
543 extern char *strtab; /* string table from a.out */
d51dad81 544 extern int aflag; /* if static functions aren't desired */
3f722622
PK
545 char *name;
546
547 /*
548 * must be a text symbol,
d51dad81 549 * and static text symbols don't qualify if aflag set.
3f722622
PK
550 */
551 if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
d51dad81 552 || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
3f722622
PK
553 return FALSE;
554 }
555 /*
ad3b82ad 556 * can't have any `funny' characters in name,
3f722622
PK
557 * where `funny' includes `.', .o file names
558 * and `$', pascal labels.
559 */
560 for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) {
561 if ( *name == '.' || *name == '$' ) {
562 return FALSE;
563 }
564 }
565 return TRUE;
566}
567
3966d652
PK
568done()
569{
570
571 exit(0);
572}