1: /*
2: * Copyright (c) 1983 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char sccsid[] = "@(#)printgprof.c 5.1 (Berkeley) 6/4/85";
9: #endif not lint
10:
11: #include "gprof.h"
12:
13: printprof()
14: {
15: register nltype *np;
16: nltype **sortednlp;
17: int index;
18:
19: actime = 0.0;
20: printf( "\f\n" );
21: flatprofheader();
22: /*
23: * Sort the symbol table in by time
24: */
25: sortednlp = (nltype **) calloc( nname , sizeof(nltype *) );
26: if ( sortednlp == (nltype **) 0 ) {
27: fprintf( stderr , "[printprof] ran out of memory for time sorting\n" );
28: }
29: for ( index = 0 ; index < nname ; index += 1 ) {
30: sortednlp[ index ] = &nl[ index ];
31: }
32: qsort( sortednlp , nname , sizeof(nltype *) , timecmp );
33: for ( index = 0 ; index < nname ; index += 1 ) {
34: np = sortednlp[ index ];
35: flatprofline( np );
36: }
37: actime = 0.0;
38: cfree( sortednlp );
39: }
40:
41: timecmp( npp1 , npp2 )
42: nltype **npp1, **npp2;
43: {
44: double timediff;
45: long calldiff;
46:
47: timediff = (*npp2) -> time - (*npp1) -> time;
48: if ( timediff > 0.0 )
49: return 1 ;
50: if ( timediff < 0.0 )
51: return -1;
52: calldiff = (*npp2) -> ncall - (*npp1) -> ncall;
53: if ( calldiff > 0 )
54: return 1;
55: if ( calldiff < 0 )
56: return -1;
57: return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
58: }
59:
60: /*
61: * header for flatprofline
62: */
63: ()
64: {
65:
66: if ( bflag ) {
67: printblurb( FLAT_BLURB );
68: }
69: printf( "\ngranularity: each sample hit covers %d byte(s)" ,
70: (long) scale * sizeof(UNIT) );
71: if ( totime > 0.0 ) {
72: printf( " for %.2f%% of %.2f seconds\n\n" ,
73: 100.0/totime , totime / hz );
74: } else {
75: printf( " no time accumulated\n\n" );
76: /*
77: * this doesn't hurt sinc eall the numerators will be zero.
78: */
79: totime = 1.0;
80: }
81: printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n" ,
82: "% " , "cumulative" , "self " , "" , "self " , "total " , "" );
83: printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n" ,
84: "time" , "seconds " , "seconds" , "calls" ,
85: "ms/call" , "ms/call" , "name" );
86: }
87:
88: flatprofline( np )
89: register nltype *np;
90: {
91:
92: if ( zflag == 0 && np -> ncall == 0 && np -> time == 0 ) {
93: return;
94: }
95: actime += np -> time;
96: printf( "%5.1f %10.2f %8.2f" ,
97: 100 * np -> time / totime , actime / hz , np -> time / hz );
98: if ( np -> ncall != 0 ) {
99: printf( " %8d %8.2f %8.2f " , np -> ncall ,
100: 1000 * np -> time / hz / np -> ncall ,
101: 1000 * ( np -> time + np -> childtime ) / hz / np -> ncall );
102: } else {
103: printf( " %8.8s %8.8s %8.8s " , "" , "" , "" );
104: }
105: printname( np );
106: printf( "\n" );
107: }
108:
109: ()
110: {
111:
112: if ( bflag ) {
113: printblurb( CALLG_BLURB );
114: }
115: printf( "\ngranularity: each sample hit covers %d byte(s)" ,
116: (long) scale * sizeof(UNIT) );
117: if ( printtime > 0.0 ) {
118: printf( " for %.2f%% of %.2f seconds\n\n" ,
119: 100.0/printtime , printtime / hz );
120: } else {
121: printf( " no time propagated\n\n" );
122: /*
123: * this doesn't hurt, since all the numerators will be 0.0
124: */
125: printtime = 1.0;
126: }
127: printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" ,
128: "" , "" , "" , "" , "called" , "total" , "parents" , "" );
129: printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" ,
130: "index" , "%time" , "self" , "descendents" ,
131: "called" , "self" , "name" , "index" );
132: printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" ,
133: "" , "" , "" , "" , "called" , "total" , "children" , "" );
134: printf( "\n" );
135: }
136:
137: gprofline( np )
138: register nltype *np;
139: {
140: char kirkbuffer[ BUFSIZ ];
141:
142: sprintf( kirkbuffer , "[%d]" , np -> index );
143: printf( "%-6.6s %5.1f %7.2f %11.2f" ,
144: kirkbuffer ,
145: 100 * ( np -> propself + np -> propchild ) / printtime ,
146: np -> propself / hz ,
147: np -> propchild / hz );
148: if ( ( np -> ncall + np -> selfcalls ) != 0 ) {
149: printf( " %7d" , np -> ncall );
150: if ( np -> selfcalls != 0 ) {
151: printf( "+%-7d " , np -> selfcalls );
152: } else {
153: printf( " %7.7s " , "" );
154: }
155: } else {
156: printf( " %7.7s %7.7s " , "" , "" );
157: }
158: printname( np );
159: printf( "\n" );
160: }
161:
162: printgprof(timesortnlp)
163: nltype **timesortnlp;
164: {
165: int index;
166: nltype *parentp;
167:
168: /*
169: * Print out the structured profiling list
170: */
171: gprofheader();
172: for ( index = 0 ; index < nname + ncycle ; index ++ ) {
173: parentp = timesortnlp[ index ];
174: if ( zflag == 0 &&
175: parentp -> ncall == 0 &&
176: parentp -> selfcalls == 0 &&
177: parentp -> propself == 0 &&
178: parentp -> propchild == 0 ) {
179: continue;
180: }
181: if ( ! parentp -> printflag ) {
182: continue;
183: }
184: if ( parentp -> name == 0 && parentp -> cycleno != 0 ) {
185: /*
186: * cycle header
187: */
188: printcycle( parentp );
189: printmembers( parentp );
190: } else {
191: printparents( parentp );
192: gprofline( parentp );
193: printchildren( parentp );
194: }
195: printf( "\n" );
196: printf( "-----------------------------------------------\n" );
197: printf( "\n" );
198: }
199: cfree( timesortnlp );
200: }
201:
202: /*
203: * sort by decreasing propagated time
204: * if times are equal, but one is a cycle header,
205: * say that's first (e.g. less, i.e. -1).
206: * if one's name doesn't have an underscore and the other does,
207: * say the one is first.
208: * all else being equal, sort by names.
209: */
210: int
211: totalcmp( npp1 , npp2 )
212: nltype **npp1;
213: nltype **npp2;
214: {
215: register nltype *np1 = *npp1;
216: register nltype *np2 = *npp2;
217: double diff;
218:
219: diff = ( np1 -> propself + np1 -> propchild )
220: - ( np2 -> propself + np2 -> propchild );
221: if ( diff < 0.0 )
222: return 1;
223: if ( diff > 0.0 )
224: return -1;
225: if ( np1 -> name == 0 && np1 -> cycleno != 0 )
226: return -1;
227: if ( np2 -> name == 0 && np2 -> cycleno != 0 )
228: return 1;
229: if ( np1 -> name == 0 )
230: return -1;
231: if ( np2 -> name == 0 )
232: return 1;
233: if ( *(np1 -> name) != '_' && *(np2 -> name) == '_' )
234: return -1;
235: if ( *(np1 -> name) == '_' && *(np2 -> name) != '_' )
236: return 1;
237: if ( np1 -> ncall > np2 -> ncall )
238: return -1;
239: if ( np1 -> ncall < np2 -> ncall )
240: return 1;
241: return strcmp( np1 -> name , np2 -> name );
242: }
243:
244: printparents( childp )
245: nltype *childp;
246: {
247: nltype *parentp;
248: arctype *arcp;
249: nltype *cycleheadp;
250:
251: if ( childp -> cyclehead != 0 ) {
252: cycleheadp = childp -> cyclehead;
253: } else {
254: cycleheadp = childp;
255: }
256: if ( childp -> parents == 0 ) {
257: printf( "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s <spontaneous>\n" ,
258: "" , "" , "" , "" , "" , "" );
259: return;
260: }
261: sortparents( childp );
262: for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) {
263: parentp = arcp -> arc_parentp;
264: if ( childp == parentp ||
265: ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) {
266: /*
267: * selfcall or call among siblings
268: */
269: printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " ,
270: "" , "" , "" , "" ,
271: arcp -> arc_count , "" );
272: printname( parentp );
273: printf( "\n" );
274: } else {
275: /*
276: * regular parent of child
277: */
278: printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " ,
279: "" , "" ,
280: arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
281: arcp -> arc_count , cycleheadp -> ncall );
282: printname( parentp );
283: printf( "\n" );
284: }
285: }
286: }
287:
288: printchildren( parentp )
289: nltype *parentp;
290: {
291: nltype *childp;
292: arctype *arcp;
293:
294: sortchildren( parentp );
295: arcp = parentp -> children;
296: for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
297: childp = arcp -> arc_childp;
298: if ( childp == parentp ||
299: ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) {
300: /*
301: * self call or call to sibling
302: */
303: printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " ,
304: "" , "" , "" , "" , arcp -> arc_count , "" );
305: printname( childp );
306: printf( "\n" );
307: } else {
308: /*
309: * regular child of parent
310: */
311: printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " ,
312: "" , "" ,
313: arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
314: arcp -> arc_count , childp -> cyclehead -> ncall );
315: printname( childp );
316: printf( "\n" );
317: }
318: }
319: }
320:
321: printname( selfp )
322: nltype *selfp;
323: {
324:
325: if ( selfp -> name != 0 ) {
326: printf( "%s" , selfp -> name );
327: # ifdef DEBUG
328: if ( debug & DFNDEBUG ) {
329: printf( "{%d} " , selfp -> toporder );
330: }
331: if ( debug & PROPDEBUG ) {
332: printf( "%5.2f%% " , selfp -> propfraction );
333: }
334: # endif DEBUG
335: }
336: if ( selfp -> cycleno != 0 ) {
337: printf( " <cycle %d>" , selfp -> cycleno );
338: }
339: if ( selfp -> index != 0 ) {
340: if ( selfp -> printflag ) {
341: printf( " [%d]" , selfp -> index );
342: } else {
343: printf( " (%d)" , selfp -> index );
344: }
345: }
346: }
347:
348: sortchildren( parentp )
349: nltype *parentp;
350: {
351: arctype *arcp;
352: arctype *detachedp;
353: arctype sorted;
354: arctype *prevp;
355:
356: /*
357: * unlink children from parent,
358: * then insertion sort back on to sorted's children.
359: * *arcp the arc you have detached and are inserting.
360: * *detachedp the rest of the arcs to be sorted.
361: * sorted arc list onto which you insertion sort.
362: * *prevp arc before the arc you are comparing.
363: */
364: sorted.arc_childlist = 0;
365: for ( (arcp = parentp -> children)&&(detachedp = arcp -> arc_childlist);
366: arcp ;
367: (arcp = detachedp)&&(detachedp = detachedp -> arc_childlist)) {
368: /*
369: * consider *arcp as disconnected
370: * insert it into sorted
371: */
372: for ( prevp = &sorted ;
373: prevp -> arc_childlist ;
374: prevp = prevp -> arc_childlist ) {
375: if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) {
376: break;
377: }
378: }
379: arcp -> arc_childlist = prevp -> arc_childlist;
380: prevp -> arc_childlist = arcp;
381: }
382: /*
383: * reattach sorted children to parent
384: */
385: parentp -> children = sorted.arc_childlist;
386: }
387:
388: sortparents( childp )
389: nltype *childp;
390: {
391: arctype *arcp;
392: arctype *detachedp;
393: arctype sorted;
394: arctype *prevp;
395:
396: /*
397: * unlink parents from child,
398: * then insertion sort back on to sorted's parents.
399: * *arcp the arc you have detached and are inserting.
400: * *detachedp the rest of the arcs to be sorted.
401: * sorted arc list onto which you insertion sort.
402: * *prevp arc before the arc you are comparing.
403: */
404: sorted.arc_parentlist = 0;
405: for ( (arcp = childp -> parents)&&(detachedp = arcp -> arc_parentlist);
406: arcp ;
407: (arcp = detachedp)&&(detachedp = detachedp -> arc_parentlist)) {
408: /*
409: * consider *arcp as disconnected
410: * insert it into sorted
411: */
412: for ( prevp = &sorted ;
413: prevp -> arc_parentlist ;
414: prevp = prevp -> arc_parentlist ) {
415: if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) {
416: break;
417: }
418: }
419: arcp -> arc_parentlist = prevp -> arc_parentlist;
420: prevp -> arc_parentlist = arcp;
421: }
422: /*
423: * reattach sorted arcs to child
424: */
425: childp -> parents = sorted.arc_parentlist;
426: }
427:
428: /*
429: * print a cycle header
430: */
431: printcycle( cyclep )
432: nltype *cyclep;
433: {
434: char kirkbuffer[ BUFSIZ ];
435:
436: sprintf( kirkbuffer , "[%d]" , cyclep -> index );
437: printf( "%-6.6s %5.1f %7.2f %11.2f %7d" ,
438: kirkbuffer ,
439: 100 * ( cyclep -> propself + cyclep -> propchild ) / printtime ,
440: cyclep -> propself / hz ,
441: cyclep -> propchild / hz ,
442: cyclep -> ncall );
443: if ( cyclep -> selfcalls != 0 ) {
444: printf( "+%-7d" , cyclep -> selfcalls );
445: } else {
446: printf( " %7.7s" , "" );
447: }
448: printf( " <cycle %d as a whole>\t[%d]\n" ,
449: cyclep -> cycleno , cyclep -> index );
450: }
451:
452: /*
453: * print the members of a cycle
454: */
455: printmembers( cyclep )
456: nltype *cyclep;
457: {
458: nltype *memberp;
459:
460: sortmembers( cyclep );
461: for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) {
462: printf( "%6.6s %5.5s %7.2f %11.2f %7d" ,
463: "" , "" , memberp -> propself / hz , memberp -> propchild / hz ,
464: memberp -> ncall );
465: if ( memberp -> selfcalls != 0 ) {
466: printf( "+%-7d" , memberp -> selfcalls );
467: } else {
468: printf( " %7.7s" , "" );
469: }
470: printf( " " );
471: printname( memberp );
472: printf( "\n" );
473: }
474: }
475:
476: /*
477: * sort members of a cycle
478: */
479: sortmembers( cyclep )
480: nltype *cyclep;
481: {
482: nltype *todo;
483: nltype *doing;
484: nltype *prev;
485:
486: /*
487: * detach cycle members from cyclehead,
488: * and insertion sort them back on.
489: */
490: todo = cyclep -> cnext;
491: cyclep -> cnext = 0;
492: for ( (doing = todo)&&(todo = doing -> cnext);
493: doing ;
494: (doing = todo )&&(todo = doing -> cnext )){
495: for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) {
496: if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) {
497: break;
498: }
499: }
500: doing -> cnext = prev -> cnext;
501: prev -> cnext = doing;
502: }
503: }
504:
505: /*
506: * major sort is on propself + propchild,
507: * next is sort on ncalls + selfcalls.
508: */
509: int
510: membercmp( this , that )
511: nltype *this;
512: nltype *that;
513: {
514: double thistime = this -> propself + this -> propchild;
515: double thattime = that -> propself + that -> propchild;
516: long thiscalls = this -> ncall + this -> selfcalls;
517: long thatcalls = that -> ncall + that -> selfcalls;
518:
519: if ( thistime > thattime ) {
520: return GREATERTHAN;
521: }
522: if ( thistime < thattime ) {
523: return LESSTHAN;
524: }
525: if ( thiscalls > thatcalls ) {
526: return GREATERTHAN;
527: }
528: if ( thiscalls < thatcalls ) {
529: return LESSTHAN;
530: }
531: return EQUALTO;
532: }
533: /*
534: * compare two arcs to/from the same child/parent.
535: * - if one arc is a self arc, it's least.
536: * - if one arc is within a cycle, it's less than.
537: * - if both arcs are within a cycle, compare arc counts.
538: * - if neither arc is within a cycle, compare with
539: * arc_time + arc_childtime as major key
540: * arc count as minor key
541: */
542: int
543: arccmp( thisp , thatp )
544: arctype *thisp;
545: arctype *thatp;
546: {
547: nltype *thisparentp = thisp -> arc_parentp;
548: nltype *thischildp = thisp -> arc_childp;
549: nltype *thatparentp = thatp -> arc_parentp;
550: nltype *thatchildp = thatp -> arc_childp;
551: double thistime;
552: double thattime;
553:
554: # ifdef DEBUG
555: if ( debug & TIMEDEBUG ) {
556: printf( "[arccmp] " );
557: printname( thisparentp );
558: printf( " calls " );
559: printname ( thischildp );
560: printf( " %f + %f %d/%d\n" ,
561: thisp -> arc_time , thisp -> arc_childtime ,
562: thisp -> arc_count , thischildp -> ncall );
563: printf( "[arccmp] " );
564: printname( thatparentp );
565: printf( " calls " );
566: printname( thatchildp );
567: printf( " %f + %f %d/%d\n" ,
568: thatp -> arc_time , thatp -> arc_childtime ,
569: thatp -> arc_count , thatchildp -> ncall );
570: printf( "\n" );
571: }
572: # endif DEBUG
573: if ( thisparentp == thischildp ) {
574: /* this is a self call */
575: return LESSTHAN;
576: }
577: if ( thatparentp == thatchildp ) {
578: /* that is a self call */
579: return GREATERTHAN;
580: }
581: if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 &&
582: thisparentp -> cycleno == thischildp -> cycleno ) {
583: /* this is a call within a cycle */
584: if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
585: thatparentp -> cycleno == thatchildp -> cycleno ) {
586: /* that is a call within the cycle, too */
587: if ( thisp -> arc_count < thatp -> arc_count ) {
588: return LESSTHAN;
589: }
590: if ( thisp -> arc_count > thatp -> arc_count ) {
591: return GREATERTHAN;
592: }
593: return EQUALTO;
594: } else {
595: /* that isn't a call within the cycle */
596: return LESSTHAN;
597: }
598: } else {
599: /* this isn't a call within a cycle */
600: if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
601: thatparentp -> cycleno == thatchildp -> cycleno ) {
602: /* that is a call within a cycle */
603: return GREATERTHAN;
604: } else {
605: /* neither is a call within a cycle */
606: thistime = thisp -> arc_time + thisp -> arc_childtime;
607: thattime = thatp -> arc_time + thatp -> arc_childtime;
608: if ( thistime < thattime )
609: return LESSTHAN;
610: if ( thistime > thattime )
611: return GREATERTHAN;
612: if ( thisp -> arc_count < thatp -> arc_count )
613: return LESSTHAN;
614: if ( thisp -> arc_count > thatp -> arc_count )
615: return GREATERTHAN;
616: return EQUALTO;
617: }
618: }
619: }
620:
621: printblurb( blurbname )
622: char *blurbname;
623: {
624: FILE *blurbfile;
625: int input;
626:
627: blurbfile = fopen( blurbname , "r" );
628: if ( blurbfile == NULL ) {
629: perror( blurbname );
630: return;
631: }
632: while ( ( input = getc( blurbfile ) ) != EOF ) {
633: putchar( input );
634: }
635: fclose( blurbfile );
636: }
637:
638: int
639: namecmp( npp1 , npp2 )
640: nltype **npp1, **npp2;
641: {
642: return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
643: }
644:
645: printindex()
646: {
647: nltype **namesortnlp;
648: register nltype *nlp;
649: int index, nnames, todo, i, j;
650: char peterbuffer[ BUFSIZ ];
651:
652: /*
653: * Now, sort regular function name alphbetically
654: * to create an index.
655: */
656: namesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
657: if ( namesortnlp == (nltype **) 0 ) {
658: fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami );
659: }
660: for ( index = 0 , nnames = 0 ; index < nname ; index++ ) {
661: if ( zflag == 0 && nl[index].ncall == 0 && nl[index].time == 0 )
662: continue;
663: namesortnlp[nnames++] = &nl[index];
664: }
665: qsort( namesortnlp , nnames , sizeof(nltype *) , namecmp );
666: for ( index = 1 , todo = nnames ; index <= ncycle ; index++ ) {
667: namesortnlp[todo++] = &cyclenl[index];
668: }
669: printf( "\f\nIndex by function name\n\n" );
670: index = ( todo + 2 ) / 3;
671: for ( i = 0; i < index ; i++ ) {
672: for ( j = i; j < todo ; j += index ) {
673: nlp = namesortnlp[ j ];
674: if ( nlp -> printflag ) {
675: sprintf( peterbuffer , "[%d]" , nlp -> index );
676: } else {
677: sprintf( peterbuffer , "(%d)" , nlp -> index );
678: }
679: if ( j < nnames ) {
680: printf( "%6.6s %-19.19s" , peterbuffer , nlp -> name );
681: } else {
682: printf( "%6.6s " , peterbuffer );
683: sprintf( peterbuffer , "<cycle %d>" , nlp -> cycleno );
684: printf( "%-19.19s" , peterbuffer );
685: }
686: }
687: printf( "\n" );
688: }
689: cfree( namesortnlp );
690: }