Add the low-level GCOV v3 byte I/O helpers and working-set summary
calculation.  These routines provide the checked encoding primitives shared
by the reader, writer, and merge implementation.

afdo_tools/ChangeLog:

        * src/gcov_io.cc: New file.
        * src/gcov_io.h: New file.
        * src/gcov_summary.cc: New file.
        * src/gcov_summary.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/gcov_io.cc      | 109 +++++++++++++++++++++++++++++
 afdo_tools/src/gcov_io.h       |  43 ++++++++++++
 afdo_tools/src/gcov_summary.cc | 124 +++++++++++++++++++++++++++++++++
 afdo_tools/src/gcov_summary.h  |  36 ++++++++++
 4 files changed, 312 insertions(+)
 create mode 100644 afdo_tools/src/gcov_io.cc
 create mode 100644 afdo_tools/src/gcov_io.h
 create mode 100644 afdo_tools/src/gcov_summary.cc
 create mode 100644 afdo_tools/src/gcov_summary.h

diff --git a/afdo_tools/src/gcov_io.cc b/afdo_tools/src/gcov_io.cc
new file mode 100644
index 00000000000..7618acea12c
--- /dev/null
+++ b/afdo_tools/src/gcov_io.cc
@@ -0,0 +1,109 @@
+/* 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/>.  */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gcov.h"
+#include "gcov_io.h"
+
+#ifdef IN_GCC
+#include "intl.h"
+#endif
+
+#include <cstdio>
+#include <cstring>
+
+namespace gcov {
+
+void
+gcov_note_count_overflow ()
+{
+  static bool warned;
+  if (warned)
+    return;
+  warned = true;
+  fprintf (stderr,
+          _("Warning: GCOV profile count overflowed a uint64_t\n"));
+}
+
+/* Write VALUE to FILE as a raw host-endian 32-bit word.  */
+void
+gcov_write_uint32 (FILE *file, uint32_t value)
+{
+  fwrite (&value, 1, sizeof (value), file);
+}
+
+/* Write VALUE to FILE as two 32-bit words, low word first.  */
+void
+gcov_write_uint64 (FILE *file, uint64_t value)
+{
+  gcov_write_uint32 (file, static_cast<uint32_t> (value));
+  gcov_write_uint32 (file, static_cast<uint32_t> (value >> 32));
+}
+
+/* Write STR to FILE prefixed by its length, which counts the trailing NUL.  */
+void
+gcov_write_string (FILE *file, const std::string &str)
+{
+  const size_t alloc = str.size () + 1; /* Include NUL.  */
+  gcov_write_uint32 (file, static_cast<uint32_t> (alloc));
+  fwrite (str.c_str (), 1, alloc, file);
+}
+
+/* Read a raw host-endian 32-bit word into VALUE, advancing CUR.  Returns
+   false when [CUR, END) is too short.  */
+bool
+gcov_read_uint32 (const uint8_t *&cur, const uint8_t *end, uint32_t &value)
+{
+  if (cur > end || sizeof (value) > (size_t) (end - cur))
+    return false;
+
+  std::memcpy (&value, cur, sizeof (value));
+  cur += sizeof (value);
+  return true;
+}
+
+/* Read two 32-bit words, low word first, into VALUE.  */
+bool
+gcov_read_uint64 (const uint8_t *&cur, const uint8_t *end, uint64_t &value)
+{
+  uint32_t lo = 0, hi = 0;
+  if (!gcov_read_uint32 (cur, end, lo) || !gcov_read_uint32 (cur, end, hi))
+    return false;
+  value = (static_cast<uint64_t> (hi) << 32) | lo;
+  return true;
+}
+
+/* Read a length-prefixed string into OUT, dropping the trailing NUL.  */
+bool
+gcov_read_string (const uint8_t *&cur, const uint8_t *end, std::string &out)
+{
+  uint32_t byte_len = 0;
+  if (!gcov_read_uint32 (cur, end, byte_len) || byte_len == 0
+      || cur > end || byte_len > (size_t) (end - cur)
+      || cur[byte_len - 1] != '\0')
+    return false;
+
+  out.assign (reinterpret_cast<const char *> (cur), byte_len - 1);
+  cur += byte_len;
+  return true;
+}
+
+} /* namespace gcov.  */
diff --git a/afdo_tools/src/gcov_io.h b/afdo_tools/src/gcov_io.h
new file mode 100644
index 00000000000..9749e85cd75
--- /dev/null
+++ b/afdo_tools/src/gcov_io.h
@@ -0,0 +1,43 @@
+/* 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_GCOV_IO_H
+#define GCC_GCOV_IO_H
+
+#include <cstdint>
+#include <cstdio>
+#include <string>
+#include <vector>
+
+namespace gcov {
+/* GCOV v3 IO primitives: raw host-endian words, and strings prefixed by a
+   length that counts the trailing NUL.  */
+void gcov_write_uint32 (FILE *file, uint32_t value);
+void gcov_write_uint64 (FILE *file, uint64_t value);
+void gcov_write_string (FILE *file, const std::string &str);
+
+bool gcov_read_uint32 (const uint8_t *&cur, const uint8_t *end,
+                      uint32_t &value);
+bool gcov_read_uint64 (const uint8_t *&cur, const uint8_t *end,
+                      uint64_t &value);
+bool gcov_read_string (const uint8_t *&cur, const uint8_t *end,
+                      std::string &out);
+
+} /* namespace gcov.  */
+
+#endif /* GCC_GCOV_IO_H.  */
diff --git a/afdo_tools/src/gcov_summary.cc b/afdo_tools/src/gcov_summary.cc
new file mode 100644
index 00000000000..7f7427f35b0
--- /dev/null
+++ b/afdo_tools/src/gcov_summary.cc
@@ -0,0 +1,124 @@
+/* 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 "gcov_summary.h"
+
+#include <cstdint>
+#include <functional>
+#include <map>
+
+namespace gcov {
+namespace {
+
+/* Cumulative profile-count targets in millionths of the total count;
+   for example, 10000 denotes 1 percent.  */
+constexpr uint32_t SUMMARY_CUTOFFS[] = {10000,
+                                       100000,
+                                       200000,
+                                       300000,
+                                       400000,
+                                       500000,
+                                       600000,
+                                       700000,
+                                       800000,
+                                       900000,
+                                       950000,
+                                       990000,
+                                       999000,
+                                       999900,
+                                       999990,
+                                       999999};
+
+/* Count -> number of positions with that count.  */
+using count_histogram = std::map<uint64_t, uint64_t, std::greater<uint64_t>>;
+
+/* Fold every leaf position count of F (recursing into inline subtrees) into 
the
+   histogram FREQ and the running aggregates.  */
+void
+accumulate (const gcov_function &f, count_histogram &freq, uint64_t &total,
+           uint64_t &max_count, uint64_t &num_counts)
+{
+  for (const auto &loc : f.locations)
+    {
+      if (loc->type == gcov_location::kind::inlined)
+       {
+         accumulate (
+           static_cast<const gcov_location_inline *> (loc.get ())->inlined_sym,
+           freq,
+           total,
+           max_count,
+           num_counts);
+         continue;
+       }
+      const uint64_t c = loc->total_count ();
+      if (c == 0)
+       continue;
+      total = gcov_add_count (total, c);
+      if (c > max_count)
+       max_count = c;
+      ++num_counts;
+      ++freq[c];
+    }
+}
+
+} /* anonymous namespace.  */
+
+void
+compute_summary (const std::vector<gcov_function> &functions, gcov_summary 
&out)
+{
+  count_histogram freq;
+  uint64_t total = 0, max_count = 0, num_counts = 0, max_function_count = 0;
+  for (const auto &f : functions)
+    {
+      if (f.head_count > max_function_count)
+       max_function_count = f.head_count;
+      accumulate (f, freq, total, max_count, num_counts);
+    }
+
+  out.total_count = total;
+  out.max_count = max_count;
+  out.max_function_count = max_function_count;
+  out.num_counts = num_counts;
+  out.num_functions = static_cast<uint64_t> (functions.size ());
+
+  const unsigned n = sizeof (SUMMARY_CUTOFFS) / sizeof (SUMMARY_CUTOFFS[0]);
+  out.num_detailed_entries = n;
+  out.detailed_entries.assign (n, {});
+
+  auto it = freq.begin ();
+  const auto end = freq.end ();
+  uint64_t curr_sum = 0, counts_seen = 0, count = 0;
+  for (unsigned i = 0; i < n; ++i)
+    {
+      const uint32_t cutoff = SUMMARY_CUTOFFS[i];
+      const unsigned __int128 desired
+       = (unsigned __int128) total * cutoff / 1000000u;
+      while (curr_sum < desired && it != end)
+       {
+         count = it->first;
+         curr_sum = gcov_add_count (curr_sum, it->first * it->second);
+         counts_seen = gcov_add_count (counts_seen, it->second);
+         ++it;
+       }
+      out.detailed_entries[i].cutoff = cutoff;
+      out.detailed_entries[i].min_count = count;
+      out.detailed_entries[i].num_counts = counts_seen;
+    }
+}
+
+} /* namespace gcov.  */
diff --git a/afdo_tools/src/gcov_summary.h b/afdo_tools/src/gcov_summary.h
new file mode 100644
index 00000000000..b2627a43c7f
--- /dev/null
+++ b/afdo_tools/src/gcov_summary.h
@@ -0,0 +1,36 @@
+/* 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_GCOV_SUMMARY_H
+#define GCC_GCOV_SUMMARY_H
+
+#include "gcov.h"
+
+#include <vector>
+
+namespace gcov {
+
+/* Recompute OUT from FUNCTIONS.  This includes the aggregate counts and the
+   per-percentile working set (cutoff/min_count/num_counts) that auto-profile's
+   get_threshold_count turns into the hot-count threshold.  */
+void compute_summary (const std::vector<gcov_function> &functions,
+                     gcov_summary &out);
+
+} /* namespace gcov.  */
+
+#endif /* GCC_GCOV_SUMMARY_H.  */
-- 
2.34.1

Reply via email to