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