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