* go-gcc.cc (Gcc_backend::global_variable_set_init): Rename
[official-gcc.git] / libgcc / libgcov-util.c
blobfc67979fcb849cbe5b32f263dc13d13370e192c1
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>.
6 This file is part of GCC.
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.
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.
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.
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/>. */
28 #define IN_GCOV_TOOL 1
30 #include "libgcov.h"
31 #include "intl.h"
32 #include "diagnostic.h"
33 #include "version.h"
34 #include "demangle.h"
36 /* Borrowed from basic-block.h. */
37 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
39 extern gcov_position_t gcov_position();
40 extern int gcov_is_error();
41 extern size_t gcov_max_filename;
43 /* Verbose mode for debug. */
44 static int verbose;
46 /* Set verbose flag. */
47 void gcov_set_verbose (void)
49 verbose = 1;
52 /* The following part is to read Gcda and reconstruct GCOV_INFO. */
54 #include "obstack.h"
55 #include <unistd.h>
56 #include <ftw.h>
58 static void tag_function (unsigned, unsigned);
59 static void tag_blocks (unsigned, unsigned);
60 static void tag_arcs (unsigned, unsigned);
61 static void tag_lines (unsigned, unsigned);
62 static void tag_counters (unsigned, unsigned);
63 static void tag_summary (unsigned, unsigned);
65 /* The gcov_info for the first module. */
66 static struct gcov_info *curr_gcov_info;
67 /* The gcov_info being processed. */
68 static struct gcov_info *gcov_info_head;
69 /* This variable contains all the functions in current module. */
70 static struct obstack fn_info;
71 /* The function being processed. */
72 static struct gcov_fn_info *curr_fn_info;
73 /* The number of functions seen so far. */
74 static unsigned num_fn_info;
75 /* This variable contains all the counters for current module. */
76 static int k_ctrs_mask[GCOV_COUNTERS];
77 /* The kind of counters that have been seen. */
78 static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
79 /* Number of kind of counters that have been seen. */
80 static int k_ctrs_types;
81 /* The longest length of all the filenames. */
82 static int max_filename_len;
84 /* Merge functions for counters. */
85 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
86 static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
87 #include "gcov-counter.def"
89 #undef DEF_GCOV_COUNTER
91 /* Set the ctrs field in gcov_fn_info object FN_INFO. */
93 static void
94 set_fn_ctrs (struct gcov_fn_info *fn_info)
96 int j = 0, i;
98 for (i = 0; i < GCOV_COUNTERS; i++)
100 if (k_ctrs_mask[i] == 0)
101 continue;
102 fn_info->ctrs[j].num = k_ctrs[i].num;
103 fn_info->ctrs[j].values = k_ctrs[i].values;
104 j++;
106 if (k_ctrs_types == 0)
107 k_ctrs_types = j;
108 else
109 gcc_assert (j == k_ctrs_types);
112 /* For each tag in gcda file, we have an entry here.
113 TAG is the tag value; NAME is the tag name; and
114 PROC is the handler function. */
116 typedef struct tag_format
118 unsigned tag;
119 char const *name;
120 void (*proc) (unsigned, unsigned);
121 } tag_format_t;
123 /* Handler table for various Tags. */
125 static const tag_format_t tag_table[] =
127 {0, "NOP", NULL},
128 {0, "UNKNOWN", NULL},
129 {0, "COUNTERS", tag_counters},
130 {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
131 {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
132 {GCOV_TAG_ARCS, "ARCS", tag_arcs},
133 {GCOV_TAG_LINES, "LINES", tag_lines},
134 {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
135 {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary},
136 {0, NULL, NULL}
139 /* Handler for reading function tag. */
141 static void
142 tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
144 int i;
146 /* write out previous fn_info. */
147 if (num_fn_info)
149 set_fn_ctrs (curr_fn_info);
150 obstack_ptr_grow (&fn_info, curr_fn_info);
153 /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
154 counter types. */
155 curr_fn_info = (struct gcov_fn_info *) xcalloc (sizeof (struct gcov_fn_info)
156 + GCOV_COUNTERS * sizeof (struct gcov_ctr_info), 1);
158 for (i = 0; i < GCOV_COUNTERS; i++)
159 k_ctrs[i].num = 0;
160 k_ctrs_types = 0;
162 curr_fn_info->key = curr_gcov_info;
163 curr_fn_info->ident = gcov_read_unsigned ();
164 curr_fn_info->lineno_checksum = gcov_read_unsigned ();
165 curr_fn_info->cfg_checksum = gcov_read_unsigned ();
166 num_fn_info++;
168 if (verbose)
169 fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
172 /* Handler for reading block tag. */
174 static void
175 tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
177 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
178 gcc_unreachable ();
181 /* Handler for reading flow arc tag. */
183 static void
184 tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
186 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
187 gcc_unreachable ();
190 /* Handler for reading line tag. */
192 static void
193 tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
195 /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
196 gcc_unreachable ();
199 /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
201 static void
202 tag_counters (unsigned tag, unsigned length)
204 unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
205 gcov_type *values;
206 unsigned ix;
207 unsigned tag_ix;
209 tag_ix = GCOV_COUNTER_FOR_TAG (tag);
210 gcc_assert (tag_ix < GCOV_COUNTERS);
211 k_ctrs_mask [tag_ix] = 1;
212 gcc_assert (k_ctrs[tag_ix].num == 0);
213 k_ctrs[tag_ix].num = n_counts;
215 k_ctrs[tag_ix].values = values = (gcov_type *) xmalloc (n_counts * sizeof (gcov_type));
216 gcc_assert (values);
218 for (ix = 0; ix != n_counts; ix++)
219 values[ix] = gcov_read_counter ();
222 /* Handler for reading summary tag. */
224 static void
225 tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
227 struct gcov_summary summary;
229 gcov_read_summary (&summary);
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. */
235 static void
236 read_gcda_finalize (struct gcov_info *obj_info)
238 int i;
240 set_fn_ctrs (curr_fn_info);
241 obstack_ptr_grow (&fn_info, curr_fn_info);
243 /* We set the following fields: merge, n_functions, and functions. */
244 obj_info->n_functions = num_fn_info;
245 obj_info->functions = (const struct gcov_fn_info**) obstack_finish (&fn_info);
247 /* wrap all the counter array. */
248 for (i=0; i< GCOV_COUNTERS; i++)
250 if (k_ctrs_mask[i])
251 obj_info->merge[i] = ctr_merge_functions[i];
255 /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
256 Program level summary CURRENT_SUMMARY will also be updated. */
258 static struct gcov_info *
259 read_gcda_file (const char *filename)
261 unsigned tags[4];
262 unsigned depth = 0;
263 unsigned magic, version;
264 struct gcov_info *obj_info;
265 int i;
267 for (i=0; i< GCOV_COUNTERS; i++)
268 k_ctrs_mask[i] = 0;
269 k_ctrs_types = 0;
271 if (!gcov_open (filename))
273 fnotice (stderr, "%s:cannot open\n", filename);
274 return NULL;
277 /* Read magic. */
278 magic = gcov_read_unsigned ();
279 if (magic != GCOV_DATA_MAGIC)
281 fnotice (stderr, "%s:not a gcov data file\n", filename);
282 gcov_close ();
283 return NULL;
286 /* Read version. */
287 version = gcov_read_unsigned ();
288 if (version != GCOV_VERSION)
290 fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
291 gcov_close ();
292 return NULL;
295 /* Instantiate a gcov_info object. */
296 curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
297 sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
299 obj_info->version = version;
300 obstack_init (&fn_info);
301 num_fn_info = 0;
302 curr_fn_info = 0;
304 char *str_dup = (char*) xmalloc (strlen (filename) + 1);
305 int len;
307 strcpy (str_dup, filename);
308 obj_info->filename = str_dup;
309 if ((len = strlen (filename)) > max_filename_len)
310 max_filename_len = len;
313 /* Read stamp. */
314 obj_info->stamp = gcov_read_unsigned ();
316 while (1)
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;
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)
333 if (((mask & 0xff) != 0xff))
335 warning (0, "%s:tag `%x' is invalid\n", filename, tag);
336 break;
338 tag_depth--;
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)
347 if (depth && depth < tag_depth)
349 if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
350 warning (0, "%s:tag `%x' is incorrectly nested\n",
351 filename, tag);
353 depth = tag_depth;
354 tags[depth - 1] = tag;
357 if (format->proc)
359 unsigned long actual_length;
361 (*format->proc) (tag, length);
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);
372 gcov_sync (base, length);
373 if ((error = gcov_is_error ()))
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;
382 read_gcda_finalize (obj_info);
383 gcov_close ();
385 return obj_info;
388 /* This will be called by ftw(). It opens and read a gcda file FILENAME.
389 Return a non-zero value to stop the tree walk. */
391 static int
392 ftw_read_file (const char *filename,
393 const struct stat *status ATTRIBUTE_UNUSED,
394 int type)
396 int filename_len;
397 int suffix_len;
398 struct gcov_info *obj_info;
400 /* Only read regular files. */
401 if (type != FTW_F)
402 return 0;
404 filename_len = strlen (filename);
405 suffix_len = strlen (GCOV_DATA_SUFFIX);
407 if (filename_len <= suffix_len)
408 return 0;
410 if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
411 return 0;
413 if (verbose)
414 fnotice (stderr, "reading file: %s\n", filename);
416 obj_info = read_gcda_file (filename);
417 if (!obj_info)
418 return 0;
420 obj_info->next = gcov_info_head;
421 gcov_info_head = obj_info;
423 return 0;
426 /* Initializer for reading a profile dir. */
428 static inline void
429 read_profile_dir_init (void)
431 gcov_info_head = 0;
434 /* Driver for read a profile directory and convert into gcov_info list in memory.
435 Return NULL on error,
436 Return the head of gcov_info list on success.
437 Note the file static variable GCOV_MAX_FILENAME is also set. */
439 struct gcov_info *
440 gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
442 char *pwd;
443 int ret;
445 read_profile_dir_init ();
447 if (access (dir_name, R_OK) != 0)
449 fnotice (stderr, "cannot access directory %s\n", dir_name);
450 return NULL;
452 pwd = getcwd (NULL, 0);
453 gcc_assert (pwd);
454 ret = chdir (dir_name);
455 if (ret !=0)
457 fnotice (stderr, "%s is not a directory\n", dir_name);
458 return NULL;
460 ftw (".", ftw_read_file, 50);
461 ret = chdir (pwd);
462 free (pwd);
465 /* gcov_max_filename is defined in libgcov.c that records the
466 max filename len. We need to set it here to allocate the
467 array for dumping. */
468 gcov_max_filename = max_filename_len;
470 return gcov_info_head;;
473 /* This part of the code is to merge profile counters. These
474 variables are set in merge_wrapper and to be used by
475 global function gcov_read_counter_mem() and gcov_get_merge_weight. */
477 /* We save the counter value address to this variable. */
478 static gcov_type *gcov_value_buf;
480 /* The number of counter values to be read by current merging. */
481 static gcov_unsigned_t gcov_value_buf_size;
483 /* The index of counter values being read. */
484 static gcov_unsigned_t gcov_value_buf_pos;
486 /* The weight of current merging. */
487 static unsigned gcov_merge_weight;
489 /* Read a counter value from gcov_value_buf array. */
491 gcov_type
492 gcov_read_counter_mem (void)
494 gcov_type ret;
495 gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
496 ret = *(gcov_value_buf + gcov_value_buf_pos);
497 ++gcov_value_buf_pos;
498 return ret;
501 /* Return the recorded merge weight. */
503 unsigned
504 gcov_get_merge_weight (void)
506 return gcov_merge_weight;
509 /* A wrapper function for merge functions. It sets up the
510 value buffer and weights and then calls the merge function. */
512 static void
513 merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n,
514 gcov_type *v2, unsigned w)
516 gcov_value_buf = v2;
517 gcov_value_buf_pos = 0;
518 gcov_value_buf_size = n;
519 gcov_merge_weight = w;
520 (*f) (v1, n);
523 /* Offline tool to manipulate profile data.
524 This tool targets on matched profiles. But it has some tolerance on
525 unmatched profiles.
526 When merging p1 to p2 (p2 is the dst),
527 * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
528 emit warning
529 * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
530 specified weight; emit warning.
531 * m.gcda in both p1 and p2:
532 ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
533 ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
534 p2->m.gcda->f and
535 drop p1->m.gcda->f. A warning is emitted. */
537 /* Add INFO2's counter to INFO1, multiplying by weight W. */
539 static int
540 gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
542 unsigned f_ix;
543 unsigned n_functions = info1->n_functions;
544 int has_mismatch = 0;
546 gcc_assert (info2->n_functions == n_functions);
547 for (f_ix = 0; f_ix < n_functions; f_ix++)
549 unsigned t_ix;
550 const struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
551 const struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
552 const struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
554 if (!gfi_ptr1 || gfi_ptr1->key != info1)
555 continue;
556 if (!gfi_ptr2 || gfi_ptr2->key != info2)
557 continue;
559 if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
561 fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
562 info1->filename);
563 has_mismatch = 1;
564 continue;
566 ci_ptr1 = gfi_ptr1->ctrs;
567 ci_ptr2 = gfi_ptr2->ctrs;
568 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
570 gcov_merge_fn merge1 = info1->merge[t_ix];
571 gcov_merge_fn merge2 = info2->merge[t_ix];
573 gcc_assert (merge1 == merge2);
574 if (!merge1)
575 continue;
576 gcc_assert (ci_ptr1->num == ci_ptr2->num);
577 merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num, ci_ptr2->values, w);
578 ci_ptr1++;
579 ci_ptr2++;
583 return has_mismatch;
586 /* Find and return the match gcov_info object for INFO from ARRAY.
587 SIZE is the length of ARRAY.
588 Return NULL if there is no match. */
590 static struct gcov_info *
591 find_match_gcov_info (struct gcov_info **array, int size, struct gcov_info *info)
593 struct gcov_info *gi_ptr;
594 struct gcov_info *ret = NULL;
595 int i;
597 for (i = 0; i < size; i++)
599 gi_ptr = array[i];
600 if (gi_ptr == 0)
601 continue;
602 if (!strcmp (gi_ptr->filename, info->filename))
604 ret = gi_ptr;
605 array[i] = 0;
606 break;
610 if (ret && ret->n_functions != info->n_functions)
612 fnotice (stderr, "mismatched profiles in %s (%d functions"
613 " vs %d functions)\n",
614 ret->filename,
615 ret->n_functions,
616 info->n_functions);
617 ret = NULL;
619 return ret;
622 /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
623 Return 0 on success: without mismatch.
624 Reutrn 1 on error. */
627 gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
628 int w1, int w2)
630 struct gcov_info *gi_ptr;
631 struct gcov_info **tgt_infos;
632 struct gcov_info *tgt_tail;
633 struct gcov_info **in_src_not_tgt;
634 unsigned tgt_cnt = 0, src_cnt = 0;
635 unsigned unmatch_info_cnt = 0;
636 unsigned int i;
638 for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
639 tgt_cnt++;
640 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
641 src_cnt++;
642 tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
643 * tgt_cnt);
644 gcc_assert (tgt_infos);
645 in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
646 * src_cnt);
647 gcc_assert (in_src_not_tgt);
649 for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
650 tgt_infos[i] = gi_ptr;
652 tgt_tail = tgt_infos[tgt_cnt - 1];
654 /* First pass on tgt_profile, we multiply w1 to all counters. */
655 if (w1 > 1)
657 for (i = 0; i < tgt_cnt; i++)
658 gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
661 /* Second pass, add src_profile to the tgt_profile. */
662 for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
664 struct gcov_info *gi_ptr1;
666 gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
667 if (gi_ptr1 == NULL)
669 in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
670 continue;
672 gcov_merge (gi_ptr1, gi_ptr, w2);
675 /* For modules in src but not in tgt. We adjust the counter and append. */
676 for (i = 0; i < unmatch_info_cnt; i++)
678 gi_ptr = in_src_not_tgt[i];
679 gcov_merge (gi_ptr, gi_ptr, w2 - 1);
680 tgt_tail->next = gi_ptr;
681 tgt_tail = gi_ptr;
684 return 0;
687 typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
689 /* Performing FN upon arc counters. */
691 static void
692 __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
693 counter_op_fn fn, void *data1, void *data2)
695 for (; n_counters; counters++, n_counters--)
697 gcov_type val = *counters;
698 *counters = fn(val, data1, data2);
702 /* Performing FN upon ior counters. */
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)
711 /* Do nothing. */
714 /* Performing FN upon time-profile counters. */
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)
723 /* Do nothing. */
726 /* Performaing FN upon delta counters. */
728 static void
729 __gcov_delta_counter_op (gcov_type *counters, unsigned n_counters,
730 counter_op_fn fn, void *data1, void *data2)
732 unsigned i, n_measures;
734 gcc_assert (!(n_counters % 4));
735 n_measures = n_counters / 4;
736 for (i = 0; i < n_measures; i++, counters += 4)
738 counters[2] = fn (counters[2], data1, data2);
739 counters[3] = fn (counters[3], data1, data2);
743 /* Performing FN upon single counters. */
745 static void
746 __gcov_single_counter_op (gcov_type *counters, unsigned n_counters,
747 counter_op_fn fn, void *data1, void *data2)
749 unsigned i, n_measures;
751 gcc_assert (!(n_counters % 3));
752 n_measures = n_counters / 3;
753 for (i = 0; i < n_measures; i++, counters += 3)
755 counters[1] = fn (counters[1], data1, data2);
756 counters[2] = fn (counters[2], data1, data2);
760 /* Scaling the counter value V by multiplying *(float*) DATA1. */
762 static gcov_type
763 fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
765 float f = *(float *) data1;
766 return (gcov_type) (v * f);
769 /* Scaling the counter value V by multiplying DATA2/DATA1. */
771 static gcov_type
772 int_scale (gcov_type v, void *data1, void *data2)
774 int n = *(int *) data1;
775 int d = *(int *) data2;
776 return (gcov_type) ( RDIV (v,d) * n);
779 /* Type of function used to process counters. */
780 typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
781 counter_op_fn, void *, void *);
783 /* Function array to process profile counters. */
784 #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
785 __gcov ## FN_TYPE ## _counter_op,
786 static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
787 #include "gcov-counter.def"
789 #undef DEF_GCOV_COUNTER
791 /* Driver for scaling profile counters. */
794 gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
796 struct gcov_info *gi_ptr;
797 unsigned f_ix;
799 if (verbose)
800 fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
802 /* Scaling the counters. */
803 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
804 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
806 unsigned t_ix;
807 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
808 const struct gcov_ctr_info *ci_ptr;
810 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
811 continue;
813 ci_ptr = gfi_ptr->ctrs;
814 for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
816 gcov_merge_fn merge = gi_ptr->merge[t_ix];
818 if (!merge)
819 continue;
820 if (d == 0)
821 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
822 fp_scale, &scale_factor, NULL);
823 else
824 (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
825 int_scale, &n, &d);
826 ci_ptr++;
830 return 0;
833 /* Driver to normalize profile counters. */
836 gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
838 struct gcov_info *gi_ptr;
839 gcov_type curr_max_val = 0;
840 unsigned f_ix;
841 unsigned int i;
842 float scale_factor;
844 /* Find the largest count value. */
845 for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
846 for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
848 unsigned t_ix;
849 const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
850 const struct gcov_ctr_info *ci_ptr;
852 if (!gfi_ptr || gfi_ptr->key != gi_ptr)
853 continue;
855 ci_ptr = gfi_ptr->ctrs;
856 for (t_ix = 0; t_ix < 1; t_ix++)
858 for (i = 0; i < ci_ptr->num; i++)
859 if (ci_ptr->values[i] > curr_max_val)
860 curr_max_val = ci_ptr->values[i];
861 ci_ptr++;
865 scale_factor = (float)max_val / curr_max_val;
866 if (verbose)
867 fnotice (stdout, "max_val is %lld\n", (long long) curr_max_val);
869 return gcov_profile_scale (profile, scale_factor, 0, 0);