110d565efSmrg /* Utility functions for reading gcda files into in-memory
210d565efSmrg    gcov_info structures and offline profile processing. */
3*ec02198aSmrg /* Copyright (C) 2014-2020 Free Software Foundation, Inc.
410d565efSmrg    Contributed by Rong Xu <xur@google.com>.
510d565efSmrg 
610d565efSmrg This file is part of GCC.
710d565efSmrg 
810d565efSmrg GCC is free software; you can redistribute it and/or modify it under
910d565efSmrg the terms of the GNU General Public License as published by the Free
1010d565efSmrg Software Foundation; either version 3, or (at your option) any later
1110d565efSmrg version.
1210d565efSmrg 
1310d565efSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1410d565efSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
1510d565efSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1610d565efSmrg for more details.
1710d565efSmrg 
1810d565efSmrg Under Section 7 of GPL version 3, you are granted additional
1910d565efSmrg permissions described in the GCC Runtime Library Exception, version
2010d565efSmrg 3.1, as published by the Free Software Foundation.
2110d565efSmrg 
2210d565efSmrg You should have received a copy of the GNU General Public License and
2310d565efSmrg a copy of the GCC Runtime Library Exception along with this program;
2410d565efSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2510d565efSmrg <http://www.gnu.org/licenses/>.  */
2610d565efSmrg 
2710d565efSmrg 
2810d565efSmrg #define IN_GCOV_TOOL 1
2910d565efSmrg 
3010d565efSmrg #include "libgcov.h"
3110d565efSmrg #include "intl.h"
3210d565efSmrg #include "diagnostic.h"
3310d565efSmrg #include "version.h"
3410d565efSmrg #include "demangle.h"
350fc04c29Smrg #include "gcov-io.h"
3610d565efSmrg 
3710d565efSmrg /* Borrowed from basic-block.h.  */
3810d565efSmrg #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
3910d565efSmrg 
4010d565efSmrg extern gcov_position_t gcov_position();
4110d565efSmrg extern int gcov_is_error();
4210d565efSmrg 
4310d565efSmrg /* Verbose mode for debug.  */
4410d565efSmrg static int verbose;
4510d565efSmrg 
4610d565efSmrg /* Set verbose flag.  */
gcov_set_verbose(void)4710d565efSmrg void gcov_set_verbose (void)
4810d565efSmrg {
4910d565efSmrg   verbose = 1;
5010d565efSmrg }
5110d565efSmrg 
5210d565efSmrg /* The following part is to read Gcda and reconstruct GCOV_INFO.  */
5310d565efSmrg 
5410d565efSmrg #include "obstack.h"
5510d565efSmrg #include <unistd.h>
5610d565efSmrg #ifdef HAVE_FTW_H
5710d565efSmrg #include <ftw.h>
5810d565efSmrg #endif
5910d565efSmrg 
6010d565efSmrg static void tag_function (unsigned, unsigned);
6110d565efSmrg static void tag_blocks (unsigned, unsigned);
6210d565efSmrg static void tag_arcs (unsigned, unsigned);
6310d565efSmrg static void tag_lines (unsigned, unsigned);
6410d565efSmrg static void tag_counters (unsigned, unsigned);
6510d565efSmrg static void tag_summary (unsigned, unsigned);
6610d565efSmrg 
6710d565efSmrg /* The gcov_info for the first module.  */
6810d565efSmrg static struct gcov_info *curr_gcov_info;
6910d565efSmrg /* The gcov_info being processed.  */
7010d565efSmrg static struct gcov_info *gcov_info_head;
7110d565efSmrg /* This variable contains all the functions in current module.  */
7210d565efSmrg static struct obstack fn_info;
7310d565efSmrg /* The function being processed.  */
7410d565efSmrg static struct gcov_fn_info *curr_fn_info;
7510d565efSmrg /* The number of functions seen so far.  */
7610d565efSmrg static unsigned num_fn_info;
7710d565efSmrg /* This variable contains all the counters for current module.  */
7810d565efSmrg static int k_ctrs_mask[GCOV_COUNTERS];
7910d565efSmrg /* The kind of counters that have been seen.  */
8010d565efSmrg static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
8110d565efSmrg /* Number of kind of counters that have been seen.  */
8210d565efSmrg static int k_ctrs_types;
830fc04c29Smrg /* The object summary being processed.  */
840fc04c29Smrg static struct gcov_summary *curr_object_summary;
8510d565efSmrg 
8610d565efSmrg /* Merge functions for counters.  */
8710d565efSmrg #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
8810d565efSmrg static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
8910d565efSmrg #include "gcov-counter.def"
9010d565efSmrg };
9110d565efSmrg #undef DEF_GCOV_COUNTER
9210d565efSmrg 
9310d565efSmrg /* Set the ctrs field in gcov_fn_info object FN_INFO.  */
9410d565efSmrg 
9510d565efSmrg static void
set_fn_ctrs(struct gcov_fn_info * fn_info)9610d565efSmrg set_fn_ctrs (struct gcov_fn_info *fn_info)
9710d565efSmrg {
9810d565efSmrg   int j = 0, i;
9910d565efSmrg 
10010d565efSmrg   for (i = 0; i < GCOV_COUNTERS; i++)
10110d565efSmrg     {
10210d565efSmrg       if (k_ctrs_mask[i] == 0)
10310d565efSmrg         continue;
10410d565efSmrg       fn_info->ctrs[j].num = k_ctrs[i].num;
10510d565efSmrg       fn_info->ctrs[j].values = k_ctrs[i].values;
10610d565efSmrg       j++;
10710d565efSmrg     }
10810d565efSmrg   if (k_ctrs_types == 0)
10910d565efSmrg     k_ctrs_types = j;
11010d565efSmrg   else
11110d565efSmrg     gcc_assert (j == k_ctrs_types);
11210d565efSmrg }
11310d565efSmrg 
11410d565efSmrg /* For each tag in gcda file, we have an entry here.
11510d565efSmrg    TAG is the tag value; NAME is the tag name; and
11610d565efSmrg    PROC is the handler function.  */
11710d565efSmrg 
11810d565efSmrg typedef struct tag_format
11910d565efSmrg {
12010d565efSmrg     unsigned tag;
12110d565efSmrg     char const *name;
12210d565efSmrg     void (*proc) (unsigned, unsigned);
12310d565efSmrg } tag_format_t;
12410d565efSmrg 
12510d565efSmrg /* Handler table for various Tags.  */
12610d565efSmrg 
12710d565efSmrg static const tag_format_t tag_table[] =
12810d565efSmrg {
12910d565efSmrg   {0, "NOP", NULL},
13010d565efSmrg   {0, "UNKNOWN", NULL},
13110d565efSmrg   {0, "COUNTERS", tag_counters},
13210d565efSmrg   {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
13310d565efSmrg   {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
13410d565efSmrg   {GCOV_TAG_ARCS, "ARCS", tag_arcs},
13510d565efSmrg   {GCOV_TAG_LINES, "LINES", tag_lines},
13610d565efSmrg   {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
13710d565efSmrg   {0, NULL, NULL}
13810d565efSmrg };
13910d565efSmrg 
14010d565efSmrg /* Handler for reading function tag.  */
14110d565efSmrg 
14210d565efSmrg static void
tag_function(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)14310d565efSmrg tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
14410d565efSmrg {
14510d565efSmrg   int i;
14610d565efSmrg 
14710d565efSmrg   /* write out previous fn_info.  */
14810d565efSmrg   if (num_fn_info)
14910d565efSmrg     {
15010d565efSmrg       set_fn_ctrs (curr_fn_info);
15110d565efSmrg       obstack_ptr_grow (&fn_info, curr_fn_info);
15210d565efSmrg     }
15310d565efSmrg 
15410d565efSmrg   /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
15510d565efSmrg      counter types.  */
15610d565efSmrg   curr_fn_info = (struct gcov_fn_info *) xcalloc (sizeof (struct gcov_fn_info)
15710d565efSmrg                    + GCOV_COUNTERS * sizeof (struct gcov_ctr_info), 1);
15810d565efSmrg 
15910d565efSmrg   for (i = 0; i < GCOV_COUNTERS; i++)
16010d565efSmrg      k_ctrs[i].num = 0;
16110d565efSmrg   k_ctrs_types = 0;
16210d565efSmrg 
16310d565efSmrg   curr_fn_info->key = curr_gcov_info;
16410d565efSmrg   curr_fn_info->ident = gcov_read_unsigned ();
16510d565efSmrg   curr_fn_info->lineno_checksum = gcov_read_unsigned ();
16610d565efSmrg   curr_fn_info->cfg_checksum = gcov_read_unsigned ();
16710d565efSmrg   num_fn_info++;
16810d565efSmrg 
16910d565efSmrg   if (verbose)
17010d565efSmrg     fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
17110d565efSmrg }
17210d565efSmrg 
17310d565efSmrg /* Handler for reading block tag.  */
17410d565efSmrg 
17510d565efSmrg static void
tag_blocks(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)17610d565efSmrg tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
17710d565efSmrg {
17810d565efSmrg   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
17910d565efSmrg   gcc_unreachable ();
18010d565efSmrg }
18110d565efSmrg 
18210d565efSmrg /* Handler for reading flow arc tag.  */
18310d565efSmrg 
18410d565efSmrg static void
tag_arcs(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)18510d565efSmrg tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
18610d565efSmrg {
18710d565efSmrg   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
18810d565efSmrg   gcc_unreachable ();
18910d565efSmrg }
19010d565efSmrg 
19110d565efSmrg /* Handler for reading line tag.  */
19210d565efSmrg 
19310d565efSmrg static void
tag_lines(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)19410d565efSmrg tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
19510d565efSmrg {
19610d565efSmrg   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
19710d565efSmrg   gcc_unreachable ();
19810d565efSmrg }
19910d565efSmrg 
20010d565efSmrg /* Handler for reading counters array tag with value as TAG and length of LENGTH.  */
20110d565efSmrg 
20210d565efSmrg static void
tag_counters(unsigned tag,unsigned length)20310d565efSmrg tag_counters (unsigned tag, unsigned length)
20410d565efSmrg {
20510d565efSmrg   unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
20610d565efSmrg   gcov_type *values;
20710d565efSmrg   unsigned ix;
20810d565efSmrg   unsigned tag_ix;
20910d565efSmrg 
21010d565efSmrg   tag_ix = GCOV_COUNTER_FOR_TAG (tag);
21110d565efSmrg   gcc_assert (tag_ix < GCOV_COUNTERS);
21210d565efSmrg   k_ctrs_mask [tag_ix] = 1;
21310d565efSmrg   gcc_assert (k_ctrs[tag_ix].num == 0);
21410d565efSmrg   k_ctrs[tag_ix].num = n_counts;
21510d565efSmrg 
21610d565efSmrg   k_ctrs[tag_ix].values = values = (gcov_type *) xmalloc (n_counts * sizeof (gcov_type));
21710d565efSmrg   gcc_assert (values);
21810d565efSmrg 
21910d565efSmrg   for (ix = 0; ix != n_counts; ix++)
22010d565efSmrg     values[ix] = gcov_read_counter ();
22110d565efSmrg }
22210d565efSmrg 
22310d565efSmrg /* Handler for reading summary tag.  */
22410d565efSmrg 
22510d565efSmrg static void
tag_summary(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)22610d565efSmrg tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
22710d565efSmrg {
2280fc04c29Smrg   curr_object_summary = (gcov_summary *) xcalloc (sizeof (gcov_summary), 1);
2290fc04c29Smrg   gcov_read_summary (curr_object_summary);
23010d565efSmrg }
23110d565efSmrg 
23210d565efSmrg /* This function is called at the end of reading a gcda file.
23310d565efSmrg    It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO.  */
23410d565efSmrg 
23510d565efSmrg static void
read_gcda_finalize(struct gcov_info * obj_info)23610d565efSmrg read_gcda_finalize (struct gcov_info *obj_info)
23710d565efSmrg {
23810d565efSmrg   int i;
23910d565efSmrg 
24010d565efSmrg   set_fn_ctrs (curr_fn_info);
24110d565efSmrg   obstack_ptr_grow (&fn_info, curr_fn_info);
24210d565efSmrg 
2430fc04c29Smrg   /* We set the following fields: merge, n_functions, functions
2440fc04c29Smrg      and summary.  */
24510d565efSmrg   obj_info->n_functions = num_fn_info;
24610d565efSmrg   obj_info->functions = (const struct gcov_fn_info**) obstack_finish (&fn_info);
24710d565efSmrg 
24810d565efSmrg   /* wrap all the counter array.  */
24910d565efSmrg   for (i=0; i< GCOV_COUNTERS; i++)
25010d565efSmrg     {
25110d565efSmrg       if (k_ctrs_mask[i])
25210d565efSmrg         obj_info->merge[i] = ctr_merge_functions[i];
25310d565efSmrg     }
25410d565efSmrg }
25510d565efSmrg 
25610d565efSmrg /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
25710d565efSmrg    Program level summary CURRENT_SUMMARY will also be updated.  */
25810d565efSmrg 
25910d565efSmrg static struct gcov_info *
read_gcda_file(const char * filename)26010d565efSmrg read_gcda_file (const char *filename)
26110d565efSmrg {
26210d565efSmrg   unsigned tags[4];
26310d565efSmrg   unsigned depth = 0;
264*ec02198aSmrg   unsigned version;
26510d565efSmrg   struct gcov_info *obj_info;
26610d565efSmrg   int i;
26710d565efSmrg 
26810d565efSmrg   for (i=0; i< GCOV_COUNTERS; i++)
26910d565efSmrg     k_ctrs_mask[i] = 0;
27010d565efSmrg   k_ctrs_types = 0;
27110d565efSmrg 
27210d565efSmrg   if (!gcov_open (filename))
27310d565efSmrg     {
27410d565efSmrg       fnotice (stderr, "%s:cannot open\n", filename);
27510d565efSmrg       return NULL;
27610d565efSmrg     }
27710d565efSmrg 
27810d565efSmrg   /* Read magic.  */
279*ec02198aSmrg   if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
28010d565efSmrg     {
28110d565efSmrg       fnotice (stderr, "%s:not a gcov data file\n", filename);
28210d565efSmrg       gcov_close ();
28310d565efSmrg       return NULL;
28410d565efSmrg     }
28510d565efSmrg 
28610d565efSmrg   /* Read version.  */
28710d565efSmrg   version = gcov_read_unsigned ();
28810d565efSmrg   if (version != GCOV_VERSION)
28910d565efSmrg     {
29010d565efSmrg       fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
29110d565efSmrg       gcov_close ();
29210d565efSmrg       return NULL;
29310d565efSmrg     }
29410d565efSmrg 
29510d565efSmrg   /* Instantiate a gcov_info object.  */
29610d565efSmrg   curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
29710d565efSmrg              sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
29810d565efSmrg 
29910d565efSmrg   obj_info->version = version;
30010d565efSmrg   obstack_init (&fn_info);
30110d565efSmrg   num_fn_info = 0;
30210d565efSmrg   curr_fn_info = 0;
3030fc04c29Smrg   curr_object_summary = NULL;
30410d565efSmrg   {
30510d565efSmrg     size_t len = strlen (filename) + 1;
30610d565efSmrg     char *str_dup = (char*) xmalloc (len);
30710d565efSmrg 
30810d565efSmrg     memcpy (str_dup, filename, len);
30910d565efSmrg     obj_info->filename = str_dup;
31010d565efSmrg   }
31110d565efSmrg 
31210d565efSmrg   /* Read stamp.  */
31310d565efSmrg   obj_info->stamp = gcov_read_unsigned ();
31410d565efSmrg 
31510d565efSmrg   while (1)
31610d565efSmrg     {
31710d565efSmrg       gcov_position_t base;
31810d565efSmrg       unsigned tag, length;
31910d565efSmrg       tag_format_t const *format;
32010d565efSmrg       unsigned tag_depth;
32110d565efSmrg       int error;
32210d565efSmrg       unsigned mask;
32310d565efSmrg 
32410d565efSmrg       tag = gcov_read_unsigned ();
32510d565efSmrg       if (!tag)
32610d565efSmrg         break;
32710d565efSmrg       length = gcov_read_unsigned ();
32810d565efSmrg       base = gcov_position ();
32910d565efSmrg       mask = GCOV_TAG_MASK (tag) >> 1;
33010d565efSmrg       for (tag_depth = 4; mask; mask >>= 8)
33110d565efSmrg         {
33210d565efSmrg           if (((mask & 0xff) != 0xff))
33310d565efSmrg             {
334*ec02198aSmrg 	      warning (0, "%s:tag %qx is invalid", filename, tag);
33510d565efSmrg               break;
33610d565efSmrg             }
33710d565efSmrg           tag_depth--;
33810d565efSmrg         }
33910d565efSmrg       for (format = tag_table; format->name; format++)
34010d565efSmrg         if (format->tag == tag)
34110d565efSmrg           goto found;
34210d565efSmrg       format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
34310d565efSmrg     found:;
34410d565efSmrg       if (tag)
34510d565efSmrg         {
34610d565efSmrg           if (depth && depth < tag_depth)
34710d565efSmrg             {
34810d565efSmrg               if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
349*ec02198aSmrg 	        warning (0, "%s:tag %qx is incorrectly nested",
35010d565efSmrg                          filename, tag);
35110d565efSmrg             }
35210d565efSmrg           depth = tag_depth;
35310d565efSmrg           tags[depth - 1] = tag;
35410d565efSmrg         }
35510d565efSmrg 
35610d565efSmrg       if (format->proc)
35710d565efSmrg         {
35810d565efSmrg           unsigned long actual_length;
35910d565efSmrg 
36010d565efSmrg           (*format->proc) (tag, length);
36110d565efSmrg 
36210d565efSmrg           actual_length = gcov_position () - base;
36310d565efSmrg           if (actual_length > length)
364*ec02198aSmrg 	    warning (0, "%s:record size mismatch %lu bytes overread",
36510d565efSmrg                      filename, actual_length - length);
36610d565efSmrg           else if (length > actual_length)
367*ec02198aSmrg 	    warning (0, "%s:record size mismatch %lu bytes unread",
36810d565efSmrg                      filename, length - actual_length);
36910d565efSmrg        }
37010d565efSmrg 
37110d565efSmrg       gcov_sync (base, length);
37210d565efSmrg       if ((error = gcov_is_error ()))
37310d565efSmrg         {
374*ec02198aSmrg 	  warning (0, error < 0 ? "%s:counter overflow at %lu" :
375*ec02198aSmrg 	                          "%s:read error at %lu", filename,
37610d565efSmrg                    (long unsigned) gcov_position ());
37710d565efSmrg           break;
37810d565efSmrg         }
37910d565efSmrg     }
38010d565efSmrg 
38110d565efSmrg   read_gcda_finalize (obj_info);
38210d565efSmrg   gcov_close ();
38310d565efSmrg 
38410d565efSmrg   return obj_info;
38510d565efSmrg }
38610d565efSmrg 
38710d565efSmrg #ifdef HAVE_FTW_H
38810d565efSmrg /* This will be called by ftw(). It opens and read a gcda file FILENAME.
38910d565efSmrg    Return a non-zero value to stop the tree walk.  */
39010d565efSmrg 
39110d565efSmrg static int
ftw_read_file(const char * filename,const struct stat * status ATTRIBUTE_UNUSED,int type)39210d565efSmrg ftw_read_file (const char *filename,
39310d565efSmrg                const struct stat *status ATTRIBUTE_UNUSED,
39410d565efSmrg                int type)
39510d565efSmrg {
39610d565efSmrg   int filename_len;
39710d565efSmrg   int suffix_len;
39810d565efSmrg   struct gcov_info *obj_info;
39910d565efSmrg 
40010d565efSmrg   /* Only read regular files.  */
40110d565efSmrg   if (type != FTW_F)
40210d565efSmrg     return 0;
40310d565efSmrg 
40410d565efSmrg   filename_len = strlen (filename);
40510d565efSmrg   suffix_len = strlen (GCOV_DATA_SUFFIX);
40610d565efSmrg 
40710d565efSmrg   if (filename_len <= suffix_len)
40810d565efSmrg     return 0;
40910d565efSmrg 
41010d565efSmrg   if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
41110d565efSmrg     return 0;
41210d565efSmrg 
41310d565efSmrg   if (verbose)
41410d565efSmrg     fnotice (stderr, "reading file: %s\n", filename);
41510d565efSmrg 
41610d565efSmrg   obj_info = read_gcda_file (filename);
41710d565efSmrg   if (!obj_info)
41810d565efSmrg     return 0;
41910d565efSmrg 
42010d565efSmrg   obj_info->next = gcov_info_head;
42110d565efSmrg   gcov_info_head = obj_info;
42210d565efSmrg 
42310d565efSmrg   return 0;
42410d565efSmrg }
42510d565efSmrg #endif
42610d565efSmrg 
42710d565efSmrg /* Initializer for reading a profile dir.  */
42810d565efSmrg 
42910d565efSmrg static inline void
read_profile_dir_init(void)43010d565efSmrg read_profile_dir_init (void)
43110d565efSmrg {
43210d565efSmrg   gcov_info_head = 0;
43310d565efSmrg }
43410d565efSmrg 
43510d565efSmrg /* Driver for read a profile directory and convert into gcov_info list in memory.
43610d565efSmrg    Return NULL on error,
43710d565efSmrg    Return the head of gcov_info list on success.  */
43810d565efSmrg 
43910d565efSmrg struct gcov_info *
gcov_read_profile_dir(const char * dir_name,int recompute_summary ATTRIBUTE_UNUSED)44010d565efSmrg gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
44110d565efSmrg {
44210d565efSmrg   char *pwd;
44310d565efSmrg   int ret;
44410d565efSmrg 
44510d565efSmrg   read_profile_dir_init ();
44610d565efSmrg 
44710d565efSmrg   if (access (dir_name, R_OK) != 0)
44810d565efSmrg     {
44910d565efSmrg       fnotice (stderr, "cannot access directory %s\n", dir_name);
45010d565efSmrg       return NULL;
45110d565efSmrg     }
45210d565efSmrg   pwd = getcwd (NULL, 0);
45310d565efSmrg   gcc_assert (pwd);
45410d565efSmrg   ret = chdir (dir_name);
45510d565efSmrg   if (ret !=0)
45610d565efSmrg     {
45710d565efSmrg       fnotice (stderr, "%s is not a directory\n", dir_name);
45810d565efSmrg       return NULL;
45910d565efSmrg     }
46010d565efSmrg #ifdef HAVE_FTW_H
46110d565efSmrg   ftw (".", ftw_read_file, 50);
46210d565efSmrg #endif
463*ec02198aSmrg   chdir (pwd);
46410d565efSmrg   free (pwd);
46510d565efSmrg 
46610d565efSmrg   return gcov_info_head;;
46710d565efSmrg }
46810d565efSmrg 
46910d565efSmrg /* This part of the code is to merge profile counters. These
47010d565efSmrg    variables are set in merge_wrapper and to be used by
47110d565efSmrg    global function gcov_read_counter_mem() and gcov_get_merge_weight.  */
47210d565efSmrg 
47310d565efSmrg /* We save the counter value address to this variable.  */
47410d565efSmrg static gcov_type *gcov_value_buf;
47510d565efSmrg 
47610d565efSmrg /* The number of counter values to be read by current merging.  */
47710d565efSmrg static gcov_unsigned_t gcov_value_buf_size;
47810d565efSmrg 
47910d565efSmrg /* The index of counter values being read.  */
48010d565efSmrg static gcov_unsigned_t gcov_value_buf_pos;
48110d565efSmrg 
48210d565efSmrg /* The weight of current merging.  */
48310d565efSmrg static unsigned gcov_merge_weight;
48410d565efSmrg 
48510d565efSmrg /* Read a counter value from gcov_value_buf array.  */
48610d565efSmrg 
48710d565efSmrg gcov_type
gcov_read_counter_mem(void)48810d565efSmrg gcov_read_counter_mem (void)
48910d565efSmrg {
49010d565efSmrg   gcov_type ret;
49110d565efSmrg   gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
49210d565efSmrg   ret = *(gcov_value_buf + gcov_value_buf_pos);
49310d565efSmrg   ++gcov_value_buf_pos;
49410d565efSmrg   return ret;
49510d565efSmrg }
49610d565efSmrg 
49710d565efSmrg /* Return the recorded merge weight.  */
49810d565efSmrg 
49910d565efSmrg unsigned
gcov_get_merge_weight(void)50010d565efSmrg gcov_get_merge_weight (void)
50110d565efSmrg {
50210d565efSmrg   return gcov_merge_weight;
50310d565efSmrg }
50410d565efSmrg 
50510d565efSmrg /* A wrapper function for merge functions. It sets up the
50610d565efSmrg    value buffer and weights and then calls the merge function.  */
50710d565efSmrg 
50810d565efSmrg static void
merge_wrapper(gcov_merge_fn f,gcov_type * v1,gcov_unsigned_t n,gcov_type * v2,unsigned w)50910d565efSmrg merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n,
51010d565efSmrg                gcov_type *v2, unsigned w)
51110d565efSmrg {
51210d565efSmrg   gcov_value_buf = v2;
51310d565efSmrg   gcov_value_buf_pos = 0;
51410d565efSmrg   gcov_value_buf_size = n;
51510d565efSmrg   gcov_merge_weight = w;
51610d565efSmrg   (*f) (v1, n);
51710d565efSmrg }
51810d565efSmrg 
51910d565efSmrg /* Offline tool to manipulate profile data.
52010d565efSmrg    This tool targets on matched profiles. But it has some tolerance on
52110d565efSmrg    unmatched profiles.
52210d565efSmrg    When merging p1 to p2 (p2 is the dst),
52310d565efSmrg    * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
52410d565efSmrg      emit warning
52510d565efSmrg    * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
52610d565efSmrg      specified weight; emit warning.
52710d565efSmrg    * m.gcda in both p1 and p2:
52810d565efSmrg    ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
52910d565efSmrg    ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
53010d565efSmrg       p2->m.gcda->f and
53110d565efSmrg       drop p1->m.gcda->f. A warning is emitted.  */
53210d565efSmrg 
53310d565efSmrg /* Add INFO2's counter to INFO1, multiplying by weight W.  */
53410d565efSmrg 
53510d565efSmrg static int
gcov_merge(struct gcov_info * info1,struct gcov_info * info2,int w)53610d565efSmrg gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
53710d565efSmrg {
53810d565efSmrg   unsigned f_ix;
53910d565efSmrg   unsigned n_functions = info1->n_functions;
54010d565efSmrg   int has_mismatch = 0;
54110d565efSmrg 
54210d565efSmrg   gcc_assert (info2->n_functions == n_functions);
54310d565efSmrg   for (f_ix = 0; f_ix < n_functions; f_ix++)
54410d565efSmrg     {
54510d565efSmrg       unsigned t_ix;
54610d565efSmrg       const struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
54710d565efSmrg       const struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
54810d565efSmrg       const struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
54910d565efSmrg 
55010d565efSmrg       if (!gfi_ptr1 || gfi_ptr1->key != info1)
55110d565efSmrg         continue;
55210d565efSmrg       if (!gfi_ptr2 || gfi_ptr2->key != info2)
55310d565efSmrg         continue;
55410d565efSmrg 
55510d565efSmrg       if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
55610d565efSmrg         {
55710d565efSmrg           fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
55810d565efSmrg                   info1->filename);
55910d565efSmrg           has_mismatch = 1;
56010d565efSmrg           continue;
56110d565efSmrg         }
56210d565efSmrg       ci_ptr1 = gfi_ptr1->ctrs;
56310d565efSmrg       ci_ptr2 = gfi_ptr2->ctrs;
56410d565efSmrg       for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
56510d565efSmrg         {
56610d565efSmrg           gcov_merge_fn merge1 = info1->merge[t_ix];
56710d565efSmrg           gcov_merge_fn merge2 = info2->merge[t_ix];
56810d565efSmrg 
56910d565efSmrg           gcc_assert (merge1 == merge2);
57010d565efSmrg           if (!merge1)
57110d565efSmrg             continue;
57210d565efSmrg           gcc_assert (ci_ptr1->num == ci_ptr2->num);
57310d565efSmrg           merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num, ci_ptr2->values, w);
57410d565efSmrg           ci_ptr1++;
57510d565efSmrg           ci_ptr2++;
57610d565efSmrg         }
57710d565efSmrg     }
57810d565efSmrg 
57910d565efSmrg   return has_mismatch;
58010d565efSmrg }
58110d565efSmrg 
58210d565efSmrg /* Find and return the match gcov_info object for INFO from ARRAY.
58310d565efSmrg    SIZE is the length of ARRAY.
58410d565efSmrg    Return NULL if there is no match.  */
58510d565efSmrg 
58610d565efSmrg static struct gcov_info *
find_match_gcov_info(struct gcov_info ** array,int size,struct gcov_info * info)58710d565efSmrg find_match_gcov_info (struct gcov_info **array, int size,
58810d565efSmrg 		      struct gcov_info *info)
58910d565efSmrg {
59010d565efSmrg   struct gcov_info *gi_ptr;
59110d565efSmrg   struct gcov_info *ret = NULL;
59210d565efSmrg   int i;
59310d565efSmrg 
59410d565efSmrg   for (i = 0; i < size; i++)
59510d565efSmrg     {
59610d565efSmrg       gi_ptr = array[i];
59710d565efSmrg       if (gi_ptr == 0)
59810d565efSmrg         continue;
59910d565efSmrg       if (!strcmp (gi_ptr->filename, info->filename))
60010d565efSmrg         {
60110d565efSmrg           ret = gi_ptr;
60210d565efSmrg           array[i] = 0;
60310d565efSmrg           break;
60410d565efSmrg         }
60510d565efSmrg     }
60610d565efSmrg 
60710d565efSmrg   if (ret && ret->n_functions != info->n_functions)
60810d565efSmrg     {
60910d565efSmrg       fnotice (stderr, "mismatched profiles in %s (%d functions"
61010d565efSmrg                        " vs %d functions)\n",
61110d565efSmrg                        ret->filename,
61210d565efSmrg                        ret->n_functions,
61310d565efSmrg                        info->n_functions);
61410d565efSmrg       ret = NULL;
61510d565efSmrg     }
61610d565efSmrg   return ret;
61710d565efSmrg }
61810d565efSmrg 
61910d565efSmrg /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
62010d565efSmrg    Return 0 on success: without mismatch.
62110d565efSmrg    Reutrn 1 on error.  */
62210d565efSmrg 
62310d565efSmrg int
gcov_profile_merge(struct gcov_info * tgt_profile,struct gcov_info * src_profile,int w1,int w2)62410d565efSmrg gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
62510d565efSmrg                     int w1, int w2)
62610d565efSmrg {
62710d565efSmrg   struct gcov_info *gi_ptr;
62810d565efSmrg   struct gcov_info **tgt_infos;
62910d565efSmrg   struct gcov_info *tgt_tail;
63010d565efSmrg   struct gcov_info **in_src_not_tgt;
63110d565efSmrg   unsigned tgt_cnt = 0, src_cnt = 0;
63210d565efSmrg   unsigned unmatch_info_cnt = 0;
63310d565efSmrg   unsigned int i;
63410d565efSmrg 
63510d565efSmrg   for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
63610d565efSmrg     tgt_cnt++;
63710d565efSmrg   for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
63810d565efSmrg     src_cnt++;
63910d565efSmrg   tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
64010d565efSmrg                  * tgt_cnt);
64110d565efSmrg   gcc_assert (tgt_infos);
64210d565efSmrg   in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
64310d565efSmrg                      * src_cnt);
64410d565efSmrg   gcc_assert (in_src_not_tgt);
64510d565efSmrg 
64610d565efSmrg   for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
64710d565efSmrg     tgt_infos[i] = gi_ptr;
64810d565efSmrg 
64910d565efSmrg   tgt_tail = tgt_infos[tgt_cnt - 1];
65010d565efSmrg 
65110d565efSmrg   /* First pass on tgt_profile, we multiply w1 to all counters.  */
65210d565efSmrg   if (w1 > 1)
65310d565efSmrg     {
65410d565efSmrg        for (i = 0; i < tgt_cnt; i++)
65510d565efSmrg          gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
65610d565efSmrg     }
65710d565efSmrg 
65810d565efSmrg   /* Second pass, add src_profile to the tgt_profile.  */
65910d565efSmrg   for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
66010d565efSmrg     {
66110d565efSmrg       struct gcov_info *gi_ptr1;
66210d565efSmrg 
66310d565efSmrg       gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
66410d565efSmrg       if (gi_ptr1 == NULL)
66510d565efSmrg         {
66610d565efSmrg           in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
66710d565efSmrg           continue;
66810d565efSmrg         }
66910d565efSmrg       gcov_merge (gi_ptr1, gi_ptr, w2);
67010d565efSmrg     }
67110d565efSmrg 
67210d565efSmrg   /* For modules in src but not in tgt. We adjust the counter and append.  */
67310d565efSmrg   for (i = 0; i < unmatch_info_cnt; i++)
67410d565efSmrg     {
67510d565efSmrg       gi_ptr = in_src_not_tgt[i];
67610d565efSmrg       gcov_merge (gi_ptr, gi_ptr, w2 - 1);
67710d565efSmrg       gi_ptr->next = NULL;
67810d565efSmrg       tgt_tail->next = gi_ptr;
67910d565efSmrg       tgt_tail = gi_ptr;
68010d565efSmrg     }
68110d565efSmrg 
682*ec02198aSmrg   free (in_src_not_tgt);
683*ec02198aSmrg   free (tgt_infos);
684*ec02198aSmrg 
68510d565efSmrg   return 0;
68610d565efSmrg }
68710d565efSmrg 
68810d565efSmrg typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
68910d565efSmrg 
69010d565efSmrg /* Performing FN upon arc counters.  */
69110d565efSmrg 
69210d565efSmrg static void
__gcov_add_counter_op(gcov_type * counters,unsigned n_counters,counter_op_fn fn,void * data1,void * data2)69310d565efSmrg __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
69410d565efSmrg                        counter_op_fn fn, void *data1, void *data2)
69510d565efSmrg {
69610d565efSmrg   for (; n_counters; counters++, n_counters--)
69710d565efSmrg     {
69810d565efSmrg       gcov_type val = *counters;
69910d565efSmrg       *counters = fn(val, data1, data2);
70010d565efSmrg     }
70110d565efSmrg }
70210d565efSmrg 
70310d565efSmrg /* Performing FN upon ior counters.  */
70410d565efSmrg 
70510d565efSmrg 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)70610d565efSmrg __gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
70710d565efSmrg                        unsigned n_counters ATTRIBUTE_UNUSED,
70810d565efSmrg                        counter_op_fn fn ATTRIBUTE_UNUSED,
70910d565efSmrg                        void *data1 ATTRIBUTE_UNUSED,
71010d565efSmrg                        void *data2 ATTRIBUTE_UNUSED)
71110d565efSmrg {
71210d565efSmrg   /* Do nothing.  */
71310d565efSmrg }
71410d565efSmrg 
71510d565efSmrg /* Performing FN upon time-profile counters.  */
71610d565efSmrg 
71710d565efSmrg 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)71810d565efSmrg __gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
71910d565efSmrg                                 unsigned n_counters ATTRIBUTE_UNUSED,
72010d565efSmrg                                 counter_op_fn fn ATTRIBUTE_UNUSED,
72110d565efSmrg                                 void *data1 ATTRIBUTE_UNUSED,
72210d565efSmrg                                 void *data2 ATTRIBUTE_UNUSED)
72310d565efSmrg {
72410d565efSmrg   /* Do nothing.  */
72510d565efSmrg }
72610d565efSmrg 
727*ec02198aSmrg /* Performing FN upon TOP N counters.  */
72810d565efSmrg 
72910d565efSmrg static void
__gcov_topn_counter_op(gcov_type * counters,unsigned n_counters,counter_op_fn fn,void * data1,void * data2)730*ec02198aSmrg __gcov_topn_counter_op (gcov_type *counters, unsigned n_counters,
73110d565efSmrg 			counter_op_fn fn, void *data1, void *data2)
73210d565efSmrg {
73310d565efSmrg   unsigned i, n_measures;
73410d565efSmrg 
73510d565efSmrg   gcc_assert (!(n_counters % 3));
73610d565efSmrg   n_measures = n_counters / 3;
73710d565efSmrg   for (i = 0; i < n_measures; i++, counters += 3)
73810d565efSmrg     {
73910d565efSmrg       counters[1] = fn (counters[1], data1, data2);
74010d565efSmrg       counters[2] = fn (counters[2], data1, data2);
74110d565efSmrg     }
74210d565efSmrg }
74310d565efSmrg 
74410d565efSmrg /* Scaling the counter value V by multiplying *(float*) DATA1.  */
74510d565efSmrg 
74610d565efSmrg static gcov_type
fp_scale(gcov_type v,void * data1,void * data2 ATTRIBUTE_UNUSED)74710d565efSmrg fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
74810d565efSmrg {
74910d565efSmrg   float f = *(float *) data1;
75010d565efSmrg   return (gcov_type) (v * f);
75110d565efSmrg }
75210d565efSmrg 
75310d565efSmrg /* Scaling the counter value V by multiplying DATA2/DATA1.  */
75410d565efSmrg 
75510d565efSmrg static gcov_type
int_scale(gcov_type v,void * data1,void * data2)75610d565efSmrg int_scale (gcov_type v, void *data1, void *data2)
75710d565efSmrg {
75810d565efSmrg   int n = *(int *) data1;
75910d565efSmrg   int d = *(int *) data2;
76010d565efSmrg   return (gcov_type) ( RDIV (v,d) * n);
76110d565efSmrg }
76210d565efSmrg 
76310d565efSmrg /* Type of function used to process counters.  */
76410d565efSmrg typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
76510d565efSmrg                           counter_op_fn, void *, void *);
76610d565efSmrg 
76710d565efSmrg /* Function array to process profile counters.  */
76810d565efSmrg #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
76910d565efSmrg   __gcov ## FN_TYPE ## _counter_op,
77010d565efSmrg static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
77110d565efSmrg #include "gcov-counter.def"
77210d565efSmrg };
77310d565efSmrg #undef DEF_GCOV_COUNTER
77410d565efSmrg 
77510d565efSmrg /* Driver for scaling profile counters.  */
77610d565efSmrg 
77710d565efSmrg int
gcov_profile_scale(struct gcov_info * profile,float scale_factor,int n,int d)77810d565efSmrg gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
77910d565efSmrg {
78010d565efSmrg   struct gcov_info *gi_ptr;
78110d565efSmrg   unsigned f_ix;
78210d565efSmrg 
78310d565efSmrg   if (verbose)
78410d565efSmrg     fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
78510d565efSmrg 
78610d565efSmrg   /* Scaling the counters.  */
78710d565efSmrg   for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
78810d565efSmrg     for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
78910d565efSmrg       {
79010d565efSmrg         unsigned t_ix;
79110d565efSmrg         const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
79210d565efSmrg         const struct gcov_ctr_info *ci_ptr;
79310d565efSmrg 
79410d565efSmrg         if (!gfi_ptr || gfi_ptr->key != gi_ptr)
79510d565efSmrg           continue;
79610d565efSmrg 
79710d565efSmrg         ci_ptr = gfi_ptr->ctrs;
79810d565efSmrg         for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
79910d565efSmrg           {
80010d565efSmrg             gcov_merge_fn merge = gi_ptr->merge[t_ix];
80110d565efSmrg 
80210d565efSmrg             if (!merge)
80310d565efSmrg               continue;
80410d565efSmrg             if (d == 0)
80510d565efSmrg               (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
80610d565efSmrg                                       fp_scale, &scale_factor, NULL);
80710d565efSmrg             else
80810d565efSmrg               (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
80910d565efSmrg                                       int_scale, &n, &d);
81010d565efSmrg             ci_ptr++;
81110d565efSmrg           }
81210d565efSmrg       }
81310d565efSmrg 
81410d565efSmrg   return 0;
81510d565efSmrg }
81610d565efSmrg 
81710d565efSmrg /* Driver to normalize profile counters.  */
81810d565efSmrg 
81910d565efSmrg int
gcov_profile_normalize(struct gcov_info * profile,gcov_type max_val)82010d565efSmrg gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
82110d565efSmrg {
82210d565efSmrg   struct gcov_info *gi_ptr;
82310d565efSmrg   gcov_type curr_max_val = 0;
82410d565efSmrg   unsigned f_ix;
82510d565efSmrg   unsigned int i;
82610d565efSmrg   float scale_factor;
82710d565efSmrg 
82810d565efSmrg   /* Find the largest count value.  */
82910d565efSmrg   for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
83010d565efSmrg     for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
83110d565efSmrg       {
83210d565efSmrg         unsigned t_ix;
83310d565efSmrg         const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
83410d565efSmrg         const struct gcov_ctr_info *ci_ptr;
83510d565efSmrg 
83610d565efSmrg         if (!gfi_ptr || gfi_ptr->key != gi_ptr)
83710d565efSmrg           continue;
83810d565efSmrg 
83910d565efSmrg         ci_ptr = gfi_ptr->ctrs;
84010d565efSmrg         for (t_ix = 0; t_ix < 1; t_ix++)
84110d565efSmrg           {
84210d565efSmrg             for (i = 0; i < ci_ptr->num; i++)
84310d565efSmrg               if (ci_ptr->values[i] > curr_max_val)
84410d565efSmrg                 curr_max_val = ci_ptr->values[i];
84510d565efSmrg             ci_ptr++;
84610d565efSmrg           }
84710d565efSmrg       }
84810d565efSmrg 
84910d565efSmrg   scale_factor = (float)max_val / curr_max_val;
85010d565efSmrg   if (verbose)
85110d565efSmrg     fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
85210d565efSmrg 
85310d565efSmrg   return gcov_profile_scale (profile, scale_factor, 0, 0);
85410d565efSmrg }
85510d565efSmrg 
85610d565efSmrg /* The following variables are defined in gcc/gcov-tool.c.  */
85710d565efSmrg extern int overlap_func_level;
85810d565efSmrg extern int overlap_obj_level;
85910d565efSmrg extern int overlap_hot_only;
86010d565efSmrg extern int overlap_use_fullname;
86110d565efSmrg extern double overlap_hot_threshold;
86210d565efSmrg 
86310d565efSmrg /* Compute the overlap score of two values. The score is defined as:
86410d565efSmrg     min (V1/SUM_1, V2/SUM_2)  */
86510d565efSmrg 
86610d565efSmrg static double
calculate_2_entries(const unsigned long v1,const unsigned long v2,const double sum_1,const double sum_2)86710d565efSmrg calculate_2_entries (const unsigned long v1, const unsigned long v2,
86810d565efSmrg                      const double sum_1, const double sum_2)
86910d565efSmrg {
87010d565efSmrg   double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
87110d565efSmrg   double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
87210d565efSmrg 
87310d565efSmrg   if (val2 < val1)
87410d565efSmrg     val1 = val2;
87510d565efSmrg 
87610d565efSmrg   return val1;
87710d565efSmrg }
87810d565efSmrg 
87910d565efSmrg /*  Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
88010d565efSmrg     This function also updates cumulative score CUM_1_RESULT and
88110d565efSmrg     CUM_2_RESULT.  */
88210d565efSmrg 
88310d565efSmrg 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)88410d565efSmrg compute_one_gcov (const struct gcov_info *gcov_info1,
88510d565efSmrg                   const struct gcov_info *gcov_info2,
88610d565efSmrg                   const double sum_1, const double sum_2,
88710d565efSmrg                   double *cum_1_result, double *cum_2_result)
88810d565efSmrg {
88910d565efSmrg   unsigned f_ix;
89010d565efSmrg   double ret = 0;
89110d565efSmrg   double cum_1 = 0, cum_2 = 0;
89210d565efSmrg   const struct gcov_info *gcov_info = 0;
89310d565efSmrg   double *cum_p;
89410d565efSmrg   double sum;
89510d565efSmrg 
89610d565efSmrg   gcc_assert (gcov_info1 || gcov_info2);
89710d565efSmrg   if (!gcov_info1)
89810d565efSmrg     {
89910d565efSmrg       gcov_info = gcov_info2;
90010d565efSmrg       cum_p = cum_2_result;
90110d565efSmrg       sum = sum_2;
90210d565efSmrg       *cum_1_result = 0;
90310d565efSmrg     } else
90410d565efSmrg   if (!gcov_info2)
90510d565efSmrg     {
90610d565efSmrg       gcov_info = gcov_info1;
90710d565efSmrg       cum_p = cum_1_result;
90810d565efSmrg       sum = sum_1;
90910d565efSmrg       *cum_2_result = 0;
91010d565efSmrg     }
91110d565efSmrg 
91210d565efSmrg   if (gcov_info)
91310d565efSmrg   {
91410d565efSmrg     for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
91510d565efSmrg       {
91610d565efSmrg         const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
91710d565efSmrg         if (!gfi_ptr || gfi_ptr->key != gcov_info)
91810d565efSmrg           continue;
91910d565efSmrg         const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
92010d565efSmrg 	unsigned c_num;
92110d565efSmrg 	for (c_num = 0; c_num < ci_ptr->num; c_num++)
92210d565efSmrg 	  cum_1 += ci_ptr->values[c_num] / sum;
92310d565efSmrg       }
92410d565efSmrg     *cum_p = cum_1;
92510d565efSmrg     return 0.0;
92610d565efSmrg   }
92710d565efSmrg 
92810d565efSmrg   for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
92910d565efSmrg     {
93010d565efSmrg       double func_cum_1 = 0.0;
93110d565efSmrg       double func_cum_2 = 0.0;
93210d565efSmrg       double func_val = 0.0;
93310d565efSmrg       int nonzero = 0;
93410d565efSmrg       int hot = 0;
93510d565efSmrg       const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
93610d565efSmrg       const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
93710d565efSmrg 
93810d565efSmrg       if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
93910d565efSmrg         continue;
94010d565efSmrg       if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
94110d565efSmrg         continue;
94210d565efSmrg 
94310d565efSmrg       const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
94410d565efSmrg       const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
94510d565efSmrg       unsigned c_num;
94610d565efSmrg       for (c_num = 0; c_num < ci_ptr1->num; c_num++)
94710d565efSmrg 	{
94810d565efSmrg 	  if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
94910d565efSmrg 	    {
95010d565efSmrg 	      func_val += calculate_2_entries (ci_ptr1->values[c_num],
95110d565efSmrg 					       ci_ptr2->values[c_num],
95210d565efSmrg 					       sum_1, sum_2);
95310d565efSmrg 
95410d565efSmrg 	      func_cum_1 += ci_ptr1->values[c_num] / sum_1;
95510d565efSmrg 	      func_cum_2 += ci_ptr2->values[c_num] / sum_2;
95610d565efSmrg 	      nonzero = 1;
9570fc04c29Smrg 	      if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
9580fc04c29Smrg 		  || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
95910d565efSmrg 		hot = 1;
96010d565efSmrg 	    }
96110d565efSmrg 	}
9620fc04c29Smrg 
96310d565efSmrg       ret += func_val;
96410d565efSmrg       cum_1 += func_cum_1;
96510d565efSmrg       cum_2 += func_cum_2;
96610d565efSmrg       if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
96710d565efSmrg         {
96810d565efSmrg           printf("   \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
96910d565efSmrg                  gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
97010d565efSmrg         }
97110d565efSmrg     }
97210d565efSmrg   *cum_1_result = cum_1;
97310d565efSmrg   *cum_2_result = cum_2;
97410d565efSmrg   return ret;
97510d565efSmrg }
97610d565efSmrg 
97710d565efSmrg /* Test if all counter values in this GCOV_INFO are cold.
97810d565efSmrg    "Cold" is defined as the counter value being less than
97910d565efSmrg    or equal to THRESHOLD.  */
98010d565efSmrg 
98110d565efSmrg static bool
gcov_info_count_all_cold(const struct gcov_info * gcov_info,gcov_type threshold)98210d565efSmrg gcov_info_count_all_cold (const struct gcov_info *gcov_info,
98310d565efSmrg                           gcov_type threshold)
98410d565efSmrg {
98510d565efSmrg   unsigned f_ix;
98610d565efSmrg 
98710d565efSmrg   for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
98810d565efSmrg     {
98910d565efSmrg       const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
99010d565efSmrg 
99110d565efSmrg       if (!gfi_ptr || gfi_ptr->key != gcov_info)
99210d565efSmrg         continue;
99310d565efSmrg       const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
9940fc04c29Smrg       for (unsigned c_num = 0; c_num < ci_ptr->num; c_num++)
99510d565efSmrg 	if (ci_ptr->values[c_num] > threshold)
99610d565efSmrg 	  return false;
99710d565efSmrg     }
99810d565efSmrg 
99910d565efSmrg   return true;
100010d565efSmrg }
100110d565efSmrg 
100210d565efSmrg /* Test if all counter values in this GCOV_INFO are 0.  */
100310d565efSmrg 
100410d565efSmrg static bool
gcov_info_count_all_zero(const struct gcov_info * gcov_info)100510d565efSmrg gcov_info_count_all_zero (const struct gcov_info *gcov_info)
100610d565efSmrg {
100710d565efSmrg   return gcov_info_count_all_cold (gcov_info, 0);
100810d565efSmrg }
100910d565efSmrg 
101010d565efSmrg /* A pair of matched GCOV_INFO.
101110d565efSmrg    The flag is a bitvector:
101210d565efSmrg      b0: obj1's all counts are 0;
101310d565efSmrg      b1: obj1's all counts are cold (but no 0);
101410d565efSmrg      b2: obj1 is hot;
101510d565efSmrg      b3: no obj1 to match obj2;
101610d565efSmrg      b4: obj2's all counts are 0;
101710d565efSmrg      b5: obj2's all counts are cold (but no 0);
101810d565efSmrg      b6: obj2 is hot;
101910d565efSmrg      b7: no obj2 to match obj1;
102010d565efSmrg  */
102110d565efSmrg struct overlap_t {
102210d565efSmrg    const struct gcov_info *obj1;
102310d565efSmrg    const struct gcov_info *obj2;
102410d565efSmrg    char flag;
102510d565efSmrg };
102610d565efSmrg 
102710d565efSmrg #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
102810d565efSmrg #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
102910d565efSmrg #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
103010d565efSmrg 
103110d565efSmrg /* Cumlative overlap dscore for profile1 and profile2.  */
103210d565efSmrg static double overlap_sum_1, overlap_sum_2;
103310d565efSmrg 
103410d565efSmrg /* The number of gcda files in the profiles.  */
103510d565efSmrg static unsigned gcda_files[2];
103610d565efSmrg 
103710d565efSmrg /* The number of unique gcda files in the profiles
103810d565efSmrg    (not existing in the other profile).  */
103910d565efSmrg static unsigned unique_gcda_files[2];
104010d565efSmrg 
104110d565efSmrg /* The number of gcda files that all counter values are 0.  */
104210d565efSmrg static unsigned zero_gcda_files[2];
104310d565efSmrg 
104410d565efSmrg /* The number of gcda files that all counter values are cold (but not 0).  */
104510d565efSmrg static unsigned cold_gcda_files[2];
104610d565efSmrg 
104710d565efSmrg /* The number of gcda files that includes hot counter values.  */
104810d565efSmrg static unsigned hot_gcda_files[2];
104910d565efSmrg 
105010d565efSmrg /* The number of gcda files with hot count value in either profiles.  */
105110d565efSmrg static unsigned both_hot_cnt;
105210d565efSmrg 
105310d565efSmrg /* The number of gcda files with all counts cold (but not 0) in
105410d565efSmrg    both profiles. */
105510d565efSmrg static unsigned both_cold_cnt;
105610d565efSmrg 
105710d565efSmrg /* The number of gcda files with all counts 0 in both profiles.  */
105810d565efSmrg static unsigned both_zero_cnt;
105910d565efSmrg 
106010d565efSmrg /* Extract the basename of the filename NAME.  */
106110d565efSmrg 
106210d565efSmrg static char *
extract_file_basename(const char * name)106310d565efSmrg extract_file_basename (const char *name)
106410d565efSmrg {
106510d565efSmrg   char *str;
106610d565efSmrg   int len = 0;
106710d565efSmrg   char *path = xstrdup (name);
106810d565efSmrg   char sep_str[2];
106910d565efSmrg 
107010d565efSmrg   sep_str[0] = DIR_SEPARATOR;
107110d565efSmrg   sep_str[1] = 0;
107210d565efSmrg   str = strstr(path, sep_str);
107310d565efSmrg   do{
107410d565efSmrg       len = strlen(str) + 1;
107510d565efSmrg       path = &path[strlen(path) - len + 2];
107610d565efSmrg       str = strstr(path, sep_str);
107710d565efSmrg   } while(str);
107810d565efSmrg 
107910d565efSmrg   return path;
108010d565efSmrg }
108110d565efSmrg 
108210d565efSmrg /* Utility function to get the filename.  */
108310d565efSmrg 
108410d565efSmrg static const char *
get_file_basename(const char * name)108510d565efSmrg get_file_basename (const char *name)
108610d565efSmrg {
108710d565efSmrg   if (overlap_use_fullname)
108810d565efSmrg     return name;
108910d565efSmrg   return extract_file_basename (name);
109010d565efSmrg }
109110d565efSmrg 
109210d565efSmrg /* A utility function to set the flag for the gcda files.  */
109310d565efSmrg 
109410d565efSmrg static void
set_flag(struct overlap_t * e)109510d565efSmrg set_flag (struct overlap_t *e)
109610d565efSmrg {
109710d565efSmrg   char flag = 0;
109810d565efSmrg 
109910d565efSmrg   if (!e->obj1)
110010d565efSmrg     {
110110d565efSmrg       unique_gcda_files[1]++;
110210d565efSmrg       flag = 0x8;
110310d565efSmrg     }
110410d565efSmrg   else
110510d565efSmrg     {
110610d565efSmrg       gcda_files[0]++;
110710d565efSmrg       if (gcov_info_count_all_zero (e->obj1))
110810d565efSmrg         {
110910d565efSmrg           zero_gcda_files[0]++;
111010d565efSmrg           flag = 0x1;
111110d565efSmrg         }
111210d565efSmrg       else
111310d565efSmrg       if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
111410d565efSmrg 			      * overlap_hot_threshold))
111510d565efSmrg         {
111610d565efSmrg           cold_gcda_files[0]++;
111710d565efSmrg           flag = 0x2;
111810d565efSmrg         }
111910d565efSmrg       else
112010d565efSmrg         {
112110d565efSmrg           hot_gcda_files[0]++;
112210d565efSmrg           flag = 0x4;
112310d565efSmrg         }
112410d565efSmrg     }
112510d565efSmrg 
112610d565efSmrg   if (!e->obj2)
112710d565efSmrg     {
112810d565efSmrg       unique_gcda_files[0]++;
112910d565efSmrg       flag |= (0x8 << 4);
113010d565efSmrg     }
113110d565efSmrg   else
113210d565efSmrg     {
113310d565efSmrg       gcda_files[1]++;
113410d565efSmrg       if (gcov_info_count_all_zero (e->obj2))
113510d565efSmrg         {
113610d565efSmrg           zero_gcda_files[1]++;
113710d565efSmrg           flag |= (0x1 << 4);
113810d565efSmrg         }
113910d565efSmrg       else
114010d565efSmrg       if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
114110d565efSmrg 			      * overlap_hot_threshold))
114210d565efSmrg         {
114310d565efSmrg           cold_gcda_files[1]++;
114410d565efSmrg           flag |= (0x2 << 4);
114510d565efSmrg         }
114610d565efSmrg       else
114710d565efSmrg         {
114810d565efSmrg           hot_gcda_files[1]++;
114910d565efSmrg           flag |= (0x4 << 4);
115010d565efSmrg         }
115110d565efSmrg     }
115210d565efSmrg 
115310d565efSmrg   gcc_assert (flag);
115410d565efSmrg   e->flag = flag;
115510d565efSmrg }
115610d565efSmrg 
115710d565efSmrg /* Test if INFO1 and INFO2 are from the matched source file.
115810d565efSmrg    Return 1 if they match; return 0 otherwise.  */
115910d565efSmrg 
116010d565efSmrg static int
matched_gcov_info(const struct gcov_info * info1,const struct gcov_info * info2)116110d565efSmrg matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
116210d565efSmrg {
116310d565efSmrg   /* For FDO, we have to match the name. This can be expensive.
116410d565efSmrg      Maybe we should use hash here.  */
116510d565efSmrg   if (strcmp (info1->filename, info2->filename))
116610d565efSmrg     return 0;
116710d565efSmrg 
116810d565efSmrg   if (info1->n_functions != info2->n_functions)
116910d565efSmrg     {
117010d565efSmrg       fnotice (stderr, "mismatched profiles in %s (%d functions"
117110d565efSmrg                        " vs %d functions)\n",
117210d565efSmrg                        info1->filename,
117310d565efSmrg                        info1->n_functions,
117410d565efSmrg                        info2->n_functions);
117510d565efSmrg       return 0;
117610d565efSmrg     }
117710d565efSmrg   return 1;
117810d565efSmrg }
117910d565efSmrg 
118010d565efSmrg /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
118110d565efSmrg    GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
118210d565efSmrg    match and 1.0 meaning a perfect match.  */
118310d565efSmrg 
118410d565efSmrg static double
calculate_overlap(struct gcov_info * gcov_list1,struct gcov_info * gcov_list2)118510d565efSmrg calculate_overlap (struct gcov_info *gcov_list1,
118610d565efSmrg                    struct gcov_info *gcov_list2)
118710d565efSmrg {
118810d565efSmrg   unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
118910d565efSmrg   unsigned int i, j;
119010d565efSmrg   const struct gcov_info *gi_ptr;
119110d565efSmrg   struct overlap_t *all_infos;
119210d565efSmrg 
119310d565efSmrg   for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
119410d565efSmrg     list1_cnt++;
119510d565efSmrg   for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
119610d565efSmrg     list2_cnt++;
119710d565efSmrg   all_cnt = list1_cnt + list2_cnt;
119810d565efSmrg   all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
119910d565efSmrg                * all_cnt * 2);
120010d565efSmrg   gcc_assert (all_infos);
120110d565efSmrg 
120210d565efSmrg   i = 0;
120310d565efSmrg   for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
120410d565efSmrg     {
120510d565efSmrg       all_infos[i].obj1 = gi_ptr;
120610d565efSmrg       all_infos[i].obj2 = 0;
120710d565efSmrg     }
120810d565efSmrg 
120910d565efSmrg   for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
121010d565efSmrg     {
121110d565efSmrg       all_infos[i].obj1 = 0;
121210d565efSmrg       all_infos[i].obj2 = gi_ptr;
121310d565efSmrg     }
121410d565efSmrg 
121510d565efSmrg   for (i = list1_cnt; i < all_cnt; i++)
121610d565efSmrg     {
121710d565efSmrg       if (all_infos[i].obj2 == 0)
121810d565efSmrg         continue;
121910d565efSmrg       for (j = 0; j < list1_cnt; j++)
122010d565efSmrg         {
122110d565efSmrg           if (all_infos[j].obj2 != 0)
122210d565efSmrg             continue;
122310d565efSmrg           if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
122410d565efSmrg             {
122510d565efSmrg               all_infos[j].obj2 = all_infos[i].obj2;
122610d565efSmrg               all_infos[i].obj2 = 0;
122710d565efSmrg               break;
122810d565efSmrg             }
122910d565efSmrg         }
123010d565efSmrg     }
123110d565efSmrg 
123210d565efSmrg   for (i = 0; i < all_cnt; i++)
123310d565efSmrg     if (all_infos[i].obj1 || all_infos[i].obj2)
123410d565efSmrg       {
123510d565efSmrg         set_flag (all_infos + i);
123610d565efSmrg         if (FLAG_ONE_HOT (all_infos[i].flag))
123710d565efSmrg             both_hot_cnt++;
123810d565efSmrg         if (FLAG_BOTH_COLD(all_infos[i].flag))
123910d565efSmrg             both_cold_cnt++;
124010d565efSmrg         if (FLAG_BOTH_ZERO(all_infos[i].flag))
124110d565efSmrg             both_zero_cnt++;
124210d565efSmrg       }
124310d565efSmrg 
124410d565efSmrg   double prg_val = 0;
124510d565efSmrg   double sum_val = 0;
124610d565efSmrg   double sum_cum_1 = 0;
124710d565efSmrg   double sum_cum_2 = 0;
124810d565efSmrg 
124910d565efSmrg   for (i = 0; i < all_cnt; i++)
125010d565efSmrg     {
125110d565efSmrg       double val;
125210d565efSmrg       double cum_1, cum_2;
125310d565efSmrg       const char *filename;
125410d565efSmrg 
125510d565efSmrg       if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
125610d565efSmrg         continue;
125710d565efSmrg       if (FLAG_BOTH_ZERO (all_infos[i].flag))
125810d565efSmrg           continue;
125910d565efSmrg 
126010d565efSmrg       if (all_infos[i].obj1)
126110d565efSmrg         filename = get_file_basename (all_infos[i].obj1->filename);
126210d565efSmrg       else
126310d565efSmrg         filename = get_file_basename (all_infos[i].obj2->filename);
126410d565efSmrg 
126510d565efSmrg       if (overlap_func_level)
126610d565efSmrg         printf("\n   processing %36s:\n", filename);
126710d565efSmrg 
126810d565efSmrg       val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
126910d565efSmrg           overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
127010d565efSmrg 
127110d565efSmrg       if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
127210d565efSmrg         {
127310d565efSmrg           printf("   obj=%36s  overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
127410d565efSmrg                   filename, val*100, cum_1*100, cum_2*100);
127510d565efSmrg           sum_val += val;
127610d565efSmrg           sum_cum_1 += cum_1;
127710d565efSmrg           sum_cum_2 += cum_2;
127810d565efSmrg         }
127910d565efSmrg 
128010d565efSmrg       prg_val += val;
128110d565efSmrg 
128210d565efSmrg     }
128310d565efSmrg 
1284*ec02198aSmrg   free (all_infos);
1285*ec02198aSmrg 
128610d565efSmrg   if (overlap_obj_level)
128710d565efSmrg     printf("   SUM:%36s  overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
128810d565efSmrg            "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
128910d565efSmrg 
129010d565efSmrg   printf ("  Statistics:\n"
129110d565efSmrg           "                    profile1_#     profile2_#       overlap_#\n");
129210d565efSmrg   printf ("    gcda files:  %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
129310d565efSmrg 	  gcda_files[0]-unique_gcda_files[0]);
129410d565efSmrg   printf ("  unique files:  %12u\t%12u\n", unique_gcda_files[0],
129510d565efSmrg 	  unique_gcda_files[1]);
129610d565efSmrg   printf ("     hot files:  %12u\t%12u\t%12u\n", hot_gcda_files[0],
129710d565efSmrg 	  hot_gcda_files[1], both_hot_cnt);
129810d565efSmrg   printf ("    cold files:  %12u\t%12u\t%12u\n", cold_gcda_files[0],
129910d565efSmrg 	  cold_gcda_files[1], both_cold_cnt);
130010d565efSmrg   printf ("    zero files:  %12u\t%12u\t%12u\n", zero_gcda_files[0],
130110d565efSmrg 	  zero_gcda_files[1], both_zero_cnt);
130210d565efSmrg 
130310d565efSmrg   return prg_val;
130410d565efSmrg }
130510d565efSmrg 
130610d565efSmrg /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
130710d565efSmrg    PROFILE2.
130810d565efSmrg    Return 0 on success: without mismatch. Reutrn 1 on error.  */
130910d565efSmrg 
131010d565efSmrg int
gcov_profile_overlap(struct gcov_info * profile1,struct gcov_info * profile2)131110d565efSmrg gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
131210d565efSmrg {
131310d565efSmrg   double result;
131410d565efSmrg 
131510d565efSmrg   result = calculate_overlap (profile1, profile2);
131610d565efSmrg 
131710d565efSmrg   if (result > 0)
131810d565efSmrg     {
131910d565efSmrg       printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
132010d565efSmrg       return 0;
132110d565efSmrg     }
132210d565efSmrg   return 1;
132310d565efSmrg }
1324