1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2024 Free Software Foundation, Inc.
4 Contributed by Rong Xu <xur@google.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
28 #define IN_GCOV_TOOL 1
32 #include "diagnostic.h"
37 /* Borrowed from basic-block.h. */
38 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
40 extern gcov_position_t
gcov_position();
41 extern int gcov_is_error();
43 /* Verbose mode for debug. */
46 /* Set verbose flag. */
47 void gcov_set_verbose (void)
52 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
60 static void tag_function (unsigned, int);
61 static void tag_blocks (unsigned, int);
62 static void tag_arcs (unsigned, int);
63 static void tag_lines (unsigned, int);
64 static void tag_counters (unsigned, int);
65 static void tag_summary (unsigned, int);
67 /* The gcov_info for the first module. */
68 static struct gcov_info
*curr_gcov_info
;
69 /* The gcov_info being processed. */
70 static struct gcov_info
*gcov_info_head
;
71 /* This variable contains all the functions in current module. */
72 static struct obstack fn_info
;
73 /* The function being processed. */
74 static struct gcov_fn_info
*curr_fn_info
;
75 /* The number of functions seen so far. */
76 static unsigned num_fn_info
;
77 /* This variable contains all the counters for current module. */
78 static int k_ctrs_mask
[GCOV_COUNTERS
];
79 /* The kind of counters that have been seen. */
80 static struct gcov_ctr_info k_ctrs
[GCOV_COUNTERS
];
81 /* Number of kind of counters that have been seen. */
82 static int k_ctrs_types
;
84 /* Merge functions for counters. */
85 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
86 static gcov_merge_fn ctr_merge_functions
[GCOV_COUNTERS
] = {
87 #include "gcov-counter.def"
89 #undef DEF_GCOV_COUNTER
91 /* Set the ctrs field in gcov_fn_info object FN_INFO. */
94 set_fn_ctrs (struct gcov_fn_info
*fn_info
)
98 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
100 if (k_ctrs_mask
[i
] == 0)
102 fn_info
->ctrs
[j
].num
= k_ctrs
[i
].num
;
103 fn_info
->ctrs
[j
].values
= k_ctrs
[i
].values
;
106 if (k_ctrs_types
== 0)
109 gcc_assert (j
== k_ctrs_types
);
112 /* For each tag in gcda file, we have an entry here.
113 TAG is the tag value; NAME is the tag name; and
114 PROC is the handler function. */
116 typedef struct tag_format
120 void (*proc
) (unsigned, int);
123 /* Handler table for various Tags. */
125 static const tag_format_t tag_table
[] =
128 {0, "UNKNOWN", NULL
},
129 {0, "COUNTERS", tag_counters
},
130 {GCOV_TAG_FUNCTION
, "FUNCTION", tag_function
},
131 {GCOV_TAG_BLOCKS
, "BLOCKS", tag_blocks
},
132 {GCOV_TAG_ARCS
, "ARCS", tag_arcs
},
133 {GCOV_TAG_LINES
, "LINES", tag_lines
},
134 {GCOV_TAG_OBJECT_SUMMARY
, "OBJECT_SUMMARY", tag_summary
},
138 /* Handler for reading function tag. */
141 tag_function (unsigned tag ATTRIBUTE_UNUSED
, int 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
, int 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
, int 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
, int 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
, int length
)
203 unsigned n_counts
= GCOV_TAG_COUNTER_NUM (abs (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
*) xcalloc (sizeof (gcov_type
),
219 for (ix
= 0; ix
!= n_counts
; ix
++)
220 values
[ix
] = gcov_read_counter ();
223 /* Handler for reading summary tag. */
226 tag_summary (unsigned tag ATTRIBUTE_UNUSED
, int ATTRIBUTE_UNUSED
)
228 gcov_read_summary (&curr_gcov_info
->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, functions
244 obj_info
->n_functions
= num_fn_info
;
245 obj_info
->functions
= (struct gcov_fn_info
**) obstack_finish (&fn_info
);
247 /* wrap all the counter array. */
248 for (i
=0; i
< GCOV_COUNTERS
; i
++)
251 obj_info
->merge
[i
] = ctr_merge_functions
[i
];
255 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
256 Program level summary CURRENT_SUMMARY will also be updated. */
258 static struct gcov_info
*
259 read_gcda_file (const char *filename
)
264 struct gcov_info
*obj_info
;
267 for (i
=0; i
< GCOV_COUNTERS
; i
++)
272 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
274 fnotice (stderr
, "%s:not a gcov data file\n", filename
);
279 version
= gcov_read_unsigned ();
280 if (version
!= GCOV_VERSION
)
282 fnotice (stderr
, "%s:incorrect gcov version %d vs %d \n", filename
, version
, GCOV_VERSION
);
286 /* Instantiate a gcov_info object. */
287 curr_gcov_info
= obj_info
= (struct gcov_info
*) xcalloc (sizeof (struct gcov_info
) +
288 sizeof (struct gcov_ctr_info
) * GCOV_COUNTERS
, 1);
290 obj_info
->version
= version
;
291 obj_info
->filename
= filename
;
292 obstack_init (&fn_info
);
296 /* Prepend to global gcov info list. */
297 obj_info
->next
= gcov_info_head
;
298 gcov_info_head
= obj_info
;
301 obj_info
->stamp
= gcov_read_unsigned ();
304 obj_info
->checksum
= gcov_read_unsigned ();
308 gcov_position_t base
;
309 unsigned tag
, length
;
310 tag_format_t
const *format
;
315 tag
= gcov_read_unsigned ();
318 int read_length
= (int)gcov_read_unsigned ();
319 length
= read_length
> 0 ? read_length
: 0;
320 base
= gcov_position ();
321 mask
= GCOV_TAG_MASK (tag
) >> 1;
322 for (tag_depth
= 4; mask
; mask
>>= 8)
324 if (((mask
& 0xff) != 0xff))
326 warning (0, "%s:tag %qx is invalid", filename
, tag
);
331 for (format
= tag_table
; format
->name
; format
++)
332 if (format
->tag
== tag
)
334 format
= &tag_table
[GCOV_TAG_IS_COUNTER (tag
) ? 2 : 1];
338 if (depth
&& depth
< tag_depth
)
340 if (!GCOV_TAG_IS_SUBTAG (tags
[depth
- 1], tag
))
341 warning (0, "%s:tag %qx is incorrectly nested",
345 tags
[depth
- 1] = tag
;
350 unsigned long actual_length
;
352 (*format
->proc
) (tag
, read_length
);
354 actual_length
= gcov_position () - base
;
355 if (actual_length
> length
)
356 warning (0, "%s:record size mismatch %lu bytes overread",
357 filename
, actual_length
- length
);
358 else if (length
> actual_length
)
359 warning (0, "%s:record size mismatch %lu bytes unread",
360 filename
, length
- actual_length
);
363 gcov_sync (base
, length
);
364 if ((error
= gcov_is_error ()))
366 warning (0, error
< 0 ? "%s:counter overflow at %lu" :
367 "%s:read error at %lu", filename
,
368 (long unsigned) gcov_position ());
373 read_gcda_finalize (obj_info
);
379 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
380 Return a non-zero value to stop the tree walk. */
383 ftw_read_file (const char *filename
,
384 const struct stat
*status ATTRIBUTE_UNUSED
,
390 /* Only read regular files. */
394 filename_len
= strlen (filename
);
395 suffix_len
= strlen (GCOV_DATA_SUFFIX
);
397 if (filename_len
<= suffix_len
)
400 if (strcmp(filename
+ filename_len
- suffix_len
, GCOV_DATA_SUFFIX
))
404 fnotice (stderr
, "reading file: %s\n", filename
);
406 if (!gcov_open (filename
, 1))
408 fnotice (stderr
, "%s:cannot open:%s\n", filename
, xstrerror (errno
));
412 (void)read_gcda_file (xstrdup (filename
));
419 /* Initializer for reading a profile dir. */
422 read_profile_dir_init (void)
427 /* Driver for read a profile directory and convert into gcov_info list in memory.
428 Return NULL on error,
429 Return the head of gcov_info list on success. */
432 gcov_read_profile_dir (const char* dir_name
, int recompute_summary ATTRIBUTE_UNUSED
)
437 read_profile_dir_init ();
439 if (access (dir_name
, R_OK
) != 0)
441 fnotice (stderr
, "cannot access directory %s\n", dir_name
);
444 pwd
= getcwd (NULL
, 0);
446 ret
= chdir (dir_name
);
449 fnotice (stderr
, "%s is not a directory\n", dir_name
);
453 ftw (".", ftw_read_file
, 50);
458 return gcov_info_head
;;
461 /* This part of the code is to merge profile counters. These
462 variables are set in merge_wrapper and to be used by
463 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
465 /* We save the counter value address to this variable. */
466 static gcov_type
*gcov_value_buf
;
468 /* The number of counter values to be read by current merging. */
469 static gcov_unsigned_t gcov_value_buf_size
;
471 /* The index of counter values being read. */
472 static gcov_unsigned_t gcov_value_buf_pos
;
474 /* The weight of current merging. */
475 static unsigned gcov_merge_weight
;
477 /* Read a counter value from gcov_value_buf array. */
480 gcov_read_counter_mem (void)
483 gcc_assert (gcov_value_buf_pos
< gcov_value_buf_size
);
484 ret
= *(gcov_value_buf
+ gcov_value_buf_pos
);
485 ++gcov_value_buf_pos
;
489 /* Return the recorded merge weight. */
492 gcov_get_merge_weight (void)
494 return gcov_merge_weight
;
497 /* A wrapper function for merge functions. It sets up the
498 value buffer and weights and then calls the merge function. */
501 merge_wrapper (gcov_merge_fn f
, gcov_type
*v1
, gcov_unsigned_t n1
,
502 gcov_type
*v2
, gcov_unsigned_t n2
, unsigned w
)
505 gcov_value_buf_pos
= 0;
506 gcov_value_buf_size
= n2
;
507 gcov_merge_weight
= w
;
511 /* Convert on disk representation of a TOPN counter to in memory representation
512 that is expected from __gcov_merge_topn function. */
515 topn_to_memory_representation (struct gcov_ctr_info
*info
)
517 auto_vec
<gcov_type
> output
;
518 gcov_type
*values
= info
->values
;
519 int count
= info
->num
;
523 output
.safe_push (values
[0]);
524 gcov_type n
= values
[1];
525 output
.safe_push (n
);
528 struct gcov_kvp
*tuples
529 = (struct gcov_kvp
*)xcalloc (sizeof (struct gcov_kvp
), n
);
530 for (unsigned i
= 0; i
< n
- 1; i
++)
531 tuples
[i
].next
= &tuples
[i
+ 1];
532 for (unsigned i
= 0; i
< n
; i
++)
534 tuples
[i
].value
= values
[2 + 2 * i
];
535 tuples
[i
].count
= values
[2 + 2 * i
+ 1];
537 output
.safe_push ((intptr_t)&tuples
[0]);
540 output
.safe_push (0);
542 unsigned len
= 2 * n
+ 2;
546 gcc_assert (count
== 0);
548 /* Allocate new buffer and copy it there. */
549 info
->num
= output
.length ();
550 info
->values
= (gcov_type
*)xmalloc (sizeof (gcov_type
) * info
->num
);
551 for (unsigned i
= 0; i
< info
->num
; i
++)
552 info
->values
[i
] = output
[i
];
555 /* Offline tool to manipulate profile data.
556 This tool targets on matched profiles. But it has some tolerance on
558 When merging p1 to p2 (p2 is the dst),
559 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
561 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
562 specified weight; emit warning.
563 * m.gcda in both p1 and p2:
564 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
565 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
567 drop p1->m.gcda->f. A warning is emitted. */
569 /* Add INFO2's counter to INFO1, multiplying by weight W. */
572 gcov_merge (struct gcov_info
*info1
, struct gcov_info
*info2
, int w
)
575 unsigned n_functions
= info1
->n_functions
;
576 int has_mismatch
= 0;
578 gcc_assert (info2
->n_functions
== n_functions
);
581 info1
->summary
.runs
+= info2
->summary
.runs
;
582 info1
->summary
.sum_max
+= info2
->summary
.sum_max
;
584 for (f_ix
= 0; f_ix
< n_functions
; f_ix
++)
587 struct gcov_fn_info
*gfi_ptr1
= info1
->functions
[f_ix
];
588 struct gcov_fn_info
*gfi_ptr2
= info2
->functions
[f_ix
];
589 struct gcov_ctr_info
*ci_ptr1
, *ci_ptr2
;
591 if (!gfi_ptr1
|| gfi_ptr1
->key
!= info1
)
593 if (!gfi_ptr2
|| gfi_ptr2
->key
!= info2
)
596 if (gfi_ptr1
->cfg_checksum
!= gfi_ptr2
->cfg_checksum
)
598 fnotice (stderr
, "in %s, cfg_checksum mismatch, skipping\n",
603 ci_ptr1
= gfi_ptr1
->ctrs
;
604 ci_ptr2
= gfi_ptr2
->ctrs
;
605 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
607 gcov_merge_fn merge1
= info1
->merge
[t_ix
];
608 gcov_merge_fn merge2
= info2
->merge
[t_ix
];
610 gcc_assert (merge1
== merge2
);
614 if (merge1
== __gcov_merge_topn
)
615 topn_to_memory_representation (ci_ptr1
);
617 gcc_assert (ci_ptr1
->num
== ci_ptr2
->num
);
619 merge_wrapper (merge1
, ci_ptr1
->values
, ci_ptr1
->num
,
620 ci_ptr2
->values
, ci_ptr2
->num
, w
);
629 /* Find and return the match gcov_info object for INFO from ARRAY.
630 SIZE is the length of ARRAY.
631 Return NULL if there is no match. */
633 static struct gcov_info
*
634 find_match_gcov_info (struct gcov_info
**array
, int size
,
635 struct gcov_info
*info
)
637 struct gcov_info
*gi_ptr
;
638 struct gcov_info
*ret
= NULL
;
641 for (i
= 0; i
< size
; i
++)
646 if (!strcmp (gi_ptr
->filename
, info
->filename
))
654 if (ret
&& ret
->n_functions
!= info
->n_functions
)
656 fnotice (stderr
, "mismatched profiles in %s (%d functions"
657 " vs %d functions)\n",
666 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
667 Return the list of merged gcov_info objects. Return NULL if the list is
671 gcov_profile_merge (struct gcov_info
*tgt_profile
, struct gcov_info
*src_profile
,
674 struct gcov_info
*gi_ptr
;
675 struct gcov_info
**tgt_infos
;
676 struct gcov_info
**tgt_tail
;
677 struct gcov_info
**in_src_not_tgt
;
678 unsigned tgt_cnt
= 0, src_cnt
= 0;
679 unsigned unmatch_info_cnt
= 0;
682 for (gi_ptr
= tgt_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
684 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
686 tgt_infos
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
688 gcc_assert (tgt_infos
);
689 in_src_not_tgt
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
691 gcc_assert (in_src_not_tgt
);
693 for (gi_ptr
= tgt_profile
, i
= 0; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
694 tgt_infos
[i
] = gi_ptr
;
697 tgt_tail
= &tgt_infos
[tgt_cnt
- 1]->next
;
699 tgt_tail
= &tgt_profile
;
701 /* First pass on tgt_profile, we multiply w1 to all counters. */
704 for (i
= 0; i
< tgt_cnt
; i
++)
705 gcov_merge (tgt_infos
[i
], tgt_infos
[i
], w1
-1);
708 /* Second pass, add src_profile to the tgt_profile. */
709 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
711 struct gcov_info
*gi_ptr1
;
713 gi_ptr1
= find_match_gcov_info (tgt_infos
, tgt_cnt
, gi_ptr
);
716 in_src_not_tgt
[unmatch_info_cnt
++] = gi_ptr
;
719 gcov_merge (gi_ptr1
, gi_ptr
, w2
);
722 /* For modules in src but not in tgt. We adjust the counter and append. */
723 for (i
= 0; i
< unmatch_info_cnt
; i
++)
725 gi_ptr
= in_src_not_tgt
[i
];
726 gcov_merge (gi_ptr
, gi_ptr
, w2
- 1);
729 tgt_tail
= &gi_ptr
->next
;
732 free (in_src_not_tgt
);
738 /* Deserialize gcov_info objects and associated filenames from the file
739 specified by FILENAME to create a profile list. When FILENAME is NULL, read
740 from stdin. Return the profile list. */
743 deserialize_profiles (const char *filename
)
745 read_profile_dir_init ();
750 const char *filename_of_info
;
751 struct gcov_info
*obj_info
;
753 if (!gcov_magic (gcov_read_unsigned (), GCOV_FILENAME_MAGIC
))
755 if (gcov_is_error () != 2)
756 fnotice (stderr
, "%s:not a gcfn stream\n", filename
);
760 version
= gcov_read_unsigned ();
761 if (version
!= GCOV_VERSION
)
763 fnotice (stderr
, "%s:incorrect gcov version %d vs %d \n",
764 filename
, version
, GCOV_VERSION
);
768 filename_of_info
= gcov_read_string ();
769 if (!filename_of_info
)
771 fnotice (stderr
, "%s:no filename in gcfn stream\n",
776 obj_info
= read_gcda_file (filename
);
780 obj_info
->filename
= filename_of_info
;
783 return gcov_info_head
;
786 /* For each profile of the list specified by SRC_PROFILE, read the GCDA file of
787 the profile. If a GCDA file exists, add the profile to a list. Return the
791 get_target_profiles_for_merge (struct gcov_info
*src_profile
)
793 struct gcov_info
*gi_ptr
;
795 read_profile_dir_init ();
797 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
798 if (gcov_open (gi_ptr
->filename
, 1))
800 (void)read_gcda_file (gi_ptr
->filename
);
804 return gcov_info_head
;
807 /* Deserialize gcov_info objects and associated filenames from the file
808 specified by FILENAME to create a source profile list. When FILENAME is
809 NULL, read from stdin. Use the filenames of the source profile list to get
810 a target profile list. Merge the source profile list into the target
811 profile list using weights W1 and W2. Return the list of merged gcov_info
812 objects. Return NULL if the list is empty. */
815 gcov_profile_merge_stream (const char *filename
, int w1
, int w2
)
817 struct gcov_info
*tgt_profile
;
818 struct gcov_info
*src_profile
;
820 if (!gcov_open (filename
, 1))
822 fnotice (stderr
, "%s:cannot open:%s\n", filename
, xstrerror (errno
));
826 src_profile
= deserialize_profiles (filename
? filename
: "<stdin>");
828 tgt_profile
= get_target_profiles_for_merge (src_profile
);
830 return gcov_profile_merge (tgt_profile
, src_profile
, w1
, w2
);
833 typedef gcov_type (*counter_op_fn
) (gcov_type
, void*, void*);
835 /* Performing FN upon arc counters. */
838 __gcov_add_counter_op (gcov_type
*counters
, unsigned n_counters
,
839 counter_op_fn fn
, void *data1
, void *data2
)
841 for (; n_counters
; counters
++, n_counters
--)
843 gcov_type val
= *counters
;
844 *counters
= fn(val
, data1
, data2
);
848 /* Performing FN upon ior counters. */
851 __gcov_ior_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
852 unsigned n_counters ATTRIBUTE_UNUSED
,
853 counter_op_fn fn ATTRIBUTE_UNUSED
,
854 void *data1 ATTRIBUTE_UNUSED
,
855 void *data2 ATTRIBUTE_UNUSED
)
860 /* Performing FN upon time-profile counters. */
863 __gcov_time_profile_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
864 unsigned n_counters ATTRIBUTE_UNUSED
,
865 counter_op_fn fn ATTRIBUTE_UNUSED
,
866 void *data1 ATTRIBUTE_UNUSED
,
867 void *data2 ATTRIBUTE_UNUSED
)
872 /* Performing FN upon TOP N counters. */
875 __gcov_topn_counter_op (gcov_type
*counters
, unsigned n_counters
,
876 counter_op_fn fn
, void *data1
, void *data2
)
878 unsigned i
, n_measures
;
880 gcc_assert (!(n_counters
% 3));
881 n_measures
= n_counters
/ 3;
882 for (i
= 0; i
< n_measures
; i
++, counters
+= 3)
884 counters
[1] = fn (counters
[1], data1
, data2
);
885 counters
[2] = fn (counters
[2], data1
, data2
);
889 /* Scaling the counter value V by multiplying *(float*) DATA1. */
892 fp_scale (gcov_type v
, void *data1
, void *data2 ATTRIBUTE_UNUSED
)
894 float f
= *(float *) data1
;
895 return (gcov_type
) (v
* f
);
898 /* Scaling the counter value V by multiplying DATA2/DATA1. */
901 int_scale (gcov_type v
, void *data1
, void *data2
)
903 int n
= *(int *) data1
;
904 int d
= *(int *) data2
;
905 return (gcov_type
) ( RDIV (v
,d
) * n
);
908 /* Type of function used to process counters. */
909 typedef void (*gcov_counter_fn
) (gcov_type
*, gcov_unsigned_t
,
910 counter_op_fn
, void *, void *);
912 /* Function array to process profile counters. */
913 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
914 __gcov ## FN_TYPE ## _counter_op,
915 static gcov_counter_fn ctr_functions
[GCOV_COUNTERS
] = {
916 #include "gcov-counter.def"
918 #undef DEF_GCOV_COUNTER
920 /* Driver for scaling profile counters. */
923 gcov_profile_scale (struct gcov_info
*profile
, float scale_factor
, int n
, int d
)
925 struct gcov_info
*gi_ptr
;
929 fnotice (stdout
, "scale_factor is %f or %d/%d\n", scale_factor
, n
, d
);
931 /* Scaling the counters. */
932 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
933 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
936 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
937 const struct gcov_ctr_info
*ci_ptr
;
939 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
942 ci_ptr
= gfi_ptr
->ctrs
;
943 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
945 gcov_merge_fn merge
= gi_ptr
->merge
[t_ix
];
950 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
951 fp_scale
, &scale_factor
, NULL
);
953 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
962 /* Driver to normalize profile counters. */
965 gcov_profile_normalize (struct gcov_info
*profile
, gcov_type max_val
)
967 struct gcov_info
*gi_ptr
;
968 gcov_type curr_max_val
= 0;
973 /* Find the largest count value. */
974 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
975 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
978 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
979 const struct gcov_ctr_info
*ci_ptr
;
981 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
984 ci_ptr
= gfi_ptr
->ctrs
;
985 for (t_ix
= 0; t_ix
< 1; t_ix
++)
987 for (i
= 0; i
< ci_ptr
->num
; i
++)
988 if (ci_ptr
->values
[i
] > curr_max_val
)
989 curr_max_val
= ci_ptr
->values
[i
];
994 scale_factor
= (float)max_val
/ curr_max_val
;
996 fnotice (stdout
, "max_val is %" PRId64
"\n", curr_max_val
);
998 return gcov_profile_scale (profile
, scale_factor
, 0, 0);
1001 /* The following variables are defined in gcc/gcov-tool.c. */
1002 extern int overlap_func_level
;
1003 extern int overlap_obj_level
;
1004 extern int overlap_hot_only
;
1005 extern int overlap_use_fullname
;
1006 extern double overlap_hot_threshold
;
1008 /* Compute the overlap score of two values. The score is defined as:
1009 min (V1/SUM_1, V2/SUM_2) */
1012 calculate_2_entries (const unsigned long v1
, const unsigned long v2
,
1013 const double sum_1
, const double sum_2
)
1015 double val1
= (sum_1
== 0.0 ? 0.0 : v1
/sum_1
);
1016 double val2
= (sum_2
== 0.0 ? 0.0 : v2
/sum_2
);
1024 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
1025 This function also updates cumulative score CUM_1_RESULT and
1029 compute_one_gcov (const struct gcov_info
*gcov_info1
,
1030 const struct gcov_info
*gcov_info2
,
1031 const double sum_1
, const double sum_2
,
1032 double *cum_1_result
, double *cum_2_result
)
1036 double cum_1
= 0, cum_2
= 0;
1037 const struct gcov_info
*gcov_info
= 0;
1041 gcc_assert (gcov_info1
|| gcov_info2
);
1044 gcov_info
= gcov_info2
;
1045 cum_p
= cum_2_result
;
1051 gcov_info
= gcov_info1
;
1052 cum_p
= cum_1_result
;
1059 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
1061 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
1062 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
1064 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
1066 for (c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
1067 cum_1
+= ci_ptr
->values
[c_num
] / sum
;
1073 for (f_ix
= 0; f_ix
< gcov_info1
->n_functions
; f_ix
++)
1075 double func_cum_1
= 0.0;
1076 double func_cum_2
= 0.0;
1077 double func_val
= 0.0;
1080 const struct gcov_fn_info
*gfi_ptr1
= gcov_info1
->functions
[f_ix
];
1081 const struct gcov_fn_info
*gfi_ptr2
= gcov_info2
->functions
[f_ix
];
1083 if (!gfi_ptr1
|| gfi_ptr1
->key
!= gcov_info1
)
1085 if (!gfi_ptr2
|| gfi_ptr2
->key
!= gcov_info2
)
1088 const struct gcov_ctr_info
*ci_ptr1
= gfi_ptr1
->ctrs
;
1089 const struct gcov_ctr_info
*ci_ptr2
= gfi_ptr2
->ctrs
;
1091 for (c_num
= 0; c_num
< ci_ptr1
->num
; c_num
++)
1093 if (ci_ptr1
->values
[c_num
] | ci_ptr2
->values
[c_num
])
1095 func_val
+= calculate_2_entries (ci_ptr1
->values
[c_num
],
1096 ci_ptr2
->values
[c_num
],
1099 func_cum_1
+= ci_ptr1
->values
[c_num
] / sum_1
;
1100 func_cum_2
+= ci_ptr2
->values
[c_num
] / sum_2
;
1102 if (ci_ptr1
->values
[c_num
] / sum_1
>= overlap_hot_threshold
1103 || ci_ptr2
->values
[c_num
] / sum_2
>= overlap_hot_threshold
)
1109 cum_1
+= func_cum_1
;
1110 cum_2
+= func_cum_2
;
1111 if (overlap_func_level
&& nonzero
&& (!overlap_hot_only
|| hot
))
1113 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1114 gfi_ptr1
->ident
, func_val
*100, func_cum_1
*100, func_cum_2
*100);
1117 *cum_1_result
= cum_1
;
1118 *cum_2_result
= cum_2
;
1122 /* Test if all counter values in this GCOV_INFO are cold.
1123 "Cold" is defined as the counter value being less than
1124 or equal to THRESHOLD. */
1127 gcov_info_count_all_cold (const struct gcov_info
*gcov_info
,
1128 gcov_type threshold
)
1132 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
1134 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
1136 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
1138 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
1139 for (unsigned c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
1140 if (ci_ptr
->values
[c_num
] > threshold
)
1147 /* Test if all counter values in this GCOV_INFO are 0. */
1150 gcov_info_count_all_zero (const struct gcov_info
*gcov_info
)
1152 return gcov_info_count_all_cold (gcov_info
, 0);
1155 /* A pair of matched GCOV_INFO.
1156 The flag is a bitvector:
1157 b0: obj1's all counts are 0;
1158 b1: obj1's all counts are cold (but no 0);
1160 b3: no obj1 to match obj2;
1161 b4: obj2's all counts are 0;
1162 b5: obj2's all counts are cold (but no 0);
1164 b7: no obj2 to match obj1;
1167 const struct gcov_info
*obj1
;
1168 const struct gcov_info
*obj2
;
1172 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1173 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1174 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1176 /* Cumlative overlap dscore for profile1 and profile2. */
1177 static double overlap_sum_1
, overlap_sum_2
;
1179 /* The number of gcda files in the profiles. */
1180 static unsigned gcda_files
[2];
1182 /* The number of unique gcda files in the profiles
1183 (not existing in the other profile). */
1184 static unsigned unique_gcda_files
[2];
1186 /* The number of gcda files that all counter values are 0. */
1187 static unsigned zero_gcda_files
[2];
1189 /* The number of gcda files that all counter values are cold (but not 0). */
1190 static unsigned cold_gcda_files
[2];
1192 /* The number of gcda files that includes hot counter values. */
1193 static unsigned hot_gcda_files
[2];
1195 /* The number of gcda files with hot count value in either profiles. */
1196 static unsigned both_hot_cnt
;
1198 /* The number of gcda files with all counts cold (but not 0) in
1200 static unsigned both_cold_cnt
;
1202 /* The number of gcda files with all counts 0 in both profiles. */
1203 static unsigned both_zero_cnt
;
1205 /* Extract the basename of the filename NAME. */
1208 extract_file_basename (const char *name
)
1212 char *path
= xstrdup (name
);
1215 sep_str
[0] = DIR_SEPARATOR
;
1217 str
= strstr(path
, sep_str
);
1219 len
= strlen(str
) + 1;
1220 path
= &path
[strlen(path
) - len
+ 2];
1221 str
= strstr(path
, sep_str
);
1227 /* Utility function to get the filename. */
1230 get_file_basename (const char *name
)
1232 if (overlap_use_fullname
)
1234 return extract_file_basename (name
);
1237 /* A utility function to set the flag for the gcda files. */
1240 set_flag (struct overlap_t
*e
)
1246 unique_gcda_files
[1]++;
1252 if (gcov_info_count_all_zero (e
->obj1
))
1254 zero_gcda_files
[0]++;
1258 if (gcov_info_count_all_cold (e
->obj1
, overlap_sum_1
1259 * overlap_hot_threshold
))
1261 cold_gcda_files
[0]++;
1266 hot_gcda_files
[0]++;
1273 unique_gcda_files
[0]++;
1279 if (gcov_info_count_all_zero (e
->obj2
))
1281 zero_gcda_files
[1]++;
1285 if (gcov_info_count_all_cold (e
->obj2
, overlap_sum_2
1286 * overlap_hot_threshold
))
1288 cold_gcda_files
[1]++;
1293 hot_gcda_files
[1]++;
1302 /* Test if INFO1 and INFO2 are from the matched source file.
1303 Return 1 if they match; return 0 otherwise. */
1306 matched_gcov_info (const struct gcov_info
*info1
, const struct gcov_info
*info2
)
1308 /* For FDO, we have to match the name. This can be expensive.
1309 Maybe we should use hash here. */
1310 if (strcmp (info1
->filename
, info2
->filename
))
1313 if (info1
->n_functions
!= info2
->n_functions
)
1315 fnotice (stderr
, "mismatched profiles in %s (%d functions"
1316 " vs %d functions)\n",
1319 info2
->n_functions
);
1325 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1326 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1327 match and 1.0 meaning a perfect match. */
1330 calculate_overlap (struct gcov_info
*gcov_list1
,
1331 struct gcov_info
*gcov_list2
)
1333 unsigned list1_cnt
= 0, list2_cnt
= 0, all_cnt
;
1335 const struct gcov_info
*gi_ptr
;
1336 struct overlap_t
*all_infos
;
1338 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1340 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1342 all_cnt
= list1_cnt
+ list2_cnt
;
1343 all_infos
= (struct overlap_t
*) xmalloc (sizeof (struct overlap_t
)
1345 gcc_assert (all_infos
);
1348 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1350 all_infos
[i
].obj1
= gi_ptr
;
1351 all_infos
[i
].obj2
= 0;
1354 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1356 all_infos
[i
].obj1
= 0;
1357 all_infos
[i
].obj2
= gi_ptr
;
1360 for (i
= list1_cnt
; i
< all_cnt
; i
++)
1362 if (all_infos
[i
].obj2
== 0)
1364 for (j
= 0; j
< list1_cnt
; j
++)
1366 if (all_infos
[j
].obj2
!= 0)
1368 if (matched_gcov_info (all_infos
[i
].obj2
, all_infos
[j
].obj1
))
1370 all_infos
[j
].obj2
= all_infos
[i
].obj2
;
1371 all_infos
[i
].obj2
= 0;
1377 for (i
= 0; i
< all_cnt
; i
++)
1378 if (all_infos
[i
].obj1
|| all_infos
[i
].obj2
)
1380 set_flag (all_infos
+ i
);
1381 if (FLAG_ONE_HOT (all_infos
[i
].flag
))
1383 if (FLAG_BOTH_COLD(all_infos
[i
].flag
))
1385 if (FLAG_BOTH_ZERO(all_infos
[i
].flag
))
1391 double sum_cum_1
= 0;
1392 double sum_cum_2
= 0;
1394 for (i
= 0; i
< all_cnt
; i
++)
1397 double cum_1
, cum_2
;
1398 const char *filename
;
1400 if (all_infos
[i
].obj1
== 0 && all_infos
[i
].obj2
== 0)
1402 if (FLAG_BOTH_ZERO (all_infos
[i
].flag
))
1405 if (all_infos
[i
].obj1
)
1406 filename
= get_file_basename (all_infos
[i
].obj1
->filename
);
1408 filename
= get_file_basename (all_infos
[i
].obj2
->filename
);
1410 if (overlap_func_level
)
1411 printf("\n processing %36s:\n", filename
);
1413 val
= compute_one_gcov (all_infos
[i
].obj1
, all_infos
[i
].obj2
,
1414 overlap_sum_1
, overlap_sum_2
, &cum_1
, &cum_2
);
1416 if (overlap_obj_level
&& (!overlap_hot_only
|| FLAG_ONE_HOT (all_infos
[i
].flag
)))
1418 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1419 filename
, val
*100, cum_1
*100, cum_2
*100);
1431 if (overlap_obj_level
)
1432 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1433 "", sum_val
*100, sum_cum_1
*100, sum_cum_2
*100);
1435 printf (" Statistics:\n"
1436 " profile1_# profile2_# overlap_#\n");
1437 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files
[0], gcda_files
[1],
1438 gcda_files
[0]-unique_gcda_files
[0]);
1439 printf (" unique files: %12u\t%12u\n", unique_gcda_files
[0],
1440 unique_gcda_files
[1]);
1441 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files
[0],
1442 hot_gcda_files
[1], both_hot_cnt
);
1443 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files
[0],
1444 cold_gcda_files
[1], both_cold_cnt
);
1445 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files
[0],
1446 zero_gcda_files
[1], both_zero_cnt
);
1451 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1453 Return 0 on success: without mismatch. Reutrn 1 on error. */
1456 gcov_profile_overlap (struct gcov_info
*profile1
, struct gcov_info
*profile2
)
1460 result
= calculate_overlap (profile1
, profile2
);
1464 printf("\nProgram level overlap result is %3.2f%%\n\n", result
*100);