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 };
335
339
340 void setUseMD5ProfileSymbolList() override { UseMD5ProfSymList = true; }
341
342 void setUseMD5IndexedTables() override { UseMD5IndexedTables = true; }
343
344 /// Select composite encoding for subsequent writes. Composite output
345 /// requires CompositeProfileVersion or newer when write() is called.
346 void setUseCompositeProfile(bool Enable) override {
348 }
349
351 verifySecLayout(SL);
352#ifndef NDEBUG
353 // Make sure resetSecLayout is called before any flag setting.
354 for (auto &Entry : SectionHdrLayout) {
355 assert(Entry.Flags == 0 &&
356 "resetSecLayout has to be called before any flag setting");
357 }
358#endif
359 SecLayout = SL;
361 }
362
363protected:
364 uint64_t markSectionStart(SecType Type, uint32_t LayoutIdx);
365 std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx,
366 uint64_t SectionStart);
367 template <class SecFlagType>
368 void addSectionFlag(SecType Type, SecFlagType Flag) {
369 for (auto &Entry : SectionHdrLayout) {
370 if (Entry.Type == Type)
371 addSecFlag(Entry, Flag);
372 }
373 }
374 void addContext(const SampleContext &Context) override;
375
376 // placeholder for subclasses to dispatch their own section writers.
377 virtual std::error_code writeCustomSection(SecType Type) = 0;
378 // Verify the SecLayout is supported by the format.
379 virtual void verifySecLayout(SectionLayout SL) = 0;
380
381 // specify the order to write sections.
382 virtual std::error_code writeSections(const SampleProfileMap &ProfileMap) = 0;
383
384 // Find the first unwritten entry in SectionHdrLayout matching Type, returning
385 // its layout index.
387
388 // Dispatch section writer for each section.
389 virtual std::error_code writeOneSection(SecType Type,
390 const SampleProfileMap &ProfileMap);
391
392 // Helper function to write name table.
393 std::error_code writeNameTable() override;
394 std::error_code writeContextIdx(const SampleContext &Context) override;
395 std::error_code writeCSNameIdx(const SampleContext &Context);
396 std::error_code writeCSNameTableSection();
397
398 std::error_code writeFuncMetadata(const SampleProfileMap &Profiles);
399 std::error_code writeFuncMetadata(const FunctionSamples &Profile);
400
401 // Functions to write various kinds of sections.
402 std::error_code writeNameTableSection(const SampleProfileMap &ProfileMap);
403 std::error_code
405 // Type selects SecFuncOffsetTable vs SecCompositeFuncOffsetTable for flags.
406 std::error_code writeFuncOffsetTable(SecType Type, bool IsNested);
407 std::error_code writeEytzingerFuncOffsetTable(SecType Type, bool IsNested);
408 std::error_code writeLegacyFuncOffsetTable(SecType Type);
409 std::error_code writeProfileSymbolListSection();
411 std::error_code writeMD5ProfileSymbolListSection();
412
414 // Specifiy the order of sections in section header table. Note
415 // the order of sections in SecHdrTable may be different that the
416 // order in SectionHdrLayout. sample Reader will follow the order
417 // in SectionHdrLayout to read each section.
420
421 // Save the start of SecLBRProfile so we can compute the offset to the
422 // start of SecLBRProfile for each Function's Profile and will keep it
423 // in FuncOffsetTable.
425
426private:
427 void allocSecHdrTable();
428 std::error_code writeSecHdrTable();
429 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
430 std::error_code compressAndOutput();
431
432 // We will swap the raw_ostream held by LocalBufStream and that
433 // held by OutputStream if we try to add a section which needs
434 // compression. After the swap, all the data written to output
435 // will be temporarily buffered into the underlying raw_string_ostream
436 // originally held by LocalBufStream. After the data writing for the
437 // section is completed, compress the data in the local buffer,
438 // swap the raw_ostream back and write the compressed data to the
439 // real output.
440 std::unique_ptr<raw_ostream> LocalBufStream;
441 // The location where the output stream starts.
442 uint64_t FileStart;
443 // The location in the output stream where the SecHdrTable should be
444 // written to.
445 uint64_t SecHdrTableOffset;
446 // The table contains SecHdrTableEntry entries in order of how they are
447 // populated in the writer. It may be different from the order in
448 // SectionHdrLayout which specifies the sequence in which sections will
449 // be read.
450 std::vector<SecHdrTableEntry> SecHdrTable;
451
452 // FuncOffsetTable maps function context to its profile offset in
453 // SecLBRProfile section. It is used to load function profile on demand.
455 // Whether to use MD5 to represent string.
456 bool UseMD5 = false;
457 // Whether to write the profile symbol list as 64-bit MD5 hashes in Eytzinger
458 // layout.
459 bool UseMD5ProfSymList = false;
460 // Whether to write MD5-based indexed NameTable and parallel FuncOffsetTable
461 // in Eytzinger layout.
462 bool UseMD5IndexedTables = false;
463 size_t NumNested = 0;
464 size_t NumFlat = 0;
465
466 /// CSNameTable maps function context to its offset in SecCSNameTable section.
467 /// The offset will be used everywhere where the context is referenced.
469
470 ProfileSymbolList *ProfSymList = nullptr;
471};
472
475public:
476 SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS);
477
478private:
479 std::error_code writeDefaultLayout(const SampleProfileMap &ProfileMap);
480 std::error_code writeCtxSplitLayout(const SampleProfileMap &ProfileMap);
481
482 std::error_code writeSections(const SampleProfileMap &ProfileMap) override;
483
484 /// Apply the selected profile representation to the section layout.
485 void configureCompositeProfile();
486
487 std::error_code writeCustomSection(SecType Type) override {
489 };
490
491 void verifySecLayout(SectionLayout SL) override {
492 assert((SL == DefaultLayout || SL == CtxSplitLayout) &&
493 "Unsupported layout");
494 }
495
496 /// Section types for profile storage and bookkeeping (used to switch between
497 /// composite and non-composite profiles).
498 SecType ProfSection = SecLBRProfile;
499 SecType FuncOffsetSection = SecFuncOffsetTable;
500};
501
502} // end namespace sampleprof
503} // end namespace llvm
504
505#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:853
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:845
static void addSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag)
Definition SampleProf.h:319
const std::array< SmallVector< SecHdrTableEntry, 8 >, NumOfLayout > ExtBinaryHdrLayoutTable
@ SecFlagPartial
SecFlagPartial means the profile is for common/shared code.
Definition SampleProf.h:254
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