LLVM 23.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"
23#include <cstdint>
24#include <memory>
25#include <set>
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
135protected:
136 SampleProfileWriter(std::unique_ptr<raw_ostream> &OS)
137 : OutputStream(std::move(OS)) {}
138
139 /// Write a file header for the profile file.
140 virtual std::error_code writeHeader(const SampleProfileMap &ProfileMap) = 0;
141
142 // Write function profiles to the profile file.
143 virtual std::error_code writeFuncProfiles(const SampleProfileMap &ProfileMap);
144
145 std::error_code writeWithSizeLimitInternal(SampleProfileMap &ProfileMap,
146 size_t OutputSizeLimit,
147 FunctionPruningStrategy *Strategy);
148
149 /// For writeWithSizeLimit in text mode, each newline takes 1 additional byte
150 /// on Windows when actually written to the file, but not written to a memory
151 /// buffer. This needs to be accounted for when rewriting the profile.
152 size_t LineCount;
153
154 /// Output stream where to emit the profile to.
155 std::unique_ptr<raw_ostream> OutputStream;
156
157 /// Profile summary.
158 std::unique_ptr<ProfileSummary> Summary;
159
160 /// Compute summary for this profile.
161 void computeSummary(const SampleProfileMap &ProfileMap);
162
163 /// Profile format.
165};
166
167/// Sample-based profile writer (text format).
169public:
170 std::error_code writeSample(const FunctionSamples &S) override;
171
172protected:
173 SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS)
174 : SampleProfileWriter(OS) {}
175
176 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override {
177 LineCount = 0;
179 }
180
181 void setUseCtxSplitLayout() override { MarkFlatProfiles = true; }
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)
204 : SampleProfileWriter(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);
217 inline void stablizeNameTable(MapVector<FunctionId, uint32_t> &NameTable,
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
226 /// Write \p CallsiteTypeMap to the output stream \p OS.
227 std::error_code
229 raw_ostream &OS);
230
231 bool WriteVTableProf = false;
232
233private:
235 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
237};
238
239class SampleProfileWriterRawBinary : public SampleProfileWriterBinary {
241};
242
243const std::array<SmallVector<SecHdrTableEntry, 8>, NumOfLayout>
245 // Note that SecFuncOffsetTable section is written after SecLBRProfile
246 // in the profile, but is put before SecLBRProfile in SectionHdrLayout.
247 // This is because sample reader follows the order in SectionHdrLayout
248 // to read each section. To read function profiles on demand, sample
249 // reader need to get the offset of each function profile first.
250 //
251 // DefaultLayout
253 {SecNameTable, 0, 0, 0, 0},
254 {SecCSNameTable, 0, 0, 0, 0},
255 {SecFuncOffsetTable, 0, 0, 0, 0},
256 {SecLBRProfile, 0, 0, 0, 0},
257 {SecProfileSymbolList, 0, 0, 0, 0},
258 {SecFuncMetadata, 0, 0, 0, 0}}),
259 // CtxSplitLayout
261 {SecNameTable, 0, 0, 0, 0},
262 // profile with inlined functions
263 // for next two sections
264 {SecFuncOffsetTable, 0, 0, 0, 0},
265 {SecLBRProfile, 0, 0, 0, 0},
266 // profile without inlined functions
267 // for next two sections
268 {SecFuncOffsetTable, 0, 0, 0, 0},
269 {SecLBRProfile, 0, 0, 0, 0},
270 {SecProfileSymbolList, 0, 0, 0, 0},
271 {SecFuncMetadata, 0, 0, 0, 0}}),
272};
273
274/// Trait class for writing the on-disk function offset hash table mapping
275/// function name GUIDs to their offsets in the SecLBRProfile section.
277public:
280 using data_type = uint32_t; // Offset
286
288 return static_cast<hash_value_type>(Key);
289 }
290
292 return LHS == RHS;
293 }
294
297
298 static std::pair<offset_type, offset_type>
300 // Implicit lengths: do NOT write anything to Out.
301 return {sizeof(key_type), sizeof(data_type)};
302 }
303
304 static void EmitKey(raw_ostream &Out, key_type_ref K, offset_type Len) {
305 using namespace llvm::support;
307 assert(Len == sizeof(key_type) && "Key length mismatch");
308 LE.write<uint64_t>(K);
309 }
310
312 offset_type Len) {
313 using namespace llvm::support;
315 assert(Len == sizeof(data_type) && "Data length mismatch");
316 LE.write<uint32_t>(V);
317 }
318};
319
321 : public SampleProfileWriterBinary {
323
324public:
325 std::error_code write(const SampleProfileMap &ProfileMap) override;
326
327 void setToCompressAllSections() override;
329 std::error_code writeSample(const FunctionSamples &S) override;
330
331 // Set to use MD5 to represent string in NameTable.
332 void setUseMD5() override {
333 UseMD5 = true;
335 // MD5 will be stored as plain uint64_t instead of variable-length
336 // quantity format in NameTable section.
338 }
339
340 // Set the profile to be partial. It means the profile is for
341 // common/shared code. The common profile is usually merged from
342 // profiles collected from running other targets.
346
348 ProfSymList = PSL;
349 };
350
354
356 verifySecLayout(SL);
357#ifndef NDEBUG
358 // Make sure resetSecLayout is called before any flag setting.
359 for (auto &Entry : SectionHdrLayout) {
360 assert(Entry.Flags == 0 &&
361 "resetSecLayout has to be called before any flag setting");
362 }
363#endif
364 SecLayout = SL;
366 }
367
368protected:
369 uint64_t markSectionStart(SecType Type, uint32_t LayoutIdx);
370 std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx,
371 uint64_t SectionStart);
372 template <class SecFlagType>
373 void addSectionFlag(SecType Type, SecFlagType Flag) {
374 for (auto &Entry : SectionHdrLayout) {
375 if (Entry.Type == Type)
376 addSecFlag(Entry, Flag);
377 }
378 }
379 template <class SecFlagType>
380 void addSectionFlag(uint32_t SectionIdx, SecFlagType Flag) {
381 addSecFlag(SectionHdrLayout[SectionIdx], Flag);
382 }
383
384 void addContext(const SampleContext &Context) override;
385
386 // placeholder for subclasses to dispatch their own section writers.
387 virtual std::error_code writeCustomSection(SecType Type) = 0;
388 // Verify the SecLayout is supported by the format.
389 virtual void verifySecLayout(SectionLayout SL) = 0;
390
391 // specify the order to write sections.
392 virtual std::error_code writeSections(const SampleProfileMap &ProfileMap) = 0;
393
394 // Dispatch section writer for each section. \p LayoutIdx is the sequence
395 // number indicating where the section is located in SectionHdrLayout.
396 virtual std::error_code writeOneSection(SecType Type, uint32_t LayoutIdx,
397 const SampleProfileMap &ProfileMap);
398
399 // Helper function to write name table.
400 std::error_code writeNameTable() override;
401 std::error_code writeContextIdx(const SampleContext &Context) override;
402 std::error_code writeCSNameIdx(const SampleContext &Context);
403 std::error_code writeCSNameTableSection();
404
405 std::error_code writeFuncMetadata(const SampleProfileMap &Profiles);
406 std::error_code writeFuncMetadata(const FunctionSamples &Profile);
407
408 // Functions to write various kinds of sections.
409 std::error_code writeNameTableSection(const SampleProfileMap &ProfileMap);
410 std::error_code writeFuncOffsetTable();
411 std::error_code writeProfileSymbolListSection();
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
458 /// CSNameTable maps function context to its offset in SecCSNameTable section.
459 /// The offset will be used everywhere where the context is referenced.
461
462 ProfileSymbolList *ProfSymList = nullptr;
463};
464
467public:
468 SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS);
469
470private:
471 std::error_code writeDefaultLayout(const SampleProfileMap &ProfileMap);
472 std::error_code writeCtxSplitLayout(const SampleProfileMap &ProfileMap);
473
474 std::error_code writeSections(const SampleProfileMap &ProfileMap) override;
475
476 std::error_code writeCustomSection(SecType Type) override {
478 };
479
480 void verifySecLayout(SectionLayout SL) override {
481 assert((SL == DefaultLayout || SL == CtxSplitLayout) &&
482 "Unsupported layout");
483 }
484};
485
486} // end namespace sampleprof
487} // end namespace llvm
488
489#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.
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:789
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)
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 void addSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag)
Definition SampleProf.h:257
const std::array< SmallVector< SecHdrTableEntry, 8 >, NumOfLayout > ExtBinaryHdrLayoutTable
@ SecFlagPartial
SecFlagPartial means the profile is for common/shared code.
Definition SampleProf.h:200
std::map< LineLocation, TypeCountMap > CallsiteTypeMap
Definition SampleProf.h:781
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:860
Adapter to write values to a stream in a particular byte order.