1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2019 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
)
264 unsigned magic
, version
;
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 magic
= gcov_read_unsigned ();
280 if (magic
!= GCOV_DATA_MAGIC
)
282 fnotice (stderr
, "%s:not a gcov data file\n", filename
);
288 version
= gcov_read_unsigned ();
289 if (version
!= GCOV_VERSION
)
291 fnotice (stderr
, "%s:incorrect gcov version %d vs %d \n", filename
, version
, GCOV_VERSION
);
296 /* Instantiate a gcov_info object. */
297 curr_gcov_info
= obj_info
= (struct gcov_info
*) xcalloc (sizeof (struct gcov_info
) +
298 sizeof (struct gcov_ctr_info
) * GCOV_COUNTERS
, 1);
300 obj_info
->version
= version
;
301 obstack_init (&fn_info
);
304 curr_object_summary
= NULL
;
306 size_t len
= strlen (filename
) + 1;
307 char *str_dup
= (char*) xmalloc (len
);
309 memcpy (str_dup
, filename
, len
);
310 obj_info
->filename
= str_dup
;
314 obj_info
->stamp
= gcov_read_unsigned ();
318 gcov_position_t base
;
319 unsigned tag
, length
;
320 tag_format_t
const *format
;
325 tag
= gcov_read_unsigned ();
328 length
= gcov_read_unsigned ();
329 base
= gcov_position ();
330 mask
= GCOV_TAG_MASK (tag
) >> 1;
331 for (tag_depth
= 4; mask
; mask
>>= 8)
333 if (((mask
& 0xff) != 0xff))
335 warning (0, "%s:tag %qx is invalid", filename
, tag
);
340 for (format
= tag_table
; format
->name
; format
++)
341 if (format
->tag
== tag
)
343 format
= &tag_table
[GCOV_TAG_IS_COUNTER (tag
) ? 2 : 1];
347 if (depth
&& depth
< tag_depth
)
349 if (!GCOV_TAG_IS_SUBTAG (tags
[depth
- 1], tag
))
350 warning (0, "%s:tag %qx is incorrectly nested",
354 tags
[depth
- 1] = tag
;
359 unsigned long actual_length
;
361 (*format
->proc
) (tag
, length
);
363 actual_length
= gcov_position () - base
;
364 if (actual_length
> length
)
365 warning (0, "%s:record size mismatch %lu bytes overread",
366 filename
, actual_length
- length
);
367 else if (length
> actual_length
)
368 warning (0, "%s:record size mismatch %lu bytes unread",
369 filename
, length
- actual_length
);
372 gcov_sync (base
, length
);
373 if ((error
= gcov_is_error ()))
375 warning (0, error
< 0 ? "%s:counter overflow at %lu" :
376 "%s:read error at %lu", filename
,
377 (long unsigned) gcov_position ());
382 read_gcda_finalize (obj_info
);
389 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
390 Return a non-zero value to stop the tree walk. */
393 ftw_read_file (const char *filename
,
394 const struct stat
*status ATTRIBUTE_UNUSED
,
399 struct gcov_info
*obj_info
;
401 /* Only read regular files. */
405 filename_len
= strlen (filename
);
406 suffix_len
= strlen (GCOV_DATA_SUFFIX
);
408 if (filename_len
<= suffix_len
)
411 if (strcmp(filename
+ filename_len
- suffix_len
, GCOV_DATA_SUFFIX
))
415 fnotice (stderr
, "reading file: %s\n", filename
);
417 obj_info
= read_gcda_file (filename
);
421 obj_info
->next
= gcov_info_head
;
422 gcov_info_head
= obj_info
;
428 /* Initializer for reading a profile dir. */
431 read_profile_dir_init (void)
436 /* Driver for read a profile directory and convert into gcov_info list in memory.
437 Return NULL on error,
438 Return the head of gcov_info list on success. */
441 gcov_read_profile_dir (const char* dir_name
, int recompute_summary ATTRIBUTE_UNUSED
)
446 read_profile_dir_init ();
448 if (access (dir_name
, R_OK
) != 0)
450 fnotice (stderr
, "cannot access directory %s\n", dir_name
);
453 pwd
= getcwd (NULL
, 0);
455 ret
= chdir (dir_name
);
458 fnotice (stderr
, "%s is not a directory\n", dir_name
);
462 ftw (".", ftw_read_file
, 50);
468 return gcov_info_head
;;
471 /* This part of the code is to merge profile counters. These
472 variables are set in merge_wrapper and to be used by
473 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
475 /* We save the counter value address to this variable. */
476 static gcov_type
*gcov_value_buf
;
478 /* The number of counter values to be read by current merging. */
479 static gcov_unsigned_t gcov_value_buf_size
;
481 /* The index of counter values being read. */
482 static gcov_unsigned_t gcov_value_buf_pos
;
484 /* The weight of current merging. */
485 static unsigned gcov_merge_weight
;
487 /* Read a counter value from gcov_value_buf array. */
490 gcov_read_counter_mem (void)
493 gcc_assert (gcov_value_buf_pos
< gcov_value_buf_size
);
494 ret
= *(gcov_value_buf
+ gcov_value_buf_pos
);
495 ++gcov_value_buf_pos
;
499 /* Return the recorded merge weight. */
502 gcov_get_merge_weight (void)
504 return gcov_merge_weight
;
507 /* A wrapper function for merge functions. It sets up the
508 value buffer and weights and then calls the merge function. */
511 merge_wrapper (gcov_merge_fn f
, gcov_type
*v1
, gcov_unsigned_t n
,
512 gcov_type
*v2
, unsigned w
)
515 gcov_value_buf_pos
= 0;
516 gcov_value_buf_size
= n
;
517 gcov_merge_weight
= w
;
521 /* Offline tool to manipulate profile data.
522 This tool targets on matched profiles. But it has some tolerance on
524 When merging p1 to p2 (p2 is the dst),
525 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
527 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
528 specified weight; emit warning.
529 * m.gcda in both p1 and p2:
530 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
531 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
533 drop p1->m.gcda->f. A warning is emitted. */
535 /* Add INFO2's counter to INFO1, multiplying by weight W. */
538 gcov_merge (struct gcov_info
*info1
, struct gcov_info
*info2
, int w
)
541 unsigned n_functions
= info1
->n_functions
;
542 int has_mismatch
= 0;
544 gcc_assert (info2
->n_functions
== n_functions
);
545 for (f_ix
= 0; f_ix
< n_functions
; f_ix
++)
548 const struct gcov_fn_info
*gfi_ptr1
= info1
->functions
[f_ix
];
549 const struct gcov_fn_info
*gfi_ptr2
= info2
->functions
[f_ix
];
550 const struct gcov_ctr_info
*ci_ptr1
, *ci_ptr2
;
552 if (!gfi_ptr1
|| gfi_ptr1
->key
!= info1
)
554 if (!gfi_ptr2
|| gfi_ptr2
->key
!= info2
)
557 if (gfi_ptr1
->cfg_checksum
!= gfi_ptr2
->cfg_checksum
)
559 fnotice (stderr
, "in %s, cfg_checksum mismatch, skipping\n",
564 ci_ptr1
= gfi_ptr1
->ctrs
;
565 ci_ptr2
= gfi_ptr2
->ctrs
;
566 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
568 gcov_merge_fn merge1
= info1
->merge
[t_ix
];
569 gcov_merge_fn merge2
= info2
->merge
[t_ix
];
571 gcc_assert (merge1
== merge2
);
574 gcc_assert (ci_ptr1
->num
== ci_ptr2
->num
);
575 merge_wrapper (merge1
, ci_ptr1
->values
, ci_ptr1
->num
, ci_ptr2
->values
, w
);
584 /* Find and return the match gcov_info object for INFO from ARRAY.
585 SIZE is the length of ARRAY.
586 Return NULL if there is no match. */
588 static struct gcov_info
*
589 find_match_gcov_info (struct gcov_info
**array
, int size
,
590 struct gcov_info
*info
)
592 struct gcov_info
*gi_ptr
;
593 struct gcov_info
*ret
= NULL
;
596 for (i
= 0; i
< size
; i
++)
601 if (!strcmp (gi_ptr
->filename
, info
->filename
))
609 if (ret
&& ret
->n_functions
!= info
->n_functions
)
611 fnotice (stderr
, "mismatched profiles in %s (%d functions"
612 " vs %d functions)\n",
621 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
622 Return 0 on success: without mismatch.
623 Reutrn 1 on error. */
626 gcov_profile_merge (struct gcov_info
*tgt_profile
, struct gcov_info
*src_profile
,
629 struct gcov_info
*gi_ptr
;
630 struct gcov_info
**tgt_infos
;
631 struct gcov_info
*tgt_tail
;
632 struct gcov_info
**in_src_not_tgt
;
633 unsigned tgt_cnt
= 0, src_cnt
= 0;
634 unsigned unmatch_info_cnt
= 0;
637 for (gi_ptr
= tgt_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
639 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
641 tgt_infos
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
643 gcc_assert (tgt_infos
);
644 in_src_not_tgt
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
646 gcc_assert (in_src_not_tgt
);
648 for (gi_ptr
= tgt_profile
, i
= 0; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
649 tgt_infos
[i
] = gi_ptr
;
651 tgt_tail
= tgt_infos
[tgt_cnt
- 1];
653 /* First pass on tgt_profile, we multiply w1 to all counters. */
656 for (i
= 0; i
< tgt_cnt
; i
++)
657 gcov_merge (tgt_infos
[i
], tgt_infos
[i
], w1
-1);
660 /* Second pass, add src_profile to the tgt_profile. */
661 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
663 struct gcov_info
*gi_ptr1
;
665 gi_ptr1
= find_match_gcov_info (tgt_infos
, tgt_cnt
, gi_ptr
);
668 in_src_not_tgt
[unmatch_info_cnt
++] = gi_ptr
;
671 gcov_merge (gi_ptr1
, gi_ptr
, w2
);
674 /* For modules in src but not in tgt. We adjust the counter and append. */
675 for (i
= 0; i
< unmatch_info_cnt
; i
++)
677 gi_ptr
= in_src_not_tgt
[i
];
678 gcov_merge (gi_ptr
, gi_ptr
, w2
- 1);
680 tgt_tail
->next
= gi_ptr
;
684 free (in_src_not_tgt
);
690 typedef gcov_type (*counter_op_fn
) (gcov_type
, void*, void*);
692 /* Performing FN upon arc counters. */
695 __gcov_add_counter_op (gcov_type
*counters
, unsigned n_counters
,
696 counter_op_fn fn
, void *data1
, void *data2
)
698 for (; n_counters
; counters
++, n_counters
--)
700 gcov_type val
= *counters
;
701 *counters
= fn(val
, data1
, data2
);
705 /* Performing FN upon ior counters. */
708 __gcov_ior_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
709 unsigned n_counters ATTRIBUTE_UNUSED
,
710 counter_op_fn fn ATTRIBUTE_UNUSED
,
711 void *data1 ATTRIBUTE_UNUSED
,
712 void *data2 ATTRIBUTE_UNUSED
)
717 /* Performing FN upon time-profile counters. */
720 __gcov_time_profile_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
721 unsigned n_counters ATTRIBUTE_UNUSED
,
722 counter_op_fn fn ATTRIBUTE_UNUSED
,
723 void *data1 ATTRIBUTE_UNUSED
,
724 void *data2 ATTRIBUTE_UNUSED
)
729 /* Performing FN upon single counters. */
732 __gcov_single_counter_op (gcov_type
*counters
, unsigned n_counters
,
733 counter_op_fn fn
, void *data1
, void *data2
)
735 unsigned i
, n_measures
;
737 gcc_assert (!(n_counters
% 3));
738 n_measures
= n_counters
/ 3;
739 for (i
= 0; i
< n_measures
; i
++, counters
+= 3)
741 counters
[1] = fn (counters
[1], data1
, data2
);
742 counters
[2] = fn (counters
[2], data1
, data2
);
746 /* Scaling the counter value V by multiplying *(float*) DATA1. */
749 fp_scale (gcov_type v
, void *data1
, void *data2 ATTRIBUTE_UNUSED
)
751 float f
= *(float *) data1
;
752 return (gcov_type
) (v
* f
);
755 /* Scaling the counter value V by multiplying DATA2/DATA1. */
758 int_scale (gcov_type v
, void *data1
, void *data2
)
760 int n
= *(int *) data1
;
761 int d
= *(int *) data2
;
762 return (gcov_type
) ( RDIV (v
,d
) * n
);
765 /* Type of function used to process counters. */
766 typedef void (*gcov_counter_fn
) (gcov_type
*, gcov_unsigned_t
,
767 counter_op_fn
, void *, void *);
769 /* Function array to process profile counters. */
770 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
771 __gcov ## FN_TYPE ## _counter_op,
772 static gcov_counter_fn ctr_functions
[GCOV_COUNTERS
] = {
773 #include "gcov-counter.def"
775 #undef DEF_GCOV_COUNTER
777 /* Driver for scaling profile counters. */
780 gcov_profile_scale (struct gcov_info
*profile
, float scale_factor
, int n
, int d
)
782 struct gcov_info
*gi_ptr
;
786 fnotice (stdout
, "scale_factor is %f or %d/%d\n", scale_factor
, n
, d
);
788 /* Scaling the counters. */
789 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
790 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
793 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
794 const struct gcov_ctr_info
*ci_ptr
;
796 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
799 ci_ptr
= gfi_ptr
->ctrs
;
800 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
802 gcov_merge_fn merge
= gi_ptr
->merge
[t_ix
];
807 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
808 fp_scale
, &scale_factor
, NULL
);
810 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
819 /* Driver to normalize profile counters. */
822 gcov_profile_normalize (struct gcov_info
*profile
, gcov_type max_val
)
824 struct gcov_info
*gi_ptr
;
825 gcov_type curr_max_val
= 0;
830 /* Find the largest count value. */
831 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
832 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
835 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
836 const struct gcov_ctr_info
*ci_ptr
;
838 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
841 ci_ptr
= gfi_ptr
->ctrs
;
842 for (t_ix
= 0; t_ix
< 1; t_ix
++)
844 for (i
= 0; i
< ci_ptr
->num
; i
++)
845 if (ci_ptr
->values
[i
] > curr_max_val
)
846 curr_max_val
= ci_ptr
->values
[i
];
851 scale_factor
= (float)max_val
/ curr_max_val
;
853 fnotice (stdout
, "max_val is %" PRId64
"\n", curr_max_val
);
855 return gcov_profile_scale (profile
, scale_factor
, 0, 0);
858 /* The following variables are defined in gcc/gcov-tool.c. */
859 extern int overlap_func_level
;
860 extern int overlap_obj_level
;
861 extern int overlap_hot_only
;
862 extern int overlap_use_fullname
;
863 extern double overlap_hot_threshold
;
865 /* Compute the overlap score of two values. The score is defined as:
866 min (V1/SUM_1, V2/SUM_2) */
869 calculate_2_entries (const unsigned long v1
, const unsigned long v2
,
870 const double sum_1
, const double sum_2
)
872 double val1
= (sum_1
== 0.0 ? 0.0 : v1
/sum_1
);
873 double val2
= (sum_2
== 0.0 ? 0.0 : v2
/sum_2
);
881 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
882 This function also updates cumulative score CUM_1_RESULT and
886 compute_one_gcov (const struct gcov_info
*gcov_info1
,
887 const struct gcov_info
*gcov_info2
,
888 const double sum_1
, const double sum_2
,
889 double *cum_1_result
, double *cum_2_result
)
893 double cum_1
= 0, cum_2
= 0;
894 const struct gcov_info
*gcov_info
= 0;
898 gcc_assert (gcov_info1
|| gcov_info2
);
901 gcov_info
= gcov_info2
;
902 cum_p
= cum_2_result
;
908 gcov_info
= gcov_info1
;
909 cum_p
= cum_1_result
;
916 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
918 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
919 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
921 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
923 for (c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
924 cum_1
+= ci_ptr
->values
[c_num
] / sum
;
930 for (f_ix
= 0; f_ix
< gcov_info1
->n_functions
; f_ix
++)
932 double func_cum_1
= 0.0;
933 double func_cum_2
= 0.0;
934 double func_val
= 0.0;
937 const struct gcov_fn_info
*gfi_ptr1
= gcov_info1
->functions
[f_ix
];
938 const struct gcov_fn_info
*gfi_ptr2
= gcov_info2
->functions
[f_ix
];
940 if (!gfi_ptr1
|| gfi_ptr1
->key
!= gcov_info1
)
942 if (!gfi_ptr2
|| gfi_ptr2
->key
!= gcov_info2
)
945 const struct gcov_ctr_info
*ci_ptr1
= gfi_ptr1
->ctrs
;
946 const struct gcov_ctr_info
*ci_ptr2
= gfi_ptr2
->ctrs
;
948 for (c_num
= 0; c_num
< ci_ptr1
->num
; c_num
++)
950 if (ci_ptr1
->values
[c_num
] | ci_ptr2
->values
[c_num
])
952 func_val
+= calculate_2_entries (ci_ptr1
->values
[c_num
],
953 ci_ptr2
->values
[c_num
],
956 func_cum_1
+= ci_ptr1
->values
[c_num
] / sum_1
;
957 func_cum_2
+= ci_ptr2
->values
[c_num
] / sum_2
;
959 if (ci_ptr1
->values
[c_num
] / sum_1
>= overlap_hot_threshold
960 || ci_ptr2
->values
[c_num
] / sum_2
>= overlap_hot_threshold
)
968 if (overlap_func_level
&& nonzero
&& (!overlap_hot_only
|| hot
))
970 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
971 gfi_ptr1
->ident
, func_val
*100, func_cum_1
*100, func_cum_2
*100);
974 *cum_1_result
= cum_1
;
975 *cum_2_result
= cum_2
;
979 /* Test if all counter values in this GCOV_INFO are cold.
980 "Cold" is defined as the counter value being less than
981 or equal to THRESHOLD. */
984 gcov_info_count_all_cold (const struct gcov_info
*gcov_info
,
989 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
991 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
993 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
995 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
996 for (unsigned c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
997 if (ci_ptr
->values
[c_num
] > threshold
)
1004 /* Test if all counter values in this GCOV_INFO are 0. */
1007 gcov_info_count_all_zero (const struct gcov_info
*gcov_info
)
1009 return gcov_info_count_all_cold (gcov_info
, 0);
1012 /* A pair of matched GCOV_INFO.
1013 The flag is a bitvector:
1014 b0: obj1's all counts are 0;
1015 b1: obj1's all counts are cold (but no 0);
1017 b3: no obj1 to match obj2;
1018 b4: obj2's all counts are 0;
1019 b5: obj2's all counts are cold (but no 0);
1021 b7: no obj2 to match obj1;
1024 const struct gcov_info
*obj1
;
1025 const struct gcov_info
*obj2
;
1029 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1030 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1031 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1033 /* Cumlative overlap dscore for profile1 and profile2. */
1034 static double overlap_sum_1
, overlap_sum_2
;
1036 /* The number of gcda files in the profiles. */
1037 static unsigned gcda_files
[2];
1039 /* The number of unique gcda files in the profiles
1040 (not existing in the other profile). */
1041 static unsigned unique_gcda_files
[2];
1043 /* The number of gcda files that all counter values are 0. */
1044 static unsigned zero_gcda_files
[2];
1046 /* The number of gcda files that all counter values are cold (but not 0). */
1047 static unsigned cold_gcda_files
[2];
1049 /* The number of gcda files that includes hot counter values. */
1050 static unsigned hot_gcda_files
[2];
1052 /* The number of gcda files with hot count value in either profiles. */
1053 static unsigned both_hot_cnt
;
1055 /* The number of gcda files with all counts cold (but not 0) in
1057 static unsigned both_cold_cnt
;
1059 /* The number of gcda files with all counts 0 in both profiles. */
1060 static unsigned both_zero_cnt
;
1062 /* Extract the basename of the filename NAME. */
1065 extract_file_basename (const char *name
)
1069 char *path
= xstrdup (name
);
1072 sep_str
[0] = DIR_SEPARATOR
;
1074 str
= strstr(path
, sep_str
);
1076 len
= strlen(str
) + 1;
1077 path
= &path
[strlen(path
) - len
+ 2];
1078 str
= strstr(path
, sep_str
);
1084 /* Utility function to get the filename. */
1087 get_file_basename (const char *name
)
1089 if (overlap_use_fullname
)
1091 return extract_file_basename (name
);
1094 /* A utility function to set the flag for the gcda files. */
1097 set_flag (struct overlap_t
*e
)
1103 unique_gcda_files
[1]++;
1109 if (gcov_info_count_all_zero (e
->obj1
))
1111 zero_gcda_files
[0]++;
1115 if (gcov_info_count_all_cold (e
->obj1
, overlap_sum_1
1116 * overlap_hot_threshold
))
1118 cold_gcda_files
[0]++;
1123 hot_gcda_files
[0]++;
1130 unique_gcda_files
[0]++;
1136 if (gcov_info_count_all_zero (e
->obj2
))
1138 zero_gcda_files
[1]++;
1142 if (gcov_info_count_all_cold (e
->obj2
, overlap_sum_2
1143 * overlap_hot_threshold
))
1145 cold_gcda_files
[1]++;
1150 hot_gcda_files
[1]++;
1159 /* Test if INFO1 and INFO2 are from the matched source file.
1160 Return 1 if they match; return 0 otherwise. */
1163 matched_gcov_info (const struct gcov_info
*info1
, const struct gcov_info
*info2
)
1165 /* For FDO, we have to match the name. This can be expensive.
1166 Maybe we should use hash here. */
1167 if (strcmp (info1
->filename
, info2
->filename
))
1170 if (info1
->n_functions
!= info2
->n_functions
)
1172 fnotice (stderr
, "mismatched profiles in %s (%d functions"
1173 " vs %d functions)\n",
1176 info2
->n_functions
);
1182 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1183 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1184 match and 1.0 meaning a perfect match. */
1187 calculate_overlap (struct gcov_info
*gcov_list1
,
1188 struct gcov_info
*gcov_list2
)
1190 unsigned list1_cnt
= 0, list2_cnt
= 0, all_cnt
;
1192 const struct gcov_info
*gi_ptr
;
1193 struct overlap_t
*all_infos
;
1195 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1197 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1199 all_cnt
= list1_cnt
+ list2_cnt
;
1200 all_infos
= (struct overlap_t
*) xmalloc (sizeof (struct overlap_t
)
1202 gcc_assert (all_infos
);
1205 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1207 all_infos
[i
].obj1
= gi_ptr
;
1208 all_infos
[i
].obj2
= 0;
1211 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1213 all_infos
[i
].obj1
= 0;
1214 all_infos
[i
].obj2
= gi_ptr
;
1217 for (i
= list1_cnt
; i
< all_cnt
; i
++)
1219 if (all_infos
[i
].obj2
== 0)
1221 for (j
= 0; j
< list1_cnt
; j
++)
1223 if (all_infos
[j
].obj2
!= 0)
1225 if (matched_gcov_info (all_infos
[i
].obj2
, all_infos
[j
].obj1
))
1227 all_infos
[j
].obj2
= all_infos
[i
].obj2
;
1228 all_infos
[i
].obj2
= 0;
1234 for (i
= 0; i
< all_cnt
; i
++)
1235 if (all_infos
[i
].obj1
|| all_infos
[i
].obj2
)
1237 set_flag (all_infos
+ i
);
1238 if (FLAG_ONE_HOT (all_infos
[i
].flag
))
1240 if (FLAG_BOTH_COLD(all_infos
[i
].flag
))
1242 if (FLAG_BOTH_ZERO(all_infos
[i
].flag
))
1248 double sum_cum_1
= 0;
1249 double sum_cum_2
= 0;
1251 for (i
= 0; i
< all_cnt
; i
++)
1254 double cum_1
, cum_2
;
1255 const char *filename
;
1257 if (all_infos
[i
].obj1
== 0 && all_infos
[i
].obj2
== 0)
1259 if (FLAG_BOTH_ZERO (all_infos
[i
].flag
))
1262 if (all_infos
[i
].obj1
)
1263 filename
= get_file_basename (all_infos
[i
].obj1
->filename
);
1265 filename
= get_file_basename (all_infos
[i
].obj2
->filename
);
1267 if (overlap_func_level
)
1268 printf("\n processing %36s:\n", filename
);
1270 val
= compute_one_gcov (all_infos
[i
].obj1
, all_infos
[i
].obj2
,
1271 overlap_sum_1
, overlap_sum_2
, &cum_1
, &cum_2
);
1273 if (overlap_obj_level
&& (!overlap_hot_only
|| FLAG_ONE_HOT (all_infos
[i
].flag
)))
1275 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1276 filename
, val
*100, cum_1
*100, cum_2
*100);
1288 if (overlap_obj_level
)
1289 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1290 "", sum_val
*100, sum_cum_1
*100, sum_cum_2
*100);
1292 printf (" Statistics:\n"
1293 " profile1_# profile2_# overlap_#\n");
1294 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files
[0], gcda_files
[1],
1295 gcda_files
[0]-unique_gcda_files
[0]);
1296 printf (" unique files: %12u\t%12u\n", unique_gcda_files
[0],
1297 unique_gcda_files
[1]);
1298 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files
[0],
1299 hot_gcda_files
[1], both_hot_cnt
);
1300 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files
[0],
1301 cold_gcda_files
[1], both_cold_cnt
);
1302 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files
[0],
1303 zero_gcda_files
[1], both_zero_cnt
);
1308 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1310 Return 0 on success: without mismatch. Reutrn 1 on error. */
1313 gcov_profile_overlap (struct gcov_info
*profile1
, struct gcov_info
*profile2
)
1317 result
= calculate_overlap (profile1
, profile2
);
1321 printf("\nProgram level overlap result is %3.2f%%\n\n", result
*100);