]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/libgcov-util.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / libgcov-util.c
CommitLineData
e76f6040 1/* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
f1717362 3/* Copyright (C) 2014-2016 Free Software Foundation, Inc.
e76f6040 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();
e76f6040 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>
c905381f 55#ifdef HAVE_FTW_H
e76f6040 56#include <ftw.h>
c905381f 57#endif
e76f6040 58
59static void tag_function (unsigned, unsigned);
60static void tag_blocks (unsigned, unsigned);
61static void tag_arcs (unsigned, unsigned);
62static void tag_lines (unsigned, unsigned);
63static void tag_counters (unsigned, unsigned);
64static void tag_summary (unsigned, unsigned);
65
66/* The gcov_info for the first module. */
67static struct gcov_info *curr_gcov_info;
68/* The gcov_info being processed. */
69static struct gcov_info *gcov_info_head;
70/* This variable contains all the functions in current module. */
71static struct obstack fn_info;
72/* The function being processed. */
73static struct gcov_fn_info *curr_fn_info;
74/* The number of functions seen so far. */
75static unsigned num_fn_info;
76/* This variable contains all the counters for current module. */
77static int k_ctrs_mask[GCOV_COUNTERS];
78/* The kind of counters that have been seen. */
79static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
80/* Number of kind of counters that have been seen. */
81static int k_ctrs_types;
e76f6040 82
83/* Merge functions for counters. */
84#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
85static 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
92static void
93set_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
115typedef 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
124static 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
140static void
141tag_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
173static void
174tag_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
182static void
183tag_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
191static void
192tag_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
200static void
201tag_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
223static void
224tag_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
234static void
235read_gcda_finalize (struct gcov_info *obj_info)
236{
237 int i;
238
239 set_fn_ctrs (curr_fn_info);
240 obstack_ptr_grow (&fn_info, curr_fn_info);
241
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
257static struct gcov_info *
258read_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 {
6401b74d 303 size_t len = strlen (filename) + 1;
304 char *str_dup = (char*) xmalloc (len);
e76f6040 305
6401b74d 306 memcpy (str_dup, filename, len);
e76f6040 307 obj_info->filename = str_dup;
e76f6040 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)
26054e0b 324 break;
e76f6040 325 length = gcov_read_unsigned ();
326 base = gcov_position ();
327 mask = GCOV_TAG_MASK (tag) >> 1;
328 for (tag_depth = 4; mask; mask >>= 8)
26054e0b 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 }
e76f6040 337 for (format = tag_table; format->name; format++)
26054e0b 338 if (format->tag == tag)
339 goto found;
e76f6040 340 format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
341 found:;
342 if (tag)
26054e0b 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 }
e76f6040 353
354 if (format->proc)
355 {
26054e0b 356 unsigned long actual_length;
e76f6040 357
26054e0b 358 (*format->proc) (tag, length);
e76f6040 359
26054e0b 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 }
e76f6040 368
369 gcov_sync (base, length);
370 if ((error = gcov_is_error ()))
26054e0b 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 }
e76f6040 377 }
378
379 read_gcda_finalize (obj_info);
380 gcov_close ();
381
382 return obj_info;
383}
384
c905381f 385#ifdef HAVE_FTW_H
e76f6040 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
389static int
390ftw_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}
c905381f 423#endif
e76f6040 424
425/* Initializer for reading a profile dir. */
426
427static inline void
428read_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,
6401b74d 435 Return the head of gcov_info list on success. */
e76f6040 436
437struct gcov_info *
438gcov_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 }
c905381f 458#ifdef HAVE_FTW_H
e76f6040 459 ftw (".", ftw_read_file, 50);
c905381f 460#endif
e76f6040 461 ret = chdir (pwd);
462 free (pwd);
463
464
e76f6040 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. */
473static gcov_type *gcov_value_buf;
474
475/* The number of counter values to be read by current merging. */
476static gcov_unsigned_t gcov_value_buf_size;
477
478/* The index of counter values being read. */
479static gcov_unsigned_t gcov_value_buf_pos;
480
481/* The weight of current merging. */
482static unsigned gcov_merge_weight;
483
484/* Read a counter value from gcov_value_buf array. */
485
486gcov_type
487gcov_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
498unsigned
499gcov_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
507static void
508merge_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
534static int
535gcov_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
585static struct gcov_info *
26054e0b 586find_match_gcov_info (struct gcov_info **array, int size,
587 struct gcov_info *info)
e76f6040 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
622int
623gcov_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 tgt_tail->next = gi_ptr;
677 tgt_tail = gi_ptr;
678 }
679
680 return 0;
681}
682
683typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
684
685/* Performing FN upon arc counters. */
686
687static void
688__gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
689 counter_op_fn fn, void *data1, void *data2)
690{
691 for (; n_counters; counters++, n_counters--)
692 {
693 gcov_type val = *counters;
694 *counters = fn(val, data1, data2);
695 }
696}
697
698/* Performing FN upon ior counters. */
699
700static void
701__gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
702 unsigned n_counters ATTRIBUTE_UNUSED,
703 counter_op_fn fn ATTRIBUTE_UNUSED,
704 void *data1 ATTRIBUTE_UNUSED,
705 void *data2 ATTRIBUTE_UNUSED)
706{
707 /* Do nothing. */
708}
709
710/* Performing FN upon time-profile counters. */
711
712static void
713__gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
714 unsigned n_counters ATTRIBUTE_UNUSED,
715 counter_op_fn fn ATTRIBUTE_UNUSED,
716 void *data1 ATTRIBUTE_UNUSED,
717 void *data2 ATTRIBUTE_UNUSED)
718{
719 /* Do nothing. */
720}
721
722/* Performaing FN upon delta counters. */
723
724static void
725__gcov_delta_counter_op (gcov_type *counters, unsigned n_counters,
726 counter_op_fn fn, void *data1, void *data2)
727{
728 unsigned i, n_measures;
729
730 gcc_assert (!(n_counters % 4));
731 n_measures = n_counters / 4;
732 for (i = 0; i < n_measures; i++, counters += 4)
733 {
734 counters[2] = fn (counters[2], data1, data2);
735 counters[3] = fn (counters[3], data1, data2);
736 }
737}
738
739/* Performing FN upon single counters. */
740
741static void
742__gcov_single_counter_op (gcov_type *counters, unsigned n_counters,
743 counter_op_fn fn, void *data1, void *data2)
744{
745 unsigned i, n_measures;
746
747 gcc_assert (!(n_counters % 3));
748 n_measures = n_counters / 3;
749 for (i = 0; i < n_measures; i++, counters += 3)
750 {
751 counters[1] = fn (counters[1], data1, data2);
752 counters[2] = fn (counters[2], data1, data2);
753 }
754}
755
8ceaa1ef 756/* Performing FN upon indirect-call profile counters. */
757
758static void
759__gcov_icall_topn_counter_op (gcov_type *counters, unsigned n_counters,
760 counter_op_fn fn, void *data1, void *data2)
761{
762 unsigned i;
763
764 gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS));
765 for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS)
766 {
767 unsigned j;
768 gcov_type *value_array = &counters[i + 1];
769
770 for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
771 value_array[j + 1] = fn (value_array[j + 1], data1, data2);
772 }
773}
774
e76f6040 775/* Scaling the counter value V by multiplying *(float*) DATA1. */
776
777static gcov_type
778fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
779{
780 float f = *(float *) data1;
781 return (gcov_type) (v * f);
782}
783
784/* Scaling the counter value V by multiplying DATA2/DATA1. */
785
786static gcov_type
787int_scale (gcov_type v, void *data1, void *data2)
788{
789 int n = *(int *) data1;
790 int d = *(int *) data2;
791 return (gcov_type) ( RDIV (v,d) * n);
792}
793
794/* Type of function used to process counters. */
795typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
796 counter_op_fn, void *, void *);
797
798/* Function array to process profile counters. */
799#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
800 __gcov ## FN_TYPE ## _counter_op,
801static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
802#include "gcov-counter.def"
803};
804#undef DEF_GCOV_COUNTER
805
806/* Driver for scaling profile counters. */
807
808int
809gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
810{
811 struct gcov_info *gi_ptr;
812 unsigned f_ix;
813
814 if (verbose)
815 fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
816
817 /* Scaling the counters. */
818 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
819 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
820 {
821 unsigned t_ix;
822 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
823 const struct gcov_ctr_info *ci_ptr;
824
825 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
826 continue;
827
828 ci_ptr = gfi_ptr->ctrs;
829 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
830 {
831 gcov_merge_fn merge = gi_ptr->merge[t_ix];
832
833 if (!merge)
834 continue;
835 if (d == 0)
836 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
837 fp_scale, &scale_factor, NULL);
838 else
839 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
840 int_scale, &n, &d);
841 ci_ptr++;
842 }
843 }
844
845 return 0;
846}
847
848/* Driver to normalize profile counters. */
849
850int
851gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
852{
853 struct gcov_info *gi_ptr;
854 gcov_type curr_max_val = 0;
855 unsigned f_ix;
856 unsigned int i;
857 float scale_factor;
858
859 /* Find the largest count value. */
860 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
861 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
862 {
863 unsigned t_ix;
864 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
865 const struct gcov_ctr_info *ci_ptr;
866
867 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
868 continue;
869
870 ci_ptr = gfi_ptr->ctrs;
871 for (t_ix = 0; t_ix < 1; t_ix++)
872 {
873 for (i = 0; i < ci_ptr->num; i++)
874 if (ci_ptr->values[i] > curr_max_val)
875 curr_max_val = ci_ptr->values[i];
876 ci_ptr++;
877 }
878 }
879
880 scale_factor = (float)max_val / curr_max_val;
881 if (verbose)
a8a5046c 882 fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
e76f6040 883
884 return gcov_profile_scale (profile, scale_factor, 0, 0);
885}
26054e0b 886
887/* The following variables are defined in gcc/gcov-tool.c. */
888extern int overlap_func_level;
889extern int overlap_obj_level;
890extern int overlap_hot_only;
891extern int overlap_use_fullname;
892extern double overlap_hot_threshold;
893
894/* Compute the overlap score of two values. The score is defined as:
895 min (V1/SUM_1, V2/SUM_2) */
896
897static double
898calculate_2_entries (const unsigned long v1, const unsigned long v2,
899 const double sum_1, const double sum_2)
900{
901 double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
902 double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
903
904 if (val2 < val1)
905 val1 = val2;
906
907 return val1;
908}
909
910/* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
911 SUM_1 is the sum_all for profile1 where GCOV_INFO1 belongs.
912 SUM_2 is the sum_all for profile2 where GCOV_INFO2 belongs.
913 This function also updates cumulative score CUM_1_RESULT and
914 CUM_2_RESULT. */
915
916static double
917compute_one_gcov (const struct gcov_info *gcov_info1,
918 const struct gcov_info *gcov_info2,
919 const double sum_1, const double sum_2,
920 double *cum_1_result, double *cum_2_result)
921{
922 unsigned f_ix;
923 double ret = 0;
924 double cum_1 = 0, cum_2 = 0;
925 const struct gcov_info *gcov_info = 0;
926 double *cum_p;
927 double sum;
928
929 gcc_assert (gcov_info1 || gcov_info2);
930 if (!gcov_info1)
931 {
932 gcov_info = gcov_info2;
933 cum_p = cum_2_result;
934 sum = sum_2;
935 *cum_1_result = 0;
936 } else
937 if (!gcov_info2)
938 {
939 gcov_info = gcov_info1;
940 cum_p = cum_1_result;
941 sum = sum_1;
942 *cum_2_result = 0;
943 }
944
945 if (gcov_info)
946 {
947 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
948 {
949 unsigned t_ix;
950 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
951 if (!gfi_ptr || gfi_ptr->key != gcov_info)
952 continue;
953 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
954 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
955 {
956 unsigned c_num;
957
958 if (!gcov_info->merge[t_ix])
959 continue;
960
961 for (c_num = 0; c_num < ci_ptr->num; c_num++)
962 {
963 cum_1 += ci_ptr->values[c_num] / sum;
964 }
965 ci_ptr++;
966 }
967 }
968 *cum_p = cum_1;
969 return 0.0;
970 }
971
972 for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
973 {
974 unsigned t_ix;
975 double func_cum_1 = 0.0;
976 double func_cum_2 = 0.0;
977 double func_val = 0.0;
978 int nonzero = 0;
979 int hot = 0;
980 const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
981 const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
982
983 if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
984 continue;
985 if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
986 continue;
987
988 const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
989 const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
990 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
991 {
992 unsigned c_num;
993
994 if (!gcov_info1->merge[t_ix])
995 continue;
996
997 for (c_num = 0; c_num < ci_ptr1->num; c_num++)
998 {
999 if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
1000 {
1001 func_val += calculate_2_entries (ci_ptr1->values[c_num],
1002 ci_ptr2->values[c_num],
1003 sum_1, sum_2);
1004
1005 func_cum_1 += ci_ptr1->values[c_num] / sum_1;
1006 func_cum_2 += ci_ptr2->values[c_num] / sum_2;
1007 nonzero = 1;
1008 if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold ||
1009 ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
1010 hot = 1;
1011 }
1012 }
1013 ci_ptr1++;
1014 ci_ptr2++;
1015 }
1016 ret += func_val;
1017 cum_1 += func_cum_1;
1018 cum_2 += func_cum_2;
1019 if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
1020 {
1021 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1022 gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
1023 }
1024 }
1025 *cum_1_result = cum_1;
1026 *cum_2_result = cum_2;
1027 return ret;
1028}
1029
1030/* Test if all counter values in this GCOV_INFO are cold.
1031 "Cold" is defined as the counter value being less than
1032 or equal to THRESHOLD. */
1033
1034static bool
1035gcov_info_count_all_cold (const struct gcov_info *gcov_info,
1036 gcov_type threshold)
1037{
1038 unsigned f_ix;
1039
1040 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
1041 {
1042 unsigned t_ix;
1043 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
1044
1045 if (!gfi_ptr || gfi_ptr->key != gcov_info)
1046 continue;
1047 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
1048 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
1049 {
1050 unsigned c_num;
1051
1052 if (!gcov_info->merge[t_ix])
1053 continue;
1054
1055 for (c_num = 0; c_num < ci_ptr->num; c_num++)
1056 {
1057 if (ci_ptr->values[c_num] > threshold)
1058 return false;
1059 }
1060 ci_ptr++;
1061 }
1062 }
1063
1064 return true;
1065}
1066
1067/* Test if all counter values in this GCOV_INFO are 0. */
1068
1069static bool
1070gcov_info_count_all_zero (const struct gcov_info *gcov_info)
1071{
1072 return gcov_info_count_all_cold (gcov_info, 0);
1073}
1074
1075/* A pair of matched GCOV_INFO.
1076 The flag is a bitvector:
1077 b0: obj1's all counts are 0;
1078 b1: obj1's all counts are cold (but no 0);
1079 b2: obj1 is hot;
1080 b3: no obj1 to match obj2;
1081 b4: obj2's all counts are 0;
1082 b5: obj2's all counts are cold (but no 0);
1083 b6: obj2 is hot;
1084 b7: no obj2 to match obj1;
1085 */
1086struct overlap_t {
1087 const struct gcov_info *obj1;
1088 const struct gcov_info *obj2;
1089 char flag;
1090};
1091
1092#define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1093#define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1094#define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1095
1096/* Cumlative overlap dscore for profile1 and profile2. */
1097static double overlap_sum_1, overlap_sum_2;
1098
1099/* sum_all for profile1 and profile2. */
1100static gcov_type p1_sum_all, p2_sum_all;
1101
1102/* run_max for profile1 and profile2. */
1103static gcov_type p1_run_max, p2_run_max;
1104
1105/* The number of gcda files in the profiles. */
1106static unsigned gcda_files[2];
1107
1108/* The number of unique gcda files in the profiles
1109 (not existing in the other profile). */
1110static unsigned unique_gcda_files[2];
1111
1112/* The number of gcda files that all counter values are 0. */
1113static unsigned zero_gcda_files[2];
1114
1115/* The number of gcda files that all counter values are cold (but not 0). */
1116static unsigned cold_gcda_files[2];
1117
1118/* The number of gcda files that includes hot counter values. */
1119static unsigned hot_gcda_files[2];
1120
1121/* The number of gcda files with hot count value in either profiles. */
1122static unsigned both_hot_cnt;
1123
1124/* The number of gcda files with all counts cold (but not 0) in
1125 both profiles. */
1126static unsigned both_cold_cnt;
1127
1128/* The number of gcda files with all counts 0 in both profiles. */
1129static unsigned both_zero_cnt;
1130
1131/* Extract the basename of the filename NAME. */
1132
1133static char *
1134extract_file_basename (const char *name)
1135{
1136 char *str;
1137 int len = 0;
1138 char *path = xstrdup (name);
1139 char sep_str[2];
1140
1141 sep_str[0] = DIR_SEPARATOR;
1142 sep_str[1] = 0;
1143 str = strstr(path, sep_str);
1144 do{
1145 len = strlen(str) + 1;
1146 path = &path[strlen(path) - len + 2];
1147 str = strstr(path, sep_str);
1148 } while(str);
1149
1150 return path;
1151}
1152
1153/* Utility function to get the filename. */
1154
1155static const char *
1156get_file_basename (const char *name)
1157{
1158 if (overlap_use_fullname)
1159 return name;
1160 return extract_file_basename (name);
1161}
1162
1163/* A utility function to set the flag for the gcda files. */
1164
1165static void
1166set_flag (struct overlap_t *e)
1167{
1168 char flag = 0;
1169
1170 if (!e->obj1)
1171 {
1172 unique_gcda_files[1]++;
1173 flag = 0x8;
1174 }
1175 else
1176 {
1177 gcda_files[0]++;
1178 if (gcov_info_count_all_zero (e->obj1))
1179 {
1180 zero_gcda_files[0]++;
1181 flag = 0x1;
1182 }
1183 else
1184 if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
1185 * overlap_hot_threshold))
1186 {
1187 cold_gcda_files[0]++;
1188 flag = 0x2;
1189 }
1190 else
1191 {
1192 hot_gcda_files[0]++;
1193 flag = 0x4;
1194 }
1195 }
1196
1197 if (!e->obj2)
1198 {
1199 unique_gcda_files[0]++;
1200 flag |= (0x8 << 4);
1201 }
1202 else
1203 {
1204 gcda_files[1]++;
1205 if (gcov_info_count_all_zero (e->obj2))
1206 {
1207 zero_gcda_files[1]++;
1208 flag |= (0x1 << 4);
1209 }
1210 else
1211 if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
1212 * overlap_hot_threshold))
1213 {
1214 cold_gcda_files[1]++;
1215 flag |= (0x2 << 4);
1216 }
1217 else
1218 {
1219 hot_gcda_files[1]++;
1220 flag |= (0x4 << 4);
1221 }
1222 }
1223
1224 gcc_assert (flag);
1225 e->flag = flag;
1226}
1227
1228/* Test if INFO1 and INFO2 are from the matched source file.
1229 Return 1 if they match; return 0 otherwise. */
1230
1231static int
1232matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
1233{
1234 /* For FDO, we have to match the name. This can be expensive.
1235 Maybe we should use hash here. */
1236 if (strcmp (info1->filename, info2->filename))
1237 return 0;
1238
1239 if (info1->n_functions != info2->n_functions)
1240 {
1241 fnotice (stderr, "mismatched profiles in %s (%d functions"
1242 " vs %d functions)\n",
1243 info1->filename,
1244 info1->n_functions,
1245 info2->n_functions);
1246 return 0;
1247 }
1248 return 1;
1249}
1250
1251/* Defined in libgcov-driver.c. */
1252extern gcov_unsigned_t compute_summary (struct gcov_info *,
1253 struct gcov_summary *, size_t *);
1254
1255/* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1256 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1257 match and 1.0 meaning a perfect match. */
1258
1259static double
1260calculate_overlap (struct gcov_info *gcov_list1,
1261 struct gcov_info *gcov_list2)
1262{
1263 struct gcov_summary this_prg;
1264 unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
1265 unsigned int i, j;
1266 size_t max_length;
1267 const struct gcov_info *gi_ptr;
1268 struct overlap_t *all_infos;
1269
1270 compute_summary (gcov_list1, &this_prg, &max_length);
1271 overlap_sum_1 = (double) (this_prg.ctrs[0].sum_all);
1272 p1_sum_all = this_prg.ctrs[0].sum_all;
1273 p1_run_max = this_prg.ctrs[0].run_max;
1274 compute_summary (gcov_list2, &this_prg, &max_length);
1275 overlap_sum_2 = (double) (this_prg.ctrs[0].sum_all);
1276 p2_sum_all = this_prg.ctrs[0].sum_all;
1277 p2_run_max = this_prg.ctrs[0].run_max;
1278
1279 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
1280 list1_cnt++;
1281 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
1282 list2_cnt++;
1283 all_cnt = list1_cnt + list2_cnt;
1284 all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
1285 * all_cnt * 2);
1286 gcc_assert (all_infos);
1287
1288 i = 0;
1289 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
1290 {
1291 all_infos[i].obj1 = gi_ptr;
1292 all_infos[i].obj2 = 0;
1293 }
1294
1295 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
1296 {
1297 all_infos[i].obj1 = 0;
1298 all_infos[i].obj2 = gi_ptr;
1299 }
1300
1301 for (i = list1_cnt; i < all_cnt; i++)
1302 {
1303 if (all_infos[i].obj2 == 0)
1304 continue;
1305 for (j = 0; j < list1_cnt; j++)
1306 {
1307 if (all_infos[j].obj2 != 0)
1308 continue;
1309 if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
1310 {
1311 all_infos[j].obj2 = all_infos[i].obj2;
1312 all_infos[i].obj2 = 0;
1313 break;
1314 }
1315 }
1316 }
1317
1318 for (i = 0; i < all_cnt; i++)
1319 if (all_infos[i].obj1 || all_infos[i].obj2)
1320 {
1321 set_flag (all_infos + i);
1322 if (FLAG_ONE_HOT (all_infos[i].flag))
1323 both_hot_cnt++;
1324 if (FLAG_BOTH_COLD(all_infos[i].flag))
1325 both_cold_cnt++;
1326 if (FLAG_BOTH_ZERO(all_infos[i].flag))
1327 both_zero_cnt++;
1328 }
1329
1330 double prg_val = 0;
1331 double sum_val = 0;
1332 double sum_cum_1 = 0;
1333 double sum_cum_2 = 0;
1334
1335 for (i = 0; i < all_cnt; i++)
1336 {
1337 double val;
1338 double cum_1, cum_2;
1339 const char *filename;
1340
1341 if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
1342 continue;
1343 if (FLAG_BOTH_ZERO (all_infos[i].flag))
1344 continue;
1345
1346 if (all_infos[i].obj1)
1347 filename = get_file_basename (all_infos[i].obj1->filename);
1348 else
1349 filename = get_file_basename (all_infos[i].obj2->filename);
1350
1351 if (overlap_func_level)
1352 printf("\n processing %36s:\n", filename);
1353
1354 val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
1355 overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
1356
1357 if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
1358 {
1359 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1360 filename, val*100, cum_1*100, cum_2*100);
1361 sum_val += val;
1362 sum_cum_1 += cum_1;
1363 sum_cum_2 += cum_2;
1364 }
1365
1366 prg_val += val;
1367
1368 }
1369
1370 if (overlap_obj_level)
1371 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1372 "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
1373
1374 printf (" Statistics:\n"
1375 " profile1_# profile2_# overlap_#\n");
1376 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
a8a5046c 1377 gcda_files[0]-unique_gcda_files[0]);
26054e0b 1378 printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
a8a5046c 1379 unique_gcda_files[1]);
26054e0b 1380 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
a8a5046c 1381 hot_gcda_files[1], both_hot_cnt);
26054e0b 1382 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
a8a5046c 1383 cold_gcda_files[1], both_cold_cnt);
26054e0b 1384 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
a8a5046c 1385 zero_gcda_files[1], both_zero_cnt);
1386 printf (" sum_all: %12" PRId64 "\t%12" PRId64 "\n",
1387 p1_sum_all, p2_sum_all);
1388 printf (" run_max: %12" PRId64 "\t%12" PRId64 "\n",
1389 p1_run_max, p2_run_max);
26054e0b 1390
1391 return prg_val;
1392}
1393
1394/* Computer the overlap score of two lists of gcov_info objects PROFILE1 and PROFILE2.
1395 Return 0 on success: without mismatch. Reutrn 1 on error. */
1396
1397int
1398gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
1399{
1400 double result;
1401
1402 result = calculate_overlap (profile1, profile2);
1403
1404 if (result > 0)
1405 {
1406 printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
1407 return 0;
1408 }
1409 return 1;
1410}