Fix summary generation with fork

Rong Xu xur@google.com
Tue Nov 19 20:14:00 GMT 2013


On Mon, Nov 18, 2013 at 2:15 PM, Jan Hubicka <hubicka@ucw.cz> wrote:
> Hi,
> this patch fixes problem we noticed with Martin Liska where gcov_dump is called
> several times per execution of firefox (on each fork and exec).  This causes
> runs to be large and makes functions executed once per program to be considered
> cold.
>
> This patch makes us to update runs just once per execution and not on each
> streaming of profile data.  While testing it I also noticed that program
> summary is now broken, since crc32 is accumulated per each dumping instead just
> once.

You are right. I forgot that gcov_exit() can be called multiple times.
Should have
initialized crc32 per gcov_exit() call.

Thanks for the fix.
>
> I believe the newly introduced static vars should go - there is nothing really
> preventing us from doing two concurent updates and also it just unnecesary
> increases to footprint of libgcov.  I converted thus all_prg and crc32 back to
> local vars.
>
> Bootstrapped/regtested x86_64-linux, comitted.
>
>         * libgcov-driver.c (get_gcov_dump_complete): Update comments.
>         (all_prg, crc32): Remove static vars.
>         (gcov_exit_compute_summary): Rewrite to return crc32; do not clear
>         all_prg.
>         (gcov_exit_merge_gcda): Add crc32 parameter.
>         (gcov_exit_merge_summary): Add crc32 and all_prg parameter;
>         do not account run if it was already accounted.
>         (gcov_exit_dump_gcov): Add crc32 and all_prg parameters.
>         (gcov_exit): Initialize all_prg; update.
> Index: libgcov-driver.c
> ===================================================================
> --- libgcov-driver.c    (revision 204945)
> +++ libgcov-driver.c    (working copy)
> @@ -96,7 +96,7 @@ static size_t gcov_max_filename = 0;
>  /* Flag when the profile has already been dumped via __gcov_dump().  */
>  static int gcov_dump_complete;
>
> -/* A global functino that get the vaule of gcov_dump_complete.  */
> +/* A global function that get the vaule of gcov_dump_complete.  */
>
>  int
>  get_gcov_dump_complete (void)
> @@ -319,12 +319,6 @@ gcov_compute_histogram (struct gcov_summ
>
>  /* summary for program.  */
>  static struct gcov_summary this_prg;
> -#if !GCOV_LOCKED
> -/* summary for all instances of program.  */
> -static struct gcov_summary all_prg;
> -#endif
> -/* crc32 for this program.  */
> -static gcov_unsigned_t crc32;
>  /* gcda filename.  */
>  static char *gi_filename;
>  /* buffer for the fn_data from another program.  */
> @@ -333,10 +327,9 @@ static struct gcov_fn_buffer *fn_buffer;
>  static struct gcov_summary_buffer *sum_buffer;
>
>  /* This funtions computes the program level summary and the histo-gram.
> -   It initializes ALL_PRG, computes CRC32, and stores the summary in
> -   THIS_PRG. All these three variables are file statics.  */
> +   It computes and returns CRC32  and stored summari in THIS_PRG.  */
>
> -static void
> +static gcov_unsigned_t
>  gcov_exit_compute_summary (void)
>  {
>    struct gcov_info *gi_ptr;
> @@ -346,10 +339,8 @@ gcov_exit_compute_summary (void)
>    int f_ix;
>    unsigned t_ix;
>    gcov_unsigned_t c_num;
> +  gcov_unsigned_t crc32 = 0;
>
> -#if !GCOV_LOCKED
> -  memset (&all_prg, 0, sizeof (all_prg));
> -#endif
>    /* Find the totals for this execution.  */
>    memset (&this_prg, 0, sizeof (this_prg));
>    for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
> @@ -391,6 +382,7 @@ gcov_exit_compute_summary (void)
>          }
>      }
>    gcov_compute_histogram (&this_prg);
> +  return crc32;
>  }
>
>  /* A struct that bundles all the related information about the
> @@ -412,7 +404,8 @@ static int
>  gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
>                        struct gcov_summary *prg_p,
>                        gcov_position_t *summary_pos_p,
> -                      gcov_position_t *eof_pos_p)
> +                      gcov_position_t *eof_pos_p,
> +                     gcov_unsigned_t crc32)
>  {
>    gcov_unsigned_t tag, length;
>    unsigned t_ix;
> @@ -652,13 +645,19 @@ gcov_exit_write_gcda (const struct gcov_
>     Return -1 on error. Return 0 on success.  */
>
>  static int
> -gcov_exit_merge_summary (const struct gcov_info *gi_ptr, struct gcov_summary *prg)
> +gcov_exit_merge_summary (const struct gcov_info *gi_ptr, struct gcov_summary *prg,
> +                        gcov_unsigned_t crc32, struct gcov_summary *all_prg)
>  {
>    struct gcov_ctr_summary *cs_prg, *cs_tprg;
> -#if !GCOV_LOCKED
> -  struct gcov_ctr_summary *cs_all;
> -#endif
>    unsigned t_ix;
> +  /* If application calls fork or exec multiple times, we end up storing
> +     profile repeadely.  We should not account this as multiple runs or
> +     functions executed once may mistakely become cold.  */
> +  static int run_accounted = 0;
> +#if !GCOV_LOCKED
> +  /* summary for all instances of program.  */
> +  struct gcov_ctr_summary *cs_all;
> +#endif
>
>    /* Merge the summaries.  */
>    for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
> @@ -668,13 +667,18 @@ gcov_exit_merge_summary (const struct gc
>
>        if (gi_ptr->merge[t_ix])
>          {
> -          if (!cs_prg->runs++)
> +         int first = !cs_prg->runs;
> +
> +         if (!run_accounted)
> +           cs_prg->runs++;
> +         run_accounted = 1;
> +          if (first)
>              cs_prg->num = cs_tprg->num;
>            cs_prg->sum_all += cs_tprg->sum_all;
>            if (cs_prg->run_max < cs_tprg->run_max)
>              cs_prg->run_max = cs_tprg->run_max;
>            cs_prg->sum_max += cs_tprg->run_max;
> -          if (cs_prg->runs == 1)
> +          if (first)
>              memcpy (cs_prg->histogram, cs_tprg->histogram,
>                     sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
>            else
> @@ -686,9 +690,8 @@ gcov_exit_merge_summary (const struct gc
>                        gi_filename);
>            return -1;
>          }
> -
>  #if !GCOV_LOCKED
> -      cs_all = &all_prg.ctrs[t_ix];
> +      cs_all = &all_prg->ctrs[t_ix];
>        if (!cs_all->runs && cs_prg->runs)
>          {
>            cs_all->num = cs_prg->num;
> @@ -697,7 +700,7 @@ gcov_exit_merge_summary (const struct gc
>            cs_all->run_max = cs_prg->run_max;
>            cs_all->sum_max = cs_prg->sum_max;
>          }
> -      else if (!all_prg.checksum
> +      else if (!all_prg->checksum
>                 /* Don't compare the histograms, which may have slight
>                    variations depending on the order they were updated
>                    due to the truncating integer divides used in the
> @@ -711,7 +714,7 @@ gcov_exit_merge_summary (const struct gc
>                 gcov_error ("profiling:%s:Data file mismatch - some "
>                             "data files may have been concurrently "
>                             "updated without locking support\n", gi_filename);
> -               all_prg.checksum = ~0u;
> +               all_prg->checksum = ~0u;
>               }
>  #endif
>      }
> @@ -729,7 +732,8 @@ gcov_exit_merge_summary (const struct gc
>     summaries separate.  */
>
>  static void
> -gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf)
> +gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf,
> +                    gcov_unsigned_t crc32, struct gcov_summary *all_prg)
>  {
>    struct gcov_summary prg; /* summary for this object over all program.  */
>    int error;
> @@ -753,7 +757,8 @@ gcov_exit_dump_gcov (struct gcov_info *g
>            gcov_error ("profiling:%s:Not a gcov data file\n", gi_filename);
>            goto read_fatal;
>          }
> -      error = gcov_exit_merge_gcda (gi_ptr, &prg, &summary_pos, &eof_pos);
> +      error = gcov_exit_merge_gcda (gi_ptr, &prg, &summary_pos, &eof_pos,
> +                                   crc32);
>        if (error == -1)
>          goto read_fatal;
>      }
> @@ -766,7 +771,7 @@ gcov_exit_dump_gcov (struct gcov_info *g
>        summary_pos = eof_pos;
>      }
>
> -  error = gcov_exit_merge_summary (gi_ptr, &prg);
> +  error = gcov_exit_merge_summary (gi_ptr, &prg, crc32, all_prg);
>    if (error == -1)
>      goto read_fatal;
>
> @@ -794,19 +799,24 @@ gcov_exit (void)
>  {
>    struct gcov_info *gi_ptr;
>    struct gcov_filename_aux gf;
> +  gcov_unsigned_t crc32;
> +  struct gcov_summary all_prg;
>
>    /* Prevent the counters from being dumped a second time on exit when the
>       application already wrote out the profile using __gcov_dump().  */
>    if (gcov_dump_complete)
>      return;
>
> -  gcov_exit_compute_summary ();
> +  crc32 = gcov_exit_compute_summary ();
>
>    allocate_filename_struct (&gf);
> +#if !GCOV_LOCKED
> +  memset (&all_prg, 0, sizeof (all_prg));
> +#endif
>
>    /* Now merge each file.  */
>    for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
> -    gcov_exit_dump_gcov (gi_ptr, &gf);
> +    gcov_exit_dump_gcov (gi_ptr, &gf, crc32, &all_prg);
>
>    if (gi_filename)
>      free (gi_filename);



More information about the Gcc-patches mailing list