blob: fc568f06ffc8e7b6ae67771d9bd13a7631dee320 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- SampleProfWriter.h - Write LLVM sample profile data ------*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
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/StringMap.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/IR/ProfileSummary.h"
19#include "llvm/ProfileData/SampleProf.h"
20#include "llvm/Support/ErrorOr.h"
21#include "llvm/Support/raw_ostream.h"
22#include <algorithm>
23#include <cstdint>
24#include <memory>
Andrew Scullcdfcccc2018-10-05 20:58:37 +010025#include <set>
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010026#include <system_error>
27
28namespace llvm {
29namespace sampleprof {
30
Andrew Scullcdfcccc2018-10-05 20:58:37 +010031/// Sample-based profile writer. Base class.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010032class SampleProfileWriter {
33public:
34 virtual ~SampleProfileWriter() = default;
35
36 /// Write sample profiles in \p S.
37 ///
38 /// \returns status code of the file update operation.
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020039 virtual std::error_code writeSample(const FunctionSamples &S) = 0;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010040
41 /// Write all the sample profiles in the given map of samples.
42 ///
43 /// \returns status code of the file update operation.
Andrew Scull0372a572018-11-16 15:47:06 +000044 virtual std::error_code write(const StringMap<FunctionSamples> &ProfileMap);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010045
46 raw_ostream &getOutputStream() { return *OutputStream; }
47
48 /// Profile writer factory.
49 ///
50 /// Create a new file writer based on the value of \p Format.
51 static ErrorOr<std::unique_ptr<SampleProfileWriter>>
52 create(StringRef Filename, SampleProfileFormat Format);
53
54 /// Create a new stream writer based on the value of \p Format.
55 /// For testing.
56 static ErrorOr<std::unique_ptr<SampleProfileWriter>>
57 create(std::unique_ptr<raw_ostream> &OS, SampleProfileFormat Format);
58
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020059 virtual void setProfileSymbolList(ProfileSymbolList *PSL) {}
60 virtual void setToCompressAllSections() {}
61 virtual void setUseMD5() {}
62 virtual void setPartialProfile() {}
63
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010064protected:
65 SampleProfileWriter(std::unique_ptr<raw_ostream> &OS)
66 : OutputStream(std::move(OS)) {}
67
Andrew Scullcdfcccc2018-10-05 20:58:37 +010068 /// Write a file header for the profile file.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010069 virtual std::error_code
70 writeHeader(const StringMap<FunctionSamples> &ProfileMap) = 0;
71
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020072 // Write function profiles to the profile file.
73 virtual std::error_code
74 writeFuncProfiles(const StringMap<FunctionSamples> &ProfileMap);
75
Andrew Scullcdfcccc2018-10-05 20:58:37 +010076 /// Output stream where to emit the profile to.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010077 std::unique_ptr<raw_ostream> OutputStream;
78
Andrew Scullcdfcccc2018-10-05 20:58:37 +010079 /// Profile summary.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010080 std::unique_ptr<ProfileSummary> Summary;
81
Andrew Scullcdfcccc2018-10-05 20:58:37 +010082 /// Compute summary for this profile.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010083 void computeSummary(const StringMap<FunctionSamples> &ProfileMap);
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020084
85 /// Profile format.
86 SampleProfileFormat Format = SPF_None;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010087};
88
Andrew Scullcdfcccc2018-10-05 20:58:37 +010089/// Sample-based profile writer (text format).
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010090class SampleProfileWriterText : public SampleProfileWriter {
91public:
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020092 std::error_code writeSample(const FunctionSamples &S) override;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010093
94protected:
95 SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS)
96 : SampleProfileWriter(OS), Indent(0) {}
97
98 std::error_code
99 writeHeader(const StringMap<FunctionSamples> &ProfileMap) override {
100 return sampleprof_error::success;
101 }
102
103private:
104 /// Indent level to use when writing.
105 ///
106 /// This is used when printing inlined callees.
107 unsigned Indent;
108
109 friend ErrorOr<std::unique_ptr<SampleProfileWriter>>
110 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
111 SampleProfileFormat Format);
112};
113
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100114/// Sample-based profile writer (binary format).
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100115class SampleProfileWriterBinary : public SampleProfileWriter {
116public:
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100117 SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
118 : SampleProfileWriter(OS) {}
119
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200120 virtual std::error_code writeSample(const FunctionSamples &S) override;
121
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100122protected:
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200123 virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
124 virtual std::error_code writeNameTable();
Andrew Scull0372a572018-11-16 15:47:06 +0000125 virtual std::error_code
126 writeHeader(const StringMap<FunctionSamples> &ProfileMap) override;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100127 std::error_code writeSummary();
128 std::error_code writeNameIdx(StringRef FName);
129 std::error_code writeBody(const FunctionSamples &S);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100130 inline void stablizeNameTable(std::set<StringRef> &V);
131
132 MapVector<StringRef, uint32_t> NameTable;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100133
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100134 void addName(StringRef FName);
135 void addNames(const FunctionSamples &S);
136
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200137private:
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100138 friend ErrorOr<std::unique_ptr<SampleProfileWriter>>
139 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
140 SampleProfileFormat Format);
141};
142
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100143class SampleProfileWriterRawBinary : public SampleProfileWriterBinary {
144 using SampleProfileWriterBinary::SampleProfileWriterBinary;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200145};
146
147class SampleProfileWriterExtBinaryBase : public SampleProfileWriterBinary {
148 using SampleProfileWriterBinary::SampleProfileWriterBinary;
149public:
150 virtual std::error_code
151 write(const StringMap<FunctionSamples> &ProfileMap) override;
152
153 virtual void setToCompressAllSections() override;
154 void setToCompressSection(SecType Type);
155 virtual std::error_code writeSample(const FunctionSamples &S) override;
156
157 // Set to use MD5 to represent string in NameTable.
158 virtual void setUseMD5() override {
159 UseMD5 = true;
160 addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagMD5Name);
161 // MD5 will be stored as plain uint64_t instead of variable-length
162 // quantity format in NameTable section.
163 addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagFixedLengthMD5);
164 }
165
166 // Set the profile to be partial. It means the profile is for
167 // common/shared code. The common profile is usually merged from
168 // profiles collected from running other targets.
169 virtual void setPartialProfile() override {
170 addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagPartial);
171 }
172
173 virtual void setProfileSymbolList(ProfileSymbolList *PSL) override {
174 ProfSymList = PSL;
175 };
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100176
177protected:
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200178 uint64_t markSectionStart(SecType Type, uint32_t LayoutIdx);
179 std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx,
180 uint64_t SectionStart);
181 template <class SecFlagType>
182 void addSectionFlag(SecType Type, SecFlagType Flag) {
183 for (auto &Entry : SectionHdrLayout) {
184 if (Entry.Type == Type)
185 addSecFlag(Entry, Flag);
186 }
187 }
188
189 // placeholder for subclasses to dispatch their own section writers.
190 virtual std::error_code writeCustomSection(SecType Type) = 0;
191
192 virtual void initSectionHdrLayout() = 0;
193 // specify the order to write sections.
194 virtual std::error_code
195 writeSections(const StringMap<FunctionSamples> &ProfileMap) = 0;
196
197 // Dispatch section writer for each section. \p LayoutIdx is the sequence
198 // number indicating where the section is located in SectionHdrLayout.
199 virtual std::error_code
200 writeOneSection(SecType Type, uint32_t LayoutIdx,
201 const StringMap<FunctionSamples> &ProfileMap);
202
203 // Helper function to write name table.
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100204 virtual std::error_code writeNameTable() override;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200205
206 std::error_code writeFuncMetadata(const StringMap<FunctionSamples> &Profiles);
207
208 // Functions to write various kinds of sections.
209 std::error_code
210 writeNameTableSection(const StringMap<FunctionSamples> &ProfileMap);
211 std::error_code writeFuncOffsetTable();
212 std::error_code writeProfileSymbolListSection();
213
214 // Specifiy the order of sections in section header table. Note
215 // the order of sections in SecHdrTable may be different that the
216 // order in SectionHdrLayout. sample Reader will follow the order
217 // in SectionHdrLayout to read each section.
218 SmallVector<SecHdrTableEntry, 8> SectionHdrLayout;
219
220 // Save the start of SecLBRProfile so we can compute the offset to the
221 // start of SecLBRProfile for each Function's Profile and will keep it
222 // in FuncOffsetTable.
223 uint64_t SecLBRProfileStart = 0;
224
225private:
226 void allocSecHdrTable();
227 std::error_code writeSecHdrTable();
228 virtual std::error_code
229 writeHeader(const StringMap<FunctionSamples> &ProfileMap) override;
230 std::error_code compressAndOutput();
231
232 // We will swap the raw_ostream held by LocalBufStream and that
233 // held by OutputStream if we try to add a section which needs
234 // compression. After the swap, all the data written to output
235 // will be temporarily buffered into the underlying raw_string_ostream
236 // originally held by LocalBufStream. After the data writing for the
237 // section is completed, compress the data in the local buffer,
238 // swap the raw_ostream back and write the compressed data to the
239 // real output.
240 std::unique_ptr<raw_ostream> LocalBufStream;
241 // The location where the output stream starts.
242 uint64_t FileStart;
243 // The location in the output stream where the SecHdrTable should be
244 // written to.
245 uint64_t SecHdrTableOffset;
246 // The table contains SecHdrTableEntry entries in order of how they are
247 // populated in the writer. It may be different from the order in
248 // SectionHdrLayout which specifies the sequence in which sections will
249 // be read.
250 std::vector<SecHdrTableEntry> SecHdrTable;
251
252 // FuncOffsetTable maps function name to its profile offset in SecLBRProfile
253 // section. It is used to load function profile on demand.
254 MapVector<StringRef, uint64_t> FuncOffsetTable;
255 // Whether to use MD5 to represent string.
256 bool UseMD5 = false;
257
258 ProfileSymbolList *ProfSymList = nullptr;
259};
260
261class SampleProfileWriterExtBinary : public SampleProfileWriterExtBinaryBase {
262public:
263 SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS)
264 : SampleProfileWriterExtBinaryBase(OS) {
265 initSectionHdrLayout();
266 }
267
268private:
269 virtual void initSectionHdrLayout() override {
270 // Note that SecFuncOffsetTable section is written after SecLBRProfile
271 // in the profile, but is put before SecLBRProfile in SectionHdrLayout.
272 //
273 // This is because sample reader follows the order of SectionHdrLayout to
274 // read each section, to read function profiles on demand sample reader
275 // need to get the offset of each function profile first.
276 //
277 // SecFuncOffsetTable section is written after SecLBRProfile in the
278 // profile because FuncOffsetTable needs to be populated while section
279 // SecLBRProfile is written.
280 SectionHdrLayout = {
281 {SecProfSummary, 0, 0, 0, 0}, {SecNameTable, 0, 0, 0, 0},
282 {SecFuncOffsetTable, 0, 0, 0, 0}, {SecLBRProfile, 0, 0, 0, 0},
283 {SecProfileSymbolList, 0, 0, 0, 0}, {SecFuncMetadata, 0, 0, 0, 0}};
284 };
285 virtual std::error_code
286 writeSections(const StringMap<FunctionSamples> &ProfileMap) override;
287
288 virtual std::error_code writeCustomSection(SecType Type) override {
289 return sampleprof_error::success;
290 };
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100291};
292
Andrew Scull0372a572018-11-16 15:47:06 +0000293// CompactBinary is a compact format of binary profile which both reduces
294// the profile size and the load time needed when compiling. It has two
295// major difference with Binary format.
296// 1. It represents all the strings in name table using md5 hash.
297// 2. It saves a function offset table which maps function name index to
298// the offset of its function profile to the start of the binary profile,
299// so by using the function offset table, for those function profiles which
300// will not be needed when compiling a module, the profile reader does't
301// have to read them and it saves compile time if the profile size is huge.
302// The layout of the compact format is shown as follows:
303//
304// Part1: Profile header, the same as binary format, containing magic
305// number, version, summary, name table...
306// Part2: Function Offset Table Offset, which saves the position of
307// Part4.
308// Part3: Function profile collection
309// function1 profile start
310// ....
311// function2 profile start
312// ....
313// function3 profile start
314// ....
315// ......
316// Part4: Function Offset Table
317// function1 name index --> function1 profile start
318// function2 name index --> function2 profile start
319// function3 name index --> function3 profile start
320//
321// We need Part2 because profile reader can use it to find out and read
322// function offset table without reading Part3 first.
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100323class SampleProfileWriterCompactBinary : public SampleProfileWriterBinary {
324 using SampleProfileWriterBinary::SampleProfileWriterBinary;
325
Andrew Scull0372a572018-11-16 15:47:06 +0000326public:
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200327 virtual std::error_code writeSample(const FunctionSamples &S) override;
Andrew Scull0372a572018-11-16 15:47:06 +0000328 virtual std::error_code
329 write(const StringMap<FunctionSamples> &ProfileMap) override;
330
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100331protected:
Andrew Scull0372a572018-11-16 15:47:06 +0000332 /// The table mapping from function name to the offset of its FunctionSample
333 /// towards profile start.
334 MapVector<StringRef, uint64_t> FuncOffsetTable;
335 /// The offset of the slot to be filled with the offset of FuncOffsetTable
336 /// towards profile start.
337 uint64_t TableOffset;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100338 virtual std::error_code writeNameTable() override;
Andrew Scull0372a572018-11-16 15:47:06 +0000339 virtual std::error_code
340 writeHeader(const StringMap<FunctionSamples> &ProfileMap) override;
341 std::error_code writeFuncOffsetTable();
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100342};
343
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100344} // end namespace sampleprof
345} // end namespace llvm
346
347#endif // LLVM_PROFILEDATA_SAMPLEPROFWRITER_H