LLVM 20.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/MapVector.h"
16#include "llvm/ADT/StringRef.h"
21#include <cstdint>
22#include <memory>
23#include <set>
24#include <system_error>
25
26namespace llvm {
27namespace sampleprof {
28
31 // The layout splits profile with inlined functions from profile without
32 // inlined functions. When Thinlto is enabled, ThinLTO postlink phase only
33 // has to load profile with inlined functions and can skip the other part.
36};
37
38/// When writing a profile with size limit, user may want to use a different
39/// strategy to reduce function count other than dropping functions with fewest
40/// samples first. In this case a class implementing the same interfaces should
41/// be provided to SampleProfileWriter::writeWithSizeLimit().
43protected:
46
47public:
48 /// \p ProfileMap A reference to the original profile map. It will be modified
49 /// by Erase().
50 /// \p OutputSizeLimit Size limit in bytes of the output profile. This is
51 /// necessary to estimate how many functions to remove.
54
55 virtual ~FunctionPruningStrategy() = default;
56
57 /// SampleProfileWriter::writeWithSizeLimit() calls this after every write
58 /// iteration if the output size still exceeds the limit. This function
59 /// should erase some functions from the profile map so that the writer tries
60 /// to write the profile again with fewer functions. At least 1 entry from the
61 /// profile map must be erased.
62 ///
63 /// \p CurrentOutputSize Number of bytes in the output if current profile map
64 /// is written.
65 virtual void Erase(size_t CurrentOutputSize) = 0;
66};
67
69 std::vector<NameFunctionSamples> SortedFunctions;
70
71public:
73 size_t OutputSizeLimit);
74
75 /// In this default implementation, functions with fewest samples are dropped
76 /// first. Since the exact size of the output cannot be easily calculated due
77 /// to compression, we use a heuristic to remove as many functions as
78 /// necessary but not too many, aiming to minimize the number of write
79 /// iterations.
80 /// Empirically, functions with larger total sample count contain linearly
81 /// more sample entries, meaning it takes linearly more space to write them.
82 /// The cumulative length is therefore quadratic if all functions are sorted
83 /// by total sample count.
84 /// TODO: Find better heuristic.
85 void Erase(size_t CurrentOutputSize) override;
86};
87
88/// Sample-based profile writer. Base class.
90public:
91 virtual ~SampleProfileWriter() = default;
92
93 /// Write sample profiles in \p S.
94 ///
95 /// \returns status code of the file update operation.
96 virtual std::error_code writeSample(const FunctionSamples &S) = 0;
97
98 /// Write all the sample profiles in the given map of samples.
99 ///
100 /// \returns status code of the file update operation.
101 virtual std::error_code write(const SampleProfileMap &ProfileMap);
102
103 /// Write sample profiles up to given size limit, using the pruning strategy
104 /// to drop some functions if necessary.
105 ///
106 /// \returns status code of the file update operation.
107 template <typename FunctionPruningStrategy = DefaultFunctionPruningStrategy>
108 std::error_code writeWithSizeLimit(SampleProfileMap &ProfileMap,
109 size_t OutputSizeLimit) {
110 FunctionPruningStrategy Strategy(ProfileMap, OutputSizeLimit);
111 return writeWithSizeLimitInternal(ProfileMap, OutputSizeLimit, &Strategy);
112 }
113
115
116 /// Profile writer factory.
117 ///
118 /// Create a new file writer based on the value of \p Format.
121
122 /// Create a new stream writer based on the value of \p Format.
123 /// For testing.
125 create(std::unique_ptr<raw_ostream> &OS, SampleProfileFormat Format);
126
128 virtual void setToCompressAllSections() {}
129 virtual void setUseMD5() {}
130 virtual void setPartialProfile() {}
131 virtual void setUseCtxSplitLayout() {}
132
133protected:
134 SampleProfileWriter(std::unique_ptr<raw_ostream> &OS)
135 : OutputStream(std::move(OS)) {}
136
137 /// Write a file header for the profile file.
138 virtual std::error_code writeHeader(const SampleProfileMap &ProfileMap) = 0;
139
140 // Write function profiles to the profile file.
141 virtual std::error_code writeFuncProfiles(const SampleProfileMap &ProfileMap);
142
143 std::error_code writeWithSizeLimitInternal(SampleProfileMap &ProfileMap,
144 size_t OutputSizeLimit,
145 FunctionPruningStrategy *Strategy);
146
147 /// For writeWithSizeLimit in text mode, each newline takes 1 additional byte
148 /// on Windows when actually written to the file, but not written to a memory
149 /// buffer. This needs to be accounted for when rewriting the profile.
150 size_t LineCount;
151
152 /// Output stream where to emit the profile to.
153 std::unique_ptr<raw_ostream> OutputStream;
154
155 /// Profile summary.
156 std::unique_ptr<ProfileSummary> Summary;
157
158 /// Compute summary for this profile.
159 void computeSummary(const SampleProfileMap &ProfileMap);
160
161 /// Profile format.
163};
164
165/// Sample-based profile writer (text format).
167public:
168 std::error_code writeSample(const FunctionSamples &S) override;
169
170protected:
171 SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS)
173
174 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override {
175 LineCount = 0;
177 }
178
179 void setUseCtxSplitLayout() override {
180 MarkFlatProfiles = true;
181 }
182
183private:
184 /// Indent level to use when writing.
185 ///
186 /// This is used when printing inlined callees.
187 unsigned Indent = 0;
188
189 /// If set, writes metadata "!Flat" to functions without inlined functions.
190 /// This flag is for manual inspection only, it has no effect for the profile
191 /// reader because a text sample profile is read sequentially and functions
192 /// cannot be skipped.
193 bool MarkFlatProfiles = false;
194
196 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
198};
199
200/// Sample-based profile writer (binary format).
202public:
203 SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
205
206 std::error_code writeSample(const FunctionSamples &S) override;
207
208protected:
210 virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
211 virtual std::error_code writeNameTable();
212 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
213 std::error_code writeSummary();
214 virtual std::error_code writeContextIdx(const SampleContext &Context);
215 std::error_code writeNameIdx(FunctionId FName);
216 std::error_code writeBody(const FunctionSamples &S);
218 std::set<FunctionId> &V);
219
221
222 void addName(FunctionId FName);
223 virtual void addContext(const SampleContext &Context);
224 void addNames(const FunctionSamples &S);
225
226private:
228 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
230};
231
234};
235
236const std::array<SmallVector<SecHdrTableEntry, 8>, NumOfLayout>
238 // Note that SecFuncOffsetTable section is written after SecLBRProfile
239 // in the profile, but is put before SecLBRProfile in SectionHdrLayout.
240 // This is because sample reader follows the order in SectionHdrLayout
241 // to read each section. To read function profiles on demand, sample
242 // reader need to get the offset of each function profile first.
243 //
244 // DefaultLayout
246 {SecNameTable, 0, 0, 0, 0},
247 {SecCSNameTable, 0, 0, 0, 0},
248 {SecFuncOffsetTable, 0, 0, 0, 0},
249 {SecLBRProfile, 0, 0, 0, 0},
250 {SecProfileSymbolList, 0, 0, 0, 0},
251 {SecFuncMetadata, 0, 0, 0, 0}}),
252 // CtxSplitLayout
254 {SecNameTable, 0, 0, 0, 0},
255 // profile with inlined functions
256 // for next two sections
257 {SecFuncOffsetTable, 0, 0, 0, 0},
258 {SecLBRProfile, 0, 0, 0, 0},
259 // profile without inlined functions
260 // for next two sections
261 {SecFuncOffsetTable, 0, 0, 0, 0},
262 {SecLBRProfile, 0, 0, 0, 0},
263 {SecProfileSymbolList, 0, 0, 0, 0},
264 {SecFuncMetadata, 0, 0, 0, 0}}),
265};
266
269public:
270 std::error_code write(const SampleProfileMap &ProfileMap) override;
271
272 void setToCompressAllSections() override;
274 std::error_code writeSample(const FunctionSamples &S) override;
275
276 // Set to use MD5 to represent string in NameTable.
277 void setUseMD5() override {
278 UseMD5 = true;
280 // MD5 will be stored as plain uint64_t instead of variable-length
281 // quantity format in NameTable section.
283 }
284
285 // Set the profile to be partial. It means the profile is for
286 // common/shared code. The common profile is usually merged from
287 // profiles collected from running other targets.
288 void setPartialProfile() override {
290 }
291
293 ProfSymList = PSL;
294 };
295
296 void setUseCtxSplitLayout() override {
298 }
299
301 verifySecLayout(SL);
302#ifndef NDEBUG
303 // Make sure resetSecLayout is called before any flag setting.
304 for (auto &Entry : SectionHdrLayout) {
305 assert(Entry.Flags == 0 &&
306 "resetSecLayout has to be called before any flag setting");
307 }
308#endif
309 SecLayout = SL;
311 }
312
313protected:
315 std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx,
316 uint64_t SectionStart);
317 template <class SecFlagType>
318 void addSectionFlag(SecType Type, SecFlagType Flag) {
319 for (auto &Entry : SectionHdrLayout) {
320 if (Entry.Type == Type)
321 addSecFlag(Entry, Flag);
322 }
323 }
324 template <class SecFlagType>
325 void addSectionFlag(uint32_t SectionIdx, SecFlagType Flag) {
326 addSecFlag(SectionHdrLayout[SectionIdx], Flag);
327 }
328
329 void addContext(const SampleContext &Context) override;
330
331 // placeholder for subclasses to dispatch their own section writers.
332 virtual std::error_code writeCustomSection(SecType Type) = 0;
333 // Verify the SecLayout is supported by the format.
334 virtual void verifySecLayout(SectionLayout SL) = 0;
335
336 // specify the order to write sections.
337 virtual std::error_code writeSections(const SampleProfileMap &ProfileMap) = 0;
338
339 // Dispatch section writer for each section. \p LayoutIdx is the sequence
340 // number indicating where the section is located in SectionHdrLayout.
341 virtual std::error_code writeOneSection(SecType Type, uint32_t LayoutIdx,
342 const SampleProfileMap &ProfileMap);
343
344 // Helper function to write name table.
345 std::error_code writeNameTable() override;
346 std::error_code writeContextIdx(const SampleContext &Context) override;
347 std::error_code writeCSNameIdx(const SampleContext &Context);
348 std::error_code writeCSNameTableSection();
349
350 std::error_code writeFuncMetadata(const SampleProfileMap &Profiles);
351 std::error_code writeFuncMetadata(const FunctionSamples &Profile);
352
353 // Functions to write various kinds of sections.
354 std::error_code writeNameTableSection(const SampleProfileMap &ProfileMap);
355 std::error_code writeFuncOffsetTable();
356 std::error_code writeProfileSymbolListSection();
357
359 // Specifiy the order of sections in section header table. Note
360 // the order of sections in SecHdrTable may be different that the
361 // order in SectionHdrLayout. sample Reader will follow the order
362 // in SectionHdrLayout to read each section.
365
366 // Save the start of SecLBRProfile so we can compute the offset to the
367 // start of SecLBRProfile for each Function's Profile and will keep it
368 // in FuncOffsetTable.
370
371private:
372 void allocSecHdrTable();
373 std::error_code writeSecHdrTable();
374 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
375 std::error_code compressAndOutput();
376
377 // We will swap the raw_ostream held by LocalBufStream and that
378 // held by OutputStream if we try to add a section which needs
379 // compression. After the swap, all the data written to output
380 // will be temporarily buffered into the underlying raw_string_ostream
381 // originally held by LocalBufStream. After the data writing for the
382 // section is completed, compress the data in the local buffer,
383 // swap the raw_ostream back and write the compressed data to the
384 // real output.
385 std::unique_ptr<raw_ostream> LocalBufStream;
386 // The location where the output stream starts.
387 uint64_t FileStart;
388 // The location in the output stream where the SecHdrTable should be
389 // written to.
390 uint64_t SecHdrTableOffset;
391 // The table contains SecHdrTableEntry entries in order of how they are
392 // populated in the writer. It may be different from the order in
393 // SectionHdrLayout which specifies the sequence in which sections will
394 // be read.
395 std::vector<SecHdrTableEntry> SecHdrTable;
396
397 // FuncOffsetTable maps function context to its profile offset in
398 // SecLBRProfile section. It is used to load function profile on demand.
400 // Whether to use MD5 to represent string.
401 bool UseMD5 = false;
402
403 /// CSNameTable maps function context to its offset in SecCSNameTable section.
404 /// The offset will be used everywhere where the context is referenced.
406
407 ProfileSymbolList *ProfSymList = nullptr;
408};
409
411public:
412 SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS)
414
415private:
416 std::error_code writeDefaultLayout(const SampleProfileMap &ProfileMap);
417 std::error_code writeCtxSplitLayout(const SampleProfileMap &ProfileMap);
418
419 std::error_code writeSections(const SampleProfileMap &ProfileMap) override;
420
421 std::error_code writeCustomSection(SecType Type) override {
423 };
424
425 void verifySecLayout(SectionLayout SL) override {
426 assert((SL == DefaultLayout || SL == CtxSplitLayout) &&
427 "Unsupported layout");
428 }
429};
430
431} // end namespace sampleprof
432} // end namespace llvm
433
434#endif // LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
Provides ErrorOr<T> smart pointer.
Load MIR Sample Profile
This file implements a map that provides insertion order iteration.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
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:36
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
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:745
ProfileSymbolList records the list of function symbols shown up in the binary used to generate the pr...
Definition: SampleProf.h:1513
This class provides operator overloads to the map container using MD5 as the key type,...
Definition: SampleProf.h:1313
Sample-based profile writer (binary format).
SampleProfileWriterBinary(std::unique_ptr< raw_ostream > &OS)
void stablizeNameTable(MapVector< FunctionId, uint32_t > &NameTable, std::set< FunctionId > &V)
virtual void addContext(const SampleContext &Context)
virtual std::error_code writeMagicIdent(SampleProfileFormat Format)
MapVector< FunctionId, uint32_t > NameTable
virtual std::error_code writeContextIdx(const SampleContext &Context)
std::error_code writeSample(const FunctionSamples &S) override
Write samples of a top-level function to a binary file.
std::error_code writeHeader(const SampleProfileMap &ProfileMap) override
Write a file header for the profile file.
virtual MapVector< FunctionId, uint32_t > & getNameTable()
std::error_code writeBody(const FunctionSamples &S)
std::error_code writeNameIdx(FunctionId FName)
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)
uint64_t markSectionStart(SecType Type, uint32_t LayoutIdx)
Return the current position and prepare to use it as the start position of a section given the sectio...
void addContext(const SampleContext &Context) override
std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx, uint64_t SectionStart)
Add a new section into section header table given the section type Type, its position LayoutIdx in Se...
void addSectionFlag(uint32_t SectionIdx, SecFlagType Flag)
std::error_code write(const SampleProfileMap &ProfileMap) override
Write all the sample profiles in the given map of samples.
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)
Sample-based profile writer (text format).
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.
Sample-based profile writer. Base class.
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)
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.
virtual std::error_code write(const SampleProfileMap &ProfileMap)
Write all the sample profiles in the given map of samples.
static void addSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag)
Definition: SampleProf.h:248
const std::array< SmallVector< SecHdrTableEntry, 8 >, NumOfLayout > ExtBinaryHdrLayoutTable
@ SecFlagPartial
SecFlagPartial means the profile is for common/shared code.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
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:1873
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858