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