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