d123f3ee9379cfca4f9121ba4e7a4b43d932e7bf
[deliverable/binutils-gdb.git] / gprof / cg_print.c
1 #include "libiberty.h"
2 #include "cg_arcs.h"
3 #include "cg_print.h"
4 #include "hist.h"
5 #include "utils.h"
6
7 /*
8 * Return value of comparison functions used to sort tables:
9 */
10 #define LESSTHAN -1
11 #define EQUALTO 0
12 #define GREATERTHAN 1
13
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));
17
18 double print_time = 0.0;
19
20
21 static void
22 DEFUN_VOID(print_header)
23 {
24 if (first_output) {
25 first_output = FALSE;
26 } else {
27 printf("\f\n");
28 } /* if */
29 if (!bsd_style_output) {
30 if (print_descriptions) {
31 printf("\t\t Call graph (explanation follows)\n\n");
32 } else {
33 printf("\t\t\tCall graph\n\n");
34 } /* if */
35 } /* if */
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);
41 } else {
42 printf(" no time propagated\n\n");
43 /*
44 * This doesn't hurt, since all the numerators will be 0.0:
45 */
46 print_time = 1.0;
47 } /* if */
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");
56 printf("\n");
57 } else {
58 printf("index %% time self children called name\n");
59 } /* if */
60 } /* print_header */
61
62
63 /*
64 * Print a cycle header.
65 */
66 static void
67 DEFUN(print_cycle, (cyc), Sym *cyc)
68 {
69 char buf[BUFSIZ];
70
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);
77 } else {
78 printf(" %7.7s", "");
79 } /* if */
80 printf(" <cycle %d as a whole>\t[%d]\n", cyc->cg.cyc.num, cyc->cg.index);
81 } /* print_cycle */
82
83
84 /*
85 * Compare LEFT and RIGHT membmer. Major comparison key is
86 * CG.PROP.SELF+CG.PROP.CHILD, secondary key is NCALLS+CG.SELF_CALLS.
87 */
88 static int
89 DEFUN(cmp_member, (left, right), Sym *left AND Sym *right)
90 {
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;
95
96 if (left_time > right_time) {
97 return GREATERTHAN;
98 } /* if */
99 if (left_time < right_time) {
100 return LESSTHAN;
101 } /* if */
102
103 if (left_calls > right_calls) {
104 return GREATERTHAN;
105 } /* if */
106 if (left_calls < right_calls) {
107 return LESSTHAN;
108 } /* if */
109 return EQUALTO;
110 } /* cmp_member */
111
112
113 /*
114 * Sort members of a cycle.
115 */
116 static void
117 DEFUN(sort_members, (cyc), Sym *cyc)
118 {
119 Sym *todo, *doing, *prev;
120 /*
121 * Detach cycle members from cyclehead, and insertion sort them
122 * back on.
123 */
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) {
130 break;
131 } /* if */
132 } /* for */
133 doing->cg.cyc.next = prev->cg.cyc.next;
134 prev->cg.cyc.next = doing;
135 } /* for */
136 } /* sort_members */
137
138
139 /*
140 * Print the members of a cycle.
141 */
142 static void
143 DEFUN(print_members, (cyc), Sym *cyc)
144 {
145 Sym *member;
146
147 sort_members(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,
151 member->ncalls);
152 if (member->cg.self_calls != 0) {
153 printf("+%-7d", member->cg.self_calls);
154 } else {
155 printf(" %7.7s", "");
156 } /* if */
157 printf(" ");
158 print_name(member);
159 printf("\n");
160 } /* for */
161 } /* print_members */
162
163
164 /*
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
172 */
173 static int
174 DEFUN(cmp_arc, (left, right), Arc *left AND Arc *right)
175 {
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;
181
182 DBG(TIMEDEBUG,
183 printf("[cmp_arc] ");
184 print_name(left_parent);
185 printf(" calls ");
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);
191 printf(" calls ");
192 print_name(right_child);
193 printf(" %f + %f %d/%d\n", right->time, right->child_time,
194 right->count, right_child->ncalls);
195 printf("\n");
196 );
197 if (left_parent == left_child) {
198 return LESSTHAN; /* left is a self call */
199 } /* if */
200 if (right_parent == right_child) {
201 return GREATERTHAN; /* right is a self call */
202 } /* if */
203
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)
206 {
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)
210 {
211 /* right is a call within the cycle, too */
212 if (left->count < right->count) {
213 return LESSTHAN;
214 } /* if */
215 if (left->count > right->count) {
216 return GREATERTHAN;
217 } /* if */
218 return EQUALTO;
219 } else {
220 /* right isn't a call within the cycle */
221 return LESSTHAN;
222 } /* if */
223 } else {
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)
227 {
228 /* right is a call within a cycle */
229 return GREATERTHAN;
230 } else {
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) {
235 return LESSTHAN;
236 } /* if */
237 if (left_time > right_time) {
238 return GREATERTHAN;
239 } /* if */
240 if (left->count < right->count) {
241 return LESSTHAN;
242 } /* if */
243 if (left->count > right->count) {
244 return GREATERTHAN;
245 } /* if */
246 return EQUALTO;
247 } /* if */
248 } /* if */
249 } /* cmp_arc */
250
251
252 static void
253 DEFUN(sort_parents, (child), Sym *child)
254 {
255 Arc *arc, *detached, sorted, *prev;
256
257 /*
258 * Unlink parents from child, then insertion sort back on to
259 * sorted's parents.
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.
264 */
265 sorted.next_parent = 0;
266 for (arc = child->cg.parents; arc; arc = detached) {
267 detached = arc->next_parent;
268
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) {
272 break;
273 } /* if */
274 } /* for */
275 arc->next_parent = prev->next_parent;
276 prev->next_parent = arc;
277 } /* for */
278
279 /* reattach sorted arcs to child: */
280 child->cg.parents = sorted.next_parent;
281 } /* sort_parents */
282
283
284 static void
285 DEFUN(print_parents, (child), Sym *child)
286 {
287 Sym *parent;
288 Arc *arc;
289 Sym *cycle_head;
290
291 if (child->cg.cyc.head != 0) {
292 cycle_head = child->cg.cyc.head;
293 } else {
294 cycle_head = child;
295 } /* if */
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 "", "", "", "", "", "");
301 return;
302 } /* if */
303 sort_parents(child);
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))
308 {
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 ",
313 "", "", "", "",
314 arc->count, "");
315 print_name(parent);
316 printf("\n");
317 } else {
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 ",
322 "", "",
323 arc->time / hz, arc->child_time / hz,
324 arc->count, cycle_head->ncalls);
325 print_name(parent);
326 printf("\n");
327 } /* if */
328 } /* for */
329 } /* print_parents */
330
331
332 static void
333 DEFUN(sort_children, (parent), Sym *parent)
334 {
335 Arc *arc, *detached, sorted, *prev;
336 /*
337 * Unlink children from parent, then insertion sort back on to
338 * sorted's children.
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.
343 */
344 sorted.next_child = 0;
345 for (arc = parent->cg.children; arc; arc = detached) {
346 detached = arc->next_child;
347
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) {
351 break;
352 } /* if */
353 } /* for */
354 arc->next_child = prev->next_child;
355 prev->next_child = arc;
356 } /* for */
357
358 /* reattach sorted children to parent: */
359 parent->cg.children = sorted.next_child;
360 } /* sort_children */
361
362
363 static void
364 DEFUN(print_children, (parent), Sym *parent)
365 {
366 Sym *child;
367 Arc *arc;
368
369 sort_children(parent);
370 arc = parent->cg.children;
371 for (arc = parent->cg.children; arc; arc = arc->next_child) {
372 child = arc->child;
373 if (child == parent || (child->cg.cyc.num != 0
374 && child->cg.cyc.num == parent->cg.cyc.num))
375 {
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, "");
381 print_name(child);
382 printf("\n");
383 } else {
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 ",
388 "", "",
389 arc->time / hz, arc->child_time / hz,
390 arc->count, child->cg.cyc.head->ncalls);
391 print_name(child);
392 printf("\n");
393 } /* if */
394 } /* for */
395 } /* print_children */
396
397
398 static void
399 DEFUN(print_line, (np), Sym *np)
400 {
401 char buf[BUFSIZ];
402
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);
413 } else {
414 printf(" %7.7s ", "");
415 } /* if */
416 } else {
417 printf(" %7.7s %7.7s ", "", "");
418 } /* if */
419 print_name(np);
420 printf("\n");
421 } /* print_line */
422
423
424 /*
425 * Print dynamic call graph.
426 */
427 void
428 DEFUN(cg_print, (timesortsym), Sym **timesortsym)
429 {
430 int index;
431 Sym *parent;
432
433 if (print_descriptions && bsd_style_output) {
434 bsd_callg_blurb(stdout);
435 } /* if */
436
437 print_header();
438
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)
445 {
446 continue;
447 } /* if */
448 if (!parent->name && parent->cg.cyc.num != 0) {
449 /* cycle header: */
450 print_cycle(parent);
451 print_members(parent);
452 } else {
453 print_parents(parent);
454 print_line(parent);
455 print_children(parent);
456 } /* if */
457 if (bsd_style_output)
458 printf("\n");
459 printf("-----------------------------------------------\n");
460 if (bsd_style_output)
461 printf("\n");
462 }
463 free(timesortsym);
464 if (print_descriptions && !bsd_style_output) {
465 fsf_callg_blurb(stdout);
466 }
467 } /* cg_print */
468
469
470 static int
471 DEFUN(cmp_name, (left, right), const PTR left AND const PTR right)
472 {
473 const Sym **npp1 = (const Sym **)left;
474 const Sym **npp2 = (const Sym **)right;
475
476 return strcmp((*npp1)->name, (*npp2)->name);
477 } /* cmp_name */
478
479
480 void
481 DEFUN_VOID(cg_print_index)
482 {
483 int index, nnames, todo, i, j, col, starting_col;
484 Sym **name_sorted_syms, *sym;
485 const char *filename;
486 char buf[20];
487 int column_width = (output_width - 1) / 3; /* don't write in last col! */
488 /*
489 * Now, sort regular function name alphabetically to create an
490 * index:
491 */
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)
496 {
497 continue;
498 } /* if */
499 name_sorted_syms[nnames++] = &symtab.base[index];
500 } /* for */
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];
504 } /* for */
505 printf("\f\nIndex by function name\n\n");
506 index = (todo + 2) / 3;
507 for (i = 0; i < index; i++) {
508 col = 0;
509 starting_col = 0;
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);
514 } else {
515 sprintf(buf, "(%d)", sym->cg.index);
516 } /* if */
517 if (j < nnames) {
518 if (bsd_style_output) {
519 printf("%6.6s %-19.19s", buf, sym->name);
520 } else {
521 col += strlen(buf);
522 for (; col < starting_col + 5; ++col) {
523 putchar(' ');
524 } /* for */
525 printf(" %s ", buf);
526 col += print_name_only(sym);
527 if (!line_granularity && sym->is_static && sym->file) {
528 filename = sym->file->name;
529 if (!print_path) {
530 filename = strrchr(filename, '/');
531 if (filename) {
532 ++filename;
533 } else {
534 filename = sym->file->name;
535 } /* if */
536 } /* if */
537 printf(" (%s)", filename);
538 col += strlen(filename) + 3;
539 } /* if */
540 } /* if */
541 } else {
542 printf("%6.6s ", buf);
543 sprintf(buf, "<cycle %d>", sym->cg.cyc.num);
544 printf("%-19.19s", buf);
545 } /* if */
546 starting_col += column_width;
547 } /* for */
548 printf("\n");
549 } /* for */
550 free(name_sorted_syms);
551 } /* cg_print_index */
552
553 /*** end of cg_print.c ***/
This page took 0.066424 seconds and 4 git commands to generate.