Commit | Line | Data |
---|---|---|
3d6c6501 SEF |
1 | /* |
2 | * Copyright (c) 1983 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
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. | |
18 | */ | |
19 | ||
20 | #ifndef lint | |
21 | static char sccsid[] = "@(#)printgprof.c 5.7 (Berkeley) 6/1/90"; | |
22 | #endif /* not lint */ | |
23 | ||
24 | #include "gprof.h" | |
dc1d1ca5 | 25 | #include <demangle.h> |
3d6c6501 SEF |
26 | |
27 | printprof() | |
28 | { | |
29 | register nltype *np; | |
30 | nltype **sortednlp; | |
31 | int index, timecmp(); | |
32 | ||
33 | actime = 0.0; | |
dc1d1ca5 PB |
34 | if ( bsd_style_output ) { |
35 | printf( "\f\n" ); | |
36 | if ( bflag) { | |
37 | printf( "\n\n\nflat profile:\n" ); | |
38 | flat_blurb(stdout); | |
39 | } | |
40 | } | |
41 | else | |
42 | printf ("Flat profile:\n"); | |
3d6c6501 SEF |
43 | flatprofheader(); |
44 | /* | |
45 | * Sort the symbol table in by time | |
46 | */ | |
47 | sortednlp = (nltype **) calloc( nname , sizeof(nltype *) ); | |
48 | if ( sortednlp == (nltype **) 0 ) { | |
49 | fprintf( stderr , "[printprof] ran out of memory for time sorting\n" ); | |
50 | } | |
51 | for ( index = 0 ; index < nname ; index += 1 ) { | |
52 | sortednlp[ index ] = &nl[ index ]; | |
53 | } | |
54 | qsort( sortednlp , nname , sizeof(nltype *) , timecmp ); | |
55 | for ( index = 0 ; index < nname ; index += 1 ) { | |
56 | np = sortednlp[ index ]; | |
57 | flatprofline( np ); | |
58 | } | |
59 | actime = 0.0; | |
a67d9a42 | 60 | free( sortednlp ); |
dc1d1ca5 PB |
61 | if ( bflag && !bsd_style_output ) { |
62 | flat_blurb(stdout); | |
63 | } | |
3d6c6501 SEF |
64 | } |
65 | ||
66 | timecmp( npp1 , npp2 ) | |
67 | nltype **npp1, **npp2; | |
68 | { | |
69 | double timediff; | |
70 | long calldiff; | |
71 | ||
72 | timediff = (*npp2) -> time - (*npp1) -> time; | |
73 | if ( timediff > 0.0 ) | |
74 | return 1 ; | |
75 | if ( timediff < 0.0 ) | |
76 | return -1; | |
77 | calldiff = (*npp2) -> ncall - (*npp1) -> ncall; | |
78 | if ( calldiff > 0 ) | |
79 | return 1; | |
80 | if ( calldiff < 0 ) | |
81 | return -1; | |
82 | return( strcmp( (*npp1) -> name , (*npp2) -> name ) ); | |
83 | } | |
84 | ||
85 | /* | |
86 | * header for flatprofline | |
87 | */ | |
88 | flatprofheader() | |
89 | { | |
90 | ||
dc1d1ca5 PB |
91 | if (bsd_style_output) { |
92 | printf( "\ngranularity: each sample hit covers %d byte(s)" , | |
93 | (long) scale * sizeof(UNIT) ); | |
a051e7cc KR |
94 | if (totime > 0.0) |
95 | printf(" for %.2f%% of %.2f seconds\n\n", 100.0/totime, totime / hz); | |
dc1d1ca5 PB |
96 | } |
97 | else { | |
98 | printf( "\nEach sample counts as %g seconds.\n", | |
99 | 1.0 / hz); | |
3d6c6501 | 100 | } |
a051e7cc KR |
101 | if (totime <= 0.0) |
102 | { | |
103 | printf(" no time accumulated\n\n"); | |
104 | /* This doesn't hurt since all the numerators will be zero. */ | |
105 | totime = 1.0; | |
106 | } | |
3d6c6501 SEF |
107 | printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n" , |
108 | "% " , "cumulative" , "self " , "" , "self " , "total " , "" ); | |
109 | printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n" , | |
110 | "time" , "seconds " , "seconds" , "calls" , | |
111 | "ms/call" , "ms/call" , "name" ); | |
112 | } | |
113 | ||
114 | flatprofline( np ) | |
115 | register nltype *np; | |
116 | { | |
117 | ||
118 | if ( zflag == 0 && np -> ncall == 0 && np -> time == 0 ) { | |
119 | return; | |
120 | } | |
121 | actime += np -> time; | |
dc1d1ca5 PB |
122 | if (bsd_style_output) |
123 | printf( "%5.1f %10.2f %8.2f" , | |
124 | 100 * np -> time / totime , actime / hz , np -> time / hz ); | |
125 | else | |
126 | printf( "%6.2f %9.2f %8.2f" , | |
127 | 100 * np -> time / totime , actime / hz , np -> time / hz ); | |
3d6c6501 SEF |
128 | if ( np -> ncall != 0 ) { |
129 | printf( " %8d %8.2f %8.2f " , np -> ncall , | |
130 | 1000 * np -> time / hz / np -> ncall , | |
131 | 1000 * ( np -> time + np -> childtime ) / hz / np -> ncall ); | |
132 | } else { | |
133 | printf( " %8.8s %8.8s %8.8s " , "" , "" , "" ); | |
134 | } | |
dc1d1ca5 PB |
135 | if (bsd_style_output) |
136 | printname( np ); | |
137 | else | |
138 | printnameonly( np ); | |
3d6c6501 SEF |
139 | printf( "\n" ); |
140 | } | |
141 | ||
142 | gprofheader() | |
143 | { | |
144 | ||
dc1d1ca5 PB |
145 | if (!bsd_style_output) |
146 | if (bflag) | |
147 | printf ("\t\t Call graph (explanation follows)\n\n"); | |
148 | else | |
149 | printf ("\t\t\tCall graph\n\n"); | |
3d6c6501 SEF |
150 | printf( "\ngranularity: each sample hit covers %d byte(s)" , |
151 | (long) scale * sizeof(UNIT) ); | |
152 | if ( printtime > 0.0 ) { | |
153 | printf( " for %.2f%% of %.2f seconds\n\n" , | |
154 | 100.0/printtime , printtime / hz ); | |
155 | } else { | |
156 | printf( " no time propagated\n\n" ); | |
157 | /* | |
158 | * this doesn't hurt, since all the numerators will be 0.0 | |
159 | */ | |
160 | printtime = 1.0; | |
161 | } | |
dc1d1ca5 PB |
162 | if (bsd_style_output) { |
163 | printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" , | |
164 | "" , "" , "" , "" , "called" , "total" , "parents"); | |
165 | printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" , | |
166 | "index" , "%time" , "self" , "descendents" , | |
167 | "called" , "self" , "name" , "index" ); | |
168 | printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" , | |
169 | "" , "" , "" , "" , "called" , "total" , "children"); | |
170 | printf( "\n" ); | |
171 | } else { | |
172 | printf( "index %% time self children called name\n" ); | |
173 | } | |
3d6c6501 SEF |
174 | } |
175 | ||
176 | gprofline( np ) | |
177 | register nltype *np; | |
178 | { | |
179 | char kirkbuffer[ BUFSIZ ]; | |
180 | ||
181 | sprintf( kirkbuffer , "[%d]" , np -> index ); | |
dc1d1ca5 PB |
182 | printf(bsd_style_output |
183 | ? "%-6.6s %5.1f %7.2f %11.2f" | |
184 | : "%-6.6s %5.1f %7.2f %7.2f" , | |
185 | kirkbuffer , | |
186 | 100 * ( np -> propself + np -> propchild ) / printtime , | |
187 | np -> propself / hz , | |
188 | np -> propchild / hz ); | |
3d6c6501 SEF |
189 | if ( ( np -> ncall + np -> selfcalls ) != 0 ) { |
190 | printf( " %7d" , np -> ncall ); | |
191 | if ( np -> selfcalls != 0 ) { | |
192 | printf( "+%-7d " , np -> selfcalls ); | |
193 | } else { | |
194 | printf( " %7.7s " , "" ); | |
195 | } | |
196 | } else { | |
197 | printf( " %7.7s %7.7s " , "" , "" ); | |
198 | } | |
199 | printname( np ); | |
200 | printf( "\n" ); | |
201 | } | |
202 | ||
203 | printgprof(timesortnlp) | |
204 | nltype **timesortnlp; | |
205 | { | |
206 | int index; | |
207 | nltype *parentp; | |
208 | ||
209 | /* | |
210 | * Print out the structured profiling list | |
211 | */ | |
dc1d1ca5 | 212 | if ( bflag && bsd_style_output ) { |
3d3e494e | 213 | bsd_callg_blurb(stdout); |
dc1d1ca5 | 214 | } |
3d6c6501 SEF |
215 | gprofheader(); |
216 | for ( index = 0 ; index < nname + ncycle ; index ++ ) { | |
217 | parentp = timesortnlp[ index ]; | |
218 | if ( zflag == 0 && | |
219 | parentp -> ncall == 0 && | |
220 | parentp -> selfcalls == 0 && | |
221 | parentp -> propself == 0 && | |
222 | parentp -> propchild == 0 ) { | |
223 | continue; | |
224 | } | |
225 | if ( ! parentp -> printflag ) { | |
226 | continue; | |
227 | } | |
228 | if ( parentp -> name == 0 && parentp -> cycleno != 0 ) { | |
229 | /* | |
230 | * cycle header | |
231 | */ | |
232 | printcycle( parentp ); | |
233 | printmembers( parentp ); | |
234 | } else { | |
235 | printparents( parentp ); | |
236 | gprofline( parentp ); | |
237 | printchildren( parentp ); | |
238 | } | |
dc1d1ca5 PB |
239 | if (bsd_style_output) |
240 | printf( "\n" ); | |
3d6c6501 | 241 | printf( "-----------------------------------------------\n" ); |
dc1d1ca5 PB |
242 | if (bsd_style_output) |
243 | printf( "\n" ); | |
3d6c6501 | 244 | } |
a67d9a42 | 245 | free( timesortnlp ); |
dc1d1ca5 | 246 | if ( bflag && !bsd_style_output) { |
3d3e494e | 247 | fsf_callg_blurb(stdout); |
dc1d1ca5 | 248 | } |
3d6c6501 SEF |
249 | } |
250 | ||
251 | /* | |
252 | * sort by decreasing propagated time | |
253 | * if times are equal, but one is a cycle header, | |
254 | * say that's first (e.g. less, i.e. -1). | |
255 | * if one's name doesn't have an underscore and the other does, | |
256 | * say the one is first. | |
257 | * all else being equal, sort by names. | |
258 | */ | |
259 | int | |
260 | totalcmp( npp1 , npp2 ) | |
261 | nltype **npp1; | |
262 | nltype **npp2; | |
263 | { | |
264 | register nltype *np1 = *npp1; | |
265 | register nltype *np2 = *npp2; | |
266 | double diff; | |
267 | ||
268 | diff = ( np1 -> propself + np1 -> propchild ) | |
269 | - ( np2 -> propself + np2 -> propchild ); | |
270 | if ( diff < 0.0 ) | |
271 | return 1; | |
272 | if ( diff > 0.0 ) | |
273 | return -1; | |
274 | if ( np1 -> name == 0 && np1 -> cycleno != 0 ) | |
275 | return -1; | |
276 | if ( np2 -> name == 0 && np2 -> cycleno != 0 ) | |
277 | return 1; | |
278 | if ( np1 -> name == 0 ) | |
279 | return -1; | |
280 | if ( np2 -> name == 0 ) | |
281 | return 1; | |
282 | if ( *(np1 -> name) != '_' && *(np2 -> name) == '_' ) | |
283 | return -1; | |
284 | if ( *(np1 -> name) == '_' && *(np2 -> name) != '_' ) | |
285 | return 1; | |
286 | if ( np1 -> ncall > np2 -> ncall ) | |
287 | return -1; | |
288 | if ( np1 -> ncall < np2 -> ncall ) | |
289 | return 1; | |
290 | return strcmp( np1 -> name , np2 -> name ); | |
291 | } | |
292 | ||
293 | printparents( childp ) | |
294 | nltype *childp; | |
295 | { | |
296 | nltype *parentp; | |
297 | arctype *arcp; | |
298 | nltype *cycleheadp; | |
299 | ||
300 | if ( childp -> cyclehead != 0 ) { | |
301 | cycleheadp = childp -> cyclehead; | |
302 | } else { | |
303 | cycleheadp = childp; | |
304 | } | |
305 | if ( childp -> parents == 0 ) { | |
dc1d1ca5 PB |
306 | printf(bsd_style_output |
307 | ? "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s <spontaneous>\n" | |
308 | : "%6.6s %5.5s %7.7s %7.7s %7.7s %7.7s <spontaneous>\n" , | |
3d6c6501 SEF |
309 | "" , "" , "" , "" , "" , "" ); |
310 | return; | |
311 | } | |
312 | sortparents( childp ); | |
313 | for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) { | |
314 | parentp = arcp -> arc_parentp; | |
315 | if ( childp == parentp || | |
316 | ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) { | |
317 | /* | |
318 | * selfcall or call among siblings | |
319 | */ | |
dc1d1ca5 PB |
320 | printf(bsd_style_output |
321 | ? "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " | |
322 | : "%6.6s %5.5s %7.7s %7.7s %7d %7.7s " , | |
3d6c6501 SEF |
323 | "" , "" , "" , "" , |
324 | arcp -> arc_count , "" ); | |
325 | printname( parentp ); | |
326 | printf( "\n" ); | |
327 | } else { | |
328 | /* | |
329 | * regular parent of child | |
330 | */ | |
dc1d1ca5 PB |
331 | printf(bsd_style_output |
332 | ? "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " | |
333 | : "%6.6s %5.5s %7.2f %7.2f %7d/%-7d ", | |
3d6c6501 SEF |
334 | "" , "" , |
335 | arcp -> arc_time / hz , arcp -> arc_childtime / hz , | |
336 | arcp -> arc_count , cycleheadp -> ncall ); | |
337 | printname( parentp ); | |
338 | printf( "\n" ); | |
339 | } | |
340 | } | |
341 | } | |
342 | ||
343 | printchildren( parentp ) | |
344 | nltype *parentp; | |
345 | { | |
346 | nltype *childp; | |
347 | arctype *arcp; | |
348 | ||
349 | sortchildren( parentp ); | |
350 | arcp = parentp -> children; | |
351 | for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { | |
352 | childp = arcp -> arc_childp; | |
353 | if ( childp == parentp || | |
354 | ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) { | |
355 | /* | |
356 | * self call or call to sibling | |
357 | */ | |
dc1d1ca5 PB |
358 | printf(bsd_style_output |
359 | ? "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " | |
360 | : "%6.6s %5.5s %7.7s %7.7s %7d %7.7s " , | |
361 | "" , "" , "" , "" , arcp -> arc_count , "" ); | |
3d6c6501 SEF |
362 | printname( childp ); |
363 | printf( "\n" ); | |
364 | } else { | |
365 | /* | |
366 | * regular child of parent | |
367 | */ | |
dc1d1ca5 PB |
368 | printf(bsd_style_output |
369 | ? "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " | |
370 | : "%6.6s %5.5s %7.2f %7.2f %7d/%-7d " , | |
371 | "" , "" , | |
372 | arcp -> arc_time / hz , arcp -> arc_childtime / hz , | |
373 | arcp -> arc_count , childp -> cyclehead -> ncall ); | |
3d6c6501 SEF |
374 | printname( childp ); |
375 | printf( "\n" ); | |
376 | } | |
377 | } | |
378 | } | |
379 | ||
dc1d1ca5 PB |
380 | /* Print name of symbol. Return number of characters printed. */ |
381 | ||
382 | int | |
383 | printnameonly ( selfp ) | |
384 | nltype *selfp; | |
385 | { | |
386 | int size = 0; | |
387 | CONST char *name = selfp->name; | |
388 | if (name != NULL) { | |
389 | char *demangled = NULL; | |
390 | if (!bsd_style_output) { | |
391 | if (name[0] == '_' && name[1] && discard_underscores) | |
392 | name++; | |
393 | demangled = cplus_demangle (name, DMGL_ANSI|DMGL_PARAMS); | |
394 | if (demangled) | |
395 | name = demangled; | |
396 | } | |
397 | printf( "%s" , name ); | |
398 | size = strlen (name); | |
399 | if (demangled) | |
400 | free (demangled); | |
401 | #ifdef DEBUG | |
402 | if ( debug & DFNDEBUG ) { | |
403 | printf( "{%d} " , selfp -> toporder ); | |
404 | } | |
405 | if ( debug & PROPDEBUG ) { | |
406 | printf( "%5.2f%% " , selfp -> propfraction ); | |
407 | } | |
408 | #endif DEBUG | |
409 | } | |
410 | return size; | |
411 | } | |
412 | ||
3d6c6501 SEF |
413 | printname( selfp ) |
414 | nltype *selfp; | |
415 | { | |
dc1d1ca5 | 416 | printnameonly (selfp); |
3d6c6501 | 417 | |
3d6c6501 SEF |
418 | if ( selfp -> cycleno != 0 ) { |
419 | printf( " <cycle %d>" , selfp -> cycleno ); | |
420 | } | |
421 | if ( selfp -> index != 0 ) { | |
422 | if ( selfp -> printflag ) { | |
423 | printf( " [%d]" , selfp -> index ); | |
424 | } else { | |
425 | printf( " (%d)" , selfp -> index ); | |
426 | } | |
427 | } | |
428 | } | |
429 | ||
430 | sortchildren( parentp ) | |
431 | nltype *parentp; | |
432 | { | |
433 | arctype *arcp; | |
434 | arctype *detachedp; | |
435 | arctype sorted; | |
436 | arctype *prevp; | |
437 | ||
438 | /* | |
439 | * unlink children from parent, | |
440 | * then insertion sort back on to sorted's children. | |
441 | * *arcp the arc you have detached and are inserting. | |
442 | * *detachedp the rest of the arcs to be sorted. | |
443 | * sorted arc list onto which you insertion sort. | |
444 | * *prevp arc before the arc you are comparing. | |
445 | */ | |
446 | sorted.arc_childlist = 0; | |
447 | for ( (arcp = parentp -> children)&&(detachedp = arcp -> arc_childlist); | |
448 | arcp ; | |
449 | (arcp = detachedp)&&(detachedp = detachedp -> arc_childlist)) { | |
450 | /* | |
451 | * consider *arcp as disconnected | |
452 | * insert it into sorted | |
453 | */ | |
454 | for ( prevp = &sorted ; | |
455 | prevp -> arc_childlist ; | |
456 | prevp = prevp -> arc_childlist ) { | |
457 | if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) { | |
458 | break; | |
459 | } | |
460 | } | |
461 | arcp -> arc_childlist = prevp -> arc_childlist; | |
462 | prevp -> arc_childlist = arcp; | |
463 | } | |
464 | /* | |
465 | * reattach sorted children to parent | |
466 | */ | |
467 | parentp -> children = sorted.arc_childlist; | |
468 | } | |
469 | ||
470 | sortparents( childp ) | |
471 | nltype *childp; | |
472 | { | |
473 | arctype *arcp; | |
474 | arctype *detachedp; | |
475 | arctype sorted; | |
476 | arctype *prevp; | |
477 | ||
478 | /* | |
479 | * unlink parents from child, | |
480 | * then insertion sort back on to sorted's parents. | |
481 | * *arcp the arc you have detached and are inserting. | |
482 | * *detachedp the rest of the arcs to be sorted. | |
483 | * sorted arc list onto which you insertion sort. | |
484 | * *prevp arc before the arc you are comparing. | |
485 | */ | |
486 | sorted.arc_parentlist = 0; | |
487 | for ( (arcp = childp -> parents)&&(detachedp = arcp -> arc_parentlist); | |
488 | arcp ; | |
489 | (arcp = detachedp)&&(detachedp = detachedp -> arc_parentlist)) { | |
490 | /* | |
491 | * consider *arcp as disconnected | |
492 | * insert it into sorted | |
493 | */ | |
494 | for ( prevp = &sorted ; | |
495 | prevp -> arc_parentlist ; | |
496 | prevp = prevp -> arc_parentlist ) { | |
497 | if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) { | |
498 | break; | |
499 | } | |
500 | } | |
501 | arcp -> arc_parentlist = prevp -> arc_parentlist; | |
502 | prevp -> arc_parentlist = arcp; | |
503 | } | |
504 | /* | |
505 | * reattach sorted arcs to child | |
506 | */ | |
507 | childp -> parents = sorted.arc_parentlist; | |
508 | } | |
509 | ||
510 | /* | |
511 | * print a cycle header | |
512 | */ | |
513 | printcycle( cyclep ) | |
514 | nltype *cyclep; | |
515 | { | |
516 | char kirkbuffer[ BUFSIZ ]; | |
517 | ||
518 | sprintf( kirkbuffer , "[%d]" , cyclep -> index ); | |
519 | printf( "%-6.6s %5.1f %7.2f %11.2f %7d" , | |
520 | kirkbuffer , | |
521 | 100 * ( cyclep -> propself + cyclep -> propchild ) / printtime , | |
522 | cyclep -> propself / hz , | |
523 | cyclep -> propchild / hz , | |
524 | cyclep -> ncall ); | |
525 | if ( cyclep -> selfcalls != 0 ) { | |
526 | printf( "+%-7d" , cyclep -> selfcalls ); | |
527 | } else { | |
528 | printf( " %7.7s" , "" ); | |
529 | } | |
530 | printf( " <cycle %d as a whole>\t[%d]\n" , | |
531 | cyclep -> cycleno , cyclep -> index ); | |
532 | } | |
533 | ||
534 | /* | |
535 | * print the members of a cycle | |
536 | */ | |
537 | printmembers( cyclep ) | |
538 | nltype *cyclep; | |
539 | { | |
540 | nltype *memberp; | |
541 | ||
542 | sortmembers( cyclep ); | |
543 | for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) { | |
544 | printf( "%6.6s %5.5s %7.2f %11.2f %7d" , | |
545 | "" , "" , memberp -> propself / hz , memberp -> propchild / hz , | |
546 | memberp -> ncall ); | |
547 | if ( memberp -> selfcalls != 0 ) { | |
548 | printf( "+%-7d" , memberp -> selfcalls ); | |
549 | } else { | |
550 | printf( " %7.7s" , "" ); | |
551 | } | |
552 | printf( " " ); | |
553 | printname( memberp ); | |
554 | printf( "\n" ); | |
555 | } | |
556 | } | |
557 | ||
558 | /* | |
559 | * sort members of a cycle | |
560 | */ | |
561 | sortmembers( cyclep ) | |
562 | nltype *cyclep; | |
563 | { | |
564 | nltype *todo; | |
565 | nltype *doing; | |
566 | nltype *prev; | |
567 | ||
568 | /* | |
569 | * detach cycle members from cyclehead, | |
570 | * and insertion sort them back on. | |
571 | */ | |
572 | todo = cyclep -> cnext; | |
573 | cyclep -> cnext = 0; | |
574 | for ( (doing = todo)&&(todo = doing -> cnext); | |
575 | doing ; | |
576 | (doing = todo )&&(todo = doing -> cnext )){ | |
577 | for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) { | |
578 | if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) { | |
579 | break; | |
580 | } | |
581 | } | |
582 | doing -> cnext = prev -> cnext; | |
583 | prev -> cnext = doing; | |
584 | } | |
585 | } | |
586 | ||
587 | /* | |
588 | * major sort is on propself + propchild, | |
589 | * next is sort on ncalls + selfcalls. | |
590 | */ | |
591 | int | |
592 | membercmp( this , that ) | |
593 | nltype *this; | |
594 | nltype *that; | |
595 | { | |
596 | double thistime = this -> propself + this -> propchild; | |
597 | double thattime = that -> propself + that -> propchild; | |
598 | long thiscalls = this -> ncall + this -> selfcalls; | |
599 | long thatcalls = that -> ncall + that -> selfcalls; | |
600 | ||
601 | if ( thistime > thattime ) { | |
602 | return GREATERTHAN; | |
603 | } | |
604 | if ( thistime < thattime ) { | |
605 | return LESSTHAN; | |
606 | } | |
607 | if ( thiscalls > thatcalls ) { | |
608 | return GREATERTHAN; | |
609 | } | |
610 | if ( thiscalls < thatcalls ) { | |
611 | return LESSTHAN; | |
612 | } | |
613 | return EQUALTO; | |
614 | } | |
615 | /* | |
616 | * compare two arcs to/from the same child/parent. | |
617 | * - if one arc is a self arc, it's least. | |
618 | * - if one arc is within a cycle, it's less than. | |
619 | * - if both arcs are within a cycle, compare arc counts. | |
620 | * - if neither arc is within a cycle, compare with | |
621 | * arc_time + arc_childtime as major key | |
622 | * arc count as minor key | |
623 | */ | |
624 | int | |
625 | arccmp( thisp , thatp ) | |
626 | arctype *thisp; | |
627 | arctype *thatp; | |
628 | { | |
629 | nltype *thisparentp = thisp -> arc_parentp; | |
630 | nltype *thischildp = thisp -> arc_childp; | |
631 | nltype *thatparentp = thatp -> arc_parentp; | |
632 | nltype *thatchildp = thatp -> arc_childp; | |
633 | double thistime; | |
634 | double thattime; | |
635 | ||
636 | # ifdef DEBUG | |
637 | if ( debug & TIMEDEBUG ) { | |
638 | printf( "[arccmp] " ); | |
639 | printname( thisparentp ); | |
640 | printf( " calls " ); | |
641 | printname ( thischildp ); | |
642 | printf( " %f + %f %d/%d\n" , | |
643 | thisp -> arc_time , thisp -> arc_childtime , | |
644 | thisp -> arc_count , thischildp -> ncall ); | |
645 | printf( "[arccmp] " ); | |
646 | printname( thatparentp ); | |
647 | printf( " calls " ); | |
648 | printname( thatchildp ); | |
649 | printf( " %f + %f %d/%d\n" , | |
650 | thatp -> arc_time , thatp -> arc_childtime , | |
651 | thatp -> arc_count , thatchildp -> ncall ); | |
652 | printf( "\n" ); | |
653 | } | |
654 | # endif DEBUG | |
655 | if ( thisparentp == thischildp ) { | |
656 | /* this is a self call */ | |
657 | return LESSTHAN; | |
658 | } | |
659 | if ( thatparentp == thatchildp ) { | |
660 | /* that is a self call */ | |
661 | return GREATERTHAN; | |
662 | } | |
663 | if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 && | |
664 | thisparentp -> cycleno == thischildp -> cycleno ) { | |
665 | /* this is a call within a cycle */ | |
666 | if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 && | |
667 | thatparentp -> cycleno == thatchildp -> cycleno ) { | |
668 | /* that is a call within the cycle, too */ | |
669 | if ( thisp -> arc_count < thatp -> arc_count ) { | |
670 | return LESSTHAN; | |
671 | } | |
672 | if ( thisp -> arc_count > thatp -> arc_count ) { | |
673 | return GREATERTHAN; | |
674 | } | |
675 | return EQUALTO; | |
676 | } else { | |
677 | /* that isn't a call within the cycle */ | |
678 | return LESSTHAN; | |
679 | } | |
680 | } else { | |
681 | /* this isn't a call within a cycle */ | |
682 | if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 && | |
683 | thatparentp -> cycleno == thatchildp -> cycleno ) { | |
684 | /* that is a call within a cycle */ | |
685 | return GREATERTHAN; | |
686 | } else { | |
687 | /* neither is a call within a cycle */ | |
688 | thistime = thisp -> arc_time + thisp -> arc_childtime; | |
689 | thattime = thatp -> arc_time + thatp -> arc_childtime; | |
690 | if ( thistime < thattime ) | |
691 | return LESSTHAN; | |
692 | if ( thistime > thattime ) | |
693 | return GREATERTHAN; | |
694 | if ( thisp -> arc_count < thatp -> arc_count ) | |
695 | return LESSTHAN; | |
696 | if ( thisp -> arc_count > thatp -> arc_count ) | |
697 | return GREATERTHAN; | |
698 | return EQUALTO; | |
699 | } | |
700 | } | |
701 | } | |
702 | ||
3d6c6501 SEF |
703 | int |
704 | namecmp( npp1 , npp2 ) | |
705 | nltype **npp1, **npp2; | |
706 | { | |
707 | return( strcmp( (*npp1) -> name , (*npp2) -> name ) ); | |
708 | } | |
709 | ||
710 | printindex() | |
711 | { | |
712 | nltype **namesortnlp; | |
713 | register nltype *nlp; | |
714 | int index, nnames, todo, i, j; | |
dc1d1ca5 | 715 | char peterbuffer[20]; |
3d6c6501 SEF |
716 | |
717 | /* | |
718 | * Now, sort regular function name alphbetically | |
719 | * to create an index. | |
720 | */ | |
721 | namesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) ); | |
722 | if ( namesortnlp == (nltype **) 0 ) { | |
723 | fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami ); | |
724 | } | |
725 | for ( index = 0 , nnames = 0 ; index < nname ; index++ ) { | |
726 | if ( zflag == 0 && nl[index].ncall == 0 && nl[index].time == 0 ) | |
727 | continue; | |
728 | namesortnlp[nnames++] = &nl[index]; | |
729 | } | |
730 | qsort( namesortnlp , nnames , sizeof(nltype *) , namecmp ); | |
731 | for ( index = 1 , todo = nnames ; index <= ncycle ; index++ ) { | |
732 | namesortnlp[todo++] = &cyclenl[index]; | |
733 | } | |
734 | printf( "\f\nIndex by function name\n\n" ); | |
735 | index = ( todo + 2 ) / 3; | |
736 | for ( i = 0; i < index ; i++ ) { | |
737 | for ( j = i; j < todo ; j += index ) { | |
738 | nlp = namesortnlp[ j ]; | |
739 | if ( nlp -> printflag ) { | |
740 | sprintf( peterbuffer , "[%d]" , nlp -> index ); | |
741 | } else { | |
742 | sprintf( peterbuffer , "(%d)" , nlp -> index ); | |
743 | } | |
744 | if ( j < nnames ) { | |
dc1d1ca5 PB |
745 | printf( "%6.6s " , peterbuffer ); |
746 | if (bsd_style_output) | |
747 | printf ("%-19.19s" , nlp->name); | |
748 | else { | |
749 | int size = printnameonly(nlp); | |
750 | for ( ; size < 19; size++) putchar(' '); | |
751 | } | |
3d6c6501 SEF |
752 | } else { |
753 | printf( "%6.6s " , peterbuffer ); | |
754 | sprintf( peterbuffer , "<cycle %d>" , nlp -> cycleno ); | |
755 | printf( "%-19.19s" , peterbuffer ); | |
756 | } | |
757 | } | |
758 | printf( "\n" ); | |
759 | } | |
a67d9a42 | 760 | free( namesortnlp ); |
3d6c6501 | 761 | } |
dc1d1ca5 PB |
762 | |
763 | PTR | |
764 | xmalloc (size) | |
765 | long size; | |
766 | { | |
8a6e5b69 | 767 | PTR val = (PTR) malloc (size); |
dc1d1ca5 PB |
768 | if (val == NULL) { |
769 | fprintf (stderr, "virtual memory exhaused\n"); | |
770 | exit (1); | |
771 | } | |
772 | return val; | |
773 | } | |
774 | ||
775 | PTR | |
776 | xrealloc (oldval, size) | |
777 | PTR oldval; | |
778 | long size; | |
779 | { | |
8a6e5b69 | 780 | PTR val = (PTR) realloc (oldval, size); |
dc1d1ca5 PB |
781 | if (val == NULL) { |
782 | fprintf (stderr, "virtual memory exhaused\n"); | |
783 | exit (1); | |
784 | } | |
785 | return val; | |
786 | } | |
787 |