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