1.5M increase is not big concern. Ok with that. David
On Tue, Sep 16, 2014 at 10:51 AM, Teresa Johnson <tejohn...@google.com> wrote: > On Tue, Sep 16, 2014 at 8:07 AM, Xinliang David Li <davi...@google.com> wrote: >> The zero_counts array is passed to gcov_build_callgraph but not used >> until the dyn-cgraph is initialized. We should avoid increasing >> runtime memory overhead by not creating it if possible. > > We could delay creation a little bit, until the callgraph has been > initialized. But I am not sure this gains us much as it doesn't avoid > having the lifetime of the array overlap with the lifetime of the > callgraph. And unless fixups have been explicitly disabled or there > are no comdats we will need to allocate it (so likely in almost all > cases). > > However, I can reduce the required overhead by using an array of chars > instead of ints. I measured the number of bytes in the array for a big > app and it was 5.6M with the int array and 1.5M with the char array. > Does this seem reasonable? To reduce it further I could encode as a > bitvector as we do in the gcda file. > > Teresa > >> >> David >> >> On Tue, Sep 16, 2014 at 7:57 AM, Teresa Johnson <tejohn...@google.com> wrote: >>> On Mon, Sep 15, 2014 at 9:29 PM, Xinliang David Li <davi...@google.com> >>> wrote: >>>> Is it necessary to declare zero_counts array at all? Can a flag field >>>> be added to dyn_cgraph_node structure to indicate if it is fixed up? >>> >>> The zero_counts array is used to pass info back to the caller in >>> libgcov-driver.cc (dyn_cgraph_node), which is where it is allocated. >>> That routine does not have access to the dyn-ipa cgraph. >>> >>> Teresa >>> >>>> >>>> David >>>> >>>> On Fri, Sep 12, 2014 at 4:31 PM, Teresa Johnson <tejohn...@google.com> >>>> wrote: >>>>> This patch addresses issues when running gcov-tool after performing >>>>> COMDAT fixup during dyn-ipa. Functions that were previously all zero >>>>> counts are marked, and the counts are discarded when being read in >>>>> by gcov-tool before recalculating module groups and summary info. >>>>> >>>>> While here, cleaned up the gcov-tool output (remove an overly-verbose >>>>> output, >>>>> make all output consistently go to stderr). >>>>> >>>>> Passes regression tests and manual tests. Ok for google branches? >>>>> >>>>> 2014-09-12 Teresa Johnson <tejohn...@google.com> >>>>> >>>>> * gcc/coverage.c (read_counts_file): Handle new section. >>>>> * gcc/gcov.c (read_count_file): Ditto. >>>>> * gcc/gcov-dump.c (dump_gcov_file): Ditto. >>>>> (tag_function): Ditto. >>>>> (tag_zero_fixup): New function. >>>>> * gcc/gcov-io.c (gcov_read_comdat_zero_fixup): Ditto. >>>>> * gcc/gcov-io.h (gcov_read_comdat_zero_fixup): Ditto. >>>>> * libgcc/dyn-ipa.c (struct checksum_alias): Change flag to >>>>> pointer. >>>>> (new_checksum_alias): Ditto. >>>>> (cfg_checksum_insert): Ditto. >>>>> (checksum_set_insert): Ditto. >>>>> (gcov_build_callgraph): New parameter. >>>>> (gcov_collect_imported_modules): Add assert for duplicate gcda >>>>> reads. >>>>> (gcov_fixup_counters_checksum): Change flag to pointer to flag, >>>>> set it. >>>>> (__gcov_compute_module_groups): New parameter. >>>>> * libgcc/libgcov-driver.c (set_gcov_fn_fixed_up): New function. >>>>> (get_gcov_fn_fixed_up): Ditto. >>>>> (gcov_exit_merge_gcda): Handle new section. >>>>> (gcov_write_comdat_zero_fixup): Ditto. >>>>> (gcov_write_build_info): Ditto. >>>>> (gcov_write_comdat_zero_fixup): New function. >>>>> (gcov_write_func_counters): Fix indent. >>>>> (gcov_dump_module_info): Write new flag section. >>>>> * libgcc/libgcov.h (gcov_get_counter): Clear fixed-up counters. >>>>> (gcov_get_counter_target): Ditto. >>>>> * libgcc/libgcov-util.c (tag_function): Annotate fixed-up >>>>> functions, >>>>> remove overly verbose output. >>>>> (tag_counters): Clear fixed-up counters. >>>>> (lipo_process_substitute_string_1): Send all verbose output to >>>>> stderr. >>>>> (tag_zero_fixup): New function. >>>>> (read_gcda_file): Deallocate flag array. >>>>> (gcov_profile_scale): Send all verbose output to stderr. >>>>> (gcov_profile_normalize): Ditto. >>>>> >>>>> Index: gcc/coverage.c >>>>> =================================================================== >>>>> --- gcc/coverage.c (revision 215230) >>>>> +++ gcc/coverage.c (working copy) >>>>> @@ -820,6 +820,14 @@ read_counts_file (const char *da_file_name, unsign >>>>> free (build_info_strings[i]); >>>>> free (build_info_strings); >>>>> } >>>>> + else if (tag == GCOV_TAG_COMDAT_ZERO_FIXUP) >>>>> + { >>>>> + /* Zero-profile fixup flags are not used by the compiler, read >>>>> and >>>>> + ignore. */ >>>>> + gcov_unsigned_t num_fn; >>>>> + int *zero_fixup_flags = gcov_read_comdat_zero_fixup >>>>> (length, &num_fn); >>>>> + free (zero_fixup_flags); >>>>> + } >>>>> else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident) >>>>> { >>>>> counts_entry_t **slot, *entry, elt; >>>>> Index: gcc/gcov.c >>>>> =================================================================== >>>>> --- gcc/gcov.c (revision 215230) >>>>> +++ gcc/gcov.c (working copy) >>>>> @@ -1441,6 +1441,12 @@ read_count_file (function_t *fns) >>>>> free (build_info_strings[i]); >>>>> free (build_info_strings); >>>>> } >>>>> + else if (tag == GCOV_TAG_COMDAT_ZERO_FIXUP) >>>>> + { >>>>> + gcov_unsigned_t num_fn; >>>>> + int *zero_fixup_flags = gcov_read_comdat_zero_fixup >>>>> (length, &num_fn); >>>>> + free (zero_fixup_flags); >>>>> + } >>>>> else if (tag == GCOV_TAG_FUNCTION && !length) >>>>> ; /* placeholder */ >>>>> else if (tag == GCOV_TAG_FUNCTION && length == >>>>> GCOV_TAG_FUNCTION_LENGTH) >>>>> Index: gcc/gcov-dump.c >>>>> =================================================================== >>>>> --- gcc/gcov-dump.c (revision 215230) >>>>> +++ gcc/gcov-dump.c (working copy) >>>>> @@ -42,6 +42,7 @@ static void tag_summary (const char *, unsigned, u >>>>> static void tag_module_info (const char *, unsigned, unsigned); >>>>> static void dump_working_sets (const char *filename ATTRIBUTE_UNUSED, >>>>> const struct gcov_ctr_summary *summary); >>>>> +static void tag_zero_fixup (const char *, unsigned, unsigned); >>>>> static void tag_build_info (const char *, unsigned, unsigned); >>>>> extern int main (int, char **); >>>>> >>>>> @@ -57,6 +58,9 @@ static int flag_dump_positions = 0; >>>>> static int flag_dump_aux_modules_only = 0; >>>>> static int flag_dump_working_sets = 0; >>>>> >>>>> +static unsigned num_fn_info; >>>>> +static int *zero_fixup_flags = NULL; >>>>> + >>>>> static const struct option options[] = >>>>> { >>>>> { "help", no_argument, NULL, 'h' }, >>>>> @@ -79,6 +83,7 @@ static const tag_format_t tag_table[] = >>>>> {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary}, >>>>> {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary}, >>>>> {GCOV_TAG_MODULE_INFO, "MODULE INFO", tag_module_info}, >>>>> + {GCOV_TAG_COMDAT_ZERO_FIXUP, "ZERO FIXUP", tag_zero_fixup}, >>>>> {GCOV_TAG_BUILD_INFO, "BUILD INFO", tag_build_info}, >>>>> {0, NULL, NULL} >>>>> }; >>>>> @@ -274,6 +279,8 @@ dump_gcov_file (const char *filename) >>>>> printf ("%s:stamp %lu\n", filename, (unsigned long)stamp); >>>>> } >>>>> >>>>> + num_fn_info = 0; >>>>> + >>>>> while (1) >>>>> { >>>>> gcov_position_t base, position = gcov_position (); >>>>> @@ -341,6 +348,7 @@ dump_gcov_file (const char *filename) >>>>> break; >>>>> } >>>>> } >>>>> + free (zero_fixup_flags); >>>>> gcov_close (); >>>>> } >>>>> >>>>> @@ -354,7 +362,9 @@ tag_function (const char *filename ATTRIBUTE_UNUSE >>>>> printf (" placeholder"); >>>>> else >>>>> { >>>>> - printf (" ident=%u", gcov_read_unsigned ()); >>>>> + int had_fixup = zero_fixup_flags && zero_fixup_flags[num_fn_info]; >>>>> + printf (" ident=%u%s", gcov_read_unsigned (), >>>>> + had_fixup ? " (Was 0-count COMDAT)" : ""); >>>>> printf (", lineno_checksum=0x%08x", gcov_read_unsigned ()); >>>>> printf (", cfg_checksum=0x%08x", gcov_read_unsigned ()); >>>>> >>>>> @@ -369,6 +379,7 @@ tag_function (const char *filename ATTRIBUTE_UNUSE >>>>> printf (":%u", gcov_read_unsigned ()); >>>>> } >>>>> } >>>>> + num_fn_info++; >>>>> } >>>>> >>>>> static void >>>>> @@ -600,6 +611,32 @@ tag_module_info (const char *filename ATTRIBUTE_UN >>>>> } >>>>> >>>>> static void >>>>> +tag_zero_fixup (const char *filename, >>>>> + unsigned tag ATTRIBUTE_UNUSED, unsigned length) >>>>> +{ >>>>> + gcov_unsigned_t num_fns = 0; >>>>> + zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fns); >>>>> + if (!zero_fixup_flags) >>>>> + { >>>>> + printf ("%s:error reading zero fixup flags\n", filename); >>>>> + return; >>>>> + } >>>>> + printf (" num_fns=%u", num_fns); >>>>> + for (unsigned i = 0; i < num_fns; i++) >>>>> + { >>>>> + if (!(i % 32)) >>>>> + { >>>>> + printf ("\n"); >>>>> + print_prefix (filename, 0, 0); >>>>> + printf ("\t\t"); >>>>> + } >>>>> + if (!(i % 8)) >>>>> + printf ("%s%4u:", (i%32)?" ":"", i); >>>>> + printf ("%u", zero_fixup_flags[i]); >>>>> + } >>>>> +} >>>>> + >>>>> +static void >>>>> tag_build_info (const char *filename, >>>>> unsigned tag ATTRIBUTE_UNUSED, unsigned length) >>>>> { >>>>> Index: gcc/gcov-io.c >>>>> =================================================================== >>>>> --- gcc/gcov-io.c (revision 215230) >>>>> +++ gcc/gcov-io.c (working copy) >>>>> @@ -691,6 +691,36 @@ gcov_read_summary (struct gcov_summary *summary) >>>>> } >>>>> } >>>>> >>>>> +/* Read LENGTH words (unsigned type) from a zero profile fixup record >>>>> with the >>>>> + number of function flags saved in NUM_FNS. Returns the int flag >>>>> array, which >>>>> + should be deallocated by caller, or NULL on error. */ >>>>> + >>>>> +GCOV_LINKAGE int * >>>>> +gcov_read_comdat_zero_fixup (gcov_unsigned_t length, >>>>> + gcov_unsigned_t *num_fns) >>>>> +{ >>>>> + unsigned ix, f_ix; >>>>> + gcov_unsigned_t num = gcov_read_unsigned (); >>>>> + /* The length consists of 1 word to hold the number of functions, >>>>> + plus enough 32-bit words to hold 1 bit/function. */ >>>>> + gcc_assert ((num + 31) / 32 + 1 == length); >>>>> + int *zero_fixup_flags = (int *) xcalloc (num, sizeof (int)); >>>>> + for (ix = 0; ix < length - 1; ix++) >>>>> + { >>>>> + gcov_unsigned_t bitvector = gcov_read_unsigned (); >>>>> + f_ix = ix * 32; >>>>> + while (bitvector) >>>>> + { >>>>> + if (bitvector & 0x1) >>>>> + zero_fixup_flags[f_ix] = 1; >>>>> + f_ix++; >>>>> + bitvector >>= 1; >>>>> + } >>>>> + } >>>>> + *num_fns = num; >>>>> + return zero_fixup_flags; >>>>> +} >>>>> + >>>>> /* Read NUM_STRINGS strings (as an unsigned array) in STRING_ARRAY, and >>>>> return >>>>> the number of words read. */ >>>>> >>>>> Index: gcc/gcov-io.h >>>>> =================================================================== >>>>> --- gcc/gcov-io.h (revision 215230) >>>>> +++ gcc/gcov-io.h (working copy) >>>>> @@ -129,7 +129,7 @@ see the files COPYING3 and COPYING.RUNTIME respect >>>>> blocks they are for. >>>>> >>>>> The data file contains the following records. >>>>> - data: {unit summary:program* build_info function-data*}* >>>>> + data: {unit summary:program* build_info zero_fixup >>>>> function-data*}* >>>>> unit: header int32:checksum >>>>> function-data: announce_function present counts >>>>> announce_function: header int32:ident >>>>> @@ -142,6 +142,7 @@ see the files COPYING3 and COPYING.RUNTIME respect >>>>> histogram: {int32:bitvector}8 histogram-buckets* >>>>> histogram-buckets: int32:num int64:min int64:sum >>>>> build_info: string:info* >>>>> + zero_fixup: int32:num int32:bitvector* >>>>> >>>>> The ANNOUNCE_FUNCTION record is the same as that in the note file, >>>>> but without the source location. The COUNTS gives the >>>>> @@ -158,6 +159,12 @@ see the files COPYING3 and COPYING.RUNTIME respect >>>>> build. For example, it can be used to include source revision >>>>> information that is useful in diagnosing profile mis-matches. >>>>> >>>>> + ZERO_FIXUP record contains a count of functions in the gcda file >>>>> + and an array of bitvectors indexed by the function index's in the >>>>> + function-data section. Each bit flags whether the function was a >>>>> + COMDAT that had all-zero profiles that was fixed up by dyn-ipa >>>>> + using profiles from functions with matching checksums in other >>>>> modules. >>>>> + >>>>> This file is included by both the compiler, gcov tools and the >>>>> runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to >>>>> distinguish which case is which. If IN_LIBGCOV is nonzero, >>>>> @@ -261,6 +268,9 @@ typedef unsigned HOST_WIDEST_INT gcov_type_unsigne >>>>> #define GCOV_TAG_COUNTER_NUM(LENGTH) ((LENGTH) / 2) >>>>> #define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t)0xa1000000) /* >>>>> Obsolete */ >>>>> #define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t)0xa3000000) >>>>> +#define GCOV_TAG_COMDAT_ZERO_FIXUP ((gcov_unsigned_t)0xa9000000) >>>>> +/* Ceiling divide by 32 bit word size, plus one word to hold NUM. */ >>>>> +#define GCOV_TAG_COMDAT_ZERO_FIXUP_LENGTH(NUM) (1 + (NUM + 31) / 32) >>>>> #define GCOV_TAG_SUMMARY_LENGTH(NUM) \ >>>>> (1 + GCOV_COUNTERS_SUMMABLE * (10 + 3 * 2) + (NUM) * 5) >>>>> #define GCOV_TAG_BUILD_INFO ((gcov_unsigned_t)0xa7000000) >>>>> @@ -441,6 +451,9 @@ GCOV_LINKAGE int gcov_close (void) ATTRIBUTE_HIDDE >>>>> GCOV_LINKAGE gcov_unsigned_t gcov_read_unsigned (void) ATTRIBUTE_HIDDEN; >>>>> GCOV_LINKAGE gcov_type gcov_read_counter (void) ATTRIBUTE_HIDDEN; >>>>> GCOV_LINKAGE void gcov_read_summary (struct gcov_summary *) >>>>> ATTRIBUTE_HIDDEN; >>>>> +GCOV_LINKAGE int *gcov_read_comdat_zero_fixup (gcov_unsigned_t, >>>>> + gcov_unsigned_t *) >>>>> + ATTRIBUTE_HIDDEN; >>>>> GCOV_LINKAGE char **gcov_read_build_info (gcov_unsigned_t, >>>>> gcov_unsigned_t *) >>>>> ATTRIBUTE_HIDDEN; >>>>> GCOV_LINKAGE const char *gcov_read_string (void); >>>>> Index: libgcc/dyn-ipa.c >>>>> =================================================================== >>>>> --- libgcc/dyn-ipa.c (revision 215230) >>>>> +++ libgcc/dyn-ipa.c (working copy) >>>>> @@ -107,8 +107,9 @@ struct checksum_alias >>>>> struct checksum_alias *next_alias; >>>>> gcov_type guid; >>>>> const struct gcov_fn_info *fi_ptr; >>>>> - /* Does this function have all-zero arc counts? */ >>>>> - int zero_counts; >>>>> + /* Non-NULL pointer to flag if this function has all-zero arc counts, >>>>> to be >>>>> + set if we perform fixup. */ >>>>> + int *zero_count_fixup; >>>>> }; >>>>> >>>>> /* Module info is stored in dyn_caph->sup_modules >>>>> @@ -178,10 +179,10 @@ extern gcov_unsigned_t __gcov_lipo_merge_modu_edge >>>>> extern gcov_unsigned_t __gcov_lipo_weak_inclusion; >>>>> >>>>> #if defined(inhibit_libc) >>>>> -void __gcov_build_callgraph (void) {} >>>>> +void __gcov_build_callgraph (int **zero_counts) {} >>>>> #else >>>>> >>>>> -int __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN; >>>>> +int __gcov_compute_module_groups (int **zero_counts) ATTRIBUTE_HIDDEN; >>>>> void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN; >>>>> static void gcov_dump_callgraph (gcov_type); >>>>> static void gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node); >>>>> @@ -378,18 +379,19 @@ lineno_checksum_get_key (const void *p) >>>>> } >>>>> >>>>> /* Create a new checksum_alias struct for function with GUID, FI_PTR, >>>>> - and ZERO_COUNTS flag. Prepends to list NEXT and returns new struct. >>>>> */ >>>>> + and ZERO_COUNT_FIXUP flag pointer. Prepends to list NEXT and returns >>>>> + new struct. */ >>>>> >>>>> static struct checksum_alias * >>>>> new_checksum_alias (gcov_type guid, const struct gcov_fn_info *fi_ptr, >>>>> - int zero_counts, >>>>> + int *zero_count_fixup, >>>>> struct checksum_alias *next) >>>>> { >>>>> struct checksum_alias *alias = XNEW (struct checksum_alias); >>>>> alias->next_alias = next; >>>>> alias->fi_ptr = fi_ptr; >>>>> alias->guid = guid; >>>>> - alias->zero_counts = zero_counts; >>>>> + alias->zero_count_fixup = zero_count_fixup; >>>>> return alias; >>>>> } >>>>> >>>>> @@ -407,11 +409,12 @@ find_cfg_checksum (struct checksum_alias_info *lis >>>>> } >>>>> >>>>> /* Insert a new checksum_alias struct into LIST for function with >>>>> - CFG_CHECKSUM and associated GUID, FI_PTR, and ZERO_COUNTS flag. */ >>>>> + CFG_CHECKSUM and associated GUID, FI_PTR, and ZERO_COUNT_FIXUP >>>>> + flag pointer. */ >>>>> >>>>> static struct checksum_alias_info * >>>>> cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid, >>>>> - const struct gcov_fn_info *fi_ptr, int zero_counts, >>>>> + const struct gcov_fn_info *fi_ptr, int >>>>> *zero_count_fixup, >>>>> struct checksum_alias_info *list) >>>>> { >>>>> struct checksum_alias_info *alias_info; >>>>> @@ -419,7 +422,8 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_t >>>>> if (alias_info) >>>>> { >>>>> gcc_assert (alias_info->alias_list); >>>>> - alias_info->alias_list = new_checksum_alias (guid, fi_ptr, >>>>> zero_counts, >>>>> + alias_info->alias_list = new_checksum_alias (guid, fi_ptr, >>>>> + zero_count_fixup, >>>>> >>>>> alias_info->alias_list); >>>>> return list; >>>>> } >>>>> @@ -428,7 +432,8 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_t >>>>> alias_info = XNEW (struct checksum_alias_info); >>>>> alias_info->next_cfg_checksum = list; >>>>> alias_info->cfg_checksum = cfg_checksum; >>>>> - alias_info->alias_list = new_checksum_alias (guid, fi_ptr, >>>>> zero_counts, >>>>> + alias_info->alias_list = new_checksum_alias (guid, fi_ptr, >>>>> + zero_count_fixup, >>>>> NULL); >>>>> return alias_info; >>>>> } >>>>> @@ -436,12 +441,12 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_t >>>>> >>>>> /* Insert a new checksum_alias struct into lineno_pointer_sets for >>>>> function with >>>>> LINENO_CHECKSUM and CFG_CHECKSUM with associated GUID, FI_PTR, and >>>>> - ZERO_COUNTS flag. */ >>>>> + ZERO_COUNT_FIXUP flag pointer. */ >>>>> >>>>> static void >>>>> checksum_set_insert (unsigned lineno_checksum, unsigned cfg_checksum, >>>>> gcov_type guid, const struct gcov_fn_info *fi_ptr, >>>>> - int zero_counts) >>>>> + int *zero_count_fixup) >>>>> { >>>>> struct dyn_pointer_set *p = the_dyn_call_graph.lineno_pointer_sets; >>>>> if (!p) >>>>> @@ -452,7 +457,7 @@ checksum_set_insert (unsigned lineno_checksum, uns >>>>> if (*m) >>>>> { >>>>> (*m)->cfg_checksum_list = cfg_checksum_insert (cfg_checksum, guid, >>>>> - fi_ptr, zero_counts, >>>>> + fi_ptr, >>>>> zero_count_fixup, >>>>> >>>>> (*m)->cfg_checksum_list); >>>>> } >>>>> else >>>>> @@ -460,7 +465,8 @@ checksum_set_insert (unsigned lineno_checksum, uns >>>>> *m = XNEW (struct lineno_checksum_alias); >>>>> (*m)->lineno_checksum = lineno_checksum; >>>>> (*m)->cfg_checksum_list = cfg_checksum_insert (cfg_checksum, guid, >>>>> - fi_ptr, >>>>> zero_counts, NULL); >>>>> + fi_ptr, >>>>> zero_count_fixup, >>>>> + NULL); >>>>> p->n_elements++; >>>>> } >>>>> } >>>>> @@ -801,10 +807,10 @@ gcov_build_callgraph_ic_fn (struct dyn_cgraph_node >>>>> } >>>>> } >>>>> >>>>> -/* Build the dynamic call graph. */ >>>>> +/* Build the dynamic call graph and update ZERO_COUNTS flags. */ >>>>> >>>>> static void >>>>> -gcov_build_callgraph (void) >>>>> +gcov_build_callgraph (int **zero_counts) >>>>> { >>>>> struct gcov_info *gi_ptr; >>>>> unsigned m_ix; >>>>> @@ -852,9 +858,19 @@ static void >>>>> if (total_arc_count != 0) >>>>> the_dyn_call_graph.num_nodes_executed++; >>>>> if (fixup_type) >>>>> - checksum_set_insert (fi_ptr->lineno_checksum, >>>>> - fi_ptr->cfg_checksum, >>>>> caller->guid, >>>>> - fi_ptr, total_arc_count == 0); >>>>> + { >>>>> + int *zero_count_fixup = NULL; >>>>> + /* Passing in a non-NULL zero_count_fixup pointer >>>>> + indicates that the counts were all zero for this >>>>> + function, and the fixup routine will set the >>>>> flag >>>>> + if the function's counters are updated to >>>>> non-zero >>>>> + values. */ >>>>> + if (total_arc_count == 0) >>>>> + zero_count_fixup = &zero_counts[m_ix][f_ix]; >>>>> + checksum_set_insert (fi_ptr->lineno_checksum, >>>>> + fi_ptr->cfg_checksum, >>>>> caller->guid, >>>>> + fi_ptr, zero_count_fixup); >>>>> + } >>>>> } >>>>> ci_ptr++; >>>>> } >>>>> @@ -1251,7 +1267,14 @@ gcov_collect_imported_modules (const void *value, >>>>> out_array = (struct gcov_import_mod_array *) data1; >>>>> >>>>> if (m->imp_mod != out_array->importing_module) >>>>> + { >>>>> out_array->imported_modules[out_array->len++] = m; >>>>> + /* Sanity check that the importing (primary) module is not >>>>> + actually the same as the new aux module. This could happen if >>>>> + we accidentally read in the same gcda file twice. */ >>>>> + gcc_assert (m->imp_mod->mod_info->ident != >>>>> + out_array->importing_module->mod_info->ident); >>>>> + } >>>>> >>>>> return 1; >>>>> } >>>>> @@ -2957,7 +2980,7 @@ gcov_fixup_counters_checksum (const struct checksu >>>>> for (alias = info->alias_list; alias; >>>>> alias = alias->next_alias) >>>>> { >>>>> - if (alias->zero_counts) >>>>> + if (alias->zero_count_fixup) >>>>> { >>>>> found = 1; >>>>> break; >>>>> @@ -2972,7 +2995,7 @@ gcov_fixup_counters_checksum (const struct checksu >>>>> for (alias = info->alias_list; alias; >>>>> alias = alias->next_alias) >>>>> { >>>>> - if (alias->zero_counts) >>>>> + if (alias->zero_count_fixup) >>>>> continue; >>>>> merge_ctrs (merged_ctrs, alias->fi_ptr->ctrs, alias->guid); >>>>> found = 1; >>>>> @@ -2990,9 +3013,10 @@ gcov_fixup_counters_checksum (const struct checksu >>>>> for (alias = info->alias_list; alias; >>>>> alias = alias->next_alias) >>>>> { >>>>> - if (!alias->zero_counts) >>>>> + if (!alias->zero_count_fixup) >>>>> continue; >>>>> copy_ctrs (alias->fi_ptr->ctrs, alias->guid, merged_ctrs); >>>>> + *alias->zero_count_fixup = 1; >>>>> } >>>>> >>>>> return 1; >>>>> @@ -3040,11 +3064,13 @@ gcov_fixup_zero_counters (void) >>>>> return changed; >>>>> } >>>>> >>>>> -/* Compute module groups needed for L-IPO compilation. Returns 1 if any >>>>> - counter fixups were applied, requiring a profile rewrite, 0 >>>>> otherwise. */ >>>>> +/* Compute module groups needed for L-IPO compilation. The ZERO_COUNTS >>>>> + flags are set for functions with zero count fixups applied. Returns 1 >>>>> + if any counter fixups were applied, requiring a profile rewrite, >>>>> + 0 otherwise. */ >>>>> >>>>> int >>>>> -__gcov_compute_module_groups (void) >>>>> +__gcov_compute_module_groups (int **zero_counts) >>>>> { >>>>> gcov_type cut_off_count; >>>>> char *seed = getenv ("LIPO_RANDOM_GROUPING"); >>>>> @@ -3091,7 +3117,7 @@ int >>>>> fixup_type = atoi (do_fixup); >>>>> >>>>> /* First compute dynamic call graph. */ >>>>> - gcov_build_callgraph (); >>>>> + gcov_build_callgraph (zero_counts); >>>>> >>>>> cut_off_count = gcov_compute_cutoff_count (); >>>>> >>>>> Index: libgcc/libgcov-driver.c >>>>> =================================================================== >>>>> --- libgcc/libgcov-driver.c (revision 215230) >>>>> +++ libgcc/libgcov-driver.c (working copy) >>>>> @@ -55,7 +55,7 @@ static gcov_unsigned_t gcov_cur_module_id = 0; >>>>> >>>>> >>>>> /* Dynamic call graph build and form module groups. */ >>>>> -int __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN; >>>>> +int __gcov_compute_module_groups (int **zero_counts) ATTRIBUTE_HIDDEN; >>>>> void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN; >>>>> >>>>> /* The following functions can be called from outside of this file. */ >>>>> @@ -129,6 +129,24 @@ set_gcov_list (struct gcov_info *head) >>>>> __gcov_list = head; >>>>> } >>>>> >>>>> +/* Flag if the current function being read was marked as having fixed-up >>>>> + zero counters. */ >>>>> +static int __gcov_curr_fn_fixed_up; >>>>> + >>>>> +/* Set function fixed up flag. */ >>>>> +void >>>>> +set_gcov_fn_fixed_up (int fixed_up) >>>>> +{ >>>>> + __gcov_curr_fn_fixed_up = fixed_up; >>>>> +} >>>>> + >>>>> +/* Return function fixed up flag. */ >>>>> +int >>>>> +get_gcov_fn_fixed_up (void) >>>>> +{ >>>>> + return __gcov_curr_fn_fixed_up; >>>>> +} >>>>> + >>>>> /* Size of the longest file name. */ >>>>> /* We need to expose this static variable when compiling for gcov-tool. >>>>> */ >>>>> #ifndef IN_GCOV_TOOL >>>>> @@ -564,6 +582,7 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, >>>>> int error = 0; >>>>> struct gcov_fn_buffer **fn_tail = &fn_buffer; >>>>> struct gcov_summary_buffer **sum_tail = &sum_buffer; >>>>> + int *zero_fixup_flags = NULL; >>>>> >>>>> length = gcov_read_unsigned (); >>>>> if (!gcov_version (gi_ptr, length, gi_filename)) >>>>> @@ -625,6 +644,21 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, >>>>> tag = gcov_read_unsigned (); >>>>> } >>>>> >>>>> + if (tag == GCOV_TAG_COMDAT_ZERO_FIXUP) >>>>> + { >>>>> + length = gcov_read_unsigned (); >>>>> + gcov_unsigned_t num_fns = 0; >>>>> + zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fns); >>>>> + if (!zero_fixup_flags) >>>>> + { >>>>> + gcov_error ("profiling:%s:Error reading zero fixup flags\n", >>>>> + gi_filename); >>>>> + return -1; >>>>> + } >>>>> + >>>>> + tag = gcov_read_unsigned (); >>>>> + } >>>>> + >>>>> /* Merge execution counts for each function. */ >>>>> for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; >>>>> f_ix++, tag = gcov_read_unsigned ()) >>>>> @@ -658,6 +692,9 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, >>>>> continue; >>>>> } >>>>> >>>>> + if (zero_fixup_flags) >>>>> + set_gcov_fn_fixed_up (zero_fixup_flags[f_ix]); >>>>> + >>>>> length = gcov_read_unsigned (); >>>>> if (length != gfi_ptr->ident) >>>>> goto read_mismatch; >>>>> @@ -689,6 +726,7 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, >>>>> if ((error = gcov_is_error ())) >>>>> goto read_error; >>>>> } >>>>> + free (zero_fixup_flags); >>>>> >>>>> if (tag && tag != GCOV_TAG_MODULE_INFO) >>>>> { >>>>> @@ -706,6 +744,34 @@ read_error: >>>>> return -1; >>>>> } >>>>> >>>>> + >>>>> +/* Write NUM_FNS ZERO_COUNTS fixup flags to a gcda file starting from its >>>>> + current location. */ >>>>> + >>>>> +static void >>>>> +gcov_write_comdat_zero_fixup (int *zero_counts, unsigned num_fns) >>>>> +{ >>>>> + unsigned f_ix; >>>>> + gcov_unsigned_t len = GCOV_TAG_COMDAT_ZERO_FIXUP_LENGTH (num_fns); >>>>> + gcov_write_tag_length (GCOV_TAG_COMDAT_ZERO_FIXUP, len); >>>>> + >>>>> + gcov_write_unsigned (num_fns); >>>>> + gcov_unsigned_t bitvector = 0, b_ix = 0; >>>>> + for (f_ix = 0; f_ix != num_fns; f_ix++) >>>>> + { >>>>> + if (zero_counts[f_ix]) >>>>> + bitvector |= 1 << b_ix; >>>>> + if (++b_ix == 32) >>>>> + { >>>>> + gcov_write_unsigned (bitvector); >>>>> + b_ix = 0; >>>>> + bitvector = 0; >>>>> + } >>>>> + } >>>>> + if (b_ix > 0) >>>>> + gcov_write_unsigned (bitvector); >>>>> +} >>>>> + >>>>> /* Write build_info strings from GI_PTR to a gcda file starting from >>>>> its current >>>>> location. */ >>>>> >>>>> @@ -758,7 +824,7 @@ gcov_write_func_counters (struct gcov_info *gi_ptr >>>>> if (gfi_ptr && gfi_ptr->key == gi_ptr) >>>>> length = GCOV_TAG_FUNCTION_LENGTH; >>>>> else >>>>> - length = 0; >>>>> + length = 0; >>>>> } >>>>> >>>>> gcov_write_tag_length (GCOV_TAG_FUNCTION, length); >>>>> @@ -1104,9 +1170,24 @@ gcov_dump_module_info (struct gcov_filename_aux *g >>>>> { >>>>> struct gcov_info *gi_ptr; >>>>> >>>>> + unsigned max_module_id = 0; >>>>> + for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next) >>>>> + { >>>>> + unsigned mod_id = gi_ptr->mod_info->ident; >>>>> + if (max_module_id < mod_id) >>>>> + max_module_id = mod_id; >>>>> + } >>>>> + int **zero_counts = (int **) xcalloc (max_module_id, sizeof (int *)); >>>>> + for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next) >>>>> + { >>>>> + unsigned mod_id = gi_ptr->mod_info->ident; >>>>> + zero_counts[mod_id-1] = (int *) xcalloc (gi_ptr->n_functions, >>>>> + sizeof (int)); >>>>> + } >>>>> + >>>>> /* Compute the module groups and record whether there were any >>>>> counter fixups applied that require rewriting the counters. */ >>>>> - int changed = __gcov_compute_module_groups (); >>>>> + int changed = __gcov_compute_module_groups (zero_counts); >>>>> >>>>> /* Now write out module group info. */ >>>>> for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next) >>>>> @@ -1129,8 +1210,15 @@ gcov_dump_module_info (struct gcov_filename_aux *g >>>>> gcov_position_t eof_pos = gi_ptr->eof_pos; >>>>> gcov_rewrite (); >>>>> gcov_seek (summary_end_pos); >>>>> + >>>>> + unsigned mod_id = gi_ptr->mod_info->ident; >>>>> + gcov_write_comdat_zero_fixup (zero_counts[mod_id-1], >>>>> + gi_ptr->n_functions); >>>>> + gcov_position_t zero_fixup_eof_pos = gcov_position (); >>>>> + >>>>> gcov_write_func_counters (gi_ptr); >>>>> - gcc_assert (eof_pos == gi_ptr->eof_pos); >>>>> + gcc_assert (eof_pos + (zero_fixup_eof_pos - >>>>> summary_end_pos) >>>>> + == gi_ptr->eof_pos); >>>>> } >>>>> } >>>>> else >>>>> @@ -1149,7 +1237,11 @@ gcov_dump_module_info (struct gcov_filename_aux *g >>>>> "profiling:%s:Error writing\n", >>>>> gi_filename); >>>>> gcov_write_import_file (gi_filename, gi_ptr); >>>>> + free (zero_counts[gi_ptr->mod_info->ident-1]); >>>>> } >>>>> + >>>>> + free (zero_counts); >>>>> + >>>>> __gcov_finalize_dyn_callgraph (); >>>>> } >>>>> >>>>> Index: libgcc/libgcov.h >>>>> =================================================================== >>>>> --- libgcc/libgcov.h (revision 215230) >>>>> +++ libgcc/libgcov.h (working copy) >>>>> @@ -349,6 +349,9 @@ gcov_get_sorted_import_module_array (struct gcov_i >>>>> ATTRIBUTE_HIDDEN; >>>>> GCOV_LINKAGE inline void gcov_rewrite (void); >>>>> >>>>> +extern void set_gcov_fn_fixed_up (int fixed_up); >>>>> +extern int get_gcov_fn_fixed_up (void); >>>>> + >>>>> /* "Counts" stored in gcda files can be a real counter value, or >>>>> an target address. When differentiate these two types because >>>>> when manipulating counts, we should only change real counter values, >>>>> @@ -361,7 +364,13 @@ gcov_get_counter (void) >>>>> /* This version is for reading count values in libgcov runtime: >>>>> we read from gcda files. */ >>>>> >>>>> - return gcov_read_counter (); >>>>> + if (get_gcov_fn_fixed_up ()) >>>>> + { >>>>> + gcov_read_counter (); >>>>> + return 0; >>>>> + } >>>>> + else >>>>> + return gcov_read_counter (); >>>>> #else >>>>> /* This version is for gcov-tool. We read the value from memory and >>>>> multiply it by the merge weight. */ >>>>> @@ -380,7 +389,13 @@ gcov_get_counter_target (void) >>>>> /* This version is for reading count target values in libgcov runtime: >>>>> we read from gcda files. */ >>>>> >>>>> - return gcov_read_counter (); >>>>> + if (get_gcov_fn_fixed_up ()) >>>>> + { >>>>> + gcov_read_counter (); >>>>> + return 0; >>>>> + } >>>>> + else >>>>> + return gcov_read_counter (); >>>>> #else >>>>> /* This version is for gcov-tool. We read the value from memory >>>>> and we do NOT >>>>> multiply it by the merge weight. */ >>>>> Index: libgcc/libgcov-util.c >>>>> =================================================================== >>>>> --- libgcc/libgcov-util.c (revision 215230) >>>>> +++ libgcc/libgcov-util.c (working copy) >>>>> @@ -66,6 +66,7 @@ static void tag_lines (unsigned, unsigned); >>>>> static void tag_counters (unsigned, unsigned); >>>>> static void tag_summary (unsigned, unsigned); >>>>> static void tag_module_info (unsigned, unsigned); >>>>> +static void tag_zero_fixup (unsigned, unsigned); >>>>> >>>>> /* The gcov_info for the first module. */ >>>>> static struct gcov_info *curr_gcov_info; >>>>> @@ -88,6 +89,8 @@ static int k_ctrs_types; >>>>> /* The longest length of all the filenames. */ >>>>> static int max_filename_len; >>>>> >>>>> +static int *zero_fixup_flags = NULL; >>>>> + >>>>> /* Merge functions for counters. Similar to __gcov_dyn_ipa_merge_* >>>>> functions in dyn-ipa.c, which were derived from these, except >>>>> the versions in dyn-ipa are used when merging from another array. */ >>>>> @@ -143,6 +146,7 @@ static const tag_format_t tag_table[] = >>>>> {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary}, >>>>> {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary}, >>>>> {GCOV_TAG_MODULE_INFO, "MODULE INFO", tag_module_info}, >>>>> + {GCOV_TAG_COMDAT_ZERO_FIXUP, "ZERO FIXUP", tag_zero_fixup}, >>>>> {0, NULL, NULL} >>>>> }; >>>>> >>>>> @@ -169,14 +173,18 @@ tag_function (unsigned tag ATTRIBUTE_UNUSED, unsig >>>>> k_ctrs[i].num = 0; >>>>> k_ctrs_types = 0; >>>>> >>>>> + if (zero_fixup_flags) >>>>> + { >>>>> + set_gcov_fn_fixed_up (zero_fixup_flags[num_fn_info]); >>>>> + if (get_gcov_fn_fixed_up () && verbose) >>>>> + fprintf (stderr, "Function id=%d fixed up\n", >>>>> curr_fn_info->ident); >>>>> + } >>>>> + >>>>> curr_fn_info->key = curr_gcov_info; >>>>> curr_fn_info->ident = gcov_read_unsigned (); >>>>> curr_fn_info->lineno_checksum = gcov_read_unsigned (); >>>>> curr_fn_info->cfg_checksum = gcov_read_unsigned (); >>>>> num_fn_info++; >>>>> - >>>>> - if (verbose) >>>>> - fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident); >>>>> } >>>>> >>>>> /* Handler for reading block tag. */ >>>>> @@ -226,7 +234,13 @@ tag_counters (unsigned tag, unsigned length) >>>>> gcc_assert (values); >>>>> >>>>> for (ix = 0; ix != n_counts; ix++) >>>>> - values[ix] = gcov_read_counter (); >>>>> + { >>>>> + gcov_type val = gcov_read_counter (); >>>>> + if (!get_gcov_fn_fixed_up ()) >>>>> + values[ix] = val; >>>>> + else >>>>> + values[ix] = 0; >>>>> + } >>>>> } >>>>> >>>>> /* Handler for reading summary tag. */ >>>>> @@ -323,7 +337,7 @@ lipo_process_substitute_string_1 (char *input_str, >>>>> char *t; >>>>> >>>>> if (verbose) >>>>> - printf ("Substitute: %s \n", input_str); >>>>> + fprintf (stderr, "Substitute: %s \n", input_str); >>>>> t = (char*) xmalloc (strlen (input_str) + 1 >>>>> + strlen (new_str) - strlen (cur_str)); >>>>> *p = 0; >>>>> @@ -332,7 +346,7 @@ lipo_process_substitute_string_1 (char *input_str, >>>>> strcat (t, new_str); >>>>> strcat (t, p + strlen (cur_str)); >>>>> if (verbose) >>>>> - printf (" --> %s\n", t); >>>>> + fprintf (stderr, " --> %s\n", t); >>>>> return t; >>>>> } >>>>> >>>>> @@ -397,6 +411,16 @@ tag_module_info (unsigned tag ATTRIBUTE_UNUSED, un >>>>> free (mod_info); >>>>> } >>>>> >>>>> +/* Handler for reading the COMDAT zero-profile fixup section. */ >>>>> + >>>>> +static void >>>>> +tag_zero_fixup (unsigned tag ATTRIBUTE_UNUSED, unsigned length) >>>>> +{ >>>>> + gcov_unsigned_t num_fns = 0; >>>>> + zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fns); >>>>> + gcc_assert (zero_fixup_flags); >>>>> +} >>>>> + >>>>> /* Read the content of a gcda file FILENAME, and return a gcov_info >>>>> data structure. >>>>> Program level summary CURRENT_SUMMARY will also be updated. */ >>>>> >>>>> @@ -520,6 +544,7 @@ read_gcda_file (const char *filename) >>>>> } >>>>> >>>>> read_gcda_finalize (obj_info); >>>>> + free (zero_fixup_flags); >>>>> gcov_close (); >>>>> >>>>> return obj_info; >>>>> @@ -1099,7 +1124,7 @@ gcov_profile_scale (struct gcov_info *profile, flo >>>>> unsigned f_ix; >>>>> >>>>> if (verbose) >>>>> - fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, >>>>> d); >>>>> + fnotice (stderr, "scale_factor is %f or %d/%d\n", scale_factor, n, >>>>> d); >>>>> >>>>> /* Scaling the counters. */ >>>>> for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next) >>>>> @@ -1167,7 +1192,7 @@ gcov_profile_normalize (struct gcov_info *profile, >>>>> scale_factor = (float)max_val / curr_max_val; >>>>> #if !defined (_WIN32) >>>>> if (verbose) >>>>> - fnotice (stdout, "max_val is %lld\n", (long long) curr_max_val); >>>>> + fnotice (stderr, "max_val is %lld\n", (long long) curr_max_val); >>>>> #endif >>>>> >>>>> return gcov_profile_scale (profile, scale_factor, 0, 0); >>>>> >>>>> -- >>>>> Teresa Johnson | Software Engineer | tejohn...@google.com | 408-460-2413 >>> >>> >>> >>> -- >>> Teresa Johnson | Software Engineer | tejohn...@google.com | 408-460-2413 > > > > -- > Teresa Johnson | Software Engineer | tejohn...@google.com | 408-460-2413