1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2025 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
30 #define INCLUDE_MEMORY
33 #include "diagnostic.h"
38 /* Borrowed from basic-block.h. */
39 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
41 extern gcov_position_t
gcov_position();
42 extern int gcov_is_error();
44 /* Verbose mode for debug. */
47 /* Set verbose flag. */
48 void gcov_set_verbose (void)
53 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
61 static void tag_function (unsigned, int);
62 static void tag_blocks (unsigned, int);
63 static void tag_arcs (unsigned, int);
64 static void tag_lines (unsigned, int);
65 static void tag_counters (unsigned, int);
66 static void tag_summary (unsigned, int);
68 /* The gcov_info for the first module. */
69 static struct gcov_info
*curr_gcov_info
;
70 /* The gcov_info being processed. */
71 static struct gcov_info
*gcov_info_head
;
72 /* This variable contains all the functions in current module. */
73 static struct obstack fn_info
;
74 /* The function being processed. */
75 static struct gcov_fn_info
*curr_fn_info
;
76 /* The number of functions seen so far. */
77 static unsigned num_fn_info
;
78 /* This variable contains all the counters for current module. */
79 static int k_ctrs_mask
[GCOV_COUNTERS
];
80 /* The kind of counters that have been seen. */
81 static struct gcov_ctr_info k_ctrs
[GCOV_COUNTERS
];
82 /* Number of kind of counters that have been seen. */
83 static int k_ctrs_types
;
85 /* Merge functions for counters. */
86 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
87 static gcov_merge_fn ctr_merge_functions
[GCOV_COUNTERS
] = {
88 #include "gcov-counter.def"
90 #undef DEF_GCOV_COUNTER
92 /* Set the ctrs field in gcov_fn_info object FN_INFO. */
95 set_fn_ctrs (struct gcov_fn_info
*fn_info
)
99 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
101 if (k_ctrs_mask
[i
] == 0)
103 fn_info
->ctrs
[j
].num
= k_ctrs
[i
].num
;
104 fn_info
->ctrs
[j
].values
= k_ctrs
[i
].values
;
107 if (k_ctrs_types
== 0)
110 gcc_assert (j
== k_ctrs_types
);
113 /* For each tag in gcda file, we have an entry here.
114 TAG is the tag value; NAME is the tag name; and
115 PROC is the handler function. */
117 typedef struct tag_format
121 void (*proc
) (unsigned, int);
124 /* Handler table for various Tags. */
126 static const tag_format_t tag_table
[] =
129 {0, "UNKNOWN", NULL
},
130 {0, "COUNTERS", tag_counters
},
131 {GCOV_TAG_FUNCTION
, "FUNCTION", tag_function
},
132 {GCOV_TAG_BLOCKS
, "BLOCKS", tag_blocks
},
133 {GCOV_TAG_ARCS
, "ARCS", tag_arcs
},
134 {GCOV_TAG_LINES
, "LINES", tag_lines
},
135 {GCOV_TAG_OBJECT_SUMMARY
, "OBJECT_SUMMARY", tag_summary
},
139 /* Handler for reading function tag. */
142 tag_function (unsigned tag ATTRIBUTE_UNUSED
, int length ATTRIBUTE_UNUSED
)
146 /* write out previous fn_info. */
149 set_fn_ctrs (curr_fn_info
);
150 obstack_ptr_grow (&fn_info
, curr_fn_info
);
153 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
155 curr_fn_info
= (struct gcov_fn_info
*) xcalloc (sizeof (struct gcov_fn_info
)
156 + GCOV_COUNTERS
* sizeof (struct gcov_ctr_info
), 1);
158 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
162 curr_fn_info
->key
= curr_gcov_info
;
163 curr_fn_info
->ident
= gcov_read_unsigned ();
164 curr_fn_info
->lineno_checksum
= gcov_read_unsigned ();
165 curr_fn_info
->cfg_checksum
= gcov_read_unsigned ();
169 fnotice (stdout
, "tag one function id=%d\n", curr_fn_info
->ident
);
172 /* Handler for reading block tag. */
175 tag_blocks (unsigned tag ATTRIBUTE_UNUSED
, int length ATTRIBUTE_UNUSED
)
177 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
181 /* Handler for reading flow arc tag. */
184 tag_arcs (unsigned tag ATTRIBUTE_UNUSED
, int length ATTRIBUTE_UNUSED
)
186 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
190 /* Handler for reading line tag. */
193 tag_lines (unsigned tag ATTRIBUTE_UNUSED
, int length ATTRIBUTE_UNUSED
)
195 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
199 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
202 tag_counters (unsigned tag
, int length
)
204 unsigned n_counts
= GCOV_TAG_COUNTER_NUM (abs (length
));
209 tag_ix
= GCOV_COUNTER_FOR_TAG (tag
);
210 gcc_assert (tag_ix
< GCOV_COUNTERS
);
211 k_ctrs_mask
[tag_ix
] = 1;
212 gcc_assert (k_ctrs
[tag_ix
].num
== 0);
213 k_ctrs
[tag_ix
].num
= n_counts
;
215 k_ctrs
[tag_ix
].values
= values
= (gcov_type
*) xcalloc (n_counts
,
220 for (ix
= 0; ix
!= n_counts
; ix
++)
221 values
[ix
] = gcov_read_counter ();
224 /* Handler for reading summary tag. */
227 tag_summary (unsigned tag ATTRIBUTE_UNUSED
, int ATTRIBUTE_UNUSED
)
229 gcov_read_summary (&curr_gcov_info
->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
= (struct gcov_fn_info
**) obstack_finish (&fn_info
);
248 /* wrap all the counter array. */
249 for (i
=0; i
< GCOV_COUNTERS
; i
++)
252 obj_info
->merge
[i
] = ctr_merge_functions
[i
];
256 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
257 Program level summary CURRENT_SUMMARY will also be updated. */
259 static struct gcov_info
*
260 read_gcda_file (const char *filename
)
265 struct gcov_info
*obj_info
;
268 for (i
=0; i
< GCOV_COUNTERS
; i
++)
273 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
275 fnotice (stderr
, "%s:not a gcov data file\n", filename
);
280 version
= gcov_read_unsigned ();
281 if (version
!= GCOV_VERSION
)
283 fnotice (stderr
, "%s:incorrect gcov version %d vs %d \n", filename
, version
, GCOV_VERSION
);
287 /* Instantiate a gcov_info object. */
288 curr_gcov_info
= obj_info
= (struct gcov_info
*) xcalloc (sizeof (struct gcov_info
) +
289 sizeof (struct gcov_ctr_info
) * GCOV_COUNTERS
, 1);
291 obj_info
->version
= version
;
292 obj_info
->filename
= filename
;
293 obstack_init (&fn_info
);
297 /* Prepend to global gcov info list. */
298 obj_info
->next
= gcov_info_head
;
299 gcov_info_head
= obj_info
;
302 obj_info
->stamp
= gcov_read_unsigned ();
305 obj_info
->checksum
= gcov_read_unsigned ();
309 gcov_position_t base
;
310 unsigned tag
, length
;
311 tag_format_t
const *format
;
316 tag
= gcov_read_unsigned ();
319 int read_length
= (int)gcov_read_unsigned ();
320 length
= read_length
> 0 ? read_length
: 0;
321 base
= gcov_position ();
322 mask
= GCOV_TAG_MASK (tag
) >> 1;
323 for (tag_depth
= 4; mask
; mask
>>= 8)
325 if (((mask
& 0xff) != 0xff))
327 warning (0, "%s:tag %qx is invalid", filename
, tag
);
332 for (format
= tag_table
; format
->name
; format
++)
333 if (format
->tag
== tag
)
335 format
= &tag_table
[GCOV_TAG_IS_COUNTER (tag
) ? 2 : 1];
339 if (depth
&& depth
< tag_depth
)
341 if (!GCOV_TAG_IS_SUBTAG (tags
[depth
- 1], tag
))
342 warning (0, "%s:tag %qx is incorrectly nested",
346 tags
[depth
- 1] = tag
;
351 unsigned long actual_length
;
353 (*format
->proc
) (tag
, read_length
);
355 actual_length
= gcov_position () - base
;
356 if (actual_length
> length
)
357 warning (0, "%s:record size mismatch %lu bytes overread",
358 filename
, actual_length
- length
);
359 else if (length
> actual_length
)
360 warning (0, "%s:record size mismatch %lu bytes unread",
361 filename
, length
- actual_length
);
364 gcov_sync (base
, length
);
365 if ((error
= gcov_is_error ()))
367 warning (0, error
< 0 ? "%s:counter overflow at %lu" :
368 "%s:read error at %lu", filename
,
369 (long unsigned) gcov_position ());
374 read_gcda_finalize (obj_info
);
380 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
381 Return a non-zero value to stop the tree walk. */
384 ftw_read_file (const char *filename
,
385 const struct stat
*status ATTRIBUTE_UNUSED
,
391 /* Only read regular files. */
395 filename_len
= strlen (filename
);
396 suffix_len
= strlen (GCOV_DATA_SUFFIX
);
398 if (filename_len
<= suffix_len
)
401 if (strcmp(filename
+ filename_len
- suffix_len
, GCOV_DATA_SUFFIX
))
405 fnotice (stderr
, "reading file: %s\n", filename
);
407 if (!gcov_open (filename
, 1))
409 fnotice (stderr
, "%s:cannot open:%s\n", filename
, xstrerror (errno
));
413 (void)read_gcda_file (xstrdup (filename
));
420 /* Initializer for reading a profile dir. */
423 read_profile_dir_init (void)
428 /* Driver for read a profile directory and convert into gcov_info list in memory.
429 Return NULL on error,
430 Return the head of gcov_info list on success. */
433 gcov_read_profile_dir (const char* dir_name
, int recompute_summary ATTRIBUTE_UNUSED
)
438 read_profile_dir_init ();
440 if (access (dir_name
, R_OK
) != 0)
442 fnotice (stderr
, "cannot access directory %s\n", dir_name
);
445 pwd
= getcwd (NULL
, 0);
447 ret
= chdir (dir_name
);
450 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 n1
,
503 gcov_type
*v2
, gcov_unsigned_t n2
, unsigned w
)
506 gcov_value_buf_pos
= 0;
507 gcov_value_buf_size
= n2
;
508 gcov_merge_weight
= w
;
512 /* Convert on disk representation of a TOPN counter to in memory representation
513 that is expected from __gcov_merge_topn function. */
516 topn_to_memory_representation (struct gcov_ctr_info
*info
)
518 auto_vec
<gcov_type
> output
;
519 gcov_type
*values
= info
->values
;
520 int count
= info
->num
;
524 output
.safe_push (values
[0]);
525 gcov_type n
= values
[1];
526 output
.safe_push (n
);
529 struct gcov_kvp
*tuples
530 = (struct gcov_kvp
*)xcalloc (n
, sizeof (struct gcov_kvp
));
531 for (unsigned i
= 0; i
< n
- 1; i
++)
532 tuples
[i
].next
= &tuples
[i
+ 1];
533 for (unsigned i
= 0; i
< n
; i
++)
535 tuples
[i
].value
= values
[2 + 2 * i
];
536 tuples
[i
].count
= values
[2 + 2 * i
+ 1];
538 output
.safe_push ((intptr_t)&tuples
[0]);
541 output
.safe_push (0);
543 unsigned len
= 2 * n
+ 2;
547 gcc_assert (count
== 0);
549 /* Allocate new buffer and copy it there. */
550 info
->num
= output
.length ();
551 info
->values
= (gcov_type
*)xmalloc (sizeof (gcov_type
) * info
->num
);
552 for (unsigned i
= 0; i
< info
->num
; i
++)
553 info
->values
[i
] = output
[i
];
556 /* Offline tool to manipulate profile data.
557 This tool targets on matched profiles. But it has some tolerance on
559 When merging p1 to p2 (p2 is the dst),
560 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
562 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
563 specified weight; emit warning.
564 * m.gcda in both p1 and p2:
565 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
566 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
568 drop p1->m.gcda->f. A warning is emitted. */
570 /* Add INFO2's counter to INFO1, multiplying by weight W. */
573 gcov_merge (struct gcov_info
*info1
, struct gcov_info
*info2
, int w
)
576 unsigned n_functions
= info1
->n_functions
;
577 int has_mismatch
= 0;
579 gcc_assert (info2
->n_functions
== n_functions
);
582 info1
->summary
.runs
+= info2
->summary
.runs
;
583 info1
->summary
.sum_max
+= info2
->summary
.sum_max
;
585 for (f_ix
= 0; f_ix
< n_functions
; f_ix
++)
588 struct gcov_fn_info
*gfi_ptr1
= info1
->functions
[f_ix
];
589 struct gcov_fn_info
*gfi_ptr2
= info2
->functions
[f_ix
];
590 struct gcov_ctr_info
*ci_ptr1
, *ci_ptr2
;
592 if (!gfi_ptr1
|| gfi_ptr1
->key
!= info1
)
594 if (!gfi_ptr2
|| gfi_ptr2
->key
!= info2
)
597 if (gfi_ptr1
->cfg_checksum
!= gfi_ptr2
->cfg_checksum
)
599 fnotice (stderr
, "in %s, cfg_checksum mismatch, skipping\n",
604 ci_ptr1
= gfi_ptr1
->ctrs
;
605 ci_ptr2
= gfi_ptr2
->ctrs
;
606 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
608 gcov_merge_fn merge1
= info1
->merge
[t_ix
];
609 gcov_merge_fn merge2
= info2
->merge
[t_ix
];
611 gcc_assert (merge1
== merge2
);
615 if (merge1
== __gcov_merge_topn
)
616 topn_to_memory_representation (ci_ptr1
);
618 gcc_assert (ci_ptr1
->num
== ci_ptr2
->num
);
620 merge_wrapper (merge1
, ci_ptr1
->values
, ci_ptr1
->num
,
621 ci_ptr2
->values
, ci_ptr2
->num
, w
);
630 /* Find and return the match gcov_info object for INFO from ARRAY.
631 SIZE is the length of ARRAY.
632 Return NULL if there is no match. */
634 static struct gcov_info
*
635 find_match_gcov_info (struct gcov_info
**array
, int size
,
636 struct gcov_info
*info
)
638 struct gcov_info
*gi_ptr
;
639 struct gcov_info
*ret
= NULL
;
642 for (i
= 0; i
< size
; i
++)
647 if (!strcmp (gi_ptr
->filename
, info
->filename
))
655 if (ret
&& ret
->n_functions
!= info
->n_functions
)
657 fnotice (stderr
, "mismatched profiles in %s (%d functions"
658 " vs %d functions)\n",
667 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
668 Return the list of merged gcov_info objects. Return NULL if the list is
672 gcov_profile_merge (struct gcov_info
*tgt_profile
, struct gcov_info
*src_profile
,
675 struct gcov_info
*gi_ptr
;
676 struct gcov_info
**tgt_infos
;
677 struct gcov_info
**tgt_tail
;
678 struct gcov_info
**in_src_not_tgt
;
679 unsigned tgt_cnt
= 0, src_cnt
= 0;
680 unsigned unmatch_info_cnt
= 0;
683 for (gi_ptr
= tgt_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
685 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
687 tgt_infos
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
689 gcc_assert (tgt_infos
);
690 in_src_not_tgt
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
692 gcc_assert (in_src_not_tgt
);
694 for (gi_ptr
= tgt_profile
, i
= 0; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
695 tgt_infos
[i
] = gi_ptr
;
698 tgt_tail
= &tgt_infos
[tgt_cnt
- 1]->next
;
700 tgt_tail
= &tgt_profile
;
702 /* First pass on tgt_profile, we multiply w1 to all counters. */
705 for (i
= 0; i
< tgt_cnt
; i
++)
706 gcov_merge (tgt_infos
[i
], tgt_infos
[i
], w1
-1);
709 /* Second pass, add src_profile to the tgt_profile. */
710 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
712 struct gcov_info
*gi_ptr1
;
714 gi_ptr1
= find_match_gcov_info (tgt_infos
, tgt_cnt
, gi_ptr
);
717 in_src_not_tgt
[unmatch_info_cnt
++] = gi_ptr
;
720 gcov_merge (gi_ptr1
, gi_ptr
, w2
);
723 /* For modules in src but not in tgt. We adjust the counter and append. */
724 for (i
= 0; i
< unmatch_info_cnt
; i
++)
726 gi_ptr
= in_src_not_tgt
[i
];
727 gcov_merge (gi_ptr
, gi_ptr
, w2
- 1);
730 tgt_tail
= &gi_ptr
->next
;
733 free (in_src_not_tgt
);
739 /* Deserialize gcov_info objects and associated filenames from the file
740 specified by FILENAME to create a profile list. When FILENAME is NULL, read
741 from stdin. Return the profile list. */
744 deserialize_profiles (const char *filename
)
746 read_profile_dir_init ();
751 const char *filename_of_info
;
752 struct gcov_info
*obj_info
;
754 if (!gcov_magic (gcov_read_unsigned (), GCOV_FILENAME_MAGIC
))
756 if (gcov_is_error () != 2)
757 fnotice (stderr
, "%s:not a gcfn stream\n", filename
);
761 version
= gcov_read_unsigned ();
762 if (version
!= GCOV_VERSION
)
764 fnotice (stderr
, "%s:incorrect gcov version %d vs %d \n",
765 filename
, version
, GCOV_VERSION
);
769 filename_of_info
= gcov_read_string ();
770 if (!filename_of_info
)
772 fnotice (stderr
, "%s:no filename in gcfn stream\n",
777 obj_info
= read_gcda_file (filename
);
781 obj_info
->filename
= filename_of_info
;
784 return gcov_info_head
;
787 /* For each profile of the list specified by SRC_PROFILE, read the GCDA file of
788 the profile. If a GCDA file exists, add the profile to a list. Return the
792 get_target_profiles_for_merge (struct gcov_info
*src_profile
)
794 struct gcov_info
*gi_ptr
;
796 read_profile_dir_init ();
798 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
799 if (gcov_open (gi_ptr
->filename
, 1))
801 (void)read_gcda_file (gi_ptr
->filename
);
805 return gcov_info_head
;
808 /* Deserialize gcov_info objects and associated filenames from the file
809 specified by FILENAME to create a source profile list. When FILENAME is
810 NULL, read from stdin. Use the filenames of the source profile list to get
811 a target profile list. Merge the source profile list into the target
812 profile list using weights W1 and W2. Return the list of merged gcov_info
813 objects. Return NULL if the list is empty. */
816 gcov_profile_merge_stream (const char *filename
, int w1
, int w2
)
818 struct gcov_info
*tgt_profile
;
819 struct gcov_info
*src_profile
;
821 if (!gcov_open (filename
, 1))
823 fnotice (stderr
, "%s:cannot open:%s\n", filename
, xstrerror (errno
));
827 src_profile
= deserialize_profiles (filename
? filename
: "<stdin>");
829 tgt_profile
= get_target_profiles_for_merge (src_profile
);
831 return gcov_profile_merge (tgt_profile
, src_profile
, w1
, w2
);
834 typedef gcov_type (*counter_op_fn
) (gcov_type
, void*, void*);
836 /* Performing FN upon arc counters. */
839 __gcov_add_counter_op (gcov_type
*counters
, unsigned n_counters
,
840 counter_op_fn fn
, void *data1
, void *data2
)
842 for (; n_counters
; counters
++, n_counters
--)
844 gcov_type val
= *counters
;
845 *counters
= fn(val
, data1
, data2
);
849 /* Performing FN upon ior counters. */
852 __gcov_ior_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
853 unsigned n_counters ATTRIBUTE_UNUSED
,
854 counter_op_fn fn ATTRIBUTE_UNUSED
,
855 void *data1 ATTRIBUTE_UNUSED
,
856 void *data2 ATTRIBUTE_UNUSED
)
861 /* Performing FN upon time-profile counters. */
864 __gcov_time_profile_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
865 unsigned n_counters ATTRIBUTE_UNUSED
,
866 counter_op_fn fn ATTRIBUTE_UNUSED
,
867 void *data1 ATTRIBUTE_UNUSED
,
868 void *data2 ATTRIBUTE_UNUSED
)
873 /* Performing FN upon TOP N counters. */
876 __gcov_topn_counter_op (gcov_type
*counters
, unsigned n_counters
,
877 counter_op_fn fn
, void *data1
, void *data2
)
879 unsigned i
, n_measures
;
881 gcc_assert (!(n_counters
% 3));
882 n_measures
= n_counters
/ 3;
883 for (i
= 0; i
< n_measures
; i
++, counters
+= 3)
885 counters
[1] = fn (counters
[1], data1
, data2
);
886 counters
[2] = fn (counters
[2], data1
, data2
);
890 /* Scaling the counter value V by multiplying *(float*) DATA1. */
893 fp_scale (gcov_type v
, void *data1
, void *data2 ATTRIBUTE_UNUSED
)
895 float f
= *(float *) data1
;
896 return (gcov_type
) (v
* f
);
899 /* Scaling the counter value V by multiplying DATA2/DATA1. */
902 int_scale (gcov_type v
, void *data1
, void *data2
)
904 int n
= *(int *) data1
;
905 int d
= *(int *) data2
;
906 return (gcov_type
) ( RDIV (v
,d
) * n
);
909 /* Type of function used to process counters. */
910 typedef void (*gcov_counter_fn
) (gcov_type
*, gcov_unsigned_t
,
911 counter_op_fn
, void *, void *);
913 /* Function array to process profile counters. */
914 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
915 __gcov ## FN_TYPE ## _counter_op,
916 static gcov_counter_fn ctr_functions
[GCOV_COUNTERS
] = {
917 #include "gcov-counter.def"
919 #undef DEF_GCOV_COUNTER
921 /* Driver for scaling profile counters. */
924 gcov_profile_scale (struct gcov_info
*profile
, float scale_factor
, int n
, int d
)
926 struct gcov_info
*gi_ptr
;
930 fnotice (stdout
, "scale_factor is %f or %d/%d\n", scale_factor
, n
, d
);
932 /* Scaling the counters. */
933 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
934 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
937 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
938 const struct gcov_ctr_info
*ci_ptr
;
940 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
943 ci_ptr
= gfi_ptr
->ctrs
;
944 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
946 gcov_merge_fn merge
= gi_ptr
->merge
[t_ix
];
951 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
952 fp_scale
, &scale_factor
, NULL
);
954 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
963 /* Driver to normalize profile counters. */
966 gcov_profile_normalize (struct gcov_info
*profile
, gcov_type max_val
)
968 struct gcov_info
*gi_ptr
;
969 gcov_type curr_max_val
= 0;
974 /* Find the largest count value. */
975 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
976 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
979 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
980 const struct gcov_ctr_info
*ci_ptr
;
982 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
985 ci_ptr
= gfi_ptr
->ctrs
;
986 for (t_ix
= 0; t_ix
< 1; t_ix
++)
988 for (i
= 0; i
< ci_ptr
->num
; i
++)
989 if (ci_ptr
->values
[i
] > curr_max_val
)
990 curr_max_val
= ci_ptr
->values
[i
];
995 scale_factor
= (float)max_val
/ curr_max_val
;
997 fnotice (stdout
, "max_val is %" PRId64
"\n", curr_max_val
);
999 return gcov_profile_scale (profile
, scale_factor
, 0, 0);
1002 /* The following variables are defined in gcc/gcov-tool.c. */
1003 extern int overlap_func_level
;
1004 extern int overlap_obj_level
;
1005 extern int overlap_hot_only
;
1006 extern int overlap_use_fullname
;
1007 extern double overlap_hot_threshold
;
1009 /* Compute the overlap score of two values. The score is defined as:
1010 min (V1/SUM_1, V2/SUM_2) */
1013 calculate_2_entries (const unsigned long v1
, const unsigned long v2
,
1014 const double sum_1
, const double sum_2
)
1016 double val1
= (sum_1
== 0.0 ? 0.0 : v1
/sum_1
);
1017 double val2
= (sum_2
== 0.0 ? 0.0 : v2
/sum_2
);
1025 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
1026 This function also updates cumulative score CUM_1_RESULT and
1030 compute_one_gcov (const struct gcov_info
*gcov_info1
,
1031 const struct gcov_info
*gcov_info2
,
1032 const double sum_1
, const double sum_2
,
1033 double *cum_1_result
, double *cum_2_result
)
1037 double cum_1
= 0, cum_2
= 0;
1038 const struct gcov_info
*gcov_info
= 0;
1042 gcc_assert (gcov_info1
|| gcov_info2
);
1045 gcov_info
= gcov_info2
;
1046 cum_p
= cum_2_result
;
1052 gcov_info
= gcov_info1
;
1053 cum_p
= cum_1_result
;
1060 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
1062 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
1063 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
1065 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
1067 for (c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
1068 cum_1
+= ci_ptr
->values
[c_num
] / sum
;
1074 for (f_ix
= 0; f_ix
< gcov_info1
->n_functions
; f_ix
++)
1076 double func_cum_1
= 0.0;
1077 double func_cum_2
= 0.0;
1078 double func_val
= 0.0;
1081 const struct gcov_fn_info
*gfi_ptr1
= gcov_info1
->functions
[f_ix
];
1082 const struct gcov_fn_info
*gfi_ptr2
= gcov_info2
->functions
[f_ix
];
1084 if (!gfi_ptr1
|| gfi_ptr1
->key
!= gcov_info1
)
1086 if (!gfi_ptr2
|| gfi_ptr2
->key
!= gcov_info2
)
1089 const struct gcov_ctr_info
*ci_ptr1
= gfi_ptr1
->ctrs
;
1090 const struct gcov_ctr_info
*ci_ptr2
= gfi_ptr2
->ctrs
;
1092 for (c_num
= 0; c_num
< ci_ptr1
->num
; c_num
++)
1094 if (ci_ptr1
->values
[c_num
] | ci_ptr2
->values
[c_num
])
1096 func_val
+= calculate_2_entries (ci_ptr1
->values
[c_num
],
1097 ci_ptr2
->values
[c_num
],
1100 func_cum_1
+= ci_ptr1
->values
[c_num
] / sum_1
;
1101 func_cum_2
+= ci_ptr2
->values
[c_num
] / sum_2
;
1103 if (ci_ptr1
->values
[c_num
] / sum_1
>= overlap_hot_threshold
1104 || ci_ptr2
->values
[c_num
] / sum_2
>= overlap_hot_threshold
)
1110 cum_1
+= func_cum_1
;
1111 cum_2
+= func_cum_2
;
1112 if (overlap_func_level
&& nonzero
&& (!overlap_hot_only
|| hot
))
1114 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1115 gfi_ptr1
->ident
, func_val
*100, func_cum_1
*100, func_cum_2
*100);
1118 *cum_1_result
= cum_1
;
1119 *cum_2_result
= cum_2
;
1123 /* Test if all counter values in this GCOV_INFO are cold.
1124 "Cold" is defined as the counter value being less than
1125 or equal to THRESHOLD. */
1128 gcov_info_count_all_cold (const struct gcov_info
*gcov_info
,
1129 gcov_type threshold
)
1133 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
1135 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
1137 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
1139 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
1140 for (unsigned c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
1141 if (ci_ptr
->values
[c_num
] > threshold
)
1148 /* Test if all counter values in this GCOV_INFO are 0. */
1151 gcov_info_count_all_zero (const struct gcov_info
*gcov_info
)
1153 return gcov_info_count_all_cold (gcov_info
, 0);
1156 /* A pair of matched GCOV_INFO.
1157 The flag is a bitvector:
1158 b0: obj1's all counts are 0;
1159 b1: obj1's all counts are cold (but no 0);
1161 b3: no obj1 to match obj2;
1162 b4: obj2's all counts are 0;
1163 b5: obj2's all counts are cold (but no 0);
1165 b7: no obj2 to match obj1;
1168 const struct gcov_info
*obj1
;
1169 const struct gcov_info
*obj2
;
1173 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1174 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1175 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1177 /* Cumlative overlap dscore for profile1 and profile2. */
1178 static double overlap_sum_1
, overlap_sum_2
;
1180 /* The number of gcda files in the profiles. */
1181 static unsigned gcda_files
[2];
1183 /* The number of unique gcda files in the profiles
1184 (not existing in the other profile). */
1185 static unsigned unique_gcda_files
[2];
1187 /* The number of gcda files that all counter values are 0. */
1188 static unsigned zero_gcda_files
[2];
1190 /* The number of gcda files that all counter values are cold (but not 0). */
1191 static unsigned cold_gcda_files
[2];
1193 /* The number of gcda files that includes hot counter values. */
1194 static unsigned hot_gcda_files
[2];
1196 /* The number of gcda files with hot count value in either profiles. */
1197 static unsigned both_hot_cnt
;
1199 /* The number of gcda files with all counts cold (but not 0) in
1201 static unsigned both_cold_cnt
;
1203 /* The number of gcda files with all counts 0 in both profiles. */
1204 static unsigned both_zero_cnt
;
1206 /* Extract the basename of the filename NAME. */
1209 extract_file_basename (const char *name
)
1213 char *path
= xstrdup (name
);
1216 sep_str
[0] = DIR_SEPARATOR
;
1218 str
= strstr(path
, sep_str
);
1220 len
= strlen(str
) + 1;
1221 path
= &path
[strlen(path
) - len
+ 2];
1222 str
= strstr(path
, sep_str
);
1228 /* Utility function to get the filename. */
1231 get_file_basename (const char *name
)
1233 if (overlap_use_fullname
)
1235 return extract_file_basename (name
);
1238 /* A utility function to set the flag for the gcda files. */
1241 set_flag (struct overlap_t
*e
)
1247 unique_gcda_files
[1]++;
1253 if (gcov_info_count_all_zero (e
->obj1
))
1255 zero_gcda_files
[0]++;
1259 if (gcov_info_count_all_cold (e
->obj1
, overlap_sum_1
1260 * overlap_hot_threshold
))
1262 cold_gcda_files
[0]++;
1267 hot_gcda_files
[0]++;
1274 unique_gcda_files
[0]++;
1280 if (gcov_info_count_all_zero (e
->obj2
))
1282 zero_gcda_files
[1]++;
1286 if (gcov_info_count_all_cold (e
->obj2
, overlap_sum_2
1287 * overlap_hot_threshold
))
1289 cold_gcda_files
[1]++;
1294 hot_gcda_files
[1]++;
1303 /* Test if INFO1 and INFO2 are from the matched source file.
1304 Return 1 if they match; return 0 otherwise. */
1307 matched_gcov_info (const struct gcov_info
*info1
, const struct gcov_info
*info2
)
1309 /* For FDO, we have to match the name. This can be expensive.
1310 Maybe we should use hash here. */
1311 if (strcmp (info1
->filename
, info2
->filename
))
1314 if (info1
->n_functions
!= info2
->n_functions
)
1316 fnotice (stderr
, "mismatched profiles in %s (%d functions"
1317 " vs %d functions)\n",
1320 info2
->n_functions
);
1326 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1327 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1328 match and 1.0 meaning a perfect match. */
1331 calculate_overlap (struct gcov_info
*gcov_list1
,
1332 struct gcov_info
*gcov_list2
)
1334 unsigned list1_cnt
= 0, list2_cnt
= 0, all_cnt
;
1336 const struct gcov_info
*gi_ptr
;
1337 struct overlap_t
*all_infos
;
1339 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1341 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1343 all_cnt
= list1_cnt
+ list2_cnt
;
1344 all_infos
= (struct overlap_t
*) xmalloc (sizeof (struct overlap_t
)
1346 gcc_assert (all_infos
);
1349 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1351 all_infos
[i
].obj1
= gi_ptr
;
1352 all_infos
[i
].obj2
= 0;
1355 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1357 all_infos
[i
].obj1
= 0;
1358 all_infos
[i
].obj2
= gi_ptr
;
1361 for (i
= list1_cnt
; i
< all_cnt
; i
++)
1363 if (all_infos
[i
].obj2
== 0)
1365 for (j
= 0; j
< list1_cnt
; j
++)
1367 if (all_infos
[j
].obj2
!= 0)
1369 if (matched_gcov_info (all_infos
[i
].obj2
, all_infos
[j
].obj1
))
1371 all_infos
[j
].obj2
= all_infos
[i
].obj2
;
1372 all_infos
[i
].obj2
= 0;
1378 for (i
= 0; i
< all_cnt
; i
++)
1379 if (all_infos
[i
].obj1
|| all_infos
[i
].obj2
)
1381 set_flag (all_infos
+ i
);
1382 if (FLAG_ONE_HOT (all_infos
[i
].flag
))
1384 if (FLAG_BOTH_COLD(all_infos
[i
].flag
))
1386 if (FLAG_BOTH_ZERO(all_infos
[i
].flag
))
1392 double sum_cum_1
= 0;
1393 double sum_cum_2
= 0;
1395 for (i
= 0; i
< all_cnt
; i
++)
1398 double cum_1
, cum_2
;
1399 const char *filename
;
1401 if (all_infos
[i
].obj1
== 0 && all_infos
[i
].obj2
== 0)
1403 if (FLAG_BOTH_ZERO (all_infos
[i
].flag
))
1406 if (all_infos
[i
].obj1
)
1407 filename
= get_file_basename (all_infos
[i
].obj1
->filename
);
1409 filename
= get_file_basename (all_infos
[i
].obj2
->filename
);
1411 if (overlap_func_level
)
1412 printf("\n processing %36s:\n", filename
);
1414 val
= compute_one_gcov (all_infos
[i
].obj1
, all_infos
[i
].obj2
,
1415 overlap_sum_1
, overlap_sum_2
, &cum_1
, &cum_2
);
1417 if (overlap_obj_level
&& (!overlap_hot_only
|| FLAG_ONE_HOT (all_infos
[i
].flag
)))
1419 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1420 filename
, val
*100, cum_1
*100, cum_2
*100);
1432 if (overlap_obj_level
)
1433 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1434 "", sum_val
*100, sum_cum_1
*100, sum_cum_2
*100);
1436 printf (" Statistics:\n"
1437 " profile1_# profile2_# overlap_#\n");
1438 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files
[0], gcda_files
[1],
1439 gcda_files
[0]-unique_gcda_files
[0]);
1440 printf (" unique files: %12u\t%12u\n", unique_gcda_files
[0],
1441 unique_gcda_files
[1]);
1442 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files
[0],
1443 hot_gcda_files
[1], both_hot_cnt
);
1444 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files
[0],
1445 cold_gcda_files
[1], both_cold_cnt
);
1446 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files
[0],
1447 zero_gcda_files
[1], both_zero_cnt
);
1452 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1454 Return 0 on success: without mismatch. Reutrn 1 on error. */
1457 gcov_profile_overlap (struct gcov_info
*profile1
, struct gcov_info
*profile2
)
1461 result
= calculate_overlap (profile1
, profile2
);
1465 printf("\nProgram level overlap result is %3.2f%%\n\n", result
*100);