1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2019 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
;
83 /* The object summary being processed. */
84 static struct gcov_summary
*curr_object_summary
;
86 /* Merge functions for counters. */
87 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
88 static gcov_merge_fn ctr_merge_functions
[GCOV_COUNTERS
] = {
89 #include "gcov-counter.def"
91 #undef DEF_GCOV_COUNTER
93 /* Set the ctrs field in gcov_fn_info object FN_INFO. */
96 set_fn_ctrs (struct gcov_fn_info
*fn_info
)
100 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
102 if (k_ctrs_mask
[i
] == 0)
104 fn_info
->ctrs
[j
].num
= k_ctrs
[i
].num
;
105 fn_info
->ctrs
[j
].values
= k_ctrs
[i
].values
;
108 if (k_ctrs_types
== 0)
111 gcc_assert (j
== k_ctrs_types
);
114 /* For each tag in gcda file, we have an entry here.
115 TAG is the tag value; NAME is the tag name; and
116 PROC is the handler function. */
118 typedef struct tag_format
122 void (*proc
) (unsigned, unsigned);
125 /* Handler table for various Tags. */
127 static const tag_format_t tag_table
[] =
130 {0, "UNKNOWN", NULL
},
131 {0, "COUNTERS", tag_counters
},
132 {GCOV_TAG_FUNCTION
, "FUNCTION", tag_function
},
133 {GCOV_TAG_BLOCKS
, "BLOCKS", tag_blocks
},
134 {GCOV_TAG_ARCS
, "ARCS", tag_arcs
},
135 {GCOV_TAG_LINES
, "LINES", tag_lines
},
136 {GCOV_TAG_OBJECT_SUMMARY
, "OBJECT_SUMMARY", tag_summary
},
140 /* Handler for reading function tag. */
143 tag_function (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
147 /* write out previous fn_info. */
150 set_fn_ctrs (curr_fn_info
);
151 obstack_ptr_grow (&fn_info
, curr_fn_info
);
154 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
156 curr_fn_info
= (struct gcov_fn_info
*) xcalloc (sizeof (struct gcov_fn_info
)
157 + GCOV_COUNTERS
* sizeof (struct gcov_ctr_info
), 1);
159 for (i
= 0; i
< GCOV_COUNTERS
; i
++)
163 curr_fn_info
->key
= curr_gcov_info
;
164 curr_fn_info
->ident
= gcov_read_unsigned ();
165 curr_fn_info
->lineno_checksum
= gcov_read_unsigned ();
166 curr_fn_info
->cfg_checksum
= gcov_read_unsigned ();
170 fnotice (stdout
, "tag one function id=%d\n", curr_fn_info
->ident
);
173 /* Handler for reading block tag. */
176 tag_blocks (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
178 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
182 /* Handler for reading flow arc tag. */
185 tag_arcs (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
187 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
191 /* Handler for reading line tag. */
194 tag_lines (unsigned tag ATTRIBUTE_UNUSED
, unsigned length ATTRIBUTE_UNUSED
)
196 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
200 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
203 tag_counters (unsigned tag
, unsigned length
)
205 unsigned n_counts
= GCOV_TAG_COUNTER_NUM (length
);
210 tag_ix
= GCOV_COUNTER_FOR_TAG (tag
);
211 gcc_assert (tag_ix
< GCOV_COUNTERS
);
212 k_ctrs_mask
[tag_ix
] = 1;
213 gcc_assert (k_ctrs
[tag_ix
].num
== 0);
214 k_ctrs
[tag_ix
].num
= n_counts
;
216 k_ctrs
[tag_ix
].values
= values
= (gcov_type
*) xmalloc (n_counts
* 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
, unsigned length ATTRIBUTE_UNUSED
)
228 curr_object_summary
= (gcov_summary
*) xcalloc (sizeof (gcov_summary
), 1);
229 gcov_read_summary (curr_object_summary
);
232 /* This function is called at the end of reading a gcda file.
233 It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO. */
236 read_gcda_finalize (struct gcov_info
*obj_info
)
240 set_fn_ctrs (curr_fn_info
);
241 obstack_ptr_grow (&fn_info
, curr_fn_info
);
243 /* We set the following fields: merge, n_functions, functions
245 obj_info
->n_functions
= num_fn_info
;
246 obj_info
->functions
= (const struct gcov_fn_info
**) obstack_finish (&fn_info
);
248 /* wrap all the counter array. */
249 for (i
=0; i
< GCOV_COUNTERS
; i
++)
252 obj_info
->merge
[i
] = ctr_merge_functions
[i
];
256 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
257 Program level summary CURRENT_SUMMARY will also be updated. */
259 static struct gcov_info
*
260 read_gcda_file (const char *filename
)
264 unsigned magic
, version
;
265 struct gcov_info
*obj_info
;
268 for (i
=0; i
< GCOV_COUNTERS
; i
++)
272 if (!gcov_open (filename
))
274 fnotice (stderr
, "%s:cannot open\n", filename
);
279 magic
= gcov_read_unsigned ();
280 if (magic
!= GCOV_DATA_MAGIC
)
282 fnotice (stderr
, "%s:not a gcov data file\n", filename
);
288 version
= gcov_read_unsigned ();
289 if (version
!= GCOV_VERSION
)
291 fnotice (stderr
, "%s:incorrect gcov version %d vs %d \n", filename
, version
, GCOV_VERSION
);
296 /* Instantiate a gcov_info object. */
297 curr_gcov_info
= obj_info
= (struct gcov_info
*) xcalloc (sizeof (struct gcov_info
) +
298 sizeof (struct gcov_ctr_info
) * GCOV_COUNTERS
, 1);
300 obj_info
->version
= version
;
301 obstack_init (&fn_info
);
304 curr_object_summary
= NULL
;
306 size_t len
= strlen (filename
) + 1;
307 char *str_dup
= (char*) xmalloc (len
);
309 memcpy (str_dup
, filename
, len
);
310 obj_info
->filename
= str_dup
;
314 obj_info
->stamp
= gcov_read_unsigned ();
318 gcov_position_t base
;
319 unsigned tag
, length
;
320 tag_format_t
const *format
;
325 tag
= gcov_read_unsigned ();
328 length
= gcov_read_unsigned ();
329 base
= gcov_position ();
330 mask
= GCOV_TAG_MASK (tag
) >> 1;
331 for (tag_depth
= 4; mask
; mask
>>= 8)
333 if (((mask
& 0xff) != 0xff))
335 warning (0, "%s:tag %qx is invalid", filename
, tag
);
340 for (format
= tag_table
; format
->name
; format
++)
341 if (format
->tag
== tag
)
343 format
= &tag_table
[GCOV_TAG_IS_COUNTER (tag
) ? 2 : 1];
347 if (depth
&& depth
< tag_depth
)
349 if (!GCOV_TAG_IS_SUBTAG (tags
[depth
- 1], tag
))
350 warning (0, "%s:tag %qx is incorrectly nested",
354 tags
[depth
- 1] = tag
;
359 unsigned long actual_length
;
361 (*format
->proc
) (tag
, length
);
363 actual_length
= gcov_position () - base
;
364 if (actual_length
> length
)
365 warning (0, "%s:record size mismatch %lu bytes overread",
366 filename
, actual_length
- length
);
367 else if (length
> actual_length
)
368 warning (0, "%s:record size mismatch %lu bytes unread",
369 filename
, length
- actual_length
);
372 gcov_sync (base
, length
);
373 if ((error
= gcov_is_error ()))
375 warning (0, error
< 0 ? "%s:counter overflow at %lu" :
376 "%s:read error at %lu", filename
,
377 (long unsigned) gcov_position ());
382 read_gcda_finalize (obj_info
);
389 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
390 Return a non-zero value to stop the tree walk. */
393 ftw_read_file (const char *filename
,
394 const struct stat
*status ATTRIBUTE_UNUSED
,
399 struct gcov_info
*obj_info
;
401 /* Only read regular files. */
405 filename_len
= strlen (filename
);
406 suffix_len
= strlen (GCOV_DATA_SUFFIX
);
408 if (filename_len
<= suffix_len
)
411 if (strcmp(filename
+ filename_len
- suffix_len
, GCOV_DATA_SUFFIX
))
415 fnotice (stderr
, "reading file: %s\n", filename
);
417 obj_info
= read_gcda_file (filename
);
421 obj_info
->next
= gcov_info_head
;
422 gcov_info_head
= obj_info
;
428 /* Initializer for reading a profile dir. */
431 read_profile_dir_init (void)
436 /* Driver for read a profile directory and convert into gcov_info list in memory.
437 Return NULL on error,
438 Return the head of gcov_info list on success. */
441 gcov_read_profile_dir (const char* dir_name
, int recompute_summary ATTRIBUTE_UNUSED
)
446 read_profile_dir_init ();
448 if (access (dir_name
, R_OK
) != 0)
450 fnotice (stderr
, "cannot access directory %s\n", dir_name
);
453 pwd
= getcwd (NULL
, 0);
455 ret
= chdir (dir_name
);
458 fnotice (stderr
, "%s is not a directory\n", dir_name
);
462 ftw (".", ftw_read_file
, 50);
467 return gcov_info_head
;;
470 /* This part of the code is to merge profile counters. These
471 variables are set in merge_wrapper and to be used by
472 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
474 /* We save the counter value address to this variable. */
475 static gcov_type
*gcov_value_buf
;
477 /* The number of counter values to be read by current merging. */
478 static gcov_unsigned_t gcov_value_buf_size
;
480 /* The index of counter values being read. */
481 static gcov_unsigned_t gcov_value_buf_pos
;
483 /* The weight of current merging. */
484 static unsigned gcov_merge_weight
;
486 /* Read a counter value from gcov_value_buf array. */
489 gcov_read_counter_mem (void)
492 gcc_assert (gcov_value_buf_pos
< gcov_value_buf_size
);
493 ret
= *(gcov_value_buf
+ gcov_value_buf_pos
);
494 ++gcov_value_buf_pos
;
498 /* Return the recorded merge weight. */
501 gcov_get_merge_weight (void)
503 return gcov_merge_weight
;
506 /* A wrapper function for merge functions. It sets up the
507 value buffer and weights and then calls the merge function. */
510 merge_wrapper (gcov_merge_fn f
, gcov_type
*v1
, gcov_unsigned_t n
,
511 gcov_type
*v2
, unsigned w
)
514 gcov_value_buf_pos
= 0;
515 gcov_value_buf_size
= n
;
516 gcov_merge_weight
= w
;
520 /* Offline tool to manipulate profile data.
521 This tool targets on matched profiles. But it has some tolerance on
523 When merging p1 to p2 (p2 is the dst),
524 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
526 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
527 specified weight; emit warning.
528 * m.gcda in both p1 and p2:
529 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
530 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
532 drop p1->m.gcda->f. A warning is emitted. */
534 /* Add INFO2's counter to INFO1, multiplying by weight W. */
537 gcov_merge (struct gcov_info
*info1
, struct gcov_info
*info2
, int w
)
540 unsigned n_functions
= info1
->n_functions
;
541 int has_mismatch
= 0;
543 gcc_assert (info2
->n_functions
== n_functions
);
544 for (f_ix
= 0; f_ix
< n_functions
; f_ix
++)
547 const struct gcov_fn_info
*gfi_ptr1
= info1
->functions
[f_ix
];
548 const struct gcov_fn_info
*gfi_ptr2
= info2
->functions
[f_ix
];
549 const struct gcov_ctr_info
*ci_ptr1
, *ci_ptr2
;
551 if (!gfi_ptr1
|| gfi_ptr1
->key
!= info1
)
553 if (!gfi_ptr2
|| gfi_ptr2
->key
!= info2
)
556 if (gfi_ptr1
->cfg_checksum
!= gfi_ptr2
->cfg_checksum
)
558 fnotice (stderr
, "in %s, cfg_checksum mismatch, skipping\n",
563 ci_ptr1
= gfi_ptr1
->ctrs
;
564 ci_ptr2
= gfi_ptr2
->ctrs
;
565 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
567 gcov_merge_fn merge1
= info1
->merge
[t_ix
];
568 gcov_merge_fn merge2
= info2
->merge
[t_ix
];
570 gcc_assert (merge1
== merge2
);
573 gcc_assert (ci_ptr1
->num
== ci_ptr2
->num
);
574 merge_wrapper (merge1
, ci_ptr1
->values
, ci_ptr1
->num
, ci_ptr2
->values
, w
);
583 /* Find and return the match gcov_info object for INFO from ARRAY.
584 SIZE is the length of ARRAY.
585 Return NULL if there is no match. */
587 static struct gcov_info
*
588 find_match_gcov_info (struct gcov_info
**array
, int size
,
589 struct gcov_info
*info
)
591 struct gcov_info
*gi_ptr
;
592 struct gcov_info
*ret
= NULL
;
595 for (i
= 0; i
< size
; i
++)
600 if (!strcmp (gi_ptr
->filename
, info
->filename
))
608 if (ret
&& ret
->n_functions
!= info
->n_functions
)
610 fnotice (stderr
, "mismatched profiles in %s (%d functions"
611 " vs %d functions)\n",
620 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
621 Return 0 on success: without mismatch.
622 Reutrn 1 on error. */
625 gcov_profile_merge (struct gcov_info
*tgt_profile
, struct gcov_info
*src_profile
,
628 struct gcov_info
*gi_ptr
;
629 struct gcov_info
**tgt_infos
;
630 struct gcov_info
*tgt_tail
;
631 struct gcov_info
**in_src_not_tgt
;
632 unsigned tgt_cnt
= 0, src_cnt
= 0;
633 unsigned unmatch_info_cnt
= 0;
636 for (gi_ptr
= tgt_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
638 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
640 tgt_infos
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
642 gcc_assert (tgt_infos
);
643 in_src_not_tgt
= (struct gcov_info
**) xmalloc (sizeof (struct gcov_info
*)
645 gcc_assert (in_src_not_tgt
);
647 for (gi_ptr
= tgt_profile
, i
= 0; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
648 tgt_infos
[i
] = gi_ptr
;
650 tgt_tail
= tgt_infos
[tgt_cnt
- 1];
652 /* First pass on tgt_profile, we multiply w1 to all counters. */
655 for (i
= 0; i
< tgt_cnt
; i
++)
656 gcov_merge (tgt_infos
[i
], tgt_infos
[i
], w1
-1);
659 /* Second pass, add src_profile to the tgt_profile. */
660 for (gi_ptr
= src_profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
662 struct gcov_info
*gi_ptr1
;
664 gi_ptr1
= find_match_gcov_info (tgt_infos
, tgt_cnt
, gi_ptr
);
667 in_src_not_tgt
[unmatch_info_cnt
++] = gi_ptr
;
670 gcov_merge (gi_ptr1
, gi_ptr
, w2
);
673 /* For modules in src but not in tgt. We adjust the counter and append. */
674 for (i
= 0; i
< unmatch_info_cnt
; i
++)
676 gi_ptr
= in_src_not_tgt
[i
];
677 gcov_merge (gi_ptr
, gi_ptr
, w2
- 1);
679 tgt_tail
->next
= gi_ptr
;
683 free (in_src_not_tgt
);
689 typedef gcov_type (*counter_op_fn
) (gcov_type
, void*, void*);
691 /* Performing FN upon arc counters. */
694 __gcov_add_counter_op (gcov_type
*counters
, unsigned n_counters
,
695 counter_op_fn fn
, void *data1
, void *data2
)
697 for (; n_counters
; counters
++, n_counters
--)
699 gcov_type val
= *counters
;
700 *counters
= fn(val
, data1
, data2
);
704 /* Performing FN upon ior counters. */
707 __gcov_ior_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
708 unsigned n_counters ATTRIBUTE_UNUSED
,
709 counter_op_fn fn ATTRIBUTE_UNUSED
,
710 void *data1 ATTRIBUTE_UNUSED
,
711 void *data2 ATTRIBUTE_UNUSED
)
716 /* Performing FN upon time-profile counters. */
719 __gcov_time_profile_counter_op (gcov_type
*counters ATTRIBUTE_UNUSED
,
720 unsigned n_counters ATTRIBUTE_UNUSED
,
721 counter_op_fn fn ATTRIBUTE_UNUSED
,
722 void *data1 ATTRIBUTE_UNUSED
,
723 void *data2 ATTRIBUTE_UNUSED
)
728 /* Performing FN upon TOP N counters. */
731 __gcov_topn_counter_op (gcov_type
*counters
, unsigned n_counters
,
732 counter_op_fn fn
, void *data1
, void *data2
)
734 unsigned i
, n_measures
;
736 gcc_assert (!(n_counters
% 3));
737 n_measures
= n_counters
/ 3;
738 for (i
= 0; i
< n_measures
; i
++, counters
+= 3)
740 counters
[1] = fn (counters
[1], data1
, data2
);
741 counters
[2] = fn (counters
[2], data1
, data2
);
745 /* Scaling the counter value V by multiplying *(float*) DATA1. */
748 fp_scale (gcov_type v
, void *data1
, void *data2 ATTRIBUTE_UNUSED
)
750 float f
= *(float *) data1
;
751 return (gcov_type
) (v
* f
);
754 /* Scaling the counter value V by multiplying DATA2/DATA1. */
757 int_scale (gcov_type v
, void *data1
, void *data2
)
759 int n
= *(int *) data1
;
760 int d
= *(int *) data2
;
761 return (gcov_type
) ( RDIV (v
,d
) * n
);
764 /* Type of function used to process counters. */
765 typedef void (*gcov_counter_fn
) (gcov_type
*, gcov_unsigned_t
,
766 counter_op_fn
, void *, void *);
768 /* Function array to process profile counters. */
769 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
770 __gcov ## FN_TYPE ## _counter_op,
771 static gcov_counter_fn ctr_functions
[GCOV_COUNTERS
] = {
772 #include "gcov-counter.def"
774 #undef DEF_GCOV_COUNTER
776 /* Driver for scaling profile counters. */
779 gcov_profile_scale (struct gcov_info
*profile
, float scale_factor
, int n
, int d
)
781 struct gcov_info
*gi_ptr
;
785 fnotice (stdout
, "scale_factor is %f or %d/%d\n", scale_factor
, n
, d
);
787 /* Scaling the counters. */
788 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
789 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
792 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
793 const struct gcov_ctr_info
*ci_ptr
;
795 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
798 ci_ptr
= gfi_ptr
->ctrs
;
799 for (t_ix
= 0; t_ix
!= GCOV_COUNTERS
; t_ix
++)
801 gcov_merge_fn merge
= gi_ptr
->merge
[t_ix
];
806 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
807 fp_scale
, &scale_factor
, NULL
);
809 (*ctr_functions
[t_ix
]) (ci_ptr
->values
, ci_ptr
->num
,
818 /* Driver to normalize profile counters. */
821 gcov_profile_normalize (struct gcov_info
*profile
, gcov_type max_val
)
823 struct gcov_info
*gi_ptr
;
824 gcov_type curr_max_val
= 0;
829 /* Find the largest count value. */
830 for (gi_ptr
= profile
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
831 for (f_ix
= 0; f_ix
< gi_ptr
->n_functions
; f_ix
++)
834 const struct gcov_fn_info
*gfi_ptr
= gi_ptr
->functions
[f_ix
];
835 const struct gcov_ctr_info
*ci_ptr
;
837 if (!gfi_ptr
|| gfi_ptr
->key
!= gi_ptr
)
840 ci_ptr
= gfi_ptr
->ctrs
;
841 for (t_ix
= 0; t_ix
< 1; t_ix
++)
843 for (i
= 0; i
< ci_ptr
->num
; i
++)
844 if (ci_ptr
->values
[i
] > curr_max_val
)
845 curr_max_val
= ci_ptr
->values
[i
];
850 scale_factor
= (float)max_val
/ curr_max_val
;
852 fnotice (stdout
, "max_val is %" PRId64
"\n", curr_max_val
);
854 return gcov_profile_scale (profile
, scale_factor
, 0, 0);
857 /* The following variables are defined in gcc/gcov-tool.c. */
858 extern int overlap_func_level
;
859 extern int overlap_obj_level
;
860 extern int overlap_hot_only
;
861 extern int overlap_use_fullname
;
862 extern double overlap_hot_threshold
;
864 /* Compute the overlap score of two values. The score is defined as:
865 min (V1/SUM_1, V2/SUM_2) */
868 calculate_2_entries (const unsigned long v1
, const unsigned long v2
,
869 const double sum_1
, const double sum_2
)
871 double val1
= (sum_1
== 0.0 ? 0.0 : v1
/sum_1
);
872 double val2
= (sum_2
== 0.0 ? 0.0 : v2
/sum_2
);
880 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
881 This function also updates cumulative score CUM_1_RESULT and
885 compute_one_gcov (const struct gcov_info
*gcov_info1
,
886 const struct gcov_info
*gcov_info2
,
887 const double sum_1
, const double sum_2
,
888 double *cum_1_result
, double *cum_2_result
)
892 double cum_1
= 0, cum_2
= 0;
893 const struct gcov_info
*gcov_info
= 0;
897 gcc_assert (gcov_info1
|| gcov_info2
);
900 gcov_info
= gcov_info2
;
901 cum_p
= cum_2_result
;
907 gcov_info
= gcov_info1
;
908 cum_p
= cum_1_result
;
915 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
917 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
918 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
920 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
922 for (c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
923 cum_1
+= ci_ptr
->values
[c_num
] / sum
;
929 for (f_ix
= 0; f_ix
< gcov_info1
->n_functions
; f_ix
++)
931 double func_cum_1
= 0.0;
932 double func_cum_2
= 0.0;
933 double func_val
= 0.0;
936 const struct gcov_fn_info
*gfi_ptr1
= gcov_info1
->functions
[f_ix
];
937 const struct gcov_fn_info
*gfi_ptr2
= gcov_info2
->functions
[f_ix
];
939 if (!gfi_ptr1
|| gfi_ptr1
->key
!= gcov_info1
)
941 if (!gfi_ptr2
|| gfi_ptr2
->key
!= gcov_info2
)
944 const struct gcov_ctr_info
*ci_ptr1
= gfi_ptr1
->ctrs
;
945 const struct gcov_ctr_info
*ci_ptr2
= gfi_ptr2
->ctrs
;
947 for (c_num
= 0; c_num
< ci_ptr1
->num
; c_num
++)
949 if (ci_ptr1
->values
[c_num
] | ci_ptr2
->values
[c_num
])
951 func_val
+= calculate_2_entries (ci_ptr1
->values
[c_num
],
952 ci_ptr2
->values
[c_num
],
955 func_cum_1
+= ci_ptr1
->values
[c_num
] / sum_1
;
956 func_cum_2
+= ci_ptr2
->values
[c_num
] / sum_2
;
958 if (ci_ptr1
->values
[c_num
] / sum_1
>= overlap_hot_threshold
959 || ci_ptr2
->values
[c_num
] / sum_2
>= overlap_hot_threshold
)
967 if (overlap_func_level
&& nonzero
&& (!overlap_hot_only
|| hot
))
969 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
970 gfi_ptr1
->ident
, func_val
*100, func_cum_1
*100, func_cum_2
*100);
973 *cum_1_result
= cum_1
;
974 *cum_2_result
= cum_2
;
978 /* Test if all counter values in this GCOV_INFO are cold.
979 "Cold" is defined as the counter value being less than
980 or equal to THRESHOLD. */
983 gcov_info_count_all_cold (const struct gcov_info
*gcov_info
,
988 for (f_ix
= 0; f_ix
< gcov_info
->n_functions
; f_ix
++)
990 const struct gcov_fn_info
*gfi_ptr
= gcov_info
->functions
[f_ix
];
992 if (!gfi_ptr
|| gfi_ptr
->key
!= gcov_info
)
994 const struct gcov_ctr_info
*ci_ptr
= gfi_ptr
->ctrs
;
995 for (unsigned c_num
= 0; c_num
< ci_ptr
->num
; c_num
++)
996 if (ci_ptr
->values
[c_num
] > threshold
)
1003 /* Test if all counter values in this GCOV_INFO are 0. */
1006 gcov_info_count_all_zero (const struct gcov_info
*gcov_info
)
1008 return gcov_info_count_all_cold (gcov_info
, 0);
1011 /* A pair of matched GCOV_INFO.
1012 The flag is a bitvector:
1013 b0: obj1's all counts are 0;
1014 b1: obj1's all counts are cold (but no 0);
1016 b3: no obj1 to match obj2;
1017 b4: obj2's all counts are 0;
1018 b5: obj2's all counts are cold (but no 0);
1020 b7: no obj2 to match obj1;
1023 const struct gcov_info
*obj1
;
1024 const struct gcov_info
*obj2
;
1028 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1029 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1030 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1032 /* Cumlative overlap dscore for profile1 and profile2. */
1033 static double overlap_sum_1
, overlap_sum_2
;
1035 /* The number of gcda files in the profiles. */
1036 static unsigned gcda_files
[2];
1038 /* The number of unique gcda files in the profiles
1039 (not existing in the other profile). */
1040 static unsigned unique_gcda_files
[2];
1042 /* The number of gcda files that all counter values are 0. */
1043 static unsigned zero_gcda_files
[2];
1045 /* The number of gcda files that all counter values are cold (but not 0). */
1046 static unsigned cold_gcda_files
[2];
1048 /* The number of gcda files that includes hot counter values. */
1049 static unsigned hot_gcda_files
[2];
1051 /* The number of gcda files with hot count value in either profiles. */
1052 static unsigned both_hot_cnt
;
1054 /* The number of gcda files with all counts cold (but not 0) in
1056 static unsigned both_cold_cnt
;
1058 /* The number of gcda files with all counts 0 in both profiles. */
1059 static unsigned both_zero_cnt
;
1061 /* Extract the basename of the filename NAME. */
1064 extract_file_basename (const char *name
)
1068 char *path
= xstrdup (name
);
1071 sep_str
[0] = DIR_SEPARATOR
;
1073 str
= strstr(path
, sep_str
);
1075 len
= strlen(str
) + 1;
1076 path
= &path
[strlen(path
) - len
+ 2];
1077 str
= strstr(path
, sep_str
);
1083 /* Utility function to get the filename. */
1086 get_file_basename (const char *name
)
1088 if (overlap_use_fullname
)
1090 return extract_file_basename (name
);
1093 /* A utility function to set the flag for the gcda files. */
1096 set_flag (struct overlap_t
*e
)
1102 unique_gcda_files
[1]++;
1108 if (gcov_info_count_all_zero (e
->obj1
))
1110 zero_gcda_files
[0]++;
1114 if (gcov_info_count_all_cold (e
->obj1
, overlap_sum_1
1115 * overlap_hot_threshold
))
1117 cold_gcda_files
[0]++;
1122 hot_gcda_files
[0]++;
1129 unique_gcda_files
[0]++;
1135 if (gcov_info_count_all_zero (e
->obj2
))
1137 zero_gcda_files
[1]++;
1141 if (gcov_info_count_all_cold (e
->obj2
, overlap_sum_2
1142 * overlap_hot_threshold
))
1144 cold_gcda_files
[1]++;
1149 hot_gcda_files
[1]++;
1158 /* Test if INFO1 and INFO2 are from the matched source file.
1159 Return 1 if they match; return 0 otherwise. */
1162 matched_gcov_info (const struct gcov_info
*info1
, const struct gcov_info
*info2
)
1164 /* For FDO, we have to match the name. This can be expensive.
1165 Maybe we should use hash here. */
1166 if (strcmp (info1
->filename
, info2
->filename
))
1169 if (info1
->n_functions
!= info2
->n_functions
)
1171 fnotice (stderr
, "mismatched profiles in %s (%d functions"
1172 " vs %d functions)\n",
1175 info2
->n_functions
);
1181 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1182 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1183 match and 1.0 meaning a perfect match. */
1186 calculate_overlap (struct gcov_info
*gcov_list1
,
1187 struct gcov_info
*gcov_list2
)
1189 unsigned list1_cnt
= 0, list2_cnt
= 0, all_cnt
;
1191 const struct gcov_info
*gi_ptr
;
1192 struct overlap_t
*all_infos
;
1194 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1196 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
)
1198 all_cnt
= list1_cnt
+ list2_cnt
;
1199 all_infos
= (struct overlap_t
*) xmalloc (sizeof (struct overlap_t
)
1201 gcc_assert (all_infos
);
1204 for (gi_ptr
= gcov_list1
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1206 all_infos
[i
].obj1
= gi_ptr
;
1207 all_infos
[i
].obj2
= 0;
1210 for (gi_ptr
= gcov_list2
; gi_ptr
; gi_ptr
= gi_ptr
->next
, i
++)
1212 all_infos
[i
].obj1
= 0;
1213 all_infos
[i
].obj2
= gi_ptr
;
1216 for (i
= list1_cnt
; i
< all_cnt
; i
++)
1218 if (all_infos
[i
].obj2
== 0)
1220 for (j
= 0; j
< list1_cnt
; j
++)
1222 if (all_infos
[j
].obj2
!= 0)
1224 if (matched_gcov_info (all_infos
[i
].obj2
, all_infos
[j
].obj1
))
1226 all_infos
[j
].obj2
= all_infos
[i
].obj2
;
1227 all_infos
[i
].obj2
= 0;
1233 for (i
= 0; i
< all_cnt
; i
++)
1234 if (all_infos
[i
].obj1
|| all_infos
[i
].obj2
)
1236 set_flag (all_infos
+ i
);
1237 if (FLAG_ONE_HOT (all_infos
[i
].flag
))
1239 if (FLAG_BOTH_COLD(all_infos
[i
].flag
))
1241 if (FLAG_BOTH_ZERO(all_infos
[i
].flag
))
1247 double sum_cum_1
= 0;
1248 double sum_cum_2
= 0;
1250 for (i
= 0; i
< all_cnt
; i
++)
1253 double cum_1
, cum_2
;
1254 const char *filename
;
1256 if (all_infos
[i
].obj1
== 0 && all_infos
[i
].obj2
== 0)
1258 if (FLAG_BOTH_ZERO (all_infos
[i
].flag
))
1261 if (all_infos
[i
].obj1
)
1262 filename
= get_file_basename (all_infos
[i
].obj1
->filename
);
1264 filename
= get_file_basename (all_infos
[i
].obj2
->filename
);
1266 if (overlap_func_level
)
1267 printf("\n processing %36s:\n", filename
);
1269 val
= compute_one_gcov (all_infos
[i
].obj1
, all_infos
[i
].obj2
,
1270 overlap_sum_1
, overlap_sum_2
, &cum_1
, &cum_2
);
1272 if (overlap_obj_level
&& (!overlap_hot_only
|| FLAG_ONE_HOT (all_infos
[i
].flag
)))
1274 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1275 filename
, val
*100, cum_1
*100, cum_2
*100);
1287 if (overlap_obj_level
)
1288 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1289 "", sum_val
*100, sum_cum_1
*100, sum_cum_2
*100);
1291 printf (" Statistics:\n"
1292 " profile1_# profile2_# overlap_#\n");
1293 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files
[0], gcda_files
[1],
1294 gcda_files
[0]-unique_gcda_files
[0]);
1295 printf (" unique files: %12u\t%12u\n", unique_gcda_files
[0],
1296 unique_gcda_files
[1]);
1297 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files
[0],
1298 hot_gcda_files
[1], both_hot_cnt
);
1299 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files
[0],
1300 cold_gcda_files
[1], both_cold_cnt
);
1301 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files
[0],
1302 zero_gcda_files
[1], both_zero_cnt
);
1307 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1309 Return 0 on success: without mismatch. Reutrn 1 on error. */
1312 gcov_profile_overlap (struct gcov_info
*profile1
, struct gcov_info
*profile2
)
1316 result
= calculate_overlap (profile1
, profile2
);
1320 printf("\nProgram level overlap result is %3.2f%%\n\n", result
*100);