4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <sys/param.h>
36 void print_demangled_name(int, nltype
*);
37 void striped_name(char *, nltype
**);
42 * Symbols that must never be printed, no matter what.
51 static bool is_special_sym(nltype
*nlp
);
54 demangled_name(nltype
*selfp
)
59 return (conv_demangle_name(selfp
->name
));
68 int print_count
= number_funcs_toprint
;
69 bool print_flag
= TRUE
;
73 (void) printf("\f\n");
77 * Sort the symbol table in by time
79 sortednlp
= (nltype
**) calloc(total_names
, sizeof (nltype
*));
80 if (sortednlp
== (nltype
**) 0) {
81 (void) fprintf(stderr
,
82 "[printprof] ran out of memory for time sorting\n");
86 for (mi
= &modules
; mi
; mi
= mi
->next
) {
87 for (i
= 0; i
< mi
->nname
; i
++)
88 sortednlp
[index
++] = &(mi
->nl
[i
]);
91 qsort(sortednlp
, total_names
, sizeof (nltype
*), timecmp
);
93 for (index
= 0; (index
< total_names
) && print_flag
; index
+= 1) {
94 np
= sortednlp
[index
];
97 if (--print_count
== 0)
106 timecmp(const void *arg1
, const void *arg2
)
108 nltype
**npp1
= (nltype
**)arg1
;
109 nltype
**npp2
= (nltype
**)arg2
;
113 timediff
= (*npp2
)->time
- (*npp1
)->time
;
121 calldiff
= (*npp2
)->ncall
- (*npp1
)->ncall
;
129 return (strcmp((*npp1
)->name
, (*npp2
)->name
));
133 * header for flatprofline
140 printblurb(FLAT_BLURB
);
144 "\ngranularity: each sample hit covers %d byte(s)",
145 (long)scale
* sizeof (UNIT
));
147 (void) printf(" for %.2f%% of %.2f seconds\n\n",
148 100.0/totime
, totime
/ hz
);
150 (void) printf(" no time accumulated\n\n");
152 * this doesn't hurt since all the numerators will
159 (void) printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
160 "% ", "cumulative", "self ", "", "self ", "total ", "");
161 (void) printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
162 "time", "seconds ", "seconds", "calls",
163 "ms/call", "ms/call", "name");
167 flatprofline(nltype
*np
)
169 if (zflag
== 0 && np
->ncall
== 0 && np
->time
== 0)
173 * Do not print certain special symbols, like PRF_EXTSYM, etc.
174 * even if zflag was on.
176 if (is_special_sym(np
))
181 (void) printf("%5.1f %10.2f %8.2f",
182 100 * np
->time
/ totime
, actime
/ hz
, np
->time
/ hz
);
184 if (np
->ncall
!= 0) {
185 (void) printf(" %8lld %8.2f %8.2f ", np
->ncall
,
186 1000 * np
->time
/ hz
/ np
->ncall
,
187 1000 * (np
->time
+ np
->childtime
) / hz
/ np
->ncall
);
190 (void) printf(" %8.8s %8.8s %8.8s ", "", "", "");
192 (void) printf(" %8.8s %8.8s %8.8s ", "", "", "");
198 print_demangled_name(55, np
);
208 printblurb(CALLG_BLURB
);
213 "\ngranularity: each sample hit covers %d byte(s)",
214 (long)scale
* sizeof (UNIT
));
216 if (printtime
> 0.0) {
217 (void) printf(" for %.2f%% of %.2f seconds\n\n",
218 100.0/printtime
, printtime
/ hz
);
220 (void) printf(" no time propagated\n\n");
222 * this doesn't hurt, since all the numerators
229 "\ngranularity: each pc-hit is considered 1 tick");
231 (void) printf(" (@ %4.3f seconds per tick)",
237 (void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
238 "", "", "", "", "called", "total", "parents");
239 (void) printf("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n",
240 "index", "%time", "self", "descendents",
241 "called", "self", "name", "index");
242 (void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
243 "", "", "", "", "called", "total", "children");
248 gprofline(nltype
*np
)
250 char kirkbuffer
[BUFSIZ
];
252 (void) sprintf(kirkbuffer
, "[%d]", np
->index
);
253 (void) printf("%-6.6s %5.1f %7.2f %11.2f", kirkbuffer
,
254 100 * (np
->propself
+ np
->propchild
) / printtime
,
255 np
->propself
/ hz
, np
->propchild
/ hz
);
257 if ((np
->ncall
+ np
->selfcalls
) != 0) {
258 (void) printf(" %7lld", np
->ncall
);
260 if (np
->selfcalls
!= 0)
261 (void) printf("+%-7lld ", np
->selfcalls
);
263 (void) printf(" %7.7s ", "");
265 (void) printf(" %7.7s %7.7s ", "", "");
271 print_demangled_name(50, np
);
277 is_special_sym(nltype
*nlp
)
281 if (nlp
->name
== NULL
)
284 for (i
= 0; splsym
[i
]; i
++)
285 if (strcmp(splsym
[i
], nlp
->name
) == 0)
292 printgprof(nltype
**timesortnlp
)
296 int print_count
= number_funcs_toprint
;
297 bool count_flag
= TRUE
;
300 * Print out the structured profiling list
304 for (index
= 0; index
< total_names
+ ncycle
&& count_flag
; index
++) {
305 parentp
= timesortnlp
[index
];
306 if (zflag
== 0 && parentp
->ncall
== 0 &&
307 parentp
->selfcalls
== 0 && parentp
->propself
== 0 &&
308 parentp
-> propchild
== 0)
311 if (!parentp
->printflag
)
315 * Do not print certain special symbols, like PRF_EXTSYM, etc.
316 * even if zflag was on.
318 if (is_special_sym(parentp
))
321 if (parentp
->name
== 0 && parentp
->cycleno
!= 0) {
326 printmembers(parentp
);
328 printparents(parentp
);
330 printchildren(parentp
);
335 "-----------------------------------------------\n");
340 if (print_count
== 0)
348 * sort by decreasing propagated time
349 * if times are equal, but one is a cycle header,
350 * say that's first (e.g. less, i.e. -1).
351 * if one's name doesn't have an underscore and the other does,
352 * say the one is first.
353 * all else being equal, sort by names.
356 totalcmp(const void *arg1
, const void *arg2
)
358 nltype
**npp1
= (nltype
**)arg1
;
359 nltype
**npp2
= (nltype
**)arg2
;
364 diff
= (np1
->propself
+ np1
->propchild
) -
365 (np2
->propself
+ np2
->propchild
);
371 if (np1
->name
== 0 && np1
->cycleno
!= 0)
373 if (np2
->name
== 0 && np2
->cycleno
!= 0)
380 if (*(np1
->name
) != '_' && *(np2
->name
) == '_')
382 if (*(np1
->name
) == '_' && *(np2
->name
) != '_')
384 if (np1
->ncall
> np2
->ncall
)
386 if (np1
->ncall
< np2
->ncall
)
388 return (strcmp(np1
->name
, np2
->name
));
392 printparents(nltype
*childp
)
398 if (childp
->cyclehead
!= 0)
399 cycleheadp
= childp
-> cyclehead
;
403 if (childp
->parents
== 0) {
404 (void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s"
405 " <spontaneous>\n", "", "", "", "", "", "");
411 for (arcp
= childp
->parents
; arcp
; arcp
= arcp
->arc_parentlist
) {
412 parentp
= arcp
-> arc_parentp
;
413 if (childp
== parentp
|| (childp
->cycleno
!= 0 &&
414 parentp
->cycleno
== childp
->cycleno
)) {
416 * selfcall or call among siblings
419 "%6.6s %5.5s %7.7s %11.11s %7lld %7.7s ",
420 "", "", "", "", arcp
->arc_count
, "");
424 print_demangled_name(54, parentp
);
429 * regular parent of child
432 "%6.6s %5.5s %7.2f %11.2f %7lld/%-7lld ", "",
433 "", arcp
->arc_time
/ hz
, arcp
->arc_childtime
/ hz
,
434 arcp
->arc_count
, cycleheadp
->ncall
);
438 print_demangled_name(54, parentp
);
446 printchildren(nltype
*parentp
)
451 sortchildren(parentp
);
453 for (arcp
= parentp
->children
; arcp
; arcp
= arcp
->arc_childlist
) {
454 childp
= arcp
->arc_childp
;
455 if (childp
== parentp
|| (childp
->cycleno
!= 0 &&
456 childp
->cycleno
== parentp
->cycleno
)) {
458 * self call or call to sibling
461 "%6.6s %5.5s %7.7s %11.11s %7lld %7.7s ",
462 "", "", "", "", arcp
->arc_count
, "");
466 print_demangled_name(54, childp
);
471 * regular child of parent
473 if (childp
->cyclehead
)
474 (void) printf("%6.6s %5.5s %7.2f %11.2f "
475 "%7lld/%-7lld ", "", "",
477 arcp
->arc_childtime
/ hz
, arcp
->arc_count
,
478 childp
->cyclehead
->ncall
);
480 (void) printf("%6.6s %5.5s %7.2f %11.2f "
482 "", "", arcp
->arc_time
/ hz
,
483 arcp
->arc_childtime
/ hz
, arcp
->arc_count
,
489 print_demangled_name(54, childp
);
497 printname(nltype
*selfp
)
500 c
= demangled_name(selfp
);
502 if (selfp
->name
!= 0) {
504 (void) printf("%s", selfp
->name
);
506 (void) printf("%s", c
);
509 if (debug
& DFNDEBUG
)
510 (void) printf("{%d} ", selfp
->toporder
);
512 if (debug
& PROPDEBUG
)
513 (void) printf("%5.2f%% ", selfp
->propfraction
);
517 if (selfp
->cycleno
!= 0)
518 (void) printf("\t<cycle %d>", selfp
->cycleno
);
520 if (selfp
->index
!= 0) {
521 if (selfp
->printflag
)
522 (void) printf(" [%d]", selfp
->index
);
524 (void) printf(" (%d)", selfp
->index
);
529 print_demangled_name(int n
, nltype
*selfp
)
536 if (strcmp(c
, demangled_name(selfp
)) == 0)
540 for (i
= 1; i
< n
; i
++)
542 (void) printf("[%s]", selfp
->name
);
547 sortchildren(nltype
*parentp
)
555 * unlink children from parent,
556 * then insertion sort back on to sorted's children.
557 * *arcp the arc you have detached and are inserting.
558 * *detachedp the rest of the arcs to be sorted.
559 * sorted arc list onto which you insertion sort.
560 * *prevp arc before the arc you are comparing.
562 sorted
.arc_childlist
= 0;
564 /* LINTED: warning: assignment operator */
565 for ((arcp
= parentp
->children
) && (detachedp
= arcp
->arc_childlist
);
567 /* LINTED: warning: assignment operator */
568 (arcp
= detachedp
) && (detachedp
= detachedp
->arc_childlist
)) {
570 * consider *arcp as disconnected
571 * insert it into sorted
573 for (prevp
= &sorted
; prevp
->arc_childlist
;
574 prevp
= prevp
->arc_childlist
) {
575 if (arccmp(arcp
, prevp
->arc_childlist
) != LESSTHAN
)
579 arcp
->arc_childlist
= prevp
->arc_childlist
;
580 prevp
->arc_childlist
= arcp
;
584 * reattach sorted children to parent
586 parentp
->children
= sorted
.arc_childlist
;
590 sortparents(nltype
*childp
)
598 * unlink parents from child,
599 * then insertion sort back on to sorted's parents.
600 * *arcp the arc you have detached and are inserting.
601 * *detachedp the rest of the arcs to be sorted.
602 * sorted arc list onto which you insertion sort.
603 * *prevp arc before the arc you are comparing.
605 sorted
.arc_parentlist
= 0;
607 /* LINTED: warning: assignment operator */
608 for ((arcp
= childp
->parents
) && (detachedp
= arcp
->arc_parentlist
);
610 /* LINTED: warning: assignment operator */
611 (arcp
= detachedp
) && (detachedp
= detachedp
->arc_parentlist
)) {
613 * consider *arcp as disconnected
614 * insert it into sorted
616 for (prevp
= &sorted
; prevp
->arc_parentlist
;
617 prevp
= prevp
->arc_parentlist
) {
618 if (arccmp(arcp
, prevp
->arc_parentlist
) != GREATERTHAN
)
621 arcp
->arc_parentlist
= prevp
->arc_parentlist
;
622 prevp
->arc_parentlist
= arcp
;
626 * reattach sorted arcs to child
628 childp
->parents
= sorted
.arc_parentlist
;
632 printcycle(nltype
*cyclep
)
634 char kirkbuffer
[BUFSIZ
];
636 (void) sprintf(kirkbuffer
, "[%d]", cyclep
->index
);
637 (void) printf("%-6.6s %5.1f %7.2f %11.2f %7lld", kirkbuffer
,
638 100 * (cyclep
->propself
+ cyclep
->propchild
) / printtime
,
639 cyclep
-> propself
/ hz
, cyclep
-> propchild
/ hz
,
642 if (cyclep
->selfcalls
!= 0)
643 (void) printf("+%-7lld", cyclep
->selfcalls
);
645 (void) printf(" %7.7s", "");
647 (void) printf(" <cycle %d as a whole>\t[%d]\n", cyclep
->cycleno
,
652 * print the members of a cycle
655 printmembers(nltype
*cyclep
)
661 for (memberp
= cyclep
->cnext
; memberp
; memberp
= memberp
->cnext
) {
662 (void) printf("%6.6s %5.5s %7.2f %11.2f %7lld", "", "",
663 memberp
->propself
/ hz
, memberp
->propchild
/ hz
,
666 if (memberp
->selfcalls
!= 0)
667 (void) printf("+%-7lld", memberp
->selfcalls
);
669 (void) printf(" %7.7s", "");
674 print_demangled_name(54, memberp
);
680 * sort members of a cycle
683 sortmembers(nltype
*cyclep
)
690 * detach cycle members from cyclehead,
691 * and insertion sort them back on.
693 todo
= cyclep
->cnext
;
696 /* LINTED: warning: assignment operator */
697 for ((doing
= todo
) && (todo
= doing
->cnext
);
699 /* LINTED: warning: assignment operator */
700 (doing
= todo
) && (todo
= doing
->cnext
)) {
701 for (prev
= cyclep
; prev
->cnext
; prev
= prev
->cnext
) {
702 if (membercmp(doing
, prev
->cnext
) == GREATERTHAN
)
705 doing
->cnext
= prev
->cnext
;
711 * major sort is on propself + propchild,
712 * next is sort on ncalls + selfcalls.
715 membercmp(nltype
*this, nltype
*that
)
717 double thistime
= this->propself
+ this->propchild
;
718 double thattime
= that
->propself
+ that
->propchild
;
719 actype thiscalls
= this->ncall
+ this->selfcalls
;
720 actype thatcalls
= that
->ncall
+ that
->selfcalls
;
722 if (thistime
> thattime
)
723 return (GREATERTHAN
);
725 if (thistime
< thattime
)
728 if (thiscalls
> thatcalls
)
729 return (GREATERTHAN
);
731 if (thiscalls
< thatcalls
)
738 * compare two arcs to/from the same child/parent.
739 * - if one arc is a self arc, it's least.
740 * - if one arc is within a cycle, it's less than.
741 * - if both arcs are within a cycle, compare arc counts.
742 * - if neither arc is within a cycle, compare with
743 * arc_time + arc_childtime as major key
744 * arc count as minor key
747 arccmp(arctype
*thisp
, arctype
*thatp
)
749 nltype
*thisparentp
= thisp
->arc_parentp
;
750 nltype
*thischildp
= thisp
->arc_childp
;
751 nltype
*thatparentp
= thatp
->arc_parentp
;
752 nltype
*thatchildp
= thatp
->arc_childp
;
757 if (debug
& TIMEDEBUG
) {
758 (void) printf("[arccmp] ");
759 printname(thisparentp
);
760 (void) printf(" calls ");
761 printname(thischildp
);
762 (void) printf(" %f + %f %lld/%lld\n", thisp
->arc_time
,
763 thisp
->arc_childtime
, thisp
->arc_count
,
765 (void) printf("[arccmp] ");
766 printname(thatparentp
);
767 (void) printf(" calls ");
768 printname(thatchildp
);
769 (void) printf(" %f + %f %lld/%lld\n", thatp
->arc_time
,
770 thatp
->arc_childtime
, thatp
->arc_count
,
776 if (thisparentp
== thischildp
) {
778 * this is a self call
783 if (thatparentp
== thatchildp
) {
785 * that is a self call
787 return (GREATERTHAN
);
790 if (thisparentp
->cycleno
!= 0 && thischildp
->cycleno
!= 0 &&
791 thisparentp
->cycleno
== thischildp
->cycleno
) {
793 * this is a call within a cycle
795 if (thatparentp
->cycleno
!= 0 && thatchildp
->cycleno
!= 0 &&
796 thatparentp
->cycleno
== thatchildp
->cycleno
) {
798 * that is a call within the cycle, too
800 if (thisp
->arc_count
< thatp
->arc_count
)
803 if (thisp
->arc_count
> thatp
->arc_count
)
804 return (GREATERTHAN
);
809 * that isn't a call within the cycle
815 * this isn't a call within a cycle
817 if (thatparentp
->cycleno
!= 0 && thatchildp
->cycleno
!= 0 &&
818 thatparentp
->cycleno
== thatchildp
->cycleno
) {
820 * that is a call within a cycle
822 return (GREATERTHAN
);
825 * neither is a call within a cycle
827 thistime
= thisp
->arc_time
+ thisp
->arc_childtime
;
828 thattime
= thatp
->arc_time
+ thatp
->arc_childtime
;
830 if (thistime
< thattime
)
833 if (thistime
> thattime
)
834 return (GREATERTHAN
);
836 if (thisp
->arc_count
< thatp
->arc_count
)
839 if (thisp
->arc_count
> thatp
->arc_count
)
840 return (GREATERTHAN
);
848 printblurb(char *blurbname
)
853 blurbfile
= fopen(blurbname
, "r");
854 if (blurbfile
== NULL
) {
859 while ((input
= getc(blurbfile
)) != EOF
)
860 (void) putchar(input
);
862 (void) fclose(blurbfile
);
868 namecmp(const void *arg1
, const void *arg2
)
870 nltype
**npp1
= (nltype
**)arg1
;
871 nltype
**npp2
= (nltype
**)arg2
;
874 return (strcmp((*npp1
)->name
, (*npp2
)->name
));
876 striped_name(s1
, npp1
);
877 striped_name(s2
, npp2
);
878 return (strcmp(s1
, s2
));
883 striped_name(char *s
, nltype
**npp
)
889 d
= demangled_name(*npp
);
891 while ((*d
!= '(') && (*d
!= '\0')) {
901 * Checks if the current symbol name is the same as its neighbour and
902 * returns TRUE if it is.
905 does_clash(nltype
**nlp
, int ndx
, int nnames
)
908 * same as previous (if there's one) ?
910 if (ndx
&& (strcmp(nlp
[ndx
]->name
, nlp
[ndx
-1]->name
) == 0))
914 * same as next (if there's one) ?
916 if ((ndx
< (nnames
- 1)) &&
917 (strcmp(nlp
[ndx
]->name
, nlp
[ndx
+1]->name
) == 0)) {
929 (void) printf("\f\nObject modules\n\n");
930 for (mi
= &modules
; mi
; mi
= mi
->next
)
931 (void) printf(" %d: %s\n", mi
->id
, mi
->name
);
934 #define IDFMT(id) ((id) < 10 ? 1 : 2)
935 #define NMFMT(id) ((id) < 10 ? 17 : 16)
940 nltype
**namesortnlp
;
942 int index
, nnames
, todo
, i
, j
;
943 char peterbuffer
[BUFSIZ
];
947 * Now, sort regular function name alphabetically
948 * to create an index.
950 namesortnlp
= calloc(total_names
+ ncycle
, sizeof (nltype
*));
952 if (namesortnlp
== NULL
)
953 (void) fprintf(stderr
, "%s: ran out of memory for sorting\n",
957 for (mi
= &modules
; mi
; mi
= mi
->next
) {
958 for (index
= 0; index
< mi
->nname
; index
++) {
959 if (zflag
== 0 && (mi
->nl
[index
]).ncall
== 0 &&
960 (mi
->nl
[index
]).time
== 0) {
965 * Do not print certain special symbols, like
966 * PRF_EXTSYM, etc. even if zflag was on.
968 if (is_special_sym(&(mi
->nl
[index
])))
971 namesortnlp
[nnames
++] = &(mi
->nl
[index
]);
976 s1
= malloc(500 * sizeof (char));
977 s2
= malloc(500 * sizeof (char));
980 qsort(namesortnlp
, nnames
, sizeof (nltype
*), namecmp
);
982 for (index
= 1, todo
= nnames
; index
<= ncycle
; index
++)
983 namesortnlp
[todo
++] = &cyclenl
[index
];
985 (void) printf("\f\nIndex by function name\n\n");
988 index
= (todo
+ 2) / 3;
992 for (i
= 0; i
< index
; i
++) {
994 for (j
= i
; j
< todo
; j
+= index
) {
995 nlp
= namesortnlp
[j
];
997 if (nlp
->printflag
) {
998 (void) sprintf(peterbuffer
,
1001 (void) sprintf(peterbuffer
,
1002 "(%d)", nlp
->index
);
1006 if (does_clash(namesortnlp
,
1011 IDFMT(nlp
->module
->id
),
1013 NMFMT(nlp
->module
->id
),
1014 NMFMT(nlp
->module
->id
),
1017 (void) printf("%6.6s %-19.19s",
1018 peterbuffer
, nlp
->name
);
1021 (void) printf("%6.6s ", peterbuffer
);
1022 (void) sprintf(peterbuffer
,
1023 "<cycle %d>", nlp
->cycleno
);
1024 (void) printf("%-19.19s", peterbuffer
);
1028 nlp
= namesortnlp
[i
];
1031 (void) sprintf(peterbuffer
, "[%d]", nlp
->index
);
1033 (void) sprintf(peterbuffer
, "(%d)", nlp
->index
);
1036 const char *d
= demangled_name(nlp
);
1038 if (does_clash(namesortnlp
, i
, nnames
)) {
1039 (void) printf("%6.6s %d:%s\n",
1040 peterbuffer
, nlp
->module
->id
, d
);
1042 (void) printf("%6.6s %s\n", peterbuffer
,
1046 (void) printf("%6.6s [%s]", "",
1049 (void) printf("%6.6s ", peterbuffer
);
1050 (void) sprintf(peterbuffer
, "<cycle %d>",
1052 (void) printf("%-33.33s", peterbuffer
);
1055 (void) printf("\n");