Index: include/llvm/ProfileData/ProfileCommon.h =================================================================== --- include/llvm/ProfileData/ProfileCommon.h +++ include/llvm/ProfileData/ProfileCommon.h @@ -17,6 +17,8 @@ #include #include +#include "llvm/Support/Casting.h" + #ifndef LLVM_PROFILEDATA_PROFILE_COMMON_H #define LLVM_PROFILEDATA_PROFILE_COMMON_H @@ -29,8 +31,14 @@ class FunctionSamples; } struct InstrProfRecord; +class LLVMContext; +class Metadata; +class MDTuple; +class MDNode; + inline const char *getHotSectionPrefix() { return ".hot"; } inline const char *getUnlikelySectionPrefix() { return ".unlikely"; } + // The profile summary is one or more (Cutoff, MinCount, NumCounts) triplets. // The semantics of counts depend on the type of profile. For instrumentation // profile, counts are block counts and for sample profile, counts are @@ -47,28 +55,42 @@ }; class ProfileSummary { +public: + enum ProfileSummaryKind { PSK_Instr, PSK_Sample }; + +private: + const ProfileSummaryKind Kind; + const char *KindStr[2] = {"InstrProf", "SampleProfile"}; // We keep track of the number of times a count (block count or samples) // appears in the profile. The map is kept sorted in the descending order of // counts. std::map> CountFrequencies; - protected: std::vector DetailedSummary; std::vector DetailedSummaryCutoffs; uint64_t TotalCount, MaxCount; uint32_t NumCounts; - ProfileSummary(std::vector Cutoffs) - : DetailedSummaryCutoffs(Cutoffs), TotalCount(0), MaxCount(0), + ProfileSummary(ProfileSummaryKind K, std::vector Cutoffs) + : Kind(K), DetailedSummaryCutoffs(Cutoffs), TotalCount(0), MaxCount(0), NumCounts(0) {} - ProfileSummary() : TotalCount(0), MaxCount(0), NumCounts(0) {} - ProfileSummary(std::vector DetailedSummary, + ProfileSummary(ProfileSummaryKind K) + : Kind(K), TotalCount(0), MaxCount(0), NumCounts(0) {} + ProfileSummary(ProfileSummaryKind K, + std::vector DetailedSummary, uint64_t TotalCount, uint64_t MaxCount, uint32_t NumCounts) - : DetailedSummary(DetailedSummary), TotalCount(TotalCount), + : Kind(K), DetailedSummary(DetailedSummary), TotalCount(TotalCount), MaxCount(MaxCount), NumCounts(NumCounts) {} inline void addCount(uint64_t Count); + /// \brief Return metadata specific to the profile format. + /// Derived classes implement this method to return a vector of Metadata. + virtual std::vector getFormatSpecificMD(LLVMContext &Context) = 0; + /// \brief Return detailed summary as metadata. + Metadata *getDetailedSummaryMD(LLVMContext &Context); public: static const int Scale = 1000000; + ProfileSummaryKind getKind() const { return Kind; } + const char *getKindStr() const { return KindStr[Kind]; } // \brief Returns true if F is a hot function. static bool isFunctionHot(const Function *F); // \brief Returns true if F is unlikley executed. @@ -77,6 +99,10 @@ void computeDetailedSummary(); /// \brief A vector of useful cutoff values for detailed summary. static const std::vector DefaultCutoffs; + /// \brief Return summary information as metadata. + Metadata *getMD(LLVMContext &Context); + /// \brief Construct profile summary from metdata. + static ProfileSummary *getFromMD(Metadata *MD); }; class InstrProfSummary : public ProfileSummary { @@ -85,11 +111,25 @@ inline void addEntryCount(uint64_t Count); inline void addInternalCount(uint64_t Count); +protected: + std::vector getFormatSpecificMD(LLVMContext &Context); + public: InstrProfSummary(std::vector Cutoffs) - : ProfileSummary(Cutoffs), MaxInternalBlockCount(0), MaxFunctionCount(0), - NumFunctions(0) {} + : ProfileSummary(PSK_Instr, Cutoffs), MaxInternalBlockCount(0), + MaxFunctionCount(0), NumFunctions(0) {} InstrProfSummary(const IndexedInstrProf::Summary &S); + InstrProfSummary(uint64_t TotalCount, uint64_t MaxBlockCount, + uint64_t MaxInternalBlockCount, uint64_t MaxFunctionCount, + uint32_t NumBlocks, uint32_t NumFunctions, + std::vector Summary) + : ProfileSummary(PSK_Instr, Summary, TotalCount, MaxBlockCount, + NumBlocks), + MaxInternalBlockCount(MaxInternalBlockCount), + MaxFunctionCount(MaxFunctionCount), NumFunctions(NumFunctions) {} + static bool classof(const ProfileSummary *PS) { + return PS->getKind() == PSK_Instr; + } void addRecord(const InstrProfRecord &); uint32_t getNumBlocks() { return NumCounts; } uint64_t getTotalCount() { return TotalCount; } @@ -103,6 +143,9 @@ uint64_t MaxHeadSamples; uint32_t NumFunctions; +protected: + std::vector getFormatSpecificMD(LLVMContext &Context); + public: uint32_t getNumLinesWithSamples() { return NumCounts; } uint64_t getTotalSamples() { return TotalCount; } @@ -111,14 +154,18 @@ uint64_t getMaxSamplesPerLine() { return MaxCount; } void addRecord(const sampleprof::FunctionSamples &FS); SampleProfileSummary(std::vector Cutoffs) - : ProfileSummary(Cutoffs), MaxHeadSamples(0), NumFunctions(0) {} + : ProfileSummary(PSK_Sample, Cutoffs), MaxHeadSamples(0), + NumFunctions(0) {} SampleProfileSummary(uint64_t TotalSamples, uint64_t MaxSamplesPerLine, uint64_t MaxHeadSamples, int32_t NumLinesWithSamples, uint32_t NumFunctions, std::vector DetailedSummary) - : ProfileSummary(DetailedSummary, TotalSamples, MaxSamplesPerLine, - NumLinesWithSamples), + : ProfileSummary(PSK_Sample, DetailedSummary, TotalSamples, + MaxSamplesPerLine, NumLinesWithSamples), MaxHeadSamples(MaxHeadSamples), NumFunctions(NumFunctions) {} + static bool classof(const ProfileSummary *PS) { + return PS->getKind() == PSK_Sample; + } }; // This is called when a count is seen in the profile. Index: lib/ProfileData/ProfileSummary.cpp =================================================================== --- lib/ProfileData/ProfileSummary.cpp +++ lib/ProfileData/ProfileSummary.cpp @@ -12,10 +12,14 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/Attributes.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Type.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/ProfileData/ProfileCommon.h" #include "llvm/ProfileData/SampleProf.h" +#include "llvm/Support/Casting.h" using namespace llvm; @@ -96,8 +100,9 @@ } InstrProfSummary::InstrProfSummary(const IndexedInstrProf::Summary &S) - : ProfileSummary(), MaxInternalBlockCount(S.get( - IndexedInstrProf::Summary::MaxInternalBlockCount)), + : ProfileSummary(PSK_Instr), + MaxInternalBlockCount( + S.get(IndexedInstrProf::Summary::MaxInternalBlockCount)), MaxFunctionCount(S.get(IndexedInstrProf::Summary::MaxFunctionCount)), NumFunctions(S.get(IndexedInstrProf::Summary::TotalNumFunctions)) { @@ -123,3 +128,237 @@ if (Count > MaxInternalBlockCount) MaxInternalBlockCount = Count; } + +// Return a MDTuple with two elements. The first element is a string Key and +// the second is a uint64_t Value. +static Metadata *getKeyValMD(LLVMContext &Context, const char *Key, + uint64_t Val) { + Type *Int64Ty = Type::getInt64Ty(Context); + Metadata *Ops[2] = {MDString::get(Context, Key), + ConstantAsMetadata::get(ConstantInt::get(Int64Ty, Val))}; + return MDTuple::get(Context, Ops); +} + +// Return a MDTuple with two elements. The first element is a string Key and +// the second is a string Value. +static Metadata *getKeyValMD(LLVMContext &Context, const char *Key, + const char *Val) { + Metadata *Ops[2] = {MDString::get(Context, Key), MDString::get(Context, Val)}; + return MDTuple::get(Context, Ops); +} + +// This returns a MDTuple representing the detiled summary. The tuple has two +// elements: a string "DetailedSummary" and a MDTuple representing the value +// of the detailed summary. Each element of this tuple is again an MDTuple whose +// elements are the (Cutoff, MinCount, NumCounts) triplet of the +// DetailedSummaryEntry. +Metadata *ProfileSummary::getDetailedSummaryMD(LLVMContext &Context) { + std::vector Entries; + Type *Int32Ty = Type::getInt32Ty(Context); + Type *Int64Ty = Type::getInt64Ty(Context); + for (auto &Entry : DetailedSummary) { + Metadata *EntryMD[3] = { + ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Entry.Cutoff)), + ConstantAsMetadata::get(ConstantInt::get(Int64Ty, Entry.MinCount)), + ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Entry.NumCounts))}; + Entries.push_back(MDTuple::get(Context, EntryMD)); + } + Metadata *Ops[2] = {MDString::get(Context, "DetailedSummary"), + MDTuple::get(Context, Entries)}; + return MDTuple::get(Context, Ops); +} + +// This returns a MDTuple representing this ProfileSummary object. The first +// entry of this tuple is another MDTuple of two elements: a string +// "ProfileFormat" and a string representing the format ("InstrProf" or +// "SampleProfile"). The rest of the elements of the outer MDTuple are specific +// to the kind of profile summary as returned by getFormatSpecificMD. +Metadata *ProfileSummary::getMD(LLVMContext &Context) { + std::vector Components; + Components.push_back(getKeyValMD(Context, "ProfileFormat", getKindStr())); + std::vector Res = getFormatSpecificMD(Context); + Components.insert(Components.end(), Res.begin(), Res.end()); + return MDTuple::get(Context, Components); +} + +// Returns a vector of MDTuples specific to InstrProfSummary. The first six +// elements of this vector are (Key, Val) pairs of the six scalar fields of +// InstrProfSummary (TotalCount, MaxBlockCount, MaxInternalBlockCount, +// MaxFunctionCount, NumBlocks, NumFunctions). The last element of this vector +// is an MDTuple returned by getDetailedSummaryMD. +std::vector +InstrProfSummary::getFormatSpecificMD(LLVMContext &Context) { + std::vector Components; + + Components.push_back(getKeyValMD(Context, "TotalCount", getTotalCount())); + Components.push_back( + getKeyValMD(Context, "MaxBlockCount", getMaxBlockCount())); + Components.push_back(getKeyValMD(Context, "MaxInternalBlockCount", + getMaxInternalBlockCount())); + Components.push_back( + getKeyValMD(Context, "MaxFunctionCount", getMaxFunctionCount())); + Components.push_back(getKeyValMD(Context, "NumBlocks", getNumBlocks())); + Components.push_back(getKeyValMD(Context, "NumFunctions", getNumFunctions())); + + Components.push_back(getDetailedSummaryMD(Context)); + return Components; +} + +std::vector +SampleProfileSummary::getFormatSpecificMD(LLVMContext &Context) { + std::vector Components; + + Components.push_back(getKeyValMD(Context, "TotalSamples", getTotalSamples())); + Components.push_back( + getKeyValMD(Context, "MaxSamplesPerLine", getMaxSamplesPerLine())); + Components.push_back( + getKeyValMD(Context, "MaxHeadSamples", getMaxHeadSamples())); + Components.push_back( + getKeyValMD(Context, "NumLinesWithSamples", getNumLinesWithSamples())); + Components.push_back(getKeyValMD(Context, "NumFunctions", NumFunctions)); + + Components.push_back(getDetailedSummaryMD(Context)); + return Components; +} + +// Parse an MDTuple representing (Key, Val) pair. +static bool getVal(MDTuple *MD, const char *Key, uint64_t &Val) { + if (!MD) + return false; + if (MD->getNumOperands() != 2) + return false; + MDString *KeyMD = dyn_cast(MD->getOperand(0)); + ConstantAsMetadata *ValMD = dyn_cast(MD->getOperand(1)); + if (!KeyMD || !ValMD) + return false; + if (!KeyMD->getString().equals(Key)) + return false; + Val = cast(ValMD->getValue())->getZExtValue(); + return true; +} + +// Check if an MDTuple represents a (Key, Val) pair. +static bool isKeyValuePair(MDTuple *MD, const char *Key, const char *Val) { + if (!MD || MD->getNumOperands() != 2) + return false; + MDString *KeyMD = dyn_cast(MD->getOperand(0)); + MDString *ValMD = dyn_cast(MD->getOperand(1)); + if (!KeyMD || !ValMD) + return false; + if (!KeyMD->getString().equals(Key) || !ValMD->getString().equals(Val)) + return false; + return true; +} + +// Parse an MDTuple representing detailed summary. +static bool getSummaryFromMD(MDTuple *MD, + std::vector &Summary) { + if (!MD || MD->getNumOperands() != 2) + return false; + MDString *KeyMD = dyn_cast(MD->getOperand(0)); + if (!KeyMD || !KeyMD->getString().equals("DetailedSummary")) + return false; + MDTuple *EntriesMD = dyn_cast(MD->getOperand(1)); + if (!EntriesMD) + return false; + for (size_t i = 0; i < EntriesMD->getNumOperands(); i++) { + MDTuple *EntryMD = dyn_cast(EntriesMD->getOperand(i)); + if (!EntryMD || EntryMD->getNumOperands() != 3) + return false; + ConstantAsMetadata *Op0 = + dyn_cast(EntryMD->getOperand(0)); + ConstantAsMetadata *Op1 = + dyn_cast(EntryMD->getOperand(1)); + ConstantAsMetadata *Op2 = + dyn_cast(EntryMD->getOperand(2)); + + if (!Op0 || !Op1 || !Op2) + return false; + Summary.emplace_back(cast(Op0->getValue())->getZExtValue(), + cast(Op1->getValue())->getZExtValue(), + cast(Op2->getValue())->getZExtValue()); + } + return true; +} + +// Parse an MDTuple representing an InstrProfSummary object. +static ProfileSummary *getInstrProfSummaryFromMD(MDTuple *Tuple) { + uint64_t NumBlocks, TotalCount, NumFunctions, MaxFunctionCount, MaxBlockCount, + MaxInternalBlockCount; + std::vector Summary; + + if (Tuple->getNumOperands() != 8) + return nullptr; + + // Skip operand 0 which has been already parsed in the caller + if (!getVal(dyn_cast(Tuple->getOperand(1)), "TotalCount", + TotalCount)) + return nullptr; + if (!getVal(dyn_cast(Tuple->getOperand(2)), "MaxBlockCount", + MaxBlockCount)) + return nullptr; + if (!getVal(dyn_cast(Tuple->getOperand(3)), "MaxInternalBlockCount", + MaxInternalBlockCount)) + return nullptr; + if (!getVal(dyn_cast(Tuple->getOperand(4)), "MaxFunctionCount", + MaxFunctionCount)) + return nullptr; + if (!getVal(dyn_cast(Tuple->getOperand(5)), "NumBlocks", NumBlocks)) + return nullptr; + if (!getVal(dyn_cast(Tuple->getOperand(6)), "NumFunctions", + NumFunctions)) + return nullptr; + if (!getSummaryFromMD(dyn_cast(Tuple->getOperand(7)), Summary)) + return nullptr; + return new InstrProfSummary(TotalCount, MaxBlockCount, MaxInternalBlockCount, + MaxFunctionCount, NumBlocks, NumFunctions, + Summary); +} + +// Parse an MDTuple representing an SampleProfileSummary object. +static ProfileSummary *getSampleProfileSummaryFromMD(MDTuple *Tuple) { + uint64_t TotalSamples, MaxSamplesPerLine, MaxHeadSamples, NumLinesWithSamples, + NumFunctions; + std::vector Summary; + + if (Tuple->getNumOperands() != 7) + return nullptr; + + // Skip operand 0 which has been already parsed in the caller + if (!getVal(dyn_cast(Tuple->getOperand(1)), "TotalSamples", + TotalSamples)) + return nullptr; + if (!getVal(dyn_cast(Tuple->getOperand(2)), "MaxSamplesPerLine", + MaxSamplesPerLine)) + return nullptr; + if (!getVal(dyn_cast(Tuple->getOperand(3)), "MaxHeadSamples", + MaxHeadSamples)) + return nullptr; + if (!getVal(dyn_cast(Tuple->getOperand(4)), "NumLinesWithSamples", + NumLinesWithSamples)) + return nullptr; + if (!getVal(dyn_cast(Tuple->getOperand(5)), "NumFunctions", + NumFunctions)) + return nullptr; + if (!getSummaryFromMD(dyn_cast(Tuple->getOperand(6)), Summary)) + return nullptr; + return new SampleProfileSummary(TotalSamples, MaxSamplesPerLine, + MaxHeadSamples, NumLinesWithSamples, + NumFunctions, Summary); +} + +ProfileSummary *ProfileSummary::getFromMD(Metadata *MD) { + std::vector Summary; + if (!isa(MD)) + return nullptr; + MDTuple *Tuple = cast(MD); + auto &FormatMD = Tuple->getOperand(0); + if (isKeyValuePair(dyn_cast_or_null(FormatMD), "ProfileFormat", + "SampleProfile")) + return getSampleProfileSummaryFromMD(Tuple); + else if (isKeyValuePair(dyn_cast_or_null(FormatMD), "ProfileFormat", + "InstrProf")) + return getInstrProfSummaryFromMD(Tuple); + else + return nullptr; +} Index: unittests/ProfileData/InstrProfTest.cpp =================================================================== --- unittests/ProfileData/InstrProfTest.cpp +++ unittests/ProfileData/InstrProfTest.cpp @@ -154,27 +154,39 @@ auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - InstrProfSummary &PS = Reader->getSummary(); - ASSERT_EQ(2305843009213693952U, PS.getMaxFunctionCount()); - ASSERT_EQ(2305843009213693952U, PS.getMaxBlockCount()); - ASSERT_EQ(10U, PS.getNumBlocks()); - ASSERT_EQ(4539628424389557499U, PS.getTotalCount()); - std::vector &Details = PS.getDetailedSummary(); - uint32_t Cutoff = 800000; - auto Predicate = [&Cutoff](const ProfileSummaryEntry &PE) { - return PE.Cutoff == Cutoff; + auto VerifySummary = [](InstrProfSummary &IPS, bool dummy) mutable { + ASSERT_EQ(2305843009213693952U, IPS.getMaxFunctionCount()); + ASSERT_EQ(2305843009213693952U, IPS.getMaxBlockCount()); + ASSERT_EQ(10U, IPS.getNumBlocks()); + ASSERT_EQ(4539628424389557499U, IPS.getTotalCount()); + std::vector &Details = IPS.getDetailedSummary(); + uint32_t Cutoff = 800000; + auto Predicate = [&Cutoff](const ProfileSummaryEntry &PE) { + return PE.Cutoff == Cutoff; + }; + auto EightyPerc = std::find_if(Details.begin(), Details.end(), Predicate); + Cutoff = 900000; + auto NinetyPerc = std::find_if(Details.begin(), Details.end(), Predicate); + Cutoff = 950000; + auto NinetyFivePerc = + std::find_if(Details.begin(), Details.end(), Predicate); + Cutoff = 990000; + auto NinetyNinePerc = + std::find_if(Details.begin(), Details.end(), Predicate); + ASSERT_EQ(576460752303423488U, EightyPerc->MinCount); + ASSERT_EQ(288230376151711744U, NinetyPerc->MinCount); + ASSERT_EQ(288230376151711744U, NinetyFivePerc->MinCount); + ASSERT_EQ(72057594037927936U, NinetyNinePerc->MinCount); }; - auto EightyPerc = std::find_if(Details.begin(), Details.end(), Predicate); - Cutoff = 900000; - auto NinetyPerc = std::find_if(Details.begin(), Details.end(), Predicate); - Cutoff = 950000; - auto NinetyFivePerc = std::find_if(Details.begin(), Details.end(), Predicate); - Cutoff = 990000; - auto NinetyNinePerc = std::find_if(Details.begin(), Details.end(), Predicate); - ASSERT_EQ(576460752303423488U, EightyPerc->MinCount); - ASSERT_EQ(288230376151711744U, NinetyPerc->MinCount); - ASSERT_EQ(288230376151711744U, NinetyFivePerc->MinCount); - ASSERT_EQ(72057594037927936U, NinetyNinePerc->MinCount); + InstrProfSummary &PS = Reader->getSummary(); + VerifySummary(PS, true); + Metadata *MD = PS.getMD(getGlobalContext()); + ASSERT_TRUE(MD); + ProfileSummary *PSFromMD = ProfileSummary::getFromMD(MD); + ASSERT_TRUE(PSFromMD); + ASSERT_TRUE(isa(PSFromMD)); + InstrProfSummary *IPS = cast(PSFromMD); + VerifySummary(*IPS, false); } TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write) { Index: unittests/ProfileData/SampleProfTest.cpp =================================================================== --- unittests/ProfileData/SampleProfTest.cpp +++ unittests/ProfileData/SampleProfTest.cpp @@ -8,6 +8,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/IR/Metadata.h" #include "llvm/ProfileData/SampleProfReader.h" #include "llvm/ProfileData/SampleProfWriter.h" #include "gtest/gtest.h" @@ -93,31 +94,43 @@ ASSERT_EQ(20301u, ReadBarSamples.getTotalSamples()); ASSERT_EQ(1437u, ReadBarSamples.getHeadSamples()); - SampleProfileSummary &Summary = Reader->getSummary(); - ASSERT_EQ(123603u, Summary.getTotalSamples()); - ASSERT_EQ(6u, Summary.getNumLinesWithSamples()); - ASSERT_EQ(2u, Summary.getNumFunctions()); - ASSERT_EQ(1437u, Summary.getMaxHeadSamples()); - ASSERT_EQ(60351u, Summary.getMaxSamplesPerLine()); - - std::vector &Details = Summary.getDetailedSummary(); - uint32_t Cutoff = 800000; - auto Predicate = [&Cutoff](const ProfileSummaryEntry &PE) { - return PE.Cutoff == Cutoff; + auto VerifySummary = [](SampleProfileSummary &Summary) mutable { + ASSERT_EQ(123603u, Summary.getTotalSamples()); + ASSERT_EQ(6u, Summary.getNumLinesWithSamples()); + ASSERT_EQ(2u, Summary.getNumFunctions()); + ASSERT_EQ(1437u, Summary.getMaxHeadSamples()); + ASSERT_EQ(60351u, Summary.getMaxSamplesPerLine()); + + uint32_t Cutoff = 800000; + auto Predicate = [&Cutoff](const ProfileSummaryEntry &PE) { + return PE.Cutoff == Cutoff; + }; + std::vector &Details = Summary.getDetailedSummary(); + auto EightyPerc = std::find_if(Details.begin(), Details.end(), Predicate); + Cutoff = 900000; + auto NinetyPerc = std::find_if(Details.begin(), Details.end(), Predicate); + Cutoff = 950000; + auto NinetyFivePerc = + std::find_if(Details.begin(), Details.end(), Predicate); + Cutoff = 990000; + auto NinetyNinePerc = + std::find_if(Details.begin(), Details.end(), Predicate); + ASSERT_EQ(60000u, EightyPerc->MinCount); + ASSERT_EQ(60000u, NinetyPerc->MinCount); + ASSERT_EQ(60000u, NinetyFivePerc->MinCount); + ASSERT_EQ(610u, NinetyNinePerc->MinCount); }; - auto EightyPerc = std::find_if(Details.begin(), Details.end(), Predicate); - Cutoff = 900000; - auto NinetyPerc = std::find_if(Details.begin(), Details.end(), Predicate); - Cutoff = 950000; - auto NinetyFivePerc = - std::find_if(Details.begin(), Details.end(), Predicate); - Cutoff = 990000; - auto NinetyNinePerc = - std::find_if(Details.begin(), Details.end(), Predicate); - ASSERT_EQ(60000u, EightyPerc->MinCount); - ASSERT_EQ(60000u, NinetyPerc->MinCount); - ASSERT_EQ(60000u, NinetyFivePerc->MinCount); - ASSERT_EQ(610u, NinetyNinePerc->MinCount); + + SampleProfileSummary &Summary = Reader->getSummary(); + VerifySummary(Summary); + + Metadata *MD = Summary.getMD(getGlobalContext()); + ASSERT_TRUE(MD); + ProfileSummary *PS = ProfileSummary::getFromMD(MD); + ASSERT_TRUE(PS); + ASSERT_TRUE(isa(PS)); + SampleProfileSummary *SPS = cast(PS); + VerifySummary(*SPS); } };