]> gcc.gnu.org Git - gcc.git/blob - libgcc/libgcov-util.c
re PR fortran/83057 (OPEN without a filename and without STATUS='SCRATCH' could produ...
[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 `%x' is invalid\n", 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 `%x' is incorrectly nested\n",
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\n",
366 filename, actual_length - length);
367 else if (length > actual_length)
368 warning (0, "%s:record size mismatch %lu bytes unread\n",
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\n" :
376 "%s:read error at %lu\n", 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 return 0;
685 }
686
687 typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
688
689 /* Performing FN upon arc counters. */
690
691 static void
692 __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
693 counter_op_fn fn, void *data1, void *data2)
694 {
695 for (; n_counters; counters++, n_counters--)
696 {
697 gcov_type val = *counters;
698 *counters = fn(val, data1, data2);
699 }
700 }
701
702 /* Performing FN upon ior counters. */
703
704 static void
705 __gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
706 unsigned n_counters ATTRIBUTE_UNUSED,
707 counter_op_fn fn ATTRIBUTE_UNUSED,
708 void *data1 ATTRIBUTE_UNUSED,
709 void *data2 ATTRIBUTE_UNUSED)
710 {
711 /* Do nothing. */
712 }
713
714 /* Performing FN upon time-profile counters. */
715
716 static void
717 __gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
718 unsigned n_counters ATTRIBUTE_UNUSED,
719 counter_op_fn fn ATTRIBUTE_UNUSED,
720 void *data1 ATTRIBUTE_UNUSED,
721 void *data2 ATTRIBUTE_UNUSED)
722 {
723 /* Do nothing. */
724 }
725
726 /* Performing FN upon single counters. */
727
728 static void
729 __gcov_single_counter_op (gcov_type *counters, unsigned n_counters,
730 counter_op_fn fn, void *data1, void *data2)
731 {
732 unsigned i, n_measures;
733
734 gcc_assert (!(n_counters % 3));
735 n_measures = n_counters / 3;
736 for (i = 0; i < n_measures; i++, counters += 3)
737 {
738 counters[1] = fn (counters[1], data1, data2);
739 counters[2] = fn (counters[2], data1, data2);
740 }
741 }
742
743 /* Performing FN upon indirect-call profile counters. */
744
745 static void
746 __gcov_icall_topn_counter_op (gcov_type *counters, unsigned n_counters,
747 counter_op_fn fn, void *data1, void *data2)
748 {
749 unsigned i;
750
751 gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS));
752 for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS)
753 {
754 unsigned j;
755 gcov_type *value_array = &counters[i + 1];
756
757 for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
758 value_array[j + 1] = fn (value_array[j + 1], data1, data2);
759 }
760 }
761
762 /* Scaling the counter value V by multiplying *(float*) DATA1. */
763
764 static gcov_type
765 fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
766 {
767 float f = *(float *) data1;
768 return (gcov_type) (v * f);
769 }
770
771 /* Scaling the counter value V by multiplying DATA2/DATA1. */
772
773 static gcov_type
774 int_scale (gcov_type v, void *data1, void *data2)
775 {
776 int n = *(int *) data1;
777 int d = *(int *) data2;
778 return (gcov_type) ( RDIV (v,d) * n);
779 }
780
781 /* Type of function used to process counters. */
782 typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
783 counter_op_fn, void *, void *);
784
785 /* Function array to process profile counters. */
786 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
787 __gcov ## FN_TYPE ## _counter_op,
788 static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
789 #include "gcov-counter.def"
790 };
791 #undef DEF_GCOV_COUNTER
792
793 /* Driver for scaling profile counters. */
794
795 int
796 gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
797 {
798 struct gcov_info *gi_ptr;
799 unsigned f_ix;
800
801 if (verbose)
802 fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
803
804 /* Scaling the counters. */
805 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
806 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
807 {
808 unsigned t_ix;
809 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
810 const struct gcov_ctr_info *ci_ptr;
811
812 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
813 continue;
814
815 ci_ptr = gfi_ptr->ctrs;
816 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
817 {
818 gcov_merge_fn merge = gi_ptr->merge[t_ix];
819
820 if (!merge)
821 continue;
822 if (d == 0)
823 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
824 fp_scale, &scale_factor, NULL);
825 else
826 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
827 int_scale, &n, &d);
828 ci_ptr++;
829 }
830 }
831
832 return 0;
833 }
834
835 /* Driver to normalize profile counters. */
836
837 int
838 gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
839 {
840 struct gcov_info *gi_ptr;
841 gcov_type curr_max_val = 0;
842 unsigned f_ix;
843 unsigned int i;
844 float scale_factor;
845
846 /* Find the largest count value. */
847 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
848 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
849 {
850 unsigned t_ix;
851 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
852 const struct gcov_ctr_info *ci_ptr;
853
854 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
855 continue;
856
857 ci_ptr = gfi_ptr->ctrs;
858 for (t_ix = 0; t_ix < 1; t_ix++)
859 {
860 for (i = 0; i < ci_ptr->num; i++)
861 if (ci_ptr->values[i] > curr_max_val)
862 curr_max_val = ci_ptr->values[i];
863 ci_ptr++;
864 }
865 }
866
867 scale_factor = (float)max_val / curr_max_val;
868 if (verbose)
869 fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
870
871 return gcov_profile_scale (profile, scale_factor, 0, 0);
872 }
873
874 /* The following variables are defined in gcc/gcov-tool.c. */
875 extern int overlap_func_level;
876 extern int overlap_obj_level;
877 extern int overlap_hot_only;
878 extern int overlap_use_fullname;
879 extern double overlap_hot_threshold;
880
881 /* Compute the overlap score of two values. The score is defined as:
882 min (V1/SUM_1, V2/SUM_2) */
883
884 static double
885 calculate_2_entries (const unsigned long v1, const unsigned long v2,
886 const double sum_1, const double sum_2)
887 {
888 double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
889 double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
890
891 if (val2 < val1)
892 val1 = val2;
893
894 return val1;
895 }
896
897 /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
898 This function also updates cumulative score CUM_1_RESULT and
899 CUM_2_RESULT. */
900
901 static double
902 compute_one_gcov (const struct gcov_info *gcov_info1,
903 const struct gcov_info *gcov_info2,
904 const double sum_1, const double sum_2,
905 double *cum_1_result, double *cum_2_result)
906 {
907 unsigned f_ix;
908 double ret = 0;
909 double cum_1 = 0, cum_2 = 0;
910 const struct gcov_info *gcov_info = 0;
911 double *cum_p;
912 double sum;
913
914 gcc_assert (gcov_info1 || gcov_info2);
915 if (!gcov_info1)
916 {
917 gcov_info = gcov_info2;
918 cum_p = cum_2_result;
919 sum = sum_2;
920 *cum_1_result = 0;
921 } else
922 if (!gcov_info2)
923 {
924 gcov_info = gcov_info1;
925 cum_p = cum_1_result;
926 sum = sum_1;
927 *cum_2_result = 0;
928 }
929
930 if (gcov_info)
931 {
932 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
933 {
934 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
935 if (!gfi_ptr || gfi_ptr->key != gcov_info)
936 continue;
937 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
938 unsigned c_num;
939 for (c_num = 0; c_num < ci_ptr->num; c_num++)
940 cum_1 += ci_ptr->values[c_num] / sum;
941 }
942 *cum_p = cum_1;
943 return 0.0;
944 }
945
946 for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
947 {
948 double func_cum_1 = 0.0;
949 double func_cum_2 = 0.0;
950 double func_val = 0.0;
951 int nonzero = 0;
952 int hot = 0;
953 const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
954 const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
955
956 if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
957 continue;
958 if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
959 continue;
960
961 const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
962 const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
963 unsigned c_num;
964 for (c_num = 0; c_num < ci_ptr1->num; c_num++)
965 {
966 if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
967 {
968 func_val += calculate_2_entries (ci_ptr1->values[c_num],
969 ci_ptr2->values[c_num],
970 sum_1, sum_2);
971
972 func_cum_1 += ci_ptr1->values[c_num] / sum_1;
973 func_cum_2 += ci_ptr2->values[c_num] / sum_2;
974 nonzero = 1;
975 if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
976 || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
977 hot = 1;
978 }
979 }
980
981 ret += func_val;
982 cum_1 += func_cum_1;
983 cum_2 += func_cum_2;
984 if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
985 {
986 printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
987 gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
988 }
989 }
990 *cum_1_result = cum_1;
991 *cum_2_result = cum_2;
992 return ret;
993 }
994
995 /* Test if all counter values in this GCOV_INFO are cold.
996 "Cold" is defined as the counter value being less than
997 or equal to THRESHOLD. */
998
999 static bool
1000 gcov_info_count_all_cold (const struct gcov_info *gcov_info,
1001 gcov_type threshold)
1002 {
1003 unsigned f_ix;
1004
1005 for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
1006 {
1007 const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
1008
1009 if (!gfi_ptr || gfi_ptr->key != gcov_info)
1010 continue;
1011 const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
1012 for (unsigned c_num = 0; c_num < ci_ptr->num; c_num++)
1013 if (ci_ptr->values[c_num] > threshold)
1014 return false;
1015 }
1016
1017 return true;
1018 }
1019
1020 /* Test if all counter values in this GCOV_INFO are 0. */
1021
1022 static bool
1023 gcov_info_count_all_zero (const struct gcov_info *gcov_info)
1024 {
1025 return gcov_info_count_all_cold (gcov_info, 0);
1026 }
1027
1028 /* A pair of matched GCOV_INFO.
1029 The flag is a bitvector:
1030 b0: obj1's all counts are 0;
1031 b1: obj1's all counts are cold (but no 0);
1032 b2: obj1 is hot;
1033 b3: no obj1 to match obj2;
1034 b4: obj2's all counts are 0;
1035 b5: obj2's all counts are cold (but no 0);
1036 b6: obj2 is hot;
1037 b7: no obj2 to match obj1;
1038 */
1039 struct overlap_t {
1040 const struct gcov_info *obj1;
1041 const struct gcov_info *obj2;
1042 char flag;
1043 };
1044
1045 #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1046 #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1047 #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1048
1049 /* Cumlative overlap dscore for profile1 and profile2. */
1050 static double overlap_sum_1, overlap_sum_2;
1051
1052 /* The number of gcda files in the profiles. */
1053 static unsigned gcda_files[2];
1054
1055 /* The number of unique gcda files in the profiles
1056 (not existing in the other profile). */
1057 static unsigned unique_gcda_files[2];
1058
1059 /* The number of gcda files that all counter values are 0. */
1060 static unsigned zero_gcda_files[2];
1061
1062 /* The number of gcda files that all counter values are cold (but not 0). */
1063 static unsigned cold_gcda_files[2];
1064
1065 /* The number of gcda files that includes hot counter values. */
1066 static unsigned hot_gcda_files[2];
1067
1068 /* The number of gcda files with hot count value in either profiles. */
1069 static unsigned both_hot_cnt;
1070
1071 /* The number of gcda files with all counts cold (but not 0) in
1072 both profiles. */
1073 static unsigned both_cold_cnt;
1074
1075 /* The number of gcda files with all counts 0 in both profiles. */
1076 static unsigned both_zero_cnt;
1077
1078 /* Extract the basename of the filename NAME. */
1079
1080 static char *
1081 extract_file_basename (const char *name)
1082 {
1083 char *str;
1084 int len = 0;
1085 char *path = xstrdup (name);
1086 char sep_str[2];
1087
1088 sep_str[0] = DIR_SEPARATOR;
1089 sep_str[1] = 0;
1090 str = strstr(path, sep_str);
1091 do{
1092 len = strlen(str) + 1;
1093 path = &path[strlen(path) - len + 2];
1094 str = strstr(path, sep_str);
1095 } while(str);
1096
1097 return path;
1098 }
1099
1100 /* Utility function to get the filename. */
1101
1102 static const char *
1103 get_file_basename (const char *name)
1104 {
1105 if (overlap_use_fullname)
1106 return name;
1107 return extract_file_basename (name);
1108 }
1109
1110 /* A utility function to set the flag for the gcda files. */
1111
1112 static void
1113 set_flag (struct overlap_t *e)
1114 {
1115 char flag = 0;
1116
1117 if (!e->obj1)
1118 {
1119 unique_gcda_files[1]++;
1120 flag = 0x8;
1121 }
1122 else
1123 {
1124 gcda_files[0]++;
1125 if (gcov_info_count_all_zero (e->obj1))
1126 {
1127 zero_gcda_files[0]++;
1128 flag = 0x1;
1129 }
1130 else
1131 if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
1132 * overlap_hot_threshold))
1133 {
1134 cold_gcda_files[0]++;
1135 flag = 0x2;
1136 }
1137 else
1138 {
1139 hot_gcda_files[0]++;
1140 flag = 0x4;
1141 }
1142 }
1143
1144 if (!e->obj2)
1145 {
1146 unique_gcda_files[0]++;
1147 flag |= (0x8 << 4);
1148 }
1149 else
1150 {
1151 gcda_files[1]++;
1152 if (gcov_info_count_all_zero (e->obj2))
1153 {
1154 zero_gcda_files[1]++;
1155 flag |= (0x1 << 4);
1156 }
1157 else
1158 if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
1159 * overlap_hot_threshold))
1160 {
1161 cold_gcda_files[1]++;
1162 flag |= (0x2 << 4);
1163 }
1164 else
1165 {
1166 hot_gcda_files[1]++;
1167 flag |= (0x4 << 4);
1168 }
1169 }
1170
1171 gcc_assert (flag);
1172 e->flag = flag;
1173 }
1174
1175 /* Test if INFO1 and INFO2 are from the matched source file.
1176 Return 1 if they match; return 0 otherwise. */
1177
1178 static int
1179 matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
1180 {
1181 /* For FDO, we have to match the name. This can be expensive.
1182 Maybe we should use hash here. */
1183 if (strcmp (info1->filename, info2->filename))
1184 return 0;
1185
1186 if (info1->n_functions != info2->n_functions)
1187 {
1188 fnotice (stderr, "mismatched profiles in %s (%d functions"
1189 " vs %d functions)\n",
1190 info1->filename,
1191 info1->n_functions,
1192 info2->n_functions);
1193 return 0;
1194 }
1195 return 1;
1196 }
1197
1198 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1199 GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1200 match and 1.0 meaning a perfect match. */
1201
1202 static double
1203 calculate_overlap (struct gcov_info *gcov_list1,
1204 struct gcov_info *gcov_list2)
1205 {
1206 unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
1207 unsigned int i, j;
1208 const struct gcov_info *gi_ptr;
1209 struct overlap_t *all_infos;
1210
1211 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
1212 list1_cnt++;
1213 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
1214 list2_cnt++;
1215 all_cnt = list1_cnt + list2_cnt;
1216 all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
1217 * all_cnt * 2);
1218 gcc_assert (all_infos);
1219
1220 i = 0;
1221 for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
1222 {
1223 all_infos[i].obj1 = gi_ptr;
1224 all_infos[i].obj2 = 0;
1225 }
1226
1227 for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
1228 {
1229 all_infos[i].obj1 = 0;
1230 all_infos[i].obj2 = gi_ptr;
1231 }
1232
1233 for (i = list1_cnt; i < all_cnt; i++)
1234 {
1235 if (all_infos[i].obj2 == 0)
1236 continue;
1237 for (j = 0; j < list1_cnt; j++)
1238 {
1239 if (all_infos[j].obj2 != 0)
1240 continue;
1241 if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
1242 {
1243 all_infos[j].obj2 = all_infos[i].obj2;
1244 all_infos[i].obj2 = 0;
1245 break;
1246 }
1247 }
1248 }
1249
1250 for (i = 0; i < all_cnt; i++)
1251 if (all_infos[i].obj1 || all_infos[i].obj2)
1252 {
1253 set_flag (all_infos + i);
1254 if (FLAG_ONE_HOT (all_infos[i].flag))
1255 both_hot_cnt++;
1256 if (FLAG_BOTH_COLD(all_infos[i].flag))
1257 both_cold_cnt++;
1258 if (FLAG_BOTH_ZERO(all_infos[i].flag))
1259 both_zero_cnt++;
1260 }
1261
1262 double prg_val = 0;
1263 double sum_val = 0;
1264 double sum_cum_1 = 0;
1265 double sum_cum_2 = 0;
1266
1267 for (i = 0; i < all_cnt; i++)
1268 {
1269 double val;
1270 double cum_1, cum_2;
1271 const char *filename;
1272
1273 if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
1274 continue;
1275 if (FLAG_BOTH_ZERO (all_infos[i].flag))
1276 continue;
1277
1278 if (all_infos[i].obj1)
1279 filename = get_file_basename (all_infos[i].obj1->filename);
1280 else
1281 filename = get_file_basename (all_infos[i].obj2->filename);
1282
1283 if (overlap_func_level)
1284 printf("\n processing %36s:\n", filename);
1285
1286 val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
1287 overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
1288
1289 if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
1290 {
1291 printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1292 filename, val*100, cum_1*100, cum_2*100);
1293 sum_val += val;
1294 sum_cum_1 += cum_1;
1295 sum_cum_2 += cum_2;
1296 }
1297
1298 prg_val += val;
1299
1300 }
1301
1302 if (overlap_obj_level)
1303 printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1304 "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
1305
1306 printf (" Statistics:\n"
1307 " profile1_# profile2_# overlap_#\n");
1308 printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
1309 gcda_files[0]-unique_gcda_files[0]);
1310 printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
1311 unique_gcda_files[1]);
1312 printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
1313 hot_gcda_files[1], both_hot_cnt);
1314 printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
1315 cold_gcda_files[1], both_cold_cnt);
1316 printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
1317 zero_gcda_files[1], both_zero_cnt);
1318
1319 return prg_val;
1320 }
1321
1322 /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1323 PROFILE2.
1324 Return 0 on success: without mismatch. Reutrn 1 on error. */
1325
1326 int
1327 gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
1328 {
1329 double result;
1330
1331 result = calculate_overlap (profile1, profile2);
1332
1333 if (result > 0)
1334 {
1335 printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
1336 return 0;
1337 }
1338 return 1;
1339 }
This page took 0.096139 seconds and 5 git commands to generate.