namaskaaram

I would like to try these tools - but first a quick question (apologies for
not scanning through all the patches)

Is there already  a performance report for a Linux kernel for  any of the
non x86/arm/risc-v  processor architectures

dhanyavaadaaha
gopi

When replying, please edit your Subject line so it is more specific
> than "Re: Contents of Gcc-patches digest..."
> Today's Topics:
>
>    1. [PATCH 36/37] [AFDO-TOOLS] Teach cc1 to read GCOV AutoFDO
>       profiles (Kugan Vivekanandarajah)
>
>
>
> ---------- Forwarded message ----------
> From: Kugan Vivekanandarajah <[email protected]>
> To: <[email protected]>
> Cc: <[email protected]>, <[email protected]>, <
> [email protected]>, <[email protected]>, <[email protected]>,
> <[email protected]>, <[email protected]>
> Bcc:
> Date: Thu, 17 Sep 2026 10:39:32 +1000
> Subject: [PATCH 36/37] [AFDO-TOOLS] Teach cc1 to read GCOV AutoFDO profiles
> From: Dhruv Chawla <[email protected]>
>
> Build libgcovreader.a from the afdo_tools GCOV reader sources and link it
> into the GCC backend so auto-profile can consume GCOV v3/v4 profiles
> produced by afdo_create:
>
>   - compile afdo-gcov-{io,reader,reader-v3,reader-v4}.o into
>     libgcovreader.a
>   - drive auto-profile.cc through the shared gcov_reader API
>   - add -fauto-profile-format= and -fauto-profile-partial
>   - document the options in invoke.texi
>   - match PHI arguments on predecessor edges (bb->preds) instead of
>     successor edges
>
> Regression tested on aarch64-linux-gnu with no new regressions.
>
> gcc/ChangeLog:
>
>         * Makefile.in (GCOVREADERLIB, GCOVREADER_OBJS): Build
>         libgcovreader.a from afdo_tools GCOV reader sources and link it
>         into the backend.
>         * auto-profile.cc: Read GCOV v3/v4 profiles through
>         libgcovreader; build afdo_source_profile from gcov_profile;
>         match PHI arguments on predecessor edges.
>         (match_with_target): Fix the symbol suffix comparison
>         loop, which never advanced.
>         * auto-profile.h: Update related declarations.
>         * common.opt (fauto-profile-format=, fauto-profile-partial): New
>         options.
>         * doc/invoke.texi: Document -fauto-profile-format and
>         -fauto-profile-partial.
>         * flag-types.h (auto_profile_format): New enumeration.
>
> Signed-off-by: Dhruv Chawla <[email protected]>
> Co-authored-by: Kugan Vivekanandarajah <[email protected]>
> Co-authored-by: Rahul Shinde <[email protected]>
> ---
>  gcc/Makefile.in     |  32 +++-
>  gcc/auto-profile.cc | 453 +++++++++++++++++---------------------------
>  gcc/auto-profile.h  |   2 +-
>  gcc/common.opt      |  24 +++
>  gcc/doc/invoke.texi |  29 ++-
>  gcc/flag-types.h    |   9 +
>  6 files changed, 268 insertions(+), 281 deletions(-)
>
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 9d43004613c..377fad85987 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -447,6 +447,11 @@ CPPINC = -I$(srcdir)/../libcpp/include
>  CODYLIB = ../libcody/libcody.a
>  CODYINC = -I$(srcdir)/../libcody
>
> +GCOVREADERLIB = libgcovreader.a
> +GCOVREADER_OBJS = afdo-file-mmap.o afdo-gcov-io.o afdo-gcov-reader.o \
> +       afdo-gcov-reader-v3.o afdo-gcov-reader-v4.o
> +GCOVREADERINC = -I$(srcdir)/../afdo_tools/src
> +
>  # Where to find decNumber
>  enable_decimal_float = @enable_decimal_float@
>  DECNUM = $(srcdir)/../libdecnumber
> @@ -1198,7 +1203,7 @@ BUILD_ERRORS = build/errors.o
>  INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \
>            -I$(srcdir)/../include $(INCINTL) \
>            $(CPPINC) $(CODYINC) $(GMPINC) $(DECNUMINC) $(BACKTRACEINC) \
> -          $(ISLINC)
> +          $(ISLINC) $(GCOVREADERINC)
>
>  COMPILE.base = $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) -o $@
>  ifeq ($(CXXDEPMODE),depmode=gcc3)
> @@ -1979,7 +1984,7 @@ endif
>  EXTRA_BACKEND_OBJS = simple-diagnostic-path.o diagnostics/lazy-paths.o
>
>  BACKEND = $(EXTRA_BACKEND_OBJS) libbackend.a main.o libcommon-target.a \
> -       libcommon.a $(CPPLIB) $(LIBDECNUMBER)
> +       libcommon.a $(CPPLIB) $(LIBDECNUMBER) $(GCOVREADERLIB)
>
>  # This is defined to "yes" if Tree checking is enabled, which roughly
> means
>  # front-end checking.
> @@ -2005,7 +2010,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h
> insn-codes.h \
>   genversion$(build_exeext) gcov$(exeext) gcov-dump$(exeext) \
>   gcov-tool$(exeext) \
>   gengtype$(exeext) *.[0-9][0-9].* *.[si] *-checksum.cc libbackend.a \
> - libcommon-target.a libcommon.a libgcc.mk perf.data
> + libcommon-target.a libcommon.a $(GCOVREADERLIB) libgcc.mk perf.data
>
>  # This symlink makes the full installation name of the driver be available
>  # from within the *build* directory, for use when running the JIT library
> @@ -2336,6 +2341,27 @@ SELFTEST_FLAGS = -nostdinc $(DEVNULL) -S -o
> $(DEVNULL) \
>  SELFTEST_TARGETS = @selftest_languages@
>  selftest: $(SELFTEST_TARGETS)
>
> +# AutoFDO reader objects: afdo_tools sources archived into
> $(GCOVREADERLIB) for
> +# cc1.
> +GCOVREADER_COMPILE = $(COMPILER) -c $(CXXFLAGS) -fno-exceptions -fno-rtti
> \
> +       -DIN_GCC -include auto-host.h -I$(srcdir) $(GCOVREADERINC)
> +
> +afdo-file-mmap.o: $(srcdir)/../afdo_tools/src/file_mmap.cc
> +       $(GCOVREADER_COMPILE) $< $(OUTPUT_OPTION)
> +afdo-gcov-io.o: $(srcdir)/../afdo_tools/src/gcov_io.cc
> +       $(GCOVREADER_COMPILE) $< $(OUTPUT_OPTION)
> +afdo-gcov-reader.o: $(srcdir)/../afdo_tools/src/gcov_reader.cc
> +       $(GCOVREADER_COMPILE) $< $(OUTPUT_OPTION)
> +afdo-gcov-reader-v3.o: $(srcdir)/../afdo_tools/src/gcov_reader_v3.cc
> +       $(GCOVREADER_COMPILE) $< $(OUTPUT_OPTION)
> +afdo-gcov-reader-v4.o: $(srcdir)/../afdo_tools/src/gcov_reader_v4.cc
> +       $(GCOVREADER_COMPILE) $< $(OUTPUT_OPTION)
> +
> +$(GCOVREADERLIB): $(GCOVREADER_OBJS)
> +       -rm -f $@
> +       $(AR) $(AR_FLAGS) $@ $(GCOVREADER_OBJS)
> +       $(RANLIB) $@
> +
>  # Recompile all the language-independent object files.
>  # This is used only if the user explicitly asks for it.
>  compilations: $(BACKEND)
> diff --git a/gcc/auto-profile.cc b/gcc/auto-profile.cc
> index 9b9ab5f4d9a..4253d54679e 100644
> --- a/gcc/auto-profile.cc
> +++ b/gcc/auto-profile.cc
> @@ -21,8 +21,15 @@ along with GCC; see the file COPYING3.  If not see
>  #include "config.h"
>  #define INCLUDE_MAP
>  #define INCLUDE_SET
> +#define INCLUDE_STRING
> +#define INCLUDE_VECTOR
>  #include "system.h"
>  #include "coretypes.h"
> +/* AutoFDO profile reader shared with the afdo_tools.  Included before
> +   gcov-io.h as its namespaced constants share names with gcov-io.h
> macros,
> +   so they must be parsed before those macros are defined.  */
> +#include "gcov.h"
> +#include "gcov_reader.h"
>  #include "backend.h"
>  #include "tree.h"
>  #include "gimple.h"
> @@ -227,44 +234,9 @@ 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);
> -};
> +/* Get the minimum count required for percentile CUTOFF from summary S.
> */
> +static uint64_t get_threshold_count (const gcov::gcov_summary &s,
> +                                    uint32_t cutoff);
>
>  /* Store a string array, indexed by string position in the array.  */
>  class string_table
> @@ -303,8 +275,10 @@ public:
>       NAME.  */
>    std::pair<const char *, int> get_original_name (const char *name) const;
>
> -  /* Read profile, return TRUE on success.  */
> -  bool read ();
> +  /* Copy the string table from a gcov_profile.  The string_table symbol
> index is
> +     kept identical to gcov_function::id, so descriptors built from
> either side
> +     agree.  */
> +  void construct (const gcov::gcov_profile &profile);
>
>    /* Return number of entries.  */
>    size_t num_entries () { return symbol_names_.length (); }
> @@ -384,11 +358,12 @@ class function_instance
>  public:
>    typedef auto_vec<function_instance *> function_instance_stack;
>
> -  /* Read the profile and return a function_instance with head count as
> -     HEAD_COUNT. Recursively read callsites to create nested
> function_instances
> -     too. STACK is used to track the recursive creation process.  */
> +  /* Build a function_instance from GF.  Recursively builds nested
> +     function_instances for inlined callsites.  STACK is used to track the
> +     recursive creation process.  */
>    static function_instance *
> -  read_function_instance (function_instance_stack *stack, bool toplevel =
> true);
> +  from_gcov (const gcov::gcov_function &gf, function_instance_stack
> *stack,
> +            bool toplevel = true);
>
>    /* Recursively deallocate all callsites (nested function_instances).  */
>    ~function_instance ();
> @@ -584,18 +559,23 @@ private:
>    /* Map from callsite to callee function_instance.  */
>    typedef std::map<callsite, function_instance *> callsite_map;
>
> +  /* Map from source location (decl_lineno) to profile (count_info).  */
> +  typedef std::map<unsigned, count_info> position_count_map;
> +
>    function_instance (unsigned symbol_name, unsigned file_name,
> -                    gcov_type head_count)
> +                    gcov_type head_count, const gcov::gcov_function *gcov)
>      : descriptor_ (file_name, symbol_name), total_count_ (0),
> -      head_count_ (head_count), timestamp_ (0),
> -      removed_icall_target_ (false), realized_ (false), in_worklist_
> (false),
> -      inlined_to_ (NULL), location_ (UNKNOWN_LOCATION),
> +      head_count_ (head_count), timestamp_ (0), gcov_ (gcov),
> +      pos_built_ (false), removed_icall_target_ (false), realized_
> (false),
> +      in_worklist_ (false), inlined_to_ (NULL), location_
> (UNKNOWN_LOCATION),
>        call_location_ (UNKNOWN_LOCATION)
>    {
>    }
>
> -  /* Map from source location (decl_lineno) to profile (count_info).  */
> -  typedef std::map<unsigned, count_info> position_count_map;
> +  /* Build pos_counts from the backing gcov_function's position counts.
> These
> +     are the bulk of the profile and are not copied up front, so a
> function the
> +     pass never queries never materializes them.  */
> +  void materialize_pos_counts () const;
>
>    /* The indices into the string table identifying the
> function_instance.  */
>    function_instance_descriptor descriptor_;
> @@ -613,8 +593,11 @@ private:
>    /* Map from callsite location to callee function_instance.  */
>    callsite_map callsites;
>
> -  /* Map from source location to count_info.  */
> -  position_count_map pos_counts;
> +  /* Backing profile function and the position counts lazily materialized
> from
> +     it.  */
> +  const gcov::gcov_function *gcov_;
> +  mutable bool pos_built_;
> +  mutable position_count_map pos_counts;
>
>    /* True if function was removed from indir target list.  */
>    bool removed_icall_target_;
> @@ -651,7 +634,7 @@ public:
>    {
>      autofdo_source_profile *map = new autofdo_source_profile ();
>
> -    if (map->read ())
> +    if (map->construct ())
>        return map;
>      delete map;
>      return NULL;
> @@ -703,8 +686,8 @@ private:
>
>    autofdo_source_profile () {}
>
> -  /* Read AutoFDO profile and returns TRUE on success.  */
> -  bool read ();
> +  /* Build afdo_source_profile from afdo_gcov_profile.  */
> +  bool construct ();
>
>    /* Return the function_instance in the profile that correspond to the
>       inline STACK.  */
> @@ -731,8 +714,8 @@ private:
>    auto_vec <function_instance *> duplicate_functions_;
>  };
>
> -/* Store the summary information from the GCOV file.  */
> -static summary_info *afdo_summary_info;
> +/* Store the summary information from the profile.  */
> +static gcov::gcov_summary afdo_summary_info;
>
>  /* Store the strings read from the profile data file.  */
>  static string_table *afdo_string_table;
> @@ -740,6 +723,10 @@ static string_table *afdo_string_table;
>  /* Store the AutoFDO source profile.  */
>  static autofdo_source_profile *afdo_source_profile;
>
> +/* The profile reader, kept alive for the whole pass.  */
> +static std::unique_ptr<gcov::gcov_reader_base> afdo_reader;
> +static const gcov::gcov_profile *afdo_gcov_profile;
> +
>  /* gcov_summary structure to store the profile_info.  */
>  static gcov_summary *afdo_profile_info;
>
> @@ -987,45 +974,24 @@ get_normalized_path (const char *path, bool
> from_gcov = false)
>    return lbasename (path);
>  }
>
> -/* 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.  */
> +/* Get the minimum count required for percentile CUTOFF from summary S.
> */
>
> -uint64_t
> -summary_info::get_threshold_count (uint32_t cutoff)
> +static uint64_t
> +get_threshold_count (const gcov::gcov_summary &s, uint32_t cutoff)
>  {
>    /* The cutoffs stored in the GCOV are fractions multiplied by
> 1,000,000.  */
>    gcc_checking_assert (cutoff <= 1'000'000);
> +  const std::vector<gcov::gcov_summary_detailed_entry> &entries
> +    = s.detailed_entries;
> +  if (entries.empty ())
> +    return 0;
>    unsigned idx = 0;
>    /* Find the first cutoff at least as high as CUTOFF.  */
> -  for (; idx < NUM_PERCENTILES; idx++)
> -    if (detailed_summaries[idx].cutoff >= cutoff)
> +  for (; idx < entries.size (); idx++)
> +    if (entries[idx].cutoff >= cutoff)
>        break;
> -  idx = std::min (NUM_PERCENTILES - 1, idx);
> -  return detailed_summaries[idx].min_count;
> +  idx = std::min ((unsigned) entries.size () - 1, idx);
> +  return entries[idx].min_count;
>  }
>
>  /* Member functions for string_table.  */
> @@ -1204,36 +1170,33 @@ string_table::add_filename (const char *name)
>    return filenames_.length () - 1;
>  }
>
> -/* Read the string table. Return TRUE if reading is successful.  */
> +/* Copy the string table from a gcov_profile.  The string_table symbol
> index is
> +   kept identical to gcov_function::id, so descriptors built from either
> side
> +   agree.  */
>
> -bool
> -string_table::read ()
> +void
> +string_table::construct (const gcov::gcov_profile &profile)
>  {
> -  if (gcov_read_unsigned () != GCOV_TAG_AFDO_FILE_NAMES)
> -    return false;
> -  /* Skip the length of the section.  */
> -  gcov_read_unsigned ();
> -  /* Read in the file name table.  */
> -  unsigned file_num = gcov_read_unsigned ();
> -  filenames_.reserve (file_num);
> -  for (unsigned i = 0; i < file_num; i++)
> +  const std::vector<std::string> &file_names = profile.get_file_names ();
> +  const std::vector<std::string> &symbols = profile.get_function_names ();
> +  const std::vector<uint32_t> &file_map = profile.get_file_name_map ();
> +
> +  filenames_.reserve (file_names.size ());
> +  for (unsigned i = 0; i < file_names.size (); i++)
>      {
> -      const char *filename = gcov_read_string ();
> -      filenames_.quick_push (xstrdup (get_normalized_path (filename,
> true)));
> +      filenames_.quick_push (
> +       xstrdup (get_normalized_path (file_names[i].c_str (), true)));
>        filename_map_[filenames_.last ()] = i;
> -      free (const_cast<char *> (filename));
> -      if (gcov_is_error ())
> -       return false;
>      }
> -  /* Read in the function name -> file name table.  */
> -  unsigned string_num = gcov_read_unsigned ();
> -  symbol_names_.reserve (string_num);
> -  for (unsigned i = 0; i < string_num; i++)
> +
> +  symbol_names_.reserve (symbols.size ());
> +  for (unsigned i = 0; i < symbols.size (); i++)
>      {
> -      symbol_names_.quick_push (const_cast<char *> (gcov_read_string ()));
> -      symbol_name_map_[symbol_names_.last ()] = i;
> -      unsigned filename_idx = gcov_read_unsigned ();
> -      symbol_to_filename_map_[symbol_names_.last ()] = filename_idx;
> +      int filename_idx = unknown_filename;
> +      if (i < file_map.size () && file_map[i] < filenames_.length ())
> +       filename_idx = (int) file_map[i];
> +      add_symbol_name (xstrdup (symbols[i].c_str ()), filename_idx);
> +
>        char *original = const_cast<char *> (
>         autofdo::get_original_name (symbol_names_.last ()));
>        if (strcmp (original, symbol_names_.last ()))
> @@ -1252,11 +1215,7 @@ string_table::read ()
>        else
>         /* There are no suffixes to remove.  */
>         free (original);
> -
> -      if (gcov_is_error ())
> -       return false;
>      }
> -  return true;
>  }
>
>  /* Return cgraph node corresponding to given NAME_INDEX,
> @@ -1449,6 +1408,8 @@ function_instance::merge (function_instance *other,
>        callsites[iter->first]->merge (iter->second, new_functions);
>      }
>
> +  materialize_pos_counts ();
> +  other->materialize_pos_counts ();
>    for (position_count_map::const_iterator iter = other->pos_counts.begin
> ();
>         iter != other->pos_counts.end (); ++iter)
>      if (pos_counts.count (iter->first) == 0)
> @@ -1572,10 +1533,8 @@ match_with_target (cgraph_node *n,
>      {
>        int i;
>        bool in_suffix = false;
> -      for (i = 0; i; i++)
> +      for (i = 0; name[i] && name[i] == symbol_name[i]; i++)
>         {
> -         if (name[i] != symbol_name[i])
> -           break;
>           if (name[i] == '.')
>             in_suffix = true;
>         }
> @@ -1644,6 +1603,7 @@ count_info *
>  function_instance::lookup_count (location_t loc, inline_stack &stack,
>                                  cgraph_node *node)
>  {
> +  materialize_pos_counts ();
>    gcc_checking_assert (stack.length () < 2);
>    if (stack.length ())
>      {
> @@ -1701,6 +1661,7 @@ function_instance::match (cgraph_node *node,
>                           vec <function_instance *> &new_functions,
>                           name_index_map &to_symbol_name)
>  {
> +  materialize_pos_counts ();
>    if (get_location () != UNKNOWN_LOCATION)
>      return false;
>    set_location (DECL_SOURCE_LOCATION (node->decl));
> @@ -2234,6 +2195,7 @@ function_instance::offline_if_not_realized
>  void
>  function_instance::dump (FILE *f, int indent, bool nested) const
>  {
> +  materialize_pos_counts ();
>    if (!nested)
>      fprintf (f, "%*s%s total:%" PRIu64 " head:%" PRId64 "\n", indent, "",
>              afdo_string_table->get_symbol_name (symbol_name ()),
> @@ -2309,6 +2271,7 @@ function_instance::debug () const
>  bool
>  function_instance::get_count_info (location_t loc, count_info *info) const
>  {
> +  materialize_pos_counts ();
>    position_count_map::const_iterator iter = pos_counts.find (loc);
>    if (iter == pos_counts.end ())
>      return false;
> @@ -2709,87 +2672,66 @@ autofdo_source_profile::offline_unrealized_inlines
> ()
>        function.second->dump (dump_file);
>  }
>
> -/* Read the profile and create a function_instance with head count as
> -   HEAD_COUNT. Recursively read callsites to create nested
> function_instances
> -   too. STACK is used to track the recursive creation process.  */
> -
> -/* function instance profile format:
> -
> -   ENTRY_COUNT: 8 bytes
> -   TIMESTAMP: 8 bytes (only for toplevel symbols)
> -   NAME_INDEX: 4 bytes
> -   NUM_POS_COUNTS: 4 bytes
> -   NUM_CALLSITES: 4 byte
> -   POS_COUNT_1:
> -     POS_1_OFFSET: 4 bytes
> -     NUM_TARGETS: 4 bytes
> -     COUNT: 8 bytes
> -     TARGET_1:
> -       VALUE_PROFILE_TYPE: 4 bytes
> -       TARGET_IDX: 8 bytes
> -       COUNT: 8 bytes
> -     TARGET_2
> -     ...
> -     TARGET_n
> -   POS_COUNT_2
> -   ...
> -   POS_COUNT_N
> -   CALLSITE_1:
> -     CALLSITE_1_OFFSET: 4 bytes
> -     FUNCTION_INSTANCE_PROFILE (nested)
> -   CALLSITE_2
> -   ...
> -   CALLSITE_n.  */
> +/* Build pos_counts from the backing gcov_function's position counts.
> These
> +   are the bulk of the profile and are not copied up front, so a function
> the
> +   pass never queries never materializes them.  */
>
> -function_instance *
> -function_instance::read_function_instance (function_instance_stack *stack,
> -                                          bool toplevel)
> +void
> +function_instance::materialize_pos_counts () const
>  {
> -  gcov_type_unsigned timestamp = 0;
> -  gcov_type head_count = -1;
> -  if (toplevel)
> +  bool built = pos_built_;
> +  pos_built_ = true;
> +  if (built || !gcov_)
> +    return;
> +  for (const std::unique_ptr<gcov::gcov_location> &locp :
> gcov_->locations)
>      {
> -      head_count = gcov_read_counter ();
> -      timestamp = (gcov_type_unsigned) gcov_read_counter ();
> +      const gcov::gcov_location *loc = locp.get ();
> +      unsigned offset = (loc->offset << 16) | (loc->discriminator &
> 0xffff);
> +      if (loc->type == gcov::gcov_location::kind::normal)
> +       pos_counts[offset].count
> +         = static_cast<const gcov::gcov_location_normal *> (loc)->count;
> +      else if (loc->type == gcov::gcov_location::kind::call)
> +       {
> +         const gcov::gcov_location_call *call
> +           = static_cast<const gcov::gcov_location_call *> (loc);
> +         pos_counts[offset].count = call->count;
> +         /* Only indirect call target histogram is supported now.  */
> +         for (const auto &t : call->callee_map)
> +           pos_counts[offset].targets[t.first] = t.second;
> +       }
>      }
> -  unsigned name = gcov_read_unsigned ();
> -  unsigned num_pos_counts = gcov_read_unsigned ();
> -  unsigned num_callsites = gcov_read_unsigned ();
> +}
> +
> +/* Build a function_instance from GF.  Recursively builds nested
> +   function_instances for inlined callsites.  STACK is used to track the
> +   recursive creation process.  */
> +
> +function_instance *
> +function_instance::from_gcov (const gcov::gcov_function &gf,
> +                             function_instance_stack *stack, bool
> toplevel)
> +{
> +  gcov_type head_count = toplevel ? (gcov_type) gf.head_count : -1;
> +  unsigned name = gf.id;
>    function_instance *s
>      = new function_instance (name,
>                              afdo_string_table->get_filename_by_symbol
> (name),
> -                            head_count);
> -  if (timestamp > 0)
> -    s->set_timestamp (timestamp);
> +                            head_count, &gf);
> +  s->total_count_ = gf.total_count;
> +  if (toplevel && gf.timestamp > 0)
> +    s->set_timestamp (gf.timestamp);
>    if (!stack->is_empty ())
>      s->set_inlined_to (stack->last ());
>    stack->safe_push (s);
>
> -  for (unsigned i = 0; i < num_pos_counts; i++)
> -    {
> -      unsigned offset = gcov_read_unsigned ();
> -      unsigned num_targets = gcov_read_unsigned ();
> -      gcov_type count = gcov_read_counter ();
> -      s->pos_counts[offset].count = count;
> -
> -      for (unsigned j = 0; j < stack->length (); j++)
> -        (*stack)[j]->total_count_ += count;
> -      for (unsigned j = 0; j < num_targets; j++)
> -        {
> -         /* Only indirect call target histogram is supported now.  */
> -         gcov_read_unsigned ();
> -         gcov_type target_idx = gcov_read_counter ();
> -         s->pos_counts[offset].targets[target_idx] = gcov_read_counter ();
> -        }
> -    }
> -  for (unsigned i = 0; i < num_callsites; i++)
> +  for (const std::unique_ptr<gcov::gcov_location> &locp : gf.locations)
>      {
> -      unsigned offset = gcov_read_unsigned ();
> -      function_instance *callee_function_instance
> -       = read_function_instance (stack, false);
> -      s->callsites[std::make_pair (offset,
> -                                  callee_function_instance->symbol_name
> ())]
> -       = callee_function_instance;
> +      if (locp->type != gcov::gcov_location::kind::inlined)
> +       continue;
> +      const gcov::gcov_location_inline *inl
> +       = static_cast<const gcov::gcov_location_inline *> (locp.get ());
> +      unsigned offset = (locp->offset << 16) | (locp->discriminator &
> 0xffff);
> +      function_instance *callee = from_gcov (inl->inlined_sym, stack,
> false);
> +      s->callsites[std::make_pair (offset, callee->symbol_name ())] =
> callee;
>      }
>    stack->pop ();
>    return s;
> @@ -3007,41 +2949,19 @@ autofdo_source_profile::get_callsite_total_count (
>    return s->total_count () * afdo_count_scale;
>  }
>
> -/* Read AutoFDO profile and returns TRUE on success.  */
> -
> -/* source profile format:
> -
> -   GCOV_TAG_AFDO_FUNCTION: 4 bytes
> -   LENGTH: 4 bytes
> -   NUM_FUNCTIONS: 4 bytes
> -   FUNCTION_INSTANCE_1
> -   FUNCTION_INSTANCE_2
> -   ...
> -   FUNCTION_INSTANCE_N.  */
> +/* Build afdo_source_profile from afdo_gcov_profile.  */
>
>  bool
> -autofdo_source_profile::read ()
> +autofdo_source_profile::construct ()
>  {
> -  if (gcov_read_unsigned () != GCOV_TAG_AFDO_FUNCTION)
> -    {
> -      inform (UNKNOWN_LOCATION, "Not expected TAG.");
> -      return false;
> -    }
> -
>    gcc_checking_assert (!afdo_source_profile);
>    afdo_source_profile = this;
>
> -  /* Skip the length of the section.  */
> -  gcov_read_unsigned ();
> -
> -  /* Read in the function/callsite profile, and store it in local
> -     data structure.  */
> -  unsigned function_num = gcov_read_unsigned ();
> -  for (unsigned i = 0; i < function_num; i++)
> +  /* Build the function/callsite profile from the gcov_profile.  */
> +  for (const gcov::gcov_function &gf : afdo_gcov_profile->get_functions
> ())
>      {
>        function_instance::function_instance_stack stack;
> -      function_instance *s
> -       = function_instance::read_function_instance (&stack);
> +      function_instance *s = function_instance::from_gcov (gf, &stack);
>
>        if (find_function_instance (s->get_descriptor ()) == nullptr)
>         add_function_instance (s);
> @@ -3063,7 +2983,7 @@ autofdo_source_profile::read ()
>    for (auto &p : timestamp_info_map)
>      p.second = tp_first_run++;
>
> -  afdo_profile_info->sum_max = afdo_summary_info->max_count;
> +  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)
> @@ -3072,7 +2992,7 @@ autofdo_source_profile::read ()
>              / afdo_profile_info->sum_max, 1);
>    afdo_profile_info->cutoff *= afdo_count_scale;
>    /* Derive the hot count threshold from the profile summary.  */
> -  afdo_hot_bb_threshold = afdo_summary_info->get_threshold_count (
> +  afdo_hot_bb_threshold = get_threshold_count (afdo_summary_info,
>                             param_hot_bb_count_ws_permille * 1000)
>                           * afdo_count_scale;
>    set_hot_bb_threshold (afdo_hot_bb_threshold);
> @@ -3087,7 +3007,7 @@ autofdo_source_profile::read ()
>              (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 (
> +            (int64_t) get_threshold_count (afdo_summary_info,
>                param_hot_bb_count_ws_permille * 1000),
>              (int64_t) afdo_hot_bb_threshold);
>    afdo_profile_info->sum_max *= afdo_count_scale;
> @@ -3186,85 +3106,65 @@ autofdo_source_profile::remove_function_instance
> (function_instance *inst)
>    return false;
>  }
>
> -/* Module profile is only used by LIPO. Here we simply ignore it.  */
> -
> -static void
> -fake_read_autofdo_module_profile ()
> -{
> -  /* Read in the module info.  */
> -  gcov_read_unsigned ();
> -
> -  /* Skip the length of the section.  */
> -  gcov_read_unsigned ();
> -
> -  /* Read in the file name table.  */
> -  unsigned total_module_num = gcov_read_unsigned ();
> -  gcc_assert (total_module_num == 0);
> -}
> -
>  /* Read data from profile data file.  */
>
>  static void
>  read_profile (void)
>  {
> -  if (gcov_open (auto_profile_file, 1) == 0)
> +  gcov::profile_format fmt;
> +  switch (flag_auto_profile_format)
>      {
> -      error ("cannot open profile file %s", auto_profile_file);
> -      return;
> +    case AUTO_PROFILE_V3:
> +      fmt = gcov::profile_format::v3_binary;
> +      break;
> +    case AUTO_PROFILE_V4:
> +      fmt = gcov::profile_format::v4_binary;
> +      break;
> +    case AUTO_PROFILE_V4_TEXT:
> +      fmt = gcov::profile_format::v4_text;
> +      break;
> +    default:
> +      fmt = gcov::detect_format (auto_profile_file);
> +      break;
>      }
>
> -  if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
> +  std::unique_ptr<gcov::gcov_reader_base> reader
> +    = gcov::make_gcov_reader (auto_profile_file, fmt);
> +  if (!reader)
>      {
> -      error ("AutoFDO profile magic number does not match");
> +      error ("cannot determine format of auto-profile file %s",
> +            auto_profile_file);
>        return;
>      }
>
> -  /* Skip the version number.  */
> -  unsigned version = gcov_read_unsigned ();
> -  if (version != AUTO_PROFILE_VERSION)
> +  bool read_ok = false;
> +  /* Per-TU partial read.  */
> +  if (flag_auto_profile_partial && reader->supports_partial_read ()
> +      && main_input_filename)
>      {
> -      error ("AutoFDO profile version %u does not match %u",
> -            version, AUTO_PROFILE_VERSION);
> -      return;
> +      const char *tu = get_normalized_path (main_input_filename);
> +      read_ok = reader->read (std::string (tu),
> +                             param_profile_func_internal_id == 1);
>      }
>
> -  /* Skip the empty integer.  */
> -  gcov_read_unsigned ();
> -
> -  /* summary_info.  */
> -  afdo_summary_info = new summary_info ();
> -  if (!afdo_summary_info->read ())
> +  if (!read_ok && !reader->read ())
>      {
> -      error ("cannot read summary information from %s",
> auto_profile_file);
> +      error ("cannot read auto-profile from %s", auto_profile_file);
>        return;
>      }
>
> -  /* string_table.  */
> +  afdo_gcov_profile = reader->get_profile ();
> +  afdo_summary_info = afdo_gcov_profile->get_summary ();
> +
>    afdo_string_table = new string_table ();
> -  if (!afdo_string_table->read ())
> -    {
> -      error ("cannot read string table from %s", auto_profile_file);
> -      return;
> -    }
> +  afdo_string_table->construct (*afdo_gcov_profile);
>
> -  /* autofdo_source_profile.  */
>    afdo_source_profile = autofdo_source_profile::create ();
> -  if (afdo_source_profile == NULL
> -      || gcov_is_error ())
> -    {
> -      error ("cannot read function profile from %s", auto_profile_file);
> -      delete afdo_source_profile;
> -      afdo_source_profile = NULL;
> -      return;
> -    }
> +  if (afdo_source_profile == NULL)
> +    error ("cannot read function profile from %s", auto_profile_file);
>
> -  /* autofdo_module_profile.  */
> -  fake_read_autofdo_module_profile ();
> -  if (gcov_is_error ())
> -    {
> -      error ("cannot read module profile from %s", auto_profile_file);
> -      return;
> -    }
> +  /* Keep the reader (and the gcov_profile it owns) alive for the pass.
> */
> +  afdo_reader = std::move (reader);
>  }
>
>  /* From AutoFDO profiles, find values inside STMT for that we want to
> measure
> @@ -4715,7 +4615,8 @@ end_auto_profile (void)
>  {
>    delete autofdo::afdo_source_profile;
>    delete autofdo::afdo_string_table;
> -  delete autofdo::afdo_summary_info;
> +  autofdo::afdo_reader.reset ();
> +  autofdo::afdo_gcov_profile = NULL;
>    profile_info = NULL;
>  }
>
> diff --git a/gcc/auto-profile.h b/gcc/auto-profile.h
> index 2685a1453c5..c52534a941d 100644
> --- a/gcc/auto-profile.h
> +++ b/gcc/auto-profile.h
> @@ -21,7 +21,7 @@ along with GCC; see the file COPYING3.  If not see
>  #ifndef AUTO_PROFILE_H
>  #define AUTO_PROFILE_H
>
> -#define AUTO_PROFILE_VERSION 3
> +#define AUTO_PROFILE_VERSION 4
>
>  /* Read, process, finalize AutoFDO data structures.  */
>  extern void read_autofdo_file (void);
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 69a55b8d40d..9e17737e4f2 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1218,6 +1218,30 @@ fauto-profile-inlining
>  Common Var(flag_auto_profile_inlining) Init(1) Optimization
>  Perform inlining using auto-profile.
>
> +fauto-profile-partial
> +Common Var(flag_auto_profile_partial) Init(0)
> +Read only the current translation unit's data from a version 4
> auto-profile,
> +instead of the whole profile.
> +
> +fauto-profile-format=
> +Common Joined RejectNegative Enum(auto_profile_format)
> Var(flag_auto_profile_format) Init(AUTO_PROFILE_AUTO)
> +Select the on-disk auto-profile format.
> +
> +Enum
> +Name(auto_profile_format) Type(enum auto_profile_format)
> UnknownError(unknown auto-profile format %qs)
> +
> +EnumValue
> +Enum(auto_profile_format) String(auto) Value(AUTO_PROFILE_AUTO)
> +
> +EnumValue
> +Enum(auto_profile_format) String(v3) Value(AUTO_PROFILE_V3)
> +
> +EnumValue
> +Enum(auto_profile_format) String(v4) Value(AUTO_PROFILE_V4)
> +
> +EnumValue
> +Enum(auto_profile_format) String(v4-text) Value(AUTO_PROFILE_V4_TEXT)
> +
>  ; -fbounds-check causes gcc to generate array bounds checks.
>  ; It's presently used only for fortran, algol68, and d languages.
>  ; In Fortran and algol68 it is a deprecated alias for -fcheck=bounds,
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 3311ff94619..c27336f0e50 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -605,7 +605,8 @@ Objective-C and Objective-C++ Dialects}.
>  -fmin-function-alignment=[@var{n}]
>  -fno-allocation-dce  -fallow-store-data-races
>  -fassociative-math  -fauto-profile  -fauto-profile[=@var{path}]
> --fauto-profile-inlining  -fauto-inc-dec  -fbranch-probabilities
> +-fauto-profile-inlining  -fauto-profile-format=@var{format}
> +-fauto-profile-partial  -fauto-inc-dec  -fbranch-probabilities
>  -fcaller-saves
>  -fcombine-stack-adjustments  -fconserve-stack
>  -ffold-mem-offsets
> @@ -16464,6 +16465,32 @@ create_gcov --binary=your_program.unstripped
> --profile=perf.data \
>  When auto-profile is available inline all relevant functions which was
>  inlined in the tran run before reading the profile feedback.  This
> improves
>  context sensitivity of the profile.  Enabled by default.
> +
> +@opindex fauto-profile-format
> +@item -fauto-profile-format=@var{format}
> +Select the on-disk format of the AutoFDO profile supplied to
> +@option{-fauto-profile}.  @var{format} is one of:
> +
> +@table @samp
> +@item auto
> +Detect the format from the file contents.  This is the default.
> +@item v3
> +The legacy @samp{gcda}-based format written by older
> @command{create_gcov}.
> +@item v4
> +The version 4 binary format.
> +@item v4-text
> +The textual variant of the version 4 format.
> +@end table
> +
> +@opindex fauto-profile-partial
> +@opindex fno-auto-profile-partial
> +@item -fauto-profile-partial
> +Read only the data needed for the translation unit being compiled from a
> +version 4 AutoFDO profile, rather than the whole profile.  This can
> +substantially reduce the time spent reading large cross-module profiles.
> The
> +option has no effect for profiles whose format does not support partial
> reads
> +(such as the legacy version 3 format), which are always read in full.
> +Disabled by default.
>  @end table
>
>  The following options control compiler behavior regarding floating-point
> diff --git a/gcc/flag-types.h b/gcc/flag-types.h
> index df983d9d947..dab1d16f12d 100644
> --- a/gcc/flag-types.h
> +++ b/gcc/flag-types.h
> @@ -160,6 +160,15 @@ enum stack_reuse_level
>    SR_ALL
>  };
>
> +/* On-disk auto-profile format selected by -fauto-profile-format.  */
> +enum auto_profile_format
> +{
> +  AUTO_PROFILE_AUTO,
> +  AUTO_PROFILE_V3,
> +  AUTO_PROFILE_V4,
> +  AUTO_PROFILE_V4_TEXT
> +};
> +
>  /* Control Flow Redundancy hardening options for noreturn calls.  */
>  enum hardcfr_noret
>  {
> --
> 2.34.1
>
>
>

Reply via email to