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