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