1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2021 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
++)
271 if (!gcov_open (filename
))
273 fnotice (stderr
, "%s:cannot open\n", filename
);
278 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC
))
280 fnotice (stderr
, "%s:not a gcov data file\n", filename
);
286 version
= gcov_read_unsigned ();
287 if (version
!= GCOV_VERSION
)
289 fnotice (stderr
, "%s:incorrect gcov version %d vs %d \n", filename
, version
, GCOV_VERSION
);
294 /* Instantiate a gcov_info object. */
295 curr_gcov_info
= obj_info
= (struct gcov_info
*) xcalloc (sizeof (struct gcov_info
) +
296 sizeof (struct gcov_ctr_info
) * GCOV_COUNTERS
, 1);
298 obj_info
->version
= version
;
299 obstack_init (&fn_info
);
303 size_t len
= strlen (filename
) + 1;
304 char *str_dup
= (char*) xmalloc (len
);
306 memcpy (str_dup
, filename
, len
);
307 obj_info
->filename
= str_dup
;
311 obj_info
->stamp
= gcov_read_unsigned ();
314 obj_info
->checksum
= gcov_read_unsigned ();
318 gcov_position_t base
;
319 unsigned tag
, length
;
320 tag_format_t
const *format
;
325 tag
= gcov_read_unsigned ();
328 int read_length
= (int)gcov_read_unsigned ();
329 length
= read_length
> 0 ? read_length
: 0;
330 base
= gcov_position ();
331 mask
= GCOV_TAG_MASK (tag
) >> 1;
332 for (tag_depth
= 4; mask
; mask
>>= 8)
334 if (((mask
& 0xff) != 0xff))
336 warning (0, "%s:tag %qx is invalid", filename
, tag
);
341 for (format
= tag_table
; format
->name
; format
++)
342 if (format
->tag
== tag
)
344 format
= &tag_table
[GCOV_TAG_IS_COUNTER (tag
) ? 2 : 1];
348 if (depth
&& depth
< tag_depth
)
350 if (!GCOV_TAG_IS_SUBTAG (tags
[depth
- 1], tag
))
351 warning (0, "%s:tag %qx is incorrectly nested",
355 tags
[depth
- 1] = tag
;
360 unsigned long actual_length
;
362 (*format
->proc
) (tag
, read_length
);
364 actual_length
= gcov_position () - base
;
365 if (actual_length
> length
)
366 warning (0, "%s:record size mismatch %lu bytes overread",
367 filename
, actual_length
- length
);
368 else if (length
> actual_length
)
369 warning (0, "%s:record size mismatch %lu bytes unread",
370 filename
, length
- actual_length
);
373 gcov_sync (base
, length
);
374 if ((error
= gcov_is_error ()))
376 warning (0, error
< 0 ? "%s:counter overflow at %lu" :
377 "%s:read error at %lu", filename
,
378 (long unsigned) gcov_position ());
383 read_gcda_finalize (obj_info
);
390 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
391 Return a non-zero value to stop the tree walk. */
394 ftw_read_file (const char *filename
,
395 const struct stat
*status ATTRIBUTE_UNUSED
,
400 struct gcov_info
*obj_info
;
402 /* Only read regular files. */
406 filename_len
= strlen (filename
);
407 suffix_len
= strlen (GCOV_DATA_SUFFIX
);
409 if (filename_len
<= suffix_len
)
412 if (strcmp(filename
+ filename_len
- suffix_len
, GCOV_DATA_SUFFIX
))
416 fnotice (stderr
, "reading file: %s\n", filename
);
418 obj_info
= read_gcda_file (filename
);
422 obj_info
->next
= gcov_info_head
;
423 gcov_info_head
= obj_info
;
429 /* Initializer for reading a profile dir. */
432 read_profile_dir_init (void)
437 /* Driver for read a profile directory and convert into gcov_info list in memory.
438 Return NULL on error,
439 Return the head of gcov_info list on success. */
442 gcov_read_profile_dir (const char* dir_name
, int recompute_summary ATTRIBUTE_UNUSED
)
447 read_profile_dir_init ();
449 if (access (dir_name
, R_OK
) != 0)
451 fnotice (stderr
, "cannot access directory %s\n", dir_name
);
454 pwd
= getcwd (NULL
, 0);
456 ret
= chdir (dir_name
);
459 fnotice (stderr
, "%s is not a directory\n", dir_name
);
463 ftw (".", ftw_read_file
, 50);
468 return gcov_info_head
;;
471 /* This part of the code is to merge profile counters. These
472 variables are set in merge_wrapper and to be used by
473 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
475 /* We save the counter value address to this variable. */
476 static gcov_type
*gcov_value_buf
;
478 /* The number of counter values to be read by current merging. */
479 static gcov_unsigned_t gcov_value_buf_size
;
481 /* The index of counter values being read. */
482 static gcov_unsigned_t gcov_value_buf_pos
;
484 /* The weight of current merging. */
485 static unsigned gcov_merge_weight
;
487 /* Read a counter value from gcov_value_buf array. */
490 gcov_read_counter_mem (void)
493 gcc_assert (gcov_value_buf_pos
< gcov_value_buf_size
);
494 ret
= *(gcov_value_buf
+ gcov_value_buf_pos
);
495 ++gcov_value_buf_pos
;
499 /* Return the recorded merge weight. */
502 gcov_get_merge_weight (void)
504 return gcov_merge_weight
;
507 /* A wrapper function for merge functions. It sets up the
508 value buffer and weights and then calls the merge function. */
511 merge_wrapper (gcov_merge_fn f
, gcov_type
*v1
, gcov_unsigned_t n1
,
512 gcov_type
*v2
, gcov_unsigned_t n2
, unsigned w
)
515 gcov_value_buf_pos
= 0;
516 gcov_value_buf_size
= n2
;
517 gcov_merge_weight
= w
;
521 /* Convert on disk representation of a TOPN counter to in memory representation
522 that is expected from __gcov_merge_topn function. */
525 topn_to_memory_representation (struct gcov_ctr_info
*info
)
527 auto_vec
<gcov_type
> output
;
528 gcov_type
*values
= info
->values
;
529 int count
= info
->num
;
533 output
.safe_push (values
[0]);
534 gcov_type n
= values
[1];
535 output
.safe_push (n
);
538 struct gcov_kvp
*tuples
539 = (struct gcov_kvp
*)xcalloc (sizeof (struct gcov_kvp
), n
);
540 for (unsigned i
= 0; i
< n
- 1; i
++)
541 tuples
[i
].next
= &tuples
[i
+ 1];
542 for (unsigned i
= 0; i
< n
; i
++)
544 tuples
[i
].value
= values
[2 + 2 * i
];
545 tuples
[i
].count
= values
[2 + 2 * i
+ 1];
547 output
.safe_push ((intptr_t)&tuples
[0]);
550 output
.safe_push (0);
552 unsigned len
= 2 * n
+ 2;
556 gcc_assert (count
== 0);
558 /* Allocate new buffer and copy it there. */
559 info
->num
= output
.length ();
560 info
->values
= (gcov_type
*)xmalloc (sizeof (gcov_type
) * info
->num
);
561 for (unsigned i
= 0; i
< info
->num
; i
++)
562 info
->values
[i
] = output
[i
];
565 /* Offline tool to manipulate profile data.
566 This tool targets on matched profiles. But it has some tolerance on
568 When merging p1 to p2 (p2 is the dst),
569 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
571 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
572 specified weight; emit warning.
573 * m.gcda in both p1 and p2:
574 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
575 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
577 drop p1->m.gcda->f. A warning is emitted. */
579 /* Add INFO2's counter to INFO1, multiplying by weight W. */
582 gcov_merge (struct gcov_info
*info1
, struct gcov_info
*info2
, int w
)
585 unsigned n_functions
= info1
->n_functions
;
586 int has_mismatch
= 0;
588 gcc_assert (info2
->n_functions
== n_functions
);
591 info1
->summary
.runs
+= info2
->summary
.runs
;
592 info1
->summary
.sum_max
+= info2
->summary
.sum_max
;
594 for (f_ix
= 0; f_ix
< n_functions
; f_ix
++)
597 struct gcov_fn_info
*gfi_ptr1
= info1
->functions
[f_ix
];
598 struct gcov_fn_info
*gfi_ptr2
= info2
->functions
[f_ix
];
599 struct gcov_ctr_info
*ci_ptr1
, *ci_ptr2
;
601 if (!gfi_ptr1
|| gfi_ptr1
->key
!= info1
)
603 if (!gfi_ptr2
|| gfi_ptr2
->key
!= info2
)
606 if (gfi_ptr1
->cfg_checksum
!= gfi_ptr2
->cfg_checksum
)
608 fnotice (stderr
, "in %s, cfg_checksum mismatch, skipping\n",
613 ci_ptr1
= gfi_ptr1
->ctrs
;
614 ci_ptr2
= gfi_ptr2
->ctrs
;
615 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
617 gcov_merge_fn merge1
= info1
->merge
[t_ix
];
618 gcov_merge_fn merge2
= info2
->merge
[t_ix
];
620 gcc_assert (merge1
== merge2
);
624 if (merge1
== __gcov_merge_topn
)
625 topn_to_memory_representation (ci_ptr1
);
627 gcc_assert (ci_ptr1
->num
== ci_ptr2
->num
);
629 merge_wrapper (merge1
, ci_ptr1
->values
, ci_ptr1
->num
,
630 ci_ptr2
->values
, ci_ptr2
->num
, w
);
639 /* Find and return the match gcov_info object for INFO from ARRAY.
640 SIZE is the length of ARRAY.
641 Return NULL if there is no match. */
643 static struct gcov_info
*
644 find_match_gcov_info (struct gcov_info
**array
, int size
,
645 struct gcov_info
*info
)
647 struct gcov_info
*gi_ptr
;
648 struct gcov_info
*ret
= NULL
;
651 for (i
= 0; i
< size
; i
++)
656 if (!strcmp (gi_ptr
->filename
, info
->filename
))
664 if (ret
&& ret
->n_functions
!= info
->n_functions
)
666 fnotice (stderr
, "mismatched profiles in %s (%d functions"
667 " vs %d functions)\n",
676 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
677 Return 0 on success: without mismatch.
678 Reutrn 1 on error. */
681 gcov_profile_merge (struct gcov_info
*tgt_profile
, struct gcov_info
*src_profile
,
684 struct gcov_info
*gi_ptr
;
685 struct gcov_info
**tgt_infos
;
686 struct gcov_info
*tgt_tail
;
687 struct gcov_info
**in_src_not_tgt
;
688 unsigned tgt_cnt
= 0, src_cnt
= 0;
689 unsigned unmatch_info_cnt
= 0;
692 for (gi_ptr
= tgt_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
694 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
696 tgt_infos
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
698 gcc_assert (tgt_infos
);
699 in_src_not_tgt
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
701 gcc_assert (in_src_not_tgt
);
703 for (gi_ptr
= tgt_profile
, i
= 0; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
704 tgt_infos
[i
] = gi_ptr
;
706 tgt_tail
= tgt_infos
[tgt_cnt
- 1];
708 /* First pass on tgt_profile, we multiply w1 to all counters. */
711 for (i
= 0; i
< tgt_cnt
; i
++)
712 gcov_merge (tgt_infos
[i
], tgt_infos
[i
], w1
-1);
715 /* Second pass, add src_profile to the tgt_profile. */
716 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
718 struct gcov_info
*gi_ptr1
;
720 gi_ptr1
= find_match_gcov_info (tgt_infos
, tgt_cnt
, gi_ptr
);
723 in_src_not_tgt
[unmatch_info_cnt
++] = gi_ptr
;
726 gcov_merge (gi_ptr1
, gi_ptr
, w2
);
729 /* For modules in src but not in tgt. We adjust the counter and append. */
730 for (i
= 0; i
< unmatch_info_cnt
; i
++)
732 gi_ptr
= in_src_not_tgt
[i
];
733 gcov_merge (gi_ptr
, gi_ptr
, w2
- 1);
735 tgt_tail
->next
= gi_ptr
;
739 free (in_src_not_tgt
);
745 typedef gcov_type (*counter_op_fn
) (gcov_type
, void*, void*);
747 /* Performing FN upon arc counters. */
750 __gcov_add_counter_op (gcov_type
*counters
, unsigned n_counters
,
751 counter_op_fn fn
, void *data1
, void *data2
)
753 for (; n_counters
; counters
++, n_counters
--)
755 gcov_type val
= *counters
;
756 *counters
= fn(val
, data1
, data2
);
760 /* Performing FN upon ior counters. */
763 __gcov_ior_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
764 unsigned n_counters ATTRIBUTE_UNUSED
,
765 counter_op_fn fn ATTRIBUTE_UNUSED
,
766 void *data1 ATTRIBUTE_UNUSED
,
767 void *data2 ATTRIBUTE_UNUSED
)
772 /* Performing FN upon time-profile counters. */
775 __gcov_time_profile_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
776 unsigned n_counters ATTRIBUTE_UNUSED
,
777 counter_op_fn fn ATTRIBUTE_UNUSED
,
778 void *data1 ATTRIBUTE_UNUSED
,
779 void *data2 ATTRIBUTE_UNUSED
)
784 /* Performing FN upon TOP N counters. */
787 __gcov_topn_counter_op (gcov_type
*counters
, unsigned n_counters
,
788 counter_op_fn fn
, void *data1
, void *data2
)
790 unsigned i
, n_measures
;
792 gcc_assert (!(n_counters
% 3));
793 n_measures
= n_counters
/ 3;
794 for (i
= 0; i
< n_measures
; i
++, counters
+= 3)
796 counters
[1] = fn (counters
[1], data1
, data2
);
797 counters
[2] = fn (counters
[2], data1
, data2
);
801 /* Scaling the counter value V by multiplying *(float*) DATA1. */
804 fp_scale (gcov_type v
, void *data1
, void *data2 ATTRIBUTE_UNUSED
)
806 float f
= *(float *) data1
;
807 return (gcov_type
) (v
* f
);
810 /* Scaling the counter value V by multiplying DATA2/DATA1. */
813 int_scale (gcov_type v
, void *data1
, void *data2
)
815 int n
= *(int *) data1
;
816 int d
= *(int *) data2
;
817 return (gcov_type
) ( RDIV (v
,d
) * n
);
820 /* Type of function used to process counters. */
821 typedef void (*gcov_counter_fn
) (gcov_type
*, gcov_unsigned_t
,
822 counter_op_fn
, void *, void *);
824 /* Function array to process profile counters. */
825 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
826 __gcov ## FN_TYPE ## _counter_op,
827 static gcov_counter_fn ctr_functions
[GCOV_COUNTERS
] = {
828 #include "gcov-counter.def"
830 #undef DEF_GCOV_COUNTER
832 /* Driver for scaling profile counters. */
835 gcov_profile_scale (struct gcov_info
*profile
, float scale_factor
, int n
, int d
)
837 struct gcov_info
*gi_ptr
;
841 fnotice (stdout
, "scale_factor is %f or %d/%d\n", scale_factor
, n
, d
);
843 /* Scaling the counters. */
844 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
845 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
848 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
849 const struct gcov_ctr_info
*ci_ptr
;
851 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
854 ci_ptr
= gfi_ptr
->ctrs
;
855 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
857 gcov_merge_fn merge
= gi_ptr
->merge
[t_ix
];
862 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
863 fp_scale
, &scale_factor
, NULL
);
865 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
874 /* Driver to normalize profile counters. */
877 gcov_profile_normalize (struct gcov_info
*profile
, gcov_type max_val
)
879 struct gcov_info
*gi_ptr
;
880 gcov_type curr_max_val
= 0;
885 /* Find the largest count value. */
886 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
887 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
890 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
891 const struct gcov_ctr_info
*ci_ptr
;
893 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
896 ci_ptr
= gfi_ptr
->ctrs
;
897 for (t_ix
= 0; t_ix
< 1; t_ix
++)
899 for (i
= 0; i
< ci_ptr
->num
; i
++)
900 if (ci_ptr
->values
[i
] > curr_max_val
)
901 curr_max_val
= ci_ptr
->values
[i
];
906 scale_factor
= (float)max_val
/ curr_max_val
;
908 fnotice (stdout
, "max_val is %" PRId64
"\n", curr_max_val
);
910 return gcov_profile_scale (profile
, scale_factor
, 0, 0);
913 /* The following variables are defined in gcc/gcov-tool.c. */
914 extern int overlap_func_level
;
915 extern int overlap_obj_level
;
916 extern int overlap_hot_only
;
917 extern int overlap_use_fullname
;
918 extern double overlap_hot_threshold
;
920 /* Compute the overlap score of two values. The score is defined as:
921 min (V1/SUM_1, V2/SUM_2) */
924 calculate_2_entries (const unsigned long v1
, const unsigned long v2
,
925 const double sum_1
, const double sum_2
)
927 double val1
= (sum_1
== 0.0 ? 0.0 : v1
/sum_1
);
928 double val2
= (sum_2
== 0.0 ? 0.0 : v2
/sum_2
);
936 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
937 This function also updates cumulative score CUM_1_RESULT and
941 compute_one_gcov (const struct gcov_info
*gcov_info1
,
942 const struct gcov_info
*gcov_info2
,
943 const double sum_1
, const double sum_2
,
944 double *cum_1_result
, double *cum_2_result
)
948 double cum_1
= 0, cum_2
= 0;
949 const struct gcov_info
*gcov_info
= 0;
953 gcc_assert (gcov_info1
|| gcov_info2
);
956 gcov_info
= gcov_info2
;
957 cum_p
= cum_2_result
;
963 gcov_info
= gcov_info1
;
964 cum_p
= cum_1_result
;
971 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
973 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
974 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
976 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
978 for (c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
979 cum_1
+= ci_ptr
->values
[c_num
] / sum
;
985 for (f_ix
= 0; f_ix
< gcov_info1
->n_functions
; f_ix
++)
987 double func_cum_1
= 0.0;
988 double func_cum_2
= 0.0;
989 double func_val
= 0.0;
992 const struct gcov_fn_info
*gfi_ptr1
= gcov_info1
->functions
[f_ix
];
993 const struct gcov_fn_info
*gfi_ptr2
= gcov_info2
->functions
[f_ix
];
995 if (!gfi_ptr1
|| gfi_ptr1
->key
!= gcov_info1
)
997 if (!gfi_ptr2
|| gfi_ptr2
->key
!= gcov_info2
)
1000 const struct gcov_ctr_info
*ci_ptr1
= gfi_ptr1
->ctrs
;
1001 const struct gcov_ctr_info
*ci_ptr2
= gfi_ptr2
->ctrs
;
1003 for (c_num
= 0; c_num
< ci_ptr1
->num
; c_num
++)
1005 if (ci_ptr1
->values
[c_num
] | ci_ptr2
->values
[c_num
])
1007 func_val
+= calculate_2_entries (ci_ptr1
->values
[c_num
],
1008 ci_ptr2
->values
[c_num
],
1011 func_cum_1
+= ci_ptr1
->values
[c_num
] / sum_1
;
1012 func_cum_2
+= ci_ptr2
->values
[c_num
] / sum_2
;
1014 if (ci_ptr1
->values
[c_num
] / sum_1
>= overlap_hot_threshold
1015 || ci_ptr2
->values
[c_num
] / sum_2
>= overlap_hot_threshold
)
1021 cum_1
+= func_cum_1
;
1022 cum_2
+= func_cum_2
;
1023 if (overlap_func_level
&& nonzero
&& (!overlap_hot_only
|| hot
))
1025 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1026 gfi_ptr1
->ident
, func_val
*100, func_cum_1
*100, func_cum_2
*100);
1029 *cum_1_result
= cum_1
;
1030 *cum_2_result
= cum_2
;
1034 /* Test if all counter values in this GCOV_INFO are cold.
1035 "Cold" is defined as the counter value being less than
1036 or equal to THRESHOLD. */
1039 gcov_info_count_all_cold (const struct gcov_info
*gcov_info
,
1040 gcov_type threshold
)
1044 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
1046 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
1048 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
1050 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
1051 for (unsigned c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
1052 if (ci_ptr
->values
[c_num
] > threshold
)
1059 /* Test if all counter values in this GCOV_INFO are 0. */
1062 gcov_info_count_all_zero (const struct gcov_info
*gcov_info
)
1064 return gcov_info_count_all_cold (gcov_info
, 0);
1067 /* A pair of matched GCOV_INFO.
1068 The flag is a bitvector:
1069 b0: obj1's all counts are 0;
1070 b1: obj1's all counts are cold (but no 0);
1072 b3: no obj1 to match obj2;
1073 b4: obj2's all counts are 0;
1074 b5: obj2's all counts are cold (but no 0);
1076 b7: no obj2 to match obj1;
1079 const struct gcov_info
*obj1
;
1080 const struct gcov_info
*obj2
;
1084 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1085 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1086 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1088 /* Cumlative overlap dscore for profile1 and profile2. */
1089 static double overlap_sum_1
, overlap_sum_2
;
1091 /* The number of gcda files in the profiles. */
1092 static unsigned gcda_files
[2];
1094 /* The number of unique gcda files in the profiles
1095 (not existing in the other profile). */
1096 static unsigned unique_gcda_files
[2];
1098 /* The number of gcda files that all counter values are 0. */
1099 static unsigned zero_gcda_files
[2];
1101 /* The number of gcda files that all counter values are cold (but not 0). */
1102 static unsigned cold_gcda_files
[2];
1104 /* The number of gcda files that includes hot counter values. */
1105 static unsigned hot_gcda_files
[2];
1107 /* The number of gcda files with hot count value in either profiles. */
1108 static unsigned both_hot_cnt
;
1110 /* The number of gcda files with all counts cold (but not 0) in
1112 static unsigned both_cold_cnt
;
1114 /* The number of gcda files with all counts 0 in both profiles. */
1115 static unsigned both_zero_cnt
;
1117 /* Extract the basename of the filename NAME. */
1120 extract_file_basename (const char *name
)
1124 char *path
= xstrdup (name
);
1127 sep_str
[0] = DIR_SEPARATOR
;
1129 str
= strstr(path
, sep_str
);
1131 len
= strlen(str
) + 1;
1132 path
= &path
[strlen(path
) - len
+ 2];
1133 str
= strstr(path
, sep_str
);
1139 /* Utility function to get the filename. */
1142 get_file_basename (const char *name
)
1144 if (overlap_use_fullname
)
1146 return extract_file_basename (name
);
1149 /* A utility function to set the flag for the gcda files. */
1152 set_flag (struct overlap_t
*e
)
1158 unique_gcda_files
[1]++;
1164 if (gcov_info_count_all_zero (e
->obj1
))
1166 zero_gcda_files
[0]++;
1170 if (gcov_info_count_all_cold (e
->obj1
, overlap_sum_1
1171 * overlap_hot_threshold
))
1173 cold_gcda_files
[0]++;
1178 hot_gcda_files
[0]++;
1185 unique_gcda_files
[0]++;
1191 if (gcov_info_count_all_zero (e
->obj2
))
1193 zero_gcda_files
[1]++;
1197 if (gcov_info_count_all_cold (e
->obj2
, overlap_sum_2
1198 * overlap_hot_threshold
))
1200 cold_gcda_files
[1]++;
1205 hot_gcda_files
[1]++;
1214 /* Test if INFO1 and INFO2 are from the matched source file.
1215 Return 1 if they match; return 0 otherwise. */
1218 matched_gcov_info (const struct gcov_info
*info1
, const struct gcov_info
*info2
)
1220 /* For FDO, we have to match the name. This can be expensive.
1221 Maybe we should use hash here. */
1222 if (strcmp (info1
->filename
, info2
->filename
))
1225 if (info1
->n_functions
!= info2
->n_functions
)
1227 fnotice (stderr
, "mismatched profiles in %s (%d functions"
1228 " vs %d functions)\n",
1231 info2
->n_functions
);
1237 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1238 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1239 match and 1.0 meaning a perfect match. */
1242 calculate_overlap (struct gcov_info
*gcov_list1
,
1243 struct gcov_info
*gcov_list2
)
1245 unsigned list1_cnt
= 0, list2_cnt
= 0, all_cnt
;
1247 const struct gcov_info
*gi_ptr
;
1248 struct overlap_t
*all_infos
;
1250 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1252 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1254 all_cnt
= list1_cnt
+ list2_cnt
;
1255 all_infos
= (struct overlap_t
*) xmalloc (sizeof (struct overlap_t
)
1257 gcc_assert (all_infos
);
1260 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1262 all_infos
[i
].obj1
= gi_ptr
;
1263 all_infos
[i
].obj2
= 0;
1266 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1268 all_infos
[i
].obj1
= 0;
1269 all_infos
[i
].obj2
= gi_ptr
;
1272 for (i
= list1_cnt
; i
< all_cnt
; i
++)
1274 if (all_infos
[i
].obj2
== 0)
1276 for (j
= 0; j
< list1_cnt
; j
++)
1278 if (all_infos
[j
].obj2
!= 0)
1280 if (matched_gcov_info (all_infos
[i
].obj2
, all_infos
[j
].obj1
))
1282 all_infos
[j
].obj2
= all_infos
[i
].obj2
;
1283 all_infos
[i
].obj2
= 0;
1289 for (i
= 0; i
< all_cnt
; i
++)
1290 if (all_infos
[i
].obj1
|| all_infos
[i
].obj2
)
1292 set_flag (all_infos
+ i
);
1293 if (FLAG_ONE_HOT (all_infos
[i
].flag
))
1295 if (FLAG_BOTH_COLD(all_infos
[i
].flag
))
1297 if (FLAG_BOTH_ZERO(all_infos
[i
].flag
))
1303 double sum_cum_1
= 0;
1304 double sum_cum_2
= 0;
1306 for (i
= 0; i
< all_cnt
; i
++)
1309 double cum_1
, cum_2
;
1310 const char *filename
;
1312 if (all_infos
[i
].obj1
== 0 && all_infos
[i
].obj2
== 0)
1314 if (FLAG_BOTH_ZERO (all_infos
[i
].flag
))
1317 if (all_infos
[i
].obj1
)
1318 filename
= get_file_basename (all_infos
[i
].obj1
->filename
);
1320 filename
= get_file_basename (all_infos
[i
].obj2
->filename
);
1322 if (overlap_func_level
)
1323 printf("\n processing %36s:\n", filename
);
1325 val
= compute_one_gcov (all_infos
[i
].obj1
, all_infos
[i
].obj2
,
1326 overlap_sum_1
, overlap_sum_2
, &cum_1
, &cum_2
);
1328 if (overlap_obj_level
&& (!overlap_hot_only
|| FLAG_ONE_HOT (all_infos
[i
].flag
)))
1330 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1331 filename
, val
*100, cum_1
*100, cum_2
*100);
1343 if (overlap_obj_level
)
1344 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1345 "", sum_val
*100, sum_cum_1
*100, sum_cum_2
*100);
1347 printf (" Statistics:\n"
1348 " profile1_# profile2_# overlap_#\n");
1349 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files
[0], gcda_files
[1],
1350 gcda_files
[0]-unique_gcda_files
[0]);
1351 printf (" unique files: %12u\t%12u\n", unique_gcda_files
[0],
1352 unique_gcda_files
[1]);
1353 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files
[0],
1354 hot_gcda_files
[1], both_hot_cnt
);
1355 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files
[0],
1356 cold_gcda_files
[1], both_cold_cnt
);
1357 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files
[0],
1358 zero_gcda_files
[1], both_zero_cnt
);
1363 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1365 Return 0 on success: without mismatch. Reutrn 1 on error. */
1368 gcov_profile_overlap (struct gcov_info
*profile1
, struct gcov_info
*profile2
)
1372 result
= calculate_overlap (profile1
, profile2
);
1376 printf("\nProgram level overlap result is %3.2f%%\n\n", result
*100);