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 {
182 MarkFlatProfiles = true;
183 }
184
185private:
186 /// Indent level to use when writing.
187 ///
188 /// This is used when printing inlined callees.
189 unsigned Indent = 0;
190
191 /// If set, writes metadata "!Flat" to functions without inlined functions.
192 /// This flag is for manual inspection only, it has no effect for the profile
193 /// reader because a text sample profile is read sequentially and functions
194 /// cannot be skipped.
195 bool MarkFlatProfiles = false;
196
198 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
200};
201
202/// Sample-based profile writer (binary format).
204public:
205 SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
206 : SampleProfileWriter(OS) {}
207
208 std::error_code writeSample(const FunctionSamples &S) override;
209
210protected:
212 virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
213 virtual std::error_code writeNameTable();
214 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
215 std::error_code writeSummary();
216 virtual std::error_code writeContextIdx(const SampleContext &Context);
217 std::error_code writeNameIdx(FunctionId FName);
218 std::error_code writeBody(const FunctionSamples &S);
219 inline void stablizeNameTable(MapVector<FunctionId, uint32_t> &NameTable,
220 std::set<FunctionId> &V);
221
223
224 void addName(FunctionId FName);
225 virtual void addContext(const SampleContext &Context);
226 void addNames(const FunctionSamples &S);
227
228 /// Write \p CallsiteTypeMap to the output stream \p OS.
229 std::error_code
231 raw_ostream &OS);
232
233 bool WriteVTableProf = false;
234
235private:
237 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
239};
240
241class SampleProfileWriterRawBinary : public SampleProfileWriterBinary {
243};
244
245const std::array<SmallVector<SecHdrTableEntry, 8>, NumOfLayout>
247 // Note that SecFuncOffsetTable section is written after SecLBRProfile
248 // in the profile, but is put before SecLBRProfile in SectionHdrLayout.
249 // This is because sample reader follows the order in SectionHdrLayout
250 // to read each section. To read function profiles on demand, sample
251 // reader need to get the offset of each function profile first.
252 //
253 // DefaultLayout
255 {SecNameTable, 0, 0, 0, 0},
256 {SecCSNameTable, 0, 0, 0, 0},
257 {SecFuncOffsetTable, 0, 0, 0, 0},
258 {SecLBRProfile, 0, 0, 0, 0},
259 {SecProfileSymbolList, 0, 0, 0, 0},
260 {SecFuncMetadata, 0, 0, 0, 0}}),
261 // CtxSplitLayout
263 {SecNameTable, 0, 0, 0, 0},
264 // profile with inlined functions
265 // for next two sections
266 {SecFuncOffsetTable, 0, 0, 0, 0},
267 {SecLBRProfile, 0, 0, 0, 0},
268 // profile without inlined functions
269 // for next two sections
270 {SecFuncOffsetTable, 0, 0, 0, 0},
271 {SecLBRProfile, 0, 0, 0, 0},
272 {SecProfileSymbolList, 0, 0, 0, 0},
273 {SecFuncMetadata, 0, 0, 0, 0}}),
274};
275
276/// Trait class for writing the on-disk function offset hash table mapping
277/// function name GUIDs to their offsets in the SecLBRProfile section.
279public:
282 using data_type = uint32_t; // Offset
288
290 return static_cast<hash_value_type>(Key);
291 }
292
294 return LHS == RHS;
295 }
296
299
300 static std::pair<offset_type, offset_type>
302 // Implicit lengths: do NOT write anything to Out.
303 return {sizeof(key_type), sizeof(data_type)};
304 }
305
306 static void EmitKey(raw_ostream &Out, key_type_ref K, offset_type Len) {
307 using namespace llvm::support;
309 assert(Len == sizeof(key_type) && "Key length mismatch");
310 LE.write<uint64_t>(K);
311 }
312
314 offset_type Len) {
315 using namespace llvm::support;
317 assert(Len == sizeof(data_type) && "Data length mismatch");
318 LE.write<uint32_t>(V);
319 }
320};
321
323 : public SampleProfileWriterBinary {
325public:
326 std::error_code write(const SampleProfileMap &ProfileMap) override;
327
328 void setToCompressAllSections() override;
330 std::error_code writeSample(const FunctionSamples &S) override;
331
332 // Set to use MD5 to represent string in NameTable.
333 void setUseMD5() override {
334 UseMD5 = true;
336 // MD5 will be stored as plain uint64_t instead of variable-length
337 // quantity format in NameTable section.
339 }
340
341 // Set the profile to be partial. It means the profile is for
342 // common/shared code. The common profile is usually merged from
343 // profiles collected from running other targets.
347
349 ProfSymList = PSL;
350 };
351
355
357 verifySecLayout(SL);
358#ifndef NDEBUG
359 // Make sure resetSecLayout is called before any flag setting.
360 for (auto &Entry : SectionHdrLayout) {
361 assert(Entry.Flags == 0 &&
362 "resetSecLayout has to be called before any flag setting");
363 }
364#endif
365 SecLayout = SL;
367 }
368
369protected:
370 uint64_t markSectionStart(SecType Type, uint32_t LayoutIdx);
371 std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx,
372 uint64_t SectionStart);
373 template <class SecFlagType>
374 void addSectionFlag(SecType Type, SecFlagType Flag) {
375 for (auto &Entry : SectionHdrLayout) {
376 if (Entry.Type == Type)
377 addSecFlag(Entry, Flag);
378 }
379 }
380 template <class SecFlagType>
381 void addSectionFlag(uint32_t SectionIdx, SecFlagType Flag) {
382 addSecFlag(SectionHdrLayout[SectionIdx], Flag);
383 }
384
385 void addContext(const SampleContext &Context) override;
386
387 // placeholder for subclasses to dispatch their own section writers.
388 virtual std::error_code writeCustomSection(SecType Type) = 0;
389 // Verify the SecLayout is supported by the format.
390 virtual void verifySecLayout(SectionLayout SL) = 0;
391
392 // specify the order to write sections.
393 virtual std::error_code writeSections(const SampleProfileMap &ProfileMap) = 0;
394
395 // Dispatch section writer for each section. \p LayoutIdx is the sequence
396 // number indicating where the section is located in SectionHdrLayout.
397 virtual std::error_code writeOneSection(SecType Type, uint32_t LayoutIdx,
398 const SampleProfileMap &ProfileMap);
399
400 // Helper function to write name table.
401 std::error_code writeNameTable() override;
402 std::error_code writeContextIdx(const SampleContext &Context) override;
403 std::error_code writeCSNameIdx(const SampleContext &Context);
404 std::error_code writeCSNameTableSection();
405
406 std::error_code writeFuncMetadata(const SampleProfileMap &Profiles);
407 std::error_code writeFuncMetadata(const FunctionSamples &Profile);
408
409 // Functions to write various kinds of sections.
410 std::error_code writeNameTableSection(const SampleProfileMap &ProfileMap);
411 std::error_code writeFuncOffsetTable();
412 std::error_code writeProfileSymbolListSection();
413
415 // Specifiy the order of sections in section header table. Note
416 // the order of sections in SecHdrTable may be different that the
417 // order in SectionHdrLayout. sample Reader will follow the order
418 // in SectionHdrLayout to read each section.
421
422 // Save the start of SecLBRProfile so we can compute the offset to the
423 // start of SecLBRProfile for each Function's Profile and will keep it
424 // in FuncOffsetTable.
426
427private:
428 void allocSecHdrTable();
429 std::error_code writeSecHdrTable();
430 std::error_code writeHeader(const SampleProfileMap &ProfileMap) override;
431 std::error_code compressAndOutput();
432
433 // We will swap the raw_ostream held by LocalBufStream and that
434 // held by OutputStream if we try to add a section which needs
435 // compression. After the swap, all the data written to output
436 // will be temporarily buffered into the underlying raw_string_ostream
437 // originally held by LocalBufStream. After the data writing for the
438 // section is completed, compress the data in the local buffer,
439 // swap the raw_ostream back and write the compressed data to the
440 // real output.
441 std::unique_ptr<raw_ostream> LocalBufStream;
442 // The location where the output stream starts.
443 uint64_t FileStart;
444 // The location in the output stream where the SecHdrTable should be
445 // written to.
446 uint64_t SecHdrTableOffset;
447 // The table contains SecHdrTableEntry entries in order of how they are
448 // populated in the writer. It may be different from the order in
449 // SectionHdrLayout which specifies the sequence in which sections will
450 // be read.
451 std::vector<SecHdrTableEntry> SecHdrTable;
452
453 // FuncOffsetTable maps function context to its profile offset in
454 // SecLBRProfile section. It is used to load function profile on demand.
456 // Whether to use MD5 to represent string.
457 bool UseMD5 = false;
458
459 /// CSNameTable maps function context to its offset in SecCSNameTable section.
460 /// The offset will be used everywhere where the context is referenced.
462
463 ProfileSymbolList *ProfSymList = nullptr;
464};
465
468public:
469 SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS);
470
471private:
472 std::error_code writeDefaultLayout(const SampleProfileMap &ProfileMap);
473 std::error_code writeCtxSplitLayout(const SampleProfileMap &ProfileMap);
474
475 std::error_code writeSections(const SampleProfileMap &ProfileMap) override;
476
477 std::error_code writeCustomSection(SecType Type) override {
479 };
480
481 void verifySecLayout(SectionLayout SL) override {
482 assert((SL == DefaultLayout || SL == CtxSplitLayout) &&
483 "Unsupported layout");
484 }
485};
486
487} // end namespace sampleprof
488} // end namespace llvm
489
490#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:792
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:784
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.