1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2020 Free Software Foundation, Inc.
4 Contributed by Rong Xu <xur@google.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
28 #define IN_GCOV_TOOL 1
32 #include "diagnostic.h"
37 /* Borrowed from basic-block.h. */
38 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
40 extern gcov_position_t
gcov_position();
41 extern int gcov_is_error();
43 /* Verbose mode for debug. */
46 /* Set verbose flag. */
47 void gcov_set_verbose (void)
52 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
60 static void tag_function (unsigned, unsigned);
61 static void tag_blocks (unsigned, unsigned);
62 static void tag_arcs (unsigned, unsigned);
63 static void tag_lines (unsigned, unsigned);
64 static void tag_counters (unsigned, unsigned);
65 static void tag_summary (unsigned, unsigned);
67 /* The gcov_info for the first module. */
68 static struct gcov_info
*curr_gcov_info
;
69 /* The gcov_info being processed. */
70 static struct gcov_info
*gcov_info_head
;
71 /* This variable contains all the functions in current module. */
72 static struct obstack fn_info
;
73 /* The function being processed. */
74 static struct gcov_fn_info
*curr_fn_info
;
75 /* The number of functions seen so far. */
76 static unsigned num_fn_info
;
77 /* This variable contains all the counters for current module. */
78 static int k_ctrs_mask
[GCOV_COUNTERS
];
79 /* The kind of counters that have been seen. */
80 static struct gcov_ctr_info k_ctrs
[GCOV_COUNTERS
];
81 /* Number of kind of counters that have been seen. */
82 static int k_ctrs_types
;
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, unsigned);
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
, unsigned length ATTRIBUTE_UNUSED
)
145 /* write out previous fn_info. */
148 set_fn_ctrs (curr_fn_info
);
149 obstack_ptr_grow (&fn_info
, curr_fn_info
);
152 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
154 curr_fn_info
= (struct gcov_fn_info
*) xcalloc (sizeof (struct gcov_fn_info
)
155 + GCOV_COUNTERS
* sizeof (struct gcov_ctr_info
), 1);
157 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
161 curr_fn_info
->key
= curr_gcov_info
;
162 curr_fn_info
->ident
= gcov_read_unsigned ();
163 curr_fn_info
->lineno_checksum
= gcov_read_unsigned ();
164 curr_fn_info
->cfg_checksum
= gcov_read_unsigned ();
168 fnotice (stdout
, "tag one function id=%d\n", curr_fn_info
->ident
);
171 /* Handler for reading block tag. */
174 tag_blocks (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
176 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
180 /* Handler for reading flow arc tag. */
183 tag_arcs (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
185 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
189 /* Handler for reading line tag. */
192 tag_lines (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
194 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
198 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
201 tag_counters (unsigned tag
, unsigned length
)
203 unsigned n_counts
= GCOV_TAG_COUNTER_NUM (length
);
208 tag_ix
= GCOV_COUNTER_FOR_TAG (tag
);
209 gcc_assert (tag_ix
< GCOV_COUNTERS
);
210 k_ctrs_mask
[tag_ix
] = 1;
211 gcc_assert (k_ctrs
[tag_ix
].num
== 0);
212 k_ctrs
[tag_ix
].num
= n_counts
;
214 k_ctrs
[tag_ix
].values
= values
= (gcov_type
*) xmalloc (n_counts
* sizeof (gcov_type
));
217 for (ix
= 0; ix
!= n_counts
; ix
++)
218 values
[ix
] = gcov_read_counter ();
221 /* Handler for reading summary tag. */
224 tag_summary (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
226 gcov_read_summary (&curr_gcov_info
->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, functions
242 obj_info
->n_functions
= num_fn_info
;
243 obj_info
->functions
= (struct gcov_fn_info
**) obstack_finish (&fn_info
);
245 /* wrap all the counter array. */
246 for (i
=0; i
< GCOV_COUNTERS
; i
++)
249 obj_info
->merge
[i
] = ctr_merge_functions
[i
];
253 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
254 Program level summary CURRENT_SUMMARY will also be updated. */
256 static struct gcov_info
*
257 read_gcda_file (const char *filename
)
262 struct gcov_info
*obj_info
;
265 for (i
=0; i
< GCOV_COUNTERS
; i
++)
269 if (!gcov_open (filename
))
271 fnotice (stderr
, "%s:cannot open\n", filename
);
276 if (!gcov_magic (gcov_read_unsigned (), 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 %qx is invalid", 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 %qx is incorrectly nested",
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",
361 filename
, actual_length
- length
);
362 else if (length
> actual_length
)
363 warning (0, "%s:record size mismatch %lu bytes unread",
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" :
371 "%s:read error at %lu", filename
,
372 (long unsigned) gcov_position ());
377 read_gcda_finalize (obj_info
);
384 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
385 Return a non-zero value to stop the tree walk. */
388 ftw_read_file (const char *filename
,
389 const struct stat
*status ATTRIBUTE_UNUSED
,
394 struct gcov_info
*obj_info
;
396 /* Only read regular files. */
400 filename_len
= strlen (filename
);
401 suffix_len
= strlen (GCOV_DATA_SUFFIX
);
403 if (filename_len
<= suffix_len
)
406 if (strcmp(filename
+ filename_len
- suffix_len
, GCOV_DATA_SUFFIX
))
410 fnotice (stderr
, "reading file: %s\n", filename
);
412 obj_info
= read_gcda_file (filename
);
416 obj_info
->next
= gcov_info_head
;
417 gcov_info_head
= obj_info
;
423 /* Initializer for reading a profile dir. */
426 read_profile_dir_init (void)
431 /* Driver for read a profile directory and convert into gcov_info list in memory.
432 Return NULL on error,
433 Return the head of gcov_info list on success. */
436 gcov_read_profile_dir (const char* dir_name
, int recompute_summary ATTRIBUTE_UNUSED
)
441 read_profile_dir_init ();
443 if (access (dir_name
, R_OK
) != 0)
445 fnotice (stderr
, "cannot access directory %s\n", dir_name
);
448 pwd
= getcwd (NULL
, 0);
450 ret
= chdir (dir_name
);
453 fnotice (stderr
, "%s is not a directory\n", dir_name
);
457 ftw (".", ftw_read_file
, 50);
462 return gcov_info_head
;;
465 /* This part of the code is to merge profile counters. These
466 variables are set in merge_wrapper and to be used by
467 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
469 /* We save the counter value address to this variable. */
470 static gcov_type
*gcov_value_buf
;
472 /* The number of counter values to be read by current merging. */
473 static gcov_unsigned_t gcov_value_buf_size
;
475 /* The index of counter values being read. */
476 static gcov_unsigned_t gcov_value_buf_pos
;
478 /* The weight of current merging. */
479 static unsigned gcov_merge_weight
;
481 /* Read a counter value from gcov_value_buf array. */
484 gcov_read_counter_mem (void)
487 gcc_assert (gcov_value_buf_pos
< gcov_value_buf_size
);
488 ret
= *(gcov_value_buf
+ gcov_value_buf_pos
);
489 ++gcov_value_buf_pos
;
493 /* Return the recorded merge weight. */
496 gcov_get_merge_weight (void)
498 return gcov_merge_weight
;
501 /* A wrapper function for merge functions. It sets up the
502 value buffer and weights and then calls the merge function. */
505 merge_wrapper (gcov_merge_fn f
, gcov_type
*v1
, gcov_unsigned_t n1
,
506 gcov_type
*v2
, gcov_unsigned_t n2
, unsigned w
)
509 gcov_value_buf_pos
= 0;
510 gcov_value_buf_size
= n2
;
511 gcov_merge_weight
= w
;
515 /* Convert on disk representation of a TOPN counter to in memory representation
516 that is expected from __gcov_merge_topn function. */
519 topn_to_memory_representation (struct gcov_ctr_info
*info
)
521 auto_vec
<gcov_type
> output
;
522 gcov_type
*values
= info
->values
;
523 int count
= info
->num
;
527 output
.safe_push (values
[0]);
528 gcov_type n
= values
[1];
529 output
.safe_push (n
);
532 struct gcov_kvp
*tuples
533 = (struct gcov_kvp
*)xcalloc (sizeof (struct gcov_kvp
), n
);
534 for (unsigned i
= 0; i
< n
- 1; i
++)
535 tuples
[i
].next
= &tuples
[i
+ 1];
536 for (unsigned i
= 0; i
< n
; i
++)
538 tuples
[i
].value
= values
[2 + 2 * i
];
539 tuples
[i
].count
= values
[2 + 2 * i
+ 1];
541 output
.safe_push ((intptr_t)&tuples
[0]);
544 output
.safe_push (0);
546 unsigned len
= 2 * n
+ 2;
550 gcc_assert (count
== 0);
552 /* Allocate new buffer and copy it there. */
553 info
->num
= output
.length ();
554 info
->values
= (gcov_type
*)xmalloc (sizeof (gcov_type
) * info
->num
);
555 for (unsigned i
= 0; i
< info
->num
; i
++)
556 info
->values
[i
] = output
[i
];
559 /* Offline tool to manipulate profile data.
560 This tool targets on matched profiles. But it has some tolerance on
562 When merging p1 to p2 (p2 is the dst),
563 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
565 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
566 specified weight; emit warning.
567 * m.gcda in both p1 and p2:
568 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
569 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
571 drop p1->m.gcda->f. A warning is emitted. */
573 /* Add INFO2's counter to INFO1, multiplying by weight W. */
576 gcov_merge (struct gcov_info
*info1
, struct gcov_info
*info2
, int w
)
579 unsigned n_functions
= info1
->n_functions
;
580 int has_mismatch
= 0;
582 gcc_assert (info2
->n_functions
== n_functions
);
585 info1
->summary
.runs
+= info2
->summary
.runs
;
586 info1
->summary
.sum_max
+= info2
->summary
.sum_max
;
588 for (f_ix
= 0; f_ix
< n_functions
; f_ix
++)
591 struct gcov_fn_info
*gfi_ptr1
= info1
->functions
[f_ix
];
592 struct gcov_fn_info
*gfi_ptr2
= info2
->functions
[f_ix
];
593 struct gcov_ctr_info
*ci_ptr1
, *ci_ptr2
;
595 if (!gfi_ptr1
|| gfi_ptr1
->key
!= info1
)
597 if (!gfi_ptr2
|| gfi_ptr2
->key
!= info2
)
600 if (gfi_ptr1
->cfg_checksum
!= gfi_ptr2
->cfg_checksum
)
602 fnotice (stderr
, "in %s, cfg_checksum mismatch, skipping\n",
607 ci_ptr1
= gfi_ptr1
->ctrs
;
608 ci_ptr2
= gfi_ptr2
->ctrs
;
609 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
611 gcov_merge_fn merge1
= info1
->merge
[t_ix
];
612 gcov_merge_fn merge2
= info2
->merge
[t_ix
];
614 gcc_assert (merge1
== merge2
);
618 if (merge1
== __gcov_merge_topn
)
619 topn_to_memory_representation (ci_ptr1
);
621 gcc_assert (ci_ptr1
->num
== ci_ptr2
->num
);
623 merge_wrapper (merge1
, ci_ptr1
->values
, ci_ptr1
->num
,
624 ci_ptr2
->values
, ci_ptr2
->num
, w
);
633 /* Find and return the match gcov_info object for INFO from ARRAY.
634 SIZE is the length of ARRAY.
635 Return NULL if there is no match. */
637 static struct gcov_info
*
638 find_match_gcov_info (struct gcov_info
**array
, int size
,
639 struct gcov_info
*info
)
641 struct gcov_info
*gi_ptr
;
642 struct gcov_info
*ret
= NULL
;
645 for (i
= 0; i
< size
; i
++)
650 if (!strcmp (gi_ptr
->filename
, info
->filename
))
658 if (ret
&& ret
->n_functions
!= info
->n_functions
)
660 fnotice (stderr
, "mismatched profiles in %s (%d functions"
661 " vs %d functions)\n",
670 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
671 Return 0 on success: without mismatch.
672 Reutrn 1 on error. */
675 gcov_profile_merge (struct gcov_info
*tgt_profile
, struct gcov_info
*src_profile
,
678 struct gcov_info
*gi_ptr
;
679 struct gcov_info
**tgt_infos
;
680 struct gcov_info
*tgt_tail
;
681 struct gcov_info
**in_src_not_tgt
;
682 unsigned tgt_cnt
= 0, src_cnt
= 0;
683 unsigned unmatch_info_cnt
= 0;
686 for (gi_ptr
= tgt_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
688 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
690 tgt_infos
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
692 gcc_assert (tgt_infos
);
693 in_src_not_tgt
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
695 gcc_assert (in_src_not_tgt
);
697 for (gi_ptr
= tgt_profile
, i
= 0; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
698 tgt_infos
[i
] = gi_ptr
;
700 tgt_tail
= tgt_infos
[tgt_cnt
- 1];
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);
729 tgt_tail
->next
= gi_ptr
;
733 free (in_src_not_tgt
);
739 typedef gcov_type (*counter_op_fn
) (gcov_type
, void*, void*);
741 /* Performing FN upon arc counters. */
744 __gcov_add_counter_op (gcov_type
*counters
, unsigned n_counters
,
745 counter_op_fn fn
, void *data1
, void *data2
)
747 for (; n_counters
; counters
++, n_counters
--)
749 gcov_type val
= *counters
;
750 *counters
= fn(val
, data1
, data2
);
754 /* Performing FN upon ior counters. */
757 __gcov_ior_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
758 unsigned n_counters ATTRIBUTE_UNUSED
,
759 counter_op_fn fn ATTRIBUTE_UNUSED
,
760 void *data1 ATTRIBUTE_UNUSED
,
761 void *data2 ATTRIBUTE_UNUSED
)
766 /* Performing FN upon time-profile counters. */
769 __gcov_time_profile_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
770 unsigned n_counters ATTRIBUTE_UNUSED
,
771 counter_op_fn fn ATTRIBUTE_UNUSED
,
772 void *data1 ATTRIBUTE_UNUSED
,
773 void *data2 ATTRIBUTE_UNUSED
)
778 /* Performing FN upon TOP N counters. */
781 __gcov_topn_counter_op (gcov_type
*counters
, unsigned n_counters
,
782 counter_op_fn fn
, void *data1
, void *data2
)
784 unsigned i
, n_measures
;
786 gcc_assert (!(n_counters
% 3));
787 n_measures
= n_counters
/ 3;
788 for (i
= 0; i
< n_measures
; i
++, counters
+= 3)
790 counters
[1] = fn (counters
[1], data1
, data2
);
791 counters
[2] = fn (counters
[2], data1
, data2
);
795 /* Scaling the counter value V by multiplying *(float*) DATA1. */
798 fp_scale (gcov_type v
, void *data1
, void *data2 ATTRIBUTE_UNUSED
)
800 float f
= *(float *) data1
;
801 return (gcov_type
) (v
* f
);
804 /* Scaling the counter value V by multiplying DATA2/DATA1. */
807 int_scale (gcov_type v
, void *data1
, void *data2
)
809 int n
= *(int *) data1
;
810 int d
= *(int *) data2
;
811 return (gcov_type
) ( RDIV (v
,d
) * n
);
814 /* Type of function used to process counters. */
815 typedef void (*gcov_counter_fn
) (gcov_type
*, gcov_unsigned_t
,
816 counter_op_fn
, void *, void *);
818 /* Function array to process profile counters. */
819 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
820 __gcov ## FN_TYPE ## _counter_op,
821 static gcov_counter_fn ctr_functions
[GCOV_COUNTERS
] = {
822 #include "gcov-counter.def"
824 #undef DEF_GCOV_COUNTER
826 /* Driver for scaling profile counters. */
829 gcov_profile_scale (struct gcov_info
*profile
, float scale_factor
, int n
, int d
)
831 struct gcov_info
*gi_ptr
;
835 fnotice (stdout
, "scale_factor is %f or %d/%d\n", scale_factor
, n
, d
);
837 /* Scaling the counters. */
838 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
839 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
842 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
843 const struct gcov_ctr_info
*ci_ptr
;
845 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
848 ci_ptr
= gfi_ptr
->ctrs
;
849 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
851 gcov_merge_fn merge
= gi_ptr
->merge
[t_ix
];
856 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
857 fp_scale
, &scale_factor
, NULL
);
859 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
868 /* Driver to normalize profile counters. */
871 gcov_profile_normalize (struct gcov_info
*profile
, gcov_type max_val
)
873 struct gcov_info
*gi_ptr
;
874 gcov_type curr_max_val
= 0;
879 /* Find the largest count value. */
880 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
881 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
884 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
885 const struct gcov_ctr_info
*ci_ptr
;
887 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
890 ci_ptr
= gfi_ptr
->ctrs
;
891 for (t_ix
= 0; t_ix
< 1; t_ix
++)
893 for (i
= 0; i
< ci_ptr
->num
; i
++)
894 if (ci_ptr
->values
[i
] > curr_max_val
)
895 curr_max_val
= ci_ptr
->values
[i
];
900 scale_factor
= (float)max_val
/ curr_max_val
;
902 fnotice (stdout
, "max_val is %" PRId64
"\n", curr_max_val
);
904 return gcov_profile_scale (profile
, scale_factor
, 0, 0);
907 /* The following variables are defined in gcc/gcov-tool.c. */
908 extern int overlap_func_level
;
909 extern int overlap_obj_level
;
910 extern int overlap_hot_only
;
911 extern int overlap_use_fullname
;
912 extern double overlap_hot_threshold
;
914 /* Compute the overlap score of two values. The score is defined as:
915 min (V1/SUM_1, V2/SUM_2) */
918 calculate_2_entries (const unsigned long v1
, const unsigned long v2
,
919 const double sum_1
, const double sum_2
)
921 double val1
= (sum_1
== 0.0 ? 0.0 : v1
/sum_1
);
922 double val2
= (sum_2
== 0.0 ? 0.0 : v2
/sum_2
);
930 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
931 This function also updates cumulative score CUM_1_RESULT and
935 compute_one_gcov (const struct gcov_info
*gcov_info1
,
936 const struct gcov_info
*gcov_info2
,
937 const double sum_1
, const double sum_2
,
938 double *cum_1_result
, double *cum_2_result
)
942 double cum_1
= 0, cum_2
= 0;
943 const struct gcov_info
*gcov_info
= 0;
947 gcc_assert (gcov_info1
|| gcov_info2
);
950 gcov_info
= gcov_info2
;
951 cum_p
= cum_2_result
;
957 gcov_info
= gcov_info1
;
958 cum_p
= cum_1_result
;
965 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
967 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
968 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
970 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
972 for (c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
973 cum_1
+= ci_ptr
->values
[c_num
] / sum
;
979 for (f_ix
= 0; f_ix
< gcov_info1
->n_functions
; f_ix
++)
981 double func_cum_1
= 0.0;
982 double func_cum_2
= 0.0;
983 double func_val
= 0.0;
986 const struct gcov_fn_info
*gfi_ptr1
= gcov_info1
->functions
[f_ix
];
987 const struct gcov_fn_info
*gfi_ptr2
= gcov_info2
->functions
[f_ix
];
989 if (!gfi_ptr1
|| gfi_ptr1
->key
!= gcov_info1
)
991 if (!gfi_ptr2
|| gfi_ptr2
->key
!= gcov_info2
)
994 const struct gcov_ctr_info
*ci_ptr1
= gfi_ptr1
->ctrs
;
995 const struct gcov_ctr_info
*ci_ptr2
= gfi_ptr2
->ctrs
;
997 for (c_num
= 0; c_num
< ci_ptr1
->num
; c_num
++)
999 if (ci_ptr1
->values
[c_num
] | ci_ptr2
->values
[c_num
])
1001 func_val
+= calculate_2_entries (ci_ptr1
->values
[c_num
],
1002 ci_ptr2
->values
[c_num
],
1005 func_cum_1
+= ci_ptr1
->values
[c_num
] / sum_1
;
1006 func_cum_2
+= ci_ptr2
->values
[c_num
] / sum_2
;
1008 if (ci_ptr1
->values
[c_num
] / sum_1
>= overlap_hot_threshold
1009 || ci_ptr2
->values
[c_num
] / sum_2
>= overlap_hot_threshold
)
1015 cum_1
+= func_cum_1
;
1016 cum_2
+= func_cum_2
;
1017 if (overlap_func_level
&& nonzero
&& (!overlap_hot_only
|| hot
))
1019 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1020 gfi_ptr1
->ident
, func_val
*100, func_cum_1
*100, func_cum_2
*100);
1023 *cum_1_result
= cum_1
;
1024 *cum_2_result
= cum_2
;
1028 /* Test if all counter values in this GCOV_INFO are cold.
1029 "Cold" is defined as the counter value being less than
1030 or equal to THRESHOLD. */
1033 gcov_info_count_all_cold (const struct gcov_info
*gcov_info
,
1034 gcov_type threshold
)
1038 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
1040 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
1042 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
1044 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
1045 for (unsigned c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
1046 if (ci_ptr
->values
[c_num
] > threshold
)
1053 /* Test if all counter values in this GCOV_INFO are 0. */
1056 gcov_info_count_all_zero (const struct gcov_info
*gcov_info
)
1058 return gcov_info_count_all_cold (gcov_info
, 0);
1061 /* A pair of matched GCOV_INFO.
1062 The flag is a bitvector:
1063 b0: obj1's all counts are 0;
1064 b1: obj1's all counts are cold (but no 0);
1066 b3: no obj1 to match obj2;
1067 b4: obj2's all counts are 0;
1068 b5: obj2's all counts are cold (but no 0);
1070 b7: no obj2 to match obj1;
1073 const struct gcov_info
*obj1
;
1074 const struct gcov_info
*obj2
;
1078 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1079 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1080 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1082 /* Cumlative overlap dscore for profile1 and profile2. */
1083 static double overlap_sum_1
, overlap_sum_2
;
1085 /* The number of gcda files in the profiles. */
1086 static unsigned gcda_files
[2];
1088 /* The number of unique gcda files in the profiles
1089 (not existing in the other profile). */
1090 static unsigned unique_gcda_files
[2];
1092 /* The number of gcda files that all counter values are 0. */
1093 static unsigned zero_gcda_files
[2];
1095 /* The number of gcda files that all counter values are cold (but not 0). */
1096 static unsigned cold_gcda_files
[2];
1098 /* The number of gcda files that includes hot counter values. */
1099 static unsigned hot_gcda_files
[2];
1101 /* The number of gcda files with hot count value in either profiles. */
1102 static unsigned both_hot_cnt
;
1104 /* The number of gcda files with all counts cold (but not 0) in
1106 static unsigned both_cold_cnt
;
1108 /* The number of gcda files with all counts 0 in both profiles. */
1109 static unsigned both_zero_cnt
;
1111 /* Extract the basename of the filename NAME. */
1114 extract_file_basename (const char *name
)
1118 char *path
= xstrdup (name
);
1121 sep_str
[0] = DIR_SEPARATOR
;
1123 str
= strstr(path
, sep_str
);
1125 len
= strlen(str
) + 1;
1126 path
= &path
[strlen(path
) - len
+ 2];
1127 str
= strstr(path
, sep_str
);
1133 /* Utility function to get the filename. */
1136 get_file_basename (const char *name
)
1138 if (overlap_use_fullname
)
1140 return extract_file_basename (name
);
1143 /* A utility function to set the flag for the gcda files. */
1146 set_flag (struct overlap_t
*e
)
1152 unique_gcda_files
[1]++;
1158 if (gcov_info_count_all_zero (e
->obj1
))
1160 zero_gcda_files
[0]++;
1164 if (gcov_info_count_all_cold (e
->obj1
, overlap_sum_1
1165 * overlap_hot_threshold
))
1167 cold_gcda_files
[0]++;
1172 hot_gcda_files
[0]++;
1179 unique_gcda_files
[0]++;
1185 if (gcov_info_count_all_zero (e
->obj2
))
1187 zero_gcda_files
[1]++;
1191 if (gcov_info_count_all_cold (e
->obj2
, overlap_sum_2
1192 * overlap_hot_threshold
))
1194 cold_gcda_files
[1]++;
1199 hot_gcda_files
[1]++;
1208 /* Test if INFO1 and INFO2 are from the matched source file.
1209 Return 1 if they match; return 0 otherwise. */
1212 matched_gcov_info (const struct gcov_info
*info1
, const struct gcov_info
*info2
)
1214 /* For FDO, we have to match the name. This can be expensive.
1215 Maybe we should use hash here. */
1216 if (strcmp (info1
->filename
, info2
->filename
))
1219 if (info1
->n_functions
!= info2
->n_functions
)
1221 fnotice (stderr
, "mismatched profiles in %s (%d functions"
1222 " vs %d functions)\n",
1225 info2
->n_functions
);
1231 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1232 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1233 match and 1.0 meaning a perfect match. */
1236 calculate_overlap (struct gcov_info
*gcov_list1
,
1237 struct gcov_info
*gcov_list2
)
1239 unsigned list1_cnt
= 0, list2_cnt
= 0, all_cnt
;
1241 const struct gcov_info
*gi_ptr
;
1242 struct overlap_t
*all_infos
;
1244 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1246 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1248 all_cnt
= list1_cnt
+ list2_cnt
;
1249 all_infos
= (struct overlap_t
*) xmalloc (sizeof (struct overlap_t
)
1251 gcc_assert (all_infos
);
1254 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1256 all_infos
[i
].obj1
= gi_ptr
;
1257 all_infos
[i
].obj2
= 0;
1260 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1262 all_infos
[i
].obj1
= 0;
1263 all_infos
[i
].obj2
= gi_ptr
;
1266 for (i
= list1_cnt
; i
< all_cnt
; i
++)
1268 if (all_infos
[i
].obj2
== 0)
1270 for (j
= 0; j
< list1_cnt
; j
++)
1272 if (all_infos
[j
].obj2
!= 0)
1274 if (matched_gcov_info (all_infos
[i
].obj2
, all_infos
[j
].obj1
))
1276 all_infos
[j
].obj2
= all_infos
[i
].obj2
;
1277 all_infos
[i
].obj2
= 0;
1283 for (i
= 0; i
< all_cnt
; i
++)
1284 if (all_infos
[i
].obj1
|| all_infos
[i
].obj2
)
1286 set_flag (all_infos
+ i
);
1287 if (FLAG_ONE_HOT (all_infos
[i
].flag
))
1289 if (FLAG_BOTH_COLD(all_infos
[i
].flag
))
1291 if (FLAG_BOTH_ZERO(all_infos
[i
].flag
))
1297 double sum_cum_1
= 0;
1298 double sum_cum_2
= 0;
1300 for (i
= 0; i
< all_cnt
; i
++)
1303 double cum_1
, cum_2
;
1304 const char *filename
;
1306 if (all_infos
[i
].obj1
== 0 && all_infos
[i
].obj2
== 0)
1308 if (FLAG_BOTH_ZERO (all_infos
[i
].flag
))
1311 if (all_infos
[i
].obj1
)
1312 filename
= get_file_basename (all_infos
[i
].obj1
->filename
);
1314 filename
= get_file_basename (all_infos
[i
].obj2
->filename
);
1316 if (overlap_func_level
)
1317 printf("\n processing %36s:\n", filename
);
1319 val
= compute_one_gcov (all_infos
[i
].obj1
, all_infos
[i
].obj2
,
1320 overlap_sum_1
, overlap_sum_2
, &cum_1
, &cum_2
);
1322 if (overlap_obj_level
&& (!overlap_hot_only
|| FLAG_ONE_HOT (all_infos
[i
].flag
)))
1324 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1325 filename
, val
*100, cum_1
*100, cum_2
*100);
1337 if (overlap_obj_level
)
1338 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1339 "", sum_val
*100, sum_cum_1
*100, sum_cum_2
*100);
1341 printf (" Statistics:\n"
1342 " profile1_# profile2_# overlap_#\n");
1343 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files
[0], gcda_files
[1],
1344 gcda_files
[0]-unique_gcda_files
[0]);
1345 printf (" unique files: %12u\t%12u\n", unique_gcda_files
[0],
1346 unique_gcda_files
[1]);
1347 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files
[0],
1348 hot_gcda_files
[1], both_hot_cnt
);
1349 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files
[0],
1350 cold_gcda_files
[1], both_cold_cnt
);
1351 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files
[0],
1352 zero_gcda_files
[1], both_zero_cnt
);
1357 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1359 Return 0 on success: without mismatch. Reutrn 1 on error. */
1362 gcov_profile_overlap (struct gcov_info
*profile1
, struct gcov_info
*profile2
)
1366 result
= calculate_overlap (profile1
, profile2
);
1370 printf("\nProgram level overlap result is %3.2f%%\n\n", result
*100);