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