[llvm] [memprof] Introduce readMemProf (NFC) (PR #88095)

Kazu Hirata via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 9 00:04:18 PDT 2024


https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/88095

This patch refactors the deserilization of the MemProf data to a
switch statement style.

  switch (Version) {
  case Version0:
    return ...;
  case Version1:
    return ...;
  }

Since memprof::Version0 doesn't really have a version number in the
header, the switch statement only has one case for now.


>From b6e29e1be18ebd37ee9a84ab1d8fe0c24a65336c Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Mon, 8 Apr 2024 21:14:11 -0700
Subject: [PATCH] [memprof] Introduce readMemProf (NFC)

This patch refactors the deserilization of the MemProf data to a
switch statement style.

  switch (Version) {
  case Version0:
    return ...;
  case Version1:
    return ...;
  }

Since memprof::Version0 doesn't really have a version number in the
header, the switch statement only has one case for now.
---
 llvm/lib/ProfileData/InstrProfReader.cpp | 209 +++++++++++++++--------
 1 file changed, 140 insertions(+), 69 deletions(-)

diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index 884334ed070e8d..3981e336b9b595 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -1206,6 +1206,143 @@ IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
   }
 }
 
+static Error
+readMemProfV0(const unsigned char *Start, const unsigned char *Ptr,
+              uint64_t FirstWord, memprof::MemProfSchema &Schema,
+              std::unique_ptr<MemProfRecordHashTable> &MemProfRecordTable,
+              std::unique_ptr<MemProfFrameHashTable> &MemProfFrameTable) {
+  using namespace support;
+
+  // The value returned from RecordTableGenerator.Emit.
+  const uint64_t RecordTableOffset = FirstWord;
+  // The offset in the stream right before invoking
+  // FrameTableGenerator.Emit.
+  const uint64_t FramePayloadOffset =
+      support::endian::readNext<uint64_t, llvm::endianness::little, unaligned>(
+          Ptr);
+  // The value returned from FrameTableGenerator.Emit.
+  const uint64_t FrameTableOffset =
+      support::endian::readNext<uint64_t, llvm::endianness::little, unaligned>(
+          Ptr);
+
+  // Read the schema.
+  auto SchemaOr = memprof::readMemProfSchema(Ptr);
+  if (!SchemaOr)
+    return SchemaOr.takeError();
+  Schema = SchemaOr.get();
+
+  // Now initialize the table reader with a pointer into data buffer.
+  MemProfRecordTable.reset(MemProfRecordHashTable::Create(
+      /*Buckets=*/Start + RecordTableOffset,
+      /*Payload=*/Ptr,
+      /*Base=*/Start, memprof::RecordLookupTrait(memprof::Version0, Schema)));
+
+  // Initialize the frame table reader with the payload and bucket offsets.
+  MemProfFrameTable.reset(MemProfFrameHashTable::Create(
+      /*Buckets=*/Start + FrameTableOffset,
+      /*Payload=*/Start + FramePayloadOffset,
+      /*Base=*/Start, memprof::FrameLookupTrait()));
+
+#ifdef EXPENSIVE_CHECKS
+  // Go through all the records and verify that CSId has been correctly
+  // populated.  Do this only under EXPENSIVE_CHECKS.  Otherwise, we
+  // would defeat the purpose of OnDiskIterableChainedHashTable.
+  for (const auto &Record : MemProfRecordTable->data())
+    verifyIndexedMemProfRecord(Record);
+#endif
+
+  return Error::success();
+}
+
+static Error
+readMemProfV1(const unsigned char *Start, const unsigned char *Ptr,
+              memprof::MemProfSchema &Schema,
+              std::unique_ptr<MemProfRecordHashTable> &MemProfRecordTable,
+              std::unique_ptr<MemProfFrameHashTable> &MemProfFrameTable) {
+  using namespace support;
+
+  // The value returned from RecordTableGenerator.Emit.
+  const uint64_t RecordTableOffset =
+      support::endian::readNext<uint64_t, llvm::endianness::little, unaligned>(
+          Ptr);
+  // The offset in the stream right before invoking
+  // FrameTableGenerator.Emit.
+  const uint64_t FramePayloadOffset =
+      support::endian::readNext<uint64_t, llvm::endianness::little, unaligned>(
+          Ptr);
+  // The value returned from FrameTableGenerator.Emit.
+  const uint64_t FrameTableOffset =
+      support::endian::readNext<uint64_t, llvm::endianness::little, unaligned>(
+          Ptr);
+
+  // Read the schema.
+  auto SchemaOr = memprof::readMemProfSchema(Ptr);
+  if (!SchemaOr)
+    return SchemaOr.takeError();
+  Schema = SchemaOr.get();
+
+  // Now initialize the table reader with a pointer into data buffer.
+  MemProfRecordTable.reset(MemProfRecordHashTable::Create(
+      /*Buckets=*/Start + RecordTableOffset,
+      /*Payload=*/Ptr,
+      /*Base=*/Start, memprof::RecordLookupTrait(memprof::Version1, Schema)));
+
+  // Initialize the frame table reader with the payload and bucket offsets.
+  MemProfFrameTable.reset(MemProfFrameHashTable::Create(
+      /*Buckets=*/Start + FrameTableOffset,
+      /*Payload=*/Start + FramePayloadOffset,
+      /*Base=*/Start, memprof::FrameLookupTrait()));
+
+#ifdef EXPENSIVE_CHECKS
+  // Go through all the records and verify that CSId has been correctly
+  // populated.  Do this only under EXPENSIVE_CHECKS.  Otherwise, we
+  // would defeat the purpose of OnDiskIterableChainedHashTable.
+  for (const auto &Record : MemProfRecordTable->data())
+    verifyIndexedMemProfRecord(Record);
+#endif
+
+  return Error::success();
+}
+
+static Error
+readMemProf(const unsigned char *Start, uint64_t MemProfOffset,
+            memprof::MemProfSchema &Schema,
+            std::unique_ptr<MemProfRecordHashTable> &MemProfRecordTable,
+            std::unique_ptr<MemProfFrameHashTable> &MemProfFrameTable) {
+  using namespace support;
+
+  const unsigned char *Ptr = Start + MemProfOffset;
+
+  // Read the first 64-bit word, which may be RecordTableOffset in
+  // memprof::MemProfVersion0 or the MemProf version number in
+  // memprof::MemProfVersion1.
+  const uint64_t FirstWord =
+      support::endian::readNext<uint64_t, llvm::endianness::little, unaligned>(
+          Ptr);
+
+  switch (FirstWord) {
+  case memprof::Version1:
+    return readMemProfV1(Start, Ptr, Schema, MemProfRecordTable,
+                         MemProfFrameTable);
+  default:
+    break;
+  }
+  if (FirstWord >= 24) {
+    // This is a heuristic/hack to detect memprof::MemProfVersion0,
+    // which does not have a version field in the header.
+    // In memprof::MemProfVersion0, FirstWord will be RecordTableOffset,
+    // which should be at least 24 because of the MemProf header size.
+    return readMemProfV0(Start, Ptr, FirstWord, Schema, MemProfRecordTable,
+                         MemProfFrameTable);
+  }
+  return make_error<InstrProfError>(
+      instrprof_error::unsupported_version,
+      formatv("MemProf version {} not supported; "
+              "requires version between {} and {}, inclusive",
+              FirstWord, memprof::MinimumSupportedVersion,
+              memprof::MaximumSupportedVersion));
+}
+
 Error IndexedInstrProfReader::readHeader() {
   using namespace support;
 
@@ -1249,75 +1386,9 @@ Error IndexedInstrProfReader::readHeader() {
         endian::byte_swap<uint64_t, llvm::endianness::little>(
             Header->MemProfOffset);
 
-    const unsigned char *Ptr = Start + MemProfOffset;
-
-    // Read the first 64-bit word, which may be RecordTableOffset in
-    // memprof::MemProfVersion0 or the MemProf version number in
-    // memprof::MemProfVersion1.
-    const uint64_t FirstWord =
-        support::endian::readNext<uint64_t, llvm::endianness::little,
-                                  unaligned>(Ptr);
-
-    memprof::IndexedVersion Version = memprof::Version0;
-    if (FirstWord == memprof::Version1) {
-      // Everything is good.  We can proceed to deserialize the rest.
-      Version = memprof::Version1;
-    } else if (FirstWord >= 24) {
-      // This is a heuristic/hack to detect memprof::MemProfVersion0,
-      // which does not have a version field in the header.
-      // In memprof::MemProfVersion0, FirstWord will be RecordTableOffset,
-      // which should be at least 24 because of the MemProf header size.
-      Version = memprof::Version0;
-    } else {
-      return make_error<InstrProfError>(
-          instrprof_error::unsupported_version,
-          formatv("MemProf version {} not supported; "
-                  "requires version between {} and {}, inclusive",
-                  FirstWord, memprof::MinimumSupportedVersion,
-                  memprof::MaximumSupportedVersion));
-    }
-
-    // The value returned from RecordTableGenerator.Emit.
-    const uint64_t RecordTableOffset =
-        Version == memprof::Version0
-            ? FirstWord
-            : support::endian::readNext<uint64_t, llvm::endianness::little,
-                                        unaligned>(Ptr);
-    // The offset in the stream right before invoking
-    // FrameTableGenerator.Emit.
-    const uint64_t FramePayloadOffset =
-        support::endian::readNext<uint64_t, llvm::endianness::little,
-                                  unaligned>(Ptr);
-    // The value returned from FrameTableGenerator.Emit.
-    const uint64_t FrameTableOffset =
-        support::endian::readNext<uint64_t, llvm::endianness::little,
-                                  unaligned>(Ptr);
-
-    // Read the schema.
-    auto SchemaOr = memprof::readMemProfSchema(Ptr);
-    if (!SchemaOr)
-      return SchemaOr.takeError();
-    Schema = SchemaOr.get();
-
-    // Now initialize the table reader with a pointer into data buffer.
-    MemProfRecordTable.reset(MemProfRecordHashTable::Create(
-        /*Buckets=*/Start + RecordTableOffset,
-        /*Payload=*/Ptr,
-        /*Base=*/Start, memprof::RecordLookupTrait(memprof::Version1, Schema)));
-
-    // Initialize the frame table reader with the payload and bucket offsets.
-    MemProfFrameTable.reset(MemProfFrameHashTable::Create(
-        /*Buckets=*/Start + FrameTableOffset,
-        /*Payload=*/Start + FramePayloadOffset,
-        /*Base=*/Start, memprof::FrameLookupTrait()));
-
-#ifdef EXPENSIVE_CHECKS
-    // Go through all the records and verify that CSId has been correctly
-    // populated.  Do this only under EXPENSIVE_CHECKS.  Otherwise, we
-    // would defeat the purpose of OnDiskIterableChainedHashTable.
-    for (const auto &Record : MemProfRecordTable->data())
-      verifyIndexedMemProfRecord(Record);
-#endif
+    if (Error E = readMemProf(Start, MemProfOffset, Schema, MemProfRecordTable,
+                              MemProfFrameTable))
+      return E;
   }
 
   // BinaryIdOffset field in the header is only valid when the format version



More information about the llvm-commits mailing list