1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2016 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"
36 /* Borrowed from basic-block.h. */
37 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
39 extern gcov_position_t
gcov_position();
40 extern int gcov_is_error();
42 /* Verbose mode for debug. */
45 /* Set verbose flag. */
46 void gcov_set_verbose (void)
51 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
59 static void tag_function (unsigned, unsigned);
60 static void tag_blocks (unsigned, unsigned);
61 static void tag_arcs (unsigned, unsigned);
62 static void tag_lines (unsigned, unsigned);
63 static void tag_counters (unsigned, unsigned);
64 static void tag_summary (unsigned, unsigned);
66 /* The gcov_info for the first module. */
67 static struct gcov_info
*curr_gcov_info
;
68 /* The gcov_info being processed. */
69 static struct gcov_info
*gcov_info_head
;
70 /* This variable contains all the functions in current module. */
71 static struct obstack fn_info
;
72 /* The function being processed. */
73 static struct gcov_fn_info
*curr_fn_info
;
74 /* The number of functions seen so far. */
75 static unsigned num_fn_info
;
76 /* This variable contains all the counters for current module. */
77 static int k_ctrs_mask
[GCOV_COUNTERS
];
78 /* The kind of counters that have been seen. */
79 static struct gcov_ctr_info k_ctrs
[GCOV_COUNTERS
];
80 /* Number of kind of counters that have been seen. */
81 static int k_ctrs_types
;
83 /* Merge functions for counters. */
84 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
85 static gcov_merge_fn ctr_merge_functions
[GCOV_COUNTERS
] = {
86 #include "gcov-counter.def"
88 #undef DEF_GCOV_COUNTER
90 /* Set the ctrs field in gcov_fn_info object FN_INFO. */
93 set_fn_ctrs (struct gcov_fn_info
*fn_info
)
97 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
99 if (k_ctrs_mask
[i
] == 0)
101 fn_info
->ctrs
[j
].num
= k_ctrs
[i
].num
;
102 fn_info
->ctrs
[j
].values
= k_ctrs
[i
].values
;
105 if (k_ctrs_types
== 0)
108 gcc_assert (j
== k_ctrs_types
);
111 /* For each tag in gcda file, we have an entry here.
112 TAG is the tag value; NAME is the tag name; and
113 PROC is the handler function. */
115 typedef struct tag_format
119 void (*proc
) (unsigned, unsigned);
122 /* Handler table for various Tags. */
124 static const tag_format_t tag_table
[] =
127 {0, "UNKNOWN", NULL
},
128 {0, "COUNTERS", tag_counters
},
129 {GCOV_TAG_FUNCTION
, "FUNCTION", tag_function
},
130 {GCOV_TAG_BLOCKS
, "BLOCKS", tag_blocks
},
131 {GCOV_TAG_ARCS
, "ARCS", tag_arcs
},
132 {GCOV_TAG_LINES
, "LINES", tag_lines
},
133 {GCOV_TAG_OBJECT_SUMMARY
, "OBJECT_SUMMARY", tag_summary
},
134 {GCOV_TAG_PROGRAM_SUMMARY
, "PROGRAM_SUMMARY", tag_summary
},
138 /* Handler for reading function tag. */
141 tag_function (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
145 /* write out previous fn_info. */
148 set_fn_ctrs (curr_fn_info
);
149 obstack_ptr_grow (&fn_info
, curr_fn_info
);
152 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
154 curr_fn_info
= (struct gcov_fn_info
*) xcalloc (sizeof (struct gcov_fn_info
)
155 + GCOV_COUNTERS
* sizeof (struct gcov_ctr_info
), 1);
157 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
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 ();
168 fnotice (stdout
, "tag one function id=%d\n", curr_fn_info
->ident
);
171 /* Handler for reading block tag. */
174 tag_blocks (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
176 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
180 /* Handler for reading flow arc tag. */
183 tag_arcs (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
185 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
189 /* Handler for reading line tag. */
192 tag_lines (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
194 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
198 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
201 tag_counters (unsigned tag
, unsigned length
)
203 unsigned n_counts
= GCOV_TAG_COUNTER_NUM (length
);
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
;
214 k_ctrs
[tag_ix
].values
= values
= (gcov_type
*) xmalloc (n_counts
* sizeof (gcov_type
));
217 for (ix
= 0; ix
!= n_counts
; ix
++)
218 values
[ix
] = gcov_read_counter ();
221 /* Handler for reading summary tag. */
224 tag_summary (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
226 struct gcov_summary summary
;
228 gcov_read_summary (&summary
);
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. */
235 read_gcda_finalize (struct gcov_info
*obj_info
)
239 set_fn_ctrs (curr_fn_info
);
240 obstack_ptr_grow (&fn_info
, curr_fn_info
);
242 /* We set the following fields: merge, n_functions, and functions. */
243 obj_info
->n_functions
= num_fn_info
;
244 obj_info
->functions
= (const struct gcov_fn_info
**) obstack_finish (&fn_info
);
246 /* wrap all the counter array. */
247 for (i
=0; i
< GCOV_COUNTERS
; i
++)
250 obj_info
->merge
[i
] = ctr_merge_functions
[i
];
254 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
255 Program level summary CURRENT_SUMMARY will also be updated. */
257 static struct gcov_info
*
258 read_gcda_file (const char *filename
)
262 unsigned magic
, version
;
263 struct gcov_info
*obj_info
;
266 for (i
=0; i
< GCOV_COUNTERS
; i
++)
270 if (!gcov_open (filename
))
272 fnotice (stderr
, "%s:cannot open\n", filename
);
277 magic
= gcov_read_unsigned ();
278 if (magic
!= GCOV_DATA_MAGIC
)
280 fnotice (stderr
, "%s:not a gcov data file\n", filename
);
286 version
= gcov_read_unsigned ();
287 if (version
!= GCOV_VERSION
)
289 fnotice (stderr
, "%s:incorrect gcov version %d vs %d \n", filename
, version
, GCOV_VERSION
);
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);
298 obj_info
->version
= version
;
299 obstack_init (&fn_info
);
303 size_t len
= strlen (filename
) + 1;
304 char *str_dup
= (char*) xmalloc (len
);
306 memcpy (str_dup
, filename
, len
);
307 obj_info
->filename
= str_dup
;
311 obj_info
->stamp
= gcov_read_unsigned ();
315 gcov_position_t base
;
316 unsigned tag
, length
;
317 tag_format_t
const *format
;
322 tag
= gcov_read_unsigned ();
325 length
= gcov_read_unsigned ();
326 base
= gcov_position ();
327 mask
= GCOV_TAG_MASK (tag
) >> 1;
328 for (tag_depth
= 4; mask
; mask
>>= 8)
330 if (((mask
& 0xff) != 0xff))
332 warning (0, "%s:tag `%x' is invalid\n", filename
, tag
);
337 for (format
= tag_table
; format
->name
; format
++)
338 if (format
->tag
== tag
)
340 format
= &tag_table
[GCOV_TAG_IS_COUNTER (tag
) ? 2 : 1];
344 if (depth
&& depth
< tag_depth
)
346 if (!GCOV_TAG_IS_SUBTAG (tags
[depth
- 1], tag
))
347 warning (0, "%s:tag `%x' is incorrectly nested\n",
351 tags
[depth
- 1] = tag
;
356 unsigned long actual_length
;
358 (*format
->proc
) (tag
, length
);
360 actual_length
= gcov_position () - base
;
361 if (actual_length
> length
)
362 warning (0, "%s:record size mismatch %lu bytes overread\n",
363 filename
, actual_length
- length
);
364 else if (length
> actual_length
)
365 warning (0, "%s:record size mismatch %lu bytes unread\n",
366 filename
, length
- actual_length
);
369 gcov_sync (base
, length
);
370 if ((error
= gcov_is_error ()))
372 warning (0, error
< 0 ? "%s:counter overflow at %lu\n" :
373 "%s:read error at %lu\n", filename
,
374 (long unsigned) gcov_position ());
379 read_gcda_finalize (obj_info
);
386 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
387 Return a non-zero value to stop the tree walk. */
390 ftw_read_file (const char *filename
,
391 const struct stat
*status ATTRIBUTE_UNUSED
,
396 struct gcov_info
*obj_info
;
398 /* Only read regular files. */
402 filename_len
= strlen (filename
);
403 suffix_len
= strlen (GCOV_DATA_SUFFIX
);
405 if (filename_len
<= suffix_len
)
408 if (strcmp(filename
+ filename_len
- suffix_len
, GCOV_DATA_SUFFIX
))
412 fnotice (stderr
, "reading file: %s\n", filename
);
414 obj_info
= read_gcda_file (filename
);
418 obj_info
->next
= gcov_info_head
;
419 gcov_info_head
= obj_info
;
425 /* Initializer for reading a profile dir. */
428 read_profile_dir_init (void)
433 /* Driver for read a profile directory and convert into gcov_info list in memory.
434 Return NULL on error,
435 Return the head of gcov_info list on success. */
438 gcov_read_profile_dir (const char* dir_name
, int recompute_summary ATTRIBUTE_UNUSED
)
443 read_profile_dir_init ();
445 if (access (dir_name
, R_OK
) != 0)
447 fnotice (stderr
, "cannot access directory %s\n", dir_name
);
450 pwd
= getcwd (NULL
, 0);
452 ret
= chdir (dir_name
);
455 fnotice (stderr
, "%s is not a directory\n", dir_name
);
459 ftw (".", ftw_read_file
, 50);
465 return gcov_info_head
;;
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. */
472 /* We save the counter value address to this variable. */
473 static gcov_type
*gcov_value_buf
;
475 /* The number of counter values to be read by current merging. */
476 static gcov_unsigned_t gcov_value_buf_size
;
478 /* The index of counter values being read. */
479 static gcov_unsigned_t gcov_value_buf_pos
;
481 /* The weight of current merging. */
482 static unsigned gcov_merge_weight
;
484 /* Read a counter value from gcov_value_buf array. */
487 gcov_read_counter_mem (void)
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
;
496 /* Return the recorded merge weight. */
499 gcov_get_merge_weight (void)
501 return gcov_merge_weight
;
504 /* A wrapper function for merge functions. It sets up the
505 value buffer and weights and then calls the merge function. */
508 merge_wrapper (gcov_merge_fn f
, gcov_type
*v1
, gcov_unsigned_t n
,
509 gcov_type
*v2
, unsigned w
)
512 gcov_value_buf_pos
= 0;
513 gcov_value_buf_size
= n
;
514 gcov_merge_weight
= w
;
518 /* Offline tool to manipulate profile data.
519 This tool targets on matched profiles. But it has some tolerance on
521 When merging p1 to p2 (p2 is the dst),
522 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
524 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
525 specified weight; emit warning.
526 * m.gcda in both p1 and p2:
527 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
528 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
530 drop p1->m.gcda->f. A warning is emitted. */
532 /* Add INFO2's counter to INFO1, multiplying by weight W. */
535 gcov_merge (struct gcov_info
*info1
, struct gcov_info
*info2
, int w
)
538 unsigned n_functions
= info1
->n_functions
;
539 int has_mismatch
= 0;
541 gcc_assert (info2
->n_functions
== n_functions
);
542 for (f_ix
= 0; f_ix
< n_functions
; f_ix
++)
545 const struct gcov_fn_info
*gfi_ptr1
= info1
->functions
[f_ix
];
546 const struct gcov_fn_info
*gfi_ptr2
= info2
->functions
[f_ix
];
547 const struct gcov_ctr_info
*ci_ptr1
, *ci_ptr2
;
549 if (!gfi_ptr1
|| gfi_ptr1
->key
!= info1
)
551 if (!gfi_ptr2
|| gfi_ptr2
->key
!= info2
)
554 if (gfi_ptr1
->cfg_checksum
!= gfi_ptr2
->cfg_checksum
)
556 fnotice (stderr
, "in %s, cfg_checksum mismatch, skipping\n",
561 ci_ptr1
= gfi_ptr1
->ctrs
;
562 ci_ptr2
= gfi_ptr2
->ctrs
;
563 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
565 gcov_merge_fn merge1
= info1
->merge
[t_ix
];
566 gcov_merge_fn merge2
= info2
->merge
[t_ix
];
568 gcc_assert (merge1
== merge2
);
571 gcc_assert (ci_ptr1
->num
== ci_ptr2
->num
);
572 merge_wrapper (merge1
, ci_ptr1
->values
, ci_ptr1
->num
, ci_ptr2
->values
, w
);
581 /* Find and return the match gcov_info object for INFO from ARRAY.
582 SIZE is the length of ARRAY.
583 Return NULL if there is no match. */
585 static struct gcov_info
*
586 find_match_gcov_info (struct gcov_info
**array
, int size
,
587 struct gcov_info
*info
)
589 struct gcov_info
*gi_ptr
;
590 struct gcov_info
*ret
= NULL
;
593 for (i
= 0; i
< size
; i
++)
598 if (!strcmp (gi_ptr
->filename
, info
->filename
))
606 if (ret
&& ret
->n_functions
!= info
->n_functions
)
608 fnotice (stderr
, "mismatched profiles in %s (%d functions"
609 " vs %d functions)\n",
618 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
619 Return 0 on success: without mismatch.
620 Reutrn 1 on error. */
623 gcov_profile_merge (struct gcov_info
*tgt_profile
, struct gcov_info
*src_profile
,
626 struct gcov_info
*gi_ptr
;
627 struct gcov_info
**tgt_infos
;
628 struct gcov_info
*tgt_tail
;
629 struct gcov_info
**in_src_not_tgt
;
630 unsigned tgt_cnt
= 0, src_cnt
= 0;
631 unsigned unmatch_info_cnt
= 0;
634 for (gi_ptr
= tgt_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
636 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
638 tgt_infos
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
640 gcc_assert (tgt_infos
);
641 in_src_not_tgt
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
643 gcc_assert (in_src_not_tgt
);
645 for (gi_ptr
= tgt_profile
, i
= 0; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
646 tgt_infos
[i
] = gi_ptr
;
648 tgt_tail
= tgt_infos
[tgt_cnt
- 1];
650 /* First pass on tgt_profile, we multiply w1 to all counters. */
653 for (i
= 0; i
< tgt_cnt
; i
++)
654 gcov_merge (tgt_infos
[i
], tgt_infos
[i
], w1
-1);
657 /* Second pass, add src_profile to the tgt_profile. */
658 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
660 struct gcov_info
*gi_ptr1
;
662 gi_ptr1
= find_match_gcov_info (tgt_infos
, tgt_cnt
, gi_ptr
);
665 in_src_not_tgt
[unmatch_info_cnt
++] = gi_ptr
;
668 gcov_merge (gi_ptr1
, gi_ptr
, w2
);
671 /* For modules in src but not in tgt. We adjust the counter and append. */
672 for (i
= 0; i
< unmatch_info_cnt
; i
++)
674 gi_ptr
= in_src_not_tgt
[i
];
675 gcov_merge (gi_ptr
, gi_ptr
, w2
- 1);
676 tgt_tail
->next
= gi_ptr
;
683 typedef gcov_type (*counter_op_fn
) (gcov_type
, void*, void*);
685 /* Performing FN upon arc counters. */
688 __gcov_add_counter_op (gcov_type
*counters
, unsigned n_counters
,
689 counter_op_fn fn
, void *data1
, void *data2
)
691 for (; n_counters
; counters
++, n_counters
--)
693 gcov_type val
= *counters
;
694 *counters
= fn(val
, data1
, data2
);
698 /* Performing FN upon ior counters. */
701 __gcov_ior_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
702 unsigned n_counters ATTRIBUTE_UNUSED
,
703 counter_op_fn fn ATTRIBUTE_UNUSED
,
704 void *data1 ATTRIBUTE_UNUSED
,
705 void *data2 ATTRIBUTE_UNUSED
)
710 /* Performing FN upon time-profile counters. */
713 __gcov_time_profile_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
714 unsigned n_counters ATTRIBUTE_UNUSED
,
715 counter_op_fn fn ATTRIBUTE_UNUSED
,
716 void *data1 ATTRIBUTE_UNUSED
,
717 void *data2 ATTRIBUTE_UNUSED
)
722 /* Performaing FN upon delta counters. */
725 __gcov_delta_counter_op (gcov_type
*counters
, unsigned n_counters
,
726 counter_op_fn fn
, void *data1
, void *data2
)
728 unsigned i
, n_measures
;
730 gcc_assert (!(n_counters
% 4));
731 n_measures
= n_counters
/ 4;
732 for (i
= 0; i
< n_measures
; i
++, counters
+= 4)
734 counters
[2] = fn (counters
[2], data1
, data2
);
735 counters
[3] = fn (counters
[3], data1
, data2
);
739 /* Performing FN upon single counters. */
742 __gcov_single_counter_op (gcov_type
*counters
, unsigned n_counters
,
743 counter_op_fn fn
, void *data1
, void *data2
)
745 unsigned i
, n_measures
;
747 gcc_assert (!(n_counters
% 3));
748 n_measures
= n_counters
/ 3;
749 for (i
= 0; i
< n_measures
; i
++, counters
+= 3)
751 counters
[1] = fn (counters
[1], data1
, data2
);
752 counters
[2] = fn (counters
[2], data1
, data2
);
756 /* Performing FN upon indirect-call profile counters. */
759 __gcov_icall_topn_counter_op (gcov_type
*counters
, unsigned n_counters
,
760 counter_op_fn fn
, void *data1
, void *data2
)
764 gcc_assert (!(n_counters
% GCOV_ICALL_TOPN_NCOUNTS
));
765 for (i
= 0; i
< n_counters
; i
+= GCOV_ICALL_TOPN_NCOUNTS
)
768 gcov_type
*value_array
= &counters
[i
+ 1];
770 for (j
= 0; j
< GCOV_ICALL_TOPN_NCOUNTS
- 1; j
+= 2)
771 value_array
[j
+ 1] = fn (value_array
[j
+ 1], data1
, data2
);
775 /* Scaling the counter value V by multiplying *(float*) DATA1. */
778 fp_scale (gcov_type v
, void *data1
, void *data2 ATTRIBUTE_UNUSED
)
780 float f
= *(float *) data1
;
781 return (gcov_type
) (v
* f
);
784 /* Scaling the counter value V by multiplying DATA2/DATA1. */
787 int_scale (gcov_type v
, void *data1
, void *data2
)
789 int n
= *(int *) data1
;
790 int d
= *(int *) data2
;
791 return (gcov_type
) ( RDIV (v
,d
) * n
);
794 /* Type of function used to process counters. */
795 typedef void (*gcov_counter_fn
) (gcov_type
*, gcov_unsigned_t
,
796 counter_op_fn
, void *, void *);
798 /* Function array to process profile counters. */
799 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
800 __gcov ## FN_TYPE ## _counter_op,
801 static gcov_counter_fn ctr_functions
[GCOV_COUNTERS
] = {
802 #include "gcov-counter.def"
804 #undef DEF_GCOV_COUNTER
806 /* Driver for scaling profile counters. */
809 gcov_profile_scale (struct gcov_info
*profile
, float scale_factor
, int n
, int d
)
811 struct gcov_info
*gi_ptr
;
815 fnotice (stdout
, "scale_factor is %f or %d/%d\n", scale_factor
, n
, d
);
817 /* Scaling the counters. */
818 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
819 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
822 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
823 const struct gcov_ctr_info
*ci_ptr
;
825 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
828 ci_ptr
= gfi_ptr
->ctrs
;
829 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
831 gcov_merge_fn merge
= gi_ptr
->merge
[t_ix
];
836 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
837 fp_scale
, &scale_factor
, NULL
);
839 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
848 /* Driver to normalize profile counters. */
851 gcov_profile_normalize (struct gcov_info
*profile
, gcov_type max_val
)
853 struct gcov_info
*gi_ptr
;
854 gcov_type curr_max_val
= 0;
859 /* Find the largest count value. */
860 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
861 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
864 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
865 const struct gcov_ctr_info
*ci_ptr
;
867 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
870 ci_ptr
= gfi_ptr
->ctrs
;
871 for (t_ix
= 0; t_ix
< 1; t_ix
++)
873 for (i
= 0; i
< ci_ptr
->num
; i
++)
874 if (ci_ptr
->values
[i
] > curr_max_val
)
875 curr_max_val
= ci_ptr
->values
[i
];
880 scale_factor
= (float)max_val
/ curr_max_val
;
882 fnotice (stdout
, "max_val is %" PRId64
"\n", curr_max_val
);
884 return gcov_profile_scale (profile
, scale_factor
, 0, 0);
887 /* The following variables are defined in gcc/gcov-tool.c. */
888 extern int overlap_func_level
;
889 extern int overlap_obj_level
;
890 extern int overlap_hot_only
;
891 extern int overlap_use_fullname
;
892 extern double overlap_hot_threshold
;
894 /* Compute the overlap score of two values. The score is defined as:
895 min (V1/SUM_1, V2/SUM_2) */
898 calculate_2_entries (const unsigned long v1
, const unsigned long v2
,
899 const double sum_1
, const double sum_2
)
901 double val1
= (sum_1
== 0.0 ? 0.0 : v1
/sum_1
);
902 double val2
= (sum_2
== 0.0 ? 0.0 : v2
/sum_2
);
910 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
911 SUM_1 is the sum_all for profile1 where GCOV_INFO1 belongs.
912 SUM_2 is the sum_all for profile2 where GCOV_INFO2 belongs.
913 This function also updates cumulative score CUM_1_RESULT and
917 compute_one_gcov (const struct gcov_info
*gcov_info1
,
918 const struct gcov_info
*gcov_info2
,
919 const double sum_1
, const double sum_2
,
920 double *cum_1_result
, double *cum_2_result
)
924 double cum_1
= 0, cum_2
= 0;
925 const struct gcov_info
*gcov_info
= 0;
929 gcc_assert (gcov_info1
|| gcov_info2
);
932 gcov_info
= gcov_info2
;
933 cum_p
= cum_2_result
;
939 gcov_info
= gcov_info1
;
940 cum_p
= cum_1_result
;
947 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
950 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
951 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
953 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
954 for (t_ix
= 0; t_ix
< GCOV_COUNTERS_SUMMABLE
; t_ix
++)
958 if (!gcov_info
->merge
[t_ix
])
961 for (c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
963 cum_1
+= ci_ptr
->values
[c_num
] / sum
;
972 for (f_ix
= 0; f_ix
< gcov_info1
->n_functions
; f_ix
++)
975 double func_cum_1
= 0.0;
976 double func_cum_2
= 0.0;
977 double func_val
= 0.0;
980 const struct gcov_fn_info
*gfi_ptr1
= gcov_info1
->functions
[f_ix
];
981 const struct gcov_fn_info
*gfi_ptr2
= gcov_info2
->functions
[f_ix
];
983 if (!gfi_ptr1
|| gfi_ptr1
->key
!= gcov_info1
)
985 if (!gfi_ptr2
|| gfi_ptr2
->key
!= gcov_info2
)
988 const struct gcov_ctr_info
*ci_ptr1
= gfi_ptr1
->ctrs
;
989 const struct gcov_ctr_info
*ci_ptr2
= gfi_ptr2
->ctrs
;
990 for (t_ix
= 0; t_ix
< GCOV_COUNTERS_SUMMABLE
; t_ix
++)
994 if (!gcov_info1
->merge
[t_ix
])
997 for (c_num
= 0; c_num
< ci_ptr1
->num
; c_num
++)
999 if (ci_ptr1
->values
[c_num
] | ci_ptr2
->values
[c_num
])
1001 func_val
+= calculate_2_entries (ci_ptr1
->values
[c_num
],
1002 ci_ptr2
->values
[c_num
],
1005 func_cum_1
+= ci_ptr1
->values
[c_num
] / sum_1
;
1006 func_cum_2
+= ci_ptr2
->values
[c_num
] / sum_2
;
1008 if (ci_ptr1
->values
[c_num
] / sum_1
>= overlap_hot_threshold
||
1009 ci_ptr2
->values
[c_num
] / sum_2
>= overlap_hot_threshold
)
1017 cum_1
+= func_cum_1
;
1018 cum_2
+= func_cum_2
;
1019 if (overlap_func_level
&& nonzero
&& (!overlap_hot_only
|| hot
))
1021 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1022 gfi_ptr1
->ident
, func_val
*100, func_cum_1
*100, func_cum_2
*100);
1025 *cum_1_result
= cum_1
;
1026 *cum_2_result
= cum_2
;
1030 /* Test if all counter values in this GCOV_INFO are cold.
1031 "Cold" is defined as the counter value being less than
1032 or equal to THRESHOLD. */
1035 gcov_info_count_all_cold (const struct gcov_info
*gcov_info
,
1036 gcov_type threshold
)
1040 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
1043 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
1045 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
1047 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
1048 for (t_ix
= 0; t_ix
< GCOV_COUNTERS_SUMMABLE
; t_ix
++)
1052 if (!gcov_info
->merge
[t_ix
])
1055 for (c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
1057 if (ci_ptr
->values
[c_num
] > threshold
)
1067 /* Test if all counter values in this GCOV_INFO are 0. */
1070 gcov_info_count_all_zero (const struct gcov_info
*gcov_info
)
1072 return gcov_info_count_all_cold (gcov_info
, 0);
1075 /* A pair of matched GCOV_INFO.
1076 The flag is a bitvector:
1077 b0: obj1's all counts are 0;
1078 b1: obj1's all counts are cold (but no 0);
1080 b3: no obj1 to match obj2;
1081 b4: obj2's all counts are 0;
1082 b5: obj2's all counts are cold (but no 0);
1084 b7: no obj2 to match obj1;
1087 const struct gcov_info
*obj1
;
1088 const struct gcov_info
*obj2
;
1092 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1093 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1094 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1096 /* Cumlative overlap dscore for profile1 and profile2. */
1097 static double overlap_sum_1
, overlap_sum_2
;
1099 /* sum_all for profile1 and profile2. */
1100 static gcov_type p1_sum_all
, p2_sum_all
;
1102 /* run_max for profile1 and profile2. */
1103 static gcov_type p1_run_max
, p2_run_max
;
1105 /* The number of gcda files in the profiles. */
1106 static unsigned gcda_files
[2];
1108 /* The number of unique gcda files in the profiles
1109 (not existing in the other profile). */
1110 static unsigned unique_gcda_files
[2];
1112 /* The number of gcda files that all counter values are 0. */
1113 static unsigned zero_gcda_files
[2];
1115 /* The number of gcda files that all counter values are cold (but not 0). */
1116 static unsigned cold_gcda_files
[2];
1118 /* The number of gcda files that includes hot counter values. */
1119 static unsigned hot_gcda_files
[2];
1121 /* The number of gcda files with hot count value in either profiles. */
1122 static unsigned both_hot_cnt
;
1124 /* The number of gcda files with all counts cold (but not 0) in
1126 static unsigned both_cold_cnt
;
1128 /* The number of gcda files with all counts 0 in both profiles. */
1129 static unsigned both_zero_cnt
;
1131 /* Extract the basename of the filename NAME. */
1134 extract_file_basename (const char *name
)
1138 char *path
= xstrdup (name
);
1141 sep_str
[0] = DIR_SEPARATOR
;
1143 str
= strstr(path
, sep_str
);
1145 len
= strlen(str
) + 1;
1146 path
= &path
[strlen(path
) - len
+ 2];
1147 str
= strstr(path
, sep_str
);
1153 /* Utility function to get the filename. */
1156 get_file_basename (const char *name
)
1158 if (overlap_use_fullname
)
1160 return extract_file_basename (name
);
1163 /* A utility function to set the flag for the gcda files. */
1166 set_flag (struct overlap_t
*e
)
1172 unique_gcda_files
[1]++;
1178 if (gcov_info_count_all_zero (e
->obj1
))
1180 zero_gcda_files
[0]++;
1184 if (gcov_info_count_all_cold (e
->obj1
, overlap_sum_1
1185 * overlap_hot_threshold
))
1187 cold_gcda_files
[0]++;
1192 hot_gcda_files
[0]++;
1199 unique_gcda_files
[0]++;
1205 if (gcov_info_count_all_zero (e
->obj2
))
1207 zero_gcda_files
[1]++;
1211 if (gcov_info_count_all_cold (e
->obj2
, overlap_sum_2
1212 * overlap_hot_threshold
))
1214 cold_gcda_files
[1]++;
1219 hot_gcda_files
[1]++;
1228 /* Test if INFO1 and INFO2 are from the matched source file.
1229 Return 1 if they match; return 0 otherwise. */
1232 matched_gcov_info (const struct gcov_info
*info1
, const struct gcov_info
*info2
)
1234 /* For FDO, we have to match the name. This can be expensive.
1235 Maybe we should use hash here. */
1236 if (strcmp (info1
->filename
, info2
->filename
))
1239 if (info1
->n_functions
!= info2
->n_functions
)
1241 fnotice (stderr
, "mismatched profiles in %s (%d functions"
1242 " vs %d functions)\n",
1245 info2
->n_functions
);
1251 /* Defined in libgcov-driver.c. */
1252 extern gcov_unsigned_t
compute_summary (struct gcov_info
*,
1253 struct gcov_summary
*, size_t *);
1255 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1256 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1257 match and 1.0 meaning a perfect match. */
1260 calculate_overlap (struct gcov_info
*gcov_list1
,
1261 struct gcov_info
*gcov_list2
)
1263 struct gcov_summary this_prg
;
1264 unsigned list1_cnt
= 0, list2_cnt
= 0, all_cnt
;
1267 const struct gcov_info
*gi_ptr
;
1268 struct overlap_t
*all_infos
;
1270 compute_summary (gcov_list1
, &this_prg
, &max_length
);
1271 overlap_sum_1
= (double) (this_prg
.ctrs
[0].sum_all
);
1272 p1_sum_all
= this_prg
.ctrs
[0].sum_all
;
1273 p1_run_max
= this_prg
.ctrs
[0].run_max
;
1274 compute_summary (gcov_list2
, &this_prg
, &max_length
);
1275 overlap_sum_2
= (double) (this_prg
.ctrs
[0].sum_all
);
1276 p2_sum_all
= this_prg
.ctrs
[0].sum_all
;
1277 p2_run_max
= this_prg
.ctrs
[0].run_max
;
1279 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1281 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1283 all_cnt
= list1_cnt
+ list2_cnt
;
1284 all_infos
= (struct overlap_t
*) xmalloc (sizeof (struct overlap_t
)
1286 gcc_assert (all_infos
);
1289 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1291 all_infos
[i
].obj1
= gi_ptr
;
1292 all_infos
[i
].obj2
= 0;
1295 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1297 all_infos
[i
].obj1
= 0;
1298 all_infos
[i
].obj2
= gi_ptr
;
1301 for (i
= list1_cnt
; i
< all_cnt
; i
++)
1303 if (all_infos
[i
].obj2
== 0)
1305 for (j
= 0; j
< list1_cnt
; j
++)
1307 if (all_infos
[j
].obj2
!= 0)
1309 if (matched_gcov_info (all_infos
[i
].obj2
, all_infos
[j
].obj1
))
1311 all_infos
[j
].obj2
= all_infos
[i
].obj2
;
1312 all_infos
[i
].obj2
= 0;
1318 for (i
= 0; i
< all_cnt
; i
++)
1319 if (all_infos
[i
].obj1
|| all_infos
[i
].obj2
)
1321 set_flag (all_infos
+ i
);
1322 if (FLAG_ONE_HOT (all_infos
[i
].flag
))
1324 if (FLAG_BOTH_COLD(all_infos
[i
].flag
))
1326 if (FLAG_BOTH_ZERO(all_infos
[i
].flag
))
1332 double sum_cum_1
= 0;
1333 double sum_cum_2
= 0;
1335 for (i
= 0; i
< all_cnt
; i
++)
1338 double cum_1
, cum_2
;
1339 const char *filename
;
1341 if (all_infos
[i
].obj1
== 0 && all_infos
[i
].obj2
== 0)
1343 if (FLAG_BOTH_ZERO (all_infos
[i
].flag
))
1346 if (all_infos
[i
].obj1
)
1347 filename
= get_file_basename (all_infos
[i
].obj1
->filename
);
1349 filename
= get_file_basename (all_infos
[i
].obj2
->filename
);
1351 if (overlap_func_level
)
1352 printf("\n processing %36s:\n", filename
);
1354 val
= compute_one_gcov (all_infos
[i
].obj1
, all_infos
[i
].obj2
,
1355 overlap_sum_1
, overlap_sum_2
, &cum_1
, &cum_2
);
1357 if (overlap_obj_level
&& (!overlap_hot_only
|| FLAG_ONE_HOT (all_infos
[i
].flag
)))
1359 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1360 filename
, val
*100, cum_1
*100, cum_2
*100);
1370 if (overlap_obj_level
)
1371 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1372 "", sum_val
*100, sum_cum_1
*100, sum_cum_2
*100);
1374 printf (" Statistics:\n"
1375 " profile1_# profile2_# overlap_#\n");
1376 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files
[0], gcda_files
[1],
1377 gcda_files
[0]-unique_gcda_files
[0]);
1378 printf (" unique files: %12u\t%12u\n", unique_gcda_files
[0],
1379 unique_gcda_files
[1]);
1380 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files
[0],
1381 hot_gcda_files
[1], both_hot_cnt
);
1382 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files
[0],
1383 cold_gcda_files
[1], both_cold_cnt
);
1384 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files
[0],
1385 zero_gcda_files
[1], both_zero_cnt
);
1386 printf (" sum_all: %12" PRId64
"\t%12" PRId64
"\n",
1387 p1_sum_all
, p2_sum_all
);
1388 printf (" run_max: %12" PRId64
"\t%12" PRId64
"\n",
1389 p1_run_max
, p2_run_max
);
1394 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1396 Return 0 on success: without mismatch. Reutrn 1 on error. */
1399 gcov_profile_overlap (struct gcov_info
*profile1
, struct gcov_info
*profile2
)
1403 result
= calculate_overlap (profile1
, profile2
);
1407 printf("\nProgram level overlap result is %3.2f%%\n\n", result
*100);