2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 /* $OpenBSD: printgprof.c,v 1.2 1996/06/26 05:33:59 deraadt Exp $ */
24 /* $NetBSD: printgprof.c,v 1.5 1995/04/19 07:16:21 cgd Exp $ */
27 * Copyright (c) 1983, 1993
28 * The Regents of the University of California. All rights reserved.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 #include "stuff/errors.h"
66 static void flatprofheader(
69 static void flatprofline(
72 static void gprofheader(
75 static void gprofline(
78 static void printparents(
81 static void printchildren(
84 static void sortchildren(
87 static void sortparents(
90 static void printcycle(
93 static void printmembers(
96 static void sortmembers(
107 static void printblurb(
126 * Sort the symbol table in by time.
128 sortednlp
= (nltype
**)calloc(nname
, sizeof(nltype
*));
129 if(sortednlp
== (nltype
**)0)
130 fatal("[printprof] ran out of memory for time sorting");
131 for(index
= 0; index
< nname
; index
+= 1){
132 sortednlp
[index
] = &nl
[index
];
134 qsort(sortednlp
, nname
, sizeof(nltype
*),
135 (int (*)(const void *, const void *))timecmp
);
136 for(index
= 0; index
< nname
; index
+= 1){
137 np
= sortednlp
[index
];
153 timediff
= (*npp2
)->time
- (*npp1
)->time
;
158 calldiff
= (*npp2
)->ncall
- (*npp1
)->ncall
;
163 return(strcmp((*npp1
)->name
, (*npp2
)->name
));
167 * header for flatprofline
176 printblurb(FLAT_BLURB
);
178 printf("\ngranularity: each sample hit covers %lu byte(s)",
179 (long)sample_sets
->scale
* sizeof(UNIT
) );
181 printf(" for %.2f%% of %.2f seconds\n\n",
182 100.0/totime
, totime
/ hz
);
185 printf(" no time accumulated\n\n");
187 * this doesn't hurt since all the numerators will be zero.
191 printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
192 "% ", "cumulative", "self ", "", "self ", "total ", "");
193 printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
194 "time", "seconds ", "seconds", "calls",
195 "ms/call", "ms/call", "name");
203 if(zflag
== FALSE
&& np
->ncall
== 0 && np
->time
== 0){
207 printf("%5.1f %10.2f %8.2f",
208 100 * np
->time
/ totime
, actime
/ hz
, np
->time
/ hz
);
210 printf(" %8ld %8.2f %8.2f ", np
->ncall
,
211 1000 * np
->time
/ hz
/ np
->ncall
,
212 1000 * (np
->time
+ np
->childtime
) / hz
/ np
->ncall
);
215 printf(" %8.8s %8.8s %8.8s ", "", "", "");
227 printblurb(CALLG_BLURB
);
229 printf("\ngranularity: each sample hit covers %lu byte(s)",
230 (long)sample_sets
->scale
* sizeof(UNIT
));
232 printf(" for %.2f%% of %.2f seconds\n\n",
233 100.0 / printtime
, printtime
/ hz
);
236 printf(" no time propagated\n\n");
238 * this doesn't hurt, since all the numerators will be 0.0
242 printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
243 "", "", "", "", "called", "total", "parents");
244 printf("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n",
245 "index", "%time", "self", "descendents",
246 "called", "self", "name", "index");
247 printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
248 "", "", "", "", "called", "total", "children");
257 char kirkbuffer
[BUFSIZ
];
259 sprintf(kirkbuffer
, "[%d]", np
->index
);
260 printf("%-6.6s %5.1f %7.2f %11.2f",
262 100 * ( np
-> propself
+ np
-> propchild
) / printtime
,
263 np
-> propself
/ hz
,
264 np
-> propchild
/ hz
);
265 if((np
->ncall
+ np
->selfcalls
) != 0){
266 printf(" %7ld", np
->ncall
);
267 if(np
->selfcalls
!= 0)
268 printf("+%-7ld", np
->selfcalls
);
270 printf(" %7.7s ", "");
273 printf(" %7.7s %7.7s ", "", "");
281 nltype
**timesortnlp
)
287 * Print out the structured profiling list
290 for(index
= 0; index
< nname
+ ncycle
; index
++){
291 parentp
= timesortnlp
[index
];
293 parentp
->ncall
== 0 &&
294 parentp
->selfcalls
== 0 &&
295 parentp
->propself
== 0 &&
296 parentp
->propchild
== 0 ){
299 if(!parentp
->printflag
){
302 if(parentp
->name
== 0 && parentp
->cycleno
!= 0){
307 printmembers(parentp
);
310 printparents(parentp
);
312 printchildren(parentp
);
315 printf("-----------------------------------------------\n");
322 * sort by decreasing propagated time
323 * if times are equal, but one is a cycle header,
324 * say that's first (e.g. less, i.e. -1).
325 * if one's name doesn't have an underscore and the other does,
326 * say the one is first.
327 * all else being equal, sort by names.
339 diff
= (np1
->propself
+ np1
->propchild
)
340 - (np2
->propself
+ np2
->propchild
);
345 if(np1
->name
== 0 && np1
->cycleno
!= 0)
347 if(np2
->name
== 0 && np2
->cycleno
!= 0)
353 if(*(np1
->name
) != '_' && *(np2
->name
) == '_')
355 if(*(np1
->name
) == '_' && *(np2
->name
) != '_')
357 if(np1
->ncall
> np2
->ncall
)
359 if(np1
->ncall
< np2
->ncall
)
361 return(strcmp(np1
->name
, np2
->name
));
373 if(childp
->cyclehead
!= 0){
374 cycleheadp
= childp
->cyclehead
;
379 if(childp
->parents
== 0){
380 printf("%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s <spontaneous>\n",
381 "" , "" , "" , "" , "" , "" );
385 for(arcp
= childp
->parents
; arcp
; arcp
= arcp
->arc_parentlist
){
386 parentp
= arcp
->arc_parentp
;
387 if(childp
== parentp
||
388 (childp
->cycleno
!= 0 && parentp
->cycleno
== childp
->cycleno
)){
390 * selfcall or call among siblings
392 printf("%6.6s %5.5s %7.7s %11.11s %7ld %7.7s ",
393 "" , "" , "" , "", arcp
->arc_count
, "");
399 * regular parent of child
401 printf("%6.6s %5.5s %7.2f %11.2f %7ld/%-7ld ",
403 arcp
->arc_time
/ hz
, arcp
->arc_childtime
/ hz
,
404 arcp
->arc_count
, cycleheadp
->ncall
);
419 sortchildren(parentp
);
420 arcp
= parentp
->children
;
421 for(arcp
= parentp
->children
; arcp
; arcp
= arcp
->arc_childlist
){
422 childp
= arcp
->arc_childp
;
423 if(childp
== parentp
||
424 (childp
->cycleno
!= 0 && childp
->cycleno
== parentp
->cycleno
)){
426 * self call or call to sibling
428 printf("%6.6s %5.5s %7.7s %11.11s %7ld %7.7s ",
429 "", "", "", "", arcp
->arc_count
, "");
435 * regular child of parent
437 printf("%6.6s %5.5s %7.2f %11.2f %7ld/%-7ld ",
439 arcp
->arc_time
/ hz
, arcp
->arc_childtime
/ hz
,
440 arcp
->arc_count
, childp
->cyclehead
->ncall
);
452 if(selfp
->name
!= NULL
){
453 printf("%s", selfp
->name
);
455 if(debug
& DFNDEBUG
){
456 printf("{%d} ", selfp
->toporder
);
458 if(debug
& PROPDEBUG
){
459 printf("%5.2f%% ", selfp
->propfraction
);
463 if(selfp
->cycleno
!= 0){
464 printf(" <cycle %d>", selfp
->cycleno
);
466 if(selfp
->index
!= 0){
467 if(selfp
->printflag
){
468 printf(" [%d]", selfp
->index
);
470 printf(" (%d)", selfp
->index
);
487 * unlink children from parent,
488 * then insertion sort back on to sorted's children.
489 * *arcp the arc you have detached and are inserting.
490 * *detachedp the rest of the arcs to be sorted.
491 * sorted arc list onto which you insertion sort.
492 * *prevp arc before the arc you are comparing.
494 sorted
.arc_childlist
= 0;
496 for((arcp
= parentp
->children
) && (detachedp
= arcp
->arc_childlist
);
498 (arcp
= detachedp
) && (detachedp
= detachedp
->arc_childlist
)){
500 if((arcp
= parentp
->children
) != NULL
)
501 detachedp
= arcp
->arc_childlist
;
504 * consider *arcp as disconnected
505 * insert it into sorted
508 prevp
->arc_childlist
;
509 prevp
= prevp
->arc_childlist
){
510 if(arccmp(arcp
, prevp
->arc_childlist
) != LESSTHAN
){
514 arcp
->arc_childlist
= prevp
->arc_childlist
;
515 prevp
->arc_childlist
= arcp
;
516 if((arcp
= detachedp
) != NULL
)
517 detachedp
= detachedp
->arc_childlist
;
520 * reattach sorted children to parent
522 parentp
->children
= sorted
.arc_childlist
;
537 * unlink parents from child,
538 * then insertion sort back on to sorted's parents.
539 * *arcp the arc you have detached and are inserting.
540 * *detachedp the rest of the arcs to be sorted.
541 * sorted arc list onto which you insertion sort.
542 * *prevp arc before the arc you are comparing.
544 sorted
.arc_parentlist
= 0;
546 for((arcp
= childp
->parents
) && (detachedp
= arcp
->arc_parentlist
);
548 (arcp
= detachedp
) && (detachedp
= detachedp
->arc_parentlist
)){
550 if((arcp
= childp
->parents
) != NULL
)
551 detachedp
= arcp
->arc_parentlist
;
554 * consider *arcp as disconnected
555 * insert it into sorted
558 prevp
->arc_parentlist
;
559 prevp
= prevp
->arc_parentlist
){
560 if(arccmp(arcp
, prevp
->arc_parentlist
) != GREATERTHAN
){
564 arcp
->arc_parentlist
= prevp
->arc_parentlist
;
565 prevp
->arc_parentlist
= arcp
;
566 if((arcp
= detachedp
) != NULL
)
567 detachedp
= detachedp
->arc_parentlist
;
570 * reattach sorted arcs to child
572 childp
->parents
= sorted
.arc_parentlist
;
576 * print a cycle header
583 char kirkbuffer
[BUFSIZ
];
585 sprintf(kirkbuffer
, "[%d]", cyclep
->index
);
586 printf("%-6.6s %5.1f %7.2f %11.2f %7ld",
588 100 * (cyclep
->propself
+ cyclep
->propchild
) / printtime
,
589 cyclep
->propself
/ hz
,
590 cyclep
->propchild
/ hz
,
592 if(cyclep
->selfcalls
!= 0){
593 printf("+%-7ld", cyclep
->selfcalls
);
596 printf(" %7.7s", "");
598 printf(" <cycle %d as a whole>\t[%d]\n",
599 cyclep
->cycleno
, cyclep
->index
);
603 * print the members of a cycle
613 for(memberp
= cyclep
->cnext
; memberp
; memberp
= memberp
->cnext
){
614 printf("%6.6s %5.5s %7.2f %11.2f %7ld",
615 "", "", memberp
->propself
/ hz
, memberp
->propchild
/ hz
,
617 if(memberp
->selfcalls
!= 0){
618 printf("+%-7ld", memberp
->selfcalls
);
621 printf(" %7.7s", "");
630 * sort members of a cycle
642 * detach cycle members from cyclehead,
643 * and insertion sort them back on.
645 todo
= cyclep
->cnext
;
648 for((doing
= todo
) && (todo
= doing
->cnext
);
650 (doing
= todo
) && (todo
= doing
->cnext
)){
652 if((doing
= todo
) != NULL
)
654 while(doing
!= NULL
){
655 for(prev
= cyclep
; prev
->cnext
; prev
= prev
->cnext
){
656 if(membercmp(doing
, prev
->cnext
) == GREATERTHAN
){
660 doing
->cnext
= prev
->cnext
;
662 if((doing
= todo
) != NULL
)
668 * major sort is on propself + propchild,
669 * next is sort on ncalls + selfcalls.
677 double thistime
, thattime
;
678 long thiscalls
, thatcalls
;
680 thistime
= this->propself
+ this->propchild
;
681 thattime
= that
->propself
+ that
->propchild
;
682 thiscalls
= this->ncall
+ this->selfcalls
;
683 thatcalls
= that
->ncall
+ that
->selfcalls
;
685 if(thistime
> thattime
){
688 if(thistime
< thattime
){
691 if(thiscalls
> thatcalls
){
694 if(thiscalls
< thatcalls
){
700 * compare two arcs to/from the same child/parent.
701 * - if one arc is a self arc, it's least.
702 * - if one arc is within a cycle, it's less than.
703 * - if both arcs are within a cycle, compare arc counts.
704 * - if neither arc is within a cycle, compare with
705 * arc_time + arc_childtime as major key
706 * arc count as minor key
714 nltype
*thisparentp
, *thischildp
, *thatparentp
, *thatchildp
;
715 double thistime
, thattime
;
717 thisparentp
= thisp
->arc_parentp
;
718 thischildp
= thisp
->arc_childp
;
719 thatparentp
= thatp
->arc_parentp
;
720 thatchildp
= thatp
->arc_childp
;
723 if(debug
& TIMEDEBUG
){
725 printname(thisparentp
);
727 printname(thischildp
);
728 printf(" %f + %f %ld/%ld\n",
729 thisp
->arc_time
, thisp
->arc_childtime
,
730 thisp
->arc_count
, thischildp
->ncall
);
732 printname(thatparentp
);
734 printname(thatchildp
);
735 printf(" %f + %f %ld/%ld\n",
736 thatp
->arc_time
, thatp
->arc_childtime
,
737 thatp
->arc_count
, thatchildp
->ncall
);
741 if(thisparentp
== thischildp
){
742 /* this is a self call */
745 if(thatparentp
== thatchildp
){
746 /* that is a self call */
749 if(thisparentp
->cycleno
!= 0 && thischildp
->cycleno
!= 0 &&
750 thisparentp
->cycleno
== thischildp
->cycleno
){
751 /* this is a call within a cycle */
752 if(thatparentp
->cycleno
!= 0 && thatchildp
->cycleno
!= 0 &&
753 thatparentp
->cycleno
== thatchildp
->cycleno
){
754 /* that is a call within the cycle, too */
755 if(thisp
->arc_count
< thatp
->arc_count
){
758 if(thisp
->arc_count
> thatp
->arc_count
){
764 /* that isn't a call within the cycle */
769 /* this isn't a call within a cycle */
770 if(thatparentp
->cycleno
!= 0 && thatchildp
->cycleno
!= 0 &&
771 thatparentp
->cycleno
== thatchildp
->cycleno
){
772 /* that is a call within a cycle */
776 /* neither is a call within a cycle */
777 thistime
= thisp
->arc_time
+ thisp
->arc_childtime
;
778 thattime
= thatp
->arc_time
+ thatp
->arc_childtime
;
779 if(thistime
< thattime
)
781 if(thistime
> thattime
)
783 if(thisp
->arc_count
< thatp
->arc_count
)
785 if(thisp
->arc_count
> thatp
->arc_count
)
800 blurbfile
= fopen(blurbname
, "r");
801 if(blurbfile
== NULL
){
805 while((input
= getc(blurbfile
)) != EOF
){
817 return(strcmp((*npp1
)->name
, (*npp2
)->name
));
824 nltype
**namesortnlp
;
826 unsigned long index
, nnames
, todo
, i
, j
;
827 char peterbuffer
[BUFSIZ
];
830 * Now, sort regular function name alphbetically
831 * to create an index.
833 namesortnlp
= (nltype
**)calloc(nname
+ ncycle
, sizeof(nltype
*));
834 if(namesortnlp
== NULL
)
835 fatal("ran out of memory for sorting");
837 for(index
= 0, nnames
= 0; index
< nname
; index
++){
838 if(zflag
== 0 && nl
[index
].ncall
== 0 && nl
[index
].time
== 0)
840 namesortnlp
[nnames
++] = &nl
[index
];
842 qsort(namesortnlp
, nnames
, sizeof(nltype
*),
843 (int (*)(const void *, const void *))namecmp
);
844 for(index
= 1, todo
= nnames
; index
<= (unsigned long)ncycle
; index
++){
845 namesortnlp
[todo
++] = &cyclenl
[index
];
847 printf("\f\nIndex by function name\n\n");
848 index
= ( todo
+ 2 ) / 3;
849 for(i
= 0; i
< index
; i
++){
850 for(j
= i
; j
< todo
; j
+= index
){
851 nlp
= namesortnlp
[j
];
853 sprintf(peterbuffer
, "[%d]", nlp
->index
);
856 sprintf(peterbuffer
, "(%d)", nlp
->index
);
859 printf("%6.6s %-19.19s", peterbuffer
, nlp
->name
);
862 printf("%6.6s ", peterbuffer
);
863 sprintf(peterbuffer
, "<cycle %d>", nlp
->cycleno
);
864 printf("%-19.19s", peterbuffer
);