Add profiler orchestration that loads samples, initializes DWARF,
correlates source data, and exports a profile.  The command-line frontend
remains separate from this reusable pipeline.

afdo_tools/ChangeLog:

        * src/autofdo_profiler.cc: New file.
        * src/autofdo_profiler.h: New file.

Signed-off-by: Kugan Vivekanandarajah <[email protected]>
Co-authored-by: Dhruv Chawla <[email protected]>
Co-authored-by: Rahul Shinde <[email protected]>
---
 afdo_tools/src/autofdo_profiler.cc | 141 +++++++++++++++++++++++++++++
 afdo_tools/src/autofdo_profiler.h  |  76 ++++++++++++++++
 2 files changed, 217 insertions(+)
 create mode 100644 afdo_tools/src/autofdo_profiler.cc
 create mode 100644 afdo_tools/src/autofdo_profiler.h

diff --git a/afdo_tools/src/autofdo_profiler.cc 
b/afdo_tools/src/autofdo_profiler.cc
new file mode 100644
index 00000000000..8f13f20b03f
--- /dev/null
+++ b/afdo_tools/src/autofdo_profiler.cc
@@ -0,0 +1,141 @@
+/* Copyright The GNU Toolchain Authors
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "autofdo_profiler.h"
+#include "autofdo_correlator.h"
+#include "autofdo_debug_dump.h"
+#include "dwarf_reader.h"
+#include "live_branch_stack_reader.h"
+#include "perf_file_reader.h"
+#include "profile_reader.h"
+#include "profile_timer.h"
+
+#include <cstdio>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace autofdo {
+
+autofdo_profiler::autofdo_profiler (const std::string &binary_path,
+                                   const profiler_run_options &run_opts,
+                                   const std::string &perf_data_path,
+                                   perf_data::sampling_mode sampling_mode)
+  : binary_path_ (binary_path), run_opts_ (run_opts)
+{
+  profile_source_ = perf_data::create_perf_reader (
+    perf_data_path, binary_path, sampling_mode);
+}
+
+autofdo_profiler::autofdo_profiler (const std::string &binary_path,
+                                   const profiler_run_options &run_opts,
+                                   std::vector<std::string> command_argv)
+  : binary_path_ (binary_path), run_opts_ (run_opts)
+{
+  profile_source_ = std::make_unique<perf_data::live_branch_stack_reader> (
+    binary_path, std::move (command_argv), run_opts.live_sample_period);
+}
+
+autofdo_profiler::~autofdo_profiler () = default;
+
+/* Run the whole pipeline: read the perf profile, load DWARF over the sampled
+   ranges, correlate samples to source, and write the gcov profile.  */
+bool
+autofdo_profiler::generate_profile ()
+{
+  /* 1.  Load samples.  */
+  profile_timer::begin_stage (_("profile load"));
+  fprintf (stderr, _("Loading profile...\n"));
+  if (profile_source_ == nullptr)
+    {
+      fprintf (stderr, _("Error: no profile reader is available\n"));
+      return false;
+    }
+  if (!profile_source_->load_and_prepare (run_opts_.use_branch_stack))
+    return false;
+  if (!run_opts_.dump_perf_maps.empty ())
+    dump_ingested_perf_maps (*profile_source_, run_opts_.dump_perf_maps);
+  {
+    std::string detail
+      = std::to_string (profile_source_->get_total_samples ()) + _(" samples");
+    if (const auto *ranges = profile_source_->range_counts ())
+      detail += _(", ") + std::to_string (ranges->size ()) + _(" ranges");
+    profile_timer::end_stage (detail);
+  }
+
+  /* 2.  Load DWARF for the sampled address scope.  */
+  profile_timer::begin_stage (_("DWARF load"));
+  dwarf_debug::pc_range_list sampled_ranges
+    = profile_source_->sample_ranges_for_dwarf ();
+  if (sampled_ranges.empty ())
+    {
+      fprintf (stderr,
+              _("Error: No profile sample scope for DWARF load\n"));
+      return false;
+    }
+  dwarf_reader_ = std::make_unique<dwarf_debug::dwarf_reader> (
+    binary_path_, std::move (sampled_ranges));
+  dwarf_reader_->set_parse_threads (run_opts_.correlate_threads);
+  if (!dwarf_reader_->load ())
+    {
+      fprintf (stderr, _("Error: Failed to load DWARF from %s\n"),
+              binary_path_.c_str ());
+      return false;
+    }
+  {
+    const dwarf_debug::dwarf_load_summary &s = dwarf_reader_->load_summary ();
+    std::string detail = std::to_string (s.touch_cus) + _(" CUs, ")
+                        + std::to_string (s.dwarf_functions)
+                        + _(" DWARF funcs, ")
+                        + std::to_string (s.symtab_functions) + _(" symtab, ")
+                        + std::to_string (s.line_segments)
+                        + _(" line segments, ") + std::to_string (s.touch_pcs)
+                        + _(" touch PCs");
+    profile_timer::end_stage (detail);
+  }
+
+  profile_source_->fold_sample_timestamps_by_function (*dwarf_reader_);
+
+  /* 3.  Correlate samples into the profile tree.  */
+  profile_timer::begin_stage (_("correlate"));
+  const bool correlated = correlate_samples_to_source
+    (profile_, *profile_source_, *dwarf_reader_, run_opts_);
+  if (!correlated)
+    return false;
+  profile_timer::end_stage ();
+
+  /* 4.  Finalize and emit GCOV.  */
+  profile_timer::begin_stage (_("finalize"));
+  profile_.finalize_after_correlate (*profile_source_);
+  profile_.materialize_alias_profiles (
+    dwarf_reader_->symtab_functions (), dwarf_reader_->symtab_aliases ());
+  profile_timer::end_stage ();
+
+  profile_timer::begin_stage (_("build gcov"));
+  profile_.build_gcov_profile (gcov_out_);
+  if (gcov_out_.get_functions ().empty ())
+    {
+      fprintf (stderr,
+              _("Error: correlation produced no source-level profile data\n"));
+      return false;
+    }
+  profile_timer::end_stage ();
+  return true;
+}
+
+} /* namespace autofdo.  */
diff --git a/afdo_tools/src/autofdo_profiler.h 
b/afdo_tools/src/autofdo_profiler.h
new file mode 100644
index 00000000000..e326fbc4aa1
--- /dev/null
+++ b/afdo_tools/src/autofdo_profiler.h
@@ -0,0 +1,76 @@
+/* Copyright The GNU Toolchain Authors
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_AUTOFDO_PROFILER_H
+#define GCC_AUTOFDO_PROFILER_H
+
+#include "autofdo_model.h"
+#include "autofdo_options.h"
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace dwarf_debug {
+class dwarf_reader;
+}
+
+namespace perf_data {
+class profile_reader;
+enum class sampling_mode : uint8_t;
+} /* namespace perf_data.  */
+
+namespace autofdo {
+
+/* Drive sample load, DWARF, correlate, then GCOV.  Offline perf.data and live
+   capture differ only in how profile_source_ is constructed.  */
+class autofdo_profiler
+{
+public:
+  autofdo_profiler (const std::string &binary_path,
+                   const profiler_run_options &run_opts,
+                   const std::string &perf_data_path,
+                   perf_data::sampling_mode sampling_mode);
+
+  /* Live capture via perf_event_open (command after --).  */
+  autofdo_profiler (const std::string &binary_path,
+                   const profiler_run_options &run_opts,
+                   std::vector<std::string> command_argv);
+
+  ~autofdo_profiler ();
+  autofdo_profiler (const autofdo_profiler &) = delete;
+  autofdo_profiler &operator= (const autofdo_profiler &) = delete;
+  autofdo_profiler (autofdo_profiler &&) = delete;
+  autofdo_profiler &operator= (autofdo_profiler &&) = delete;
+
+  bool generate_profile ();
+  const gcov::gcov_profile &get_gcov_profile () const { return gcov_out_; }
+
+private:
+  std::string binary_path_;
+  profiler_run_options run_opts_;
+  std::unique_ptr<perf_data::profile_reader> profile_source_;
+  std::unique_ptr<dwarf_debug::dwarf_reader> dwarf_reader_;
+  profile_builder profile_;
+  gcov::gcov_profile gcov_out_;
+};
+
+} /* namespace autofdo.  */
+
+#endif /* GCC_AUTOFDO_PROFILER_H.  */
-- 
2.34.1

Reply via email to