2 * Copyright (c) 1983 Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that: (1) source distributions retain this entire copyright
7 * notice and comment, and (2) distributions including binaries display
8 * the following acknowledgement: ``This product includes software
9 * developed by the University of California, Berkeley and its contributors''
10 * in the documentation or other materials provided with the distribution
11 * and in all advertising materials mentioning features or use of this
12 * software. Neither the name of the University nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 static char sccsid[] = "@(#)printgprof.c 5.7 (Berkeley) 6/1/90";
34 if ( bsd_style_output ) {
37 printf( "\n\n\nflat profile:\n" );
42 printf ("Flat profile:\n");
45 * Sort the symbol table in by time
47 sortednlp = (nltype **) calloc( nname , sizeof(nltype *) );
48 if ( sortednlp == (nltype **) 0 ) {
49 fprintf( stderr , "[printprof] ran out of memory for time sorting\n" );
51 for ( index = 0 ; index < nname ; index += 1 ) {
52 sortednlp[ index ] = &nl[ index ];
54 qsort( sortednlp , nname , sizeof(nltype *) , timecmp );
55 for ( index = 0 ; index < nname ; index += 1 ) {
56 np = sortednlp[ index ];
61 if ( bflag && !bsd_style_output ) {
66 timecmp( npp1 , npp2 )
67 nltype **npp1, **npp2;
72 timediff = (*npp2) -> time - (*npp1) -> time;
77 calldiff = (*npp2) -> ncall - (*npp1) -> ncall;
82 return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
86 * header for flatprofline
91 if (bsd_style_output) {
92 printf( "\ngranularity: each sample hit covers %d byte(s)" ,
93 (long) scale * sizeof(UNIT) );
95 printf( " for %.2f%% of %.2f seconds\n\n" ,
96 100.0/totime , totime / hz );
98 printf( " no time accumulated\n\n" );
100 * this doesn't hurt since all the numerators will be zero.
106 printf( "\nEach sample counts as %g seconds.\n",
109 printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n" ,
110 "% " , "cumulative" , "self " , "" , "self " , "total " , "" );
111 printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n" ,
112 "time" , "seconds " , "seconds" , "calls" ,
113 "ms/call" , "ms/call" , "name" );
120 if ( zflag == 0 && np -> ncall == 0 && np -> time == 0 ) {
123 actime += np -> time;
124 if (bsd_style_output)
125 printf( "%5.1f %10.2f %8.2f" ,
126 100 * np -> time / totime , actime / hz , np -> time / hz );
128 printf( "%6.2f %9.2f %8.2f" ,
129 100 * np -> time / totime , actime / hz , np -> time / hz );
130 if ( np -> ncall != 0 ) {
131 printf( " %8d %8.2f %8.2f " , np -> ncall ,
132 1000 * np -> time / hz / np -> ncall ,
133 1000 * ( np -> time + np -> childtime ) / hz / np -> ncall );
135 printf( " %8.8s %8.8s %8.8s " , "" , "" , "" );
137 if (bsd_style_output)
147 if (!bsd_style_output)
149 printf ("\t\t Call graph (explanation follows)\n\n");
151 printf ("\t\t\tCall graph\n\n");
152 printf( "\ngranularity: each sample hit covers %d byte(s)" ,
153 (long) scale * sizeof(UNIT) );
154 if ( printtime > 0.0 ) {
155 printf( " for %.2f%% of %.2f seconds\n\n" ,
156 100.0/printtime , printtime / hz );
158 printf( " no time propagated\n\n" );
160 * this doesn't hurt, since all the numerators will be 0.0
164 if (bsd_style_output) {
165 printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" ,
166 "" , "" , "" , "" , "called" , "total" , "parents");
167 printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" ,
168 "index" , "%time" , "self" , "descendents" ,
169 "called" , "self" , "name" , "index" );
170 printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" ,
171 "" , "" , "" , "" , "called" , "total" , "children");
174 printf( "index %% time self children called name\n" );
181 char kirkbuffer[ BUFSIZ ];
183 sprintf( kirkbuffer , "[%d]" , np -> index );
184 printf(bsd_style_output
185 ? "%-6.6s %5.1f %7.2f %11.2f"
186 : "%-6.6s %5.1f %7.2f %7.2f" ,
188 100 * ( np -> propself + np -> propchild ) / printtime ,
189 np -> propself / hz ,
190 np -> propchild / hz );
191 if ( ( np -> ncall + np -> selfcalls ) != 0 ) {
192 printf( " %7d" , np -> ncall );
193 if ( np -> selfcalls != 0 ) {
194 printf( "+%-7d " , np -> selfcalls );
196 printf( " %7.7s " , "" );
199 printf( " %7.7s %7.7s " , "" , "" );
205 printgprof(timesortnlp)
206 nltype **timesortnlp;
212 * Print out the structured profiling list
214 if ( bflag && bsd_style_output ) {
218 for ( index = 0 ; index < nname + ncycle ; index ++ ) {
219 parentp = timesortnlp[ index ];
221 parentp -> ncall == 0 &&
222 parentp -> selfcalls == 0 &&
223 parentp -> propself == 0 &&
224 parentp -> propchild == 0 ) {
227 if ( ! parentp -> printflag ) {
230 if ( parentp -> name == 0 && parentp -> cycleno != 0 ) {
234 printcycle( parentp );
235 printmembers( parentp );
237 printparents( parentp );
238 gprofline( parentp );
239 printchildren( parentp );
241 if (bsd_style_output)
243 printf( "-----------------------------------------------\n" );
244 if (bsd_style_output)
247 cfree( timesortnlp );
248 if ( bflag && !bsd_style_output) {
254 * sort by decreasing propagated time
255 * if times are equal, but one is a cycle header,
256 * say that's first (e.g. less, i.e. -1).
257 * if one's name doesn't have an underscore and the other does,
258 * say the one is first.
259 * all else being equal, sort by names.
262 totalcmp( npp1 , npp2 )
266 register nltype *np1 = *npp1;
267 register nltype *np2 = *npp2;
270 diff = ( np1 -> propself + np1 -> propchild )
271 - ( np2 -> propself + np2 -> propchild );
276 if ( np1 -> name == 0 && np1 -> cycleno != 0 )
278 if ( np2 -> name == 0 && np2 -> cycleno != 0 )
280 if ( np1 -> name == 0 )
282 if ( np2 -> name == 0 )
284 if ( *(np1 -> name) != '_' && *(np2 -> name) == '_' )
286 if ( *(np1 -> name) == '_' && *(np2 -> name) != '_' )
288 if ( np1 -> ncall > np2 -> ncall )
290 if ( np1 -> ncall < np2 -> ncall )
292 return strcmp( np1 -> name , np2 -> name );
295 printparents( childp )
302 if ( childp -> cyclehead != 0 ) {
303 cycleheadp = childp -> cyclehead;
307 if ( childp -> parents == 0 ) {
308 printf(bsd_style_output
309 ? "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s <spontaneous>\n"
310 : "%6.6s %5.5s %7.7s %7.7s %7.7s %7.7s <spontaneous>\n" ,
311 "" , "" , "" , "" , "" , "" );
314 sortparents( childp );
315 for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) {
316 parentp = arcp -> arc_parentp;
317 if ( childp == parentp ||
318 ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) {
320 * selfcall or call among siblings
322 printf(bsd_style_output
323 ? "%6.6s %5.5s %7.7s %11.11s %7d %7.7s "
324 : "%6.6s %5.5s %7.7s %7.7s %7d %7.7s " ,
326 arcp -> arc_count , "" );
327 printname( parentp );
331 * regular parent of child
333 printf(bsd_style_output
334 ? "%6.6s %5.5s %7.2f %11.2f %7d/%-7d "
335 : "%6.6s %5.5s %7.2f %7.2f %7d/%-7d ",
337 arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
338 arcp -> arc_count , cycleheadp -> ncall );
339 printname( parentp );
345 printchildren( parentp )
351 sortchildren( parentp );
352 arcp = parentp -> children;
353 for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
354 childp = arcp -> arc_childp;
355 if ( childp == parentp ||
356 ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) {
358 * self call or call to sibling
360 printf(bsd_style_output
361 ? "%6.6s %5.5s %7.7s %11.11s %7d %7.7s "
362 : "%6.6s %5.5s %7.7s %7.7s %7d %7.7s " ,
363 "" , "" , "" , "" , arcp -> arc_count , "" );
368 * regular child of parent
370 printf(bsd_style_output
371 ? "%6.6s %5.5s %7.2f %11.2f %7d/%-7d "
372 : "%6.6s %5.5s %7.2f %7.2f %7d/%-7d " ,
374 arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
375 arcp -> arc_count , childp -> cyclehead -> ncall );
382 /* Print name of symbol. Return number of characters printed. */
385 printnameonly ( selfp )
389 CONST char *name = selfp->name;
391 char *demangled = NULL;
392 if (!bsd_style_output) {
393 if (name[0] == '_' && name[1] && discard_underscores)
395 demangled = cplus_demangle (name, DMGL_ANSI|DMGL_PARAMS);
399 printf( "%s" , name );
400 size = strlen (name);
404 if ( debug & DFNDEBUG ) {
405 printf( "{%d} " , selfp -> toporder );
407 if ( debug & PROPDEBUG ) {
408 printf( "%5.2f%% " , selfp -> propfraction );
418 printnameonly (selfp);
420 if ( selfp -> cycleno != 0 ) {
421 printf( " <cycle %d>" , selfp -> cycleno );
423 if ( selfp -> index != 0 ) {
424 if ( selfp -> printflag ) {
425 printf( " [%d]" , selfp -> index );
427 printf( " (%d)" , selfp -> index );
432 sortchildren( parentp )
441 * unlink children from parent,
442 * then insertion sort back on to sorted's children.
443 * *arcp the arc you have detached and are inserting.
444 * *detachedp the rest of the arcs to be sorted.
445 * sorted arc list onto which you insertion sort.
446 * *prevp arc before the arc you are comparing.
448 sorted.arc_childlist = 0;
449 for ( (arcp = parentp -> children)&&(detachedp = arcp -> arc_childlist);
451 (arcp = detachedp)&&(detachedp = detachedp -> arc_childlist)) {
453 * consider *arcp as disconnected
454 * insert it into sorted
456 for ( prevp = &sorted ;
457 prevp -> arc_childlist ;
458 prevp = prevp -> arc_childlist ) {
459 if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) {
463 arcp -> arc_childlist = prevp -> arc_childlist;
464 prevp -> arc_childlist = arcp;
467 * reattach sorted children to parent
469 parentp -> children = sorted.arc_childlist;
472 sortparents( childp )
481 * unlink parents from child,
482 * then insertion sort back on to sorted's parents.
483 * *arcp the arc you have detached and are inserting.
484 * *detachedp the rest of the arcs to be sorted.
485 * sorted arc list onto which you insertion sort.
486 * *prevp arc before the arc you are comparing.
488 sorted.arc_parentlist = 0;
489 for ( (arcp = childp -> parents)&&(detachedp = arcp -> arc_parentlist);
491 (arcp = detachedp)&&(detachedp = detachedp -> arc_parentlist)) {
493 * consider *arcp as disconnected
494 * insert it into sorted
496 for ( prevp = &sorted ;
497 prevp -> arc_parentlist ;
498 prevp = prevp -> arc_parentlist ) {
499 if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) {
503 arcp -> arc_parentlist = prevp -> arc_parentlist;
504 prevp -> arc_parentlist = arcp;
507 * reattach sorted arcs to child
509 childp -> parents = sorted.arc_parentlist;
513 * print a cycle header
518 char kirkbuffer[ BUFSIZ ];
520 sprintf( kirkbuffer , "[%d]" , cyclep -> index );
521 printf( "%-6.6s %5.1f %7.2f %11.2f %7d" ,
523 100 * ( cyclep -> propself + cyclep -> propchild ) / printtime ,
524 cyclep -> propself / hz ,
525 cyclep -> propchild / hz ,
527 if ( cyclep -> selfcalls != 0 ) {
528 printf( "+%-7d" , cyclep -> selfcalls );
530 printf( " %7.7s" , "" );
532 printf( " <cycle %d as a whole>\t[%d]\n" ,
533 cyclep -> cycleno , cyclep -> index );
537 * print the members of a cycle
539 printmembers( cyclep )
544 sortmembers( cyclep );
545 for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) {
546 printf( "%6.6s %5.5s %7.2f %11.2f %7d" ,
547 "" , "" , memberp -> propself / hz , memberp -> propchild / hz ,
549 if ( memberp -> selfcalls != 0 ) {
550 printf( "+%-7d" , memberp -> selfcalls );
552 printf( " %7.7s" , "" );
555 printname( memberp );
561 * sort members of a cycle
563 sortmembers( cyclep )
571 * detach cycle members from cyclehead,
572 * and insertion sort them back on.
574 todo = cyclep -> cnext;
576 for ( (doing = todo)&&(todo = doing -> cnext);
578 (doing = todo )&&(todo = doing -> cnext )){
579 for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) {
580 if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) {
584 doing -> cnext = prev -> cnext;
585 prev -> cnext = doing;
590 * major sort is on propself + propchild,
591 * next is sort on ncalls + selfcalls.
594 membercmp( this , that )
598 double thistime = this -> propself + this -> propchild;
599 double thattime = that -> propself + that -> propchild;
600 long thiscalls = this -> ncall + this -> selfcalls;
601 long thatcalls = that -> ncall + that -> selfcalls;
603 if ( thistime > thattime ) {
606 if ( thistime < thattime ) {
609 if ( thiscalls > thatcalls ) {
612 if ( thiscalls < thatcalls ) {
618 * compare two arcs to/from the same child/parent.
619 * - if one arc is a self arc, it's least.
620 * - if one arc is within a cycle, it's less than.
621 * - if both arcs are within a cycle, compare arc counts.
622 * - if neither arc is within a cycle, compare with
623 * arc_time + arc_childtime as major key
624 * arc count as minor key
627 arccmp( thisp , thatp )
631 nltype *thisparentp = thisp -> arc_parentp;
632 nltype *thischildp = thisp -> arc_childp;
633 nltype *thatparentp = thatp -> arc_parentp;
634 nltype *thatchildp = thatp -> arc_childp;
639 if ( debug & TIMEDEBUG ) {
640 printf( "[arccmp] " );
641 printname( thisparentp );
643 printname ( thischildp );
644 printf( " %f + %f %d/%d\n" ,
645 thisp -> arc_time , thisp -> arc_childtime ,
646 thisp -> arc_count , thischildp -> ncall );
647 printf( "[arccmp] " );
648 printname( thatparentp );
650 printname( thatchildp );
651 printf( " %f + %f %d/%d\n" ,
652 thatp -> arc_time , thatp -> arc_childtime ,
653 thatp -> arc_count , thatchildp -> ncall );
657 if ( thisparentp == thischildp ) {
658 /* this is a self call */
661 if ( thatparentp == thatchildp ) {
662 /* that is a self call */
665 if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 &&
666 thisparentp -> cycleno == thischildp -> cycleno ) {
667 /* this is a call within a cycle */
668 if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
669 thatparentp -> cycleno == thatchildp -> cycleno ) {
670 /* that is a call within the cycle, too */
671 if ( thisp -> arc_count < thatp -> arc_count ) {
674 if ( thisp -> arc_count > thatp -> arc_count ) {
679 /* that isn't a call within the cycle */
683 /* this isn't a call within a cycle */
684 if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
685 thatparentp -> cycleno == thatchildp -> cycleno ) {
686 /* that is a call within a cycle */
689 /* neither is a call within a cycle */
690 thistime = thisp -> arc_time + thisp -> arc_childtime;
691 thattime = thatp -> arc_time + thatp -> arc_childtime;
692 if ( thistime < thattime )
694 if ( thistime > thattime )
696 if ( thisp -> arc_count < thatp -> arc_count )
698 if ( thisp -> arc_count > thatp -> arc_count )
706 namecmp( npp1 , npp2 )
707 nltype **npp1, **npp2;
709 return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
714 nltype **namesortnlp;
715 register nltype *nlp;
716 int index, nnames, todo, i, j;
717 char peterbuffer[20];
720 * Now, sort regular function name alphbetically
721 * to create an index.
723 namesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
724 if ( namesortnlp == (nltype **) 0 ) {
725 fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami );
727 for ( index = 0 , nnames = 0 ; index < nname ; index++ ) {
728 if ( zflag == 0 && nl[index].ncall == 0 && nl[index].time == 0 )
730 namesortnlp[nnames++] = &nl[index];
732 qsort( namesortnlp , nnames , sizeof(nltype *) , namecmp );
733 for ( index = 1 , todo = nnames ; index <= ncycle ; index++ ) {
734 namesortnlp[todo++] = &cyclenl[index];
736 printf( "\f\nIndex by function name\n\n" );
737 index = ( todo + 2 ) / 3;
738 for ( i = 0; i < index ; i++ ) {
739 for ( j = i; j < todo ; j += index ) {
740 nlp = namesortnlp[ j ];
741 if ( nlp -> printflag ) {
742 sprintf( peterbuffer , "[%d]" , nlp -> index );
744 sprintf( peterbuffer , "(%d)" , nlp -> index );
747 printf( "%6.6s " , peterbuffer );
748 if (bsd_style_output)
749 printf ("%-19.19s" , nlp->name);
751 int size = printnameonly(nlp);
752 for ( ; size < 19; size++) putchar(' ');
755 printf( "%6.6s " , peterbuffer );
756 sprintf( peterbuffer , "<cycle %d>" , nlp -> cycleno );
757 printf( "%-19.19s" , peterbuffer );
762 cfree( namesortnlp );
769 PTR val = malloc (size);
771 fprintf (stderr, "virtual memory exhaused\n");
778 xrealloc (oldval, size)
782 PTR val = realloc (oldval, size);
784 fprintf (stderr, "virtual memory exhaused\n");