Skip to content

Commit 7b6b6ed

Browse files
committed
[ctx_prof] Move the "from json" logic more centrally to reuse it from test.
1 parent bb27dd8 commit 7b6b6ed

File tree

3 files changed

+90
-75
lines changed

3 files changed

+90
-75
lines changed

llvm/include/llvm/ProfileData/PGOCtxProfWriter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,6 @@ class PGOCtxProfileWriter final {
8181
static constexpr StringRef ContainerMagic = "CTXP";
8282
};
8383

84+
Error createCtxProfFromJSON(StringRef Profile, raw_ostream &Out);
8485
} // namespace llvm
8586
#endif

llvm/lib/ProfileData/PGOCtxProfWriter.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
#include "llvm/ProfileData/PGOCtxProfWriter.h"
1414
#include "llvm/Bitstream/BitCodeEnums.h"
15+
#include "llvm/ProfileData/CtxInstrContextNode.h"
16+
#include "llvm/Support/JSON.h"
1517

1618
using namespace llvm;
1719
using namespace llvm::ctx_profile;
@@ -81,3 +83,83 @@ void PGOCtxProfileWriter::writeImpl(std::optional<uint32_t> CallerIndex,
8183
void PGOCtxProfileWriter::write(const ContextNode &RootNode) {
8284
writeImpl(std::nullopt, RootNode);
8385
}
86+
87+
namespace {
88+
// A structural representation of the JSON input.
89+
struct DeserializableCtx {
90+
ctx_profile::GUID Guid = 0;
91+
std::vector<uint64_t> Counters;
92+
std::vector<std::vector<DeserializableCtx>> Callsites;
93+
};
94+
95+
ctx_profile::ContextNode *
96+
createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
97+
const std::vector<DeserializableCtx> &DCList);
98+
99+
// Convert a DeserializableCtx into a ContextNode, potentially linking it to
100+
// its sibling (e.g. callee at same callsite) "Next".
101+
ctx_profile::ContextNode *
102+
createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
103+
const DeserializableCtx &DC,
104+
ctx_profile::ContextNode *Next = nullptr) {
105+
auto AllocSize = ctx_profile::ContextNode::getAllocSize(DC.Counters.size(),
106+
DC.Callsites.size());
107+
auto *Mem = Nodes.emplace_back(std::make_unique<char[]>(AllocSize)).get();
108+
std::memset(Mem, 0, AllocSize);
109+
auto *Ret = new (Mem) ctx_profile::ContextNode(DC.Guid, DC.Counters.size(),
110+
DC.Callsites.size(), Next);
111+
std::memcpy(Ret->counters(), DC.Counters.data(),
112+
sizeof(uint64_t) * DC.Counters.size());
113+
for (const auto &[I, DCList] : llvm::enumerate(DC.Callsites))
114+
Ret->subContexts()[I] = createNode(Nodes, DCList);
115+
return Ret;
116+
}
117+
118+
// Convert a list of DeserializableCtx into a linked list of ContextNodes.
119+
ctx_profile::ContextNode *
120+
createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
121+
const std::vector<DeserializableCtx> &DCList) {
122+
ctx_profile::ContextNode *List = nullptr;
123+
for (const auto &DC : DCList)
124+
List = createNode(Nodes, DC, List);
125+
return List;
126+
}
127+
} // namespace
128+
129+
namespace llvm {
130+
namespace json {
131+
bool fromJSON(const Value &E, DeserializableCtx &R, Path P) {
132+
json::ObjectMapper Mapper(E, P);
133+
return Mapper && Mapper.map("Guid", R.Guid) &&
134+
Mapper.map("Counters", R.Counters) &&
135+
Mapper.mapOptional("Callsites", R.Callsites);
136+
}
137+
} // namespace json
138+
} // namespace llvm
139+
140+
Error llvm::createCtxProfFromJSON(StringRef Profile, raw_ostream &Out) {
141+
auto P = json::parse(Profile);
142+
if (!P)
143+
return P.takeError();
144+
145+
json::Path::Root R("");
146+
std::vector<DeserializableCtx> DCList;
147+
if (!fromJSON(*P, DCList, R))
148+
return R.getError();
149+
// Nodes provides memory backing for the ContextualNodes.
150+
std::vector<std::unique_ptr<char[]>> Nodes;
151+
std::error_code EC;
152+
if (EC)
153+
return createStringError(EC, "failed to open output");
154+
PGOCtxProfileWriter Writer(Out);
155+
for (const auto &DC : DCList) {
156+
auto *TopList = createNode(Nodes, DC);
157+
if (!TopList)
158+
return createStringError(
159+
"Unexpected error converting internal structure to ctx profile");
160+
Writer.write(*TopList);
161+
}
162+
if (EC)
163+
return createStringError(EC, "failed to write output");
164+
return Error::success();
165+
}

llvm/tools/llvm-ctxprof-util/llvm-ctxprof-util.cpp

Lines changed: 7 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -46,90 +46,22 @@ static cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
4646
cl::desc("Output file"),
4747
cl::sub(FromJSON));
4848

49-
namespace {
50-
// A structural representation of the JSON input.
51-
struct DeserializableCtx {
52-
GlobalValue::GUID Guid = 0;
53-
std::vector<uint64_t> Counters;
54-
std::vector<std::vector<DeserializableCtx>> Callsites;
55-
};
56-
57-
ctx_profile::ContextNode *
58-
createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
59-
const std::vector<DeserializableCtx> &DCList);
60-
61-
// Convert a DeserializableCtx into a ContextNode, potentially linking it to
62-
// its sibling (e.g. callee at same callsite) "Next".
63-
ctx_profile::ContextNode *
64-
createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
65-
const DeserializableCtx &DC,
66-
ctx_profile::ContextNode *Next = nullptr) {
67-
auto AllocSize = ctx_profile::ContextNode::getAllocSize(DC.Counters.size(),
68-
DC.Callsites.size());
69-
auto *Mem = Nodes.emplace_back(std::make_unique<char[]>(AllocSize)).get();
70-
std::memset(Mem, 0, AllocSize);
71-
auto *Ret = new (Mem) ctx_profile::ContextNode(DC.Guid, DC.Counters.size(),
72-
DC.Callsites.size(), Next);
73-
std::memcpy(Ret->counters(), DC.Counters.data(),
74-
sizeof(uint64_t) * DC.Counters.size());
75-
for (const auto &[I, DCList] : llvm::enumerate(DC.Callsites))
76-
Ret->subContexts()[I] = createNode(Nodes, DCList);
77-
return Ret;
78-
}
79-
80-
// Convert a list of DeserializableCtx into a linked list of ContextNodes.
81-
ctx_profile::ContextNode *
82-
createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
83-
const std::vector<DeserializableCtx> &DCList) {
84-
ctx_profile::ContextNode *List = nullptr;
85-
for (const auto &DC : DCList)
86-
List = createNode(Nodes, DC, List);
87-
return List;
88-
}
89-
} // namespace
90-
91-
namespace llvm {
92-
namespace json {
93-
// Hook into the JSON deserialization.
94-
bool fromJSON(const Value &E, DeserializableCtx &R, Path P) {
95-
json::ObjectMapper Mapper(E, P);
96-
return Mapper && Mapper.map("Guid", R.Guid) &&
97-
Mapper.map("Counters", R.Counters) &&
98-
Mapper.mapOptional("Callsites", R.Callsites);
99-
}
100-
} // namespace json
101-
} // namespace llvm
102-
10349
// Save the bitstream profile from the JSON representation.
10450
Error convertFromJSON() {
10551
auto BufOrError = MemoryBuffer::getFileOrSTDIN(InputFilename);
10652
if (!BufOrError)
10753
return createFileError(InputFilename, BufOrError.getError());
108-
auto P = json::parse(BufOrError.get()->getBuffer());
109-
if (!P)
110-
return P.takeError();
11154

112-
std::vector<DeserializableCtx> DCList;
113-
json::Path::Root R("");
114-
if (!fromJSON(*P, DCList, R))
115-
return R.getError();
116-
// Nodes provides memory backing for the ContextualNodes.
117-
std::vector<std::unique_ptr<char[]>> Nodes;
11855
std::error_code EC;
119-
raw_fd_stream Out(OutputFilename, EC);
56+
// Using a fd_ostream instead of a fd_stream. The latter would be more
57+
// efficient as the bitstream writer supports incremental flush to it, but the
58+
// json scenario is for test, and file size scalability doesn't really concern
59+
// us.
60+
raw_fd_ostream Out(OutputFilename, EC);
12061
if (EC)
12162
return createStringError(EC, "failed to open output");
122-
PGOCtxProfileWriter Writer(Out);
123-
for (const auto &DC : DCList) {
124-
auto *TopList = createNode(Nodes, DC);
125-
if (!TopList)
126-
return createStringError(
127-
"Unexpected error converting internal structure to ctx profile");
128-
Writer.write(*TopList);
129-
}
130-
if (EC)
131-
return createStringError(EC, "failed to write output");
132-
return Error::success();
63+
64+
return llvm::createCtxProfFromJSON(BufOrError.get()->getBuffer(), Out);
13365
}
13466

13567
int main(int argc, const char **argv) {

0 commit comments

Comments
 (0)