1c572e92cSDiego Novillo //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
2c572e92cSDiego Novillo //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c572e92cSDiego Novillo //
7c572e92cSDiego Novillo //===----------------------------------------------------------------------===//
8c572e92cSDiego Novillo //
9c572e92cSDiego Novillo // This file implements the class that writes LLVM sample profiles. It
10c572e92cSDiego Novillo // supports two file formats: text and binary. The textual representation
11c572e92cSDiego Novillo // is useful for debugging and testing purposes. The binary representation
12c572e92cSDiego Novillo // is more compact, resulting in smaller file sizes. However, they can
13c572e92cSDiego Novillo // both be used interchangeably.
14c572e92cSDiego Novillo //
15c572e92cSDiego Novillo // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
16c572e92cSDiego Novillo // supported formats.
17c572e92cSDiego Novillo //
18c572e92cSDiego Novillo //===----------------------------------------------------------------------===//
19c572e92cSDiego Novillo
206bda14b3SChandler Carruth #include "llvm/ProfileData/SampleProfWriter.h"
21e78d131aSEugene Zelenko #include "llvm/ADT/StringRef.h"
22e78d131aSEugene Zelenko #include "llvm/ProfileData/ProfileCommon.h"
23e78d131aSEugene Zelenko #include "llvm/ProfileData/SampleProf.h"
24b523790aSWei Mi #include "llvm/Support/Compression.h"
256a14325dSWei Mi #include "llvm/Support/Endian.h"
266a14325dSWei Mi #include "llvm/Support/EndianStream.h"
27c572e92cSDiego Novillo #include "llvm/Support/ErrorOr.h"
28e78d131aSEugene Zelenko #include "llvm/Support/FileSystem.h"
29c572e92cSDiego Novillo #include "llvm/Support/LEB128.h"
30a0c0857eSWei Mi #include "llvm/Support/MD5.h"
31e78d131aSEugene Zelenko #include "llvm/Support/raw_ostream.h"
32e78d131aSEugene Zelenko #include <algorithm>
33e78d131aSEugene Zelenko #include <cstdint>
34e78d131aSEugene Zelenko #include <memory>
358d1c983fSDehao Chen #include <set>
36e78d131aSEugene Zelenko #include <system_error>
37e78d131aSEugene Zelenko #include <utility>
38e78d131aSEugene Zelenko #include <vector>
39c572e92cSDiego Novillo
40c572e92cSDiego Novillo using namespace llvm;
41e78d131aSEugene Zelenko using namespace sampleprof;
42c572e92cSDiego Novillo
43b9db7036SHongtao Yu std::error_code
writeFuncProfiles(const SampleProfileMap & ProfileMap)44b9db7036SHongtao Yu SampleProfileWriter::writeFuncProfiles(const SampleProfileMap &ProfileMap) {
458d1c983fSDehao Chen std::vector<NameFunctionSamples> V;
46f27fee62SHongtao Yu sortFuncProfiles(ProfileMap, V);
478d1c983fSDehao Chen for (const auto &I : V) {
48be907324SWei Mi if (std::error_code EC = writeSample(*I.second))
498d1c983fSDehao Chen return EC;
508d1c983fSDehao Chen }
518d1c983fSDehao Chen return sampleprof_error::success;
528d1c983fSDehao Chen }
538d1c983fSDehao Chen
write(const SampleProfileMap & ProfileMap)54b9db7036SHongtao Yu std::error_code SampleProfileWriter::write(const SampleProfileMap &ProfileMap) {
55be907324SWei Mi if (std::error_code EC = writeHeader(ProfileMap))
56be907324SWei Mi return EC;
57be907324SWei Mi
58be907324SWei Mi if (std::error_code EC = writeFuncProfiles(ProfileMap))
59be907324SWei Mi return EC;
60be907324SWei Mi
61be907324SWei Mi return sampleprof_error::success;
62be907324SWei Mi }
63be907324SWei Mi
64b523790aSWei Mi /// Return the current position and prepare to use it as the start
65a906e3ecSWei Mi /// position of a section given the section type \p Type and its position
66a906e3ecSWei Mi /// \p LayoutIdx in SectionHdrLayout.
67a906e3ecSWei Mi uint64_t
markSectionStart(SecType Type,uint32_t LayoutIdx)68a906e3ecSWei Mi SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type,
69a906e3ecSWei Mi uint32_t LayoutIdx) {
70b523790aSWei Mi uint64_t SectionStart = OutputStream->tell();
71a906e3ecSWei Mi assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
72a906e3ecSWei Mi const auto &Entry = SectionHdrLayout[LayoutIdx];
73a906e3ecSWei Mi assert(Entry.Type == Type && "Unexpected section type");
74b523790aSWei Mi // Use LocalBuf as a temporary output for writting data.
75ebad6788SWei Mi if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
76b523790aSWei Mi LocalBufStream.swap(OutputStream);
77b523790aSWei Mi return SectionStart;
78b523790aSWei Mi }
79b523790aSWei Mi
compressAndOutput()80b523790aSWei Mi std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
81ea61750cSCole Kissane if (!llvm::compression::zlib::isAvailable())
82b523790aSWei Mi return sampleprof_error::zlib_unavailable;
83b523790aSWei Mi std::string &UncompressedStrings =
84b523790aSWei Mi static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
85b523790aSWei Mi if (UncompressedStrings.size() == 0)
86b523790aSWei Mi return sampleprof_error::success;
87b523790aSWei Mi auto &OS = *OutputStream;
88*e690137dSFangrui Song SmallVector<uint8_t, 128> CompressedStrings;
89*e690137dSFangrui Song compression::zlib::compress(arrayRefFromStringRef(UncompressedStrings),
90*e690137dSFangrui Song CompressedStrings,
91ea61750cSCole Kissane compression::zlib::BestSizeCompression);
92b523790aSWei Mi encodeULEB128(UncompressedStrings.size(), OS);
93b523790aSWei Mi encodeULEB128(CompressedStrings.size(), OS);
94*e690137dSFangrui Song OS << toStringRef(CompressedStrings);
95b523790aSWei Mi UncompressedStrings.clear();
96b523790aSWei Mi return sampleprof_error::success;
97b523790aSWei Mi }
98b523790aSWei Mi
99a906e3ecSWei Mi /// Add a new section into section header table given the section type
100a906e3ecSWei Mi /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the
101a906e3ecSWei Mi /// location \p SectionStart where the section should be written to.
addNewSection(SecType Type,uint32_t LayoutIdx,uint64_t SectionStart)102a906e3ecSWei Mi std::error_code SampleProfileWriterExtBinaryBase::addNewSection(
103a906e3ecSWei Mi SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) {
104a906e3ecSWei Mi assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
105a906e3ecSWei Mi const auto &Entry = SectionHdrLayout[LayoutIdx];
106a906e3ecSWei Mi assert(Entry.Type == Type && "Unexpected section type");
107ebad6788SWei Mi if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) {
108b523790aSWei Mi LocalBufStream.swap(OutputStream);
109b523790aSWei Mi if (std::error_code EC = compressAndOutput())
110b523790aSWei Mi return EC;
111b523790aSWei Mi }
112b523790aSWei Mi SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
113a906e3ecSWei Mi OutputStream->tell() - SectionStart, LayoutIdx});
114b523790aSWei Mi return sampleprof_error::success;
115be907324SWei Mi }
116be907324SWei Mi
117b9db7036SHongtao Yu std::error_code
write(const SampleProfileMap & ProfileMap)118b9db7036SHongtao Yu SampleProfileWriterExtBinaryBase::write(const SampleProfileMap &ProfileMap) {
119be907324SWei Mi if (std::error_code EC = writeHeader(ProfileMap))
120be907324SWei Mi return EC;
121be907324SWei Mi
122b523790aSWei Mi std::string LocalBuf;
123b523790aSWei Mi LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
124be907324SWei Mi if (std::error_code EC = writeSections(ProfileMap))
125be907324SWei Mi return EC;
126be907324SWei Mi
127be907324SWei Mi if (std::error_code EC = writeSecHdrTable())
128be907324SWei Mi return EC;
129be907324SWei Mi
130be907324SWei Mi return sampleprof_error::success;
131be907324SWei Mi }
132be907324SWei Mi
writeContextIdx(const SampleContext & Context)133b9db7036SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeContextIdx(
134b9db7036SHongtao Yu const SampleContext &Context) {
135b9db7036SHongtao Yu if (Context.hasContext())
136b9db7036SHongtao Yu return writeCSNameIdx(Context);
137b9db7036SHongtao Yu else
138b9db7036SHongtao Yu return SampleProfileWriterBinary::writeNameIdx(Context.getName());
139b9db7036SHongtao Yu }
140b9db7036SHongtao Yu
141b9db7036SHongtao Yu std::error_code
writeCSNameIdx(const SampleContext & Context)142b9db7036SHongtao Yu SampleProfileWriterExtBinaryBase::writeCSNameIdx(const SampleContext &Context) {
143b9db7036SHongtao Yu const auto &Ret = CSNameTable.find(Context);
144b9db7036SHongtao Yu if (Ret == CSNameTable.end())
145b9db7036SHongtao Yu return sampleprof_error::truncated_name_table;
146b9db7036SHongtao Yu encodeULEB128(Ret->second, *OutputStream);
147b9db7036SHongtao Yu return sampleprof_error::success;
148b9db7036SHongtao Yu }
149b9db7036SHongtao Yu
15009dcfe68SWei Mi std::error_code
writeSample(const FunctionSamples & S)15193953d41SWei Mi SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) {
15209dcfe68SWei Mi uint64_t Offset = OutputStream->tell();
153b9db7036SHongtao Yu auto &Context = S.getContext();
154b9db7036SHongtao Yu FuncOffsetTable[Context] = Offset - SecLBRProfileStart;
15509dcfe68SWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream);
15609dcfe68SWei Mi return writeBody(S);
15709dcfe68SWei Mi }
15809dcfe68SWei Mi
writeFuncOffsetTable()15993953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() {
16009dcfe68SWei Mi auto &OS = *OutputStream;
16109dcfe68SWei Mi
16209dcfe68SWei Mi // Write out the table size.
16309dcfe68SWei Mi encodeULEB128(FuncOffsetTable.size(), OS);
16409dcfe68SWei Mi
16509dcfe68SWei Mi // Write out FuncOffsetTable.
166f4711e0dSHongtao Yu auto WriteItem = [&](const SampleContext &Context, uint64_t Offset) {
167f4711e0dSHongtao Yu if (std::error_code EC = writeContextIdx(Context))
16800ef28efSWenlei He return EC;
169f4711e0dSHongtao Yu encodeULEB128(Offset, OS);
170f4711e0dSHongtao Yu return (std::error_code)sampleprof_error::success;
171f4711e0dSHongtao Yu };
172f4711e0dSHongtao Yu
173e36786d1SHongtao Yu if (FunctionSamples::ProfileIsCS) {
174f4711e0dSHongtao Yu // Sort the contexts before writing them out. This is to help fast load all
175f4711e0dSHongtao Yu // context profiles for a function as well as their callee contexts which
176f4711e0dSHongtao Yu // can help profile-guided importing for ThinLTO.
177f4711e0dSHongtao Yu std::map<SampleContext, uint64_t> OrderedFuncOffsetTable(
178f4711e0dSHongtao Yu FuncOffsetTable.begin(), FuncOffsetTable.end());
179f4711e0dSHongtao Yu for (const auto &Entry : OrderedFuncOffsetTable) {
180f4711e0dSHongtao Yu if (std::error_code EC = WriteItem(Entry.first, Entry.second))
181f4711e0dSHongtao Yu return EC;
18209dcfe68SWei Mi }
183f4711e0dSHongtao Yu addSectionFlag(SecFuncOffsetTable, SecFuncOffsetFlags::SecFlagOrdered);
184f4711e0dSHongtao Yu } else {
185f4711e0dSHongtao Yu for (const auto &Entry : FuncOffsetTable) {
186f4711e0dSHongtao Yu if (std::error_code EC = WriteItem(Entry.first, Entry.second))
187f4711e0dSHongtao Yu return EC;
188f4711e0dSHongtao Yu }
189f4711e0dSHongtao Yu }
190f4711e0dSHongtao Yu
191a906e3ecSWei Mi FuncOffsetTable.clear();
19209dcfe68SWei Mi return sampleprof_error::success;
19309dcfe68SWei Mi }
19409dcfe68SWei Mi
writeFuncMetadata(const FunctionSamples & FunctionProfile)195ac068e01SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
1965740bb80SHongtao Yu const FunctionSamples &FunctionProfile) {
197ac068e01SHongtao Yu auto &OS = *OutputStream;
1985740bb80SHongtao Yu if (std::error_code EC = writeContextIdx(FunctionProfile.getContext()))
19900ef28efSWenlei He return EC;
2005740bb80SHongtao Yu
2011410db70SWenlei He if (FunctionSamples::ProfileIsProbeBased)
2025740bb80SHongtao Yu encodeULEB128(FunctionProfile.getFunctionHash(), OS);
203e36786d1SHongtao Yu if (FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsPreInlined) {
2045740bb80SHongtao Yu encodeULEB128(FunctionProfile.getContext().getAllAttributes(), OS);
2055740bb80SHongtao Yu }
2065740bb80SHongtao Yu
207e36786d1SHongtao Yu if (!FunctionSamples::ProfileIsCS) {
2085740bb80SHongtao Yu // Recursively emit attributes for all callee samples.
2095740bb80SHongtao Yu uint64_t NumCallsites = 0;
2105740bb80SHongtao Yu for (const auto &J : FunctionProfile.getCallsiteSamples())
2115740bb80SHongtao Yu NumCallsites += J.second.size();
2125740bb80SHongtao Yu encodeULEB128(NumCallsites, OS);
2135740bb80SHongtao Yu for (const auto &J : FunctionProfile.getCallsiteSamples()) {
2145740bb80SHongtao Yu for (const auto &FS : J.second) {
2155740bb80SHongtao Yu LineLocation Loc = J.first;
2165740bb80SHongtao Yu encodeULEB128(Loc.LineOffset, OS);
2175740bb80SHongtao Yu encodeULEB128(Loc.Discriminator, OS);
2185740bb80SHongtao Yu if (std::error_code EC = writeFuncMetadata(FS.second))
2195740bb80SHongtao Yu return EC;
2205740bb80SHongtao Yu }
2215740bb80SHongtao Yu }
2225740bb80SHongtao Yu }
2235740bb80SHongtao Yu
2245740bb80SHongtao Yu return sampleprof_error::success;
2255740bb80SHongtao Yu }
2265740bb80SHongtao Yu
writeFuncMetadata(const SampleProfileMap & Profiles)2275740bb80SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
2285740bb80SHongtao Yu const SampleProfileMap &Profiles) {
229e36786d1SHongtao Yu if (!FunctionSamples::ProfileIsProbeBased && !FunctionSamples::ProfileIsCS &&
230e36786d1SHongtao Yu !FunctionSamples::ProfileIsPreInlined)
2315740bb80SHongtao Yu return sampleprof_error::success;
2325740bb80SHongtao Yu for (const auto &Entry : Profiles) {
2335740bb80SHongtao Yu if (std::error_code EC = writeFuncMetadata(Entry.second))
2345740bb80SHongtao Yu return EC;
235ac068e01SHongtao Yu }
236ac068e01SHongtao Yu return sampleprof_error::success;
237ac068e01SHongtao Yu }
238ac068e01SHongtao Yu
writeNameTable()23993953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() {
240ebad6788SWei Mi if (!UseMD5)
241ebad6788SWei Mi return SampleProfileWriterBinary::writeNameTable();
242ebad6788SWei Mi
243ebad6788SWei Mi auto &OS = *OutputStream;
244ebad6788SWei Mi std::set<StringRef> V;
245b9db7036SHongtao Yu stablizeNameTable(NameTable, V);
246ebad6788SWei Mi
24764e76853SWei Mi // Write out the MD5 name table. We wrote unencoded MD5 so reader can
24864e76853SWei Mi // retrieve the name using the name index without having to read the
24964e76853SWei Mi // whole name table.
250ebad6788SWei Mi encodeULEB128(NameTable.size(), OS);
25164e76853SWei Mi support::endian::Writer Writer(OS, support::little);
25264e76853SWei Mi for (auto N : V)
25364e76853SWei Mi Writer.write(MD5Hash(N));
254ebad6788SWei Mi return sampleprof_error::success;
255ebad6788SWei Mi }
256ebad6788SWei Mi
writeNameTableSection(const SampleProfileMap & ProfileMap)25793953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection(
258b9db7036SHongtao Yu const SampleProfileMap &ProfileMap) {
259be907324SWei Mi for (const auto &I : ProfileMap) {
260b9db7036SHongtao Yu assert(I.first == I.second.getContext() && "Inconsistent profile map");
261b9db7036SHongtao Yu addContext(I.second.getContext());
262be907324SWei Mi addNames(I.second);
263be907324SWei Mi }
264ee35784aSWei Mi
265ee35784aSWei Mi // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag
266ee35784aSWei Mi // so compiler won't strip the suffix during profile matching after
267ee35784aSWei Mi // seeing the flag in the profile.
268ee35784aSWei Mi for (const auto &I : NameTable) {
269d14d7068SKazu Hirata if (I.first.contains(FunctionSamples::UniqSuffix)) {
270ee35784aSWei Mi addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix);
271ee35784aSWei Mi break;
272ee35784aSWei Mi }
273ee35784aSWei Mi }
274ee35784aSWei Mi
27593953d41SWei Mi if (auto EC = writeNameTable())
276b523790aSWei Mi return EC;
27793953d41SWei Mi return sampleprof_error::success;
27893953d41SWei Mi }
279be907324SWei Mi
writeCSNameTableSection()280b9db7036SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeCSNameTableSection() {
281b9db7036SHongtao Yu // Sort the names to make CSNameTable deterministic.
282b9db7036SHongtao Yu std::set<SampleContext> OrderedContexts;
283b9db7036SHongtao Yu for (const auto &I : CSNameTable)
284b9db7036SHongtao Yu OrderedContexts.insert(I.first);
285b9db7036SHongtao Yu assert(OrderedContexts.size() == CSNameTable.size() &&
286b9db7036SHongtao Yu "Unmatched ordered and unordered contexts");
287b9db7036SHongtao Yu uint64_t I = 0;
288b9db7036SHongtao Yu for (auto &Context : OrderedContexts)
289b9db7036SHongtao Yu CSNameTable[Context] = I++;
290b9db7036SHongtao Yu
291b9db7036SHongtao Yu auto &OS = *OutputStream;
292b9db7036SHongtao Yu encodeULEB128(OrderedContexts.size(), OS);
293b9db7036SHongtao Yu support::endian::Writer Writer(OS, support::little);
294b9db7036SHongtao Yu for (auto Context : OrderedContexts) {
295b9db7036SHongtao Yu auto Frames = Context.getContextFrames();
296b9db7036SHongtao Yu encodeULEB128(Frames.size(), OS);
297b9db7036SHongtao Yu for (auto &Callsite : Frames) {
298fb29d812Swlei if (std::error_code EC = writeNameIdx(Callsite.FuncName))
299b9db7036SHongtao Yu return EC;
300fb29d812Swlei encodeULEB128(Callsite.Location.LineOffset, OS);
301fb29d812Swlei encodeULEB128(Callsite.Location.Discriminator, OS);
302b9db7036SHongtao Yu }
303b9db7036SHongtao Yu }
304b9db7036SHongtao Yu
305b9db7036SHongtao Yu return sampleprof_error::success;
306b9db7036SHongtao Yu }
307b9db7036SHongtao Yu
30893953d41SWei Mi std::error_code
writeProfileSymbolListSection()30993953d41SWei Mi SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() {
310798e59b8SWei Mi if (ProfSymList && ProfSymList->size() > 0)
311798e59b8SWei Mi if (std::error_code EC = ProfSymList->write(*OutputStream))
312798e59b8SWei Mi return EC;
313be907324SWei Mi
31493953d41SWei Mi return sampleprof_error::success;
31593953d41SWei Mi }
31609dcfe68SWei Mi
writeOneSection(SecType Type,uint32_t LayoutIdx,const SampleProfileMap & ProfileMap)31793953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
318b9db7036SHongtao Yu SecType Type, uint32_t LayoutIdx, const SampleProfileMap &ProfileMap) {
31993953d41SWei Mi // The setting of SecFlagCompress should happen before markSectionStart.
32093953d41SWei Mi if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress())
32193953d41SWei Mi setToCompressSection(SecProfileSymbolList);
322ac068e01SHongtao Yu if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased)
323ac068e01SHongtao Yu addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased);
3245740bb80SHongtao Yu if (Type == SecFuncMetadata &&
325e36786d1SHongtao Yu (FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsPreInlined))
3261410db70SWenlei He addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagHasAttribute);
327e36786d1SHongtao Yu if (Type == SecProfSummary && FunctionSamples::ProfileIsCS)
3285740bb80SHongtao Yu addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext);
329e36786d1SHongtao Yu if (Type == SecProfSummary && FunctionSamples::ProfileIsPreInlined)
330e36786d1SHongtao Yu addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagIsPreInlined);
3316745ffe4SRong Xu if (Type == SecProfSummary && FunctionSamples::ProfileIsFS)
3326745ffe4SRong Xu addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFSDiscriminator);
33393953d41SWei Mi
334a906e3ecSWei Mi uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
33593953d41SWei Mi switch (Type) {
33693953d41SWei Mi case SecProfSummary:
33793953d41SWei Mi computeSummary(ProfileMap);
33893953d41SWei Mi if (auto EC = writeSummary())
33993953d41SWei Mi return EC;
34093953d41SWei Mi break;
34193953d41SWei Mi case SecNameTable:
34293953d41SWei Mi if (auto EC = writeNameTableSection(ProfileMap))
34393953d41SWei Mi return EC;
34493953d41SWei Mi break;
345b9db7036SHongtao Yu case SecCSNameTable:
346b9db7036SHongtao Yu if (auto EC = writeCSNameTableSection())
347b9db7036SHongtao Yu return EC;
348b9db7036SHongtao Yu break;
34993953d41SWei Mi case SecLBRProfile:
35093953d41SWei Mi SecLBRProfileStart = OutputStream->tell();
35193953d41SWei Mi if (std::error_code EC = writeFuncProfiles(ProfileMap))
35293953d41SWei Mi return EC;
35393953d41SWei Mi break;
35493953d41SWei Mi case SecFuncOffsetTable:
35593953d41SWei Mi if (auto EC = writeFuncOffsetTable())
35693953d41SWei Mi return EC;
35793953d41SWei Mi break;
358ac068e01SHongtao Yu case SecFuncMetadata:
359ac068e01SHongtao Yu if (std::error_code EC = writeFuncMetadata(ProfileMap))
360ac068e01SHongtao Yu return EC;
361ac068e01SHongtao Yu break;
36293953d41SWei Mi case SecProfileSymbolList:
36393953d41SWei Mi if (auto EC = writeProfileSymbolListSection())
36493953d41SWei Mi return EC;
36593953d41SWei Mi break;
36693953d41SWei Mi default:
36793953d41SWei Mi if (auto EC = writeCustomSection(Type))
36893953d41SWei Mi return EC;
36993953d41SWei Mi break;
37093953d41SWei Mi }
371a906e3ecSWei Mi if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart))
37293953d41SWei Mi return EC;
37393953d41SWei Mi return sampleprof_error::success;
37493953d41SWei Mi }
37593953d41SWei Mi
writeDefaultLayout(const SampleProfileMap & ProfileMap)37621b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
377b9db7036SHongtao Yu const SampleProfileMap &ProfileMap) {
378a906e3ecSWei Mi // The const indices passed to writeOneSection below are specifying the
379a906e3ecSWei Mi // positions of the sections in SectionHdrLayout. Look at
380a906e3ecSWei Mi // initSectionHdrLayout to find out where each section is located in
381a906e3ecSWei Mi // SectionHdrLayout.
382a906e3ecSWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
38393953d41SWei Mi return EC;
384a906e3ecSWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
38593953d41SWei Mi return EC;
386b9db7036SHongtao Yu if (auto EC = writeOneSection(SecCSNameTable, 2, ProfileMap))
38793953d41SWei Mi return EC;
388b9db7036SHongtao Yu if (auto EC = writeOneSection(SecLBRProfile, 4, ProfileMap))
38993953d41SWei Mi return EC;
390b9db7036SHongtao Yu if (auto EC = writeOneSection(SecProfileSymbolList, 5, ProfileMap))
39193953d41SWei Mi return EC;
392b9db7036SHongtao Yu if (auto EC = writeOneSection(SecFuncOffsetTable, 3, ProfileMap))
393b9db7036SHongtao Yu return EC;
394b9db7036SHongtao Yu if (auto EC = writeOneSection(SecFuncMetadata, 6, ProfileMap))
395ac068e01SHongtao Yu return EC;
396be907324SWei Mi return sampleprof_error::success;
397be907324SWei Mi }
398be907324SWei Mi
splitProfileMapToTwo(const SampleProfileMap & ProfileMap,SampleProfileMap & ContextProfileMap,SampleProfileMap & NoContextProfileMap)399b9db7036SHongtao Yu static void splitProfileMapToTwo(const SampleProfileMap &ProfileMap,
400b9db7036SHongtao Yu SampleProfileMap &ContextProfileMap,
401b9db7036SHongtao Yu SampleProfileMap &NoContextProfileMap) {
40221b1ad03SWei Mi for (const auto &I : ProfileMap) {
40321b1ad03SWei Mi if (I.second.getCallsiteSamples().size())
404b9db7036SHongtao Yu ContextProfileMap.insert({I.first, I.second});
40521b1ad03SWei Mi else
406b9db7036SHongtao Yu NoContextProfileMap.insert({I.first, I.second});
40721b1ad03SWei Mi }
40821b1ad03SWei Mi }
40921b1ad03SWei Mi
writeCtxSplitLayout(const SampleProfileMap & ProfileMap)41021b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
411b9db7036SHongtao Yu const SampleProfileMap &ProfileMap) {
412b9db7036SHongtao Yu SampleProfileMap ContextProfileMap, NoContextProfileMap;
41321b1ad03SWei Mi splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap);
41421b1ad03SWei Mi
41521b1ad03SWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
41621b1ad03SWei Mi return EC;
41721b1ad03SWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
41821b1ad03SWei Mi return EC;
41921b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap))
42021b1ad03SWei Mi return EC;
42121b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap))
42221b1ad03SWei Mi return EC;
42321b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set
42421b1ad03SWei Mi // before writing the section.
42521b1ad03SWei Mi addSectionFlag(5, SecCommonFlags::SecFlagFlat);
42621b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap))
42721b1ad03SWei Mi return EC;
42821b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set
42921b1ad03SWei Mi // before writing the section.
43021b1ad03SWei Mi addSectionFlag(4, SecCommonFlags::SecFlagFlat);
43121b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap))
43221b1ad03SWei Mi return EC;
43321b1ad03SWei Mi if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap))
43421b1ad03SWei Mi return EC;
43521b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap))
43621b1ad03SWei Mi return EC;
43721b1ad03SWei Mi
43821b1ad03SWei Mi return sampleprof_error::success;
43921b1ad03SWei Mi }
44021b1ad03SWei Mi
writeSections(const SampleProfileMap & ProfileMap)44121b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeSections(
442b9db7036SHongtao Yu const SampleProfileMap &ProfileMap) {
44321b1ad03SWei Mi std::error_code EC;
44421b1ad03SWei Mi if (SecLayout == DefaultLayout)
44521b1ad03SWei Mi EC = writeDefaultLayout(ProfileMap);
44621b1ad03SWei Mi else if (SecLayout == CtxSplitLayout)
44721b1ad03SWei Mi EC = writeCtxSplitLayout(ProfileMap);
44821b1ad03SWei Mi else
44921b1ad03SWei Mi llvm_unreachable("Unsupported layout");
45021b1ad03SWei Mi return EC;
45121b1ad03SWei Mi }
45221b1ad03SWei Mi
453b9db7036SHongtao Yu std::error_code
write(const SampleProfileMap & ProfileMap)454b9db7036SHongtao Yu SampleProfileWriterCompactBinary::write(const SampleProfileMap &ProfileMap) {
4556a14325dSWei Mi if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
4566a14325dSWei Mi return EC;
4576a14325dSWei Mi if (std::error_code EC = writeFuncOffsetTable())
4586a14325dSWei Mi return EC;
4596a14325dSWei Mi return sampleprof_error::success;
4606a14325dSWei Mi }
4616a14325dSWei Mi
4625f8f34e4SAdrian Prantl /// Write samples to a text file.
4638e415a82SDiego Novillo ///
4648e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of
465ef548d29SDiego Novillo /// FunctionSamples::print(). Please don't. The dump functionality is intended
4668e415a82SDiego Novillo /// for debugging and has no specified form.
4678e415a82SDiego Novillo ///
4688e415a82SDiego Novillo /// The format used here is more structured and deliberate because
4698e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class.
writeSample(const FunctionSamples & S)470be907324SWei Mi std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
47151abea74SNathan Slingerland auto &OS = *OutputStream;
472e36786d1SHongtao Yu if (FunctionSamples::ProfileIsCS)
473b9db7036SHongtao Yu OS << "[" << S.getContext().toString() << "]:" << S.getTotalSamples();
47400ef28efSWenlei He else
47500ef28efSWenlei He OS << S.getName() << ":" << S.getTotalSamples();
47600ef28efSWenlei He
477aae1ed8eSDiego Novillo if (Indent == 0)
478aae1ed8eSDiego Novillo OS << ":" << S.getHeadSamples();
479aae1ed8eSDiego Novillo OS << "\n";
480c572e92cSDiego Novillo
481ef548d29SDiego Novillo SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
482ef548d29SDiego Novillo for (const auto &I : SortedSamples.get()) {
483ef548d29SDiego Novillo LineLocation Loc = I->first;
484ef548d29SDiego Novillo const SampleRecord &Sample = I->second;
485aae1ed8eSDiego Novillo OS.indent(Indent + 1);
486c572e92cSDiego Novillo if (Loc.Discriminator == 0)
487c572e92cSDiego Novillo OS << Loc.LineOffset << ": ";
488c572e92cSDiego Novillo else
489c572e92cSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
490c572e92cSDiego Novillo
491c572e92cSDiego Novillo OS << Sample.getSamples();
492c572e92cSDiego Novillo
4935adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets())
4945adace35SWenlei He OS << " " << J.first << ":" << J.second;
495c572e92cSDiego Novillo OS << "\n";
496c572e92cSDiego Novillo }
497c572e92cSDiego Novillo
4982c7ca9b5SDehao Chen SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
499ef548d29SDiego Novillo S.getCallsiteSamples());
500aae1ed8eSDiego Novillo Indent += 1;
5012c7ca9b5SDehao Chen for (const auto &I : SortedCallsiteSamples.get())
5022c7ca9b5SDehao Chen for (const auto &FS : I->second) {
50357d1dda5SDehao Chen LineLocation Loc = I->first;
5042c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second;
505aae1ed8eSDiego Novillo OS.indent(Indent);
506aae1ed8eSDiego Novillo if (Loc.Discriminator == 0)
507aae1ed8eSDiego Novillo OS << Loc.LineOffset << ": ";
508aae1ed8eSDiego Novillo else
509aae1ed8eSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
510be907324SWei Mi if (std::error_code EC = writeSample(CalleeSamples))
511760c5a8fSDiego Novillo return EC;
512aae1ed8eSDiego Novillo }
513aae1ed8eSDiego Novillo Indent -= 1;
514aae1ed8eSDiego Novillo
515ac068e01SHongtao Yu if (FunctionSamples::ProfileIsProbeBased) {
516ac068e01SHongtao Yu OS.indent(Indent + 1);
517ac068e01SHongtao Yu OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
518ac068e01SHongtao Yu }
5195740bb80SHongtao Yu
5205740bb80SHongtao Yu if (S.getContext().getAllAttributes()) {
5211410db70SWenlei He OS.indent(Indent + 1);
5221410db70SWenlei He OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n";
5231410db70SWenlei He }
524ac068e01SHongtao Yu
525760c5a8fSDiego Novillo return sampleprof_error::success;
526c572e92cSDiego Novillo }
527c572e92cSDiego Novillo
528b9db7036SHongtao Yu std::error_code
writeContextIdx(const SampleContext & Context)529b9db7036SHongtao Yu SampleProfileWriterBinary::writeContextIdx(const SampleContext &Context) {
530b9db7036SHongtao Yu assert(!Context.hasContext() && "cs profile is not supported");
531b9db7036SHongtao Yu return writeNameIdx(Context.getName());
53200ef28efSWenlei He }
53300ef28efSWenlei He
writeNameIdx(StringRef FName)534b9db7036SHongtao Yu std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
535b9db7036SHongtao Yu auto &NTable = getNameTable();
536b9db7036SHongtao Yu const auto &Ret = NTable.find(FName);
537b9db7036SHongtao Yu if (Ret == NTable.end())
538760c5a8fSDiego Novillo return sampleprof_error::truncated_name_table;
53900ef28efSWenlei He encodeULEB128(Ret->second, *OutputStream);
540760c5a8fSDiego Novillo return sampleprof_error::success;
541760c5a8fSDiego Novillo }
542c572e92cSDiego Novillo
addName(StringRef FName)543b9db7036SHongtao Yu void SampleProfileWriterBinary::addName(StringRef FName) {
544b9db7036SHongtao Yu auto &NTable = getNameTable();
545b9db7036SHongtao Yu NTable.insert(std::make_pair(FName, 0));
54600ef28efSWenlei He }
547b9db7036SHongtao Yu
addContext(const SampleContext & Context)548b9db7036SHongtao Yu void SampleProfileWriterBinary::addContext(const SampleContext &Context) {
549b9db7036SHongtao Yu addName(Context.getName());
550760c5a8fSDiego Novillo }
551760c5a8fSDiego Novillo
addNames(const FunctionSamples & S)552760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
553760c5a8fSDiego Novillo // Add all the names in indirect call targets.
554760c5a8fSDiego Novillo for (const auto &I : S.getBodySamples()) {
555760c5a8fSDiego Novillo const SampleRecord &Sample = I.second;
556760c5a8fSDiego Novillo for (const auto &J : Sample.getCallTargets())
557760c5a8fSDiego Novillo addName(J.first());
558760c5a8fSDiego Novillo }
559760c5a8fSDiego Novillo
560760c5a8fSDiego Novillo // Recursively add all the names for inlined callsites.
5612c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples())
5622c7ca9b5SDehao Chen for (const auto &FS : J.second) {
5632c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second;
56457d1dda5SDehao Chen addName(CalleeSamples.getName());
565760c5a8fSDiego Novillo addNames(CalleeSamples);
566760c5a8fSDiego Novillo }
567760c5a8fSDiego Novillo }
568760c5a8fSDiego Novillo
addContext(const SampleContext & Context)569b9db7036SHongtao Yu void SampleProfileWriterExtBinaryBase::addContext(
570b9db7036SHongtao Yu const SampleContext &Context) {
571b9db7036SHongtao Yu if (Context.hasContext()) {
572b9db7036SHongtao Yu for (auto &Callsite : Context.getContextFrames())
573fb29d812Swlei SampleProfileWriterBinary::addName(Callsite.FuncName);
574b9db7036SHongtao Yu CSNameTable.insert(std::make_pair(Context, 0));
575b9db7036SHongtao Yu } else {
576b9db7036SHongtao Yu SampleProfileWriterBinary::addName(Context.getName());
577b9db7036SHongtao Yu }
578b9db7036SHongtao Yu }
579b9db7036SHongtao Yu
stablizeNameTable(MapVector<StringRef,uint32_t> & NameTable,std::set<StringRef> & V)580b9db7036SHongtao Yu void SampleProfileWriterBinary::stablizeNameTable(
581b9db7036SHongtao Yu MapVector<StringRef, uint32_t> &NameTable, std::set<StringRef> &V) {
582a0c0857eSWei Mi // Sort the names to make NameTable deterministic.
583a0c0857eSWei Mi for (const auto &I : NameTable)
584a0c0857eSWei Mi V.insert(I.first);
585a0c0857eSWei Mi int i = 0;
586a0c0857eSWei Mi for (const StringRef &N : V)
587a0c0857eSWei Mi NameTable[N] = i++;
588a0c0857eSWei Mi }
58951abea74SNathan Slingerland
writeNameTable()590be907324SWei Mi std::error_code SampleProfileWriterBinary::writeNameTable() {
591a0c0857eSWei Mi auto &OS = *OutputStream;
592a0c0857eSWei Mi std::set<StringRef> V;
593b9db7036SHongtao Yu stablizeNameTable(NameTable, V);
594a0c0857eSWei Mi
595a0c0857eSWei Mi // Write out the name table.
596a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS);
597a0c0857eSWei Mi for (auto N : V) {
598a0c0857eSWei Mi OS << N;
599a0c0857eSWei Mi encodeULEB128(0, OS);
600a0c0857eSWei Mi }
601a0c0857eSWei Mi return sampleprof_error::success;
602a0c0857eSWei Mi }
603a0c0857eSWei Mi
writeFuncOffsetTable()6046a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
6056a14325dSWei Mi auto &OS = *OutputStream;
6066a14325dSWei Mi
6076a14325dSWei Mi // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
6086a14325dSWei Mi auto &OFS = static_cast<raw_fd_ostream &>(OS);
6096a14325dSWei Mi uint64_t FuncOffsetTableStart = OS.tell();
6106a14325dSWei Mi if (OFS.seek(TableOffset) == (uint64_t)-1)
6116a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported;
6126a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little);
6136a14325dSWei Mi Writer.write(FuncOffsetTableStart);
6146a14325dSWei Mi if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
6156a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported;
6166a14325dSWei Mi
6176a14325dSWei Mi // Write out the table size.
6186a14325dSWei Mi encodeULEB128(FuncOffsetTable.size(), OS);
6196a14325dSWei Mi
6206a14325dSWei Mi // Write out FuncOffsetTable.
62100ef28efSWenlei He for (auto Entry : FuncOffsetTable) {
622b9db7036SHongtao Yu if (std::error_code EC = writeNameIdx(Entry.first))
62300ef28efSWenlei He return EC;
62400ef28efSWenlei He encodeULEB128(Entry.second, OS);
6256a14325dSWei Mi }
6266a14325dSWei Mi return sampleprof_error::success;
6276a14325dSWei Mi }
6286a14325dSWei Mi
writeNameTable()629a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
630a0c0857eSWei Mi auto &OS = *OutputStream;
631a0c0857eSWei Mi std::set<StringRef> V;
632b9db7036SHongtao Yu stablizeNameTable(NameTable, V);
633a0c0857eSWei Mi
634a0c0857eSWei Mi // Write out the name table.
635a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS);
636a0c0857eSWei Mi for (auto N : V) {
637a0c0857eSWei Mi encodeULEB128(MD5Hash(N), OS);
638a0c0857eSWei Mi }
639a0c0857eSWei Mi return sampleprof_error::success;
640a0c0857eSWei Mi }
641a0c0857eSWei Mi
642be907324SWei Mi std::error_code
writeMagicIdent(SampleProfileFormat Format)643be907324SWei Mi SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
644a0c0857eSWei Mi auto &OS = *OutputStream;
645760c5a8fSDiego Novillo // Write file magic identifier.
646be907324SWei Mi encodeULEB128(SPMagic(Format), OS);
647a0c0857eSWei Mi encodeULEB128(SPVersion(), OS);
648a0c0857eSWei Mi return sampleprof_error::success;
649a0c0857eSWei Mi }
650a0c0857eSWei Mi
651b9db7036SHongtao Yu std::error_code
writeHeader(const SampleProfileMap & ProfileMap)652b9db7036SHongtao Yu SampleProfileWriterBinary::writeHeader(const SampleProfileMap &ProfileMap) {
653be907324SWei Mi writeMagicIdent(Format);
654760c5a8fSDiego Novillo
65540ee23dbSEaswaran Raman computeSummary(ProfileMap);
65640ee23dbSEaswaran Raman if (auto EC = writeSummary())
65740ee23dbSEaswaran Raman return EC;
65840ee23dbSEaswaran Raman
659760c5a8fSDiego Novillo // Generate the name table for all the functions referenced in the profile.
660760c5a8fSDiego Novillo for (const auto &I : ProfileMap) {
661b9db7036SHongtao Yu assert(I.first == I.second.getContext() && "Inconsistent profile map");
662b9db7036SHongtao Yu addContext(I.first);
663760c5a8fSDiego Novillo addNames(I.second);
664760c5a8fSDiego Novillo }
665760c5a8fSDiego Novillo
666a0c0857eSWei Mi writeNameTable();
667760c5a8fSDiego Novillo return sampleprof_error::success;
668c572e92cSDiego Novillo }
669c572e92cSDiego Novillo
setToCompressAllSections()670b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
67109dcfe68SWei Mi for (auto &Entry : SectionHdrLayout)
672ebad6788SWei Mi addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
673b523790aSWei Mi }
674b523790aSWei Mi
setToCompressSection(SecType Type)675b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
676ebad6788SWei Mi addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
677b523790aSWei Mi }
678b523790aSWei Mi
allocSecHdrTable()679be907324SWei Mi void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
680be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little);
681be907324SWei Mi
68209dcfe68SWei Mi Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
683be907324SWei Mi SecHdrTableOffset = OutputStream->tell();
68409dcfe68SWei Mi for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
685be907324SWei Mi Writer.write(static_cast<uint64_t>(-1));
686be907324SWei Mi Writer.write(static_cast<uint64_t>(-1));
687be907324SWei Mi Writer.write(static_cast<uint64_t>(-1));
688be907324SWei Mi Writer.write(static_cast<uint64_t>(-1));
689be907324SWei Mi }
690be907324SWei Mi }
691be907324SWei Mi
writeSecHdrTable()692be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
693be907324SWei Mi auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
694be907324SWei Mi uint64_t Saved = OutputStream->tell();
695be907324SWei Mi
696be907324SWei Mi // Set OutputStream to the location saved in SecHdrTableOffset.
697be907324SWei Mi if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
698be907324SWei Mi return sampleprof_error::ostream_seek_unsupported;
699be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little);
700be907324SWei Mi
701a906e3ecSWei Mi assert(SecHdrTable.size() == SectionHdrLayout.size() &&
702a906e3ecSWei Mi "SecHdrTable entries doesn't match SectionHdrLayout");
703a906e3ecSWei Mi SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
704a906e3ecSWei Mi for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
705a906e3ecSWei Mi IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
706be907324SWei Mi }
707be907324SWei Mi
70809dcfe68SWei Mi // Write the section header table in the order specified in
709a906e3ecSWei Mi // SectionHdrLayout. SectionHdrLayout specifies the sections
710a906e3ecSWei Mi // order in which profile reader expect to read, so the section
711a906e3ecSWei Mi // header table should be written in the order in SectionHdrLayout.
712a906e3ecSWei Mi // Note that the section order in SecHdrTable may be different
713a906e3ecSWei Mi // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
714a906e3ecSWei Mi // needs to be computed after SecLBRProfile (the order in SecHdrTable),
715a906e3ecSWei Mi // but it needs to be read before SecLBRProfile (the order in
716a906e3ecSWei Mi // SectionHdrLayout). So we use IndexMap above to switch the order.
717a906e3ecSWei Mi for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
718a906e3ecSWei Mi LayoutIdx++) {
719a906e3ecSWei Mi assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
720a906e3ecSWei Mi "Incorrect LayoutIdx in SecHdrTable");
721a906e3ecSWei Mi auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
722a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Type));
723a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Flags));
724a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Offset));
725a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Size));
726be907324SWei Mi }
727be907324SWei Mi
728be907324SWei Mi // Reset OutputStream.
729be907324SWei Mi if (OFS.seek(Saved) == (uint64_t)-1)
730be907324SWei Mi return sampleprof_error::ostream_seek_unsupported;
731be907324SWei Mi
732be907324SWei Mi return sampleprof_error::success;
733be907324SWei Mi }
734be907324SWei Mi
writeHeader(const SampleProfileMap & ProfileMap)735be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
736b9db7036SHongtao Yu const SampleProfileMap &ProfileMap) {
737be907324SWei Mi auto &OS = *OutputStream;
738be907324SWei Mi FileStart = OS.tell();
739be907324SWei Mi writeMagicIdent(Format);
740be907324SWei Mi
741be907324SWei Mi allocSecHdrTable();
742be907324SWei Mi return sampleprof_error::success;
743be907324SWei Mi }
744be907324SWei Mi
writeHeader(const SampleProfileMap & ProfileMap)7456a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader(
746b9db7036SHongtao Yu const SampleProfileMap &ProfileMap) {
7476a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little);
7486a14325dSWei Mi if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
7496a14325dSWei Mi return EC;
7506a14325dSWei Mi
7516a14325dSWei Mi // Reserve a slot for the offset of function offset table. The slot will
7526a14325dSWei Mi // be populated with the offset of FuncOffsetTable later.
7536a14325dSWei Mi TableOffset = OutputStream->tell();
7546a14325dSWei Mi Writer.write(static_cast<uint64_t>(-2));
7556a14325dSWei Mi return sampleprof_error::success;
7566a14325dSWei Mi }
7576a14325dSWei Mi
writeSummary()75840ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() {
75940ee23dbSEaswaran Raman auto &OS = *OutputStream;
7607cefdb81SEaswaran Raman encodeULEB128(Summary->getTotalCount(), OS);
7617cefdb81SEaswaran Raman encodeULEB128(Summary->getMaxCount(), OS);
7626f4903d9SEaswaran Raman encodeULEB128(Summary->getMaxFunctionCount(), OS);
7637cefdb81SEaswaran Raman encodeULEB128(Summary->getNumCounts(), OS);
76440ee23dbSEaswaran Raman encodeULEB128(Summary->getNumFunctions(), OS);
765d6790a0aSMircea Trofin const std::vector<ProfileSummaryEntry> &Entries =
766d6790a0aSMircea Trofin Summary->getDetailedSummary();
76740ee23dbSEaswaran Raman encodeULEB128(Entries.size(), OS);
76840ee23dbSEaswaran Raman for (auto Entry : Entries) {
76940ee23dbSEaswaran Raman encodeULEB128(Entry.Cutoff, OS);
77040ee23dbSEaswaran Raman encodeULEB128(Entry.MinCount, OS);
77140ee23dbSEaswaran Raman encodeULEB128(Entry.NumCounts, OS);
77240ee23dbSEaswaran Raman }
77340ee23dbSEaswaran Raman return sampleprof_error::success;
77440ee23dbSEaswaran Raman }
writeBody(const FunctionSamples & S)77557d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
77651abea74SNathan Slingerland auto &OS = *OutputStream;
777b9db7036SHongtao Yu if (std::error_code EC = writeContextIdx(S.getContext()))
778760c5a8fSDiego Novillo return EC;
779760c5a8fSDiego Novillo
780c572e92cSDiego Novillo encodeULEB128(S.getTotalSamples(), OS);
781a7f1e8efSDiego Novillo
782a7f1e8efSDiego Novillo // Emit all the body samples.
783b93483dbSDiego Novillo encodeULEB128(S.getBodySamples().size(), OS);
784d5336ae2SDiego Novillo for (const auto &I : S.getBodySamples()) {
785d5336ae2SDiego Novillo LineLocation Loc = I.first;
786d5336ae2SDiego Novillo const SampleRecord &Sample = I.second;
787c572e92cSDiego Novillo encodeULEB128(Loc.LineOffset, OS);
788c572e92cSDiego Novillo encodeULEB128(Loc.Discriminator, OS);
789c572e92cSDiego Novillo encodeULEB128(Sample.getSamples(), OS);
790c572e92cSDiego Novillo encodeULEB128(Sample.getCallTargets().size(), OS);
7915adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) {
7925adace35SWenlei He StringRef Callee = J.first;
79338be3330SDiego Novillo uint64_t CalleeSamples = J.second;
794760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(Callee))
795760c5a8fSDiego Novillo return EC;
796c572e92cSDiego Novillo encodeULEB128(CalleeSamples, OS);
797c572e92cSDiego Novillo }
798c572e92cSDiego Novillo }
799c572e92cSDiego Novillo
800a7f1e8efSDiego Novillo // Recursively emit all the callsite samples.
8012c27daf7SDehao Chen uint64_t NumCallsites = 0;
8022c27daf7SDehao Chen for (const auto &J : S.getCallsiteSamples())
8032c27daf7SDehao Chen NumCallsites += J.second.size();
8042c27daf7SDehao Chen encodeULEB128(NumCallsites, OS);
8052c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples())
8062c7ca9b5SDehao Chen for (const auto &FS : J.second) {
80757d1dda5SDehao Chen LineLocation Loc = J.first;
8082c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second;
809a7f1e8efSDiego Novillo encodeULEB128(Loc.LineOffset, OS);
810a7f1e8efSDiego Novillo encodeULEB128(Loc.Discriminator, OS);
81157d1dda5SDehao Chen if (std::error_code EC = writeBody(CalleeSamples))
812760c5a8fSDiego Novillo return EC;
813a7f1e8efSDiego Novillo }
814a7f1e8efSDiego Novillo
815760c5a8fSDiego Novillo return sampleprof_error::success;
816c572e92cSDiego Novillo }
817d5336ae2SDiego Novillo
8185f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file.
819b93483dbSDiego Novillo ///
820b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise.
821be907324SWei Mi std::error_code
writeSample(const FunctionSamples & S)822be907324SWei Mi SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
82351abea74SNathan Slingerland encodeULEB128(S.getHeadSamples(), *OutputStream);
82457d1dda5SDehao Chen return writeBody(S);
825b93483dbSDiego Novillo }
826b93483dbSDiego Novillo
8276a14325dSWei Mi std::error_code
writeSample(const FunctionSamples & S)828be907324SWei Mi SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
8296a14325dSWei Mi uint64_t Offset = OutputStream->tell();
8306a14325dSWei Mi StringRef Name = S.getName();
8316a14325dSWei Mi FuncOffsetTable[Name] = Offset;
8326a14325dSWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream);
8336a14325dSWei Mi return writeBody(S);
8346a14325dSWei Mi }
8356a14325dSWei Mi
8365f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format.
837d5336ae2SDiego Novillo ///
838d5336ae2SDiego Novillo /// \param Filename The file to create.
839d5336ae2SDiego Novillo ///
840d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file.
841d5336ae2SDiego Novillo ///
842d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer.
843fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(StringRef Filename,SampleProfileFormat Format)844fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
845d5336ae2SDiego Novillo std::error_code EC;
84651abea74SNathan Slingerland std::unique_ptr<raw_ostream> OS;
847be907324SWei Mi if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
848be907324SWei Mi Format == SPF_Compact_Binary)
849d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
85051abea74SNathan Slingerland else
85182b3e28eSAbhina Sreeskantharajan OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF));
85251abea74SNathan Slingerland if (EC)
85351abea74SNathan Slingerland return EC;
85451abea74SNathan Slingerland
85551abea74SNathan Slingerland return create(OS, Format);
85651abea74SNathan Slingerland }
85751abea74SNathan Slingerland
8585f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format.
85951abea74SNathan Slingerland ///
86051abea74SNathan Slingerland /// \param OS The output stream to store the profile data to.
86151abea74SNathan Slingerland ///
86251abea74SNathan Slingerland /// \param Format Encoding format for the profile file.
86351abea74SNathan Slingerland ///
86451abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer.
86551abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(std::unique_ptr<raw_ostream> & OS,SampleProfileFormat Format)86651abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
86751abea74SNathan Slingerland SampleProfileFormat Format) {
86851abea74SNathan Slingerland std::error_code EC;
869fcd55607SDiego Novillo std::unique_ptr<SampleProfileWriter> Writer;
870d5336ae2SDiego Novillo
871b2d07937SWenlei He // Currently only Text and Extended Binary format are supported for CSSPGO.
872e36786d1SHongtao Yu if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) &&
873b2d07937SWenlei He (Format == SPF_Binary || Format == SPF_Compact_Binary))
874b2d07937SWenlei He return sampleprof_error::unsupported_writing_format;
875b2d07937SWenlei He
876d9be2c7eSWei Mi if (Format == SPF_Binary)
877a0c0857eSWei Mi Writer.reset(new SampleProfileWriterRawBinary(OS));
878be907324SWei Mi else if (Format == SPF_Ext_Binary)
879be907324SWei Mi Writer.reset(new SampleProfileWriterExtBinary(OS));
880a0c0857eSWei Mi else if (Format == SPF_Compact_Binary)
881a0c0857eSWei Mi Writer.reset(new SampleProfileWriterCompactBinary(OS));
882d5336ae2SDiego Novillo else if (Format == SPF_Text)
88351abea74SNathan Slingerland Writer.reset(new SampleProfileWriterText(OS));
884760c5a8fSDiego Novillo else if (Format == SPF_GCC)
885760c5a8fSDiego Novillo EC = sampleprof_error::unsupported_writing_format;
886d5336ae2SDiego Novillo else
887d5336ae2SDiego Novillo EC = sampleprof_error::unrecognized_format;
888d5336ae2SDiego Novillo
889fcd55607SDiego Novillo if (EC)
890d5336ae2SDiego Novillo return EC;
891fcd55607SDiego Novillo
892be907324SWei Mi Writer->Format = Format;
893c55cf4afSBill Wendling return std::move(Writer);
894d5336ae2SDiego Novillo }
89540ee23dbSEaswaran Raman
computeSummary(const SampleProfileMap & ProfileMap)896b9db7036SHongtao Yu void SampleProfileWriter::computeSummary(const SampleProfileMap &ProfileMap) {
897e5a17e3fSEaswaran Raman SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
898801d9cc7SWenlei He Summary = Builder.computeSummaryForProfiles(ProfileMap);
89940ee23dbSEaswaran Raman }
900