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