Lots of changes from David Mosberger-Tang; see ChangeLog and NOTES for details:
[external/binutils.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 ***/