Merge from trunk:
[official-gcc.git] / main / libgcc / dyn-ipa.c
blobe35766a761323b09f7343ecb5a81290961f10e64
1 /* Compile this one with gcc. */
2 /* Copyright (C) 2009. Free Software Foundation, Inc.
3 Contributed by Xinliang David Li (davidxl@google.com) and
4 Raksit Ashok (raksit@google.com)
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
28 struct dyn_pointer_set;
29 struct gcov_info;
30 struct gcov_info *__gcov_list __attribute__((hidden));
32 #ifdef IN_GCOV_TOOL
33 struct dyn_imp_mod;
34 struct gcov_info;
36 void __gcov_compute_module_groups (void) {}
37 const struct dyn_imp_mod **
38 gcov_get_sorted_import_module_array (struct gcov_info *mod_info,
39 unsigned *len) {return 0;}
40 void
41 gcov_write_module_infos (struct gcov_info *mod_info) {}
42 void
43 __gcov_finalize_dyn_callgraph (void) {}
44 #else
46 #include "tconfig.h"
47 #include "tsystem.h"
48 #include "coretypes.h"
49 #include "tm.h"
52 #include "libgcov.h"
53 #define XNEWVEC(type,ne) (type *)malloc(sizeof(type) * (ne))
54 #define XCNEWVEC(type,ne) (type *)calloc(1, sizeof(type) * (ne))
55 #define XNEW(type) (type *)malloc(sizeof(type))
56 #define XDELETEVEC(p) free(p)
57 #define XDELETE(p) free(p)
59 struct dyn_cgraph_node
61 struct dyn_cgraph_edge *callees;
62 struct dyn_cgraph_edge *callers;
63 struct dyn_pointer_set *imported_modules;
65 gcov_type guid;
66 gcov_type sum_in_count;
67 gcov_unsigned_t visited;
70 struct dyn_cgraph_edge
72 struct dyn_cgraph_node *caller;
73 struct dyn_cgraph_node *callee;
74 struct dyn_cgraph_edge *next_caller;
75 struct dyn_cgraph_edge *next_callee;
76 gcov_type count;
79 struct dyn_module_info
81 struct dyn_pointer_set *imported_modules;
82 gcov_unsigned_t max_func_ident;
84 /* Used by new algorithm. This dyn_pointer_set only
85 stored the gcov_info pointer, keyed by
86 module ident. */
87 struct dyn_pointer_set *exported_to;
88 gcov_unsigned_t group_ggc_mem;
91 struct dyn_cgraph
93 struct dyn_pointer_set **call_graph_nodes;
94 struct gcov_info **modules;
95 /* supplement module information */
96 struct dyn_module_info *sup_modules;
97 unsigned num_modules;
98 unsigned num_nodes_executed;
99 /* used by new algorithm */
100 struct modu_node *modu_nodes;
103 /* Module info is stored in dyn_caph->sup_modules
104 which is indexed by m_ix. */
105 struct modu_node
107 struct gcov_info *module;
108 struct modu_edge *callees;
109 struct modu_edge *callers;
112 struct modu_edge
114 struct modu_node *caller;
115 struct modu_node *callee;
116 struct modu_edge *next_caller;
117 struct modu_edge *next_callee;
118 unsigned n_edges; /* used when combining edges */
119 gcov_type sum_count;
120 unsigned char visited;
123 struct dyn_pointer_set
125 size_t log_slots;
126 size_t n_slots; /* n_slots = 2^log_slots */
127 size_t n_elements;
129 void **slots;
130 unsigned (*get_key) (const void *);
133 typedef long dyn_fibheapkey_t;
135 typedef struct dyn_fibheap
137 size_t nodes;
138 struct fibnode *min;
139 struct fibnode *root;
140 } *dyn_fibheap_t;
142 typedef struct fibnode
144 struct fibnode *parent;
145 struct fibnode *child;
146 struct fibnode *left;
147 struct fibnode *right;
148 dyn_fibheapkey_t key;
149 void *data;
150 unsigned int degree : 31;
151 unsigned int mark : 1;
152 } *fibnode_t;
154 static dyn_fibheap_t dyn_fibheap_new (void);
155 static fibnode_t dyn_fibheap_insert (dyn_fibheap_t, dyn_fibheapkey_t, void *);
156 static void *dyn_fibheap_extract_min (dyn_fibheap_t);
158 extern gcov_unsigned_t __gcov_lipo_cutoff;
159 extern gcov_unsigned_t __gcov_lipo_random_seed;
160 extern gcov_unsigned_t __gcov_lipo_random_group_size;
161 extern gcov_unsigned_t __gcov_lipo_propagate_scale;
162 extern gcov_unsigned_t __gcov_lipo_dump_cgraph;
163 extern gcov_unsigned_t __gcov_lipo_max_mem;
164 extern gcov_unsigned_t __gcov_lipo_grouping_algorithm;
165 extern gcov_unsigned_t __gcov_lipo_merge_modu_edges;
166 extern gcov_unsigned_t __gcov_lipo_weak_inclusion;
168 #if defined(inhibit_libc)
169 void __gcov_build_callgraph (void) {}
170 #else
172 void __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN;
173 void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN;
174 static void gcov_dump_callgraph (gcov_type);
175 static void gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node);
176 static void gcov_dump_cgraph_node (struct dyn_cgraph_node *node,
177 unsigned m, unsigned f);
178 static int do_cgraph_dump (void);
180 static void
181 gcov_dump_cgraph_node_dot (struct dyn_cgraph_node *node,
182 unsigned m, unsigned f,
183 gcov_type cutoff_count);
184 static void
185 pointer_set_destroy (struct dyn_pointer_set *pset);
186 static void
187 pointer_set_destroy_not_free_value_pointer (struct dyn_pointer_set *);
188 static void **
189 pointer_set_find_or_insert (struct dyn_pointer_set *pset, unsigned key);
190 static struct dyn_pointer_set *
191 pointer_set_create (unsigned (*get_key) (const void *));
193 static struct dyn_cgraph the_dyn_call_graph;
194 static int total_zero_count = 0;
195 static int total_insane_count = 0;
197 enum GROUPING_ALGORITHM
199 EAGER_PROPAGATION_ALGORITHM=0,
200 INCLUSION_BASED_PRIORITY_ALGORITHM
202 static int flag_alg_mode;
203 static int flag_modu_merge_edges;
204 static int flag_weak_inclusion;
205 static gcov_unsigned_t mem_threshold;
207 /* Returns 0 if no dump is enabled. Returns 1 if text form graph
208 dump is enabled. Returns 2 if .dot form dump is enabled. */
210 static int
211 do_cgraph_dump (void)
213 const char *dyn_cgraph_dump = 0;
215 if (__gcov_lipo_dump_cgraph)
216 return __gcov_lipo_dump_cgraph;
218 dyn_cgraph_dump = getenv ("GCOV_DYN_CGRAPH_DUMP");
220 if (!dyn_cgraph_dump || !strlen (dyn_cgraph_dump))
221 return 0;
223 if (dyn_cgraph_dump[0] == '1')
224 return 1;
225 if (dyn_cgraph_dump[0] == '2')
226 return 2;
228 return 0;
231 static void
232 init_dyn_cgraph_node (struct dyn_cgraph_node *node, gcov_type guid)
234 node->callees = 0;
235 node->callers = 0;
236 node->imported_modules = 0;
237 node->guid = guid;
238 node->visited = 0;
241 /* Return module_id. FUNC_GUID is the global unique id.
242 This id is 1 based. 0 is the invalid id. */
244 static inline gcov_unsigned_t
245 get_module_ident_from_func_glob_uid (gcov_type func_guid)
247 return EXTRACT_MODULE_ID_FROM_GLOBAL_ID (func_guid);
250 /* Return module_id for MODULE_INFO. */
252 static inline gcov_unsigned_t
253 get_module_ident (const struct gcov_info *module_info)
255 return module_info->mod_info->ident;
258 /* Return intra-module function id given function global unique id
259 FUNC_GUID. */
261 static inline gcov_unsigned_t
262 get_intra_module_func_id (gcov_type func_guid)
264 return EXTRACT_FUNC_ID_FROM_GLOBAL_ID (func_guid);
267 /* Return the pointer to the dynamic call graph node for FUNC_GUID. */
269 static inline struct dyn_cgraph_node *
270 get_cgraph_node (gcov_type func_guid)
272 gcov_unsigned_t mod_idx, func_id;
274 mod_idx = get_module_ident_from_func_glob_uid (func_guid) - 1;
276 /* This is to workaround: calls in __static_initialization_and_destruction
277 should not be instrumented as the module id context for the callees have
278 not setup yet -- this leads to mod_idx == (unsigned) (0 - 1). Multithreaded
279 programs may also produce insane func_guid in the profile counter. */
280 if (mod_idx >= the_dyn_call_graph.num_modules)
281 return 0;
283 func_id = get_intra_module_func_id (func_guid);
284 if (func_id > the_dyn_call_graph.sup_modules[mod_idx].max_func_ident)
285 return 0;
287 return *(pointer_set_find_or_insert
288 (the_dyn_call_graph.call_graph_nodes[mod_idx], func_id));
291 static inline unsigned
292 imp_mod_get_key (const void *p)
294 return ((const struct dyn_imp_mod *) p)->imp_mod->mod_info->ident;
297 static int
298 imp_mod_set_insert (struct dyn_pointer_set *p, const struct gcov_info *imp_mod,
299 double wt)
301 struct dyn_imp_mod **m = (struct dyn_imp_mod **)
302 pointer_set_find_or_insert (p, get_module_ident (imp_mod));
303 if (*m)
305 (*m)->weight += wt;
306 return 1;
308 else
310 *m = XNEW (struct dyn_imp_mod);
311 (*m)->imp_mod = imp_mod;
312 (*m)->weight = wt;
313 p->n_elements++;
314 return 0;
318 /* Return the gcov_info pointer for module with id MODULE_ID. */
320 static inline struct gcov_info *
321 get_module_info (gcov_unsigned_t module_id)
323 return the_dyn_call_graph.modules[module_id - 1];
327 static inline unsigned
328 cgraph_node_get_key (const void *p)
330 return get_intra_module_func_id (((const struct dyn_cgraph_node *) p)->guid);
333 static inline unsigned
334 gcov_info_get_key (const void *p)
336 return get_module_ident ((const struct gcov_info *)p);
339 static struct dyn_pointer_set *
340 get_exported_to (unsigned module_ident)
342 gcc_assert (module_ident != 0);
343 return the_dyn_call_graph.sup_modules[module_ident - 1].exported_to;
346 static struct dyn_pointer_set *
347 create_exported_to (unsigned module_ident)
349 struct dyn_pointer_set *p;
351 gcc_assert (module_ident != 0);
352 p = pointer_set_create (gcov_info_get_key);
353 the_dyn_call_graph.sup_modules[module_ident - 1].exported_to = p;
354 return p;
357 static struct dyn_pointer_set *
358 get_imported_modus (unsigned module_ident)
360 struct dyn_pointer_set *p;
361 struct gcov_info *gi_ptr;
363 gcc_assert (module_ident != 0);
364 p = the_dyn_call_graph.sup_modules[module_ident - 1].imported_modules;
366 if (p)
367 return p;
369 the_dyn_call_graph.sup_modules[module_ident - 1].imported_modules = p
370 = pointer_set_create (imp_mod_get_key);
372 gi_ptr = the_dyn_call_graph.modules[module_ident - 1];
373 /* make the modules an auxiliay module to itself. */
374 imp_mod_set_insert (p, gi_ptr, 0);
376 return p;
379 /* Initialize dynamic call graph. */
381 static void
382 init_dyn_call_graph (void)
384 unsigned num_modules = 0;
385 struct gcov_info *gi_ptr;
386 const char *env_str;
387 int do_dump = (do_cgraph_dump () != 0);
389 the_dyn_call_graph.call_graph_nodes = 0;
390 the_dyn_call_graph.modules = 0;
391 the_dyn_call_graph.num_nodes_executed = 0;
393 flag_alg_mode = __gcov_lipo_grouping_algorithm;
394 flag_modu_merge_edges = __gcov_lipo_merge_modu_edges;
395 flag_weak_inclusion = __gcov_lipo_weak_inclusion;
396 mem_threshold = __gcov_lipo_max_mem * 1.25;
398 gi_ptr = __gcov_list;
400 for (; gi_ptr; gi_ptr = gi_ptr->next)
401 num_modules++;
403 the_dyn_call_graph.num_modules = num_modules;
405 the_dyn_call_graph.modules
406 = XNEWVEC (struct gcov_info *, num_modules);
408 the_dyn_call_graph.sup_modules
409 = XNEWVEC (struct dyn_module_info, num_modules);
410 memset (the_dyn_call_graph.sup_modules, 0,
411 num_modules * sizeof (struct dyn_module_info));
413 the_dyn_call_graph.call_graph_nodes
414 = XNEWVEC (struct dyn_pointer_set *, num_modules);
416 gi_ptr = __gcov_list;
418 if ((env_str = getenv ("GCOV_DYN_ALG")))
420 flag_alg_mode = atoi (env_str);
422 if ((env_str = getenv ("GCOV_DYN_MERGE_EDGES")))
423 flag_modu_merge_edges = atoi (env_str);
425 if ((env_str = getenv ("GCOV_DYN_WEAK_INCLUSION")))
426 flag_weak_inclusion = atoi (env_str);
428 if (do_dump)
429 fprintf (stderr,
430 "!!!! Using ALG=%d merge_edges=%d weak_inclusion=%d. \n",
431 flag_alg_mode, flag_modu_merge_edges, flag_weak_inclusion);
434 if (do_dump)
435 fprintf (stderr, "Group mem limit: %u KB \n",
436 __gcov_lipo_max_mem);
438 for (; gi_ptr; gi_ptr = gi_ptr->next)
440 /* mod_idx is module_ident - 1. */
441 unsigned j, mod_id, mod_idx, max_func_ident = 0;
442 struct dyn_cgraph_node *node;
444 /* initialize flags field. */
445 gi_ptr->mod_info->flags = 0;
447 mod_id = get_module_ident (gi_ptr);
448 if (do_dump)
449 fprintf (stderr, "Module %s %d uses %u KB memory in parsing\n",
450 gi_ptr->mod_info->source_filename, mod_id,
451 gi_ptr->mod_info->ggc_memory);
453 if (mod_id == 0)
455 fprintf (stderr, "Bad module_ident of 0. Skipping.\n");
456 continue;
458 mod_idx = mod_id - 1;
460 the_dyn_call_graph.modules[mod_idx] = gi_ptr;
462 the_dyn_call_graph.call_graph_nodes[mod_idx]
463 = pointer_set_create (cgraph_node_get_key);
465 for (j = 0; j < gi_ptr->n_functions; j++)
467 const struct gcov_fn_info *fi_ptr = gi_ptr->functions[j];
468 *(pointer_set_find_or_insert
469 (the_dyn_call_graph.call_graph_nodes[mod_idx], fi_ptr->ident))
470 = node = XNEW (struct dyn_cgraph_node);
471 the_dyn_call_graph.call_graph_nodes[mod_idx]->n_elements++;
472 init_dyn_cgraph_node (node, GEN_FUNC_GLOBAL_ID (gi_ptr->mod_info->ident,
473 fi_ptr->ident));
474 if (fi_ptr->ident > max_func_ident)
475 max_func_ident = fi_ptr->ident;
477 the_dyn_call_graph.sup_modules[mod_idx].max_func_ident = max_func_ident;
478 if (flag_alg_mode == INCLUSION_BASED_PRIORITY_ALGORITHM)
480 struct dyn_module_info *sup_module =
481 &(the_dyn_call_graph.sup_modules[mod_idx]);
483 sup_module->group_ggc_mem = gi_ptr->mod_info->ggc_memory;
484 sup_module->imported_modules = 0;
485 sup_module->exported_to = 0;
490 /* Free up memory allocated for dynamic call graph. */
492 void
493 __gcov_finalize_dyn_callgraph (void)
495 unsigned i;
496 struct gcov_info *gi_ptr;
498 for (i = 0; i < the_dyn_call_graph.num_modules; i++)
500 gi_ptr = the_dyn_call_graph.modules[i];
501 const struct gcov_fn_info *fi_ptr;
502 unsigned f_ix;
503 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
505 struct dyn_cgraph_node *node;
506 struct dyn_cgraph_edge *callees, *next_callee;
507 fi_ptr = gi_ptr->functions[f_ix];
508 node = *(pointer_set_find_or_insert
509 (the_dyn_call_graph.call_graph_nodes[i], fi_ptr->ident));
510 gcc_assert (node);
511 callees = node->callees;
513 if (!callees)
514 continue;
515 while (callees != 0)
517 next_callee = callees->next_callee;
518 XDELETE (callees);
519 callees = next_callee;
521 if (node->imported_modules)
522 pointer_set_destroy (node->imported_modules);
524 if (the_dyn_call_graph.call_graph_nodes[i])
525 pointer_set_destroy (the_dyn_call_graph.call_graph_nodes[i]);
526 /* Now delete sup modules */
527 if (the_dyn_call_graph.sup_modules[i].imported_modules)
528 pointer_set_destroy (the_dyn_call_graph.sup_modules[i].imported_modules);
529 if (flag_alg_mode == INCLUSION_BASED_PRIORITY_ALGORITHM
530 && the_dyn_call_graph.sup_modules[i].exported_to)
531 pointer_set_destroy_not_free_value_pointer
532 (the_dyn_call_graph.sup_modules[i].exported_to);
534 XDELETEVEC (the_dyn_call_graph.call_graph_nodes);
535 XDELETEVEC (the_dyn_call_graph.sup_modules);
536 XDELETEVEC (the_dyn_call_graph.modules);
539 /* Add outgoing edge OUT_EDGE for caller node CALLER. */
541 static void
542 gcov_add_out_edge (struct dyn_cgraph_node *caller,
543 struct dyn_cgraph_edge *out_edge)
545 if (!caller->callees)
546 caller->callees = out_edge;
547 else
549 out_edge->next_callee = caller->callees;
550 caller->callees = out_edge;
554 /* Add incoming edge IN_EDGE for callee node CALLEE. */
556 static void
557 gcov_add_in_edge (struct dyn_cgraph_node *callee,
558 struct dyn_cgraph_edge *in_edge)
560 if (!callee->callers)
561 callee->callers = in_edge;
562 else
564 in_edge->next_caller = callee->callers;
565 callee->callers = in_edge;
569 /* Add a call graph edge between caller CALLER and callee CALLEE.
570 The edge count is COUNT. */
572 static void
573 gcov_add_cgraph_edge (struct dyn_cgraph_node *caller,
574 struct dyn_cgraph_node *callee,
575 gcov_type count)
577 struct dyn_cgraph_edge *new_edge = XNEW (struct dyn_cgraph_edge);
578 new_edge->caller = caller;
579 new_edge->callee = callee;
580 new_edge->count = count;
581 new_edge->next_caller = 0;
582 new_edge->next_callee = 0;
584 gcov_add_out_edge (caller, new_edge);
585 gcov_add_in_edge (callee, new_edge);
588 /* Add call graph edges from direct calls for caller CALLER. DIR_CALL_COUNTERS
589 is the array of call counters. N_COUNTS is the number of counters. */
591 static void
592 gcov_build_callgraph_dc_fn (struct dyn_cgraph_node *caller,
593 gcov_type *dir_call_counters,
594 unsigned n_counts)
596 unsigned i;
598 for (i = 0; i < n_counts; i += 2)
600 struct dyn_cgraph_node *callee;
601 gcov_type count;
602 gcov_type callee_guid = dir_call_counters[i];
604 count = dir_call_counters[i + 1];
605 if (count == 0)
607 total_zero_count++;
608 continue;
610 callee = get_cgraph_node (callee_guid);
611 if (!callee)
613 total_insane_count++;
614 continue;
616 gcov_add_cgraph_edge (caller, callee, count);
620 /* Add call graph edges from indirect calls for caller CALLER. ICALL_COUNTERS
621 is the array of icall counters. N_COUNTS is the number of counters. */
623 static void
624 gcov_build_callgraph_ic_fn (struct dyn_cgraph_node *caller,
625 gcov_type *icall_counters,
626 unsigned n_counts)
628 unsigned i, j;
630 for (i = 0; i < n_counts; i += GCOV_ICALL_TOPN_NCOUNTS)
632 gcov_type *value_array = &icall_counters[i + 1];
633 for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
635 struct dyn_cgraph_node *callee;
636 gcov_type count;
637 gcov_type callee_guid = value_array[j];
639 count = value_array[j + 1];
640 /* Do not update zero count edge count
641 * as it means there is no target in this entry. */
642 if (count == 0)
643 continue;
644 callee = get_cgraph_node (callee_guid);
645 if (!callee)
647 total_insane_count++;
648 continue;
650 gcov_add_cgraph_edge (caller, callee, count);
655 /* Build the dynamic call graph. */
657 static void
658 gcov_build_callgraph (void)
660 struct gcov_info *gi_ptr;
661 unsigned m_ix;
663 init_dyn_call_graph ();
665 for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
667 const struct gcov_fn_info *fi_ptr;
668 unsigned f_ix, i;
670 gi_ptr = the_dyn_call_graph.modules[m_ix];
672 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
674 struct dyn_cgraph_node *caller;
675 const struct gcov_ctr_info *ci_ptr = 0;
677 fi_ptr = gi_ptr->functions[f_ix];
678 ci_ptr = fi_ptr->ctrs;
680 caller = *(pointer_set_find_or_insert
681 (the_dyn_call_graph.call_graph_nodes[m_ix],
682 fi_ptr->ident));
683 gcc_assert (caller);
685 for (i = 0; i < GCOV_COUNTERS; i++)
687 if (!gi_ptr->merge[i])
688 continue;
689 if (i == GCOV_COUNTER_DIRECT_CALL)
690 gcov_build_callgraph_dc_fn (caller, ci_ptr->values, ci_ptr->num);
692 if (i == GCOV_COUNTER_ICALL_TOPNV)
693 gcov_build_callgraph_ic_fn (caller, ci_ptr->values, ci_ptr->num);
695 if (i == GCOV_COUNTER_ARCS && 0)
697 gcov_type total_arc_count = 0;
698 unsigned arc;
699 for (arc = 0; arc < ci_ptr->num; arc++)
700 total_arc_count += ci_ptr->values[arc];
701 if (total_arc_count != 0)
702 the_dyn_call_graph.num_nodes_executed++;
704 ci_ptr++;
710 static inline size_t
711 hash1 (unsigned p, unsigned long max, unsigned long logmax)
713 const unsigned long long A = 0x9e3779b97f4a7c16ull;
714 const unsigned long long shift = 64 - logmax;
716 return ((A * (unsigned long) p) >> shift) & (max - 1);
719 /* Allocate an empty imported-modules set. */
721 static struct dyn_pointer_set *
722 pointer_set_create (unsigned (*get_key) (const void *))
724 struct dyn_pointer_set *result = XNEW (struct dyn_pointer_set);
726 result->n_elements = 0;
727 result->log_slots = 8;
728 result->n_slots = (size_t) 1 << result->log_slots;
730 result->slots = XNEWVEC (void *, result->n_slots);
731 memset (result->slots, 0, sizeof (void *) * result->n_slots);
732 result->get_key = get_key;
734 return result;
737 /* Reclaim all memory associated with PSET. */
739 static void
740 pointer_set_destroy (struct dyn_pointer_set *pset)
742 size_t i;
743 for (i = 0; i < pset->n_slots; i++)
744 if (pset->slots[i])
745 XDELETE (pset->slots[i]);
746 XDELETEVEC (pset->slots);
747 XDELETE (pset);
750 /* Reclaim the memory of PSET but not the value pointer. */
751 static void
752 pointer_set_destroy_not_free_value_pointer (struct dyn_pointer_set *pset)
754 XDELETEVEC (pset->slots);
755 XDELETE (pset);
758 /* Subroutine of pointer_set_find_or_insert. Return the insertion slot for KEY
759 into an empty element of SLOTS, an array of length N_SLOTS. */
760 static inline size_t
761 insert_aux (unsigned key, void **slots,
762 size_t n_slots, size_t log_slots,
763 unsigned (*get_key) (const void *))
765 size_t n = hash1 (key, n_slots, log_slots);
766 while (1)
768 if (slots[n] == 0 || get_key (slots[n]) == key)
769 return n;
770 else
772 ++n;
773 if (n == n_slots)
774 n = 0;
779 /* Find slot for KEY. KEY must be nonnull. */
781 static void **
782 pointer_set_find_or_insert (struct dyn_pointer_set *pset, unsigned key)
784 size_t n;
786 /* For simplicity, expand the set even if KEY is already there. This can be
787 superfluous but can happen at most once. */
788 if (pset->n_elements > pset->n_slots / 4)
790 size_t new_log_slots = pset->log_slots + 1;
791 size_t new_n_slots = pset->n_slots * 2;
792 void **new_slots = XNEWVEC (void *, new_n_slots);
793 memset (new_slots, 0, sizeof (void *) * new_n_slots);
794 size_t i;
796 for (i = 0; i < pset->n_slots; ++i)
798 void *value = pset->slots[i];
799 if (!value)
800 continue;
801 n = insert_aux (pset->get_key (value), new_slots, new_n_slots,
802 new_log_slots, pset->get_key);
803 new_slots[n] = value;
806 XDELETEVEC (pset->slots);
807 pset->n_slots = new_n_slots;
808 pset->log_slots = new_log_slots;
809 pset->slots = new_slots;
812 n = insert_aux (key, pset->slots, pset->n_slots, pset->log_slots,
813 pset->get_key);
814 return &pset->slots[n];
818 /* Pass each pointer in PSET to the function in FN, together with the fixed
819 parameters DATA1, DATA2, DATA3. If FN returns false, the iteration stops. */
821 static void
822 pointer_set_traverse (const struct dyn_pointer_set *pset,
823 int (*fn) (const void *, void *, void *, void *),
824 void *data1, void *data2, void *data3)
826 size_t i;
827 for (i = 0; i < pset->n_slots; ++i)
828 if (pset->slots[i] && !fn (pset->slots[i], data1, data2, data3))
829 break;
833 /* Returns nonzero if PSET contains an entry with KEY as the key value.
834 Collisions are resolved by linear probing. */
836 static int
837 pointer_set_contains (const struct dyn_pointer_set *pset, unsigned key)
839 size_t n = hash1 (key, pset->n_slots, pset->log_slots);
841 while (1)
843 if (pset->slots[n] == 0)
844 return 0;
845 else if (pset->get_key (pset->slots[n]) == key)
846 return 1;
847 else
849 ++n;
850 if (n == pset->n_slots)
851 n = 0;
856 /* Callback function to propagate import module (VALUE) from callee to
857 caller's imported-module-set (DATA1).
858 The weight is scaled by the scaling-factor (DATA2) before propagation,
859 and accumulated into DATA3. */
861 static int
862 gcov_propagate_imp_modules (const void *value, void *data1, void *data2,
863 void *data3)
865 const struct dyn_imp_mod *m = (const struct dyn_imp_mod *) value;
866 struct dyn_pointer_set *receiving_set = (struct dyn_pointer_set *) data1;
867 double *scale = (double *) data2;
868 double *sum = (double *) data3;
869 double wt = m->weight;
870 if (scale)
871 wt *= *scale;
872 if (sum)
873 (*sum) += wt;
874 imp_mod_set_insert (receiving_set, m->imp_mod, wt);
875 return 1;
878 static int
879 sort_by_count (const void *pa, const void *pb)
881 const struct dyn_cgraph_edge *edge_a = *(struct dyn_cgraph_edge * const *)pa;
882 const struct dyn_cgraph_edge *edge_b = *(struct dyn_cgraph_edge * const *)pb;
884 /* This can overvlow. */
885 /* return edge_b->count - edge_a->count; */
886 if (edge_b->count > edge_a->count)
887 return 1;
888 else if (edge_b->count == edge_a->count)
889 return 0;
890 else
891 return -1;
894 /* Compute the hot callgraph edge threhold. */
896 static gcov_type
897 gcov_compute_cutoff_count (void)
899 unsigned m_ix, capacity, i;
900 unsigned num_edges = 0;
901 gcov_type cutoff_count = 0;
902 double total, cum, cum_cutoff;
903 struct dyn_cgraph_edge **edges;
904 struct gcov_info *gi_ptr;
905 char *cutoff_str;
906 char *num_perc_str;
907 unsigned cutoff_perc;
908 unsigned num_perc;
909 int do_dump;
911 capacity = 100;
912 /* allocate an edge array */
913 edges = XNEWVEC (struct dyn_cgraph_edge*, capacity);
914 /* First count the number of edges. */
915 for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
917 const struct gcov_fn_info *fi_ptr;
918 unsigned f_ix;
920 gi_ptr = the_dyn_call_graph.modules[m_ix];
922 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
924 struct dyn_cgraph_node *node;
925 struct dyn_cgraph_edge *callees;
927 fi_ptr = gi_ptr->functions[f_ix];
929 node = *(pointer_set_find_or_insert
930 (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
931 gcc_assert (node);
933 callees = node->callees;
934 while (callees != 0)
936 num_edges++;
937 if (num_edges < capacity)
938 edges[num_edges - 1] = callees;
939 else
941 capacity = capacity + (capacity >> 1);
942 edges = (struct dyn_cgraph_edge **)realloc (edges, sizeof (void*) * capacity);
943 edges[num_edges - 1] = callees;
945 callees = callees->next_callee;
950 /* Now sort */
951 qsort (edges, num_edges, sizeof (void *), sort_by_count);
952 #define CUM_CUTOFF_PERCENT 80
953 #define MIN_NUM_EDGE_PERCENT 0
955 /* The default parameter value is 100 which is a reserved special value. When
956 the cutoff parameter is 100, use the environment variable setting if it
957 exists, otherwise, use the default value 80. */
958 if (__gcov_lipo_cutoff != 100)
960 cutoff_perc = __gcov_lipo_cutoff;
961 num_perc = MIN_NUM_EDGE_PERCENT;
963 else
965 cutoff_str = getenv ("GCOV_DYN_CGRAPH_CUTOFF");
966 if (cutoff_str && strlen (cutoff_str))
968 if ((num_perc_str = strchr (cutoff_str, ':')))
970 *num_perc_str = '\0';
971 num_perc_str++;
973 cutoff_perc = atoi (cutoff_str);
974 if (num_perc_str)
975 num_perc = atoi (num_perc_str);
976 else
977 num_perc = MIN_NUM_EDGE_PERCENT;
979 else
981 cutoff_perc = CUM_CUTOFF_PERCENT;
982 num_perc = MIN_NUM_EDGE_PERCENT;
986 total = 0;
987 cum = 0;
988 for (i = 0; i < num_edges; i++)
989 total += edges[i]->count;
991 cum_cutoff = (total * cutoff_perc)/100;
992 do_dump = (do_cgraph_dump () != 0);
993 for (i = 0; i < num_edges; i++)
995 cum += edges[i]->count;
996 if (do_dump)
997 fprintf (stderr, "// edge[%d] count = %.0f [%llx --> %llx]\n",
998 i, (double) edges[i]->count,
999 (long long) edges[i]->caller->guid,
1000 (long long) edges[i]->callee->guid);
1001 if (cum >= cum_cutoff && (i * 100 >= num_edges * num_perc))
1003 cutoff_count = edges[i]->count;
1004 break;
1008 if (do_dump)
1009 fprintf (stderr,"cum count cutoff = %d%%, minimal num edge cutoff = %d%%\n",
1010 cutoff_perc, num_perc);
1012 if (do_dump)
1013 fprintf (stderr, "// total = %.0f cum = %.0f cum/total = %.0f%%"
1014 " cutoff_count = %lld [total edges: %d hot edges: %d perc: %d%%]\n"
1015 " total_zero_count_edges = %d total_insane_count_edgess = %d\n"
1016 " total_nodes_executed = %d\n",
1017 total, cum, (cum * 100)/total, (long long) cutoff_count,
1018 num_edges, i, (i * 100)/num_edges, total_zero_count,
1019 total_insane_count, the_dyn_call_graph.num_nodes_executed);
1021 XDELETEVEC (edges);
1022 return cutoff_count;
1025 /* Return the imported module set for NODE. */
1027 static struct dyn_pointer_set *
1028 gcov_get_imp_module_set (struct dyn_cgraph_node *node)
1030 if (!node->imported_modules)
1031 node->imported_modules = pointer_set_create (imp_mod_get_key);
1033 return node->imported_modules;
1036 /* Return the imported module set for MODULE MI. */
1038 static struct dyn_pointer_set *
1039 gcov_get_module_imp_module_set (struct dyn_module_info *mi)
1041 if (!mi->imported_modules)
1042 mi->imported_modules = pointer_set_create (imp_mod_get_key);
1044 return mi->imported_modules;
1047 /* Callback function to mark if a module needs to be exported. */
1049 static int
1050 gcov_mark_export_modules (const void *value,
1051 void *data1 ATTRIBUTE_UNUSED,
1052 void *data2 ATTRIBUTE_UNUSED,
1053 void *data3 ATTRIBUTE_UNUSED)
1055 const struct gcov_info *module_info
1056 = ((const struct dyn_imp_mod *) value)->imp_mod;
1058 SET_MODULE_EXPORTED (module_info->mod_info);
1059 return 1;
1062 struct gcov_import_mod_array
1064 const struct dyn_imp_mod **imported_modules;
1065 struct gcov_info *importing_module;
1066 unsigned len;
1069 /* Callback function to compute pointer set size. */
1071 static int
1072 gcov_compute_mset_size (const void *value ATTRIBUTE_UNUSED,
1073 void *data1,
1074 void *data2 ATTRIBUTE_UNUSED,
1075 void *data3 ATTRIBUTE_UNUSED)
1077 unsigned *len = (unsigned *) data1;
1078 (*len)++;
1079 return 1;
1082 /* Callback function to collect imported modules. */
1084 static int
1085 gcov_collect_imported_modules (const void *value,
1086 void *data1,
1087 void *data2 ATTRIBUTE_UNUSED,
1088 void *data3 ATTRIBUTE_UNUSED)
1090 struct gcov_import_mod_array *out_array;
1091 const struct dyn_imp_mod *m
1092 = (const struct dyn_imp_mod *) value;
1094 out_array = (struct gcov_import_mod_array *) data1;
1096 if (m->imp_mod != out_array->importing_module)
1097 out_array->imported_modules[out_array->len++] = m;
1099 return 1;
1102 /* Comparator for sorting imported modules using weights. */
1104 static int
1105 sort_by_module_wt (const void *pa, const void *pb)
1107 const struct dyn_imp_mod *m_a = *((const struct dyn_imp_mod * const *) pa);
1108 const struct dyn_imp_mod *m_b = *((const struct dyn_imp_mod * const *) pb);
1110 /* We want to sort in descending order of weights. */
1111 if (m_a->weight < m_b->weight)
1112 return +1;
1113 if (m_a->weight > m_b->weight)
1114 return -1;
1115 return get_module_ident (m_a->imp_mod) - get_module_ident (m_b->imp_mod);
1118 /* Return a dynamic array of imported modules that is sorted for
1119 the importing module MOD_INFO. The length of the array is returned
1120 in *LEN. */
1122 const struct dyn_imp_mod **
1123 gcov_get_sorted_import_module_array (struct gcov_info *mod_info,
1124 unsigned *len)
1126 unsigned mod_idx;
1127 struct dyn_module_info *sup_mod_info;
1128 unsigned array_len = 0;
1129 struct gcov_import_mod_array imp_array;
1131 mod_idx = get_module_ident (mod_info) - 1;
1132 sup_mod_info = &the_dyn_call_graph.sup_modules[mod_idx];
1134 if (sup_mod_info->imported_modules == 0)
1135 return 0;
1137 pointer_set_traverse (sup_mod_info->imported_modules,
1138 gcov_compute_mset_size, &array_len, 0, 0);
1139 imp_array.imported_modules = XNEWVEC (const struct dyn_imp_mod *, array_len);
1140 imp_array.len = 0;
1141 imp_array.importing_module = mod_info;
1142 pointer_set_traverse (sup_mod_info->imported_modules,
1143 gcov_collect_imported_modules, &imp_array, 0, 0);
1144 *len = imp_array.len;
1145 qsort (imp_array.imported_modules, imp_array.len,
1146 sizeof (void *), sort_by_module_wt);
1147 return imp_array.imported_modules;
1150 /* Compute modules that are needed for NODE (for cross module inlining).
1151 CUTTOFF_COUNT is the call graph edge count cutoff value.
1152 IMPORT_SCALE is the scaling-factor (percent) by which to scale the
1153 weights of imported modules of a callee before propagating them to
1154 the caller, if the callee and caller are in different modules.
1156 Each imported module is assigned a weight that corresponds to the
1157 expected benefit due to cross-module inlining. When the imported modules
1158 are written out, they are sorted with highest weight first.
1160 The following example illustrates how the weight is computed:
1162 Suppose we are processing call-graph node A. It calls function B 50 times,
1163 which calls function C 1000 times, and function E 800 times. Lets say B has
1164 another in-edge from function D, with edge-count of 50. Say all the
1165 functions are in separate modules (modules a, b, c, d, e, respectively):
1169 | 50
1171 50 v 1000
1172 A --------> B ----------> C
1174 | 800
1179 Nodes are processed in depth-first order, so when processing A, we first
1180 process B. For node B, we are going to add module c to the imported-module
1181 set, with weight 1000 (edge-count), and module e with weight 800.
1182 Coming back to A, we are going to add the imported-module-set of B to A,
1183 after doing some scaling.
1184 The first scaling factor comes from the fact that A calls B 50 times, but B
1185 has in-edge-count total of 100. So this scaling factor is 50/100 = 0.5
1186 The second scaling factor is that since B is in a different module than A,
1187 we want to slightly downgrade imported modules of B, before adding to the
1188 imported-modules set of A. This scaling factor has a default value of 50%
1189 (can be set via env variable GCOV_DYN_IMPORT_SCALE).
1190 So we end up adding modules c and e to the imported-set of A, with weights
1191 0.5*0.5*1000=250 and 0.5*0.5*800=200, respectively.
1193 Next, we have to add module b itself to A. The weight is computed as the
1194 edge-count plus the sum of scaled-weights of all modules in the
1195 imported-module set of B, i.e., 50 + 250 + 200 = 500.
1197 In computing the weight of module b, we add the sum of scaled-weights of
1198 imported modules of b, because it doesn't make sense to import c, e in
1199 module a, until module b is imported. */
1201 static void
1202 gcov_process_cgraph_node (struct dyn_cgraph_node *node,
1203 gcov_type cutoff_count,
1204 unsigned import_scale)
1206 unsigned mod_id;
1207 struct dyn_cgraph_edge *callees;
1208 struct dyn_cgraph_edge *callers;
1209 node->visited = 1;
1210 node->sum_in_count = 0;
1212 callers = node->callers;
1213 while (callers)
1215 node->sum_in_count += callers->count;
1216 callers = callers->next_caller;
1219 callees = node->callees;
1220 mod_id = get_module_ident_from_func_glob_uid (node->guid);
1222 while (callees)
1224 if (!callees->callee->visited)
1225 gcov_process_cgraph_node (callees->callee,
1226 cutoff_count,
1227 import_scale);
1228 callees = callees->next_callee;
1231 callees = node->callees;
1232 while (callees)
1234 if (callees->count >= cutoff_count)
1236 unsigned callee_mod_id;
1237 struct dyn_pointer_set *imp_modules
1238 = gcov_get_imp_module_set (node);
1240 callee_mod_id
1241 = get_module_ident_from_func_glob_uid (callees->callee->guid);
1243 double callee_mod_wt = (double) callees->count;
1244 if (callees->callee->imported_modules)
1246 double scale = ((double) callees->count) /
1247 ((double) callees->callee->sum_in_count);
1248 /* Reduce weight if callee is in different module. */
1249 if (mod_id != callee_mod_id)
1250 scale = (scale * import_scale) / 100.0;
1251 pointer_set_traverse (callees->callee->imported_modules,
1252 gcov_propagate_imp_modules,
1253 imp_modules, &scale, &callee_mod_wt);
1255 if (mod_id != callee_mod_id)
1257 struct gcov_info *callee_mod_info
1258 = get_module_info (callee_mod_id);
1259 imp_mod_set_insert (imp_modules, callee_mod_info, callee_mod_wt);
1263 callees = callees->next_callee;
1267 static void gcov_compute_module_groups_eager_propagation (gcov_type);
1268 static void gcov_compute_module_groups_inclusion_based_with_priority
1269 (gcov_type);
1271 /* dyn_fibheap */
1272 static void dyn_fibheap_ins_root (dyn_fibheap_t, fibnode_t);
1273 static void dyn_fibheap_rem_root (dyn_fibheap_t, fibnode_t);
1274 static void dyn_fibheap_consolidate (dyn_fibheap_t);
1275 static void dyn_fibheap_link (dyn_fibheap_t, fibnode_t, fibnode_t);
1276 static fibnode_t dyn_fibheap_extr_min_node (dyn_fibheap_t);
1277 static int dyn_fibheap_compare (dyn_fibheap_t, fibnode_t, fibnode_t);
1278 static int dyn_fibheap_comp_data (dyn_fibheap_t, dyn_fibheapkey_t,
1279 void *, fibnode_t);
1280 static fibnode_t fibnode_new (void);
1281 static void fibnode_insert_after (fibnode_t, fibnode_t);
1282 #define fibnode_insert_before(a, b) fibnode_insert_after (a->left, b)
1283 static fibnode_t fibnode_remove (fibnode_t);
1285 /* Create a new fibonacci heap. */
1286 static dyn_fibheap_t
1287 dyn_fibheap_new (void)
1289 return (dyn_fibheap_t) calloc (1, sizeof (struct dyn_fibheap));
1292 /* Create a new fibonacci heap node. */
1293 static fibnode_t
1294 fibnode_new (void)
1296 fibnode_t node;
1298 node = (fibnode_t) calloc (1, sizeof *node);
1299 node->left = node;
1300 node->right = node;
1302 return node;
1305 static inline int
1306 dyn_fibheap_compare (dyn_fibheap_t heap ATTRIBUTE_UNUSED, fibnode_t a,
1307 fibnode_t b)
1309 if (a->key < b->key)
1310 return -1;
1311 if (a->key > b->key)
1312 return 1;
1313 return 0;
1316 static inline int
1317 dyn_fibheap_comp_data (dyn_fibheap_t heap, dyn_fibheapkey_t key,
1318 void *data, fibnode_t b)
1320 struct fibnode a;
1322 a.key = key;
1323 a.data = data;
1325 return dyn_fibheap_compare (heap, &a, b);
1328 /* Insert DATA, with priority KEY, into HEAP. */
1329 static fibnode_t
1330 dyn_fibheap_insert (dyn_fibheap_t heap, dyn_fibheapkey_t key, void *data)
1332 fibnode_t node;
1334 /* Create the new node. */
1335 node = fibnode_new ();
1337 /* Set the node's data. */
1338 node->data = data;
1339 node->key = key;
1341 /* Insert it into the root list. */
1342 dyn_fibheap_ins_root (heap, node);
1344 /* If their was no minimum, or this key is less than the min,
1345 it's the new min. */
1346 if (heap->min == 0 || node->key < heap->min->key)
1347 heap->min = node;
1349 heap->nodes++;
1351 return node;
1354 /* Extract the data of the minimum node from HEAP. */
1355 static void *
1356 dyn_fibheap_extract_min (dyn_fibheap_t heap)
1358 fibnode_t z;
1359 void *ret = 0;
1361 /* If we don't have a min set, it means we have no nodes. */
1362 if (heap->min != 0)
1364 /* Otherwise, extract the min node, free the node, and return the
1365 node's data. */
1366 z = dyn_fibheap_extr_min_node (heap);
1367 ret = z->data;
1368 free (z);
1371 return ret;
1374 /* Delete HEAP. */
1375 static void
1376 dyn_fibheap_delete (dyn_fibheap_t heap)
1378 while (heap->min != 0)
1379 free (dyn_fibheap_extr_min_node (heap));
1381 free (heap);
1384 /* Extract the minimum node of the heap. */
1385 static fibnode_t
1386 dyn_fibheap_extr_min_node (dyn_fibheap_t heap)
1388 fibnode_t ret = heap->min;
1389 fibnode_t x, y, orig;
1391 /* Attach the child list of the minimum node to the root list of the heap.
1392 If there is no child list, we don't do squat. */
1393 for (x = ret->child, orig = 0; x != orig && x != 0; x = y)
1395 if (orig == 0)
1396 orig = x;
1397 y = x->right;
1398 x->parent = 0;
1399 dyn_fibheap_ins_root (heap, x);
1402 /* Remove the old root. */
1403 dyn_fibheap_rem_root (heap, ret);
1404 heap->nodes--;
1406 /* If we are left with no nodes, then the min is 0. */
1407 if (heap->nodes == 0)
1408 heap->min = 0;
1409 else
1411 /* Otherwise, consolidate to find new minimum, as well as do the reorg
1412 work that needs to be done. */
1413 heap->min = ret->right;
1414 dyn_fibheap_consolidate (heap);
1417 return ret;
1420 /* Insert NODE into the root list of HEAP. */
1421 static void
1422 dyn_fibheap_ins_root (dyn_fibheap_t heap, fibnode_t node)
1424 /* If the heap is currently empty, the new node becomes the singleton
1425 circular root list. */
1426 if (heap->root == 0)
1428 heap->root = node;
1429 node->left = node;
1430 node->right = node;
1431 return;
1434 /* Otherwise, insert it in the circular root list between the root
1435 and it's right node. */
1436 fibnode_insert_after (heap->root, node);
1439 /* Remove NODE from the rootlist of HEAP. */
1440 static void
1441 dyn_fibheap_rem_root (dyn_fibheap_t heap, fibnode_t node)
1443 if (node->left == node)
1444 heap->root = 0;
1445 else
1446 heap->root = fibnode_remove (node);
1449 /* Consolidate the heap. */
1450 static void
1451 dyn_fibheap_consolidate (dyn_fibheap_t heap)
1453 fibnode_t a[1 + 8 * sizeof (long)];
1454 fibnode_t w;
1455 fibnode_t y;
1456 fibnode_t x;
1457 int i;
1458 int d;
1459 int D;
1461 D = 1 + 8 * sizeof (long);
1463 memset (a, 0, sizeof (fibnode_t) * D);
1465 while ((w = heap->root) != 0)
1467 x = w;
1468 dyn_fibheap_rem_root (heap, w);
1469 d = x->degree;
1470 while (a[d] != 0)
1472 y = a[d];
1473 if (dyn_fibheap_compare (heap, x, y) > 0)
1475 fibnode_t temp;
1476 temp = x;
1477 x = y;
1478 y = temp;
1480 dyn_fibheap_link (heap, y, x);
1481 a[d] = 0;
1482 d++;
1484 a[d] = x;
1486 heap->min = 0;
1487 for (i = 0; i < D; i++)
1488 if (a[i] != 0)
1490 dyn_fibheap_ins_root (heap, a[i]);
1491 if (heap->min == 0 || dyn_fibheap_compare (heap, a[i], heap->min) < 0)
1492 heap->min = a[i];
1496 /* Make NODE a child of PARENT. */
1497 static void
1498 dyn_fibheap_link (dyn_fibheap_t heap ATTRIBUTE_UNUSED,
1499 fibnode_t node, fibnode_t parent)
1501 if (parent->child == 0)
1502 parent->child = node;
1503 else
1504 fibnode_insert_before (parent->child, node);
1505 node->parent = parent;
1506 parent->degree++;
1507 node->mark = 0;
1510 static void
1511 fibnode_insert_after (fibnode_t a, fibnode_t b)
1513 if (a == a->right)
1515 a->right = b;
1516 a->left = b;
1517 b->right = a;
1518 b->left = a;
1520 else
1522 b->right = a->right;
1523 a->right->left = b;
1524 a->right = b;
1525 b->left = a;
1529 static fibnode_t
1530 fibnode_remove (fibnode_t node)
1532 fibnode_t ret;
1534 if (node == node->left)
1535 ret = 0;
1536 else
1537 ret = node->left;
1539 if (node->parent != 0 && node->parent->child == node)
1540 node->parent->child = ret;
1542 node->right->left = node->left;
1543 node->left->right = node->right;
1545 node->parent = 0;
1546 node->left = node;
1547 node->right = node;
1549 return ret;
1551 /* end of dyn_fibheap */
1553 /* Compute module grouping using CUTOFF_COUNT as the hot edge
1554 threshold. */
1556 static void
1557 gcov_compute_module_groups (gcov_type cutoff_count)
1559 switch (flag_alg_mode)
1561 case INCLUSION_BASED_PRIORITY_ALGORITHM:
1562 return gcov_compute_module_groups_inclusion_based_with_priority
1563 (cutoff_count);
1564 case EAGER_PROPAGATION_ALGORITHM:
1565 default:
1566 return gcov_compute_module_groups_eager_propagation (cutoff_count);
1570 static void
1571 modu_graph_add_edge (unsigned m_id, unsigned callee_m_id, gcov_type count)
1573 struct modu_node *mnode;
1574 struct modu_node *callee_mnode;
1575 struct modu_edge *e;
1577 if (m_id == 0 || callee_m_id == 0)
1578 return;
1580 mnode = &the_dyn_call_graph.modu_nodes[m_id - 1];
1581 callee_mnode = &the_dyn_call_graph.modu_nodes[callee_m_id - 1];
1583 if (flag_modu_merge_edges)
1585 struct modu_edge *callees = mnode->callees;
1586 while (callees)
1588 if (callees->callee == callee_mnode)
1590 callees->n_edges += 1;
1591 callees->sum_count += count;
1592 return;
1594 callees = callees->next_callee;
1597 e = XNEW (struct modu_edge);
1598 e->caller = mnode;
1599 e->callee = callee_mnode;
1600 e->n_edges = 1;
1601 e->sum_count = count;
1602 e->next_callee = mnode->callees;
1603 e->next_caller = callee_mnode->callers;
1604 mnode->callees = e;
1605 callee_mnode->callers = e;
1606 e->visited = 0;
1609 static void
1610 modu_graph_process_dyn_cgraph_node (struct dyn_cgraph_node *node,
1611 gcov_type cutoff_count)
1613 unsigned m_id = get_module_ident_from_func_glob_uid (node->guid);
1614 struct dyn_cgraph_edge *callees;
1615 struct dyn_cgraph_node *callee;
1617 callees = node->callees;
1618 while (callees != 0)
1620 callee = callees->callee;
1621 unsigned callee_m_id =
1622 get_module_ident_from_func_glob_uid (callee->guid);
1623 if (callee_m_id != m_id)
1625 if (callees->count >= cutoff_count)
1626 modu_graph_add_edge (m_id, callee_m_id, callees->count);
1628 callees = callees->next_callee;
1632 static void
1633 build_modu_graph (gcov_type cutoff_count)
1635 unsigned m_ix;
1636 struct gcov_info *gi_ptr;
1637 unsigned n_modules = the_dyn_call_graph.num_modules;
1638 struct modu_node *modu_nodes;
1640 /* Create modu graph nodes/edges. */
1641 modu_nodes = XCNEWVEC (struct modu_node, n_modules);
1642 the_dyn_call_graph.modu_nodes = modu_nodes;
1643 for (m_ix = 0; m_ix < n_modules; m_ix++)
1645 const struct gcov_fn_info *fi_ptr;
1646 unsigned f_ix;
1648 gi_ptr = the_dyn_call_graph.modules[m_ix];
1649 modu_nodes[m_ix].module = gi_ptr;
1651 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
1653 struct dyn_cgraph_node *node;
1655 fi_ptr = gi_ptr->functions[f_ix];
1656 node = *(pointer_set_find_or_insert
1657 (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
1658 if (!node)
1660 fprintf (stderr, "Cannot find module_node (ix = %u)./n", m_ix);
1661 continue;
1663 modu_graph_process_dyn_cgraph_node (node, cutoff_count);
1668 /* Collect ggc_mem_size for the impored_module in VALUE
1669 if DATA1 (a pointer_set) is provided, only count these not in DATA1.
1670 Result is stored in DATA2. */
1672 static int
1673 collect_ggc_mem_size (const void *value,
1674 void *data1,
1675 void *data2,
1676 void *data3 ATTRIBUTE_UNUSED)
1678 const struct dyn_imp_mod *g = (const struct dyn_imp_mod *) value;
1679 struct dyn_pointer_set *s = (struct dyn_pointer_set *) data1;
1680 unsigned mod_id = get_module_ident (g->imp_mod);
1681 gcov_unsigned_t *size = (gcov_unsigned_t *) data2;
1683 if (s && pointer_set_contains (s, mod_id))
1684 return 1;
1686 (*size) += g->imp_mod->mod_info->ggc_memory;
1688 return 1;
1692 /* Get the group ggc_memory size of a imported list. */
1694 static gcov_unsigned_t
1695 get_group_ggc_mem (struct dyn_pointer_set *s)
1697 gcov_unsigned_t ggc_size = 0;
1699 pointer_set_traverse (s, collect_ggc_mem_size, 0, &ggc_size, 0);
1700 return ggc_size;
1703 /* Get the group ggc_memory size of the unioned imported lists. */
1705 static gcov_unsigned_t
1706 modu_union_ggc_size (unsigned t_mid, unsigned s_mid)
1708 struct dyn_pointer_set *t_imported_mods = get_imported_modus (t_mid);
1709 struct dyn_pointer_set *s_imported_mods = get_imported_modus (s_mid);
1710 gcov_unsigned_t size = 0;
1712 pointer_set_traverse (s_imported_mods, collect_ggc_mem_size,
1713 t_imported_mods, &size, 0);
1715 size += get_group_ggc_mem (t_imported_mods);
1717 return size;
1720 /* Insert one module (VALUE) to the target module (DATA1) */
1722 static int
1723 modu_add_auxiliary_1 (const void *value,
1724 void *data1,
1725 void *data2,
1726 void *data3 ATTRIBUTE_UNUSED)
1728 const struct dyn_imp_mod *src = (const struct dyn_imp_mod *) value;
1729 const struct gcov_info *src_modu = src->imp_mod;
1730 unsigned t_m_id = *(unsigned *) data1;
1731 struct dyn_pointer_set *t_imported_mods = get_imported_modus (t_m_id);
1732 double wt = (double) *(gcov_type*)data2;
1733 unsigned s_m_id = get_module_ident (src_modu);
1734 struct gcov_info **gp;
1735 struct dyn_pointer_set *s_exported_to;
1736 int already_have = 0;
1738 if (pointer_set_contains (t_imported_mods, s_m_id))
1739 already_have = 1;
1741 /* Insert even it's already there. This is to update the wt. */
1742 imp_mod_set_insert (t_imported_mods, src_modu, wt);
1744 if (already_have)
1745 return 1;
1747 /* add module t_m_id to s_m_id's exported list. */
1748 s_exported_to = get_exported_to (s_m_id);
1749 if (!s_exported_to)
1750 s_exported_to = create_exported_to (s_m_id);
1751 gp = (struct gcov_info **) pointer_set_find_or_insert
1752 (s_exported_to, t_m_id);
1753 *gp = the_dyn_call_graph.modules[t_m_id - 1];
1754 s_exported_to->n_elements++;
1756 return 1;
1759 /* Insert module S_MID and it's imported modules to
1760 imported list of module T_MID. */
1762 static void
1763 modu_add_auxiliary (unsigned t_mid, unsigned s_mid, gcov_type count)
1765 struct dyn_pointer_set *s_imported_mods = get_imported_modus (s_mid);
1767 pointer_set_traverse (s_imported_mods, modu_add_auxiliary_1,
1768 &t_mid, &count, 0);
1770 /* Recompute the gcc_memory for the group. */
1771 the_dyn_call_graph.sup_modules[t_mid - 1].group_ggc_mem =
1772 get_group_ggc_mem (get_imported_modus (t_mid));
1775 /* Check if inserting the module specified by DATA1 (including
1776 it's imported list to grouping VALUE, makes the ggc_memory
1777 size exceed the memory threshold.
1778 Return 0 if size is great than the thereshold and 0 otherwise. */
1780 static int
1781 ps_check_ggc_mem (const void *value,
1782 void *data1,
1783 void *data2,
1784 void *data3 ATTRIBUTE_UNUSED)
1786 const struct gcov_info *modu = (const struct gcov_info *) value;
1787 unsigned s_m_id = *(unsigned *) data1;
1788 unsigned *fail = (unsigned *) data2;
1789 unsigned m_id = get_module_ident (modu);
1790 gcov_unsigned_t new_ggc_size;
1792 new_ggc_size = modu_union_ggc_size (m_id, s_m_id);
1793 if (new_ggc_size > mem_threshold)
1795 (*fail) = 1;
1796 return 0;
1799 return 1;
1802 /* Add module specified by DATA1 and it's imported list to
1803 the grouping specified by VALUE. */
1805 static int
1806 ps_add_auxiliary (const void *value,
1807 void *data1,
1808 void *data2,
1809 void *data3)
1811 const struct gcov_info *modu = (const struct gcov_info *) value;
1812 unsigned s_m_id = *(unsigned *) data1;
1813 unsigned m_id = get_module_ident (modu);
1814 int not_safe_to_insert = *(int *) data3;
1815 gcov_unsigned_t new_ggc_size;
1817 /* For strict inclusion, we know it's safe to insert. */
1818 if (!not_safe_to_insert)
1820 modu_add_auxiliary (m_id, s_m_id, *(gcov_type*)data2);
1821 return 1;
1824 /* Check if we can do a partial insertion. */
1825 new_ggc_size = modu_union_ggc_size (m_id, s_m_id);
1826 if (new_ggc_size > mem_threshold)
1827 return 1;
1829 modu_add_auxiliary (m_id, s_m_id, *(gcov_type*)data2);
1830 return 1;
1833 /* Return 1 if insertion happened, otherwise 0. */
1835 static int
1836 modu_edge_add_auxiliary (struct modu_edge *edge)
1838 struct modu_node *node;
1839 struct modu_node *callee;
1840 struct gcov_info *node_modu;
1841 struct gcov_info *callee_modu;
1842 gcov_unsigned_t group_ggc_mem;
1843 gcov_unsigned_t new_ggc_size;
1844 struct dyn_pointer_set *node_imported_mods;
1845 struct dyn_pointer_set *node_exported_to;
1846 unsigned m_id, callee_m_id;
1847 int fail = 0;
1849 node = edge->caller;
1850 callee = edge->callee;
1851 node_modu = node->module;
1852 callee_modu = callee->module;
1853 m_id = get_module_ident (node_modu);
1855 if (m_id == 0)
1856 return 0;
1858 group_ggc_mem = the_dyn_call_graph.sup_modules[m_id - 1].group_ggc_mem;
1860 if (group_ggc_mem >= mem_threshold)
1861 return 0;
1863 node_imported_mods = get_imported_modus (m_id);
1865 /* Check if the callee is already included. */
1866 callee_m_id = get_module_ident (callee_modu);
1867 if (pointer_set_contains (node_imported_mods, callee_m_id))
1868 return 0;
1870 new_ggc_size = modu_union_ggc_size (m_id, callee_m_id);
1871 if (new_ggc_size > mem_threshold)
1872 return 0;
1874 /* check the size for the grouping that includes this node. */
1875 node_exported_to = get_exported_to (m_id);
1876 if (node_exported_to)
1878 pointer_set_traverse (node_exported_to, ps_check_ggc_mem,
1879 &callee_m_id, &fail, 0);
1880 if (fail && !flag_weak_inclusion)
1881 return 0;
1884 /* Perform the insertion: first insert to node
1885 and then to all the exported_to nodes. */
1886 modu_add_auxiliary (m_id, callee_m_id, edge->sum_count);
1888 if (node_exported_to)
1889 pointer_set_traverse (node_exported_to, ps_add_auxiliary,
1890 &callee_m_id, &(edge->sum_count), &fail);
1891 return 1;
1894 static void
1895 compute_module_groups_inclusion_impl (void)
1897 dyn_fibheap_t heap;
1898 unsigned i;
1899 unsigned n_modules = the_dyn_call_graph.num_modules;
1901 /* insert all the edges to the heap. */
1902 heap = dyn_fibheap_new ();
1903 for (i = 0; i < n_modules; i++)
1905 struct modu_edge * callees;
1906 struct modu_node *node = &the_dyn_call_graph.modu_nodes[i];
1908 callees = node->callees;
1909 while (callees != 0)
1911 dyn_fibheap_insert (heap, -1 * callees->sum_count, callees);
1912 callees = callees->next_callee;
1916 while (1)
1918 struct modu_edge *curr
1919 = (struct modu_edge *) dyn_fibheap_extract_min (heap);
1921 if (!curr)
1922 break;
1923 if (curr->visited)
1924 continue;
1925 curr->visited = 1;
1927 modu_edge_add_auxiliary (curr);
1930 dyn_fibheap_delete (heap);
1932 /* Now compute the export attribute */
1933 for (i = 0; i < n_modules; i++)
1935 struct dyn_module_info *mi
1936 = &the_dyn_call_graph.sup_modules[i];
1937 if (mi->exported_to)
1938 SET_MODULE_EXPORTED (the_dyn_call_graph.modules[i]->mod_info);
1942 static void
1943 gcov_compute_module_groups_inclusion_based_with_priority
1944 (gcov_type cutoff_count)
1946 build_modu_graph (cutoff_count);
1947 compute_module_groups_inclusion_impl ();
1950 static void
1951 gcov_compute_module_groups_eager_propagation (gcov_type cutoff_count)
1953 unsigned m_ix;
1954 struct gcov_info *gi_ptr;
1955 const char *import_scale_str;
1956 unsigned import_scale = __gcov_lipo_propagate_scale;
1958 /* Different from __gcov_lipo_cutoff handling, the
1959 environment variable here takes precedance */
1960 import_scale_str = getenv ("GCOV_DYN_IMPORT_SCALE");
1961 if (import_scale_str && strlen (import_scale_str))
1962 import_scale = atoi (import_scale_str);
1964 for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
1966 const struct gcov_fn_info *fi_ptr;
1967 unsigned f_ix;
1969 gi_ptr = the_dyn_call_graph.modules[m_ix];
1971 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
1973 struct dyn_cgraph_node *node;
1975 fi_ptr = gi_ptr->functions[f_ix];
1976 node = *(pointer_set_find_or_insert
1977 (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
1978 gcc_assert (node);
1979 if (node->visited)
1980 continue;
1982 gcov_process_cgraph_node (node, cutoff_count, import_scale);
1986 for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
1988 const struct gcov_fn_info *fi_ptr;
1989 unsigned f_ix;
1991 gi_ptr = the_dyn_call_graph.modules[m_ix];
1993 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
1995 struct dyn_cgraph_node *node;
1996 unsigned mod_id;
1997 struct dyn_pointer_set *imp_modules;
1999 fi_ptr = gi_ptr->functions[f_ix];
2000 node = *(pointer_set_find_or_insert
2001 (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
2002 gcc_assert (node);
2004 if (!node->imported_modules)
2005 continue;
2007 mod_id = get_module_ident_from_func_glob_uid (node->guid);
2008 gcc_assert (mod_id == (m_ix + 1));
2010 imp_modules
2011 = gcov_get_module_imp_module_set (
2012 &the_dyn_call_graph.sup_modules[mod_id - 1]);
2014 pointer_set_traverse (node->imported_modules,
2015 gcov_propagate_imp_modules,
2016 imp_modules, 0, 0);
2020 /* Now compute the export attribute */
2021 for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
2023 struct dyn_module_info *mi
2024 = &the_dyn_call_graph.sup_modules[m_ix];
2026 if (mi->imported_modules)
2027 pointer_set_traverse (mi->imported_modules,
2028 gcov_mark_export_modules, 0, 0, 0);
2032 /* For each module, compute at random, the group of imported modules,
2033 that is of size at most MAX_GROUP_SIZE. */
2035 static void
2036 gcov_compute_random_module_groups (unsigned max_group_size)
2038 unsigned m_ix;
2040 if (max_group_size > the_dyn_call_graph.num_modules)
2041 max_group_size = the_dyn_call_graph.num_modules;
2043 for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
2045 struct dyn_pointer_set *imp_modules =
2046 gcov_get_module_imp_module_set (&the_dyn_call_graph.sup_modules[m_ix]);
2047 int cur_group_size = random () % max_group_size;
2048 int i = 0;
2049 while (i < cur_group_size)
2051 struct gcov_info *imp_mod_info;
2052 unsigned mod_idx = random () % the_dyn_call_graph.num_modules;
2053 if (mod_idx == m_ix)
2054 continue;
2055 imp_mod_info = get_module_info (mod_idx + 1);
2056 if (!imp_mod_set_insert (imp_modules, imp_mod_info, 1.0))
2057 i++;
2061 /* Now compute the export attribute */
2062 for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
2064 struct dyn_module_info *mi
2065 = &the_dyn_call_graph.sup_modules[m_ix];
2066 if (mi->imported_modules)
2067 pointer_set_traverse (mi->imported_modules,
2068 gcov_mark_export_modules, 0, 0, 0);
2072 /* Write out MOD_INFO into the gcda file. IS_PRIMARY is a flag
2073 indicating if the module is the primary module in the group. */
2075 static void
2076 gcov_write_module_info (const struct gcov_info *mod_info,
2077 unsigned is_primary)
2079 gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i, j;
2080 gcov_unsigned_t num_strings;
2081 gcov_unsigned_t *aligned_fname;
2082 struct gcov_module_info *module_info = mod_info->mod_info;
2083 filename_len = (strlen (module_info->da_filename) +
2084 sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t);
2085 src_filename_len = (strlen (module_info->source_filename) +
2086 sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t);
2087 len = filename_len + src_filename_len;
2088 len += 2; /* each name string is led by a length. */
2090 num_strings = module_info->num_quote_paths + module_info->num_bracket_paths
2091 + module_info->num_system_paths
2092 + module_info->num_cpp_defines + module_info->num_cpp_includes
2093 + module_info->num_cl_args;
2094 for (i = 0; i < num_strings; i++)
2096 gcov_unsigned_t string_len
2097 = (strlen (module_info->string_array[i]) + sizeof (gcov_unsigned_t))
2098 / sizeof (gcov_unsigned_t);
2099 len += string_len;
2100 len += 1; /* Each string is lead by a length. */
2103 len += 11; /* 11 more fields */
2105 gcov_write_tag_length (GCOV_TAG_MODULE_INFO, len);
2106 gcov_write_unsigned (module_info->ident);
2107 gcov_write_unsigned (is_primary);
2108 if (flag_alg_mode == INCLUSION_BASED_PRIORITY_ALGORITHM && is_primary)
2109 SET_MODULE_INCLUDE_ALL_AUX (module_info);
2110 gcov_write_unsigned (module_info->flags);
2111 gcov_write_unsigned (module_info->lang);
2112 gcov_write_unsigned (module_info->ggc_memory);
2113 gcov_write_unsigned (module_info->num_quote_paths);
2114 gcov_write_unsigned (module_info->num_bracket_paths);
2115 gcov_write_unsigned (module_info->num_system_paths);
2116 gcov_write_unsigned (module_info->num_cpp_defines);
2117 gcov_write_unsigned (module_info->num_cpp_includes);
2118 gcov_write_unsigned (module_info->num_cl_args);
2120 /* Now write the filenames */
2121 aligned_fname = (gcov_unsigned_t *) alloca ((filename_len + src_filename_len + 2) *
2122 sizeof (gcov_unsigned_t));
2123 memset (aligned_fname, 0,
2124 (filename_len + src_filename_len + 2) * sizeof (gcov_unsigned_t));
2125 aligned_fname[0] = filename_len;
2126 strcpy ((char*) (aligned_fname + 1), module_info->da_filename);
2127 aligned_fname[filename_len + 1] = src_filename_len;
2128 strcpy ((char*) (aligned_fname + filename_len + 2), module_info->source_filename);
2130 for (i = 0; i < (filename_len + src_filename_len + 2); i++)
2131 gcov_write_unsigned (aligned_fname[i]);
2133 /* Now write the string array. */
2134 for (j = 0; j < num_strings; j++)
2136 gcov_unsigned_t *aligned_string;
2137 gcov_unsigned_t string_len =
2138 (strlen (module_info->string_array[j]) + sizeof (gcov_unsigned_t)) /
2139 sizeof (gcov_unsigned_t);
2140 aligned_string = (gcov_unsigned_t *)
2141 alloca ((string_len + 1) * sizeof (gcov_unsigned_t));
2142 memset (aligned_string, 0, (string_len + 1) * sizeof (gcov_unsigned_t));
2143 aligned_string[0] = string_len;
2144 strcpy ((char*) (aligned_string + 1), module_info->string_array[j]);
2145 for (i = 0; i < (string_len + 1); i++)
2146 gcov_write_unsigned (aligned_string[i]);
2150 /* Write out MOD_INFO and its imported modules into gcda file. */
2152 void
2153 gcov_write_module_infos (struct gcov_info *mod_info)
2155 unsigned imp_len = 0;
2156 const struct dyn_imp_mod **imp_mods;
2158 gcov_write_module_info (mod_info, 1);
2160 imp_mods = gcov_get_sorted_import_module_array (mod_info, &imp_len);
2161 if (imp_mods)
2163 unsigned i;
2165 for (i = 0; i < imp_len; i++)
2167 const struct gcov_info *imp_mod = imp_mods[i]->imp_mod;
2168 if (imp_mod != mod_info)
2169 gcov_write_module_info (imp_mod, 0);
2171 free (imp_mods);
2175 /* Compute module groups needed for L-IPO compilation. */
2177 void
2178 __gcov_compute_module_groups (void)
2180 gcov_type cut_off_count;
2181 char *seed = getenv ("LIPO_RANDOM_GROUPING");
2182 char *max_group_size = seed ? strchr (seed, ':') : 0;
2184 /* The random group is set via compile time parameter. */
2185 if (__gcov_lipo_random_group_size != 0)
2187 srandom (__gcov_lipo_random_seed);
2188 init_dyn_call_graph ();
2189 gcov_compute_random_module_groups (__gcov_lipo_random_group_size);
2190 if (do_cgraph_dump () != 0)
2192 fprintf (stderr, " Creating random grouping with %u:%u\n",
2193 __gcov_lipo_random_seed, __gcov_lipo_random_group_size);
2195 return;
2197 else if (seed && max_group_size)
2199 *max_group_size = '\0';
2200 max_group_size++;
2201 srandom (atoi (seed));
2202 init_dyn_call_graph ();
2203 gcov_compute_random_module_groups (atoi (max_group_size));
2204 if (do_cgraph_dump () != 0)
2206 fprintf (stderr, " Creating random grouping with %s:%s\n",
2207 seed, max_group_size);
2209 return;
2212 /* First compute dynamic call graph. */
2213 gcov_build_callgraph ();
2215 cut_off_count = gcov_compute_cutoff_count ();
2217 gcov_compute_module_groups (cut_off_count);
2219 gcov_dump_callgraph (cut_off_count);
2223 /* Dumper function for NODE. */
2224 static void
2225 gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node)
2227 unsigned mod_id, func_id;
2228 struct gcov_info *mod_info;
2229 mod_id = get_module_ident_from_func_glob_uid (node->guid);
2230 func_id = get_intra_module_func_id (node->guid);
2232 mod_info = the_dyn_call_graph.modules[mod_id - 1];
2234 fprintf (stderr, "NODE(%llx) module(%s) func(%u)",
2235 (long long)node->guid,
2236 mod_info->mod_info->source_filename, func_id);
2239 /* Dumper function for NODE. M is the module id and F is the function id. */
2241 static void
2242 gcov_dump_cgraph_node (struct dyn_cgraph_node *node, unsigned m, unsigned f)
2244 unsigned mod_id, func_id;
2245 struct gcov_info *mod_info;
2246 struct dyn_cgraph_edge *callers;
2247 struct dyn_cgraph_edge *callees;
2249 mod_id = get_module_ident_from_func_glob_uid (node->guid);
2250 func_id = get_intra_module_func_id (node->guid);
2251 gcc_assert (mod_id == (m + 1) && func_id == f);
2253 mod_info = the_dyn_call_graph.modules[mod_id - 1];
2255 fprintf (stderr, "NODE(%llx) module(%s) func(%x)\n",
2256 (long long) node->guid,
2257 mod_info->mod_info->source_filename, f);
2259 /* Now dump callers. */
2260 callers = node->callers;
2261 fprintf (stderr, "\t[CALLERS]\n");
2262 while (callers != 0)
2264 fprintf (stderr,"\t\t[count=%ld] ", (long) callers->count);
2265 gcov_dump_cgraph_node_short (callers->caller);
2266 fprintf (stderr,"\n");
2267 callers = callers->next_caller;
2270 callees = node->callees;
2271 fprintf (stderr, "\t[CALLEES]\n");
2272 while (callees != 0)
2274 fprintf (stderr,"\t\t[count=%ld] ", (long) callees->count);
2275 gcov_dump_cgraph_node_short (callees->callee);
2276 fprintf (stderr,"\n");
2277 callees = callees->next_callee;
2281 /* Dumper function for NODE. M is the module_ident -1
2282 and F is the function id. */
2284 static void
2285 gcov_dump_cgraph_node_dot (struct dyn_cgraph_node *node,
2286 unsigned m, unsigned f,
2287 gcov_type cutoff_count)
2289 unsigned mod_id, func_id, imp_len = 0, i;
2290 struct gcov_info *mod_info;
2291 const struct dyn_imp_mod **imp_mods;
2292 struct dyn_cgraph_edge *callees;
2294 mod_id = get_module_ident_from_func_glob_uid (node->guid);
2295 func_id = get_intra_module_func_id (node->guid);
2296 gcc_assert (mod_id == (m + 1) && func_id == f);
2298 mod_info = the_dyn_call_graph.modules[mod_id - 1];
2300 fprintf (stderr, "NODE_%llx[label=\"MODULE\\n(%s)\\n FUNC(%x)\\n",
2301 (long long) node->guid, mod_info->mod_info->source_filename, f);
2303 imp_mods = gcov_get_sorted_import_module_array (mod_info, &imp_len);
2304 fprintf (stderr, "IMPORTS:\\n");
2305 if (imp_mods)
2307 for (i = 0; i < imp_len; i++)
2308 fprintf (stderr, "%s\\n", imp_mods[i]->imp_mod->mod_info->source_filename);
2309 fprintf (stderr, "\"]\n");
2310 free (imp_mods);
2312 else
2313 fprintf (stderr, "\"]\n");
2315 callees = node->callees;
2316 while (callees != 0)
2318 if (callees->count >= cutoff_count)
2319 fprintf (stderr, "NODE_%llx -> NODE_%llx[label=%lld color=red]\n",
2320 (long long) node->guid, (long long) callees->callee->guid,
2321 (long long) callees->count);
2322 else
2323 fprintf (stderr, "NODE_%llx -> NODE_%llx[label=%lld color=blue]\n",
2324 (long long) node->guid, (long long) callees->callee->guid,
2325 (long long) callees->count);
2326 callees = callees->next_callee;
2330 /* Dump dynamic call graph. CUTOFF_COUNT is the computed hot edge threshold. */
2332 static void
2333 gcov_dump_callgraph (gcov_type cutoff_count)
2335 struct gcov_info *gi_ptr;
2336 unsigned m_ix;
2337 int do_dump;
2339 do_dump = do_cgraph_dump ();
2341 if (do_dump == 0)
2342 return;
2344 fprintf (stderr,"digraph dyn_call_graph {\n");
2345 fprintf (stderr,"node[shape=box]\nsize=\"11,8.5\"\n");
2347 for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
2349 const struct gcov_fn_info *fi_ptr;
2350 unsigned f_ix;
2352 gi_ptr = the_dyn_call_graph.modules[m_ix];
2354 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
2356 struct dyn_cgraph_node *node;
2358 fi_ptr = gi_ptr->functions[f_ix];
2359 node = *(pointer_set_find_or_insert
2360 (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
2361 gcc_assert (node);
2363 /* skip dead functions */
2364 if (!node->callees && !node->callers)
2365 continue;
2367 if (do_dump == 1)
2368 gcov_dump_cgraph_node (node, m_ix, fi_ptr->ident);
2369 else
2370 gcov_dump_cgraph_node_dot (node, m_ix, fi_ptr->ident,
2371 cutoff_count);
2374 fprintf (stderr,"}\n");
2377 static int
2378 dump_imported_modules_1 (const void *value,
2379 void *data1 ATTRIBUTE_UNUSED,
2380 void *data2 ATTRIBUTE_UNUSED,
2381 void *data3 ATTRIBUTE_UNUSED)
2383 const struct dyn_imp_mod *d = (const struct dyn_imp_mod*) value;
2384 fprintf (stderr, "%d ", get_module_ident (d->imp_mod));
2385 return 1;
2388 static int
2389 dump_exported_to_1 (const void *value,
2390 void *data1 ATTRIBUTE_UNUSED,
2391 void *data2 ATTRIBUTE_UNUSED,
2392 void *data3 ATTRIBUTE_UNUSED)
2394 const struct gcov_info *modu = (const struct gcov_info *) value;
2395 fprintf (stderr, "%d ", get_module_ident (modu));
2396 return 1;
2399 static void ATTRIBUTE_UNUSED
2400 debug_dump_imported_modules (const struct dyn_pointer_set *p)
2402 fprintf (stderr, "imported: ");
2403 pointer_set_traverse (p, dump_imported_modules_1, 0, 0, 0);
2404 fprintf (stderr, "\n");
2407 static void ATTRIBUTE_UNUSED
2408 debug_dump_exported_to (const struct dyn_pointer_set *p)
2410 fprintf (stderr, "exported: ");
2411 pointer_set_traverse (p, dump_exported_to_1, 0, 0, 0);
2412 fprintf (stderr, "\n");
2414 #endif
2415 #endif /* IN_GCOV_TOOL */