2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#)printgprof.c 8.1 (Berkeley) 6/6/93
34 * $FreeBSD: src/usr.bin/gprof/printgprof.c,v 1.6 1999/08/28 01:01:56 peter Exp $
35 * $DragonFly: src/usr.bin/gprof/printgprof.c,v 1.5 2006/01/22 03:43:37 swildner Exp $
40 #include "pathnames.h"
52 * Sort the symbol table in by time
54 sortednlp
= (nltype
**) calloc( nname
, sizeof(nltype
*) );
55 if ( sortednlp
== NULL
) {
56 fprintf( stderr
, "[printprof] ran out of memory for time sorting\n" );
58 for ( index
= 0 ; index
< nname
; index
+= 1 ) {
59 sortednlp
[ index
] = &nl
[ index
];
61 qsort( sortednlp
, nname
, sizeof(nltype
*) , timecmp
);
62 for ( index
= 0 ; index
< nname
; index
+= 1 ) {
63 np
= sortednlp
[ index
];
70 timecmp(nltype
**npp1
, nltype
**npp2
)
75 timediff
= (*npp2
) -> time
- (*npp1
) -> time
;
80 calldiff
= (*npp2
) -> ncall
- (*npp1
) -> ncall
;
85 return( strcmp( (*npp1
) -> name
, (*npp2
) -> name
) );
89 * header for flatprofline
95 printblurb( _PATH_FLAT_BLURB
);
97 printf( "\ngranularity: each sample hit covers %d byte(s)" ,
98 (long) scale
* sizeof(UNIT
) );
100 printf( " for %.2f%% of %.2f seconds\n\n" ,
101 100.0/totime
, totime
/ hz
);
103 printf( " no time accumulated\n\n" );
105 * this doesn't hurt sinc eall the numerators will be zero.
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 hz
>= 10000000 ? "ns/call" : hz
>= 10000 ? "us/call" : "ms/call" ,
114 hz
>= 10000000 ? "ns/call" : hz
>= 10000 ? "us/call" : "ms/call" ,
118 flatprofline(nltype
*np
)
121 if ( zflag
== 0 && np
-> ncall
== 0 && np
-> time
== 0 ) {
124 actime
+= np
-> time
;
126 printf( "%5.1f %10.3f %8.3f" ,
127 100 * np
-> time
/ totime
, actime
/ hz
, np
-> time
/ hz
);
129 printf( "%5.1f %10.2f %8.2f" ,
130 100 * np
-> time
/ totime
, actime
/ hz
, np
-> time
/ hz
);
131 if ( np
-> ncall
!= 0 ) {
133 printf( " %8d %8.0f %8.0f " , np
-> ncall
,
134 1e9
* np
-> time
/ hz
/ np
-> ncall
,
135 1e9
* ( np
-> time
+ np
-> childtime
) / hz
/ np
-> ncall
);
136 else if (hz
>= 10000)
137 printf( " %8d %8.0f %8.0f " , np
-> ncall
,
138 1e6
* np
-> time
/ hz
/ np
-> ncall
,
139 1e6
* ( np
-> time
+ np
-> childtime
) / hz
/ np
-> ncall
);
141 printf( " %8d %8.2f %8.2f " , np
-> ncall
,
142 1000 * np
-> time
/ hz
/ np
-> ncall
,
143 1000 * ( np
-> time
+ np
-> childtime
) / hz
/ np
-> ncall
);
145 printf( " %8.8s %8.8s %8.8s " , "" , "" , "" );
155 printblurb( _PATH_CALLG_BLURB
);
157 printf( "\ngranularity: each sample hit covers %d byte(s)" ,
158 (long) scale
* sizeof(UNIT
) );
159 if ( printtime
> 0.0 ) {
160 printf( " for %.2f%% of %.2f seconds\n\n" ,
161 100.0/printtime
, printtime
/ hz
);
163 printf( " no time propagated\n\n" );
165 * this doesn't hurt, since all the numerators will be 0.0
169 printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" ,
170 "" , "" , "" , "" , "called" , "total" , "parents");
171 printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" ,
172 "index" , "%time" , "self" , "descendents" ,
173 "called" , "self" , "name" , "index" );
174 printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" ,
175 "" , "" , "" , "" , "called" , "total" , "children");
179 gprofline(nltype
*np
)
181 char kirkbuffer
[ BUFSIZ
];
183 sprintf( kirkbuffer
, "[%d]" , np
-> index
);
184 printf( "%-6.6s %5.1f %7.2f %11.2f" ,
186 100 * ( np
-> propself
+ np
-> propchild
) / printtime
,
187 np
-> propself
/ hz
,
188 np
-> propchild
/ hz
);
189 if ( ( np
-> ncall
+ np
-> selfcalls
) != 0 ) {
190 printf( " %7d" , np
-> npropcall
);
191 if ( np
-> selfcalls
!= 0 ) {
192 printf( "+%-7d " , np
-> selfcalls
);
194 printf( " %7.7s " , "" );
197 printf( " %7.7s %7.7s " , "" , "" );
203 printgprof(nltype
**timesortnlp
)
209 * Print out the structured profiling list
212 for ( index
= 0 ; index
< nname
+ ncycle
; index
++ ) {
213 parentp
= timesortnlp
[ index
];
215 parentp
-> ncall
== 0 &&
216 parentp
-> selfcalls
== 0 &&
217 parentp
-> propself
== 0 &&
218 parentp
-> propchild
== 0 ) {
221 if ( ! parentp
-> printflag
) {
224 if ( parentp
-> name
== 0 && parentp
-> cycleno
!= 0 ) {
228 printcycle( parentp
);
229 printmembers( parentp
);
231 printparents( parentp
);
232 gprofline( parentp
);
233 printchildren( parentp
);
236 printf( "-----------------------------------------------\n" );
243 * sort by decreasing propagated time
244 * if times are equal, but one is a cycle header,
245 * say that's first (e.g. less, i.e. -1).
246 * if one's name doesn't have an underscore and the other does,
247 * say the one is first.
248 * all else being equal, sort by names.
251 totalcmp(nltype
**npp1
, nltype
**npp2
)
257 diff
= ( np1
-> propself
+ np1
-> propchild
)
258 - ( np2
-> propself
+ np2
-> propchild
);
263 if ( np1
-> name
== 0 && np1
-> cycleno
!= 0 )
265 if ( np2
-> name
== 0 && np2
-> cycleno
!= 0 )
267 if ( np1
-> name
== 0 )
269 if ( np2
-> name
== 0 )
271 if ( *(np1
-> name
) != '_' && *(np2
-> name
) == '_' )
273 if ( *(np1
-> name
) == '_' && *(np2
-> name
) != '_' )
275 if ( np1
-> ncall
> np2
-> ncall
)
277 if ( np1
-> ncall
< np2
-> ncall
)
279 return strcmp( np1
-> name
, np2
-> name
);
282 printparents(nltype
*childp
)
288 if ( childp
-> cyclehead
!= 0 ) {
289 cycleheadp
= childp
-> cyclehead
;
293 if ( childp
-> parents
== 0 ) {
294 printf( "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s <spontaneous>\n" ,
295 "" , "" , "" , "" , "" , "" );
298 sortparents( childp
);
299 for ( arcp
= childp
-> parents
; arcp
; arcp
= arcp
-> arc_parentlist
) {
300 parentp
= arcp
-> arc_parentp
;
301 if ( childp
== parentp
|| ( arcp
-> arc_flags
& DEADARC
) ||
302 ( childp
->cycleno
!= 0 && parentp
->cycleno
== childp
->cycleno
) ) {
304 * selfcall or call among siblings
306 printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " ,
308 arcp
-> arc_count
, "" );
309 printname( parentp
);
313 * regular parent of child
315 printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " ,
317 arcp
-> arc_time
/ hz
, arcp
-> arc_childtime
/ hz
,
318 arcp
-> arc_count
, cycleheadp
-> npropcall
);
319 printname( parentp
);
325 printchildren(nltype
*parentp
)
330 sortchildren( parentp
);
331 arcp
= parentp
-> children
;
332 for ( arcp
= parentp
-> children
; arcp
; arcp
= arcp
-> arc_childlist
) {
333 childp
= arcp
-> arc_childp
;
334 if ( childp
== parentp
|| ( arcp
-> arc_flags
& DEADARC
) ||
335 ( childp
->cycleno
!= 0 && childp
->cycleno
== parentp
->cycleno
) ) {
337 * self call or call to sibling
339 printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " ,
340 "" , "" , "" , "" , arcp
-> arc_count
, "" );
345 * regular child of parent
347 printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " ,
349 arcp
-> arc_time
/ hz
, arcp
-> arc_childtime
/ hz
,
350 arcp
-> arc_count
, childp
-> cyclehead
-> npropcall
);
357 printname(nltype
*selfp
)
360 if ( selfp
-> name
!= 0 ) {
361 printf( "%s" , selfp
-> name
);
363 if ( debug
& DFNDEBUG
) {
364 printf( "{%d} " , selfp
-> toporder
);
366 if ( debug
& PROPDEBUG
) {
367 printf( "%5.2f%% " , selfp
-> propfraction
);
371 if ( selfp
-> cycleno
!= 0 ) {
372 printf( " <cycle %d>" , selfp
-> cycleno
);
374 if ( selfp
-> index
!= 0 ) {
375 if ( selfp
-> printflag
) {
376 printf( " [%d]" , selfp
-> index
);
378 printf( " (%d)" , selfp
-> index
);
383 sortchildren(nltype
*parentp
)
391 * unlink children from parent,
392 * then insertion sort back on to sorted's children.
393 * *arcp the arc you have detached and are inserting.
394 * *detachedp the rest of the arcs to be sorted.
395 * sorted arc list onto which you insertion sort.
396 * *prevp arc before the arc you are comparing.
398 sorted
.arc_childlist
= 0;
399 for ( (arcp
= parentp
-> children
)&&(detachedp
= arcp
-> arc_childlist
);
401 (arcp
= detachedp
)&&(detachedp
= detachedp
-> arc_childlist
)) {
403 * consider *arcp as disconnected
404 * insert it into sorted
406 for ( prevp
= &sorted
;
407 prevp
-> arc_childlist
;
408 prevp
= prevp
-> arc_childlist
) {
409 if ( arccmp( arcp
, prevp
-> arc_childlist
) != LESSTHAN
) {
413 arcp
-> arc_childlist
= prevp
-> arc_childlist
;
414 prevp
-> arc_childlist
= arcp
;
417 * reattach sorted children to parent
419 parentp
-> children
= sorted
.arc_childlist
;
422 sortparents(nltype
*childp
)
430 * unlink parents from child,
431 * then insertion sort back on to sorted's parents.
432 * *arcp the arc you have detached and are inserting.
433 * *detachedp the rest of the arcs to be sorted.
434 * sorted arc list onto which you insertion sort.
435 * *prevp arc before the arc you are comparing.
437 sorted
.arc_parentlist
= 0;
438 for ( (arcp
= childp
-> parents
)&&(detachedp
= arcp
-> arc_parentlist
);
440 (arcp
= detachedp
)&&(detachedp
= detachedp
-> arc_parentlist
)) {
442 * consider *arcp as disconnected
443 * insert it into sorted
445 for ( prevp
= &sorted
;
446 prevp
-> arc_parentlist
;
447 prevp
= prevp
-> arc_parentlist
) {
448 if ( arccmp( arcp
, prevp
-> arc_parentlist
) != GREATERTHAN
) {
452 arcp
-> arc_parentlist
= prevp
-> arc_parentlist
;
453 prevp
-> arc_parentlist
= arcp
;
456 * reattach sorted arcs to child
458 childp
-> parents
= sorted
.arc_parentlist
;
462 * print a cycle header
464 printcycle(nltype
*cyclep
)
466 char kirkbuffer
[ BUFSIZ
];
468 sprintf( kirkbuffer
, "[%d]" , cyclep
-> index
);
469 printf( "%-6.6s %5.1f %7.2f %11.2f %7d" ,
471 100 * ( cyclep
-> propself
+ cyclep
-> propchild
) / printtime
,
472 cyclep
-> propself
/ hz
,
473 cyclep
-> propchild
/ hz
,
474 cyclep
-> npropcall
);
475 if ( cyclep
-> selfcalls
!= 0 ) {
476 printf( "+%-7d" , cyclep
-> selfcalls
);
478 printf( " %7.7s" , "" );
480 printf( " <cycle %d as a whole>\t[%d]\n" ,
481 cyclep
-> cycleno
, cyclep
-> index
);
485 * print the members of a cycle
487 printmembers(nltype
*cyclep
)
491 sortmembers( cyclep
);
492 for ( memberp
= cyclep
-> cnext
; memberp
; memberp
= memberp
-> cnext
) {
493 printf( "%6.6s %5.5s %7.2f %11.2f %7d" ,
494 "" , "" , memberp
-> propself
/ hz
, memberp
-> propchild
/ hz
,
495 memberp
-> npropcall
);
496 if ( memberp
-> selfcalls
!= 0 ) {
497 printf( "+%-7d" , memberp
-> selfcalls
);
499 printf( " %7.7s" , "" );
502 printname( memberp
);
508 * sort members of a cycle
510 sortmembers(nltype
*cyclep
)
517 * detach cycle members from cyclehead,
518 * and insertion sort them back on.
520 todo
= cyclep
-> cnext
;
522 for ( (doing
= todo
)&&(todo
= doing
-> cnext
);
524 (doing
= todo
)&&(todo
= doing
-> cnext
)){
525 for ( prev
= cyclep
; prev
-> cnext
; prev
= prev
-> cnext
) {
526 if ( membercmp( doing
, prev
-> cnext
) == GREATERTHAN
) {
530 doing
-> cnext
= prev
-> cnext
;
531 prev
-> cnext
= doing
;
536 * major sort is on propself + propchild,
537 * next is sort on ncalls + selfcalls.
540 membercmp(nltype
*this, nltype
*that
)
542 double thistime
= this -> propself
+ this -> propchild
;
543 double thattime
= that
-> propself
+ that
-> propchild
;
544 long thiscalls
= this -> ncall
+ this -> selfcalls
;
545 long thatcalls
= that
-> ncall
+ that
-> selfcalls
;
547 if ( thistime
> thattime
) {
550 if ( thistime
< thattime
) {
553 if ( thiscalls
> thatcalls
) {
556 if ( thiscalls
< thatcalls
) {
562 * compare two arcs to/from the same child/parent.
563 * - if one arc is a self arc, it's least.
564 * - if one arc is within a cycle, it's less than.
565 * - if both arcs are within a cycle, compare arc counts.
566 * - if neither arc is within a cycle, compare with
567 * arc_time + arc_childtime as major key
568 * arc count as minor key
571 arccmp(arctype
*thisp
, arctype
*thatp
)
573 nltype
*thisparentp
= thisp
-> arc_parentp
;
574 nltype
*thischildp
= thisp
-> arc_childp
;
575 nltype
*thatparentp
= thatp
-> arc_parentp
;
576 nltype
*thatchildp
= thatp
-> arc_childp
;
581 if ( debug
& TIMEDEBUG
) {
582 printf( "[arccmp] " );
583 printname( thisparentp
);
585 printname ( thischildp
);
586 printf( " %f + %f %d/%d\n" ,
587 thisp
-> arc_time
, thisp
-> arc_childtime
,
588 thisp
-> arc_count
, thischildp
-> ncall
);
589 printf( "[arccmp] " );
590 printname( thatparentp
);
592 printname( thatchildp
);
593 printf( " %f + %f %d/%d\n" ,
594 thatp
-> arc_time
, thatp
-> arc_childtime
,
595 thatp
-> arc_count
, thatchildp
-> ncall
);
599 if ( thisparentp
== thischildp
) {
600 /* this is a self call */
603 if ( thatparentp
== thatchildp
) {
604 /* that is a self call */
607 if ( thisparentp
-> cycleno
!= 0 && thischildp
-> cycleno
!= 0 &&
608 thisparentp
-> cycleno
== thischildp
-> cycleno
) {
609 /* this is a call within a cycle */
610 if ( thatparentp
-> cycleno
!= 0 && thatchildp
-> cycleno
!= 0 &&
611 thatparentp
-> cycleno
== thatchildp
-> cycleno
) {
612 /* that is a call within the cycle, too */
613 if ( thisp
-> arc_count
< thatp
-> arc_count
) {
616 if ( thisp
-> arc_count
> thatp
-> arc_count
) {
621 /* that isn't a call within the cycle */
625 /* this isn't a call within a cycle */
626 if ( thatparentp
-> cycleno
!= 0 && thatchildp
-> cycleno
!= 0 &&
627 thatparentp
-> cycleno
== thatchildp
-> cycleno
) {
628 /* that is a call within a cycle */
631 /* neither is a call within a cycle */
632 thistime
= thisp
-> arc_time
+ thisp
-> arc_childtime
;
633 thattime
= thatp
-> arc_time
+ thatp
-> arc_childtime
;
634 if ( thistime
< thattime
)
636 if ( thistime
> thattime
)
638 if ( thisp
-> arc_count
< thatp
-> arc_count
)
640 if ( thisp
-> arc_count
> thatp
-> arc_count
)
647 printblurb(char *blurbname
)
652 blurbfile
= fopen( blurbname
, "r" );
653 if ( blurbfile
== NULL
) {
657 while ( ( input
= getc( blurbfile
) ) != EOF
) {
664 namecmp(nltype
**npp1
, nltype
**npp2
)
666 return( strcmp( (*npp1
) -> name
, (*npp2
) -> name
) );
671 nltype
**namesortnlp
;
673 int index
, nnames
, todo
, i
, j
;
674 char peterbuffer
[ BUFSIZ
];
677 * Now, sort regular function name alphbetically
678 * to create an index.
680 namesortnlp
= (nltype
**) calloc( nname
+ ncycle
, sizeof(nltype
*) );
681 if ( namesortnlp
== NULL
) {
682 warnx("ran out of memory for sorting");
684 for ( index
= 0 , nnames
= 0 ; index
< nname
; index
++ ) {
685 if ( zflag
== 0 && nl
[index
].ncall
== 0 && nl
[index
].time
== 0 )
687 namesortnlp
[nnames
++] = &nl
[index
];
689 qsort( namesortnlp
, nnames
, sizeof(nltype
*) , namecmp
);
690 for ( index
= 1 , todo
= nnames
; index
<= ncycle
; index
++ ) {
691 namesortnlp
[todo
++] = &cyclenl
[index
];
693 printf( "\f\nIndex by function name\n\n" );
694 index
= ( todo
+ 2 ) / 3;
695 for ( i
= 0; i
< index
; i
++ ) {
696 for ( j
= i
; j
< todo
; j
+= index
) {
697 nlp
= namesortnlp
[ j
];
698 if ( nlp
-> printflag
) {
699 sprintf( peterbuffer
, "[%d]" , nlp
-> index
);
701 sprintf( peterbuffer
, "(%d)" , nlp
-> index
);
704 printf( "%6.6s %-19.19s" , peterbuffer
, nlp
-> name
);
706 printf( "%6.6s " , peterbuffer
);
707 sprintf( peterbuffer
, "<cycle %d>" , nlp
-> cycleno
);
708 printf( "%-19.19s" , peterbuffer
);