]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/libgcov-util.c
LibF7: Use monic denominator polynomials to save a multiplication.
[thirdparty/gcc.git] / libgcc / libgcov-util.c
CommitLineData
c77556a5
RX
1/* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
83ffe9cd 3/* Copyright (C) 2014-2023 Free Software Foundation, Inc.
c77556a5
RX
4 Contributed by Rong Xu <xur@google.com>.
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 3, or (at your option) any later
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18Under Section 7 of GPL version 3, you are granted additional
19permissions described in the GCC Runtime Library Exception, version
203.1, as published by the Free Software Foundation.
21
22You should have received a copy of the GNU General Public License and
23a copy of the GCC Runtime Library Exception along with this program;
24see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25<http://www.gnu.org/licenses/>. */
26
27
28#define IN_GCOV_TOOL 1
29
30#include "libgcov.h"
31#include "intl.h"
32#include "diagnostic.h"
33#include "version.h"
34#include "demangle.h"
512cc015 35#include "gcov-io.h"
c77556a5
RX
36
37/* Borrowed from basic-block.h. */
38#define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
39
40extern gcov_position_t gcov_position();
41extern int gcov_is_error();
c77556a5
RX
42
43/* Verbose mode for debug. */
44static int verbose;
45
46/* Set verbose flag. */
47void gcov_set_verbose (void)
48{
49 verbose = 1;
50}
51
52/* The following part is to read Gcda and reconstruct GCOV_INFO. */
53
54#include "obstack.h"
55#include <unistd.h>
0e4a0def 56#ifdef HAVE_FTW_H
c77556a5 57#include <ftw.h>
0e4a0def 58#endif
c77556a5 59
ece21ff6
ML
60static void tag_function (unsigned, int);
61static void tag_blocks (unsigned, int);
62static void tag_arcs (unsigned, int);
63static void tag_lines (unsigned, int);
64static void tag_counters (unsigned, int);
65static void tag_summary (unsigned, int);
c77556a5
RX
66
67/* The gcov_info for the first module. */
68static struct gcov_info *curr_gcov_info;
69/* The gcov_info being processed. */
70static struct gcov_info *gcov_info_head;
71/* This variable contains all the functions in current module. */
72static struct obstack fn_info;
73/* The function being processed. */
74static struct gcov_fn_info *curr_fn_info;
75/* The number of functions seen so far. */
76static unsigned num_fn_info;
77/* This variable contains all the counters for current module. */
78static int k_ctrs_mask[GCOV_COUNTERS];
79/* The kind of counters that have been seen. */
80static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
81/* Number of kind of counters that have been seen. */
82static int k_ctrs_types;
c77556a5
RX
83
84/* Merge functions for counters. */
85#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
86static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
87#include "gcov-counter.def"
88};
89#undef DEF_GCOV_COUNTER
90
91/* Set the ctrs field in gcov_fn_info object FN_INFO. */
92
93static void
94set_fn_ctrs (struct gcov_fn_info *fn_info)
95{
96 int j = 0, i;
97
98 for (i = 0; i < GCOV_COUNTERS; i++)
99 {
100 if (k_ctrs_mask[i] == 0)
101 continue;
102 fn_info->ctrs[j].num = k_ctrs[i].num;
103 fn_info->ctrs[j].values = k_ctrs[i].values;
104 j++;
105 }
106 if (k_ctrs_types == 0)
107 k_ctrs_types = j;
108 else
109 gcc_assert (j == k_ctrs_types);
110}
111
112/* For each tag in gcda file, we have an entry here.
113 TAG is the tag value; NAME is the tag name; and
114 PROC is the handler function. */
115
116typedef struct tag_format
117{
118 unsigned tag;
119 char const *name;
ece21ff6 120 void (*proc) (unsigned, int);
c77556a5
RX
121} tag_format_t;
122
123/* Handler table for various Tags. */
124
125static const tag_format_t tag_table[] =
126{
127 {0, "NOP", NULL},
128 {0, "UNKNOWN", NULL},
129 {0, "COUNTERS", tag_counters},
130 {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
131 {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
132 {GCOV_TAG_ARCS, "ARCS", tag_arcs},
133 {GCOV_TAG_LINES, "LINES", tag_lines},
134 {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
c77556a5
RX
135 {0, NULL, NULL}
136};
137
138/* Handler for reading function tag. */
139
140static void
ece21ff6 141tag_function (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
c77556a5
RX
142{
143 int i;
144
145 /* write out previous fn_info. */
146 if (num_fn_info)
147 {
148 set_fn_ctrs (curr_fn_info);
149 obstack_ptr_grow (&fn_info, curr_fn_info);
150 }
151
152 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
153 counter types. */
154 curr_fn_info = (struct gcov_fn_info *) xcalloc (sizeof (struct gcov_fn_info)
155 + GCOV_COUNTERS * sizeof (struct gcov_ctr_info), 1);
156
157 for (i = 0; i < GCOV_COUNTERS; i++)
158 k_ctrs[i].num = 0;
159 k_ctrs_types = 0;
160
161 curr_fn_info->key = curr_gcov_info;
162 curr_fn_info->ident = gcov_read_unsigned ();
163 curr_fn_info->lineno_checksum = gcov_read_unsigned ();
164 curr_fn_info->cfg_checksum = gcov_read_unsigned ();
165 num_fn_info++;
166
167 if (verbose)
168 fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
169}
170
171/* Handler for reading block tag. */
172
173static void
ece21ff6 174tag_blocks (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
c77556a5
RX
175{
176 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
177 gcc_unreachable ();
178}
179
180/* Handler for reading flow arc tag. */
181
182static void
ece21ff6 183tag_arcs (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
c77556a5
RX
184{
185 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
186 gcc_unreachable ();
187}
188
189/* Handler for reading line tag. */
190
191static void
ece21ff6 192tag_lines (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
c77556a5
RX
193{
194 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
195 gcc_unreachable ();
196}
197
198/* Handler for reading counters array tag with value as TAG and length of LENGTH. */
199
200static void
ece21ff6 201tag_counters (unsigned tag, int length)
c77556a5 202{
ece21ff6 203 unsigned n_counts = GCOV_TAG_COUNTER_NUM (abs (length));
c77556a5
RX
204 gcov_type *values;
205 unsigned ix;
206 unsigned tag_ix;
207
208 tag_ix = GCOV_COUNTER_FOR_TAG (tag);
209 gcc_assert (tag_ix < GCOV_COUNTERS);
210 k_ctrs_mask [tag_ix] = 1;
211 gcc_assert (k_ctrs[tag_ix].num == 0);
212 k_ctrs[tag_ix].num = n_counts;
213
ece21ff6
ML
214 k_ctrs[tag_ix].values = values = (gcov_type *) xcalloc (sizeof (gcov_type),
215 n_counts);
c77556a5
RX
216 gcc_assert (values);
217
ece21ff6
ML
218 if (length > 0)
219 for (ix = 0; ix != n_counts; ix++)
220 values[ix] = gcov_read_counter ();
c77556a5
RX
221}
222
223/* Handler for reading summary tag. */
224
225static void
ece21ff6 226tag_summary (unsigned tag ATTRIBUTE_UNUSED, int ATTRIBUTE_UNUSED)
c77556a5 227{
88891c5f 228 gcov_read_summary (&curr_gcov_info->summary);
c77556a5
RX
229}
230
231/* This function is called at the end of reading a gcda file.
232 It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO. */
233
234static void
235read_gcda_finalize (struct gcov_info *obj_info)
236{
237 int i;
238
239 set_fn_ctrs (curr_fn_info);
240 obstack_ptr_grow (&fn_info, curr_fn_info);
241
512cc015
ML
242 /* We set the following fields: merge, n_functions, functions
243 and summary. */
c77556a5 244 obj_info->n_functions = num_fn_info;
5fc312a9 245 obj_info->functions = (struct gcov_fn_info**) obstack_finish (&fn_info);
c77556a5
RX
246
247 /* wrap all the counter array. */
248 for (i=0; i< GCOV_COUNTERS; i++)
249 {
250 if (k_ctrs_mask[i])
251 obj_info->merge[i] = ctr_merge_functions[i];
252 }
253}
254
255/* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
256 Program level summary CURRENT_SUMMARY will also be updated. */
257
258static struct gcov_info *
259read_gcda_file (const char *filename)
260{
261 unsigned tags[4];
262 unsigned depth = 0;
17d1594b 263 unsigned version;
c77556a5
RX
264 struct gcov_info *obj_info;
265 int i;
266
267 for (i=0; i< GCOV_COUNTERS; i++)
268 k_ctrs_mask[i] = 0;
269 k_ctrs_types = 0;
270
c77556a5 271 /* Read magic. */
17d1594b 272 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
c77556a5
RX
273 {
274 fnotice (stderr, "%s:not a gcov data file\n", filename);
c77556a5
RX
275 return NULL;
276 }
277
278 /* Read version. */
279 version = gcov_read_unsigned ();
280 if (version != GCOV_VERSION)
281 {
282 fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
c77556a5
RX
283 return NULL;
284 }
285
286 /* Instantiate a gcov_info object. */
287 curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
288 sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
289
290 obj_info->version = version;
f9b59dd8 291 obj_info->filename = filename;
c77556a5
RX
292 obstack_init (&fn_info);
293 num_fn_info = 0;
294 curr_fn_info = 0;
c77556a5 295
76cae648
SH
296 /* Prepend to global gcov info list. */
297 obj_info->next = gcov_info_head;
298 gcov_info_head = obj_info;
c77556a5
RX
299
300 /* Read stamp. */
301 obj_info->stamp = gcov_read_unsigned ();
302
72e0c742
ML
303 /* Read checksum. */
304 obj_info->checksum = gcov_read_unsigned ();
305
c77556a5
RX
306 while (1)
307 {
308 gcov_position_t base;
309 unsigned tag, length;
310 tag_format_t const *format;
311 unsigned tag_depth;
312 int error;
313 unsigned mask;
314
315 tag = gcov_read_unsigned ();
316 if (!tag)
9b84e7a8 317 break;
ece21ff6
ML
318 int read_length = (int)gcov_read_unsigned ();
319 length = read_length > 0 ? read_length : 0;
c77556a5
RX
320 base = gcov_position ();
321 mask = GCOV_TAG_MASK (tag) >> 1;
322 for (tag_depth = 4; mask; mask >>= 8)
9b84e7a8
RX
323 {
324 if (((mask & 0xff) != 0xff))
325 {
a9c697b8 326 warning (0, "%s:tag %qx is invalid", filename, tag);
9b84e7a8
RX
327 break;
328 }
329 tag_depth--;
330 }
c77556a5 331 for (format = tag_table; format->name; format++)
9b84e7a8
RX
332 if (format->tag == tag)
333 goto found;
c77556a5
RX
334 format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
335 found:;
336 if (tag)
9b84e7a8
RX
337 {
338 if (depth && depth < tag_depth)
339 {
340 if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
a9c697b8 341 warning (0, "%s:tag %qx is incorrectly nested",
9b84e7a8
RX
342 filename, tag);
343 }
344 depth = tag_depth;
345 tags[depth - 1] = tag;
346 }
c77556a5
RX
347
348 if (format->proc)
349 {
9b84e7a8 350 unsigned long actual_length;
c77556a5 351
ece21ff6 352 (*format->proc) (tag, read_length);
c77556a5 353
9b84e7a8
RX
354 actual_length = gcov_position () - base;
355 if (actual_length > length)
a9c697b8 356 warning (0, "%s:record size mismatch %lu bytes overread",
9b84e7a8
RX
357 filename, actual_length - length);
358 else if (length > actual_length)
a9c697b8 359 warning (0, "%s:record size mismatch %lu bytes unread",
9b84e7a8
RX
360 filename, length - actual_length);
361 }
c77556a5
RX
362
363 gcov_sync (base, length);
364 if ((error = gcov_is_error ()))
9b84e7a8 365 {
a9c697b8
MS
366 warning (0, error < 0 ? "%s:counter overflow at %lu" :
367 "%s:read error at %lu", filename,
9b84e7a8
RX
368 (long unsigned) gcov_position ());
369 break;
370 }
c77556a5
RX
371 }
372
373 read_gcda_finalize (obj_info);
c77556a5
RX
374
375 return obj_info;
376}
377
0e4a0def 378#ifdef HAVE_FTW_H
c77556a5
RX
379/* This will be called by ftw(). It opens and read a gcda file FILENAME.
380 Return a non-zero value to stop the tree walk. */
381
382static int
383ftw_read_file (const char *filename,
384 const struct stat *status ATTRIBUTE_UNUSED,
385 int type)
386{
1ff8d194
SH
387 size_t filename_len;
388 size_t suffix_len;
c77556a5
RX
389
390 /* Only read regular files. */
391 if (type != FTW_F)
392 return 0;
393
394 filename_len = strlen (filename);
395 suffix_len = strlen (GCOV_DATA_SUFFIX);
396
397 if (filename_len <= suffix_len)
398 return 0;
399
400 if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
401 return 0;
402
403 if (verbose)
404 fnotice (stderr, "reading file: %s\n", filename);
405
c190b0e6
SH
406 if (!gcov_open (filename, 1))
407 {
92475ea8 408 fnotice (stderr, "%s:cannot open:%s\n", filename, xstrerror (errno));
c190b0e6
SH
409 return 0;
410 }
411
76cae648 412 (void)read_gcda_file (xstrdup (filename));
c190b0e6 413 gcov_close ();
c77556a5
RX
414
415 return 0;
416}
0e4a0def 417#endif
c77556a5
RX
418
419/* Initializer for reading a profile dir. */
420
421static inline void
422read_profile_dir_init (void)
423{
424 gcov_info_head = 0;
425}
426
427/* Driver for read a profile directory and convert into gcov_info list in memory.
428 Return NULL on error,
6dc33097 429 Return the head of gcov_info list on success. */
c77556a5
RX
430
431struct gcov_info *
432gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
433{
434 char *pwd;
435 int ret;
436
437 read_profile_dir_init ();
438
439 if (access (dir_name, R_OK) != 0)
440 {
441 fnotice (stderr, "cannot access directory %s\n", dir_name);
442 return NULL;
443 }
444 pwd = getcwd (NULL, 0);
445 gcc_assert (pwd);
446 ret = chdir (dir_name);
447 if (ret !=0)
448 {
449 fnotice (stderr, "%s is not a directory\n", dir_name);
450 return NULL;
451 }
0e4a0def 452#ifdef HAVE_FTW_H
c77556a5 453 ftw (".", ftw_read_file, 50);
0e4a0def 454#endif
45309d28 455 chdir (pwd);
c77556a5
RX
456 free (pwd);
457
c77556a5
RX
458 return gcov_info_head;;
459}
460
461/* This part of the code is to merge profile counters. These
462 variables are set in merge_wrapper and to be used by
463 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
464
465/* We save the counter value address to this variable. */
466static gcov_type *gcov_value_buf;
467
468/* The number of counter values to be read by current merging. */
469static gcov_unsigned_t gcov_value_buf_size;
470
471/* The index of counter values being read. */
472static gcov_unsigned_t gcov_value_buf_pos;
473
474/* The weight of current merging. */
475static unsigned gcov_merge_weight;
476
477/* Read a counter value from gcov_value_buf array. */
478
479gcov_type
480gcov_read_counter_mem (void)
481{
482 gcov_type ret;
483 gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
484 ret = *(gcov_value_buf + gcov_value_buf_pos);
485 ++gcov_value_buf_pos;
486 return ret;
487}
488
489/* Return the recorded merge weight. */
490
491unsigned
492gcov_get_merge_weight (void)
493{
494 return gcov_merge_weight;
495}
496
497/* A wrapper function for merge functions. It sets up the
498 value buffer and weights and then calls the merge function. */
499
500static void
5fc312a9
ML
501merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n1,
502 gcov_type *v2, gcov_unsigned_t n2, unsigned w)
c77556a5
RX
503{
504 gcov_value_buf = v2;
505 gcov_value_buf_pos = 0;
5fc312a9 506 gcov_value_buf_size = n2;
c77556a5 507 gcov_merge_weight = w;
5fc312a9
ML
508 (*f) (v1, n1);
509}
510
511/* Convert on disk representation of a TOPN counter to in memory representation
512 that is expected from __gcov_merge_topn function. */
513
514static void
515topn_to_memory_representation (struct gcov_ctr_info *info)
516{
517 auto_vec<gcov_type> output;
518 gcov_type *values = info->values;
519 int count = info->num;
520
521 while (count > 0)
522 {
523 output.safe_push (values[0]);
524 gcov_type n = values[1];
525 output.safe_push (n);
526 if (n > 0)
527 {
528 struct gcov_kvp *tuples
529 = (struct gcov_kvp *)xcalloc (sizeof (struct gcov_kvp), n);
530 for (unsigned i = 0; i < n - 1; i++)
531 tuples[i].next = &tuples[i + 1];
532 for (unsigned i = 0; i < n; i++)
533 {
534 tuples[i].value = values[2 + 2 * i];
535 tuples[i].count = values[2 + 2 * i + 1];
536 }
537 output.safe_push ((intptr_t)&tuples[0]);
538 }
539 else
540 output.safe_push (0);
541
542 unsigned len = 2 * n + 2;
543 values += len;
544 count -= len;
545 }
546 gcc_assert (count == 0);
547
548 /* Allocate new buffer and copy it there. */
549 info->num = output.length ();
550 info->values = (gcov_type *)xmalloc (sizeof (gcov_type) * info->num);
551 for (unsigned i = 0; i < info->num; i++)
552 info->values[i] = output[i];
c77556a5
RX
553}
554
555/* Offline tool to manipulate profile data.
556 This tool targets on matched profiles. But it has some tolerance on
557 unmatched profiles.
558 When merging p1 to p2 (p2 is the dst),
559 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
560 emit warning
561 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
562 specified weight; emit warning.
563 * m.gcda in both p1 and p2:
564 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
565 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
566 p2->m.gcda->f and
567 drop p1->m.gcda->f. A warning is emitted. */
568
569/* Add INFO2's counter to INFO1, multiplying by weight W. */
570
571static int
572gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
573{
574 unsigned f_ix;
575 unsigned n_functions = info1->n_functions;
576 int has_mismatch = 0;
577
578 gcc_assert (info2->n_functions == n_functions);
88891c5f
ML
579
580 /* Merge summary. */
581 info1->summary.runs += info2->summary.runs;
582 info1->summary.sum_max += info2->summary.sum_max;
583
c77556a5
RX
584 for (f_ix = 0; f_ix < n_functions; f_ix++)
585 {
586 unsigned t_ix;
5fc312a9
ML
587 struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
588 struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
589 struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
c77556a5
RX
590
591 if (!gfi_ptr1 || gfi_ptr1->key != info1)
592 continue;
593 if (!gfi_ptr2 || gfi_ptr2->key != info2)
594 continue;
595
596 if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
597 {
598 fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
599 info1->filename);
600 has_mismatch = 1;
601 continue;
602 }
603 ci_ptr1 = gfi_ptr1->ctrs;
604 ci_ptr2 = gfi_ptr2->ctrs;
605 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
606 {
607 gcov_merge_fn merge1 = info1->merge[t_ix];
608 gcov_merge_fn merge2 = info2->merge[t_ix];
609
610 gcc_assert (merge1 == merge2);
611 if (!merge1)
612 continue;
5fc312a9
ML
613
614 if (merge1 == __gcov_merge_topn)
615 topn_to_memory_representation (ci_ptr1);
616 else
617 gcc_assert (ci_ptr1->num == ci_ptr2->num);
618
619 merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num,
620 ci_ptr2->values, ci_ptr2->num, w);
c77556a5
RX
621 ci_ptr1++;
622 ci_ptr2++;
623 }
624 }
625
626 return has_mismatch;
627}
628
629/* Find and return the match gcov_info object for INFO from ARRAY.
630 SIZE is the length of ARRAY.
631 Return NULL if there is no match. */
632
633static struct gcov_info *
9b84e7a8
RX
634find_match_gcov_info (struct gcov_info **array, int size,
635 struct gcov_info *info)
c77556a5
RX
636{
637 struct gcov_info *gi_ptr;
638 struct gcov_info *ret = NULL;
639 int i;
640
641 for (i = 0; i < size; i++)
642 {
643 gi_ptr = array[i];
644 if (gi_ptr == 0)
645 continue;
646 if (!strcmp (gi_ptr->filename, info->filename))
647 {
648 ret = gi_ptr;
649 array[i] = 0;
650 break;
651 }
652 }
653
654 if (ret && ret->n_functions != info->n_functions)
655 {
656 fnotice (stderr, "mismatched profiles in %s (%d functions"
657 " vs %d functions)\n",
658 ret->filename,
659 ret->n_functions,
660 info->n_functions);
661 ret = NULL;
662 }
663 return ret;
664}
665
666/* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
336ea18a
SH
667 Return the list of merged gcov_info objects. Return NULL if the list is
668 empty. */
c77556a5 669
336ea18a 670struct gcov_info *
c77556a5
RX
671gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
672 int w1, int w2)
673{
674 struct gcov_info *gi_ptr;
675 struct gcov_info **tgt_infos;
336ea18a 676 struct gcov_info **tgt_tail;
c77556a5
RX
677 struct gcov_info **in_src_not_tgt;
678 unsigned tgt_cnt = 0, src_cnt = 0;
679 unsigned unmatch_info_cnt = 0;
680 unsigned int i;
681
682 for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
683 tgt_cnt++;
684 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
685 src_cnt++;
686 tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
687 * tgt_cnt);
688 gcc_assert (tgt_infos);
689 in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
690 * src_cnt);
691 gcc_assert (in_src_not_tgt);
692
693 for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
694 tgt_infos[i] = gi_ptr;
695
336ea18a
SH
696 if (tgt_cnt)
697 tgt_tail = &tgt_infos[tgt_cnt - 1]->next;
698 else
699 tgt_tail = &tgt_profile;
c77556a5
RX
700
701 /* First pass on tgt_profile, we multiply w1 to all counters. */
702 if (w1 > 1)
703 {
704 for (i = 0; i < tgt_cnt; i++)
705 gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
706 }
707
708 /* Second pass, add src_profile to the tgt_profile. */
709 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
710 {
711 struct gcov_info *gi_ptr1;
712
713 gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
714 if (gi_ptr1 == NULL)
715 {
716 in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
717 continue;
718 }
719 gcov_merge (gi_ptr1, gi_ptr, w2);
720 }
721
722 /* For modules in src but not in tgt. We adjust the counter and append. */
723 for (i = 0; i < unmatch_info_cnt; i++)
724 {
725 gi_ptr = in_src_not_tgt[i];
726 gcov_merge (gi_ptr, gi_ptr, w2 - 1);
2e6fc1ac 727 gi_ptr->next = NULL;
336ea18a
SH
728 *tgt_tail = gi_ptr;
729 tgt_tail = &gi_ptr->next;
c77556a5
RX
730 }
731
c2f7a665
ML
732 free (in_src_not_tgt);
733 free (tgt_infos);
734
336ea18a 735 return tgt_profile;
c77556a5
RX
736}
737
210e32b6
SH
738/* Deserialize gcov_info objects and associated filenames from the file
739 specified by FILENAME to create a profile list. When FILENAME is NULL, read
740 from stdin. Return the profile list. */
741
742struct gcov_info *
743deserialize_profiles (const char *filename)
744{
745 read_profile_dir_init ();
746
747 while (true)
748 {
749 unsigned version;
750 const char *filename_of_info;
751 struct gcov_info *obj_info;
752
753 if (!gcov_magic (gcov_read_unsigned (), GCOV_FILENAME_MAGIC))
754 {
755 if (gcov_is_error () != 2)
756 fnotice (stderr, "%s:not a gcfn stream\n", filename);
757 break;
758 }
759
760 version = gcov_read_unsigned ();
761 if (version != GCOV_VERSION)
762 {
763 fnotice (stderr, "%s:incorrect gcov version %d vs %d \n",
764 filename, version, GCOV_VERSION);
765 break;
766 }
767
768 filename_of_info = gcov_read_string ();
769 if (!filename_of_info)
770 {
771 fnotice (stderr, "%s:no filename in gcfn stream\n",
772 filename);
773 break;
774 }
775
776 obj_info = read_gcda_file (filename);
777 if (!obj_info)
778 break;
779
780 obj_info->filename = filename_of_info;
781 }
782
783 return gcov_info_head;
784}
785
786/* For each profile of the list specified by SRC_PROFILE, read the GCDA file of
787 the profile. If a GCDA file exists, add the profile to a list. Return the
788 profile list. */
789
790struct gcov_info *
791get_target_profiles_for_merge (struct gcov_info *src_profile)
792{
793 struct gcov_info *gi_ptr;
794
795 read_profile_dir_init ();
796
797 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
798 if (gcov_open (gi_ptr->filename, 1))
799 {
800 (void)read_gcda_file (gi_ptr->filename);
801 gcov_close ();
802 }
803
804 return gcov_info_head;
805}
806
807/* Deserialize gcov_info objects and associated filenames from the file
808 specified by FILENAME to create a source profile list. When FILENAME is
809 NULL, read from stdin. Use the filenames of the source profile list to get
810 a target profile list. Merge the source profile list into the target
811 profile list using weights W1 and W2. Return the list of merged gcov_info
812 objects. Return NULL if the list is empty. */
813
814struct gcov_info *
815gcov_profile_merge_stream (const char *filename, int w1, int w2)
816{
817 struct gcov_info *tgt_profile;
818 struct gcov_info *src_profile;
819
820 if (!gcov_open (filename, 1))
821 {
92475ea8 822 fnotice (stderr, "%s:cannot open:%s\n", filename, xstrerror (errno));
210e32b6
SH
823 return NULL;
824 }
825
826 src_profile = deserialize_profiles (filename ? filename : "<stdin>");
827 gcov_close ();
828 tgt_profile = get_target_profiles_for_merge (src_profile);
829
830 return gcov_profile_merge (tgt_profile, src_profile, w1, w2);
831}
832
c77556a5
RX
833typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
834
835/* Performing FN upon arc counters. */
836
837static void
838__gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
839 counter_op_fn fn, void *data1, void *data2)
840{
841 for (; n_counters; counters++, n_counters--)
842 {
843 gcov_type val = *counters;
844 *counters = fn(val, data1, data2);
845 }
846}
847
848/* Performing FN upon ior counters. */
849
850static void
851__gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
852 unsigned n_counters ATTRIBUTE_UNUSED,
853 counter_op_fn fn ATTRIBUTE_UNUSED,
854 void *data1 ATTRIBUTE_UNUSED,
855 void *data2 ATTRIBUTE_UNUSED)
856{
857 /* Do nothing. */
858}
859
860/* Performing FN upon time-profile counters. */
861
862static void
863__gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
864 unsigned n_counters ATTRIBUTE_UNUSED,
865 counter_op_fn fn ATTRIBUTE_UNUSED,
866 void *data1 ATTRIBUTE_UNUSED,
867 void *data2 ATTRIBUTE_UNUSED)
868{
869 /* Do nothing. */
870}
871
596341c7 872/* Performing FN upon TOP N counters. */
c77556a5
RX
873
874static void
596341c7
ML
875__gcov_topn_counter_op (gcov_type *counters, unsigned n_counters,
876 counter_op_fn fn, void *data1, void *data2)
c77556a5
RX
877{
878 unsigned i, n_measures;
879
880 gcc_assert (!(n_counters % 3));
881 n_measures = n_counters / 3;
882 for (i = 0; i < n_measures; i++, counters += 3)
883 {
884 counters[1] = fn (counters[1], data1, data2);
885 counters[2] = fn (counters[2], data1, data2);
886 }
887}
888
889/* Scaling the counter value V by multiplying *(float*) DATA1. */
890
891static gcov_type
892fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
893{
894 float f = *(float *) data1;
895 return (gcov_type) (v * f);
896}
897
898/* Scaling the counter value V by multiplying DATA2/DATA1. */
899
900static gcov_type
901int_scale (gcov_type v, void *data1, void *data2)
902{
903 int n = *(int *) data1;
904 int d = *(int *) data2;
905 return (gcov_type) ( RDIV (v,d) * n);
906}
907
908/* Type of function used to process counters. */
909typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
910 counter_op_fn, void *, void *);
911
912/* Function array to process profile counters. */
913#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
914 __gcov ## FN_TYPE ## _counter_op,
915static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
916#include "gcov-counter.def"
917};
918#undef DEF_GCOV_COUNTER
919
920/* Driver for scaling profile counters. */
921
922int
923gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
924{
925 struct gcov_info *gi_ptr;
926 unsigned f_ix;
927
928 if (verbose)
929 fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
930
931 /* Scaling the counters. */
932 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
933 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
934 {
935 unsigned t_ix;
936 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
937 const struct gcov_ctr_info *ci_ptr;
938
939 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
940 continue;
941
942 ci_ptr = gfi_ptr->ctrs;
943 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
944 {
945 gcov_merge_fn merge = gi_ptr->merge[t_ix];
946
947 if (!merge)
948 continue;
949 if (d == 0)
950 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
951 fp_scale, &scale_factor, NULL);
952 else
953 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
954 int_scale, &n, &d);
955 ci_ptr++;
956 }
957 }
958
959 return 0;
960}
961
962/* Driver to normalize profile counters. */
963
964int
965gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
966{
967 struct gcov_info *gi_ptr;
968 gcov_type curr_max_val = 0;
969 unsigned f_ix;
970 unsigned int i;
971 float scale_factor;
972
973 /* Find the largest count value. */
974 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
975 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
976 {
977 unsigned t_ix;
978 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
979 const struct gcov_ctr_info *ci_ptr;
980
981 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
982 continue;
983
984 ci_ptr = gfi_ptr->ctrs;
985 for (t_ix = 0; t_ix < 1; t_ix++)
986 {
987 for (i = 0; i < ci_ptr->num; i++)
988 if (ci_ptr->values[i] > curr_max_val)
989 curr_max_val = ci_ptr->values[i];
990 ci_ptr++;
991 }
992 }
993
994 scale_factor = (float)max_val / curr_max_val;
995 if (verbose)
98b5dc61 996 fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
c77556a5
RX
997
998 return gcov_profile_scale (profile, scale_factor, 0, 0);
999}
9b84e7a8
RX
1000
1001/* The following variables are defined in gcc/gcov-tool.c. */
1002extern int overlap_func_level;
1003extern int overlap_obj_level;
1004extern int overlap_hot_only;
1005extern int overlap_use_fullname;
1006extern double overlap_hot_threshold;
1007
1008/* Compute the overlap score of two values. The score is defined as:
1009 min (V1/SUM_1, V2/SUM_2) */
1010
1011static double
1012calculate_2_entries (const unsigned long v1, const unsigned long v2,
1013 const double sum_1, const double sum_2)
1014{
1015 double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
1016 double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
1017
1018 if (val2 < val1)
1019 val1 = val2;
1020
1021 return val1;
1022}
1023
1024/* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
9b84e7a8
RX
1025 This function also updates cumulative score CUM_1_RESULT and
1026 CUM_2_RESULT. */
1027
1028static double
1029compute_one_gcov (const struct gcov_info *gcov_info1,
1030 const struct gcov_info *gcov_info2,
1031 const double sum_1, const double sum_2,
1032 double *cum_1_result, double *cum_2_result)
1033{
1034 unsigned f_ix;
1035 double ret = 0;
1036 double cum_1 = 0, cum_2 = 0;
1037 const struct gcov_info *gcov_info = 0;
1038 double *cum_p;
1039 double sum;
1040
1041 gcc_assert (gcov_info1 || gcov_info2);
1042 if (!gcov_info1)
1043 {
1044 gcov_info = gcov_info2;
1045 cum_p = cum_2_result;
1046 sum = sum_2;
1047 *cum_1_result = 0;
1048 } else
1049 if (!gcov_info2)
1050 {
1051 gcov_info = gcov_info1;
1052 cum_p = cum_1_result;
1053 sum = sum_1;
1054 *cum_2_result = 0;
1055 }
1056
1057 if (gcov_info)
1058 {
1059 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
1060 {
9b84e7a8
RX
1061 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
1062 if (!gfi_ptr || gfi_ptr->key != gcov_info)
1063 continue;
1064 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
7f3577f5
ML
1065 unsigned c_num;
1066 for (c_num = 0; c_num < ci_ptr->num; c_num++)
1067 cum_1 += ci_ptr->values[c_num] / sum;
9b84e7a8
RX
1068 }
1069 *cum_p = cum_1;
1070 return 0.0;
1071 }
1072
1073 for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
1074 {
9b84e7a8
RX
1075 double func_cum_1 = 0.0;
1076 double func_cum_2 = 0.0;
1077 double func_val = 0.0;
1078 int nonzero = 0;
1079 int hot = 0;
1080 const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
1081 const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
1082
1083 if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
1084 continue;
1085 if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
1086 continue;
1087
1088 const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
1089 const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
7f3577f5
ML
1090 unsigned c_num;
1091 for (c_num = 0; c_num < ci_ptr1->num; c_num++)
1092 {
1093 if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
1094 {
1095 func_val += calculate_2_entries (ci_ptr1->values[c_num],
1096 ci_ptr2->values[c_num],
1097 sum_1, sum_2);
1098
1099 func_cum_1 += ci_ptr1->values[c_num] / sum_1;
1100 func_cum_2 += ci_ptr2->values[c_num] / sum_2;
1101 nonzero = 1;
1102 if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
1103 || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
1104 hot = 1;
1105 }
1106 }
9b84e7a8 1107
9b84e7a8
RX
1108 ret += func_val;
1109 cum_1 += func_cum_1;
1110 cum_2 += func_cum_2;
1111 if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
1112 {
1113 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1114 gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
1115 }
1116 }
1117 *cum_1_result = cum_1;
1118 *cum_2_result = cum_2;
1119 return ret;
1120}
1121
1122/* Test if all counter values in this GCOV_INFO are cold.
1123 "Cold" is defined as the counter value being less than
1124 or equal to THRESHOLD. */
1125
1126static bool
1127gcov_info_count_all_cold (const struct gcov_info *gcov_info,
1128 gcov_type threshold)
1129{
1130 unsigned f_ix;
1131
1132 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
1133 {
9b84e7a8
RX
1134 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
1135
1136 if (!gfi_ptr || gfi_ptr->key != gcov_info)
1137 continue;
1138 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
7f3577f5
ML
1139 for (unsigned c_num = 0; c_num < ci_ptr->num; c_num++)
1140 if (ci_ptr->values[c_num] > threshold)
1141 return false;
9b84e7a8
RX
1142 }
1143
1144 return true;
1145}
1146
1147/* Test if all counter values in this GCOV_INFO are 0. */
1148
1149static bool
1150gcov_info_count_all_zero (const struct gcov_info *gcov_info)
1151{
1152 return gcov_info_count_all_cold (gcov_info, 0);
1153}
1154
1155/* A pair of matched GCOV_INFO.
1156 The flag is a bitvector:
1157 b0: obj1's all counts are 0;
1158 b1: obj1's all counts are cold (but no 0);
1159 b2: obj1 is hot;
1160 b3: no obj1 to match obj2;
1161 b4: obj2's all counts are 0;
1162 b5: obj2's all counts are cold (but no 0);
1163 b6: obj2 is hot;
1164 b7: no obj2 to match obj1;
1165 */
1166struct overlap_t {
1167 const struct gcov_info *obj1;
1168 const struct gcov_info *obj2;
1169 char flag;
1170};
1171
1172#define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1173#define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1174#define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1175
1176/* Cumlative overlap dscore for profile1 and profile2. */
1177static double overlap_sum_1, overlap_sum_2;
1178
9b84e7a8
RX
1179/* The number of gcda files in the profiles. */
1180static unsigned gcda_files[2];
1181
1182/* The number of unique gcda files in the profiles
1183 (not existing in the other profile). */
1184static unsigned unique_gcda_files[2];
1185
1186/* The number of gcda files that all counter values are 0. */
1187static unsigned zero_gcda_files[2];
1188
1189/* The number of gcda files that all counter values are cold (but not 0). */
1190static unsigned cold_gcda_files[2];
1191
1192/* The number of gcda files that includes hot counter values. */
1193static unsigned hot_gcda_files[2];
1194
1195/* The number of gcda files with hot count value in either profiles. */
1196static unsigned both_hot_cnt;
1197
1198/* The number of gcda files with all counts cold (but not 0) in
1199 both profiles. */
1200static unsigned both_cold_cnt;
1201
1202/* The number of gcda files with all counts 0 in both profiles. */
1203static unsigned both_zero_cnt;
1204
1205/* Extract the basename of the filename NAME. */
1206
1207static char *
1208extract_file_basename (const char *name)
1209{
1210 char *str;
1211 int len = 0;
1212 char *path = xstrdup (name);
1213 char sep_str[2];
1214
1215 sep_str[0] = DIR_SEPARATOR;
1216 sep_str[1] = 0;
1217 str = strstr(path, sep_str);
1218 do{
1219 len = strlen(str) + 1;
1220 path = &path[strlen(path) - len + 2];
1221 str = strstr(path, sep_str);
1222 } while(str);
1223
1224 return path;
1225}
1226
1227/* Utility function to get the filename. */
1228
1229static const char *
1230get_file_basename (const char *name)
1231{
1232 if (overlap_use_fullname)
1233 return name;
1234 return extract_file_basename (name);
1235}
1236
1237/* A utility function to set the flag for the gcda files. */
1238
1239static void
1240set_flag (struct overlap_t *e)
1241{
1242 char flag = 0;
1243
1244 if (!e->obj1)
1245 {
1246 unique_gcda_files[1]++;
1247 flag = 0x8;
1248 }
1249 else
1250 {
1251 gcda_files[0]++;
1252 if (gcov_info_count_all_zero (e->obj1))
1253 {
1254 zero_gcda_files[0]++;
1255 flag = 0x1;
1256 }
1257 else
1258 if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
1259 * overlap_hot_threshold))
1260 {
1261 cold_gcda_files[0]++;
1262 flag = 0x2;
1263 }
1264 else
1265 {
1266 hot_gcda_files[0]++;
1267 flag = 0x4;
1268 }
1269 }
1270
1271 if (!e->obj2)
1272 {
1273 unique_gcda_files[0]++;
1274 flag |= (0x8 << 4);
1275 }
1276 else
1277 {
1278 gcda_files[1]++;
1279 if (gcov_info_count_all_zero (e->obj2))
1280 {
1281 zero_gcda_files[1]++;
1282 flag |= (0x1 << 4);
1283 }
1284 else
1285 if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
1286 * overlap_hot_threshold))
1287 {
1288 cold_gcda_files[1]++;
1289 flag |= (0x2 << 4);
1290 }
1291 else
1292 {
1293 hot_gcda_files[1]++;
1294 flag |= (0x4 << 4);
1295 }
1296 }
1297
1298 gcc_assert (flag);
1299 e->flag = flag;
1300}
1301
1302/* Test if INFO1 and INFO2 are from the matched source file.
1303 Return 1 if they match; return 0 otherwise. */
1304
1305static int
1306matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
1307{
1308 /* For FDO, we have to match the name. This can be expensive.
1309 Maybe we should use hash here. */
1310 if (strcmp (info1->filename, info2->filename))
1311 return 0;
1312
1313 if (info1->n_functions != info2->n_functions)
1314 {
1315 fnotice (stderr, "mismatched profiles in %s (%d functions"
1316 " vs %d functions)\n",
1317 info1->filename,
1318 info1->n_functions,
1319 info2->n_functions);
1320 return 0;
1321 }
1322 return 1;
1323}
1324
9b84e7a8
RX
1325/* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1326 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1327 match and 1.0 meaning a perfect match. */
1328
1329static double
1330calculate_overlap (struct gcov_info *gcov_list1,
1331 struct gcov_info *gcov_list2)
1332{
9b84e7a8
RX
1333 unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
1334 unsigned int i, j;
9b84e7a8
RX
1335 const struct gcov_info *gi_ptr;
1336 struct overlap_t *all_infos;
1337
9b84e7a8
RX
1338 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
1339 list1_cnt++;
1340 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
1341 list2_cnt++;
1342 all_cnt = list1_cnt + list2_cnt;
1343 all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
1344 * all_cnt * 2);
1345 gcc_assert (all_infos);
1346
1347 i = 0;
1348 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
1349 {
1350 all_infos[i].obj1 = gi_ptr;
1351 all_infos[i].obj2 = 0;
1352 }
1353
1354 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
1355 {
1356 all_infos[i].obj1 = 0;
1357 all_infos[i].obj2 = gi_ptr;
1358 }
1359
1360 for (i = list1_cnt; i < all_cnt; i++)
1361 {
1362 if (all_infos[i].obj2 == 0)
1363 continue;
1364 for (j = 0; j < list1_cnt; j++)
1365 {
1366 if (all_infos[j].obj2 != 0)
1367 continue;
1368 if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
1369 {
1370 all_infos[j].obj2 = all_infos[i].obj2;
1371 all_infos[i].obj2 = 0;
1372 break;
1373 }
1374 }
1375 }
1376
1377 for (i = 0; i < all_cnt; i++)
1378 if (all_infos[i].obj1 || all_infos[i].obj2)
1379 {
1380 set_flag (all_infos + i);
1381 if (FLAG_ONE_HOT (all_infos[i].flag))
1382 both_hot_cnt++;
1383 if (FLAG_BOTH_COLD(all_infos[i].flag))
1384 both_cold_cnt++;
1385 if (FLAG_BOTH_ZERO(all_infos[i].flag))
1386 both_zero_cnt++;
1387 }
1388
1389 double prg_val = 0;
1390 double sum_val = 0;
1391 double sum_cum_1 = 0;
1392 double sum_cum_2 = 0;
1393
1394 for (i = 0; i < all_cnt; i++)
1395 {
1396 double val;
1397 double cum_1, cum_2;
1398 const char *filename;
1399
1400 if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
1401 continue;
1402 if (FLAG_BOTH_ZERO (all_infos[i].flag))
1403 continue;
1404
1405 if (all_infos[i].obj1)
1406 filename = get_file_basename (all_infos[i].obj1->filename);
1407 else
1408 filename = get_file_basename (all_infos[i].obj2->filename);
1409
1410 if (overlap_func_level)
1411 printf("\n processing %36s:\n", filename);
1412
1413 val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
1414 overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
1415
1416 if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
1417 {
1418 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1419 filename, val*100, cum_1*100, cum_2*100);
1420 sum_val += val;
1421 sum_cum_1 += cum_1;
1422 sum_cum_2 += cum_2;
1423 }
1424
1425 prg_val += val;
1426
1427 }
1428
c2f7a665
ML
1429 free (all_infos);
1430
9b84e7a8
RX
1431 if (overlap_obj_level)
1432 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1433 "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
1434
1435 printf (" Statistics:\n"
1436 " profile1_# profile2_# overlap_#\n");
1437 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
98b5dc61 1438 gcda_files[0]-unique_gcda_files[0]);
9b84e7a8 1439 printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
98b5dc61 1440 unique_gcda_files[1]);
9b84e7a8 1441 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
98b5dc61 1442 hot_gcda_files[1], both_hot_cnt);
9b84e7a8 1443 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
98b5dc61 1444 cold_gcda_files[1], both_cold_cnt);
9b84e7a8 1445 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
98b5dc61 1446 zero_gcda_files[1], both_zero_cnt);
9b84e7a8
RX
1447
1448 return prg_val;
1449}
1450
e0c8eebf
ML
1451/* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1452 PROFILE2.
9b84e7a8
RX
1453 Return 0 on success: without mismatch. Reutrn 1 on error. */
1454
1455int
1456gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
1457{
1458 double result;
1459
1460 result = calculate_overlap (profile1, profile2);
1461
1462 if (result > 0)
1463 {
1464 printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
1465 return 0;
1466 }
1467 return 1;
1468}