Daily bump.
[official-gcc.git] / libgcc / libgcov-util.c
blob224c190ee6330402151d61d441fb6ec3436d9219
1 /* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
3 /* Copyright (C) 2014-2020 Free Software Foundation, Inc.
4 Contributed by Rong Xu <xur@google.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
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"
35 #include "gcov-io.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. */
44 static int verbose;
46 /* Set verbose flag. */
47 void gcov_set_verbose (void)
49 verbose = 1;
52 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
54 #include "obstack.h"
55 #include <unistd.h>
56 #ifdef HAVE_FTW_H
57 #include <ftw.h>
58 #endif
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. */
95 static void
96 set_fn_ctrs (struct gcov_fn_info *fn_info)
98 int j = 0, i;
100 for (i = 0; i < GCOV_COUNTERS; i++)
102 if (k_ctrs_mask[i] == 0)
103 continue;
104 fn_info->ctrs[j].num = k_ctrs[i].num;
105 fn_info->ctrs[j].values = k_ctrs[i].values;
106 j++;
108 if (k_ctrs_types == 0)
109 k_ctrs_types = j;
110 else
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
120 unsigned tag;
121 char const *name;
122 void (*proc) (unsigned, unsigned);
123 } tag_format_t;
125 /* Handler table for various Tags. */
127 static const tag_format_t tag_table[] =
129 {0, "NOP", NULL},
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},
137 {0, NULL, NULL}
140 /* Handler for reading function tag. */
142 static void
143 tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
145 int i;
147 /* write out previous fn_info. */
148 if (num_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
155 counter types. */
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++)
160 k_ctrs[i].num = 0;
161 k_ctrs_types = 0;
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 ();
167 num_fn_info++;
169 if (verbose)
170 fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
173 /* Handler for reading block tag. */
175 static void
176 tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
178 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
179 gcc_unreachable ();
182 /* Handler for reading flow arc tag. */
184 static void
185 tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
187 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
188 gcc_unreachable ();
191 /* Handler for reading line tag. */
193 static void
194 tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
196 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
197 gcc_unreachable ();
200 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
202 static void
203 tag_counters (unsigned tag, unsigned length)
205 unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
206 gcov_type *values;
207 unsigned ix;
208 unsigned tag_ix;
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));
217 gcc_assert (values);
219 for (ix = 0; ix != n_counts; ix++)
220 values[ix] = gcov_read_counter ();
223 /* Handler for reading summary tag. */
225 static void
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. */
235 static void
236 read_gcda_finalize (struct gcov_info *obj_info)
238 int i;
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
244 and summary. */
245 obj_info->n_functions = num_fn_info;
246 obj_info->functions = (struct gcov_fn_info**) obstack_finish (&fn_info);
248 /* wrap all the counter array. */
249 for (i=0; i< GCOV_COUNTERS; i++)
251 if (k_ctrs_mask[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)
262 unsigned tags[4];
263 unsigned depth = 0;
264 unsigned version;
265 struct gcov_info *obj_info;
266 int i;
268 for (i=0; i< GCOV_COUNTERS; i++)
269 k_ctrs_mask[i] = 0;
270 k_ctrs_types = 0;
272 if (!gcov_open (filename))
274 fnotice (stderr, "%s:cannot open\n", filename);
275 return NULL;
278 /* Read magic. */
279 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
281 fnotice (stderr, "%s:not a gcov data file\n", filename);
282 gcov_close ();
283 return NULL;
286 /* Read version. */
287 version = gcov_read_unsigned ();
288 if (version != GCOV_VERSION)
290 fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
291 gcov_close ();
292 return NULL;
295 /* Instantiate a gcov_info object. */
296 curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
297 sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
299 obj_info->version = version;
300 obstack_init (&fn_info);
301 num_fn_info = 0;
302 curr_fn_info = 0;
303 curr_object_summary = NULL;
305 size_t len = strlen (filename) + 1;
306 char *str_dup = (char*) xmalloc (len);
308 memcpy (str_dup, filename, len);
309 obj_info->filename = str_dup;
312 /* Read stamp. */
313 obj_info->stamp = gcov_read_unsigned ();
315 while (1)
317 gcov_position_t base;
318 unsigned tag, length;
319 tag_format_t const *format;
320 unsigned tag_depth;
321 int error;
322 unsigned mask;
324 tag = gcov_read_unsigned ();
325 if (!tag)
326 break;
327 length = gcov_read_unsigned ();
328 base = gcov_position ();
329 mask = GCOV_TAG_MASK (tag) >> 1;
330 for (tag_depth = 4; mask; mask >>= 8)
332 if (((mask & 0xff) != 0xff))
334 warning (0, "%s:tag %qx is invalid", filename, tag);
335 break;
337 tag_depth--;
339 for (format = tag_table; format->name; format++)
340 if (format->tag == tag)
341 goto found;
342 format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
343 found:;
344 if (tag)
346 if (depth && depth < tag_depth)
348 if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
349 warning (0, "%s:tag %qx is incorrectly nested",
350 filename, tag);
352 depth = tag_depth;
353 tags[depth - 1] = tag;
356 if (format->proc)
358 unsigned long actual_length;
360 (*format->proc) (tag, length);
362 actual_length = gcov_position () - base;
363 if (actual_length > length)
364 warning (0, "%s:record size mismatch %lu bytes overread",
365 filename, actual_length - length);
366 else if (length > actual_length)
367 warning (0, "%s:record size mismatch %lu bytes unread",
368 filename, length - actual_length);
371 gcov_sync (base, length);
372 if ((error = gcov_is_error ()))
374 warning (0, error < 0 ? "%s:counter overflow at %lu" :
375 "%s:read error at %lu", filename,
376 (long unsigned) gcov_position ());
377 break;
381 read_gcda_finalize (obj_info);
382 gcov_close ();
384 return obj_info;
387 #ifdef HAVE_FTW_H
388 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
389 Return a non-zero value to stop the tree walk. */
391 static int
392 ftw_read_file (const char *filename,
393 const struct stat *status ATTRIBUTE_UNUSED,
394 int type)
396 int filename_len;
397 int suffix_len;
398 struct gcov_info *obj_info;
400 /* Only read regular files. */
401 if (type != FTW_F)
402 return 0;
404 filename_len = strlen (filename);
405 suffix_len = strlen (GCOV_DATA_SUFFIX);
407 if (filename_len <= suffix_len)
408 return 0;
410 if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
411 return 0;
413 if (verbose)
414 fnotice (stderr, "reading file: %s\n", filename);
416 obj_info = read_gcda_file (filename);
417 if (!obj_info)
418 return 0;
420 obj_info->next = gcov_info_head;
421 gcov_info_head = obj_info;
423 return 0;
425 #endif
427 /* Initializer for reading a profile dir. */
429 static inline void
430 read_profile_dir_init (void)
432 gcov_info_head = 0;
435 /* Driver for read a profile directory and convert into gcov_info list in memory.
436 Return NULL on error,
437 Return the head of gcov_info list on success. */
439 struct gcov_info *
440 gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
442 char *pwd;
443 int ret;
445 read_profile_dir_init ();
447 if (access (dir_name, R_OK) != 0)
449 fnotice (stderr, "cannot access directory %s\n", dir_name);
450 return NULL;
452 pwd = getcwd (NULL, 0);
453 gcc_assert (pwd);
454 ret = chdir (dir_name);
455 if (ret !=0)
457 fnotice (stderr, "%s is not a directory\n", dir_name);
458 return NULL;
460 #ifdef HAVE_FTW_H
461 ftw (".", ftw_read_file, 50);
462 #endif
463 chdir (pwd);
464 free (pwd);
466 return gcov_info_head;;
469 /* This part of the code is to merge profile counters. These
470 variables are set in merge_wrapper and to be used by
471 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
473 /* We save the counter value address to this variable. */
474 static gcov_type *gcov_value_buf;
476 /* The number of counter values to be read by current merging. */
477 static gcov_unsigned_t gcov_value_buf_size;
479 /* The index of counter values being read. */
480 static gcov_unsigned_t gcov_value_buf_pos;
482 /* The weight of current merging. */
483 static unsigned gcov_merge_weight;
485 /* Read a counter value from gcov_value_buf array. */
487 gcov_type
488 gcov_read_counter_mem (void)
490 gcov_type ret;
491 gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
492 ret = *(gcov_value_buf + gcov_value_buf_pos);
493 ++gcov_value_buf_pos;
494 return ret;
497 /* Return the recorded merge weight. */
499 unsigned
500 gcov_get_merge_weight (void)
502 return gcov_merge_weight;
505 /* A wrapper function for merge functions. It sets up the
506 value buffer and weights and then calls the merge function. */
508 static void
509 merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n1,
510 gcov_type *v2, gcov_unsigned_t n2, unsigned w)
512 gcov_value_buf = v2;
513 gcov_value_buf_pos = 0;
514 gcov_value_buf_size = n2;
515 gcov_merge_weight = w;
516 (*f) (v1, n1);
519 /* Convert on disk representation of a TOPN counter to in memory representation
520 that is expected from __gcov_merge_topn function. */
522 static void
523 topn_to_memory_representation (struct gcov_ctr_info *info)
525 auto_vec<gcov_type> output;
526 gcov_type *values = info->values;
527 int count = info->num;
529 while (count > 0)
531 output.safe_push (values[0]);
532 gcov_type n = values[1];
533 output.safe_push (n);
534 if (n > 0)
536 struct gcov_kvp *tuples
537 = (struct gcov_kvp *)xcalloc (sizeof (struct gcov_kvp), n);
538 for (unsigned i = 0; i < n - 1; i++)
539 tuples[i].next = &tuples[i + 1];
540 for (unsigned i = 0; i < n; i++)
542 tuples[i].value = values[2 + 2 * i];
543 tuples[i].count = values[2 + 2 * i + 1];
545 output.safe_push ((intptr_t)&tuples[0]);
547 else
548 output.safe_push (0);
550 unsigned len = 2 * n + 2;
551 values += len;
552 count -= len;
554 gcc_assert (count == 0);
556 /* Allocate new buffer and copy it there. */
557 info->num = output.length ();
558 info->values = (gcov_type *)xmalloc (sizeof (gcov_type) * info->num);
559 for (unsigned i = 0; i < info->num; i++)
560 info->values[i] = output[i];
563 /* Offline tool to manipulate profile data.
564 This tool targets on matched profiles. But it has some tolerance on
565 unmatched profiles.
566 When merging p1 to p2 (p2 is the dst),
567 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
568 emit warning
569 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
570 specified weight; emit warning.
571 * m.gcda in both p1 and p2:
572 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
573 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
574 p2->m.gcda->f and
575 drop p1->m.gcda->f. A warning is emitted. */
577 /* Add INFO2's counter to INFO1, multiplying by weight W. */
579 static int
580 gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
582 unsigned f_ix;
583 unsigned n_functions = info1->n_functions;
584 int has_mismatch = 0;
586 gcc_assert (info2->n_functions == n_functions);
587 for (f_ix = 0; f_ix < n_functions; f_ix++)
589 unsigned t_ix;
590 struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
591 struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
592 struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
594 if (!gfi_ptr1 || gfi_ptr1->key != info1)
595 continue;
596 if (!gfi_ptr2 || gfi_ptr2->key != info2)
597 continue;
599 if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
601 fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
602 info1->filename);
603 has_mismatch = 1;
604 continue;
606 ci_ptr1 = gfi_ptr1->ctrs;
607 ci_ptr2 = gfi_ptr2->ctrs;
608 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
610 gcov_merge_fn merge1 = info1->merge[t_ix];
611 gcov_merge_fn merge2 = info2->merge[t_ix];
613 gcc_assert (merge1 == merge2);
614 if (!merge1)
615 continue;
617 if (merge1 == __gcov_merge_topn)
618 topn_to_memory_representation (ci_ptr1);
619 else
620 gcc_assert (ci_ptr1->num == ci_ptr2->num);
622 merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num,
623 ci_ptr2->values, ci_ptr2->num, w);
624 ci_ptr1++;
625 ci_ptr2++;
629 return has_mismatch;
632 /* Find and return the match gcov_info object for INFO from ARRAY.
633 SIZE is the length of ARRAY.
634 Return NULL if there is no match. */
636 static struct gcov_info *
637 find_match_gcov_info (struct gcov_info **array, int size,
638 struct gcov_info *info)
640 struct gcov_info *gi_ptr;
641 struct gcov_info *ret = NULL;
642 int i;
644 for (i = 0; i < size; i++)
646 gi_ptr = array[i];
647 if (gi_ptr == 0)
648 continue;
649 if (!strcmp (gi_ptr->filename, info->filename))
651 ret = gi_ptr;
652 array[i] = 0;
653 break;
657 if (ret && ret->n_functions != info->n_functions)
659 fnotice (stderr, "mismatched profiles in %s (%d functions"
660 " vs %d functions)\n",
661 ret->filename,
662 ret->n_functions,
663 info->n_functions);
664 ret = NULL;
666 return ret;
669 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
670 Return 0 on success: without mismatch.
671 Reutrn 1 on error. */
674 gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
675 int w1, int w2)
677 struct gcov_info *gi_ptr;
678 struct gcov_info **tgt_infos;
679 struct gcov_info *tgt_tail;
680 struct gcov_info **in_src_not_tgt;
681 unsigned tgt_cnt = 0, src_cnt = 0;
682 unsigned unmatch_info_cnt = 0;
683 unsigned int i;
685 for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
686 tgt_cnt++;
687 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
688 src_cnt++;
689 tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
690 * tgt_cnt);
691 gcc_assert (tgt_infos);
692 in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
693 * src_cnt);
694 gcc_assert (in_src_not_tgt);
696 for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
697 tgt_infos[i] = gi_ptr;
699 tgt_tail = tgt_infos[tgt_cnt - 1];
701 /* First pass on tgt_profile, we multiply w1 to all counters. */
702 if (w1 > 1)
704 for (i = 0; i < tgt_cnt; i++)
705 gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
708 /* Second pass, add src_profile to the tgt_profile. */
709 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
711 struct gcov_info *gi_ptr1;
713 gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
714 if (gi_ptr1 == NULL)
716 in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
717 continue;
719 gcov_merge (gi_ptr1, gi_ptr, w2);
722 /* For modules in src but not in tgt. We adjust the counter and append. */
723 for (i = 0; i < unmatch_info_cnt; i++)
725 gi_ptr = in_src_not_tgt[i];
726 gcov_merge (gi_ptr, gi_ptr, w2 - 1);
727 gi_ptr->next = NULL;
728 tgt_tail->next = gi_ptr;
729 tgt_tail = gi_ptr;
732 free (in_src_not_tgt);
733 free (tgt_infos);
735 return 0;
738 typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
740 /* Performing FN upon arc counters. */
742 static void
743 __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
744 counter_op_fn fn, void *data1, void *data2)
746 for (; n_counters; counters++, n_counters--)
748 gcov_type val = *counters;
749 *counters = fn(val, data1, data2);
753 /* Performing FN upon ior counters. */
755 static void
756 __gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
757 unsigned n_counters ATTRIBUTE_UNUSED,
758 counter_op_fn fn ATTRIBUTE_UNUSED,
759 void *data1 ATTRIBUTE_UNUSED,
760 void *data2 ATTRIBUTE_UNUSED)
762 /* Do nothing. */
765 /* Performing FN upon time-profile counters. */
767 static void
768 __gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
769 unsigned n_counters ATTRIBUTE_UNUSED,
770 counter_op_fn fn ATTRIBUTE_UNUSED,
771 void *data1 ATTRIBUTE_UNUSED,
772 void *data2 ATTRIBUTE_UNUSED)
774 /* Do nothing. */
777 /* Performing FN upon TOP N counters. */
779 static void
780 __gcov_topn_counter_op (gcov_type *counters, unsigned n_counters,
781 counter_op_fn fn, void *data1, void *data2)
783 unsigned i, n_measures;
785 gcc_assert (!(n_counters % 3));
786 n_measures = n_counters / 3;
787 for (i = 0; i < n_measures; i++, counters += 3)
789 counters[1] = fn (counters[1], data1, data2);
790 counters[2] = fn (counters[2], data1, data2);
794 /* Scaling the counter value V by multiplying *(float*) DATA1. */
796 static gcov_type
797 fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
799 float f = *(float *) data1;
800 return (gcov_type) (v * f);
803 /* Scaling the counter value V by multiplying DATA2/DATA1. */
805 static gcov_type
806 int_scale (gcov_type v, void *data1, void *data2)
808 int n = *(int *) data1;
809 int d = *(int *) data2;
810 return (gcov_type) ( RDIV (v,d) * n);
813 /* Type of function used to process counters. */
814 typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
815 counter_op_fn, void *, void *);
817 /* Function array to process profile counters. */
818 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
819 __gcov ## FN_TYPE ## _counter_op,
820 static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
821 #include "gcov-counter.def"
823 #undef DEF_GCOV_COUNTER
825 /* Driver for scaling profile counters. */
828 gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
830 struct gcov_info *gi_ptr;
831 unsigned f_ix;
833 if (verbose)
834 fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
836 /* Scaling the counters. */
837 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
838 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
840 unsigned t_ix;
841 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
842 const struct gcov_ctr_info *ci_ptr;
844 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
845 continue;
847 ci_ptr = gfi_ptr->ctrs;
848 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
850 gcov_merge_fn merge = gi_ptr->merge[t_ix];
852 if (!merge)
853 continue;
854 if (d == 0)
855 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
856 fp_scale, &scale_factor, NULL);
857 else
858 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
859 int_scale, &n, &d);
860 ci_ptr++;
864 return 0;
867 /* Driver to normalize profile counters. */
870 gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
872 struct gcov_info *gi_ptr;
873 gcov_type curr_max_val = 0;
874 unsigned f_ix;
875 unsigned int i;
876 float scale_factor;
878 /* Find the largest count value. */
879 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
880 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
882 unsigned t_ix;
883 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
884 const struct gcov_ctr_info *ci_ptr;
886 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
887 continue;
889 ci_ptr = gfi_ptr->ctrs;
890 for (t_ix = 0; t_ix < 1; t_ix++)
892 for (i = 0; i < ci_ptr->num; i++)
893 if (ci_ptr->values[i] > curr_max_val)
894 curr_max_val = ci_ptr->values[i];
895 ci_ptr++;
899 scale_factor = (float)max_val / curr_max_val;
900 if (verbose)
901 fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
903 return gcov_profile_scale (profile, scale_factor, 0, 0);
906 /* The following variables are defined in gcc/gcov-tool.c. */
907 extern int overlap_func_level;
908 extern int overlap_obj_level;
909 extern int overlap_hot_only;
910 extern int overlap_use_fullname;
911 extern double overlap_hot_threshold;
913 /* Compute the overlap score of two values. The score is defined as:
914 min (V1/SUM_1, V2/SUM_2) */
916 static double
917 calculate_2_entries (const unsigned long v1, const unsigned long v2,
918 const double sum_1, const double sum_2)
920 double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
921 double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
923 if (val2 < val1)
924 val1 = val2;
926 return val1;
929 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
930 This function also updates cumulative score CUM_1_RESULT and
931 CUM_2_RESULT. */
933 static double
934 compute_one_gcov (const struct gcov_info *gcov_info1,
935 const struct gcov_info *gcov_info2,
936 const double sum_1, const double sum_2,
937 double *cum_1_result, double *cum_2_result)
939 unsigned f_ix;
940 double ret = 0;
941 double cum_1 = 0, cum_2 = 0;
942 const struct gcov_info *gcov_info = 0;
943 double *cum_p;
944 double sum;
946 gcc_assert (gcov_info1 || gcov_info2);
947 if (!gcov_info1)
949 gcov_info = gcov_info2;
950 cum_p = cum_2_result;
951 sum = sum_2;
952 *cum_1_result = 0;
953 } else
954 if (!gcov_info2)
956 gcov_info = gcov_info1;
957 cum_p = cum_1_result;
958 sum = sum_1;
959 *cum_2_result = 0;
962 if (gcov_info)
964 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
966 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
967 if (!gfi_ptr || gfi_ptr->key != gcov_info)
968 continue;
969 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
970 unsigned c_num;
971 for (c_num = 0; c_num < ci_ptr->num; c_num++)
972 cum_1 += ci_ptr->values[c_num] / sum;
974 *cum_p = cum_1;
975 return 0.0;
978 for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
980 double func_cum_1 = 0.0;
981 double func_cum_2 = 0.0;
982 double func_val = 0.0;
983 int nonzero = 0;
984 int hot = 0;
985 const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
986 const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
988 if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
989 continue;
990 if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
991 continue;
993 const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
994 const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
995 unsigned c_num;
996 for (c_num = 0; c_num < ci_ptr1->num; c_num++)
998 if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
1000 func_val += calculate_2_entries (ci_ptr1->values[c_num],
1001 ci_ptr2->values[c_num],
1002 sum_1, sum_2);
1004 func_cum_1 += ci_ptr1->values[c_num] / sum_1;
1005 func_cum_2 += ci_ptr2->values[c_num] / sum_2;
1006 nonzero = 1;
1007 if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
1008 || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
1009 hot = 1;
1013 ret += func_val;
1014 cum_1 += func_cum_1;
1015 cum_2 += func_cum_2;
1016 if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
1018 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1019 gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
1022 *cum_1_result = cum_1;
1023 *cum_2_result = cum_2;
1024 return ret;
1027 /* Test if all counter values in this GCOV_INFO are cold.
1028 "Cold" is defined as the counter value being less than
1029 or equal to THRESHOLD. */
1031 static bool
1032 gcov_info_count_all_cold (const struct gcov_info *gcov_info,
1033 gcov_type threshold)
1035 unsigned f_ix;
1037 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
1039 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
1041 if (!gfi_ptr || gfi_ptr->key != gcov_info)
1042 continue;
1043 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
1044 for (unsigned c_num = 0; c_num < ci_ptr->num; c_num++)
1045 if (ci_ptr->values[c_num] > threshold)
1046 return false;
1049 return true;
1052 /* Test if all counter values in this GCOV_INFO are 0. */
1054 static bool
1055 gcov_info_count_all_zero (const struct gcov_info *gcov_info)
1057 return gcov_info_count_all_cold (gcov_info, 0);
1060 /* A pair of matched GCOV_INFO.
1061 The flag is a bitvector:
1062 b0: obj1's all counts are 0;
1063 b1: obj1's all counts are cold (but no 0);
1064 b2: obj1 is hot;
1065 b3: no obj1 to match obj2;
1066 b4: obj2's all counts are 0;
1067 b5: obj2's all counts are cold (but no 0);
1068 b6: obj2 is hot;
1069 b7: no obj2 to match obj1;
1071 struct overlap_t {
1072 const struct gcov_info *obj1;
1073 const struct gcov_info *obj2;
1074 char flag;
1077 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1078 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1079 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1081 /* Cumlative overlap dscore for profile1 and profile2. */
1082 static double overlap_sum_1, overlap_sum_2;
1084 /* The number of gcda files in the profiles. */
1085 static unsigned gcda_files[2];
1087 /* The number of unique gcda files in the profiles
1088 (not existing in the other profile). */
1089 static unsigned unique_gcda_files[2];
1091 /* The number of gcda files that all counter values are 0. */
1092 static unsigned zero_gcda_files[2];
1094 /* The number of gcda files that all counter values are cold (but not 0). */
1095 static unsigned cold_gcda_files[2];
1097 /* The number of gcda files that includes hot counter values. */
1098 static unsigned hot_gcda_files[2];
1100 /* The number of gcda files with hot count value in either profiles. */
1101 static unsigned both_hot_cnt;
1103 /* The number of gcda files with all counts cold (but not 0) in
1104 both profiles. */
1105 static unsigned both_cold_cnt;
1107 /* The number of gcda files with all counts 0 in both profiles. */
1108 static unsigned both_zero_cnt;
1110 /* Extract the basename of the filename NAME. */
1112 static char *
1113 extract_file_basename (const char *name)
1115 char *str;
1116 int len = 0;
1117 char *path = xstrdup (name);
1118 char sep_str[2];
1120 sep_str[0] = DIR_SEPARATOR;
1121 sep_str[1] = 0;
1122 str = strstr(path, sep_str);
1124 len = strlen(str) + 1;
1125 path = &path[strlen(path) - len + 2];
1126 str = strstr(path, sep_str);
1127 } while(str);
1129 return path;
1132 /* Utility function to get the filename. */
1134 static const char *
1135 get_file_basename (const char *name)
1137 if (overlap_use_fullname)
1138 return name;
1139 return extract_file_basename (name);
1142 /* A utility function to set the flag for the gcda files. */
1144 static void
1145 set_flag (struct overlap_t *e)
1147 char flag = 0;
1149 if (!e->obj1)
1151 unique_gcda_files[1]++;
1152 flag = 0x8;
1154 else
1156 gcda_files[0]++;
1157 if (gcov_info_count_all_zero (e->obj1))
1159 zero_gcda_files[0]++;
1160 flag = 0x1;
1162 else
1163 if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
1164 * overlap_hot_threshold))
1166 cold_gcda_files[0]++;
1167 flag = 0x2;
1169 else
1171 hot_gcda_files[0]++;
1172 flag = 0x4;
1176 if (!e->obj2)
1178 unique_gcda_files[0]++;
1179 flag |= (0x8 << 4);
1181 else
1183 gcda_files[1]++;
1184 if (gcov_info_count_all_zero (e->obj2))
1186 zero_gcda_files[1]++;
1187 flag |= (0x1 << 4);
1189 else
1190 if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
1191 * overlap_hot_threshold))
1193 cold_gcda_files[1]++;
1194 flag |= (0x2 << 4);
1196 else
1198 hot_gcda_files[1]++;
1199 flag |= (0x4 << 4);
1203 gcc_assert (flag);
1204 e->flag = flag;
1207 /* Test if INFO1 and INFO2 are from the matched source file.
1208 Return 1 if they match; return 0 otherwise. */
1210 static int
1211 matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
1213 /* For FDO, we have to match the name. This can be expensive.
1214 Maybe we should use hash here. */
1215 if (strcmp (info1->filename, info2->filename))
1216 return 0;
1218 if (info1->n_functions != info2->n_functions)
1220 fnotice (stderr, "mismatched profiles in %s (%d functions"
1221 " vs %d functions)\n",
1222 info1->filename,
1223 info1->n_functions,
1224 info2->n_functions);
1225 return 0;
1227 return 1;
1230 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1231 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1232 match and 1.0 meaning a perfect match. */
1234 static double
1235 calculate_overlap (struct gcov_info *gcov_list1,
1236 struct gcov_info *gcov_list2)
1238 unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
1239 unsigned int i, j;
1240 const struct gcov_info *gi_ptr;
1241 struct overlap_t *all_infos;
1243 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
1244 list1_cnt++;
1245 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
1246 list2_cnt++;
1247 all_cnt = list1_cnt + list2_cnt;
1248 all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
1249 * all_cnt * 2);
1250 gcc_assert (all_infos);
1252 i = 0;
1253 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
1255 all_infos[i].obj1 = gi_ptr;
1256 all_infos[i].obj2 = 0;
1259 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
1261 all_infos[i].obj1 = 0;
1262 all_infos[i].obj2 = gi_ptr;
1265 for (i = list1_cnt; i < all_cnt; i++)
1267 if (all_infos[i].obj2 == 0)
1268 continue;
1269 for (j = 0; j < list1_cnt; j++)
1271 if (all_infos[j].obj2 != 0)
1272 continue;
1273 if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
1275 all_infos[j].obj2 = all_infos[i].obj2;
1276 all_infos[i].obj2 = 0;
1277 break;
1282 for (i = 0; i < all_cnt; i++)
1283 if (all_infos[i].obj1 || all_infos[i].obj2)
1285 set_flag (all_infos + i);
1286 if (FLAG_ONE_HOT (all_infos[i].flag))
1287 both_hot_cnt++;
1288 if (FLAG_BOTH_COLD(all_infos[i].flag))
1289 both_cold_cnt++;
1290 if (FLAG_BOTH_ZERO(all_infos[i].flag))
1291 both_zero_cnt++;
1294 double prg_val = 0;
1295 double sum_val = 0;
1296 double sum_cum_1 = 0;
1297 double sum_cum_2 = 0;
1299 for (i = 0; i < all_cnt; i++)
1301 double val;
1302 double cum_1, cum_2;
1303 const char *filename;
1305 if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
1306 continue;
1307 if (FLAG_BOTH_ZERO (all_infos[i].flag))
1308 continue;
1310 if (all_infos[i].obj1)
1311 filename = get_file_basename (all_infos[i].obj1->filename);
1312 else
1313 filename = get_file_basename (all_infos[i].obj2->filename);
1315 if (overlap_func_level)
1316 printf("\n processing %36s:\n", filename);
1318 val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
1319 overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
1321 if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
1323 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1324 filename, val*100, cum_1*100, cum_2*100);
1325 sum_val += val;
1326 sum_cum_1 += cum_1;
1327 sum_cum_2 += cum_2;
1330 prg_val += val;
1334 free (all_infos);
1336 if (overlap_obj_level)
1337 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1338 "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
1340 printf (" Statistics:\n"
1341 " profile1_# profile2_# overlap_#\n");
1342 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
1343 gcda_files[0]-unique_gcda_files[0]);
1344 printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
1345 unique_gcda_files[1]);
1346 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
1347 hot_gcda_files[1], both_hot_cnt);
1348 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
1349 cold_gcda_files[1], both_cold_cnt);
1350 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
1351 zero_gcda_files[1], both_zero_cnt);
1353 return prg_val;
1356 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1357 PROFILE2.
1358 Return 0 on success: without mismatch. Reutrn 1 on error. */
1361 gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
1363 double result;
1365 result = calculate_overlap (profile1, profile2);
1367 if (result > 0)
1369 printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
1370 return 0;
1372 return 1;