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