8 * Return value of comparison functions used to sort tables:
14 /* declarations of automatically generated functions to output blurbs: */
15 extern void bsd_callg_blurb
PARAMS((FILE *fp
));
16 extern void fsf_callg_blurb
PARAMS((FILE *fp
));
18 double print_time
= 0.0;
22 DEFUN_VOID(print_header
)
29 if (!bsd_style_output
) {
30 if (print_descriptions
) {
31 printf("\t\t Call graph (explanation follows)\n\n");
33 printf("\t\t\tCall graph\n\n");
36 printf("\ngranularity: each sample hit covers %ld byte(s)",
37 (long) hist_scale
* sizeof(UNIT
));
38 if (print_time
> 0.0) {
39 printf(" for %.2f%% of %.2f seconds\n\n",
40 100.0/print_time
, print_time
/ hz
);
42 printf(" no time propagated\n\n");
44 * This doesn't hurt, since all the numerators will be 0.0:
48 if (bsd_style_output
) {
49 printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
50 "", "", "", "", "called", "total", "parents");
51 printf("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n",
52 "index", "%time", "self", "descendents",
53 "called", "self", "name", "index");
54 printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
55 "", "", "", "", "called", "total", "children");
58 printf("index %% time self children called name\n");
64 * Print a cycle header.
67 DEFUN(print_cycle
, (cyc
), Sym
*cyc
)
71 sprintf(buf
, "[%d]", cyc
->cg
.index
);
72 printf("%-6.6s %5.1f %7.2f %11.2f %7d", buf
,
73 100 * (cyc
->cg
.prop
.self
+ cyc
->cg
.prop
.child
) / print_time
,
74 cyc
->cg
.prop
.self
/ hz
, cyc
->cg
.prop
.child
/ hz
, cyc
->ncalls
);
75 if (cyc
->cg
.self_calls
!= 0) {
76 printf("+%-7d", cyc
->cg
.self_calls
);
80 printf(" <cycle %d as a whole>\t[%d]\n", cyc
->cg
.cyc
.num
, cyc
->cg
.index
);
85 * Compare LEFT and RIGHT membmer. Major comparison key is
86 * CG.PROP.SELF+CG.PROP.CHILD, secondary key is NCALLS+CG.SELF_CALLS.
89 DEFUN(cmp_member
, (left
, right
), Sym
*left AND Sym
*right
)
91 double left_time
= left
->cg
.prop
.self
+ left
->cg
.prop
.child
;
92 double right_time
= right
->cg
.prop
.self
+ right
->cg
.prop
.child
;
93 long left_calls
= left
->ncalls
+ left
->cg
.self_calls
;
94 long right_calls
= right
->ncalls
+ right
->cg
.self_calls
;
96 if (left_time
> right_time
) {
99 if (left_time
< right_time
) {
103 if (left_calls
> right_calls
) {
106 if (left_calls
< right_calls
) {
114 * Sort members of a cycle.
117 DEFUN(sort_members
, (cyc
), Sym
*cyc
)
119 Sym
*todo
, *doing
, *prev
;
121 * Detach cycle members from cyclehead, and insertion sort them
124 todo
= cyc
->cg
.cyc
.next
;
125 cyc
->cg
.cyc
.next
= 0;
126 for (doing
= todo
; doing
&& doing
->cg
.cyc
.next
; doing
= todo
) {
127 todo
= doing
->cg
.cyc
.next
;
128 for (prev
= cyc
; prev
->cg
.cyc
.next
; prev
= prev
->cg
.cyc
.next
) {
129 if (cmp_member(doing
, prev
->cg
.cyc
.next
) == GREATERTHAN
) {
133 doing
->cg
.cyc
.next
= prev
->cg
.cyc
.next
;
134 prev
->cg
.cyc
.next
= doing
;
140 * Print the members of a cycle.
143 DEFUN(print_members
, (cyc
), Sym
*cyc
)
148 for (member
= cyc
->cg
.cyc
.next
; member
; member
= member
->cg
.cyc
.next
) {
149 printf("%6.6s %5.5s %7.2f %11.2f %7d",
150 "", "", member
->cg
.prop
.self
/ hz
, member
->cg
.prop
.child
/ hz
,
152 if (member
->cg
.self_calls
!= 0) {
153 printf("+%-7d", member
->cg
.self_calls
);
155 printf(" %7.7s", "");
161 } /* print_members */
165 * Compare two arcs to/from the same child/parent.
166 * - if one arc is a self arc, it's least.
167 * - if one arc is within a cycle, it's less than.
168 * - if both arcs are within a cycle, compare arc counts.
169 * - if neither arc is within a cycle, compare with
170 * time + child_time as major key
171 * arc count as minor key
174 DEFUN(cmp_arc
, (left
, right
), Arc
*left AND Arc
*right
)
176 Sym
*left_parent
= left
->parent
;
177 Sym
*left_child
= left
->child
;
178 Sym
*right_parent
= right
->parent
;
179 Sym
*right_child
= right
->child
;
180 double left_time
, right_time
;
183 printf("[cmp_arc] ");
184 print_name(left_parent
);
186 print_name(left_child
);
187 printf(" %f + %f %d/%d\n", left
->time
, left
->child_time
,
188 left
->count
, left_child
->ncalls
);
189 printf("[cmp_arc] ");
190 print_name(right_parent
);
192 print_name(right_child
);
193 printf(" %f + %f %d/%d\n", right
->time
, right
->child_time
,
194 right
->count
, right_child
->ncalls
);
197 if (left_parent
== left_child
) {
198 return LESSTHAN
; /* left is a self call */
200 if (right_parent
== right_child
) {
201 return GREATERTHAN
; /* right is a self call */
204 if (left_parent
->cg
.cyc
.num
!= 0 && left_child
->cg
.cyc
.num
!= 0
205 && left_parent
->cg
.cyc
.num
== left_child
->cg
.cyc
.num
)
207 /* left is a call within a cycle */
208 if (right_parent
->cg
.cyc
.num
!= 0 && right_child
->cg
.cyc
.num
!= 0
209 && right_parent
->cg
.cyc
.num
== right_child
->cg
.cyc
.num
)
211 /* right is a call within the cycle, too */
212 if (left
->count
< right
->count
) {
215 if (left
->count
> right
->count
) {
220 /* right isn't a call within the cycle */
224 /* left isn't a call within a cycle */
225 if (right_parent
->cg
.cyc
.num
!= 0 && right_child
->cg
.cyc
.num
!= 0
226 && right_parent
->cg
.cyc
.num
== right_child
->cg
.cyc
.num
)
228 /* right is a call within a cycle */
231 /* neither is a call within a cycle */
232 left_time
= left
->time
+ left
->child_time
;
233 right_time
= right
->time
+ right
->child_time
;
234 if (left_time
< right_time
) {
237 if (left_time
> right_time
) {
240 if (left
->count
< right
->count
) {
243 if (left
->count
> right
->count
) {
253 DEFUN(sort_parents
, (child
), Sym
*child
)
255 Arc
*arc
, *detached
, sorted
, *prev
;
258 * Unlink parents from child, then insertion sort back on to
260 * *arc the arc you have detached and are inserting.
261 * *detached the rest of the arcs to be sorted.
262 * sorted arc list onto which you insertion sort.
263 * *prev arc before the arc you are comparing.
265 sorted
.next_parent
= 0;
266 for (arc
= child
->cg
.parents
; arc
; arc
= detached
) {
267 detached
= arc
->next_parent
;
269 /* consider *arc as disconnected; insert it into sorted: */
270 for (prev
= &sorted
; prev
->next_parent
; prev
= prev
->next_parent
) {
271 if (cmp_arc(arc
, prev
->next_parent
) != GREATERTHAN
) {
275 arc
->next_parent
= prev
->next_parent
;
276 prev
->next_parent
= arc
;
279 /* reattach sorted arcs to child: */
280 child
->cg
.parents
= sorted
.next_parent
;
285 DEFUN(print_parents
, (child
), Sym
*child
)
291 if (child
->cg
.cyc
.head
!= 0) {
292 cycle_head
= child
->cg
.cyc
.head
;
296 if (!child
->cg
.parents
) {
297 printf(bsd_style_output
298 ? "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s <spontaneous>\n"
299 : "%6.6s %5.5s %7.7s %7.7s %7.7s %7.7s <spontaneous>\n",
300 "", "", "", "", "", "");
304 for (arc
= child
->cg
.parents
; arc
; arc
= arc
->next_parent
) {
305 parent
= arc
->parent
;
306 if (child
== parent
|| (child
->cg
.cyc
.num
!= 0
307 && parent
->cg
.cyc
.num
== child
->cg
.cyc
.num
))
309 /* selfcall or call among siblings: */
310 printf(bsd_style_output
311 ? "%6.6s %5.5s %7.7s %11.11s %7d %7.7s "
312 : "%6.6s %5.5s %7.7s %7.7s %7d %7.7s ",
318 /* regular parent of child: */
319 printf(bsd_style_output
320 ? "%6.6s %5.5s %7.2f %11.2f %7d/%-7d "
321 : "%6.6s %5.5s %7.2f %7.2f %7d/%-7d ",
323 arc
->time
/ hz
, arc
->child_time
/ hz
,
324 arc
->count
, cycle_head
->ncalls
);
329 } /* print_parents */
333 DEFUN(sort_children
, (parent
), Sym
*parent
)
335 Arc
*arc
, *detached
, sorted
, *prev
;
337 * Unlink children from parent, then insertion sort back on to
339 * *arc the arc you have detached and are inserting.
340 * *detached the rest of the arcs to be sorted.
341 * sorted arc list onto which you insertion sort.
342 * *prev arc before the arc you are comparing.
344 sorted
.next_child
= 0;
345 for (arc
= parent
->cg
.children
; arc
; arc
= detached
) {
346 detached
= arc
->next_child
;
348 /* consider *arc as disconnected; insert it into sorted: */
349 for (prev
= &sorted
; prev
->next_child
; prev
= prev
->next_child
) {
350 if (cmp_arc(arc
, prev
->next_child
) != LESSTHAN
) {
354 arc
->next_child
= prev
->next_child
;
355 prev
->next_child
= arc
;
358 /* reattach sorted children to parent: */
359 parent
->cg
.children
= sorted
.next_child
;
360 } /* sort_children */
364 DEFUN(print_children
, (parent
), Sym
*parent
)
369 sort_children(parent
);
370 arc
= parent
->cg
.children
;
371 for (arc
= parent
->cg
.children
; arc
; arc
= arc
->next_child
) {
373 if (child
== parent
|| (child
->cg
.cyc
.num
!= 0
374 && child
->cg
.cyc
.num
== parent
->cg
.cyc
.num
))
376 /* self call or call to sibling: */
377 printf(bsd_style_output
378 ? "%6.6s %5.5s %7.7s %11.11s %7d %7.7s "
379 : "%6.6s %5.5s %7.7s %7.7s %7d %7.7s ",
380 "", "", "", "", arc
->count
, "");
384 /* regular child of parent: */
385 printf(bsd_style_output
386 ? "%6.6s %5.5s %7.2f %11.2f %7d/%-7d "
387 : "%6.6s %5.5s %7.2f %7.2f %7d/%-7d ",
389 arc
->time
/ hz
, arc
->child_time
/ hz
,
390 arc
->count
, child
->cg
.cyc
.head
->ncalls
);
395 } /* print_children */
399 DEFUN(print_line
, (np
), Sym
*np
)
403 sprintf(buf
, "[%d]", np
->cg
.index
);
404 printf(bsd_style_output
405 ? "%-6.6s %5.1f %7.2f %11.2f"
406 : "%-6.6s %5.1f %7.2f %7.2f", buf
,
407 100 * (np
->cg
.prop
.self
+ np
->cg
.prop
.child
) / print_time
,
408 np
->cg
.prop
.self
/ hz
, np
->cg
.prop
.child
/ hz
);
409 if ((np
->ncalls
+ np
->cg
.self_calls
) != 0) {
410 printf(" %7d", np
->ncalls
);
411 if (np
->cg
.self_calls
!= 0) {
412 printf("+%-7d ", np
->cg
.self_calls
);
414 printf(" %7.7s ", "");
417 printf(" %7.7s %7.7s ", "", "");
425 * Print dynamic call graph.
428 DEFUN(cg_print
, (timesortsym
), Sym
**timesortsym
)
433 if (print_descriptions
&& bsd_style_output
) {
434 bsd_callg_blurb(stdout
);
439 for (index
= 0; index
< symtab
.len
+ num_cycles
; ++index
) {
440 parent
= timesortsym
[index
];
441 if ((ignore_zeros
&& parent
->ncalls
== 0
442 && parent
->cg
.self_calls
== 0 && parent
->cg
.prop
.self
== 0
443 && parent
->cg
.prop
.child
== 0)
444 || !parent
->cg
.print_flag
)
448 if (!parent
->name
&& parent
->cg
.cyc
.num
!= 0) {
451 print_members(parent
);
453 print_parents(parent
);
455 print_children(parent
);
457 if (bsd_style_output
)
459 printf("-----------------------------------------------\n");
460 if (bsd_style_output
)
464 if (print_descriptions
&& !bsd_style_output
) {
465 fsf_callg_blurb(stdout
);
471 DEFUN(cmp_name
, (left
, right
), const PTR left AND
const PTR right
)
473 const Sym
**npp1
= (const Sym
**)left
;
474 const Sym
**npp2
= (const Sym
**)right
;
476 return strcmp((*npp1
)->name
, (*npp2
)->name
);
481 DEFUN_VOID(cg_print_index
)
483 int index
, nnames
, todo
, i
, j
, col
, starting_col
;
484 Sym
**name_sorted_syms
, *sym
;
485 const char *filename
;
487 int column_width
= (output_width
- 1) / 3; /* don't write in last col! */
489 * Now, sort regular function name alphabetically to create an
492 name_sorted_syms
= (Sym
**)xmalloc((symtab
.len
+ num_cycles
)*sizeof(Sym
*));
493 for (index
= 0, nnames
= 0; index
< symtab
.len
; index
++) {
494 if (ignore_zeros
&& symtab
.base
[index
].ncalls
== 0
495 && symtab
.base
[index
].hist
.time
== 0)
499 name_sorted_syms
[nnames
++] = &symtab
.base
[index
];
501 qsort(name_sorted_syms
, nnames
, sizeof(Sym
*), cmp_name
);
502 for (index
= 1, todo
= nnames
; index
<= num_cycles
; index
++) {
503 name_sorted_syms
[todo
++] = &cycle_header
[index
];
505 printf("\f\nIndex by function name\n\n");
506 index
= (todo
+ 2) / 3;
507 for (i
= 0; i
< index
; i
++) {
510 for (j
= i
; j
< todo
; j
+= index
) {
511 sym
= name_sorted_syms
[j
];
512 if (sym
->cg
.print_flag
) {
513 sprintf(buf
, "[%d]", sym
->cg
.index
);
515 sprintf(buf
, "(%d)", sym
->cg
.index
);
518 if (bsd_style_output
) {
519 printf("%6.6s %-19.19s", buf
, sym
->name
);
522 for (; col
< starting_col
+ 5; ++col
) {
526 col
+= print_name_only(sym
);
527 if (!line_granularity
&& sym
->is_static
&& sym
->file
) {
528 filename
= sym
->file
->name
;
530 filename
= strrchr(filename
, '/');
534 filename
= sym
->file
->name
;
537 printf(" (%s)", filename
);
538 col
+= strlen(filename
) + 3;
542 printf("%6.6s ", buf
);
543 sprintf(buf
, "<cycle %d>", sym
->cg
.cyc
.num
);
544 printf("%-19.19s", buf
);
546 starting_col
+= column_width
;
550 free(name_sorted_syms
);
551 } /* cg_print_index */
553 /*** end of cg_print.c ***/