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