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