Revert accidental commit.
[official-gcc.git] / libgcc / libgcov-util.c
blob24ee50ec4ab78f1f8df09ac704de683bb1a9e4b8
1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2016 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
11 version.
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
16 for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
28 #define IN_GCOV_TOOL 1
30 #include "libgcov.h"
31 #include "intl.h"
32 #include "diagnostic.h"
33 #include "version.h"
34 #include "demangle.h"
36 /* Borrowed from basic-block.h. */
37 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
39 extern gcov_position_t gcov_position();
40 extern int gcov_is_error();
42 /* Verbose mode for debug. */
43 static int verbose;
45 /* Set verbose flag. */
46 void gcov_set_verbose (void)
48 verbose = 1;
51 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
53 #include "obstack.h"
54 #include <unistd.h>
55 #ifdef HAVE_FTW_H
56 #include <ftw.h>
57 #endif
59 static void tag_function (unsigned, unsigned);
60 static void tag_blocks (unsigned, unsigned);
61 static void tag_arcs (unsigned, unsigned);
62 static void tag_lines (unsigned, unsigned);
63 static void tag_counters (unsigned, unsigned);
64 static void tag_summary (unsigned, unsigned);
66 /* The gcov_info for the first module. */
67 static struct gcov_info *curr_gcov_info;
68 /* The gcov_info being processed. */
69 static struct gcov_info *gcov_info_head;
70 /* This variable contains all the functions in current module. */
71 static struct obstack fn_info;
72 /* The function being processed. */
73 static struct gcov_fn_info *curr_fn_info;
74 /* The number of functions seen so far. */
75 static unsigned num_fn_info;
76 /* This variable contains all the counters for current module. */
77 static int k_ctrs_mask[GCOV_COUNTERS];
78 /* The kind of counters that have been seen. */
79 static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
80 /* Number of kind of counters that have been seen. */
81 static int k_ctrs_types;
83 /* Merge functions for counters. */
84 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
85 static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
86 #include "gcov-counter.def"
88 #undef DEF_GCOV_COUNTER
90 /* Set the ctrs field in gcov_fn_info object FN_INFO. */
92 static void
93 set_fn_ctrs (struct gcov_fn_info *fn_info)
95 int j = 0, i;
97 for (i = 0; i < GCOV_COUNTERS; i++)
99 if (k_ctrs_mask[i] == 0)
100 continue;
101 fn_info->ctrs[j].num = k_ctrs[i].num;
102 fn_info->ctrs[j].values = k_ctrs[i].values;
103 j++;
105 if (k_ctrs_types == 0)
106 k_ctrs_types = j;
107 else
108 gcc_assert (j == k_ctrs_types);
111 /* For each tag in gcda file, we have an entry here.
112 TAG is the tag value; NAME is the tag name; and
113 PROC is the handler function. */
115 typedef struct tag_format
117 unsigned tag;
118 char const *name;
119 void (*proc) (unsigned, unsigned);
120 } tag_format_t;
122 /* Handler table for various Tags. */
124 static const tag_format_t tag_table[] =
126 {0, "NOP", NULL},
127 {0, "UNKNOWN", NULL},
128 {0, "COUNTERS", tag_counters},
129 {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
130 {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
131 {GCOV_TAG_ARCS, "ARCS", tag_arcs},
132 {GCOV_TAG_LINES, "LINES", tag_lines},
133 {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
134 {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary},
135 {0, NULL, NULL}
138 /* Handler for reading function tag. */
140 static void
141 tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
143 int i;
145 /* write out previous fn_info. */
146 if (num_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
153 counter types. */
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++)
158 k_ctrs[i].num = 0;
159 k_ctrs_types = 0;
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 ();
165 num_fn_info++;
167 if (verbose)
168 fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
171 /* Handler for reading block tag. */
173 static void
174 tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
176 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
177 gcc_unreachable ();
180 /* Handler for reading flow arc tag. */
182 static void
183 tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
185 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
186 gcc_unreachable ();
189 /* Handler for reading line tag. */
191 static void
192 tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
194 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
195 gcc_unreachable ();
198 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
200 static void
201 tag_counters (unsigned tag, unsigned length)
203 unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
204 gcov_type *values;
205 unsigned ix;
206 unsigned tag_ix;
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));
215 gcc_assert (values);
217 for (ix = 0; ix != n_counts; ix++)
218 values[ix] = gcov_read_counter ();
221 /* Handler for reading summary tag. */
223 static void
224 tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
226 struct gcov_summary summary;
228 gcov_read_summary (&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. */
234 static void
235 read_gcda_finalize (struct gcov_info *obj_info)
237 int i;
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, and functions. */
243 obj_info->n_functions = num_fn_info;
244 obj_info->functions = (const struct gcov_fn_info**) obstack_finish (&fn_info);
246 /* wrap all the counter array. */
247 for (i=0; i< GCOV_COUNTERS; i++)
249 if (k_ctrs_mask[i])
250 obj_info->merge[i] = ctr_merge_functions[i];
254 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
255 Program level summary CURRENT_SUMMARY will also be updated. */
257 static struct gcov_info *
258 read_gcda_file (const char *filename)
260 unsigned tags[4];
261 unsigned depth = 0;
262 unsigned magic, version;
263 struct gcov_info *obj_info;
264 int i;
266 for (i=0; i< GCOV_COUNTERS; i++)
267 k_ctrs_mask[i] = 0;
268 k_ctrs_types = 0;
270 if (!gcov_open (filename))
272 fnotice (stderr, "%s:cannot open\n", filename);
273 return NULL;
276 /* Read magic. */
277 magic = gcov_read_unsigned ();
278 if (magic != GCOV_DATA_MAGIC)
280 fnotice (stderr, "%s:not a gcov data file\n", filename);
281 gcov_close ();
282 return NULL;
285 /* Read version. */
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);
290 gcov_close ();
291 return NULL;
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);
300 num_fn_info = 0;
301 curr_fn_info = 0;
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;
310 /* Read stamp. */
311 obj_info->stamp = gcov_read_unsigned ();
313 while (1)
315 gcov_position_t base;
316 unsigned tag, length;
317 tag_format_t const *format;
318 unsigned tag_depth;
319 int error;
320 unsigned mask;
322 tag = gcov_read_unsigned ();
323 if (!tag)
324 break;
325 length = gcov_read_unsigned ();
326 base = gcov_position ();
327 mask = GCOV_TAG_MASK (tag) >> 1;
328 for (tag_depth = 4; mask; mask >>= 8)
330 if (((mask & 0xff) != 0xff))
332 warning (0, "%s:tag `%x' is invalid\n", filename, tag);
333 break;
335 tag_depth--;
337 for (format = tag_table; format->name; format++)
338 if (format->tag == tag)
339 goto found;
340 format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
341 found:;
342 if (tag)
344 if (depth && depth < tag_depth)
346 if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
347 warning (0, "%s:tag `%x' is incorrectly nested\n",
348 filename, tag);
350 depth = tag_depth;
351 tags[depth - 1] = tag;
354 if (format->proc)
356 unsigned long actual_length;
358 (*format->proc) (tag, length);
360 actual_length = gcov_position () - base;
361 if (actual_length > length)
362 warning (0, "%s:record size mismatch %lu bytes overread\n",
363 filename, actual_length - length);
364 else if (length > actual_length)
365 warning (0, "%s:record size mismatch %lu bytes unread\n",
366 filename, length - actual_length);
369 gcov_sync (base, length);
370 if ((error = gcov_is_error ()))
372 warning (0, error < 0 ? "%s:counter overflow at %lu\n" :
373 "%s:read error at %lu\n", filename,
374 (long unsigned) gcov_position ());
375 break;
379 read_gcda_finalize (obj_info);
380 gcov_close ();
382 return obj_info;
385 #ifdef HAVE_FTW_H
386 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
387 Return a non-zero value to stop the tree walk. */
389 static int
390 ftw_read_file (const char *filename,
391 const struct stat *status ATTRIBUTE_UNUSED,
392 int type)
394 int filename_len;
395 int suffix_len;
396 struct gcov_info *obj_info;
398 /* Only read regular files. */
399 if (type != FTW_F)
400 return 0;
402 filename_len = strlen (filename);
403 suffix_len = strlen (GCOV_DATA_SUFFIX);
405 if (filename_len <= suffix_len)
406 return 0;
408 if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
409 return 0;
411 if (verbose)
412 fnotice (stderr, "reading file: %s\n", filename);
414 obj_info = read_gcda_file (filename);
415 if (!obj_info)
416 return 0;
418 obj_info->next = gcov_info_head;
419 gcov_info_head = obj_info;
421 return 0;
423 #endif
425 /* Initializer for reading a profile dir. */
427 static inline void
428 read_profile_dir_init (void)
430 gcov_info_head = 0;
433 /* Driver for read a profile directory and convert into gcov_info list in memory.
434 Return NULL on error,
435 Return the head of gcov_info list on success. */
437 struct gcov_info *
438 gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
440 char *pwd;
441 int ret;
443 read_profile_dir_init ();
445 if (access (dir_name, R_OK) != 0)
447 fnotice (stderr, "cannot access directory %s\n", dir_name);
448 return NULL;
450 pwd = getcwd (NULL, 0);
451 gcc_assert (pwd);
452 ret = chdir (dir_name);
453 if (ret !=0)
455 fnotice (stderr, "%s is not a directory\n", dir_name);
456 return NULL;
458 #ifdef HAVE_FTW_H
459 ftw (".", ftw_read_file, 50);
460 #endif
461 ret = chdir (pwd);
462 free (pwd);
465 return gcov_info_head;;
468 /* This part of the code is to merge profile counters. These
469 variables are set in merge_wrapper and to be used by
470 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
472 /* We save the counter value address to this variable. */
473 static gcov_type *gcov_value_buf;
475 /* The number of counter values to be read by current merging. */
476 static gcov_unsigned_t gcov_value_buf_size;
478 /* The index of counter values being read. */
479 static gcov_unsigned_t gcov_value_buf_pos;
481 /* The weight of current merging. */
482 static unsigned gcov_merge_weight;
484 /* Read a counter value from gcov_value_buf array. */
486 gcov_type
487 gcov_read_counter_mem (void)
489 gcov_type ret;
490 gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
491 ret = *(gcov_value_buf + gcov_value_buf_pos);
492 ++gcov_value_buf_pos;
493 return ret;
496 /* Return the recorded merge weight. */
498 unsigned
499 gcov_get_merge_weight (void)
501 return gcov_merge_weight;
504 /* A wrapper function for merge functions. It sets up the
505 value buffer and weights and then calls the merge function. */
507 static void
508 merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n,
509 gcov_type *v2, unsigned w)
511 gcov_value_buf = v2;
512 gcov_value_buf_pos = 0;
513 gcov_value_buf_size = n;
514 gcov_merge_weight = w;
515 (*f) (v1, n);
518 /* Offline tool to manipulate profile data.
519 This tool targets on matched profiles. But it has some tolerance on
520 unmatched profiles.
521 When merging p1 to p2 (p2 is the dst),
522 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
523 emit warning
524 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
525 specified weight; emit warning.
526 * m.gcda in both p1 and p2:
527 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
528 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
529 p2->m.gcda->f and
530 drop p1->m.gcda->f. A warning is emitted. */
532 /* Add INFO2's counter to INFO1, multiplying by weight W. */
534 static int
535 gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
537 unsigned f_ix;
538 unsigned n_functions = info1->n_functions;
539 int has_mismatch = 0;
541 gcc_assert (info2->n_functions == n_functions);
542 for (f_ix = 0; f_ix < n_functions; f_ix++)
544 unsigned t_ix;
545 const struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
546 const struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
547 const struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
549 if (!gfi_ptr1 || gfi_ptr1->key != info1)
550 continue;
551 if (!gfi_ptr2 || gfi_ptr2->key != info2)
552 continue;
554 if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
556 fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
557 info1->filename);
558 has_mismatch = 1;
559 continue;
561 ci_ptr1 = gfi_ptr1->ctrs;
562 ci_ptr2 = gfi_ptr2->ctrs;
563 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
565 gcov_merge_fn merge1 = info1->merge[t_ix];
566 gcov_merge_fn merge2 = info2->merge[t_ix];
568 gcc_assert (merge1 == merge2);
569 if (!merge1)
570 continue;
571 gcc_assert (ci_ptr1->num == ci_ptr2->num);
572 merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num, ci_ptr2->values, w);
573 ci_ptr1++;
574 ci_ptr2++;
578 return has_mismatch;
581 /* Find and return the match gcov_info object for INFO from ARRAY.
582 SIZE is the length of ARRAY.
583 Return NULL if there is no match. */
585 static struct gcov_info *
586 find_match_gcov_info (struct gcov_info **array, int size,
587 struct gcov_info *info)
589 struct gcov_info *gi_ptr;
590 struct gcov_info *ret = NULL;
591 int i;
593 for (i = 0; i < size; i++)
595 gi_ptr = array[i];
596 if (gi_ptr == 0)
597 continue;
598 if (!strcmp (gi_ptr->filename, info->filename))
600 ret = gi_ptr;
601 array[i] = 0;
602 break;
606 if (ret && ret->n_functions != info->n_functions)
608 fnotice (stderr, "mismatched profiles in %s (%d functions"
609 " vs %d functions)\n",
610 ret->filename,
611 ret->n_functions,
612 info->n_functions);
613 ret = NULL;
615 return ret;
618 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
619 Return 0 on success: without mismatch.
620 Reutrn 1 on error. */
623 gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
624 int w1, int w2)
626 struct gcov_info *gi_ptr;
627 struct gcov_info **tgt_infos;
628 struct gcov_info *tgt_tail;
629 struct gcov_info **in_src_not_tgt;
630 unsigned tgt_cnt = 0, src_cnt = 0;
631 unsigned unmatch_info_cnt = 0;
632 unsigned int i;
634 for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
635 tgt_cnt++;
636 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
637 src_cnt++;
638 tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
639 * tgt_cnt);
640 gcc_assert (tgt_infos);
641 in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
642 * src_cnt);
643 gcc_assert (in_src_not_tgt);
645 for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
646 tgt_infos[i] = gi_ptr;
648 tgt_tail = tgt_infos[tgt_cnt - 1];
650 /* First pass on tgt_profile, we multiply w1 to all counters. */
651 if (w1 > 1)
653 for (i = 0; i < tgt_cnt; i++)
654 gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
657 /* Second pass, add src_profile to the tgt_profile. */
658 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
660 struct gcov_info *gi_ptr1;
662 gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
663 if (gi_ptr1 == NULL)
665 in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
666 continue;
668 gcov_merge (gi_ptr1, gi_ptr, w2);
671 /* For modules in src but not in tgt. We adjust the counter and append. */
672 for (i = 0; i < unmatch_info_cnt; i++)
674 gi_ptr = in_src_not_tgt[i];
675 gcov_merge (gi_ptr, gi_ptr, w2 - 1);
676 gi_ptr->next = NULL;
677 tgt_tail->next = gi_ptr;
678 tgt_tail = gi_ptr;
681 return 0;
684 typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
686 /* Performing FN upon arc counters. */
688 static void
689 __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
690 counter_op_fn fn, void *data1, void *data2)
692 for (; n_counters; counters++, n_counters--)
694 gcov_type val = *counters;
695 *counters = fn(val, data1, data2);
699 /* Performing FN upon ior counters. */
701 static void
702 __gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
703 unsigned n_counters ATTRIBUTE_UNUSED,
704 counter_op_fn fn ATTRIBUTE_UNUSED,
705 void *data1 ATTRIBUTE_UNUSED,
706 void *data2 ATTRIBUTE_UNUSED)
708 /* Do nothing. */
711 /* Performing FN upon time-profile counters. */
713 static void
714 __gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
715 unsigned n_counters ATTRIBUTE_UNUSED,
716 counter_op_fn fn ATTRIBUTE_UNUSED,
717 void *data1 ATTRIBUTE_UNUSED,
718 void *data2 ATTRIBUTE_UNUSED)
720 /* Do nothing. */
723 /* Performaing FN upon delta counters. */
725 static void
726 __gcov_delta_counter_op (gcov_type *counters, unsigned n_counters,
727 counter_op_fn fn, void *data1, void *data2)
729 unsigned i, n_measures;
731 gcc_assert (!(n_counters % 4));
732 n_measures = n_counters / 4;
733 for (i = 0; i < n_measures; i++, counters += 4)
735 counters[2] = fn (counters[2], data1, data2);
736 counters[3] = fn (counters[3], data1, data2);
740 /* Performing FN upon single counters. */
742 static void
743 __gcov_single_counter_op (gcov_type *counters, unsigned n_counters,
744 counter_op_fn fn, void *data1, void *data2)
746 unsigned i, n_measures;
748 gcc_assert (!(n_counters % 3));
749 n_measures = n_counters / 3;
750 for (i = 0; i < n_measures; i++, counters += 3)
752 counters[1] = fn (counters[1], data1, data2);
753 counters[2] = fn (counters[2], data1, data2);
757 /* Performing FN upon indirect-call profile counters. */
759 static void
760 __gcov_icall_topn_counter_op (gcov_type *counters, unsigned n_counters,
761 counter_op_fn fn, void *data1, void *data2)
763 unsigned i;
765 gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS));
766 for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS)
768 unsigned j;
769 gcov_type *value_array = &counters[i + 1];
771 for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
772 value_array[j + 1] = fn (value_array[j + 1], data1, data2);
776 /* Scaling the counter value V by multiplying *(float*) DATA1. */
778 static gcov_type
779 fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
781 float f = *(float *) data1;
782 return (gcov_type) (v * f);
785 /* Scaling the counter value V by multiplying DATA2/DATA1. */
787 static gcov_type
788 int_scale (gcov_type v, void *data1, void *data2)
790 int n = *(int *) data1;
791 int d = *(int *) data2;
792 return (gcov_type) ( RDIV (v,d) * n);
795 /* Type of function used to process counters. */
796 typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
797 counter_op_fn, void *, void *);
799 /* Function array to process profile counters. */
800 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
801 __gcov ## FN_TYPE ## _counter_op,
802 static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
803 #include "gcov-counter.def"
805 #undef DEF_GCOV_COUNTER
807 /* Driver for scaling profile counters. */
810 gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
812 struct gcov_info *gi_ptr;
813 unsigned f_ix;
815 if (verbose)
816 fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
818 /* Scaling the counters. */
819 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
820 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
822 unsigned t_ix;
823 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
824 const struct gcov_ctr_info *ci_ptr;
826 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
827 continue;
829 ci_ptr = gfi_ptr->ctrs;
830 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
832 gcov_merge_fn merge = gi_ptr->merge[t_ix];
834 if (!merge)
835 continue;
836 if (d == 0)
837 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
838 fp_scale, &scale_factor, NULL);
839 else
840 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
841 int_scale, &n, &d);
842 ci_ptr++;
846 return 0;
849 /* Driver to normalize profile counters. */
852 gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
854 struct gcov_info *gi_ptr;
855 gcov_type curr_max_val = 0;
856 unsigned f_ix;
857 unsigned int i;
858 float scale_factor;
860 /* Find the largest count value. */
861 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
862 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
864 unsigned t_ix;
865 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
866 const struct gcov_ctr_info *ci_ptr;
868 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
869 continue;
871 ci_ptr = gfi_ptr->ctrs;
872 for (t_ix = 0; t_ix < 1; t_ix++)
874 for (i = 0; i < ci_ptr->num; i++)
875 if (ci_ptr->values[i] > curr_max_val)
876 curr_max_val = ci_ptr->values[i];
877 ci_ptr++;
881 scale_factor = (float)max_val / curr_max_val;
882 if (verbose)
883 fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
885 return gcov_profile_scale (profile, scale_factor, 0, 0);
888 /* The following variables are defined in gcc/gcov-tool.c. */
889 extern int overlap_func_level;
890 extern int overlap_obj_level;
891 extern int overlap_hot_only;
892 extern int overlap_use_fullname;
893 extern double overlap_hot_threshold;
895 /* Compute the overlap score of two values. The score is defined as:
896 min (V1/SUM_1, V2/SUM_2) */
898 static double
899 calculate_2_entries (const unsigned long v1, const unsigned long v2,
900 const double sum_1, const double sum_2)
902 double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
903 double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
905 if (val2 < val1)
906 val1 = val2;
908 return val1;
911 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
912 SUM_1 is the sum_all for profile1 where GCOV_INFO1 belongs.
913 SUM_2 is the sum_all for profile2 where GCOV_INFO2 belongs.
914 This function also updates cumulative score CUM_1_RESULT and
915 CUM_2_RESULT. */
917 static double
918 compute_one_gcov (const struct gcov_info *gcov_info1,
919 const struct gcov_info *gcov_info2,
920 const double sum_1, const double sum_2,
921 double *cum_1_result, double *cum_2_result)
923 unsigned f_ix;
924 double ret = 0;
925 double cum_1 = 0, cum_2 = 0;
926 const struct gcov_info *gcov_info = 0;
927 double *cum_p;
928 double sum;
930 gcc_assert (gcov_info1 || gcov_info2);
931 if (!gcov_info1)
933 gcov_info = gcov_info2;
934 cum_p = cum_2_result;
935 sum = sum_2;
936 *cum_1_result = 0;
937 } else
938 if (!gcov_info2)
940 gcov_info = gcov_info1;
941 cum_p = cum_1_result;
942 sum = sum_1;
943 *cum_2_result = 0;
946 if (gcov_info)
948 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
950 unsigned t_ix;
951 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
952 if (!gfi_ptr || gfi_ptr->key != gcov_info)
953 continue;
954 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
955 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
957 unsigned c_num;
959 if (!gcov_info->merge[t_ix])
960 continue;
962 for (c_num = 0; c_num < ci_ptr->num; c_num++)
964 cum_1 += ci_ptr->values[c_num] / sum;
966 ci_ptr++;
969 *cum_p = cum_1;
970 return 0.0;
973 for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
975 unsigned t_ix;
976 double func_cum_1 = 0.0;
977 double func_cum_2 = 0.0;
978 double func_val = 0.0;
979 int nonzero = 0;
980 int hot = 0;
981 const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
982 const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
984 if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
985 continue;
986 if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
987 continue;
989 const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
990 const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
991 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
993 unsigned c_num;
995 if (!gcov_info1->merge[t_ix])
996 continue;
998 for (c_num = 0; c_num < ci_ptr1->num; c_num++)
1000 if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
1002 func_val += calculate_2_entries (ci_ptr1->values[c_num],
1003 ci_ptr2->values[c_num],
1004 sum_1, sum_2);
1006 func_cum_1 += ci_ptr1->values[c_num] / sum_1;
1007 func_cum_2 += ci_ptr2->values[c_num] / sum_2;
1008 nonzero = 1;
1009 if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold ||
1010 ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
1011 hot = 1;
1014 ci_ptr1++;
1015 ci_ptr2++;
1017 ret += func_val;
1018 cum_1 += func_cum_1;
1019 cum_2 += func_cum_2;
1020 if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
1022 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1023 gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
1026 *cum_1_result = cum_1;
1027 *cum_2_result = cum_2;
1028 return ret;
1031 /* Test if all counter values in this GCOV_INFO are cold.
1032 "Cold" is defined as the counter value being less than
1033 or equal to THRESHOLD. */
1035 static bool
1036 gcov_info_count_all_cold (const struct gcov_info *gcov_info,
1037 gcov_type threshold)
1039 unsigned f_ix;
1041 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
1043 unsigned t_ix;
1044 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
1046 if (!gfi_ptr || gfi_ptr->key != gcov_info)
1047 continue;
1048 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
1049 for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
1051 unsigned c_num;
1053 if (!gcov_info->merge[t_ix])
1054 continue;
1056 for (c_num = 0; c_num < ci_ptr->num; c_num++)
1058 if (ci_ptr->values[c_num] > threshold)
1059 return false;
1061 ci_ptr++;
1065 return true;
1068 /* Test if all counter values in this GCOV_INFO are 0. */
1070 static bool
1071 gcov_info_count_all_zero (const struct gcov_info *gcov_info)
1073 return gcov_info_count_all_cold (gcov_info, 0);
1076 /* A pair of matched GCOV_INFO.
1077 The flag is a bitvector:
1078 b0: obj1's all counts are 0;
1079 b1: obj1's all counts are cold (but no 0);
1080 b2: obj1 is hot;
1081 b3: no obj1 to match obj2;
1082 b4: obj2's all counts are 0;
1083 b5: obj2's all counts are cold (but no 0);
1084 b6: obj2 is hot;
1085 b7: no obj2 to match obj1;
1087 struct overlap_t {
1088 const struct gcov_info *obj1;
1089 const struct gcov_info *obj2;
1090 char flag;
1093 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1094 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1095 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1097 /* Cumlative overlap dscore for profile1 and profile2. */
1098 static double overlap_sum_1, overlap_sum_2;
1100 /* sum_all for profile1 and profile2. */
1101 static gcov_type p1_sum_all, p2_sum_all;
1103 /* run_max for profile1 and profile2. */
1104 static gcov_type p1_run_max, p2_run_max;
1106 /* The number of gcda files in the profiles. */
1107 static unsigned gcda_files[2];
1109 /* The number of unique gcda files in the profiles
1110 (not existing in the other profile). */
1111 static unsigned unique_gcda_files[2];
1113 /* The number of gcda files that all counter values are 0. */
1114 static unsigned zero_gcda_files[2];
1116 /* The number of gcda files that all counter values are cold (but not 0). */
1117 static unsigned cold_gcda_files[2];
1119 /* The number of gcda files that includes hot counter values. */
1120 static unsigned hot_gcda_files[2];
1122 /* The number of gcda files with hot count value in either profiles. */
1123 static unsigned both_hot_cnt;
1125 /* The number of gcda files with all counts cold (but not 0) in
1126 both profiles. */
1127 static unsigned both_cold_cnt;
1129 /* The number of gcda files with all counts 0 in both profiles. */
1130 static unsigned both_zero_cnt;
1132 /* Extract the basename of the filename NAME. */
1134 static char *
1135 extract_file_basename (const char *name)
1137 char *str;
1138 int len = 0;
1139 char *path = xstrdup (name);
1140 char sep_str[2];
1142 sep_str[0] = DIR_SEPARATOR;
1143 sep_str[1] = 0;
1144 str = strstr(path, sep_str);
1146 len = strlen(str) + 1;
1147 path = &path[strlen(path) - len + 2];
1148 str = strstr(path, sep_str);
1149 } while(str);
1151 return path;
1154 /* Utility function to get the filename. */
1156 static const char *
1157 get_file_basename (const char *name)
1159 if (overlap_use_fullname)
1160 return name;
1161 return extract_file_basename (name);
1164 /* A utility function to set the flag for the gcda files. */
1166 static void
1167 set_flag (struct overlap_t *e)
1169 char flag = 0;
1171 if (!e->obj1)
1173 unique_gcda_files[1]++;
1174 flag = 0x8;
1176 else
1178 gcda_files[0]++;
1179 if (gcov_info_count_all_zero (e->obj1))
1181 zero_gcda_files[0]++;
1182 flag = 0x1;
1184 else
1185 if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
1186 * overlap_hot_threshold))
1188 cold_gcda_files[0]++;
1189 flag = 0x2;
1191 else
1193 hot_gcda_files[0]++;
1194 flag = 0x4;
1198 if (!e->obj2)
1200 unique_gcda_files[0]++;
1201 flag |= (0x8 << 4);
1203 else
1205 gcda_files[1]++;
1206 if (gcov_info_count_all_zero (e->obj2))
1208 zero_gcda_files[1]++;
1209 flag |= (0x1 << 4);
1211 else
1212 if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
1213 * overlap_hot_threshold))
1215 cold_gcda_files[1]++;
1216 flag |= (0x2 << 4);
1218 else
1220 hot_gcda_files[1]++;
1221 flag |= (0x4 << 4);
1225 gcc_assert (flag);
1226 e->flag = flag;
1229 /* Test if INFO1 and INFO2 are from the matched source file.
1230 Return 1 if they match; return 0 otherwise. */
1232 static int
1233 matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
1235 /* For FDO, we have to match the name. This can be expensive.
1236 Maybe we should use hash here. */
1237 if (strcmp (info1->filename, info2->filename))
1238 return 0;
1240 if (info1->n_functions != info2->n_functions)
1242 fnotice (stderr, "mismatched profiles in %s (%d functions"
1243 " vs %d functions)\n",
1244 info1->filename,
1245 info1->n_functions,
1246 info2->n_functions);
1247 return 0;
1249 return 1;
1252 /* Defined in libgcov-driver.c. */
1253 extern gcov_unsigned_t compute_summary (struct gcov_info *,
1254 struct gcov_summary *, size_t *);
1256 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1257 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1258 match and 1.0 meaning a perfect match. */
1260 static double
1261 calculate_overlap (struct gcov_info *gcov_list1,
1262 struct gcov_info *gcov_list2)
1264 struct gcov_summary this_prg;
1265 unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
1266 unsigned int i, j;
1267 size_t max_length;
1268 const struct gcov_info *gi_ptr;
1269 struct overlap_t *all_infos;
1271 compute_summary (gcov_list1, &this_prg, &max_length);
1272 overlap_sum_1 = (double) (this_prg.ctrs[0].sum_all);
1273 p1_sum_all = this_prg.ctrs[0].sum_all;
1274 p1_run_max = this_prg.ctrs[0].run_max;
1275 compute_summary (gcov_list2, &this_prg, &max_length);
1276 overlap_sum_2 = (double) (this_prg.ctrs[0].sum_all);
1277 p2_sum_all = this_prg.ctrs[0].sum_all;
1278 p2_run_max = this_prg.ctrs[0].run_max;
1280 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
1281 list1_cnt++;
1282 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
1283 list2_cnt++;
1284 all_cnt = list1_cnt + list2_cnt;
1285 all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
1286 * all_cnt * 2);
1287 gcc_assert (all_infos);
1289 i = 0;
1290 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
1292 all_infos[i].obj1 = gi_ptr;
1293 all_infos[i].obj2 = 0;
1296 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
1298 all_infos[i].obj1 = 0;
1299 all_infos[i].obj2 = gi_ptr;
1302 for (i = list1_cnt; i < all_cnt; i++)
1304 if (all_infos[i].obj2 == 0)
1305 continue;
1306 for (j = 0; j < list1_cnt; j++)
1308 if (all_infos[j].obj2 != 0)
1309 continue;
1310 if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
1312 all_infos[j].obj2 = all_infos[i].obj2;
1313 all_infos[i].obj2 = 0;
1314 break;
1319 for (i = 0; i < all_cnt; i++)
1320 if (all_infos[i].obj1 || all_infos[i].obj2)
1322 set_flag (all_infos + i);
1323 if (FLAG_ONE_HOT (all_infos[i].flag))
1324 both_hot_cnt++;
1325 if (FLAG_BOTH_COLD(all_infos[i].flag))
1326 both_cold_cnt++;
1327 if (FLAG_BOTH_ZERO(all_infos[i].flag))
1328 both_zero_cnt++;
1331 double prg_val = 0;
1332 double sum_val = 0;
1333 double sum_cum_1 = 0;
1334 double sum_cum_2 = 0;
1336 for (i = 0; i < all_cnt; i++)
1338 double val;
1339 double cum_1, cum_2;
1340 const char *filename;
1342 if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
1343 continue;
1344 if (FLAG_BOTH_ZERO (all_infos[i].flag))
1345 continue;
1347 if (all_infos[i].obj1)
1348 filename = get_file_basename (all_infos[i].obj1->filename);
1349 else
1350 filename = get_file_basename (all_infos[i].obj2->filename);
1352 if (overlap_func_level)
1353 printf("\n processing %36s:\n", filename);
1355 val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
1356 overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
1358 if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
1360 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1361 filename, val*100, cum_1*100, cum_2*100);
1362 sum_val += val;
1363 sum_cum_1 += cum_1;
1364 sum_cum_2 += cum_2;
1367 prg_val += val;
1371 if (overlap_obj_level)
1372 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1373 "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
1375 printf (" Statistics:\n"
1376 " profile1_# profile2_# overlap_#\n");
1377 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
1378 gcda_files[0]-unique_gcda_files[0]);
1379 printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
1380 unique_gcda_files[1]);
1381 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
1382 hot_gcda_files[1], both_hot_cnt);
1383 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
1384 cold_gcda_files[1], both_cold_cnt);
1385 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
1386 zero_gcda_files[1], both_zero_cnt);
1387 printf (" sum_all: %12" PRId64 "\t%12" PRId64 "\n",
1388 p1_sum_all, p2_sum_all);
1389 printf (" run_max: %12" PRId64 "\t%12" PRId64 "\n",
1390 p1_run_max, p2_run_max);
1392 return prg_val;
1395 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1396 PROFILE2.
1397 Return 0 on success: without mismatch. Reutrn 1 on error. */
1400 gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
1402 double result;
1404 result = calculate_overlap (profile1, profile2);
1406 if (result > 0)
1408 printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
1409 return 0;
1411 return 1;