1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2015 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. */
57 static void tag_function (unsigned, unsigned);
58 static void tag_blocks (unsigned, unsigned);
59 static void tag_arcs (unsigned, unsigned);
60 static void tag_lines (unsigned, unsigned);
61 static void tag_counters (unsigned, unsigned);
62 static void tag_summary (unsigned, unsigned);
64 /* The gcov_info for the first module. */
65 static struct gcov_info
*curr_gcov_info
;
66 /* The gcov_info being processed. */
67 static struct gcov_info
*gcov_info_head
;
68 /* This variable contains all the functions in current module. */
69 static struct obstack fn_info
;
70 /* The function being processed. */
71 static struct gcov_fn_info
*curr_fn_info
;
72 /* The number of functions seen so far. */
73 static unsigned num_fn_info
;
74 /* This variable contains all the counters for current module. */
75 static int k_ctrs_mask
[GCOV_COUNTERS
];
76 /* The kind of counters that have been seen. */
77 static struct gcov_ctr_info k_ctrs
[GCOV_COUNTERS
];
78 /* Number of kind of counters that have been seen. */
79 static int k_ctrs_types
;
81 /* Merge functions for counters. */
82 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
83 static gcov_merge_fn ctr_merge_functions
[GCOV_COUNTERS
] = {
84 #include "gcov-counter.def"
86 #undef DEF_GCOV_COUNTER
88 /* Set the ctrs field in gcov_fn_info object FN_INFO. */
91 set_fn_ctrs (struct gcov_fn_info
*fn_info
)
95 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
97 if (k_ctrs_mask
[i
] == 0)
99 fn_info
->ctrs
[j
].num
= k_ctrs
[i
].num
;
100 fn_info
->ctrs
[j
].values
= k_ctrs
[i
].values
;
103 if (k_ctrs_types
== 0)
106 gcc_assert (j
== k_ctrs_types
);
109 /* For each tag in gcda file, we have an entry here.
110 TAG is the tag value; NAME is the tag name; and
111 PROC is the handler function. */
113 typedef struct tag_format
117 void (*proc
) (unsigned, unsigned);
120 /* Handler table for various Tags. */
122 static const tag_format_t tag_table
[] =
125 {0, "UNKNOWN", NULL
},
126 {0, "COUNTERS", tag_counters
},
127 {GCOV_TAG_FUNCTION
, "FUNCTION", tag_function
},
128 {GCOV_TAG_BLOCKS
, "BLOCKS", tag_blocks
},
129 {GCOV_TAG_ARCS
, "ARCS", tag_arcs
},
130 {GCOV_TAG_LINES
, "LINES", tag_lines
},
131 {GCOV_TAG_OBJECT_SUMMARY
, "OBJECT_SUMMARY", tag_summary
},
132 {GCOV_TAG_PROGRAM_SUMMARY
, "PROGRAM_SUMMARY", tag_summary
},
136 /* Handler for reading function tag. */
139 tag_function (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
143 /* write out previous fn_info. */
146 set_fn_ctrs (curr_fn_info
);
147 obstack_ptr_grow (&fn_info
, curr_fn_info
);
150 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
152 curr_fn_info
= (struct gcov_fn_info
*) xcalloc (sizeof (struct gcov_fn_info
)
153 + GCOV_COUNTERS
* sizeof (struct gcov_ctr_info
), 1);
155 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
159 curr_fn_info
->key
= curr_gcov_info
;
160 curr_fn_info
->ident
= gcov_read_unsigned ();
161 curr_fn_info
->lineno_checksum
= gcov_read_unsigned ();
162 curr_fn_info
->cfg_checksum
= gcov_read_unsigned ();
166 fnotice (stdout
, "tag one function id=%d\n", curr_fn_info
->ident
);
169 /* Handler for reading block tag. */
172 tag_blocks (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
174 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
178 /* Handler for reading flow arc tag. */
181 tag_arcs (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
183 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
187 /* Handler for reading line tag. */
190 tag_lines (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
192 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
196 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
199 tag_counters (unsigned tag
, unsigned length
)
201 unsigned n_counts
= GCOV_TAG_COUNTER_NUM (length
);
206 tag_ix
= GCOV_COUNTER_FOR_TAG (tag
);
207 gcc_assert (tag_ix
< GCOV_COUNTERS
);
208 k_ctrs_mask
[tag_ix
] = 1;
209 gcc_assert (k_ctrs
[tag_ix
].num
== 0);
210 k_ctrs
[tag_ix
].num
= n_counts
;
212 k_ctrs
[tag_ix
].values
= values
= (gcov_type
*) xmalloc (n_counts
* sizeof (gcov_type
));
215 for (ix
= 0; ix
!= n_counts
; ix
++)
216 values
[ix
] = gcov_read_counter ();
219 /* Handler for reading summary tag. */
222 tag_summary (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
224 struct gcov_summary summary
;
226 gcov_read_summary (&summary
);
229 /* This function is called at the end of reading a gcda file.
230 It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO. */
233 read_gcda_finalize (struct gcov_info
*obj_info
)
237 set_fn_ctrs (curr_fn_info
);
238 obstack_ptr_grow (&fn_info
, curr_fn_info
);
240 /* We set the following fields: merge, n_functions, and functions. */
241 obj_info
->n_functions
= num_fn_info
;
242 obj_info
->functions
= (const struct gcov_fn_info
**) obstack_finish (&fn_info
);
244 /* wrap all the counter array. */
245 for (i
=0; i
< GCOV_COUNTERS
; i
++)
248 obj_info
->merge
[i
] = ctr_merge_functions
[i
];
252 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
253 Program level summary CURRENT_SUMMARY will also be updated. */
255 static struct gcov_info
*
256 read_gcda_file (const char *filename
)
260 unsigned magic
, version
;
261 struct gcov_info
*obj_info
;
264 for (i
=0; i
< GCOV_COUNTERS
; i
++)
268 if (!gcov_open (filename
))
270 fnotice (stderr
, "%s:cannot open\n", filename
);
275 magic
= gcov_read_unsigned ();
276 if (magic
!= GCOV_DATA_MAGIC
)
278 fnotice (stderr
, "%s:not a gcov data file\n", filename
);
284 version
= gcov_read_unsigned ();
285 if (version
!= GCOV_VERSION
)
287 fnotice (stderr
, "%s:incorrect gcov version %d vs %d \n", filename
, version
, GCOV_VERSION
);
292 /* Instantiate a gcov_info object. */
293 curr_gcov_info
= obj_info
= (struct gcov_info
*) xcalloc (sizeof (struct gcov_info
) +
294 sizeof (struct gcov_ctr_info
) * GCOV_COUNTERS
, 1);
296 obj_info
->version
= version
;
297 obstack_init (&fn_info
);
301 size_t len
= strlen (filename
) + 1;
302 char *str_dup
= (char*) xmalloc (len
);
304 memcpy (str_dup
, filename
, len
);
305 obj_info
->filename
= str_dup
;
309 obj_info
->stamp
= gcov_read_unsigned ();
313 gcov_position_t base
;
314 unsigned tag
, length
;
315 tag_format_t
const *format
;
320 tag
= gcov_read_unsigned ();
323 length
= gcov_read_unsigned ();
324 base
= gcov_position ();
325 mask
= GCOV_TAG_MASK (tag
) >> 1;
326 for (tag_depth
= 4; mask
; mask
>>= 8)
328 if (((mask
& 0xff) != 0xff))
330 warning (0, "%s:tag `%x' is invalid\n", filename
, tag
);
335 for (format
= tag_table
; format
->name
; format
++)
336 if (format
->tag
== tag
)
338 format
= &tag_table
[GCOV_TAG_IS_COUNTER (tag
) ? 2 : 1];
342 if (depth
&& depth
< tag_depth
)
344 if (!GCOV_TAG_IS_SUBTAG (tags
[depth
- 1], tag
))
345 warning (0, "%s:tag `%x' is incorrectly nested\n",
349 tags
[depth
- 1] = tag
;
354 unsigned long actual_length
;
356 (*format
->proc
) (tag
, length
);
358 actual_length
= gcov_position () - base
;
359 if (actual_length
> length
)
360 warning (0, "%s:record size mismatch %lu bytes overread\n",
361 filename
, actual_length
- length
);
362 else if (length
> actual_length
)
363 warning (0, "%s:record size mismatch %lu bytes unread\n",
364 filename
, length
- actual_length
);
367 gcov_sync (base
, length
);
368 if ((error
= gcov_is_error ()))
370 warning (0, error
< 0 ? "%s:counter overflow at %lu\n" :
371 "%s:read error at %lu\n", filename
,
372 (long unsigned) gcov_position ());
377 read_gcda_finalize (obj_info
);
383 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
384 Return a non-zero value to stop the tree walk. */
387 ftw_read_file (const char *filename
,
388 const struct stat
*status ATTRIBUTE_UNUSED
,
393 struct gcov_info
*obj_info
;
395 /* Only read regular files. */
399 filename_len
= strlen (filename
);
400 suffix_len
= strlen (GCOV_DATA_SUFFIX
);
402 if (filename_len
<= suffix_len
)
405 if (strcmp(filename
+ filename_len
- suffix_len
, GCOV_DATA_SUFFIX
))
409 fnotice (stderr
, "reading file: %s\n", filename
);
411 obj_info
= read_gcda_file (filename
);
415 obj_info
->next
= gcov_info_head
;
416 gcov_info_head
= obj_info
;
421 /* Initializer for reading a profile dir. */
424 read_profile_dir_init (void)
429 /* Driver for read a profile directory and convert into gcov_info list in memory.
430 Return NULL on error,
431 Return the head of gcov_info list on success. */
434 gcov_read_profile_dir (const char* dir_name
, int recompute_summary ATTRIBUTE_UNUSED
)
439 read_profile_dir_init ();
441 if (access (dir_name
, R_OK
) != 0)
443 fnotice (stderr
, "cannot access directory %s\n", dir_name
);
446 pwd
= getcwd (NULL
, 0);
448 ret
= chdir (dir_name
);
451 fnotice (stderr
, "%s is not a directory\n", dir_name
);
454 ftw (".", ftw_read_file
, 50);
459 return gcov_info_head
;;
462 /* This part of the code is to merge profile counters. These
463 variables are set in merge_wrapper and to be used by
464 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
466 /* We save the counter value address to this variable. */
467 static gcov_type
*gcov_value_buf
;
469 /* The number of counter values to be read by current merging. */
470 static gcov_unsigned_t gcov_value_buf_size
;
472 /* The index of counter values being read. */
473 static gcov_unsigned_t gcov_value_buf_pos
;
475 /* The weight of current merging. */
476 static unsigned gcov_merge_weight
;
478 /* Read a counter value from gcov_value_buf array. */
481 gcov_read_counter_mem (void)
484 gcc_assert (gcov_value_buf_pos
< gcov_value_buf_size
);
485 ret
= *(gcov_value_buf
+ gcov_value_buf_pos
);
486 ++gcov_value_buf_pos
;
490 /* Return the recorded merge weight. */
493 gcov_get_merge_weight (void)
495 return gcov_merge_weight
;
498 /* A wrapper function for merge functions. It sets up the
499 value buffer and weights and then calls the merge function. */
502 merge_wrapper (gcov_merge_fn f
, gcov_type
*v1
, gcov_unsigned_t n
,
503 gcov_type
*v2
, unsigned w
)
506 gcov_value_buf_pos
= 0;
507 gcov_value_buf_size
= n
;
508 gcov_merge_weight
= w
;
512 /* Offline tool to manipulate profile data.
513 This tool targets on matched profiles. But it has some tolerance on
515 When merging p1 to p2 (p2 is the dst),
516 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
518 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
519 specified weight; emit warning.
520 * m.gcda in both p1 and p2:
521 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
522 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
524 drop p1->m.gcda->f. A warning is emitted. */
526 /* Add INFO2's counter to INFO1, multiplying by weight W. */
529 gcov_merge (struct gcov_info
*info1
, struct gcov_info
*info2
, int w
)
532 unsigned n_functions
= info1
->n_functions
;
533 int has_mismatch
= 0;
535 gcc_assert (info2
->n_functions
== n_functions
);
536 for (f_ix
= 0; f_ix
< n_functions
; f_ix
++)
539 const struct gcov_fn_info
*gfi_ptr1
= info1
->functions
[f_ix
];
540 const struct gcov_fn_info
*gfi_ptr2
= info2
->functions
[f_ix
];
541 const struct gcov_ctr_info
*ci_ptr1
, *ci_ptr2
;
543 if (!gfi_ptr1
|| gfi_ptr1
->key
!= info1
)
545 if (!gfi_ptr2
|| gfi_ptr2
->key
!= info2
)
548 if (gfi_ptr1
->cfg_checksum
!= gfi_ptr2
->cfg_checksum
)
550 fnotice (stderr
, "in %s, cfg_checksum mismatch, skipping\n",
555 ci_ptr1
= gfi_ptr1
->ctrs
;
556 ci_ptr2
= gfi_ptr2
->ctrs
;
557 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
559 gcov_merge_fn merge1
= info1
->merge
[t_ix
];
560 gcov_merge_fn merge2
= info2
->merge
[t_ix
];
562 gcc_assert (merge1
== merge2
);
565 gcc_assert (ci_ptr1
->num
== ci_ptr2
->num
);
566 merge_wrapper (merge1
, ci_ptr1
->values
, ci_ptr1
->num
, ci_ptr2
->values
, w
);
575 /* Find and return the match gcov_info object for INFO from ARRAY.
576 SIZE is the length of ARRAY.
577 Return NULL if there is no match. */
579 static struct gcov_info
*
580 find_match_gcov_info (struct gcov_info
**array
, int size
,
581 struct gcov_info
*info
)
583 struct gcov_info
*gi_ptr
;
584 struct gcov_info
*ret
= NULL
;
587 for (i
= 0; i
< size
; i
++)
592 if (!strcmp (gi_ptr
->filename
, info
->filename
))
600 if (ret
&& ret
->n_functions
!= info
->n_functions
)
602 fnotice (stderr
, "mismatched profiles in %s (%d functions"
603 " vs %d functions)\n",
612 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
613 Return 0 on success: without mismatch.
614 Reutrn 1 on error. */
617 gcov_profile_merge (struct gcov_info
*tgt_profile
, struct gcov_info
*src_profile
,
620 struct gcov_info
*gi_ptr
;
621 struct gcov_info
**tgt_infos
;
622 struct gcov_info
*tgt_tail
;
623 struct gcov_info
**in_src_not_tgt
;
624 unsigned tgt_cnt
= 0, src_cnt
= 0;
625 unsigned unmatch_info_cnt
= 0;
628 for (gi_ptr
= tgt_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
630 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
632 tgt_infos
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
634 gcc_assert (tgt_infos
);
635 in_src_not_tgt
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
637 gcc_assert (in_src_not_tgt
);
639 for (gi_ptr
= tgt_profile
, i
= 0; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
640 tgt_infos
[i
] = gi_ptr
;
642 tgt_tail
= tgt_infos
[tgt_cnt
- 1];
644 /* First pass on tgt_profile, we multiply w1 to all counters. */
647 for (i
= 0; i
< tgt_cnt
; i
++)
648 gcov_merge (tgt_infos
[i
], tgt_infos
[i
], w1
-1);
651 /* Second pass, add src_profile to the tgt_profile. */
652 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
654 struct gcov_info
*gi_ptr1
;
656 gi_ptr1
= find_match_gcov_info (tgt_infos
, tgt_cnt
, gi_ptr
);
659 in_src_not_tgt
[unmatch_info_cnt
++] = gi_ptr
;
662 gcov_merge (gi_ptr1
, gi_ptr
, w2
);
665 /* For modules in src but not in tgt. We adjust the counter and append. */
666 for (i
= 0; i
< unmatch_info_cnt
; i
++)
668 gi_ptr
= in_src_not_tgt
[i
];
669 gcov_merge (gi_ptr
, gi_ptr
, w2
- 1);
670 tgt_tail
->next
= gi_ptr
;
677 typedef gcov_type (*counter_op_fn
) (gcov_type
, void*, void*);
679 /* Performing FN upon arc counters. */
682 __gcov_add_counter_op (gcov_type
*counters
, unsigned n_counters
,
683 counter_op_fn fn
, void *data1
, void *data2
)
685 for (; n_counters
; counters
++, n_counters
--)
687 gcov_type val
= *counters
;
688 *counters
= fn(val
, data1
, data2
);
692 /* Performing FN upon ior counters. */
695 __gcov_ior_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
696 unsigned n_counters ATTRIBUTE_UNUSED
,
697 counter_op_fn fn ATTRIBUTE_UNUSED
,
698 void *data1 ATTRIBUTE_UNUSED
,
699 void *data2 ATTRIBUTE_UNUSED
)
704 /* Performing FN upon time-profile counters. */
707 __gcov_time_profile_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
708 unsigned n_counters ATTRIBUTE_UNUSED
,
709 counter_op_fn fn ATTRIBUTE_UNUSED
,
710 void *data1 ATTRIBUTE_UNUSED
,
711 void *data2 ATTRIBUTE_UNUSED
)
716 /* Performaing FN upon delta counters. */
719 __gcov_delta_counter_op (gcov_type
*counters
, unsigned n_counters
,
720 counter_op_fn fn
, void *data1
, void *data2
)
722 unsigned i
, n_measures
;
724 gcc_assert (!(n_counters
% 4));
725 n_measures
= n_counters
/ 4;
726 for (i
= 0; i
< n_measures
; i
++, counters
+= 4)
728 counters
[2] = fn (counters
[2], data1
, data2
);
729 counters
[3] = fn (counters
[3], data1
, data2
);
733 /* Performing FN upon single counters. */
736 __gcov_single_counter_op (gcov_type
*counters
, unsigned n_counters
,
737 counter_op_fn fn
, void *data1
, void *data2
)
739 unsigned i
, n_measures
;
741 gcc_assert (!(n_counters
% 3));
742 n_measures
= n_counters
/ 3;
743 for (i
= 0; i
< n_measures
; i
++, counters
+= 3)
745 counters
[1] = fn (counters
[1], data1
, data2
);
746 counters
[2] = fn (counters
[2], data1
, data2
);
750 /* Performing FN upon indirect-call profile counters. */
753 __gcov_icall_topn_counter_op (gcov_type
*counters
, unsigned n_counters
,
754 counter_op_fn fn
, void *data1
, void *data2
)
758 gcc_assert (!(n_counters
% GCOV_ICALL_TOPN_NCOUNTS
));
759 for (i
= 0; i
< n_counters
; i
+= GCOV_ICALL_TOPN_NCOUNTS
)
762 gcov_type
*value_array
= &counters
[i
+ 1];
764 for (j
= 0; j
< GCOV_ICALL_TOPN_NCOUNTS
- 1; j
+= 2)
765 value_array
[j
+ 1] = fn (value_array
[j
+ 1], data1
, data2
);
769 /* Scaling the counter value V by multiplying *(float*) DATA1. */
772 fp_scale (gcov_type v
, void *data1
, void *data2 ATTRIBUTE_UNUSED
)
774 float f
= *(float *) data1
;
775 return (gcov_type
) (v
* f
);
778 /* Scaling the counter value V by multiplying DATA2/DATA1. */
781 int_scale (gcov_type v
, void *data1
, void *data2
)
783 int n
= *(int *) data1
;
784 int d
= *(int *) data2
;
785 return (gcov_type
) ( RDIV (v
,d
) * n
);
788 /* Type of function used to process counters. */
789 typedef void (*gcov_counter_fn
) (gcov_type
*, gcov_unsigned_t
,
790 counter_op_fn
, void *, void *);
792 /* Function array to process profile counters. */
793 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
794 __gcov ## FN_TYPE ## _counter_op,
795 static gcov_counter_fn ctr_functions
[GCOV_COUNTERS
] = {
796 #include "gcov-counter.def"
798 #undef DEF_GCOV_COUNTER
800 /* Driver for scaling profile counters. */
803 gcov_profile_scale (struct gcov_info
*profile
, float scale_factor
, int n
, int d
)
805 struct gcov_info
*gi_ptr
;
809 fnotice (stdout
, "scale_factor is %f or %d/%d\n", scale_factor
, n
, d
);
811 /* Scaling the counters. */
812 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
813 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
816 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
817 const struct gcov_ctr_info
*ci_ptr
;
819 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
822 ci_ptr
= gfi_ptr
->ctrs
;
823 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
825 gcov_merge_fn merge
= gi_ptr
->merge
[t_ix
];
830 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
831 fp_scale
, &scale_factor
, NULL
);
833 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
842 /* Driver to normalize profile counters. */
845 gcov_profile_normalize (struct gcov_info
*profile
, gcov_type max_val
)
847 struct gcov_info
*gi_ptr
;
848 gcov_type curr_max_val
= 0;
853 /* Find the largest count value. */
854 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
855 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
858 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
859 const struct gcov_ctr_info
*ci_ptr
;
861 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
864 ci_ptr
= gfi_ptr
->ctrs
;
865 for (t_ix
= 0; t_ix
< 1; t_ix
++)
867 for (i
= 0; i
< ci_ptr
->num
; i
++)
868 if (ci_ptr
->values
[i
] > curr_max_val
)
869 curr_max_val
= ci_ptr
->values
[i
];
874 scale_factor
= (float)max_val
/ curr_max_val
;
876 fnotice (stdout
, "max_val is %"PRId64
"\n", curr_max_val
);
878 return gcov_profile_scale (profile
, scale_factor
, 0, 0);
881 /* The following variables are defined in gcc/gcov-tool.c. */
882 extern int overlap_func_level
;
883 extern int overlap_obj_level
;
884 extern int overlap_hot_only
;
885 extern int overlap_use_fullname
;
886 extern double overlap_hot_threshold
;
888 /* Compute the overlap score of two values. The score is defined as:
889 min (V1/SUM_1, V2/SUM_2) */
892 calculate_2_entries (const unsigned long v1
, const unsigned long v2
,
893 const double sum_1
, const double sum_2
)
895 double val1
= (sum_1
== 0.0 ? 0.0 : v1
/sum_1
);
896 double val2
= (sum_2
== 0.0 ? 0.0 : v2
/sum_2
);
904 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
905 SUM_1 is the sum_all for profile1 where GCOV_INFO1 belongs.
906 SUM_2 is the sum_all for profile2 where GCOV_INFO2 belongs.
907 This function also updates cumulative score CUM_1_RESULT and
911 compute_one_gcov (const struct gcov_info
*gcov_info1
,
912 const struct gcov_info
*gcov_info2
,
913 const double sum_1
, const double sum_2
,
914 double *cum_1_result
, double *cum_2_result
)
918 double cum_1
= 0, cum_2
= 0;
919 const struct gcov_info
*gcov_info
= 0;
923 gcc_assert (gcov_info1
|| gcov_info2
);
926 gcov_info
= gcov_info2
;
927 cum_p
= cum_2_result
;
933 gcov_info
= gcov_info1
;
934 cum_p
= cum_1_result
;
941 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
944 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
945 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
947 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
948 for (t_ix
= 0; t_ix
< GCOV_COUNTERS_SUMMABLE
; t_ix
++)
952 if (!gcov_info
->merge
[t_ix
])
955 for (c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
957 cum_1
+= ci_ptr
->values
[c_num
] / sum
;
966 for (f_ix
= 0; f_ix
< gcov_info1
->n_functions
; f_ix
++)
969 double func_cum_1
= 0.0;
970 double func_cum_2
= 0.0;
971 double func_val
= 0.0;
974 const struct gcov_fn_info
*gfi_ptr1
= gcov_info1
->functions
[f_ix
];
975 const struct gcov_fn_info
*gfi_ptr2
= gcov_info2
->functions
[f_ix
];
977 if (!gfi_ptr1
|| gfi_ptr1
->key
!= gcov_info1
)
979 if (!gfi_ptr2
|| gfi_ptr2
->key
!= gcov_info2
)
982 const struct gcov_ctr_info
*ci_ptr1
= gfi_ptr1
->ctrs
;
983 const struct gcov_ctr_info
*ci_ptr2
= gfi_ptr2
->ctrs
;
984 for (t_ix
= 0; t_ix
< GCOV_COUNTERS_SUMMABLE
; t_ix
++)
988 if (!gcov_info1
->merge
[t_ix
])
991 for (c_num
= 0; c_num
< ci_ptr1
->num
; c_num
++)
993 if (ci_ptr1
->values
[c_num
] | ci_ptr2
->values
[c_num
])
995 func_val
+= calculate_2_entries (ci_ptr1
->values
[c_num
],
996 ci_ptr2
->values
[c_num
],
999 func_cum_1
+= ci_ptr1
->values
[c_num
] / sum_1
;
1000 func_cum_2
+= ci_ptr2
->values
[c_num
] / sum_2
;
1002 if (ci_ptr1
->values
[c_num
] / sum_1
>= overlap_hot_threshold
||
1003 ci_ptr2
->values
[c_num
] / sum_2
>= overlap_hot_threshold
)
1011 cum_1
+= func_cum_1
;
1012 cum_2
+= func_cum_2
;
1013 if (overlap_func_level
&& nonzero
&& (!overlap_hot_only
|| hot
))
1015 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1016 gfi_ptr1
->ident
, func_val
*100, func_cum_1
*100, func_cum_2
*100);
1019 *cum_1_result
= cum_1
;
1020 *cum_2_result
= cum_2
;
1024 /* Test if all counter values in this GCOV_INFO are cold.
1025 "Cold" is defined as the counter value being less than
1026 or equal to THRESHOLD. */
1029 gcov_info_count_all_cold (const struct gcov_info
*gcov_info
,
1030 gcov_type threshold
)
1034 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
1037 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
1039 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
1041 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
1042 for (t_ix
= 0; t_ix
< GCOV_COUNTERS_SUMMABLE
; t_ix
++)
1046 if (!gcov_info
->merge
[t_ix
])
1049 for (c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
1051 if (ci_ptr
->values
[c_num
] > threshold
)
1061 /* Test if all counter values in this GCOV_INFO are 0. */
1064 gcov_info_count_all_zero (const struct gcov_info
*gcov_info
)
1066 return gcov_info_count_all_cold (gcov_info
, 0);
1069 /* A pair of matched GCOV_INFO.
1070 The flag is a bitvector:
1071 b0: obj1's all counts are 0;
1072 b1: obj1's all counts are cold (but no 0);
1074 b3: no obj1 to match obj2;
1075 b4: obj2's all counts are 0;
1076 b5: obj2's all counts are cold (but no 0);
1078 b7: no obj2 to match obj1;
1081 const struct gcov_info
*obj1
;
1082 const struct gcov_info
*obj2
;
1086 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1087 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1088 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1090 /* Cumlative overlap dscore for profile1 and profile2. */
1091 static double overlap_sum_1
, overlap_sum_2
;
1093 /* sum_all for profile1 and profile2. */
1094 static gcov_type p1_sum_all
, p2_sum_all
;
1096 /* run_max for profile1 and profile2. */
1097 static gcov_type p1_run_max
, p2_run_max
;
1099 /* The number of gcda files in the profiles. */
1100 static unsigned gcda_files
[2];
1102 /* The number of unique gcda files in the profiles
1103 (not existing in the other profile). */
1104 static unsigned unique_gcda_files
[2];
1106 /* The number of gcda files that all counter values are 0. */
1107 static unsigned zero_gcda_files
[2];
1109 /* The number of gcda files that all counter values are cold (but not 0). */
1110 static unsigned cold_gcda_files
[2];
1112 /* The number of gcda files that includes hot counter values. */
1113 static unsigned hot_gcda_files
[2];
1115 /* The number of gcda files with hot count value in either profiles. */
1116 static unsigned both_hot_cnt
;
1118 /* The number of gcda files with all counts cold (but not 0) in
1120 static unsigned both_cold_cnt
;
1122 /* The number of gcda files with all counts 0 in both profiles. */
1123 static unsigned both_zero_cnt
;
1125 /* Extract the basename of the filename NAME. */
1128 extract_file_basename (const char *name
)
1132 char *path
= xstrdup (name
);
1135 sep_str
[0] = DIR_SEPARATOR
;
1137 str
= strstr(path
, sep_str
);
1139 len
= strlen(str
) + 1;
1140 path
= &path
[strlen(path
) - len
+ 2];
1141 str
= strstr(path
, sep_str
);
1147 /* Utility function to get the filename. */
1150 get_file_basename (const char *name
)
1152 if (overlap_use_fullname
)
1154 return extract_file_basename (name
);
1157 /* A utility function to set the flag for the gcda files. */
1160 set_flag (struct overlap_t
*e
)
1166 unique_gcda_files
[1]++;
1172 if (gcov_info_count_all_zero (e
->obj1
))
1174 zero_gcda_files
[0]++;
1178 if (gcov_info_count_all_cold (e
->obj1
, overlap_sum_1
1179 * overlap_hot_threshold
))
1181 cold_gcda_files
[0]++;
1186 hot_gcda_files
[0]++;
1193 unique_gcda_files
[0]++;
1199 if (gcov_info_count_all_zero (e
->obj2
))
1201 zero_gcda_files
[1]++;
1205 if (gcov_info_count_all_cold (e
->obj2
, overlap_sum_2
1206 * overlap_hot_threshold
))
1208 cold_gcda_files
[1]++;
1213 hot_gcda_files
[1]++;
1222 /* Test if INFO1 and INFO2 are from the matched source file.
1223 Return 1 if they match; return 0 otherwise. */
1226 matched_gcov_info (const struct gcov_info
*info1
, const struct gcov_info
*info2
)
1228 /* For FDO, we have to match the name. This can be expensive.
1229 Maybe we should use hash here. */
1230 if (strcmp (info1
->filename
, info2
->filename
))
1233 if (info1
->n_functions
!= info2
->n_functions
)
1235 fnotice (stderr
, "mismatched profiles in %s (%d functions"
1236 " vs %d functions)\n",
1239 info2
->n_functions
);
1245 /* Defined in libgcov-driver.c. */
1246 extern gcov_unsigned_t
compute_summary (struct gcov_info
*,
1247 struct gcov_summary
*, size_t *);
1249 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1250 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1251 match and 1.0 meaning a perfect match. */
1254 calculate_overlap (struct gcov_info
*gcov_list1
,
1255 struct gcov_info
*gcov_list2
)
1257 struct gcov_summary this_prg
;
1258 unsigned list1_cnt
= 0, list2_cnt
= 0, all_cnt
;
1261 const struct gcov_info
*gi_ptr
;
1262 struct overlap_t
*all_infos
;
1264 compute_summary (gcov_list1
, &this_prg
, &max_length
);
1265 overlap_sum_1
= (double) (this_prg
.ctrs
[0].sum_all
);
1266 p1_sum_all
= this_prg
.ctrs
[0].sum_all
;
1267 p1_run_max
= this_prg
.ctrs
[0].run_max
;
1268 compute_summary (gcov_list2
, &this_prg
, &max_length
);
1269 overlap_sum_2
= (double) (this_prg
.ctrs
[0].sum_all
);
1270 p2_sum_all
= this_prg
.ctrs
[0].sum_all
;
1271 p2_run_max
= this_prg
.ctrs
[0].run_max
;
1273 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1275 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1277 all_cnt
= list1_cnt
+ list2_cnt
;
1278 all_infos
= (struct overlap_t
*) xmalloc (sizeof (struct overlap_t
)
1280 gcc_assert (all_infos
);
1283 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1285 all_infos
[i
].obj1
= gi_ptr
;
1286 all_infos
[i
].obj2
= 0;
1289 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1291 all_infos
[i
].obj1
= 0;
1292 all_infos
[i
].obj2
= gi_ptr
;
1295 for (i
= list1_cnt
; i
< all_cnt
; i
++)
1297 if (all_infos
[i
].obj2
== 0)
1299 for (j
= 0; j
< list1_cnt
; j
++)
1301 if (all_infos
[j
].obj2
!= 0)
1303 if (matched_gcov_info (all_infos
[i
].obj2
, all_infos
[j
].obj1
))
1305 all_infos
[j
].obj2
= all_infos
[i
].obj2
;
1306 all_infos
[i
].obj2
= 0;
1312 for (i
= 0; i
< all_cnt
; i
++)
1313 if (all_infos
[i
].obj1
|| all_infos
[i
].obj2
)
1315 set_flag (all_infos
+ i
);
1316 if (FLAG_ONE_HOT (all_infos
[i
].flag
))
1318 if (FLAG_BOTH_COLD(all_infos
[i
].flag
))
1320 if (FLAG_BOTH_ZERO(all_infos
[i
].flag
))
1326 double sum_cum_1
= 0;
1327 double sum_cum_2
= 0;
1329 for (i
= 0; i
< all_cnt
; i
++)
1332 double cum_1
, cum_2
;
1333 const char *filename
;
1335 if (all_infos
[i
].obj1
== 0 && all_infos
[i
].obj2
== 0)
1337 if (FLAG_BOTH_ZERO (all_infos
[i
].flag
))
1340 if (all_infos
[i
].obj1
)
1341 filename
= get_file_basename (all_infos
[i
].obj1
->filename
);
1343 filename
= get_file_basename (all_infos
[i
].obj2
->filename
);
1345 if (overlap_func_level
)
1346 printf("\n processing %36s:\n", filename
);
1348 val
= compute_one_gcov (all_infos
[i
].obj1
, all_infos
[i
].obj2
,
1349 overlap_sum_1
, overlap_sum_2
, &cum_1
, &cum_2
);
1351 if (overlap_obj_level
&& (!overlap_hot_only
|| FLAG_ONE_HOT (all_infos
[i
].flag
)))
1353 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1354 filename
, val
*100, cum_1
*100, cum_2
*100);
1364 if (overlap_obj_level
)
1365 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1366 "", sum_val
*100, sum_cum_1
*100, sum_cum_2
*100);
1368 printf (" Statistics:\n"
1369 " profile1_# profile2_# overlap_#\n");
1370 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files
[0], gcda_files
[1],
1371 gcda_files
[0]-unique_gcda_files
[0]);
1372 printf (" unique files: %12u\t%12u\n", unique_gcda_files
[0],
1373 unique_gcda_files
[1]);
1374 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files
[0],
1375 hot_gcda_files
[1], both_hot_cnt
);
1376 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files
[0],
1377 cold_gcda_files
[1], both_cold_cnt
);
1378 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files
[0],
1379 zero_gcda_files
[1], both_zero_cnt
);
1380 printf (" sum_all: %12"PRId64
"\t%12"PRId64
"\n", p1_sum_all
, p2_sum_all
);
1381 printf (" run_max: %12"PRId64
"\t%12"PRId64
"\n", p1_run_max
, p2_run_max
);
1386 /* Computer the overlap score of two lists of gcov_info objects PROFILE1 and PROFILE2.
1387 Return 0 on success: without mismatch. Reutrn 1 on error. */
1390 gcov_profile_overlap (struct gcov_info
*profile1
, struct gcov_info
*profile2
)
1394 result
= calculate_overlap (profile1
, profile2
);
1398 printf("\nProgram level overlap result is %3.2f%%\n\n", result
*100);