LLVM 22.0.0git
MemProfYAML.h
Go to the documentation of this file.
1#ifndef LLVM_PROFILEDATA_MEMPROFYAML_H_
2#define LLVM_PROFILEDATA_MEMPROFYAML_H_
3
9
10namespace llvm {
11namespace memprof {
12// A "typedef" for GUID. See ScalarTraits<memprof::GUIDHex64> for how a GUID is
13// serialized and deserialized in YAML.
15
16// Helper struct for AllMemProfData. In YAML, we treat the GUID and the fields
17// within MemProfRecord at the same level as if the GUID were part of
18// MemProfRecord.
20 GUIDHex64 GUID;
22};
23
24// Helper struct to yamlify memprof::DataAccessProfData. The struct
25// members use owned strings. This is for simplicity and assumes that most real
26// world use cases do look-ups and regression test scale is small.
28 std::vector<memprof::DataAccessProfRecord> Records;
29 std::vector<uint64_t> KnownColdStrHashes;
30 std::vector<std::string> KnownColdSymbols;
31
32 bool isEmpty() const {
33 return Records.empty() && KnownColdStrHashes.empty() &&
34 KnownColdSymbols.empty();
35 }
36};
37
38// The top-level data structure, only used with YAML for now.
40 std::vector<GUIDMemProfRecordPair> HeapProfileRecords;
42};
43} // namespace memprof
44
45namespace yaml {
46template <> struct ScalarTraits<memprof::GUIDHex64> {
47 static void output(const memprof::GUIDHex64 &Val, void *, raw_ostream &Out) {
48 // Print GUID as a hexadecimal number with 0x prefix, no padding to keep
49 // test strings compact.
50 Out << format("0x%" PRIx64, (uint64_t)Val);
51 }
52 static StringRef input(StringRef Scalar, void *, memprof::GUIDHex64 &Val) {
53 // Reject decimal GUIDs.
54 if (all_of(Scalar, [](char C) { return std::isdigit(C); }))
55 return "use a hexadecimal GUID or a function instead";
56
57 uint64_t Num;
58 if (Scalar.starts_with_insensitive("0x")) {
59 // Accept hexadecimal numbers starting with 0x or 0X.
60 if (Scalar.getAsInteger(0, Num))
61 return "invalid hex64 number";
62 Val = Num;
63 } else {
64 // Otherwise, treat the input as a string containing a function name.
65 Val = memprof::getGUID(Scalar);
66 }
67 return StringRef();
68 }
69 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
70};
71
72template <> struct MappingTraits<memprof::Frame> {
73 // Essentially the same as memprof::Frame except that Function is of type
74 // memprof::GUIDHex64 instead of GlobalValue::GUID. This class helps in two
75 // ways. During serialization, we print Function as a 16-digit hexadecimal
76 // number. During deserialization, we accept a function name as an
77 // alternative to the usual GUID expressed as a hexadecimal number.
78 class FrameWithHex64 {
79 public:
82 : Function(F.Function), LineOffset(F.LineOffset), Column(F.Column),
83 IsInlineFrame(F.IsInlineFrame) {}
85 return memprof::Frame(Function, LineOffset, Column, IsInlineFrame);
86 }
87
88 memprof::GUIDHex64 Function = 0;
89 static_assert(std::is_same_v<decltype(Function.value),
90 decltype(memprof::Frame::Function)>);
91 decltype(memprof::Frame::LineOffset) LineOffset = 0;
92 decltype(memprof::Frame::Column) Column = 0;
93 decltype(memprof::Frame::IsInlineFrame) IsInlineFrame = false;
94 };
95
96 static void mapping(IO &Io, memprof::Frame &F) {
97 MappingNormalization<FrameWithHex64, memprof::Frame> Keys(Io, F);
98
99 Io.mapRequired("Function", Keys->Function);
100 Io.mapRequired("LineOffset", Keys->LineOffset);
101 Io.mapRequired("Column", Keys->Column);
102 Io.mapRequired("IsInlineFrame", Keys->IsInlineFrame);
103
104 // Assert that the definition of Frame matches what we expect. The
105 // structured bindings below detect changes to the number of fields.
106 // static_assert checks the type of each field.
107 const auto &[Function, SymbolName, LineOffset, Column, IsInlineFrame] = F;
108 static_assert(
109 std::is_same_v<remove_cvref_t<decltype(Function)>, GlobalValue::GUID>);
110 static_assert(std::is_same_v<remove_cvref_t<decltype(SymbolName)>,
111 std::unique_ptr<std::string>>);
112 static_assert(
113 std::is_same_v<remove_cvref_t<decltype(LineOffset)>, uint32_t>);
114 static_assert(std::is_same_v<remove_cvref_t<decltype(Column)>, uint32_t>);
115 static_assert(
116 std::is_same_v<remove_cvref_t<decltype(IsInlineFrame)>, bool>);
117
118 // MSVC issues unused variable warnings despite the uses in static_assert
119 // above.
120 (void)Function;
121 (void)SymbolName;
122 (void)LineOffset;
123 (void)Column;
124 (void)IsInlineFrame;
125 }
126
127 // Request the inline notation for brevity:
128 // { Function: 123, LineOffset: 11, Column: 10; IsInlineFrame: true }
129 static const bool flow = true;
130};
131
132template <> struct CustomMappingTraits<memprof::PortableMemInfoBlock> {
133 static void inputOne(IO &Io, StringRef KeyStr,
135 // PortableMemInfoBlock keeps track of the set of fields that actually have
136 // values. We update the set here as we receive a key-value pair from the
137 // YAML document.
138 //
139 // We set MIB.Name via a temporary variable because ScalarTraits<uintptr_t>
140 // isn't available on macOS.
141#define MIBEntryDef(NameTag, Name, Type) \
142 if (KeyStr == #Name) { \
143 uint64_t Value; \
144 Io.mapRequired(KeyStr.str().c_str(), Value); \
145 MIB.Name = static_cast<Type>(Value); \
146 MIB.Schema.set(llvm::to_underlying(memprof::Meta::Name)); \
147 return; \
148 }
150#undef MIBEntryDef
151 Io.setError("Key is not a valid validation event");
152 }
153
154 static void output(IO &Io, memprof::PortableMemInfoBlock &MIB) {
155 auto Schema = MIB.getSchema();
156#define MIBEntryDef(NameTag, Name, Type) \
157 if (Schema.test(llvm::to_underlying(memprof::Meta::Name))) { \
158 uint64_t Value = MIB.Name; \
159 Io.mapRequired(#Name, Value); \
160 }
162#undef MIBEntryDef
163 }
164};
165
166template <> struct MappingTraits<memprof::AllocationInfo> {
167 static void mapping(IO &Io, memprof::AllocationInfo &AI) {
168 Io.mapRequired("Callstack", AI.CallStack);
169 Io.mapRequired("MemInfoBlock", AI.Info);
170 }
171};
172
173// In YAML, we use GUIDMemProfRecordPair instead of MemProfRecord so that we can
174// treat the GUID and the fields within MemProfRecord at the same level as if
175// the GUID were part of MemProfRecord.
176template <> struct MappingTraits<memprof::CallSiteInfo> {
177 // Helper class to normalize CalleeGuids to use GUIDHex64 for YAML I/O.
178 class CallSiteInfoWithHex64Guids {
179 public:
182 : Frames(CS.Frames) {
183 // Convert uint64_t GUIDs to GUIDHex64 for serialization.
184 CalleeGuids.reserve(CS.CalleeGuids.size());
185 for (uint64_t Guid : CS.CalleeGuids)
186 CalleeGuids.push_back(memprof::GUIDHex64(Guid));
187 }
188
191 CS.Frames = Frames;
192 // Convert GUIDHex64 back to uint64_t GUIDs after deserialization.
193 CS.CalleeGuids.reserve(CalleeGuids.size());
194 for (memprof::GUIDHex64 HexGuid : CalleeGuids)
195 CS.CalleeGuids.push_back(HexGuid.value);
196 return CS;
197 }
198
199 // Keep Frames as is, since MappingTraits<memprof::Frame> handles its
200 // Function GUID.
201 decltype(memprof::CallSiteInfo::Frames) Frames;
202 // Use a vector of GUIDHex64 for CalleeGuids to leverage its ScalarTraits.
204 };
205
206 static void mapping(IO &Io, memprof::CallSiteInfo &CS) {
207 // Use MappingNormalization to handle the conversion between
208 // memprof::CallSiteInfo and CallSiteInfoWithHex64Guids.
209 MappingNormalization<CallSiteInfoWithHex64Guids, memprof::CallSiteInfo>
210 Keys(Io, CS);
211 Io.mapRequired("Frames", Keys->Frames);
212 // Map the normalized CalleeGuids (which are now GUIDHex64).
213 Io.mapOptional("CalleeGuids", Keys->CalleeGuids);
214 }
215};
216
217template <> struct MappingTraits<memprof::GUIDMemProfRecordPair> {
218 static void mapping(IO &Io, memprof::GUIDMemProfRecordPair &Pair) {
219 Io.mapRequired("GUID", Pair.GUID);
220 Io.mapRequired("AllocSites", Pair.Record.AllocSites);
221 Io.mapRequired("CallSites", Pair.Record.CallSites);
222 }
223};
224
225template <> struct MappingTraits<memprof::SourceLocation> {
226 static void mapping(IO &Io, memprof::SourceLocation &Loc) {
227 Io.mapOptional("FileName", Loc.FileName);
228 Io.mapOptional("Line", Loc.Line);
229 }
230};
231
232template <> struct MappingTraits<memprof::DataAccessProfRecord> {
233 static void mapping(IO &Io, memprof::DataAccessProfRecord &Rec) {
234 if (Io.outputting()) {
235 if (std::holds_alternative<std::string>(Rec.SymHandle)) {
236 Io.mapOptional("Symbol", std::get<std::string>(Rec.SymHandle));
237 } else {
238 Io.mapOptional("Hash", std::get<uint64_t>(Rec.SymHandle));
239 }
240 } else {
241 std::string SymName;
242 uint64_t Hash = 0;
243 Io.mapOptional("Symbol", SymName);
244 Io.mapOptional("Hash", Hash);
245 if (!SymName.empty()) {
246 Rec.SymHandle = SymName;
247 } else {
248 Rec.SymHandle = Hash;
249 }
250 }
251 Io.mapRequired("AccessCount", Rec.AccessCount);
252 Io.mapOptional("Locations", Rec.Locations);
253 }
254};
255
256template <> struct MappingTraits<memprof::YamlDataAccessProfData> {
258 Io.mapOptional("SampledRecords", Data.Records);
259 Io.mapOptional("KnownColdSymbols", Data.KnownColdSymbols);
260 Io.mapOptional("KnownColdStrHashes", Data.KnownColdStrHashes);
261 }
262};
263
264template <> struct MappingTraits<memprof::AllMemProfData> {
265 static void mapping(IO &Io, memprof::AllMemProfData &Data) {
266 if (!Io.outputting() || !Data.HeapProfileRecords.empty())
267 Io.mapOptional("HeapProfileRecords", Data.HeapProfileRecords);
268 // Map data access profiles if reading input, or if writing output &&
269 // the struct is populated.
270 if (!Io.outputting() || !Data.YamlifiedDataAccessProfiles.isEmpty())
271 Io.mapOptional("DataAccessProfiles", Data.YamlifiedDataAccessProfiles);
272 }
273};
274
275template <> struct SequenceTraits<SmallVector<memprof::GUIDHex64>> {
276 static size_t size(IO &io, SmallVector<memprof::GUIDHex64> &Seq) {
277 return Seq.size();
278 }
279 static memprof::GUIDHex64 &
281 if (Index >= Seq.size())
282 Seq.resize(Index + 1);
283 return Seq[Index];
284 }
285 static const bool flow = true;
286};
287
288} // namespace yaml
289} // namespace llvm
290
291LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::Frame)
292LLVM_YAML_IS_SEQUENCE_VECTOR(std::vector<memprof::Frame>)
293LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::AllocationInfo)
294LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::CallSiteInfo)
295LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::GUIDMemProfRecordPair)
296LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::GUIDHex64) // Used for CalleeGuids
297LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::DataAccessProfRecord)
298LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::SourceLocation)
299
300#endif // LLVM_PROFILEDATA_MEMPROFYAML_H_
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
uint32_t Index
#define F(x, y, z)
Definition: MD5.cpp:55
This file defines the SmallVector class.
#define LLVM_YAML_IS_SEQUENCE_VECTOR(type)
#define LLVM_YAML_STRONG_TYPEDEF(_base, _type)
size_t size() const
Definition: SmallVector.h:79
void resize(size_type N)
Definition: SmallVector.h:639
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1744
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:126
YamlDataAccessProfData YamlifiedDataAccessProfiles
Definition: MemProfYAML.h:41
std::vector< GUIDMemProfRecordPair > HeapProfileRecords
Definition: MemProfYAML.h:40
std::vector< Frame > CallStack
Definition: MemProf.h:417
PortableMemInfoBlock Info
Definition: MemProf.h:419
std::vector< Frame > Frames
Definition: MemProf.h:495
SmallVector< GlobalValue::GUID, 1 > CalleeGuids
Definition: MemProf.h:498
The data access profiles for a symbol.
SmallVector< SourceLocation > Locations
llvm::SmallVector< CallSiteInfo > CallSites
Definition: MemProf.h:522
llvm::SmallVector< AllocationInfo > AllocSites
Definition: MemProf.h:520
std::bitset< llvm::to_underlying(Meta::Size)> getSchema() const
Definition: MemProf.h:163
The location of data in the source code. Used by profile lookup API.
uint32_t Line
The line number in the source code.
std::string FileName
The filename where the data is located.
std::vector< memprof::DataAccessProfRecord > Records
Definition: MemProfYAML.h:28
std::vector< uint64_t > KnownColdStrHashes
Definition: MemProfYAML.h:29
std::vector< std::string > KnownColdSymbols
Definition: MemProfYAML.h:30
Serializable representation of CallSiteInfo.
static void inputOne(IO &Io, StringRef KeyStr, memprof::PortableMemInfoBlock &MIB)
Definition: MemProfYAML.h:133
static void output(IO &Io, memprof::PortableMemInfoBlock &MIB)
Definition: MemProfYAML.h:154
static void mapping(IO &Io, memprof::AllMemProfData &Data)
Definition: MemProfYAML.h:265
static void mapping(IO &Io, memprof::AllocationInfo &AI)
Definition: MemProfYAML.h:167
static void mapping(IO &Io, memprof::CallSiteInfo &CS)
Definition: MemProfYAML.h:206
static void mapping(IO &Io, memprof::DataAccessProfRecord &Rec)
Definition: MemProfYAML.h:233
static void mapping(IO &Io, memprof::Frame &F)
Definition: MemProfYAML.h:96
static void mapping(IO &Io, memprof::GUIDMemProfRecordPair &Pair)
Definition: MemProfYAML.h:218
static void mapping(IO &Io, memprof::SourceLocation &Loc)
Definition: MemProfYAML.h:226
static void mapping(IO &Io, memprof::YamlDataAccessProfData &Data)
Definition: MemProfYAML.h:257
static QuotingType mustQuote(StringRef)
Definition: MemProfYAML.h:69
static StringRef input(StringRef Scalar, void *, memprof::GUIDHex64 &Val)
Definition: MemProfYAML.h:52
static void output(const memprof::GUIDHex64 &Val, void *, raw_ostream &Out)
Definition: MemProfYAML.h:47
static size_t size(IO &io, SmallVector< memprof::GUIDHex64 > &Seq)
Definition: MemProfYAML.h:276
static memprof::GUIDHex64 & element(IO &io, SmallVector< memprof::GUIDHex64 > &Seq, size_t Index)
Definition: MemProfYAML.h:280