On 10/11/25 11:19, Dhruv Chawla wrote:
External email: Use caution opening links or attachments


On 30/10/25 11:17, Dhruv Chawla wrote:
External email: Use caution opening links or attachments


On 22/10/25 13:38, [email protected] wrote:
External email: Use caution opening links or attachments


From: Dhruv Chawla <[email protected]>

This patch aims to implement summary support in auto-profile, similar to
LLVM. The summary information stores various information about the
profile being read such as the number of functions, the maximum sample
count, the total number of samples and so on.

It also adds a section called the "detailed summary" which contains a
histogram-based calculation of the minimum execution count for a sample
needed to belong to a specific percentile of samples. This is used to
decide the hot count threshold (which can be controlled with a command
line parameter). The default is any sample belonging to the 99th percentile
being marked as hot.

Signed-off-by: Dhruv Chawla <[email protected]>

gcc/ChangeLog:

         * auto-profile.cc (AUTO_PROFILE_VERSION): Update to 3 from 2.
         (maybe_hot_afdo_count_p): Fix typo
         afdo_hot_bb_threshod -> afdo_hot_bb_threshold.
         (struct summary_info): New struct.
         (summary_info::read): New function.
         (summary_info::get_threshold_count): Likewise.
         (function_instance::read_function_instance): Read
         afdo_profile_info->sum_max directly from summary info.
         (autofdo_source_profile::read): Set afdo_hot_bb_threshold from
         param_hot_bb_count_ws_permille.
         (read_profile): Call summary_info->read.
         (end_auto_profile): Free afdo_summary_info.
         * gcov-io.h (GCOV_TAG_AFDO_SUMMARY): New define.

gcc/c/ChangeLog:

         * Make-lang.in: Update GCOV version to 3.

gcc/cp/ChangeLog:

         * Make-lang.in: Update GCOV version to 3.

gcc/lto/ChangeLog:

         * Make-lang.in: Update GCOV version to 3.

gcc/testsuite/ChangeLog:

         * lib/profopt.exp: Update GCOV version to 3.
---
  gcc/auto-profile.cc           | 135 ++++++++++++++++++++++++++++------
  gcc/c/Make-lang.in            |   4 +-
  gcc/cp/Make-lang.in           |   4 +-
  gcc/gcov-io.h                 |   2 +
  gcc/lto/Make-lang.in          |   4 +-
  gcc/testsuite/lib/profopt.exp |   2 +-
  6 files changed, 123 insertions(+), 28 deletions(-)

diff --git a/gcc/auto-profile.cc b/gcc/auto-profile.cc
index cf7a2191336..035138accc4 100644
--- a/gcc/auto-profile.cc
+++ b/gcc/auto-profile.cc
@@ -122,18 +122,18 @@ along with GCC; see the file COPYING3.  If not see
  */

  #define DEFAULT_AUTO_PROFILE_FILE "fbdata.afdo"
-#define AUTO_PROFILE_VERSION 2
+#define AUTO_PROFILE_VERSION 3

  /* profile counts determined by AFDO smaller than afdo_hot_bb_threshold are
     considered cols.  */
-gcov_type afdo_hot_bb_threshod = -1;
+gcov_type afdo_hot_bb_threshold = -1;

  /* Return true if COUNT is possibly hot.  */
  bool
  maybe_hot_afdo_count_p (profile_count count)
  {
    gcc_checking_assert (count.ipa ().initialized_p ());
-  return count.ipa ().to_gcov_type () >= afdo_hot_bb_threshod;
+  return count.ipa ().to_gcov_type () >= afdo_hot_bb_threshold;
  }

  /* Return true if location of STMT may be expressed by debug info.  */
@@ -228,6 +228,45 @@ struct string_compare
    }
  };

+/* Store the summary information for the profile.  */
+struct summary_info
+{
+  /* There are currently 16 hard-coded percentiles in the GCOV format.  */
+  static constexpr unsigned NUM_PERCENTILES = 16;
+
+  /* The detailed summary is a histogram-based calculation of the minimum
+     execution count required to belong to a certain set of percentile of
+     counts.  */
+  struct detailed_summary
+  {
+    /* The percentile that this represents (multiplied by 1,000,000).  */
+    uint32_t cutoff;
+    /* The minimum execution count required to belong to this percentile.  */
+    uint64_t min_count;
+    /* The number of samples which belong to this percentile.  */
+    uint64_t num_counts;
+  };
+
+  /* The sum of execution counts of all samples.  */
+  uint64_t total_count;
+  /* The maximum individual count.  */
+  uint64_t max_count;
+  /* The maximum head count across all functions.  */
+  uint64_t max_function_count;
+  /* The number of lines that have samples.  */
+  uint64_t num_counts;
+  /* The number of functions that have samples.  */
+  uint64_t num_functions;
+  /* The percentile threshold information.  */
+  detailed_summary detailed_summaries[NUM_PERCENTILES];
+
+  /* Read profile.  Return TRUE on success.  */
+  bool read ();
+
+  /* Get the minimum count required for percentile CUTOFF.  */
+  uint64_t get_threshold_count (uint32_t cutoff);
+};
+
  /* Store a string array, indexed by string position in the array.  */
  class string_table
  {
@@ -592,6 +631,9 @@ private:
    auto_vec <function_instance *> duplicate_functions_;
  };

+/* Store the summary information from the GCOV file.  */
+static summary_info *afdo_summary_info;
+
  /* Store the strings read from the profile data file.  */
  static string_table *afdo_string_table;

@@ -826,6 +868,47 @@ get_relative_location_for_stmt (tree fn, gimple *stmt)
            gimple_location (stmt));
  }

+/* Member functions for summary_info.  */
+
+bool
+summary_info::read ()
+{
+  if (gcov_read_unsigned () != GCOV_TAG_AFDO_SUMMARY)
+    return false;
+
+  total_count = gcov_read_counter ();
+  max_count = gcov_read_counter ();
+  max_function_count = gcov_read_counter ();
+  num_counts = gcov_read_counter ();
+  num_functions = gcov_read_counter ();
+  uint64_t num_detailed_summaries = gcov_read_counter ();
+  gcc_checking_assert (num_detailed_summaries == NUM_PERCENTILES);
+  for (uint64_t i = 0; i < num_detailed_summaries; i++)
+    {
+      detailed_summaries[i].cutoff = gcov_read_unsigned ();
+      detailed_summaries[i].min_count = gcov_read_counter ();
+      detailed_summaries[i].num_counts = gcov_read_counter ();
+    }
+
+  return !gcov_is_error ();
+}
+
+/* Get the minimum count required for percentile CUTOFF.  */
+
+uint64_t
+summary_info::get_threshold_count (uint32_t cutoff)
+{
+  /* The cutoffs stored in the GCOV are fractions multiplied by 1,000,000.  */
+  gcc_checking_assert (cutoff < 1'000'000);
+  unsigned idx = 0;
+  /* Find the first cutoff at least as high as CUTOFF.  */
+  for (; idx < NUM_PERCENTILES; idx++)
+    if (detailed_summaries[idx].cutoff >= cutoff)
+      break;
+  idx = std::max (NUM_PERCENTILES - 1, idx);
+  return detailed_summaries[idx].min_count;
+}
+
  /* Member functions for string_table.  */

  /* Deconstructor.  */
@@ -2365,8 +2448,6 @@ function_instance::read_function_instance 
(function_instance_stack *stack,
        unsigned num_targets = gcov_read_unsigned ();
        gcov_type count = gcov_read_counter ();
        s->pos_counts[offset].count = count;
-      afdo_profile_info->sum_max = std::max (afdo_profile_info->sum_max,
-                                            count);

        for (unsigned j = 0; j < stack->length (); j++)
          (*stack)[j]->total_count_ += count;
@@ -2644,7 +2725,7 @@ autofdo_source_profile::read ()
                      "auto-profile contains duplicated function instance %s",
                      afdo_string_table->get_name (s->name ()));
      }
-  int hot_frac = param_hot_bb_count_fraction;
+  afdo_profile_info->sum_max = afdo_summary_info->max_count;
    /* Scale up the profile, but leave some bits in case some counts gets
       bigger than sum_max eventually.  */
    if (afdo_profile_info->sum_max)
@@ -2652,22 +2733,25 @@ autofdo_source_profile::read ()
        = MAX (((gcov_type)1 << (profile_count::n_bits - 10))
              / afdo_profile_info->sum_max, 1);
    afdo_profile_info->cutoff *= afdo_count_scale;
-  afdo_hot_bb_threshod
-    = hot_frac
-      ? afdo_profile_info->sum_max * afdo_count_scale / hot_frac
-      : (gcov_type)profile_count::max_count;
-  set_hot_bb_threshold (afdo_hot_bb_threshod);
+  /* Derive the hot count threshold from the profile summary.  */
+  afdo_hot_bb_threshold = afdo_summary_info->get_threshold_count (
+                           param_hot_bb_count_ws_permille * 1000)
+                         * afdo_count_scale;
+  set_hot_bb_threshold (afdo_hot_bb_threshold);
    if (dump_file)
-    fprintf (dump_file, "Max count in profile %" PRIu64 "\n"
-                       "Setting scale %" PRIu64 "\n"
-                       "Scaled max count %" PRIu64 "\n"
-                       "Cutoff %" PRIu64 "\n"
-                       "Hot count threshold %" PRIu64 "\n\n",
-            (int64_t)afdo_profile_info->sum_max,
-            (int64_t)afdo_count_scale,
-            (int64_t)(afdo_profile_info->sum_max * afdo_count_scale),
-            (int64_t)afdo_profile_info->cutoff,
-            (int64_t)afdo_hot_bb_threshod);
+    fprintf (dump_file,
+            "Max count in profile %" PRIu64 "\n"
+            "Setting scale %" PRIu64 "\n"
+            "Scaled max count %" PRIu64 "\n"
+            "Cutoff %" PRIu64 "\n"
+            "Unscaled hot count threshold %" PRIu64 "\n"
+            "Hot count threshold %" PRIu64 "\n\n",
+            (int64_t) afdo_profile_info->sum_max, (int64_t) afdo_count_scale,
+            (int64_t) (afdo_profile_info->sum_max * afdo_count_scale),
+            (int64_t) afdo_profile_info->cutoff,
+            (int64_t) afdo_summary_info->get_threshold_count (
+              param_hot_bb_count_ws_permille * 1000),
+            (int64_t) afdo_hot_bb_threshold);
    afdo_profile_info->sum_max *= afdo_count_scale;
    return true;
  }
@@ -2761,6 +2845,14 @@ read_profile (void)
    /* Skip the empty integer.  */
    gcov_read_unsigned ();

+  /* summary_info.  */
+  afdo_summary_info = new summary_info ();
+  if (!afdo_summary_info->read ())
+    {
+      error ("cannot read summary information from %s", auto_profile_file);
+      return;
+    }
+
    /* string_table.  */
    afdo_string_table = new string_table ();
    if (!afdo_string_table->read ())
@@ -4201,6 +4293,7 @@ end_auto_profile (void)
  {
    delete autofdo::afdo_source_profile;
    delete autofdo::afdo_string_table;
+  delete autofdo::afdo_summary_info;
    profile_info = NULL;
  }

diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in
index f09fc99467b..95a7dad8350 100644
--- a/gcc/c/Make-lang.in
+++ b/gcc/c/Make-lang.in
@@ -102,7 +102,7 @@ create_fdas_for_cc1: ../stage1-gcc/cc1$(exeext) 
../prev-gcc/$(PERF_DATA)
           echo $$perf_path; \
           if [ -f $$perf_path ]; then \
             profile_name=cc1_$$component_in_prev.fda; \
-           $(CREATE_GCOV) -binary ../stage1-gcc/cc1$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 2 || exit 1; \
+           $(CREATE_GCOV) -binary ../stage1-gcc/cc1$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 3 || exit 1; \
           fi; \
         done;

@@ -112,7 +112,7 @@ create_fdas_for_cc1: ../stage1-gcc/cc1$(exeext) 
../prev-gcc/$(PERF_DATA)
           echo $$perf_path; \
           if [ -f $$perf_path ]; then \
             profile_name=cc1_$$component_in_prev_target.fda; \
-           $(CREATE_GCOV) -binary ../prev-gcc/cc1$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 2 || exit 1; \
+           $(CREATE_GCOV) -binary ../prev-gcc/cc1$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 3 || exit 1; \
           fi; \
         done;

diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 70cfe2b1663..20ae96c18ed 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -201,7 +201,7 @@ create_fdas_for_cc1plus: ../stage1-gcc/cc1plus$(exeext) 
../prev-gcc/$(PERF_DATA)
           echo $$perf_path; \
           if [ -f $$perf_path ]; then \
             profile_name=cc1plus_$$component_in_prev.fda; \
-           $(CREATE_GCOV) -binary ../stage1-gcc/cc1plus$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 2 || exit 1; \
+           $(CREATE_GCOV) -binary ../stage1-gcc/cc1plus$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 3 || exit 1; \
           fi; \
         done;

@@ -211,7 +211,7 @@ create_fdas_for_cc1plus: ../stage1-gcc/cc1plus$(exeext) 
../prev-gcc/$(PERF_DATA)
           echo $$perf_path; \
           if [ -f $$perf_path ]; then \
             profile_name=cc1plus_$$component_in_prev_target.fda; \
-           $(CREATE_GCOV) -binary ../prev-gcc/cc1plus$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 2 || exit 1; \
+           $(CREATE_GCOV) -binary ../prev-gcc/cc1plus$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 3 || exit 1; \
           fi; \
         done;

diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index 313c15cecbb..7b1d93f961d 100644
--- a/gcc/gcov-io.h
+++ b/gcc/gcov-io.h
@@ -274,6 +274,8 @@ typedef uint64_t gcov_type_unsigned;
  #define GCOV_TAG_OBJECT_SUMMARY  ((gcov_unsigned_t)0xa1000000)
  #define GCOV_TAG_OBJECT_SUMMARY_LENGTH (2 * GCOV_WORD_SIZE)
  #define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t)0xa3000000) /* Obsolete */
+
+#define GCOV_TAG_AFDO_SUMMARY    ((gcov_unsigned_t)0xa8000000)
  #define GCOV_TAG_AFDO_FILE_NAMES ((gcov_unsigned_t)0xaa000000)
  #define GCOV_TAG_AFDO_FUNCTION ((gcov_unsigned_t)0xac000000)
  #define GCOV_TAG_AFDO_WORKING_SET ((gcov_unsigned_t)0xaf000000)
diff --git a/gcc/lto/Make-lang.in b/gcc/lto/Make-lang.in
index 2af8bba44ca..a24fa059a7a 100644
--- a/gcc/lto/Make-lang.in
+++ b/gcc/lto/Make-lang.in
@@ -115,7 +115,7 @@ create_fdas_for_lto1: ../stage1-gcc/lto1$(exeext) 
../prev-gcc/$(PERF_DATA)
           echo $$perf_path; \
           if [ -f $$perf_path ]; then \
             profile_name=lto1_$$component_in_prev.fda; \
-           $(CREATE_GCOV) -binary ../stage1-gcc/lto1$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 2 || exit 1; \
+           $(CREATE_GCOV) -binary ../stage1-gcc/lto1$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 3 || exit 1; \
           fi; \
         done;

@@ -125,7 +125,7 @@ create_fdas_for_lto1: ../stage1-gcc/lto1$(exeext) 
../prev-gcc/$(PERF_DATA)
           echo $$perf_path; \
           if [ -f $$perf_path ]; then \
             profile_name=lto1_$$component_in_prev_target.fda; \
-           $(CREATE_GCOV) -binary ../prev-gcc/lto1$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 2 || exit 1; \
+           $(CREATE_GCOV) -binary ../prev-gcc/lto1$(exeext) -gcov 
$$profile_name -profile $$perf_path -gcov_version 3 || exit 1; \
           fi; \
         done;

diff --git a/gcc/testsuite/lib/profopt.exp b/gcc/testsuite/lib/profopt.exp
index 81d86c632d1..0001f6798dd 100644
--- a/gcc/testsuite/lib/profopt.exp
+++ b/gcc/testsuite/lib/profopt.exp
@@ -452,7 +452,7 @@ proc profopt-execute { src } {
             # convert profile
             if { $run_autofdo == 1 } {
                  set bprefix "afdo."
-               set cmd "create_gcov --binary $execname1 
--profile=$tmpdir/$base.perf.data -gcov_version=2 --gcov=$tmpdir/$bprefix$base.$ext"
+               set cmd "create_gcov --binary $execname1 
--profile=$tmpdir/$base.perf.data --gcov_version=3 --gcov=$tmpdir/$bprefix$base.$ext"
                 verbose "Running $cmd"
                 set id [remote_spawn "" $cmd]
                 if { $id < 0 } {
--
2.44.0


Ping (https://gcc.gnu.org/pipermail/gcc-patches/2025-October/698332.html).

--
Regards,
Dhruv

Ping (https://gcc.gnu.org/pipermail/gcc-patches/2025-October/698332.html).

--
Regards,
Dhruv

Ping (https://gcc.gnu.org/pipermail/gcc-patches/2025-October/698332.html).

--
Regards,
Dhruv

Reply via email to