This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [GOOGLE] Fix LIPO COMDAT fixup and gcov-tool interactions
- From: Xinliang David Li <davidxl at google dot com>
- To: Teresa Johnson <tejohnson at google dot com>
- Cc: "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>, Rong Xu <xur at google dot com>
- Date: Tue, 16 Sep 2014 08:07:26 -0700
- Subject: Re: [GOOGLE] Fix LIPO COMDAT fixup and gcov-tool interactions
- Authentication-results: sourceware.org; auth=none
- References: <CAAe5K+UWHKvyeo9o1t16KsAn54A8FObES-sXnXT5Vycj_mTv7g at mail dot gmail dot com> <CAAkRFZLWYxy=q1xdRqSimHdDPye8++j1OVBEEOBdVOSa8iJkcA at mail dot gmail dot com> <CAAe5K+WJ3HiHxSoB+-qpXPM7gUkDTWAA6wDBWZyquCm2i4BQwA at mail dot gmail dot com>
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.
David
On Tue, Sep 16, 2014 at 7:57 AM, Teresa Johnson <tejohnson@google.com> wrote:
> On Mon, Sep 15, 2014 at 9:29 PM, Xinliang David Li <davidxl@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 <tejohnson@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 <tejohnson@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 | tejohnson@google.com | 408-460-2413
>
>
>
> --
> Teresa Johnson | Software Engineer | tejohnson@google.com | 408-460-2413