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