This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Compute and emit working set information from gcov-dump (issue6940061)


Ping. Thanks, Teresa

On Fri, Dec 14, 2012 at 6:11 PM, Teresa Johnson <tejohnson@google.com> wrote:
> This patch enables the gcov-dump tool to optionally compute and dump
> the working set information from the counter histogram, via a new -w option.
> This is useful to help understand and tune how the compiler will use
> the counter histogram, since it first computes the working set and selects
> thresholds based on that.
>
> This required moving the bulk of the compute_working_sets functionality
> into gcov-io.c so that it was accessible by gcov-dump.c.
>
> Bootstrapped and tested on x86_64-unknown-linux-gnu, and tested with various
> gcda files. Ok for trunk?
>
> 2012-12-14  Teresa Johnson  <tejohnson@google.com>
>
>         * lto-cgraph.c (input_symtab): Replace call to compute_working_sets
>         to get_working_sets.
>         * gcov-io.c (compute_working_sets): Moved most of body of old
>         compute_working_sets here from profile.c.
>         * gcov-io.h (NUM_GCOV_WORKING_SETS): Moved here from profile.c.
>         (gcov_working_set_t): Moved typedef here from basic-block.h
>         (compute_working_set): Declare.
>         * profile.c (NUM_GCOV_WORKING_SETS): Moved to gcov-io.h.
>         (get_working_sets): Renamed from compute_working_set,
>         replace most of body with call to new compute_working_sets.
>         (get_exec_counts): Replace call to compute_working_sets
>         to get_working_sets.
>         * profile.h (get_working_sets): Renamed from
>         compute_working_set.
>         * basic-block.h (gcov_working_set_t): Moved to gcov-io.h.
>         * gcov-dump.c (dump_working_sets): New function.
>
> Index: lto-cgraph.c
> ===================================================================
> --- lto-cgraph.c        (revision 194502)
> +++ lto-cgraph.c        (working copy)
> @@ -1457,7 +1457,7 @@ input_symtab (void)
>      }
>
>    merge_profile_summaries (file_data_vec);
> -  compute_working_sets ();
> +  get_working_sets ();
>
>
>    /* Clear out the aux field that was used to store enough state to
> Index: gcov-io.c
> ===================================================================
> --- gcov-io.c   (revision 194502)
> +++ gcov-io.c   (working copy)
> @@ -806,3 +806,110 @@ static void gcov_histogram_merge (gcov_bucket_type
>    memcpy(tgt_histo, tmp_histo, sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
>  }
>  #endif /* !IN_GCOV */
> +
> +/* This is used by gcov-dump (IN_GCOV == -1) and in the compiler
> +   (!IN_GCOV && !IN_LIBGCOV).  */
> +#if IN_GCOV <= 0 && !IN_LIBGCOV
> +/* Compute the working set information from the counter histogram in
> +   the profile summary. This is an array of information corresponding to a
> +   range of percentages of the total execution count (sum_all), and includes
> +   the number of counters required to cover that working set percentage and
> +   the minimum counter value in that working set.  */
> +
> +GCOV_LINKAGE void
> +compute_working_sets (const struct gcov_ctr_summary *summary,
> +                      gcov_working_set_t *gcov_working_sets)
> +{
> +  gcov_type working_set_cum_values[NUM_GCOV_WORKING_SETS];
> +  gcov_type ws_cum_hotness_incr;
> +  gcov_type cum, tmp_cum;
> +  const gcov_bucket_type *histo_bucket;
> +  unsigned ws_ix, c_num, count;
> +  int h_ix;
> +
> +  /* Compute the amount of sum_all that the cumulative hotness grows
> +     by in each successive working set entry, which depends on the
> +     number of working set entries.  */
> +  ws_cum_hotness_incr = summary->sum_all / NUM_GCOV_WORKING_SETS;
> +
> +  /* Next fill in an array of the cumulative hotness values corresponding
> +     to each working set summary entry we are going to compute below.
> +     Skip 0% statistics, which can be extrapolated from the
> +     rest of the summary data.  */
> +  cum = ws_cum_hotness_incr;
> +  for (ws_ix = 0; ws_ix < NUM_GCOV_WORKING_SETS;
> +       ws_ix++, cum += ws_cum_hotness_incr)
> +    working_set_cum_values[ws_ix] = cum;
> +  /* The last summary entry is reserved for (roughly) 99.9% of the
> +     working set. Divide by 1024 so it becomes a shift, which gives
> +     almost exactly 99.9%.  */
> +  working_set_cum_values[NUM_GCOV_WORKING_SETS-1]
> +      = summary->sum_all - summary->sum_all/1024;
> +
> +  /* Next, walk through the histogram in decending order of hotness
> +     and compute the statistics for the working set summary array.
> +     As histogram entries are accumulated, we check to see which
> +     working set entries have had their expected cum_value reached
> +     and fill them in, walking the working set entries in increasing
> +     size of cum_value.  */
> +  ws_ix = 0; /* The current entry into the working set array.  */
> +  cum = 0; /* The current accumulated counter sum.  */
> +  count = 0; /* The current accumulated count of block counters.  */
> +  for (h_ix = GCOV_HISTOGRAM_SIZE - 1;
> +       h_ix >= 0 && ws_ix < NUM_GCOV_WORKING_SETS; h_ix--)
> +    {
> +      histo_bucket = &summary->histogram[h_ix];
> +
> +      /* If we haven't reached the required cumulative counter value for
> +         the current working set percentage, simply accumulate this histogram
> +         entry into the running sums and continue to the next histogram
> +         entry.  */
> +      if (cum + histo_bucket->cum_value < working_set_cum_values[ws_ix])
> +        {
> +          cum += histo_bucket->cum_value;
> +          count += histo_bucket->num_counters;
> +          continue;
> +        }
> +
> +      /* If adding the current histogram entry's cumulative counter value
> +         causes us to exceed the current working set size, then estimate
> +         how many of this histogram entry's counter values are required to
> +         reach the working set size, and fill in working set entries
> +         as we reach their expected cumulative value.  */
> +      for (c_num = 0, tmp_cum = cum;
> +           c_num < histo_bucket->num_counters && ws_ix < NUM_GCOV_WORKING_SETS;
> +           c_num++)
> +        {
> +          count++;
> +          /* If we haven't reached the last histogram entry counter, add
> +             in the minimum value again. This will underestimate the
> +             cumulative sum so far, because many of the counter values in this
> +             entry may have been larger than the minimum. We could add in the
> +             average value every time, but that would require an expensive
> +             divide operation.  */
> +          if (c_num + 1 < histo_bucket->num_counters)
> +            tmp_cum += histo_bucket->min_value;
> +          /* If we have reached the last histogram entry counter, then add
> +             in the entire cumulative value.  */
> +          else
> +            tmp_cum = cum + histo_bucket->cum_value;
> +
> +         /* Next walk through successive working set entries and fill in
> +            the statistics for any whose size we have reached by accumulating
> +            this histogram counter.  */
> +         while (ws_ix < NUM_GCOV_WORKING_SETS
> +                && tmp_cum >= working_set_cum_values[ws_ix])
> +            {
> +              gcov_working_sets[ws_ix].num_counters = count;
> +              gcov_working_sets[ws_ix].min_counter
> +                  = histo_bucket->min_value;
> +              ws_ix++;
> +            }
> +        }
> +      /* Finally, update the running cumulative value since we were
> +         using a temporary above.  */
> +      cum += histo_bucket->cum_value;
> +    }
> +  gcc_assert (ws_ix == NUM_GCOV_WORKING_SETS);
> +}
> +#endif /* IN_GCOV <= 0 && !IN_LIBGCOV */
> Index: gcov-io.h
> ===================================================================
> --- gcov-io.h   (revision 194502)
> +++ gcov-io.h   (working copy)
> @@ -618,6 +618,28 @@ GCOV_LINKAGE gcov_position_t gcov_write_tag (gcov_
>  GCOV_LINKAGE void gcov_write_length (gcov_position_t /*position*/);
>  #endif
>
> +#if IN_GCOV <= 0 && !IN_LIBGCOV
> +/* Available in gcov-dump and the compiler.  */
> +
> +/* Number of data points in the working set summary array. Using 128
> +   provides information for at least every 1% increment of the total
> +   profile size. The last entry is hardwired to 99.9% of the total.  */
> +#define NUM_GCOV_WORKING_SETS 128
> +
> +/* Working set size statistics for a given percentage of the entire
> +   profile (sum_all from the counter summary).  */
> +typedef struct gcov_working_set_info
> +{
> +  /* Number of hot counters included in this working set.  */
> +  unsigned num_counters;
> +  /* Smallest counter included in this working set.  */
> +  gcov_type min_counter;
> +} gcov_working_set_t;
> +
> +GCOV_LINKAGE void compute_working_sets (const struct gcov_ctr_summary *summary,
> +                                        gcov_working_set_t *gcov_working_sets);
> +#endif
> +
>  #if IN_GCOV > 0
>  /* Available in gcov */
>  GCOV_LINKAGE time_t gcov_time (void);
> Index: profile.c
> ===================================================================
> --- profile.c   (revision 194502)
> +++ profile.c   (working copy)
> @@ -84,11 +84,6 @@ struct bb_info {
>
>  const struct gcov_ctr_summary *profile_info;
>
> -/* Number of data points in the working set summary array. Using 128
> -   provides information for at least every 1% increment of the total
> -   profile size. The last entry is hardwired to 99.9% of the total.  */
> -#define NUM_GCOV_WORKING_SETS 128
> -
>  /* Counter working set information computed from the current counter
>     summary. Not initialized unless profile_info summary is non-NULL.  */
>  static gcov_working_set_t gcov_working_sets[NUM_GCOV_WORKING_SETS];
> @@ -208,104 +203,16 @@ instrument_values (histogram_values values)
>     the minimum counter value in that working set.  */
>
>  void
> -compute_working_sets (void)
> +get_working_sets (void)
>  {
> -  gcov_type working_set_cum_values[NUM_GCOV_WORKING_SETS];
> -  gcov_type ws_cum_hotness_incr;
> -  gcov_type cum, tmp_cum;
> -  const gcov_bucket_type *histo_bucket;
> -  unsigned ws_ix, c_num, count, pctinc, pct;
> -  int h_ix;
> +  unsigned ws_ix, pctinc, pct;
>    gcov_working_set_t *ws_info;
>
>    if (!profile_info)
>      return;
>
> -  /* Compute the amount of sum_all that the cumulative hotness grows
> -     by in each successive working set entry, which depends on the
> -     number of working set entries.  */
> -  ws_cum_hotness_incr = profile_info->sum_all / NUM_GCOV_WORKING_SETS;
> +  compute_working_sets (profile_info, gcov_working_sets);
>
> -  /* Next fill in an array of the cumulative hotness values corresponding
> -     to each working set summary entry we are going to compute below.
> -     Skip 0% statistics, which can be extrapolated from the
> -     rest of the summary data.  */
> -  cum = ws_cum_hotness_incr;
> -  for (ws_ix = 0; ws_ix < NUM_GCOV_WORKING_SETS;
> -       ws_ix++, cum += ws_cum_hotness_incr)
> -    working_set_cum_values[ws_ix] = cum;
> -  /* The last summary entry is reserved for (roughly) 99.9% of the
> -     working set. Divide by 1024 so it becomes a shift, which gives
> -     almost exactly 99.9%.  */
> -  working_set_cum_values[NUM_GCOV_WORKING_SETS-1]
> -      = profile_info->sum_all - profile_info->sum_all/1024;
> -
> -  /* Next, walk through the histogram in decending order of hotness
> -     and compute the statistics for the working set summary array.
> -     As histogram entries are accumulated, we check to see which
> -     working set entries have had their expected cum_value reached
> -     and fill them in, walking the working set entries in increasing
> -     size of cum_value.  */
> -  ws_ix = 0; /* The current entry into the working set array.  */
> -  cum = 0; /* The current accumulated counter sum.  */
> -  count = 0; /* The current accumulated count of block counters.  */
> -  for (h_ix = GCOV_HISTOGRAM_SIZE - 1;
> -       h_ix >= 0 && ws_ix < NUM_GCOV_WORKING_SETS; h_ix--)
> -    {
> -      histo_bucket = &profile_info->histogram[h_ix];
> -
> -      /* If we haven't reached the required cumulative counter value for
> -         the current working set percentage, simply accumulate this histogram
> -         entry into the running sums and continue to the next histogram
> -         entry.  */
> -      if (cum + histo_bucket->cum_value < working_set_cum_values[ws_ix])
> -        {
> -          cum += histo_bucket->cum_value;
> -          count += histo_bucket->num_counters;
> -          continue;
> -        }
> -
> -      /* If adding the current histogram entry's cumulative counter value
> -         causes us to exceed the current working set size, then estimate
> -         how many of this histogram entry's counter values are required to
> -         reach the working set size, and fill in working set entries
> -         as we reach their expected cumulative value.  */
> -      for (c_num = 0, tmp_cum = cum;
> -           c_num < histo_bucket->num_counters && ws_ix < NUM_GCOV_WORKING_SETS;
> -           c_num++)
> -        {
> -          count++;
> -          /* If we haven't reached the last histogram entry counter, add
> -             in the minimum value again. This will underestimate the
> -             cumulative sum so far, because many of the counter values in this
> -             entry may have been larger than the minimum. We could add in the
> -             average value every time, but that would require an expensive
> -             divide operation.  */
> -          if (c_num + 1 < histo_bucket->num_counters)
> -            tmp_cum += histo_bucket->min_value;
> -          /* If we have reached the last histogram entry counter, then add
> -             in the entire cumulative value.  */
> -          else
> -            tmp_cum = cum + histo_bucket->cum_value;
> -
> -         /* Next walk through successive working set entries and fill in
> -            the statistics for any whose size we have reached by accumulating
> -            this histogram counter.  */
> -         while (ws_ix < NUM_GCOV_WORKING_SETS
> -                && tmp_cum >= working_set_cum_values[ws_ix])
> -            {
> -              gcov_working_sets[ws_ix].num_counters = count;
> -              gcov_working_sets[ws_ix].min_counter
> -                  = histo_bucket->min_value;
> -              ws_ix++;
> -            }
> -        }
> -      /* Finally, update the running cumulative value since we were
> -         using a temporary above.  */
> -      cum += histo_bucket->cum_value;
> -    }
> -  gcc_assert (ws_ix == NUM_GCOV_WORKING_SETS);
> -
>    if (dump_file)
>      {
>        fprintf (dump_file, "Counter working sets:\n");
> @@ -374,7 +281,7 @@ get_exec_counts (unsigned cfg_checksum, unsigned l
>    if (!counts)
>      return NULL;
>
> -  compute_working_sets();
> +  get_working_sets();
>
>    if (dump_file && profile_info)
>      fprintf(dump_file, "Merged %u profiles with maximal count %u.\n",
> Index: profile.h
> ===================================================================
> --- profile.h   (revision 194502)
> +++ profile.h   (working copy)
> @@ -47,6 +47,6 @@ extern gcov_type sum_edge_counts (vec<edge, va_gc>
>  extern void init_node_map (void);
>  extern void del_node_map (void);
>
> -extern void compute_working_sets (void);
> +extern void get_working_sets (void);
>
>  #endif /* PROFILE_H */
> Index: basic-block.h
> ===================================================================
> --- basic-block.h       (revision 194502)
> +++ basic-block.h       (working copy)
> @@ -88,16 +88,6 @@ enum cfg_edge_flags {
>     profile.c.  */
>  extern const struct gcov_ctr_summary *profile_info;
>
> -/* Working set size statistics for a given percentage of the entire
> -   profile (sum_all from the counter summary).  */
> -typedef struct gcov_working_set_info
> -{
> -  /* Number of hot counters included in this working set.  */
> -  unsigned num_counters;
> -  /* Smallest counter included in this working set.  */
> -  gcov_type min_counter;
> -} gcov_working_set_t;
> -
>  /* Structure to gather statistic about profile consistency, per pass.
>     An array of this structure, indexed by pass static number, is allocated
>     in passes.c.  The structure is defined here so that different CFG modes
> @@ -934,6 +924,7 @@ extern void rtl_profile_for_edge (edge);
>  extern void default_rtl_profile (void);
>
>  /* In profile.c.  */
> +typedef struct gcov_working_set_info gcov_working_set_t;
>  extern gcov_working_set_t *find_working_set(unsigned pct_times_10);
>
>  /* Check tha probability is sane.  */
> Index: gcov-dump.c
> ===================================================================
> --- gcov-dump.c (revision 194502)
> +++ gcov-dump.c (working copy)
> @@ -39,6 +39,8 @@ static void tag_arcs (const char *, unsigned, unsi
>  static void tag_lines (const char *, unsigned, unsigned);
>  static void tag_counters (const char *, unsigned, unsigned);
>  static void tag_summary (const char *, unsigned, unsigned);
> +static void dump_working_sets (const char *filename ATTRIBUTE_UNUSED,
> +                               const struct gcov_ctr_summary *summary);
>  extern int main (int, char **);
>
>  typedef struct tag_format
> @@ -50,6 +52,7 @@ typedef struct tag_format
>
>  static int flag_dump_contents = 0;
>  static int flag_dump_positions = 0;
> +static int flag_dump_working_sets = 0;
>
>  static const struct option options[] =
>  {
> @@ -57,6 +60,7 @@ static const struct option options[] =
>    { "version",              no_argument,       NULL, 'v' },
>    { "long",                 no_argument,       NULL, 'l' },
>    { "positions",           no_argument,       NULL, 'o' },
> +  { "working-sets",        no_argument,       NULL, 'w' },
>    { 0, 0, 0, 0 }
>  };
>
> @@ -94,7 +98,7 @@ main (int argc ATTRIBUTE_UNUSED, char **argv)
>
>    diagnostic_initialize (global_dc, 0);
>
> -  while ((opt = getopt_long (argc, argv, "hlpv", options, NULL)) != -1)
> +  while ((opt = getopt_long (argc, argv, "hlpvw", options, NULL)) != -1)
>      {
>        switch (opt)
>         {
> @@ -110,6 +114,9 @@ main (int argc ATTRIBUTE_UNUSED, char **argv)
>         case 'p':
>           flag_dump_positions = 1;
>           break;
> +       case 'w':
> +         flag_dump_working_sets = 1;
> +         break;
>         default:
>           fprintf (stderr, "unknown flag `%c'\n", opt);
>         }
> @@ -129,6 +136,7 @@ print_usage (void)
>    printf ("  -v, --version        Print version number\n");
>    printf ("  -l, --long           Dump record contents too\n");
>    printf ("  -p, --positions      Dump record positions\n");
> +  printf ("  -w, --working-sets   Dump working set computed from summary\n");
>  }
>
>  static void
> @@ -485,5 +493,39 @@ tag_summary (const char *filename ATTRIBUTE_UNUSED
>                (HOST_WIDEST_INT)histo_bucket->min_value,
>                (HOST_WIDEST_INT)histo_bucket->cum_value);
>          }
> +      if (flag_dump_working_sets)
> +        dump_working_sets (filename, &summary.ctrs[ix]);
>      }
>  }
> +
> +static void
> +dump_working_sets (const char *filename ATTRIBUTE_UNUSED,
> +                   const struct gcov_ctr_summary *summary)
> +{
> +  gcov_working_set_t gcov_working_sets[NUM_GCOV_WORKING_SETS];
> +  unsigned ws_ix, pctinc, pct;
> +  gcov_working_set_t *ws_info;
> +
> +  compute_working_sets (summary, gcov_working_sets);
> +
> +  printf ("\n");
> +  print_prefix (filename, 0, 0);
> +  printf ("\t\tcounter working sets:");
> +  /* Multiply the percentage by 100 to avoid float.  */
> +  pctinc = 100 * 100 / NUM_GCOV_WORKING_SETS;
> +  for (ws_ix = 0, pct = pctinc; ws_ix < NUM_GCOV_WORKING_SETS;
> +       ws_ix++, pct += pctinc)
> +    {
> +      if (ws_ix == NUM_GCOV_WORKING_SETS - 1)
> +        pct = 9990;
> +      ws_info = &gcov_working_sets[ws_ix];
> +      /* Print out the percentage using int arithmatic to avoid float.  */
> +      printf ("\n");
> +      print_prefix (filename, 0, 0);
> +      printf ("\t\t%u.%02u%%: num counts=%u, min counter="
> +               HOST_WIDEST_INT_PRINT_DEC,
> +               pct / 100, pct - (pct / 100 * 100),
> +               ws_info->num_counters,
> +               (HOST_WIDEST_INT)ws_info->min_counter);
> +    }
> +}
>
> --
> This patch is available for review at http://codereview.appspot.com/6940061



-- 
Teresa Johnson | Software Engineer | tejohnson@google.com | 408-460-2413


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]