[ctxprof] Prepare profile format for flat profiles (#129626)
The profile format has now a separate section called "Contexts" - there will be a corresponding one for flat profiles. The root has a separate tag because, in addition to not having a callsite ID as all the other context nodes have under it, it will have additional fields in subsequent patches. The rest of this patch amounts to a bit of refactorings in the reader/writer (for better reuse later) and tests fixups.
This commit is contained in:
parent
bdbc434498
commit
5223ddd83f
@ -114,9 +114,14 @@ public:
|
||||
};
|
||||
|
||||
/// Abstraction for the parameter passed to `__llvm_ctx_profile_fetch`.
|
||||
/// `startContextSection` is called before any context roots are sent for
|
||||
/// writing. Then one or more `writeContextual` calls are made; finally,
|
||||
/// `endContextSection` is called.
|
||||
class ProfileWriter {
|
||||
public:
|
||||
virtual void startContextSection() = 0;
|
||||
virtual void writeContextual(const ctx_profile::ContextNode &RootNode) = 0;
|
||||
virtual void endContextSection() = 0;
|
||||
virtual ~ProfileWriter() = default;
|
||||
};
|
||||
} // namespace ctx_profile
|
||||
|
||||
@ -298,6 +298,7 @@ bool __llvm_ctx_profile_fetch(ProfileWriter &Writer) {
|
||||
__sanitizer::GenericScopedLock<__sanitizer::SpinMutex> Lock(
|
||||
&AllContextsMutex);
|
||||
|
||||
Writer.startContextSection();
|
||||
for (int I = 0, E = AllContextRoots.Size(); I < E; ++I) {
|
||||
auto *Root = AllContextRoots[I];
|
||||
__sanitizer::GenericScopedLock<__sanitizer::StaticSpinMutex> TakenLock(
|
||||
@ -308,6 +309,7 @@ bool __llvm_ctx_profile_fetch(ProfileWriter &Writer) {
|
||||
}
|
||||
Writer.writeContextual(*Root->FirstNode);
|
||||
}
|
||||
Writer.endContextSection();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -183,11 +183,18 @@ TEST_F(ContextTest, Dump) {
|
||||
public:
|
||||
ContextRoot *const Root;
|
||||
const size_t Entries;
|
||||
|
||||
int EnteredSectionCount = 0;
|
||||
int ExitedSectionCount = 0;
|
||||
|
||||
bool State = false;
|
||||
|
||||
TestProfileWriter(ContextRoot *Root, size_t Entries)
|
||||
: Root(Root), Entries(Entries) {}
|
||||
|
||||
void writeContextual(const ContextNode &Node) override {
|
||||
EXPECT_EQ(EnteredSectionCount, 1);
|
||||
EXPECT_EQ(ExitedSectionCount, 0);
|
||||
EXPECT_FALSE(Root->Taken.TryLock());
|
||||
EXPECT_EQ(Node.guid(), 1U);
|
||||
EXPECT_EQ(Node.counters()[0], Entries);
|
||||
@ -205,7 +212,13 @@ TEST_F(ContextTest, Dump) {
|
||||
EXPECT_EQ(SN.subContexts()[0], nullptr);
|
||||
State = true;
|
||||
}
|
||||
void startContextSection() override { ++EnteredSectionCount; }
|
||||
void endContextSection() override {
|
||||
EXPECT_EQ(EnteredSectionCount, 1);
|
||||
++ExitedSectionCount;
|
||||
}
|
||||
};
|
||||
|
||||
TestProfileWriter W(&Root, 1);
|
||||
EXPECT_FALSE(W.State);
|
||||
__llvm_ctx_profile_fetch(W);
|
||||
@ -217,4 +230,6 @@ TEST_F(ContextTest, Dump) {
|
||||
EXPECT_FALSE(W2.State);
|
||||
__llvm_ctx_profile_fetch(W2);
|
||||
EXPECT_TRUE(W2.State);
|
||||
EXPECT_EQ(W2.EnteredSectionCount, 1);
|
||||
EXPECT_EQ(W2.ExitedSectionCount, 1);
|
||||
}
|
||||
|
||||
@ -62,7 +62,14 @@ class TestProfileWriter : public ProfileWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void startContextSection() override {
|
||||
std::cout << "Entered Context Section" << std::endl;
|
||||
}
|
||||
|
||||
void endContextSection() override {
|
||||
std::cout << "Exited Context Section" << std::endl;
|
||||
}
|
||||
|
||||
void writeContextual(const ContextNode &RootNode) override {
|
||||
printProfile(RootNode, "", "");
|
||||
}
|
||||
@ -77,6 +84,7 @@ public:
|
||||
// path gets instrumented).
|
||||
// The second context is in the loop. We expect 2 entries and each of the
|
||||
// branches would be taken once, so the second counter is 1.
|
||||
// CHECK-NEXT: Entered Context Section
|
||||
// CHECK-NEXT: Guid: 8657661246551306189
|
||||
// CHECK-NEXT: Entries: 1
|
||||
// CHECK-NEXT: 2 counters and 3 callsites
|
||||
@ -91,6 +99,7 @@ public:
|
||||
// CHECK-NEXT: Entries: 2
|
||||
// CHECK-NEXT: 2 counters and 2 callsites
|
||||
// CHECK-NEXT: Counter values: 2 1
|
||||
// CHECK-NEXT: Exited Context Section
|
||||
|
||||
bool profileWriter() {
|
||||
TestProfileWriter W;
|
||||
|
||||
@ -54,6 +54,8 @@ public:
|
||||
return Profiles.Contexts;
|
||||
}
|
||||
|
||||
const PGOCtxProfile &profiles() const { return Profiles; }
|
||||
|
||||
bool isFunctionKnown(const Function &F) const {
|
||||
return getDefinedFunctionGUID(F) != 0;
|
||||
}
|
||||
|
||||
@ -114,9 +114,14 @@ public:
|
||||
};
|
||||
|
||||
/// Abstraction for the parameter passed to `__llvm_ctx_profile_fetch`.
|
||||
/// `startContextSection` is called before any context roots are sent for
|
||||
/// writing. Then one or more `writeContextual` calls are made; finally,
|
||||
/// `endContextSection` is called.
|
||||
class ProfileWriter {
|
||||
public:
|
||||
virtual void startContextSection() = 0;
|
||||
virtual void writeContextual(const ctx_profile::ContextNode &RootNode) = 0;
|
||||
virtual void endContextSection() = 0;
|
||||
virtual ~ProfileWriter() = default;
|
||||
};
|
||||
} // namespace ctx_profile
|
||||
|
||||
@ -190,8 +190,12 @@ class PGOCtxProfileReader final {
|
||||
Error unsupported(const Twine &);
|
||||
|
||||
Expected<std::pair<std::optional<uint32_t>, PGOCtxProfContext>>
|
||||
readContext(bool ExpectIndex);
|
||||
bool canReadContext();
|
||||
readProfile(PGOCtxProfileBlockIDs Kind);
|
||||
|
||||
bool canEnterBlockWithID(PGOCtxProfileBlockIDs ID);
|
||||
Error enterBlockWithID(PGOCtxProfileBlockIDs ID);
|
||||
|
||||
Error loadContexts(CtxProfContextualProfiles &);
|
||||
|
||||
public:
|
||||
PGOCtxProfileReader(StringRef Buffer)
|
||||
@ -201,7 +205,6 @@ public:
|
||||
Expected<PGOCtxProfile> loadProfiles();
|
||||
};
|
||||
|
||||
void convertCtxProfToYaml(raw_ostream &OS,
|
||||
const PGOCtxProfContext::CallTargetMapTy &);
|
||||
void convertCtxProfToYaml(raw_ostream &OS, const PGOCtxProfile &);
|
||||
} // namespace llvm
|
||||
#endif
|
||||
|
||||
@ -23,7 +23,9 @@ enum PGOCtxProfileRecords { Invalid = 0, Version, Guid, CalleeIndex, Counters };
|
||||
|
||||
enum PGOCtxProfileBlockIDs {
|
||||
ProfileMetadataBlockID = bitc::FIRST_APPLICATION_BLOCKID,
|
||||
ContextNodeBlockID = ProfileMetadataBlockID + 1
|
||||
ContextsSectionBlockID = ProfileMetadataBlockID + 1,
|
||||
ContextRootBlockID = ContextsSectionBlockID + 1,
|
||||
ContextNodeBlockID = ContextRootBlockID + 1,
|
||||
};
|
||||
|
||||
/// Write one or more ContextNodes to the provided raw_fd_stream.
|
||||
@ -60,23 +62,30 @@ enum PGOCtxProfileBlockIDs {
|
||||
/// 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 {
|
||||
BitstreamWriter Writer;
|
||||
class PGOCtxProfileWriter : public ctx_profile::ProfileWriter {
|
||||
enum class EmptyContextCriteria { None, EntryIsZero, AllAreZero };
|
||||
|
||||
void writeCounters(const ctx_profile::ContextNode &Node);
|
||||
BitstreamWriter Writer;
|
||||
const bool IncludeEmpty;
|
||||
|
||||
void writeGuid(ctx_profile::GUID Guid);
|
||||
void writeCounters(ArrayRef<uint64_t> Counters);
|
||||
void writeImpl(std::optional<uint32_t> CallerIndex,
|
||||
const ctx_profile::ContextNode &Node);
|
||||
|
||||
public:
|
||||
PGOCtxProfileWriter(raw_ostream &Out,
|
||||
std::optional<unsigned> VersionOverride = std::nullopt);
|
||||
std::optional<unsigned> VersionOverride = std::nullopt,
|
||||
bool IncludeEmpty = false);
|
||||
~PGOCtxProfileWriter() { Writer.ExitBlock(); }
|
||||
|
||||
void write(const ctx_profile::ContextNode &);
|
||||
void startContextSection() override;
|
||||
void writeContextual(const ctx_profile::ContextNode &RootNode) override;
|
||||
void endContextSection() override;
|
||||
|
||||
// constants used in writing which a reader may find useful.
|
||||
static constexpr unsigned CodeLen = 2;
|
||||
static constexpr uint32_t CurrentVersion = 1;
|
||||
static constexpr uint32_t CurrentVersion = 2;
|
||||
static constexpr unsigned VBREncodingBits = 6;
|
||||
static constexpr StringRef ContainerMagic = "CTXP";
|
||||
};
|
||||
|
||||
@ -180,7 +180,7 @@ PreservedAnalyses CtxProfAnalysisPrinterPass::run(Module &M,
|
||||
|
||||
if (Mode == PrintMode::Everything)
|
||||
OS << "\nCurrent Profile:\n";
|
||||
convertCtxProfToYaml(OS, C.contexts());
|
||||
convertCtxProfToYaml(OS, C.profiles());
|
||||
OS << "\n";
|
||||
if (Mode == PrintMode::YAML)
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/YAMLTraits.h"
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
@ -58,19 +57,26 @@ Error PGOCtxProfileReader::unsupported(const Twine &Msg) {
|
||||
return make_error<InstrProfError>(instrprof_error::unsupported_version, Msg);
|
||||
}
|
||||
|
||||
bool PGOCtxProfileReader::canReadContext() {
|
||||
bool PGOCtxProfileReader::canEnterBlockWithID(PGOCtxProfileBlockIDs ID) {
|
||||
auto Blk = advance();
|
||||
if (!Blk) {
|
||||
consumeError(Blk.takeError());
|
||||
return false;
|
||||
}
|
||||
return Blk->Kind == BitstreamEntry::SubBlock &&
|
||||
Blk->ID == PGOCtxProfileBlockIDs::ContextNodeBlockID;
|
||||
return Blk->Kind == BitstreamEntry::SubBlock && Blk->ID == ID;
|
||||
}
|
||||
|
||||
Error PGOCtxProfileReader::enterBlockWithID(PGOCtxProfileBlockIDs ID) {
|
||||
RET_ON_ERR(Cursor.EnterSubBlock(ID));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<std::pair<std::optional<uint32_t>, PGOCtxProfContext>>
|
||||
PGOCtxProfileReader::readContext(bool ExpectIndex) {
|
||||
RET_ON_ERR(Cursor.EnterSubBlock(PGOCtxProfileBlockIDs::ContextNodeBlockID));
|
||||
PGOCtxProfileReader::readProfile(PGOCtxProfileBlockIDs Kind) {
|
||||
assert((Kind == PGOCtxProfileBlockIDs::ContextRootBlockID ||
|
||||
Kind == PGOCtxProfileBlockIDs::ContextNodeBlockID) &&
|
||||
"Unexpected profile kind");
|
||||
RET_ON_ERR(enterBlockWithID(Kind));
|
||||
|
||||
std::optional<ctx_profile::GUID> Guid;
|
||||
std::optional<SmallVector<uint64_t, 16>> Counters;
|
||||
@ -78,6 +84,7 @@ PGOCtxProfileReader::readContext(bool ExpectIndex) {
|
||||
|
||||
SmallVector<uint64_t, 1> RecordValues;
|
||||
|
||||
const bool ExpectIndex = Kind == PGOCtxProfileBlockIDs::ContextNodeBlockID;
|
||||
// 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.
|
||||
@ -121,8 +128,8 @@ PGOCtxProfileReader::readContext(bool ExpectIndex) {
|
||||
|
||||
PGOCtxProfContext Ret(*Guid, std::move(*Counters));
|
||||
|
||||
while (canReadContext()) {
|
||||
EXPECT_OR_RET(SC, readContext(true));
|
||||
while (canEnterBlockWithID(PGOCtxProfileBlockIDs::ContextNodeBlockID)) {
|
||||
EXPECT_OR_RET(SC, readProfile(PGOCtxProfileBlockIDs::ContextNodeBlockID));
|
||||
auto &Targets = Ret.callsites()[*SC->first];
|
||||
auto [_, Inserted] =
|
||||
Targets.insert({SC->second.guid(), std::move(SC->second)});
|
||||
@ -168,15 +175,23 @@ Error PGOCtxProfileReader::readMetadata() {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<PGOCtxProfile> PGOCtxProfileReader::loadProfiles() {
|
||||
PGOCtxProfile Ret;
|
||||
RET_ON_ERR(readMetadata());
|
||||
while (canReadContext()) {
|
||||
EXPECT_OR_RET(E, readContext(false));
|
||||
auto Key = E->second.guid();
|
||||
if (!Ret.Contexts.insert({Key, std::move(E->second)}).second)
|
||||
return wrongValue("Duplicate roots");
|
||||
Error PGOCtxProfileReader::loadContexts(CtxProfContextualProfiles &P) {
|
||||
if (canEnterBlockWithID(PGOCtxProfileBlockIDs::ContextsSectionBlockID)) {
|
||||
RET_ON_ERR(enterBlockWithID(PGOCtxProfileBlockIDs::ContextsSectionBlockID));
|
||||
while (canEnterBlockWithID(PGOCtxProfileBlockIDs::ContextRootBlockID)) {
|
||||
EXPECT_OR_RET(E, readProfile(PGOCtxProfileBlockIDs::ContextRootBlockID));
|
||||
auto Key = E->second.guid();
|
||||
if (!P.insert({Key, std::move(E->second)}).second)
|
||||
return wrongValue("Duplicate roots");
|
||||
}
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<PGOCtxProfile> PGOCtxProfileReader::loadProfiles() {
|
||||
RET_ON_ERR(readMetadata());
|
||||
PGOCtxProfile Ret;
|
||||
RET_ON_ERR(loadContexts(Ret.Contexts));
|
||||
return std::move(Ret);
|
||||
}
|
||||
|
||||
@ -224,7 +239,9 @@ void toYaml(yaml::Output &Out,
|
||||
Out.endSequence();
|
||||
}
|
||||
|
||||
void toYaml(yaml::Output &Out, const PGOCtxProfContext &Ctx) {
|
||||
void toYaml(yaml::Output &Out, GlobalValue::GUID Guid,
|
||||
const SmallVectorImpl<uint64_t> &Counters,
|
||||
const PGOCtxProfContext::CallsiteMapTy &Callsites) {
|
||||
yaml::EmptyContext Empty;
|
||||
Out.beginMapping();
|
||||
void *SaveInfo = nullptr;
|
||||
@ -232,33 +249,44 @@ void toYaml(yaml::Output &Out, const PGOCtxProfContext &Ctx) {
|
||||
{
|
||||
Out.preflightKey("Guid", /*Required=*/true, /*SameAsDefault=*/false,
|
||||
UseDefault, SaveInfo);
|
||||
auto Guid = Ctx.guid();
|
||||
yaml::yamlize(Out, Guid, true, Empty);
|
||||
Out.postflightKey(nullptr);
|
||||
}
|
||||
{
|
||||
Out.preflightKey("Counters", true, false, UseDefault, SaveInfo);
|
||||
Out.beginFlowSequence();
|
||||
for (size_t I = 0U, E = Ctx.counters().size(); I < E; ++I) {
|
||||
for (size_t I = 0U, E = Counters.size(); I < E; ++I) {
|
||||
Out.preflightFlowElement(I, SaveInfo);
|
||||
uint64_t V = Ctx.counters()[I];
|
||||
uint64_t V = Counters[I];
|
||||
yaml::yamlize(Out, V, true, Empty);
|
||||
Out.postflightFlowElement(SaveInfo);
|
||||
}
|
||||
Out.endFlowSequence();
|
||||
Out.postflightKey(nullptr);
|
||||
}
|
||||
if (!Ctx.callsites().empty()) {
|
||||
if (!Callsites.empty()) {
|
||||
Out.preflightKey("Callsites", true, false, UseDefault, SaveInfo);
|
||||
toYaml(Out, Ctx.callsites());
|
||||
toYaml(Out, Callsites);
|
||||
Out.postflightKey(nullptr);
|
||||
}
|
||||
Out.endMapping();
|
||||
}
|
||||
void toYaml(yaml::Output &Out, const PGOCtxProfContext &Ctx) {
|
||||
toYaml(Out, Ctx.guid(), Ctx.counters(), Ctx.callsites());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void llvm::convertCtxProfToYaml(
|
||||
raw_ostream &OS, const PGOCtxProfContext::CallTargetMapTy &Profiles) {
|
||||
void llvm::convertCtxProfToYaml(raw_ostream &OS,
|
||||
const PGOCtxProfile &Profiles) {
|
||||
yaml::Output Out(OS);
|
||||
toYaml(Out, Profiles);
|
||||
}
|
||||
void *SaveInfo = nullptr;
|
||||
bool UseDefault = false;
|
||||
Out.beginMapping();
|
||||
if (!Profiles.Contexts.empty()) {
|
||||
Out.preflightKey("Contexts", false, false, UseDefault, SaveInfo);
|
||||
toYaml(Out, Profiles.Contexts);
|
||||
Out.postflightKey(nullptr);
|
||||
}
|
||||
Out.endMapping();
|
||||
}
|
||||
|
||||
@ -13,17 +13,25 @@
|
||||
#include "llvm/ProfileData/PGOCtxProfWriter.h"
|
||||
#include "llvm/Bitstream/BitCodeEnums.h"
|
||||
#include "llvm/ProfileData/CtxInstrContextNode.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/YAMLTraits.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::ctx_profile;
|
||||
|
||||
static cl::opt<bool>
|
||||
IncludeEmptyOpt("ctx-prof-include-empty", cl::init(false),
|
||||
cl::desc("Also write profiles with all-zero counters. "
|
||||
"Intended for testing/debugging."));
|
||||
|
||||
PGOCtxProfileWriter::PGOCtxProfileWriter(
|
||||
raw_ostream &Out, std::optional<unsigned> VersionOverride)
|
||||
: Writer(Out, 0) {
|
||||
raw_ostream &Out, std::optional<unsigned> VersionOverride,
|
||||
bool IncludeEmpty)
|
||||
: Writer(Out, 0),
|
||||
IncludeEmpty(IncludeEmptyOpt.getNumOccurrences() > 0 ? IncludeEmptyOpt
|
||||
: IncludeEmpty) {
|
||||
static_assert(ContainerMagic.size() == 4);
|
||||
Out.write(ContainerMagic.data(), ContainerMagic.size());
|
||||
Writer.EnterBlockInfoBlock();
|
||||
@ -43,6 +51,10 @@ PGOCtxProfileWriter::PGOCtxProfileWriter(
|
||||
};
|
||||
DescribeBlock(PGOCtxProfileBlockIDs::ProfileMetadataBlockID, "Metadata");
|
||||
DescribeRecord(PGOCtxProfileRecords::Version, "Version");
|
||||
DescribeBlock(PGOCtxProfileBlockIDs::ContextsSectionBlockID, "Contexts");
|
||||
DescribeBlock(PGOCtxProfileBlockIDs::ContextRootBlockID, "Root");
|
||||
DescribeRecord(PGOCtxProfileRecords::Guid, "GUID");
|
||||
DescribeRecord(PGOCtxProfileRecords::Counters, "Counters");
|
||||
DescribeBlock(PGOCtxProfileBlockIDs::ContextNodeBlockID, "Context");
|
||||
DescribeRecord(PGOCtxProfileRecords::Guid, "GUID");
|
||||
DescribeRecord(PGOCtxProfileRecords::CalleeIndex, "CalleeIndex");
|
||||
@ -55,12 +67,16 @@ PGOCtxProfileWriter::PGOCtxProfileWriter(
|
||||
SmallVector<unsigned, 1>({Version}));
|
||||
}
|
||||
|
||||
void PGOCtxProfileWriter::writeCounters(const ContextNode &Node) {
|
||||
void PGOCtxProfileWriter::writeCounters(ArrayRef<uint64_t> Counters) {
|
||||
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);
|
||||
Writer.EmitVBR(Counters.size(), VBREncodingBits);
|
||||
for (uint64_t C : Counters)
|
||||
Writer.EmitVBR64(C, VBREncodingBits);
|
||||
}
|
||||
|
||||
void PGOCtxProfileWriter::writeGuid(ctx_profile::GUID Guid) {
|
||||
Writer.EmitRecord(PGOCtxProfileRecords::Guid, SmallVector<uint64_t, 1>{Guid});
|
||||
}
|
||||
|
||||
// recursively write all the subcontexts. We do need to traverse depth first to
|
||||
@ -69,13 +85,18 @@ void PGOCtxProfileWriter::writeCounters(const ContextNode &Node) {
|
||||
// keep the implementation simple.
|
||||
void PGOCtxProfileWriter::writeImpl(std::optional<uint32_t> CallerIndex,
|
||||
const ContextNode &Node) {
|
||||
Writer.EnterSubblock(PGOCtxProfileBlockIDs::ContextNodeBlockID, CodeLen);
|
||||
Writer.EmitRecord(PGOCtxProfileRecords::Guid,
|
||||
SmallVector<uint64_t, 1>{Node.guid()});
|
||||
// A node with no counters is an error. We don't expect this to happen from
|
||||
// the runtime, rather, this is interesting for testing the reader.
|
||||
if (!IncludeEmpty && (Node.counters_size() > 0 && Node.entrycount() == 0))
|
||||
return;
|
||||
Writer.EnterSubblock(CallerIndex ? PGOCtxProfileBlockIDs::ContextNodeBlockID
|
||||
: PGOCtxProfileBlockIDs::ContextRootBlockID,
|
||||
CodeLen);
|
||||
writeGuid(Node.guid());
|
||||
if (CallerIndex)
|
||||
Writer.EmitRecord(PGOCtxProfileRecords::CalleeIndex,
|
||||
SmallVector<uint64_t, 1>{*CallerIndex});
|
||||
writeCounters(Node);
|
||||
writeCounters({Node.counters(), Node.counters_size()});
|
||||
for (uint32_t I = 0U; I < Node.callsites_size(); ++I)
|
||||
for (const auto *Subcontext = Node.subContexts()[I]; Subcontext;
|
||||
Subcontext = Subcontext->next())
|
||||
@ -83,7 +104,13 @@ void PGOCtxProfileWriter::writeImpl(std::optional<uint32_t> CallerIndex,
|
||||
Writer.ExitBlock();
|
||||
}
|
||||
|
||||
void PGOCtxProfileWriter::write(const ContextNode &RootNode) {
|
||||
void PGOCtxProfileWriter::startContextSection() {
|
||||
Writer.EnterSubblock(PGOCtxProfileBlockIDs::ContextsSectionBlockID, CodeLen);
|
||||
}
|
||||
|
||||
void PGOCtxProfileWriter::endContextSection() { Writer.ExitBlock(); }
|
||||
|
||||
void PGOCtxProfileWriter::writeContextual(const ContextNode &RootNode) {
|
||||
writeImpl(std::nullopt, RootNode);
|
||||
}
|
||||
|
||||
@ -96,6 +123,9 @@ struct SerializableCtxRepresentation {
|
||||
std::vector<uint64_t> Counters;
|
||||
std::vector<std::vector<SerializableCtxRepresentation>> Callsites;
|
||||
};
|
||||
struct SerializableProfileRepresentation {
|
||||
std::vector<SerializableCtxRepresentation> Contexts;
|
||||
};
|
||||
|
||||
ctx_profile::ContextNode *
|
||||
createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
|
||||
@ -142,10 +172,16 @@ template <> struct yaml::MappingTraits<SerializableCtxRepresentation> {
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct yaml::MappingTraits<SerializableProfileRepresentation> {
|
||||
static void mapping(yaml::IO &IO, SerializableProfileRepresentation &SPR) {
|
||||
IO.mapOptional("Contexts", SPR.Contexts);
|
||||
}
|
||||
};
|
||||
|
||||
Error llvm::createCtxProfFromYAML(StringRef Profile, raw_ostream &Out) {
|
||||
yaml::Input In(Profile);
|
||||
std::vector<SerializableCtxRepresentation> DCList;
|
||||
In >> DCList;
|
||||
SerializableProfileRepresentation SPR;
|
||||
In >> SPR;
|
||||
if (In.error())
|
||||
return createStringError(In.error(), "incorrect yaml content");
|
||||
std::vector<std::unique_ptr<char[]>> Nodes;
|
||||
@ -153,12 +189,17 @@ Error llvm::createCtxProfFromYAML(StringRef Profile, raw_ostream &Out) {
|
||||
if (EC)
|
||||
return createStringError(EC, "failed to open output");
|
||||
PGOCtxProfileWriter Writer(Out);
|
||||
for (const auto &DC : DCList) {
|
||||
auto *TopList = createNode(Nodes, DC);
|
||||
if (!TopList)
|
||||
return createStringError(
|
||||
"Unexpected error converting internal structure to ctx profile");
|
||||
Writer.write(*TopList);
|
||||
|
||||
if (!SPR.Contexts.empty()) {
|
||||
Writer.startContextSection();
|
||||
for (const auto &DC : SPR.Contexts) {
|
||||
auto *TopList = createNode(Nodes, DC);
|
||||
if (!TopList)
|
||||
return createStringError(
|
||||
"Unexpected error converting internal structure to ctx profile");
|
||||
Writer.writeContextual(*TopList);
|
||||
}
|
||||
Writer.endContextSection();
|
||||
}
|
||||
if (EC)
|
||||
return createStringError(EC, "failed to write output");
|
||||
|
||||
@ -59,14 +59,15 @@
|
||||
; CHECK: ![[AN_ENTRYPOINT_BW]] = !{!"branch_weights", i32 40, i32 60}
|
||||
|
||||
;--- profile.yaml
|
||||
- Guid: 4909520559318251808
|
||||
Counters: [100, 40]
|
||||
Callsites: -
|
||||
- Guid: 11872291593386833696
|
||||
Counters: [ 100, 5 ]
|
||||
-
|
||||
- Guid: 11872291593386833696
|
||||
Counters: [ 40, 10 ]
|
||||
Contexts:
|
||||
- Guid: 4909520559318251808
|
||||
Counters: [100, 40]
|
||||
Callsites: -
|
||||
- Guid: 11872291593386833696
|
||||
Counters: [ 100, 5 ]
|
||||
-
|
||||
- Guid: 11872291593386833696
|
||||
Counters: [ 40, 10 ]
|
||||
;--- example.ll
|
||||
declare void @bar()
|
||||
|
||||
|
||||
@ -39,8 +39,9 @@ exit:
|
||||
!0 = !{i64 1234}
|
||||
|
||||
;--- profile_ok.yaml
|
||||
- Guid: 1234
|
||||
Counters: [2, 2, 1, 2]
|
||||
Contexts:
|
||||
- Guid: 1234
|
||||
Counters: [2, 2, 1, 2]
|
||||
|
||||
;--- message_pump.ll
|
||||
; This is a message pump: the loop never exits. This should result in an
|
||||
@ -61,8 +62,9 @@ exit:
|
||||
!0 = !{i64 1234}
|
||||
|
||||
;--- profile_pump.yaml
|
||||
- Guid: 1234
|
||||
Counters: [2, 10, 0]
|
||||
Contexts:
|
||||
- Guid: 1234
|
||||
Counters: [2, 10, 0]
|
||||
|
||||
;--- unreachable.ll
|
||||
; An unreachable block is reached, that's an error
|
||||
@ -84,5 +86,6 @@ exit:
|
||||
!0 = !{i64 1234}
|
||||
|
||||
;--- profile_unreachable.yaml
|
||||
- Guid: 1234
|
||||
Counters: [2, 1, 1, 2]
|
||||
Contexts:
|
||||
- Guid: 1234
|
||||
Counters: [2, 1, 1, 2]
|
||||
|
||||
@ -46,17 +46,18 @@ attributes #1 = { noinline }
|
||||
!2 = !{i64 4000}
|
||||
|
||||
;--- profile.yaml
|
||||
- Guid: 4000
|
||||
Counters: [10]
|
||||
Callsites: -
|
||||
- Guid: 3000
|
||||
Counters: [10]
|
||||
Callsites: -
|
||||
- Guid: 1000
|
||||
Counters: [10]
|
||||
-
|
||||
- Guid: 3000
|
||||
Counters: [10]
|
||||
Callsites: -
|
||||
- Guid: 9000
|
||||
Counters: [10]
|
||||
Contexts:
|
||||
- Guid: 4000
|
||||
Counters: [10]
|
||||
Callsites: -
|
||||
- Guid: 3000
|
||||
Counters: [10]
|
||||
Callsites: -
|
||||
- Guid: 1000
|
||||
Counters: [10]
|
||||
-
|
||||
- Guid: 3000
|
||||
Counters: [10]
|
||||
Callsites: -
|
||||
- Guid: 9000
|
||||
Counters: [10]
|
||||
|
||||
@ -52,5 +52,6 @@ exit:
|
||||
!0 = !{i64 1234}
|
||||
|
||||
;--- profile.yaml
|
||||
- Guid: 1234
|
||||
Counters: [6,0,0,0]
|
||||
Contexts:
|
||||
- Guid: 1234
|
||||
Counters: [6,0,0,0]
|
||||
|
||||
@ -66,20 +66,21 @@ define void @entrypoint() {
|
||||
ret void
|
||||
}
|
||||
;--- profile.yaml
|
||||
- Guid: 10507721908651011566
|
||||
Counters: [1]
|
||||
Callsites: -
|
||||
- Guid: 2072045998141807037
|
||||
Counters: [7]
|
||||
Callsites: -
|
||||
- Guid: 3087265239403591524
|
||||
Counters: [10, 7]
|
||||
-
|
||||
- Guid: 4197650231481825559
|
||||
Counters: [2]
|
||||
Callsites: -
|
||||
- Guid: 3087265239403591524
|
||||
Counters: [1, 2]
|
||||
Contexts:
|
||||
- Guid: 10507721908651011566
|
||||
Counters: [1]
|
||||
Callsites: -
|
||||
- Guid: 2072045998141807037
|
||||
Counters: [7]
|
||||
Callsites: -
|
||||
- Guid: 3087265239403591524
|
||||
Counters: [10, 7]
|
||||
-
|
||||
- Guid: 4197650231481825559
|
||||
Counters: [2]
|
||||
Callsites: -
|
||||
- Guid: 3087265239403591524
|
||||
Counters: [1, 2]
|
||||
;--- expected.txt
|
||||
Function Info:
|
||||
2072045998141807037 : f1. MaxCounterID: 1. MaxCallsiteID: 1
|
||||
@ -89,19 +90,20 @@ Function Info:
|
||||
|
||||
Current Profile:
|
||||
|
||||
- Guid: 10507721908651011566
|
||||
Counters: [ 1 ]
|
||||
Callsites:
|
||||
- - Guid: 2072045998141807037
|
||||
Counters: [ 7 ]
|
||||
Callsites:
|
||||
- - Guid: 3087265239403591524
|
||||
Counters: [ 10, 7 ]
|
||||
- - Guid: 4197650231481825559
|
||||
Counters: [ 2 ]
|
||||
Callsites:
|
||||
- - Guid: 3087265239403591524
|
||||
Counters: [ 1, 2 ]
|
||||
Contexts:
|
||||
- Guid: 10507721908651011566
|
||||
Counters: [ 1 ]
|
||||
Callsites:
|
||||
- - Guid: 2072045998141807037
|
||||
Counters: [ 7 ]
|
||||
Callsites:
|
||||
- - Guid: 3087265239403591524
|
||||
Counters: [ 10, 7 ]
|
||||
- - Guid: 4197650231481825559
|
||||
Counters: [ 2 ]
|
||||
Callsites:
|
||||
- - Guid: 3087265239403591524
|
||||
Counters: [ 1, 2 ]
|
||||
|
||||
Flat Profile:
|
||||
2072045998141807037 : 7
|
||||
|
||||
@ -73,11 +73,12 @@ define i32 @bar(i32 %t) !guid !1 {
|
||||
!1 = !{i64 5678}
|
||||
|
||||
;--- profile.yaml
|
||||
- Guid: 1234
|
||||
Counters: [10, 4]
|
||||
Callsites: -
|
||||
- Guid: 5678
|
||||
Counters: [4,3]
|
||||
-
|
||||
- Guid: 5678
|
||||
Counters: [6,6]
|
||||
Contexts:
|
||||
- Guid: 1234
|
||||
Counters: [10, 4]
|
||||
Callsites: -
|
||||
- Guid: 5678
|
||||
Counters: [4,3]
|
||||
-
|
||||
- Guid: 5678
|
||||
Counters: [6,6]
|
||||
|
||||
@ -96,30 +96,32 @@ define i32 @b() !guid !2 {
|
||||
!1 = !{i64 1001}
|
||||
!2 = !{i64 1002}
|
||||
;--- profile.yaml
|
||||
- Guid: 1000
|
||||
Counters: [10, 2, 8]
|
||||
Callsites: -
|
||||
- Guid: 1001
|
||||
Counters: [2, 100]
|
||||
Callsites: -
|
||||
- Guid: 1002
|
||||
Counters: [100]
|
||||
-
|
||||
- Guid: 1001
|
||||
Counters: [8, 500]
|
||||
Callsites: -
|
||||
- Guid: 1002
|
||||
Counters: [500]
|
||||
Contexts:
|
||||
- Guid: 1000
|
||||
Counters: [10, 2, 8]
|
||||
Callsites: -
|
||||
- Guid: 1001
|
||||
Counters: [2, 100]
|
||||
Callsites: -
|
||||
- Guid: 1002
|
||||
Counters: [100]
|
||||
-
|
||||
- Guid: 1001
|
||||
Counters: [8, 500]
|
||||
Callsites: -
|
||||
- Guid: 1002
|
||||
Counters: [500]
|
||||
;--- expected.yaml
|
||||
|
||||
- Guid: 1000
|
||||
Counters: [ 10, 2, 8, 100 ]
|
||||
Callsites:
|
||||
- [ ]
|
||||
- - Guid: 1001
|
||||
Counters: [ 8, 500 ]
|
||||
Callsites:
|
||||
- - Guid: 1002
|
||||
Counters: [ 500 ]
|
||||
- - Guid: 1002
|
||||
Counters: [ 100 ]
|
||||
Contexts:
|
||||
- Guid: 1000
|
||||
Counters: [ 10, 2, 8, 100 ]
|
||||
Callsites:
|
||||
- [ ]
|
||||
- - Guid: 1001
|
||||
Counters: [ 8, 500 ]
|
||||
Callsites:
|
||||
- - Guid: 1002
|
||||
Counters: [ 500 ]
|
||||
- - Guid: 1002
|
||||
Counters: [ 100 ]
|
||||
|
||||
@ -16,15 +16,16 @@
|
||||
; the GUID present in the module, which is otherwise present in the profile, but not
|
||||
; as a root.
|
||||
;--- profile.yaml
|
||||
- Guid: 12341
|
||||
Counters: [9]
|
||||
- Guid: 1000
|
||||
Counters: [5]
|
||||
- Guid: 34234
|
||||
Counters: [1]
|
||||
Callsites: -
|
||||
- Guid: 1000
|
||||
Counters: [6, 7]
|
||||
Contexts:
|
||||
- Guid: 12341
|
||||
Counters: [9]
|
||||
- Guid: 1000
|
||||
Counters: [5]
|
||||
- Guid: 34234
|
||||
Counters: [1]
|
||||
Callsites: -
|
||||
- Guid: 1000
|
||||
Counters: [6, 7]
|
||||
;--- example.ll
|
||||
declare void @bar()
|
||||
|
||||
|
||||
@ -24,15 +24,16 @@
|
||||
; This is the reference profile, laid out in the format the json formatter will
|
||||
; output it from opt.
|
||||
;--- profile.yaml
|
||||
- Guid: 12341
|
||||
Counters: [9]
|
||||
- Guid: 12074870348631550642
|
||||
Counters: [5]
|
||||
- Guid: 11872291593386833696
|
||||
Counters: [1]
|
||||
Callsites: -
|
||||
- Guid: 728453322856651412
|
||||
Counters: [6, 7]
|
||||
Contexts:
|
||||
- Guid: 12341
|
||||
Counters: [9]
|
||||
- Guid: 12074870348631550642
|
||||
Counters: [5]
|
||||
- Guid: 11872291593386833696
|
||||
Counters: [1]
|
||||
Callsites: -
|
||||
- Guid: 728453322856651412
|
||||
Counters: [6, 7]
|
||||
;--- expected-profile-output.txt
|
||||
Function Info:
|
||||
4909520559318251808 : an_entrypoint. MaxCounterID: 2. MaxCallsiteID: 1
|
||||
@ -41,13 +42,14 @@ Function Info:
|
||||
|
||||
Current Profile:
|
||||
|
||||
- Guid: 11872291593386833696
|
||||
Counters: [ 1 ]
|
||||
Callsites:
|
||||
- - Guid: 728453322856651412
|
||||
Counters: [ 6, 7 ]
|
||||
- Guid: 12074870348631550642
|
||||
Counters: [ 5 ]
|
||||
Contexts:
|
||||
- Guid: 11872291593386833696
|
||||
Counters: [ 1 ]
|
||||
Callsites:
|
||||
- - Guid: 728453322856651412
|
||||
Counters: [ 6, 7 ]
|
||||
- Guid: 12074870348631550642
|
||||
Counters: [ 5 ]
|
||||
|
||||
Flat Profile:
|
||||
728453322856651412 : 6 7
|
||||
@ -91,4 +93,4 @@ no:
|
||||
}
|
||||
|
||||
attributes #0 = { noinline }
|
||||
!0 = !{ i64 11872291593386833696 }
|
||||
!0 = !{ i64 11872291593386833696 }
|
||||
|
||||
@ -52,10 +52,10 @@
|
||||
; RUN: opt -module-summary -passes=assign-guid,ctx-instr-gen %t/m1.ll -o %t/m1-instr.bc
|
||||
; RUN: opt -module-summary -passes=assign-guid,ctx-instr-gen %t/m2.ll -o %t/m2-instr.bc
|
||||
;
|
||||
; RUN: echo '[ \
|
||||
; RUN: echo '{"Contexts": [ \
|
||||
; RUN: {"Guid": 6019442868614718803, "Counters": [1], "Callsites": [[{"Guid": 15593096274670919754, "Counters": [1]}]]}, \
|
||||
; RUN: {"Guid": 15593096274670919754, "Counters": [1], "Callsites": [[{"Guid": 6019442868614718803, "Counters": [1]}]]} \
|
||||
; RUN: ]' > %t_exp/ctxprof.yaml
|
||||
; RUN: ]}' > %t_exp/ctxprof.yaml
|
||||
; RUN: llvm-ctxprof-util fromYAML --input %t_exp/ctxprof.yaml --output %t_exp/ctxprof.bitstream
|
||||
; RUN: llvm-lto2 run %t/m1-instr.bc %t/m2-instr.bc \
|
||||
; RUN: -o %t_exp/result.o -save-temps \
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
; REQUIRES: asserts
|
||||
; RUN: opt -passes=elim-avail-extern -avail-extern-to-local -stats -S 2>&1 < %s | FileCheck %s
|
||||
;
|
||||
; RUN: echo '[{"Guid":1234, "Counters": [1]}]' | llvm-ctxprof-util fromYAML --input=- --output=%t_profile.ctxprofdata
|
||||
; RUN: echo '{"Contexts": [{"Guid":1234, "Counters": [1]}]}' | llvm-ctxprof-util fromYAML --input=- --output=%t_profile.ctxprofdata
|
||||
;
|
||||
; Because we pass a contextual profile with a root defined in this module, we expect the outcome to be the same as-if
|
||||
; we passed -avail-extern-to-local, i.e. available_externally don't get elided and instead get converted to local linkage
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
; If the profile doesn't apply to this module, available_externally won't get converted to internal linkage, and will be
|
||||
; removed instead.
|
||||
; RUN: echo '[{"Guid":5678, "Counters": [1]}]' | llvm-ctxprof-util fromYAML --input=- --output=%t_profile_bad.ctxprofdata
|
||||
; RUN: echo '{"Contexts": [{"Guid":5678, "Counters": [1]}]}' | llvm-ctxprof-util fromYAML --input=- --output=%t_profile_bad.ctxprofdata
|
||||
; RUN: opt -passes='assign-guid,require<ctx-prof-analysis>,elim-avail-extern' -use-ctx-profile=%t_profile_bad.ctxprofdata -stats -S 2>&1 < %s | FileCheck %s --check-prefix=NOOP
|
||||
|
||||
declare void @call_out(ptr %fct)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
- Guid: 123
|
||||
Counters: [1, 2]
|
||||
Callsites: - Guid: 1
|
||||
Contexts:
|
||||
- Guid: 123
|
||||
Counters: [1, 2]
|
||||
Callsites: - Guid: 1
|
||||
|
||||
|
||||
@ -1 +1,2 @@
|
||||
- Guid: 1231
|
||||
Contexts:
|
||||
- Guid: 1231
|
||||
|
||||
@ -0,0 +1 @@
|
||||
- Guid: 1
|
||||
@ -1 +0,0 @@
|
||||
Guid: 1
|
||||
@ -1,13 +1,14 @@
|
||||
|
||||
- Guid: 1000
|
||||
Counters: [ 1, 2, 3 ]
|
||||
Callsites:
|
||||
- [ ]
|
||||
- - Guid: 2000
|
||||
Counters: [ 4, 5 ]
|
||||
- Guid: 18446744073709551613
|
||||
Counters: [ 6, 7, 8 ]
|
||||
- - Guid: 3000
|
||||
Counters: [ 40, 50 ]
|
||||
- Guid: 18446744073709551612
|
||||
Counters: [ 5, 9, 10 ]
|
||||
Contexts:
|
||||
- Guid: 1000
|
||||
Counters: [ 1, 2, 3 ]
|
||||
Callsites:
|
||||
- [ ]
|
||||
- - Guid: 2000
|
||||
Counters: [ 4, 5 ]
|
||||
- Guid: 18446744073709551613
|
||||
Counters: [ 6, 7, 8 ]
|
||||
- - Guid: 3000
|
||||
Counters: [ 40, 50 ]
|
||||
- Guid: 18446744073709551612
|
||||
Counters: [ 5, 9, 10 ]
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
; RUN: not llvm-ctxprof-util fromYAML nofile.yaml 2>&1 | FileCheck %s --check-prefix=NO_FLAG
|
||||
; RUN: not llvm-ctxprof-util fromYAML --input nofile.yaml 2>&1 | FileCheck -DMSG=%errc_ENOENT %s --check-prefix=NO_FILE
|
||||
; RUN: not llvm-ctxprof-util fromYAML --input %S/Inputs/bad.yaml 2>&1 | FileCheck %s --check-prefix=BAD_FORMAT
|
||||
; RUN: not llvm-ctxprof-util fromYAML --input %S/Inputs/invalid-no-vector.yaml 2>&1 | FileCheck %s --check-prefix=NO_VECTOR
|
||||
; RUN: not llvm-ctxprof-util fromYAML --input %S/Inputs/invalid-no-section.yaml 2>&1 | FileCheck %s --check-prefix=NO_SECTION
|
||||
; RUN: not llvm-ctxprof-util fromYAML --input %S/Inputs/invalid-no-ctx.yaml 2>&1 | FileCheck %s --check-prefix=NO_CTX
|
||||
; RUN: not llvm-ctxprof-util fromYAML --input %S/Inputs/invalid-no-counters.yaml 2>&1 | FileCheck %s --check-prefix=NO_COUNTERS
|
||||
; RUN: not llvm-ctxprof-util fromYAML --input %S/Inputs/invalid-bad-subctx.yaml 2>&1 | FileCheck %s --check-prefix=BAD_SUBCTX
|
||||
@ -16,9 +16,9 @@
|
||||
; INVALID_CMD: Unknown subcommand 'invalidCmd'
|
||||
; NO_FLAG: Unknown command line argument 'nofile.yaml'.
|
||||
; NO_FILE: 'nofile.yaml': [[MSG]]
|
||||
; BAD_FORMAT: YAML:1:3: error: not a mapping
|
||||
; NO_VECTOR: YAML:1:1: error: not a sequence
|
||||
; NO_CTX: YAML:1:2: error: not a mapping
|
||||
; NO_COUNTERS: YAML:1:3: error: missing required key 'Counters'
|
||||
; BAD_SUBCTX: YAML:3:16: error: not a sequence
|
||||
; BAD_FORMAT: YAML:1:1: error: not a mapping
|
||||
; NO_SECTION: YAML:1:1: error: not a mapping
|
||||
; NO_CTX: YAML:1:1: error: not a mapping
|
||||
; NO_COUNTERS: YAML:2:5: error: missing required key 'Counters'
|
||||
; BAD_SUBCTX: YAML:4:18: error: not a sequence
|
||||
; NO_DIR: failed to open output
|
||||
|
||||
@ -18,33 +18,35 @@
|
||||
|
||||
; EMPTY: <BLOCKINFO_BLOCK/>
|
||||
; EMPTY-NEXT: <Metadata NumWords=1 BlockCodeSize=2>
|
||||
; EMPTY-NEXT: <Version op0=1/>
|
||||
; EMPTY-NEXT: <Version op0=2/>
|
||||
; EMPTY-NEXT: </Metadata>
|
||||
|
||||
; VALID: <BLOCKINFO_BLOCK/>
|
||||
; VALID-NEXT: <Metadata NumWords=30 BlockCodeSize=2>
|
||||
; VALID-NEXT: <Version op0=1/>
|
||||
; VALID-NEXT: <Context NumWords=20 BlockCodeSize=2>
|
||||
; VALID-NEXT: <GUID op0=1000/>
|
||||
; VALID-NEXT: <Counters op0=1 op1=2 op2=3/>
|
||||
; VALID-NEXT: <Context NumWords=5 BlockCodeSize=2>
|
||||
; VALID-NEXT: <GUID op0=-3/>
|
||||
; VALID-NEXT: <CalleeIndex op0=1/>
|
||||
; VALID-NEXT: <Counters op0=6 op1=7 op2=8/>
|
||||
; VALID-NEXT: </Context>
|
||||
; VALID-NEXT: <Context NumWords=3 BlockCodeSize=2>
|
||||
; VALID-NEXT: <GUID op0=2000/>
|
||||
; VALID-NEXT: <CalleeIndex op0=1/>
|
||||
; VALID-NEXT: <Counters op0=4 op1=5/>
|
||||
; VALID-NEXT: </Context>
|
||||
; VALID-NEXT: <Context NumWords=3 BlockCodeSize=2>
|
||||
; VALID-NEXT: <GUID op0=3000/>
|
||||
; VALID-NEXT: <CalleeIndex op0=2/>
|
||||
; VALID-NEXT: <Counters op0=40 op1=50/>
|
||||
; VALID-NEXT: </Context>
|
||||
; VALID-NEXT: </Context>
|
||||
; VALID-NEXT: <Context NumWords=4 BlockCodeSize=2>
|
||||
; VALID-NEXT: <GUID op0=-4/>
|
||||
; VALID-NEXT: <Counters op0=5 op1=9 op2=10/>
|
||||
; VALID-NEXT: </Context>
|
||||
; VALID-NEXT: </Metadata>
|
||||
; VALID-NEXT: <Metadata NumWords=33 BlockCodeSize=2>
|
||||
; VALID-NEXT: <Version op0=2/>
|
||||
; VALID-NEXT: <Contexts NumWords=29 BlockCodeSize=2>
|
||||
; VALID-NEXT: <Root NumWords=20 BlockCodeSize=2>
|
||||
; VALID-NEXT: <GUID op0=1000/>
|
||||
; VALID-NEXT: <Counters op0=1 op1=2 op2=3/>
|
||||
; VALID-NEXT: <Context NumWords=5 BlockCodeSize=2>
|
||||
; VALID-NEXT: <GUID op0=-3/>
|
||||
; VALID-NEXT: <CalleeIndex op0=1/>
|
||||
; VALID-NEXT: <Counters op0=6 op1=7 op2=8/>
|
||||
; VALID-NEXT: </Context>
|
||||
; VALID-NEXT: <Context NumWords=3 BlockCodeSize=2>
|
||||
; VALID-NEXT: <GUID op0=2000/>
|
||||
; VALID-NEXT: <CalleeIndex op0=1/>
|
||||
; VALID-NEXT: <Counters op0=4 op1=5/>
|
||||
; VALID-NEXT: </Context>
|
||||
; VALID-NEXT: <Context NumWords=3 BlockCodeSize=2>
|
||||
; VALID-NEXT: <GUID op0=3000/>
|
||||
; VALID-NEXT: <CalleeIndex op0=2/>
|
||||
; VALID-NEXT: <Counters op0=40 op1=50/>
|
||||
; VALID-NEXT: </Context>
|
||||
; VALID-NEXT: </Root>
|
||||
; VALID-NEXT: <Root NumWords=4 BlockCodeSize=2>
|
||||
; VALID-NEXT: <GUID op0=-4/>
|
||||
; VALID-NEXT: <Counters op0=5 op1=9 op2=10/>
|
||||
; VALID-NEXT: </Root>
|
||||
; VALID-NEXT: </Contexts>
|
||||
; VALID-NEXT: </Metadata>
|
||||
@ -77,7 +77,7 @@ Error convertToYaml() {
|
||||
auto Prof = Reader.loadProfiles();
|
||||
if (!Prof)
|
||||
return Prof.takeError();
|
||||
llvm::convertCtxProfToYaml(Out, Prof->Contexts);
|
||||
llvm::convertCtxProfToYaml(Out, *Prof);
|
||||
Out << "\n";
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
@ -31,6 +31,9 @@ public:
|
||||
auto *Mem = Nodes.emplace_back(std::make_unique<char[]>(AllocSize)).get();
|
||||
std::memset(Mem, 0, AllocSize);
|
||||
auto *Ret = new (Mem) ContextNode(Guid, NumCounters, NumCallsites, Next);
|
||||
// set the entrycount to something - unless we're creating an invalid root.
|
||||
if (Ret->counters_size() > 0)
|
||||
Ret->counters()[0] = 42;
|
||||
return Ret;
|
||||
}
|
||||
|
||||
@ -98,8 +101,10 @@ TEST_F(PGOCtxProfRWTest, RoundTrip) {
|
||||
ASSERT_FALSE(EC);
|
||||
{
|
||||
PGOCtxProfileWriter Writer(Out);
|
||||
Writer.startContextSection();
|
||||
for (auto &[_, R] : roots())
|
||||
Writer.write(*R);
|
||||
Writer.writeContextual(*R);
|
||||
Writer.endContextSection();
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -149,7 +154,9 @@ TEST_F(PGOCtxProfRWTest, InvalidCounters) {
|
||||
ASSERT_FALSE(EC);
|
||||
{
|
||||
PGOCtxProfileWriter Writer(Out);
|
||||
Writer.write(*R);
|
||||
Writer.startContextSection();
|
||||
Writer.writeContextual(*R);
|
||||
Writer.endContextSection();
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -163,6 +170,60 @@ TEST_F(PGOCtxProfRWTest, InvalidCounters) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PGOCtxProfRWTest, CountersAllZero) {
|
||||
auto *R = createNode(1, 2, 1);
|
||||
R->counters()[0] = 0;
|
||||
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.startContextSection();
|
||||
Writer.writeContextual(*R);
|
||||
Writer.endContextSection();
|
||||
}
|
||||
}
|
||||
{
|
||||
auto MB = MemoryBuffer::getFile(ProfileFile.path());
|
||||
ASSERT_TRUE(!!MB);
|
||||
ASSERT_NE(*MB, nullptr);
|
||||
PGOCtxProfileReader Reader((*MB)->getBuffer());
|
||||
auto Expected = Reader.loadProfiles();
|
||||
EXPECT_TRUE(!!Expected);
|
||||
EXPECT_TRUE(Expected->Contexts.empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PGOCtxProfRWTest, CountersAllZeroWithOverride) {
|
||||
auto *R = createNode(42, 2, 1);
|
||||
R->counters()[0] = 0;
|
||||
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, /*VersionOverride=*/std::nullopt,
|
||||
/*IncludeEmpty=*/true);
|
||||
Writer.startContextSection();
|
||||
Writer.writeContextual(*R);
|
||||
Writer.endContextSection();
|
||||
}
|
||||
}
|
||||
{
|
||||
auto MB = MemoryBuffer::getFile(ProfileFile.path());
|
||||
ASSERT_TRUE(!!MB);
|
||||
ASSERT_NE(*MB, nullptr);
|
||||
PGOCtxProfileReader Reader((*MB)->getBuffer());
|
||||
auto Expected = Reader.loadProfiles();
|
||||
EXPECT_TRUE(!!Expected);
|
||||
EXPECT_EQ(Expected->Contexts.size(), 1U);
|
||||
EXPECT_EQ(Expected->Contexts.begin()->second.guid(), 42U);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PGOCtxProfRWTest, Empty) {
|
||||
PGOCtxProfileReader Reader("");
|
||||
auto Expected = Reader.loadProfiles();
|
||||
@ -229,9 +290,12 @@ TEST_F(PGOCtxProfRWTest, DuplicateRoots) {
|
||||
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));
|
||||
PGOCtxProfileWriter Writer(Out, /*VersionOverride=*/std::nullopt,
|
||||
/*IncludeEmpty=*/true);
|
||||
Writer.startContextSection();
|
||||
Writer.writeContextual(*createNode(1, 1, 1));
|
||||
Writer.writeContextual(*createNode(1, 1, 1));
|
||||
Writer.endContextSection();
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -257,7 +321,9 @@ TEST_F(PGOCtxProfRWTest, DuplicateTargets) {
|
||||
auto *L2 = createNode(2, 1, 0, L1);
|
||||
R->subContexts()[0] = L2;
|
||||
PGOCtxProfileWriter Writer(Out);
|
||||
Writer.write(*R);
|
||||
Writer.startContextSection();
|
||||
Writer.writeContextual(*R);
|
||||
Writer.endContextSection();
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
@ -507,6 +507,7 @@ define i32 @f4() !guid !3 {
|
||||
)IR");
|
||||
|
||||
const char *Profile = R"json(
|
||||
{ "Contexts":
|
||||
[
|
||||
{
|
||||
"Guid": 1000,
|
||||
@ -537,7 +538,7 @@ define i32 @f4() !guid !3 {
|
||||
},
|
||||
{ "Guid": 1003,
|
||||
"Counters": [103]
|
||||
}]]}]]}]
|
||||
}]]}]]}]}
|
||||
)json";
|
||||
|
||||
llvm::unittest::TempFile ProfileFile("ctx_profile", "", "", /*Unique=*/true);
|
||||
@ -572,33 +573,34 @@ define i32 @f4() !guid !3 {
|
||||
CtxProfAnalysisPrinterPass Printer(OS);
|
||||
Printer.run(*M, MAM);
|
||||
const char *Expected = R"yaml(
|
||||
- Guid: 1000
|
||||
Counters: [ 1, 11, 22 ]
|
||||
Callsites:
|
||||
- - Guid: 1001
|
||||
Counters: [ 10 ]
|
||||
- Guid: 1003
|
||||
Counters: [ 12 ]
|
||||
- - Guid: 1002
|
||||
Counters: [ 11 ]
|
||||
Callsites:
|
||||
- - Guid: 1004
|
||||
Counters: [ 13 ]
|
||||
- Guid: 1005
|
||||
Counters: [ 2 ]
|
||||
Callsites:
|
||||
- - Guid: 1000
|
||||
Counters: [ 1, 102, 204 ]
|
||||
Callsites:
|
||||
- - Guid: 1001
|
||||
Counters: [ 101 ]
|
||||
- Guid: 1003
|
||||
Counters: [ 103 ]
|
||||
- - Guid: 1002
|
||||
Counters: [ 102 ]
|
||||
Callsites:
|
||||
- - Guid: 1004
|
||||
Counters: [ 104 ]
|
||||
Contexts:
|
||||
- Guid: 1000
|
||||
Counters: [ 1, 11, 22 ]
|
||||
Callsites:
|
||||
- - Guid: 1001
|
||||
Counters: [ 10 ]
|
||||
- Guid: 1003
|
||||
Counters: [ 12 ]
|
||||
- - Guid: 1002
|
||||
Counters: [ 11 ]
|
||||
Callsites:
|
||||
- - Guid: 1004
|
||||
Counters: [ 13 ]
|
||||
- Guid: 1005
|
||||
Counters: [ 2 ]
|
||||
Callsites:
|
||||
- - Guid: 1000
|
||||
Counters: [ 1, 102, 204 ]
|
||||
Callsites:
|
||||
- - Guid: 1001
|
||||
Counters: [ 101 ]
|
||||
- Guid: 1003
|
||||
Counters: [ 103 ]
|
||||
- - Guid: 1002
|
||||
Counters: [ 102 ]
|
||||
Callsites:
|
||||
- - Guid: 1004
|
||||
Counters: [ 104 ]
|
||||
)yaml";
|
||||
EXPECT_EQ(Expected, Str);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user