Mon Sep 25 22:49:32 1995 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
[platform/upstream/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     {
26       first_output = FALSE;
27     }
28   else
29     {
30       printf ("\f\n");
31     }
32   if (!bsd_style_output)
33     {
34       if (print_descriptions)
35         {
36           printf ("\t\t     Call graph (explanation follows)\n\n");
37         }
38       else
39         {
40           printf ("\t\t\tCall graph\n\n");
41         }
42     }
43   printf ("\ngranularity: each sample hit covers %ld byte(s)",
44           (long) hist_scale * sizeof (UNIT));
45   if (print_time > 0.0)
46     {
47       printf (" for %.2f%% of %.2f seconds\n\n",
48               100.0 / print_time, print_time / hz);
49     }
50   else
51     {
52       printf (" no time propagated\n\n");
53       /*
54        * This doesn't hurt, since all the numerators will be 0.0:
55        */
56       print_time = 1.0;
57     }
58   if (bsd_style_output)
59     {
60       printf ("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n",
61               "", "", "", "", "called", "total", "parents");
62       printf ("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n",
63               "index", "%time", "self", "descendents",
64               "called", "self", "name", "index");
65       printf ("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n",
66               "", "", "", "", "called", "total", "children");
67       printf ("\n");
68     }
69   else
70     {
71       printf ("index %% time    self  children    called     name\n");
72     }
73 }
74
75
76 /*
77  * Print a cycle header.
78  */
79 static void
80 DEFUN (print_cycle, (cyc), Sym * cyc)
81 {
82   char buf[BUFSIZ];
83
84   sprintf (buf, "[%d]", cyc->cg.index);
85   printf (bsd_style_output
86           ? "%-6.6s %5.1f %7.2f %11.2f %7d"
87           : "%-6.6s %5.1f %7.2f %7.2f %7d", buf,
88           100 * (cyc->cg.prop.self + cyc->cg.prop.child) / print_time,
89           cyc->cg.prop.self / hz, cyc->cg.prop.child / hz, cyc->ncalls);
90   if (cyc->cg.self_calls != 0)
91     {
92       printf ("+%-7d", cyc->cg.self_calls);
93     }
94   else
95     {
96       printf (" %7.7s", "");
97     }
98   printf (" <cycle %d as a whole> [%d]\n", cyc->cg.cyc.num, cyc->cg.index);
99 }
100
101
102 /*
103  * Compare LEFT and RIGHT membmer.  Major comparison key is
104  * CG.PROP.SELF+CG.PROP.CHILD, secondary key is NCALLS+CG.SELF_CALLS.
105  */
106 static int
107 DEFUN (cmp_member, (left, right), Sym * left AND Sym * right)
108 {
109   double left_time = left->cg.prop.self + left->cg.prop.child;
110   double right_time = right->cg.prop.self + right->cg.prop.child;
111   long left_calls = left->ncalls + left->cg.self_calls;
112   long right_calls = right->ncalls + right->cg.self_calls;
113
114   if (left_time > right_time)
115     {
116       return GREATERTHAN;
117     }
118   if (left_time < right_time)
119     {
120       return LESSTHAN;
121     }
122
123   if (left_calls > right_calls)
124     {
125       return GREATERTHAN;
126     }
127   if (left_calls < right_calls)
128     {
129       return LESSTHAN;
130     }
131   return EQUALTO;
132 }
133
134
135 /*
136  * Sort members of a cycle.
137  */
138 static void
139 DEFUN (sort_members, (cyc), Sym * cyc)
140 {
141   Sym *todo, *doing, *prev;
142   /*
143    * Detach cycle members from cyclehead, and insertion sort them
144    * back on.
145    */
146   todo = cyc->cg.cyc.next;
147   cyc->cg.cyc.next = 0;
148   for (doing = todo; doing && doing->cg.cyc.next; doing = todo)
149     {
150       todo = doing->cg.cyc.next;
151       for (prev = cyc; prev->cg.cyc.next; prev = prev->cg.cyc.next)
152         {
153           if (cmp_member (doing, prev->cg.cyc.next) == GREATERTHAN)
154             {
155               break;
156             }
157         }
158       doing->cg.cyc.next = prev->cg.cyc.next;
159       prev->cg.cyc.next = doing;
160     }
161 }
162
163
164 /*
165  * Print the members of a cycle.
166  */
167 static void
168 DEFUN (print_members, (cyc), Sym * cyc)
169 {
170   Sym *member;
171
172   sort_members (cyc);
173   for (member = cyc->cg.cyc.next; member; member = member->cg.cyc.next)
174     {
175       printf (bsd_style_output
176               ? "%6.6s %5.5s %7.2f %11.2f %7d"
177               : "%6.6s %5.5s %7.2f %7.2f %7d",
178               "", "", member->cg.prop.self / hz, member->cg.prop.child / hz,
179               member->ncalls);
180       if (member->cg.self_calls != 0)
181         {
182           printf ("+%-7d", member->cg.self_calls);
183         }
184       else
185         {
186           printf (" %7.7s", "");
187         }
188       printf ("     ");
189       print_name (member);
190       printf ("\n");
191     }
192 }
193
194
195 /*
196  * Compare two arcs to/from the same child/parent.
197  *      - if one arc is a self arc, it's least.
198  *      - if one arc is within a cycle, it's less than.
199  *      - if both arcs are within a cycle, compare arc counts.
200  *      - if neither arc is within a cycle, compare with
201  *              time + child_time as major key
202  *              arc count as minor key
203  */
204 static int
205 DEFUN (cmp_arc, (left, right), Arc * left AND Arc * right)
206 {
207   Sym *left_parent = left->parent;
208   Sym *left_child = left->child;
209   Sym *right_parent = right->parent;
210   Sym *right_child = right->child;
211   double left_time, right_time;
212
213   DBG (TIMEDEBUG,
214        printf ("[cmp_arc] ");
215        print_name (left_parent);
216        printf (" calls ");
217        print_name (left_child);
218        printf (" %f + %f %d/%d\n", left->time, left->child_time,
219                left->count, left_child->ncalls);
220        printf ("[cmp_arc] ");
221        print_name (right_parent);
222        printf (" calls ");
223        print_name (right_child);
224        printf (" %f + %f %d/%d\n", right->time, right->child_time,
225                right->count, right_child->ncalls);
226        printf ("\n");
227     );
228   if (left_parent == left_child)
229     {
230       return LESSTHAN;          /* left is a self call */
231     }
232   if (right_parent == right_child)
233     {
234       return GREATERTHAN;       /* right is a self call */
235     }
236
237   if (left_parent->cg.cyc.num != 0 && left_child->cg.cyc.num != 0
238       && left_parent->cg.cyc.num == left_child->cg.cyc.num)
239     {
240       /* left is a call within a cycle */
241       if (right_parent->cg.cyc.num != 0 && right_child->cg.cyc.num != 0
242           && right_parent->cg.cyc.num == right_child->cg.cyc.num)
243         {
244           /* right is a call within the cycle, too */
245           if (left->count < right->count)
246             {
247               return LESSTHAN;
248             }
249           if (left->count > right->count)
250             {
251               return GREATERTHAN;
252             }
253           return EQUALTO;
254         }
255       else
256         {
257           /* right isn't a call within the cycle */
258           return LESSTHAN;
259         }
260     }
261   else
262     {
263       /* left isn't a call within a cycle */
264       if (right_parent->cg.cyc.num != 0 && right_child->cg.cyc.num != 0
265           && right_parent->cg.cyc.num == right_child->cg.cyc.num)
266         {
267           /* right is a call within a cycle */
268           return GREATERTHAN;
269         }
270       else
271         {
272           /* neither is a call within a cycle */
273           left_time = left->time + left->child_time;
274           right_time = right->time + right->child_time;
275           if (left_time < right_time)
276             {
277               return LESSTHAN;
278             }
279           if (left_time > right_time)
280             {
281               return GREATERTHAN;
282             }
283           if (left->count < right->count)
284             {
285               return LESSTHAN;
286             }
287           if (left->count > right->count)
288             {
289               return GREATERTHAN;
290             }
291           return EQUALTO;
292         }
293     }
294 }
295
296
297 static void
298 DEFUN (sort_parents, (child), Sym * child)
299 {
300   Arc *arc, *detached, sorted, *prev;
301
302   /*
303    * Unlink parents from child, then insertion sort back on to
304    * sorted's parents.
305    *      *arc        the arc you have detached and are inserting.
306    *      *detached   the rest of the arcs to be sorted.
307    *      sorted      arc list onto which you insertion sort.
308    *      *prev       arc before the arc you are comparing.
309    */
310   sorted.next_parent = 0;
311   for (arc = child->cg.parents; arc; arc = detached)
312     {
313       detached = arc->next_parent;
314
315       /* consider *arc as disconnected; insert it into sorted: */
316       for (prev = &sorted; prev->next_parent; prev = prev->next_parent)
317         {
318           if (cmp_arc (arc, prev->next_parent) != GREATERTHAN)
319             {
320               break;
321             }
322         }
323       arc->next_parent = prev->next_parent;
324       prev->next_parent = arc;
325     }
326
327   /* reattach sorted arcs to child: */
328   child->cg.parents = sorted.next_parent;
329 }
330
331
332 static void
333 DEFUN (print_parents, (child), Sym * child)
334 {
335   Sym *parent;
336   Arc *arc;
337   Sym *cycle_head;
338
339   if (child->cg.cyc.head != 0)
340     {
341       cycle_head = child->cg.cyc.head;
342     }
343   else
344     {
345       cycle_head = child;
346     }
347   if (!child->cg.parents)
348     {
349       printf (bsd_style_output
350               ? "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s     <spontaneous>\n"
351               : "%6.6s %5.5s %7.7s %7.7s %7.7s %7.7s     <spontaneous>\n",
352               "", "", "", "", "", "");
353       return;
354     }
355   sort_parents (child);
356   for (arc = child->cg.parents; arc; arc = arc->next_parent)
357     {
358       parent = arc->parent;
359       if (child == parent || (child->cg.cyc.num != 0
360                               && parent->cg.cyc.num == child->cg.cyc.num))
361         {
362           /* selfcall or call among siblings: */
363           printf (bsd_style_output
364                   ? "%6.6s %5.5s %7.7s %11.11s %7d %7.7s     "
365                   : "%6.6s %5.5s %7.7s %7.7s %7d %7.7s     ",
366                   "", "", "", "",
367                   arc->count, "");
368           print_name (parent);
369           printf ("\n");
370         }
371       else
372         {
373           /* regular parent of child: */
374           printf (bsd_style_output
375                   ? "%6.6s %5.5s %7.2f %11.2f %7d/%-7d     "
376                   : "%6.6s %5.5s %7.2f %7.2f %7d/%-7d     ",
377                   "", "",
378                   arc->time / hz, arc->child_time / hz,
379                   arc->count, cycle_head->ncalls);
380           print_name (parent);
381           printf ("\n");
382         }
383     }
384 }
385
386
387 static void
388 DEFUN (sort_children, (parent), Sym * parent)
389 {
390   Arc *arc, *detached, sorted, *prev;
391   /*
392    * Unlink children from parent, then insertion sort back on to
393    * sorted's children.
394    *      *arc        the arc you have detached and are inserting.
395    *      *detached   the rest of the arcs to be sorted.
396    *      sorted      arc list onto which you insertion sort.
397    *      *prev       arc before the arc you are comparing.
398    */
399   sorted.next_child = 0;
400   for (arc = parent->cg.children; arc; arc = detached)
401     {
402       detached = arc->next_child;
403
404       /* consider *arc as disconnected; insert it into sorted: */
405       for (prev = &sorted; prev->next_child; prev = prev->next_child)
406         {
407           if (cmp_arc (arc, prev->next_child) != LESSTHAN)
408             {
409               break;
410             }
411         }
412       arc->next_child = prev->next_child;
413       prev->next_child = arc;
414     }
415
416   /* reattach sorted children to parent: */
417   parent->cg.children = sorted.next_child;
418 }
419
420
421 static void
422 DEFUN (print_children, (parent), Sym * parent)
423 {
424   Sym *child;
425   Arc *arc;
426
427   sort_children (parent);
428   arc = parent->cg.children;
429   for (arc = parent->cg.children; arc; arc = arc->next_child)
430     {
431       child = arc->child;
432       if (child == parent || (child->cg.cyc.num != 0
433                               && child->cg.cyc.num == parent->cg.cyc.num))
434         {
435           /* self call or call to sibling: */
436           printf (bsd_style_output
437                   ? "%6.6s %5.5s %7.7s %11.11s %7d %7.7s     "
438                   : "%6.6s %5.5s %7.7s %7.7s %7d %7.7s     ",
439                   "", "", "", "", arc->count, "");
440           print_name (child);
441           printf ("\n");
442         }
443       else
444         {
445           /* regular child of parent: */
446           printf (bsd_style_output
447                   ? "%6.6s %5.5s %7.2f %11.2f %7d/%-7d     "
448                   : "%6.6s %5.5s %7.2f %7.2f %7d/%-7d     ",
449                   "", "",
450                   arc->time / hz, arc->child_time / hz,
451                   arc->count, child->cg.cyc.head->ncalls);
452           print_name (child);
453           printf ("\n");
454         }
455     }
456 }
457
458
459 static void
460 DEFUN (print_line, (np), Sym * np)
461 {
462   char buf[BUFSIZ];
463
464   sprintf (buf, "[%d]", np->cg.index);
465   printf (bsd_style_output
466           ? "%-6.6s %5.1f %7.2f %11.2f"
467           : "%-6.6s %5.1f %7.2f %7.2f", buf,
468           100 * (np->cg.prop.self + np->cg.prop.child) / print_time,
469           np->cg.prop.self / hz, np->cg.prop.child / hz);
470   if ((np->ncalls + np->cg.self_calls) != 0)
471     {
472       printf (" %7d", np->ncalls);
473       if (np->cg.self_calls != 0)
474         {
475           printf ("+%-7d ", np->cg.self_calls);
476         }
477       else
478         {
479           printf (" %7.7s ", "");
480         }
481     }
482   else
483     {
484       printf (" %7.7s %7.7s ", "", "");
485     }
486   print_name (np);
487   printf ("\n");
488 }
489
490
491 /*
492  * Print dynamic call graph.
493  */
494 void
495 DEFUN (cg_print, (timesortsym), Sym ** timesortsym)
496 {
497   int index;
498   Sym *parent;
499
500   if (print_descriptions && bsd_style_output)
501     {
502       bsd_callg_blurb (stdout);
503     }
504
505   print_header ();
506
507   for (index = 0; index < symtab.len + num_cycles; ++index)
508     {
509       parent = timesortsym[index];
510       if ((ignore_zeros && parent->ncalls == 0
511            && parent->cg.self_calls == 0 && parent->cg.prop.self == 0
512            && parent->cg.prop.child == 0)
513           || !parent->cg.print_flag)
514         {
515           continue;
516         }
517       if (!parent->name && parent->cg.cyc.num != 0)
518         {
519           /* cycle header: */
520           print_cycle (parent);
521           print_members (parent);
522         }
523       else
524         {
525           print_parents (parent);
526           print_line (parent);
527           print_children (parent);
528         }
529       if (bsd_style_output)
530         printf ("\n");
531       printf ("-----------------------------------------------\n");
532       if (bsd_style_output)
533         printf ("\n");
534     }
535   free (timesortsym);
536   if (print_descriptions && !bsd_style_output)
537     {
538       fsf_callg_blurb (stdout);
539     }
540 }
541
542
543 static int
544 DEFUN (cmp_name, (left, right), const PTR left AND const PTR right)
545 {
546   const Sym **npp1 = (const Sym **) left;
547   const Sym **npp2 = (const Sym **) right;
548
549   return strcmp ((*npp1)->name, (*npp2)->name);
550 }
551
552
553 void
554 DEFUN_VOID (cg_print_index)
555 {
556   int index, nnames, todo, i, j, col, starting_col;
557   Sym **name_sorted_syms, *sym;
558   const char *filename;
559   char buf[20];
560   int column_width = (output_width - 1) / 3;    /* don't write in last col! */
561   /*
562    * Now, sort regular function name alphabetically to create an
563    * index:
564    */
565   name_sorted_syms = (Sym **) xmalloc ((symtab.len + num_cycles) * sizeof (Sym *));
566   for (index = 0, nnames = 0; index < symtab.len; index++)
567     {
568       if (ignore_zeros && symtab.base[index].ncalls == 0
569           && symtab.base[index].hist.time == 0)
570         {
571           continue;
572         }
573       name_sorted_syms[nnames++] = &symtab.base[index];
574     }
575   qsort (name_sorted_syms, nnames, sizeof (Sym *), cmp_name);
576   for (index = 1, todo = nnames; index <= num_cycles; index++)
577     {
578       name_sorted_syms[todo++] = &cycle_header[index];
579     }
580   printf ("\f\nIndex by function name\n\n");
581   index = (todo + 2) / 3;
582   for (i = 0; i < index; i++)
583     {
584       col = 0;
585       starting_col = 0;
586       for (j = i; j < todo; j += index)
587         {
588           sym = name_sorted_syms[j];
589           if (sym->cg.print_flag)
590             {
591               sprintf (buf, "[%d]", sym->cg.index);
592             }
593           else
594             {
595               sprintf (buf, "(%d)", sym->cg.index);
596             }
597           if (j < nnames)
598             {
599               if (bsd_style_output)
600                 {
601                   printf ("%6.6s %-19.19s", buf, sym->name);
602                 }
603               else
604                 {
605                   col += strlen (buf);
606                   for (; col < starting_col + 5; ++col)
607                     {
608                       putchar (' ');
609                     }
610                   printf (" %s ", buf);
611                   col += print_name_only (sym);
612                   if (!line_granularity && sym->is_static && sym->file)
613                     {
614                       filename = sym->file->name;
615                       if (!print_path)
616                         {
617                           filename = strrchr (filename, '/');
618                           if (filename)
619                             {
620                               ++filename;
621                             }
622                           else
623                             {
624                               filename = sym->file->name;
625                             }
626                         }
627                       printf (" (%s)", filename);
628                       col += strlen (filename) + 3;
629                     }
630                 }
631             }
632           else
633             {
634               if (bsd_style_output)
635                 {
636                   printf ("%6.6s ", buf);
637                   sprintf (buf, "<cycle %d>", sym->cg.cyc.num);
638                   printf ("%-19.19s", buf);
639                 }
640               else
641                 {
642                   col += strlen (buf);
643                   for (; col < starting_col + 5; ++col)
644                     putchar (' ');
645                   printf (" %s ", buf);
646                   sprintf (buf, "<cycle %d>", sym->cg.cyc.num);
647                   printf ("%s", buf);
648                   col += strlen (buf);
649                 }
650             }
651           starting_col += column_width;
652         }
653       printf ("\n");
654     }
655   free (name_sorted_syms);
656 }