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