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