From 2c54bf497f7d7aecd24f4b849ee08e37a3519611 Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Wed, 15 May 2024 11:44:26 -0700 Subject: [PATCH] Revert "Reapply "[ctx_profile] Profile reader and writer" (#92199)" This reverts commit c19f2c773b0e23fd623502888894add822079f63. Broke the gcc-7 bot. --- .../llvm/ProfileData/PGOCtxProfReader.h | 92 ------- .../llvm/ProfileData/PGOCtxProfWriter.h | 91 ------- llvm/lib/ProfileData/CMakeLists.txt | 3 - llvm/lib/ProfileData/PGOCtxProfReader.cpp | 173 ------------ llvm/lib/ProfileData/PGOCtxProfWriter.cpp | 49 ---- llvm/unittests/ProfileData/CMakeLists.txt | 1 - .../PGOCtxProfReaderWriterTest.cpp | 255 ------------------ 7 files changed, 664 deletions(-) delete mode 100644 llvm/include/llvm/ProfileData/PGOCtxProfReader.h delete mode 100644 llvm/include/llvm/ProfileData/PGOCtxProfWriter.h delete mode 100644 llvm/lib/ProfileData/PGOCtxProfReader.cpp delete mode 100644 llvm/lib/ProfileData/PGOCtxProfWriter.cpp delete mode 100644 llvm/unittests/ProfileData/PGOCtxProfReaderWriterTest.cpp diff --git a/llvm/include/llvm/ProfileData/PGOCtxProfReader.h b/llvm/include/llvm/ProfileData/PGOCtxProfReader.h deleted file mode 100644 index a19b3f51d642d..0000000000000 --- a/llvm/include/llvm/ProfileData/PGOCtxProfReader.h +++ /dev/null @@ -1,92 +0,0 @@ -//===--- PGOCtxProfReader.h - Contextual profile reader ---------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// -/// Reader for contextual iFDO profile, which comes in bitstream format. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_PROFILEDATA_CTXINSTRPROFILEREADER_H -#define LLVM_PROFILEDATA_CTXINSTRPROFILEREADER_H - -#include "llvm/ADT/DenseSet.h" -#include "llvm/Bitstream/BitstreamReader.h" -#include "llvm/IR/GlobalValue.h" -#include "llvm/ProfileData/PGOCtxProfWriter.h" -#include "llvm/Support/Error.h" -#include -#include - -namespace llvm { -/// The loaded contextual profile, suitable for mutation during IPO passes. We -/// generally expect a fraction of counters and of callsites to be populated. -/// We continue to model counters as vectors, but callsites are modeled as a map -/// of a map. The expectation is that, typically, there is a small number of -/// indirect targets (usually, 1 for direct calls); but potentially a large -/// number of callsites, and, as inlining progresses, the callsite count of a -/// caller will grow. -class PGOContextualProfile final { -public: - using CallTargetMapTy = std::map; - using CallsiteMapTy = DenseMap; - -private: - friend class PGOCtxProfileReader; - GlobalValue::GUID GUID = 0; - SmallVector Counters; - CallsiteMapTy Callsites; - - PGOContextualProfile(GlobalValue::GUID G, - SmallVectorImpl &&Counters) - : GUID(G), Counters(std::move(Counters)) {} - - Expected - getOrEmplace(uint32_t Index, GlobalValue::GUID G, - SmallVectorImpl &&Counters); - -public: - PGOContextualProfile(const PGOContextualProfile &) = delete; - PGOContextualProfile &operator=(const PGOContextualProfile &) = delete; - PGOContextualProfile(PGOContextualProfile &&) = default; - PGOContextualProfile &operator=(PGOContextualProfile &&) = default; - - GlobalValue::GUID guid() const { return GUID; } - const SmallVectorImpl &counters() const { return Counters; } - const CallsiteMapTy &callsites() const { return Callsites; } - CallsiteMapTy &callsites() { return Callsites; } - - bool hasCallsite(uint32_t I) const { - return Callsites.find(I) != Callsites.end(); - } - - const CallTargetMapTy &callsite(uint32_t I) const { - assert(hasCallsite(I) && "Callsite not found"); - return Callsites.find(I)->second; - } - void getContainedGuids(DenseSet &Guids) const; -}; - -class PGOCtxProfileReader final { - BitstreamCursor &Cursor; - Expected advance(); - Error readMetadata(); - Error wrongValue(const Twine &); - Error unsupported(const Twine &); - - Expected, PGOContextualProfile>> - readContext(bool ExpectIndex); - bool canReadContext(); - -public: - PGOCtxProfileReader(BitstreamCursor &Cursor) : Cursor(Cursor) {} - - Expected> loadContexts(); -}; -} // namespace llvm -#endif diff --git a/llvm/include/llvm/ProfileData/PGOCtxProfWriter.h b/llvm/include/llvm/ProfileData/PGOCtxProfWriter.h deleted file mode 100644 index 15578c51a4957..0000000000000 --- a/llvm/include/llvm/ProfileData/PGOCtxProfWriter.h +++ /dev/null @@ -1,91 +0,0 @@ -//===- PGOCtxProfWriter.h - Contextual Profile Writer -----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file declares a utility for writing a contextual profile to bitstream. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_PROFILEDATA_PGOCTXPROFWRITER_H_ -#define LLVM_PROFILEDATA_PGOCTXPROFWRITER_H_ - -#include "llvm/Bitstream/BitstreamWriter.h" -#include "llvm/ProfileData/CtxInstrContextNode.h" - -namespace llvm { -enum PGOCtxProfileRecords { Invalid = 0, Version, Guid, CalleeIndex, Counters }; - -enum PGOCtxProfileBlockIDs { - ProfileMetadataBlockID = 100, - ContextNodeBlockID = ProfileMetadataBlockID + 1 -}; - -/// Write one or more ContextNodes to the provided raw_fd_stream. -/// The caller must destroy the PGOCtxProfileWriter object before closing the -/// stream. -/// The design allows serializing a bunch of contexts embedded in some other -/// file. The overall format is: -/// -/// [... other data written to the stream...] -/// SubBlock(ProfileMetadataBlockID) -/// Version -/// SubBlock(ContextNodeBlockID) -/// [RECORDS] -/// SubBlock(ContextNodeBlockID) -/// [RECORDS] -/// [... more SubBlocks] -/// EndBlock -/// EndBlock -/// -/// The "RECORDS" are bitsream records. The IDs are in CtxProfileCodes (except) -/// for Version, which is just for metadata). All contexts will have Guid and -/// Counters, and all but the roots have CalleeIndex. The order in which the -/// records appear does not matter, but they must precede any subcontexts, -/// because that helps keep the reader code simpler. -/// -/// Subblock containment captures the context->subcontext relationship. The -/// "next()" relationship in the raw profile, between call targets of indirect -/// calls, are just modeled as peer subblocks where the callee index is the -/// same. -/// -/// Versioning: the writer may produce additional records not known by the -/// reader. The version number indicates a more structural change. -/// The current version, in particular, is set up to expect optional extensions -/// like value profiling - which would appear as additional records. For -/// example, value profiling would produce a new record with a new record ID, -/// containing the profiled values (much like the counters) -class PGOCtxProfileWriter final { - SmallVector Buff; - BitstreamWriter Writer; - - void writeCounters(const ctx_profile::ContextNode &Node); - void writeImpl(std::optional CallerIndex, - const ctx_profile::ContextNode &Node); - -public: - PGOCtxProfileWriter(raw_fd_stream &Out, - std::optional VersionOverride = std::nullopt) - : Writer(Buff, &Out, 0) { - Writer.EnterSubblock(PGOCtxProfileBlockIDs::ProfileMetadataBlockID, - CodeLen); - const auto Version = VersionOverride ? *VersionOverride : CurrentVersion; - Writer.EmitRecord(PGOCtxProfileRecords::Version, - SmallVector({Version})); - } - - ~PGOCtxProfileWriter() { Writer.ExitBlock(); } - - void write(const ctx_profile::ContextNode &); - - // constants used in writing which a reader may find useful. - static constexpr unsigned CodeLen = 2; - static constexpr uint32_t CurrentVersion = 1; - static constexpr unsigned VBREncodingBits = 6; -}; - -} // namespace llvm -#endif diff --git a/llvm/lib/ProfileData/CMakeLists.txt b/llvm/lib/ProfileData/CMakeLists.txt index 4fa1b76f0a062..408f9ff01ec87 100644 --- a/llvm/lib/ProfileData/CMakeLists.txt +++ b/llvm/lib/ProfileData/CMakeLists.txt @@ -7,8 +7,6 @@ add_llvm_component_library(LLVMProfileData ItaniumManglingCanonicalizer.cpp MemProf.cpp MemProfReader.cpp - PGOCtxProfReader.cpp - PGOCtxProfWriter.cpp ProfileSummaryBuilder.cpp SampleProf.cpp SampleProfReader.cpp @@ -22,7 +20,6 @@ add_llvm_component_library(LLVMProfileData intrinsics_gen LINK_COMPONENTS - BitstreamReader Core Object Support diff --git a/llvm/lib/ProfileData/PGOCtxProfReader.cpp b/llvm/lib/ProfileData/PGOCtxProfReader.cpp deleted file mode 100644 index 3710f2e4b8185..0000000000000 --- a/llvm/lib/ProfileData/PGOCtxProfReader.cpp +++ /dev/null @@ -1,173 +0,0 @@ -//===- PGOCtxProfReader.cpp - Contextual Instrumentation profile reader ---===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Read a contextual profile into a datastructure suitable for maintenance -// throughout IPO -// -//===----------------------------------------------------------------------===// - -#include "llvm/ProfileData/PGOCtxProfReader.h" -#include "llvm/Bitstream/BitCodeEnums.h" -#include "llvm/Bitstream/BitstreamReader.h" -#include "llvm/ProfileData/InstrProf.h" -#include "llvm/ProfileData/PGOCtxProfWriter.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Error.h" - -using namespace llvm; - -// FIXME(#92054) - these Error handling macros are (re-)invented in a few -// places. -#define EXPECT_OR_RET(LHS, RHS) \ - auto LHS = RHS; \ - if (!LHS) \ - return LHS.takeError(); - -#define RET_ON_ERR(EXPR) \ - if (auto Err = (EXPR)) \ - return Err; - -Expected -PGOContextualProfile::getOrEmplace(uint32_t Index, GlobalValue::GUID G, - SmallVectorImpl &&Counters) { - auto [Iter, Inserted] = Callsites[Index].insert( - {G, PGOContextualProfile(G, std::move(Counters))}); - if (!Inserted) - return make_error(instrprof_error::invalid_prof, - "Duplicate GUID for same callsite."); - return Iter->second; -} - -void PGOContextualProfile::getContainedGuids( - DenseSet &Guids) const { - Guids.insert(GUID); - for (const auto &[_, Callsite] : Callsites) - for (const auto &[_, Callee] : Callsite) - Callee.getContainedGuids(Guids); -} - -Expected PGOCtxProfileReader::advance() { - return Cursor.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs); -} - -Error PGOCtxProfileReader::wrongValue(const Twine &Msg) { - return make_error(instrprof_error::invalid_prof, Msg); -} - -Error PGOCtxProfileReader::unsupported(const Twine &Msg) { - return make_error(instrprof_error::unsupported_version, Msg); -} - -bool PGOCtxProfileReader::canReadContext() { - auto Blk = advance(); - if (!Blk) { - consumeError(Blk.takeError()); - return false; - } - return Blk->Kind == BitstreamEntry::SubBlock && - Blk->ID == PGOCtxProfileBlockIDs::ContextNodeBlockID; -} - -Expected, PGOContextualProfile>> -PGOCtxProfileReader::readContext(bool ExpectIndex) { - RET_ON_ERR(Cursor.EnterSubBlock(PGOCtxProfileBlockIDs::ContextNodeBlockID)); - - std::optional Guid; - std::optional> Counters; - std::optional CallsiteIndex; - - SmallVector RecordValues; - - // We don't prescribe the order in which the records come in, and we are ok - // if other unsupported records appear. We seek in the current subblock until - // we get all we know. - auto GotAllWeNeed = [&]() { - return Guid.has_value() && Counters.has_value() && - (!ExpectIndex || CallsiteIndex.has_value()); - }; - while (!GotAllWeNeed()) { - RecordValues.clear(); - EXPECT_OR_RET(Entry, advance()); - if (Entry->Kind != BitstreamEntry::Record) - return wrongValue( - "Expected records before encountering more subcontexts"); - EXPECT_OR_RET(ReadRecord, - Cursor.readRecord(bitc::UNABBREV_RECORD, RecordValues)); - switch (*ReadRecord) { - case PGOCtxProfileRecords::Guid: - if (RecordValues.size() != 1) - return wrongValue("The GUID record should have exactly one value"); - Guid = RecordValues[0]; - break; - case PGOCtxProfileRecords::Counters: - Counters = std::move(RecordValues); - if (Counters->empty()) - return wrongValue("Empty counters. At least the entry counter (one " - "value) was expected"); - break; - case PGOCtxProfileRecords::CalleeIndex: - if (!ExpectIndex) - return wrongValue("The root context should not have a callee index"); - if (RecordValues.size() != 1) - return wrongValue("The callee index should have exactly one value"); - CallsiteIndex = RecordValues[0]; - break; - default: - // OK if we see records we do not understand, like records (profile - // components) introduced later. - break; - } - } - - PGOContextualProfile Ret(*Guid, std::move(*Counters)); - - while (canReadContext()) { - EXPECT_OR_RET(SC, readContext(true)); - auto &Targets = Ret.callsites()[*SC->first]; - auto [_, Inserted] = - Targets.insert({SC->second.guid(), std::move(SC->second)}); - if (!Inserted) - return wrongValue( - "Unexpected duplicate target (callee) at the same callsite."); - } - return std::make_pair(CallsiteIndex, std::move(Ret)); -} - -Error PGOCtxProfileReader::readMetadata() { - EXPECT_OR_RET(Blk, advance()); - if (Blk->Kind != BitstreamEntry::SubBlock) - return unsupported("Expected Version record"); - RET_ON_ERR( - Cursor.EnterSubBlock(PGOCtxProfileBlockIDs::ProfileMetadataBlockID)); - EXPECT_OR_RET(MData, advance()); - if (MData->Kind != BitstreamEntry::Record) - return unsupported("Expected Version record"); - - SmallVector Ver; - EXPECT_OR_RET(Code, Cursor.readRecord(bitc::UNABBREV_RECORD, Ver)); - if (*Code != PGOCtxProfileRecords::Version) - return unsupported("Expected Version record"); - if (Ver.size() != 1 || Ver[0] > PGOCtxProfileWriter::CurrentVersion) - return unsupported("Version " + Twine(*Code) + - " is higher than supported version " + - Twine(PGOCtxProfileWriter::CurrentVersion)); - return Error::success(); -} - -Expected> -PGOCtxProfileReader::loadContexts() { - std::map Ret; - RET_ON_ERR(readMetadata()); - while (canReadContext()) { - EXPECT_OR_RET(E, readContext(false)); - auto Key = E->second.guid(); - if (!Ret.insert({Key, std::move(E->second)}).second) - return wrongValue("Duplicate roots"); - } - return Ret; -} diff --git a/llvm/lib/ProfileData/PGOCtxProfWriter.cpp b/llvm/lib/ProfileData/PGOCtxProfWriter.cpp deleted file mode 100644 index 5081797564469..0000000000000 --- a/llvm/lib/ProfileData/PGOCtxProfWriter.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//===- PGOCtxProfWriter.cpp - Contextual Instrumentation profile writer ---===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Write a contextual profile to bitstream. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ProfileData/PGOCtxProfWriter.h" -#include "llvm/Bitstream/BitCodeEnums.h" - -using namespace llvm; -using namespace llvm::ctx_profile; - -void PGOCtxProfileWriter::writeCounters(const ContextNode &Node) { - Writer.EmitCode(bitc::UNABBREV_RECORD); - Writer.EmitVBR(PGOCtxProfileRecords::Counters, VBREncodingBits); - Writer.EmitVBR(Node.counters_size(), VBREncodingBits); - for (uint32_t I = 0U; I < Node.counters_size(); ++I) - Writer.EmitVBR64(Node.counters()[I], VBREncodingBits); -} - -// recursively write all the subcontexts. We do need to traverse depth first to -// model the context->subcontext implicitly, and since this captures call -// stacks, we don't really need to be worried about stack overflow and we can -// keep the implementation simple. -void PGOCtxProfileWriter::writeImpl(std::optional CallerIndex, - const ContextNode &Node) { - Writer.EnterSubblock(PGOCtxProfileBlockIDs::ContextNodeBlockID, CodeLen); - Writer.EmitRecord(PGOCtxProfileRecords::Guid, - SmallVector{Node.guid()}); - if (CallerIndex) - Writer.EmitRecord(PGOCtxProfileRecords::CalleeIndex, - SmallVector{*CallerIndex}); - writeCounters(Node); - for (uint32_t I = 0U; I < Node.callsites_size(); ++I) - for (const auto *Subcontext = Node.subContexts()[I]; Subcontext; - Subcontext = Subcontext->next()) - writeImpl(I, *Subcontext); - Writer.ExitBlock(); -} - -void PGOCtxProfileWriter::write(const ContextNode &RootNode) { - writeImpl(std::nullopt, RootNode); -} diff --git a/llvm/unittests/ProfileData/CMakeLists.txt b/llvm/unittests/ProfileData/CMakeLists.txt index c92642ded8282..ce3a0a45ccf18 100644 --- a/llvm/unittests/ProfileData/CMakeLists.txt +++ b/llvm/unittests/ProfileData/CMakeLists.txt @@ -13,7 +13,6 @@ add_llvm_unittest(ProfileDataTests InstrProfTest.cpp ItaniumManglingCanonicalizerTest.cpp MemProfTest.cpp - PGOCtxProfReaderWriterTest.cpp SampleProfTest.cpp SymbolRemappingReaderTest.cpp ) diff --git a/llvm/unittests/ProfileData/PGOCtxProfReaderWriterTest.cpp b/llvm/unittests/ProfileData/PGOCtxProfReaderWriterTest.cpp deleted file mode 100644 index d2cdbb28e2fce..0000000000000 --- a/llvm/unittests/ProfileData/PGOCtxProfReaderWriterTest.cpp +++ /dev/null @@ -1,255 +0,0 @@ -//===-------------- PGOCtxProfReadWriteTest.cpp ---------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/Bitstream/BitstreamReader.h" -#include "llvm/ProfileData/CtxInstrContextNode.h" -#include "llvm/ProfileData/PGOCtxProfReader.h" -#include "llvm/ProfileData/PGOCtxProfWriter.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Testing/Support/SupportHelpers.h" -#include "gtest/gtest.h" - -using namespace llvm; -using namespace llvm::ctx_profile; - -class PGOCtxProfRWTest : public ::testing::Test { - std::vector> Nodes; - std::map Roots; - -public: - ContextNode *createNode(GUID Guid, uint32_t NrCounters, uint32_t NrCallsites, - ContextNode *Next = nullptr) { - auto AllocSize = ContextNode::getAllocSize(NrCounters, NrCallsites); - auto *Mem = Nodes.emplace_back(std::make_unique(AllocSize)).get(); - std::memset(Mem, 0, AllocSize); - auto *Ret = new (Mem) ContextNode(Guid, NrCounters, NrCallsites, Next); - return Ret; - } - - void SetUp() override { - // Root (guid 1) has 2 callsites, one used for an indirect call to either - // guid 2 or 4. - // guid 2 calls guid 5 - // guid 5 calls guid 2 - // there's also a second root, guid3. - auto *Root1 = createNode(1, 2, 2); - Root1->counters()[0] = 10; - Root1->counters()[1] = 11; - Roots.insert({1, Root1}); - auto *L1 = createNode(2, 1, 1); - L1->counters()[0] = 12; - Root1->subContexts()[1] = createNode(4, 3, 1, L1); - Root1->subContexts()[1]->counters()[0] = 13; - Root1->subContexts()[1]->counters()[1] = 14; - Root1->subContexts()[1]->counters()[2] = 15; - - auto *L3 = createNode(5, 6, 3); - for (auto I = 0; I < 6; ++I) - L3->counters()[I] = 16 + I; - L1->subContexts()[0] = L3; - L3->subContexts()[2] = createNode(2, 1, 1); - L3->subContexts()[2]->counters()[0] = 30; - auto *Root2 = createNode(3, 1, 0); - Root2->counters()[0] = 40; - Roots.insert({3, Root2}); - } - - const std::map &roots() const { return Roots; } -}; - -void checkSame(const ContextNode &Raw, const PGOContextualProfile &Profile) { - EXPECT_EQ(Raw.guid(), Profile.guid()); - ASSERT_EQ(Raw.counters_size(), Profile.counters().size()); - for (auto I = 0U; I < Raw.counters_size(); ++I) - EXPECT_EQ(Raw.counters()[I], Profile.counters()[I]); - - for (auto I = 0U; I < Raw.callsites_size(); ++I) { - if (Raw.subContexts()[I] == nullptr) - continue; - EXPECT_TRUE(Profile.hasCallsite(I)); - const auto &ProfileTargets = Profile.callsite(I); - - std::map Targets; - for (const auto *N = Raw.subContexts()[I]; N; N = N->next()) - EXPECT_TRUE(Targets.insert({N->guid(), N}).second); - - EXPECT_EQ(Targets.size(), ProfileTargets.size()); - for (auto It : Targets) { - auto PIt = ProfileTargets.find(It.second->guid()); - EXPECT_NE(PIt, ProfileTargets.end()); - checkSame(*It.second, PIt->second); - } - } -} - -TEST_F(PGOCtxProfRWTest, RoundTrip) { - llvm::unittest::TempFile ProfileFile("ctx_profile", "", "", /*Unique*/ true); - { - std::error_code EC; - raw_fd_stream Out(ProfileFile.path(), EC); - ASSERT_FALSE(EC); - { - PGOCtxProfileWriter Writer(Out); - for (auto &[_, R] : roots()) - Writer.write(*R); - } - } - { - ErrorOr> MB = - MemoryBuffer::getFile(ProfileFile.path()); - ASSERT_TRUE(!!MB); - ASSERT_NE(*MB, nullptr); - BitstreamCursor Cursor((*MB)->getBuffer()); - PGOCtxProfileReader Reader(Cursor); - auto Expected = Reader.loadContexts(); - ASSERT_TRUE(!!Expected); - auto &Ctxes = *Expected; - EXPECT_EQ(Ctxes.size(), roots().size()); - EXPECT_EQ(Ctxes.size(), 2U); - for (auto &[G, R] : roots()) - checkSame(*R, Ctxes.find(G)->second); - } -} - -TEST_F(PGOCtxProfRWTest, InvalidCounters) { - auto *R = createNode(1, 0, 1); - llvm::unittest::TempFile ProfileFile("ctx_profile", "", "", /*Unique*/ true); - { - std::error_code EC; - raw_fd_stream Out(ProfileFile.path(), EC); - ASSERT_FALSE(EC); - { - PGOCtxProfileWriter Writer(Out); - Writer.write(*R); - } - } - { - auto MB = MemoryBuffer::getFile(ProfileFile.path()); - ASSERT_TRUE(!!MB); - ASSERT_NE(*MB, nullptr); - BitstreamCursor Cursor((*MB)->getBuffer()); - PGOCtxProfileReader Reader(Cursor); - auto Expected = Reader.loadContexts(); - EXPECT_FALSE(Expected); - consumeError(Expected.takeError()); - } -} - -TEST_F(PGOCtxProfRWTest, Empty) { - BitstreamCursor Cursor(""); - PGOCtxProfileReader Reader(Cursor); - auto Expected = Reader.loadContexts(); - EXPECT_FALSE(Expected); - consumeError(Expected.takeError()); -} - -TEST_F(PGOCtxProfRWTest, Invalid) { - BitstreamCursor Cursor("Surely this is not valid"); - PGOCtxProfileReader Reader(Cursor); - auto Expected = Reader.loadContexts(); - EXPECT_FALSE(Expected); - consumeError(Expected.takeError()); -} - -TEST_F(PGOCtxProfRWTest, ValidButEmpty) { - llvm::unittest::TempFile ProfileFile("ctx_profile", "", "", /*Unique*/ true); - { - std::error_code EC; - raw_fd_stream Out(ProfileFile.path(), EC); - ASSERT_FALSE(EC); - { - PGOCtxProfileWriter Writer(Out); - // don't write anything - this will just produce the metadata subblock. - } - } - { - auto MB = MemoryBuffer::getFile(ProfileFile.path()); - ASSERT_TRUE(!!MB); - ASSERT_NE(*MB, nullptr); - BitstreamCursor Cursor((*MB)->getBuffer()); - PGOCtxProfileReader Reader(Cursor); - auto Expected = Reader.loadContexts(); - EXPECT_TRUE(!!Expected); - EXPECT_TRUE(Expected->empty()); - } -} - -TEST_F(PGOCtxProfRWTest, WrongVersion) { - llvm::unittest::TempFile ProfileFile("ctx_profile", "", "", /*Unique*/ true); - { - std::error_code EC; - raw_fd_stream Out(ProfileFile.path(), EC); - ASSERT_FALSE(EC); - { - PGOCtxProfileWriter Writer(Out, PGOCtxProfileWriter::CurrentVersion + 1); - } - } - { - auto MB = MemoryBuffer::getFile(ProfileFile.path()); - ASSERT_TRUE(!!MB); - ASSERT_NE(*MB, nullptr); - BitstreamCursor Cursor((*MB)->getBuffer()); - PGOCtxProfileReader Reader(Cursor); - auto Expected = Reader.loadContexts(); - EXPECT_FALSE(Expected); - consumeError(Expected.takeError()); - } -} - -TEST_F(PGOCtxProfRWTest, DuplicateRoots) { - llvm::unittest::TempFile ProfileFile("ctx_profile", "", "", /*Unique*/ true); - { - std::error_code EC; - raw_fd_stream Out(ProfileFile.path(), EC); - ASSERT_FALSE(EC); - { - PGOCtxProfileWriter Writer(Out); - Writer.write(*createNode(1, 1, 1)); - Writer.write(*createNode(1, 1, 1)); - } - } - { - auto MB = MemoryBuffer::getFile(ProfileFile.path()); - ASSERT_TRUE(!!MB); - ASSERT_NE(*MB, nullptr); - BitstreamCursor Cursor((*MB)->getBuffer()); - PGOCtxProfileReader Reader(Cursor); - auto Expected = Reader.loadContexts(); - EXPECT_FALSE(Expected); - consumeError(Expected.takeError()); - } -} - -TEST_F(PGOCtxProfRWTest, DuplicateTargets) { - llvm::unittest::TempFile ProfileFile("ctx_profile", "", "", /*Unique*/ true); - { - std::error_code EC; - raw_fd_stream Out(ProfileFile.path(), EC); - ASSERT_FALSE(EC); - { - auto *R = createNode(1, 1, 1); - auto *L1 = createNode(2, 1, 0); - auto *L2 = createNode(2, 1, 0, L1); - R->subContexts()[0] = L2; - PGOCtxProfileWriter Writer(Out); - Writer.write(*R); - } - } - { - auto MB = MemoryBuffer::getFile(ProfileFile.path()); - ASSERT_TRUE(!!MB); - ASSERT_NE(*MB, nullptr); - BitstreamCursor Cursor((*MB)->getBuffer()); - PGOCtxProfileReader Reader(Cursor); - auto Expected = Reader.loadContexts(); - EXPECT_FALSE(Expected); - consumeError(Expected.takeError()); - } -}