LLVM 19.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 context information from profile without
32 // context information. When Thinlto is enabled, ThinLTO postlink phase only
33 // has to load profile with context information 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 resetSecLayout(SectionLayout SL) {}
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)
172 : SampleProfileWriter(OS), Indent(0) {}
173
174 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override {
175 LineCount = 0;
177 }
178
179private:
180 /// Indent level to use when writing.
181 ///
182 /// This is used when printing inlined callees.
183 unsigned Indent;
184
186 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
188};
189
190/// Sample-based profile writer (binary format).
192public:
193 SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
195
196 std::error_code writeSample(const FunctionSamples &S) override;
197
198protected:
200 virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
201 virtual std::error_code writeNameTable();
202 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
203 std::error_code writeSummary();
204 virtual std::error_code writeContextIdx(const SampleContext &Context);
205 std::error_code writeNameIdx(FunctionId FName);
206 std::error_code writeBody(const FunctionSamples &S);
208 std::set<FunctionId> &V);
209
211
212 void addName(FunctionId FName);
213 virtual void addContext(const SampleContext &Context);
214 void addNames(const FunctionSamples &S);
215
216private:
218 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
220};
221
224};
225
226const std::array<SmallVector<SecHdrTableEntry, 8>, NumOfLayout>
228 // Note that SecFuncOffsetTable section is written after SecLBRProfile
229 // in the profile, but is put before SecLBRProfile in SectionHdrLayout.
230 // This is because sample reader follows the order in SectionHdrLayout
231 // to read each section. To read function profiles on demand, sample
232 // reader need to get the offset of each function profile first.
233 //
234 // DefaultLayout
236 {SecNameTable, 0, 0, 0, 0},
237 {SecCSNameTable, 0, 0, 0, 0},
238 {SecFuncOffsetTable, 0, 0, 0, 0},
239 {SecLBRProfile, 0, 0, 0, 0},
240 {SecProfileSymbolList, 0, 0, 0, 0},
241 {SecFuncMetadata, 0, 0, 0, 0}}),
242 // CtxSplitLayout
244 {SecNameTable, 0, 0, 0, 0},
245 // profile with context
246 // for next two sections
247 {SecFuncOffsetTable, 0, 0, 0, 0},
248 {SecLBRProfile, 0, 0, 0, 0},
249 // profile without context
250 // for next two sections
251 {SecFuncOffsetTable, 0, 0, 0, 0},
252 {SecLBRProfile, 0, 0, 0, 0},
253 {SecProfileSymbolList, 0, 0, 0, 0},
254 {SecFuncMetadata, 0, 0, 0, 0}}),
255};
256
259public:
260 std::error_code write(const SampleProfileMap &ProfileMap) override;
261
262 void setToCompressAllSections() override;
264 std::error_code writeSample(const FunctionSamples &S) override;
265
266 // Set to use MD5 to represent string in NameTable.
267 void setUseMD5() override {
268 UseMD5 = true;
270 // MD5 will be stored as plain uint64_t instead of variable-length
271 // quantity format in NameTable section.
273 }
274
275 // Set the profile to be partial. It means the profile is for
276 // common/shared code. The common profile is usually merged from
277 // profiles collected from running other targets.
278 void setPartialProfile() override {
280 }
281
283 ProfSymList = PSL;
284 };
285
286 void resetSecLayout(SectionLayout SL) override {
287 verifySecLayout(SL);
288#ifndef NDEBUG
289 // Make sure resetSecLayout is called before any flag setting.
290 for (auto &Entry : SectionHdrLayout) {
291 assert(Entry.Flags == 0 &&
292 "resetSecLayout has to be called before any flag setting");
293 }
294#endif
295 SecLayout = SL;
297 }
298
299protected:
301 std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx,
302 uint64_t SectionStart);
303 template <class SecFlagType>
304 void addSectionFlag(SecType Type, SecFlagType Flag) {
305 for (auto &Entry : SectionHdrLayout) {
306 if (Entry.Type == Type)
307 addSecFlag(Entry, Flag);
308 }
309 }
310 template <class SecFlagType>
311 void addSectionFlag(uint32_t SectionIdx, SecFlagType Flag) {
312 addSecFlag(SectionHdrLayout[SectionIdx], Flag);
313 }
314
315 void addContext(const SampleContext &Context) override;
316
317 // placeholder for subclasses to dispatch their own section writers.
318 virtual std::error_code writeCustomSection(SecType Type) = 0;
319 // Verify the SecLayout is supported by the format.
320 virtual void verifySecLayout(SectionLayout SL) = 0;
321
322 // specify the order to write sections.
323 virtual std::error_code writeSections(const SampleProfileMap &ProfileMap) = 0;
324
325 // Dispatch section writer for each section. \p LayoutIdx is the sequence
326 // number indicating where the section is located in SectionHdrLayout.
327 virtual std::error_code writeOneSection(SecType Type, uint32_t LayoutIdx,
328 const SampleProfileMap &ProfileMap);
329
330 // Helper function to write name table.
331 std::error_code writeNameTable() override;
332 std::error_code writeContextIdx(const SampleContext &Context) override;
333 std::error_code writeCSNameIdx(const SampleContext &Context);
334 std::error_code writeCSNameTableSection();
335
336 std::error_code writeFuncMetadata(const SampleProfileMap &Profiles);
337 std::error_code writeFuncMetadata(const FunctionSamples &Profile);
338
339 // Functions to write various kinds of sections.
340 std::error_code writeNameTableSection(const SampleProfileMap &ProfileMap);
341 std::error_code writeFuncOffsetTable();
342 std::error_code writeProfileSymbolListSection();
343
345 // Specifiy the order of sections in section header table. Note
346 // the order of sections in SecHdrTable may be different that the
347 // order in SectionHdrLayout. sample Reader will follow the order
348 // in SectionHdrLayout to read each section.
351
352 // Save the start of SecLBRProfile so we can compute the offset to the
353 // start of SecLBRProfile for each Function's Profile and will keep it
354 // in FuncOffsetTable.
356
357private:
358 void allocSecHdrTable();
359 std::error_code writeSecHdrTable();
360 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
361 std::error_code compressAndOutput();
362
363 // We will swap the raw_ostream held by LocalBufStream and that
364 // held by OutputStream if we try to add a section which needs
365 // compression. After the swap, all the data written to output
366 // will be temporarily buffered into the underlying raw_string_ostream
367 // originally held by LocalBufStream. After the data writing for the
368 // section is completed, compress the data in the local buffer,
369 // swap the raw_ostream back and write the compressed data to the
370 // real output.
371 std::unique_ptr<raw_ostream> LocalBufStream;
372 // The location where the output stream starts.
373 uint64_t FileStart;
374 // The location in the output stream where the SecHdrTable should be
375 // written to.
376 uint64_t SecHdrTableOffset;
377 // The table contains SecHdrTableEntry entries in order of how they are
378 // populated in the writer. It may be different from the order in
379 // SectionHdrLayout which specifies the sequence in which sections will
380 // be read.
381 std::vector<SecHdrTableEntry> SecHdrTable;
382
383 // FuncOffsetTable maps function context to its profile offset in
384 // SecLBRProfile section. It is used to load function profile on demand.
386 // Whether to use MD5 to represent string.
387 bool UseMD5 = false;
388
389 /// CSNameTable maps function context to its offset in SecCSNameTable section.
390 /// The offset will be used everywhere where the context is referenced.
392
393 ProfileSymbolList *ProfSymList = nullptr;
394};
395
397public:
398 SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS)
400
401private:
402 std::error_code writeDefaultLayout(const SampleProfileMap &ProfileMap);
403 std::error_code writeCtxSplitLayout(const SampleProfileMap &ProfileMap);
404
405 std::error_code writeSections(const SampleProfileMap &ProfileMap) override;
406
407 std::error_code writeCustomSection(SecType Type) override {
409 };
410
411 void verifySecLayout(SectionLayout SL) override {
412 assert((SL == DefaultLayout || SL == CtxSplitLayout) &&
413 "Unsupported layout");
414 }
415};
416
417} // end namespace sampleprof
418} // end namespace llvm
419
420#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:1209
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
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:744
ProfileSymbolList records the list of function symbols shown up in the binary used to generate the pr...
Definition: SampleProf.h:1506
This class provides operator overloads to the map container using MD5 as the key type,...
Definition: SampleProf.h:1306
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)
virtual void resetSecLayout(SectionLayout SL)
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:1858
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858