]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgcc/libgcov-util.c
gcov-tool: fix merge operation for summary
[thirdparty/gcc.git] / libgcc / libgcov-util.c
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>.
5
6 This file is part of GCC.
7
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.
12
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.
17
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.
21
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/>. */
26
27
28 #define IN_GCOV_TOOL 1
29
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"
36
37 /* Borrowed from basic-block.h. */
38 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
39
40 extern gcov_position_t gcov_position();
41 extern int gcov_is_error();
42
43 /* Verbose mode for debug. */
44 static int verbose;
45
46 /* Set verbose flag. */
47 void gcov_set_verbose (void)
48 {
49 verbose = 1;
50 }
51
52 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
53
54 #include "obstack.h"
55 #include <unistd.h>
56 #ifdef HAVE_FTW_H
57 #include <ftw.h>
58 #endif
59
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);
66
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
84 /* Merge functions for counters. */
85 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
86 static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
87 #include "gcov-counter.def"
88 };
89 #undef DEF_GCOV_COUNTER
90
91 /* Set the ctrs field in gcov_fn_info object FN_INFO. */
92
93 static void
94 set_fn_ctrs (struct gcov_fn_info *fn_info)
95 {
96 int j = 0, i;
97
98 for (i = 0; i < GCOV_COUNTERS; i++)
99 {
100 if (k_ctrs_mask[i] == 0)
101 continue;
102 fn_info->ctrs[j].num = k_ctrs[i].num;
103 fn_info->ctrs[j].values = k_ctrs[i].values;
104 j++;
105 }
106 if (k_ctrs_types == 0)
107 k_ctrs_types = j;
108 else
109 gcc_assert (j == k_ctrs_types);
110 }
111
112 /* For each tag in gcda file, we have an entry here.
113 TAG is the tag value; NAME is the tag name; and
114 PROC is the handler function. */
115
116 typedef struct tag_format
117 {
118 unsigned tag;
119 char const *name;
120 void (*proc) (unsigned, unsigned);
121 } tag_format_t;
122
123 /* Handler table for various Tags. */
124
125 static const tag_format_t tag_table[] =
126 {
127 {0, "NOP", NULL},
128 {0, "UNKNOWN", NULL},
129 {0, "COUNTERS", tag_counters},
130 {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
131 {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
132 {GCOV_TAG_ARCS, "ARCS", tag_arcs},
133 {GCOV_TAG_LINES, "LINES", tag_lines},
134 {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
135 {0, NULL, NULL}
136 };
137
138 /* Handler for reading function tag. */
139
140 static void
141 tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
142 {
143 int i;
144
145 /* write out previous fn_info. */
146 if (num_fn_info)
147 {
148 set_fn_ctrs (curr_fn_info);
149 obstack_ptr_grow (&fn_info, curr_fn_info);
150 }
151
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);
156
157 for (i = 0; i < GCOV_COUNTERS; i++)
158 k_ctrs[i].num = 0;
159 k_ctrs_types = 0;
160
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++;
166
167 if (verbose)
168 fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
169 }
170
171 /* Handler for reading block tag. */
172
173 static void
174 tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
175 {
176 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
177 gcc_unreachable ();
178 }
179
180 /* Handler for reading flow arc tag. */
181
182 static void
183 tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
184 {
185 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
186 gcc_unreachable ();
187 }
188
189 /* Handler for reading line tag. */
190
191 static void
192 tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
193 {
194 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
195 gcc_unreachable ();
196 }
197
198 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
199
200 static void
201 tag_counters (unsigned tag, unsigned length)
202 {
203 unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
204 gcov_type *values;
205 unsigned ix;
206 unsigned tag_ix;
207
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;
213
214 k_ctrs[tag_ix].values = values = (gcov_type *) xmalloc (n_counts * sizeof (gcov_type));
215 gcc_assert (values);
216
217 for (ix = 0; ix != n_counts; ix++)
218 values[ix] = gcov_read_counter ();
219 }
220
221 /* Handler for reading summary tag. */
222
223 static void
224 tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
225 {
226 gcov_read_summary (&curr_gcov_info->summary);
227 }
228
229 /* This function is called at the end of reading a gcda file.
230 It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO. */
231
232 static void
233 read_gcda_finalize (struct gcov_info *obj_info)
234 {
235 int i;
236
237 set_fn_ctrs (curr_fn_info);
238 obstack_ptr_grow (&fn_info, curr_fn_info);
239
240 /* We set the following fields: merge, n_functions, functions
241 and summary. */
242 obj_info->n_functions = num_fn_info;
243 obj_info->functions = (struct gcov_fn_info**) obstack_finish (&fn_info);
244
245 /* wrap all the counter array. */
246 for (i=0; i< GCOV_COUNTERS; i++)
247 {
248 if (k_ctrs_mask[i])
249 obj_info->merge[i] = ctr_merge_functions[i];
250 }
251 }
252
253 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
254 Program level summary CURRENT_SUMMARY will also be updated. */
255
256 static struct gcov_info *
257 read_gcda_file (const char *filename)
258 {
259 unsigned tags[4];
260 unsigned depth = 0;
261 unsigned version;
262 struct gcov_info *obj_info;
263 int i;
264
265 for (i=0; i< GCOV_COUNTERS; i++)
266 k_ctrs_mask[i] = 0;
267 k_ctrs_types = 0;
268
269 if (!gcov_open (filename))
270 {
271 fnotice (stderr, "%s:cannot open\n", filename);
272 return NULL;
273 }
274
275 /* Read magic. */
276 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
277 {
278 fnotice (stderr, "%s:not a gcov data file\n", filename);
279 gcov_close ();
280 return NULL;
281 }
282
283 /* Read version. */
284 version = gcov_read_unsigned ();
285 if (version != GCOV_VERSION)
286 {
287 fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
288 gcov_close ();
289 return NULL;
290 }
291
292 /* Instantiate a gcov_info object. */
293 curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
294 sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
295
296 obj_info->version = version;
297 obstack_init (&fn_info);
298 num_fn_info = 0;
299 curr_fn_info = 0;
300 {
301 size_t len = strlen (filename) + 1;
302 char *str_dup = (char*) xmalloc (len);
303
304 memcpy (str_dup, filename, len);
305 obj_info->filename = str_dup;
306 }
307
308 /* Read stamp. */
309 obj_info->stamp = gcov_read_unsigned ();
310
311 while (1)
312 {
313 gcov_position_t base;
314 unsigned tag, length;
315 tag_format_t const *format;
316 unsigned tag_depth;
317 int error;
318 unsigned mask;
319
320 tag = gcov_read_unsigned ();
321 if (!tag)
322 break;
323 length = gcov_read_unsigned ();
324 base = gcov_position ();
325 mask = GCOV_TAG_MASK (tag) >> 1;
326 for (tag_depth = 4; mask; mask >>= 8)
327 {
328 if (((mask & 0xff) != 0xff))
329 {
330 warning (0, "%s:tag %qx is invalid", filename, tag);
331 break;
332 }
333 tag_depth--;
334 }
335 for (format = tag_table; format->name; format++)
336 if (format->tag == tag)
337 goto found;
338 format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
339 found:;
340 if (tag)
341 {
342 if (depth && depth < tag_depth)
343 {
344 if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
345 warning (0, "%s:tag %qx is incorrectly nested",
346 filename, tag);
347 }
348 depth = tag_depth;
349 tags[depth - 1] = tag;
350 }
351
352 if (format->proc)
353 {
354 unsigned long actual_length;
355
356 (*format->proc) (tag, length);
357
358 actual_length = gcov_position () - base;
359 if (actual_length > length)
360 warning (0, "%s:record size mismatch %lu bytes overread",
361 filename, actual_length - length);
362 else if (length > actual_length)
363 warning (0, "%s:record size mismatch %lu bytes unread",
364 filename, length - actual_length);
365 }
366
367 gcov_sync (base, length);
368 if ((error = gcov_is_error ()))
369 {
370 warning (0, error < 0 ? "%s:counter overflow at %lu" :
371 "%s:read error at %lu", filename,
372 (long unsigned) gcov_position ());
373 break;
374 }
375 }
376
377 read_gcda_finalize (obj_info);
378 gcov_close ();
379
380 return obj_info;
381 }
382
383 #ifdef HAVE_FTW_H
384 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
385 Return a non-zero value to stop the tree walk. */
386
387 static int
388 ftw_read_file (const char *filename,
389 const struct stat *status ATTRIBUTE_UNUSED,
390 int type)
391 {
392 int filename_len;
393 int suffix_len;
394 struct gcov_info *obj_info;
395
396 /* Only read regular files. */
397 if (type != FTW_F)
398 return 0;
399
400 filename_len = strlen (filename);
401 suffix_len = strlen (GCOV_DATA_SUFFIX);
402
403 if (filename_len <= suffix_len)
404 return 0;
405
406 if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
407 return 0;
408
409 if (verbose)
410 fnotice (stderr, "reading file: %s\n", filename);
411
412 obj_info = read_gcda_file (filename);
413 if (!obj_info)
414 return 0;
415
416 obj_info->next = gcov_info_head;
417 gcov_info_head = obj_info;
418
419 return 0;
420 }
421 #endif
422
423 /* Initializer for reading a profile dir. */
424
425 static inline void
426 read_profile_dir_init (void)
427 {
428 gcov_info_head = 0;
429 }
430
431 /* Driver for read a profile directory and convert into gcov_info list in memory.
432 Return NULL on error,
433 Return the head of gcov_info list on success. */
434
435 struct gcov_info *
436 gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
437 {
438 char *pwd;
439 int ret;
440
441 read_profile_dir_init ();
442
443 if (access (dir_name, R_OK) != 0)
444 {
445 fnotice (stderr, "cannot access directory %s\n", dir_name);
446 return NULL;
447 }
448 pwd = getcwd (NULL, 0);
449 gcc_assert (pwd);
450 ret = chdir (dir_name);
451 if (ret !=0)
452 {
453 fnotice (stderr, "%s is not a directory\n", dir_name);
454 return NULL;
455 }
456 #ifdef HAVE_FTW_H
457 ftw (".", ftw_read_file, 50);
458 #endif
459 chdir (pwd);
460 free (pwd);
461
462 return gcov_info_head;;
463 }
464
465 /* This part of the code is to merge profile counters. These
466 variables are set in merge_wrapper and to be used by
467 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
468
469 /* We save the counter value address to this variable. */
470 static gcov_type *gcov_value_buf;
471
472 /* The number of counter values to be read by current merging. */
473 static gcov_unsigned_t gcov_value_buf_size;
474
475 /* The index of counter values being read. */
476 static gcov_unsigned_t gcov_value_buf_pos;
477
478 /* The weight of current merging. */
479 static unsigned gcov_merge_weight;
480
481 /* Read a counter value from gcov_value_buf array. */
482
483 gcov_type
484 gcov_read_counter_mem (void)
485 {
486 gcov_type ret;
487 gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
488 ret = *(gcov_value_buf + gcov_value_buf_pos);
489 ++gcov_value_buf_pos;
490 return ret;
491 }
492
493 /* Return the recorded merge weight. */
494
495 unsigned
496 gcov_get_merge_weight (void)
497 {
498 return gcov_merge_weight;
499 }
500
501 /* A wrapper function for merge functions. It sets up the
502 value buffer and weights and then calls the merge function. */
503
504 static void
505 merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n1,
506 gcov_type *v2, gcov_unsigned_t n2, unsigned w)
507 {
508 gcov_value_buf = v2;
509 gcov_value_buf_pos = 0;
510 gcov_value_buf_size = n2;
511 gcov_merge_weight = w;
512 (*f) (v1, n1);
513 }
514
515 /* Convert on disk representation of a TOPN counter to in memory representation
516 that is expected from __gcov_merge_topn function. */
517
518 static void
519 topn_to_memory_representation (struct gcov_ctr_info *info)
520 {
521 auto_vec<gcov_type> output;
522 gcov_type *values = info->values;
523 int count = info->num;
524
525 while (count > 0)
526 {
527 output.safe_push (values[0]);
528 gcov_type n = values[1];
529 output.safe_push (n);
530 if (n > 0)
531 {
532 struct gcov_kvp *tuples
533 = (struct gcov_kvp *)xcalloc (sizeof (struct gcov_kvp), n);
534 for (unsigned i = 0; i < n - 1; i++)
535 tuples[i].next = &tuples[i + 1];
536 for (unsigned i = 0; i < n; i++)
537 {
538 tuples[i].value = values[2 + 2 * i];
539 tuples[i].count = values[2 + 2 * i + 1];
540 }
541 output.safe_push ((intptr_t)&tuples[0]);
542 }
543 else
544 output.safe_push (0);
545
546 unsigned len = 2 * n + 2;
547 values += len;
548 count -= len;
549 }
550 gcc_assert (count == 0);
551
552 /* Allocate new buffer and copy it there. */
553 info->num = output.length ();
554 info->values = (gcov_type *)xmalloc (sizeof (gcov_type) * info->num);
555 for (unsigned i = 0; i < info->num; i++)
556 info->values[i] = output[i];
557 }
558
559 /* Offline tool to manipulate profile data.
560 This tool targets on matched profiles. But it has some tolerance on
561 unmatched profiles.
562 When merging p1 to p2 (p2 is the dst),
563 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
564 emit warning
565 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
566 specified weight; emit warning.
567 * m.gcda in both p1 and p2:
568 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
569 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
570 p2->m.gcda->f and
571 drop p1->m.gcda->f. A warning is emitted. */
572
573 /* Add INFO2's counter to INFO1, multiplying by weight W. */
574
575 static int
576 gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
577 {
578 unsigned f_ix;
579 unsigned n_functions = info1->n_functions;
580 int has_mismatch = 0;
581
582 gcc_assert (info2->n_functions == n_functions);
583
584 /* Merge summary. */
585 info1->summary.runs += info2->summary.runs;
586 info1->summary.sum_max += info2->summary.sum_max;
587
588 for (f_ix = 0; f_ix < n_functions; f_ix++)
589 {
590 unsigned t_ix;
591 struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
592 struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
593 struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
594
595 if (!gfi_ptr1 || gfi_ptr1->key != info1)
596 continue;
597 if (!gfi_ptr2 || gfi_ptr2->key != info2)
598 continue;
599
600 if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
601 {
602 fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
603 info1->filename);
604 has_mismatch = 1;
605 continue;
606 }
607 ci_ptr1 = gfi_ptr1->ctrs;
608 ci_ptr2 = gfi_ptr2->ctrs;
609 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
610 {
611 gcov_merge_fn merge1 = info1->merge[t_ix];
612 gcov_merge_fn merge2 = info2->merge[t_ix];
613
614 gcc_assert (merge1 == merge2);
615 if (!merge1)
616 continue;
617
618 if (merge1 == __gcov_merge_topn)
619 topn_to_memory_representation (ci_ptr1);
620 else
621 gcc_assert (ci_ptr1->num == ci_ptr2->num);
622
623 merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num,
624 ci_ptr2->values, ci_ptr2->num, w);
625 ci_ptr1++;
626 ci_ptr2++;
627 }
628 }
629
630 return has_mismatch;
631 }
632
633 /* Find and return the match gcov_info object for INFO from ARRAY.
634 SIZE is the length of ARRAY.
635 Return NULL if there is no match. */
636
637 static struct gcov_info *
638 find_match_gcov_info (struct gcov_info **array, int size,
639 struct gcov_info *info)
640 {
641 struct gcov_info *gi_ptr;
642 struct gcov_info *ret = NULL;
643 int i;
644
645 for (i = 0; i < size; i++)
646 {
647 gi_ptr = array[i];
648 if (gi_ptr == 0)
649 continue;
650 if (!strcmp (gi_ptr->filename, info->filename))
651 {
652 ret = gi_ptr;
653 array[i] = 0;
654 break;
655 }
656 }
657
658 if (ret && ret->n_functions != info->n_functions)
659 {
660 fnotice (stderr, "mismatched profiles in %s (%d functions"
661 " vs %d functions)\n",
662 ret->filename,
663 ret->n_functions,
664 info->n_functions);
665 ret = NULL;
666 }
667 return ret;
668 }
669
670 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
671 Return 0 on success: without mismatch.
672 Reutrn 1 on error. */
673
674 int
675 gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
676 int w1, int w2)
677 {
678 struct gcov_info *gi_ptr;
679 struct gcov_info **tgt_infos;
680 struct gcov_info *tgt_tail;
681 struct gcov_info **in_src_not_tgt;
682 unsigned tgt_cnt = 0, src_cnt = 0;
683 unsigned unmatch_info_cnt = 0;
684 unsigned int i;
685
686 for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
687 tgt_cnt++;
688 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
689 src_cnt++;
690 tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
691 * tgt_cnt);
692 gcc_assert (tgt_infos);
693 in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
694 * src_cnt);
695 gcc_assert (in_src_not_tgt);
696
697 for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
698 tgt_infos[i] = gi_ptr;
699
700 tgt_tail = tgt_infos[tgt_cnt - 1];
701
702 /* First pass on tgt_profile, we multiply w1 to all counters. */
703 if (w1 > 1)
704 {
705 for (i = 0; i < tgt_cnt; i++)
706 gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
707 }
708
709 /* Second pass, add src_profile to the tgt_profile. */
710 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
711 {
712 struct gcov_info *gi_ptr1;
713
714 gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
715 if (gi_ptr1 == NULL)
716 {
717 in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
718 continue;
719 }
720 gcov_merge (gi_ptr1, gi_ptr, w2);
721 }
722
723 /* For modules in src but not in tgt. We adjust the counter and append. */
724 for (i = 0; i < unmatch_info_cnt; i++)
725 {
726 gi_ptr = in_src_not_tgt[i];
727 gcov_merge (gi_ptr, gi_ptr, w2 - 1);
728 gi_ptr->next = NULL;
729 tgt_tail->next = gi_ptr;
730 tgt_tail = gi_ptr;
731 }
732
733 free (in_src_not_tgt);
734 free (tgt_infos);
735
736 return 0;
737 }
738
739 typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
740
741 /* Performing FN upon arc counters. */
742
743 static void
744 __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
745 counter_op_fn fn, void *data1, void *data2)
746 {
747 for (; n_counters; counters++, n_counters--)
748 {
749 gcov_type val = *counters;
750 *counters = fn(val, data1, data2);
751 }
752 }
753
754 /* Performing FN upon ior counters. */
755
756 static void
757 __gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
758 unsigned n_counters ATTRIBUTE_UNUSED,
759 counter_op_fn fn ATTRIBUTE_UNUSED,
760 void *data1 ATTRIBUTE_UNUSED,
761 void *data2 ATTRIBUTE_UNUSED)
762 {
763 /* Do nothing. */
764 }
765
766 /* Performing FN upon time-profile counters. */
767
768 static void
769 __gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
770 unsigned n_counters ATTRIBUTE_UNUSED,
771 counter_op_fn fn ATTRIBUTE_UNUSED,
772 void *data1 ATTRIBUTE_UNUSED,
773 void *data2 ATTRIBUTE_UNUSED)
774 {
775 /* Do nothing. */
776 }
777
778 /* Performing FN upon TOP N counters. */
779
780 static void
781 __gcov_topn_counter_op (gcov_type *counters, unsigned n_counters,
782 counter_op_fn fn, void *data1, void *data2)
783 {
784 unsigned i, n_measures;
785
786 gcc_assert (!(n_counters % 3));
787 n_measures = n_counters / 3;
788 for (i = 0; i < n_measures; i++, counters += 3)
789 {
790 counters[1] = fn (counters[1], data1, data2);
791 counters[2] = fn (counters[2], data1, data2);
792 }
793 }
794
795 /* Scaling the counter value V by multiplying *(float*) DATA1. */
796
797 static gcov_type
798 fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
799 {
800 float f = *(float *) data1;
801 return (gcov_type) (v * f);
802 }
803
804 /* Scaling the counter value V by multiplying DATA2/DATA1. */
805
806 static gcov_type
807 int_scale (gcov_type v, void *data1, void *data2)
808 {
809 int n = *(int *) data1;
810 int d = *(int *) data2;
811 return (gcov_type) ( RDIV (v,d) * n);
812 }
813
814 /* Type of function used to process counters. */
815 typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
816 counter_op_fn, void *, void *);
817
818 /* Function array to process profile counters. */
819 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
820 __gcov ## FN_TYPE ## _counter_op,
821 static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
822 #include "gcov-counter.def"
823 };
824 #undef DEF_GCOV_COUNTER
825
826 /* Driver for scaling profile counters. */
827
828 int
829 gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
830 {
831 struct gcov_info *gi_ptr;
832 unsigned f_ix;
833
834 if (verbose)
835 fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
836
837 /* Scaling the counters. */
838 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
839 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
840 {
841 unsigned t_ix;
842 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
843 const struct gcov_ctr_info *ci_ptr;
844
845 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
846 continue;
847
848 ci_ptr = gfi_ptr->ctrs;
849 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
850 {
851 gcov_merge_fn merge = gi_ptr->merge[t_ix];
852
853 if (!merge)
854 continue;
855 if (d == 0)
856 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
857 fp_scale, &scale_factor, NULL);
858 else
859 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
860 int_scale, &n, &d);
861 ci_ptr++;
862 }
863 }
864
865 return 0;
866 }
867
868 /* Driver to normalize profile counters. */
869
870 int
871 gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
872 {
873 struct gcov_info *gi_ptr;
874 gcov_type curr_max_val = 0;
875 unsigned f_ix;
876 unsigned int i;
877 float scale_factor;
878
879 /* Find the largest count value. */
880 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
881 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
882 {
883 unsigned t_ix;
884 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
885 const struct gcov_ctr_info *ci_ptr;
886
887 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
888 continue;
889
890 ci_ptr = gfi_ptr->ctrs;
891 for (t_ix = 0; t_ix < 1; t_ix++)
892 {
893 for (i = 0; i < ci_ptr->num; i++)
894 if (ci_ptr->values[i] > curr_max_val)
895 curr_max_val = ci_ptr->values[i];
896 ci_ptr++;
897 }
898 }
899
900 scale_factor = (float)max_val / curr_max_val;
901 if (verbose)
902 fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
903
904 return gcov_profile_scale (profile, scale_factor, 0, 0);
905 }
906
907 /* The following variables are defined in gcc/gcov-tool.c. */
908 extern int overlap_func_level;
909 extern int overlap_obj_level;
910 extern int overlap_hot_only;
911 extern int overlap_use_fullname;
912 extern double overlap_hot_threshold;
913
914 /* Compute the overlap score of two values. The score is defined as:
915 min (V1/SUM_1, V2/SUM_2) */
916
917 static double
918 calculate_2_entries (const unsigned long v1, const unsigned long v2,
919 const double sum_1, const double sum_2)
920 {
921 double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
922 double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
923
924 if (val2 < val1)
925 val1 = val2;
926
927 return val1;
928 }
929
930 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
931 This function also updates cumulative score CUM_1_RESULT and
932 CUM_2_RESULT. */
933
934 static double
935 compute_one_gcov (const struct gcov_info *gcov_info1,
936 const struct gcov_info *gcov_info2,
937 const double sum_1, const double sum_2,
938 double *cum_1_result, double *cum_2_result)
939 {
940 unsigned f_ix;
941 double ret = 0;
942 double cum_1 = 0, cum_2 = 0;
943 const struct gcov_info *gcov_info = 0;
944 double *cum_p;
945 double sum;
946
947 gcc_assert (gcov_info1 || gcov_info2);
948 if (!gcov_info1)
949 {
950 gcov_info = gcov_info2;
951 cum_p = cum_2_result;
952 sum = sum_2;
953 *cum_1_result = 0;
954 } else
955 if (!gcov_info2)
956 {
957 gcov_info = gcov_info1;
958 cum_p = cum_1_result;
959 sum = sum_1;
960 *cum_2_result = 0;
961 }
962
963 if (gcov_info)
964 {
965 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
966 {
967 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
968 if (!gfi_ptr || gfi_ptr->key != gcov_info)
969 continue;
970 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
971 unsigned c_num;
972 for (c_num = 0; c_num < ci_ptr->num; c_num++)
973 cum_1 += ci_ptr->values[c_num] / sum;
974 }
975 *cum_p = cum_1;
976 return 0.0;
977 }
978
979 for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
980 {
981 double func_cum_1 = 0.0;
982 double func_cum_2 = 0.0;
983 double func_val = 0.0;
984 int nonzero = 0;
985 int hot = 0;
986 const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
987 const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
988
989 if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
990 continue;
991 if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
992 continue;
993
994 const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
995 const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
996 unsigned c_num;
997 for (c_num = 0; c_num < ci_ptr1->num; c_num++)
998 {
999 if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
1000 {
1001 func_val += calculate_2_entries (ci_ptr1->values[c_num],
1002 ci_ptr2->values[c_num],
1003 sum_1, sum_2);
1004
1005 func_cum_1 += ci_ptr1->values[c_num] / sum_1;
1006 func_cum_2 += ci_ptr2->values[c_num] / sum_2;
1007 nonzero = 1;
1008 if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
1009 || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
1010 hot = 1;
1011 }
1012 }
1013
1014 ret += func_val;
1015 cum_1 += func_cum_1;
1016 cum_2 += func_cum_2;
1017 if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
1018 {
1019 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1020 gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
1021 }
1022 }
1023 *cum_1_result = cum_1;
1024 *cum_2_result = cum_2;
1025 return ret;
1026 }
1027
1028 /* Test if all counter values in this GCOV_INFO are cold.
1029 "Cold" is defined as the counter value being less than
1030 or equal to THRESHOLD. */
1031
1032 static bool
1033 gcov_info_count_all_cold (const struct gcov_info *gcov_info,
1034 gcov_type threshold)
1035 {
1036 unsigned f_ix;
1037
1038 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
1039 {
1040 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
1041
1042 if (!gfi_ptr || gfi_ptr->key != gcov_info)
1043 continue;
1044 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
1045 for (unsigned c_num = 0; c_num < ci_ptr->num; c_num++)
1046 if (ci_ptr->values[c_num] > threshold)
1047 return false;
1048 }
1049
1050 return true;
1051 }
1052
1053 /* Test if all counter values in this GCOV_INFO are 0. */
1054
1055 static bool
1056 gcov_info_count_all_zero (const struct gcov_info *gcov_info)
1057 {
1058 return gcov_info_count_all_cold (gcov_info, 0);
1059 }
1060
1061 /* A pair of matched GCOV_INFO.
1062 The flag is a bitvector:
1063 b0: obj1's all counts are 0;
1064 b1: obj1's all counts are cold (but no 0);
1065 b2: obj1 is hot;
1066 b3: no obj1 to match obj2;
1067 b4: obj2's all counts are 0;
1068 b5: obj2's all counts are cold (but no 0);
1069 b6: obj2 is hot;
1070 b7: no obj2 to match obj1;
1071 */
1072 struct overlap_t {
1073 const struct gcov_info *obj1;
1074 const struct gcov_info *obj2;
1075 char flag;
1076 };
1077
1078 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1079 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1080 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1081
1082 /* Cumlative overlap dscore for profile1 and profile2. */
1083 static double overlap_sum_1, overlap_sum_2;
1084
1085 /* The number of gcda files in the profiles. */
1086 static unsigned gcda_files[2];
1087
1088 /* The number of unique gcda files in the profiles
1089 (not existing in the other profile). */
1090 static unsigned unique_gcda_files[2];
1091
1092 /* The number of gcda files that all counter values are 0. */
1093 static unsigned zero_gcda_files[2];
1094
1095 /* The number of gcda files that all counter values are cold (but not 0). */
1096 static unsigned cold_gcda_files[2];
1097
1098 /* The number of gcda files that includes hot counter values. */
1099 static unsigned hot_gcda_files[2];
1100
1101 /* The number of gcda files with hot count value in either profiles. */
1102 static unsigned both_hot_cnt;
1103
1104 /* The number of gcda files with all counts cold (but not 0) in
1105 both profiles. */
1106 static unsigned both_cold_cnt;
1107
1108 /* The number of gcda files with all counts 0 in both profiles. */
1109 static unsigned both_zero_cnt;
1110
1111 /* Extract the basename of the filename NAME. */
1112
1113 static char *
1114 extract_file_basename (const char *name)
1115 {
1116 char *str;
1117 int len = 0;
1118 char *path = xstrdup (name);
1119 char sep_str[2];
1120
1121 sep_str[0] = DIR_SEPARATOR;
1122 sep_str[1] = 0;
1123 str = strstr(path, sep_str);
1124 do{
1125 len = strlen(str) + 1;
1126 path = &path[strlen(path) - len + 2];
1127 str = strstr(path, sep_str);
1128 } while(str);
1129
1130 return path;
1131 }
1132
1133 /* Utility function to get the filename. */
1134
1135 static const char *
1136 get_file_basename (const char *name)
1137 {
1138 if (overlap_use_fullname)
1139 return name;
1140 return extract_file_basename (name);
1141 }
1142
1143 /* A utility function to set the flag for the gcda files. */
1144
1145 static void
1146 set_flag (struct overlap_t *e)
1147 {
1148 char flag = 0;
1149
1150 if (!e->obj1)
1151 {
1152 unique_gcda_files[1]++;
1153 flag = 0x8;
1154 }
1155 else
1156 {
1157 gcda_files[0]++;
1158 if (gcov_info_count_all_zero (e->obj1))
1159 {
1160 zero_gcda_files[0]++;
1161 flag = 0x1;
1162 }
1163 else
1164 if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
1165 * overlap_hot_threshold))
1166 {
1167 cold_gcda_files[0]++;
1168 flag = 0x2;
1169 }
1170 else
1171 {
1172 hot_gcda_files[0]++;
1173 flag = 0x4;
1174 }
1175 }
1176
1177 if (!e->obj2)
1178 {
1179 unique_gcda_files[0]++;
1180 flag |= (0x8 << 4);
1181 }
1182 else
1183 {
1184 gcda_files[1]++;
1185 if (gcov_info_count_all_zero (e->obj2))
1186 {
1187 zero_gcda_files[1]++;
1188 flag |= (0x1 << 4);
1189 }
1190 else
1191 if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
1192 * overlap_hot_threshold))
1193 {
1194 cold_gcda_files[1]++;
1195 flag |= (0x2 << 4);
1196 }
1197 else
1198 {
1199 hot_gcda_files[1]++;
1200 flag |= (0x4 << 4);
1201 }
1202 }
1203
1204 gcc_assert (flag);
1205 e->flag = flag;
1206 }
1207
1208 /* Test if INFO1 and INFO2 are from the matched source file.
1209 Return 1 if they match; return 0 otherwise. */
1210
1211 static int
1212 matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
1213 {
1214 /* For FDO, we have to match the name. This can be expensive.
1215 Maybe we should use hash here. */
1216 if (strcmp (info1->filename, info2->filename))
1217 return 0;
1218
1219 if (info1->n_functions != info2->n_functions)
1220 {
1221 fnotice (stderr, "mismatched profiles in %s (%d functions"
1222 " vs %d functions)\n",
1223 info1->filename,
1224 info1->n_functions,
1225 info2->n_functions);
1226 return 0;
1227 }
1228 return 1;
1229 }
1230
1231 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1232 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1233 match and 1.0 meaning a perfect match. */
1234
1235 static double
1236 calculate_overlap (struct gcov_info *gcov_list1,
1237 struct gcov_info *gcov_list2)
1238 {
1239 unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
1240 unsigned int i, j;
1241 const struct gcov_info *gi_ptr;
1242 struct overlap_t *all_infos;
1243
1244 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
1245 list1_cnt++;
1246 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
1247 list2_cnt++;
1248 all_cnt = list1_cnt + list2_cnt;
1249 all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
1250 * all_cnt * 2);
1251 gcc_assert (all_infos);
1252
1253 i = 0;
1254 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
1255 {
1256 all_infos[i].obj1 = gi_ptr;
1257 all_infos[i].obj2 = 0;
1258 }
1259
1260 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
1261 {
1262 all_infos[i].obj1 = 0;
1263 all_infos[i].obj2 = gi_ptr;
1264 }
1265
1266 for (i = list1_cnt; i < all_cnt; i++)
1267 {
1268 if (all_infos[i].obj2 == 0)
1269 continue;
1270 for (j = 0; j < list1_cnt; j++)
1271 {
1272 if (all_infos[j].obj2 != 0)
1273 continue;
1274 if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
1275 {
1276 all_infos[j].obj2 = all_infos[i].obj2;
1277 all_infos[i].obj2 = 0;
1278 break;
1279 }
1280 }
1281 }
1282
1283 for (i = 0; i < all_cnt; i++)
1284 if (all_infos[i].obj1 || all_infos[i].obj2)
1285 {
1286 set_flag (all_infos + i);
1287 if (FLAG_ONE_HOT (all_infos[i].flag))
1288 both_hot_cnt++;
1289 if (FLAG_BOTH_COLD(all_infos[i].flag))
1290 both_cold_cnt++;
1291 if (FLAG_BOTH_ZERO(all_infos[i].flag))
1292 both_zero_cnt++;
1293 }
1294
1295 double prg_val = 0;
1296 double sum_val = 0;
1297 double sum_cum_1 = 0;
1298 double sum_cum_2 = 0;
1299
1300 for (i = 0; i < all_cnt; i++)
1301 {
1302 double val;
1303 double cum_1, cum_2;
1304 const char *filename;
1305
1306 if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
1307 continue;
1308 if (FLAG_BOTH_ZERO (all_infos[i].flag))
1309 continue;
1310
1311 if (all_infos[i].obj1)
1312 filename = get_file_basename (all_infos[i].obj1->filename);
1313 else
1314 filename = get_file_basename (all_infos[i].obj2->filename);
1315
1316 if (overlap_func_level)
1317 printf("\n processing %36s:\n", filename);
1318
1319 val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
1320 overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
1321
1322 if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
1323 {
1324 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1325 filename, val*100, cum_1*100, cum_2*100);
1326 sum_val += val;
1327 sum_cum_1 += cum_1;
1328 sum_cum_2 += cum_2;
1329 }
1330
1331 prg_val += val;
1332
1333 }
1334
1335 free (all_infos);
1336
1337 if (overlap_obj_level)
1338 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1339 "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
1340
1341 printf (" Statistics:\n"
1342 " profile1_# profile2_# overlap_#\n");
1343 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
1344 gcda_files[0]-unique_gcda_files[0]);
1345 printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
1346 unique_gcda_files[1]);
1347 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
1348 hot_gcda_files[1], both_hot_cnt);
1349 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
1350 cold_gcda_files[1], both_cold_cnt);
1351 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
1352 zero_gcda_files[1], both_zero_cnt);
1353
1354 return prg_val;
1355 }
1356
1357 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1358 PROFILE2.
1359 Return 0 on success: without mismatch. Reutrn 1 on error. */
1360
1361 int
1362 gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
1363 {
1364 double result;
1365
1366 result = calculate_overlap (profile1, profile2);
1367
1368 if (result > 0)
1369 {
1370 printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
1371 return 0;
1372 }
1373 return 1;
1374 }