[llvm] f4b7944 - Revert "[memprof] Store callsite metadata with memprof records."

Mitch Phillips via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 21 15:59:31 PDT 2022


Author: Mitch Phillips
Date: 2022-03-21T15:59:13-07:00
New Revision: f4b794427e8037a4e952cacdfe7201e961f31a6f

URL: https://github.com/llvm/llvm-project/commit/f4b794427e8037a4e952cacdfe7201e961f31a6f
DIFF: https://github.com/llvm/llvm-project/commit/f4b794427e8037a4e952cacdfe7201e961f31a6f.diff

LOG: Revert "[memprof] Store callsite metadata with memprof records."

This reverts commit 0d362c90d335509c57c0fbd01ae1829e2b9c3765.

Reason: Causes the MSan buildbot to fail (see comments on
https://reviews.llvm.org/D121179 for more information

Added: 
    

Modified: 
    llvm/include/llvm/ProfileData/InstrProfWriter.h
    llvm/include/llvm/ProfileData/MemProf.h
    llvm/include/llvm/ProfileData/RawMemProfReader.h
    llvm/lib/ProfileData/InstrProfWriter.cpp
    llvm/lib/ProfileData/MemProf.cpp
    llvm/lib/ProfileData/RawMemProfReader.cpp
    llvm/test/tools/llvm-profdata/memprof-basic.test
    llvm/test/tools/llvm-profdata/memprof-inline.test
    llvm/tools/llvm-profdata/llvm-profdata.cpp
    llvm/unittests/ProfileData/InstrProfTest.cpp
    llvm/unittests/ProfileData/MemProfTest.cpp

Removed: 
    llvm/test/tools/llvm-profdata/Inputs/inline.memprofexe


################################################################################
diff  --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h
index bb37f41cddc86..a8cfd380c4a19 100644
--- a/llvm/include/llvm/ProfileData/InstrProfWriter.h
+++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h
@@ -15,9 +15,7 @@
 #define LLVM_PROFILEDATA_INSTRPROFWRITER_H
 
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/IR/GlobalValue.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/MemProf.h"
 #include "llvm/Support/Endian.h"
@@ -43,7 +41,7 @@ class InstrProfWriter {
 
   // A map to hold memprof data per function. The lower 64 bits obtained from
   // the md5 hash of the function name is used to index into the map.
-  llvm::MapVector<GlobalValue::GUID, memprof::MemProfRecord> MemProfData;
+  memprof::FunctionMemProfMap MemProfData;
 
   // An enum describing the attributes of the profile.
   InstrProfKind ProfileKind = InstrProfKind::Unknown;
@@ -65,8 +63,7 @@ class InstrProfWriter {
     addRecord(std::move(I), 1, Warn);
   }
 
-  void addRecord(const GlobalValue::GUID Id,
-                 const memprof::MemProfRecord &Record,
+  void addRecord(const ::llvm::memprof::MemProfRecord &MR,
                  function_ref<void(Error)> Warn);
 
   /// Merge existing function counts from the given writer.

diff  --git a/llvm/include/llvm/ProfileData/MemProf.h b/llvm/include/llvm/ProfileData/MemProf.h
index 3055b38ebe342..1436ea2a32938 100644
--- a/llvm/include/llvm/ProfileData/MemProf.h
+++ b/llvm/include/llvm/ProfileData/MemProf.h
@@ -82,9 +82,9 @@ struct PortableMemInfoBlock {
 
   // Print out the contents of the MemInfoBlock in YAML format.
   void printYAML(raw_ostream &OS) const {
-    OS << "      MemInfoBlock:\n";
+    OS << "    MemInfoBlock:\n";
 #define MIBEntryDef(NameTag, Name, Type)                                       \
-  OS << "        " << #Name << ": " << Name << "\n";
+  OS << "      " << #Name << ": " << Name << "\n";
 #include "llvm/ProfileData/MIBEntryDef.inc"
 #undef MIBEntryDef
   }
@@ -133,7 +133,6 @@ struct PortableMemInfoBlock {
 #undef MIBEntryDef
 };
 
-// Holds the memprof profile information for a function.
 struct MemProfRecord {
   // Describes a call frame for a dynamic allocation context. The contents of
   // the frame are populated by symbolizing the stack depot call frame from the
@@ -194,152 +193,64 @@ struct MemProfRecord {
       return sizeof(Frame::Function) + sizeof(Frame::LineOffset) +
              sizeof(Frame::Column) + sizeof(Frame::IsInlineFrame);
     }
-
-    // Print the frame information in YAML format.
-    void printYAML(raw_ostream &OS) const {
-      OS << "      -\n"
-         << "        Function: " << Function << "\n"
-         << "        LineOffset: " << LineOffset << "\n"
-         << "        Column: " << Column << "\n"
-         << "        Inline: " << IsInlineFrame << "\n";
-    }
   };
 
-  struct AllocationInfo {
-    // The dynamic calling context for the allocation.
-    llvm::SmallVector<Frame> CallStack;
-    // The statistics obtained from the runtime for the allocation.
-    PortableMemInfoBlock Info;
-
-    AllocationInfo() = default;
-    AllocationInfo(ArrayRef<Frame> CS, const MemInfoBlock &MB)
-        : CallStack(CS.begin(), CS.end()), Info(MB) {}
-
-    void printYAML(raw_ostream &OS) const {
-      OS << "    -\n";
-      OS << "      Callstack:\n";
-      // TODO: Print out the frame on one line with to make it easier for deep
-      // callstacks once we have a test to check valid YAML is generated.
-      for (const auto &Frame : CallStack)
-        Frame.printYAML(OS);
-      Info.printYAML(OS);
-    }
-
-    size_t serializedSize() const {
-      return sizeof(uint64_t) + // The number of frames to serialize.
-             Frame::serializedSize() *
-                 CallStack.size() + // The contents of the frames.
-             PortableMemInfoBlock::serializedSize(); // The size of the payload.
-    }
-
-    bool operator==(const AllocationInfo &Other) const {
-      if (Other.Info != Info)
-        return false;
-
-      if (Other.CallStack.size() != CallStack.size())
-        return false;
-
-      for (size_t J = 0; J < Other.CallStack.size(); J++) {
-        if (Other.CallStack[J] != CallStack[J])
-          return false;
-      }
-      return true;
-    }
-
-    bool operator!=(const AllocationInfo &Other) const {
-      return !operator==(Other);
-    }
-  };
-
-  // Memory allocation sites in this function for which we have memory profiling
-  // data.
-  llvm::SmallVector<AllocationInfo> AllocSites;
-  // Holds call sites in this function which are part of some memory allocation
-  // context. We store this as a list of locations, each with its list of
-  // inline locations in bottom-up order i.e. from leaf to root. The inline
-  // location list may include additional entries, users should pick the last
-  // entry in the list with the same function GUID.
-  llvm::SmallVector<llvm::SmallVector<Frame>> CallSites;
+  // The dynamic calling context for the allocation.
+  llvm::SmallVector<Frame> CallStack;
+  // The statistics obtained from the runtime for the allocation.
+  PortableMemInfoBlock Info;
 
   void clear() {
-    AllocSites.clear();
-    CallSites.clear();
-  }
-
-  void merge(const MemProfRecord &Other) {
-    // TODO: Filter out duplicates which may occur if multiple memprof profiles
-    // are merged together using llvm-profdata.
-    AllocSites.append(Other.AllocSites);
-    CallSites.append(Other.CallSites);
+    CallStack.clear();
+    Info.clear();
   }
 
   size_t serializedSize() const {
-    size_t Result = sizeof(GlobalValue::GUID);
-    for (const AllocationInfo &N : AllocSites)
-      Result += N.serializedSize();
-
-    // The number of callsites we have information for.
-    Result += sizeof(uint64_t);
-    for (const auto &Frames : CallSites) {
-      // The number of frames to serialize.
-      Result += sizeof(uint64_t);
-      for (const Frame &F : Frames)
-        Result += F.serializedSize();
-    }
-    return Result;
+    return sizeof(uint64_t) + // The number of frames to serialize.
+           Frame::serializedSize() *
+               CallStack.size() + // The contents of the frames.
+           PortableMemInfoBlock::serializedSize(); // The size of the payload.
   }
 
   // Prints out the contents of the memprof record in YAML.
   void print(llvm::raw_ostream &OS) const {
-    if (!AllocSites.empty()) {
-      OS << "    AllocSites:\n";
-      for (const AllocationInfo &N : AllocSites)
-        N.printYAML(OS);
+    OS << "    Callstack:\n";
+    // TODO: Print out the frame on one line with to make it easier for deep
+    // callstacks once we have a test to check valid YAML is generated.
+    for (const auto &Frame : CallStack) {
+      OS << "    -\n"
+         << "      Function: " << Frame.Function << "\n"
+         << "      LineOffset: " << Frame.LineOffset << "\n"
+         << "      Column: " << Frame.Column << "\n"
+         << "      Inline: " << Frame.IsInlineFrame << "\n";
     }
 
-    if (!CallSites.empty()) {
-      OS << "    CallSites:\n";
-      for (const auto &Frames : CallSites) {
-        for (const auto &F : Frames) {
-          OS << "    -\n";
-          F.printYAML(OS);
-        }
-      }
-    }
+    Info.printYAML(OS);
   }
 
   bool operator==(const MemProfRecord &Other) const {
-    if (Other.AllocSites.size() != AllocSites.size())
+    if (Other.Info != Info)
       return false;
 
-    if (Other.CallSites.size() != CallSites.size())
+    if (Other.CallStack.size() != CallStack.size())
       return false;
 
-    for (size_t I = 0; I < AllocSites.size(); I++) {
-      if (AllocSites[I] != Other.AllocSites[I])
-        return false;
-    }
-
-    for (size_t I = 0; I < CallSites.size(); I++) {
-      if (CallSites[I] != Other.CallSites[I])
+    for (size_t I = 0; I < Other.CallStack.size(); I++) {
+      if (Other.CallStack[I] != CallStack[I])
         return false;
     }
     return true;
   }
+};
 
-  // Serializes the memprof records in \p Records to the ostream \p OS based on
-  // the schema provided in \p Schema.
-  void serialize(const MemProfSchema &Schema, raw_ostream &OS);
-
-  // Deserializes memprof records from the Buffer.
-  static MemProfRecord deserialize(const MemProfSchema &Schema,
-                                   const unsigned char *Buffer);
+// Serializes the memprof records in \p Records to the ostream \p OS based on
+// the schema provided in \p Schema.
+void serializeRecords(const ArrayRef<MemProfRecord> Records,
+                      const MemProfSchema &Schema, raw_ostream &OS);
 
-  // Returns the GUID for the function name after canonicalization. For memprof,
-  // we remove any .llvm suffix added by LTO. MemProfRecords are mapped to
-  // functions using this GUID.
-  static GlobalValue::GUID getGUID(const StringRef FunctionName);
-};
+// Deserializes memprof records from the Buffer
+SmallVector<MemProfRecord, 4> deserializeRecords(const MemProfSchema &Schema,
+                                                 const unsigned char *Buffer);
 
 // Reads a memprof schema from a buffer. All entries in the buffer are
 // interpreted as uint64_t. The first entry in the buffer denotes the number of
@@ -348,11 +259,14 @@ struct MemProfRecord {
 // byte past the schema contents.
 Expected<MemProfSchema> readMemProfSchema(const unsigned char *&Buffer);
 
+using FunctionMemProfMap =
+    DenseMap<uint64_t, SmallVector<memprof::MemProfRecord, 4>>;
+
 /// Trait for lookups into the on-disk hash table for memprof format in the
 /// indexed profile.
 class MemProfRecordLookupTrait {
 public:
-  using data_type = const MemProfRecord &;
+  using data_type = ArrayRef<MemProfRecord>;
   using internal_key_type = uint64_t;
   using external_key_type = uint64_t;
   using hash_value_type = uint64_t;
@@ -383,15 +297,15 @@ class MemProfRecordLookupTrait {
 
   data_type ReadData(uint64_t K, const unsigned char *D,
                      offset_type /*Unused*/) {
-    Record = MemProfRecord::deserialize(Schema, D);
-    return Record;
+    Records = deserializeRecords(Schema, D);
+    return Records;
   }
 
 private:
   // Holds the memprof schema used to deserialize records.
   MemProfSchema Schema;
   // Holds the records from one function deserialized from the indexed format.
-  MemProfRecord Record;
+  llvm::SmallVector<MemProfRecord, 4> Records;
 };
 
 class MemProfRecordWriterTrait {
@@ -399,8 +313,8 @@ class MemProfRecordWriterTrait {
   using key_type = uint64_t;
   using key_type_ref = uint64_t;
 
-  using data_type = MemProfRecord;
-  using data_type_ref = MemProfRecord &;
+  using data_type = ArrayRef<MemProfRecord>;
+  using data_type_ref = ArrayRef<MemProfRecord>;
 
   using hash_value_type = uint64_t;
   using offset_type = uint64_t;
@@ -419,9 +333,17 @@ class MemProfRecordWriterTrait {
     using namespace support;
 
     endian::Writer LE(Out, little);
+
     offset_type N = sizeof(K);
     LE.write<offset_type>(N);
-    offset_type M = V.serializedSize();
+
+    offset_type M = 0;
+
+    M += sizeof(uint64_t);
+    for (const auto &Record : V) {
+      M += Record.serializedSize();
+    }
+
     LE.write<offset_type>(M);
     return std::make_pair(N, M);
   }
@@ -435,7 +357,7 @@ class MemProfRecordWriterTrait {
   void EmitData(raw_ostream &Out, key_type_ref /*Unused*/, data_type_ref V,
                 offset_type /*Unused*/) {
     assert(Schema != nullptr && "MemProf schema is not initialized!");
-    V.serialize(*Schema, Out);
+    serializeRecords(V, *Schema, Out);
   }
 };
 

diff  --git a/llvm/include/llvm/ProfileData/RawMemProfReader.h b/llvm/include/llvm/ProfileData/RawMemProfReader.h
index 872a71fd5cf56..944d71386a4b2 100644
--- a/llvm/include/llvm/ProfileData/RawMemProfReader.h
+++ b/llvm/include/llvm/ProfileData/RawMemProfReader.h
@@ -14,11 +14,9 @@
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/MapVector.h"
-#include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
-#include "llvm/IR/GlobalValue.h"
 #include "llvm/Object/Binary.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/ProfileData/InstrProfReader.h"
@@ -59,16 +57,15 @@ class RawMemProfReader {
   static Expected<std::unique_ptr<RawMemProfReader>>
   create(const Twine &Path, const StringRef ProfiledBinary);
 
-  using GuidMemProfRecordPair = std::pair<GlobalValue::GUID, MemProfRecord>;
-  using Iterator = InstrProfIterator<GuidMemProfRecordPair, RawMemProfReader>;
+  Error readNextRecord(MemProfRecord &Record);
+
+  using Iterator = InstrProfIterator<MemProfRecord, RawMemProfReader>;
   Iterator end() { return Iterator(); }
   Iterator begin() {
-    Iter = FunctionProfileData.begin();
+    Iter = ProfileData.begin();
     return Iterator(this);
   }
 
-  Error readNextRecord(GuidMemProfRecordPair &GuidRecord);
-
   // The RawMemProfReader only holds memory profile information.
   InstrProfKind getProfileKind() const { return InstrProfKind::MemProf; }
 
@@ -78,7 +75,7 @@ class RawMemProfReader {
                    llvm::MapVector<uint64_t, MemInfoBlock> &Prof,
                    CallStackMap &SM)
       : Symbolizer(std::move(Sym)), SegmentInfo(Seg.begin(), Seg.end()),
-        CallstackProfileData(Prof), StackMap(SM) {
+        ProfileData(Prof), StackMap(SM) {
     // We don't call initialize here since there is no raw profile to read. The
     // test should pass in the raw profile as structured data.
 
@@ -86,8 +83,6 @@ class RawMemProfReader {
     // initialized properly.
     if (Error E = symbolizeAndFilterStackFrames())
       report_fatal_error(std::move(E));
-    if (Error E = mapRawProfileToRecords())
-      report_fatal_error(std::move(E));
   }
 
 private:
@@ -101,12 +96,10 @@ class RawMemProfReader {
   // symbolize or those that belong to the runtime. For profile entries where
   // the entire callstack is pruned, we drop the entry from the profile.
   Error symbolizeAndFilterStackFrames();
-  // Construct memprof records for each function and store it in the
-  // `FunctionProfileData` map. A function may have allocation profile data or
-  // callsite data or both.
-  Error mapRawProfileToRecords();
 
   object::SectionedAddress getModuleOffset(uint64_t VirtualAddress);
+  Error fillRecord(const uint64_t Id, const MemInfoBlock &MIB,
+                   MemProfRecord &Record);
   // Prints aggregate counts for each raw profile parsed from the DataBuffer in
   // YAML format.
   void printSummaries(raw_ostream &OS) const;
@@ -119,15 +112,15 @@ class RawMemProfReader {
   llvm::SmallVector<SegmentEntry, 16> SegmentInfo;
   // A map from callstack id (same as key in CallStackMap below) to the heap
   // information recorded for that allocation context.
-  llvm::MapVector<uint64_t, MemInfoBlock> CallstackProfileData;
+  llvm::MapVector<uint64_t, MemInfoBlock> ProfileData;
   CallStackMap StackMap;
 
   // Cached symbolization from PC to Frame.
   llvm::DenseMap<uint64_t, llvm::SmallVector<MemProfRecord::Frame>>
       SymbolizedFrame;
 
-  llvm::MapVector<GlobalValue::GUID, MemProfRecord> FunctionProfileData;
-  llvm::MapVector<GlobalValue::GUID, MemProfRecord>::iterator Iter;
+  // Iterator to read from the ProfileData MapVector.
+  llvm::MapVector<uint64_t, MemInfoBlock>::iterator Iter = ProfileData.end();
 };
 
 } // namespace memprof

diff  --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index 494d563917678..6c08f83be5dc2 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -253,14 +253,28 @@ void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
   Dest.sortValueData();
 }
 
-void InstrProfWriter::addRecord(const Function::GUID Id,
-                                const memprof::MemProfRecord &Record,
+void InstrProfWriter::addRecord(const memprof::MemProfRecord &MR,
                                 function_ref<void(Error)> Warn) {
-  auto Result = MemProfData.insert({Id, Record});
-  if (!Result.second) {
-    memprof::MemProfRecord &Existing = Result.first->second;
-    Existing.merge(Record);
+  // Use 0 as a sentinel value since its highly unlikely that the lower 64-bits
+  // of a 128 bit md5 hash will be all zeros.
+  // TODO: Move this Key frame detection to the contructor to avoid having to
+  // scan all the callstacks again when adding a new record.
+  uint64_t Key = 0;
+  for (auto Iter = MR.CallStack.rbegin(), End = MR.CallStack.rend();
+       Iter != End; Iter++) {
+    if (!Iter->IsInlineFrame) {
+      Key = Iter->Function;
+      break;
+    }
+  }
+
+  if (Key == 0) {
+    Warn(make_error<InstrProfError>(
+        instrprof_error::invalid_prof,
+        "could not determine leaf function for memprof record."));
   }
+
+  MemProfData[Key].push_back(MR);
 }
 
 void InstrProfWriter::mergeRecordsFromWriter(InstrProfWriter &&IPW,
@@ -269,9 +283,9 @@ void InstrProfWriter::mergeRecordsFromWriter(InstrProfWriter &&IPW,
     for (auto &Func : I.getValue())
       addRecord(I.getKey(), Func.first, std::move(Func.second), 1, Warn);
 
-  for (auto &I : IPW.MemProfData) {
-    addRecord(I.first, I.second, Warn);
-  }
+  for (auto &I : IPW.MemProfData)
+    for (const auto &MR : I.second)
+      addRecord(MR, Warn);
 }
 
 bool InstrProfWriter::shouldEncodeData(const ProfilingData &PD) {
@@ -401,8 +415,8 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
     MemProfWriter->Schema = &Schema;
     OnDiskChainedHashTableGenerator<memprof::MemProfRecordWriterTrait>
         MemProfGenerator;
-    for (auto &I : MemProfData) {
-      // Insert the key (func hash) and value (memprof record).
+    for (const auto &I : MemProfData) {
+      // Insert the key (func hash) and value (vector of memprof records).
       MemProfGenerator.insert(I.first, I.second);
     }
 

diff  --git a/llvm/lib/ProfileData/MemProf.cpp b/llvm/lib/ProfileData/MemProf.cpp
index 92d759a88ea45..cdfc261256c65 100644
--- a/llvm/lib/ProfileData/MemProf.cpp
+++ b/llvm/lib/ProfileData/MemProf.cpp
@@ -1,6 +1,4 @@
 #include "llvm/ProfileData/MemProf.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/IR/Function.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/EndianStream.h"
@@ -8,76 +6,43 @@
 namespace llvm {
 namespace memprof {
 
-void MemProfRecord::serialize(const MemProfSchema &Schema, raw_ostream &OS) {
+void serializeRecords(const ArrayRef<MemProfRecord> Records,
+                      const MemProfSchema &Schema, raw_ostream &OS) {
   using namespace support;
 
   endian::Writer LE(OS, little);
 
-  LE.write<uint64_t>(AllocSites.size());
-  for (const AllocationInfo &N : AllocSites) {
-    LE.write<uint64_t>(N.CallStack.size());
-    for (const Frame &F : N.CallStack)
-      F.serialize(OS);
-    N.Info.serialize(Schema, OS);
-  }
-
-  // Related contexts.
-  LE.write<uint64_t>(CallSites.size());
-  for (const auto &Frames : CallSites) {
-    LE.write<uint64_t>(Frames.size());
-    for (const Frame &F : Frames)
+  LE.write<uint64_t>(Records.size());
+  for (const MemProfRecord &MR : Records) {
+    LE.write<uint64_t>(MR.CallStack.size());
+    for (const MemProfRecord::Frame &F : MR.CallStack) {
       F.serialize(OS);
+    }
+    MR.Info.serialize(Schema, OS);
   }
 }
 
-MemProfRecord MemProfRecord::deserialize(const MemProfSchema &Schema,
-                                         const unsigned char *Ptr) {
+SmallVector<MemProfRecord, 4> deserializeRecords(const MemProfSchema &Schema,
+                                                 const unsigned char *Ptr) {
   using namespace support;
 
-  MemProfRecord Record;
-
-  // Read the meminfo nodes.
-  const uint64_t NumNodes = endian::readNext<uint64_t, little, unaligned>(Ptr);
-  for (uint64_t I = 0; I < NumNodes; I++) {
-    MemProfRecord::AllocationInfo Node;
+  SmallVector<MemProfRecord, 4> Records;
+  const uint64_t NumRecords =
+      endian::readNext<uint64_t, little, unaligned>(Ptr);
+  for (uint64_t I = 0; I < NumRecords; I++) {
+    MemProfRecord MR;
     const uint64_t NumFrames =
         endian::readNext<uint64_t, little, unaligned>(Ptr);
     for (uint64_t J = 0; J < NumFrames; J++) {
       const auto F = MemProfRecord::Frame::deserialize(Ptr);
       Ptr += MemProfRecord::Frame::serializedSize();
-      Node.CallStack.push_back(F);
+      MR.CallStack.push_back(F);
     }
-    Node.Info.deserialize(Schema, Ptr);
+    MR.Info.deserialize(Schema, Ptr);
     Ptr += PortableMemInfoBlock::serializedSize();
-    Record.AllocSites.push_back(Node);
+    Records.push_back(MR);
   }
-
-  // Read the callsite information.
-  const uint64_t NumCtxs = endian::readNext<uint64_t, little, unaligned>(Ptr);
-  for (uint64_t J = 0; J < NumCtxs; J++) {
-    const uint64_t NumFrames =
-        endian::readNext<uint64_t, little, unaligned>(Ptr);
-    llvm::SmallVector<Frame> Frames;
-    for (uint64_t K = 0; K < NumFrames; K++) {
-      const auto F = MemProfRecord::Frame::deserialize(Ptr);
-      Ptr += MemProfRecord::Frame::serializedSize();
-      Frames.push_back(F);
-    }
-    Record.CallSites.push_back(Frames);
-  }
-
-  return Record;
-}
-
-GlobalValue::GUID MemProfRecord::getGUID(const StringRef FunctionName) {
-  const auto Pos = FunctionName.find(".llvm.");
-
-  // We use the function guid which we expect to be a uint64_t. At
-  // this time, it is the lower 64 bits of the md5 of the function
-  // name. Any suffix with .llvm. is trimmed since these are added by
-  // thinLTO global promotion. At the time the profile is consumed,
-  // these suffixes will not be present.
-  return Function::getGUID(FunctionName.take_front(Pos));
+  return Records;
 }
 
 Expected<MemProfSchema> readMemProfSchema(const unsigned char *&Buffer) {

diff  --git a/llvm/lib/ProfileData/RawMemProfReader.cpp b/llvm/lib/ProfileData/RawMemProfReader.cpp
index a5b7ea9e728c3..a87410f6e5099 100644
--- a/llvm/lib/ProfileData/RawMemProfReader.cpp
+++ b/llvm/lib/ProfileData/RawMemProfReader.cpp
@@ -14,13 +14,13 @@
 #include <cstdint>
 #include <type_traits>
 
-#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
 #include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h"
+#include "llvm/IR/Function.h"
 #include "llvm/Object/Binary.h"
 #include "llvm/Object/ELFObjectFile.h"
 #include "llvm/Object/ObjectFile.h"
@@ -163,6 +163,11 @@ bool mergeStackMap(const CallStackMap &From, CallStackMap &To) {
   return false;
 }
 
+StringRef trimSuffix(const StringRef Name) {
+  const auto Pos = Name.find(".llvm.");
+  return Name.take_front(Pos);
+}
+
 Error report(Error E, const StringRef Context) {
   return joinErrors(createStringError(inconvertibleErrorCode(), Context),
                     std::move(E));
@@ -228,10 +233,9 @@ void RawMemProfReader::printYAML(raw_ostream &OS) {
   printSummaries(OS);
   // Print out the merged contents of the profiles.
   OS << "  Records:\n";
-  for (const auto &Entry : *this) {
+  for (const auto &Record : *this) {
     OS << "  -\n";
-    OS << "    FunctionGUID: " << Entry.first << "\n";
-    Entry.second.print(OS);
+    Record.print(OS);
   }
 }
 
@@ -284,90 +288,7 @@ Error RawMemProfReader::initialize() {
   if (Error E = readRawProfile())
     return E;
 
-  if (Error E = symbolizeAndFilterStackFrames())
-    return E;
-
-  return mapRawProfileToRecords();
-}
-
-Error RawMemProfReader::mapRawProfileToRecords() {
-  // Hold a mapping from function to each callsite location we encounter within
-  // it that is part of some dynamic allocation context. The location is stored
-  // as a pointer to a symbolized list of inline frames.
-  using LocationPtr = const llvm::SmallVector<MemProfRecord::Frame> *;
-  llvm::DenseMap<GlobalValue::GUID, llvm::SetVector<LocationPtr>>
-      PerFunctionCallSites;
-
-  // Convert the raw profile callstack data into memprof records. While doing so
-  // keep track of related contexts so that we can fill these in later.
-  for (const auto &Entry : CallstackProfileData) {
-    const uint64_t StackId = Entry.first;
-
-    auto It = StackMap.find(StackId);
-    if (It == StackMap.end())
-      return make_error<InstrProfError>(
-          instrprof_error::malformed,
-          "memprof callstack record does not contain id: " + Twine(StackId));
-
-    // Construct the symbolized callstack.
-    llvm::SmallVector<MemProfRecord::Frame> Callstack;
-    Callstack.reserve(It->getSecond().size());
-
-    llvm::ArrayRef<uint64_t> Addresses = It->getSecond();
-    for (size_t I = 0; I < Addresses.size(); I++) {
-      const uint64_t Address = Addresses[I];
-      assert(SymbolizedFrame.count(Address) > 0 &&
-             "Address not found in SymbolizedFrame map");
-      const SmallVector<MemProfRecord::Frame> &Frames =
-          SymbolizedFrame[Address];
-
-      assert(!Frames.back().IsInlineFrame &&
-             "The last frame should not be inlined");
-
-      // Record the callsites for each function. Skip the first frame of the
-      // first address since it is the allocation site itself that is recorded
-      // as an alloc site.
-      for (size_t J = 0; J < Frames.size(); J++) {
-        if (I == 0 && J == 0)
-          continue;
-        // We attach the entire bottom-up frame here for the callsite even
-        // though we only need the frames up to and including the frame for
-        // Frames[J].Function. This will enable better deduplication for
-        // compression in the future.
-        PerFunctionCallSites[Frames[J].Function].insert(&Frames);
-      }
-
-      // Add all the frames to the current allocation callstack.
-      Callstack.append(Frames.begin(), Frames.end());
-    }
-
-    // We attach the memprof record to each function bottom-up including the
-    // first non-inline frame.
-    for (size_t I = 0; /*Break out using the condition below*/; I++) {
-      auto Result =
-          FunctionProfileData.insert({Callstack[I].Function, MemProfRecord()});
-      MemProfRecord &Record = Result.first->second;
-      Record.AllocSites.emplace_back(Callstack, Entry.second);
-
-      if (!Callstack[I].IsInlineFrame)
-        break;
-    }
-  }
-
-  // Fill in the related callsites per function.
-  for (auto I = PerFunctionCallSites.begin(), E = PerFunctionCallSites.end();
-       I != E; I++) {
-    const GlobalValue::GUID Id = I->first;
-    // Some functions may have only callsite data and no allocation data. Here
-    // we insert a new entry for callsite data if we need to.
-    auto Result = FunctionProfileData.insert({Id, MemProfRecord()});
-    MemProfRecord &Record = Result.first->second;
-    for (LocationPtr Loc : I->getSecond()) {
-      Record.CallSites.push_back(*Loc);
-    }
-  }
-
-  return Error::success();
+  return symbolizeAndFilterStackFrames();
 }
 
 Error RawMemProfReader::symbolizeAndFilterStackFrames() {
@@ -410,10 +331,15 @@ Error RawMemProfReader::symbolizeAndFilterStackFrames() {
         LLVM_DEBUG(
             // Print out the name to guid mapping for debugging.
             llvm::dbgs() << "FunctionName: " << Frame.FunctionName << " GUID: "
-                         << MemProfRecord::getGUID(Frame.FunctionName)
+                         << Function::getGUID(trimSuffix(Frame.FunctionName))
                          << "\n";);
         SymbolizedFrame[VAddr].emplace_back(
-            MemProfRecord::getGUID(Frame.FunctionName),
+            // We use the function guid which we expect to be a uint64_t. At
+            // this time, it is the lower 64 bits of the md5 of the function
+            // name. Any suffix with .llvm. is trimmed since these are added by
+            // thinLTO global promotion. At the time the profile is consumed,
+            // these suffixes will not be present.
+            Function::getGUID(trimSuffix(Frame.FunctionName)),
             Frame.Line - Frame.StartLine, Frame.Column,
             // Only the last entry is not an inlined location.
             I != NumFrames - 1);
@@ -433,7 +359,7 @@ Error RawMemProfReader::symbolizeAndFilterStackFrames() {
   // Drop the entries where the callstack is empty.
   for (const uint64_t Id : EntriesToErase) {
     StackMap.erase(Id);
-    CallstackProfileData.erase(Id);
+    ProfileData.erase(Id);
   }
 
   if (StackMap.empty())
@@ -468,10 +394,10 @@ Error RawMemProfReader::readRawProfile() {
     // raw profiles in the same binary file are from the same process so the
     // stackdepot ids are the same.
     for (const auto &Value : readMemInfoBlocks(Next + Header->MIBOffset)) {
-      if (CallstackProfileData.count(Value.first)) {
-        CallstackProfileData[Value.first].Merge(Value.second);
+      if (ProfileData.count(Value.first)) {
+        ProfileData[Value.first].Merge(Value.second);
       } else {
-        CallstackProfileData[Value.first] = Value.second;
+        ProfileData[Value.first] = Value.second;
       }
     }
 
@@ -512,14 +438,29 @@ RawMemProfReader::getModuleOffset(const uint64_t VirtualAddress) {
   return object::SectionedAddress{VirtualAddress};
 }
 
-Error RawMemProfReader::readNextRecord(GuidMemProfRecordPair &GuidRecord) {
-  if (FunctionProfileData.empty())
+Error RawMemProfReader::fillRecord(const uint64_t Id, const MemInfoBlock &MIB,
+                                   MemProfRecord &Record) {
+  auto &CallStack = StackMap[Id];
+  for (const uint64_t Address : CallStack) {
+    assert(SymbolizedFrame.count(Address) &&
+           "Address not found in symbolized frame cache.");
+    Record.CallStack.append(SymbolizedFrame[Address]);
+  }
+  Record.Info = PortableMemInfoBlock(MIB);
+  return Error::success();
+}
+
+Error RawMemProfReader::readNextRecord(MemProfRecord &Record) {
+  if (ProfileData.empty())
     return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
 
-  if (Iter == FunctionProfileData.end())
+  if (Iter == ProfileData.end())
     return make_error<InstrProfError>(instrprof_error::eof);
 
-  GuidRecord = {Iter->first, Iter->second};
+  Record.clear();
+  if (Error E = fillRecord(Iter->first, Iter->second, Record)) {
+    return E;
+  }
   Iter++;
   return Error::success();
 }

diff  --git a/llvm/test/tools/llvm-profdata/Inputs/inline.memprofexe b/llvm/test/tools/llvm-profdata/Inputs/inline.memprofexe
deleted file mode 100755
index 9b6fd16e9a272..0000000000000
Binary files a/llvm/test/tools/llvm-profdata/Inputs/inline.memprofexe and /dev/null 
diff er

diff  --git a/llvm/test/tools/llvm-profdata/memprof-basic.test b/llvm/test/tools/llvm-profdata/memprof-basic.test
index e72728af101dd..af22c3b6c39b3 100644
--- a/llvm/test/tools/llvm-profdata/memprof-basic.test
+++ b/llvm/test/tools/llvm-profdata/memprof-basic.test
@@ -26,7 +26,7 @@ recorded.
 ```
 clang -fuse-ld=lld -Wl,--no-rosegment -gmlt -fdebug-info-for-profiling \
       -fmemory-profile -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer \
-      -fno-optimize-sibling-calls -m64 -Wl,-build-id source.c -o basic.memprofexe
+      -fno-optimize-sibling-calls -m64 -Wl,-build-id source.c -o basic.memprofexe 
 
 env MEMPROF_OPTIONS=log_path=stdout ./rawprofile.out > basic.memprofraw
 ```
@@ -46,59 +46,56 @@ CHECK-NEXT:     NumMibInfo: 3
 CHECK-NEXT:     NumStackOffsets: 3
 CHECK-NEXT:   Records:
 CHECK-NEXT:   -
-CHECK-NEXT:     FunctionGUID: {{[0-9]+}}
-CHECK-NEXT:     AllocSites:
+CHECK-NEXT:     Callstack:
 CHECK-NEXT:     -
-CHECK-NEXT:       Callstack:
-CHECK-NEXT:       -
-CHECK-NEXT:         Function: {{[0-9]+}}
-CHECK-NEXT:         LineOffset: 1
-CHECK-NEXT:         Column: 21
-CHECK-NEXT:         Inline: 0
-CHECK-NEXT:       MemInfoBlock:
-CHECK-NEXT:         AllocCount: 1
-CHECK-NEXT:         TotalAccessCount: 2
-CHECK-NEXT:         MinAccessCount: 2
-CHECK-NEXT:         MaxAccessCount: 2
-CHECK-NEXT:         TotalSize: 10
-CHECK-NEXT:         MinSize: 10
-CHECK-NEXT:         MaxSize: 10
-CHECK-NEXT:         AllocTimestamp: 986
-CHECK-NEXT:         DeallocTimestamp: 986
-CHECK-NEXT:         TotalLifetime: 0
-CHECK-NEXT:         MinLifetime: 0
-CHECK-NEXT:         MaxLifetime: 0
-CHECK-NEXT:         AllocCpuId: 56
-CHECK-NEXT:         DeallocCpuId: 56
-CHECK-NEXT:         NumMigratedCpu: 0
-CHECK-NEXT:         NumLifetimeOverlaps: 0
-CHECK-NEXT:         NumSameAllocCpu: 0
-CHECK-NEXT:         NumSameDeallocCpu: 0
-CHECK-NEXT:         DataTypeId: {{[0-9]+}}
+CHECK-NEXT:       Function: {{[0-9]+}}
+CHECK-NEXT:       LineOffset: 1
+CHECK-NEXT:       Column: 21
+CHECK-NEXT:       Inline: 0
+CHECK-NEXT:     MemInfoBlock:
+CHECK-NEXT:       AllocCount: 1
+CHECK-NEXT:       TotalAccessCount: 2
+CHECK-NEXT:       MinAccessCount: 2
+CHECK-NEXT:       MaxAccessCount: 2
+CHECK-NEXT:       TotalSize: 10
+CHECK-NEXT:       MinSize: 10
+CHECK-NEXT:       MaxSize: 10
+CHECK-NEXT:       AllocTimestamp: 986
+CHECK-NEXT:       DeallocTimestamp: 986
+CHECK-NEXT:       TotalLifetime: 0
+CHECK-NEXT:       MinLifetime: 0
+CHECK-NEXT:       MaxLifetime: 0
+CHECK-NEXT:       AllocCpuId: 56
+CHECK-NEXT:       DeallocCpuId: 56
+CHECK-NEXT:       NumMigratedCpu: 0
+CHECK-NEXT:       NumLifetimeOverlaps: 0
+CHECK-NEXT:       NumSameAllocCpu: 0
+CHECK-NEXT:       NumSameDeallocCpu: 0
+CHECK-NEXT:       DataTypeId: {{[0-9]+}}
+CHECK-NEXT:   -
+CHECK-NEXT:     Callstack:
 CHECK-NEXT:     -
-CHECK-NEXT:       Callstack:
-CHECK-NEXT:       -
-CHECK-NEXT:         Function: {{[0-9]+}}
-CHECK-NEXT:         LineOffset: 5
-CHECK-NEXT:         Column: 15
-CHECK-NEXT:         Inline: 0
-CHECK-NEXT:       MemInfoBlock:
-CHECK-NEXT:         AllocCount: 1
-CHECK-NEXT:         TotalAccessCount: 2
-CHECK-NEXT:         MinAccessCount: 2
-CHECK-NEXT:         MaxAccessCount: 2
-CHECK-NEXT:         TotalSize: 10
-CHECK-NEXT:         MinSize: 10
-CHECK-NEXT:         MaxSize: 10
-CHECK-NEXT:         AllocTimestamp: 987
-CHECK-NEXT:         DeallocTimestamp: 987
-CHECK-NEXT:         TotalLifetime: 0
-CHECK-NEXT:         MinLifetime: 0
-CHECK-NEXT:         MaxLifetime: 0
-CHECK-NEXT:         AllocCpuId: 56
-CHECK-NEXT:         DeallocCpuId: 56
-CHECK-NEXT:         NumMigratedCpu: 0
-CHECK-NEXT:         NumLifetimeOverlaps: 0
-CHECK-NEXT:         NumSameAllocCpu: 0
-CHECK-NEXT:         NumSameDeallocCpu: 0
-CHECK-NEXT:         DataTypeId: {{[0-9]+}}
+CHECK-NEXT:       Function: {{[0-9]+}}
+CHECK-NEXT:       LineOffset: 5
+CHECK-NEXT:       Column: 15
+CHECK-NEXT:       Inline: 0
+CHECK-NEXT:     MemInfoBlock:
+CHECK-NEXT:       AllocCount: 1
+CHECK-NEXT:       TotalAccessCount: 2
+CHECK-NEXT:       MinAccessCount: 2
+CHECK-NEXT:       MaxAccessCount: 2
+CHECK-NEXT:       TotalSize: 10
+CHECK-NEXT:       MinSize: 10
+CHECK-NEXT:       MaxSize: 10
+CHECK-NEXT:       AllocTimestamp: 987
+CHECK-NEXT:       DeallocTimestamp: 987
+CHECK-NEXT:       TotalLifetime: 0
+CHECK-NEXT:       MinLifetime: 0
+CHECK-NEXT:       MaxLifetime: 0
+CHECK-NEXT:       AllocCpuId: 56
+CHECK-NEXT:       DeallocCpuId: 56
+CHECK-NEXT:       NumMigratedCpu: 0
+CHECK-NEXT:       NumLifetimeOverlaps: 0
+CHECK-NEXT:       NumSameAllocCpu: 0
+CHECK-NEXT:       NumSameDeallocCpu: 0
+CHECK-NEXT:       DataTypeId: {{[0-9]+}}

diff  --git a/llvm/test/tools/llvm-profdata/memprof-inline.test b/llvm/test/tools/llvm-profdata/memprof-inline.test
index a31903e120c72..ecf4f178a9743 100644
--- a/llvm/test/tools/llvm-profdata/memprof-inline.test
+++ b/llvm/test/tools/llvm-profdata/memprof-inline.test
@@ -50,7 +50,7 @@ FunctionName: main GUID: 15822663052811949562
 [..omit output here which is checked below..]
 ```
 
-RUN: llvm-profdata show --memory %p/Inputs/inline.memprofraw --profiled-binary %p/Inputs/inline.memprofexe | FileCheck %s
+RUN: llvm-profdata show --memory %p/Inputs/inline.memprofraw --profiled-binary %p/Inputs/memprof-inline.exe
 
 CHECK:  MemprofProfile:
 CHECK-NEXT:  -
@@ -62,123 +62,45 @@ CHECK-NEXT:    NumMibInfo: 2
 CHECK-NEXT:    NumStackOffsets: 2
 CHECK-NEXT:  Records:
 CHECK-NEXT:  -
-CHECK-NEXT:    FunctionGUID: 15505678318020221912
-CHECK-NEXT:    AllocSites:
+CHECK-NEXT:    Callstack:
 CHECK-NEXT:    -
-CHECK-NEXT:      Callstack:
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 15505678318020221912
-CHECK-NEXT:        LineOffset: 1
-CHECK-NEXT:        Column: 15
-CHECK-NEXT:        Inline: 1
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 6699318081062747564
-CHECK-NEXT:        LineOffset: 0
-CHECK-NEXT:        Column: 18
-CHECK-NEXT:        Inline: 0
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 16434608426314478903
-CHECK-NEXT:        LineOffset: 0
-CHECK-NEXT:        Column: 19
-CHECK-NEXT:        Inline: 0
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 15822663052811949562
-CHECK-NEXT:        LineOffset: 1
-CHECK-NEXT:        Column: 3
-CHECK-NEXT:        Inline: 0
-CHECK-NEXT:      MemInfoBlock:
-CHECK-NEXT:        AllocCount: 1
-CHECK-NEXT:        TotalAccessCount: 1
-CHECK-NEXT:        MinAccessCount: 1
-CHECK-NEXT:        MaxAccessCount: 1
-CHECK-NEXT:        TotalSize: 1
-CHECK-NEXT:        MinSize: 1
-CHECK-NEXT:        MaxSize: 1
-CHECK-NEXT:        AllocTimestamp: 894
-CHECK-NEXT:        DeallocTimestamp: 894
-CHECK-NEXT:        TotalLifetime: 0
-CHECK-NEXT:        MinLifetime: 0
-CHECK-NEXT:        MaxLifetime: 0
-CHECK-NEXT:        AllocCpuId: 23
-CHECK-NEXT:        DeallocCpuId: 23
-CHECK-NEXT:        NumMigratedCpu: 0
-CHECK-NEXT:        NumLifetimeOverlaps: 0
-CHECK-NEXT:        NumSameAllocCpu: 0
-CHECK-NEXT:        NumSameDeallocCpu: 0
-CHECK-NEXT:        DataTypeId: {{[0-9]+}}
-CHECK-NEXT:  -
-CHECK-NEXT:    FunctionGUID: 6699318081062747564
-CHECK-NEXT:    AllocSites:
-CHECK-NEXT:    -
-CHECK-NEXT:      Callstack:
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 15505678318020221912
-CHECK-NEXT:        LineOffset: 1
-CHECK-NEXT:        Column: 15
-CHECK-NEXT:        Inline: 1
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 6699318081062747564
-CHECK-NEXT:        LineOffset: 0
-CHECK-NEXT:        Column: 18
-CHECK-NEXT:        Inline: 0
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 16434608426314478903
-CHECK-NEXT:        LineOffset: 0
-CHECK-NEXT:        Column: 19
-CHECK-NEXT:        Inline: 0
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 15822663052811949562
-CHECK-NEXT:        LineOffset: 1
-CHECK-NEXT:        Column: 3
-CHECK-NEXT:        Inline: 0
-CHECK-NEXT:      MemInfoBlock:
-CHECK-NEXT:        AllocCount: 1
-CHECK-NEXT:        TotalAccessCount: 1
-CHECK-NEXT:        MinAccessCount: 1
-CHECK-NEXT:        MaxAccessCount: 1
-CHECK-NEXT:        TotalSize: 1
-CHECK-NEXT:        MinSize: 1
-CHECK-NEXT:        MaxSize: 1
-CHECK-NEXT:        AllocTimestamp: 894
-CHECK-NEXT:        DeallocTimestamp: 894
-CHECK-NEXT:        TotalLifetime: 0
-CHECK-NEXT:        MinLifetime: 0
-CHECK-NEXT:        MaxLifetime: 0
-CHECK-NEXT:        AllocCpuId: 23
-CHECK-NEXT:        DeallocCpuId: 23
-CHECK-NEXT:        NumMigratedCpu: 0
-CHECK-NEXT:        NumLifetimeOverlaps: 0
-CHECK-NEXT:        NumSameAllocCpu: 0
-CHECK-NEXT:        NumSameDeallocCpu: 0
-CHECK-NEXT:        DataTypeId: {{[0-9]+}}
-CHECK-NEXT:    CallSites:
-CHECK-NEXT:    -
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 15505678318020221912
-CHECK-NEXT:        LineOffset: 1
-CHECK-NEXT:        Column: 15
-CHECK-NEXT:        Inline: 1
+CHECK-NEXT:      Function: 15505678318020221912
+CHECK-NEXT:      LineOffset: 1
+CHECK-NEXT:      Column: 15
+CHECK-NEXT:      Inline: 0
 CHECK-NEXT:    -
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 6699318081062747564
-CHECK-NEXT:        LineOffset: 0
-CHECK-NEXT:        Column: 18
-CHECK-NEXT:        Inline: 0
-CHECK-NEXT:  -
-CHECK-NEXT:    FunctionGUID: 15822663052811949562
-CHECK-NEXT:    CallSites:
+CHECK-NEXT:      Function: 6699318081062747564
+CHECK-NEXT:      LineOffset: 0
+CHECK-NEXT:      Column: 18
+CHECK-NEXT:      Inline: 1
 CHECK-NEXT:    -
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 15822663052811949562
-CHECK-NEXT:        LineOffset: 1
-CHECK-NEXT:        Column: 3
-CHECK-NEXT:        Inline: 0
-CHECK-NEXT:  -
-CHECK-NEXT:    FunctionGUID: 16434608426314478903
-CHECK-NEXT:    CallSites:
+CHECK-NEXT:      Function: 16434608426314478903
+CHECK-NEXT:      LineOffset: 0
+CHECK-NEXT:      Column: 19
+CHECK-NEXT:      Inline: 0
 CHECK-NEXT:    -
-CHECK-NEXT:      -
-CHECK-NEXT:        Function: 16434608426314478903
-CHECK-NEXT:        LineOffset: 0
-CHECK-NEXT:        Column: 19
-CHECK-NEXT:        Inline: 0
+CHECK-NEXT:      Function: 15822663052811949562
+CHECK-NEXT:      LineOffset: 1
+CHECK-NEXT:      Column: 3
+CHECK-NEXT:      Inline: 0
+CHECK-NEXT:    MemInfoBlock:
+CHECK-NEXT:      AllocCount: 1
+CHECK-NEXT:      TotalAccessCount: 1
+CHECK-NEXT:      MinAccessCount: 1
+CHECK-NEXT:      MaxAccessCount: 1
+CHECK-NEXT:      TotalSize: 1
+CHECK-NEXT:      MinSize: 1
+CHECK-NEXT:      MaxSize: 1
+CHECK-NEXT:      AllocTimestamp: 894
+CHECK-NEXT:      DeallocTimestamp: 894
+CHECK-NEXT:      TotalLifetime: 0
+CHECK-NEXT:      MinLifetime: 0
+CHECK-NEXT:      MaxLifetime: 0
+CHECK-NEXT:      AllocCpuId: 23
+CHECK-NEXT:      DeallocCpuId: 23
+CHECK-NEXT:      NumMigratedCpu: 0
+CHECK-NEXT:      NumLifetimeOverlaps: 0
+CHECK-NEXT:      NumSameAllocCpu: 0
+CHECK-NEXT:      NumSameDeallocCpu: 0
+CHECK-NEXT:      DataTypeId: {{[0-9]+}}
+

diff  --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index df56a76b1552e..ba2f1b6038c48 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -267,8 +267,8 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
     }
 
     // Add the records into the writer context.
-    for (auto I = Reader->begin(), E = Reader->end(); I != E; ++I) {
-      WC->Writer.addRecord(/*Id=*/I->first, /*Record=*/I->second, [&](Error E) {
+    for (const memprof::MemProfRecord &MR : *Reader) {
+      WC->Writer.addRecord(MR, [&](Error E) {
         instrprof_error IPE = InstrProfError::take(std::move(E));
         WC->Errors.emplace_back(make_error<InstrProfError>(IPE), Filename);
       });

diff  --git a/llvm/unittests/ProfileData/InstrProfTest.cpp b/llvm/unittests/ProfileData/InstrProfTest.cpp
index 422492266797e..434e6aaee8b02 100644
--- a/llvm/unittests/ProfileData/InstrProfTest.cpp
+++ b/llvm/unittests/ProfileData/InstrProfTest.cpp
@@ -13,7 +13,6 @@
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/ProfileData/InstrProfWriter.h"
 #include "llvm/ProfileData/MemProf.h"
-#include "llvm/ProfileData/MemProfData.inc"
 #include "llvm/Support/Compression.h"
 #include "llvm/Testing/Support/Error.h"
 #include "llvm/Testing/Support/SupportHelpers.h"
@@ -223,41 +222,18 @@ TEST_F(InstrProfTest, test_writer_merge) {
   ASSERT_EQ(0U, R->Counts[1]);
 }
 
-using ::llvm::memprof::MemInfoBlock;
-using ::llvm::memprof::MemProfRecord;
-MemProfRecord
-makeRecord(std::initializer_list<std::initializer_list<MemProfRecord::Frame>>
-               AllocFrames,
-           std::initializer_list<std::initializer_list<MemProfRecord::Frame>>
-               CallSiteFrames,
-           const MemInfoBlock &Block = MemInfoBlock()) {
-  llvm::memprof::MemProfRecord MR;
-  for (const auto &Frames : AllocFrames)
-    MR.AllocSites.emplace_back(Frames, Block);
-  for (const auto &Frames : CallSiteFrames)
-    MR.CallSites.push_back(Frames);
-  return MR;
-}
-
 TEST_F(InstrProfTest, test_memprof) {
   ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf),
                     Succeeded());
-
-  const MemProfRecord MR = makeRecord(
-      /*AllocFrames=*/
-      {
-          {{0x123, 1, 2, false}, {0x345, 3, 4, true}},
-          {{0x125, 5, 6, false}, {0x567, 7, 8, true}},
-      },
-      /*CallSiteFrames=*/{
-          {{0x124, 5, 6, false}, {0x789, 8, 9, true}},
-      });
-  Writer.addRecord(/*Id=*/0x9999, MR, Err);
+  llvm::memprof::MemProfRecord MR;
+  MR.CallStack.push_back({0x123, 1, 2, false});
+  MR.CallStack.push_back({0x345, 3, 4, true});
+  Writer.addRecord(MR, Err);
 
   auto Profile = Writer.writeBuffer();
   readProfile(std::move(Profile));
 
-  auto RecordsOr = Reader->getMemProfRecord(0x9999);
+  auto RecordsOr = Reader->getMemProfRecord(0x123);
   ASSERT_THAT_ERROR(RecordsOr.takeError(), Succeeded());
   const auto Records = RecordsOr.get();
   ASSERT_EQ(Records.size(), 1U);
@@ -271,16 +247,10 @@ TEST_F(InstrProfTest, test_memprof_merge) {
   ASSERT_THAT_ERROR(Writer2.mergeProfileKind(InstrProfKind::MemProf),
                     Succeeded());
 
-  const MemProfRecord MR = makeRecord(
-      /*AllocFrames=*/
-      {
-          {{0x123, 1, 2, false}, {0x345, 3, 4, true}},
-          {{0x125, 5, 6, false}, {0x567, 7, 8, true}},
-      },
-      /*CallSiteFrames=*/{
-          {{0x124, 5, 6, false}, {0x789, 8, 9, true}},
-      });
-  Writer2.addRecord(/*Id=*/0x9999, MR, Err);
+  llvm::memprof::MemProfRecord MR;
+  MR.CallStack.push_back({0x123, 1, 2, false});
+  MR.CallStack.push_back({0x345, 3, 4, true});
+  Writer2.addRecord(MR, Err);
 
   ASSERT_THAT_ERROR(Writer.mergeProfileKind(Writer2.getProfileKind()),
                     Succeeded());
@@ -294,13 +264,25 @@ TEST_F(InstrProfTest, test_memprof_merge) {
   ASSERT_EQ(1U, R->Counts.size());
   ASSERT_EQ(42U, R->Counts[0]);
 
-  auto RecordsOr = Reader->getMemProfRecord(0x9999);
+  auto RecordsOr = Reader->getMemProfRecord(0x123);
   ASSERT_THAT_ERROR(RecordsOr.takeError(), Succeeded());
   const auto Records = RecordsOr.get();
   ASSERT_EQ(Records.size(), 1U);
   EXPECT_EQ(Records[0], MR);
 }
 
+TEST_F(InstrProfTest, test_memprof_invalid_add_record) {
+  llvm::memprof::MemProfRecord MR;
+  // At least one of the frames should be a non-inline frame.
+  MR.CallStack.push_back({0x123, 1, 2, true});
+  MR.CallStack.push_back({0x345, 3, 4, true});
+
+  auto CheckErr = [](Error &&E) {
+    EXPECT_TRUE(ErrorEquals(instrprof_error::invalid_prof, std::move(E)));
+  };
+  Writer.addRecord(MR, CheckErr);
+}
+
 static const char callee1[] = "callee1";
 static const char callee2[] = "callee2";
 static const char callee3[] = "callee3";

diff  --git a/llvm/unittests/ProfileData/MemProfTest.cpp b/llvm/unittests/ProfileData/MemProfTest.cpp
index 7f7cd64f54065..8921235d063fb 100644
--- a/llvm/unittests/ProfileData/MemProfTest.cpp
+++ b/llvm/unittests/ProfileData/MemProfTest.cpp
@@ -4,7 +4,6 @@
 #include "llvm/DebugInfo/DIContext.h"
 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
 #include "llvm/IR/Function.h"
-#include "llvm/IR/Value.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/MemProfData.inc"
@@ -134,13 +133,6 @@ MemProfSchema getFullSchema() {
 TEST(MemProf, FillsValue) {
   std::unique_ptr<MockSymbolizer> Symbolizer(new MockSymbolizer());
 
-  EXPECT_CALL(*Symbolizer, symbolizeInlinedCode(SectionedAddress{0x1000},
-                                                specifier(), false))
-      .Times(1) // Only once since we remember invalid PCs.
-      .WillRepeatedly(Return(makeInliningInfo({
-          {"new", 70, 57, 3, "memprof/memprof_new_delete.cpp"},
-      })));
-
   EXPECT_CALL(*Symbolizer, symbolizeInlinedCode(SectionedAddress{0x2000},
                                                 specifier(), false))
       .Times(1) // Only once since we cache the result for future lookups.
@@ -149,98 +141,41 @@ TEST(MemProf, FillsValue) {
           {"bar", 201, 150, 20},
       })));
 
-  EXPECT_CALL(*Symbolizer, symbolizeInlinedCode(SectionedAddress{0x3000},
+  EXPECT_CALL(*Symbolizer, symbolizeInlinedCode(SectionedAddress{0x6000},
                                                 specifier(), false))
       .Times(1)
       .WillRepeatedly(Return(makeInliningInfo({
-          {"xyz", 10, 5, 30},
-          {"abc", 10, 5, 30},
+          {"baz", 10, 5, 30},
+          {"qux.llvm.12345", 75, 70, 10},
       })));
 
   CallStackMap CSM;
-  CSM[0x1] = {0x1000, 0x2000, 0x3000};
+  CSM[0x1] = {0x2000};
+  CSM[0x2] = {0x6000, 0x2000};
 
   llvm::MapVector<uint64_t, MemInfoBlock> Prof;
   Prof[0x1].AllocCount = 1;
+  Prof[0x2].AllocCount = 2;
 
   auto Seg = makeSegments();
 
   RawMemProfReader Reader(std::move(Symbolizer), Seg, Prof, CSM);
 
-  llvm::DenseMap<llvm::GlobalValue::GUID, MemProfRecord> Records;
-  for (const auto &Pair : Reader) {
-    Records.insert({Pair.first, Pair.second});
+  std::vector<MemProfRecord> Records;
+  for (const MemProfRecord &R : Reader) {
+    Records.push_back(R);
   }
+  EXPECT_EQ(Records.size(), 2U);
+
+  EXPECT_EQ(Records[0].Info.getAllocCount(), 1U);
+  EXPECT_EQ(Records[1].Info.getAllocCount(), 2U);
+  EXPECT_THAT(Records[0].CallStack[0], FrameContains("foo", 5U, 30U, true));
+  EXPECT_THAT(Records[0].CallStack[1], FrameContains("bar", 51U, 20U, false));
 
-  // Mock program psuedocode and expected memprof record contents.
-  //
-  //                              AllocSite       CallSite
-  // inline foo() { new(); }         Y               N
-  // bar() { foo(); }                Y               Y
-  // inline xyz() { bar(); }         N               Y
-  // abc() { xyz(); }                N               Y
-
-  // We expect 4 records. We attach alloc site data to foo and bar, i.e.
-  // all frames bottom up until we find a non-inline frame. We attach call site
-  // data to bar, xyz and abc.
-  ASSERT_EQ(Records.size(), 4U);
-
-  // Check the memprof record for foo.
-  const llvm::GlobalValue::GUID FooId = MemProfRecord::getGUID("foo");
-  ASSERT_EQ(Records.count(FooId), 1U);
-  const MemProfRecord &Foo = Records[FooId];
-  ASSERT_EQ(Foo.AllocSites.size(), 1U);
-  EXPECT_EQ(Foo.AllocSites[0].Info.getAllocCount(), 1U);
-  EXPECT_THAT(Foo.AllocSites[0].CallStack[0],
-              FrameContains("foo", 5U, 30U, true));
-  EXPECT_THAT(Foo.AllocSites[0].CallStack[1],
-              FrameContains("bar", 51U, 20U, false));
-  EXPECT_THAT(Foo.AllocSites[0].CallStack[2],
-              FrameContains("xyz", 5U, 30U, true));
-  EXPECT_THAT(Foo.AllocSites[0].CallStack[3],
-              FrameContains("abc", 5U, 30U, false));
-  EXPECT_TRUE(Foo.CallSites.empty());
-
-  // Check the memprof record for bar.
-  const llvm::GlobalValue::GUID BarId = MemProfRecord::getGUID("bar");
-  ASSERT_EQ(Records.count(BarId), 1U);
-  const MemProfRecord &Bar = Records[BarId];
-  ASSERT_EQ(Bar.AllocSites.size(), 1U);
-  EXPECT_EQ(Bar.AllocSites[0].Info.getAllocCount(), 1U);
-  EXPECT_THAT(Bar.AllocSites[0].CallStack[0],
-              FrameContains("foo", 5U, 30U, true));
-  EXPECT_THAT(Bar.AllocSites[0].CallStack[1],
-              FrameContains("bar", 51U, 20U, false));
-  EXPECT_THAT(Bar.AllocSites[0].CallStack[2],
-              FrameContains("xyz", 5U, 30U, true));
-  EXPECT_THAT(Bar.AllocSites[0].CallStack[3],
-              FrameContains("abc", 5U, 30U, false));
-
-  ASSERT_EQ(Bar.CallSites.size(), 1U);
-  ASSERT_EQ(Bar.CallSites[0].size(), 2U);
-  EXPECT_THAT(Bar.CallSites[0][0], FrameContains("foo", 5U, 30U, true));
-  EXPECT_THAT(Bar.CallSites[0][1], FrameContains("bar", 51U, 20U, false));
-
-  // Check the memprof record for xyz.
-  const llvm::GlobalValue::GUID XyzId = MemProfRecord::getGUID("xyz");
-  ASSERT_EQ(Records.count(XyzId), 1U);
-  const MemProfRecord &Xyz = Records[XyzId];
-  ASSERT_EQ(Xyz.CallSites.size(), 1U);
-  ASSERT_EQ(Xyz.CallSites[0].size(), 2U);
-  // Expect the entire frame even though in practice we only need the first
-  // entry here.
-  EXPECT_THAT(Xyz.CallSites[0][0], FrameContains("xyz", 5U, 30U, true));
-  EXPECT_THAT(Xyz.CallSites[0][1], FrameContains("abc", 5U, 30U, false));
-
-  // Check the memprof record for abc.
-  const llvm::GlobalValue::GUID AbcId = MemProfRecord::getGUID("abc");
-  ASSERT_EQ(Records.count(AbcId), 1U);
-  const MemProfRecord &Abc = Records[AbcId];
-  EXPECT_TRUE(Abc.AllocSites.empty());
-  ASSERT_EQ(Abc.CallSites.size(), 1U);
-  ASSERT_EQ(Abc.CallSites[0].size(), 2U);
-  EXPECT_THAT(Abc.CallSites[0][0], FrameContains("xyz", 5U, 30U, true));
-  EXPECT_THAT(Abc.CallSites[0][1], FrameContains("abc", 5U, 30U, false));
+  EXPECT_THAT(Records[1].CallStack[0], FrameContains("baz", 5U, 30U, true));
+  EXPECT_THAT(Records[1].CallStack[1], FrameContains("qux", 5U, 10U, false));
+  EXPECT_THAT(Records[1].CallStack[2], FrameContains("foo", 5U, 30U, true));
+  EXPECT_THAT(Records[1].CallStack[3], FrameContains("bar", 51U, 20U, false));
 }
 
 TEST(MemProf, PortableWrapper) {
@@ -271,33 +206,36 @@ TEST(MemProf, PortableWrapper) {
 TEST(MemProf, RecordSerializationRoundTrip) {
   const MemProfSchema Schema = getFullSchema();
 
+  llvm::SmallVector<MemProfRecord, 3> Records;
+  MemProfRecord MR;
+
   MemInfoBlock Info(/*size=*/16, /*access_count=*/7, /*alloc_timestamp=*/1000,
                     /*dealloc_timestamp=*/2000, /*alloc_cpu=*/3,
                     /*dealloc_cpu=*/4);
 
-  llvm::SmallVector<llvm::SmallVector<MemProfRecord::Frame>> AllocCallStacks = {
-      {{0x123, 1, 2, false}, {0x345, 3, 4, false}},
-      {{0x123, 1, 2, false}, {0x567, 5, 6, false}}};
+  MR.Info = PortableMemInfoBlock(Info);
+  MR.CallStack.push_back({0x123, 1, 2, false});
+  MR.CallStack.push_back({0x345, 3, 4, false});
+  Records.push_back(MR);
 
-  llvm::SmallVector<llvm::SmallVector<MemProfRecord::Frame>> CallSites = {
-      {{0x333, 1, 2, false}, {0x777, 3, 4, true}}};
-
-  MemProfRecord Record;
-  for (const auto &ACS : AllocCallStacks) {
-    // Use the same info block for both allocation sites.
-    Record.AllocSites.emplace_back(ACS, Info);
-  }
-  Record.CallSites.assign(CallSites);
+  MR.clear();
+  MR.Info = PortableMemInfoBlock(Info);
+  MR.CallStack.push_back({0x567, 5, 6, false});
+  MR.CallStack.push_back({0x789, 7, 8, false});
+  Records.push_back(MR);
 
   std::string Buffer;
   llvm::raw_string_ostream OS(Buffer);
-  Record.serialize(Schema, OS);
+  serializeRecords(Records, Schema, OS);
   OS.flush();
 
-  const MemProfRecord GotRecord = MemProfRecord::deserialize(
+  const llvm::SmallVector<MemProfRecord, 4> GotRecords = deserializeRecords(
       Schema, reinterpret_cast<const unsigned char *>(Buffer.data()));
 
-  EXPECT_THAT(GotRecord, EqualsRecord(Record));
+  ASSERT_TRUE(!GotRecords.empty());
+  EXPECT_EQ(GotRecords.size(), Records.size());
+  EXPECT_THAT(GotRecords[0], EqualsRecord(Records[0]));
+  EXPECT_THAT(GotRecords[1], EqualsRecord(Records[1]));
 }
 
 TEST(MemProf, SymbolizationFilter) {
@@ -345,15 +283,12 @@ TEST(MemProf, SymbolizationFilter) {
 
   RawMemProfReader Reader(std::move(Symbolizer), Seg, Prof, CSM);
 
-  llvm::SmallVector<MemProfRecord, 1> Records;
-  for (const auto &KeyRecordPair : Reader) {
-    Records.push_back(KeyRecordPair.second);
+  std::vector<MemProfRecord> Records;
+  for (const MemProfRecord &R : Reader) {
+    Records.push_back(R);
   }
-
   ASSERT_EQ(Records.size(), 1U);
-  ASSERT_EQ(Records[0].AllocSites.size(), 1U);
-  ASSERT_EQ(Records[0].AllocSites[0].CallStack.size(), 1U);
-  EXPECT_THAT(Records[0].AllocSites[0].CallStack[0],
-              FrameContains("foo", 5U, 30U, false));
+  ASSERT_EQ(Records[0].CallStack.size(), 1U);
+  EXPECT_THAT(Records[0].CallStack[0], FrameContains("foo", 5U, 30U, false));
 }
 } // namespace


        


More information about the llvm-commits mailing list