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; 4900ef28efSWenlei He for (const auto &I : ProfileMap) { 5000ef28efSWenlei He assert(I.getKey() == I.second.getNameWithContext() && 5100ef28efSWenlei He "Inconsistent profile map"); 5200ef28efSWenlei He V.push_back(std::make_pair(I.second.getNameWithContext(), &I.second)); 5300ef28efSWenlei 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(); 15200ef28efSWenlei 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. 16500ef28efSWenlei He for (auto Entry : FuncOffsetTable) { 16600ef28efSWenlei He if (std::error_code EC = 16700ef28efSWenlei He writeNameIdx(Entry.first, FunctionSamples::ProfileIsCS)) 16800ef28efSWenlei He return EC; 16900ef28efSWenlei 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) { 18100ef28efSWenlei He if (std::error_code EC = writeNameIdx(Entry.second.getNameWithContext(), 18200ef28efSWenlei He FunctionSamples::ProfileIsCS)) 18300ef28efSWenlei 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) { 21300ef28efSWenlei He assert(I.first() == I.second.getNameWithContext() && 21400ef28efSWenlei He "Inconsistent profile map"); 21500ef28efSWenlei 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); 255*6745ffe4SRong Xu if (Type == SecProfSummary && FunctionSamples::ProfileIsFS) 256*6745ffe4SRong Xu addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFSDiscriminator); 25793953d41SWei Mi 258a906e3ecSWei Mi uint64_t SectionStart = markSectionStart(Type, LayoutIdx); 25993953d41SWei Mi switch (Type) { 26093953d41SWei Mi case SecProfSummary: 26193953d41SWei Mi computeSummary(ProfileMap); 26293953d41SWei Mi if (auto EC = writeSummary()) 26393953d41SWei Mi return EC; 26493953d41SWei Mi break; 26593953d41SWei Mi case SecNameTable: 26693953d41SWei Mi if (auto EC = writeNameTableSection(ProfileMap)) 26793953d41SWei Mi return EC; 26893953d41SWei Mi break; 26993953d41SWei Mi case SecLBRProfile: 27093953d41SWei Mi SecLBRProfileStart = OutputStream->tell(); 27193953d41SWei Mi if (std::error_code EC = writeFuncProfiles(ProfileMap)) 27293953d41SWei Mi return EC; 27393953d41SWei Mi break; 27493953d41SWei Mi case SecFuncOffsetTable: 27593953d41SWei Mi if (auto EC = writeFuncOffsetTable()) 27693953d41SWei Mi return EC; 27793953d41SWei Mi break; 278ac068e01SHongtao Yu case SecFuncMetadata: 279ac068e01SHongtao Yu if (std::error_code EC = writeFuncMetadata(ProfileMap)) 280ac068e01SHongtao Yu return EC; 281ac068e01SHongtao Yu break; 28293953d41SWei Mi case SecProfileSymbolList: 28393953d41SWei Mi if (auto EC = writeProfileSymbolListSection()) 28493953d41SWei Mi return EC; 28593953d41SWei Mi break; 28693953d41SWei Mi default: 28793953d41SWei Mi if (auto EC = writeCustomSection(Type)) 28893953d41SWei Mi return EC; 28993953d41SWei Mi break; 29093953d41SWei Mi } 291a906e3ecSWei Mi if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart)) 29293953d41SWei Mi return EC; 29393953d41SWei Mi return sampleprof_error::success; 29493953d41SWei Mi } 29593953d41SWei Mi 29621b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeDefaultLayout( 29793953d41SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 298a906e3ecSWei Mi // The const indices passed to writeOneSection below are specifying the 299a906e3ecSWei Mi // positions of the sections in SectionHdrLayout. Look at 300a906e3ecSWei Mi // initSectionHdrLayout to find out where each section is located in 301a906e3ecSWei Mi // SectionHdrLayout. 302a906e3ecSWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 30393953d41SWei Mi return EC; 304a906e3ecSWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 30593953d41SWei Mi return EC; 306a906e3ecSWei Mi if (auto EC = writeOneSection(SecLBRProfile, 3, ProfileMap)) 30793953d41SWei Mi return EC; 308a906e3ecSWei Mi if (auto EC = writeOneSection(SecProfileSymbolList, 4, ProfileMap)) 30993953d41SWei Mi return EC; 310a906e3ecSWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ProfileMap)) 31193953d41SWei Mi return EC; 312a906e3ecSWei Mi if (auto EC = writeOneSection(SecFuncMetadata, 5, ProfileMap)) 313ac068e01SHongtao Yu return EC; 314be907324SWei Mi return sampleprof_error::success; 315be907324SWei Mi } 316be907324SWei Mi 31721b1ad03SWei Mi static void 31821b1ad03SWei Mi splitProfileMapToTwo(const StringMap<FunctionSamples> &ProfileMap, 31921b1ad03SWei Mi StringMap<FunctionSamples> &ContextProfileMap, 32021b1ad03SWei Mi StringMap<FunctionSamples> &NoContextProfileMap) { 32121b1ad03SWei Mi for (const auto &I : ProfileMap) { 32221b1ad03SWei Mi if (I.second.getCallsiteSamples().size()) 32321b1ad03SWei Mi ContextProfileMap.insert({I.first(), I.second}); 32421b1ad03SWei Mi else 32521b1ad03SWei Mi NoContextProfileMap.insert({I.first(), I.second}); 32621b1ad03SWei Mi } 32721b1ad03SWei Mi } 32821b1ad03SWei Mi 32921b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout( 33021b1ad03SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 33121b1ad03SWei Mi StringMap<FunctionSamples> ContextProfileMap, NoContextProfileMap; 33221b1ad03SWei Mi splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap); 33321b1ad03SWei Mi 33421b1ad03SWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 33521b1ad03SWei Mi return EC; 33621b1ad03SWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 33721b1ad03SWei Mi return EC; 33821b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap)) 33921b1ad03SWei Mi return EC; 34021b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap)) 34121b1ad03SWei Mi return EC; 34221b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set 34321b1ad03SWei Mi // before writing the section. 34421b1ad03SWei Mi addSectionFlag(5, SecCommonFlags::SecFlagFlat); 34521b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap)) 34621b1ad03SWei Mi return EC; 34721b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set 34821b1ad03SWei Mi // before writing the section. 34921b1ad03SWei Mi addSectionFlag(4, SecCommonFlags::SecFlagFlat); 35021b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap)) 35121b1ad03SWei Mi return EC; 35221b1ad03SWei Mi if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap)) 35321b1ad03SWei Mi return EC; 35421b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap)) 35521b1ad03SWei Mi return EC; 35621b1ad03SWei Mi 35721b1ad03SWei Mi return sampleprof_error::success; 35821b1ad03SWei Mi } 35921b1ad03SWei Mi 36021b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeSections( 36121b1ad03SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 36221b1ad03SWei Mi std::error_code EC; 36321b1ad03SWei Mi if (SecLayout == DefaultLayout) 36421b1ad03SWei Mi EC = writeDefaultLayout(ProfileMap); 36521b1ad03SWei Mi else if (SecLayout == CtxSplitLayout) 36621b1ad03SWei Mi EC = writeCtxSplitLayout(ProfileMap); 36721b1ad03SWei Mi else 36821b1ad03SWei Mi llvm_unreachable("Unsupported layout"); 36921b1ad03SWei Mi return EC; 37021b1ad03SWei Mi } 37121b1ad03SWei Mi 3726a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::write( 3736a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 3746a14325dSWei Mi if (std::error_code EC = SampleProfileWriter::write(ProfileMap)) 3756a14325dSWei Mi return EC; 3766a14325dSWei Mi if (std::error_code EC = writeFuncOffsetTable()) 3776a14325dSWei Mi return EC; 3786a14325dSWei Mi return sampleprof_error::success; 3796a14325dSWei Mi } 3806a14325dSWei Mi 3815f8f34e4SAdrian Prantl /// Write samples to a text file. 3828e415a82SDiego Novillo /// 3838e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of 384ef548d29SDiego Novillo /// FunctionSamples::print(). Please don't. The dump functionality is intended 3858e415a82SDiego Novillo /// for debugging and has no specified form. 3868e415a82SDiego Novillo /// 3878e415a82SDiego Novillo /// The format used here is more structured and deliberate because 3888e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class. 389be907324SWei Mi std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { 39051abea74SNathan Slingerland auto &OS = *OutputStream; 39100ef28efSWenlei He if (FunctionSamples::ProfileIsCS) 39200ef28efSWenlei He OS << "[" << S.getNameWithContext() << "]:" << S.getTotalSamples(); 39300ef28efSWenlei He else 39400ef28efSWenlei He OS << S.getName() << ":" << S.getTotalSamples(); 39500ef28efSWenlei He 396aae1ed8eSDiego Novillo if (Indent == 0) 397aae1ed8eSDiego Novillo OS << ":" << S.getHeadSamples(); 398aae1ed8eSDiego Novillo OS << "\n"; 399c572e92cSDiego Novillo 400ef548d29SDiego Novillo SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 401ef548d29SDiego Novillo for (const auto &I : SortedSamples.get()) { 402ef548d29SDiego Novillo LineLocation Loc = I->first; 403ef548d29SDiego Novillo const SampleRecord &Sample = I->second; 404aae1ed8eSDiego Novillo OS.indent(Indent + 1); 405c572e92cSDiego Novillo if (Loc.Discriminator == 0) 406c572e92cSDiego Novillo OS << Loc.LineOffset << ": "; 407c572e92cSDiego Novillo else 408c572e92cSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 409c572e92cSDiego Novillo 410c572e92cSDiego Novillo OS << Sample.getSamples(); 411c572e92cSDiego Novillo 4125adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) 4135adace35SWenlei He OS << " " << J.first << ":" << J.second; 414c572e92cSDiego Novillo OS << "\n"; 415c572e92cSDiego Novillo } 416c572e92cSDiego Novillo 4172c7ca9b5SDehao Chen SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 418ef548d29SDiego Novillo S.getCallsiteSamples()); 419aae1ed8eSDiego Novillo Indent += 1; 4202c7ca9b5SDehao Chen for (const auto &I : SortedCallsiteSamples.get()) 4212c7ca9b5SDehao Chen for (const auto &FS : I->second) { 42257d1dda5SDehao Chen LineLocation Loc = I->first; 4232c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 424aae1ed8eSDiego Novillo OS.indent(Indent); 425aae1ed8eSDiego Novillo if (Loc.Discriminator == 0) 426aae1ed8eSDiego Novillo OS << Loc.LineOffset << ": "; 427aae1ed8eSDiego Novillo else 428aae1ed8eSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 429be907324SWei Mi if (std::error_code EC = writeSample(CalleeSamples)) 430760c5a8fSDiego Novillo return EC; 431aae1ed8eSDiego Novillo } 432aae1ed8eSDiego Novillo Indent -= 1; 433aae1ed8eSDiego Novillo 434ac068e01SHongtao Yu if (Indent == 0) { 435ac068e01SHongtao Yu if (FunctionSamples::ProfileIsProbeBased) { 436ac068e01SHongtao Yu OS.indent(Indent + 1); 437ac068e01SHongtao Yu OS << "!CFGChecksum: " << S.getFunctionHash() << "\n"; 438ac068e01SHongtao Yu } 4391410db70SWenlei He if (FunctionSamples::ProfileIsCS) { 4401410db70SWenlei He OS.indent(Indent + 1); 4411410db70SWenlei He OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n"; 4421410db70SWenlei He } 443ac068e01SHongtao Yu } 444ac068e01SHongtao Yu 445760c5a8fSDiego Novillo return sampleprof_error::success; 446c572e92cSDiego Novillo } 447c572e92cSDiego Novillo 44800ef28efSWenlei He std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName, 44900ef28efSWenlei He bool IsContextName) { 45000ef28efSWenlei He std::string BracketedName; 45100ef28efSWenlei He if (IsContextName) { 45200ef28efSWenlei He BracketedName = "[" + FName.str() + "]"; 45300ef28efSWenlei He FName = StringRef(BracketedName); 45400ef28efSWenlei He } 45500ef28efSWenlei He 45600ef28efSWenlei He const auto &Ret = NameTable.find(FName); 45700ef28efSWenlei He if (Ret == NameTable.end()) 458760c5a8fSDiego Novillo return sampleprof_error::truncated_name_table; 45900ef28efSWenlei He encodeULEB128(Ret->second, *OutputStream); 460760c5a8fSDiego Novillo return sampleprof_error::success; 461760c5a8fSDiego Novillo } 462c572e92cSDiego Novillo 46300ef28efSWenlei He void SampleProfileWriterBinary::addName(StringRef FName, bool IsContextName) { 46400ef28efSWenlei He if (IsContextName) { 46500ef28efSWenlei He auto It = BracketedContextStr.insert("[" + FName.str() + "]"); 46600ef28efSWenlei He FName = StringRef(*It.first); 46700ef28efSWenlei He } 4688d1c983fSDehao Chen NameTable.insert(std::make_pair(FName, 0)); 469760c5a8fSDiego Novillo } 470760c5a8fSDiego Novillo 471760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 472760c5a8fSDiego Novillo // Add all the names in indirect call targets. 473760c5a8fSDiego Novillo for (const auto &I : S.getBodySamples()) { 474760c5a8fSDiego Novillo const SampleRecord &Sample = I.second; 475760c5a8fSDiego Novillo for (const auto &J : Sample.getCallTargets()) 476760c5a8fSDiego Novillo addName(J.first()); 477760c5a8fSDiego Novillo } 478760c5a8fSDiego Novillo 479760c5a8fSDiego Novillo // Recursively add all the names for inlined callsites. 4802c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 4812c7ca9b5SDehao Chen for (const auto &FS : J.second) { 4822c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 48357d1dda5SDehao Chen addName(CalleeSamples.getName()); 484760c5a8fSDiego Novillo addNames(CalleeSamples); 485760c5a8fSDiego Novillo } 486760c5a8fSDiego Novillo } 487760c5a8fSDiego Novillo 488a0c0857eSWei Mi void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) { 489a0c0857eSWei Mi // Sort the names to make NameTable deterministic. 490a0c0857eSWei Mi for (const auto &I : NameTable) 491a0c0857eSWei Mi V.insert(I.first); 492a0c0857eSWei Mi int i = 0; 493a0c0857eSWei Mi for (const StringRef &N : V) 494a0c0857eSWei Mi NameTable[N] = i++; 495a0c0857eSWei Mi } 49651abea74SNathan Slingerland 497be907324SWei Mi std::error_code SampleProfileWriterBinary::writeNameTable() { 498a0c0857eSWei Mi auto &OS = *OutputStream; 499a0c0857eSWei Mi std::set<StringRef> V; 500a0c0857eSWei Mi stablizeNameTable(V); 501a0c0857eSWei Mi 502a0c0857eSWei Mi // Write out the name table. 503a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 504a0c0857eSWei Mi for (auto N : V) { 505a0c0857eSWei Mi OS << N; 506a0c0857eSWei Mi encodeULEB128(0, OS); 507a0c0857eSWei Mi } 508a0c0857eSWei Mi return sampleprof_error::success; 509a0c0857eSWei Mi } 510a0c0857eSWei Mi 5116a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { 5126a14325dSWei Mi auto &OS = *OutputStream; 5136a14325dSWei Mi 5146a14325dSWei Mi // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. 5156a14325dSWei Mi auto &OFS = static_cast<raw_fd_ostream &>(OS); 5166a14325dSWei Mi uint64_t FuncOffsetTableStart = OS.tell(); 5176a14325dSWei Mi if (OFS.seek(TableOffset) == (uint64_t)-1) 5186a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 5196a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 5206a14325dSWei Mi Writer.write(FuncOffsetTableStart); 5216a14325dSWei Mi if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) 5226a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 5236a14325dSWei Mi 5246a14325dSWei Mi // Write out the table size. 5256a14325dSWei Mi encodeULEB128(FuncOffsetTable.size(), OS); 5266a14325dSWei Mi 5276a14325dSWei Mi // Write out FuncOffsetTable. 52800ef28efSWenlei He for (auto Entry : FuncOffsetTable) { 52900ef28efSWenlei He if (std::error_code EC = 53000ef28efSWenlei He writeNameIdx(Entry.first, FunctionSamples::ProfileIsCS)) 53100ef28efSWenlei He return EC; 53200ef28efSWenlei He encodeULEB128(Entry.second, OS); 5336a14325dSWei Mi } 5346a14325dSWei Mi return sampleprof_error::success; 5356a14325dSWei Mi } 5366a14325dSWei Mi 537a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() { 538a0c0857eSWei Mi auto &OS = *OutputStream; 539a0c0857eSWei Mi std::set<StringRef> V; 540a0c0857eSWei Mi stablizeNameTable(V); 541a0c0857eSWei Mi 542a0c0857eSWei Mi // Write out the name table. 543a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 544a0c0857eSWei Mi for (auto N : V) { 545a0c0857eSWei Mi encodeULEB128(MD5Hash(N), OS); 546a0c0857eSWei Mi } 547a0c0857eSWei Mi return sampleprof_error::success; 548a0c0857eSWei Mi } 549a0c0857eSWei Mi 550be907324SWei Mi std::error_code 551be907324SWei Mi SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { 552a0c0857eSWei Mi auto &OS = *OutputStream; 553760c5a8fSDiego Novillo // Write file magic identifier. 554be907324SWei Mi encodeULEB128(SPMagic(Format), OS); 555a0c0857eSWei Mi encodeULEB128(SPVersion(), OS); 556a0c0857eSWei Mi return sampleprof_error::success; 557a0c0857eSWei Mi } 558a0c0857eSWei Mi 559a0c0857eSWei Mi std::error_code SampleProfileWriterBinary::writeHeader( 560a0c0857eSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 561be907324SWei Mi writeMagicIdent(Format); 562760c5a8fSDiego Novillo 56340ee23dbSEaswaran Raman computeSummary(ProfileMap); 56440ee23dbSEaswaran Raman if (auto EC = writeSummary()) 56540ee23dbSEaswaran Raman return EC; 56640ee23dbSEaswaran Raman 567760c5a8fSDiego Novillo // Generate the name table for all the functions referenced in the profile. 568760c5a8fSDiego Novillo for (const auto &I : ProfileMap) { 56900ef28efSWenlei He assert(I.first() == I.second.getNameWithContext() && 57000ef28efSWenlei He "Inconsistent profile map"); 57100ef28efSWenlei He addName(I.first(), FunctionSamples::ProfileIsCS); 572760c5a8fSDiego Novillo addNames(I.second); 573760c5a8fSDiego Novillo } 574760c5a8fSDiego Novillo 575a0c0857eSWei Mi writeNameTable(); 576760c5a8fSDiego Novillo return sampleprof_error::success; 577c572e92cSDiego Novillo } 578c572e92cSDiego Novillo 579b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressAllSections() { 58009dcfe68SWei Mi for (auto &Entry : SectionHdrLayout) 581ebad6788SWei Mi addSecFlag(Entry, SecCommonFlags::SecFlagCompress); 582b523790aSWei Mi } 583b523790aSWei Mi 584b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) { 585ebad6788SWei Mi addSectionFlag(Type, SecCommonFlags::SecFlagCompress); 586b523790aSWei Mi } 587b523790aSWei Mi 588be907324SWei Mi void SampleProfileWriterExtBinaryBase::allocSecHdrTable() { 589be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 590be907324SWei Mi 59109dcfe68SWei Mi Writer.write(static_cast<uint64_t>(SectionHdrLayout.size())); 592be907324SWei Mi SecHdrTableOffset = OutputStream->tell(); 59309dcfe68SWei Mi for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 594be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 595be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 596be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 597be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 598be907324SWei Mi } 599be907324SWei Mi } 600be907324SWei Mi 601be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { 602be907324SWei Mi auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream); 603be907324SWei Mi uint64_t Saved = OutputStream->tell(); 604be907324SWei Mi 605be907324SWei Mi // Set OutputStream to the location saved in SecHdrTableOffset. 606be907324SWei Mi if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1) 607be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 608be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 609be907324SWei Mi 610a906e3ecSWei Mi assert(SecHdrTable.size() == SectionHdrLayout.size() && 611a906e3ecSWei Mi "SecHdrTable entries doesn't match SectionHdrLayout"); 612a906e3ecSWei Mi SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1); 613a906e3ecSWei Mi for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) { 614a906e3ecSWei Mi IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx; 615be907324SWei Mi } 616be907324SWei Mi 61709dcfe68SWei Mi // Write the section header table in the order specified in 618a906e3ecSWei Mi // SectionHdrLayout. SectionHdrLayout specifies the sections 619a906e3ecSWei Mi // order in which profile reader expect to read, so the section 620a906e3ecSWei Mi // header table should be written in the order in SectionHdrLayout. 621a906e3ecSWei Mi // Note that the section order in SecHdrTable may be different 622a906e3ecSWei Mi // from the order in SectionHdrLayout, for example, SecFuncOffsetTable 623a906e3ecSWei Mi // needs to be computed after SecLBRProfile (the order in SecHdrTable), 624a906e3ecSWei Mi // but it needs to be read before SecLBRProfile (the order in 625a906e3ecSWei Mi // SectionHdrLayout). So we use IndexMap above to switch the order. 626a906e3ecSWei Mi for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size(); 627a906e3ecSWei Mi LayoutIdx++) { 628a906e3ecSWei Mi assert(IndexMap[LayoutIdx] < SecHdrTable.size() && 629a906e3ecSWei Mi "Incorrect LayoutIdx in SecHdrTable"); 630a906e3ecSWei Mi auto Entry = SecHdrTable[IndexMap[LayoutIdx]]; 631a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Type)); 632a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Flags)); 633a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Offset)); 634a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Size)); 635be907324SWei Mi } 636be907324SWei Mi 637be907324SWei Mi // Reset OutputStream. 638be907324SWei Mi if (OFS.seek(Saved) == (uint64_t)-1) 639be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 640be907324SWei Mi 641be907324SWei Mi return sampleprof_error::success; 642be907324SWei Mi } 643be907324SWei Mi 644be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeHeader( 645be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 646be907324SWei Mi auto &OS = *OutputStream; 647be907324SWei Mi FileStart = OS.tell(); 648be907324SWei Mi writeMagicIdent(Format); 649be907324SWei Mi 650be907324SWei Mi allocSecHdrTable(); 651be907324SWei Mi return sampleprof_error::success; 652be907324SWei Mi } 653be907324SWei Mi 6546a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader( 6556a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 6566a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 6576a14325dSWei Mi if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) 6586a14325dSWei Mi return EC; 6596a14325dSWei Mi 6606a14325dSWei Mi // Reserve a slot for the offset of function offset table. The slot will 6616a14325dSWei Mi // be populated with the offset of FuncOffsetTable later. 6626a14325dSWei Mi TableOffset = OutputStream->tell(); 6636a14325dSWei Mi Writer.write(static_cast<uint64_t>(-2)); 6646a14325dSWei Mi return sampleprof_error::success; 6656a14325dSWei Mi } 6666a14325dSWei Mi 66740ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() { 66840ee23dbSEaswaran Raman auto &OS = *OutputStream; 6697cefdb81SEaswaran Raman encodeULEB128(Summary->getTotalCount(), OS); 6707cefdb81SEaswaran Raman encodeULEB128(Summary->getMaxCount(), OS); 6716f4903d9SEaswaran Raman encodeULEB128(Summary->getMaxFunctionCount(), OS); 6727cefdb81SEaswaran Raman encodeULEB128(Summary->getNumCounts(), OS); 67340ee23dbSEaswaran Raman encodeULEB128(Summary->getNumFunctions(), OS); 67440ee23dbSEaswaran Raman std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 67540ee23dbSEaswaran Raman encodeULEB128(Entries.size(), OS); 67640ee23dbSEaswaran Raman for (auto Entry : Entries) { 67740ee23dbSEaswaran Raman encodeULEB128(Entry.Cutoff, OS); 67840ee23dbSEaswaran Raman encodeULEB128(Entry.MinCount, OS); 67940ee23dbSEaswaran Raman encodeULEB128(Entry.NumCounts, OS); 68040ee23dbSEaswaran Raman } 68140ee23dbSEaswaran Raman return sampleprof_error::success; 68240ee23dbSEaswaran Raman } 68357d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 68451abea74SNathan Slingerland auto &OS = *OutputStream; 68551abea74SNathan Slingerland 68600ef28efSWenlei He if (std::error_code EC = 68700ef28efSWenlei He writeNameIdx(S.getNameWithContext(), FunctionSamples::ProfileIsCS)) 688760c5a8fSDiego Novillo return EC; 689760c5a8fSDiego Novillo 690c572e92cSDiego Novillo encodeULEB128(S.getTotalSamples(), OS); 691a7f1e8efSDiego Novillo 692a7f1e8efSDiego Novillo // Emit all the body samples. 693b93483dbSDiego Novillo encodeULEB128(S.getBodySamples().size(), OS); 694d5336ae2SDiego Novillo for (const auto &I : S.getBodySamples()) { 695d5336ae2SDiego Novillo LineLocation Loc = I.first; 696d5336ae2SDiego Novillo const SampleRecord &Sample = I.second; 697c572e92cSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 698c572e92cSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 699c572e92cSDiego Novillo encodeULEB128(Sample.getSamples(), OS); 700c572e92cSDiego Novillo encodeULEB128(Sample.getCallTargets().size(), OS); 7015adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) { 7025adace35SWenlei He StringRef Callee = J.first; 70338be3330SDiego Novillo uint64_t CalleeSamples = J.second; 704760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(Callee)) 705760c5a8fSDiego Novillo return EC; 706c572e92cSDiego Novillo encodeULEB128(CalleeSamples, OS); 707c572e92cSDiego Novillo } 708c572e92cSDiego Novillo } 709c572e92cSDiego Novillo 710a7f1e8efSDiego Novillo // Recursively emit all the callsite samples. 7112c27daf7SDehao Chen uint64_t NumCallsites = 0; 7122c27daf7SDehao Chen for (const auto &J : S.getCallsiteSamples()) 7132c27daf7SDehao Chen NumCallsites += J.second.size(); 7142c27daf7SDehao Chen encodeULEB128(NumCallsites, OS); 7152c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 7162c7ca9b5SDehao Chen for (const auto &FS : J.second) { 71757d1dda5SDehao Chen LineLocation Loc = J.first; 7182c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 719a7f1e8efSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 720a7f1e8efSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 72157d1dda5SDehao Chen if (std::error_code EC = writeBody(CalleeSamples)) 722760c5a8fSDiego Novillo return EC; 723a7f1e8efSDiego Novillo } 724a7f1e8efSDiego Novillo 725760c5a8fSDiego Novillo return sampleprof_error::success; 726c572e92cSDiego Novillo } 727d5336ae2SDiego Novillo 7285f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file. 729b93483dbSDiego Novillo /// 730b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise. 731be907324SWei Mi std::error_code 732be907324SWei Mi SampleProfileWriterBinary::writeSample(const FunctionSamples &S) { 73351abea74SNathan Slingerland encodeULEB128(S.getHeadSamples(), *OutputStream); 73457d1dda5SDehao Chen return writeBody(S); 735b93483dbSDiego Novillo } 736b93483dbSDiego Novillo 7376a14325dSWei Mi std::error_code 738be907324SWei Mi SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) { 7396a14325dSWei Mi uint64_t Offset = OutputStream->tell(); 7406a14325dSWei Mi StringRef Name = S.getName(); 7416a14325dSWei Mi FuncOffsetTable[Name] = Offset; 7426a14325dSWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream); 7436a14325dSWei Mi return writeBody(S); 7446a14325dSWei Mi } 7456a14325dSWei Mi 7465f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format. 747d5336ae2SDiego Novillo /// 748d5336ae2SDiego Novillo /// \param Filename The file to create. 749d5336ae2SDiego Novillo /// 750d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file. 751d5336ae2SDiego Novillo /// 752d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer. 753fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>> 754fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 755d5336ae2SDiego Novillo std::error_code EC; 75651abea74SNathan Slingerland std::unique_ptr<raw_ostream> OS; 757be907324SWei Mi if (Format == SPF_Binary || Format == SPF_Ext_Binary || 758be907324SWei Mi Format == SPF_Compact_Binary) 759d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None)); 76051abea74SNathan Slingerland else 76182b3e28eSAbhina Sreeskantharajan OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF)); 76251abea74SNathan Slingerland if (EC) 76351abea74SNathan Slingerland return EC; 76451abea74SNathan Slingerland 76551abea74SNathan Slingerland return create(OS, Format); 76651abea74SNathan Slingerland } 76751abea74SNathan Slingerland 7685f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format. 76951abea74SNathan Slingerland /// 77051abea74SNathan Slingerland /// \param OS The output stream to store the profile data to. 77151abea74SNathan Slingerland /// 77251abea74SNathan Slingerland /// \param Format Encoding format for the profile file. 77351abea74SNathan Slingerland /// 77451abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer. 77551abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>> 77651abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 77751abea74SNathan Slingerland SampleProfileFormat Format) { 77851abea74SNathan Slingerland std::error_code EC; 779fcd55607SDiego Novillo std::unique_ptr<SampleProfileWriter> Writer; 780d5336ae2SDiego Novillo 781b2d07937SWenlei He // Currently only Text and Extended Binary format are supported for CSSPGO. 782b2d07937SWenlei He if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) && 783b2d07937SWenlei He (Format == SPF_Binary || Format == SPF_Compact_Binary)) 784b2d07937SWenlei He return sampleprof_error::unsupported_writing_format; 785b2d07937SWenlei He 786d9be2c7eSWei Mi if (Format == SPF_Binary) 787a0c0857eSWei Mi Writer.reset(new SampleProfileWriterRawBinary(OS)); 788be907324SWei Mi else if (Format == SPF_Ext_Binary) 789be907324SWei Mi Writer.reset(new SampleProfileWriterExtBinary(OS)); 790a0c0857eSWei Mi else if (Format == SPF_Compact_Binary) 791a0c0857eSWei Mi Writer.reset(new SampleProfileWriterCompactBinary(OS)); 792d5336ae2SDiego Novillo else if (Format == SPF_Text) 79351abea74SNathan Slingerland Writer.reset(new SampleProfileWriterText(OS)); 794760c5a8fSDiego Novillo else if (Format == SPF_GCC) 795760c5a8fSDiego Novillo EC = sampleprof_error::unsupported_writing_format; 796d5336ae2SDiego Novillo else 797d5336ae2SDiego Novillo EC = sampleprof_error::unrecognized_format; 798d5336ae2SDiego Novillo 799fcd55607SDiego Novillo if (EC) 800d5336ae2SDiego Novillo return EC; 801fcd55607SDiego Novillo 802be907324SWei Mi Writer->Format = Format; 803c55cf4afSBill Wendling return std::move(Writer); 804d5336ae2SDiego Novillo } 80540ee23dbSEaswaran Raman 80640ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary( 80740ee23dbSEaswaran Raman const StringMap<FunctionSamples> &ProfileMap) { 808e5a17e3fSEaswaran Raman SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 809801d9cc7SWenlei He Summary = Builder.computeSummaryForProfiles(ProfileMap); 81040ee23dbSEaswaran Raman } 811