Skip to content

Commit 8fa826a

Browse files
committed
[ctxprof] use yaml for serialization (for testing)
1 parent 7c165f7 commit 8fa826a

File tree

11 files changed

+174
-200
lines changed

11 files changed

+174
-200
lines changed

llvm/include/llvm/Analysis/CtxProfAnalysis.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class CtxProfAnalysis : public AnalysisInfoMixin<CtxProfAnalysis> {
140140
class CtxProfAnalysisPrinterPass
141141
: public PassInfoMixin<CtxProfAnalysisPrinterPass> {
142142
public:
143-
enum class PrintMode { Everything, JSON };
143+
enum class PrintMode { Everything, YAML };
144144
explicit CtxProfAnalysisPrinterPass(raw_ostream &OS);
145145

146146
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);

llvm/include/llvm/ProfileData/PGOCtxProfReader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,5 +183,7 @@ class PGOCtxProfileReader final {
183183

184184
Expected<std::map<GlobalValue::GUID, PGOCtxProfContext>> loadContexts();
185185
};
186+
187+
void convertToYaml(raw_ostream &OS, const PGOCtxProfContext::CallTargetMapTy &);
186188
} // namespace llvm
187189
#endif

llvm/include/llvm/ProfileData/PGOCtxProfWriter.h

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

84-
/// Representation of the context node suitable for yaml / json serialization /
85-
/// deserialization.
86-
struct SerializableCtxRepresentation {
87-
ctx_profile::GUID Guid = 0;
88-
std::vector<uint64_t> Counters;
89-
std::vector<std::vector<SerializableCtxRepresentation>> Callsites;
90-
};
91-
9284
Error createCtxProfFromYAML(StringRef Profile, raw_ostream &Out);
9385
} // namespace llvm
9486
#endif

llvm/lib/Analysis/CtxProfAnalysis.cpp

Lines changed: 6 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include "llvm/IR/PassManager.h"
2020
#include "llvm/ProfileData/PGOCtxProfReader.h"
2121
#include "llvm/Support/CommandLine.h"
22-
#include "llvm/Support/JSON.h"
2322
#include "llvm/Support/MemoryBuffer.h"
2423

2524
#define DEBUG_TYPE "ctx_prof"
@@ -31,49 +30,13 @@ cl::opt<std::string>
3130

3231
static cl::opt<CtxProfAnalysisPrinterPass::PrintMode> PrintLevel(
3332
"ctx-profile-printer-level",
34-
cl::init(CtxProfAnalysisPrinterPass::PrintMode::JSON), cl::Hidden,
33+
cl::init(CtxProfAnalysisPrinterPass::PrintMode::YAML), cl::Hidden,
3534
cl::values(clEnumValN(CtxProfAnalysisPrinterPass::PrintMode::Everything,
3635
"everything", "print everything - most verbose"),
37-
clEnumValN(CtxProfAnalysisPrinterPass::PrintMode::JSON, "json",
38-
"just the json representation of the profile")),
36+
clEnumValN(CtxProfAnalysisPrinterPass::PrintMode::YAML, "yaml",
37+
"just the yaml representation of the profile")),
3938
cl::desc("Verbosity level of the contextual profile printer pass."));
4039

41-
namespace llvm {
42-
namespace json {
43-
Value toJSON(const PGOCtxProfContext &P) {
44-
Object Ret;
45-
Ret["Guid"] = P.guid();
46-
Ret["Counters"] = Array(P.counters());
47-
if (P.callsites().empty())
48-
return Ret;
49-
auto AllCS =
50-
::llvm::map_range(P.callsites(), [](const auto &P) { return P.first; });
51-
auto MaxIt = ::llvm::max_element(AllCS);
52-
assert(MaxIt != AllCS.end() && "We should have a max value because the "
53-
"callsites collection is not empty.");
54-
Array CSites;
55-
// Iterate to, and including, the maximum index.
56-
for (auto I = 0U, Max = *MaxIt; I <= Max; ++I) {
57-
CSites.push_back(Array());
58-
Array &Targets = *CSites.back().getAsArray();
59-
if (P.hasCallsite(I))
60-
for (const auto &[_, Ctx] : P.callsite(I))
61-
Targets.push_back(toJSON(Ctx));
62-
}
63-
Ret["Callsites"] = std::move(CSites);
64-
65-
return Ret;
66-
}
67-
68-
Value toJSON(const PGOCtxProfContext::CallTargetMapTy &P) {
69-
Array Ret;
70-
for (const auto &[_, Ctx] : P)
71-
Ret.push_back(toJSON(Ctx));
72-
return Ret;
73-
}
74-
} // namespace json
75-
} // namespace llvm
76-
7740
const char *AssignGUIDPass::GUIDMetadataName = "guid";
7841

7942
PreservedAnalyses AssignGUIDPass::run(Module &M, ModuleAnalysisManager &MAM) {
@@ -214,15 +177,13 @@ PreservedAnalyses CtxProfAnalysisPrinterPass::run(Module &M,
214177
<< ". MaxCallsiteID: " << FuncInfo.NextCallsiteIndex << "\n";
215178
}
216179

217-
const auto JSONed = ::llvm::json::toJSON(C.profiles());
218-
219180
if (Mode == PrintMode::Everything)
220181
OS << "\nCurrent Profile:\n";
221-
OS << formatv("{0:2}", JSONed);
222-
if (Mode == PrintMode::JSON)
182+
convertToYaml(OS, C.profiles());
183+
OS << "\n";
184+
if (Mode == PrintMode::YAML)
223185
return PreservedAnalyses::all();
224186

225-
OS << "\n";
226187
OS << "\nFlat Profile:\n";
227188
auto Flat = C.flatten();
228189
for (const auto &[Guid, Counters] : Flat) {

llvm/lib/ProfileData/PGOCtxProfReader.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#include "llvm/ProfileData/InstrProf.h"
1818
#include "llvm/ProfileData/PGOCtxProfWriter.h"
1919
#include "llvm/Support/Error.h"
20+
#include "llvm/Support/ErrorHandling.h"
21+
#include "llvm/Support/YAMLTraits.h"
22+
#include <iterator>
23+
#include <utility>
2024

2125
using namespace llvm;
2226

@@ -176,3 +180,87 @@ PGOCtxProfileReader::loadContexts() {
176180
}
177181
return std::move(Ret);
178182
}
183+
184+
namespace {
185+
// We want to pass `const` values PGOCtxProfContext references to the yaml
186+
// converter, and the regular yaml mapping APIs are designed to handle both
187+
// serialization and deserialization, which prevents using const for
188+
// serialization. Using an intermediate datastructure is overkill, both
189+
// space-wise and design complexity-wise. Instead, we use the lower-level APIs.
190+
void toYaml(yaml::Output &Out, const PGOCtxProfContext &Ctx);
191+
192+
void toYaml(yaml::Output &Out,
193+
const PGOCtxProfContext::CallTargetMapTy &CallTargets) {
194+
Out.beginSequence();
195+
size_t Index = 0;
196+
void *SaveData = nullptr;
197+
for (const auto &[_, Ctx] : CallTargets) {
198+
Out.preflightElement(Index++, SaveData);
199+
toYaml(Out, Ctx);
200+
Out.postflightElement(nullptr);
201+
}
202+
Out.endSequence();
203+
}
204+
205+
void toYaml(yaml::Output &Out,
206+
const PGOCtxProfContext::CallsiteMapTy &Callsites) {
207+
auto AllCS =
208+
::llvm::map_range(Callsites, [](const auto &P) { return P.first; });
209+
auto MaxIt = ::llvm::max_element(AllCS);
210+
assert(MaxIt != AllCS.end() && "We should have a max value because the "
211+
"callsites collection is not empty.");
212+
void *SaveData = nullptr;
213+
Out.beginSequence();
214+
for (auto I = 0U; I <= *MaxIt; ++I) {
215+
Out.preflightElement(I, SaveData);
216+
auto It = Callsites.find(I);
217+
if (It == Callsites.end()) {
218+
// This will produce a `[ ]` sequence, which is what we want here.
219+
Out.beginFlowSequence();
220+
Out.endFlowSequence();
221+
} else {
222+
toYaml(Out, It->second);
223+
}
224+
Out.postflightElement(nullptr);
225+
}
226+
Out.endSequence();
227+
}
228+
229+
void toYaml(yaml::Output &Out, const PGOCtxProfContext &Ctx) {
230+
yaml::EmptyContext Empty;
231+
Out.beginMapping();
232+
void *SaveInfo = nullptr;
233+
bool UseDefault = false;
234+
{
235+
Out.preflightKey("Guid", /*Required=*/true, /*SameAsDefault=*/false,
236+
UseDefault, SaveInfo);
237+
auto Guid = Ctx.guid();
238+
yaml::yamlize(Out, Guid, true, Empty);
239+
Out.postflightKey(nullptr);
240+
}
241+
{
242+
Out.preflightKey("Counters", true, false, UseDefault, SaveInfo);
243+
Out.beginFlowSequence();
244+
for (size_t I = 0U, E = Ctx.counters().size(); I < E; ++I) {
245+
Out.preflightFlowElement(I, SaveInfo);
246+
uint64_t V = Ctx.counters()[I];
247+
yaml::yamlize(Out, V, true, Empty);
248+
Out.postflightFlowElement(SaveInfo);
249+
}
250+
Out.endFlowSequence();
251+
Out.postflightKey(nullptr);
252+
}
253+
if (!Ctx.callsites().empty()) {
254+
Out.preflightKey("Callsites", true, false, UseDefault, SaveInfo);
255+
toYaml(Out, Ctx.callsites());
256+
Out.postflightKey(nullptr);
257+
}
258+
Out.endMapping();
259+
}
260+
} // namespace
261+
262+
void llvm::convertToYaml(raw_ostream &OS,
263+
const PGOCtxProfContext::CallTargetMapTy &Profiles) {
264+
yaml::Output Out(OS);
265+
toYaml(Out, Profiles);
266+
}

llvm/lib/ProfileData/PGOCtxProfWriter.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "llvm/Bitstream/BitCodeEnums.h"
1515
#include "llvm/ProfileData/CtxInstrContextNode.h"
1616
#include "llvm/Support/Error.h"
17-
#include "llvm/Support/JSON.h"
1817
#include "llvm/Support/MemoryBuffer.h"
1918
#include "llvm/Support/YAMLTraits.h"
2019
#include "llvm/Support/raw_ostream.h"
@@ -89,6 +88,15 @@ void PGOCtxProfileWriter::write(const ContextNode &RootNode) {
8988
}
9089

9190
namespace {
91+
92+
/// Representation of the context node suitable for yaml serialization /
93+
/// deserialization.
94+
struct SerializableCtxRepresentation {
95+
ctx_profile::GUID Guid = 0;
96+
std::vector<uint64_t> Counters;
97+
std::vector<std::vector<SerializableCtxRepresentation>> Callsites;
98+
};
99+
92100
ctx_profile::ContextNode *
93101
createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
94102
const std::vector<SerializableCtxRepresentation> &DCList);

llvm/test/Analysis/CtxProfAnalysis/full-cycle.ll

Lines changed: 14 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -88,54 +88,20 @@ Function Info:
8888
10507721908651011566 : entrypoint. MaxCounterID: 1. MaxCallsiteID: 2
8989

9090
Current Profile:
91-
[
92-
{
93-
"Callsites": [
94-
[
95-
{
96-
"Callsites": [
97-
[
98-
{
99-
"Counters": [
100-
10,
101-
7
102-
],
103-
"Guid": 3087265239403591524
104-
}
105-
]
106-
],
107-
"Counters": [
108-
7
109-
],
110-
"Guid": 2072045998141807037
111-
}
112-
],
113-
[
114-
{
115-
"Callsites": [
116-
[
117-
{
118-
"Counters": [
119-
1,
120-
2
121-
],
122-
"Guid": 3087265239403591524
123-
}
124-
]
125-
],
126-
"Counters": [
127-
2
128-
],
129-
"Guid": 4197650231481825559
130-
}
131-
]
132-
],
133-
"Counters": [
134-
1
135-
],
136-
"Guid": 10507721908651011566
137-
}
138-
]
91+
92+
- Guid: 10507721908651011566
93+
Counters: [ 1 ]
94+
Callsites:
95+
- - Guid: 2072045998141807037
96+
Counters: [ 7 ]
97+
Callsites:
98+
- - Guid: 3087265239403591524
99+
Counters: [ 10, 7 ]
100+
- - Guid: 4197650231481825559
101+
Counters: [ 2 ]
102+
Callsites:
103+
- - Guid: 3087265239403591524
104+
Counters: [ 1, 2 ]
139105

140106
Flat Profile:
141107
2072045998141807037 : 7

llvm/test/Analysis/CtxProfAnalysis/inline.ll

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
; RUN: llvm-ctxprof-util fromYAML --input=%t/profile.yaml --output=%t/profile.ctxprofdata
44

55
; RUN: opt -passes='module-inline,print<ctx-prof-analysis>' -ctx-profile-printer-level=everything %t/module.ll -S \
6-
; RUN: -use-ctx-profile=%t/profile.ctxprofdata -ctx-profile-printer-level=json \
7-
; RUN: -o - 2> %t/profile-final.txt | FileCheck %s
8-
; RUN: %python %S/json_equals.py %t/profile-final.txt %t/expected.json
6+
; RUN: -use-ctx-profile=%t/profile.ctxprofdata -ctx-profile-printer-level=yaml \
7+
; RUN: -o - 2> %t/profile-final.yaml | FileCheck %s
8+
; RUN: diff %t/profile-final.yaml %t/expected.yaml
99

1010
; There are 2 calls to @a from @entrypoint. We only inline the one callsite
1111
; marked as alwaysinline, the rest are blocked (marked noinline). After the inline,
@@ -109,17 +109,16 @@ define i32 @b() !guid !2 {
109109
Callsites: -
110110
- Guid: 1002
111111
Counters: [500]
112-
;--- expected.json
113-
[
114-
{ "Guid": 1000,
115-
"Counters": [10, 2, 8, 100],
116-
"Callsites": [
117-
[],
118-
[ { "Guid": 1001,
119-
"Counters": [8, 500],
120-
"Callsites": [[{"Guid": 1002, "Counters": [500]}]]}
121-
],
122-
[{ "Guid": 1002, "Counters": [100]}]
123-
]
124-
}
125-
]
112+
;--- expected.yaml
113+
114+
- Guid: 1000
115+
Counters: [ 10, 2, 8, 100 ]
116+
Callsites:
117+
- [ ]
118+
- - Guid: 1001
119+
Counters: [ 8, 500 ]
120+
Callsites:
121+
- - Guid: 1002
122+
Counters: [ 500 ]
123+
- - Guid: 1002
124+
Counters: [ 100 ]

llvm/test/Analysis/CtxProfAnalysis/json_equals.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)