1 /* Utility functions for reading gcda files into in-memory
2    gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2020 Free Software Foundation, Inc.
4    Contributed by Rong Xu <xur@google.com>.
5 
6 This file is part of GCC.
7 
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.
12 
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.
17 
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.
21 
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/>.  */
26 
27 
28 #define IN_GCOV_TOOL 1
29 
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"
36 
37 /* Borrowed from basic-block.h.  */
38 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
39 
40 extern gcov_position_t gcov_position();
41 extern int gcov_is_error();
42 
43 /* Verbose mode for debug.  */
44 static int verbose;
45 
46 /* Set verbose flag.  */
gcov_set_verbose(void)47 void gcov_set_verbose (void)
48 {
49   verbose = 1;
50 }
51 
52 /* The following part is to read Gcda and reconstruct GCOV_INFO.  */
53 
54 #include "obstack.h"
55 #include <unistd.h>
56 #ifdef HAVE_FTW_H
57 #include <ftw.h>
58 #endif
59 
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);
66 
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;
85 
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"
90 };
91 #undef DEF_GCOV_COUNTER
92 
93 /* Set the ctrs field in gcov_fn_info object FN_INFO.  */
94 
95 static void
set_fn_ctrs(struct gcov_fn_info * fn_info)96 set_fn_ctrs (struct gcov_fn_info *fn_info)
97 {
98   int j = 0, i;
99 
100   for (i = 0; i < GCOV_COUNTERS; i++)
101     {
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++;
107     }
108   if (k_ctrs_types == 0)
109     k_ctrs_types = j;
110   else
111     gcc_assert (j == k_ctrs_types);
112 }
113 
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.  */
117 
118 typedef struct tag_format
119 {
120     unsigned tag;
121     char const *name;
122     void (*proc) (unsigned, unsigned);
123 } tag_format_t;
124 
125 /* Handler table for various Tags.  */
126 
127 static const tag_format_t tag_table[] =
128 {
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}
138 };
139 
140 /* Handler for reading function tag.  */
141 
142 static void
tag_function(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)143 tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
144 {
145   int i;
146 
147   /* write out previous fn_info.  */
148   if (num_fn_info)
149     {
150       set_fn_ctrs (curr_fn_info);
151       obstack_ptr_grow (&fn_info, curr_fn_info);
152     }
153 
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);
158 
159   for (i = 0; i < GCOV_COUNTERS; i++)
160      k_ctrs[i].num = 0;
161   k_ctrs_types = 0;
162 
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++;
168 
169   if (verbose)
170     fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
171 }
172 
173 /* Handler for reading block tag.  */
174 
175 static void
tag_blocks(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)176 tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
177 {
178   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
179   gcc_unreachable ();
180 }
181 
182 /* Handler for reading flow arc tag.  */
183 
184 static void
tag_arcs(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)185 tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
186 {
187   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
188   gcc_unreachable ();
189 }
190 
191 /* Handler for reading line tag.  */
192 
193 static void
tag_lines(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)194 tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
195 {
196   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
197   gcc_unreachable ();
198 }
199 
200 /* Handler for reading counters array tag with value as TAG and length of LENGTH.  */
201 
202 static void
tag_counters(unsigned tag,unsigned length)203 tag_counters (unsigned tag, unsigned length)
204 {
205   unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
206   gcov_type *values;
207   unsigned ix;
208   unsigned tag_ix;
209 
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;
215 
216   k_ctrs[tag_ix].values = values = (gcov_type *) xmalloc (n_counts * sizeof (gcov_type));
217   gcc_assert (values);
218 
219   for (ix = 0; ix != n_counts; ix++)
220     values[ix] = gcov_read_counter ();
221 }
222 
223 /* Handler for reading summary tag.  */
224 
225 static void
tag_summary(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)226 tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
227 {
228   curr_object_summary = (gcov_summary *) xcalloc (sizeof (gcov_summary), 1);
229   gcov_read_summary (curr_object_summary);
230 }
231 
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.  */
234 
235 static void
read_gcda_finalize(struct gcov_info * obj_info)236 read_gcda_finalize (struct gcov_info *obj_info)
237 {
238   int i;
239 
240   set_fn_ctrs (curr_fn_info);
241   obstack_ptr_grow (&fn_info, curr_fn_info);
242 
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);
247 
248   /* wrap all the counter array.  */
249   for (i=0; i< GCOV_COUNTERS; i++)
250     {
251       if (k_ctrs_mask[i])
252         obj_info->merge[i] = ctr_merge_functions[i];
253     }
254 }
255 
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.  */
258 
259 static struct gcov_info *
read_gcda_file(const char * filename)260 read_gcda_file (const char *filename)
261 {
262   unsigned tags[4];
263   unsigned depth = 0;
264   unsigned version;
265   struct gcov_info *obj_info;
266   int i;
267 
268   for (i=0; i< GCOV_COUNTERS; i++)
269     k_ctrs_mask[i] = 0;
270   k_ctrs_types = 0;
271 
272   if (!gcov_open (filename))
273     {
274       fnotice (stderr, "%s:cannot open\n", filename);
275       return NULL;
276     }
277 
278   /* Read magic.  */
279   if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
280     {
281       fnotice (stderr, "%s:not a gcov data file\n", filename);
282       gcov_close ();
283       return NULL;
284     }
285 
286   /* Read version.  */
287   version = gcov_read_unsigned ();
288   if (version != GCOV_VERSION)
289     {
290       fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
291       gcov_close ();
292       return NULL;
293     }
294 
295   /* Instantiate a gcov_info object.  */
296   curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
297              sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
298 
299   obj_info->version = version;
300   obstack_init (&fn_info);
301   num_fn_info = 0;
302   curr_fn_info = 0;
303   curr_object_summary = NULL;
304   {
305     size_t len = strlen (filename) + 1;
306     char *str_dup = (char*) xmalloc (len);
307 
308     memcpy (str_dup, filename, len);
309     obj_info->filename = str_dup;
310   }
311 
312   /* Read stamp.  */
313   obj_info->stamp = gcov_read_unsigned ();
314 
315   while (1)
316     {
317       gcov_position_t base;
318       unsigned tag, length;
319       tag_format_t const *format;
320       unsigned tag_depth;
321       int error;
322       unsigned mask;
323 
324       tag = gcov_read_unsigned ();
325       if (!tag)
326         break;
327       length = gcov_read_unsigned ();
328       base = gcov_position ();
329       mask = GCOV_TAG_MASK (tag) >> 1;
330       for (tag_depth = 4; mask; mask >>= 8)
331         {
332           if (((mask & 0xff) != 0xff))
333             {
334 	      warning (0, "%s:tag %qx is invalid", filename, tag);
335               break;
336             }
337           tag_depth--;
338         }
339       for (format = tag_table; format->name; format++)
340         if (format->tag == tag)
341           goto found;
342       format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
343     found:;
344       if (tag)
345         {
346           if (depth && depth < tag_depth)
347             {
348               if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
349 	        warning (0, "%s:tag %qx is incorrectly nested",
350                          filename, tag);
351             }
352           depth = tag_depth;
353           tags[depth - 1] = tag;
354         }
355 
356       if (format->proc)
357         {
358           unsigned long actual_length;
359 
360           (*format->proc) (tag, length);
361 
362           actual_length = gcov_position () - base;
363           if (actual_length > length)
364 	    warning (0, "%s:record size mismatch %lu bytes overread",
365                      filename, actual_length - length);
366           else if (length > actual_length)
367 	    warning (0, "%s:record size mismatch %lu bytes unread",
368                      filename, length - actual_length);
369        }
370 
371       gcov_sync (base, length);
372       if ((error = gcov_is_error ()))
373         {
374 	  warning (0, error < 0 ? "%s:counter overflow at %lu" :
375 	                          "%s:read error at %lu", filename,
376                    (long unsigned) gcov_position ());
377           break;
378         }
379     }
380 
381   read_gcda_finalize (obj_info);
382   gcov_close ();
383 
384   return obj_info;
385 }
386 
387 #ifdef HAVE_FTW_H
388 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
389    Return a non-zero value to stop the tree walk.  */
390 
391 static int
ftw_read_file(const char * filename,const struct stat * status ATTRIBUTE_UNUSED,int type)392 ftw_read_file (const char *filename,
393                const struct stat *status ATTRIBUTE_UNUSED,
394                int type)
395 {
396   int filename_len;
397   int suffix_len;
398   struct gcov_info *obj_info;
399 
400   /* Only read regular files.  */
401   if (type != FTW_F)
402     return 0;
403 
404   filename_len = strlen (filename);
405   suffix_len = strlen (GCOV_DATA_SUFFIX);
406 
407   if (filename_len <= suffix_len)
408     return 0;
409 
410   if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
411     return 0;
412 
413   if (verbose)
414     fnotice (stderr, "reading file: %s\n", filename);
415 
416   obj_info = read_gcda_file (filename);
417   if (!obj_info)
418     return 0;
419 
420   obj_info->next = gcov_info_head;
421   gcov_info_head = obj_info;
422 
423   return 0;
424 }
425 #endif
426 
427 /* Initializer for reading a profile dir.  */
428 
429 static inline void
read_profile_dir_init(void)430 read_profile_dir_init (void)
431 {
432   gcov_info_head = 0;
433 }
434 
435 /* Driver for read a profile directory and convert into gcov_info list in memory.
436    Return NULL on error,
437    Return the head of gcov_info list on success.  */
438 
439 struct gcov_info *
gcov_read_profile_dir(const char * dir_name,int recompute_summary ATTRIBUTE_UNUSED)440 gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
441 {
442   char *pwd;
443   int ret;
444 
445   read_profile_dir_init ();
446 
447   if (access (dir_name, R_OK) != 0)
448     {
449       fnotice (stderr, "cannot access directory %s\n", dir_name);
450       return NULL;
451     }
452   pwd = getcwd (NULL, 0);
453   gcc_assert (pwd);
454   ret = chdir (dir_name);
455   if (ret !=0)
456     {
457       fnotice (stderr, "%s is not a directory\n", dir_name);
458       return NULL;
459     }
460 #ifdef HAVE_FTW_H
461   ftw (".", ftw_read_file, 50);
462 #endif
463   chdir (pwd);
464   free (pwd);
465 
466   return gcov_info_head;;
467 }
468 
469 /* This part of the code is to merge profile counters. These
470    variables are set in merge_wrapper and to be used by
471    global function gcov_read_counter_mem() and gcov_get_merge_weight.  */
472 
473 /* We save the counter value address to this variable.  */
474 static gcov_type *gcov_value_buf;
475 
476 /* The number of counter values to be read by current merging.  */
477 static gcov_unsigned_t gcov_value_buf_size;
478 
479 /* The index of counter values being read.  */
480 static gcov_unsigned_t gcov_value_buf_pos;
481 
482 /* The weight of current merging.  */
483 static unsigned gcov_merge_weight;
484 
485 /* Read a counter value from gcov_value_buf array.  */
486 
487 gcov_type
gcov_read_counter_mem(void)488 gcov_read_counter_mem (void)
489 {
490   gcov_type ret;
491   gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
492   ret = *(gcov_value_buf + gcov_value_buf_pos);
493   ++gcov_value_buf_pos;
494   return ret;
495 }
496 
497 /* Return the recorded merge weight.  */
498 
499 unsigned
gcov_get_merge_weight(void)500 gcov_get_merge_weight (void)
501 {
502   return gcov_merge_weight;
503 }
504 
505 /* A wrapper function for merge functions. It sets up the
506    value buffer and weights and then calls the merge function.  */
507 
508 static void
merge_wrapper(gcov_merge_fn f,gcov_type * v1,gcov_unsigned_t n,gcov_type * v2,unsigned w)509 merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n,
510                gcov_type *v2, unsigned w)
511 {
512   gcov_value_buf = v2;
513   gcov_value_buf_pos = 0;
514   gcov_value_buf_size = n;
515   gcov_merge_weight = w;
516   (*f) (v1, n);
517 }
518 
519 /* Offline tool to manipulate profile data.
520    This tool targets on matched profiles. But it has some tolerance on
521    unmatched profiles.
522    When merging p1 to p2 (p2 is the dst),
523    * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
524      emit warning
525    * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
526      specified weight; emit warning.
527    * m.gcda in both p1 and p2:
528    ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
529    ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
530       p2->m.gcda->f and
531       drop p1->m.gcda->f. A warning is emitted.  */
532 
533 /* Add INFO2's counter to INFO1, multiplying by weight W.  */
534 
535 static int
gcov_merge(struct gcov_info * info1,struct gcov_info * info2,int w)536 gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
537 {
538   unsigned f_ix;
539   unsigned n_functions = info1->n_functions;
540   int has_mismatch = 0;
541 
542   gcc_assert (info2->n_functions == n_functions);
543   for (f_ix = 0; f_ix < n_functions; f_ix++)
544     {
545       unsigned t_ix;
546       const struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
547       const struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
548       const struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
549 
550       if (!gfi_ptr1 || gfi_ptr1->key != info1)
551         continue;
552       if (!gfi_ptr2 || gfi_ptr2->key != info2)
553         continue;
554 
555       if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
556         {
557           fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
558                   info1->filename);
559           has_mismatch = 1;
560           continue;
561         }
562       ci_ptr1 = gfi_ptr1->ctrs;
563       ci_ptr2 = gfi_ptr2->ctrs;
564       for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
565         {
566           gcov_merge_fn merge1 = info1->merge[t_ix];
567           gcov_merge_fn merge2 = info2->merge[t_ix];
568 
569           gcc_assert (merge1 == merge2);
570           if (!merge1)
571             continue;
572           gcc_assert (ci_ptr1->num == ci_ptr2->num);
573           merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num, ci_ptr2->values, w);
574           ci_ptr1++;
575           ci_ptr2++;
576         }
577     }
578 
579   return has_mismatch;
580 }
581 
582 /* Find and return the match gcov_info object for INFO from ARRAY.
583    SIZE is the length of ARRAY.
584    Return NULL if there is no match.  */
585 
586 static struct gcov_info *
find_match_gcov_info(struct gcov_info ** array,int size,struct gcov_info * info)587 find_match_gcov_info (struct gcov_info **array, int size,
588 		      struct gcov_info *info)
589 {
590   struct gcov_info *gi_ptr;
591   struct gcov_info *ret = NULL;
592   int i;
593 
594   for (i = 0; i < size; i++)
595     {
596       gi_ptr = array[i];
597       if (gi_ptr == 0)
598         continue;
599       if (!strcmp (gi_ptr->filename, info->filename))
600         {
601           ret = gi_ptr;
602           array[i] = 0;
603           break;
604         }
605     }
606 
607   if (ret && ret->n_functions != info->n_functions)
608     {
609       fnotice (stderr, "mismatched profiles in %s (%d functions"
610                        " vs %d functions)\n",
611                        ret->filename,
612                        ret->n_functions,
613                        info->n_functions);
614       ret = NULL;
615     }
616   return ret;
617 }
618 
619 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
620    Return 0 on success: without mismatch.
621    Reutrn 1 on error.  */
622 
623 int
gcov_profile_merge(struct gcov_info * tgt_profile,struct gcov_info * src_profile,int w1,int w2)624 gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
625                     int w1, int w2)
626 {
627   struct gcov_info *gi_ptr;
628   struct gcov_info **tgt_infos;
629   struct gcov_info *tgt_tail;
630   struct gcov_info **in_src_not_tgt;
631   unsigned tgt_cnt = 0, src_cnt = 0;
632   unsigned unmatch_info_cnt = 0;
633   unsigned int i;
634 
635   for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
636     tgt_cnt++;
637   for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
638     src_cnt++;
639   tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
640                  * tgt_cnt);
641   gcc_assert (tgt_infos);
642   in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
643                      * src_cnt);
644   gcc_assert (in_src_not_tgt);
645 
646   for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
647     tgt_infos[i] = gi_ptr;
648 
649   tgt_tail = tgt_infos[tgt_cnt - 1];
650 
651   /* First pass on tgt_profile, we multiply w1 to all counters.  */
652   if (w1 > 1)
653     {
654        for (i = 0; i < tgt_cnt; i++)
655          gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
656     }
657 
658   /* Second pass, add src_profile to the tgt_profile.  */
659   for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
660     {
661       struct gcov_info *gi_ptr1;
662 
663       gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
664       if (gi_ptr1 == NULL)
665         {
666           in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
667           continue;
668         }
669       gcov_merge (gi_ptr1, gi_ptr, w2);
670     }
671 
672   /* For modules in src but not in tgt. We adjust the counter and append.  */
673   for (i = 0; i < unmatch_info_cnt; i++)
674     {
675       gi_ptr = in_src_not_tgt[i];
676       gcov_merge (gi_ptr, gi_ptr, w2 - 1);
677       gi_ptr->next = NULL;
678       tgt_tail->next = gi_ptr;
679       tgt_tail = gi_ptr;
680     }
681 
682   free (in_src_not_tgt);
683   free (tgt_infos);
684 
685   return 0;
686 }
687 
688 typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
689 
690 /* Performing FN upon arc counters.  */
691 
692 static void
__gcov_add_counter_op(gcov_type * counters,unsigned n_counters,counter_op_fn fn,void * data1,void * data2)693 __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
694                        counter_op_fn fn, void *data1, void *data2)
695 {
696   for (; n_counters; counters++, n_counters--)
697     {
698       gcov_type val = *counters;
699       *counters = fn(val, data1, data2);
700     }
701 }
702 
703 /* Performing FN upon ior counters.  */
704 
705 static void
__gcov_ior_counter_op(gcov_type * counters ATTRIBUTE_UNUSED,unsigned n_counters ATTRIBUTE_UNUSED,counter_op_fn fn ATTRIBUTE_UNUSED,void * data1 ATTRIBUTE_UNUSED,void * data2 ATTRIBUTE_UNUSED)706 __gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
707                        unsigned n_counters ATTRIBUTE_UNUSED,
708                        counter_op_fn fn ATTRIBUTE_UNUSED,
709                        void *data1 ATTRIBUTE_UNUSED,
710                        void *data2 ATTRIBUTE_UNUSED)
711 {
712   /* Do nothing.  */
713 }
714 
715 /* Performing FN upon time-profile counters.  */
716 
717 static void
__gcov_time_profile_counter_op(gcov_type * counters ATTRIBUTE_UNUSED,unsigned n_counters ATTRIBUTE_UNUSED,counter_op_fn fn ATTRIBUTE_UNUSED,void * data1 ATTRIBUTE_UNUSED,void * data2 ATTRIBUTE_UNUSED)718 __gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
719                                 unsigned n_counters ATTRIBUTE_UNUSED,
720                                 counter_op_fn fn ATTRIBUTE_UNUSED,
721                                 void *data1 ATTRIBUTE_UNUSED,
722                                 void *data2 ATTRIBUTE_UNUSED)
723 {
724   /* Do nothing.  */
725 }
726 
727 /* Performing FN upon TOP N counters.  */
728 
729 static void
__gcov_topn_counter_op(gcov_type * counters,unsigned n_counters,counter_op_fn fn,void * data1,void * data2)730 __gcov_topn_counter_op (gcov_type *counters, unsigned n_counters,
731 			counter_op_fn fn, void *data1, void *data2)
732 {
733   unsigned i, n_measures;
734 
735   gcc_assert (!(n_counters % 3));
736   n_measures = n_counters / 3;
737   for (i = 0; i < n_measures; i++, counters += 3)
738     {
739       counters[1] = fn (counters[1], data1, data2);
740       counters[2] = fn (counters[2], data1, data2);
741     }
742 }
743 
744 /* Scaling the counter value V by multiplying *(float*) DATA1.  */
745 
746 static gcov_type
fp_scale(gcov_type v,void * data1,void * data2 ATTRIBUTE_UNUSED)747 fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
748 {
749   float f = *(float *) data1;
750   return (gcov_type) (v * f);
751 }
752 
753 /* Scaling the counter value V by multiplying DATA2/DATA1.  */
754 
755 static gcov_type
int_scale(gcov_type v,void * data1,void * data2)756 int_scale (gcov_type v, void *data1, void *data2)
757 {
758   int n = *(int *) data1;
759   int d = *(int *) data2;
760   return (gcov_type) ( RDIV (v,d) * n);
761 }
762 
763 /* Type of function used to process counters.  */
764 typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
765                           counter_op_fn, void *, void *);
766 
767 /* Function array to process profile counters.  */
768 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
769   __gcov ## FN_TYPE ## _counter_op,
770 static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
771 #include "gcov-counter.def"
772 };
773 #undef DEF_GCOV_COUNTER
774 
775 /* Driver for scaling profile counters.  */
776 
777 int
gcov_profile_scale(struct gcov_info * profile,float scale_factor,int n,int d)778 gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
779 {
780   struct gcov_info *gi_ptr;
781   unsigned f_ix;
782 
783   if (verbose)
784     fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
785 
786   /* Scaling the counters.  */
787   for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
788     for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
789       {
790         unsigned t_ix;
791         const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
792         const struct gcov_ctr_info *ci_ptr;
793 
794         if (!gfi_ptr || gfi_ptr->key != gi_ptr)
795           continue;
796 
797         ci_ptr = gfi_ptr->ctrs;
798         for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
799           {
800             gcov_merge_fn merge = gi_ptr->merge[t_ix];
801 
802             if (!merge)
803               continue;
804             if (d == 0)
805               (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
806                                       fp_scale, &scale_factor, NULL);
807             else
808               (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
809                                       int_scale, &n, &d);
810             ci_ptr++;
811           }
812       }
813 
814   return 0;
815 }
816 
817 /* Driver to normalize profile counters.  */
818 
819 int
gcov_profile_normalize(struct gcov_info * profile,gcov_type max_val)820 gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
821 {
822   struct gcov_info *gi_ptr;
823   gcov_type curr_max_val = 0;
824   unsigned f_ix;
825   unsigned int i;
826   float scale_factor;
827 
828   /* Find the largest count value.  */
829   for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
830     for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
831       {
832         unsigned t_ix;
833         const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
834         const struct gcov_ctr_info *ci_ptr;
835 
836         if (!gfi_ptr || gfi_ptr->key != gi_ptr)
837           continue;
838 
839         ci_ptr = gfi_ptr->ctrs;
840         for (t_ix = 0; t_ix < 1; t_ix++)
841           {
842             for (i = 0; i < ci_ptr->num; i++)
843               if (ci_ptr->values[i] > curr_max_val)
844                 curr_max_val = ci_ptr->values[i];
845             ci_ptr++;
846           }
847       }
848 
849   scale_factor = (float)max_val / curr_max_val;
850   if (verbose)
851     fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
852 
853   return gcov_profile_scale (profile, scale_factor, 0, 0);
854 }
855 
856 /* The following variables are defined in gcc/gcov-tool.c.  */
857 extern int overlap_func_level;
858 extern int overlap_obj_level;
859 extern int overlap_hot_only;
860 extern int overlap_use_fullname;
861 extern double overlap_hot_threshold;
862 
863 /* Compute the overlap score of two values. The score is defined as:
864     min (V1/SUM_1, V2/SUM_2)  */
865 
866 static double
calculate_2_entries(const unsigned long v1,const unsigned long v2,const double sum_1,const double sum_2)867 calculate_2_entries (const unsigned long v1, const unsigned long v2,
868                      const double sum_1, const double sum_2)
869 {
870   double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
871   double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
872 
873   if (val2 < val1)
874     val1 = val2;
875 
876   return val1;
877 }
878 
879 /*  Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
880     This function also updates cumulative score CUM_1_RESULT and
881     CUM_2_RESULT.  */
882 
883 static double
compute_one_gcov(const struct gcov_info * gcov_info1,const struct gcov_info * gcov_info2,const double sum_1,const double sum_2,double * cum_1_result,double * cum_2_result)884 compute_one_gcov (const struct gcov_info *gcov_info1,
885                   const struct gcov_info *gcov_info2,
886                   const double sum_1, const double sum_2,
887                   double *cum_1_result, double *cum_2_result)
888 {
889   unsigned f_ix;
890   double ret = 0;
891   double cum_1 = 0, cum_2 = 0;
892   const struct gcov_info *gcov_info = 0;
893   double *cum_p;
894   double sum;
895 
896   gcc_assert (gcov_info1 || gcov_info2);
897   if (!gcov_info1)
898     {
899       gcov_info = gcov_info2;
900       cum_p = cum_2_result;
901       sum = sum_2;
902       *cum_1_result = 0;
903     } else
904   if (!gcov_info2)
905     {
906       gcov_info = gcov_info1;
907       cum_p = cum_1_result;
908       sum = sum_1;
909       *cum_2_result = 0;
910     }
911 
912   if (gcov_info)
913   {
914     for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
915       {
916         const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
917         if (!gfi_ptr || gfi_ptr->key != gcov_info)
918           continue;
919         const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
920 	unsigned c_num;
921 	for (c_num = 0; c_num < ci_ptr->num; c_num++)
922 	  cum_1 += ci_ptr->values[c_num] / sum;
923       }
924     *cum_p = cum_1;
925     return 0.0;
926   }
927 
928   for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
929     {
930       double func_cum_1 = 0.0;
931       double func_cum_2 = 0.0;
932       double func_val = 0.0;
933       int nonzero = 0;
934       int hot = 0;
935       const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
936       const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
937 
938       if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
939         continue;
940       if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
941         continue;
942 
943       const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
944       const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
945       unsigned c_num;
946       for (c_num = 0; c_num < ci_ptr1->num; c_num++)
947 	{
948 	  if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
949 	    {
950 	      func_val += calculate_2_entries (ci_ptr1->values[c_num],
951 					       ci_ptr2->values[c_num],
952 					       sum_1, sum_2);
953 
954 	      func_cum_1 += ci_ptr1->values[c_num] / sum_1;
955 	      func_cum_2 += ci_ptr2->values[c_num] / sum_2;
956 	      nonzero = 1;
957 	      if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
958 		  || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
959 		hot = 1;
960 	    }
961 	}
962 
963       ret += func_val;
964       cum_1 += func_cum_1;
965       cum_2 += func_cum_2;
966       if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
967         {
968           printf("   \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
969                  gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
970         }
971     }
972   *cum_1_result = cum_1;
973   *cum_2_result = cum_2;
974   return ret;
975 }
976 
977 /* Test if all counter values in this GCOV_INFO are cold.
978    "Cold" is defined as the counter value being less than
979    or equal to THRESHOLD.  */
980 
981 static bool
gcov_info_count_all_cold(const struct gcov_info * gcov_info,gcov_type threshold)982 gcov_info_count_all_cold (const struct gcov_info *gcov_info,
983                           gcov_type threshold)
984 {
985   unsigned f_ix;
986 
987   for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
988     {
989       const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
990 
991       if (!gfi_ptr || gfi_ptr->key != gcov_info)
992         continue;
993       const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
994       for (unsigned c_num = 0; c_num < ci_ptr->num; c_num++)
995 	if (ci_ptr->values[c_num] > threshold)
996 	  return false;
997     }
998 
999   return true;
1000 }
1001 
1002 /* Test if all counter values in this GCOV_INFO are 0.  */
1003 
1004 static bool
gcov_info_count_all_zero(const struct gcov_info * gcov_info)1005 gcov_info_count_all_zero (const struct gcov_info *gcov_info)
1006 {
1007   return gcov_info_count_all_cold (gcov_info, 0);
1008 }
1009 
1010 /* A pair of matched GCOV_INFO.
1011    The flag is a bitvector:
1012      b0: obj1's all counts are 0;
1013      b1: obj1's all counts are cold (but no 0);
1014      b2: obj1 is hot;
1015      b3: no obj1 to match obj2;
1016      b4: obj2's all counts are 0;
1017      b5: obj2's all counts are cold (but no 0);
1018      b6: obj2 is hot;
1019      b7: no obj2 to match obj1;
1020  */
1021 struct overlap_t {
1022    const struct gcov_info *obj1;
1023    const struct gcov_info *obj2;
1024    char flag;
1025 };
1026 
1027 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1028 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1029 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1030 
1031 /* Cumlative overlap dscore for profile1 and profile2.  */
1032 static double overlap_sum_1, overlap_sum_2;
1033 
1034 /* The number of gcda files in the profiles.  */
1035 static unsigned gcda_files[2];
1036 
1037 /* The number of unique gcda files in the profiles
1038    (not existing in the other profile).  */
1039 static unsigned unique_gcda_files[2];
1040 
1041 /* The number of gcda files that all counter values are 0.  */
1042 static unsigned zero_gcda_files[2];
1043 
1044 /* The number of gcda files that all counter values are cold (but not 0).  */
1045 static unsigned cold_gcda_files[2];
1046 
1047 /* The number of gcda files that includes hot counter values.  */
1048 static unsigned hot_gcda_files[2];
1049 
1050 /* The number of gcda files with hot count value in either profiles.  */
1051 static unsigned both_hot_cnt;
1052 
1053 /* The number of gcda files with all counts cold (but not 0) in
1054    both profiles. */
1055 static unsigned both_cold_cnt;
1056 
1057 /* The number of gcda files with all counts 0 in both profiles.  */
1058 static unsigned both_zero_cnt;
1059 
1060 /* Extract the basename of the filename NAME.  */
1061 
1062 static char *
extract_file_basename(const char * name)1063 extract_file_basename (const char *name)
1064 {
1065   char *str;
1066   int len = 0;
1067   char *path = xstrdup (name);
1068   char sep_str[2];
1069 
1070   sep_str[0] = DIR_SEPARATOR;
1071   sep_str[1] = 0;
1072   str = strstr(path, sep_str);
1073   do{
1074       len = strlen(str) + 1;
1075       path = &path[strlen(path) - len + 2];
1076       str = strstr(path, sep_str);
1077   } while(str);
1078 
1079   return path;
1080 }
1081 
1082 /* Utility function to get the filename.  */
1083 
1084 static const char *
get_file_basename(const char * name)1085 get_file_basename (const char *name)
1086 {
1087   if (overlap_use_fullname)
1088     return name;
1089   return extract_file_basename (name);
1090 }
1091 
1092 /* A utility function to set the flag for the gcda files.  */
1093 
1094 static void
set_flag(struct overlap_t * e)1095 set_flag (struct overlap_t *e)
1096 {
1097   char flag = 0;
1098 
1099   if (!e->obj1)
1100     {
1101       unique_gcda_files[1]++;
1102       flag = 0x8;
1103     }
1104   else
1105     {
1106       gcda_files[0]++;
1107       if (gcov_info_count_all_zero (e->obj1))
1108         {
1109           zero_gcda_files[0]++;
1110           flag = 0x1;
1111         }
1112       else
1113       if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
1114 			      * overlap_hot_threshold))
1115         {
1116           cold_gcda_files[0]++;
1117           flag = 0x2;
1118         }
1119       else
1120         {
1121           hot_gcda_files[0]++;
1122           flag = 0x4;
1123         }
1124     }
1125 
1126   if (!e->obj2)
1127     {
1128       unique_gcda_files[0]++;
1129       flag |= (0x8 << 4);
1130     }
1131   else
1132     {
1133       gcda_files[1]++;
1134       if (gcov_info_count_all_zero (e->obj2))
1135         {
1136           zero_gcda_files[1]++;
1137           flag |= (0x1 << 4);
1138         }
1139       else
1140       if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
1141 			      * overlap_hot_threshold))
1142         {
1143           cold_gcda_files[1]++;
1144           flag |= (0x2 << 4);
1145         }
1146       else
1147         {
1148           hot_gcda_files[1]++;
1149           flag |= (0x4 << 4);
1150         }
1151     }
1152 
1153   gcc_assert (flag);
1154   e->flag = flag;
1155 }
1156 
1157 /* Test if INFO1 and INFO2 are from the matched source file.
1158    Return 1 if they match; return 0 otherwise.  */
1159 
1160 static int
matched_gcov_info(const struct gcov_info * info1,const struct gcov_info * info2)1161 matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
1162 {
1163   /* For FDO, we have to match the name. This can be expensive.
1164      Maybe we should use hash here.  */
1165   if (strcmp (info1->filename, info2->filename))
1166     return 0;
1167 
1168   if (info1->n_functions != info2->n_functions)
1169     {
1170       fnotice (stderr, "mismatched profiles in %s (%d functions"
1171                        " vs %d functions)\n",
1172                        info1->filename,
1173                        info1->n_functions,
1174                        info2->n_functions);
1175       return 0;
1176     }
1177   return 1;
1178 }
1179 
1180 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1181    GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1182    match and 1.0 meaning a perfect match.  */
1183 
1184 static double
calculate_overlap(struct gcov_info * gcov_list1,struct gcov_info * gcov_list2)1185 calculate_overlap (struct gcov_info *gcov_list1,
1186                    struct gcov_info *gcov_list2)
1187 {
1188   unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
1189   unsigned int i, j;
1190   const struct gcov_info *gi_ptr;
1191   struct overlap_t *all_infos;
1192 
1193   for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
1194     list1_cnt++;
1195   for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
1196     list2_cnt++;
1197   all_cnt = list1_cnt + list2_cnt;
1198   all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
1199                * all_cnt * 2);
1200   gcc_assert (all_infos);
1201 
1202   i = 0;
1203   for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
1204     {
1205       all_infos[i].obj1 = gi_ptr;
1206       all_infos[i].obj2 = 0;
1207     }
1208 
1209   for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
1210     {
1211       all_infos[i].obj1 = 0;
1212       all_infos[i].obj2 = gi_ptr;
1213     }
1214 
1215   for (i = list1_cnt; i < all_cnt; i++)
1216     {
1217       if (all_infos[i].obj2 == 0)
1218         continue;
1219       for (j = 0; j < list1_cnt; j++)
1220         {
1221           if (all_infos[j].obj2 != 0)
1222             continue;
1223           if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
1224             {
1225               all_infos[j].obj2 = all_infos[i].obj2;
1226               all_infos[i].obj2 = 0;
1227               break;
1228             }
1229         }
1230     }
1231 
1232   for (i = 0; i < all_cnt; i++)
1233     if (all_infos[i].obj1 || all_infos[i].obj2)
1234       {
1235         set_flag (all_infos + i);
1236         if (FLAG_ONE_HOT (all_infos[i].flag))
1237             both_hot_cnt++;
1238         if (FLAG_BOTH_COLD(all_infos[i].flag))
1239             both_cold_cnt++;
1240         if (FLAG_BOTH_ZERO(all_infos[i].flag))
1241             both_zero_cnt++;
1242       }
1243 
1244   double prg_val = 0;
1245   double sum_val = 0;
1246   double sum_cum_1 = 0;
1247   double sum_cum_2 = 0;
1248 
1249   for (i = 0; i < all_cnt; i++)
1250     {
1251       double val;
1252       double cum_1, cum_2;
1253       const char *filename;
1254 
1255       if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
1256         continue;
1257       if (FLAG_BOTH_ZERO (all_infos[i].flag))
1258           continue;
1259 
1260       if (all_infos[i].obj1)
1261         filename = get_file_basename (all_infos[i].obj1->filename);
1262       else
1263         filename = get_file_basename (all_infos[i].obj2->filename);
1264 
1265       if (overlap_func_level)
1266         printf("\n   processing %36s:\n", filename);
1267 
1268       val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
1269           overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
1270 
1271       if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
1272         {
1273           printf("   obj=%36s  overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1274                   filename, val*100, cum_1*100, cum_2*100);
1275           sum_val += val;
1276           sum_cum_1 += cum_1;
1277           sum_cum_2 += cum_2;
1278         }
1279 
1280       prg_val += val;
1281 
1282     }
1283 
1284   free (all_infos);
1285 
1286   if (overlap_obj_level)
1287     printf("   SUM:%36s  overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1288            "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
1289 
1290   printf ("  Statistics:\n"
1291           "                    profile1_#     profile2_#       overlap_#\n");
1292   printf ("    gcda files:  %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
1293 	  gcda_files[0]-unique_gcda_files[0]);
1294   printf ("  unique files:  %12u\t%12u\n", unique_gcda_files[0],
1295 	  unique_gcda_files[1]);
1296   printf ("     hot files:  %12u\t%12u\t%12u\n", hot_gcda_files[0],
1297 	  hot_gcda_files[1], both_hot_cnt);
1298   printf ("    cold files:  %12u\t%12u\t%12u\n", cold_gcda_files[0],
1299 	  cold_gcda_files[1], both_cold_cnt);
1300   printf ("    zero files:  %12u\t%12u\t%12u\n", zero_gcda_files[0],
1301 	  zero_gcda_files[1], both_zero_cnt);
1302 
1303   return prg_val;
1304 }
1305 
1306 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1307    PROFILE2.
1308    Return 0 on success: without mismatch. Reutrn 1 on error.  */
1309 
1310 int
gcov_profile_overlap(struct gcov_info * profile1,struct gcov_info * profile2)1311 gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
1312 {
1313   double result;
1314 
1315   result = calculate_overlap (profile1, profile2);
1316 
1317   if (result > 0)
1318     {
1319       printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
1320       return 0;
1321     }
1322   return 1;
1323 }
1324