Do not enable -mpcrel by default at the current time
[official-gcc.git] / libgcc / libgcov-util.c
blobc794132c17237b7269ac2aab91af3ec6d07dda25
1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2019 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
30 #include "libgcov.h"
31 #include "intl.h"
32 #include "diagnostic.h"
33 #include "version.h"
34 #include "demangle.h"
35 #include "gcov-io.h"
37 /* Borrowed from basic-block.h. */
38 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
40 extern gcov_position_t gcov_position();
41 extern int gcov_is_error();
43 /* Verbose mode for debug. */
44 static int verbose;
46 /* Set verbose flag. */
47 void gcov_set_verbose (void)
49 verbose = 1;
52 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
54 #include "obstack.h"
55 #include <unistd.h>
56 #ifdef HAVE_FTW_H
57 #include <ftw.h>
58 #endif
60 static void tag_function (unsigned, unsigned);
61 static void tag_blocks (unsigned, unsigned);
62 static void tag_arcs (unsigned, unsigned);
63 static void tag_lines (unsigned, unsigned);
64 static void tag_counters (unsigned, unsigned);
65 static void tag_summary (unsigned, unsigned);
67 /* The gcov_info for the first module. */
68 static struct gcov_info *curr_gcov_info;
69 /* The gcov_info being processed. */
70 static struct gcov_info *gcov_info_head;
71 /* This variable contains all the functions in current module. */
72 static struct obstack fn_info;
73 /* The function being processed. */
74 static struct gcov_fn_info *curr_fn_info;
75 /* The number of functions seen so far. */
76 static unsigned num_fn_info;
77 /* This variable contains all the counters for current module. */
78 static int k_ctrs_mask[GCOV_COUNTERS];
79 /* The kind of counters that have been seen. */
80 static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
81 /* Number of kind of counters that have been seen. */
82 static int k_ctrs_types;
83 /* The object summary being processed. */
84 static struct gcov_summary *curr_object_summary;
86 /* Merge functions for counters. */
87 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
88 static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
89 #include "gcov-counter.def"
91 #undef DEF_GCOV_COUNTER
93 /* Set the ctrs field in gcov_fn_info object FN_INFO. */
95 static void
96 set_fn_ctrs (struct gcov_fn_info *fn_info)
98 int j = 0, i;
100 for (i = 0; i < GCOV_COUNTERS; i++)
102 if (k_ctrs_mask[i] == 0)
103 continue;
104 fn_info->ctrs[j].num = k_ctrs[i].num;
105 fn_info->ctrs[j].values = k_ctrs[i].values;
106 j++;
108 if (k_ctrs_types == 0)
109 k_ctrs_types = j;
110 else
111 gcc_assert (j == k_ctrs_types);
114 /* For each tag in gcda file, we have an entry here.
115 TAG is the tag value; NAME is the tag name; and
116 PROC is the handler function. */
118 typedef struct tag_format
120 unsigned tag;
121 char const *name;
122 void (*proc) (unsigned, unsigned);
123 } tag_format_t;
125 /* Handler table for various Tags. */
127 static const tag_format_t tag_table[] =
129 {0, "NOP", NULL},
130 {0, "UNKNOWN", NULL},
131 {0, "COUNTERS", tag_counters},
132 {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
133 {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
134 {GCOV_TAG_ARCS, "ARCS", tag_arcs},
135 {GCOV_TAG_LINES, "LINES", tag_lines},
136 {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
137 {0, NULL, NULL}
140 /* Handler for reading function tag. */
142 static void
143 tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
145 int i;
147 /* write out previous fn_info. */
148 if (num_fn_info)
150 set_fn_ctrs (curr_fn_info);
151 obstack_ptr_grow (&fn_info, curr_fn_info);
154 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
155 counter types. */
156 curr_fn_info = (struct gcov_fn_info *) xcalloc (sizeof (struct gcov_fn_info)
157 + GCOV_COUNTERS * sizeof (struct gcov_ctr_info), 1);
159 for (i = 0; i < GCOV_COUNTERS; i++)
160 k_ctrs[i].num = 0;
161 k_ctrs_types = 0;
163 curr_fn_info->key = curr_gcov_info;
164 curr_fn_info->ident = gcov_read_unsigned ();
165 curr_fn_info->lineno_checksum = gcov_read_unsigned ();
166 curr_fn_info->cfg_checksum = gcov_read_unsigned ();
167 num_fn_info++;
169 if (verbose)
170 fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
173 /* Handler for reading block tag. */
175 static void
176 tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
178 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
179 gcc_unreachable ();
182 /* Handler for reading flow arc tag. */
184 static void
185 tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
187 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
188 gcc_unreachable ();
191 /* Handler for reading line tag. */
193 static void
194 tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
196 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
197 gcc_unreachable ();
200 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
202 static void
203 tag_counters (unsigned tag, unsigned length)
205 unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
206 gcov_type *values;
207 unsigned ix;
208 unsigned tag_ix;
210 tag_ix = GCOV_COUNTER_FOR_TAG (tag);
211 gcc_assert (tag_ix < GCOV_COUNTERS);
212 k_ctrs_mask [tag_ix] = 1;
213 gcc_assert (k_ctrs[tag_ix].num == 0);
214 k_ctrs[tag_ix].num = n_counts;
216 k_ctrs[tag_ix].values = values = (gcov_type *) xmalloc (n_counts * sizeof (gcov_type));
217 gcc_assert (values);
219 for (ix = 0; ix != n_counts; ix++)
220 values[ix] = gcov_read_counter ();
223 /* Handler for reading summary tag. */
225 static void
226 tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
228 curr_object_summary = (gcov_summary *) xcalloc (sizeof (gcov_summary), 1);
229 gcov_read_summary (curr_object_summary);
232 /* This function is called at the end of reading a gcda file.
233 It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO. */
235 static void
236 read_gcda_finalize (struct gcov_info *obj_info)
238 int i;
240 set_fn_ctrs (curr_fn_info);
241 obstack_ptr_grow (&fn_info, curr_fn_info);
243 /* We set the following fields: merge, n_functions, functions
244 and summary. */
245 obj_info->n_functions = num_fn_info;
246 obj_info->functions = (const struct gcov_fn_info**) obstack_finish (&fn_info);
248 /* wrap all the counter array. */
249 for (i=0; i< GCOV_COUNTERS; i++)
251 if (k_ctrs_mask[i])
252 obj_info->merge[i] = ctr_merge_functions[i];
256 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
257 Program level summary CURRENT_SUMMARY will also be updated. */
259 static struct gcov_info *
260 read_gcda_file (const char *filename)
262 unsigned tags[4];
263 unsigned depth = 0;
264 unsigned magic, version;
265 struct gcov_info *obj_info;
266 int i;
268 for (i=0; i< GCOV_COUNTERS; i++)
269 k_ctrs_mask[i] = 0;
270 k_ctrs_types = 0;
272 if (!gcov_open (filename))
274 fnotice (stderr, "%s:cannot open\n", filename);
275 return NULL;
278 /* Read magic. */
279 magic = gcov_read_unsigned ();
280 if (magic != GCOV_DATA_MAGIC)
282 fnotice (stderr, "%s:not a gcov data file\n", filename);
283 gcov_close ();
284 return NULL;
287 /* Read version. */
288 version = gcov_read_unsigned ();
289 if (version != GCOV_VERSION)
291 fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
292 gcov_close ();
293 return NULL;
296 /* Instantiate a gcov_info object. */
297 curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
298 sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
300 obj_info->version = version;
301 obstack_init (&fn_info);
302 num_fn_info = 0;
303 curr_fn_info = 0;
304 curr_object_summary = NULL;
306 size_t len = strlen (filename) + 1;
307 char *str_dup = (char*) xmalloc (len);
309 memcpy (str_dup, filename, len);
310 obj_info->filename = str_dup;
313 /* Read stamp. */
314 obj_info->stamp = gcov_read_unsigned ();
316 while (1)
318 gcov_position_t base;
319 unsigned tag, length;
320 tag_format_t const *format;
321 unsigned tag_depth;
322 int error;
323 unsigned mask;
325 tag = gcov_read_unsigned ();
326 if (!tag)
327 break;
328 length = gcov_read_unsigned ();
329 base = gcov_position ();
330 mask = GCOV_TAG_MASK (tag) >> 1;
331 for (tag_depth = 4; mask; mask >>= 8)
333 if (((mask & 0xff) != 0xff))
335 warning (0, "%s:tag %qx is invalid", filename, tag);
336 break;
338 tag_depth--;
340 for (format = tag_table; format->name; format++)
341 if (format->tag == tag)
342 goto found;
343 format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
344 found:;
345 if (tag)
347 if (depth && depth < tag_depth)
349 if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
350 warning (0, "%s:tag %qx is incorrectly nested",
351 filename, tag);
353 depth = tag_depth;
354 tags[depth - 1] = tag;
357 if (format->proc)
359 unsigned long actual_length;
361 (*format->proc) (tag, length);
363 actual_length = gcov_position () - base;
364 if (actual_length > length)
365 warning (0, "%s:record size mismatch %lu bytes overread",
366 filename, actual_length - length);
367 else if (length > actual_length)
368 warning (0, "%s:record size mismatch %lu bytes unread",
369 filename, length - actual_length);
372 gcov_sync (base, length);
373 if ((error = gcov_is_error ()))
375 warning (0, error < 0 ? "%s:counter overflow at %lu" :
376 "%s:read error at %lu", filename,
377 (long unsigned) gcov_position ());
378 break;
382 read_gcda_finalize (obj_info);
383 gcov_close ();
385 return obj_info;
388 #ifdef HAVE_FTW_H
389 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
390 Return a non-zero value to stop the tree walk. */
392 static int
393 ftw_read_file (const char *filename,
394 const struct stat *status ATTRIBUTE_UNUSED,
395 int type)
397 int filename_len;
398 int suffix_len;
399 struct gcov_info *obj_info;
401 /* Only read regular files. */
402 if (type != FTW_F)
403 return 0;
405 filename_len = strlen (filename);
406 suffix_len = strlen (GCOV_DATA_SUFFIX);
408 if (filename_len <= suffix_len)
409 return 0;
411 if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
412 return 0;
414 if (verbose)
415 fnotice (stderr, "reading file: %s\n", filename);
417 obj_info = read_gcda_file (filename);
418 if (!obj_info)
419 return 0;
421 obj_info->next = gcov_info_head;
422 gcov_info_head = obj_info;
424 return 0;
426 #endif
428 /* Initializer for reading a profile dir. */
430 static inline void
431 read_profile_dir_init (void)
433 gcov_info_head = 0;
436 /* Driver for read a profile directory and convert into gcov_info list in memory.
437 Return NULL on error,
438 Return the head of gcov_info list on success. */
440 struct gcov_info *
441 gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
443 char *pwd;
444 int ret;
446 read_profile_dir_init ();
448 if (access (dir_name, R_OK) != 0)
450 fnotice (stderr, "cannot access directory %s\n", dir_name);
451 return NULL;
453 pwd = getcwd (NULL, 0);
454 gcc_assert (pwd);
455 ret = chdir (dir_name);
456 if (ret !=0)
458 fnotice (stderr, "%s is not a directory\n", dir_name);
459 return NULL;
461 #ifdef HAVE_FTW_H
462 ftw (".", ftw_read_file, 50);
463 #endif
464 ret = chdir (pwd);
465 free (pwd);
468 return gcov_info_head;;
471 /* This part of the code is to merge profile counters. These
472 variables are set in merge_wrapper and to be used by
473 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
475 /* We save the counter value address to this variable. */
476 static gcov_type *gcov_value_buf;
478 /* The number of counter values to be read by current merging. */
479 static gcov_unsigned_t gcov_value_buf_size;
481 /* The index of counter values being read. */
482 static gcov_unsigned_t gcov_value_buf_pos;
484 /* The weight of current merging. */
485 static unsigned gcov_merge_weight;
487 /* Read a counter value from gcov_value_buf array. */
489 gcov_type
490 gcov_read_counter_mem (void)
492 gcov_type ret;
493 gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
494 ret = *(gcov_value_buf + gcov_value_buf_pos);
495 ++gcov_value_buf_pos;
496 return ret;
499 /* Return the recorded merge weight. */
501 unsigned
502 gcov_get_merge_weight (void)
504 return gcov_merge_weight;
507 /* A wrapper function for merge functions. It sets up the
508 value buffer and weights and then calls the merge function. */
510 static void
511 merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n,
512 gcov_type *v2, unsigned w)
514 gcov_value_buf = v2;
515 gcov_value_buf_pos = 0;
516 gcov_value_buf_size = n;
517 gcov_merge_weight = w;
518 (*f) (v1, n);
521 /* Offline tool to manipulate profile data.
522 This tool targets on matched profiles. But it has some tolerance on
523 unmatched profiles.
524 When merging p1 to p2 (p2 is the dst),
525 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
526 emit warning
527 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
528 specified weight; emit warning.
529 * m.gcda in both p1 and p2:
530 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
531 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
532 p2->m.gcda->f and
533 drop p1->m.gcda->f. A warning is emitted. */
535 /* Add INFO2's counter to INFO1, multiplying by weight W. */
537 static int
538 gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
540 unsigned f_ix;
541 unsigned n_functions = info1->n_functions;
542 int has_mismatch = 0;
544 gcc_assert (info2->n_functions == n_functions);
545 for (f_ix = 0; f_ix < n_functions; f_ix++)
547 unsigned t_ix;
548 const struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
549 const struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
550 const struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
552 if (!gfi_ptr1 || gfi_ptr1->key != info1)
553 continue;
554 if (!gfi_ptr2 || gfi_ptr2->key != info2)
555 continue;
557 if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
559 fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
560 info1->filename);
561 has_mismatch = 1;
562 continue;
564 ci_ptr1 = gfi_ptr1->ctrs;
565 ci_ptr2 = gfi_ptr2->ctrs;
566 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
568 gcov_merge_fn merge1 = info1->merge[t_ix];
569 gcov_merge_fn merge2 = info2->merge[t_ix];
571 gcc_assert (merge1 == merge2);
572 if (!merge1)
573 continue;
574 gcc_assert (ci_ptr1->num == ci_ptr2->num);
575 merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num, ci_ptr2->values, w);
576 ci_ptr1++;
577 ci_ptr2++;
581 return has_mismatch;
584 /* Find and return the match gcov_info object for INFO from ARRAY.
585 SIZE is the length of ARRAY.
586 Return NULL if there is no match. */
588 static struct gcov_info *
589 find_match_gcov_info (struct gcov_info **array, int size,
590 struct gcov_info *info)
592 struct gcov_info *gi_ptr;
593 struct gcov_info *ret = NULL;
594 int i;
596 for (i = 0; i < size; i++)
598 gi_ptr = array[i];
599 if (gi_ptr == 0)
600 continue;
601 if (!strcmp (gi_ptr->filename, info->filename))
603 ret = gi_ptr;
604 array[i] = 0;
605 break;
609 if (ret && ret->n_functions != info->n_functions)
611 fnotice (stderr, "mismatched profiles in %s (%d functions"
612 " vs %d functions)\n",
613 ret->filename,
614 ret->n_functions,
615 info->n_functions);
616 ret = NULL;
618 return ret;
621 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
622 Return 0 on success: without mismatch.
623 Reutrn 1 on error. */
626 gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
627 int w1, int w2)
629 struct gcov_info *gi_ptr;
630 struct gcov_info **tgt_infos;
631 struct gcov_info *tgt_tail;
632 struct gcov_info **in_src_not_tgt;
633 unsigned tgt_cnt = 0, src_cnt = 0;
634 unsigned unmatch_info_cnt = 0;
635 unsigned int i;
637 for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
638 tgt_cnt++;
639 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
640 src_cnt++;
641 tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
642 * tgt_cnt);
643 gcc_assert (tgt_infos);
644 in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
645 * src_cnt);
646 gcc_assert (in_src_not_tgt);
648 for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
649 tgt_infos[i] = gi_ptr;
651 tgt_tail = tgt_infos[tgt_cnt - 1];
653 /* First pass on tgt_profile, we multiply w1 to all counters. */
654 if (w1 > 1)
656 for (i = 0; i < tgt_cnt; i++)
657 gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
660 /* Second pass, add src_profile to the tgt_profile. */
661 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
663 struct gcov_info *gi_ptr1;
665 gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
666 if (gi_ptr1 == NULL)
668 in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
669 continue;
671 gcov_merge (gi_ptr1, gi_ptr, w2);
674 /* For modules in src but not in tgt. We adjust the counter and append. */
675 for (i = 0; i < unmatch_info_cnt; i++)
677 gi_ptr = in_src_not_tgt[i];
678 gcov_merge (gi_ptr, gi_ptr, w2 - 1);
679 gi_ptr->next = NULL;
680 tgt_tail->next = gi_ptr;
681 tgt_tail = gi_ptr;
684 return 0;
687 typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
689 /* Performing FN upon arc counters. */
691 static void
692 __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
693 counter_op_fn fn, void *data1, void *data2)
695 for (; n_counters; counters++, n_counters--)
697 gcov_type val = *counters;
698 *counters = fn(val, data1, data2);
702 /* Performing FN upon ior counters. */
704 static void
705 __gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
706 unsigned n_counters ATTRIBUTE_UNUSED,
707 counter_op_fn fn ATTRIBUTE_UNUSED,
708 void *data1 ATTRIBUTE_UNUSED,
709 void *data2 ATTRIBUTE_UNUSED)
711 /* Do nothing. */
714 /* Performing FN upon time-profile counters. */
716 static void
717 __gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
718 unsigned n_counters ATTRIBUTE_UNUSED,
719 counter_op_fn fn ATTRIBUTE_UNUSED,
720 void *data1 ATTRIBUTE_UNUSED,
721 void *data2 ATTRIBUTE_UNUSED)
723 /* Do nothing. */
726 /* Performing FN upon single counters. */
728 static void
729 __gcov_single_counter_op (gcov_type *counters, unsigned n_counters,
730 counter_op_fn fn, void *data1, void *data2)
732 unsigned i, n_measures;
734 gcc_assert (!(n_counters % 3));
735 n_measures = n_counters / 3;
736 for (i = 0; i < n_measures; i++, counters += 3)
738 counters[1] = fn (counters[1], data1, data2);
739 counters[2] = fn (counters[2], data1, data2);
743 /* Scaling the counter value V by multiplying *(float*) DATA1. */
745 static gcov_type
746 fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
748 float f = *(float *) data1;
749 return (gcov_type) (v * f);
752 /* Scaling the counter value V by multiplying DATA2/DATA1. */
754 static gcov_type
755 int_scale (gcov_type v, void *data1, void *data2)
757 int n = *(int *) data1;
758 int d = *(int *) data2;
759 return (gcov_type) ( RDIV (v,d) * n);
762 /* Type of function used to process counters. */
763 typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
764 counter_op_fn, void *, void *);
766 /* Function array to process profile counters. */
767 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
768 __gcov ## FN_TYPE ## _counter_op,
769 static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
770 #include "gcov-counter.def"
772 #undef DEF_GCOV_COUNTER
774 /* Driver for scaling profile counters. */
777 gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
779 struct gcov_info *gi_ptr;
780 unsigned f_ix;
782 if (verbose)
783 fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
785 /* Scaling the counters. */
786 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
787 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
789 unsigned t_ix;
790 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
791 const struct gcov_ctr_info *ci_ptr;
793 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
794 continue;
796 ci_ptr = gfi_ptr->ctrs;
797 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
799 gcov_merge_fn merge = gi_ptr->merge[t_ix];
801 if (!merge)
802 continue;
803 if (d == 0)
804 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
805 fp_scale, &scale_factor, NULL);
806 else
807 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
808 int_scale, &n, &d);
809 ci_ptr++;
813 return 0;
816 /* Driver to normalize profile counters. */
819 gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
821 struct gcov_info *gi_ptr;
822 gcov_type curr_max_val = 0;
823 unsigned f_ix;
824 unsigned int i;
825 float scale_factor;
827 /* Find the largest count value. */
828 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
829 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
831 unsigned t_ix;
832 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
833 const struct gcov_ctr_info *ci_ptr;
835 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
836 continue;
838 ci_ptr = gfi_ptr->ctrs;
839 for (t_ix = 0; t_ix < 1; t_ix++)
841 for (i = 0; i < ci_ptr->num; i++)
842 if (ci_ptr->values[i] > curr_max_val)
843 curr_max_val = ci_ptr->values[i];
844 ci_ptr++;
848 scale_factor = (float)max_val / curr_max_val;
849 if (verbose)
850 fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
852 return gcov_profile_scale (profile, scale_factor, 0, 0);
855 /* The following variables are defined in gcc/gcov-tool.c. */
856 extern int overlap_func_level;
857 extern int overlap_obj_level;
858 extern int overlap_hot_only;
859 extern int overlap_use_fullname;
860 extern double overlap_hot_threshold;
862 /* Compute the overlap score of two values. The score is defined as:
863 min (V1/SUM_1, V2/SUM_2) */
865 static double
866 calculate_2_entries (const unsigned long v1, const unsigned long v2,
867 const double sum_1, const double sum_2)
869 double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
870 double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
872 if (val2 < val1)
873 val1 = val2;
875 return val1;
878 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
879 This function also updates cumulative score CUM_1_RESULT and
880 CUM_2_RESULT. */
882 static double
883 compute_one_gcov (const struct gcov_info *gcov_info1,
884 const struct gcov_info *gcov_info2,
885 const double sum_1, const double sum_2,
886 double *cum_1_result, double *cum_2_result)
888 unsigned f_ix;
889 double ret = 0;
890 double cum_1 = 0, cum_2 = 0;
891 const struct gcov_info *gcov_info = 0;
892 double *cum_p;
893 double sum;
895 gcc_assert (gcov_info1 || gcov_info2);
896 if (!gcov_info1)
898 gcov_info = gcov_info2;
899 cum_p = cum_2_result;
900 sum = sum_2;
901 *cum_1_result = 0;
902 } else
903 if (!gcov_info2)
905 gcov_info = gcov_info1;
906 cum_p = cum_1_result;
907 sum = sum_1;
908 *cum_2_result = 0;
911 if (gcov_info)
913 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
915 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
916 if (!gfi_ptr || gfi_ptr->key != gcov_info)
917 continue;
918 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
919 unsigned c_num;
920 for (c_num = 0; c_num < ci_ptr->num; c_num++)
921 cum_1 += ci_ptr->values[c_num] / sum;
923 *cum_p = cum_1;
924 return 0.0;
927 for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
929 double func_cum_1 = 0.0;
930 double func_cum_2 = 0.0;
931 double func_val = 0.0;
932 int nonzero = 0;
933 int hot = 0;
934 const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
935 const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
937 if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
938 continue;
939 if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
940 continue;
942 const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
943 const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
944 unsigned c_num;
945 for (c_num = 0; c_num < ci_ptr1->num; c_num++)
947 if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
949 func_val += calculate_2_entries (ci_ptr1->values[c_num],
950 ci_ptr2->values[c_num],
951 sum_1, sum_2);
953 func_cum_1 += ci_ptr1->values[c_num] / sum_1;
954 func_cum_2 += ci_ptr2->values[c_num] / sum_2;
955 nonzero = 1;
956 if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
957 || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
958 hot = 1;
962 ret += func_val;
963 cum_1 += func_cum_1;
964 cum_2 += func_cum_2;
965 if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
967 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
968 gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
971 *cum_1_result = cum_1;
972 *cum_2_result = cum_2;
973 return ret;
976 /* Test if all counter values in this GCOV_INFO are cold.
977 "Cold" is defined as the counter value being less than
978 or equal to THRESHOLD. */
980 static bool
981 gcov_info_count_all_cold (const struct gcov_info *gcov_info,
982 gcov_type threshold)
984 unsigned f_ix;
986 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
988 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
990 if (!gfi_ptr || gfi_ptr->key != gcov_info)
991 continue;
992 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
993 for (unsigned c_num = 0; c_num < ci_ptr->num; c_num++)
994 if (ci_ptr->values[c_num] > threshold)
995 return false;
998 return true;
1001 /* Test if all counter values in this GCOV_INFO are 0. */
1003 static bool
1004 gcov_info_count_all_zero (const struct gcov_info *gcov_info)
1006 return gcov_info_count_all_cold (gcov_info, 0);
1009 /* A pair of matched GCOV_INFO.
1010 The flag is a bitvector:
1011 b0: obj1's all counts are 0;
1012 b1: obj1's all counts are cold (but no 0);
1013 b2: obj1 is hot;
1014 b3: no obj1 to match obj2;
1015 b4: obj2's all counts are 0;
1016 b5: obj2's all counts are cold (but no 0);
1017 b6: obj2 is hot;
1018 b7: no obj2 to match obj1;
1020 struct overlap_t {
1021 const struct gcov_info *obj1;
1022 const struct gcov_info *obj2;
1023 char flag;
1026 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1027 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1028 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1030 /* Cumlative overlap dscore for profile1 and profile2. */
1031 static double overlap_sum_1, overlap_sum_2;
1033 /* The number of gcda files in the profiles. */
1034 static unsigned gcda_files[2];
1036 /* The number of unique gcda files in the profiles
1037 (not existing in the other profile). */
1038 static unsigned unique_gcda_files[2];
1040 /* The number of gcda files that all counter values are 0. */
1041 static unsigned zero_gcda_files[2];
1043 /* The number of gcda files that all counter values are cold (but not 0). */
1044 static unsigned cold_gcda_files[2];
1046 /* The number of gcda files that includes hot counter values. */
1047 static unsigned hot_gcda_files[2];
1049 /* The number of gcda files with hot count value in either profiles. */
1050 static unsigned both_hot_cnt;
1052 /* The number of gcda files with all counts cold (but not 0) in
1053 both profiles. */
1054 static unsigned both_cold_cnt;
1056 /* The number of gcda files with all counts 0 in both profiles. */
1057 static unsigned both_zero_cnt;
1059 /* Extract the basename of the filename NAME. */
1061 static char *
1062 extract_file_basename (const char *name)
1064 char *str;
1065 int len = 0;
1066 char *path = xstrdup (name);
1067 char sep_str[2];
1069 sep_str[0] = DIR_SEPARATOR;
1070 sep_str[1] = 0;
1071 str = strstr(path, sep_str);
1073 len = strlen(str) + 1;
1074 path = &path[strlen(path) - len + 2];
1075 str = strstr(path, sep_str);
1076 } while(str);
1078 return path;
1081 /* Utility function to get the filename. */
1083 static const char *
1084 get_file_basename (const char *name)
1086 if (overlap_use_fullname)
1087 return name;
1088 return extract_file_basename (name);
1091 /* A utility function to set the flag for the gcda files. */
1093 static void
1094 set_flag (struct overlap_t *e)
1096 char flag = 0;
1098 if (!e->obj1)
1100 unique_gcda_files[1]++;
1101 flag = 0x8;
1103 else
1105 gcda_files[0]++;
1106 if (gcov_info_count_all_zero (e->obj1))
1108 zero_gcda_files[0]++;
1109 flag = 0x1;
1111 else
1112 if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
1113 * overlap_hot_threshold))
1115 cold_gcda_files[0]++;
1116 flag = 0x2;
1118 else
1120 hot_gcda_files[0]++;
1121 flag = 0x4;
1125 if (!e->obj2)
1127 unique_gcda_files[0]++;
1128 flag |= (0x8 << 4);
1130 else
1132 gcda_files[1]++;
1133 if (gcov_info_count_all_zero (e->obj2))
1135 zero_gcda_files[1]++;
1136 flag |= (0x1 << 4);
1138 else
1139 if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
1140 * overlap_hot_threshold))
1142 cold_gcda_files[1]++;
1143 flag |= (0x2 << 4);
1145 else
1147 hot_gcda_files[1]++;
1148 flag |= (0x4 << 4);
1152 gcc_assert (flag);
1153 e->flag = flag;
1156 /* Test if INFO1 and INFO2 are from the matched source file.
1157 Return 1 if they match; return 0 otherwise. */
1159 static int
1160 matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
1162 /* For FDO, we have to match the name. This can be expensive.
1163 Maybe we should use hash here. */
1164 if (strcmp (info1->filename, info2->filename))
1165 return 0;
1167 if (info1->n_functions != info2->n_functions)
1169 fnotice (stderr, "mismatched profiles in %s (%d functions"
1170 " vs %d functions)\n",
1171 info1->filename,
1172 info1->n_functions,
1173 info2->n_functions);
1174 return 0;
1176 return 1;
1179 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1180 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1181 match and 1.0 meaning a perfect match. */
1183 static double
1184 calculate_overlap (struct gcov_info *gcov_list1,
1185 struct gcov_info *gcov_list2)
1187 unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
1188 unsigned int i, j;
1189 const struct gcov_info *gi_ptr;
1190 struct overlap_t *all_infos;
1192 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
1193 list1_cnt++;
1194 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
1195 list2_cnt++;
1196 all_cnt = list1_cnt + list2_cnt;
1197 all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
1198 * all_cnt * 2);
1199 gcc_assert (all_infos);
1201 i = 0;
1202 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
1204 all_infos[i].obj1 = gi_ptr;
1205 all_infos[i].obj2 = 0;
1208 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
1210 all_infos[i].obj1 = 0;
1211 all_infos[i].obj2 = gi_ptr;
1214 for (i = list1_cnt; i < all_cnt; i++)
1216 if (all_infos[i].obj2 == 0)
1217 continue;
1218 for (j = 0; j < list1_cnt; j++)
1220 if (all_infos[j].obj2 != 0)
1221 continue;
1222 if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
1224 all_infos[j].obj2 = all_infos[i].obj2;
1225 all_infos[i].obj2 = 0;
1226 break;
1231 for (i = 0; i < all_cnt; i++)
1232 if (all_infos[i].obj1 || all_infos[i].obj2)
1234 set_flag (all_infos + i);
1235 if (FLAG_ONE_HOT (all_infos[i].flag))
1236 both_hot_cnt++;
1237 if (FLAG_BOTH_COLD(all_infos[i].flag))
1238 both_cold_cnt++;
1239 if (FLAG_BOTH_ZERO(all_infos[i].flag))
1240 both_zero_cnt++;
1243 double prg_val = 0;
1244 double sum_val = 0;
1245 double sum_cum_1 = 0;
1246 double sum_cum_2 = 0;
1248 for (i = 0; i < all_cnt; i++)
1250 double val;
1251 double cum_1, cum_2;
1252 const char *filename;
1254 if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
1255 continue;
1256 if (FLAG_BOTH_ZERO (all_infos[i].flag))
1257 continue;
1259 if (all_infos[i].obj1)
1260 filename = get_file_basename (all_infos[i].obj1->filename);
1261 else
1262 filename = get_file_basename (all_infos[i].obj2->filename);
1264 if (overlap_func_level)
1265 printf("\n processing %36s:\n", filename);
1267 val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
1268 overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
1270 if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
1272 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1273 filename, val*100, cum_1*100, cum_2*100);
1274 sum_val += val;
1275 sum_cum_1 += cum_1;
1276 sum_cum_2 += cum_2;
1279 prg_val += val;
1283 if (overlap_obj_level)
1284 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1285 "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
1287 printf (" Statistics:\n"
1288 " profile1_# profile2_# overlap_#\n");
1289 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
1290 gcda_files[0]-unique_gcda_files[0]);
1291 printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
1292 unique_gcda_files[1]);
1293 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
1294 hot_gcda_files[1], both_hot_cnt);
1295 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
1296 cold_gcda_files[1], both_cold_cnt);
1297 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
1298 zero_gcda_files[1], both_zero_cnt);
1300 return prg_val;
1303 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1304 PROFILE2.
1305 Return 0 on success: without mismatch. Reutrn 1 on error. */
1308 gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
1310 double result;
1312 result = calculate_overlap (profile1, profile2);
1314 if (result > 0)
1316 printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
1317 return 0;
1319 return 1;