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