LLVM 24.0.0git
SampleProfWriter.h
Go to the documentation of this file.
1//===- SampleProfWriter.h - Write LLVM sample profile data ------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains definitions needed for writing sample profiles.
10//
11//===----------------------------------------------------------------------===//
12#ifndef LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
13#define LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
14
15#include "llvm/ADT/Eytzinger.h"
16#include "llvm/ADT/MapVector.h"
17#include "llvm/ADT/StringRef.h"
23#include <cstdint>
24#include <memory>
25#include <system_error>
26
27namespace llvm {
28namespace sampleprof {
29
32 // The layout splits profile with inlined functions from profile without
33 // inlined functions. When Thinlto is enabled, ThinLTO postlink phase only
34 // has to load profile with inlined functions and can skip the other part.
37};
38
39/// When writing a profile with size limit, user may want to use a different
40/// strategy to reduce function count other than dropping functions with fewest
41/// samples first. In this case a class implementing the same interfaces should
42/// be provided to SampleProfileWriter::writeWithSizeLimit().
44protected:
47
48public:
49 /// \p ProfileMap A reference to the original profile map. It will be modified
50 /// by Erase().
51 /// \p OutputSizeLimit Size limit in bytes of the output profile. This is
52 /// necessary to estimate how many functions to remove.
55
56 virtual ~FunctionPruningStrategy() = default;
57
58 /// SampleProfileWriter::writeWithSizeLimit() calls this after every write
59 /// iteration if the output size still exceeds the limit. This function
60 /// should erase some functions from the profile map so that the writer tries
61 /// to write the profile again with fewer functions. At least 1 entry from the
62 /// profile map must be erased.
63 ///
64 /// \p CurrentOutputSize Number of bytes in the output if current profile map
65 /// is written.
66 virtual void Erase(size_t CurrentOutputSize) = 0;
67};
68
70 std::vector<NameFunctionSamples> SortedFunctions;
71
72public:
74 size_t OutputSizeLimit);
75
76 /// In this default implementation, functions with fewest samples are dropped
77 /// first. Since the exact size of the output cannot be easily calculated due
78 /// to compression, we use a heuristic to remove as many functions as
79 /// necessary but not too many, aiming to minimize the number of write
80 /// iterations.
81 /// Empirically, functions with larger total sample count contain linearly
82 /// more sample entries, meaning it takes linearly more space to write them.
83 /// The cumulative length is therefore quadratic if all functions are sorted
84 /// by total sample count.
85 /// TODO: Find better heuristic.
86 void Erase(size_t CurrentOutputSize) override;
87};
88
89/// Sample-based profile writer. Base class.
91public:
92 virtual ~SampleProfileWriter() = default;
93
94 /// Write sample profiles in \p S.
95 ///
96 /// \returns status code of the file update operation.
97 virtual std::error_code writeSample(const FunctionSamples &S) = 0;
98
99 /// Write all the sample profiles in the given map of samples.
100 ///
101 /// \returns status code of the file update operation.
102 virtual std::error_code write(const SampleProfileMap &ProfileMap);
103
104 /// Write sample profiles up to given size limit, using the pruning strategy
105 /// to drop some functions if necessary.
106 ///
107 /// \returns status code of the file update operation.
108 template <typename FunctionPruningStrategy = DefaultFunctionPruningStrategy>
109 std::error_code writeWithSizeLimit(SampleProfileMap &ProfileMap,
110 size_t OutputSizeLimit) {
111 FunctionPruningStrategy Strategy(ProfileMap, OutputSizeLimit);
112 return writeWithSizeLimitInternal(ProfileMap, OutputSizeLimit, &Strategy);
113 }
114
116
117 /// Profile writer factory.
118 ///
119 /// Create a new file writer based on the value of \p Format.
122
123 /// Create a new stream writer based on the value of \p Format.
124 /// For testing.
126 create(std::unique_ptr<raw_ostream> &OS, SampleProfileFormat Format);
127
129 virtual void setToCompressAllSections() {}
130 virtual void setUseMD5() {}
131 virtual void setPartialProfile() {}
132 virtual void setUseCtxSplitLayout() {}
133
136 "Unsupported format version");
137 FormatVersion = V;
138 }
140
141protected:
142 SampleProfileWriter(std::unique_ptr<raw_ostream> &OS)
143 : OutputStream(std::move(OS)) {}
144
145 /// Write a file header for the profile file.
146 virtual std::error_code writeHeader(const SampleProfileMap &ProfileMap) = 0;
147
148 // Write function profiles to the profile file.
149 virtual std::error_code writeFuncProfiles(const SampleProfileMap &ProfileMap);
150
151 std::error_code writeWithSizeLimitInternal(SampleProfileMap &ProfileMap,
152 size_t OutputSizeLimit,
153 FunctionPruningStrategy *Strategy);
154
155 /// For writeWithSizeLimit in text mode, each newline takes 1 additional byte
156 /// on Windows when actually written to the file, but not written to a memory
157 /// buffer. This needs to be accounted for when rewriting the profile.
158 size_t LineCount;
159
160 /// Output stream where to emit the profile to.
161 std::unique_ptr<raw_ostream> OutputStream;
162
163 /// Profile summary.
164 std::unique_ptr<ProfileSummary> Summary;
165
166 /// Compute summary for this profile.
167 void computeSummary(const SampleProfileMap &ProfileMap);
168
169 /// Profile format.
171
172 /// Format version to write.
174};
175
176/// Sample-based profile writer (text format).
178public:
179 std::error_code writeSample(const FunctionSamples &S) override;
180
181protected:
182 SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS)
183 : SampleProfileWriter(OS) {}
184
185 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override {
186 LineCount = 0;
188 }
189
190 void setUseCtxSplitLayout() override { MarkFlatProfiles = true; }
191
192private:
193 /// Indent level to use when writing.
194 ///
195 /// This is used when printing inlined callees.
196 unsigned Indent = 0;
197
198 /// If set, writes metadata "!Flat" to functions without inlined functions.
199 /// This flag is for manual inspection only, it has no effect for the profile
200 /// reader because a text sample profile is read sequentially and functions
201 /// cannot be skipped.
202 bool MarkFlatProfiles = false;
203
205 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
207};
208
209/// Sample-based profile writer (binary format).
211public:
212 SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
213 : SampleProfileWriter(OS) {}
214
215 std::error_code writeSample(const FunctionSamples &S) override;
216
217protected:
219 virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
220 virtual std::error_code writeNameTable();
221 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
222 std::error_code writeSummary();
223 virtual std::error_code writeContextIdx(const SampleContext &Context);
224 std::error_code writeNameIdx(FunctionId FName);
225 std::error_code writeBody(const FunctionSamples &S);
226
228
229 void addName(FunctionId FName);
230 virtual void addContext(const SampleContext &Context);
231 void addNames(const FunctionSamples &S);
232
233 /// Write \p CallsiteTypeMap to the output stream \p OS.
234 std::error_code
236 raw_ostream &OS);
237
238 bool WriteVTableProf = false;
239
240private:
242 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
244};
245
246class SampleProfileWriterRawBinary : public SampleProfileWriterBinary {
248};
249
250const std::array<SmallVector<SecHdrTableEntry, 8>, NumOfLayout>
252 // Note that SecFuncOffsetTable section is written after SecLBRProfile
253 // in the profile, but is put before SecLBRProfile in SectionHdrLayout.
254 // This is because sample reader follows the order in SectionHdrLayout
255 // to read each section. To read function profiles on demand, sample
256 // reader need to get the offset of each function profile first.
257 //
258 // DefaultLayout
260 {SecNameTable, 0, 0, 0, 0},
261 {SecCSNameTable, 0, 0, 0, 0},
262 {SecFuncOffsetTable, 0, 0, 0, 0},
263 {SecLBRProfile, 0, 0, 0, 0},
264 {SecProfileSymbolList, 0, 0, 0, 0},
265 {SecFuncMetadata, 0, 0, 0, 0}}),
266 // CtxSplitLayout
268 {{SecProfSummary, 0, 0, 0, 0},
269 {SecNameTable, 0, 0, 0, 0},
270 // profile with inlined functions
271 // for next two sections
272 {SecFuncOffsetTable, 0, 0, 0, 0},
273 {SecLBRProfile, 0, 0, 0, 0},
274 // profile without inlined functions
275 // for next two sections
277 static_cast<uint64_t>(SecCommonFlags::SecFlagFlat), 0, 0, 0},
279 0, 0, 0},
280 {SecProfileSymbolList, 0, 0, 0, 0},
281 {SecFuncMetadata, 0, 0, 0, 0}}),
282};
283
285 : public SampleProfileWriterBinary {
287
288public:
289 std::error_code write(const SampleProfileMap &ProfileMap) override;
290
291 void setToCompressAllSections() override;
293 std::error_code writeSample(const FunctionSamples &S) override;
294
295 // Set to use MD5 to represent string in NameTable.
296 void setUseMD5() override {
297 UseMD5 = true;
299 // MD5 will be stored as plain uint64_t instead of variable-length
300 // quantity format in NameTable section.
302 }
303
304 // Set the profile to be partial. It means the profile is for
305 // common/shared code. The common profile is usually merged from
306 // profiles collected from running other targets.
310
312 ProfSymList = PSL;
313 };
314
318
320 verifySecLayout(SL);
321#ifndef NDEBUG
322 // Make sure resetSecLayout is called before any flag setting.
323 for (auto &Entry : SectionHdrLayout) {
324 assert(Entry.Flags == 0 &&
325 "resetSecLayout has to be called before any flag setting");
326 }
327#endif
328 SecLayout = SL;
330 }
331
332protected:
333 uint64_t markSectionStart(SecType Type, uint32_t LayoutIdx);
334 std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx,
335 uint64_t SectionStart);
336 template <class SecFlagType>
337 void addSectionFlag(SecType Type, SecFlagType Flag) {
338 for (auto &Entry : SectionHdrLayout) {
339 if (Entry.Type == Type)
340 addSecFlag(Entry, Flag);
341 }
342 }
343 void addContext(const SampleContext &Context) override;
344
345 // placeholder for subclasses to dispatch their own section writers.
346 virtual std::error_code writeCustomSection(SecType Type) = 0;
347 // Verify the SecLayout is supported by the format.
348 virtual void verifySecLayout(SectionLayout SL) = 0;
349
350 // specify the order to write sections.
351 virtual std::error_code writeSections(const SampleProfileMap &ProfileMap) = 0;
352
353 // Find the first unwritten entry in SectionHdrLayout matching Type, returning
354 // its layout index.
356
357 // Dispatch section writer for each section.
358 virtual std::error_code writeOneSection(SecType Type,
359 const SampleProfileMap &ProfileMap);
360
361 // Helper function to write name table.
362 std::error_code writeNameTable() override;
363 std::error_code writeContextIdx(const SampleContext &Context) override;
364 std::error_code writeCSNameIdx(const SampleContext &Context);
365 std::error_code writeCSNameTableSection();
366
367 std::error_code writeFuncMetadata(const SampleProfileMap &Profiles);
368 std::error_code writeFuncMetadata(const FunctionSamples &Profile);
369
370 // Functions to write various kinds of sections.
371 std::error_code writeNameTableSection(const SampleProfileMap &ProfileMap);
372 std::error_code
374 std::error_code writeFuncOffsetTable(bool IsNested);
375 std::error_code writeEytzingerFuncOffsetTable(bool IsNested);
376 std::error_code writeLegacyFuncOffsetTable();
377 std::error_code writeProfileSymbolListSection();
379 std::error_code writeMD5ProfileSymbolListSection();
380
382 // Specifiy the order of sections in section header table. Note
383 // the order of sections in SecHdrTable may be different that the
384 // order in SectionHdrLayout. sample Reader will follow the order
385 // in SectionHdrLayout to read each section.
388
389 // Save the start of SecLBRProfile so we can compute the offset to the
390 // start of SecLBRProfile for each Function's Profile and will keep it
391 // in FuncOffsetTable.
393
394private:
395 void allocSecHdrTable();
396 std::error_code writeSecHdrTable();
397 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
398 std::error_code compressAndOutput();
399
400 // We will swap the raw_ostream held by LocalBufStream and that
401 // held by OutputStream if we try to add a section which needs
402 // compression. After the swap, all the data written to output
403 // will be temporarily buffered into the underlying raw_string_ostream
404 // originally held by LocalBufStream. After the data writing for the
405 // section is completed, compress the data in the local buffer,
406 // swap the raw_ostream back and write the compressed data to the
407 // real output.
408 std::unique_ptr<raw_ostream> LocalBufStream;
409 // The location where the output stream starts.
410 uint64_t FileStart;
411 // The location in the output stream where the SecHdrTable should be
412 // written to.
413 uint64_t SecHdrTableOffset;
414 // The table contains SecHdrTableEntry entries in order of how they are
415 // populated in the writer. It may be different from the order in
416 // SectionHdrLayout which specifies the sequence in which sections will
417 // be read.
418 std::vector<SecHdrTableEntry> SecHdrTable;
419
420 // FuncOffsetTable maps function context to its profile offset in
421 // SecLBRProfile section. It is used to load function profile on demand.
423 // Whether to use MD5 to represent string.
424 bool UseMD5 = false;
425 size_t NumNested = 0;
426 size_t NumFlat = 0;
427
428 /// CSNameTable maps function context to its offset in SecCSNameTable section.
429 /// The offset will be used everywhere where the context is referenced.
431
432 ProfileSymbolList *ProfSymList = nullptr;
433};
434
437public:
438 SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS);
439
440private:
441 std::error_code writeDefaultLayout(const SampleProfileMap &ProfileMap);
442 std::error_code writeCtxSplitLayout(const SampleProfileMap &ProfileMap);
443
444 std::error_code writeSections(const SampleProfileMap &ProfileMap) override;
445
446 std::error_code writeCustomSection(SecType Type) override {
448 };
449
450 void verifySecLayout(SectionLayout SL) override {
451 assert((SL == DefaultLayout || SL == CtxSplitLayout) &&
452 "Unsupported layout");
453 }
454};
455
456} // end namespace sampleprof
457} // end namespace llvm
458
459#endif // LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_ABI
Definition Compiler.h:215
Provides ErrorOr<T> smart pointer.
This file defines the EytzingerTableSpan class, a non-owning view of a buffer formatted as a complete...
Load MIR Sample Profile
This file implements a map that provides insertion order iteration.
static constexpr StringLiteral Filename
static void write(bool isBE, void *P, T V)
Represents either an error or a value T.
Definition ErrorOr.h:56
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
DefaultFunctionPruningStrategy(SampleProfileMap &ProfileMap, size_t OutputSizeLimit)
void Erase(size_t CurrentOutputSize) override
In this default implementation, functions with fewest samples are dropped first.
This class represents a function that is read from a sample profile.
Definition FunctionId.h:36
When writing a profile with size limit, user may want to use a different strategy to reduce function ...
virtual void Erase(size_t CurrentOutputSize)=0
SampleProfileWriter::writeWithSizeLimit() calls this after every write iteration if the output size s...
FunctionPruningStrategy(SampleProfileMap &ProfileMap, size_t OutputSizeLimit)
ProfileMap A reference to the original profile map.
Representation of the samples collected for a function.
Definition SampleProf.h:821
ProfileSymbolList records the list of function symbols shown up in the binary used to generate the pr...
This class provides operator overloads to the map container using MD5 as the key type,...
SampleProfileWriterBinary(std::unique_ptr< raw_ostream > &OS)
virtual void addContext(const SampleContext &Context)
MapVector< FunctionId, uint32_t > NameTable
std::error_code writeCallsiteVTableProf(const CallsiteTypeMap &CallsiteTypeMap, raw_ostream &OS)
Write CallsiteTypeMap to the output stream OS.
virtual MapVector< FunctionId, uint32_t > & getNameTable()
std::error_code writeNameTableSection(const SampleProfileMap &ProfileMap)
SmallVector< SecHdrTableEntry, 8 > SectionHdrLayout
std::error_code writeFuncMetadata(const SampleProfileMap &Profiles)
virtual std::error_code writeCustomSection(SecType Type)=0
virtual std::error_code writeOneSection(SecType Type, const SampleProfileMap &ProfileMap)
std::error_code writeCSNameIdx(const SampleContext &Context)
virtual void verifySecLayout(SectionLayout SL)=0
void setProfileSymbolList(ProfileSymbolList *PSL) override
virtual std::error_code writeSections(const SampleProfileMap &ProfileMap)=0
void addSectionFlag(SecType Type, SecFlagType Flag)
std::error_code writeEytzingerFuncOffsetTable(bool IsNested)
std::error_code writeEytzingerNameTableSection(const SampleProfileMap &ProfileMap)
std::error_code writeContextIdx(const SampleContext &Context) override
std::error_code writeSample(const FunctionSamples &S) override
Write samples of a top-level function to a binary file.
SampleProfileWriterExtBinary(std::unique_ptr< raw_ostream > &OS)
SampleProfileWriterText(std::unique_ptr< raw_ostream > &OS)
std::error_code writeHeader(const SampleProfileMap &ProfileMap) override
Write a file header for the profile file.
std::error_code writeSample(const FunctionSamples &S) override
Write samples to a text file.
SampleProfileWriter(std::unique_ptr< raw_ostream > &OS)
std::unique_ptr< ProfileSummary > Summary
Profile summary.
virtual std::error_code writeSample(const FunctionSamples &S)=0
Write sample profiles in S.
SampleProfileFormat Format
Profile format.
std::error_code writeWithSizeLimitInternal(SampleProfileMap &ProfileMap, size_t OutputSizeLimit, FunctionPruningStrategy *Strategy)
void computeSummary(const SampleProfileMap &ProfileMap)
Compute summary for this profile.
virtual std::error_code writeFuncProfiles(const SampleProfileMap &ProfileMap)
std::unique_ptr< raw_ostream > OutputStream
Output stream where to emit the profile to.
std::error_code writeWithSizeLimit(SampleProfileMap &ProfileMap, size_t OutputSizeLimit)
Write sample profiles up to given size limit, using the pruning strategy to drop some functions if ne...
virtual void setProfileSymbolList(ProfileSymbolList *PSL)
uint64_t FormatVersion
Format version to write.
size_t LineCount
For writeWithSizeLimit in text mode, each newline takes 1 additional byte on Windows when actually wr...
static ErrorOr< std::unique_ptr< SampleProfileWriter > > create(StringRef Filename, SampleProfileFormat Format)
Profile writer factory.
virtual std::error_code writeHeader(const SampleProfileMap &ProfileMap)=0
Write a file header for the profile file.
static bool formatVersionIsSupported(uint64_t Version)
Definition SampleProf.h:132
static void addSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag)
Definition SampleProf.h:292
const std::array< SmallVector< SecHdrTableEntry, 8 >, NumOfLayout > ExtBinaryHdrLayoutTable
@ SecFlagPartial
SecFlagPartial means the profile is for common/shared code.
Definition SampleProf.h:228
static constexpr uint64_t DefaultVersion
Definition SampleProf.h:126
std::map< LineLocation, TypeCountMap > CallsiteTypeMap
Definition SampleProf.h:813
This is an optimization pass for GlobalISel generic memory operations.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1917
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878