perf report: Allow limiting the number of entries to print in callchains
[pandora-kernel.git] / tools / perf / util / hist.c
1 #include "hist.h"
2 #include "session.h"
3 #include "sort.h"
4 #include <math.h>
5
6 struct callchain_param  callchain_param = {
7         .mode   = CHAIN_GRAPH_REL,
8         .min_percent = 0.5
9 };
10
11 static void perf_session__add_cpumode_count(struct hist_entry *he,
12                                             unsigned int cpumode, u64 count)
13 {
14         switch (cpumode) {
15         case PERF_RECORD_MISC_KERNEL:
16                 he->count_sys += count;
17                 break;
18         case PERF_RECORD_MISC_USER:
19                 he->count_us += count;
20                 break;
21         case PERF_RECORD_MISC_GUEST_KERNEL:
22                 he->count_guest_sys += count;
23                 break;
24         case PERF_RECORD_MISC_GUEST_USER:
25                 he->count_guest_us += count;
26                 break;
27         default:
28                 break;
29         }
30 }
31
32 /*
33  * histogram, sorted on item, collects counts
34  */
35
36 static struct hist_entry *hist_entry__new(struct hist_entry *template)
37 {
38         size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_node) : 0;
39         struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
40
41         if (self != NULL) {
42                 *self = *template;
43                 if (symbol_conf.use_callchain)
44                         callchain_init(self->callchain);
45         }
46
47         return self;
48 }
49
50 struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
51                                                   struct addr_location *al,
52                                                   struct symbol *sym_parent,
53                                                   u64 count)
54 {
55         struct rb_node **p = &hists->rb_node;
56         struct rb_node *parent = NULL;
57         struct hist_entry *he;
58         struct hist_entry entry = {
59                 .thread = al->thread,
60                 .ms = {
61                         .map    = al->map,
62                         .sym    = al->sym,
63                 },
64                 .ip     = al->addr,
65                 .level  = al->level,
66                 .count  = count,
67                 .parent = sym_parent,
68         };
69         int cmp;
70
71         while (*p != NULL) {
72                 parent = *p;
73                 he = rb_entry(parent, struct hist_entry, rb_node);
74
75                 cmp = hist_entry__cmp(&entry, he);
76
77                 if (!cmp) {
78                         he->count += count;
79                         goto out;
80                 }
81
82                 if (cmp < 0)
83                         p = &(*p)->rb_left;
84                 else
85                         p = &(*p)->rb_right;
86         }
87
88         he = hist_entry__new(&entry);
89         if (!he)
90                 return NULL;
91         rb_link_node(&he->rb_node, parent, p);
92         rb_insert_color(&he->rb_node, hists);
93 out:
94         perf_session__add_cpumode_count(he, al->cpumode, count);
95         return he;
96 }
97
98 int64_t
99 hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
100 {
101         struct sort_entry *se;
102         int64_t cmp = 0;
103
104         list_for_each_entry(se, &hist_entry__sort_list, list) {
105                 cmp = se->se_cmp(left, right);
106                 if (cmp)
107                         break;
108         }
109
110         return cmp;
111 }
112
113 int64_t
114 hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
115 {
116         struct sort_entry *se;
117         int64_t cmp = 0;
118
119         list_for_each_entry(se, &hist_entry__sort_list, list) {
120                 int64_t (*f)(struct hist_entry *, struct hist_entry *);
121
122                 f = se->se_collapse ?: se->se_cmp;
123
124                 cmp = f(left, right);
125                 if (cmp)
126                         break;
127         }
128
129         return cmp;
130 }
131
132 void hist_entry__free(struct hist_entry *he)
133 {
134         free(he);
135 }
136
137 /*
138  * collapse the histogram
139  */
140
141 static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
142 {
143         struct rb_node **p = &root->rb_node;
144         struct rb_node *parent = NULL;
145         struct hist_entry *iter;
146         int64_t cmp;
147
148         while (*p != NULL) {
149                 parent = *p;
150                 iter = rb_entry(parent, struct hist_entry, rb_node);
151
152                 cmp = hist_entry__collapse(iter, he);
153
154                 if (!cmp) {
155                         iter->count += he->count;
156                         hist_entry__free(he);
157                         return;
158                 }
159
160                 if (cmp < 0)
161                         p = &(*p)->rb_left;
162                 else
163                         p = &(*p)->rb_right;
164         }
165
166         rb_link_node(&he->rb_node, parent, p);
167         rb_insert_color(&he->rb_node, root);
168 }
169
170 void perf_session__collapse_resort(struct rb_root *hists)
171 {
172         struct rb_root tmp;
173         struct rb_node *next;
174         struct hist_entry *n;
175
176         if (!sort__need_collapse)
177                 return;
178
179         tmp = RB_ROOT;
180         next = rb_first(hists);
181
182         while (next) {
183                 n = rb_entry(next, struct hist_entry, rb_node);
184                 next = rb_next(&n->rb_node);
185
186                 rb_erase(&n->rb_node, hists);
187                 collapse__insert_entry(&tmp, n);
188         }
189
190         *hists = tmp;
191 }
192
193 /*
194  * reverse the map, sort on count.
195  */
196
197 static void perf_session__insert_output_hist_entry(struct rb_root *root,
198                                                    struct hist_entry *he,
199                                                    u64 min_callchain_hits)
200 {
201         struct rb_node **p = &root->rb_node;
202         struct rb_node *parent = NULL;
203         struct hist_entry *iter;
204
205         if (symbol_conf.use_callchain)
206                 callchain_param.sort(&he->sorted_chain, he->callchain,
207                                       min_callchain_hits, &callchain_param);
208
209         while (*p != NULL) {
210                 parent = *p;
211                 iter = rb_entry(parent, struct hist_entry, rb_node);
212
213                 if (he->count > iter->count)
214                         p = &(*p)->rb_left;
215                 else
216                         p = &(*p)->rb_right;
217         }
218
219         rb_link_node(&he->rb_node, parent, p);
220         rb_insert_color(&he->rb_node, root);
221 }
222
223 u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples)
224 {
225         struct rb_root tmp;
226         struct rb_node *next;
227         struct hist_entry *n;
228         u64 min_callchain_hits;
229         u64 nr_hists = 0;
230
231         min_callchain_hits =
232                 total_samples * (callchain_param.min_percent / 100);
233
234         tmp = RB_ROOT;
235         next = rb_first(hists);
236
237         while (next) {
238                 n = rb_entry(next, struct hist_entry, rb_node);
239                 next = rb_next(&n->rb_node);
240
241                 rb_erase(&n->rb_node, hists);
242                 perf_session__insert_output_hist_entry(&tmp, n,
243                                                        min_callchain_hits);
244                 ++nr_hists;
245         }
246
247         *hists = tmp;
248         return nr_hists;
249 }
250
251 static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
252 {
253         int i;
254         int ret = fprintf(fp, "            ");
255
256         for (i = 0; i < left_margin; i++)
257                 ret += fprintf(fp, " ");
258
259         return ret;
260 }
261
262 static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
263                                           int left_margin)
264 {
265         int i;
266         size_t ret = callchain__fprintf_left_margin(fp, left_margin);
267
268         for (i = 0; i < depth; i++)
269                 if (depth_mask & (1 << i))
270                         ret += fprintf(fp, "|          ");
271                 else
272                         ret += fprintf(fp, "           ");
273
274         ret += fprintf(fp, "\n");
275
276         return ret;
277 }
278
279 static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
280                                      int depth, int depth_mask, int count,
281                                      u64 total_samples, int hits,
282                                      int left_margin)
283 {
284         int i;
285         size_t ret = 0;
286
287         ret += callchain__fprintf_left_margin(fp, left_margin);
288         for (i = 0; i < depth; i++) {
289                 if (depth_mask & (1 << i))
290                         ret += fprintf(fp, "|");
291                 else
292                         ret += fprintf(fp, " ");
293                 if (!count && i == depth - 1) {
294                         double percent;
295
296                         percent = hits * 100.0 / total_samples;
297                         ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
298                 } else
299                         ret += fprintf(fp, "%s", "          ");
300         }
301         if (chain->ms.sym)
302                 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
303         else
304                 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
305
306         return ret;
307 }
308
309 static struct symbol *rem_sq_bracket;
310 static struct callchain_list rem_hits;
311
312 static void init_rem_hits(void)
313 {
314         rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
315         if (!rem_sq_bracket) {
316                 fprintf(stderr, "Not enough memory to display remaining hits\n");
317                 return;
318         }
319
320         strcpy(rem_sq_bracket->name, "[...]");
321         rem_hits.ms.sym = rem_sq_bracket;
322 }
323
324 static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
325                                          u64 total_samples, int depth,
326                                          int depth_mask, int left_margin)
327 {
328         struct rb_node *node, *next;
329         struct callchain_node *child;
330         struct callchain_list *chain;
331         int new_depth_mask = depth_mask;
332         u64 new_total;
333         u64 remaining;
334         size_t ret = 0;
335         int i;
336         uint entries_printed = 0;
337
338         if (callchain_param.mode == CHAIN_GRAPH_REL)
339                 new_total = self->children_hit;
340         else
341                 new_total = total_samples;
342
343         remaining = new_total;
344
345         node = rb_first(&self->rb_root);
346         while (node) {
347                 u64 cumul;
348
349                 child = rb_entry(node, struct callchain_node, rb_node);
350                 cumul = cumul_hits(child);
351                 remaining -= cumul;
352
353                 /*
354                  * The depth mask manages the output of pipes that show
355                  * the depth. We don't want to keep the pipes of the current
356                  * level for the last child of this depth.
357                  * Except if we have remaining filtered hits. They will
358                  * supersede the last child
359                  */
360                 next = rb_next(node);
361                 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
362                         new_depth_mask &= ~(1 << (depth - 1));
363
364                 /*
365                  * But we keep the older depth mask for the line separator
366                  * to keep the level link until we reach the last child
367                  */
368                 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
369                                                    left_margin);
370                 i = 0;
371                 list_for_each_entry(chain, &child->val, list) {
372                         ret += ipchain__fprintf_graph(fp, chain, depth,
373                                                       new_depth_mask, i++,
374                                                       new_total,
375                                                       cumul,
376                                                       left_margin);
377                 }
378                 ret += __callchain__fprintf_graph(fp, child, new_total,
379                                                   depth + 1,
380                                                   new_depth_mask | (1 << depth),
381                                                   left_margin);
382                 node = next;
383                 if (++entries_printed == callchain_param.print_limit)
384                         break;
385         }
386
387         if (callchain_param.mode == CHAIN_GRAPH_REL &&
388                 remaining && remaining != new_total) {
389
390                 if (!rem_sq_bracket)
391                         return ret;
392
393                 new_depth_mask &= ~(1 << (depth - 1));
394
395                 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
396                                               new_depth_mask, 0, new_total,
397                                               remaining, left_margin);
398         }
399
400         return ret;
401 }
402
403 static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
404                                        u64 total_samples, int left_margin)
405 {
406         struct callchain_list *chain;
407         bool printed = false;
408         int i = 0;
409         int ret = 0;
410         u32 entries_printed = 0;
411
412         list_for_each_entry(chain, &self->val, list) {
413                 if (!i++ && sort__first_dimension == SORT_SYM)
414                         continue;
415
416                 if (!printed) {
417                         ret += callchain__fprintf_left_margin(fp, left_margin);
418                         ret += fprintf(fp, "|\n");
419                         ret += callchain__fprintf_left_margin(fp, left_margin);
420                         ret += fprintf(fp, "---");
421
422                         left_margin += 3;
423                         printed = true;
424                 } else
425                         ret += callchain__fprintf_left_margin(fp, left_margin);
426
427                 if (chain->ms.sym)
428                         ret += fprintf(fp, " %s\n", chain->ms.sym->name);
429                 else
430                         ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
431
432                 if (++entries_printed == callchain_param.print_limit)
433                         break;
434         }
435
436         ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
437
438         return ret;
439 }
440
441 static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
442                                       u64 total_samples)
443 {
444         struct callchain_list *chain;
445         size_t ret = 0;
446
447         if (!self)
448                 return 0;
449
450         ret += callchain__fprintf_flat(fp, self->parent, total_samples);
451
452
453         list_for_each_entry(chain, &self->val, list) {
454                 if (chain->ip >= PERF_CONTEXT_MAX)
455                         continue;
456                 if (chain->ms.sym)
457                         ret += fprintf(fp, "                %s\n", chain->ms.sym->name);
458                 else
459                         ret += fprintf(fp, "                %p\n",
460                                         (void *)(long)chain->ip);
461         }
462
463         return ret;
464 }
465
466 static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
467                                             u64 total_samples, int left_margin)
468 {
469         struct rb_node *rb_node;
470         struct callchain_node *chain;
471         size_t ret = 0;
472         u32 entries_printed = 0;
473
474         rb_node = rb_first(&self->sorted_chain);
475         while (rb_node) {
476                 double percent;
477
478                 chain = rb_entry(rb_node, struct callchain_node, rb_node);
479                 percent = chain->hit * 100.0 / total_samples;
480                 switch (callchain_param.mode) {
481                 case CHAIN_FLAT:
482                         ret += percent_color_fprintf(fp, "           %6.2f%%\n",
483                                                      percent);
484                         ret += callchain__fprintf_flat(fp, chain, total_samples);
485                         break;
486                 case CHAIN_GRAPH_ABS: /* Falldown */
487                 case CHAIN_GRAPH_REL:
488                         ret += callchain__fprintf_graph(fp, chain, total_samples,
489                                                         left_margin);
490                 case CHAIN_NONE:
491                 default:
492                         break;
493                 }
494                 ret += fprintf(fp, "\n");
495                 if (++entries_printed == callchain_param.print_limit)
496                         break;
497                 rb_node = rb_next(rb_node);
498         }
499
500         return ret;
501 }
502
503 int hist_entry__snprintf(struct hist_entry *self,
504                            char *s, size_t size,
505                            struct perf_session *pair_session,
506                            bool show_displacement,
507                            long displacement, bool color,
508                            u64 session_total)
509 {
510         struct sort_entry *se;
511         u64 count, total, count_sys, count_us, count_guest_sys, count_guest_us;
512         const char *sep = symbol_conf.field_sep;
513         int ret;
514
515         if (symbol_conf.exclude_other && !self->parent)
516                 return 0;
517
518         if (pair_session) {
519                 count = self->pair ? self->pair->count : 0;
520                 total = pair_session->events_stats.total;
521                 count_sys = self->pair ? self->pair->count_sys : 0;
522                 count_us = self->pair ? self->pair->count_us : 0;
523                 count_guest_sys = self->pair ? self->pair->count_guest_sys : 0;
524                 count_guest_us = self->pair ? self->pair->count_guest_us : 0;
525         } else {
526                 count = self->count;
527                 total = session_total;
528                 count_sys = self->count_sys;
529                 count_us = self->count_us;
530                 count_guest_sys = self->count_guest_sys;
531                 count_guest_us = self->count_guest_us;
532         }
533
534         if (total) {
535                 if (color)
536                         ret = percent_color_snprintf(s, size,
537                                                      sep ? "%.2f" : "   %6.2f%%",
538                                                      (count * 100.0) / total);
539                 else
540                         ret = snprintf(s, size, sep ? "%.2f" : "   %6.2f%%",
541                                        (count * 100.0) / total);
542                 if (symbol_conf.show_cpu_utilization) {
543                         ret += percent_color_snprintf(s + ret, size - ret,
544                                         sep ? "%.2f" : "   %6.2f%%",
545                                         (count_sys * 100.0) / total);
546                         ret += percent_color_snprintf(s + ret, size - ret,
547                                         sep ? "%.2f" : "   %6.2f%%",
548                                         (count_us * 100.0) / total);
549                         if (perf_guest) {
550                                 ret += percent_color_snprintf(s + ret,
551                                                 size - ret,
552                                                 sep ? "%.2f" : "   %6.2f%%",
553                                                 (count_guest_sys * 100.0) /
554                                                                 total);
555                                 ret += percent_color_snprintf(s + ret,
556                                                 size - ret,
557                                                 sep ? "%.2f" : "   %6.2f%%",
558                                                 (count_guest_us * 100.0) /
559                                                                 total);
560                         }
561                 }
562         } else
563                 ret = snprintf(s, size, sep ? "%lld" : "%12lld ", count);
564
565         if (symbol_conf.show_nr_samples) {
566                 if (sep)
567                         ret += snprintf(s + ret, size - ret, "%c%lld", *sep, count);
568                 else
569                         ret += snprintf(s + ret, size - ret, "%11lld", count);
570         }
571
572         if (pair_session) {
573                 char bf[32];
574                 double old_percent = 0, new_percent = 0, diff;
575
576                 if (total > 0)
577                         old_percent = (count * 100.0) / total;
578                 if (session_total > 0)
579                         new_percent = (self->count * 100.0) / session_total;
580
581                 diff = new_percent - old_percent;
582
583                 if (fabs(diff) >= 0.01)
584                         snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
585                 else
586                         snprintf(bf, sizeof(bf), " ");
587
588                 if (sep)
589                         ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
590                 else
591                         ret += snprintf(s + ret, size - ret, "%11.11s", bf);
592
593                 if (show_displacement) {
594                         if (displacement)
595                                 snprintf(bf, sizeof(bf), "%+4ld", displacement);
596                         else
597                                 snprintf(bf, sizeof(bf), " ");
598
599                         if (sep)
600                                 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
601                         else
602                                 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
603                 }
604         }
605
606         list_for_each_entry(se, &hist_entry__sort_list, list) {
607                 if (se->elide)
608                         continue;
609
610                 ret += snprintf(s + ret, size - ret, "%s", sep ?: "  ");
611                 ret += se->se_snprintf(self, s + ret, size - ret,
612                                        se->se_width ? *se->se_width : 0);
613         }
614
615         return ret;
616 }
617
618 int hist_entry__fprintf(struct hist_entry *self,
619                         struct perf_session *pair_session,
620                         bool show_displacement,
621                         long displacement, FILE *fp,
622                         u64 session_total)
623 {
624         char bf[512];
625         hist_entry__snprintf(self, bf, sizeof(bf), pair_session,
626                              show_displacement, displacement,
627                              true, session_total);
628         return fprintf(fp, "%s\n", bf);
629 }
630
631 static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
632                                             u64 session_total)
633 {
634         int left_margin = 0;
635
636         if (sort__first_dimension == SORT_COMM) {
637                 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
638                                                          typeof(*se), list);
639                 left_margin = se->se_width ? *se->se_width : 0;
640                 left_margin -= thread__comm_len(self->thread);
641         }
642
643         return hist_entry_callchain__fprintf(fp, self, session_total,
644                                              left_margin);
645 }
646
647 size_t perf_session__fprintf_hists(struct rb_root *hists,
648                                    struct perf_session *pair,
649                                    bool show_displacement, FILE *fp,
650                                    u64 session_total)
651 {
652         struct sort_entry *se;
653         struct rb_node *nd;
654         size_t ret = 0;
655         unsigned long position = 1;
656         long displacement = 0;
657         unsigned int width;
658         const char *sep = symbol_conf.field_sep;
659         char *col_width = symbol_conf.col_width_list_str;
660
661         init_rem_hits();
662
663         fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
664
665         if (symbol_conf.show_nr_samples) {
666                 if (sep)
667                         fprintf(fp, "%cSamples", *sep);
668                 else
669                         fputs("  Samples  ", fp);
670         }
671
672         if (symbol_conf.show_cpu_utilization) {
673                 if (sep) {
674                         ret += fprintf(fp, "%csys", *sep);
675                         ret += fprintf(fp, "%cus", *sep);
676                         if (perf_guest) {
677                                 ret += fprintf(fp, "%cguest sys", *sep);
678                                 ret += fprintf(fp, "%cguest us", *sep);
679                         }
680                 } else {
681                         ret += fprintf(fp, "  sys  ");
682                         ret += fprintf(fp, "  us  ");
683                         if (perf_guest) {
684                                 ret += fprintf(fp, "  guest sys  ");
685                                 ret += fprintf(fp, "  guest us  ");
686                         }
687                 }
688         }
689
690         if (pair) {
691                 if (sep)
692                         ret += fprintf(fp, "%cDelta", *sep);
693                 else
694                         ret += fprintf(fp, "  Delta    ");
695
696                 if (show_displacement) {
697                         if (sep)
698                                 ret += fprintf(fp, "%cDisplacement", *sep);
699                         else
700                                 ret += fprintf(fp, " Displ");
701                 }
702         }
703
704         list_for_each_entry(se, &hist_entry__sort_list, list) {
705                 if (se->elide)
706                         continue;
707                 if (sep) {
708                         fprintf(fp, "%c%s", *sep, se->se_header);
709                         continue;
710                 }
711                 width = strlen(se->se_header);
712                 if (se->se_width) {
713                         if (symbol_conf.col_width_list_str) {
714                                 if (col_width) {
715                                         *se->se_width = atoi(col_width);
716                                         col_width = strchr(col_width, ',');
717                                         if (col_width)
718                                                 ++col_width;
719                                 }
720                         }
721                         width = *se->se_width = max(*se->se_width, width);
722                 }
723                 fprintf(fp, "  %*s", width, se->se_header);
724         }
725         fprintf(fp, "\n");
726
727         if (sep)
728                 goto print_entries;
729
730         fprintf(fp, "# ........");
731         if (symbol_conf.show_nr_samples)
732                 fprintf(fp, " ..........");
733         if (pair) {
734                 fprintf(fp, " ..........");
735                 if (show_displacement)
736                         fprintf(fp, " .....");
737         }
738         list_for_each_entry(se, &hist_entry__sort_list, list) {
739                 unsigned int i;
740
741                 if (se->elide)
742                         continue;
743
744                 fprintf(fp, "  ");
745                 if (se->se_width)
746                         width = *se->se_width;
747                 else
748                         width = strlen(se->se_header);
749                 for (i = 0; i < width; i++)
750                         fprintf(fp, ".");
751         }
752
753         fprintf(fp, "\n#\n");
754
755 print_entries:
756         for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
757                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
758
759                 if (show_displacement) {
760                         if (h->pair != NULL)
761                                 displacement = ((long)h->pair->position -
762                                                 (long)position);
763                         else
764                                 displacement = 0;
765                         ++position;
766                 }
767                 ret += hist_entry__fprintf(h, pair, show_displacement,
768                                            displacement, fp, session_total);
769
770                 if (symbol_conf.use_callchain)
771                         ret += hist_entry__fprintf_callchain(h, fp, session_total);
772
773                 if (h->ms.map == NULL && verbose > 1) {
774                         __map_groups__fprintf_maps(&h->thread->mg,
775                                                    MAP__FUNCTION, verbose, fp);
776                         fprintf(fp, "%.10s end\n", graph_dotted_line);
777                 }
778         }
779
780         free(rem_sq_bracket);
781
782         return ret;
783 }