cfgcleanup.c (try_optimize_cfg): Do not remove label with LABEL_PRESERVE_P flag set.
[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 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
36 /* Borrowed from basic-block.h. */
37 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
38
39 extern gcov_position_t gcov_position();
40 extern int gcov_is_error();
41
42 /* Verbose mode for debug. */
43 static int verbose;
44
45 /* Set verbose flag. */
46 void gcov_set_verbose (void)
47 {
48 verbose = 1;
49 }
50
51 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
52
53 #include "obstack.h"
54 #include <unistd.h>
55 #include <ftw.h>
56
57 static void tag_function (unsigned, unsigned);
58 static void tag_blocks (unsigned, unsigned);
59 static void tag_arcs (unsigned, unsigned);
60 static void tag_lines (unsigned, unsigned);
61 static void tag_counters (unsigned, unsigned);
62 static void tag_summary (unsigned, unsigned);
63
64 /* The gcov_info for the first module. */
65 static struct gcov_info *curr_gcov_info;
66 /* The gcov_info being processed. */
67 static struct gcov_info *gcov_info_head;
68 /* This variable contains all the functions in current module. */
69 static struct obstack fn_info;
70 /* The function being processed. */
71 static struct gcov_fn_info *curr_fn_info;
72 /* The number of functions seen so far. */
73 static unsigned num_fn_info;
74 /* This variable contains all the counters for current module. */
75 static int k_ctrs_mask[GCOV_COUNTERS];
76 /* The kind of counters that have been seen. */
77 static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
78 /* Number of kind of counters that have been seen. */
79 static int k_ctrs_types;
80
81 /* Merge functions for counters. */
82 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
83 static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
84 #include "gcov-counter.def"
85 };
86 #undef DEF_GCOV_COUNTER
87
88 /* Set the ctrs field in gcov_fn_info object FN_INFO. */
89
90 static void
91 set_fn_ctrs (struct gcov_fn_info *fn_info)
92 {
93 int j = 0, i;
94
95 for (i = 0; i < GCOV_COUNTERS; i++)
96 {
97 if (k_ctrs_mask[i] == 0)
98 continue;
99 fn_info->ctrs[j].num = k_ctrs[i].num;
100 fn_info->ctrs[j].values = k_ctrs[i].values;
101 j++;
102 }
103 if (k_ctrs_types == 0)
104 k_ctrs_types = j;
105 else
106 gcc_assert (j == k_ctrs_types);
107 }
108
109 /* For each tag in gcda file, we have an entry here.
110 TAG is the tag value; NAME is the tag name; and
111 PROC is the handler function. */
112
113 typedef struct tag_format
114 {
115 unsigned tag;
116 char const *name;
117 void (*proc) (unsigned, unsigned);
118 } tag_format_t;
119
120 /* Handler table for various Tags. */
121
122 static const tag_format_t tag_table[] =
123 {
124 {0, "NOP", NULL},
125 {0, "UNKNOWN", NULL},
126 {0, "COUNTERS", tag_counters},
127 {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
128 {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
129 {GCOV_TAG_ARCS, "ARCS", tag_arcs},
130 {GCOV_TAG_LINES, "LINES", tag_lines},
131 {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
132 {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary},
133 {0, NULL, NULL}
134 };
135
136 /* Handler for reading function tag. */
137
138 static void
139 tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
140 {
141 int i;
142
143 /* write out previous fn_info. */
144 if (num_fn_info)
145 {
146 set_fn_ctrs (curr_fn_info);
147 obstack_ptr_grow (&fn_info, curr_fn_info);
148 }
149
150 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
151 counter types. */
152 curr_fn_info = (struct gcov_fn_info *) xcalloc (sizeof (struct gcov_fn_info)
153 + GCOV_COUNTERS * sizeof (struct gcov_ctr_info), 1);
154
155 for (i = 0; i < GCOV_COUNTERS; i++)
156 k_ctrs[i].num = 0;
157 k_ctrs_types = 0;
158
159 curr_fn_info->key = curr_gcov_info;
160 curr_fn_info->ident = gcov_read_unsigned ();
161 curr_fn_info->lineno_checksum = gcov_read_unsigned ();
162 curr_fn_info->cfg_checksum = gcov_read_unsigned ();
163 num_fn_info++;
164
165 if (verbose)
166 fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
167 }
168
169 /* Handler for reading block tag. */
170
171 static void
172 tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
173 {
174 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
175 gcc_unreachable ();
176 }
177
178 /* Handler for reading flow arc tag. */
179
180 static void
181 tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
182 {
183 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
184 gcc_unreachable ();
185 }
186
187 /* Handler for reading line tag. */
188
189 static void
190 tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
191 {
192 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
193 gcc_unreachable ();
194 }
195
196 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
197
198 static void
199 tag_counters (unsigned tag, unsigned length)
200 {
201 unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
202 gcov_type *values;
203 unsigned ix;
204 unsigned tag_ix;
205
206 tag_ix = GCOV_COUNTER_FOR_TAG (tag);
207 gcc_assert (tag_ix < GCOV_COUNTERS);
208 k_ctrs_mask [tag_ix] = 1;
209 gcc_assert (k_ctrs[tag_ix].num == 0);
210 k_ctrs[tag_ix].num = n_counts;
211
212 k_ctrs[tag_ix].values = values = (gcov_type *) xmalloc (n_counts * sizeof (gcov_type));
213 gcc_assert (values);
214
215 for (ix = 0; ix != n_counts; ix++)
216 values[ix] = gcov_read_counter ();
217 }
218
219 /* Handler for reading summary tag. */
220
221 static void
222 tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
223 {
224 struct gcov_summary summary;
225
226 gcov_read_summary (&summary);
227 }
228
229 /* This function is called at the end of reading a gcda file.
230 It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO. */
231
232 static void
233 read_gcda_finalize (struct gcov_info *obj_info)
234 {
235 int i;
236
237 set_fn_ctrs (curr_fn_info);
238 obstack_ptr_grow (&fn_info, curr_fn_info);
239
240 /* We set the following fields: merge, n_functions, and functions. */
241 obj_info->n_functions = num_fn_info;
242 obj_info->functions = (const struct gcov_fn_info**) obstack_finish (&fn_info);
243
244 /* wrap all the counter array. */
245 for (i=0; i< GCOV_COUNTERS; i++)
246 {
247 if (k_ctrs_mask[i])
248 obj_info->merge[i] = ctr_merge_functions[i];
249 }
250 }
251
252 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
253 Program level summary CURRENT_SUMMARY will also be updated. */
254
255 static struct gcov_info *
256 read_gcda_file (const char *filename)
257 {
258 unsigned tags[4];
259 unsigned depth = 0;
260 unsigned magic, version;
261 struct gcov_info *obj_info;
262 int i;
263
264 for (i=0; i< GCOV_COUNTERS; i++)
265 k_ctrs_mask[i] = 0;
266 k_ctrs_types = 0;
267
268 if (!gcov_open (filename))
269 {
270 fnotice (stderr, "%s:cannot open\n", filename);
271 return NULL;
272 }
273
274 /* Read magic. */
275 magic = gcov_read_unsigned ();
276 if (magic != GCOV_DATA_MAGIC)
277 {
278 fnotice (stderr, "%s:not a gcov data file\n", filename);
279 gcov_close ();
280 return NULL;
281 }
282
283 /* Read version. */
284 version = gcov_read_unsigned ();
285 if (version != GCOV_VERSION)
286 {
287 fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
288 gcov_close ();
289 return NULL;
290 }
291
292 /* Instantiate a gcov_info object. */
293 curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
294 sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
295
296 obj_info->version = version;
297 obstack_init (&fn_info);
298 num_fn_info = 0;
299 curr_fn_info = 0;
300 {
301 size_t len = strlen (filename) + 1;
302 char *str_dup = (char*) xmalloc (len);
303
304 memcpy (str_dup, filename, len);
305 obj_info->filename = str_dup;
306 }
307
308 /* Read stamp. */
309 obj_info->stamp = gcov_read_unsigned ();
310
311 while (1)
312 {
313 gcov_position_t base;
314 unsigned tag, length;
315 tag_format_t const *format;
316 unsigned tag_depth;
317 int error;
318 unsigned mask;
319
320 tag = gcov_read_unsigned ();
321 if (!tag)
322 break;
323 length = gcov_read_unsigned ();
324 base = gcov_position ();
325 mask = GCOV_TAG_MASK (tag) >> 1;
326 for (tag_depth = 4; mask; mask >>= 8)
327 {
328 if (((mask & 0xff) != 0xff))
329 {
330 warning (0, "%s:tag `%x' is invalid\n", filename, tag);
331 break;
332 }
333 tag_depth--;
334 }
335 for (format = tag_table; format->name; format++)
336 if (format->tag == tag)
337 goto found;
338 format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
339 found:;
340 if (tag)
341 {
342 if (depth && depth < tag_depth)
343 {
344 if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
345 warning (0, "%s:tag `%x' is incorrectly nested\n",
346 filename, tag);
347 }
348 depth = tag_depth;
349 tags[depth - 1] = tag;
350 }
351
352 if (format->proc)
353 {
354 unsigned long actual_length;
355
356 (*format->proc) (tag, length);
357
358 actual_length = gcov_position () - base;
359 if (actual_length > length)
360 warning (0, "%s:record size mismatch %lu bytes overread\n",
361 filename, actual_length - length);
362 else if (length > actual_length)
363 warning (0, "%s:record size mismatch %lu bytes unread\n",
364 filename, length - actual_length);
365 }
366
367 gcov_sync (base, length);
368 if ((error = gcov_is_error ()))
369 {
370 warning (0, error < 0 ? "%s:counter overflow at %lu\n" :
371 "%s:read error at %lu\n", filename,
372 (long unsigned) gcov_position ());
373 break;
374 }
375 }
376
377 read_gcda_finalize (obj_info);
378 gcov_close ();
379
380 return obj_info;
381 }
382
383 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
384 Return a non-zero value to stop the tree walk. */
385
386 static int
387 ftw_read_file (const char *filename,
388 const struct stat *status ATTRIBUTE_UNUSED,
389 int type)
390 {
391 int filename_len;
392 int suffix_len;
393 struct gcov_info *obj_info;
394
395 /* Only read regular files. */
396 if (type != FTW_F)
397 return 0;
398
399 filename_len = strlen (filename);
400 suffix_len = strlen (GCOV_DATA_SUFFIX);
401
402 if (filename_len <= suffix_len)
403 return 0;
404
405 if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
406 return 0;
407
408 if (verbose)
409 fnotice (stderr, "reading file: %s\n", filename);
410
411 obj_info = read_gcda_file (filename);
412 if (!obj_info)
413 return 0;
414
415 obj_info->next = gcov_info_head;
416 gcov_info_head = obj_info;
417
418 return 0;
419 }
420
421 /* Initializer for reading a profile dir. */
422
423 static inline void
424 read_profile_dir_init (void)
425 {
426 gcov_info_head = 0;
427 }
428
429 /* Driver for read a profile directory and convert into gcov_info list in memory.
430 Return NULL on error,
431 Return the head of gcov_info list on success. */
432
433 struct gcov_info *
434 gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
435 {
436 char *pwd;
437 int ret;
438
439 read_profile_dir_init ();
440
441 if (access (dir_name, R_OK) != 0)
442 {
443 fnotice (stderr, "cannot access directory %s\n", dir_name);
444 return NULL;
445 }
446 pwd = getcwd (NULL, 0);
447 gcc_assert (pwd);
448 ret = chdir (dir_name);
449 if (ret !=0)
450 {
451 fnotice (stderr, "%s is not a directory\n", dir_name);
452 return NULL;
453 }
454 ftw (".", ftw_read_file, 50);
455 ret = chdir (pwd);
456 free (pwd);
457
458
459 return gcov_info_head;;
460 }
461
462 /* This part of the code is to merge profile counters. These
463 variables are set in merge_wrapper and to be used by
464 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
465
466 /* We save the counter value address to this variable. */
467 static gcov_type *gcov_value_buf;
468
469 /* The number of counter values to be read by current merging. */
470 static gcov_unsigned_t gcov_value_buf_size;
471
472 /* The index of counter values being read. */
473 static gcov_unsigned_t gcov_value_buf_pos;
474
475 /* The weight of current merging. */
476 static unsigned gcov_merge_weight;
477
478 /* Read a counter value from gcov_value_buf array. */
479
480 gcov_type
481 gcov_read_counter_mem (void)
482 {
483 gcov_type ret;
484 gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
485 ret = *(gcov_value_buf + gcov_value_buf_pos);
486 ++gcov_value_buf_pos;
487 return ret;
488 }
489
490 /* Return the recorded merge weight. */
491
492 unsigned
493 gcov_get_merge_weight (void)
494 {
495 return gcov_merge_weight;
496 }
497
498 /* A wrapper function for merge functions. It sets up the
499 value buffer and weights and then calls the merge function. */
500
501 static void
502 merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n,
503 gcov_type *v2, unsigned w)
504 {
505 gcov_value_buf = v2;
506 gcov_value_buf_pos = 0;
507 gcov_value_buf_size = n;
508 gcov_merge_weight = w;
509 (*f) (v1, n);
510 }
511
512 /* Offline tool to manipulate profile data.
513 This tool targets on matched profiles. But it has some tolerance on
514 unmatched profiles.
515 When merging p1 to p2 (p2 is the dst),
516 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
517 emit warning
518 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
519 specified weight; emit warning.
520 * m.gcda in both p1 and p2:
521 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
522 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
523 p2->m.gcda->f and
524 drop p1->m.gcda->f. A warning is emitted. */
525
526 /* Add INFO2's counter to INFO1, multiplying by weight W. */
527
528 static int
529 gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
530 {
531 unsigned f_ix;
532 unsigned n_functions = info1->n_functions;
533 int has_mismatch = 0;
534
535 gcc_assert (info2->n_functions == n_functions);
536 for (f_ix = 0; f_ix < n_functions; f_ix++)
537 {
538 unsigned t_ix;
539 const struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
540 const struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
541 const struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
542
543 if (!gfi_ptr1 || gfi_ptr1->key != info1)
544 continue;
545 if (!gfi_ptr2 || gfi_ptr2->key != info2)
546 continue;
547
548 if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
549 {
550 fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
551 info1->filename);
552 has_mismatch = 1;
553 continue;
554 }
555 ci_ptr1 = gfi_ptr1->ctrs;
556 ci_ptr2 = gfi_ptr2->ctrs;
557 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
558 {
559 gcov_merge_fn merge1 = info1->merge[t_ix];
560 gcov_merge_fn merge2 = info2->merge[t_ix];
561
562 gcc_assert (merge1 == merge2);
563 if (!merge1)
564 continue;
565 gcc_assert (ci_ptr1->num == ci_ptr2->num);
566 merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num, ci_ptr2->values, w);
567 ci_ptr1++;
568 ci_ptr2++;
569 }
570 }
571
572 return has_mismatch;
573 }
574
575 /* Find and return the match gcov_info object for INFO from ARRAY.
576 SIZE is the length of ARRAY.
577 Return NULL if there is no match. */
578
579 static struct gcov_info *
580 find_match_gcov_info (struct gcov_info **array, int size, struct gcov_info *info)
581 {
582 struct gcov_info *gi_ptr;
583 struct gcov_info *ret = NULL;
584 int i;
585
586 for (i = 0; i < size; i++)
587 {
588 gi_ptr = array[i];
589 if (gi_ptr == 0)
590 continue;
591 if (!strcmp (gi_ptr->filename, info->filename))
592 {
593 ret = gi_ptr;
594 array[i] = 0;
595 break;
596 }
597 }
598
599 if (ret && ret->n_functions != info->n_functions)
600 {
601 fnotice (stderr, "mismatched profiles in %s (%d functions"
602 " vs %d functions)\n",
603 ret->filename,
604 ret->n_functions,
605 info->n_functions);
606 ret = NULL;
607 }
608 return ret;
609 }
610
611 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
612 Return 0 on success: without mismatch.
613 Reutrn 1 on error. */
614
615 int
616 gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
617 int w1, int w2)
618 {
619 struct gcov_info *gi_ptr;
620 struct gcov_info **tgt_infos;
621 struct gcov_info *tgt_tail;
622 struct gcov_info **in_src_not_tgt;
623 unsigned tgt_cnt = 0, src_cnt = 0;
624 unsigned unmatch_info_cnt = 0;
625 unsigned int i;
626
627 for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
628 tgt_cnt++;
629 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
630 src_cnt++;
631 tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
632 * tgt_cnt);
633 gcc_assert (tgt_infos);
634 in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
635 * src_cnt);
636 gcc_assert (in_src_not_tgt);
637
638 for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
639 tgt_infos[i] = gi_ptr;
640
641 tgt_tail = tgt_infos[tgt_cnt - 1];
642
643 /* First pass on tgt_profile, we multiply w1 to all counters. */
644 if (w1 > 1)
645 {
646 for (i = 0; i < tgt_cnt; i++)
647 gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
648 }
649
650 /* Second pass, add src_profile to the tgt_profile. */
651 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
652 {
653 struct gcov_info *gi_ptr1;
654
655 gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
656 if (gi_ptr1 == NULL)
657 {
658 in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
659 continue;
660 }
661 gcov_merge (gi_ptr1, gi_ptr, w2);
662 }
663
664 /* For modules in src but not in tgt. We adjust the counter and append. */
665 for (i = 0; i < unmatch_info_cnt; i++)
666 {
667 gi_ptr = in_src_not_tgt[i];
668 gcov_merge (gi_ptr, gi_ptr, w2 - 1);
669 tgt_tail->next = gi_ptr;
670 tgt_tail = gi_ptr;
671 }
672
673 return 0;
674 }
675
676 typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
677
678 /* Performing FN upon arc counters. */
679
680 static void
681 __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
682 counter_op_fn fn, void *data1, void *data2)
683 {
684 for (; n_counters; counters++, n_counters--)
685 {
686 gcov_type val = *counters;
687 *counters = fn(val, data1, data2);
688 }
689 }
690
691 /* Performing FN upon ior counters. */
692
693 static void
694 __gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
695 unsigned n_counters ATTRIBUTE_UNUSED,
696 counter_op_fn fn ATTRIBUTE_UNUSED,
697 void *data1 ATTRIBUTE_UNUSED,
698 void *data2 ATTRIBUTE_UNUSED)
699 {
700 /* Do nothing. */
701 }
702
703 /* Performing FN upon time-profile counters. */
704
705 static void
706 __gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
707 unsigned n_counters ATTRIBUTE_UNUSED,
708 counter_op_fn fn ATTRIBUTE_UNUSED,
709 void *data1 ATTRIBUTE_UNUSED,
710 void *data2 ATTRIBUTE_UNUSED)
711 {
712 /* Do nothing. */
713 }
714
715 /* Performaing FN upon delta counters. */
716
717 static void
718 __gcov_delta_counter_op (gcov_type *counters, unsigned n_counters,
719 counter_op_fn fn, void *data1, void *data2)
720 {
721 unsigned i, n_measures;
722
723 gcc_assert (!(n_counters % 4));
724 n_measures = n_counters / 4;
725 for (i = 0; i < n_measures; i++, counters += 4)
726 {
727 counters[2] = fn (counters[2], data1, data2);
728 counters[3] = fn (counters[3], data1, data2);
729 }
730 }
731
732 /* Performing FN upon single counters. */
733
734 static void
735 __gcov_single_counter_op (gcov_type *counters, unsigned n_counters,
736 counter_op_fn fn, void *data1, void *data2)
737 {
738 unsigned i, n_measures;
739
740 gcc_assert (!(n_counters % 3));
741 n_measures = n_counters / 3;
742 for (i = 0; i < n_measures; i++, counters += 3)
743 {
744 counters[1] = fn (counters[1], data1, data2);
745 counters[2] = fn (counters[2], data1, data2);
746 }
747 }
748
749 /* Scaling the counter value V by multiplying *(float*) DATA1. */
750
751 static gcov_type
752 fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
753 {
754 float f = *(float *) data1;
755 return (gcov_type) (v * f);
756 }
757
758 /* Scaling the counter value V by multiplying DATA2/DATA1. */
759
760 static gcov_type
761 int_scale (gcov_type v, void *data1, void *data2)
762 {
763 int n = *(int *) data1;
764 int d = *(int *) data2;
765 return (gcov_type) ( RDIV (v,d) * n);
766 }
767
768 /* Type of function used to process counters. */
769 typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
770 counter_op_fn, void *, void *);
771
772 /* Function array to process profile counters. */
773 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
774 __gcov ## FN_TYPE ## _counter_op,
775 static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
776 #include "gcov-counter.def"
777 };
778 #undef DEF_GCOV_COUNTER
779
780 /* Driver for scaling profile counters. */
781
782 int
783 gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
784 {
785 struct gcov_info *gi_ptr;
786 unsigned f_ix;
787
788 if (verbose)
789 fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
790
791 /* Scaling the counters. */
792 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
793 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
794 {
795 unsigned t_ix;
796 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
797 const struct gcov_ctr_info *ci_ptr;
798
799 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
800 continue;
801
802 ci_ptr = gfi_ptr->ctrs;
803 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
804 {
805 gcov_merge_fn merge = gi_ptr->merge[t_ix];
806
807 if (!merge)
808 continue;
809 if (d == 0)
810 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
811 fp_scale, &scale_factor, NULL);
812 else
813 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
814 int_scale, &n, &d);
815 ci_ptr++;
816 }
817 }
818
819 return 0;
820 }
821
822 /* Driver to normalize profile counters. */
823
824 int
825 gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
826 {
827 struct gcov_info *gi_ptr;
828 gcov_type curr_max_val = 0;
829 unsigned f_ix;
830 unsigned int i;
831 float scale_factor;
832
833 /* Find the largest count value. */
834 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
835 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
836 {
837 unsigned t_ix;
838 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
839 const struct gcov_ctr_info *ci_ptr;
840
841 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
842 continue;
843
844 ci_ptr = gfi_ptr->ctrs;
845 for (t_ix = 0; t_ix < 1; t_ix++)
846 {
847 for (i = 0; i < ci_ptr->num; i++)
848 if (ci_ptr->values[i] > curr_max_val)
849 curr_max_val = ci_ptr->values[i];
850 ci_ptr++;
851 }
852 }
853
854 scale_factor = (float)max_val / curr_max_val;
855 if (verbose)
856 fnotice (stdout, "max_val is %lld\n", (long long) curr_max_val);
857
858 return gcov_profile_scale (profile, scale_factor, 0, 0);
859 }