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