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"
18#include "llvm/ADT/StringRef.h"
24#include <cstdint>
25#include <memory>
26#include <system_error>
27
28namespace llvm {
29namespace sampleprof {
30
33 // The layout splits profile with inlined functions from profile without
34 // inlined functions. When Thinlto is enabled, ThinLTO postlink phase only
35 // has to load profile with inlined functions and can skip the other part.
38};
39
40/// When writing a profile with size limit, user may want to use a different
41/// strategy to reduce function count other than dropping functions with fewest
42/// samples first. In this case a class implementing the same interfaces should
43/// be provided to SampleProfileWriter::writeWithSizeLimit().
45protected:
48
49public:
50 /// \p ProfileMap A reference to the original profile map. It will be modified
51 /// by Erase().
52 /// \p OutputSizeLimit Size limit in bytes of the output profile. This is
53 /// necessary to estimate how many functions to remove.
56
57 virtual ~FunctionPruningStrategy() = default;
58
59 /// SampleProfileWriter::writeWithSizeLimit() calls this after every write
60 /// iteration if the output size still exceeds the limit. This function
61 /// should erase some functions from the profile map so that the writer tries
62 /// to write the profile again with fewer functions. At least 1 entry from the
63 /// profile map must be erased.
64 ///
65 /// \p CurrentOutputSize Number of bytes in the output if current profile map
66 /// is written.
67 virtual void Erase(size_t CurrentOutputSize) = 0;
68};
69
71 std::vector<NameFunctionSamples> SortedFunctions;
72
73public:
75 size_t OutputSizeLimit);
76
77 /// In this default implementation, functions with fewest samples are dropped
78 /// first. Since the exact size of the output cannot be easily calculated due
79 /// to compression, we use a heuristic to remove as many functions as
80 /// necessary but not too many, aiming to minimize the number of write
81 /// iterations.
82 /// Empirically, functions with larger total sample count contain linearly
83 /// more sample entries, meaning it takes linearly more space to write them.
84 /// The cumulative length is therefore quadratic if all functions are sorted
85 /// by total sample count.
86 /// TODO: Find better heuristic.
87 void Erase(size_t CurrentOutputSize) override;
88};
89
90/// Sample-based profile writer. Base class.
92public:
93 virtual ~SampleProfileWriter() = default;
94
95 /// Write sample profiles in \p S.
96 ///
97 /// \returns status code of the file update operation.
98 virtual std::error_code writeSample(const FunctionSamples &S) = 0;
99
100 /// Write all the sample profiles in the given map of samples.
101 ///
102 /// \returns status code of the file update operation.
103 virtual std::error_code write(const SampleProfileMap &ProfileMap);
104
105 /// Write sample profiles up to given size limit, using the pruning strategy
106 /// to drop some functions if necessary.
107 ///
108 /// \returns status code of the file update operation.
109 template <typename FunctionPruningStrategy = DefaultFunctionPruningStrategy>
110 std::error_code writeWithSizeLimit(SampleProfileMap &ProfileMap,
111 size_t OutputSizeLimit) {
112 FunctionPruningStrategy Strategy(ProfileMap, OutputSizeLimit);
113 return writeWithSizeLimitInternal(ProfileMap, OutputSizeLimit, &Strategy);
114 }
115
117
118 /// Profile writer factory.
119 ///
120 /// Create a new file writer based on the value of \p Format.
123
124 /// Create a new stream writer based on the value of \p Format.
125 /// For testing.
127 create(std::unique_ptr<raw_ostream> &OS, SampleProfileFormat Format);
128
130 virtual void setToCompressAllSections() {}
131 virtual void setUseMD5() {}
132 virtual void setPartialProfile() {}
133 virtual void setUseCtxSplitLayout() {}
135 virtual void setUseMD5IndexedTables() {}
136 virtual void setUseCompositeProfile(bool /*Enable*/) {}
137
140 "Unsupported format version");
141 FormatVersion = V;
142 }
144
145protected:
146 SampleProfileWriter(std::unique_ptr<raw_ostream> &OS)
147 : OutputStream(std::move(OS)) {}
148
149 /// Write a file header for the profile file.
150 virtual std::error_code writeHeader(const SampleProfileMap &ProfileMap) = 0;
151
152 // Write function profiles to the profile file.
153 virtual std::error_code writeFuncProfiles(const SampleProfileMap &ProfileMap);
154
155 std::error_code writeWithSizeLimitInternal(SampleProfileMap &ProfileMap,
156 size_t OutputSizeLimit,
157 FunctionPruningStrategy *Strategy);
158
159 /// For writeWithSizeLimit in text mode, each newline takes 1 additional byte
160 /// on Windows when actually written to the file, but not written to a memory
161 /// buffer. This needs to be accounted for when rewriting the profile.
162 size_t LineCount;
163
164 /// Output stream where to emit the profile to.
165 std::unique_ptr<raw_ostream> OutputStream;
166
167 /// Profile summary.
168 std::unique_ptr<ProfileSummary> Summary;
169
170 /// Compute summary for this profile.
171 void computeSummary(const SampleProfileMap &ProfileMap);
172
173 /// Profile format.
175
176 /// Format version to write.
178};
179
180/// Sample-based profile writer (text format).
182public:
183 std::error_code writeSample(const FunctionSamples &S) override;
184
185protected:
186 SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS)
187 : SampleProfileWriter(OS) {}
188
189 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override {
190 LineCount = 0;
192 }
193
194 void setUseCtxSplitLayout() override { MarkFlatProfiles = true; }
195
196private:
197 /// Indent level to use when writing.
198 ///
199 /// This is used when printing inlined callees.
200 unsigned Indent = 0;
201
202 /// If set, writes metadata "!Flat" to functions without inlined functions.
203 /// This flag is for manual inspection only, it has no effect for the profile
204 /// reader because a text sample profile is read sequentially and functions
205 /// cannot be skipped.
206 bool MarkFlatProfiles = false;
207
209 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
211};
212
213/// Sample-based profile writer (binary format).
215public:
216 SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
217 : SampleProfileWriter(OS) {}
218
219 std::error_code writeSample(const FunctionSamples &S) override;
220
221protected:
223 virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
224 virtual std::error_code writeNameTable();
225 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
226 std::error_code writeSummary();
227 virtual std::error_code writeContextIdx(const SampleContext &Context);
228 std::error_code writeNameIdx(FunctionId FName);
229 std::error_code writeBody(const FunctionSamples &S, bool IsNested);
230 std::error_code writeLBRProfile(const FunctionSamples &S, bool IsNested);
231
232 /// Interfaces for composite profile writing.
233 std::error_code writeCompositeProfile(const FunctionSamples &S,
234 bool IsNested);
235 /// Write one \p Type and the size-prefixed payload emitted by \p
236 /// WritePayload. The callback is invoked once to count its bytes and again to
237 /// emit them, so both calls must produce identical output without external
238 /// side effects.
239 std::error_code
240 writeProfileType(ProfTypes Type,
241 function_ref<std::error_code()> WritePayload);
242 /// Reusable stream that counts payload bytes without retaining them.
243 std::unique_ptr<raw_ostream> PayloadSizeStream;
244 /// Whether a profile payload callback is currently being executed.
245 bool WritingProfileType = false;
246
248
249 void addName(FunctionId FName);
250 virtual void addContext(const SampleContext &Context);
251 void addNames(const FunctionSamples &S);
252
253 /// Write \p CallsiteTypeMap to the output stream \p OS.
254 std::error_code
256 raw_ostream &OS);
257
258 bool WriteVTableProf = false;
259 bool WriteCompositeProf = false;
260
261private:
263 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
265};
266
267class SampleProfileWriterRawBinary : public SampleProfileWriterBinary {
269};
270
271const std::array<SmallVector<SecHdrTableEntry, 8>, NumOfLayout>
273 // Note that SecFuncOffsetTable section is written after SecLBRProfile
274 // in the profile, but is put before SecLBRProfile in SectionHdrLayout.
275 // This is because sample reader follows the order in SectionHdrLayout
276 // to read each section. To read function profiles on demand, sample
277 // reader need to get the offset of each function profile first.
278 //
279 // DefaultLayout
281 {SecNameTable, 0, 0, 0, 0},
282 {SecCSNameTable, 0, 0, 0, 0},
283 {SecFuncOffsetTable, 0, 0, 0, 0},
284 {SecLBRProfile, 0, 0, 0, 0},
285 {SecProfileSymbolList, 0, 0, 0, 0},
286 {SecFuncMetadata, 0, 0, 0, 0}}),
287 // CtxSplitLayout
289 {{SecProfSummary, 0, 0, 0, 0},
290 {SecNameTable, 0, 0, 0, 0},
291 // profile with inlined functions
292 // for next two sections
293 {SecFuncOffsetTable, 0, 0, 0, 0},
294 {SecLBRProfile, 0, 0, 0, 0},
295 // profile without inlined functions
296 // for next two sections
298 static_cast<uint64_t>(SecCommonFlags::SecFlagFlat), 0, 0, 0},
300 0, 0, 0},
301 {SecProfileSymbolList, 0, 0, 0, 0},
302 {SecFuncMetadata, 0, 0, 0, 0}}),
303};
304
306 : public SampleProfileWriterBinary {
308
309public:
310 std::error_code write(const SampleProfileMap &ProfileMap) override;
311
312 void setToCompressAllSections() override;
314 std::error_code writeSample(const FunctionSamples &S) override;
315
316 // Set to use MD5 to represent string in NameTable.
317 void setUseMD5() override {
318 UseMD5 = true;
320 // MD5 will be stored as plain uint64_t instead of variable-length
321 // quantity format in NameTable section.
323 }
324
325 // Set the profile to be partial. It means the profile is for
326 // common/shared code. The common profile is usually merged from
327 // profiles collected from running other targets.
331
333 ProfSymList = PSL;
334 if (ProfSymList && ProfSymList->isMD5())
336 }
337
341
342 void setUseMD5ProfileSymbolList() override { UseMD5ProfSymList = true; }
343
344 void setUseMD5IndexedTables() override { UseMD5IndexedTables = true; }
345
346 /// Select composite encoding for subsequent writes. Composite output
347 /// requires CompositeProfileVersion or newer when write() is called.
348 void setUseCompositeProfile(bool Enable) override {
350 }
351
353 verifySecLayout(SL);
354#ifndef NDEBUG
355 // Make sure resetSecLayout is called before any flag setting.
356 for (auto &Entry : SectionHdrLayout) {
357 assert(Entry.Flags == 0 &&
358 "resetSecLayout has to be called before any flag setting");
359 }
360#endif
361 SecLayout = SL;
363 }
364
365protected:
366 uint64_t markSectionStart(SecType Type, uint32_t LayoutIdx);
367 std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx,
368 uint64_t SectionStart);
369 template <class SecFlagType>
370 void addSectionFlag(SecType Type, SecFlagType Flag) {
371 for (auto &Entry : SectionHdrLayout) {
372 if (Entry.Type == Type)
373 addSecFlag(Entry, Flag);
374 }
375 }
376 void addContext(const SampleContext &Context) override;
377
378 // placeholder for subclasses to dispatch their own section writers.
379 virtual std::error_code writeCustomSection(SecType Type) = 0;
380 // Verify the SecLayout is supported by the format.
381 virtual void verifySecLayout(SectionLayout SL) = 0;
382
383 // specify the order to write sections.
384 virtual std::error_code writeSections(const SampleProfileMap &ProfileMap) = 0;
385
386 // Find the first unwritten entry in SectionHdrLayout matching Type, returning
387 // its layout index.
389
390 // Dispatch section writer for each section.
391 virtual std::error_code writeOneSection(SecType Type,
392 const SampleProfileMap &ProfileMap);
393
394 // Helper function to write name table.
395 std::error_code writeNameTable() override;
396 std::error_code writeContextIdx(const SampleContext &Context) override;
397 std::error_code writeCSNameIdx(const SampleContext &Context);
398 std::error_code writeCSNameTableSection();
399
400 std::error_code writeFuncMetadata(const SampleProfileMap &Profiles);
401 std::error_code writeFuncMetadata(const FunctionSamples &Profile);
402
403 // Functions to write various kinds of sections.
404 std::error_code writeNameTableSection(const SampleProfileMap &ProfileMap);
405 std::error_code
407 // Type selects SecFuncOffsetTable vs SecCompositeFuncOffsetTable for flags.
408 std::error_code writeFuncOffsetTable(SecType Type, bool IsNested);
409 std::error_code writeEytzingerFuncOffsetTable(SecType Type, bool IsNested);
410 std::error_code writeLegacyFuncOffsetTable(SecType Type);
411 std::error_code writeProfileSymbolListSection();
413 std::error_code writeMD5ProfileSymbolListSection();
414
416 // Specifiy the order of sections in section header table. Note
417 // the order of sections in SecHdrTable may be different that the
418 // order in SectionHdrLayout. sample Reader will follow the order
419 // in SectionHdrLayout to read each section.
422
423 // Save the start of SecLBRProfile so we can compute the offset to the
424 // start of SecLBRProfile for each Function's Profile and will keep it
425 // in FuncOffsetTable.
427
428private:
429 void allocSecHdrTable();
430 std::error_code writeSecHdrTable();
431 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
432 std::error_code compressAndOutput();
433
434 // We will swap the raw_ostream held by LocalBufStream and that
435 // held by OutputStream if we try to add a section which needs
436 // compression. After the swap, all the data written to output
437 // will be temporarily buffered into the underlying raw_string_ostream
438 // originally held by LocalBufStream. After the data writing for the
439 // section is completed, compress the data in the local buffer,
440 // swap the raw_ostream back and write the compressed data to the
441 // real output.
442 std::unique_ptr<raw_ostream> LocalBufStream;
443 // The location where the output stream starts.
444 uint64_t FileStart;
445 // The location in the output stream where the SecHdrTable should be
446 // written to.
447 uint64_t SecHdrTableOffset;
448 // The table contains SecHdrTableEntry entries in order of how they are
449 // populated in the writer. It may be different from the order in
450 // SectionHdrLayout which specifies the sequence in which sections will
451 // be read.
452 std::vector<SecHdrTableEntry> SecHdrTable;
453
454 // FuncOffsetTable maps function context to its profile offset in
455 // SecLBRProfile section. It is used to load function profile on demand.
457 // Whether to use MD5 to represent string.
458 bool UseMD5 = false;
459 // Whether to write the profile symbol list as 64-bit MD5 hashes in Eytzinger
460 // layout.
461 bool UseMD5ProfSymList = false;
462 // Whether to write MD5-based indexed NameTable and parallel FuncOffsetTable
463 // in Eytzinger layout.
464 bool UseMD5IndexedTables = false;
465 size_t NumNested = 0;
466 size_t NumFlat = 0;
467
468 /// CSNameTable maps function context to its offset in SecCSNameTable section.
469 /// The offset will be used everywhere where the context is referenced.
471
472 ProfileSymbolList *ProfSymList = nullptr;
473};
474
477public:
478 SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS);
479
480private:
481 std::error_code writeDefaultLayout(const SampleProfileMap &ProfileMap);
482 std::error_code writeCtxSplitLayout(const SampleProfileMap &ProfileMap);
483
484 std::error_code writeSections(const SampleProfileMap &ProfileMap) override;
485
486 /// Apply the selected profile representation to the section layout.
487 void configureCompositeProfile();
488
489 std::error_code writeCustomSection(SecType Type) override {
491 };
492
493 void verifySecLayout(SectionLayout SL) override {
494 assert((SL == DefaultLayout || SL == CtxSplitLayout) &&
495 "Unsupported layout");
496 }
497
498 /// Section types for profile storage and bookkeeping (used to switch between
499 /// composite and non-composite profiles).
500 SecType ProfSection = SecLBRProfile;
501 SecType FuncOffsetSection = SecFuncOffsetTable;
502};
503
504} // end namespace sampleprof
505} // end namespace llvm
506
507#endif // LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
#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
An efficient, type-erasing, non-owning reference to a callable.
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:854
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)
bool WritingProfileType
Whether a profile payload callback is currently being executed.
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.
std::unique_ptr< raw_ostream > PayloadSizeStream
Reusable stream that counts payload bytes without retaining them.
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
std::error_code writeEytzingerFuncOffsetTable(SecType Type, bool IsNested)
void setProfileSymbolList(ProfileSymbolList *PSL) override
virtual std::error_code writeSections(const SampleProfileMap &ProfileMap)=0
std::error_code writeFuncOffsetTable(SecType Type, bool IsNested)
void addSectionFlag(SecType Type, SecFlagType Flag)
std::error_code writeEytzingerNameTableSection(const SampleProfileMap &ProfileMap)
void setUseCompositeProfile(bool Enable) override
Select composite encoding for subsequent writes.
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:136
SortedVectorMap< LineLocation, TypeCountMap, 0 > CallsiteTypeMap
Definition SampleProf.h:846
static void addSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag)
Definition SampleProf.h:320
const std::array< SmallVector< SecHdrTableEntry, 8 >, NumOfLayout > ExtBinaryHdrLayoutTable
@ SecFlagPartial
SecFlagPartial means the profile is for common/shared code.
Definition SampleProf.h:255
static constexpr uint64_t DefaultVersion
Definition SampleProf.h:127
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:1933
@ Enable
Enable colors.
Definition WithColor.h:47
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878