libgcov-util.c revision 1.1.1.10 1 1.1 mrg /* Utility functions for reading gcda files into in-memory
2 1.1 mrg gcov_info structures and offline profile processing. */
3 1.1.1.10 mrg /* Copyright (C) 2014-2024 Free Software Foundation, Inc.
4 1.1 mrg Contributed by Rong Xu <xur (at) google.com>.
5 1.1 mrg
6 1.1 mrg This file is part of GCC.
7 1.1 mrg
8 1.1 mrg GCC is free software; you can redistribute it and/or modify it under
9 1.1 mrg the terms of the GNU General Public License as published by the Free
10 1.1 mrg Software Foundation; either version 3, or (at your option) any later
11 1.1 mrg version.
12 1.1 mrg
13 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 1.1 mrg for more details.
17 1.1 mrg
18 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
19 1.1 mrg permissions described in the GCC Runtime Library Exception, version
20 1.1 mrg 3.1, as published by the Free Software Foundation.
21 1.1 mrg
22 1.1 mrg You should have received a copy of the GNU General Public License and
23 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
24 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 1.1 mrg <http://www.gnu.org/licenses/>. */
26 1.1 mrg
27 1.1 mrg
28 1.1 mrg #define IN_GCOV_TOOL 1
29 1.1 mrg
30 1.1 mrg #include "libgcov.h"
31 1.1 mrg #include "intl.h"
32 1.1 mrg #include "diagnostic.h"
33 1.1 mrg #include "version.h"
34 1.1 mrg #include "demangle.h"
35 1.1.1.7 mrg #include "gcov-io.h"
36 1.1 mrg
37 1.1 mrg /* Borrowed from basic-block.h. */
38 1.1 mrg #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
39 1.1 mrg
40 1.1 mrg extern gcov_position_t gcov_position();
41 1.1 mrg extern int gcov_is_error();
42 1.1 mrg
43 1.1 mrg /* Verbose mode for debug. */
44 1.1 mrg static int verbose;
45 1.1 mrg
46 1.1 mrg /* Set verbose flag. */
47 1.1 mrg void gcov_set_verbose (void)
48 1.1 mrg {
49 1.1 mrg verbose = 1;
50 1.1 mrg }
51 1.1 mrg
52 1.1 mrg /* The following part is to read Gcda and reconstruct GCOV_INFO. */
53 1.1 mrg
54 1.1 mrg #include "obstack.h"
55 1.1 mrg #include <unistd.h>
56 1.1 mrg #ifdef HAVE_FTW_H
57 1.1 mrg #include <ftw.h>
58 1.1 mrg #endif
59 1.1 mrg
60 1.1.1.9 mrg static void tag_function (unsigned, int);
61 1.1.1.9 mrg static void tag_blocks (unsigned, int);
62 1.1.1.9 mrg static void tag_arcs (unsigned, int);
63 1.1.1.9 mrg static void tag_lines (unsigned, int);
64 1.1.1.9 mrg static void tag_counters (unsigned, int);
65 1.1.1.9 mrg static void tag_summary (unsigned, int);
66 1.1 mrg
67 1.1 mrg /* The gcov_info for the first module. */
68 1.1 mrg static struct gcov_info *curr_gcov_info;
69 1.1 mrg /* The gcov_info being processed. */
70 1.1 mrg static struct gcov_info *gcov_info_head;
71 1.1 mrg /* This variable contains all the functions in current module. */
72 1.1 mrg static struct obstack fn_info;
73 1.1 mrg /* The function being processed. */
74 1.1 mrg static struct gcov_fn_info *curr_fn_info;
75 1.1 mrg /* The number of functions seen so far. */
76 1.1 mrg static unsigned num_fn_info;
77 1.1 mrg /* This variable contains all the counters for current module. */
78 1.1 mrg static int k_ctrs_mask[GCOV_COUNTERS];
79 1.1 mrg /* The kind of counters that have been seen. */
80 1.1 mrg static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
81 1.1 mrg /* Number of kind of counters that have been seen. */
82 1.1 mrg static int k_ctrs_types;
83 1.1 mrg
84 1.1 mrg /* Merge functions for counters. */
85 1.1 mrg #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
86 1.1 mrg static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
87 1.1 mrg #include "gcov-counter.def"
88 1.1 mrg };
89 1.1 mrg #undef DEF_GCOV_COUNTER
90 1.1 mrg
91 1.1 mrg /* Set the ctrs field in gcov_fn_info object FN_INFO. */
92 1.1 mrg
93 1.1 mrg static void
94 1.1 mrg set_fn_ctrs (struct gcov_fn_info *fn_info)
95 1.1 mrg {
96 1.1 mrg int j = 0, i;
97 1.1 mrg
98 1.1 mrg for (i = 0; i < GCOV_COUNTERS; i++)
99 1.1 mrg {
100 1.1 mrg if (k_ctrs_mask[i] == 0)
101 1.1 mrg continue;
102 1.1 mrg fn_info->ctrs[j].num = k_ctrs[i].num;
103 1.1 mrg fn_info->ctrs[j].values = k_ctrs[i].values;
104 1.1 mrg j++;
105 1.1 mrg }
106 1.1 mrg if (k_ctrs_types == 0)
107 1.1 mrg k_ctrs_types = j;
108 1.1 mrg else
109 1.1 mrg gcc_assert (j == k_ctrs_types);
110 1.1 mrg }
111 1.1 mrg
112 1.1 mrg /* For each tag in gcda file, we have an entry here.
113 1.1 mrg TAG is the tag value; NAME is the tag name; and
114 1.1 mrg PROC is the handler function. */
115 1.1 mrg
116 1.1 mrg typedef struct tag_format
117 1.1 mrg {
118 1.1 mrg unsigned tag;
119 1.1 mrg char const *name;
120 1.1.1.9 mrg void (*proc) (unsigned, int);
121 1.1 mrg } tag_format_t;
122 1.1 mrg
123 1.1 mrg /* Handler table for various Tags. */
124 1.1 mrg
125 1.1 mrg static const tag_format_t tag_table[] =
126 1.1 mrg {
127 1.1 mrg {0, "NOP", NULL},
128 1.1 mrg {0, "UNKNOWN", NULL},
129 1.1 mrg {0, "COUNTERS", tag_counters},
130 1.1 mrg {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
131 1.1 mrg {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
132 1.1 mrg {GCOV_TAG_ARCS, "ARCS", tag_arcs},
133 1.1 mrg {GCOV_TAG_LINES, "LINES", tag_lines},
134 1.1 mrg {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
135 1.1 mrg {0, NULL, NULL}
136 1.1 mrg };
137 1.1 mrg
138 1.1 mrg /* Handler for reading function tag. */
139 1.1 mrg
140 1.1 mrg static void
141 1.1.1.9 mrg tag_function (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
142 1.1 mrg {
143 1.1 mrg int i;
144 1.1 mrg
145 1.1 mrg /* write out previous fn_info. */
146 1.1 mrg if (num_fn_info)
147 1.1 mrg {
148 1.1 mrg set_fn_ctrs (curr_fn_info);
149 1.1 mrg obstack_ptr_grow (&fn_info, curr_fn_info);
150 1.1 mrg }
151 1.1 mrg
152 1.1 mrg /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
153 1.1 mrg counter types. */
154 1.1 mrg curr_fn_info = (struct gcov_fn_info *) xcalloc (sizeof (struct gcov_fn_info)
155 1.1 mrg + GCOV_COUNTERS * sizeof (struct gcov_ctr_info), 1);
156 1.1 mrg
157 1.1 mrg for (i = 0; i < GCOV_COUNTERS; i++)
158 1.1 mrg k_ctrs[i].num = 0;
159 1.1 mrg k_ctrs_types = 0;
160 1.1 mrg
161 1.1 mrg curr_fn_info->key = curr_gcov_info;
162 1.1 mrg curr_fn_info->ident = gcov_read_unsigned ();
163 1.1 mrg curr_fn_info->lineno_checksum = gcov_read_unsigned ();
164 1.1 mrg curr_fn_info->cfg_checksum = gcov_read_unsigned ();
165 1.1 mrg num_fn_info++;
166 1.1 mrg
167 1.1 mrg if (verbose)
168 1.1 mrg fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
169 1.1 mrg }
170 1.1 mrg
171 1.1 mrg /* Handler for reading block tag. */
172 1.1 mrg
173 1.1 mrg static void
174 1.1.1.9 mrg tag_blocks (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
175 1.1 mrg {
176 1.1 mrg /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
177 1.1 mrg gcc_unreachable ();
178 1.1 mrg }
179 1.1 mrg
180 1.1 mrg /* Handler for reading flow arc tag. */
181 1.1 mrg
182 1.1 mrg static void
183 1.1.1.9 mrg tag_arcs (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
184 1.1 mrg {
185 1.1 mrg /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
186 1.1 mrg gcc_unreachable ();
187 1.1 mrg }
188 1.1 mrg
189 1.1 mrg /* Handler for reading line tag. */
190 1.1 mrg
191 1.1 mrg static void
192 1.1.1.9 mrg tag_lines (unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED)
193 1.1 mrg {
194 1.1 mrg /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
195 1.1 mrg gcc_unreachable ();
196 1.1 mrg }
197 1.1 mrg
198 1.1 mrg /* Handler for reading counters array tag with value as TAG and length of LENGTH. */
199 1.1 mrg
200 1.1 mrg static void
201 1.1.1.9 mrg tag_counters (unsigned tag, int length)
202 1.1 mrg {
203 1.1.1.9 mrg unsigned n_counts = GCOV_TAG_COUNTER_NUM (abs (length));
204 1.1 mrg gcov_type *values;
205 1.1 mrg unsigned ix;
206 1.1 mrg unsigned tag_ix;
207 1.1 mrg
208 1.1 mrg tag_ix = GCOV_COUNTER_FOR_TAG (tag);
209 1.1 mrg gcc_assert (tag_ix < GCOV_COUNTERS);
210 1.1 mrg k_ctrs_mask [tag_ix] = 1;
211 1.1 mrg gcc_assert (k_ctrs[tag_ix].num == 0);
212 1.1 mrg k_ctrs[tag_ix].num = n_counts;
213 1.1 mrg
214 1.1.1.9 mrg k_ctrs[tag_ix].values = values = (gcov_type *) xcalloc (sizeof (gcov_type),
215 1.1.1.9 mrg n_counts);
216 1.1 mrg gcc_assert (values);
217 1.1 mrg
218 1.1.1.9 mrg if (length > 0)
219 1.1.1.9 mrg for (ix = 0; ix != n_counts; ix++)
220 1.1.1.9 mrg values[ix] = gcov_read_counter ();
221 1.1 mrg }
222 1.1 mrg
223 1.1 mrg /* Handler for reading summary tag. */
224 1.1 mrg
225 1.1 mrg static void
226 1.1.1.9 mrg tag_summary (unsigned tag ATTRIBUTE_UNUSED, int ATTRIBUTE_UNUSED)
227 1.1 mrg {
228 1.1.1.9 mrg gcov_read_summary (&curr_gcov_info->summary);
229 1.1 mrg }
230 1.1 mrg
231 1.1 mrg /* This function is called at the end of reading a gcda file.
232 1.1 mrg It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO. */
233 1.1 mrg
234 1.1 mrg static void
235 1.1 mrg read_gcda_finalize (struct gcov_info *obj_info)
236 1.1 mrg {
237 1.1 mrg int i;
238 1.1 mrg
239 1.1 mrg set_fn_ctrs (curr_fn_info);
240 1.1 mrg obstack_ptr_grow (&fn_info, curr_fn_info);
241 1.1 mrg
242 1.1.1.7 mrg /* We set the following fields: merge, n_functions, functions
243 1.1.1.7 mrg and summary. */
244 1.1 mrg obj_info->n_functions = num_fn_info;
245 1.1.1.9 mrg obj_info->functions = (struct gcov_fn_info**) obstack_finish (&fn_info);
246 1.1 mrg
247 1.1 mrg /* wrap all the counter array. */
248 1.1 mrg for (i=0; i< GCOV_COUNTERS; i++)
249 1.1 mrg {
250 1.1 mrg if (k_ctrs_mask[i])
251 1.1 mrg obj_info->merge[i] = ctr_merge_functions[i];
252 1.1 mrg }
253 1.1 mrg }
254 1.1 mrg
255 1.1 mrg /* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
256 1.1 mrg Program level summary CURRENT_SUMMARY will also be updated. */
257 1.1 mrg
258 1.1 mrg static struct gcov_info *
259 1.1 mrg read_gcda_file (const char *filename)
260 1.1 mrg {
261 1.1 mrg unsigned tags[4];
262 1.1 mrg unsigned depth = 0;
263 1.1.1.8 mrg unsigned version;
264 1.1 mrg struct gcov_info *obj_info;
265 1.1 mrg int i;
266 1.1 mrg
267 1.1 mrg for (i=0; i< GCOV_COUNTERS; i++)
268 1.1 mrg k_ctrs_mask[i] = 0;
269 1.1 mrg k_ctrs_types = 0;
270 1.1 mrg
271 1.1 mrg /* Read magic. */
272 1.1.1.8 mrg if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
273 1.1 mrg {
274 1.1 mrg fnotice (stderr, "%s:not a gcov data file\n", filename);
275 1.1 mrg return NULL;
276 1.1 mrg }
277 1.1 mrg
278 1.1 mrg /* Read version. */
279 1.1 mrg version = gcov_read_unsigned ();
280 1.1 mrg if (version != GCOV_VERSION)
281 1.1 mrg {
282 1.1 mrg fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
283 1.1 mrg return NULL;
284 1.1 mrg }
285 1.1 mrg
286 1.1 mrg /* Instantiate a gcov_info object. */
287 1.1 mrg curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
288 1.1 mrg sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
289 1.1 mrg
290 1.1 mrg obj_info->version = version;
291 1.1.1.10 mrg obj_info->filename = filename;
292 1.1 mrg obstack_init (&fn_info);
293 1.1 mrg num_fn_info = 0;
294 1.1 mrg curr_fn_info = 0;
295 1.1 mrg
296 1.1.1.10 mrg /* Prepend to global gcov info list. */
297 1.1.1.10 mrg obj_info->next = gcov_info_head;
298 1.1.1.10 mrg gcov_info_head = obj_info;
299 1.1 mrg
300 1.1 mrg /* Read stamp. */
301 1.1 mrg obj_info->stamp = gcov_read_unsigned ();
302 1.1 mrg
303 1.1.1.9 mrg /* Read checksum. */
304 1.1.1.9 mrg obj_info->checksum = gcov_read_unsigned ();
305 1.1.1.9 mrg
306 1.1 mrg while (1)
307 1.1 mrg {
308 1.1 mrg gcov_position_t base;
309 1.1 mrg unsigned tag, length;
310 1.1 mrg tag_format_t const *format;
311 1.1 mrg unsigned tag_depth;
312 1.1 mrg int error;
313 1.1 mrg unsigned mask;
314 1.1 mrg
315 1.1 mrg tag = gcov_read_unsigned ();
316 1.1 mrg if (!tag)
317 1.1 mrg break;
318 1.1.1.9 mrg int read_length = (int)gcov_read_unsigned ();
319 1.1.1.9 mrg length = read_length > 0 ? read_length : 0;
320 1.1 mrg base = gcov_position ();
321 1.1 mrg mask = GCOV_TAG_MASK (tag) >> 1;
322 1.1 mrg for (tag_depth = 4; mask; mask >>= 8)
323 1.1 mrg {
324 1.1 mrg if (((mask & 0xff) != 0xff))
325 1.1 mrg {
326 1.1.1.8 mrg warning (0, "%s:tag %qx is invalid", filename, tag);
327 1.1 mrg break;
328 1.1 mrg }
329 1.1 mrg tag_depth--;
330 1.1 mrg }
331 1.1 mrg for (format = tag_table; format->name; format++)
332 1.1 mrg if (format->tag == tag)
333 1.1 mrg goto found;
334 1.1 mrg format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
335 1.1 mrg found:;
336 1.1 mrg if (tag)
337 1.1 mrg {
338 1.1 mrg if (depth && depth < tag_depth)
339 1.1 mrg {
340 1.1 mrg if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
341 1.1.1.8 mrg warning (0, "%s:tag %qx is incorrectly nested",
342 1.1 mrg filename, tag);
343 1.1 mrg }
344 1.1 mrg depth = tag_depth;
345 1.1 mrg tags[depth - 1] = tag;
346 1.1 mrg }
347 1.1 mrg
348 1.1 mrg if (format->proc)
349 1.1 mrg {
350 1.1 mrg unsigned long actual_length;
351 1.1 mrg
352 1.1.1.9 mrg (*format->proc) (tag, read_length);
353 1.1 mrg
354 1.1 mrg actual_length = gcov_position () - base;
355 1.1 mrg if (actual_length > length)
356 1.1.1.8 mrg warning (0, "%s:record size mismatch %lu bytes overread",
357 1.1 mrg filename, actual_length - length);
358 1.1 mrg else if (length > actual_length)
359 1.1.1.8 mrg warning (0, "%s:record size mismatch %lu bytes unread",
360 1.1 mrg filename, length - actual_length);
361 1.1 mrg }
362 1.1 mrg
363 1.1 mrg gcov_sync (base, length);
364 1.1 mrg if ((error = gcov_is_error ()))
365 1.1 mrg {
366 1.1.1.8 mrg warning (0, error < 0 ? "%s:counter overflow at %lu" :
367 1.1.1.8 mrg "%s:read error at %lu", filename,
368 1.1 mrg (long unsigned) gcov_position ());
369 1.1 mrg break;
370 1.1 mrg }
371 1.1 mrg }
372 1.1 mrg
373 1.1 mrg read_gcda_finalize (obj_info);
374 1.1 mrg
375 1.1 mrg return obj_info;
376 1.1 mrg }
377 1.1 mrg
378 1.1 mrg #ifdef HAVE_FTW_H
379 1.1 mrg /* This will be called by ftw(). It opens and read a gcda file FILENAME.
380 1.1 mrg Return a non-zero value to stop the tree walk. */
381 1.1 mrg
382 1.1 mrg static int
383 1.1 mrg ftw_read_file (const char *filename,
384 1.1 mrg const struct stat *status ATTRIBUTE_UNUSED,
385 1.1 mrg int type)
386 1.1 mrg {
387 1.1.1.10 mrg size_t filename_len;
388 1.1.1.10 mrg size_t suffix_len;
389 1.1 mrg
390 1.1 mrg /* Only read regular files. */
391 1.1 mrg if (type != FTW_F)
392 1.1 mrg return 0;
393 1.1 mrg
394 1.1 mrg filename_len = strlen (filename);
395 1.1 mrg suffix_len = strlen (GCOV_DATA_SUFFIX);
396 1.1 mrg
397 1.1 mrg if (filename_len <= suffix_len)
398 1.1 mrg return 0;
399 1.1 mrg
400 1.1 mrg if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
401 1.1 mrg return 0;
402 1.1 mrg
403 1.1 mrg if (verbose)
404 1.1 mrg fnotice (stderr, "reading file: %s\n", filename);
405 1.1 mrg
406 1.1.1.10 mrg if (!gcov_open (filename, 1))
407 1.1.1.10 mrg {
408 1.1.1.10 mrg fnotice (stderr, "%s:cannot open:%s\n", filename, xstrerror (errno));
409 1.1.1.10 mrg return 0;
410 1.1.1.10 mrg }
411 1.1 mrg
412 1.1.1.10 mrg (void)read_gcda_file (xstrdup (filename));
413 1.1.1.10 mrg gcov_close ();
414 1.1 mrg
415 1.1 mrg return 0;
416 1.1 mrg }
417 1.1 mrg #endif
418 1.1 mrg
419 1.1 mrg /* Initializer for reading a profile dir. */
420 1.1 mrg
421 1.1 mrg static inline void
422 1.1 mrg read_profile_dir_init (void)
423 1.1 mrg {
424 1.1 mrg gcov_info_head = 0;
425 1.1 mrg }
426 1.1 mrg
427 1.1 mrg /* Driver for read a profile directory and convert into gcov_info list in memory.
428 1.1 mrg Return NULL on error,
429 1.1 mrg Return the head of gcov_info list on success. */
430 1.1 mrg
431 1.1 mrg struct gcov_info *
432 1.1 mrg gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
433 1.1 mrg {
434 1.1 mrg char *pwd;
435 1.1 mrg int ret;
436 1.1 mrg
437 1.1 mrg read_profile_dir_init ();
438 1.1 mrg
439 1.1 mrg if (access (dir_name, R_OK) != 0)
440 1.1 mrg {
441 1.1 mrg fnotice (stderr, "cannot access directory %s\n", dir_name);
442 1.1 mrg return NULL;
443 1.1 mrg }
444 1.1 mrg pwd = getcwd (NULL, 0);
445 1.1 mrg gcc_assert (pwd);
446 1.1 mrg ret = chdir (dir_name);
447 1.1 mrg if (ret !=0)
448 1.1 mrg {
449 1.1 mrg fnotice (stderr, "%s is not a directory\n", dir_name);
450 1.1 mrg return NULL;
451 1.1 mrg }
452 1.1 mrg #ifdef HAVE_FTW_H
453 1.1 mrg ftw (".", ftw_read_file, 50);
454 1.1 mrg #endif
455 1.1.1.8 mrg chdir (pwd);
456 1.1 mrg free (pwd);
457 1.1 mrg
458 1.1 mrg return gcov_info_head;;
459 1.1 mrg }
460 1.1 mrg
461 1.1 mrg /* This part of the code is to merge profile counters. These
462 1.1 mrg variables are set in merge_wrapper and to be used by
463 1.1 mrg global function gcov_read_counter_mem() and gcov_get_merge_weight. */
464 1.1 mrg
465 1.1 mrg /* We save the counter value address to this variable. */
466 1.1 mrg static gcov_type *gcov_value_buf;
467 1.1 mrg
468 1.1 mrg /* The number of counter values to be read by current merging. */
469 1.1 mrg static gcov_unsigned_t gcov_value_buf_size;
470 1.1 mrg
471 1.1 mrg /* The index of counter values being read. */
472 1.1 mrg static gcov_unsigned_t gcov_value_buf_pos;
473 1.1 mrg
474 1.1 mrg /* The weight of current merging. */
475 1.1 mrg static unsigned gcov_merge_weight;
476 1.1 mrg
477 1.1 mrg /* Read a counter value from gcov_value_buf array. */
478 1.1 mrg
479 1.1 mrg gcov_type
480 1.1 mrg gcov_read_counter_mem (void)
481 1.1 mrg {
482 1.1 mrg gcov_type ret;
483 1.1 mrg gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
484 1.1 mrg ret = *(gcov_value_buf + gcov_value_buf_pos);
485 1.1 mrg ++gcov_value_buf_pos;
486 1.1 mrg return ret;
487 1.1 mrg }
488 1.1 mrg
489 1.1 mrg /* Return the recorded merge weight. */
490 1.1 mrg
491 1.1 mrg unsigned
492 1.1 mrg gcov_get_merge_weight (void)
493 1.1 mrg {
494 1.1 mrg return gcov_merge_weight;
495 1.1 mrg }
496 1.1 mrg
497 1.1 mrg /* A wrapper function for merge functions. It sets up the
498 1.1 mrg value buffer and weights and then calls the merge function. */
499 1.1 mrg
500 1.1 mrg static void
501 1.1.1.9 mrg merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n1,
502 1.1.1.9 mrg gcov_type *v2, gcov_unsigned_t n2, unsigned w)
503 1.1 mrg {
504 1.1 mrg gcov_value_buf = v2;
505 1.1 mrg gcov_value_buf_pos = 0;
506 1.1.1.9 mrg gcov_value_buf_size = n2;
507 1.1 mrg gcov_merge_weight = w;
508 1.1.1.9 mrg (*f) (v1, n1);
509 1.1.1.9 mrg }
510 1.1.1.9 mrg
511 1.1.1.9 mrg /* Convert on disk representation of a TOPN counter to in memory representation
512 1.1.1.9 mrg that is expected from __gcov_merge_topn function. */
513 1.1.1.9 mrg
514 1.1.1.9 mrg static void
515 1.1.1.9 mrg topn_to_memory_representation (struct gcov_ctr_info *info)
516 1.1.1.9 mrg {
517 1.1.1.9 mrg auto_vec<gcov_type> output;
518 1.1.1.9 mrg gcov_type *values = info->values;
519 1.1.1.9 mrg int count = info->num;
520 1.1.1.9 mrg
521 1.1.1.9 mrg while (count > 0)
522 1.1.1.9 mrg {
523 1.1.1.9 mrg output.safe_push (values[0]);
524 1.1.1.9 mrg gcov_type n = values[1];
525 1.1.1.9 mrg output.safe_push (n);
526 1.1.1.9 mrg if (n > 0)
527 1.1.1.9 mrg {
528 1.1.1.9 mrg struct gcov_kvp *tuples
529 1.1.1.9 mrg = (struct gcov_kvp *)xcalloc (sizeof (struct gcov_kvp), n);
530 1.1.1.9 mrg for (unsigned i = 0; i < n - 1; i++)
531 1.1.1.9 mrg tuples[i].next = &tuples[i + 1];
532 1.1.1.9 mrg for (unsigned i = 0; i < n; i++)
533 1.1.1.9 mrg {
534 1.1.1.9 mrg tuples[i].value = values[2 + 2 * i];
535 1.1.1.9 mrg tuples[i].count = values[2 + 2 * i + 1];
536 1.1.1.9 mrg }
537 1.1.1.9 mrg output.safe_push ((intptr_t)&tuples[0]);
538 1.1.1.9 mrg }
539 1.1.1.9 mrg else
540 1.1.1.9 mrg output.safe_push (0);
541 1.1.1.9 mrg
542 1.1.1.9 mrg unsigned len = 2 * n + 2;
543 1.1.1.9 mrg values += len;
544 1.1.1.9 mrg count -= len;
545 1.1.1.9 mrg }
546 1.1.1.9 mrg gcc_assert (count == 0);
547 1.1.1.9 mrg
548 1.1.1.9 mrg /* Allocate new buffer and copy it there. */
549 1.1.1.9 mrg info->num = output.length ();
550 1.1.1.9 mrg info->values = (gcov_type *)xmalloc (sizeof (gcov_type) * info->num);
551 1.1.1.9 mrg for (unsigned i = 0; i < info->num; i++)
552 1.1.1.9 mrg info->values[i] = output[i];
553 1.1 mrg }
554 1.1 mrg
555 1.1 mrg /* Offline tool to manipulate profile data.
556 1.1 mrg This tool targets on matched profiles. But it has some tolerance on
557 1.1 mrg unmatched profiles.
558 1.1 mrg When merging p1 to p2 (p2 is the dst),
559 1.1 mrg * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
560 1.1 mrg emit warning
561 1.1 mrg * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
562 1.1 mrg specified weight; emit warning.
563 1.1 mrg * m.gcda in both p1 and p2:
564 1.1 mrg ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
565 1.1 mrg ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
566 1.1 mrg p2->m.gcda->f and
567 1.1 mrg drop p1->m.gcda->f. A warning is emitted. */
568 1.1 mrg
569 1.1 mrg /* Add INFO2's counter to INFO1, multiplying by weight W. */
570 1.1 mrg
571 1.1 mrg static int
572 1.1 mrg gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
573 1.1 mrg {
574 1.1 mrg unsigned f_ix;
575 1.1 mrg unsigned n_functions = info1->n_functions;
576 1.1 mrg int has_mismatch = 0;
577 1.1 mrg
578 1.1 mrg gcc_assert (info2->n_functions == n_functions);
579 1.1.1.9 mrg
580 1.1.1.9 mrg /* Merge summary. */
581 1.1.1.9 mrg info1->summary.runs += info2->summary.runs;
582 1.1.1.9 mrg info1->summary.sum_max += info2->summary.sum_max;
583 1.1.1.9 mrg
584 1.1 mrg for (f_ix = 0; f_ix < n_functions; f_ix++)
585 1.1 mrg {
586 1.1 mrg unsigned t_ix;
587 1.1.1.9 mrg struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
588 1.1.1.9 mrg struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
589 1.1.1.9 mrg struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
590 1.1 mrg
591 1.1 mrg if (!gfi_ptr1 || gfi_ptr1->key != info1)
592 1.1 mrg continue;
593 1.1 mrg if (!gfi_ptr2 || gfi_ptr2->key != info2)
594 1.1 mrg continue;
595 1.1 mrg
596 1.1 mrg if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
597 1.1 mrg {
598 1.1 mrg fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
599 1.1 mrg info1->filename);
600 1.1 mrg has_mismatch = 1;
601 1.1 mrg continue;
602 1.1 mrg }
603 1.1 mrg ci_ptr1 = gfi_ptr1->ctrs;
604 1.1 mrg ci_ptr2 = gfi_ptr2->ctrs;
605 1.1 mrg for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
606 1.1 mrg {
607 1.1 mrg gcov_merge_fn merge1 = info1->merge[t_ix];
608 1.1 mrg gcov_merge_fn merge2 = info2->merge[t_ix];
609 1.1 mrg
610 1.1 mrg gcc_assert (merge1 == merge2);
611 1.1 mrg if (!merge1)
612 1.1 mrg continue;
613 1.1.1.9 mrg
614 1.1.1.9 mrg if (merge1 == __gcov_merge_topn)
615 1.1.1.9 mrg topn_to_memory_representation (ci_ptr1);
616 1.1.1.9 mrg else
617 1.1.1.9 mrg gcc_assert (ci_ptr1->num == ci_ptr2->num);
618 1.1.1.9 mrg
619 1.1.1.9 mrg merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num,
620 1.1.1.9 mrg ci_ptr2->values, ci_ptr2->num, w);
621 1.1 mrg ci_ptr1++;
622 1.1 mrg ci_ptr2++;
623 1.1 mrg }
624 1.1 mrg }
625 1.1 mrg
626 1.1 mrg return has_mismatch;
627 1.1 mrg }
628 1.1 mrg
629 1.1 mrg /* Find and return the match gcov_info object for INFO from ARRAY.
630 1.1 mrg SIZE is the length of ARRAY.
631 1.1 mrg Return NULL if there is no match. */
632 1.1 mrg
633 1.1 mrg static struct gcov_info *
634 1.1 mrg find_match_gcov_info (struct gcov_info **array, int size,
635 1.1 mrg struct gcov_info *info)
636 1.1 mrg {
637 1.1 mrg struct gcov_info *gi_ptr;
638 1.1 mrg struct gcov_info *ret = NULL;
639 1.1 mrg int i;
640 1.1 mrg
641 1.1 mrg for (i = 0; i < size; i++)
642 1.1 mrg {
643 1.1 mrg gi_ptr = array[i];
644 1.1 mrg if (gi_ptr == 0)
645 1.1 mrg continue;
646 1.1 mrg if (!strcmp (gi_ptr->filename, info->filename))
647 1.1 mrg {
648 1.1 mrg ret = gi_ptr;
649 1.1 mrg array[i] = 0;
650 1.1 mrg break;
651 1.1 mrg }
652 1.1 mrg }
653 1.1 mrg
654 1.1 mrg if (ret && ret->n_functions != info->n_functions)
655 1.1 mrg {
656 1.1 mrg fnotice (stderr, "mismatched profiles in %s (%d functions"
657 1.1 mrg " vs %d functions)\n",
658 1.1 mrg ret->filename,
659 1.1 mrg ret->n_functions,
660 1.1 mrg info->n_functions);
661 1.1 mrg ret = NULL;
662 1.1 mrg }
663 1.1 mrg return ret;
664 1.1 mrg }
665 1.1 mrg
666 1.1 mrg /* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
667 1.1.1.10 mrg Return the list of merged gcov_info objects. Return NULL if the list is
668 1.1.1.10 mrg empty. */
669 1.1 mrg
670 1.1.1.10 mrg struct gcov_info *
671 1.1 mrg gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
672 1.1 mrg int w1, int w2)
673 1.1 mrg {
674 1.1 mrg struct gcov_info *gi_ptr;
675 1.1 mrg struct gcov_info **tgt_infos;
676 1.1.1.10 mrg struct gcov_info **tgt_tail;
677 1.1 mrg struct gcov_info **in_src_not_tgt;
678 1.1 mrg unsigned tgt_cnt = 0, src_cnt = 0;
679 1.1 mrg unsigned unmatch_info_cnt = 0;
680 1.1 mrg unsigned int i;
681 1.1 mrg
682 1.1 mrg for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
683 1.1 mrg tgt_cnt++;
684 1.1 mrg for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
685 1.1 mrg src_cnt++;
686 1.1 mrg tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
687 1.1 mrg * tgt_cnt);
688 1.1 mrg gcc_assert (tgt_infos);
689 1.1 mrg in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
690 1.1 mrg * src_cnt);
691 1.1 mrg gcc_assert (in_src_not_tgt);
692 1.1 mrg
693 1.1 mrg for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
694 1.1 mrg tgt_infos[i] = gi_ptr;
695 1.1 mrg
696 1.1.1.10 mrg if (tgt_cnt)
697 1.1.1.10 mrg tgt_tail = &tgt_infos[tgt_cnt - 1]->next;
698 1.1.1.10 mrg else
699 1.1.1.10 mrg tgt_tail = &tgt_profile;
700 1.1 mrg
701 1.1 mrg /* First pass on tgt_profile, we multiply w1 to all counters. */
702 1.1 mrg if (w1 > 1)
703 1.1 mrg {
704 1.1 mrg for (i = 0; i < tgt_cnt; i++)
705 1.1 mrg gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
706 1.1 mrg }
707 1.1 mrg
708 1.1 mrg /* Second pass, add src_profile to the tgt_profile. */
709 1.1 mrg for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
710 1.1 mrg {
711 1.1 mrg struct gcov_info *gi_ptr1;
712 1.1 mrg
713 1.1 mrg gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
714 1.1 mrg if (gi_ptr1 == NULL)
715 1.1 mrg {
716 1.1 mrg in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
717 1.1 mrg continue;
718 1.1 mrg }
719 1.1 mrg gcov_merge (gi_ptr1, gi_ptr, w2);
720 1.1 mrg }
721 1.1 mrg
722 1.1 mrg /* For modules in src but not in tgt. We adjust the counter and append. */
723 1.1 mrg for (i = 0; i < unmatch_info_cnt; i++)
724 1.1 mrg {
725 1.1 mrg gi_ptr = in_src_not_tgt[i];
726 1.1 mrg gcov_merge (gi_ptr, gi_ptr, w2 - 1);
727 1.1.1.3 mrg gi_ptr->next = NULL;
728 1.1.1.10 mrg *tgt_tail = gi_ptr;
729 1.1.1.10 mrg tgt_tail = &gi_ptr->next;
730 1.1 mrg }
731 1.1 mrg
732 1.1.1.8 mrg free (in_src_not_tgt);
733 1.1.1.8 mrg free (tgt_infos);
734 1.1.1.8 mrg
735 1.1.1.10 mrg return tgt_profile;
736 1.1.1.10 mrg }
737 1.1.1.10 mrg
738 1.1.1.10 mrg /* Deserialize gcov_info objects and associated filenames from the file
739 1.1.1.10 mrg specified by FILENAME to create a profile list. When FILENAME is NULL, read
740 1.1.1.10 mrg from stdin. Return the profile list. */
741 1.1.1.10 mrg
742 1.1.1.10 mrg struct gcov_info *
743 1.1.1.10 mrg deserialize_profiles (const char *filename)
744 1.1.1.10 mrg {
745 1.1.1.10 mrg read_profile_dir_init ();
746 1.1.1.10 mrg
747 1.1.1.10 mrg while (true)
748 1.1.1.10 mrg {
749 1.1.1.10 mrg unsigned version;
750 1.1.1.10 mrg const char *filename_of_info;
751 1.1.1.10 mrg struct gcov_info *obj_info;
752 1.1.1.10 mrg
753 1.1.1.10 mrg if (!gcov_magic (gcov_read_unsigned (), GCOV_FILENAME_MAGIC))
754 1.1.1.10 mrg {
755 1.1.1.10 mrg if (gcov_is_error () != 2)
756 1.1.1.10 mrg fnotice (stderr, "%s:not a gcfn stream\n", filename);
757 1.1.1.10 mrg break;
758 1.1.1.10 mrg }
759 1.1.1.10 mrg
760 1.1.1.10 mrg version = gcov_read_unsigned ();
761 1.1.1.10 mrg if (version != GCOV_VERSION)
762 1.1.1.10 mrg {
763 1.1.1.10 mrg fnotice (stderr, "%s:incorrect gcov version %d vs %d \n",
764 1.1.1.10 mrg filename, version, GCOV_VERSION);
765 1.1.1.10 mrg break;
766 1.1.1.10 mrg }
767 1.1.1.10 mrg
768 1.1.1.10 mrg filename_of_info = gcov_read_string ();
769 1.1.1.10 mrg if (!filename_of_info)
770 1.1.1.10 mrg {
771 1.1.1.10 mrg fnotice (stderr, "%s:no filename in gcfn stream\n",
772 1.1.1.10 mrg filename);
773 1.1.1.10 mrg break;
774 1.1.1.10 mrg }
775 1.1.1.10 mrg
776 1.1.1.10 mrg obj_info = read_gcda_file (filename);
777 1.1.1.10 mrg if (!obj_info)
778 1.1.1.10 mrg break;
779 1.1.1.10 mrg
780 1.1.1.10 mrg obj_info->filename = filename_of_info;
781 1.1.1.10 mrg }
782 1.1.1.10 mrg
783 1.1.1.10 mrg return gcov_info_head;
784 1.1.1.10 mrg }
785 1.1.1.10 mrg
786 1.1.1.10 mrg /* For each profile of the list specified by SRC_PROFILE, read the GCDA file of
787 1.1.1.10 mrg the profile. If a GCDA file exists, add the profile to a list. Return the
788 1.1.1.10 mrg profile list. */
789 1.1.1.10 mrg
790 1.1.1.10 mrg struct gcov_info *
791 1.1.1.10 mrg get_target_profiles_for_merge (struct gcov_info *src_profile)
792 1.1.1.10 mrg {
793 1.1.1.10 mrg struct gcov_info *gi_ptr;
794 1.1.1.10 mrg
795 1.1.1.10 mrg read_profile_dir_init ();
796 1.1.1.10 mrg
797 1.1.1.10 mrg for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
798 1.1.1.10 mrg if (gcov_open (gi_ptr->filename, 1))
799 1.1.1.10 mrg {
800 1.1.1.10 mrg (void)read_gcda_file (gi_ptr->filename);
801 1.1.1.10 mrg gcov_close ();
802 1.1.1.10 mrg }
803 1.1.1.10 mrg
804 1.1.1.10 mrg return gcov_info_head;
805 1.1.1.10 mrg }
806 1.1.1.10 mrg
807 1.1.1.10 mrg /* Deserialize gcov_info objects and associated filenames from the file
808 1.1.1.10 mrg specified by FILENAME to create a source profile list. When FILENAME is
809 1.1.1.10 mrg NULL, read from stdin. Use the filenames of the source profile list to get
810 1.1.1.10 mrg a target profile list. Merge the source profile list into the target
811 1.1.1.10 mrg profile list using weights W1 and W2. Return the list of merged gcov_info
812 1.1.1.10 mrg objects. Return NULL if the list is empty. */
813 1.1.1.10 mrg
814 1.1.1.10 mrg struct gcov_info *
815 1.1.1.10 mrg gcov_profile_merge_stream (const char *filename, int w1, int w2)
816 1.1.1.10 mrg {
817 1.1.1.10 mrg struct gcov_info *tgt_profile;
818 1.1.1.10 mrg struct gcov_info *src_profile;
819 1.1.1.10 mrg
820 1.1.1.10 mrg if (!gcov_open (filename, 1))
821 1.1.1.10 mrg {
822 1.1.1.10 mrg fnotice (stderr, "%s:cannot open:%s\n", filename, xstrerror (errno));
823 1.1.1.10 mrg return NULL;
824 1.1.1.10 mrg }
825 1.1.1.10 mrg
826 1.1.1.10 mrg src_profile = deserialize_profiles (filename ? filename : "<stdin>");
827 1.1.1.10 mrg gcov_close ();
828 1.1.1.10 mrg tgt_profile = get_target_profiles_for_merge (src_profile);
829 1.1.1.10 mrg
830 1.1.1.10 mrg return gcov_profile_merge (tgt_profile, src_profile, w1, w2);
831 1.1 mrg }
832 1.1 mrg
833 1.1 mrg typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
834 1.1 mrg
835 1.1 mrg /* Performing FN upon arc counters. */
836 1.1 mrg
837 1.1 mrg static void
838 1.1 mrg __gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
839 1.1 mrg counter_op_fn fn, void *data1, void *data2)
840 1.1 mrg {
841 1.1 mrg for (; n_counters; counters++, n_counters--)
842 1.1 mrg {
843 1.1 mrg gcov_type val = *counters;
844 1.1 mrg *counters = fn(val, data1, data2);
845 1.1 mrg }
846 1.1 mrg }
847 1.1 mrg
848 1.1 mrg /* Performing FN upon ior counters. */
849 1.1 mrg
850 1.1 mrg static void
851 1.1 mrg __gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
852 1.1 mrg unsigned n_counters ATTRIBUTE_UNUSED,
853 1.1 mrg counter_op_fn fn ATTRIBUTE_UNUSED,
854 1.1 mrg void *data1 ATTRIBUTE_UNUSED,
855 1.1 mrg void *data2 ATTRIBUTE_UNUSED)
856 1.1 mrg {
857 1.1 mrg /* Do nothing. */
858 1.1 mrg }
859 1.1 mrg
860 1.1 mrg /* Performing FN upon time-profile counters. */
861 1.1 mrg
862 1.1 mrg static void
863 1.1 mrg __gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
864 1.1 mrg unsigned n_counters ATTRIBUTE_UNUSED,
865 1.1 mrg counter_op_fn fn ATTRIBUTE_UNUSED,
866 1.1 mrg void *data1 ATTRIBUTE_UNUSED,
867 1.1 mrg void *data2 ATTRIBUTE_UNUSED)
868 1.1 mrg {
869 1.1 mrg /* Do nothing. */
870 1.1 mrg }
871 1.1 mrg
872 1.1.1.8 mrg /* Performing FN upon TOP N counters. */
873 1.1 mrg
874 1.1 mrg static void
875 1.1.1.8 mrg __gcov_topn_counter_op (gcov_type *counters, unsigned n_counters,
876 1.1.1.8 mrg counter_op_fn fn, void *data1, void *data2)
877 1.1 mrg {
878 1.1 mrg unsigned i, n_measures;
879 1.1 mrg
880 1.1 mrg gcc_assert (!(n_counters % 3));
881 1.1 mrg n_measures = n_counters / 3;
882 1.1 mrg for (i = 0; i < n_measures; i++, counters += 3)
883 1.1 mrg {
884 1.1 mrg counters[1] = fn (counters[1], data1, data2);
885 1.1 mrg counters[2] = fn (counters[2], data1, data2);
886 1.1 mrg }
887 1.1 mrg }
888 1.1 mrg
889 1.1 mrg /* Scaling the counter value V by multiplying *(float*) DATA1. */
890 1.1 mrg
891 1.1 mrg static gcov_type
892 1.1 mrg fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
893 1.1 mrg {
894 1.1 mrg float f = *(float *) data1;
895 1.1 mrg return (gcov_type) (v * f);
896 1.1 mrg }
897 1.1 mrg
898 1.1 mrg /* Scaling the counter value V by multiplying DATA2/DATA1. */
899 1.1 mrg
900 1.1 mrg static gcov_type
901 1.1 mrg int_scale (gcov_type v, void *data1, void *data2)
902 1.1 mrg {
903 1.1 mrg int n = *(int *) data1;
904 1.1 mrg int d = *(int *) data2;
905 1.1 mrg return (gcov_type) ( RDIV (v,d) * n);
906 1.1 mrg }
907 1.1 mrg
908 1.1 mrg /* Type of function used to process counters. */
909 1.1 mrg typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
910 1.1 mrg counter_op_fn, void *, void *);
911 1.1 mrg
912 1.1 mrg /* Function array to process profile counters. */
913 1.1 mrg #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
914 1.1 mrg __gcov ## FN_TYPE ## _counter_op,
915 1.1 mrg static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
916 1.1 mrg #include "gcov-counter.def"
917 1.1 mrg };
918 1.1 mrg #undef DEF_GCOV_COUNTER
919 1.1 mrg
920 1.1 mrg /* Driver for scaling profile counters. */
921 1.1 mrg
922 1.1 mrg int
923 1.1 mrg gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
924 1.1 mrg {
925 1.1 mrg struct gcov_info *gi_ptr;
926 1.1 mrg unsigned f_ix;
927 1.1 mrg
928 1.1 mrg if (verbose)
929 1.1 mrg fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
930 1.1 mrg
931 1.1 mrg /* Scaling the counters. */
932 1.1 mrg for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
933 1.1 mrg for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
934 1.1 mrg {
935 1.1 mrg unsigned t_ix;
936 1.1 mrg const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
937 1.1 mrg const struct gcov_ctr_info *ci_ptr;
938 1.1 mrg
939 1.1 mrg if (!gfi_ptr || gfi_ptr->key != gi_ptr)
940 1.1 mrg continue;
941 1.1 mrg
942 1.1 mrg ci_ptr = gfi_ptr->ctrs;
943 1.1 mrg for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
944 1.1 mrg {
945 1.1 mrg gcov_merge_fn merge = gi_ptr->merge[t_ix];
946 1.1 mrg
947 1.1 mrg if (!merge)
948 1.1 mrg continue;
949 1.1 mrg if (d == 0)
950 1.1 mrg (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
951 1.1 mrg fp_scale, &scale_factor, NULL);
952 1.1 mrg else
953 1.1 mrg (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
954 1.1 mrg int_scale, &n, &d);
955 1.1 mrg ci_ptr++;
956 1.1 mrg }
957 1.1 mrg }
958 1.1 mrg
959 1.1 mrg return 0;
960 1.1 mrg }
961 1.1 mrg
962 1.1 mrg /* Driver to normalize profile counters. */
963 1.1 mrg
964 1.1 mrg int
965 1.1 mrg gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
966 1.1 mrg {
967 1.1 mrg struct gcov_info *gi_ptr;
968 1.1 mrg gcov_type curr_max_val = 0;
969 1.1 mrg unsigned f_ix;
970 1.1 mrg unsigned int i;
971 1.1 mrg float scale_factor;
972 1.1 mrg
973 1.1 mrg /* Find the largest count value. */
974 1.1 mrg for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
975 1.1 mrg for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
976 1.1 mrg {
977 1.1 mrg unsigned t_ix;
978 1.1 mrg const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
979 1.1 mrg const struct gcov_ctr_info *ci_ptr;
980 1.1 mrg
981 1.1 mrg if (!gfi_ptr || gfi_ptr->key != gi_ptr)
982 1.1 mrg continue;
983 1.1 mrg
984 1.1 mrg ci_ptr = gfi_ptr->ctrs;
985 1.1 mrg for (t_ix = 0; t_ix < 1; t_ix++)
986 1.1 mrg {
987 1.1 mrg for (i = 0; i < ci_ptr->num; i++)
988 1.1 mrg if (ci_ptr->values[i] > curr_max_val)
989 1.1 mrg curr_max_val = ci_ptr->values[i];
990 1.1 mrg ci_ptr++;
991 1.1 mrg }
992 1.1 mrg }
993 1.1 mrg
994 1.1 mrg scale_factor = (float)max_val / curr_max_val;
995 1.1 mrg if (verbose)
996 1.1.1.2 mrg fnotice (stdout, "max_val is %" PRId64 "\n", curr_max_val);
997 1.1 mrg
998 1.1 mrg return gcov_profile_scale (profile, scale_factor, 0, 0);
999 1.1 mrg }
1000 1.1 mrg
1001 1.1 mrg /* The following variables are defined in gcc/gcov-tool.c. */
1002 1.1 mrg extern int overlap_func_level;
1003 1.1 mrg extern int overlap_obj_level;
1004 1.1 mrg extern int overlap_hot_only;
1005 1.1 mrg extern int overlap_use_fullname;
1006 1.1 mrg extern double overlap_hot_threshold;
1007 1.1 mrg
1008 1.1 mrg /* Compute the overlap score of two values. The score is defined as:
1009 1.1 mrg min (V1/SUM_1, V2/SUM_2) */
1010 1.1 mrg
1011 1.1 mrg static double
1012 1.1 mrg calculate_2_entries (const unsigned long v1, const unsigned long v2,
1013 1.1 mrg const double sum_1, const double sum_2)
1014 1.1 mrg {
1015 1.1 mrg double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
1016 1.1 mrg double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
1017 1.1 mrg
1018 1.1 mrg if (val2 < val1)
1019 1.1 mrg val1 = val2;
1020 1.1 mrg
1021 1.1 mrg return val1;
1022 1.1 mrg }
1023 1.1 mrg
1024 1.1 mrg /* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
1025 1.1 mrg This function also updates cumulative score CUM_1_RESULT and
1026 1.1 mrg CUM_2_RESULT. */
1027 1.1 mrg
1028 1.1 mrg static double
1029 1.1 mrg compute_one_gcov (const struct gcov_info *gcov_info1,
1030 1.1 mrg const struct gcov_info *gcov_info2,
1031 1.1 mrg const double sum_1, const double sum_2,
1032 1.1 mrg double *cum_1_result, double *cum_2_result)
1033 1.1 mrg {
1034 1.1 mrg unsigned f_ix;
1035 1.1 mrg double ret = 0;
1036 1.1 mrg double cum_1 = 0, cum_2 = 0;
1037 1.1 mrg const struct gcov_info *gcov_info = 0;
1038 1.1 mrg double *cum_p;
1039 1.1 mrg double sum;
1040 1.1 mrg
1041 1.1 mrg gcc_assert (gcov_info1 || gcov_info2);
1042 1.1 mrg if (!gcov_info1)
1043 1.1 mrg {
1044 1.1 mrg gcov_info = gcov_info2;
1045 1.1 mrg cum_p = cum_2_result;
1046 1.1 mrg sum = sum_2;
1047 1.1 mrg *cum_1_result = 0;
1048 1.1 mrg } else
1049 1.1 mrg if (!gcov_info2)
1050 1.1 mrg {
1051 1.1 mrg gcov_info = gcov_info1;
1052 1.1 mrg cum_p = cum_1_result;
1053 1.1 mrg sum = sum_1;
1054 1.1 mrg *cum_2_result = 0;
1055 1.1 mrg }
1056 1.1 mrg
1057 1.1 mrg if (gcov_info)
1058 1.1 mrg {
1059 1.1 mrg for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
1060 1.1 mrg {
1061 1.1 mrg const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
1062 1.1 mrg if (!gfi_ptr || gfi_ptr->key != gcov_info)
1063 1.1 mrg continue;
1064 1.1 mrg const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
1065 1.1.1.7 mrg unsigned c_num;
1066 1.1.1.7 mrg for (c_num = 0; c_num < ci_ptr->num; c_num++)
1067 1.1.1.7 mrg cum_1 += ci_ptr->values[c_num] / sum;
1068 1.1 mrg }
1069 1.1 mrg *cum_p = cum_1;
1070 1.1 mrg return 0.0;
1071 1.1 mrg }
1072 1.1 mrg
1073 1.1 mrg for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
1074 1.1 mrg {
1075 1.1 mrg double func_cum_1 = 0.0;
1076 1.1 mrg double func_cum_2 = 0.0;
1077 1.1 mrg double func_val = 0.0;
1078 1.1 mrg int nonzero = 0;
1079 1.1 mrg int hot = 0;
1080 1.1 mrg const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
1081 1.1 mrg const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
1082 1.1 mrg
1083 1.1 mrg if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
1084 1.1 mrg continue;
1085 1.1 mrg if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
1086 1.1 mrg continue;
1087 1.1 mrg
1088 1.1 mrg const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
1089 1.1 mrg const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
1090 1.1.1.7 mrg unsigned c_num;
1091 1.1.1.7 mrg for (c_num = 0; c_num < ci_ptr1->num; c_num++)
1092 1.1.1.7 mrg {
1093 1.1.1.7 mrg if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
1094 1.1.1.7 mrg {
1095 1.1.1.7 mrg func_val += calculate_2_entries (ci_ptr1->values[c_num],
1096 1.1.1.7 mrg ci_ptr2->values[c_num],
1097 1.1.1.7 mrg sum_1, sum_2);
1098 1.1.1.7 mrg
1099 1.1.1.7 mrg func_cum_1 += ci_ptr1->values[c_num] / sum_1;
1100 1.1.1.7 mrg func_cum_2 += ci_ptr2->values[c_num] / sum_2;
1101 1.1.1.7 mrg nonzero = 1;
1102 1.1.1.7 mrg if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
1103 1.1.1.7 mrg || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
1104 1.1.1.7 mrg hot = 1;
1105 1.1.1.7 mrg }
1106 1.1.1.7 mrg }
1107 1.1 mrg
1108 1.1 mrg ret += func_val;
1109 1.1 mrg cum_1 += func_cum_1;
1110 1.1 mrg cum_2 += func_cum_2;
1111 1.1 mrg if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
1112 1.1 mrg {
1113 1.1 mrg printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
1114 1.1 mrg gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
1115 1.1 mrg }
1116 1.1 mrg }
1117 1.1 mrg *cum_1_result = cum_1;
1118 1.1 mrg *cum_2_result = cum_2;
1119 1.1 mrg return ret;
1120 1.1 mrg }
1121 1.1 mrg
1122 1.1 mrg /* Test if all counter values in this GCOV_INFO are cold.
1123 1.1 mrg "Cold" is defined as the counter value being less than
1124 1.1 mrg or equal to THRESHOLD. */
1125 1.1 mrg
1126 1.1 mrg static bool
1127 1.1 mrg gcov_info_count_all_cold (const struct gcov_info *gcov_info,
1128 1.1 mrg gcov_type threshold)
1129 1.1 mrg {
1130 1.1 mrg unsigned f_ix;
1131 1.1 mrg
1132 1.1 mrg for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
1133 1.1 mrg {
1134 1.1 mrg const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
1135 1.1 mrg
1136 1.1 mrg if (!gfi_ptr || gfi_ptr->key != gcov_info)
1137 1.1 mrg continue;
1138 1.1 mrg const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
1139 1.1.1.7 mrg for (unsigned c_num = 0; c_num < ci_ptr->num; c_num++)
1140 1.1.1.7 mrg if (ci_ptr->values[c_num] > threshold)
1141 1.1.1.7 mrg return false;
1142 1.1 mrg }
1143 1.1 mrg
1144 1.1 mrg return true;
1145 1.1 mrg }
1146 1.1 mrg
1147 1.1 mrg /* Test if all counter values in this GCOV_INFO are 0. */
1148 1.1 mrg
1149 1.1 mrg static bool
1150 1.1 mrg gcov_info_count_all_zero (const struct gcov_info *gcov_info)
1151 1.1 mrg {
1152 1.1 mrg return gcov_info_count_all_cold (gcov_info, 0);
1153 1.1 mrg }
1154 1.1 mrg
1155 1.1 mrg /* A pair of matched GCOV_INFO.
1156 1.1 mrg The flag is a bitvector:
1157 1.1 mrg b0: obj1's all counts are 0;
1158 1.1 mrg b1: obj1's all counts are cold (but no 0);
1159 1.1 mrg b2: obj1 is hot;
1160 1.1 mrg b3: no obj1 to match obj2;
1161 1.1 mrg b4: obj2's all counts are 0;
1162 1.1 mrg b5: obj2's all counts are cold (but no 0);
1163 1.1 mrg b6: obj2 is hot;
1164 1.1 mrg b7: no obj2 to match obj1;
1165 1.1 mrg */
1166 1.1 mrg struct overlap_t {
1167 1.1 mrg const struct gcov_info *obj1;
1168 1.1 mrg const struct gcov_info *obj2;
1169 1.1 mrg char flag;
1170 1.1 mrg };
1171 1.1 mrg
1172 1.1 mrg #define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
1173 1.1 mrg #define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
1174 1.1 mrg #define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
1175 1.1 mrg
1176 1.1 mrg /* Cumlative overlap dscore for profile1 and profile2. */
1177 1.1 mrg static double overlap_sum_1, overlap_sum_2;
1178 1.1 mrg
1179 1.1 mrg /* The number of gcda files in the profiles. */
1180 1.1 mrg static unsigned gcda_files[2];
1181 1.1 mrg
1182 1.1 mrg /* The number of unique gcda files in the profiles
1183 1.1 mrg (not existing in the other profile). */
1184 1.1 mrg static unsigned unique_gcda_files[2];
1185 1.1 mrg
1186 1.1 mrg /* The number of gcda files that all counter values are 0. */
1187 1.1 mrg static unsigned zero_gcda_files[2];
1188 1.1 mrg
1189 1.1 mrg /* The number of gcda files that all counter values are cold (but not 0). */
1190 1.1 mrg static unsigned cold_gcda_files[2];
1191 1.1 mrg
1192 1.1 mrg /* The number of gcda files that includes hot counter values. */
1193 1.1 mrg static unsigned hot_gcda_files[2];
1194 1.1 mrg
1195 1.1 mrg /* The number of gcda files with hot count value in either profiles. */
1196 1.1 mrg static unsigned both_hot_cnt;
1197 1.1 mrg
1198 1.1 mrg /* The number of gcda files with all counts cold (but not 0) in
1199 1.1 mrg both profiles. */
1200 1.1 mrg static unsigned both_cold_cnt;
1201 1.1 mrg
1202 1.1 mrg /* The number of gcda files with all counts 0 in both profiles. */
1203 1.1 mrg static unsigned both_zero_cnt;
1204 1.1 mrg
1205 1.1 mrg /* Extract the basename of the filename NAME. */
1206 1.1 mrg
1207 1.1 mrg static char *
1208 1.1 mrg extract_file_basename (const char *name)
1209 1.1 mrg {
1210 1.1 mrg char *str;
1211 1.1 mrg int len = 0;
1212 1.1 mrg char *path = xstrdup (name);
1213 1.1 mrg char sep_str[2];
1214 1.1 mrg
1215 1.1 mrg sep_str[0] = DIR_SEPARATOR;
1216 1.1 mrg sep_str[1] = 0;
1217 1.1 mrg str = strstr(path, sep_str);
1218 1.1 mrg do{
1219 1.1 mrg len = strlen(str) + 1;
1220 1.1 mrg path = &path[strlen(path) - len + 2];
1221 1.1 mrg str = strstr(path, sep_str);
1222 1.1 mrg } while(str);
1223 1.1 mrg
1224 1.1 mrg return path;
1225 1.1 mrg }
1226 1.1 mrg
1227 1.1 mrg /* Utility function to get the filename. */
1228 1.1 mrg
1229 1.1 mrg static const char *
1230 1.1 mrg get_file_basename (const char *name)
1231 1.1 mrg {
1232 1.1 mrg if (overlap_use_fullname)
1233 1.1 mrg return name;
1234 1.1 mrg return extract_file_basename (name);
1235 1.1 mrg }
1236 1.1 mrg
1237 1.1 mrg /* A utility function to set the flag for the gcda files. */
1238 1.1 mrg
1239 1.1 mrg static void
1240 1.1 mrg set_flag (struct overlap_t *e)
1241 1.1 mrg {
1242 1.1 mrg char flag = 0;
1243 1.1 mrg
1244 1.1 mrg if (!e->obj1)
1245 1.1 mrg {
1246 1.1 mrg unique_gcda_files[1]++;
1247 1.1 mrg flag = 0x8;
1248 1.1 mrg }
1249 1.1 mrg else
1250 1.1 mrg {
1251 1.1 mrg gcda_files[0]++;
1252 1.1 mrg if (gcov_info_count_all_zero (e->obj1))
1253 1.1 mrg {
1254 1.1 mrg zero_gcda_files[0]++;
1255 1.1 mrg flag = 0x1;
1256 1.1 mrg }
1257 1.1 mrg else
1258 1.1 mrg if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
1259 1.1 mrg * overlap_hot_threshold))
1260 1.1 mrg {
1261 1.1 mrg cold_gcda_files[0]++;
1262 1.1 mrg flag = 0x2;
1263 1.1 mrg }
1264 1.1 mrg else
1265 1.1 mrg {
1266 1.1 mrg hot_gcda_files[0]++;
1267 1.1 mrg flag = 0x4;
1268 1.1 mrg }
1269 1.1 mrg }
1270 1.1 mrg
1271 1.1 mrg if (!e->obj2)
1272 1.1 mrg {
1273 1.1 mrg unique_gcda_files[0]++;
1274 1.1 mrg flag |= (0x8 << 4);
1275 1.1 mrg }
1276 1.1 mrg else
1277 1.1 mrg {
1278 1.1 mrg gcda_files[1]++;
1279 1.1 mrg if (gcov_info_count_all_zero (e->obj2))
1280 1.1 mrg {
1281 1.1 mrg zero_gcda_files[1]++;
1282 1.1 mrg flag |= (0x1 << 4);
1283 1.1 mrg }
1284 1.1 mrg else
1285 1.1 mrg if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
1286 1.1 mrg * overlap_hot_threshold))
1287 1.1 mrg {
1288 1.1 mrg cold_gcda_files[1]++;
1289 1.1 mrg flag |= (0x2 << 4);
1290 1.1 mrg }
1291 1.1 mrg else
1292 1.1 mrg {
1293 1.1 mrg hot_gcda_files[1]++;
1294 1.1 mrg flag |= (0x4 << 4);
1295 1.1 mrg }
1296 1.1 mrg }
1297 1.1 mrg
1298 1.1 mrg gcc_assert (flag);
1299 1.1 mrg e->flag = flag;
1300 1.1 mrg }
1301 1.1 mrg
1302 1.1 mrg /* Test if INFO1 and INFO2 are from the matched source file.
1303 1.1 mrg Return 1 if they match; return 0 otherwise. */
1304 1.1 mrg
1305 1.1 mrg static int
1306 1.1 mrg matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
1307 1.1 mrg {
1308 1.1 mrg /* For FDO, we have to match the name. This can be expensive.
1309 1.1 mrg Maybe we should use hash here. */
1310 1.1 mrg if (strcmp (info1->filename, info2->filename))
1311 1.1 mrg return 0;
1312 1.1 mrg
1313 1.1 mrg if (info1->n_functions != info2->n_functions)
1314 1.1 mrg {
1315 1.1 mrg fnotice (stderr, "mismatched profiles in %s (%d functions"
1316 1.1 mrg " vs %d functions)\n",
1317 1.1 mrg info1->filename,
1318 1.1 mrg info1->n_functions,
1319 1.1 mrg info2->n_functions);
1320 1.1 mrg return 0;
1321 1.1 mrg }
1322 1.1 mrg return 1;
1323 1.1 mrg }
1324 1.1 mrg
1325 1.1 mrg /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
1326 1.1 mrg GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
1327 1.1 mrg match and 1.0 meaning a perfect match. */
1328 1.1 mrg
1329 1.1 mrg static double
1330 1.1 mrg calculate_overlap (struct gcov_info *gcov_list1,
1331 1.1 mrg struct gcov_info *gcov_list2)
1332 1.1 mrg {
1333 1.1 mrg unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
1334 1.1 mrg unsigned int i, j;
1335 1.1 mrg const struct gcov_info *gi_ptr;
1336 1.1 mrg struct overlap_t *all_infos;
1337 1.1 mrg
1338 1.1 mrg for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
1339 1.1 mrg list1_cnt++;
1340 1.1 mrg for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
1341 1.1 mrg list2_cnt++;
1342 1.1 mrg all_cnt = list1_cnt + list2_cnt;
1343 1.1 mrg all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
1344 1.1 mrg * all_cnt * 2);
1345 1.1 mrg gcc_assert (all_infos);
1346 1.1 mrg
1347 1.1 mrg i = 0;
1348 1.1 mrg for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
1349 1.1 mrg {
1350 1.1 mrg all_infos[i].obj1 = gi_ptr;
1351 1.1 mrg all_infos[i].obj2 = 0;
1352 1.1 mrg }
1353 1.1 mrg
1354 1.1 mrg for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
1355 1.1 mrg {
1356 1.1 mrg all_infos[i].obj1 = 0;
1357 1.1 mrg all_infos[i].obj2 = gi_ptr;
1358 1.1 mrg }
1359 1.1 mrg
1360 1.1 mrg for (i = list1_cnt; i < all_cnt; i++)
1361 1.1 mrg {
1362 1.1 mrg if (all_infos[i].obj2 == 0)
1363 1.1 mrg continue;
1364 1.1 mrg for (j = 0; j < list1_cnt; j++)
1365 1.1 mrg {
1366 1.1 mrg if (all_infos[j].obj2 != 0)
1367 1.1 mrg continue;
1368 1.1 mrg if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
1369 1.1 mrg {
1370 1.1 mrg all_infos[j].obj2 = all_infos[i].obj2;
1371 1.1 mrg all_infos[i].obj2 = 0;
1372 1.1 mrg break;
1373 1.1 mrg }
1374 1.1 mrg }
1375 1.1 mrg }
1376 1.1 mrg
1377 1.1 mrg for (i = 0; i < all_cnt; i++)
1378 1.1 mrg if (all_infos[i].obj1 || all_infos[i].obj2)
1379 1.1 mrg {
1380 1.1 mrg set_flag (all_infos + i);
1381 1.1 mrg if (FLAG_ONE_HOT (all_infos[i].flag))
1382 1.1 mrg both_hot_cnt++;
1383 1.1 mrg if (FLAG_BOTH_COLD(all_infos[i].flag))
1384 1.1 mrg both_cold_cnt++;
1385 1.1 mrg if (FLAG_BOTH_ZERO(all_infos[i].flag))
1386 1.1 mrg both_zero_cnt++;
1387 1.1 mrg }
1388 1.1 mrg
1389 1.1 mrg double prg_val = 0;
1390 1.1 mrg double sum_val = 0;
1391 1.1 mrg double sum_cum_1 = 0;
1392 1.1 mrg double sum_cum_2 = 0;
1393 1.1 mrg
1394 1.1 mrg for (i = 0; i < all_cnt; i++)
1395 1.1 mrg {
1396 1.1 mrg double val;
1397 1.1 mrg double cum_1, cum_2;
1398 1.1 mrg const char *filename;
1399 1.1 mrg
1400 1.1 mrg if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
1401 1.1 mrg continue;
1402 1.1 mrg if (FLAG_BOTH_ZERO (all_infos[i].flag))
1403 1.1 mrg continue;
1404 1.1 mrg
1405 1.1 mrg if (all_infos[i].obj1)
1406 1.1 mrg filename = get_file_basename (all_infos[i].obj1->filename);
1407 1.1 mrg else
1408 1.1 mrg filename = get_file_basename (all_infos[i].obj2->filename);
1409 1.1 mrg
1410 1.1 mrg if (overlap_func_level)
1411 1.1 mrg printf("\n processing %36s:\n", filename);
1412 1.1 mrg
1413 1.1 mrg val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
1414 1.1 mrg overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
1415 1.1 mrg
1416 1.1 mrg if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
1417 1.1 mrg {
1418 1.1 mrg printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1419 1.1 mrg filename, val*100, cum_1*100, cum_2*100);
1420 1.1 mrg sum_val += val;
1421 1.1 mrg sum_cum_1 += cum_1;
1422 1.1 mrg sum_cum_2 += cum_2;
1423 1.1 mrg }
1424 1.1 mrg
1425 1.1 mrg prg_val += val;
1426 1.1 mrg
1427 1.1 mrg }
1428 1.1 mrg
1429 1.1.1.8 mrg free (all_infos);
1430 1.1.1.8 mrg
1431 1.1 mrg if (overlap_obj_level)
1432 1.1 mrg printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
1433 1.1 mrg "", sum_val*100, sum_cum_1*100, sum_cum_2*100);
1434 1.1 mrg
1435 1.1 mrg printf (" Statistics:\n"
1436 1.1 mrg " profile1_# profile2_# overlap_#\n");
1437 1.1 mrg printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
1438 1.1.1.2 mrg gcda_files[0]-unique_gcda_files[0]);
1439 1.1 mrg printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
1440 1.1.1.2 mrg unique_gcda_files[1]);
1441 1.1 mrg printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
1442 1.1.1.2 mrg hot_gcda_files[1], both_hot_cnt);
1443 1.1 mrg printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
1444 1.1.1.2 mrg cold_gcda_files[1], both_cold_cnt);
1445 1.1 mrg printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
1446 1.1.1.2 mrg zero_gcda_files[1], both_zero_cnt);
1447 1.1 mrg
1448 1.1 mrg return prg_val;
1449 1.1 mrg }
1450 1.1 mrg
1451 1.1.1.3 mrg /* Compute the overlap score of two lists of gcov_info objects PROFILE1 and
1452 1.1.1.3 mrg PROFILE2.
1453 1.1 mrg Return 0 on success: without mismatch. Reutrn 1 on error. */
1454 1.1 mrg
1455 1.1 mrg int
1456 1.1 mrg gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
1457 1.1 mrg {
1458 1.1 mrg double result;
1459 1.1 mrg
1460 1.1 mrg result = calculate_overlap (profile1, profile2);
1461 1.1 mrg
1462 1.1 mrg if (result > 0)
1463 1.1 mrg {
1464 1.1 mrg printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
1465 1.1 mrg return 0;
1466 1.1 mrg }
1467 1.1 mrg return 1;
1468 1.1 mrg }
1469