Add the common utilities used by the AutoFDO host tools: assertion handling,
file-backed mappings, hashing, and stage timing.  Keeping these facilities
separate establishes the shared support layer without introducing a profile
format or command-line tool.

afdo_tools/ChangeLog:

        * src/afdo_assert.h: New file.
        * src/file_mmap.cc: New file.
        * src/file_mmap.h: New file.
        * src/hash_util.h: New file.
        * src/profile_timer.cc: New file.
        * src/profile_timer.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/afdo_assert.h    | 37 ++++++++++++++
 afdo_tools/src/file_mmap.cc     | 82 ++++++++++++++++++++++++++++++
 afdo_tools/src/file_mmap.h      | 56 ++++++++++++++++++++
 afdo_tools/src/hash_util.h      | 38 ++++++++++++++
 afdo_tools/src/profile_timer.cc | 90 +++++++++++++++++++++++++++++++++
 afdo_tools/src/profile_timer.h  | 40 +++++++++++++++
 6 files changed, 343 insertions(+)
 create mode 100644 afdo_tools/src/afdo_assert.h
 create mode 100644 afdo_tools/src/file_mmap.cc
 create mode 100644 afdo_tools/src/file_mmap.h
 create mode 100644 afdo_tools/src/hash_util.h
 create mode 100644 afdo_tools/src/profile_timer.cc
 create mode 100644 afdo_tools/src/profile_timer.h

diff --git a/afdo_tools/src/afdo_assert.h b/afdo_tools/src/afdo_assert.h
new file mode 100644
index 00000000000..f1783e85185
--- /dev/null
+++ b/afdo_tools/src/afdo_assert.h
@@ -0,0 +1,37 @@
+/* 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_AFDO_ASSERT_H
+#define GCC_AFDO_ASSERT_H
+
+/* Host tools abort on failure; when linked into cc1, use gcc_assert.  */
+#ifdef IN_GCC
+#define afdo_assert(EXPR) gcc_assert (EXPR)
+#else
+#include <cstdio>
+#include <cstdlib>
+#define afdo_assert(EXPR) \
+  ((void) (!(EXPR) \
+          ? (std::fprintf (stderr, \
+                           "%s:%d: afdo_assert failed: %s\n", \
+                           __FILE__, __LINE__, #EXPR), \
+             std::abort (), 0) \
+          : 0))
+#endif
+
+#endif /* GCC_AFDO_ASSERT_H.  */
diff --git a/afdo_tools/src/file_mmap.cc b/afdo_tools/src/file_mmap.cc
new file mode 100644
index 00000000000..c7f3f7499b7
--- /dev/null
+++ b/afdo_tools/src/file_mmap.cc
@@ -0,0 +1,82 @@
+/* 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 "file_mmap.h"
+
+#include <fcntl.h>
+#include <limits>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+namespace afdo_tools {
+
+file_mmap::~file_mmap ()
+{
+  unmap ();
+}
+
+void
+file_mmap::unmap ()
+{
+  if (addr_ != nullptr)
+    {
+      ::munmap (addr_, size_);
+      addr_ = nullptr;
+      size_ = 0;
+    }
+}
+
+bool
+file_mmap::map (const std::string &path)
+{
+  unmap ();
+
+  int fd = ::open (path.c_str (), O_RDONLY);
+  if (fd < 0)
+    return false;
+
+  struct stat st;
+  if (::fstat (fd, &st) != 0 || st.st_size <= 0)
+    {
+      ::close (fd);
+      return false;
+    }
+
+  if (static_cast<uintmax_t> (st.st_size)
+      > static_cast<uintmax_t> (std::numeric_limits<size_t>::max ()))
+    {
+      ::close (fd);
+      return false;
+    }
+  const size_t len = static_cast<size_t> (st.st_size);
+  void *m = ::mmap (nullptr, len, PROT_READ, MAP_PRIVATE, fd, 0);
+  ::close (fd);
+  if (m == MAP_FAILED)
+    return false;
+
+#ifdef MADV_SEQUENTIAL
+  ::madvise (m, len, MADV_SEQUENTIAL);
+#endif
+
+  addr_ = m;
+  size_ = len;
+  return true;
+}
+
+} /* namespace afdo_tools.  */
diff --git a/afdo_tools/src/file_mmap.h b/afdo_tools/src/file_mmap.h
new file mode 100644
index 00000000000..8ab86eb6479
--- /dev/null
+++ b/afdo_tools/src/file_mmap.h
@@ -0,0 +1,56 @@
+/* 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_FILE_MMAP_H
+#define GCC_FILE_MMAP_H
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+namespace afdo_tools {
+
+/* Readonly whole-file mmap for GCOV profiles and offline perf.data.
+   Live perf ring buffers use MAP_SHARED separately and do not use this.  */
+class file_mmap
+{
+  void *addr_ = nullptr;
+  size_t size_ = 0;
+
+public:
+  file_mmap () = default;
+  ~file_mmap ();
+
+  file_mmap (const file_mmap &) = delete;
+  file_mmap &operator= (const file_mmap &) = delete;
+  file_mmap (file_mmap &&) = delete;
+  file_mmap &operator= (file_mmap &&) = delete;
+
+  /* Map PATH with PROT_READ / MAP_PRIVATE.  Unmaps any previous mapping.
+     Returns false on open/fstat/empty/mmap failure (object left empty).  */
+  bool map (const std::string &path);
+  void unmap ();
+
+  const uint8_t *data () const { return static_cast<const uint8_t *> (addr_); }
+  size_t size () const { return size_; }
+  explicit operator bool () const { return addr_ != nullptr; }
+};
+
+} /* namespace afdo_tools.  */
+
+#endif /* GCC_FILE_MMAP_H.  */
diff --git a/afdo_tools/src/hash_util.h b/afdo_tools/src/hash_util.h
new file mode 100644
index 00000000000..253332c5095
--- /dev/null
+++ b/afdo_tools/src/hash_util.h
@@ -0,0 +1,38 @@
+/* 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_HASH_UTIL_H
+#define GCC_HASH_UTIL_H
+
+#include <cstddef>
+
+namespace autofdo {
+
+/* Mix VALUE into SEED (the Boost hash_combine mixing step).  */
+template <typename T>
+void
+hash_combine (size_t &seed, T value) noexcept
+{
+  seed ^= static_cast<size_t> (value)
+         + static_cast<size_t> (0x9e3779b97f4a7c15ULL) + (seed << 6)
+         + (seed >> 2);
+}
+
+} /* namespace autofdo.  */
+
+#endif /* GCC_HASH_UTIL_H.  */
diff --git a/afdo_tools/src/profile_timer.cc b/afdo_tools/src/profile_timer.cc
new file mode 100644
index 00000000000..f985d09a16a
--- /dev/null
+++ b/afdo_tools/src/profile_timer.cc
@@ -0,0 +1,90 @@
+/* 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 "profile_timer.h"
+
+#include <chrono>
+#include <cstdio>
+#include <utility>
+#include <vector>
+
+namespace autofdo {
+namespace profile_timer {
+
+using clock_type = std::chrono::steady_clock;
+
+struct stage_timer
+{
+  std::string label;
+  clock_type::time_point start;
+};
+
+static clock_type::time_point s_start;
+static bool s_started = false;
+static std::vector<stage_timer> s_stages;
+
+void
+start ()
+{
+  s_start = clock_type::now ();
+  s_started = true;
+  s_stages.clear ();
+}
+
+/* Push a named stage starting now.  */
+void
+begin_stage (const char *label)
+{
+  if (!s_started)
+    start ();
+  s_stages.push_back ({label, clock_type::now ()});
+}
+
+/* Report and pop the innermost stage.  */
+void
+end_stage (const std::string &detail)
+{
+  if (!s_started || s_stages.empty ())
+    {
+      /* Ignoring this silently would misindent every later stage.  */
+      fprintf (stderr, _("Warning: no profiling stage to end\n"));
+      return;
+    }
+
+  const clock_type::time_point now = clock_type::now ();
+  stage_timer stage = std::move (s_stages.back ());
+  s_stages.pop_back ();
+  const double total = std::chrono::duration<double> (now - s_start).count ();
+  const double elapsed
+    = std::chrono::duration<double> (now - stage.start).count ();
+  const int indent = static_cast<int> (s_stages.size () * 2);
+
+  fprintf (stderr,
+          _("%*sStage: %s [%.1fs] (+%.1fs)"),
+          indent,
+          "",
+          stage.label.c_str (),
+          total,
+          elapsed);
+  if (!detail.empty ())
+    fprintf (stderr, "  %s", detail.c_str ());
+  fprintf (stderr, "\n");
+}
+
+} /* namespace profile_timer.  */
+} /* namespace autofdo.  */
diff --git a/afdo_tools/src/profile_timer.h b/afdo_tools/src/profile_timer.h
new file mode 100644
index 00000000000..8954f0a9185
--- /dev/null
+++ b/afdo_tools/src/profile_timer.h
@@ -0,0 +1,40 @@
+/* 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_PROFILE_TIMER_H
+#define GCC_PROFILE_TIMER_H
+
+#include <string>
+
+/* Nested elapsed-time stages for the AutoFDO pipeline.  */
+namespace autofdo {
+namespace profile_timer {
+
+/* Reset the timer and discard any open stages.  */
+void start ();
+
+/* Push a stage named LABEL onto the timer stack.  */
+void begin_stage (const char *label);
+
+/* Pop and report the innermost stage with optional DETAIL.  */
+void end_stage (const std::string &detail = {});
+
+} /* namespace profile_timer.  */
+} /* namespace autofdo.  */
+
+#endif /* GCC_PROFILE_TIMER_H.  */
-- 
2.34.1

Reply via email to