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" 2221b1ad03SWei Mi #include "llvm/ADT/StringSet.h" 23e78d131aSEugene Zelenko #include "llvm/ProfileData/ProfileCommon.h" 24e78d131aSEugene Zelenko #include "llvm/ProfileData/SampleProf.h" 25b523790aSWei Mi #include "llvm/Support/Compression.h" 266a14325dSWei Mi #include "llvm/Support/Endian.h" 276a14325dSWei Mi #include "llvm/Support/EndianStream.h" 28c572e92cSDiego Novillo #include "llvm/Support/ErrorOr.h" 29e78d131aSEugene Zelenko #include "llvm/Support/FileSystem.h" 30c572e92cSDiego Novillo #include "llvm/Support/LEB128.h" 31a0c0857eSWei Mi #include "llvm/Support/MD5.h" 32e78d131aSEugene Zelenko #include "llvm/Support/raw_ostream.h" 33e78d131aSEugene Zelenko #include <algorithm> 34e78d131aSEugene Zelenko #include <cstdint> 35e78d131aSEugene Zelenko #include <memory> 368d1c983fSDehao Chen #include <set> 37e78d131aSEugene Zelenko #include <system_error> 38e78d131aSEugene Zelenko #include <utility> 39e78d131aSEugene Zelenko #include <vector> 40c572e92cSDiego Novillo 41c572e92cSDiego Novillo using namespace llvm; 42e78d131aSEugene Zelenko using namespace sampleprof; 43c572e92cSDiego Novillo 44be907324SWei Mi std::error_code SampleProfileWriter::writeFuncProfiles( 45be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 468d1c983fSDehao Chen // Sort the ProfileMap by total samples. 478d1c983fSDehao Chen typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples; 488d1c983fSDehao Chen std::vector<NameFunctionSamples> V; 49*00ef28efSWenlei He for (const auto &I : ProfileMap) { 50*00ef28efSWenlei He assert(I.getKey() == I.second.getNameWithContext() && 51*00ef28efSWenlei He "Inconsistent profile map"); 52*00ef28efSWenlei He V.push_back(std::make_pair(I.second.getNameWithContext(), &I.second)); 53*00ef28efSWenlei He } 54efd94c56SFangrui Song llvm::stable_sort( 55efd94c56SFangrui Song V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) { 568d1c983fSDehao Chen if (A.second->getTotalSamples() == B.second->getTotalSamples()) 578d1c983fSDehao Chen return A.first > B.first; 588d1c983fSDehao Chen return A.second->getTotalSamples() > B.second->getTotalSamples(); 598d1c983fSDehao Chen }); 608d1c983fSDehao Chen 618d1c983fSDehao Chen for (const auto &I : V) { 62be907324SWei Mi if (std::error_code EC = writeSample(*I.second)) 638d1c983fSDehao Chen return EC; 648d1c983fSDehao Chen } 658d1c983fSDehao Chen return sampleprof_error::success; 668d1c983fSDehao Chen } 678d1c983fSDehao Chen 68be907324SWei Mi std::error_code 69be907324SWei Mi SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) { 70be907324SWei Mi if (std::error_code EC = writeHeader(ProfileMap)) 71be907324SWei Mi return EC; 72be907324SWei Mi 73be907324SWei Mi if (std::error_code EC = writeFuncProfiles(ProfileMap)) 74be907324SWei Mi return EC; 75be907324SWei Mi 76be907324SWei Mi return sampleprof_error::success; 77be907324SWei Mi } 78be907324SWei Mi 79b523790aSWei Mi /// Return the current position and prepare to use it as the start 80a906e3ecSWei Mi /// position of a section given the section type \p Type and its position 81a906e3ecSWei Mi /// \p LayoutIdx in SectionHdrLayout. 82a906e3ecSWei Mi uint64_t 83a906e3ecSWei Mi SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type, 84a906e3ecSWei Mi uint32_t LayoutIdx) { 85b523790aSWei Mi uint64_t SectionStart = OutputStream->tell(); 86a906e3ecSWei Mi assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range"); 87a906e3ecSWei Mi const auto &Entry = SectionHdrLayout[LayoutIdx]; 88a906e3ecSWei Mi assert(Entry.Type == Type && "Unexpected section type"); 89b523790aSWei Mi // Use LocalBuf as a temporary output for writting data. 90ebad6788SWei Mi if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) 91b523790aSWei Mi LocalBufStream.swap(OutputStream); 92b523790aSWei Mi return SectionStart; 93b523790aSWei Mi } 94b523790aSWei Mi 95b523790aSWei Mi std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() { 96b523790aSWei Mi if (!llvm::zlib::isAvailable()) 97b523790aSWei Mi return sampleprof_error::zlib_unavailable; 98b523790aSWei Mi std::string &UncompressedStrings = 99b523790aSWei Mi static_cast<raw_string_ostream *>(LocalBufStream.get())->str(); 100b523790aSWei Mi if (UncompressedStrings.size() == 0) 101b523790aSWei Mi return sampleprof_error::success; 102b523790aSWei Mi auto &OS = *OutputStream; 103b523790aSWei Mi SmallString<128> CompressedStrings; 104b523790aSWei Mi llvm::Error E = zlib::compress(UncompressedStrings, CompressedStrings, 105b523790aSWei Mi zlib::BestSizeCompression); 106b523790aSWei Mi if (E) 107b523790aSWei Mi return sampleprof_error::compress_failed; 108b523790aSWei Mi encodeULEB128(UncompressedStrings.size(), OS); 109b523790aSWei Mi encodeULEB128(CompressedStrings.size(), OS); 110b523790aSWei Mi OS << CompressedStrings.str(); 111b523790aSWei Mi UncompressedStrings.clear(); 112b523790aSWei Mi return sampleprof_error::success; 113b523790aSWei Mi } 114b523790aSWei Mi 115a906e3ecSWei Mi /// Add a new section into section header table given the section type 116a906e3ecSWei Mi /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the 117a906e3ecSWei Mi /// location \p SectionStart where the section should be written to. 118a906e3ecSWei Mi std::error_code SampleProfileWriterExtBinaryBase::addNewSection( 119a906e3ecSWei Mi SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) { 120a906e3ecSWei Mi assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range"); 121a906e3ecSWei Mi const auto &Entry = SectionHdrLayout[LayoutIdx]; 122a906e3ecSWei Mi assert(Entry.Type == Type && "Unexpected section type"); 123ebad6788SWei Mi if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) { 124b523790aSWei Mi LocalBufStream.swap(OutputStream); 125b523790aSWei Mi if (std::error_code EC = compressAndOutput()) 126b523790aSWei Mi return EC; 127b523790aSWei Mi } 128b523790aSWei Mi SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart, 129a906e3ecSWei Mi OutputStream->tell() - SectionStart, LayoutIdx}); 130b523790aSWei Mi return sampleprof_error::success; 131be907324SWei Mi } 132be907324SWei Mi 133be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::write( 134be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 135be907324SWei Mi if (std::error_code EC = writeHeader(ProfileMap)) 136be907324SWei Mi return EC; 137be907324SWei Mi 138b523790aSWei Mi std::string LocalBuf; 139b523790aSWei Mi LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf); 140be907324SWei Mi if (std::error_code EC = writeSections(ProfileMap)) 141be907324SWei Mi return EC; 142be907324SWei Mi 143be907324SWei Mi if (std::error_code EC = writeSecHdrTable()) 144be907324SWei Mi return EC; 145be907324SWei Mi 146be907324SWei Mi return sampleprof_error::success; 147be907324SWei Mi } 148be907324SWei Mi 14909dcfe68SWei Mi std::error_code 15093953d41SWei Mi SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) { 15109dcfe68SWei Mi uint64_t Offset = OutputStream->tell(); 152*00ef28efSWenlei He StringRef Name = S.getNameWithContext(); 15309dcfe68SWei Mi FuncOffsetTable[Name] = Offset - SecLBRProfileStart; 15409dcfe68SWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream); 15509dcfe68SWei Mi return writeBody(S); 15609dcfe68SWei Mi } 15709dcfe68SWei Mi 15893953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() { 15909dcfe68SWei Mi auto &OS = *OutputStream; 16009dcfe68SWei Mi 16109dcfe68SWei Mi // Write out the table size. 16209dcfe68SWei Mi encodeULEB128(FuncOffsetTable.size(), OS); 16309dcfe68SWei Mi 16409dcfe68SWei Mi // Write out FuncOffsetTable. 165*00ef28efSWenlei He for (auto Entry : FuncOffsetTable) { 166*00ef28efSWenlei He if (std::error_code EC = 167*00ef28efSWenlei He writeNameIdx(Entry.first, FunctionSamples::ProfileIsCS)) 168*00ef28efSWenlei He return EC; 169*00ef28efSWenlei He encodeULEB128(Entry.second, OS); 17009dcfe68SWei Mi } 171a906e3ecSWei Mi FuncOffsetTable.clear(); 17209dcfe68SWei Mi return sampleprof_error::success; 17309dcfe68SWei Mi } 17409dcfe68SWei Mi 175ac068e01SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata( 176ac068e01SHongtao Yu const StringMap<FunctionSamples> &Profiles) { 1771410db70SWenlei He if (!FunctionSamples::ProfileIsProbeBased && !FunctionSamples::ProfileIsCS) 178ac068e01SHongtao Yu return sampleprof_error::success; 179ac068e01SHongtao Yu auto &OS = *OutputStream; 180ac068e01SHongtao Yu for (const auto &Entry : Profiles) { 181*00ef28efSWenlei He if (std::error_code EC = writeNameIdx(Entry.second.getNameWithContext(), 182*00ef28efSWenlei He FunctionSamples::ProfileIsCS)) 183*00ef28efSWenlei He return EC; 1841410db70SWenlei He if (FunctionSamples::ProfileIsProbeBased) 185ac068e01SHongtao Yu encodeULEB128(Entry.second.getFunctionHash(), OS); 1861410db70SWenlei He if (FunctionSamples::ProfileIsCS) 1871410db70SWenlei He encodeULEB128(Entry.second.getContext().getAllAttributes(), OS); 188ac068e01SHongtao Yu } 189ac068e01SHongtao Yu return sampleprof_error::success; 190ac068e01SHongtao Yu } 191ac068e01SHongtao Yu 19293953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() { 193ebad6788SWei Mi if (!UseMD5) 194ebad6788SWei Mi return SampleProfileWriterBinary::writeNameTable(); 195ebad6788SWei Mi 196ebad6788SWei Mi auto &OS = *OutputStream; 197ebad6788SWei Mi std::set<StringRef> V; 198ebad6788SWei Mi stablizeNameTable(V); 199ebad6788SWei Mi 20064e76853SWei Mi // Write out the MD5 name table. We wrote unencoded MD5 so reader can 20164e76853SWei Mi // retrieve the name using the name index without having to read the 20264e76853SWei Mi // whole name table. 203ebad6788SWei Mi encodeULEB128(NameTable.size(), OS); 20464e76853SWei Mi support::endian::Writer Writer(OS, support::little); 20564e76853SWei Mi for (auto N : V) 20664e76853SWei Mi Writer.write(MD5Hash(N)); 207ebad6788SWei Mi return sampleprof_error::success; 208ebad6788SWei Mi } 209ebad6788SWei Mi 21093953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection( 211be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 212be907324SWei Mi for (const auto &I : ProfileMap) { 213*00ef28efSWenlei He assert(I.first() == I.second.getNameWithContext() && 214*00ef28efSWenlei He "Inconsistent profile map"); 215*00ef28efSWenlei He addName(I.second.getNameWithContext(), FunctionSamples::ProfileIsCS); 216be907324SWei Mi addNames(I.second); 217be907324SWei Mi } 218ee35784aSWei Mi 219ee35784aSWei Mi // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag 220ee35784aSWei Mi // so compiler won't strip the suffix during profile matching after 221ee35784aSWei Mi // seeing the flag in the profile. 222ee35784aSWei Mi for (const auto &I : NameTable) { 223ee35784aSWei Mi if (I.first.find(FunctionSamples::UniqSuffix) != StringRef::npos) { 224ee35784aSWei Mi addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix); 225ee35784aSWei Mi break; 226ee35784aSWei Mi } 227ee35784aSWei Mi } 228ee35784aSWei Mi 22993953d41SWei Mi if (auto EC = writeNameTable()) 230b523790aSWei Mi return EC; 23193953d41SWei Mi return sampleprof_error::success; 23293953d41SWei Mi } 233be907324SWei Mi 23493953d41SWei Mi std::error_code 23593953d41SWei Mi SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() { 236798e59b8SWei Mi if (ProfSymList && ProfSymList->size() > 0) 237798e59b8SWei Mi if (std::error_code EC = ProfSymList->write(*OutputStream)) 238798e59b8SWei Mi return EC; 239be907324SWei Mi 24093953d41SWei Mi return sampleprof_error::success; 24193953d41SWei Mi } 24209dcfe68SWei Mi 24393953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeOneSection( 244a906e3ecSWei Mi SecType Type, uint32_t LayoutIdx, 245a906e3ecSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 24693953d41SWei Mi // The setting of SecFlagCompress should happen before markSectionStart. 24793953d41SWei Mi if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress()) 24893953d41SWei Mi setToCompressSection(SecProfileSymbolList); 249ac068e01SHongtao Yu if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased) 250ac068e01SHongtao Yu addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased); 251a5d30421SWenlei He if (Type == SecProfSummary && FunctionSamples::ProfileIsCS) 252a5d30421SWenlei He addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext); 2531410db70SWenlei He if (Type == SecFuncMetadata && FunctionSamples::ProfileIsCS) 2541410db70SWenlei He addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagHasAttribute); 25593953d41SWei Mi 256a906e3ecSWei Mi uint64_t SectionStart = markSectionStart(Type, LayoutIdx); 25793953d41SWei Mi switch (Type) { 25893953d41SWei Mi case SecProfSummary: 25993953d41SWei Mi computeSummary(ProfileMap); 26093953d41SWei Mi if (auto EC = writeSummary()) 26193953d41SWei Mi return EC; 26293953d41SWei Mi break; 26393953d41SWei Mi case SecNameTable: 26493953d41SWei Mi if (auto EC = writeNameTableSection(ProfileMap)) 26593953d41SWei Mi return EC; 26693953d41SWei Mi break; 26793953d41SWei Mi case SecLBRProfile: 26893953d41SWei Mi SecLBRProfileStart = OutputStream->tell(); 26993953d41SWei Mi if (std::error_code EC = writeFuncProfiles(ProfileMap)) 27093953d41SWei Mi return EC; 27193953d41SWei Mi break; 27293953d41SWei Mi case SecFuncOffsetTable: 27393953d41SWei Mi if (auto EC = writeFuncOffsetTable()) 27493953d41SWei Mi return EC; 27593953d41SWei Mi break; 276ac068e01SHongtao Yu case SecFuncMetadata: 277ac068e01SHongtao Yu if (std::error_code EC = writeFuncMetadata(ProfileMap)) 278ac068e01SHongtao Yu return EC; 279ac068e01SHongtao Yu break; 28093953d41SWei Mi case SecProfileSymbolList: 28193953d41SWei Mi if (auto EC = writeProfileSymbolListSection()) 28293953d41SWei Mi return EC; 28393953d41SWei Mi break; 28493953d41SWei Mi default: 28593953d41SWei Mi if (auto EC = writeCustomSection(Type)) 28693953d41SWei Mi return EC; 28793953d41SWei Mi break; 28893953d41SWei Mi } 289a906e3ecSWei Mi if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart)) 29093953d41SWei Mi return EC; 29193953d41SWei Mi return sampleprof_error::success; 29293953d41SWei Mi } 29393953d41SWei Mi 29421b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeDefaultLayout( 29593953d41SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 296a906e3ecSWei Mi // The const indices passed to writeOneSection below are specifying the 297a906e3ecSWei Mi // positions of the sections in SectionHdrLayout. Look at 298a906e3ecSWei Mi // initSectionHdrLayout to find out where each section is located in 299a906e3ecSWei Mi // SectionHdrLayout. 300a906e3ecSWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 30193953d41SWei Mi return EC; 302a906e3ecSWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 30393953d41SWei Mi return EC; 304a906e3ecSWei Mi if (auto EC = writeOneSection(SecLBRProfile, 3, ProfileMap)) 30593953d41SWei Mi return EC; 306a906e3ecSWei Mi if (auto EC = writeOneSection(SecProfileSymbolList, 4, ProfileMap)) 30793953d41SWei Mi return EC; 308a906e3ecSWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ProfileMap)) 30993953d41SWei Mi return EC; 310a906e3ecSWei Mi if (auto EC = writeOneSection(SecFuncMetadata, 5, ProfileMap)) 311ac068e01SHongtao Yu return EC; 312be907324SWei Mi return sampleprof_error::success; 313be907324SWei Mi } 314be907324SWei Mi 31521b1ad03SWei Mi static void 31621b1ad03SWei Mi splitProfileMapToTwo(const StringMap<FunctionSamples> &ProfileMap, 31721b1ad03SWei Mi StringMap<FunctionSamples> &ContextProfileMap, 31821b1ad03SWei Mi StringMap<FunctionSamples> &NoContextProfileMap) { 31921b1ad03SWei Mi for (const auto &I : ProfileMap) { 32021b1ad03SWei Mi if (I.second.getCallsiteSamples().size()) 32121b1ad03SWei Mi ContextProfileMap.insert({I.first(), I.second}); 32221b1ad03SWei Mi else 32321b1ad03SWei Mi NoContextProfileMap.insert({I.first(), I.second}); 32421b1ad03SWei Mi } 32521b1ad03SWei Mi } 32621b1ad03SWei Mi 32721b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout( 32821b1ad03SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 32921b1ad03SWei Mi StringMap<FunctionSamples> ContextProfileMap, NoContextProfileMap; 33021b1ad03SWei Mi splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap); 33121b1ad03SWei Mi 33221b1ad03SWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 33321b1ad03SWei Mi return EC; 33421b1ad03SWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 33521b1ad03SWei Mi return EC; 33621b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap)) 33721b1ad03SWei Mi return EC; 33821b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap)) 33921b1ad03SWei Mi return EC; 34021b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set 34121b1ad03SWei Mi // before writing the section. 34221b1ad03SWei Mi addSectionFlag(5, SecCommonFlags::SecFlagFlat); 34321b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap)) 34421b1ad03SWei Mi return EC; 34521b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set 34621b1ad03SWei Mi // before writing the section. 34721b1ad03SWei Mi addSectionFlag(4, SecCommonFlags::SecFlagFlat); 34821b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap)) 34921b1ad03SWei Mi return EC; 35021b1ad03SWei Mi if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap)) 35121b1ad03SWei Mi return EC; 35221b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap)) 35321b1ad03SWei Mi return EC; 35421b1ad03SWei Mi 35521b1ad03SWei Mi return sampleprof_error::success; 35621b1ad03SWei Mi } 35721b1ad03SWei Mi 35821b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeSections( 35921b1ad03SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 36021b1ad03SWei Mi std::error_code EC; 36121b1ad03SWei Mi if (SecLayout == DefaultLayout) 36221b1ad03SWei Mi EC = writeDefaultLayout(ProfileMap); 36321b1ad03SWei Mi else if (SecLayout == CtxSplitLayout) 36421b1ad03SWei Mi EC = writeCtxSplitLayout(ProfileMap); 36521b1ad03SWei Mi else 36621b1ad03SWei Mi llvm_unreachable("Unsupported layout"); 36721b1ad03SWei Mi return EC; 36821b1ad03SWei Mi } 36921b1ad03SWei Mi 3706a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::write( 3716a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 3726a14325dSWei Mi if (std::error_code EC = SampleProfileWriter::write(ProfileMap)) 3736a14325dSWei Mi return EC; 3746a14325dSWei Mi if (std::error_code EC = writeFuncOffsetTable()) 3756a14325dSWei Mi return EC; 3766a14325dSWei Mi return sampleprof_error::success; 3776a14325dSWei Mi } 3786a14325dSWei Mi 3795f8f34e4SAdrian Prantl /// Write samples to a text file. 3808e415a82SDiego Novillo /// 3818e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of 382ef548d29SDiego Novillo /// FunctionSamples::print(). Please don't. The dump functionality is intended 3838e415a82SDiego Novillo /// for debugging and has no specified form. 3848e415a82SDiego Novillo /// 3858e415a82SDiego Novillo /// The format used here is more structured and deliberate because 3868e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class. 387be907324SWei Mi std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { 38851abea74SNathan Slingerland auto &OS = *OutputStream; 389*00ef28efSWenlei He if (FunctionSamples::ProfileIsCS) 390*00ef28efSWenlei He OS << "[" << S.getNameWithContext() << "]:" << S.getTotalSamples(); 391*00ef28efSWenlei He else 392*00ef28efSWenlei He OS << S.getName() << ":" << S.getTotalSamples(); 393*00ef28efSWenlei He 394aae1ed8eSDiego Novillo if (Indent == 0) 395aae1ed8eSDiego Novillo OS << ":" << S.getHeadSamples(); 396aae1ed8eSDiego Novillo OS << "\n"; 397c572e92cSDiego Novillo 398ef548d29SDiego Novillo SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 399ef548d29SDiego Novillo for (const auto &I : SortedSamples.get()) { 400ef548d29SDiego Novillo LineLocation Loc = I->first; 401ef548d29SDiego Novillo const SampleRecord &Sample = I->second; 402aae1ed8eSDiego Novillo OS.indent(Indent + 1); 403c572e92cSDiego Novillo if (Loc.Discriminator == 0) 404c572e92cSDiego Novillo OS << Loc.LineOffset << ": "; 405c572e92cSDiego Novillo else 406c572e92cSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 407c572e92cSDiego Novillo 408c572e92cSDiego Novillo OS << Sample.getSamples(); 409c572e92cSDiego Novillo 4105adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) 4115adace35SWenlei He OS << " " << J.first << ":" << J.second; 412c572e92cSDiego Novillo OS << "\n"; 413c572e92cSDiego Novillo } 414c572e92cSDiego Novillo 4152c7ca9b5SDehao Chen SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 416ef548d29SDiego Novillo S.getCallsiteSamples()); 417aae1ed8eSDiego Novillo Indent += 1; 4182c7ca9b5SDehao Chen for (const auto &I : SortedCallsiteSamples.get()) 4192c7ca9b5SDehao Chen for (const auto &FS : I->second) { 42057d1dda5SDehao Chen LineLocation Loc = I->first; 4212c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 422aae1ed8eSDiego Novillo OS.indent(Indent); 423aae1ed8eSDiego Novillo if (Loc.Discriminator == 0) 424aae1ed8eSDiego Novillo OS << Loc.LineOffset << ": "; 425aae1ed8eSDiego Novillo else 426aae1ed8eSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 427be907324SWei Mi if (std::error_code EC = writeSample(CalleeSamples)) 428760c5a8fSDiego Novillo return EC; 429aae1ed8eSDiego Novillo } 430aae1ed8eSDiego Novillo Indent -= 1; 431aae1ed8eSDiego Novillo 432ac068e01SHongtao Yu if (Indent == 0) { 433ac068e01SHongtao Yu if (FunctionSamples::ProfileIsProbeBased) { 434ac068e01SHongtao Yu OS.indent(Indent + 1); 435ac068e01SHongtao Yu OS << "!CFGChecksum: " << S.getFunctionHash() << "\n"; 436ac068e01SHongtao Yu } 4371410db70SWenlei He if (FunctionSamples::ProfileIsCS) { 4381410db70SWenlei He OS.indent(Indent + 1); 4391410db70SWenlei He OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n"; 4401410db70SWenlei He } 441ac068e01SHongtao Yu } 442ac068e01SHongtao Yu 443760c5a8fSDiego Novillo return sampleprof_error::success; 444c572e92cSDiego Novillo } 445c572e92cSDiego Novillo 446*00ef28efSWenlei He std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName, 447*00ef28efSWenlei He bool IsContextName) { 448*00ef28efSWenlei He std::string BracketedName; 449*00ef28efSWenlei He if (IsContextName) { 450*00ef28efSWenlei He BracketedName = "[" + FName.str() + "]"; 451*00ef28efSWenlei He FName = StringRef(BracketedName); 452*00ef28efSWenlei He } 453*00ef28efSWenlei He 454*00ef28efSWenlei He const auto &Ret = NameTable.find(FName); 455*00ef28efSWenlei He if (Ret == NameTable.end()) 456760c5a8fSDiego Novillo return sampleprof_error::truncated_name_table; 457*00ef28efSWenlei He encodeULEB128(Ret->second, *OutputStream); 458760c5a8fSDiego Novillo return sampleprof_error::success; 459760c5a8fSDiego Novillo } 460c572e92cSDiego Novillo 461*00ef28efSWenlei He void SampleProfileWriterBinary::addName(StringRef FName, bool IsContextName) { 462*00ef28efSWenlei He if (IsContextName) { 463*00ef28efSWenlei He auto It = BracketedContextStr.insert("[" + FName.str() + "]"); 464*00ef28efSWenlei He FName = StringRef(*It.first); 465*00ef28efSWenlei He } 4668d1c983fSDehao Chen NameTable.insert(std::make_pair(FName, 0)); 467760c5a8fSDiego Novillo } 468760c5a8fSDiego Novillo 469760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 470760c5a8fSDiego Novillo // Add all the names in indirect call targets. 471760c5a8fSDiego Novillo for (const auto &I : S.getBodySamples()) { 472760c5a8fSDiego Novillo const SampleRecord &Sample = I.second; 473760c5a8fSDiego Novillo for (const auto &J : Sample.getCallTargets()) 474760c5a8fSDiego Novillo addName(J.first()); 475760c5a8fSDiego Novillo } 476760c5a8fSDiego Novillo 477760c5a8fSDiego Novillo // Recursively add all the names for inlined callsites. 4782c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 4792c7ca9b5SDehao Chen for (const auto &FS : J.second) { 4802c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 48157d1dda5SDehao Chen addName(CalleeSamples.getName()); 482760c5a8fSDiego Novillo addNames(CalleeSamples); 483760c5a8fSDiego Novillo } 484760c5a8fSDiego Novillo } 485760c5a8fSDiego Novillo 486a0c0857eSWei Mi void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) { 487a0c0857eSWei Mi // Sort the names to make NameTable deterministic. 488a0c0857eSWei Mi for (const auto &I : NameTable) 489a0c0857eSWei Mi V.insert(I.first); 490a0c0857eSWei Mi int i = 0; 491a0c0857eSWei Mi for (const StringRef &N : V) 492a0c0857eSWei Mi NameTable[N] = i++; 493a0c0857eSWei Mi } 49451abea74SNathan Slingerland 495be907324SWei Mi std::error_code SampleProfileWriterBinary::writeNameTable() { 496a0c0857eSWei Mi auto &OS = *OutputStream; 497a0c0857eSWei Mi std::set<StringRef> V; 498a0c0857eSWei Mi stablizeNameTable(V); 499a0c0857eSWei Mi 500a0c0857eSWei Mi // Write out the name table. 501a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 502a0c0857eSWei Mi for (auto N : V) { 503a0c0857eSWei Mi OS << N; 504a0c0857eSWei Mi encodeULEB128(0, OS); 505a0c0857eSWei Mi } 506a0c0857eSWei Mi return sampleprof_error::success; 507a0c0857eSWei Mi } 508a0c0857eSWei Mi 5096a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { 5106a14325dSWei Mi auto &OS = *OutputStream; 5116a14325dSWei Mi 5126a14325dSWei Mi // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. 5136a14325dSWei Mi auto &OFS = static_cast<raw_fd_ostream &>(OS); 5146a14325dSWei Mi uint64_t FuncOffsetTableStart = OS.tell(); 5156a14325dSWei Mi if (OFS.seek(TableOffset) == (uint64_t)-1) 5166a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 5176a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 5186a14325dSWei Mi Writer.write(FuncOffsetTableStart); 5196a14325dSWei Mi if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) 5206a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 5216a14325dSWei Mi 5226a14325dSWei Mi // Write out the table size. 5236a14325dSWei Mi encodeULEB128(FuncOffsetTable.size(), OS); 5246a14325dSWei Mi 5256a14325dSWei Mi // Write out FuncOffsetTable. 526*00ef28efSWenlei He for (auto Entry : FuncOffsetTable) { 527*00ef28efSWenlei He if (std::error_code EC = 528*00ef28efSWenlei He writeNameIdx(Entry.first, FunctionSamples::ProfileIsCS)) 529*00ef28efSWenlei He return EC; 530*00ef28efSWenlei He encodeULEB128(Entry.second, OS); 5316a14325dSWei Mi } 5326a14325dSWei Mi return sampleprof_error::success; 5336a14325dSWei Mi } 5346a14325dSWei Mi 535a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() { 536a0c0857eSWei Mi auto &OS = *OutputStream; 537a0c0857eSWei Mi std::set<StringRef> V; 538a0c0857eSWei Mi stablizeNameTable(V); 539a0c0857eSWei Mi 540a0c0857eSWei Mi // Write out the name table. 541a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 542a0c0857eSWei Mi for (auto N : V) { 543a0c0857eSWei Mi encodeULEB128(MD5Hash(N), OS); 544a0c0857eSWei Mi } 545a0c0857eSWei Mi return sampleprof_error::success; 546a0c0857eSWei Mi } 547a0c0857eSWei Mi 548be907324SWei Mi std::error_code 549be907324SWei Mi SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { 550a0c0857eSWei Mi auto &OS = *OutputStream; 551760c5a8fSDiego Novillo // Write file magic identifier. 552be907324SWei Mi encodeULEB128(SPMagic(Format), OS); 553a0c0857eSWei Mi encodeULEB128(SPVersion(), OS); 554a0c0857eSWei Mi return sampleprof_error::success; 555a0c0857eSWei Mi } 556a0c0857eSWei Mi 557a0c0857eSWei Mi std::error_code SampleProfileWriterBinary::writeHeader( 558a0c0857eSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 559be907324SWei Mi writeMagicIdent(Format); 560760c5a8fSDiego Novillo 56140ee23dbSEaswaran Raman computeSummary(ProfileMap); 56240ee23dbSEaswaran Raman if (auto EC = writeSummary()) 56340ee23dbSEaswaran Raman return EC; 56440ee23dbSEaswaran Raman 565760c5a8fSDiego Novillo // Generate the name table for all the functions referenced in the profile. 566760c5a8fSDiego Novillo for (const auto &I : ProfileMap) { 567*00ef28efSWenlei He assert(I.first() == I.second.getNameWithContext() && 568*00ef28efSWenlei He "Inconsistent profile map"); 569*00ef28efSWenlei He addName(I.first(), FunctionSamples::ProfileIsCS); 570760c5a8fSDiego Novillo addNames(I.second); 571760c5a8fSDiego Novillo } 572760c5a8fSDiego Novillo 573a0c0857eSWei Mi writeNameTable(); 574760c5a8fSDiego Novillo return sampleprof_error::success; 575c572e92cSDiego Novillo } 576c572e92cSDiego Novillo 577b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressAllSections() { 57809dcfe68SWei Mi for (auto &Entry : SectionHdrLayout) 579ebad6788SWei Mi addSecFlag(Entry, SecCommonFlags::SecFlagCompress); 580b523790aSWei Mi } 581b523790aSWei Mi 582b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) { 583ebad6788SWei Mi addSectionFlag(Type, SecCommonFlags::SecFlagCompress); 584b523790aSWei Mi } 585b523790aSWei Mi 586be907324SWei Mi void SampleProfileWriterExtBinaryBase::allocSecHdrTable() { 587be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 588be907324SWei Mi 58909dcfe68SWei Mi Writer.write(static_cast<uint64_t>(SectionHdrLayout.size())); 590be907324SWei Mi SecHdrTableOffset = OutputStream->tell(); 59109dcfe68SWei Mi for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 592be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 593be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 594be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 595be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 596be907324SWei Mi } 597be907324SWei Mi } 598be907324SWei Mi 599be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { 600be907324SWei Mi auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream); 601be907324SWei Mi uint64_t Saved = OutputStream->tell(); 602be907324SWei Mi 603be907324SWei Mi // Set OutputStream to the location saved in SecHdrTableOffset. 604be907324SWei Mi if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1) 605be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 606be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 607be907324SWei Mi 608a906e3ecSWei Mi assert(SecHdrTable.size() == SectionHdrLayout.size() && 609a906e3ecSWei Mi "SecHdrTable entries doesn't match SectionHdrLayout"); 610a906e3ecSWei Mi SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1); 611a906e3ecSWei Mi for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) { 612a906e3ecSWei Mi IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx; 613be907324SWei Mi } 614be907324SWei Mi 61509dcfe68SWei Mi // Write the section header table in the order specified in 616a906e3ecSWei Mi // SectionHdrLayout. SectionHdrLayout specifies the sections 617a906e3ecSWei Mi // order in which profile reader expect to read, so the section 618a906e3ecSWei Mi // header table should be written in the order in SectionHdrLayout. 619a906e3ecSWei Mi // Note that the section order in SecHdrTable may be different 620a906e3ecSWei Mi // from the order in SectionHdrLayout, for example, SecFuncOffsetTable 621a906e3ecSWei Mi // needs to be computed after SecLBRProfile (the order in SecHdrTable), 622a906e3ecSWei Mi // but it needs to be read before SecLBRProfile (the order in 623a906e3ecSWei Mi // SectionHdrLayout). So we use IndexMap above to switch the order. 624a906e3ecSWei Mi for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size(); 625a906e3ecSWei Mi LayoutIdx++) { 626a906e3ecSWei Mi assert(IndexMap[LayoutIdx] < SecHdrTable.size() && 627a906e3ecSWei Mi "Incorrect LayoutIdx in SecHdrTable"); 628a906e3ecSWei Mi auto Entry = SecHdrTable[IndexMap[LayoutIdx]]; 629a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Type)); 630a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Flags)); 631a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Offset)); 632a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Size)); 633be907324SWei Mi } 634be907324SWei Mi 635be907324SWei Mi // Reset OutputStream. 636be907324SWei Mi if (OFS.seek(Saved) == (uint64_t)-1) 637be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 638be907324SWei Mi 639be907324SWei Mi return sampleprof_error::success; 640be907324SWei Mi } 641be907324SWei Mi 642be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeHeader( 643be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 644be907324SWei Mi auto &OS = *OutputStream; 645be907324SWei Mi FileStart = OS.tell(); 646be907324SWei Mi writeMagicIdent(Format); 647be907324SWei Mi 648be907324SWei Mi allocSecHdrTable(); 649be907324SWei Mi return sampleprof_error::success; 650be907324SWei Mi } 651be907324SWei Mi 6526a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader( 6536a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 6546a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 6556a14325dSWei Mi if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) 6566a14325dSWei Mi return EC; 6576a14325dSWei Mi 6586a14325dSWei Mi // Reserve a slot for the offset of function offset table. The slot will 6596a14325dSWei Mi // be populated with the offset of FuncOffsetTable later. 6606a14325dSWei Mi TableOffset = OutputStream->tell(); 6616a14325dSWei Mi Writer.write(static_cast<uint64_t>(-2)); 6626a14325dSWei Mi return sampleprof_error::success; 6636a14325dSWei Mi } 6646a14325dSWei Mi 66540ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() { 66640ee23dbSEaswaran Raman auto &OS = *OutputStream; 6677cefdb81SEaswaran Raman encodeULEB128(Summary->getTotalCount(), OS); 6687cefdb81SEaswaran Raman encodeULEB128(Summary->getMaxCount(), OS); 6696f4903d9SEaswaran Raman encodeULEB128(Summary->getMaxFunctionCount(), OS); 6707cefdb81SEaswaran Raman encodeULEB128(Summary->getNumCounts(), OS); 67140ee23dbSEaswaran Raman encodeULEB128(Summary->getNumFunctions(), OS); 67240ee23dbSEaswaran Raman std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 67340ee23dbSEaswaran Raman encodeULEB128(Entries.size(), OS); 67440ee23dbSEaswaran Raman for (auto Entry : Entries) { 67540ee23dbSEaswaran Raman encodeULEB128(Entry.Cutoff, OS); 67640ee23dbSEaswaran Raman encodeULEB128(Entry.MinCount, OS); 67740ee23dbSEaswaran Raman encodeULEB128(Entry.NumCounts, OS); 67840ee23dbSEaswaran Raman } 67940ee23dbSEaswaran Raman return sampleprof_error::success; 68040ee23dbSEaswaran Raman } 68157d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 68251abea74SNathan Slingerland auto &OS = *OutputStream; 68351abea74SNathan Slingerland 684*00ef28efSWenlei He if (std::error_code EC = 685*00ef28efSWenlei He writeNameIdx(S.getNameWithContext(), FunctionSamples::ProfileIsCS)) 686760c5a8fSDiego Novillo return EC; 687760c5a8fSDiego Novillo 688c572e92cSDiego Novillo encodeULEB128(S.getTotalSamples(), OS); 689a7f1e8efSDiego Novillo 690a7f1e8efSDiego Novillo // Emit all the body samples. 691b93483dbSDiego Novillo encodeULEB128(S.getBodySamples().size(), OS); 692d5336ae2SDiego Novillo for (const auto &I : S.getBodySamples()) { 693d5336ae2SDiego Novillo LineLocation Loc = I.first; 694d5336ae2SDiego Novillo const SampleRecord &Sample = I.second; 695c572e92cSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 696c572e92cSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 697c572e92cSDiego Novillo encodeULEB128(Sample.getSamples(), OS); 698c572e92cSDiego Novillo encodeULEB128(Sample.getCallTargets().size(), OS); 6995adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) { 7005adace35SWenlei He StringRef Callee = J.first; 70138be3330SDiego Novillo uint64_t CalleeSamples = J.second; 702760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(Callee)) 703760c5a8fSDiego Novillo return EC; 704c572e92cSDiego Novillo encodeULEB128(CalleeSamples, OS); 705c572e92cSDiego Novillo } 706c572e92cSDiego Novillo } 707c572e92cSDiego Novillo 708a7f1e8efSDiego Novillo // Recursively emit all the callsite samples. 7092c27daf7SDehao Chen uint64_t NumCallsites = 0; 7102c27daf7SDehao Chen for (const auto &J : S.getCallsiteSamples()) 7112c27daf7SDehao Chen NumCallsites += J.second.size(); 7122c27daf7SDehao Chen encodeULEB128(NumCallsites, OS); 7132c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 7142c7ca9b5SDehao Chen for (const auto &FS : J.second) { 71557d1dda5SDehao Chen LineLocation Loc = J.first; 7162c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 717a7f1e8efSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 718a7f1e8efSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 71957d1dda5SDehao Chen if (std::error_code EC = writeBody(CalleeSamples)) 720760c5a8fSDiego Novillo return EC; 721a7f1e8efSDiego Novillo } 722a7f1e8efSDiego Novillo 723760c5a8fSDiego Novillo return sampleprof_error::success; 724c572e92cSDiego Novillo } 725d5336ae2SDiego Novillo 7265f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file. 727b93483dbSDiego Novillo /// 728b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise. 729be907324SWei Mi std::error_code 730be907324SWei Mi SampleProfileWriterBinary::writeSample(const FunctionSamples &S) { 73151abea74SNathan Slingerland encodeULEB128(S.getHeadSamples(), *OutputStream); 73257d1dda5SDehao Chen return writeBody(S); 733b93483dbSDiego Novillo } 734b93483dbSDiego Novillo 7356a14325dSWei Mi std::error_code 736be907324SWei Mi SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) { 7376a14325dSWei Mi uint64_t Offset = OutputStream->tell(); 7386a14325dSWei Mi StringRef Name = S.getName(); 7396a14325dSWei Mi FuncOffsetTable[Name] = Offset; 7406a14325dSWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream); 7416a14325dSWei Mi return writeBody(S); 7426a14325dSWei Mi } 7436a14325dSWei Mi 7445f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format. 745d5336ae2SDiego Novillo /// 746d5336ae2SDiego Novillo /// \param Filename The file to create. 747d5336ae2SDiego Novillo /// 748d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file. 749d5336ae2SDiego Novillo /// 750d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer. 751fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>> 752fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 753d5336ae2SDiego Novillo std::error_code EC; 75451abea74SNathan Slingerland std::unique_ptr<raw_ostream> OS; 755be907324SWei Mi if (Format == SPF_Binary || Format == SPF_Ext_Binary || 756be907324SWei Mi Format == SPF_Compact_Binary) 757d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None)); 75851abea74SNathan Slingerland else 75982b3e28eSAbhina Sreeskantharajan OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF)); 76051abea74SNathan Slingerland if (EC) 76151abea74SNathan Slingerland return EC; 76251abea74SNathan Slingerland 76351abea74SNathan Slingerland return create(OS, Format); 76451abea74SNathan Slingerland } 76551abea74SNathan Slingerland 7665f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format. 76751abea74SNathan Slingerland /// 76851abea74SNathan Slingerland /// \param OS The output stream to store the profile data to. 76951abea74SNathan Slingerland /// 77051abea74SNathan Slingerland /// \param Format Encoding format for the profile file. 77151abea74SNathan Slingerland /// 77251abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer. 77351abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>> 77451abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 77551abea74SNathan Slingerland SampleProfileFormat Format) { 77651abea74SNathan Slingerland std::error_code EC; 777fcd55607SDiego Novillo std::unique_ptr<SampleProfileWriter> Writer; 778d5336ae2SDiego Novillo 779d9be2c7eSWei Mi if (Format == SPF_Binary) 780a0c0857eSWei Mi Writer.reset(new SampleProfileWriterRawBinary(OS)); 781be907324SWei Mi else if (Format == SPF_Ext_Binary) 782be907324SWei Mi Writer.reset(new SampleProfileWriterExtBinary(OS)); 783a0c0857eSWei Mi else if (Format == SPF_Compact_Binary) 784a0c0857eSWei Mi Writer.reset(new SampleProfileWriterCompactBinary(OS)); 785d5336ae2SDiego Novillo else if (Format == SPF_Text) 78651abea74SNathan Slingerland Writer.reset(new SampleProfileWriterText(OS)); 787760c5a8fSDiego Novillo else if (Format == SPF_GCC) 788760c5a8fSDiego Novillo EC = sampleprof_error::unsupported_writing_format; 789d5336ae2SDiego Novillo else 790d5336ae2SDiego Novillo EC = sampleprof_error::unrecognized_format; 791d5336ae2SDiego Novillo 792fcd55607SDiego Novillo if (EC) 793d5336ae2SDiego Novillo return EC; 794fcd55607SDiego Novillo 795be907324SWei Mi Writer->Format = Format; 796c55cf4afSBill Wendling return std::move(Writer); 797d5336ae2SDiego Novillo } 79840ee23dbSEaswaran Raman 79940ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary( 80040ee23dbSEaswaran Raman const StringMap<FunctionSamples> &ProfileMap) { 801e5a17e3fSEaswaran Raman SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 802801d9cc7SWenlei He Summary = Builder.computeSummaryForProfiles(ProfileMap); 80340ee23dbSEaswaran Raman } 804