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"
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() {}
134
137 "Unsupported format version");
138 FormatVersion = V;
139 }
141
142protected:
143 SampleProfileWriter(std::unique_ptr<raw_ostream> &OS)
144 : OutputStream(std::move(OS)) {}
145
146 /// Write a file header for the profile file.
147 virtual std::error_code writeHeader(const SampleProfileMap &ProfileMap) = 0;
148
149 // Write function profiles to the profile file.
150 virtual std::error_code writeFuncProfiles(const SampleProfileMap &ProfileMap);
151
152 std::error_code writeWithSizeLimitInternal(SampleProfileMap &ProfileMap,
153 size_t OutputSizeLimit,
154 FunctionPruningStrategy *Strategy);
155
156 /// For writeWithSizeLimit in text mode, each newline takes 1 additional byte
157 /// on Windows when actually written to the file, but not written to a memory
158 /// buffer. This needs to be accounted for when rewriting the profile.
159 size_t LineCount;
160
161 /// Output stream where to emit the profile to.
162 std::unique_ptr<raw_ostream> OutputStream;
163
164 /// Profile summary.
165 std::unique_ptr<ProfileSummary> Summary;
166
167 /// Compute summary for this profile.
168 void computeSummary(const SampleProfileMap &ProfileMap);
169
170 /// Profile format.
172
173 /// Format version to write.
175};
176
177/// Sample-based profile writer (text format).
179public:
180 std::error_code writeSample(const FunctionSamples &S) override;
181
182protected:
183 SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS)
184 : SampleProfileWriter(OS) {}
185
186 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override {
187 LineCount = 0;
189 }
190
191 void setUseCtxSplitLayout() override { MarkFlatProfiles = true; }
192
193private:
194 /// Indent level to use when writing.
195 ///
196 /// This is used when printing inlined callees.
197 unsigned Indent = 0;
198
199 /// If set, writes metadata "!Flat" to functions without inlined functions.
200 /// This flag is for manual inspection only, it has no effect for the profile
201 /// reader because a text sample profile is read sequentially and functions
202 /// cannot be skipped.
203 bool MarkFlatProfiles = false;
204
206 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
208};
209
210/// Sample-based profile writer (binary format).
212public:
213 SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
214 : SampleProfileWriter(OS) {}
215
216 std::error_code writeSample(const FunctionSamples &S) override;
217
218protected:
220 virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
221 virtual std::error_code writeNameTable();
222 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
223 std::error_code writeSummary();
224 virtual std::error_code writeContextIdx(const SampleContext &Context);
225 std::error_code writeNameIdx(FunctionId FName);
226 std::error_code writeBody(const FunctionSamples &S);
227
229
230 void addName(FunctionId FName);
231 virtual void addContext(const SampleContext &Context);
232 void addNames(const FunctionSamples &S);
233
234 /// Write \p CallsiteTypeMap to the output stream \p OS.
235 std::error_code
237 raw_ostream &OS);
238
239 bool WriteVTableProf = false;
240
241private:
243 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
245};
246
247class SampleProfileWriterRawBinary : public SampleProfileWriterBinary {
249};
250
251const std::array<SmallVector<SecHdrTableEntry, 8>, NumOfLayout>
253 // Note that SecFuncOffsetTable section is written after SecLBRProfile
254 // in the profile, but is put before SecLBRProfile in SectionHdrLayout.
255 // This is because sample reader follows the order in SectionHdrLayout
256 // to read each section. To read function profiles on demand, sample
257 // reader need to get the offset of each function profile first.
258 //
259 // DefaultLayout
261 {SecNameTable, 0, 0, 0, 0},
262 {SecCSNameTable, 0, 0, 0, 0},
263 {SecFuncOffsetTable, 0, 0, 0, 0},
264 {SecLBRProfile, 0, 0, 0, 0},
265 {SecProfileSymbolList, 0, 0, 0, 0},
266 {SecFuncMetadata, 0, 0, 0, 0}}),
267 // CtxSplitLayout
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
276 {SecFuncOffsetTable, 0, 0, 0, 0},
277 {SecLBRProfile, 0, 0, 0, 0},
278 {SecProfileSymbolList, 0, 0, 0, 0},
279 {SecFuncMetadata, 0, 0, 0, 0}}),
280};
281
282/// Trait class for writing the on-disk function offset hash table mapping
283/// function name GUIDs to their offsets in the SecLBRProfile section.
285public:
288 using data_type = uint32_t; // Offset
294
296 return static_cast<hash_value_type>(Key);
297 }
298
300 return LHS == RHS;
301 }
302
305
306 static std::pair<offset_type, offset_type>
308 // Implicit lengths: do NOT write anything to Out.
309 return {sizeof(key_type), sizeof(data_type)};
310 }
311
312 static void EmitKey(raw_ostream &Out, key_type_ref K, offset_type Len) {
313 using namespace llvm::support;
315 assert(Len == sizeof(key_type) && "Key length mismatch");
316 LE.write<uint64_t>(K);
317 }
318
320 offset_type Len) {
321 using namespace llvm::support;
323 assert(Len == sizeof(data_type) && "Data length mismatch");
324 LE.write<uint32_t>(V);
325 }
326};
327
329 : public SampleProfileWriterBinary {
331
332public:
333 std::error_code write(const SampleProfileMap &ProfileMap) override;
334
335 void setToCompressAllSections() override;
337 std::error_code writeSample(const FunctionSamples &S) override;
338
339 // Set to use MD5 to represent string in NameTable.
340 void setUseMD5() override {
341 UseMD5 = true;
343 // MD5 will be stored as plain uint64_t instead of variable-length
344 // quantity format in NameTable section.
346 }
347
348 // Set the profile to be partial. It means the profile is for
349 // common/shared code. The common profile is usually merged from
350 // profiles collected from running other targets.
354
356 ProfSymList = PSL;
357 };
358
362
364 verifySecLayout(SL);
365#ifndef NDEBUG
366 // Make sure resetSecLayout is called before any flag setting.
367 for (auto &Entry : SectionHdrLayout) {
368 assert(Entry.Flags == 0 &&
369 "resetSecLayout has to be called before any flag setting");
370 }
371#endif
372 SecLayout = SL;
374 }
375
376protected:
377 uint64_t markSectionStart(SecType Type, uint32_t LayoutIdx);
378 std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx,
379 uint64_t SectionStart);
380 template <class SecFlagType>
381 void addSectionFlag(SecType Type, SecFlagType Flag) {
382 for (auto &Entry : SectionHdrLayout) {
383 if (Entry.Type == Type)
384 addSecFlag(Entry, Flag);
385 }
386 }
387 template <class SecFlagType>
388 void addSectionFlag(uint32_t SectionIdx, SecFlagType Flag) {
389 addSecFlag(SectionHdrLayout[SectionIdx], Flag);
390 }
391
392 void addContext(const SampleContext &Context) override;
393
394 // placeholder for subclasses to dispatch their own section writers.
395 virtual std::error_code writeCustomSection(SecType Type) = 0;
396 // Verify the SecLayout is supported by the format.
397 virtual void verifySecLayout(SectionLayout SL) = 0;
398
399 // specify the order to write sections.
400 virtual std::error_code writeSections(const SampleProfileMap &ProfileMap) = 0;
401
402 // Dispatch section writer for each section. \p LayoutIdx is the sequence
403 // number indicating where the section is located in SectionHdrLayout.
404 virtual std::error_code writeOneSection(SecType Type, uint32_t LayoutIdx,
405 const SampleProfileMap &ProfileMap);
406
407 // Helper function to write name table.
408 std::error_code writeNameTable() override;
409 std::error_code writeContextIdx(const SampleContext &Context) override;
410 std::error_code writeCSNameIdx(const SampleContext &Context);
411 std::error_code writeCSNameTableSection();
412
413 std::error_code writeFuncMetadata(const SampleProfileMap &Profiles);
414 std::error_code writeFuncMetadata(const FunctionSamples &Profile);
415
416 // Functions to write various kinds of sections.
417 std::error_code writeNameTableSection(const SampleProfileMap &ProfileMap);
418 std::error_code writeFuncOffsetTable();
419 std::error_code writeProfileSymbolListSection();
421 std::error_code writeMD5ProfileSymbolListSection();
422
424 // Specifiy the order of sections in section header table. Note
425 // the order of sections in SecHdrTable may be different that the
426 // order in SectionHdrLayout. sample Reader will follow the order
427 // in SectionHdrLayout to read each section.
430
431 // Save the start of SecLBRProfile so we can compute the offset to the
432 // start of SecLBRProfile for each Function's Profile and will keep it
433 // in FuncOffsetTable.
435
436private:
437 void allocSecHdrTable();
438 std::error_code writeSecHdrTable();
439 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
440 std::error_code compressAndOutput();
441
442 // We will swap the raw_ostream held by LocalBufStream and that
443 // held by OutputStream if we try to add a section which needs
444 // compression. After the swap, all the data written to output
445 // will be temporarily buffered into the underlying raw_string_ostream
446 // originally held by LocalBufStream. After the data writing for the
447 // section is completed, compress the data in the local buffer,
448 // swap the raw_ostream back and write the compressed data to the
449 // real output.
450 std::unique_ptr<raw_ostream> LocalBufStream;
451 // The location where the output stream starts.
452 uint64_t FileStart;
453 // The location in the output stream where the SecHdrTable should be
454 // written to.
455 uint64_t SecHdrTableOffset;
456 // The table contains SecHdrTableEntry entries in order of how they are
457 // populated in the writer. It may be different from the order in
458 // SectionHdrLayout which specifies the sequence in which sections will
459 // be read.
460 std::vector<SecHdrTableEntry> SecHdrTable;
461
462 // FuncOffsetTable maps function context to its profile offset in
463 // SecLBRProfile section. It is used to load function profile on demand.
465 // Whether to use MD5 to represent string.
466 bool UseMD5 = false;
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 std::error_code writeCustomSection(SecType Type) override {
488 };
489
490 void verifySecLayout(SectionLayout SL) override {
491 assert((SL == DefaultLayout || SL == CtxSplitLayout) &&
492 "Unsupported layout");
493 }
494};
495
496} // end namespace sampleprof
497} // end namespace llvm
498
499#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)
Value * RHS
Value * LHS
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.
Trait class for writing the on-disk function offset hash table mapping function name GUIDs to their o...
static key_type GetInternalKey(key_type_ref Key)
static void EmitData(raw_ostream &Out, key_type_ref K, data_type_ref V, offset_type Len)
static void EmitKey(raw_ostream &Out, key_type_ref K, offset_type Len)
static bool EqualKey(key_type_ref LHS, key_type_ref RHS)
static hash_value_type ComputeHash(key_type_ref Key)
static std::pair< offset_type, offset_type > EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V)
static external_key_type GetExternalKey(internal_key_type Key)
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:810
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, uint32_t LayoutIdx, 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)
void addSectionFlag(uint32_t SectionIdx, SecFlagType Flag)
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:130
static void addSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag)
Definition SampleProf.h:281
const std::array< SmallVector< SecHdrTableEntry, 8 >, NumOfLayout > ExtBinaryHdrLayoutTable
@ SecFlagPartial
SecFlagPartial means the profile is for common/shared code.
Definition SampleProf.h:221
static constexpr uint64_t DefaultVersion
Definition SampleProf.h:124
std::map< LineLocation, TypeCountMap > CallsiteTypeMap
Definition SampleProf.h:802
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...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
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
Adapter to write values to a stream in a particular byte order.