diff mbox

Fix summary generation with fork

Message ID 20131118221547.GA2555@kam.mff.cuni.cz
State New
Headers show

Commit Message

Jan Hubicka Nov. 18, 2013, 10:15 p.m. UTC
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.

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.

Comments

Rong Xu Nov. 19, 2013, 6:23 p.m. UTC | #1
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);
diff mbox

Patch

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);