xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/libgcov-util.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg /* Utility functions for reading gcda files into in-memory
21debfc3dSmrg    gcov_info structures and offline profile processing. */
3*8feb0f0bSmrg /* Copyright (C) 2014-2020 Free Software Foundation, Inc.
41debfc3dSmrg    Contributed by Rong Xu <xur@google.com>.
51debfc3dSmrg 
61debfc3dSmrg This file is part of GCC.
71debfc3dSmrg 
81debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
91debfc3dSmrg the terms of the GNU General Public License as published by the Free
101debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
111debfc3dSmrg version.
121debfc3dSmrg 
131debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
141debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
151debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
161debfc3dSmrg for more details.
171debfc3dSmrg 
181debfc3dSmrg Under Section 7 of GPL version 3, you are granted additional
191debfc3dSmrg permissions described in the GCC Runtime Library Exception, version
201debfc3dSmrg 3.1, as published by the Free Software Foundation.
211debfc3dSmrg 
221debfc3dSmrg You should have received a copy of the GNU General Public License and
231debfc3dSmrg a copy of the GCC Runtime Library Exception along with this program;
241debfc3dSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
251debfc3dSmrg <http://www.gnu.org/licenses/>.  */
261debfc3dSmrg 
271debfc3dSmrg 
281debfc3dSmrg #define IN_GCOV_TOOL 1
291debfc3dSmrg 
301debfc3dSmrg #include "libgcov.h"
311debfc3dSmrg #include "intl.h"
321debfc3dSmrg #include "diagnostic.h"
331debfc3dSmrg #include "version.h"
341debfc3dSmrg #include "demangle.h"
35c0a68be4Smrg #include "gcov-io.h"
361debfc3dSmrg 
371debfc3dSmrg /* Borrowed from basic-block.h.  */
381debfc3dSmrg #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
391debfc3dSmrg 
401debfc3dSmrg extern gcov_position_t gcov_position();
411debfc3dSmrg extern int gcov_is_error();
421debfc3dSmrg 
431debfc3dSmrg /* Verbose mode for debug.  */
441debfc3dSmrg static int verbose;
451debfc3dSmrg 
461debfc3dSmrg /* Set verbose flag.  */
gcov_set_verbose(void)471debfc3dSmrg void gcov_set_verbose (void)
481debfc3dSmrg {
491debfc3dSmrg   verbose = 1;
501debfc3dSmrg }
511debfc3dSmrg 
521debfc3dSmrg /* The following part is to read Gcda and reconstruct GCOV_INFO.  */
531debfc3dSmrg 
541debfc3dSmrg #include "obstack.h"
551debfc3dSmrg #include <unistd.h>
561debfc3dSmrg #ifdef HAVE_FTW_H
571debfc3dSmrg #include <ftw.h>
581debfc3dSmrg #endif
591debfc3dSmrg 
601debfc3dSmrg static void tag_function (unsigned, unsigned);
611debfc3dSmrg static void tag_blocks (unsigned, unsigned);
621debfc3dSmrg static void tag_arcs (unsigned, unsigned);
631debfc3dSmrg static void tag_lines (unsigned, unsigned);
641debfc3dSmrg static void tag_counters (unsigned, unsigned);
651debfc3dSmrg static void tag_summary (unsigned, unsigned);
661debfc3dSmrg 
671debfc3dSmrg /* The gcov_info for the first module.  */
681debfc3dSmrg static struct gcov_info *curr_gcov_info;
691debfc3dSmrg /* The gcov_info being processed.  */
701debfc3dSmrg static struct gcov_info *gcov_info_head;
711debfc3dSmrg /* This variable contains all the functions in current module.  */
721debfc3dSmrg static struct obstack fn_info;
731debfc3dSmrg /* The function being processed.  */
741debfc3dSmrg static struct gcov_fn_info *curr_fn_info;
751debfc3dSmrg /* The number of functions seen so far.  */
761debfc3dSmrg static unsigned num_fn_info;
771debfc3dSmrg /* This variable contains all the counters for current module.  */
781debfc3dSmrg static int k_ctrs_mask[GCOV_COUNTERS];
791debfc3dSmrg /* The kind of counters that have been seen.  */
801debfc3dSmrg static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
811debfc3dSmrg /* Number of kind of counters that have been seen.  */
821debfc3dSmrg static int k_ctrs_types;
83c0a68be4Smrg /* The object summary being processed.  */
84c0a68be4Smrg static struct gcov_summary *curr_object_summary;
851debfc3dSmrg 
861debfc3dSmrg /* Merge functions for counters.  */
871debfc3dSmrg #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
881debfc3dSmrg static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
891debfc3dSmrg #include "gcov-counter.def"
901debfc3dSmrg };
911debfc3dSmrg #undef DEF_GCOV_COUNTER
921debfc3dSmrg 
931debfc3dSmrg /* Set the ctrs field in gcov_fn_info object FN_INFO.  */
941debfc3dSmrg 
951debfc3dSmrg static void
set_fn_ctrs(struct gcov_fn_info * fn_info)961debfc3dSmrg set_fn_ctrs (struct gcov_fn_info *fn_info)
971debfc3dSmrg {
981debfc3dSmrg   int j = 0, i;
991debfc3dSmrg 
1001debfc3dSmrg   for (i = 0; i < GCOV_COUNTERS; i++)
1011debfc3dSmrg     {
1021debfc3dSmrg       if (k_ctrs_mask[i] == 0)
1031debfc3dSmrg         continue;
1041debfc3dSmrg       fn_info->ctrs[j].num = k_ctrs[i].num;
1051debfc3dSmrg       fn_info->ctrs[j].values = k_ctrs[i].values;
1061debfc3dSmrg       j++;
1071debfc3dSmrg     }
1081debfc3dSmrg   if (k_ctrs_types == 0)
1091debfc3dSmrg     k_ctrs_types = j;
1101debfc3dSmrg   else
1111debfc3dSmrg     gcc_assert (j == k_ctrs_types);
1121debfc3dSmrg }
1131debfc3dSmrg 
1141debfc3dSmrg /* For each tag in gcda file, we have an entry here.
1151debfc3dSmrg    TAG is the tag value; NAME is the tag name; and
1161debfc3dSmrg    PROC is the handler function.  */
1171debfc3dSmrg 
1181debfc3dSmrg typedef struct tag_format
1191debfc3dSmrg {
1201debfc3dSmrg     unsigned tag;
1211debfc3dSmrg     char const *name;
1221debfc3dSmrg     void (*proc) (unsigned, unsigned);
1231debfc3dSmrg } tag_format_t;
1241debfc3dSmrg 
1251debfc3dSmrg /* Handler table for various Tags.  */
1261debfc3dSmrg 
1271debfc3dSmrg static const tag_format_t tag_table[] =
1281debfc3dSmrg {
1291debfc3dSmrg   {0, "NOP", NULL},
1301debfc3dSmrg   {0, "UNKNOWN", NULL},
1311debfc3dSmrg   {0, "COUNTERS", tag_counters},
1321debfc3dSmrg   {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
1331debfc3dSmrg   {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
1341debfc3dSmrg   {GCOV_TAG_ARCS, "ARCS", tag_arcs},
1351debfc3dSmrg   {GCOV_TAG_LINES, "LINES", tag_lines},
1361debfc3dSmrg   {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
1371debfc3dSmrg   {0, NULL, NULL}
1381debfc3dSmrg };
1391debfc3dSmrg 
1401debfc3dSmrg /* Handler for reading function tag.  */
1411debfc3dSmrg 
1421debfc3dSmrg static void
tag_function(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)1431debfc3dSmrg tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
1441debfc3dSmrg {
1451debfc3dSmrg   int i;
1461debfc3dSmrg 
1471debfc3dSmrg   /* write out previous fn_info.  */
1481debfc3dSmrg   if (num_fn_info)
1491debfc3dSmrg     {
1501debfc3dSmrg       set_fn_ctrs (curr_fn_info);
1511debfc3dSmrg       obstack_ptr_grow (&fn_info, curr_fn_info);
1521debfc3dSmrg     }
1531debfc3dSmrg 
1541debfc3dSmrg   /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
1551debfc3dSmrg      counter types.  */
1561debfc3dSmrg   curr_fn_info = (struct gcov_fn_info *) xcalloc (sizeof (struct gcov_fn_info)
1571debfc3dSmrg                    + GCOV_COUNTERS * sizeof (struct gcov_ctr_info), 1);
1581debfc3dSmrg 
1591debfc3dSmrg   for (i = 0; i < GCOV_COUNTERS; i++)
1601debfc3dSmrg      k_ctrs[i].num = 0;
1611debfc3dSmrg   k_ctrs_types = 0;
1621debfc3dSmrg 
1631debfc3dSmrg   curr_fn_info->key = curr_gcov_info;
1641debfc3dSmrg   curr_fn_info->ident = gcov_read_unsigned ();
1651debfc3dSmrg   curr_fn_info->lineno_checksum = gcov_read_unsigned ();
1661debfc3dSmrg   curr_fn_info->cfg_checksum = gcov_read_unsigned ();
1671debfc3dSmrg   num_fn_info++;
1681debfc3dSmrg 
1691debfc3dSmrg   if (verbose)
1701debfc3dSmrg     fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
1711debfc3dSmrg }
1721debfc3dSmrg 
1731debfc3dSmrg /* Handler for reading block tag.  */
1741debfc3dSmrg 
1751debfc3dSmrg static void
tag_blocks(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)1761debfc3dSmrg tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
1771debfc3dSmrg {
1781debfc3dSmrg   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
1791debfc3dSmrg   gcc_unreachable ();
1801debfc3dSmrg }
1811debfc3dSmrg 
1821debfc3dSmrg /* Handler for reading flow arc tag.  */
1831debfc3dSmrg 
1841debfc3dSmrg static void
tag_arcs(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)1851debfc3dSmrg tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
1861debfc3dSmrg {
1871debfc3dSmrg   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
1881debfc3dSmrg   gcc_unreachable ();
1891debfc3dSmrg }
1901debfc3dSmrg 
1911debfc3dSmrg /* Handler for reading line tag.  */
1921debfc3dSmrg 
1931debfc3dSmrg static void
tag_lines(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)1941debfc3dSmrg tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
1951debfc3dSmrg {
1961debfc3dSmrg   /* TBD: gcov-tool currently does not handle gcno files. Assert here.  */
1971debfc3dSmrg   gcc_unreachable ();
1981debfc3dSmrg }
1991debfc3dSmrg 
2001debfc3dSmrg /* Handler for reading counters array tag with value as TAG and length of LENGTH.  */
2011debfc3dSmrg 
2021debfc3dSmrg static void
tag_counters(unsigned tag,unsigned length)2031debfc3dSmrg tag_counters (unsigned tag, unsigned length)
2041debfc3dSmrg {
2051debfc3dSmrg   unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
2061debfc3dSmrg   gcov_type *values;
2071debfc3dSmrg   unsigned ix;
2081debfc3dSmrg   unsigned tag_ix;
2091debfc3dSmrg 
2101debfc3dSmrg   tag_ix = GCOV_COUNTER_FOR_TAG (tag);
2111debfc3dSmrg   gcc_assert (tag_ix < GCOV_COUNTERS);
2121debfc3dSmrg   k_ctrs_mask [tag_ix] = 1;
2131debfc3dSmrg   gcc_assert (k_ctrs[tag_ix].num == 0);
2141debfc3dSmrg   k_ctrs[tag_ix].num = n_counts;
2151debfc3dSmrg 
2161debfc3dSmrg   k_ctrs[tag_ix].values = values = (gcov_type *) xmalloc (n_counts * sizeof (gcov_type));
2171debfc3dSmrg   gcc_assert (values);
2181debfc3dSmrg 
2191debfc3dSmrg   for (ix = 0; ix != n_counts; ix++)
2201debfc3dSmrg     values[ix] = gcov_read_counter ();
2211debfc3dSmrg }
2221debfc3dSmrg 
2231debfc3dSmrg /* Handler for reading summary tag.  */
2241debfc3dSmrg 
2251debfc3dSmrg static void
tag_summary(unsigned tag ATTRIBUTE_UNUSED,unsigned length ATTRIBUTE_UNUSED)2261debfc3dSmrg tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
2271debfc3dSmrg {
228c0a68be4Smrg   curr_object_summary = (gcov_summary *) xcalloc (sizeof (gcov_summary), 1);
229c0a68be4Smrg   gcov_read_summary (curr_object_summary);
2301debfc3dSmrg }
2311debfc3dSmrg 
2321debfc3dSmrg /* This function is called at the end of reading a gcda file.
2331debfc3dSmrg    It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO.  */
2341debfc3dSmrg 
2351debfc3dSmrg static void
read_gcda_finalize(struct gcov_info * obj_info)2361debfc3dSmrg read_gcda_finalize (struct gcov_info *obj_info)
2371debfc3dSmrg {
2381debfc3dSmrg   int i;
2391debfc3dSmrg 
2401debfc3dSmrg   set_fn_ctrs (curr_fn_info);
2411debfc3dSmrg   obstack_ptr_grow (&fn_info, curr_fn_info);
2421debfc3dSmrg 
243c0a68be4Smrg   /* We set the following fields: merge, n_functions, functions
244c0a68be4Smrg      and summary.  */
2451debfc3dSmrg   obj_info->n_functions = num_fn_info;
2461debfc3dSmrg   obj_info->functions = (const struct gcov_fn_info**) obstack_finish (&fn_info);
2471debfc3dSmrg 
2481debfc3dSmrg   /* wrap all the counter array.  */
2491debfc3dSmrg   for (i=0; i< GCOV_COUNTERS; i++)
2501debfc3dSmrg     {
2511debfc3dSmrg       if (k_ctrs_mask[i])
2521debfc3dSmrg         obj_info->merge[i] = ctr_merge_functions[i];
2531debfc3dSmrg     }
2541debfc3dSmrg }
2551debfc3dSmrg 
2561debfc3dSmrg /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
2571debfc3dSmrg    Program level summary CURRENT_SUMMARY will also be updated.  */
2581debfc3dSmrg 
2591debfc3dSmrg static struct gcov_info *
read_gcda_file(const char * filename)2601debfc3dSmrg read_gcda_file (const char *filename)
2611debfc3dSmrg {
2621debfc3dSmrg   unsigned tags[4];
2631debfc3dSmrg   unsigned depth = 0;
264*8feb0f0bSmrg   unsigned version;
2651debfc3dSmrg   struct gcov_info *obj_info;
2661debfc3dSmrg   int i;
2671debfc3dSmrg 
2681debfc3dSmrg   for (i=0; i< GCOV_COUNTERS; i++)
2691debfc3dSmrg     k_ctrs_mask[i] = 0;
2701debfc3dSmrg   k_ctrs_types = 0;
2711debfc3dSmrg 
2721debfc3dSmrg   if (!gcov_open (filename))
2731debfc3dSmrg     {
2741debfc3dSmrg       fnotice (stderr, "%s:cannot open\n", filename);
2751debfc3dSmrg       return NULL;
2761debfc3dSmrg     }
2771debfc3dSmrg 
2781debfc3dSmrg   /* Read magic.  */
279*8feb0f0bSmrg   if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
2801debfc3dSmrg     {
2811debfc3dSmrg       fnotice (stderr, "%s:not a gcov data file\n", filename);
2821debfc3dSmrg       gcov_close ();
2831debfc3dSmrg       return NULL;
2841debfc3dSmrg     }
2851debfc3dSmrg 
2861debfc3dSmrg   /* Read version.  */
2871debfc3dSmrg   version = gcov_read_unsigned ();
2881debfc3dSmrg   if (version != GCOV_VERSION)
2891debfc3dSmrg     {
2901debfc3dSmrg       fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
2911debfc3dSmrg       gcov_close ();
2921debfc3dSmrg       return NULL;
2931debfc3dSmrg     }
2941debfc3dSmrg 
2951debfc3dSmrg   /* Instantiate a gcov_info object.  */
2961debfc3dSmrg   curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
2971debfc3dSmrg              sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
2981debfc3dSmrg 
2991debfc3dSmrg   obj_info->version = version;
3001debfc3dSmrg   obstack_init (&fn_info);
3011debfc3dSmrg   num_fn_info = 0;
3021debfc3dSmrg   curr_fn_info = 0;
303c0a68be4Smrg   curr_object_summary = NULL;
3041debfc3dSmrg   {
3051debfc3dSmrg     size_t len = strlen (filename) + 1;
3061debfc3dSmrg     char *str_dup = (char*) xmalloc (len);
3071debfc3dSmrg 
3081debfc3dSmrg     memcpy (str_dup, filename, len);
3091debfc3dSmrg     obj_info->filename = str_dup;
3101debfc3dSmrg   }
3111debfc3dSmrg 
3121debfc3dSmrg   /* Read stamp.  */
3131debfc3dSmrg   obj_info->stamp = gcov_read_unsigned ();
3141debfc3dSmrg 
3151debfc3dSmrg   while (1)
3161debfc3dSmrg     {
3171debfc3dSmrg       gcov_position_t base;
3181debfc3dSmrg       unsigned tag, length;
3191debfc3dSmrg       tag_format_t const *format;
3201debfc3dSmrg       unsigned tag_depth;
3211debfc3dSmrg       int error;
3221debfc3dSmrg       unsigned mask;
3231debfc3dSmrg 
3241debfc3dSmrg       tag = gcov_read_unsigned ();
3251debfc3dSmrg       if (!tag)
3261debfc3dSmrg         break;
3271debfc3dSmrg       length = gcov_read_unsigned ();
3281debfc3dSmrg       base = gcov_position ();
3291debfc3dSmrg       mask = GCOV_TAG_MASK (tag) >> 1;
3301debfc3dSmrg       for (tag_depth = 4; mask; mask >>= 8)
3311debfc3dSmrg         {
3321debfc3dSmrg           if (((mask & 0xff) != 0xff))
3331debfc3dSmrg             {
334*8feb0f0bSmrg 	      warning (0, "%s:tag %qx is invalid", filename, tag);
3351debfc3dSmrg               break;
3361debfc3dSmrg             }
3371debfc3dSmrg           tag_depth--;
3381debfc3dSmrg         }
3391debfc3dSmrg       for (format = tag_table; format->name; format++)
3401debfc3dSmrg         if (format->tag == tag)
3411debfc3dSmrg           goto found;
3421debfc3dSmrg       format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
3431debfc3dSmrg     found:;
3441debfc3dSmrg       if (tag)
3451debfc3dSmrg         {
3461debfc3dSmrg           if (depth && depth < tag_depth)
3471debfc3dSmrg             {
3481debfc3dSmrg               if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
349*8feb0f0bSmrg 	        warning (0, "%s:tag %qx is incorrectly nested",
3501debfc3dSmrg                          filename, tag);
3511debfc3dSmrg             }
3521debfc3dSmrg           depth = tag_depth;
3531debfc3dSmrg           tags[depth - 1] = tag;
3541debfc3dSmrg         }
3551debfc3dSmrg 
3561debfc3dSmrg       if (format->proc)
3571debfc3dSmrg         {
3581debfc3dSmrg           unsigned long actual_length;
3591debfc3dSmrg 
3601debfc3dSmrg           (*format->proc) (tag, length);
3611debfc3dSmrg 
3621debfc3dSmrg           actual_length = gcov_position () - base;
3631debfc3dSmrg           if (actual_length > length)
364*8feb0f0bSmrg 	    warning (0, "%s:record size mismatch %lu bytes overread",
3651debfc3dSmrg                      filename, actual_length - length);
3661debfc3dSmrg           else if (length > actual_length)
367*8feb0f0bSmrg 	    warning (0, "%s:record size mismatch %lu bytes unread",
3681debfc3dSmrg                      filename, length - actual_length);
3691debfc3dSmrg        }
3701debfc3dSmrg 
3711debfc3dSmrg       gcov_sync (base, length);
3721debfc3dSmrg       if ((error = gcov_is_error ()))
3731debfc3dSmrg         {
374*8feb0f0bSmrg 	  warning (0, error < 0 ? "%s:counter overflow at %lu" :
375*8feb0f0bSmrg 	                          "%s:read error at %lu", filename,
3761debfc3dSmrg                    (long unsigned) gcov_position ());
3771debfc3dSmrg           break;
3781debfc3dSmrg         }
3791debfc3dSmrg     }
3801debfc3dSmrg 
3811debfc3dSmrg   read_gcda_finalize (obj_info);
3821debfc3dSmrg   gcov_close ();
3831debfc3dSmrg 
3841debfc3dSmrg   return obj_info;
3851debfc3dSmrg }
3861debfc3dSmrg 
3871debfc3dSmrg #ifdef HAVE_FTW_H
3881debfc3dSmrg /* This will be called by ftw(). It opens and read a gcda file FILENAME.
3891debfc3dSmrg    Return a non-zero value to stop the tree walk.  */
3901debfc3dSmrg 
3911debfc3dSmrg static int
ftw_read_file(const char * filename,const struct stat * status ATTRIBUTE_UNUSED,int type)3921debfc3dSmrg ftw_read_file (const char *filename,
3931debfc3dSmrg                const struct stat *status ATTRIBUTE_UNUSED,
3941debfc3dSmrg                int type)
3951debfc3dSmrg {
3961debfc3dSmrg   int filename_len;
3971debfc3dSmrg   int suffix_len;
3981debfc3dSmrg   struct gcov_info *obj_info;
3991debfc3dSmrg 
4001debfc3dSmrg   /* Only read regular files.  */
4011debfc3dSmrg   if (type != FTW_F)
4021debfc3dSmrg     return 0;
4031debfc3dSmrg 
4041debfc3dSmrg   filename_len = strlen (filename);
4051debfc3dSmrg   suffix_len = strlen (GCOV_DATA_SUFFIX);
4061debfc3dSmrg 
4071debfc3dSmrg   if (filename_len <= suffix_len)
4081debfc3dSmrg     return 0;
4091debfc3dSmrg 
4101debfc3dSmrg   if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
4111debfc3dSmrg     return 0;
4121debfc3dSmrg 
4131debfc3dSmrg   if (verbose)
4141debfc3dSmrg     fnotice (stderr, "reading file: %s\n", filename);
4151debfc3dSmrg 
4161debfc3dSmrg   obj_info = read_gcda_file (filename);
4171debfc3dSmrg   if (!obj_info)
4181debfc3dSmrg     return 0;
4191debfc3dSmrg 
4201debfc3dSmrg   obj_info->next = gcov_info_head;
4211debfc3dSmrg   gcov_info_head = obj_info;
4221debfc3dSmrg 
4231debfc3dSmrg   return 0;
4241debfc3dSmrg }
4251debfc3dSmrg #endif
4261debfc3dSmrg 
4271debfc3dSmrg /* Initializer for reading a profile dir.  */
4281debfc3dSmrg 
4291debfc3dSmrg static inline void
read_profile_dir_init(void)4301debfc3dSmrg read_profile_dir_init (void)
4311debfc3dSmrg {
4321debfc3dSmrg   gcov_info_head = 0;
4331debfc3dSmrg }
4341debfc3dSmrg 
4351debfc3dSmrg /* Driver for read a profile directory and convert into gcov_info list in memory.
4361debfc3dSmrg    Return NULL on error,
4371debfc3dSmrg    Return the head of gcov_info list on success.  */
4381debfc3dSmrg 
4391debfc3dSmrg struct gcov_info *
gcov_read_profile_dir(const char * dir_name,int recompute_summary ATTRIBUTE_UNUSED)4401debfc3dSmrg gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
4411debfc3dSmrg {
4421debfc3dSmrg   char *pwd;
4431debfc3dSmrg   int ret;
4441debfc3dSmrg 
4451debfc3dSmrg   read_profile_dir_init ();
4461debfc3dSmrg 
4471debfc3dSmrg   if (access (dir_name, R_OK) != 0)
4481debfc3dSmrg     {
4491debfc3dSmrg       fnotice (stderr, "cannot access directory %s\n", dir_name);
4501debfc3dSmrg       return NULL;
4511debfc3dSmrg     }
4521debfc3dSmrg   pwd = getcwd (NULL, 0);
4531debfc3dSmrg   gcc_assert (pwd);
4541debfc3dSmrg   ret = chdir (dir_name);
4551debfc3dSmrg   if (ret !=0)
4561debfc3dSmrg     {
4571debfc3dSmrg       fnotice (stderr, "%s is not a directory\n", dir_name);
4581debfc3dSmrg       return NULL;
4591debfc3dSmrg     }
4601debfc3dSmrg #ifdef HAVE_FTW_H
4611debfc3dSmrg   ftw (".", ftw_read_file, 50);
4621debfc3dSmrg #endif
463*8feb0f0bSmrg   chdir (pwd);
4641debfc3dSmrg   free (pwd);
4651debfc3dSmrg 
4661debfc3dSmrg   return gcov_info_head;;
4671debfc3dSmrg }
4681debfc3dSmrg 
4691debfc3dSmrg /* This part of the code is to merge profile counters. These
4701debfc3dSmrg    variables are set in merge_wrapper and to be used by
4711debfc3dSmrg    global function gcov_read_counter_mem() and gcov_get_merge_weight.  */
4721debfc3dSmrg 
4731debfc3dSmrg /* We save the counter value address to this variable.  */
4741debfc3dSmrg static gcov_type *gcov_value_buf;
4751debfc3dSmrg 
4761debfc3dSmrg /* The number of counter values to be read by current merging.  */
4771debfc3dSmrg static gcov_unsigned_t gcov_value_buf_size;
4781debfc3dSmrg 
4791debfc3dSmrg /* The index of counter values being read.  */
4801debfc3dSmrg static gcov_unsigned_t gcov_value_buf_pos;
4811debfc3dSmrg 
4821debfc3dSmrg /* The weight of current merging.  */
4831debfc3dSmrg static unsigned gcov_merge_weight;
4841debfc3dSmrg 
4851debfc3dSmrg /* Read a counter value from gcov_value_buf array.  */
4861debfc3dSmrg 
4871debfc3dSmrg gcov_type
gcov_read_counter_mem(void)4881debfc3dSmrg gcov_read_counter_mem (void)
4891debfc3dSmrg {
4901debfc3dSmrg   gcov_type ret;
4911debfc3dSmrg   gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
4921debfc3dSmrg   ret = *(gcov_value_buf + gcov_value_buf_pos);
4931debfc3dSmrg   ++gcov_value_buf_pos;
4941debfc3dSmrg   return ret;
4951debfc3dSmrg }
4961debfc3dSmrg 
4971debfc3dSmrg /* Return the recorded merge weight.  */
4981debfc3dSmrg 
4991debfc3dSmrg unsigned
gcov_get_merge_weight(void)5001debfc3dSmrg gcov_get_merge_weight (void)
5011debfc3dSmrg {
5021debfc3dSmrg   return gcov_merge_weight;
5031debfc3dSmrg }
5041debfc3dSmrg 
5051debfc3dSmrg /* A wrapper function for merge functions. It sets up the
5061debfc3dSmrg    value buffer and weights and then calls the merge function.  */
5071debfc3dSmrg 
5081debfc3dSmrg static void
merge_wrapper(gcov_merge_fn f,gcov_type * v1,gcov_unsigned_t n,gcov_type * v2,unsigned w)5091debfc3dSmrg merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n,
5101debfc3dSmrg                gcov_type *v2, unsigned w)
5111debfc3dSmrg {
5121debfc3dSmrg   gcov_value_buf = v2;
5131debfc3dSmrg   gcov_value_buf_pos = 0;
5141debfc3dSmrg   gcov_value_buf_size = n;
5151debfc3dSmrg   gcov_merge_weight = w;
5161debfc3dSmrg   (*f) (v1, n);
5171debfc3dSmrg }
5181debfc3dSmrg 
5191debfc3dSmrg /* Offline tool to manipulate profile data.
5201debfc3dSmrg    This tool targets on matched profiles. But it has some tolerance on
5211debfc3dSmrg    unmatched profiles.
5221debfc3dSmrg    When merging p1 to p2 (p2 is the dst),
5231debfc3dSmrg    * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
5241debfc3dSmrg      emit warning
5251debfc3dSmrg    * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
5261debfc3dSmrg      specified weight; emit warning.
5271debfc3dSmrg    * m.gcda in both p1 and p2:
5281debfc3dSmrg    ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
5291debfc3dSmrg    ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
5301debfc3dSmrg       p2->m.gcda->f and
5311debfc3dSmrg       drop p1->m.gcda->f. A warning is emitted.  */
5321debfc3dSmrg 
5331debfc3dSmrg /* Add INFO2's counter to INFO1, multiplying by weight W.  */
5341debfc3dSmrg 
5351debfc3dSmrg static int
gcov_merge(struct gcov_info * info1,struct gcov_info * info2,int w)5361debfc3dSmrg gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
5371debfc3dSmrg {
5381debfc3dSmrg   unsigned f_ix;
5391debfc3dSmrg   unsigned n_functions = info1->n_functions;
5401debfc3dSmrg   int has_mismatch = 0;
5411debfc3dSmrg 
5421debfc3dSmrg   gcc_assert (info2->n_functions == n_functions);
5431debfc3dSmrg   for (f_ix = 0; f_ix < n_functions; f_ix++)
5441debfc3dSmrg     {
5451debfc3dSmrg       unsigned t_ix;
5461debfc3dSmrg       const struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
5471debfc3dSmrg       const struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
5481debfc3dSmrg       const struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
5491debfc3dSmrg 
5501debfc3dSmrg       if (!gfi_ptr1 || gfi_ptr1->key != info1)
5511debfc3dSmrg         continue;
5521debfc3dSmrg       if (!gfi_ptr2 || gfi_ptr2->key != info2)
5531debfc3dSmrg         continue;
5541debfc3dSmrg 
5551debfc3dSmrg       if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
5561debfc3dSmrg         {
5571debfc3dSmrg           fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
5581debfc3dSmrg                   info1->filename);
5591debfc3dSmrg           has_mismatch = 1;
5601debfc3dSmrg           continue;
5611debfc3dSmrg         }
5621debfc3dSmrg       ci_ptr1 = gfi_ptr1->ctrs;
5631debfc3dSmrg       ci_ptr2 = gfi_ptr2->ctrs;
5641debfc3dSmrg       for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
5651debfc3dSmrg         {
5661debfc3dSmrg           gcov_merge_fn merge1 = info1->merge[t_ix];
5671debfc3dSmrg           gcov_merge_fn merge2 = info2->merge[t_ix];
5681debfc3dSmrg 
5691debfc3dSmrg           gcc_assert (merge1 == merge2);
5701debfc3dSmrg           if (!merge1)
5711debfc3dSmrg             continue;
5721debfc3dSmrg           gcc_assert (ci_ptr1->num == ci_ptr2->num);
5731debfc3dSmrg           merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num, ci_ptr2->values, w);
5741debfc3dSmrg           ci_ptr1++;
5751debfc3dSmrg           ci_ptr2++;
5761debfc3dSmrg         }
5771debfc3dSmrg     }
5781debfc3dSmrg 
5791debfc3dSmrg   return has_mismatch;
5801debfc3dSmrg }
5811debfc3dSmrg 
5821debfc3dSmrg /* Find and return the match gcov_info object for INFO from ARRAY.
5831debfc3dSmrg    SIZE is the length of ARRAY.
5841debfc3dSmrg    Return NULL if there is no match.  */
5851debfc3dSmrg 
5861debfc3dSmrg static struct gcov_info *
find_match_gcov_info(struct gcov_info ** array,int size,struct gcov_info * info)5871debfc3dSmrg find_match_gcov_info (struct gcov_info **array, int size,
5881debfc3dSmrg 		      struct gcov_info *info)
5891debfc3dSmrg {
5901debfc3dSmrg   struct gcov_info *gi_ptr;
5911debfc3dSmrg   struct gcov_info *ret = NULL;
5921debfc3dSmrg   int i;
5931debfc3dSmrg 
5941debfc3dSmrg   for (i = 0; i < size; i++)
5951debfc3dSmrg     {
5961debfc3dSmrg       gi_ptr = array[i];
5971debfc3dSmrg       if (gi_ptr == 0)
5981debfc3dSmrg         continue;
5991debfc3dSmrg       if (!strcmp (gi_ptr->filename, info->filename))
6001debfc3dSmrg         {
6011debfc3dSmrg           ret = gi_ptr;
6021debfc3dSmrg           array[i] = 0;
6031debfc3dSmrg           break;
6041debfc3dSmrg         }
6051debfc3dSmrg     }
6061debfc3dSmrg 
6071debfc3dSmrg   if (ret && ret->n_functions != info->n_functions)
6081debfc3dSmrg     {
6091debfc3dSmrg       fnotice (stderr, "mismatched profiles in %s (%d functions"
6101debfc3dSmrg                        " vs %d functions)\n",
6111debfc3dSmrg                        ret->filename,
6121debfc3dSmrg                        ret->n_functions,
6131debfc3dSmrg                        info->n_functions);
6141debfc3dSmrg       ret = NULL;
6151debfc3dSmrg     }
6161debfc3dSmrg   return ret;
6171debfc3dSmrg }
6181debfc3dSmrg 
6191debfc3dSmrg /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
6201debfc3dSmrg    Return 0 on success: without mismatch.
6211debfc3dSmrg    Reutrn 1 on error.  */
6221debfc3dSmrg 
6231debfc3dSmrg int
gcov_profile_merge(struct gcov_info * tgt_profile,struct gcov_info * src_profile,int w1,int w2)6241debfc3dSmrg gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
6251debfc3dSmrg                     int w1, int w2)
6261debfc3dSmrg {
6271debfc3dSmrg   struct gcov_info *gi_ptr;
6281debfc3dSmrg   struct gcov_info **tgt_infos;
6291debfc3dSmrg   struct gcov_info *tgt_tail;
6301debfc3dSmrg   struct gcov_info **in_src_not_tgt;
6311debfc3dSmrg   unsigned tgt_cnt = 0, src_cnt = 0;
6321debfc3dSmrg   unsigned unmatch_info_cnt = 0;
6331debfc3dSmrg   unsigned int i;
6341debfc3dSmrg 
6351debfc3dSmrg   for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
6361debfc3dSmrg     tgt_cnt++;
6371debfc3dSmrg   for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
6381debfc3dSmrg     src_cnt++;
6391debfc3dSmrg   tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
6401debfc3dSmrg                  * tgt_cnt);
6411debfc3dSmrg   gcc_assert (tgt_infos);
6421debfc3dSmrg   in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
6431debfc3dSmrg                      * src_cnt);
6441debfc3dSmrg   gcc_assert (in_src_not_tgt);
6451debfc3dSmrg 
6461debfc3dSmrg   for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
6471debfc3dSmrg     tgt_infos[i] = gi_ptr;
6481debfc3dSmrg 
6491debfc3dSmrg   tgt_tail = tgt_infos[tgt_cnt - 1];
6501debfc3dSmrg 
6511debfc3dSmrg   /* First pass on tgt_profile, we multiply w1 to all counters.  */
6521debfc3dSmrg   if (w1 > 1)
6531debfc3dSmrg     {
6541debfc3dSmrg        for (i = 0; i < tgt_cnt; i++)
6551debfc3dSmrg          gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
6561debfc3dSmrg     }
6571debfc3dSmrg 
6581debfc3dSmrg   /* Second pass, add src_profile to the tgt_profile.  */
6591debfc3dSmrg   for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
6601debfc3dSmrg     {
6611debfc3dSmrg       struct gcov_info *gi_ptr1;
6621debfc3dSmrg 
6631debfc3dSmrg       gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
6641debfc3dSmrg       if (gi_ptr1 == NULL)
6651debfc3dSmrg         {
6661debfc3dSmrg           in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
6671debfc3dSmrg           continue;
6681debfc3dSmrg         }
6691debfc3dSmrg       gcov_merge (gi_ptr1, gi_ptr, w2);
6701debfc3dSmrg     }
6711debfc3dSmrg 
6721debfc3dSmrg   /* For modules in src but not in tgt. We adjust the counter and append.  */
6731debfc3dSmrg   for (i = 0; i < unmatch_info_cnt; i++)
6741debfc3dSmrg     {
6751debfc3dSmrg       gi_ptr = in_src_not_tgt[i];
6761debfc3dSmrg       gcov_merge (gi_ptr, gi_ptr, w2 - 1);
6771debfc3dSmrg       gi_ptr->next = NULL;
6781debfc3dSmrg       tgt_tail->next = gi_ptr;
6791debfc3dSmrg       tgt_tail = gi_ptr;
6801debfc3dSmrg     }
6811debfc3dSmrg 
682*8feb0f0bSmrg   free (in_src_not_tgt);
683*8feb0f0bSmrg   free (tgt_infos);
684*8feb0f0bSmrg 
6851debfc3dSmrg   return 0;
6861debfc3dSmrg }
6871debfc3dSmrg 
6881debfc3dSmrg typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
6891debfc3dSmrg 
6901debfc3dSmrg /* Performing FN upon arc counters.  */
6911debfc3dSmrg 
6921debfc3dSmrg static void
__gcov_add_counter_op(gcov_type * counters,unsigned n_counters,counter_op_fn fn,void * data1,void * data2)6931debfc3dSmrg __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
6941debfc3dSmrg                        counter_op_fn fn, void *data1, void *data2)
6951debfc3dSmrg {
6961debfc3dSmrg   for (; n_counters; counters++, n_counters--)
6971debfc3dSmrg     {
6981debfc3dSmrg       gcov_type val = *counters;
6991debfc3dSmrg       *counters = fn(val, data1, data2);
7001debfc3dSmrg     }
7011debfc3dSmrg }
7021debfc3dSmrg 
7031debfc3dSmrg /* Performing FN upon ior counters.  */
7041debfc3dSmrg 
7051debfc3dSmrg 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)7061debfc3dSmrg __gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
7071debfc3dSmrg                        unsigned n_counters ATTRIBUTE_UNUSED,
7081debfc3dSmrg                        counter_op_fn fn ATTRIBUTE_UNUSED,
7091debfc3dSmrg                        void *data1 ATTRIBUTE_UNUSED,
7101debfc3dSmrg                        void *data2 ATTRIBUTE_UNUSED)
7111debfc3dSmrg {
7121debfc3dSmrg   /* Do nothing.  */
7131debfc3dSmrg }
7141debfc3dSmrg 
7151debfc3dSmrg /* Performing FN upon time-profile counters.  */
7161debfc3dSmrg 
7171debfc3dSmrg 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)7181debfc3dSmrg __gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
7191debfc3dSmrg                                 unsigned n_counters ATTRIBUTE_UNUSED,
7201debfc3dSmrg                                 counter_op_fn fn ATTRIBUTE_UNUSED,
7211debfc3dSmrg                                 void *data1 ATTRIBUTE_UNUSED,
7221debfc3dSmrg                                 void *data2 ATTRIBUTE_UNUSED)
7231debfc3dSmrg {
7241debfc3dSmrg   /* Do nothing.  */
7251debfc3dSmrg }
7261debfc3dSmrg 
727*8feb0f0bSmrg /* Performing FN upon TOP N counters.  */
7281debfc3dSmrg 
7291debfc3dSmrg static void
__gcov_topn_counter_op(gcov_type * counters,unsigned n_counters,counter_op_fn fn,void * data1,void * data2)730*8feb0f0bSmrg __gcov_topn_counter_op (gcov_type *counters, unsigned n_counters,
7311debfc3dSmrg 			counter_op_fn fn, void *data1, void *data2)
7321debfc3dSmrg {
7331debfc3dSmrg   unsigned i, n_measures;
7341debfc3dSmrg 
7351debfc3dSmrg   gcc_assert (!(n_counters % 3));
7361debfc3dSmrg   n_measures = n_counters / 3;
7371debfc3dSmrg   for (i = 0; i < n_measures; i++, counters += 3)
7381debfc3dSmrg     {
7391debfc3dSmrg       counters[1] = fn (counters[1], data1, data2);
7401debfc3dSmrg       counters[2] = fn (counters[2], data1, data2);
7411debfc3dSmrg     }
7421debfc3dSmrg }
7431debfc3dSmrg 
7441debfc3dSmrg /* Scaling the counter value V by multiplying *(float*) DATA1.  */
7451debfc3dSmrg 
7461debfc3dSmrg static gcov_type
fp_scale(gcov_type v,void * data1,void * data2 ATTRIBUTE_UNUSED)7471debfc3dSmrg fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
7481debfc3dSmrg {
7491debfc3dSmrg   float f = *(float *) data1;
7501debfc3dSmrg   return (gcov_type) (v * f);
7511debfc3dSmrg }
7521debfc3dSmrg 
7531debfc3dSmrg /* Scaling the counter value V by multiplying DATA2/DATA1.  */
7541debfc3dSmrg 
7551debfc3dSmrg static gcov_type
int_scale(gcov_type v,void * data1,void * data2)7561debfc3dSmrg int_scale (gcov_type v, void *data1, void *data2)
7571debfc3dSmrg {
7581debfc3dSmrg   int n = *(int *) data1;
7591debfc3dSmrg   int d = *(int *) data2;
7601debfc3dSmrg   return (gcov_type) ( RDIV (v,d) * n);
7611debfc3dSmrg }
7621debfc3dSmrg 
7631debfc3dSmrg /* Type of function used to process counters.  */
7641debfc3dSmrg typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
7651debfc3dSmrg                           counter_op_fn, void *, void *);
7661debfc3dSmrg 
7671debfc3dSmrg /* Function array to process profile counters.  */
7681debfc3dSmrg #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
7691debfc3dSmrg   __gcov ## FN_TYPE ## _counter_op,
7701debfc3dSmrg static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
7711debfc3dSmrg #include "gcov-counter.def"
7721debfc3dSmrg };
7731debfc3dSmrg #undef DEF_GCOV_COUNTER
7741debfc3dSmrg 
7751debfc3dSmrg /* Driver for scaling profile counters.  */
7761debfc3dSmrg 
7771debfc3dSmrg int
gcov_profile_scale(struct gcov_info * profile,float scale_factor,int n,int d)7781debfc3dSmrg gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
7791debfc3dSmrg {
7801debfc3dSmrg   struct gcov_info *gi_ptr;
7811debfc3dSmrg   unsigned f_ix;
7821debfc3dSmrg 
7831debfc3dSmrg   if (verbose)
7841debfc3dSmrg     fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
7851debfc3dSmrg 
7861debfc3dSmrg   /* Scaling the counters.  */
7871debfc3dSmrg   for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
7881debfc3dSmrg     for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
7891debfc3dSmrg       {
7901debfc3dSmrg         unsigned t_ix;
7911debfc3dSmrg         const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
7921debfc3dSmrg         const struct gcov_ctr_info *ci_ptr;
7931debfc3dSmrg 
7941debfc3dSmrg         if (!gfi_ptr || gfi_ptr->key != gi_ptr)
7951debfc3dSmrg           continue;
7961debfc3dSmrg 
7971debfc3dSmrg         ci_ptr = gfi_ptr->ctrs;
7981debfc3dSmrg         for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
7991debfc3dSmrg           {
8001debfc3dSmrg             gcov_merge_fn merge = gi_ptr->merge[t_ix];
8011debfc3dSmrg 
8021debfc3dSmrg             if (!merge)
8031debfc3dSmrg               continue;
8041debfc3dSmrg             if (d == 0)
8051debfc3dSmrg               (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
8061debfc3dSmrg                                       fp_scale, &scale_factor, NULL);
8071debfc3dSmrg             else
8081debfc3dSmrg               (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
8091debfc3dSmrg                                       int_scale, &n, &d);
8101debfc3dSmrg             ci_ptr++;
8111debfc3dSmrg           }
8121debfc3dSmrg       }
8131debfc3dSmrg 
8141debfc3dSmrg   return 0;
8151debfc3dSmrg }
8161debfc3dSmrg 
8171debfc3dSmrg /* Driver to normalize profile counters.  */
8181debfc3dSmrg 
8191debfc3dSmrg int
gcov_profile_normalize(struct gcov_info * profile,gcov_type max_val)8201debfc3dSmrg gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
8211debfc3dSmrg {
8221debfc3dSmrg   struct gcov_info *gi_ptr;
8231debfc3dSmrg   gcov_type curr_max_val = 0;
8241debfc3dSmrg   unsigned f_ix;
8251debfc3dSmrg   unsigned int i;
8261debfc3dSmrg   float scale_factor;
8271debfc3dSmrg 
8281debfc3dSmrg   /* Find the largest count value.  */
8291debfc3dSmrg   for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
8301debfc3dSmrg     for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
8311debfc3dSmrg       {
8321debfc3dSmrg         unsigned t_ix;
8331debfc3dSmrg         const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
8341debfc3dSmrg         const struct gcov_ctr_info *ci_ptr;
8351debfc3dSmrg 
8361debfc3dSmrg         if (!gfi_ptr || gfi_ptr->key != gi_ptr)
8371debfc3dSmrg           continue;
8381debfc3dSmrg 
8391debfc3dSmrg         ci_ptr = gfi_ptr->ctrs;
8401debfc3dSmrg         for (t_ix = 0; t_ix < 1; t_ix++)
8411debfc3dSmrg           {
8421debfc3dSmrg             for (i = 0; i < ci_ptr->num; i++)
8431debfc3dSmrg               if (ci_ptr->values[i] > curr_max_val)
8441debfc3dSmrg                 curr_max_val = ci_ptr->values[i];
8451debfc3dSmrg             ci_ptr++;
8461debfc3dSmrg           }
8471debfc3dSmrg       }
8481debfc3dSmrg 
8491debfc3dSmrg   scale_factor = (float)max_val / curr_max_val;
8501debfc3dSmrg   if (verbose)
8511debfc3dSmrg     fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
8521debfc3dSmrg 
8531debfc3dSmrg   return gcov_profile_scale (profile, scale_factor, 0, 0);
8541debfc3dSmrg }
8551debfc3dSmrg 
8561debfc3dSmrg /* The following variables are defined in gcc/gcov-tool.c.  */
8571debfc3dSmrg extern int overlap_func_level;
8581debfc3dSmrg extern int overlap_obj_level;
8591debfc3dSmrg extern int overlap_hot_only;
8601debfc3dSmrg extern int overlap_use_fullname;
8611debfc3dSmrg extern double overlap_hot_threshold;
8621debfc3dSmrg 
8631debfc3dSmrg /* Compute the overlap score of two values. The score is defined as:
8641debfc3dSmrg     min (V1/SUM_1, V2/SUM_2)  */
8651debfc3dSmrg 
8661debfc3dSmrg static double
calculate_2_entries(const unsigned long v1,const unsigned long v2,const double sum_1,const double sum_2)8671debfc3dSmrg calculate_2_entries (const unsigned long v1, const unsigned long v2,
8681debfc3dSmrg                      const double sum_1, const double sum_2)
8691debfc3dSmrg {
8701debfc3dSmrg   double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
8711debfc3dSmrg   double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
8721debfc3dSmrg 
8731debfc3dSmrg   if (val2 < val1)
8741debfc3dSmrg     val1 = val2;
8751debfc3dSmrg 
8761debfc3dSmrg   return val1;
8771debfc3dSmrg }
8781debfc3dSmrg 
8791debfc3dSmrg /*  Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
8801debfc3dSmrg     This function also updates cumulative score CUM_1_RESULT and
8811debfc3dSmrg     CUM_2_RESULT.  */
8821debfc3dSmrg 
8831debfc3dSmrg 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)8841debfc3dSmrg compute_one_gcov (const struct gcov_info *gcov_info1,
8851debfc3dSmrg                   const struct gcov_info *gcov_info2,
8861debfc3dSmrg                   const double sum_1, const double sum_2,
8871debfc3dSmrg                   double *cum_1_result, double *cum_2_result)
8881debfc3dSmrg {
8891debfc3dSmrg   unsigned f_ix;
8901debfc3dSmrg   double ret = 0;
8911debfc3dSmrg   double cum_1 = 0, cum_2 = 0;
8921debfc3dSmrg   const struct gcov_info *gcov_info = 0;
8931debfc3dSmrg   double *cum_p;
8941debfc3dSmrg   double sum;
8951debfc3dSmrg 
8961debfc3dSmrg   gcc_assert (gcov_info1 || gcov_info2);
8971debfc3dSmrg   if (!gcov_info1)
8981debfc3dSmrg     {
8991debfc3dSmrg       gcov_info = gcov_info2;
9001debfc3dSmrg       cum_p = cum_2_result;
9011debfc3dSmrg       sum = sum_2;
9021debfc3dSmrg       *cum_1_result = 0;
9031debfc3dSmrg     } else
9041debfc3dSmrg   if (!gcov_info2)
9051debfc3dSmrg     {
9061debfc3dSmrg       gcov_info = gcov_info1;
9071debfc3dSmrg       cum_p = cum_1_result;
9081debfc3dSmrg       sum = sum_1;
9091debfc3dSmrg       *cum_2_result = 0;
9101debfc3dSmrg     }
9111debfc3dSmrg 
9121debfc3dSmrg   if (gcov_info)
9131debfc3dSmrg   {
9141debfc3dSmrg     for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
9151debfc3dSmrg       {
9161debfc3dSmrg         const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
9171debfc3dSmrg         if (!gfi_ptr || gfi_ptr->key != gcov_info)
9181debfc3dSmrg           continue;
9191debfc3dSmrg         const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
9201debfc3dSmrg 	unsigned c_num;
9211debfc3dSmrg 	for (c_num = 0; c_num < ci_ptr->num; c_num++)
9221debfc3dSmrg 	  cum_1 += ci_ptr->values[c_num] / sum;
9231debfc3dSmrg       }
9241debfc3dSmrg     *cum_p = cum_1;
9251debfc3dSmrg     return 0.0;
9261debfc3dSmrg   }
9271debfc3dSmrg 
9281debfc3dSmrg   for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
9291debfc3dSmrg     {
9301debfc3dSmrg       double func_cum_1 = 0.0;
9311debfc3dSmrg       double func_cum_2 = 0.0;
9321debfc3dSmrg       double func_val = 0.0;
9331debfc3dSmrg       int nonzero = 0;
9341debfc3dSmrg       int hot = 0;
9351debfc3dSmrg       const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
9361debfc3dSmrg       const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
9371debfc3dSmrg 
9381debfc3dSmrg       if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
9391debfc3dSmrg         continue;
9401debfc3dSmrg       if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
9411debfc3dSmrg         continue;
9421debfc3dSmrg 
9431debfc3dSmrg       const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
9441debfc3dSmrg       const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
9451debfc3dSmrg       unsigned c_num;
9461debfc3dSmrg       for (c_num = 0; c_num < ci_ptr1->num; c_num++)
9471debfc3dSmrg 	{
9481debfc3dSmrg 	  if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
9491debfc3dSmrg 	    {
9501debfc3dSmrg 	      func_val += calculate_2_entries (ci_ptr1->values[c_num],
9511debfc3dSmrg 					       ci_ptr2->values[c_num],
9521debfc3dSmrg 					       sum_1, sum_2);
9531debfc3dSmrg 
9541debfc3dSmrg 	      func_cum_1 += ci_ptr1->values[c_num] / sum_1;
9551debfc3dSmrg 	      func_cum_2 += ci_ptr2->values[c_num] / sum_2;
9561debfc3dSmrg 	      nonzero = 1;
957c0a68be4Smrg 	      if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
958c0a68be4Smrg 		  || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
9591debfc3dSmrg 		hot = 1;
9601debfc3dSmrg 	    }
9611debfc3dSmrg 	}
962c0a68be4Smrg 
9631debfc3dSmrg       ret += func_val;
9641debfc3dSmrg       cum_1 += func_cum_1;
9651debfc3dSmrg       cum_2 += func_cum_2;
9661debfc3dSmrg       if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
9671debfc3dSmrg         {
9681debfc3dSmrg           printf("   \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
9691debfc3dSmrg                  gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
9701debfc3dSmrg         }
9711debfc3dSmrg     }
9721debfc3dSmrg   *cum_1_result = cum_1;
9731debfc3dSmrg   *cum_2_result = cum_2;
9741debfc3dSmrg   return ret;
9751debfc3dSmrg }
9761debfc3dSmrg 
9771debfc3dSmrg /* Test if all counter values in this GCOV_INFO are cold.
9781debfc3dSmrg    "Cold" is defined as the counter value being less than
9791debfc3dSmrg    or equal to THRESHOLD.  */
9801debfc3dSmrg 
9811debfc3dSmrg static bool
gcov_info_count_all_cold(const struct gcov_info * gcov_info,gcov_type threshold)9821debfc3dSmrg gcov_info_count_all_cold (const struct gcov_info *gcov_info,
9831debfc3dSmrg                           gcov_type threshold)
9841debfc3dSmrg {
9851debfc3dSmrg   unsigned f_ix;
9861debfc3dSmrg 
9871debfc3dSmrg   for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
9881debfc3dSmrg     {
9891debfc3dSmrg       const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
9901debfc3dSmrg 
9911debfc3dSmrg       if (!gfi_ptr || gfi_ptr->key != gcov_info)
9921debfc3dSmrg         continue;
9931debfc3dSmrg       const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
994c0a68be4Smrg       for (unsigned c_num = 0; c_num < ci_ptr->num; c_num++)
9951debfc3dSmrg 	if (ci_ptr->values[c_num] > threshold)
9961debfc3dSmrg 	  return false;
9971debfc3dSmrg     }
9981debfc3dSmrg 
9991debfc3dSmrg   return true;
10001debfc3dSmrg }
10011debfc3dSmrg 
10021debfc3dSmrg /* Test if all counter values in this GCOV_INFO are 0.  */
10031debfc3dSmrg 
10041debfc3dSmrg static bool
gcov_info_count_all_zero(const struct gcov_info * gcov_info)10051debfc3dSmrg gcov_info_count_all_zero (const struct gcov_info *gcov_info)
10061debfc3dSmrg {
10071debfc3dSmrg   return gcov_info_count_all_cold (gcov_info, 0);
10081debfc3dSmrg }
10091debfc3dSmrg 
10101debfc3dSmrg /* A pair of matched GCOV_INFO.
10111debfc3dSmrg    The flag is a bitvector:
10121debfc3dSmrg      b0: obj1's all counts are 0;
10131debfc3dSmrg      b1: obj1's all counts are cold (but no 0);
10141debfc3dSmrg      b2: obj1 is hot;
10151debfc3dSmrg      b3: no obj1 to match obj2;
10161debfc3dSmrg      b4: obj2's all counts are 0;
10171debfc3dSmrg      b5: obj2's all counts are cold (but no 0);
10181debfc3dSmrg      b6: obj2 is hot;
10191debfc3dSmrg      b7: no obj2 to match obj1;
10201debfc3dSmrg  */
10211debfc3dSmrg struct overlap_t {
10221debfc3dSmrg    const struct gcov_info *obj1;
10231debfc3dSmrg    const struct gcov_info *obj2;
10241debfc3dSmrg    char flag;
10251debfc3dSmrg };
10261debfc3dSmrg 
10271debfc3dSmrg #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
10281debfc3dSmrg #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
10291debfc3dSmrg #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
10301debfc3dSmrg 
10311debfc3dSmrg /* Cumlative overlap dscore for profile1 and profile2.  */
10321debfc3dSmrg static double overlap_sum_1, overlap_sum_2;
10331debfc3dSmrg 
10341debfc3dSmrg /* The number of gcda files in the profiles.  */
10351debfc3dSmrg static unsigned gcda_files[2];
10361debfc3dSmrg 
10371debfc3dSmrg /* The number of unique gcda files in the profiles
10381debfc3dSmrg    (not existing in the other profile).  */
10391debfc3dSmrg static unsigned unique_gcda_files[2];
10401debfc3dSmrg 
10411debfc3dSmrg /* The number of gcda files that all counter values are 0.  */
10421debfc3dSmrg static unsigned zero_gcda_files[2];
10431debfc3dSmrg 
10441debfc3dSmrg /* The number of gcda files that all counter values are cold (but not 0).  */
10451debfc3dSmrg static unsigned cold_gcda_files[2];
10461debfc3dSmrg 
10471debfc3dSmrg /* The number of gcda files that includes hot counter values.  */
10481debfc3dSmrg static unsigned hot_gcda_files[2];
10491debfc3dSmrg 
10501debfc3dSmrg /* The number of gcda files with hot count value in either profiles.  */
10511debfc3dSmrg static unsigned both_hot_cnt;
10521debfc3dSmrg 
10531debfc3dSmrg /* The number of gcda files with all counts cold (but not 0) in
10541debfc3dSmrg    both profiles. */
10551debfc3dSmrg static unsigned both_cold_cnt;
10561debfc3dSmrg 
10571debfc3dSmrg /* The number of gcda files with all counts 0 in both profiles.  */
10581debfc3dSmrg static unsigned both_zero_cnt;
10591debfc3dSmrg 
10601debfc3dSmrg /* Extract the basename of the filename NAME.  */
10611debfc3dSmrg 
10621debfc3dSmrg static char *
extract_file_basename(const char * name)10631debfc3dSmrg extract_file_basename (const char *name)
10641debfc3dSmrg {
10651debfc3dSmrg   char *str;
10661debfc3dSmrg   int len = 0;
10671debfc3dSmrg   char *path = xstrdup (name);
10681debfc3dSmrg   char sep_str[2];
10691debfc3dSmrg 
10701debfc3dSmrg   sep_str[0] = DIR_SEPARATOR;
10711debfc3dSmrg   sep_str[1] = 0;
10721debfc3dSmrg   str = strstr(path, sep_str);
10731debfc3dSmrg   do{
10741debfc3dSmrg       len = strlen(str) + 1;
10751debfc3dSmrg       path = &path[strlen(path) - len + 2];
10761debfc3dSmrg       str = strstr(path, sep_str);
10771debfc3dSmrg   } while(str);
10781debfc3dSmrg 
10791debfc3dSmrg   return path;
10801debfc3dSmrg }
10811debfc3dSmrg 
10821debfc3dSmrg /* Utility function to get the filename.  */
10831debfc3dSmrg 
10841debfc3dSmrg static const char *
get_file_basename(const char * name)10851debfc3dSmrg get_file_basename (const char *name)
10861debfc3dSmrg {
10871debfc3dSmrg   if (overlap_use_fullname)
10881debfc3dSmrg     return name;
10891debfc3dSmrg   return extract_file_basename (name);
10901debfc3dSmrg }
10911debfc3dSmrg 
10921debfc3dSmrg /* A utility function to set the flag for the gcda files.  */
10931debfc3dSmrg 
10941debfc3dSmrg static void
set_flag(struct overlap_t * e)10951debfc3dSmrg set_flag (struct overlap_t *e)
10961debfc3dSmrg {
10971debfc3dSmrg   char flag = 0;
10981debfc3dSmrg 
10991debfc3dSmrg   if (!e->obj1)
11001debfc3dSmrg     {
11011debfc3dSmrg       unique_gcda_files[1]++;
11021debfc3dSmrg       flag = 0x8;
11031debfc3dSmrg     }
11041debfc3dSmrg   else
11051debfc3dSmrg     {
11061debfc3dSmrg       gcda_files[0]++;
11071debfc3dSmrg       if (gcov_info_count_all_zero (e->obj1))
11081debfc3dSmrg         {
11091debfc3dSmrg           zero_gcda_files[0]++;
11101debfc3dSmrg           flag = 0x1;
11111debfc3dSmrg         }
11121debfc3dSmrg       else
11131debfc3dSmrg       if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
11141debfc3dSmrg 			      * overlap_hot_threshold))
11151debfc3dSmrg         {
11161debfc3dSmrg           cold_gcda_files[0]++;
11171debfc3dSmrg           flag = 0x2;
11181debfc3dSmrg         }
11191debfc3dSmrg       else
11201debfc3dSmrg         {
11211debfc3dSmrg           hot_gcda_files[0]++;
11221debfc3dSmrg           flag = 0x4;
11231debfc3dSmrg         }
11241debfc3dSmrg     }
11251debfc3dSmrg 
11261debfc3dSmrg   if (!e->obj2)
11271debfc3dSmrg     {
11281debfc3dSmrg       unique_gcda_files[0]++;
11291debfc3dSmrg       flag |= (0x8 << 4);
11301debfc3dSmrg     }
11311debfc3dSmrg   else
11321debfc3dSmrg     {
11331debfc3dSmrg       gcda_files[1]++;
11341debfc3dSmrg       if (gcov_info_count_all_zero (e->obj2))
11351debfc3dSmrg         {
11361debfc3dSmrg           zero_gcda_files[1]++;
11371debfc3dSmrg           flag |= (0x1 << 4);
11381debfc3dSmrg         }
11391debfc3dSmrg       else
11401debfc3dSmrg       if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
11411debfc3dSmrg 			      * overlap_hot_threshold))
11421debfc3dSmrg         {
11431debfc3dSmrg           cold_gcda_files[1]++;
11441debfc3dSmrg           flag |= (0x2 << 4);
11451debfc3dSmrg         }
11461debfc3dSmrg       else
11471debfc3dSmrg         {
11481debfc3dSmrg           hot_gcda_files[1]++;
11491debfc3dSmrg           flag |= (0x4 << 4);
11501debfc3dSmrg         }
11511debfc3dSmrg     }
11521debfc3dSmrg 
11531debfc3dSmrg   gcc_assert (flag);
11541debfc3dSmrg   e->flag = flag;
11551debfc3dSmrg }
11561debfc3dSmrg 
11571debfc3dSmrg /* Test if INFO1 and INFO2 are from the matched source file.
11581debfc3dSmrg    Return 1 if they match; return 0 otherwise.  */
11591debfc3dSmrg 
11601debfc3dSmrg static int
matched_gcov_info(const struct gcov_info * info1,const struct gcov_info * info2)11611debfc3dSmrg matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
11621debfc3dSmrg {
11631debfc3dSmrg   /* For FDO, we have to match the name. This can be expensive.
11641debfc3dSmrg      Maybe we should use hash here.  */
11651debfc3dSmrg   if (strcmp (info1->filename, info2->filename))
11661debfc3dSmrg     return 0;
11671debfc3dSmrg 
11681debfc3dSmrg   if (info1->n_functions != info2->n_functions)
11691debfc3dSmrg     {
11701debfc3dSmrg       fnotice (stderr, "mismatched profiles in %s (%d functions"
11711debfc3dSmrg                        " vs %d functions)\n",
11721debfc3dSmrg                        info1->filename,
11731debfc3dSmrg                        info1->n_functions,
11741debfc3dSmrg                        info2->n_functions);
11751debfc3dSmrg       return 0;
11761debfc3dSmrg     }
11771debfc3dSmrg   return 1;
11781debfc3dSmrg }
11791debfc3dSmrg 
11801debfc3dSmrg /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
11811debfc3dSmrg    GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
11821debfc3dSmrg    match and 1.0 meaning a perfect match.  */
11831debfc3dSmrg 
11841debfc3dSmrg static double
calculate_overlap(struct gcov_info * gcov_list1,struct gcov_info * gcov_list2)11851debfc3dSmrg calculate_overlap (struct gcov_info *gcov_list1,
11861debfc3dSmrg                    struct gcov_info *gcov_list2)
11871debfc3dSmrg {
11881debfc3dSmrg   unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
11891debfc3dSmrg   unsigned int i, j;
11901debfc3dSmrg   const struct gcov_info *gi_ptr;
11911debfc3dSmrg   struct overlap_t *all_infos;
11921debfc3dSmrg 
11931debfc3dSmrg   for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
11941debfc3dSmrg     list1_cnt++;
11951debfc3dSmrg   for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
11961debfc3dSmrg     list2_cnt++;
11971debfc3dSmrg   all_cnt = list1_cnt + list2_cnt;
11981debfc3dSmrg   all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
11991debfc3dSmrg                * all_cnt * 2);
12001debfc3dSmrg   gcc_assert (all_infos);
12011debfc3dSmrg 
12021debfc3dSmrg   i = 0;
12031debfc3dSmrg   for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
12041debfc3dSmrg     {
12051debfc3dSmrg       all_infos[i].obj1 = gi_ptr;
12061debfc3dSmrg       all_infos[i].obj2 = 0;
12071debfc3dSmrg     }
12081debfc3dSmrg 
12091debfc3dSmrg   for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
12101debfc3dSmrg     {
12111debfc3dSmrg       all_infos[i].obj1 = 0;
12121debfc3dSmrg       all_infos[i].obj2 = gi_ptr;
12131debfc3dSmrg     }
12141debfc3dSmrg 
12151debfc3dSmrg   for (i = list1_cnt; i < all_cnt; i++)
12161debfc3dSmrg     {
12171debfc3dSmrg       if (all_infos[i].obj2 == 0)
12181debfc3dSmrg         continue;
12191debfc3dSmrg       for (j = 0; j < list1_cnt; j++)
12201debfc3dSmrg         {
12211debfc3dSmrg           if (all_infos[j].obj2 != 0)
12221debfc3dSmrg             continue;
12231debfc3dSmrg           if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
12241debfc3dSmrg             {
12251debfc3dSmrg               all_infos[j].obj2 = all_infos[i].obj2;
12261debfc3dSmrg               all_infos[i].obj2 = 0;
12271debfc3dSmrg               break;
12281debfc3dSmrg             }
12291debfc3dSmrg         }
12301debfc3dSmrg     }
12311debfc3dSmrg 
12321debfc3dSmrg   for (i = 0; i < all_cnt; i++)
12331debfc3dSmrg     if (all_infos[i].obj1 || all_infos[i].obj2)
12341debfc3dSmrg       {
12351debfc3dSmrg         set_flag (all_infos + i);
12361debfc3dSmrg         if (FLAG_ONE_HOT (all_infos[i].flag))
12371debfc3dSmrg             both_hot_cnt++;
12381debfc3dSmrg         if (FLAG_BOTH_COLD(all_infos[i].flag))
12391debfc3dSmrg             both_cold_cnt++;
12401debfc3dSmrg         if (FLAG_BOTH_ZERO(all_infos[i].flag))
12411debfc3dSmrg             both_zero_cnt++;
12421debfc3dSmrg       }
12431debfc3dSmrg 
12441debfc3dSmrg   double prg_val = 0;
12451debfc3dSmrg   double sum_val = 0;
12461debfc3dSmrg   double sum_cum_1 = 0;
12471debfc3dSmrg   double sum_cum_2 = 0;
12481debfc3dSmrg 
12491debfc3dSmrg   for (i = 0; i < all_cnt; i++)
12501debfc3dSmrg     {
12511debfc3dSmrg       double val;
12521debfc3dSmrg       double cum_1, cum_2;
12531debfc3dSmrg       const char *filename;
12541debfc3dSmrg 
12551debfc3dSmrg       if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
12561debfc3dSmrg         continue;
12571debfc3dSmrg       if (FLAG_BOTH_ZERO (all_infos[i].flag))
12581debfc3dSmrg           continue;
12591debfc3dSmrg 
12601debfc3dSmrg       if (all_infos[i].obj1)
12611debfc3dSmrg         filename = get_file_basename (all_infos[i].obj1->filename);
12621debfc3dSmrg       else
12631debfc3dSmrg         filename = get_file_basename (all_infos[i].obj2->filename);
12641debfc3dSmrg 
12651debfc3dSmrg       if (overlap_func_level)
12661debfc3dSmrg         printf("\n   processing %36s:\n", filename);
12671debfc3dSmrg 
12681debfc3dSmrg       val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
12691debfc3dSmrg           overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
12701debfc3dSmrg 
12711debfc3dSmrg       if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
12721debfc3dSmrg         {
12731debfc3dSmrg           printf("   obj=%36s  overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
12741debfc3dSmrg                   filename, val*100, cum_1*100, cum_2*100);
12751debfc3dSmrg           sum_val += val;
12761debfc3dSmrg           sum_cum_1 += cum_1;
12771debfc3dSmrg           sum_cum_2 += cum_2;
12781debfc3dSmrg         }
12791debfc3dSmrg 
12801debfc3dSmrg       prg_val += val;
12811debfc3dSmrg 
12821debfc3dSmrg     }
12831debfc3dSmrg 
1284*8feb0f0bSmrg   free (all_infos);
1285*8feb0f0bSmrg 
12861debfc3dSmrg   if (overlap_obj_level)
12871debfc3dSmrg     printf("   SUM:%36s  overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
12881debfc3dSmrg            "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
12891debfc3dSmrg 
12901debfc3dSmrg   printf ("  Statistics:\n"
12911debfc3dSmrg           "                    profile1_#     profile2_#       overlap_#\n");
12921debfc3dSmrg   printf ("    gcda files:  %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
12931debfc3dSmrg 	  gcda_files[0]-unique_gcda_files[0]);
12941debfc3dSmrg   printf ("  unique files:  %12u\t%12u\n", unique_gcda_files[0],
12951debfc3dSmrg 	  unique_gcda_files[1]);
12961debfc3dSmrg   printf ("     hot files:  %12u\t%12u\t%12u\n", hot_gcda_files[0],
12971debfc3dSmrg 	  hot_gcda_files[1], both_hot_cnt);
12981debfc3dSmrg   printf ("    cold files:  %12u\t%12u\t%12u\n", cold_gcda_files[0],
12991debfc3dSmrg 	  cold_gcda_files[1], both_cold_cnt);
13001debfc3dSmrg   printf ("    zero files:  %12u\t%12u\t%12u\n", zero_gcda_files[0],
13011debfc3dSmrg 	  zero_gcda_files[1], both_zero_cnt);
13021debfc3dSmrg 
13031debfc3dSmrg   return prg_val;
13041debfc3dSmrg }
13051debfc3dSmrg 
13061debfc3dSmrg /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
13071debfc3dSmrg    PROFILE2.
13081debfc3dSmrg    Return 0 on success: without mismatch. Reutrn 1 on error.  */
13091debfc3dSmrg 
13101debfc3dSmrg int
gcov_profile_overlap(struct gcov_info * profile1,struct gcov_info * profile2)13111debfc3dSmrg gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
13121debfc3dSmrg {
13131debfc3dSmrg   double result;
13141debfc3dSmrg 
13151debfc3dSmrg   result = calculate_overlap (profile1, profile2);
13161debfc3dSmrg 
13171debfc3dSmrg   if (result > 0)
13181debfc3dSmrg     {
13191debfc3dSmrg       printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
13201debfc3dSmrg       return 0;
13211debfc3dSmrg     }
13221debfc3dSmrg   return 1;
13231debfc3dSmrg }
1324