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