]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/libgcov-util.c
[Ada] Initialize gnat_argc/gnat_argv only the first time
[thirdparty/gcc.git] / libgcc / libgcov-util.c
CommitLineData
e76f6040 1/* Utility functions for reading gcda files into in-memory
2 gcov_info structures and offline profile processing. */
fbd26352 3/* Copyright (C) 2014-2019 Free Software Foundation, Inc.
e76f6040 4 Contributed by Rong Xu <xur@google.com>.
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 3, or (at your option) any later
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18Under Section 7 of GPL version 3, you are granted additional
19permissions described in the GCC Runtime Library Exception, version
203.1, as published by the Free Software Foundation.
21
22You should have received a copy of the GNU General Public License and
23a copy of the GCC Runtime Library Exception along with this program;
24see 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"
56621355 35#include "gcov-io.h"
e76f6040 36
37/* Borrowed from basic-block.h. */
38#define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
39
40extern gcov_position_t gcov_position();
41extern int gcov_is_error();
e76f6040 42
43/* Verbose mode for debug. */
44static int verbose;
45
46/* Set verbose flag. */
47void 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>
c905381f 56#ifdef HAVE_FTW_H
e76f6040 57#include <ftw.h>
c905381f 58#endif
e76f6040 59
60static void tag_function (unsigned, unsigned);
61static void tag_blocks (unsigned, unsigned);
62static void tag_arcs (unsigned, unsigned);
63static void tag_lines (unsigned, unsigned);
64static void tag_counters (unsigned, unsigned);
65static void tag_summary (unsigned, unsigned);
66
67/* The gcov_info for the first module. */
68static struct gcov_info *curr_gcov_info;
69/* The gcov_info being processed. */
70static struct gcov_info *gcov_info_head;
71/* This variable contains all the functions in current module. */
72static struct obstack fn_info;
73/* The function being processed. */
74static struct gcov_fn_info *curr_fn_info;
75/* The number of functions seen so far. */
76static unsigned num_fn_info;
77/* This variable contains all the counters for current module. */
78static int k_ctrs_mask[GCOV_COUNTERS];
79/* The kind of counters that have been seen. */
80static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
81/* Number of kind of counters that have been seen. */
82static int k_ctrs_types;
56621355 83/* The object summary being processed. */
84static struct gcov_summary *curr_object_summary;
e76f6040 85
86/* Merge functions for counters. */
87#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
88static 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
95static void
96set_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
118typedef 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
127static 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},
e76f6040 137 {0, NULL, NULL}
138};
139
140/* Handler for reading function tag. */
141
142static void
143tag_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
175static void
176tag_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
184static void
185tag_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
193static void
194tag_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
202static void
203tag_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
225static void
226tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
227{
56621355 228 curr_object_summary = (gcov_summary *) xcalloc (sizeof (gcov_summary), 1);
229 gcov_read_summary (curr_object_summary);
e76f6040 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
235static void
236read_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
56621355 243 /* We set the following fields: merge, n_functions, functions
244 and summary. */
e76f6040 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
259static struct gcov_info *
260read_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;
56621355 304 curr_object_summary = NULL;
e76f6040 305 {
6401b74d 306 size_t len = strlen (filename) + 1;
307 char *str_dup = (char*) xmalloc (len);
e76f6040 308
6401b74d 309 memcpy (str_dup, filename, len);
e76f6040 310 obj_info->filename = str_dup;
e76f6040 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)
26054e0b 327 break;
e76f6040 328 length = gcov_read_unsigned ();
329 base = gcov_position ();
330 mask = GCOV_TAG_MASK (tag) >> 1;
331 for (tag_depth = 4; mask; mask >>= 8)
26054e0b 332 {
333 if (((mask & 0xff) != 0xff))
334 {
85b9be9b 335 warning (0, "%s:tag %qx is invalid", filename, tag);
26054e0b 336 break;
337 }
338 tag_depth--;
339 }
e76f6040 340 for (format = tag_table; format->name; format++)
26054e0b 341 if (format->tag == tag)
342 goto found;
e76f6040 343 format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
344 found:;
345 if (tag)
26054e0b 346 {
347 if (depth && depth < tag_depth)
348 {
349 if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
85b9be9b 350 warning (0, "%s:tag %qx is incorrectly nested",
26054e0b 351 filename, tag);
352 }
353 depth = tag_depth;
354 tags[depth - 1] = tag;
355 }
e76f6040 356
357 if (format->proc)
358 {
26054e0b 359 unsigned long actual_length;
e76f6040 360
26054e0b 361 (*format->proc) (tag, length);
e76f6040 362
26054e0b 363 actual_length = gcov_position () - base;
364 if (actual_length > length)
85b9be9b 365 warning (0, "%s:record size mismatch %lu bytes overread",
26054e0b 366 filename, actual_length - length);
367 else if (length > actual_length)
85b9be9b 368 warning (0, "%s:record size mismatch %lu bytes unread",
26054e0b 369 filename, length - actual_length);
370 }
e76f6040 371
372 gcov_sync (base, length);
373 if ((error = gcov_is_error ()))
26054e0b 374 {
85b9be9b 375 warning (0, error < 0 ? "%s:counter overflow at %lu" :
376 "%s:read error at %lu", filename,
26054e0b 377 (long unsigned) gcov_position ());
378 break;
379 }
e76f6040 380 }
381
382 read_gcda_finalize (obj_info);
383 gcov_close ();
384
385 return obj_info;
386}
387
c905381f 388#ifdef HAVE_FTW_H
e76f6040 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
392static int
393ftw_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}
c905381f 426#endif
e76f6040 427
428/* Initializer for reading a profile dir. */
429
430static inline void
431read_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,
6401b74d 438 Return the head of gcov_info list on success. */
e76f6040 439
440struct gcov_info *
441gcov_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 }
c905381f 461#ifdef HAVE_FTW_H
e76f6040 462 ftw (".", ftw_read_file, 50);
c905381f 463#endif
22eb1ed5 464 chdir (pwd);
e76f6040 465 free (pwd);
466
e76f6040 467 return gcov_info_head;;
468}
469
470/* This part of the code is to merge profile counters. These
471 variables are set in merge_wrapper and to be used by
472 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
473
474/* We save the counter value address to this variable. */
475static gcov_type *gcov_value_buf;
476
477/* The number of counter values to be read by current merging. */
478static gcov_unsigned_t gcov_value_buf_size;
479
480/* The index of counter values being read. */
481static gcov_unsigned_t gcov_value_buf_pos;
482
483/* The weight of current merging. */
484static unsigned gcov_merge_weight;
485
486/* Read a counter value from gcov_value_buf array. */
487
488gcov_type
489gcov_read_counter_mem (void)
490{
491 gcov_type ret;
492 gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
493 ret = *(gcov_value_buf + gcov_value_buf_pos);
494 ++gcov_value_buf_pos;
495 return ret;
496}
497
498/* Return the recorded merge weight. */
499
500unsigned
501gcov_get_merge_weight (void)
502{
503 return gcov_merge_weight;
504}
505
506/* A wrapper function for merge functions. It sets up the
507 value buffer and weights and then calls the merge function. */
508
509static void
510merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n,
511 gcov_type *v2, unsigned w)
512{
513 gcov_value_buf = v2;
514 gcov_value_buf_pos = 0;
515 gcov_value_buf_size = n;
516 gcov_merge_weight = w;
517 (*f) (v1, n);
518}
519
520/* Offline tool to manipulate profile data.
521 This tool targets on matched profiles. But it has some tolerance on
522 unmatched profiles.
523 When merging p1 to p2 (p2 is the dst),
524 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
525 emit warning
526 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
527 specified weight; emit warning.
528 * m.gcda in both p1 and p2:
529 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
530 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
531 p2->m.gcda->f and
532 drop p1->m.gcda->f. A warning is emitted. */
533
534/* Add INFO2's counter to INFO1, multiplying by weight W. */
535
536static int
537gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
538{
539 unsigned f_ix;
540 unsigned n_functions = info1->n_functions;
541 int has_mismatch = 0;
542
543 gcc_assert (info2->n_functions == n_functions);
544 for (f_ix = 0; f_ix < n_functions; f_ix++)
545 {
546 unsigned t_ix;
547 const struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
548 const struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
549 const struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
550
551 if (!gfi_ptr1 || gfi_ptr1->key != info1)
552 continue;
553 if (!gfi_ptr2 || gfi_ptr2->key != info2)
554 continue;
555
556 if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
557 {
558 fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
559 info1->filename);
560 has_mismatch = 1;
561 continue;
562 }
563 ci_ptr1 = gfi_ptr1->ctrs;
564 ci_ptr2 = gfi_ptr2->ctrs;
565 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
566 {
567 gcov_merge_fn merge1 = info1->merge[t_ix];
568 gcov_merge_fn merge2 = info2->merge[t_ix];
569
570 gcc_assert (merge1 == merge2);
571 if (!merge1)
572 continue;
573 gcc_assert (ci_ptr1->num == ci_ptr2->num);
574 merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num, ci_ptr2->values, w);
575 ci_ptr1++;
576 ci_ptr2++;
577 }
578 }
579
580 return has_mismatch;
581}
582
583/* Find and return the match gcov_info object for INFO from ARRAY.
584 SIZE is the length of ARRAY.
585 Return NULL if there is no match. */
586
587static struct gcov_info *
26054e0b 588find_match_gcov_info (struct gcov_info **array, int size,
589 struct gcov_info *info)
e76f6040 590{
591 struct gcov_info *gi_ptr;
592 struct gcov_info *ret = NULL;
593 int i;
594
595 for (i = 0; i < size; i++)
596 {
597 gi_ptr = array[i];
598 if (gi_ptr == 0)
599 continue;
600 if (!strcmp (gi_ptr->filename, info->filename))
601 {
602 ret = gi_ptr;
603 array[i] = 0;
604 break;
605 }
606 }
607
608 if (ret && ret->n_functions != info->n_functions)
609 {
610 fnotice (stderr, "mismatched profiles in %s (%d functions"
611 " vs %d functions)\n",
612 ret->filename,
613 ret->n_functions,
614 info->n_functions);
615 ret = NULL;
616 }
617 return ret;
618}
619
620/* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
621 Return 0 on success: without mismatch.
622 Reutrn 1 on error. */
623
624int
625gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
626 int w1, int w2)
627{
628 struct gcov_info *gi_ptr;
629 struct gcov_info **tgt_infos;
630 struct gcov_info *tgt_tail;
631 struct gcov_info **in_src_not_tgt;
632 unsigned tgt_cnt = 0, src_cnt = 0;
633 unsigned unmatch_info_cnt = 0;
634 unsigned int i;
635
636 for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
637 tgt_cnt++;
638 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
639 src_cnt++;
640 tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
641 * tgt_cnt);
642 gcc_assert (tgt_infos);
643 in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
644 * src_cnt);
645 gcc_assert (in_src_not_tgt);
646
647 for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
648 tgt_infos[i] = gi_ptr;
649
650 tgt_tail = tgt_infos[tgt_cnt - 1];
651
652 /* First pass on tgt_profile, we multiply w1 to all counters. */
653 if (w1 > 1)
654 {
655 for (i = 0; i < tgt_cnt; i++)
656 gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
657 }
658
659 /* Second pass, add src_profile to the tgt_profile. */
660 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
661 {
662 struct gcov_info *gi_ptr1;
663
664 gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
665 if (gi_ptr1 == NULL)
666 {
667 in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
668 continue;
669 }
670 gcov_merge (gi_ptr1, gi_ptr, w2);
671 }
672
673 /* For modules in src but not in tgt. We adjust the counter and append. */
674 for (i = 0; i < unmatch_info_cnt; i++)
675 {
676 gi_ptr = in_src_not_tgt[i];
677 gcov_merge (gi_ptr, gi_ptr, w2 - 1);
196b8968 678 gi_ptr->next = NULL;
e76f6040 679 tgt_tail->next = gi_ptr;
680 tgt_tail = gi_ptr;
681 }
682
e6ccd50e 683 free (in_src_not_tgt);
684 free (tgt_infos);
685
e76f6040 686 return 0;
687}
688
689typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
690
691/* Performing FN upon arc counters. */
692
693static void
694__gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
695 counter_op_fn fn, void *data1, void *data2)
696{
697 for (; n_counters; counters++, n_counters--)
698 {
699 gcov_type val = *counters;
700 *counters = fn(val, data1, data2);
701 }
702}
703
704/* Performing FN upon ior counters. */
705
706static void
707__gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
708 unsigned n_counters ATTRIBUTE_UNUSED,
709 counter_op_fn fn ATTRIBUTE_UNUSED,
710 void *data1 ATTRIBUTE_UNUSED,
711 void *data2 ATTRIBUTE_UNUSED)
712{
713 /* Do nothing. */
714}
715
716/* Performing FN upon time-profile counters. */
717
718static void
719__gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
720 unsigned n_counters ATTRIBUTE_UNUSED,
721 counter_op_fn fn ATTRIBUTE_UNUSED,
722 void *data1 ATTRIBUTE_UNUSED,
723 void *data2 ATTRIBUTE_UNUSED)
724{
725 /* Do nothing. */
726}
727
ac65c341 728/* Performing FN upon TOP N counters. */
e76f6040 729
730static void
ac65c341 731__gcov_topn_counter_op (gcov_type *counters, unsigned n_counters,
732 counter_op_fn fn, void *data1, void *data2)
e76f6040 733{
734 unsigned i, n_measures;
735
736 gcc_assert (!(n_counters % 3));
737 n_measures = n_counters / 3;
738 for (i = 0; i < n_measures; i++, counters += 3)
739 {
740 counters[1] = fn (counters[1], data1, data2);
741 counters[2] = fn (counters[2], data1, data2);
742 }
743}
744
745/* Scaling the counter value V by multiplying *(float*) DATA1. */
746
747static gcov_type
748fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
749{
750 float f = *(float *) data1;
751 return (gcov_type) (v * f);
752}
753
754/* Scaling the counter value V by multiplying DATA2/DATA1. */
755
756static gcov_type
757int_scale (gcov_type v, void *data1, void *data2)
758{
759 int n = *(int *) data1;
760 int d = *(int *) data2;
761 return (gcov_type) ( RDIV (v,d) * n);
762}
763
764/* Type of function used to process counters. */
765typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
766 counter_op_fn, void *, void *);
767
768/* Function array to process profile counters. */
769#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
770 __gcov ## FN_TYPE ## _counter_op,
771static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
772#include "gcov-counter.def"
773};
774#undef DEF_GCOV_COUNTER
775
776/* Driver for scaling profile counters. */
777
778int
779gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
780{
781 struct gcov_info *gi_ptr;
782 unsigned f_ix;
783
784 if (verbose)
785 fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
786
787 /* Scaling the counters. */
788 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
789 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
790 {
791 unsigned t_ix;
792 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
793 const struct gcov_ctr_info *ci_ptr;
794
795 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
796 continue;
797
798 ci_ptr = gfi_ptr->ctrs;
799 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
800 {
801 gcov_merge_fn merge = gi_ptr->merge[t_ix];
802
803 if (!merge)
804 continue;
805 if (d == 0)
806 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
807 fp_scale, &scale_factor, NULL);
808 else
809 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
810 int_scale, &n, &d);
811 ci_ptr++;
812 }
813 }
814
815 return 0;
816}
817
818/* Driver to normalize profile counters. */
819
820int
821gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
822{
823 struct gcov_info *gi_ptr;
824 gcov_type curr_max_val = 0;
825 unsigned f_ix;
826 unsigned int i;
827 float scale_factor;
828
829 /* Find the largest count value. */
830 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
831 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
832 {
833 unsigned t_ix;
834 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
835 const struct gcov_ctr_info *ci_ptr;
836
837 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
838 continue;
839
840 ci_ptr = gfi_ptr->ctrs;
841 for (t_ix = 0; t_ix < 1; t_ix++)
842 {
843 for (i = 0; i < ci_ptr->num; i++)
844 if (ci_ptr->values[i] > curr_max_val)
845 curr_max_val = ci_ptr->values[i];
846 ci_ptr++;
847 }
848 }
849
850 scale_factor = (float)max_val / curr_max_val;
851 if (verbose)
a8a5046c 852 fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
e76f6040 853
854 return gcov_profile_scale (profile, scale_factor, 0, 0);
855}
26054e0b 856
857/* The following variables are defined in gcc/gcov-tool.c. */
858extern int overlap_func_level;
859extern int overlap_obj_level;
860extern int overlap_hot_only;
861extern int overlap_use_fullname;
862extern double overlap_hot_threshold;
863
864/* Compute the overlap score of two values. The score is defined as:
865 min (V1/SUM_1, V2/SUM_2) */
866
867static double
868calculate_2_entries (const unsigned long v1, const unsigned long v2,
869 const double sum_1, const double sum_2)
870{
871 double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
872 double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
873
874 if (val2 < val1)
875 val1 = val2;
876
877 return val1;
878}
879
880/* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
26054e0b 881 This function also updates cumulative score CUM_1_RESULT and
882 CUM_2_RESULT. */
883
884static double
885compute_one_gcov (const struct gcov_info *gcov_info1,
886 const struct gcov_info *gcov_info2,
887 const double sum_1, const double sum_2,
888 double *cum_1_result, double *cum_2_result)
889{
890 unsigned f_ix;
891 double ret = 0;
892 double cum_1 = 0, cum_2 = 0;
893 const struct gcov_info *gcov_info = 0;
894 double *cum_p;
895 double sum;
896
897 gcc_assert (gcov_info1 || gcov_info2);
898 if (!gcov_info1)
899 {
900 gcov_info = gcov_info2;
901 cum_p = cum_2_result;
902 sum = sum_2;
903 *cum_1_result = 0;
904 } else
905 if (!gcov_info2)
906 {
907 gcov_info = gcov_info1;
908 cum_p = cum_1_result;
909 sum = sum_1;
910 *cum_2_result = 0;
911 }
912
913 if (gcov_info)
914 {
915 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
916 {
26054e0b 917 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
918 if (!gfi_ptr || gfi_ptr->key != gcov_info)
919 continue;
920 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
5860b185 921 unsigned c_num;
922 for (c_num = 0; c_num < ci_ptr->num; c_num++)
923 cum_1 += ci_ptr->values[c_num] / sum;
26054e0b 924 }
925 *cum_p = cum_1;
926 return 0.0;
927 }
928
929 for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
930 {
26054e0b 931 double func_cum_1 = 0.0;
932 double func_cum_2 = 0.0;
933 double func_val = 0.0;
934 int nonzero = 0;
935 int hot = 0;
936 const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
937 const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
938
939 if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
940 continue;
941 if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
942 continue;
943
944 const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
945 const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
5860b185 946 unsigned c_num;
947 for (c_num = 0; c_num < ci_ptr1->num; c_num++)
948 {
949 if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
950 {
951 func_val += calculate_2_entries (ci_ptr1->values[c_num],
952 ci_ptr2->values[c_num],
953 sum_1, sum_2);
954
955 func_cum_1 += ci_ptr1->values[c_num] / sum_1;
956 func_cum_2 += ci_ptr2->values[c_num] / sum_2;
957 nonzero = 1;
958 if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
959 || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
960 hot = 1;
961 }
962 }
26054e0b 963
26054e0b 964 ret += func_val;
965 cum_1 += func_cum_1;
966 cum_2 += func_cum_2;
967 if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
968 {
969 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
970 gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
971 }
972 }
973 *cum_1_result = cum_1;
974 *cum_2_result = cum_2;
975 return ret;
976}
977
978/* Test if all counter values in this GCOV_INFO are cold.
979 "Cold" is defined as the counter value being less than
980 or equal to THRESHOLD. */
981
982static bool
983gcov_info_count_all_cold (const struct gcov_info *gcov_info,
984 gcov_type threshold)
985{
986 unsigned f_ix;
987
988 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
989 {
26054e0b 990 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
991
992 if (!gfi_ptr || gfi_ptr->key != gcov_info)
993 continue;
994 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
5860b185 995 for (unsigned c_num = 0; c_num < ci_ptr->num; c_num++)
996 if (ci_ptr->values[c_num] > threshold)
997 return false;
26054e0b 998 }
999
1000 return true;
1001}
1002
1003/* Test if all counter values in this GCOV_INFO are 0. */
1004
1005static bool
1006gcov_info_count_all_zero (const struct gcov_info *gcov_info)
1007{
1008 return gcov_info_count_all_cold (gcov_info, 0);
1009}
1010
1011/* A pair of matched GCOV_INFO.
1012 The flag is a bitvector:
1013 b0: obj1's all counts are 0;
1014 b1: obj1's all counts are cold (but no 0);
1015 b2: obj1 is hot;
1016 b3: no obj1 to match obj2;
1017 b4: obj2's all counts are 0;
1018 b5: obj2's all counts are cold (but no 0);
1019 b6: obj2 is hot;
1020 b7: no obj2 to match obj1;
1021 */
1022struct overlap_t {
1023 const struct gcov_info *obj1;
1024 const struct gcov_info *obj2;
1025 char flag;
1026};
1027
1028#define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1029#define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1030#define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1031
1032/* Cumlative overlap dscore for profile1 and profile2. */
1033static double overlap_sum_1, overlap_sum_2;
1034
26054e0b 1035/* The number of gcda files in the profiles. */
1036static unsigned gcda_files[2];
1037
1038/* The number of unique gcda files in the profiles
1039 (not existing in the other profile). */
1040static unsigned unique_gcda_files[2];
1041
1042/* The number of gcda files that all counter values are 0. */
1043static unsigned zero_gcda_files[2];
1044
1045/* The number of gcda files that all counter values are cold (but not 0). */
1046static unsigned cold_gcda_files[2];
1047
1048/* The number of gcda files that includes hot counter values. */
1049static unsigned hot_gcda_files[2];
1050
1051/* The number of gcda files with hot count value in either profiles. */
1052static unsigned both_hot_cnt;
1053
1054/* The number of gcda files with all counts cold (but not 0) in
1055 both profiles. */
1056static unsigned both_cold_cnt;
1057
1058/* The number of gcda files with all counts 0 in both profiles. */
1059static unsigned both_zero_cnt;
1060
1061/* Extract the basename of the filename NAME. */
1062
1063static char *
1064extract_file_basename (const char *name)
1065{
1066 char *str;
1067 int len = 0;
1068 char *path = xstrdup (name);
1069 char sep_str[2];
1070
1071 sep_str[0] = DIR_SEPARATOR;
1072 sep_str[1] = 0;
1073 str = strstr(path, sep_str);
1074 do{
1075 len = strlen(str) + 1;
1076 path = &path[strlen(path) - len + 2];
1077 str = strstr(path, sep_str);
1078 } while(str);
1079
1080 return path;
1081}
1082
1083/* Utility function to get the filename. */
1084
1085static const char *
1086get_file_basename (const char *name)
1087{
1088 if (overlap_use_fullname)
1089 return name;
1090 return extract_file_basename (name);
1091}
1092
1093/* A utility function to set the flag for the gcda files. */
1094
1095static void
1096set_flag (struct overlap_t *e)
1097{
1098 char flag = 0;
1099
1100 if (!e->obj1)
1101 {
1102 unique_gcda_files[1]++;
1103 flag = 0x8;
1104 }
1105 else
1106 {
1107 gcda_files[0]++;
1108 if (gcov_info_count_all_zero (e->obj1))
1109 {
1110 zero_gcda_files[0]++;
1111 flag = 0x1;
1112 }
1113 else
1114 if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
1115 * overlap_hot_threshold))
1116 {
1117 cold_gcda_files[0]++;
1118 flag = 0x2;
1119 }
1120 else
1121 {
1122 hot_gcda_files[0]++;
1123 flag = 0x4;
1124 }
1125 }
1126
1127 if (!e->obj2)
1128 {
1129 unique_gcda_files[0]++;
1130 flag |= (0x8 << 4);
1131 }
1132 else
1133 {
1134 gcda_files[1]++;
1135 if (gcov_info_count_all_zero (e->obj2))
1136 {
1137 zero_gcda_files[1]++;
1138 flag |= (0x1 << 4);
1139 }
1140 else
1141 if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
1142 * overlap_hot_threshold))
1143 {
1144 cold_gcda_files[1]++;
1145 flag |= (0x2 << 4);
1146 }
1147 else
1148 {
1149 hot_gcda_files[1]++;
1150 flag |= (0x4 << 4);
1151 }
1152 }
1153
1154 gcc_assert (flag);
1155 e->flag = flag;
1156}
1157
1158/* Test if INFO1 and INFO2 are from the matched source file.
1159 Return 1 if they match; return 0 otherwise. */
1160
1161static int
1162matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
1163{
1164 /* For FDO, we have to match the name. This can be expensive.
1165 Maybe we should use hash here. */
1166 if (strcmp (info1->filename, info2->filename))
1167 return 0;
1168
1169 if (info1->n_functions != info2->n_functions)
1170 {
1171 fnotice (stderr, "mismatched profiles in %s (%d functions"
1172 " vs %d functions)\n",
1173 info1->filename,
1174 info1->n_functions,
1175 info2->n_functions);
1176 return 0;
1177 }
1178 return 1;
1179}
1180
26054e0b 1181/* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1182 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1183 match and 1.0 meaning a perfect match. */
1184
1185static double
1186calculate_overlap (struct gcov_info *gcov_list1,
1187 struct gcov_info *gcov_list2)
1188{
26054e0b 1189 unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
1190 unsigned int i, j;
26054e0b 1191 const struct gcov_info *gi_ptr;
1192 struct overlap_t *all_infos;
1193
26054e0b 1194 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
1195 list1_cnt++;
1196 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
1197 list2_cnt++;
1198 all_cnt = list1_cnt + list2_cnt;
1199 all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
1200 * all_cnt * 2);
1201 gcc_assert (all_infos);
1202
1203 i = 0;
1204 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
1205 {
1206 all_infos[i].obj1 = gi_ptr;
1207 all_infos[i].obj2 = 0;
1208 }
1209
1210 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
1211 {
1212 all_infos[i].obj1 = 0;
1213 all_infos[i].obj2 = gi_ptr;
1214 }
1215
1216 for (i = list1_cnt; i < all_cnt; i++)
1217 {
1218 if (all_infos[i].obj2 == 0)
1219 continue;
1220 for (j = 0; j < list1_cnt; j++)
1221 {
1222 if (all_infos[j].obj2 != 0)
1223 continue;
1224 if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
1225 {
1226 all_infos[j].obj2 = all_infos[i].obj2;
1227 all_infos[i].obj2 = 0;
1228 break;
1229 }
1230 }
1231 }
1232
1233 for (i = 0; i < all_cnt; i++)
1234 if (all_infos[i].obj1 || all_infos[i].obj2)
1235 {
1236 set_flag (all_infos + i);
1237 if (FLAG_ONE_HOT (all_infos[i].flag))
1238 both_hot_cnt++;
1239 if (FLAG_BOTH_COLD(all_infos[i].flag))
1240 both_cold_cnt++;
1241 if (FLAG_BOTH_ZERO(all_infos[i].flag))
1242 both_zero_cnt++;
1243 }
1244
1245 double prg_val = 0;
1246 double sum_val = 0;
1247 double sum_cum_1 = 0;
1248 double sum_cum_2 = 0;
1249
1250 for (i = 0; i < all_cnt; i++)
1251 {
1252 double val;
1253 double cum_1, cum_2;
1254 const char *filename;
1255
1256 if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
1257 continue;
1258 if (FLAG_BOTH_ZERO (all_infos[i].flag))
1259 continue;
1260
1261 if (all_infos[i].obj1)
1262 filename = get_file_basename (all_infos[i].obj1->filename);
1263 else
1264 filename = get_file_basename (all_infos[i].obj2->filename);
1265
1266 if (overlap_func_level)
1267 printf("\n processing %36s:\n", filename);
1268
1269 val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
1270 overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
1271
1272 if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
1273 {
1274 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1275 filename, val*100, cum_1*100, cum_2*100);
1276 sum_val += val;
1277 sum_cum_1 += cum_1;
1278 sum_cum_2 += cum_2;
1279 }
1280
1281 prg_val += val;
1282
1283 }
1284
e6ccd50e 1285 free (all_infos);
1286
26054e0b 1287 if (overlap_obj_level)
1288 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1289 "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
1290
1291 printf (" Statistics:\n"
1292 " profile1_# profile2_# overlap_#\n");
1293 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
a8a5046c 1294 gcda_files[0]-unique_gcda_files[0]);
26054e0b 1295 printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
a8a5046c 1296 unique_gcda_files[1]);
26054e0b 1297 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
a8a5046c 1298 hot_gcda_files[1], both_hot_cnt);
26054e0b 1299 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
a8a5046c 1300 cold_gcda_files[1], both_cold_cnt);
26054e0b 1301 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
a8a5046c 1302 zero_gcda_files[1], both_zero_cnt);
26054e0b 1303
1304 return prg_val;
1305}
1306
ba662a81 1307/* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1308 PROFILE2.
26054e0b 1309 Return 0 on success: without mismatch. Reutrn 1 on error. */
1310
1311int
1312gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
1313{
1314 double result;
1315
1316 result = calculate_overlap (profile1, profile2);
1317
1318 if (result > 0)
1319 {
1320 printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
1321 return 0;
1322 }
1323 return 1;
1324}