Backport r203445 from v17
[official-gcc.git] / gcc-4_8 / libgcc / libgcov-util.c
blobb3098e5cda57ef5475a2ded8b938642d9c81e744
1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014 Free Software Foundation, Inc.
4 Contributed by Rong Xu <xur@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 #define IN_GCOV_TOOL 1
29 #define L_gcov 1
30 #define L_gcov_merge_add 1
31 #define L_gcov_merge_single 1
32 #define L_gcov_merge_delta 1
33 #define L_gcov_merge_icall_topn 1
34 #define L_gcov_merge_dc 1
35 #define L_gcov_merge_ior 1
36 #define L_gcov_merge_reusedist 1
38 #include "libgcov.h"
39 #include "intl.h"
40 #include "diagnostic.h"
41 #include "version.h"
42 #include "demangle.h"
44 extern gcov_type gcov_read_counter_mem();
45 extern unsigned gcov_get_merge_weight();
47 /* We need the dumping and merge part of code in libgcov. */
48 #include "libgcov-driver.c"
49 #include "libgcov-merge.c"
51 /* Verbose mode for debug. */
52 static int verbose;
54 /* Set verbose flag. */
55 void gcov_set_verbose (void)
57 verbose = 1;
60 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
62 #include "obstack.h"
63 #include <unistd.h>
64 #include <ftw.h>
66 static void tag_function (unsigned, unsigned);
67 static void tag_blocks (unsigned, unsigned);
68 static void tag_arcs (unsigned, unsigned);
69 static void tag_lines (unsigned, unsigned);
70 static void tag_counters (unsigned, unsigned);
71 static void tag_summary (unsigned, unsigned);
72 static void tag_module_info (unsigned, unsigned);
74 /* The gcov_info for the first module. */
75 static struct gcov_info *curr_gcov_info;
76 /* The gcov_info being processed. */
77 static struct gcov_info *gcov_info_head;
78 /* This variable points to the module being processed. */
79 static struct gcov_module_info *curr_module_info;
80 /* This variable contains all the functions in current module. */
81 static struct obstack fn_info;
82 /* The function being processed. */
83 static struct gcov_fn_info *curr_fn_info;
84 /* The number of functions seen so far. */
85 static unsigned num_fn_info;
86 /* This variable contains all the counters for current module. */
87 static int k_ctrs_mask[GCOV_COUNTERS];
88 /* The kind of counters that have been seen. */
89 static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
90 /* Number of kind of counters that have been seen. */
91 static int k_ctrs_types;
92 /* The longest length of all the filenames. */
93 static int max_filename_len;
95 /* Merge functions for counters. */
96 static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
97 __gcov_merge_add,
98 __gcov_merge_add,
99 __gcov_merge_add,
100 __gcov_merge_single,
101 __gcov_merge_delta,
102 __gcov_merge_single,
103 __gcov_merge_add,
104 __gcov_merge_ior,
105 __gcov_merge_icall_topn,
106 __gcov_merge_dc,
109 /* Set the ctrs field in gcvo_fn_info object FN_INFO. */
111 static void
112 set_fn_ctrs (struct gcov_fn_info *fn_info)
114 int j = 0, i;
116 for (i = 0; i < GCOV_COUNTERS; i++)
118 if (k_ctrs_mask[i] == 0)
119 continue;
120 fn_info->ctrs[j].num = k_ctrs[i].num;
121 fn_info->ctrs[j].values = k_ctrs[i].values;
122 j++;
124 if (k_ctrs_types == 0)
125 k_ctrs_types = j;
126 else
127 gcc_assert (j == k_ctrs_types);
130 typedef struct tag_format
132 unsigned tag;
133 char const *name;
134 void (*proc) (unsigned, unsigned);
135 } tag_format_t;
137 static const tag_format_t tag_table[] =
139 {0, "NOP", NULL},
140 {0, "UNKNOWN", NULL},
141 {0, "COUNTERS", tag_counters},
142 {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
143 {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
144 {GCOV_TAG_ARCS, "ARCS", tag_arcs},
145 {GCOV_TAG_LINES, "LINES", tag_lines},
146 {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
147 {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary},
148 {GCOV_TAG_MODULE_INFO, "MODULE INFO", tag_module_info},
149 {0, NULL, NULL}
152 /* Handler for reading function tag. */
154 static void
155 tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
157 int i;
159 /* write out previous fn_info. */
160 if (num_fn_info)
162 set_fn_ctrs (curr_fn_info);
163 obstack_ptr_grow (&fn_info, curr_fn_info);
166 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
167 counter types. */
168 curr_fn_info = (struct gcov_fn_info *) xcalloc (sizeof (struct gcov_fn_info)
169 + GCOV_COUNTERS * sizeof (struct gcov_ctr_info), 1);
171 for (i = 0; i < GCOV_COUNTERS; i++)
172 k_ctrs[i].num = 0;
173 k_ctrs_types = 0;
175 curr_fn_info->key = curr_gcov_info;
176 curr_fn_info->ident = gcov_read_unsigned ();
177 curr_fn_info->lineno_checksum = gcov_read_unsigned ();
178 curr_fn_info->cfg_checksum = gcov_read_unsigned ();
179 num_fn_info++;
181 if (verbose)
182 fprintf (stdout, "tag one function id=%d\n", curr_fn_info->ident);
185 /* Handler for reading block tag. */
187 static void
188 tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
190 gcc_assert (0);
193 /* Handler for reading flow arc tag. */
195 static void
196 tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
198 gcc_assert (0);
201 /* Handler for reading line tag. */
203 static void
204 tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
206 gcc_assert (0);
209 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
211 static void
212 tag_counters (unsigned tag, unsigned length)
214 unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
215 gcov_type *values;
216 unsigned ix;
217 unsigned tag_ix;
219 tag_ix = GCOV_COUNTER_FOR_TAG (tag);
220 gcc_assert (tag_ix < GCOV_COUNTERS);
221 k_ctrs_mask [tag_ix] = 1;
222 gcc_assert (k_ctrs[tag_ix].num == 0);
223 k_ctrs[tag_ix].num = n_counts;
225 k_ctrs[tag_ix].values = values = (gcov_type *) xmalloc (n_counts * sizeof (gcov_type));
226 gcc_assert (values);
228 for (ix = 0; ix != n_counts; ix++)
229 values[ix] = gcov_read_counter ();
232 /* Handler for reading summary tag. */
234 static void
235 tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
237 struct gcov_summary summary;
239 gcov_read_summary (&summary);
242 /* This function is called at the end of reading a gcda file.
243 It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO. */
245 static void
246 read_gcda_finalize (struct gcov_info *obj_info)
248 int i;
250 set_fn_ctrs (curr_fn_info);
251 obstack_ptr_grow (&fn_info, curr_fn_info);
253 /* We set the following fields: merge, n_functions, and functions. */
254 obj_info->n_functions = num_fn_info;
255 obj_info->functions = (const struct gcov_fn_info**) obstack_finish (&fn_info);
257 /* wrap all the counter array. */
258 for (i=0; i< GCOV_COUNTERS; i++)
260 if (k_ctrs_mask[i])
261 obj_info->merge[i] = ctr_merge_functions[i];
264 obj_info->mod_info = curr_module_info;
267 extern void gcov_read_module_info (struct gcov_module_info *mod_info,
268 gcov_unsigned_t len);
270 /* Substitute string is of this format:
271 old_sub1:new_sub1[,old_sub2:new_sub2]
272 Note that we only apply the substutution ONE time, for the first match. */
274 static const char *substitute_string;
276 /* A global function to set the substitute string. */
278 void
279 lipo_set_substitute_string (const char *str)
281 char *sub_dup = xstrdup (str);
282 char *cur_sub = sub_dup;
284 /* First check if the str is in the right form.
285 Dup the string and split it into tokens with
286 ',' and ':' as the delimiters. */
289 char *new_str;
290 char *next = strchr (cur_sub, ',');
291 if (next)
292 *next++ = '\0';
293 new_str = strchr (cur_sub, ':');
294 if (!new_str)
296 fprintf (stderr, "Warning: Skip invalid substibution string:%s\n",
297 str);
298 free (sub_dup);
299 return;
301 *new_str++ = '\0';
302 cur_sub = next;
303 } while (cur_sub);
305 free (sub_dup);
306 substitute_string = str;
309 /* Replace the first occurance of CUT_STR to NEW_STR in INPUT_STR. */
311 static char *
312 lipo_process_substitute_string_1 (char *input_str,
313 const char *cur_str,
314 const char *new_str)
316 char *p;
318 if (!input_str || !cur_str || !new_str)
319 return input_str;
321 if ((p = strstr (input_str, cur_str)) != NULL)
323 char *t;
325 if (verbose)
326 printf ("Substitute: %s \n", input_str);
327 t = (char*) xmalloc (strlen (input_str) + 1
328 + strlen (new_str) - strlen (cur_str));
329 *p = 0;
331 strcpy (t, input_str);
332 strcat (t, new_str);
333 strcat (t, p + strlen (cur_str));
334 if (verbose)
335 printf (" --> %s\n", t);
336 return t;
339 return input_str;
342 /* Parse the substitute string and apply to the INPUT_STR. */
344 static char *
345 lipo_process_substitute_string (char *input_str)
347 char *sub_dup, *cur_sub, *ret;
349 if (substitute_string == NULL)
350 return input_str;
352 sub_dup = xstrdup (substitute_string);
353 cur_sub = sub_dup;
354 ret = input_str;
356 /* Dup the string and split it into tokens with
357 ',' and ':' as the delimiters. */
360 char *new_str, *new_input;
361 char *next = strchr (cur_sub, ',');
362 if (next)
363 *next++ = '\0';
364 new_str = strchr (cur_sub, ':');
365 gcc_assert (new_str);
366 *new_str++ = '\0';
367 new_input = ret;
368 ret = lipo_process_substitute_string_1 (new_input, cur_sub, new_str);
369 if (ret != new_input)
370 free (new_input);
371 cur_sub = next;
372 } while (cur_sub);
374 free (sub_dup);
375 return ret;
378 /* This function reads module_info from a gcda file. */
380 static void
381 tag_module_info (unsigned tag ATTRIBUTE_UNUSED, unsigned length)
383 struct gcov_module_info* mod_info;
385 mod_info = (struct gcov_module_info *)
386 xmalloc ((length + 2) * sizeof (gcov_unsigned_t));
388 gcov_read_module_info (mod_info, length);
390 if (mod_info->is_primary)
392 mod_info->da_filename =
393 lipo_process_substitute_string (mod_info->da_filename);
394 curr_module_info = mod_info;
396 else
397 free (mod_info);
400 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
401 Program level summary CURRENT_SUMMARY will also be updated. */
403 static struct gcov_info *
404 read_gcda_file (const char *filename)
406 unsigned tags[4];
407 unsigned depth = 0;
408 unsigned magic, version;
409 struct gcov_info *obj_info;
410 int i, len;
411 char *str_dup;
413 for (i=0; i< GCOV_COUNTERS; i++)
414 k_ctrs_mask[i] = 0;
415 k_ctrs_types = 0;
417 if (!gcov_open (filename))
419 fprintf (stderr, "%s:cannot open\n", filename);
420 return NULL;
423 /* Read magic. */
424 magic = gcov_read_unsigned ();
425 if (magic != GCOV_DATA_MAGIC)
427 fprintf (stderr, "%s:not a gcov data file\n", filename);
428 gcov_close ();
429 return NULL;
432 /* Read version. */
433 version = gcov_read_unsigned ();
434 if (version != GCOV_VERSION)
436 fprintf (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
437 gcov_close ();
438 return NULL;
441 /* Instantiate a gcov_info object. */
442 curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
443 sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
445 obj_info->version = version;
446 obstack_init (&fn_info);
447 num_fn_info = 0;
448 curr_fn_info = 0;
449 curr_module_info = 0;
451 str_dup = lipo_process_substitute_string (xstrdup (filename));
452 obj_info->filename = str_dup;
454 if ((len = strlen (str_dup)) > max_filename_len)
455 max_filename_len = len;
457 /* Read stamp. */
458 obj_info->stamp = gcov_read_unsigned ();
460 while (1)
462 gcov_position_t base;
463 unsigned tag, length;
464 tag_format_t const *format;
465 unsigned tag_depth;
466 int error;
467 unsigned mask;
469 tag = gcov_read_unsigned ();
470 if (!tag)
471 break;
472 length = gcov_read_unsigned ();
473 base = gcov_position ();
474 mask = GCOV_TAG_MASK (tag) >> 1;
475 for (tag_depth = 4; mask; mask >>= 8)
477 if (((mask & 0xff) != 0xff))
479 fprintf (stderr, "warning: %s:tag `%08x' is invalid\n", filename, tag);
480 break;
482 tag_depth--;
484 for (format = tag_table; format->name; format++)
485 if (format->tag == tag)
486 goto found;
487 format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
488 found:;
489 if (tag)
491 if (depth && depth < tag_depth)
493 if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
494 fprintf (stderr, "warning: %s:tag `%08x' is incorrectly nested\n",
495 filename, tag);
497 depth = tag_depth;
498 tags[depth - 1] = tag;
501 if (format->proc)
503 unsigned long actual_length;
505 (*format->proc) (tag, length);
507 actual_length = gcov_position () - base;
508 if (actual_length > length)
509 fprintf (stderr,"warning: %s:record size mismatch %lu bytes overread\n",
510 filename, actual_length - length);
511 else if (length > actual_length)
512 fprintf (stderr,"warning: %s:record size mismatch %lu bytes unread\n",
513 filename, length - actual_length);
516 gcov_sync (base, length);
517 if ((error = gcov_is_error ()))
519 fprintf (stderr,error < 0 ? "warning:%s:counter overflow at %lu\n" :
520 "Warning:%s:read error at %lu\n", filename,
521 (long unsigned) gcov_position ());
522 break;
526 read_gcda_finalize (obj_info);
527 gcov_close ();
529 return obj_info;
532 extern int is_module_available (const char *, unsigned *, int);
534 /* If only use the modules in the modu_list. */
536 static int flag_use_modu_list;
538 /* Set to use only the modules in the modu_list file. */
540 void
541 set_use_modu_list (void)
543 flag_use_modu_list = 1;
547 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
548 Return a non-zero value to stop the tree walk. */
550 static int
551 ftw_read_file (const char *filename,
552 const struct stat *status ATTRIBUTE_UNUSED,
553 int type)
555 int filename_len;
556 int suffix_len;
557 struct gcov_info *obj_info;
559 /* Only read regular files. */
560 if (type != FTW_F)
561 return 0;
563 filename_len = strlen (filename);
564 suffix_len = strlen (GCOV_DATA_SUFFIX);
566 if (filename_len <= suffix_len)
567 return 0;
569 if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
570 return 0;
572 if (verbose)
573 fprintf (stderr, "reading file: %s\n", filename);
575 obj_info = read_gcda_file (filename);
577 if (obj_info->mod_info)
579 unsigned mod_id = obj_info->mod_info->ident;
580 int create = (flag_use_modu_list ? 0 : 1);
582 if (!is_module_available (obj_info->mod_info->source_filename,
583 &mod_id, create))
585 if (verbose)
586 fprintf (stderr, "warning: module %s (%d) is not avail\n",
587 obj_info->mod_info->source_filename, mod_id);
588 return 0;
592 obj_info->next = gcov_info_head;
593 gcov_info_head = obj_info;
595 return 0;
598 /* Source profile directory name. */
600 static const char *source_profile_dir;
602 /* Return Source profile directory name. */
604 const char *
605 get_source_profile_dir (void)
607 return source_profile_dir;
610 /* Initializer for reading a profile dir. */
612 static inline void
613 read_profile_dir_init (void)
615 gcov_info_head = 0;
618 /* Driver for read a profile directory and convert into gcov_info list in memory.
619 Return NULL on error,
620 Return the head of gcov_info list on success.
621 Note the file static variable GCOV_MAX_FILENAME is also set. */
623 struct gcov_info *
624 gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
626 char *pwd;
627 int ret;
629 read_profile_dir_init ();
631 if (access (dir_name, R_OK) != 0)
633 fprintf (stderr, "cannot access directory %s\n", dir_name);
634 return NULL;
636 pwd = getcwd (NULL, 0);
637 gcc_assert (pwd);
638 ret = chdir (dir_name);
639 if (ret !=0)
641 fprintf (stderr, "%s is not a directory\n", dir_name);
642 return NULL;
644 source_profile_dir = getcwd (NULL, 0);
646 ftw (".", ftw_read_file, 50);
647 ret = chdir (pwd);
648 free (pwd);
651 /* gcov_max_filename is defined in libgcov.c that records the
652 max filename len. We need to set it here to allocate the
653 array for dumping. */
654 gcov_max_filename = max_filename_len;
656 return gcov_info_head;;
659 /* This part of the code is to merge profile counters. */
661 static gcov_type *gcov_value_buf;
662 static gcov_unsigned_t gcov_value_buf_size;
663 static gcov_unsigned_t gcov_value_buf_pos;
664 static unsigned gcov_merge_weight;
666 /* Read a counter value from gcov_value_buf array. */
668 gcov_type
669 gcov_read_counter_mem (void)
671 gcov_type ret;
672 gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
673 ret = *(gcov_value_buf + gcov_value_buf_pos);
674 ++gcov_value_buf_pos;
675 return ret;
678 /* Return the recorded merge weight. */
680 unsigned
681 gcov_get_merge_weight (void)
683 return gcov_merge_weight;
686 /* A wrapper function for merge functions. It sets up the
687 value buffer and weights and then calls the merge function. */
689 static void
690 merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n,
691 gcov_type *v2, unsigned w)
693 gcov_value_buf = v2;
694 gcov_value_buf_pos = 0;
695 gcov_value_buf_size = n;
696 gcov_merge_weight = w;
697 (*f) (v1, n);
700 /* Offline tool to manipulate profile data.
701 This tool targets on matched profiles. But it has some tolerance on
702 unmatched profiles.
703 When merging p1 to p2 (p2 is the dst),
704 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
705 emit warning
706 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
707 specified weight; emit warning.
708 * m.gcda in both p1 and p2:
709 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
710 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
711 p2->m.gcda->f and
712 drop p1->m.gcda->f. A warning is emitted. */
714 /* Add INFO2's counter to INFO1, multiplying by weight W. */
716 static int
717 gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
719 unsigned f_ix;
720 unsigned n_functions = info1->n_functions;
721 int has_mismatch = 0;
723 gcc_assert (info2->n_functions == n_functions);
724 for (f_ix = 0; f_ix < n_functions; f_ix++)
726 unsigned t_ix;
727 const struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
728 const struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
729 const struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
731 if (!gfi_ptr1 || gfi_ptr1->key != info1)
732 continue;
733 if (!gfi_ptr2 || gfi_ptr2->key != info2)
734 continue;
736 if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
738 fprintf (stderr, "in %s, cfg_checksum mismatch, skipping\n",
739 info1->filename);
740 has_mismatch = 1;
741 continue;
743 ci_ptr1 = gfi_ptr1->ctrs;
744 ci_ptr2 = gfi_ptr2->ctrs;
745 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
747 gcov_merge_fn merge1 = info1->merge[t_ix];
748 gcov_merge_fn merge2 = info2->merge[t_ix];
750 gcc_assert (merge1 == merge2);
751 if (!merge1)
752 continue;
753 gcc_assert (ci_ptr1->num == ci_ptr2->num);
754 merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num, ci_ptr2->values, w);
755 ci_ptr1++;
756 ci_ptr2++;
760 return has_mismatch;
763 /* Find and return the match gcov_info object for INFO from ARRAY.
764 SIZE is the length of ARRAY.
765 Return NULL if there is no match. */
767 static struct gcov_info *
768 find_match_gcov_info (struct gcov_info **array, int size, struct gcov_info *info)
770 struct gcov_info *gi_ptr;
771 struct gcov_info *ret = NULL;
772 int i;
774 for (i = 0; i < size; i++)
776 gi_ptr = array[i];
777 if (gi_ptr == 0)
778 continue;
779 /* For LIPO, it's easy as we can just match the module_id. */
780 if (gi_ptr->mod_info && info->mod_info)
782 if (gi_ptr->mod_info->ident == info->mod_info->ident)
784 ret = gi_ptr;
785 array[i] = 0;
786 break;
789 else /* For FDO, we have to match the name. This can be expensive.
790 Maybe we should use hash here. */
791 if (!strcmp (gi_ptr->filename, info->filename))
793 ret = gi_ptr;
794 array[i] = 0;
795 break;
799 if (ret && ret->n_functions != info->n_functions)
801 fprintf (stderr, "mismatched profiles in %s (%d functions"
802 " vs %d functions)\n",
803 ret->filename,
804 ret->n_functions,
805 info->n_functions);
806 ret = NULL;
808 return ret;
811 /* Merge the list of gcov_info list from SRC_PROFILE to TGT_PROFILE.
812 Return 0 on success: without mismatch.
813 Reutrn 1 on error. */
816 gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
817 int w1, int w2)
819 struct gcov_info *gi_ptr;
820 struct gcov_info **tgt_infos;
821 struct gcov_info *tgt_tail;
822 struct gcov_info **in_src_not_tgt;
823 unsigned tgt_cnt = 0, src_cnt = 0;
824 unsigned unmatch_info_cnt = 0;
825 unsigned int i;
827 for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
828 tgt_cnt++;
829 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
830 src_cnt++;
831 tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
832 * tgt_cnt);
833 gcc_assert (tgt_infos);
834 in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
835 * src_cnt);
836 gcc_assert (in_src_not_tgt);
838 for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
839 tgt_infos[i] = gi_ptr;
841 tgt_tail = tgt_infos[tgt_cnt - 1];
843 /* First pass on tgt_profile, we multiply w1 to all counters. */
844 if (w1 > 1)
846 for (i = 0; i < tgt_cnt; i++)
847 gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
850 /* Second pass, add src_profile to the tgt_profile. */
851 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
853 struct gcov_info *gi_ptr1;
855 gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
856 if (gi_ptr1 == NULL)
858 in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
859 continue;
861 gcov_merge (gi_ptr1, gi_ptr, w2);
864 /* For modules in src but not in tgt. We adjust the counter and append. */
865 for (i = 0; i < unmatch_info_cnt; i++)
867 gi_ptr = in_src_not_tgt[i];
868 gcov_merge (gi_ptr, gi_ptr, w2 - 1);
869 tgt_tail->next = gi_ptr;
870 tgt_tail = gi_ptr;
873 return 0;
876 typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
878 /* Performing FN upon arc counters. */
880 static void
881 __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
882 counter_op_fn fn, void *data1, void *data2)
884 for (; n_counters; counters++, n_counters--)
886 gcov_type val = *counters;
887 *counters = fn(val, data1, data2);
891 /* Performing FN upon ior counters. */
893 static void
894 __gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
895 unsigned n_counters ATTRIBUTE_UNUSED,
896 counter_op_fn fn ATTRIBUTE_UNUSED,
897 void *data1 ATTRIBUTE_UNUSED,
898 void *data2 ATTRIBUTE_UNUSED)
900 /* Do nothing. */
903 /* Performaing FN upon delta counters. */
905 static void
906 __gcov_delta_counter_op (gcov_type *counters, unsigned n_counters,
907 counter_op_fn fn, void *data1, void *data2)
909 unsigned i, n_measures;
911 gcc_assert (!(n_counters % 4));
912 n_measures = n_counters / 4;
913 for (i = 0; i < n_measures; i++, counters += 4)
915 counters[2] = fn (counters[2], data1, data2);
916 counters[3] = fn (counters[3], data1, data2);
920 /* Performing FN upon single counters. */
922 static void
923 __gcov_single_counter_op (gcov_type *counters, unsigned n_counters,
924 counter_op_fn fn, void *data1, void *data2)
926 unsigned i, n_measures;
928 gcc_assert (!(n_counters % 3));
929 n_measures = n_counters / 3;
930 for (i = 0; i < n_measures; i++, counters += 3)
932 counters[1] = fn (counters[1], data1, data2);
933 counters[2] = fn (counters[2], data1, data2);
937 /* Performing FN upon indirect-call profile counters. */
939 static void
940 __gcov_icall_topn_op (gcov_type *counters, unsigned n_counters,
941 counter_op_fn fn, void *data1, void *data2)
943 unsigned i;
945 gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS));
946 for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS)
948 unsigned j;
949 gcov_type *value_array = &counters[i + 1];
951 for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
952 value_array[j + 1] = fn (value_array[j + 1], data1, data2);
956 /* Performing FN upon direct-call profile counters. */
958 static void
959 __gcov_dc_op (gcov_type *counters, unsigned n_counters,
960 counter_op_fn fn, void *data1, void *data2)
962 unsigned i;
964 gcc_assert (!(n_counters % 2));
965 for (i = 0; i < n_counters; i += 2)
966 counters[i + 1] = fn (counters[i + 1], data1, data2);
970 /* Scaling the counter value V by multiplying *(float*) DATA1. */
972 static gcov_type
973 fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
975 float f = *(float *) data1;
976 return (gcov_type) (v * f);
979 /* Scaling the counter value V by multiplying DATA2/DATA1. */
981 static gcov_type
982 int_scale (gcov_type v, void *data1, void *data2)
984 int n = *(int *) data1;
985 int d = *(int *) data2;
986 return (gcov_type) ((v / d) * n);
989 /* Type of function used to process counters. */
990 typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
991 counter_op_fn, void *, void *);
993 /* Function array to process profile counters. */
994 static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
995 __gcov_add_counter_op,
996 __gcov_add_counter_op,
997 __gcov_add_counter_op,
998 __gcov_single_counter_op,
999 __gcov_delta_counter_op,
1000 __gcov_single_counter_op,
1001 __gcov_add_counter_op,
1002 __gcov_ior_counter_op,
1003 __gcov_icall_topn_op,
1004 __gcov_dc_op,
1007 /* Driver for scaling profile counters. */
1010 gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
1012 struct gcov_info *gi_ptr;
1013 unsigned f_ix;
1015 if (verbose)
1016 fprintf (stdout, "scale_factor is %f\n", scale_factor);
1018 /* Scaling the counters. */
1019 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
1020 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
1022 unsigned t_ix;
1023 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
1024 const struct gcov_ctr_info *ci_ptr;
1026 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
1027 continue;
1029 ci_ptr = gfi_ptr->ctrs;
1030 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
1032 gcov_merge_fn merge = gi_ptr->merge[t_ix];
1034 if (!merge)
1035 continue;
1036 if (d == 0)
1037 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
1038 fp_scale, &scale_factor, NULL);
1039 else
1040 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
1041 int_scale, &n, &d);
1042 ci_ptr++;
1046 return 0;
1049 /* Driver to normalize profile counters. */
1052 gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
1054 struct gcov_info *gi_ptr;
1055 gcov_type curr_max_val = 0;
1056 unsigned f_ix;
1057 unsigned int i;
1058 float scale_factor;
1060 /* Find the largest count value. */
1061 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
1062 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
1064 unsigned t_ix;
1065 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
1066 const struct gcov_ctr_info *ci_ptr;
1068 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
1069 continue;
1071 ci_ptr = gfi_ptr->ctrs;
1072 for (t_ix = 0; t_ix < 1; t_ix++)
1074 for (i = 0; i < ci_ptr->num; i++)
1075 if (ci_ptr->values[i] > curr_max_val)
1076 curr_max_val = ci_ptr->values[i];
1077 ci_ptr++;
1081 scale_factor = (float)max_val / curr_max_val;
1082 if (verbose)
1083 fprintf (stdout, "max_val is %lld\n", (long long) curr_max_val);
1085 return gcov_profile_scale (profile, scale_factor, 0, 0);