1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2020 Free Software Foundation, Inc.
4 Contributed by Rong Xu <xur@google.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
28 #define IN_GCOV_TOOL 1
32 #include "diagnostic.h"
37 /* Borrowed from basic-block.h. */
38 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
40 extern gcov_position_t
gcov_position();
41 extern int gcov_is_error();
43 /* Verbose mode for debug. */
46 /* Set verbose flag. */
47 void gcov_set_verbose (void)
52 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
60 static void tag_function (unsigned, unsigned);
61 static void tag_blocks (unsigned, unsigned);
62 static void tag_arcs (unsigned, unsigned);
63 static void tag_lines (unsigned, unsigned);
64 static void tag_counters (unsigned, unsigned);
65 static void tag_summary (unsigned, unsigned);
67 /* The gcov_info for the first module. */
68 static struct gcov_info
*curr_gcov_info
;
69 /* The gcov_info being processed. */
70 static struct gcov_info
*gcov_info_head
;
71 /* This variable contains all the functions in current module. */
72 static struct obstack fn_info
;
73 /* The function being processed. */
74 static struct gcov_fn_info
*curr_fn_info
;
75 /* The number of functions seen so far. */
76 static unsigned num_fn_info
;
77 /* This variable contains all the counters for current module. */
78 static int k_ctrs_mask
[GCOV_COUNTERS
];
79 /* The kind of counters that have been seen. */
80 static struct gcov_ctr_info k_ctrs
[GCOV_COUNTERS
];
81 /* Number of kind of counters that have been seen. */
82 static int k_ctrs_types
;
83 /* The object summary being processed. */
84 static struct gcov_summary
*curr_object_summary
;
86 /* Merge functions for counters. */
87 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
88 static gcov_merge_fn ctr_merge_functions
[GCOV_COUNTERS
] = {
89 #include "gcov-counter.def"
91 #undef DEF_GCOV_COUNTER
93 /* Set the ctrs field in gcov_fn_info object FN_INFO. */
96 set_fn_ctrs (struct gcov_fn_info
*fn_info
)
100 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
102 if (k_ctrs_mask
[i
] == 0)
104 fn_info
->ctrs
[j
].num
= k_ctrs
[i
].num
;
105 fn_info
->ctrs
[j
].values
= k_ctrs
[i
].values
;
108 if (k_ctrs_types
== 0)
111 gcc_assert (j
== k_ctrs_types
);
114 /* For each tag in gcda file, we have an entry here.
115 TAG is the tag value; NAME is the tag name; and
116 PROC is the handler function. */
118 typedef struct tag_format
122 void (*proc
) (unsigned, unsigned);
125 /* Handler table for various Tags. */
127 static const tag_format_t tag_table
[] =
130 {0, "UNKNOWN", NULL
},
131 {0, "COUNTERS", tag_counters
},
132 {GCOV_TAG_FUNCTION
, "FUNCTION", tag_function
},
133 {GCOV_TAG_BLOCKS
, "BLOCKS", tag_blocks
},
134 {GCOV_TAG_ARCS
, "ARCS", tag_arcs
},
135 {GCOV_TAG_LINES
, "LINES", tag_lines
},
136 {GCOV_TAG_OBJECT_SUMMARY
, "OBJECT_SUMMARY", tag_summary
},
140 /* Handler for reading function tag. */
143 tag_function (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
147 /* write out previous fn_info. */
150 set_fn_ctrs (curr_fn_info
);
151 obstack_ptr_grow (&fn_info
, curr_fn_info
);
154 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
156 curr_fn_info
= (struct gcov_fn_info
*) xcalloc (sizeof (struct gcov_fn_info
)
157 + GCOV_COUNTERS
* sizeof (struct gcov_ctr_info
), 1);
159 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
163 curr_fn_info
->key
= curr_gcov_info
;
164 curr_fn_info
->ident
= gcov_read_unsigned ();
165 curr_fn_info
->lineno_checksum
= gcov_read_unsigned ();
166 curr_fn_info
->cfg_checksum
= gcov_read_unsigned ();
170 fnotice (stdout
, "tag one function id=%d\n", curr_fn_info
->ident
);
173 /* Handler for reading block tag. */
176 tag_blocks (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
178 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
182 /* Handler for reading flow arc tag. */
185 tag_arcs (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
187 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
191 /* Handler for reading line tag. */
194 tag_lines (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
196 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
200 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
203 tag_counters (unsigned tag
, unsigned length
)
205 unsigned n_counts
= GCOV_TAG_COUNTER_NUM (length
);
210 tag_ix
= GCOV_COUNTER_FOR_TAG (tag
);
211 gcc_assert (tag_ix
< GCOV_COUNTERS
);
212 k_ctrs_mask
[tag_ix
] = 1;
213 gcc_assert (k_ctrs
[tag_ix
].num
== 0);
214 k_ctrs
[tag_ix
].num
= n_counts
;
216 k_ctrs
[tag_ix
].values
= values
= (gcov_type
*) xmalloc (n_counts
* sizeof (gcov_type
));
219 for (ix
= 0; ix
!= n_counts
; ix
++)
220 values
[ix
] = gcov_read_counter ();
223 /* Handler for reading summary tag. */
226 tag_summary (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
228 curr_object_summary
= (gcov_summary
*) xcalloc (sizeof (gcov_summary
), 1);
229 gcov_read_summary (curr_object_summary
);
232 /* This function is called at the end of reading a gcda file.
233 It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO. */
236 read_gcda_finalize (struct gcov_info
*obj_info
)
240 set_fn_ctrs (curr_fn_info
);
241 obstack_ptr_grow (&fn_info
, curr_fn_info
);
243 /* We set the following fields: merge, n_functions, functions
245 obj_info
->n_functions
= num_fn_info
;
246 obj_info
->functions
= (const struct gcov_fn_info
**) obstack_finish (&fn_info
);
248 /* wrap all the counter array. */
249 for (i
=0; i
< GCOV_COUNTERS
; i
++)
252 obj_info
->merge
[i
] = ctr_merge_functions
[i
];
256 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
257 Program level summary CURRENT_SUMMARY will also be updated. */
259 static struct gcov_info
*
260 read_gcda_file (const char *filename
)
265 struct gcov_info
*obj_info
;
268 for (i
=0; i
< GCOV_COUNTERS
; i
++)
272 if (!gcov_open (filename
))
274 fnotice (stderr
, "%s:cannot open\n", filename
);
279 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
281 fnotice (stderr
, "%s:not a gcov data file\n", filename
);
287 version
= gcov_read_unsigned ();
288 if (version
!= GCOV_VERSION
)
290 fnotice (stderr
, "%s:incorrect gcov version %d vs %d \n", filename
, version
, GCOV_VERSION
);
295 /* Instantiate a gcov_info object. */
296 curr_gcov_info
= obj_info
= (struct gcov_info
*) xcalloc (sizeof (struct gcov_info
) +
297 sizeof (struct gcov_ctr_info
) * GCOV_COUNTERS
, 1);
299 obj_info
->version
= version
;
300 obstack_init (&fn_info
);
303 curr_object_summary
= NULL
;
305 size_t len
= strlen (filename
) + 1;
306 char *str_dup
= (char*) xmalloc (len
);
308 memcpy (str_dup
, filename
, len
);
309 obj_info
->filename
= str_dup
;
313 obj_info
->stamp
= gcov_read_unsigned ();
317 gcov_position_t base
;
318 unsigned tag
, length
;
319 tag_format_t
const *format
;
324 tag
= gcov_read_unsigned ();
327 length
= gcov_read_unsigned ();
328 base
= gcov_position ();
329 mask
= GCOV_TAG_MASK (tag
) >> 1;
330 for (tag_depth
= 4; mask
; mask
>>= 8)
332 if (((mask
& 0xff) != 0xff))
334 warning (0, "%s:tag %qx is invalid", filename
, tag
);
339 for (format
= tag_table
; format
->name
; format
++)
340 if (format
->tag
== tag
)
342 format
= &tag_table
[GCOV_TAG_IS_COUNTER (tag
) ? 2 : 1];
346 if (depth
&& depth
< tag_depth
)
348 if (!GCOV_TAG_IS_SUBTAG (tags
[depth
- 1], tag
))
349 warning (0, "%s:tag %qx is incorrectly nested",
353 tags
[depth
- 1] = tag
;
358 unsigned long actual_length
;
360 (*format
->proc
) (tag
, length
);
362 actual_length
= gcov_position () - base
;
363 if (actual_length
> length
)
364 warning (0, "%s:record size mismatch %lu bytes overread",
365 filename
, actual_length
- length
);
366 else if (length
> actual_length
)
367 warning (0, "%s:record size mismatch %lu bytes unread",
368 filename
, length
- actual_length
);
371 gcov_sync (base
, length
);
372 if ((error
= gcov_is_error ()))
374 warning (0, error
< 0 ? "%s:counter overflow at %lu" :
375 "%s:read error at %lu", filename
,
376 (long unsigned) gcov_position ());
381 read_gcda_finalize (obj_info
);
388 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
389 Return a non-zero value to stop the tree walk. */
392 ftw_read_file (const char *filename
,
393 const struct stat
*status ATTRIBUTE_UNUSED
,
398 struct gcov_info
*obj_info
;
400 /* Only read regular files. */
404 filename_len
= strlen (filename
);
405 suffix_len
= strlen (GCOV_DATA_SUFFIX
);
407 if (filename_len
<= suffix_len
)
410 if (strcmp(filename
+ filename_len
- suffix_len
, GCOV_DATA_SUFFIX
))
414 fnotice (stderr
, "reading file: %s\n", filename
);
416 obj_info
= read_gcda_file (filename
);
420 obj_info
->next
= gcov_info_head
;
421 gcov_info_head
= obj_info
;
427 /* Initializer for reading a profile dir. */
430 read_profile_dir_init (void)
435 /* Driver for read a profile directory and convert into gcov_info list in memory.
436 Return NULL on error,
437 Return the head of gcov_info list on success. */
440 gcov_read_profile_dir (const char* dir_name
, int recompute_summary ATTRIBUTE_UNUSED
)
445 read_profile_dir_init ();
447 if (access (dir_name
, R_OK
) != 0)
449 fnotice (stderr
, "cannot access directory %s\n", dir_name
);
452 pwd
= getcwd (NULL
, 0);
454 ret
= chdir (dir_name
);
457 fnotice (stderr
, "%s is not a directory\n", dir_name
);
461 ftw (".", ftw_read_file
, 50);
466 return gcov_info_head
;;
469 /* This part of the code is to merge profile counters. These
470 variables are set in merge_wrapper and to be used by
471 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
473 /* We save the counter value address to this variable. */
474 static gcov_type
*gcov_value_buf
;
476 /* The number of counter values to be read by current merging. */
477 static gcov_unsigned_t gcov_value_buf_size
;
479 /* The index of counter values being read. */
480 static gcov_unsigned_t gcov_value_buf_pos
;
482 /* The weight of current merging. */
483 static unsigned gcov_merge_weight
;
485 /* Read a counter value from gcov_value_buf array. */
488 gcov_read_counter_mem (void)
491 gcc_assert (gcov_value_buf_pos
< gcov_value_buf_size
);
492 ret
= *(gcov_value_buf
+ gcov_value_buf_pos
);
493 ++gcov_value_buf_pos
;
497 /* Return the recorded merge weight. */
500 gcov_get_merge_weight (void)
502 return gcov_merge_weight
;
505 /* A wrapper function for merge functions. It sets up the
506 value buffer and weights and then calls the merge function. */
509 merge_wrapper (gcov_merge_fn f
, gcov_type
*v1
, gcov_unsigned_t n
,
510 gcov_type
*v2
, unsigned w
)
513 gcov_value_buf_pos
= 0;
514 gcov_value_buf_size
= n
;
515 gcov_merge_weight
= w
;
519 /* Offline tool to manipulate profile data.
520 This tool targets on matched profiles. But it has some tolerance on
522 When merging p1 to p2 (p2 is the dst),
523 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
525 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
526 specified weight; emit warning.
527 * m.gcda in both p1 and p2:
528 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
529 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
531 drop p1->m.gcda->f. A warning is emitted. */
533 /* Add INFO2's counter to INFO1, multiplying by weight W. */
536 gcov_merge (struct gcov_info
*info1
, struct gcov_info
*info2
, int w
)
539 unsigned n_functions
= info1
->n_functions
;
540 int has_mismatch
= 0;
542 gcc_assert (info2
->n_functions
== n_functions
);
543 for (f_ix
= 0; f_ix
< n_functions
; f_ix
++)
546 const struct gcov_fn_info
*gfi_ptr1
= info1
->functions
[f_ix
];
547 const struct gcov_fn_info
*gfi_ptr2
= info2
->functions
[f_ix
];
548 const struct gcov_ctr_info
*ci_ptr1
, *ci_ptr2
;
550 if (!gfi_ptr1
|| gfi_ptr1
->key
!= info1
)
552 if (!gfi_ptr2
|| gfi_ptr2
->key
!= info2
)
555 if (gfi_ptr1
->cfg_checksum
!= gfi_ptr2
->cfg_checksum
)
557 fnotice (stderr
, "in %s, cfg_checksum mismatch, skipping\n",
562 ci_ptr1
= gfi_ptr1
->ctrs
;
563 ci_ptr2
= gfi_ptr2
->ctrs
;
564 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
566 gcov_merge_fn merge1
= info1
->merge
[t_ix
];
567 gcov_merge_fn merge2
= info2
->merge
[t_ix
];
569 gcc_assert (merge1
== merge2
);
572 gcc_assert (ci_ptr1
->num
== ci_ptr2
->num
);
573 merge_wrapper (merge1
, ci_ptr1
->values
, ci_ptr1
->num
, ci_ptr2
->values
, w
);
582 /* Find and return the match gcov_info object for INFO from ARRAY.
583 SIZE is the length of ARRAY.
584 Return NULL if there is no match. */
586 static struct gcov_info
*
587 find_match_gcov_info (struct gcov_info
**array
, int size
,
588 struct gcov_info
*info
)
590 struct gcov_info
*gi_ptr
;
591 struct gcov_info
*ret
= NULL
;
594 for (i
= 0; i
< size
; i
++)
599 if (!strcmp (gi_ptr
->filename
, info
->filename
))
607 if (ret
&& ret
->n_functions
!= info
->n_functions
)
609 fnotice (stderr
, "mismatched profiles in %s (%d functions"
610 " vs %d functions)\n",
619 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
620 Return 0 on success: without mismatch.
621 Reutrn 1 on error. */
624 gcov_profile_merge (struct gcov_info
*tgt_profile
, struct gcov_info
*src_profile
,
627 struct gcov_info
*gi_ptr
;
628 struct gcov_info
**tgt_infos
;
629 struct gcov_info
*tgt_tail
;
630 struct gcov_info
**in_src_not_tgt
;
631 unsigned tgt_cnt
= 0, src_cnt
= 0;
632 unsigned unmatch_info_cnt
= 0;
635 for (gi_ptr
= tgt_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
637 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
639 tgt_infos
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
641 gcc_assert (tgt_infos
);
642 in_src_not_tgt
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
644 gcc_assert (in_src_not_tgt
);
646 for (gi_ptr
= tgt_profile
, i
= 0; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
647 tgt_infos
[i
] = gi_ptr
;
649 tgt_tail
= tgt_infos
[tgt_cnt
- 1];
651 /* First pass on tgt_profile, we multiply w1 to all counters. */
654 for (i
= 0; i
< tgt_cnt
; i
++)
655 gcov_merge (tgt_infos
[i
], tgt_infos
[i
], w1
-1);
658 /* Second pass, add src_profile to the tgt_profile. */
659 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
661 struct gcov_info
*gi_ptr1
;
663 gi_ptr1
= find_match_gcov_info (tgt_infos
, tgt_cnt
, gi_ptr
);
666 in_src_not_tgt
[unmatch_info_cnt
++] = gi_ptr
;
669 gcov_merge (gi_ptr1
, gi_ptr
, w2
);
672 /* For modules in src but not in tgt. We adjust the counter and append. */
673 for (i
= 0; i
< unmatch_info_cnt
; i
++)
675 gi_ptr
= in_src_not_tgt
[i
];
676 gcov_merge (gi_ptr
, gi_ptr
, w2
- 1);
678 tgt_tail
->next
= gi_ptr
;
682 free (in_src_not_tgt
);
688 typedef gcov_type (*counter_op_fn
) (gcov_type
, void*, void*);
690 /* Performing FN upon arc counters. */
693 __gcov_add_counter_op (gcov_type
*counters
, unsigned n_counters
,
694 counter_op_fn fn
, void *data1
, void *data2
)
696 for (; n_counters
; counters
++, n_counters
--)
698 gcov_type val
= *counters
;
699 *counters
= fn(val
, data1
, data2
);
703 /* Performing FN upon ior counters. */
706 __gcov_ior_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
707 unsigned n_counters ATTRIBUTE_UNUSED
,
708 counter_op_fn fn ATTRIBUTE_UNUSED
,
709 void *data1 ATTRIBUTE_UNUSED
,
710 void *data2 ATTRIBUTE_UNUSED
)
715 /* Performing FN upon time-profile counters. */
718 __gcov_time_profile_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
719 unsigned n_counters ATTRIBUTE_UNUSED
,
720 counter_op_fn fn ATTRIBUTE_UNUSED
,
721 void *data1 ATTRIBUTE_UNUSED
,
722 void *data2 ATTRIBUTE_UNUSED
)
727 /* Performing FN upon TOP N counters. */
730 __gcov_topn_counter_op (gcov_type
*counters
, unsigned n_counters
,
731 counter_op_fn fn
, void *data1
, void *data2
)
733 unsigned i
, n_measures
;
735 gcc_assert (!(n_counters
% 3));
736 n_measures
= n_counters
/ 3;
737 for (i
= 0; i
< n_measures
; i
++, counters
+= 3)
739 counters
[1] = fn (counters
[1], data1
, data2
);
740 counters
[2] = fn (counters
[2], data1
, data2
);
744 /* Scaling the counter value V by multiplying *(float*) DATA1. */
747 fp_scale (gcov_type v
, void *data1
, void *data2 ATTRIBUTE_UNUSED
)
749 float f
= *(float *) data1
;
750 return (gcov_type
) (v
* f
);
753 /* Scaling the counter value V by multiplying DATA2/DATA1. */
756 int_scale (gcov_type v
, void *data1
, void *data2
)
758 int n
= *(int *) data1
;
759 int d
= *(int *) data2
;
760 return (gcov_type
) ( RDIV (v
,d
) * n
);
763 /* Type of function used to process counters. */
764 typedef void (*gcov_counter_fn
) (gcov_type
*, gcov_unsigned_t
,
765 counter_op_fn
, void *, void *);
767 /* Function array to process profile counters. */
768 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
769 __gcov ## FN_TYPE ## _counter_op,
770 static gcov_counter_fn ctr_functions
[GCOV_COUNTERS
] = {
771 #include "gcov-counter.def"
773 #undef DEF_GCOV_COUNTER
775 /* Driver for scaling profile counters. */
778 gcov_profile_scale (struct gcov_info
*profile
, float scale_factor
, int n
, int d
)
780 struct gcov_info
*gi_ptr
;
784 fnotice (stdout
, "scale_factor is %f or %d/%d\n", scale_factor
, n
, d
);
786 /* Scaling the counters. */
787 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
788 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
791 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
792 const struct gcov_ctr_info
*ci_ptr
;
794 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
797 ci_ptr
= gfi_ptr
->ctrs
;
798 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
800 gcov_merge_fn merge
= gi_ptr
->merge
[t_ix
];
805 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
806 fp_scale
, &scale_factor
, NULL
);
808 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
817 /* Driver to normalize profile counters. */
820 gcov_profile_normalize (struct gcov_info
*profile
, gcov_type max_val
)
822 struct gcov_info
*gi_ptr
;
823 gcov_type curr_max_val
= 0;
828 /* Find the largest count value. */
829 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
830 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
833 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
834 const struct gcov_ctr_info
*ci_ptr
;
836 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
839 ci_ptr
= gfi_ptr
->ctrs
;
840 for (t_ix
= 0; t_ix
< 1; t_ix
++)
842 for (i
= 0; i
< ci_ptr
->num
; i
++)
843 if (ci_ptr
->values
[i
] > curr_max_val
)
844 curr_max_val
= ci_ptr
->values
[i
];
849 scale_factor
= (float)max_val
/ curr_max_val
;
851 fnotice (stdout
, "max_val is %" PRId64
"\n", curr_max_val
);
853 return gcov_profile_scale (profile
, scale_factor
, 0, 0);
856 /* The following variables are defined in gcc/gcov-tool.c. */
857 extern int overlap_func_level
;
858 extern int overlap_obj_level
;
859 extern int overlap_hot_only
;
860 extern int overlap_use_fullname
;
861 extern double overlap_hot_threshold
;
863 /* Compute the overlap score of two values. The score is defined as:
864 min (V1/SUM_1, V2/SUM_2) */
867 calculate_2_entries (const unsigned long v1
, const unsigned long v2
,
868 const double sum_1
, const double sum_2
)
870 double val1
= (sum_1
== 0.0 ? 0.0 : v1
/sum_1
);
871 double val2
= (sum_2
== 0.0 ? 0.0 : v2
/sum_2
);
879 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
880 This function also updates cumulative score CUM_1_RESULT and
884 compute_one_gcov (const struct gcov_info
*gcov_info1
,
885 const struct gcov_info
*gcov_info2
,
886 const double sum_1
, const double sum_2
,
887 double *cum_1_result
, double *cum_2_result
)
891 double cum_1
= 0, cum_2
= 0;
892 const struct gcov_info
*gcov_info
= 0;
896 gcc_assert (gcov_info1
|| gcov_info2
);
899 gcov_info
= gcov_info2
;
900 cum_p
= cum_2_result
;
906 gcov_info
= gcov_info1
;
907 cum_p
= cum_1_result
;
914 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
916 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
917 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
919 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
921 for (c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
922 cum_1
+= ci_ptr
->values
[c_num
] / sum
;
928 for (f_ix
= 0; f_ix
< gcov_info1
->n_functions
; f_ix
++)
930 double func_cum_1
= 0.0;
931 double func_cum_2
= 0.0;
932 double func_val
= 0.0;
935 const struct gcov_fn_info
*gfi_ptr1
= gcov_info1
->functions
[f_ix
];
936 const struct gcov_fn_info
*gfi_ptr2
= gcov_info2
->functions
[f_ix
];
938 if (!gfi_ptr1
|| gfi_ptr1
->key
!= gcov_info1
)
940 if (!gfi_ptr2
|| gfi_ptr2
->key
!= gcov_info2
)
943 const struct gcov_ctr_info
*ci_ptr1
= gfi_ptr1
->ctrs
;
944 const struct gcov_ctr_info
*ci_ptr2
= gfi_ptr2
->ctrs
;
946 for (c_num
= 0; c_num
< ci_ptr1
->num
; c_num
++)
948 if (ci_ptr1
->values
[c_num
] | ci_ptr2
->values
[c_num
])
950 func_val
+= calculate_2_entries (ci_ptr1
->values
[c_num
],
951 ci_ptr2
->values
[c_num
],
954 func_cum_1
+= ci_ptr1
->values
[c_num
] / sum_1
;
955 func_cum_2
+= ci_ptr2
->values
[c_num
] / sum_2
;
957 if (ci_ptr1
->values
[c_num
] / sum_1
>= overlap_hot_threshold
958 || ci_ptr2
->values
[c_num
] / sum_2
>= overlap_hot_threshold
)
966 if (overlap_func_level
&& nonzero
&& (!overlap_hot_only
|| hot
))
968 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
969 gfi_ptr1
->ident
, func_val
*100, func_cum_1
*100, func_cum_2
*100);
972 *cum_1_result
= cum_1
;
973 *cum_2_result
= cum_2
;
977 /* Test if all counter values in this GCOV_INFO are cold.
978 "Cold" is defined as the counter value being less than
979 or equal to THRESHOLD. */
982 gcov_info_count_all_cold (const struct gcov_info
*gcov_info
,
987 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
989 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
991 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
993 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
994 for (unsigned c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
995 if (ci_ptr
->values
[c_num
] > threshold
)
1002 /* Test if all counter values in this GCOV_INFO are 0. */
1005 gcov_info_count_all_zero (const struct gcov_info
*gcov_info
)
1007 return gcov_info_count_all_cold (gcov_info
, 0);
1010 /* A pair of matched GCOV_INFO.
1011 The flag is a bitvector:
1012 b0: obj1's all counts are 0;
1013 b1: obj1's all counts are cold (but no 0);
1015 b3: no obj1 to match obj2;
1016 b4: obj2's all counts are 0;
1017 b5: obj2's all counts are cold (but no 0);
1019 b7: no obj2 to match obj1;
1022 const struct gcov_info
*obj1
;
1023 const struct gcov_info
*obj2
;
1027 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1028 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1029 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1031 /* Cumlative overlap dscore for profile1 and profile2. */
1032 static double overlap_sum_1
, overlap_sum_2
;
1034 /* The number of gcda files in the profiles. */
1035 static unsigned gcda_files
[2];
1037 /* The number of unique gcda files in the profiles
1038 (not existing in the other profile). */
1039 static unsigned unique_gcda_files
[2];
1041 /* The number of gcda files that all counter values are 0. */
1042 static unsigned zero_gcda_files
[2];
1044 /* The number of gcda files that all counter values are cold (but not 0). */
1045 static unsigned cold_gcda_files
[2];
1047 /* The number of gcda files that includes hot counter values. */
1048 static unsigned hot_gcda_files
[2];
1050 /* The number of gcda files with hot count value in either profiles. */
1051 static unsigned both_hot_cnt
;
1053 /* The number of gcda files with all counts cold (but not 0) in
1055 static unsigned both_cold_cnt
;
1057 /* The number of gcda files with all counts 0 in both profiles. */
1058 static unsigned both_zero_cnt
;
1060 /* Extract the basename of the filename NAME. */
1063 extract_file_basename (const char *name
)
1067 char *path
= xstrdup (name
);
1070 sep_str
[0] = DIR_SEPARATOR
;
1072 str
= strstr(path
, sep_str
);
1074 len
= strlen(str
) + 1;
1075 path
= &path
[strlen(path
) - len
+ 2];
1076 str
= strstr(path
, sep_str
);
1082 /* Utility function to get the filename. */
1085 get_file_basename (const char *name
)
1087 if (overlap_use_fullname
)
1089 return extract_file_basename (name
);
1092 /* A utility function to set the flag for the gcda files. */
1095 set_flag (struct overlap_t
*e
)
1101 unique_gcda_files
[1]++;
1107 if (gcov_info_count_all_zero (e
->obj1
))
1109 zero_gcda_files
[0]++;
1113 if (gcov_info_count_all_cold (e
->obj1
, overlap_sum_1
1114 * overlap_hot_threshold
))
1116 cold_gcda_files
[0]++;
1121 hot_gcda_files
[0]++;
1128 unique_gcda_files
[0]++;
1134 if (gcov_info_count_all_zero (e
->obj2
))
1136 zero_gcda_files
[1]++;
1140 if (gcov_info_count_all_cold (e
->obj2
, overlap_sum_2
1141 * overlap_hot_threshold
))
1143 cold_gcda_files
[1]++;
1148 hot_gcda_files
[1]++;
1157 /* Test if INFO1 and INFO2 are from the matched source file.
1158 Return 1 if they match; return 0 otherwise. */
1161 matched_gcov_info (const struct gcov_info
*info1
, const struct gcov_info
*info2
)
1163 /* For FDO, we have to match the name. This can be expensive.
1164 Maybe we should use hash here. */
1165 if (strcmp (info1
->filename
, info2
->filename
))
1168 if (info1
->n_functions
!= info2
->n_functions
)
1170 fnotice (stderr
, "mismatched profiles in %s (%d functions"
1171 " vs %d functions)\n",
1174 info2
->n_functions
);
1180 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1181 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1182 match and 1.0 meaning a perfect match. */
1185 calculate_overlap (struct gcov_info
*gcov_list1
,
1186 struct gcov_info
*gcov_list2
)
1188 unsigned list1_cnt
= 0, list2_cnt
= 0, all_cnt
;
1190 const struct gcov_info
*gi_ptr
;
1191 struct overlap_t
*all_infos
;
1193 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1195 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1197 all_cnt
= list1_cnt
+ list2_cnt
;
1198 all_infos
= (struct overlap_t
*) xmalloc (sizeof (struct overlap_t
)
1200 gcc_assert (all_infos
);
1203 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1205 all_infos
[i
].obj1
= gi_ptr
;
1206 all_infos
[i
].obj2
= 0;
1209 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1211 all_infos
[i
].obj1
= 0;
1212 all_infos
[i
].obj2
= gi_ptr
;
1215 for (i
= list1_cnt
; i
< all_cnt
; i
++)
1217 if (all_infos
[i
].obj2
== 0)
1219 for (j
= 0; j
< list1_cnt
; j
++)
1221 if (all_infos
[j
].obj2
!= 0)
1223 if (matched_gcov_info (all_infos
[i
].obj2
, all_infos
[j
].obj1
))
1225 all_infos
[j
].obj2
= all_infos
[i
].obj2
;
1226 all_infos
[i
].obj2
= 0;
1232 for (i
= 0; i
< all_cnt
; i
++)
1233 if (all_infos
[i
].obj1
|| all_infos
[i
].obj2
)
1235 set_flag (all_infos
+ i
);
1236 if (FLAG_ONE_HOT (all_infos
[i
].flag
))
1238 if (FLAG_BOTH_COLD(all_infos
[i
].flag
))
1240 if (FLAG_BOTH_ZERO(all_infos
[i
].flag
))
1246 double sum_cum_1
= 0;
1247 double sum_cum_2
= 0;
1249 for (i
= 0; i
< all_cnt
; i
++)
1252 double cum_1
, cum_2
;
1253 const char *filename
;
1255 if (all_infos
[i
].obj1
== 0 && all_infos
[i
].obj2
== 0)
1257 if (FLAG_BOTH_ZERO (all_infos
[i
].flag
))
1260 if (all_infos
[i
].obj1
)
1261 filename
= get_file_basename (all_infos
[i
].obj1
->filename
);
1263 filename
= get_file_basename (all_infos
[i
].obj2
->filename
);
1265 if (overlap_func_level
)
1266 printf("\n processing %36s:\n", filename
);
1268 val
= compute_one_gcov (all_infos
[i
].obj1
, all_infos
[i
].obj2
,
1269 overlap_sum_1
, overlap_sum_2
, &cum_1
, &cum_2
);
1271 if (overlap_obj_level
&& (!overlap_hot_only
|| FLAG_ONE_HOT (all_infos
[i
].flag
)))
1273 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1274 filename
, val
*100, cum_1
*100, cum_2
*100);
1286 if (overlap_obj_level
)
1287 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1288 "", sum_val
*100, sum_cum_1
*100, sum_cum_2
*100);
1290 printf (" Statistics:\n"
1291 " profile1_# profile2_# overlap_#\n");
1292 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files
[0], gcda_files
[1],
1293 gcda_files
[0]-unique_gcda_files
[0]);
1294 printf (" unique files: %12u\t%12u\n", unique_gcda_files
[0],
1295 unique_gcda_files
[1]);
1296 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files
[0],
1297 hot_gcda_files
[1], both_hot_cnt
);
1298 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files
[0],
1299 cold_gcda_files
[1], both_cold_cnt
);
1300 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files
[0],
1301 zero_gcda_files
[1], both_zero_cnt
);
1306 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1308 Return 0 on success: without mismatch. Reutrn 1 on error. */
1311 gcov_profile_overlap (struct gcov_info
*profile1
, struct gcov_info
*profile2
)
1315 result
= calculate_overlap (profile1
, profile2
);
1319 printf("\nProgram level overlap result is %3.2f%%\n\n", result
*100);