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; 498d1c983fSDehao Chen for (const auto &I : ProfileMap) 508d1c983fSDehao Chen V.push_back(std::make_pair(I.getKey(), &I.second)); 518d1c983fSDehao Chen 52efd94c56SFangrui Song llvm::stable_sort( 53efd94c56SFangrui Song V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) { 548d1c983fSDehao Chen if (A.second->getTotalSamples() == B.second->getTotalSamples()) 558d1c983fSDehao Chen return A.first > B.first; 568d1c983fSDehao Chen return A.second->getTotalSamples() > B.second->getTotalSamples(); 578d1c983fSDehao Chen }); 588d1c983fSDehao Chen 598d1c983fSDehao Chen for (const auto &I : V) { 60be907324SWei Mi if (std::error_code EC = writeSample(*I.second)) 618d1c983fSDehao Chen return EC; 628d1c983fSDehao Chen } 638d1c983fSDehao Chen return sampleprof_error::success; 648d1c983fSDehao Chen } 658d1c983fSDehao Chen 66be907324SWei Mi std::error_code 67be907324SWei Mi SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) { 68be907324SWei Mi if (std::error_code EC = writeHeader(ProfileMap)) 69be907324SWei Mi return EC; 70be907324SWei Mi 71be907324SWei Mi if (std::error_code EC = writeFuncProfiles(ProfileMap)) 72be907324SWei Mi return EC; 73be907324SWei Mi 74be907324SWei Mi return sampleprof_error::success; 75be907324SWei Mi } 76be907324SWei Mi 77b523790aSWei Mi /// Return the current position and prepare to use it as the start 78a906e3ecSWei Mi /// position of a section given the section type \p Type and its position 79a906e3ecSWei Mi /// \p LayoutIdx in SectionHdrLayout. 80a906e3ecSWei Mi uint64_t 81a906e3ecSWei Mi SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type, 82a906e3ecSWei Mi uint32_t LayoutIdx) { 83b523790aSWei Mi uint64_t SectionStart = OutputStream->tell(); 84a906e3ecSWei Mi assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range"); 85a906e3ecSWei Mi const auto &Entry = SectionHdrLayout[LayoutIdx]; 86a906e3ecSWei Mi assert(Entry.Type == Type && "Unexpected section type"); 87b523790aSWei Mi // Use LocalBuf as a temporary output for writting data. 88ebad6788SWei Mi if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) 89b523790aSWei Mi LocalBufStream.swap(OutputStream); 90b523790aSWei Mi return SectionStart; 91b523790aSWei Mi } 92b523790aSWei Mi 93b523790aSWei Mi std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() { 94b523790aSWei Mi if (!llvm::zlib::isAvailable()) 95b523790aSWei Mi return sampleprof_error::zlib_unavailable; 96b523790aSWei Mi std::string &UncompressedStrings = 97b523790aSWei Mi static_cast<raw_string_ostream *>(LocalBufStream.get())->str(); 98b523790aSWei Mi if (UncompressedStrings.size() == 0) 99b523790aSWei Mi return sampleprof_error::success; 100b523790aSWei Mi auto &OS = *OutputStream; 101b523790aSWei Mi SmallString<128> CompressedStrings; 102b523790aSWei Mi llvm::Error E = zlib::compress(UncompressedStrings, CompressedStrings, 103b523790aSWei Mi zlib::BestSizeCompression); 104b523790aSWei Mi if (E) 105b523790aSWei Mi return sampleprof_error::compress_failed; 106b523790aSWei Mi encodeULEB128(UncompressedStrings.size(), OS); 107b523790aSWei Mi encodeULEB128(CompressedStrings.size(), OS); 108b523790aSWei Mi OS << CompressedStrings.str(); 109b523790aSWei Mi UncompressedStrings.clear(); 110b523790aSWei Mi return sampleprof_error::success; 111b523790aSWei Mi } 112b523790aSWei Mi 113a906e3ecSWei Mi /// Add a new section into section header table given the section type 114a906e3ecSWei Mi /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the 115a906e3ecSWei Mi /// location \p SectionStart where the section should be written to. 116a906e3ecSWei Mi std::error_code SampleProfileWriterExtBinaryBase::addNewSection( 117a906e3ecSWei Mi SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) { 118a906e3ecSWei Mi assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range"); 119a906e3ecSWei Mi const auto &Entry = SectionHdrLayout[LayoutIdx]; 120a906e3ecSWei Mi assert(Entry.Type == Type && "Unexpected section type"); 121ebad6788SWei Mi if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) { 122b523790aSWei Mi LocalBufStream.swap(OutputStream); 123b523790aSWei Mi if (std::error_code EC = compressAndOutput()) 124b523790aSWei Mi return EC; 125b523790aSWei Mi } 126b523790aSWei Mi SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart, 127a906e3ecSWei Mi OutputStream->tell() - SectionStart, LayoutIdx}); 128b523790aSWei Mi return sampleprof_error::success; 129be907324SWei Mi } 130be907324SWei Mi 131be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::write( 132be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 133be907324SWei Mi if (std::error_code EC = writeHeader(ProfileMap)) 134be907324SWei Mi return EC; 135be907324SWei Mi 136b523790aSWei Mi std::string LocalBuf; 137b523790aSWei Mi LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf); 138be907324SWei Mi if (std::error_code EC = writeSections(ProfileMap)) 139be907324SWei Mi return EC; 140be907324SWei Mi 141be907324SWei Mi if (std::error_code EC = writeSecHdrTable()) 142be907324SWei Mi return EC; 143be907324SWei Mi 144be907324SWei Mi return sampleprof_error::success; 145be907324SWei Mi } 146be907324SWei Mi 14709dcfe68SWei Mi std::error_code 14893953d41SWei Mi SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) { 14909dcfe68SWei Mi uint64_t Offset = OutputStream->tell(); 1507e99bddfSHongtao Yu StringRef Name = S.getNameWithContext(true); 15109dcfe68SWei Mi FuncOffsetTable[Name] = Offset - SecLBRProfileStart; 15209dcfe68SWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream); 15309dcfe68SWei Mi return writeBody(S); 15409dcfe68SWei Mi } 15509dcfe68SWei Mi 15693953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() { 15709dcfe68SWei Mi auto &OS = *OutputStream; 15809dcfe68SWei Mi 15909dcfe68SWei Mi // Write out the table size. 16009dcfe68SWei Mi encodeULEB128(FuncOffsetTable.size(), OS); 16109dcfe68SWei Mi 16209dcfe68SWei Mi // Write out FuncOffsetTable. 16309dcfe68SWei Mi for (auto entry : FuncOffsetTable) { 16409dcfe68SWei Mi writeNameIdx(entry.first); 16509dcfe68SWei Mi encodeULEB128(entry.second, OS); 16609dcfe68SWei Mi } 167a906e3ecSWei Mi FuncOffsetTable.clear(); 16809dcfe68SWei Mi return sampleprof_error::success; 16909dcfe68SWei Mi } 17009dcfe68SWei Mi 171ac068e01SHongtao Yu std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata( 172ac068e01SHongtao Yu const StringMap<FunctionSamples> &Profiles) { 173ac068e01SHongtao Yu if (!FunctionSamples::ProfileIsProbeBased) 174ac068e01SHongtao Yu return sampleprof_error::success; 175ac068e01SHongtao Yu auto &OS = *OutputStream; 176ac068e01SHongtao Yu for (const auto &Entry : Profiles) { 177ac068e01SHongtao Yu writeNameIdx(Entry.first()); 178ac068e01SHongtao Yu encodeULEB128(Entry.second.getFunctionHash(), OS); 179ac068e01SHongtao Yu } 180ac068e01SHongtao Yu return sampleprof_error::success; 181ac068e01SHongtao Yu } 182ac068e01SHongtao Yu 18393953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() { 184ebad6788SWei Mi if (!UseMD5) 185ebad6788SWei Mi return SampleProfileWriterBinary::writeNameTable(); 186ebad6788SWei Mi 187ebad6788SWei Mi auto &OS = *OutputStream; 188ebad6788SWei Mi std::set<StringRef> V; 189ebad6788SWei Mi stablizeNameTable(V); 190ebad6788SWei Mi 19164e76853SWei Mi // Write out the MD5 name table. We wrote unencoded MD5 so reader can 19264e76853SWei Mi // retrieve the name using the name index without having to read the 19364e76853SWei Mi // whole name table. 194ebad6788SWei Mi encodeULEB128(NameTable.size(), OS); 19564e76853SWei Mi support::endian::Writer Writer(OS, support::little); 19664e76853SWei Mi for (auto N : V) 19764e76853SWei Mi Writer.write(MD5Hash(N)); 198ebad6788SWei Mi return sampleprof_error::success; 199ebad6788SWei Mi } 200ebad6788SWei Mi 20193953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection( 202be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 203be907324SWei Mi for (const auto &I : ProfileMap) { 204be907324SWei Mi addName(I.first()); 205be907324SWei Mi addNames(I.second); 206be907324SWei Mi } 207ee35784aSWei Mi 208ee35784aSWei Mi // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag 209ee35784aSWei Mi // so compiler won't strip the suffix during profile matching after 210ee35784aSWei Mi // seeing the flag in the profile. 211ee35784aSWei Mi for (const auto &I : NameTable) { 212ee35784aSWei Mi if (I.first.find(FunctionSamples::UniqSuffix) != StringRef::npos) { 213ee35784aSWei Mi addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix); 214ee35784aSWei Mi break; 215ee35784aSWei Mi } 216ee35784aSWei Mi } 217ee35784aSWei Mi 21893953d41SWei Mi if (auto EC = writeNameTable()) 219b523790aSWei Mi return EC; 22093953d41SWei Mi return sampleprof_error::success; 22193953d41SWei Mi } 222be907324SWei Mi 22393953d41SWei Mi std::error_code 22493953d41SWei Mi SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() { 225798e59b8SWei Mi if (ProfSymList && ProfSymList->size() > 0) 226798e59b8SWei Mi if (std::error_code EC = ProfSymList->write(*OutputStream)) 227798e59b8SWei Mi return EC; 228be907324SWei Mi 22993953d41SWei Mi return sampleprof_error::success; 23093953d41SWei Mi } 23109dcfe68SWei Mi 23293953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeOneSection( 233a906e3ecSWei Mi SecType Type, uint32_t LayoutIdx, 234a906e3ecSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 23593953d41SWei Mi // The setting of SecFlagCompress should happen before markSectionStart. 23693953d41SWei Mi if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress()) 23793953d41SWei Mi setToCompressSection(SecProfileSymbolList); 238ac068e01SHongtao Yu if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased) 239ac068e01SHongtao Yu addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased); 240*a5d30421SWenlei He if (Type == SecProfSummary && FunctionSamples::ProfileIsCS) 241*a5d30421SWenlei He addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext); 24293953d41SWei Mi 243a906e3ecSWei Mi uint64_t SectionStart = markSectionStart(Type, LayoutIdx); 24493953d41SWei Mi switch (Type) { 24593953d41SWei Mi case SecProfSummary: 24693953d41SWei Mi computeSummary(ProfileMap); 24793953d41SWei Mi if (auto EC = writeSummary()) 24893953d41SWei Mi return EC; 24993953d41SWei Mi break; 25093953d41SWei Mi case SecNameTable: 25193953d41SWei Mi if (auto EC = writeNameTableSection(ProfileMap)) 25293953d41SWei Mi return EC; 25393953d41SWei Mi break; 25493953d41SWei Mi case SecLBRProfile: 25593953d41SWei Mi SecLBRProfileStart = OutputStream->tell(); 25693953d41SWei Mi if (std::error_code EC = writeFuncProfiles(ProfileMap)) 25793953d41SWei Mi return EC; 25893953d41SWei Mi break; 25993953d41SWei Mi case SecFuncOffsetTable: 26093953d41SWei Mi if (auto EC = writeFuncOffsetTable()) 26193953d41SWei Mi return EC; 26293953d41SWei Mi break; 263ac068e01SHongtao Yu case SecFuncMetadata: 264ac068e01SHongtao Yu if (std::error_code EC = writeFuncMetadata(ProfileMap)) 265ac068e01SHongtao Yu return EC; 266ac068e01SHongtao Yu break; 26793953d41SWei Mi case SecProfileSymbolList: 26893953d41SWei Mi if (auto EC = writeProfileSymbolListSection()) 26993953d41SWei Mi return EC; 27093953d41SWei Mi break; 27193953d41SWei Mi default: 27293953d41SWei Mi if (auto EC = writeCustomSection(Type)) 27393953d41SWei Mi return EC; 27493953d41SWei Mi break; 27593953d41SWei Mi } 276a906e3ecSWei Mi if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart)) 27793953d41SWei Mi return EC; 27893953d41SWei Mi return sampleprof_error::success; 27993953d41SWei Mi } 28093953d41SWei Mi 28121b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeDefaultLayout( 28293953d41SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 283a906e3ecSWei Mi // The const indices passed to writeOneSection below are specifying the 284a906e3ecSWei Mi // positions of the sections in SectionHdrLayout. Look at 285a906e3ecSWei Mi // initSectionHdrLayout to find out where each section is located in 286a906e3ecSWei Mi // SectionHdrLayout. 287a906e3ecSWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 28893953d41SWei Mi return EC; 289a906e3ecSWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 29093953d41SWei Mi return EC; 291a906e3ecSWei Mi if (auto EC = writeOneSection(SecLBRProfile, 3, ProfileMap)) 29293953d41SWei Mi return EC; 293a906e3ecSWei Mi if (auto EC = writeOneSection(SecProfileSymbolList, 4, ProfileMap)) 29493953d41SWei Mi return EC; 295a906e3ecSWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ProfileMap)) 29693953d41SWei Mi return EC; 297a906e3ecSWei Mi if (auto EC = writeOneSection(SecFuncMetadata, 5, ProfileMap)) 298ac068e01SHongtao Yu return EC; 299be907324SWei Mi return sampleprof_error::success; 300be907324SWei Mi } 301be907324SWei Mi 30221b1ad03SWei Mi static void 30321b1ad03SWei Mi splitProfileMapToTwo(const StringMap<FunctionSamples> &ProfileMap, 30421b1ad03SWei Mi StringMap<FunctionSamples> &ContextProfileMap, 30521b1ad03SWei Mi StringMap<FunctionSamples> &NoContextProfileMap) { 30621b1ad03SWei Mi for (const auto &I : ProfileMap) { 30721b1ad03SWei Mi if (I.second.getCallsiteSamples().size()) 30821b1ad03SWei Mi ContextProfileMap.insert({I.first(), I.second}); 30921b1ad03SWei Mi else 31021b1ad03SWei Mi NoContextProfileMap.insert({I.first(), I.second}); 31121b1ad03SWei Mi } 31221b1ad03SWei Mi } 31321b1ad03SWei Mi 31421b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout( 31521b1ad03SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 31621b1ad03SWei Mi StringMap<FunctionSamples> ContextProfileMap, NoContextProfileMap; 31721b1ad03SWei Mi splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap); 31821b1ad03SWei Mi 31921b1ad03SWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 32021b1ad03SWei Mi return EC; 32121b1ad03SWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 32221b1ad03SWei Mi return EC; 32321b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap)) 32421b1ad03SWei Mi return EC; 32521b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap)) 32621b1ad03SWei Mi return EC; 32721b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set 32821b1ad03SWei Mi // before writing the section. 32921b1ad03SWei Mi addSectionFlag(5, SecCommonFlags::SecFlagFlat); 33021b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap)) 33121b1ad03SWei Mi return EC; 33221b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set 33321b1ad03SWei Mi // before writing the section. 33421b1ad03SWei Mi addSectionFlag(4, SecCommonFlags::SecFlagFlat); 33521b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap)) 33621b1ad03SWei Mi return EC; 33721b1ad03SWei Mi if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap)) 33821b1ad03SWei Mi return EC; 33921b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap)) 34021b1ad03SWei Mi return EC; 34121b1ad03SWei Mi 34221b1ad03SWei Mi return sampleprof_error::success; 34321b1ad03SWei Mi } 34421b1ad03SWei Mi 34521b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeSections( 34621b1ad03SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 34721b1ad03SWei Mi std::error_code EC; 34821b1ad03SWei Mi if (SecLayout == DefaultLayout) 34921b1ad03SWei Mi EC = writeDefaultLayout(ProfileMap); 35021b1ad03SWei Mi else if (SecLayout == CtxSplitLayout) 35121b1ad03SWei Mi EC = writeCtxSplitLayout(ProfileMap); 35221b1ad03SWei Mi else 35321b1ad03SWei Mi llvm_unreachable("Unsupported layout"); 35421b1ad03SWei Mi return EC; 35521b1ad03SWei Mi } 35621b1ad03SWei Mi 3576a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::write( 3586a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 3596a14325dSWei Mi if (std::error_code EC = SampleProfileWriter::write(ProfileMap)) 3606a14325dSWei Mi return EC; 3616a14325dSWei Mi if (std::error_code EC = writeFuncOffsetTable()) 3626a14325dSWei Mi return EC; 3636a14325dSWei Mi return sampleprof_error::success; 3646a14325dSWei Mi } 3656a14325dSWei Mi 3665f8f34e4SAdrian Prantl /// Write samples to a text file. 3678e415a82SDiego Novillo /// 3688e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of 369ef548d29SDiego Novillo /// FunctionSamples::print(). Please don't. The dump functionality is intended 3708e415a82SDiego Novillo /// for debugging and has no specified form. 3718e415a82SDiego Novillo /// 3728e415a82SDiego Novillo /// The format used here is more structured and deliberate because 3738e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class. 374be907324SWei Mi std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { 37551abea74SNathan Slingerland auto &OS = *OutputStream; 376c3aeabaeSwlei OS << S.getNameWithContext(true) << ":" << S.getTotalSamples(); 377aae1ed8eSDiego Novillo if (Indent == 0) 378aae1ed8eSDiego Novillo OS << ":" << S.getHeadSamples(); 379aae1ed8eSDiego Novillo OS << "\n"; 380c572e92cSDiego Novillo 381ef548d29SDiego Novillo SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 382ef548d29SDiego Novillo for (const auto &I : SortedSamples.get()) { 383ef548d29SDiego Novillo LineLocation Loc = I->first; 384ef548d29SDiego Novillo const SampleRecord &Sample = I->second; 385aae1ed8eSDiego Novillo OS.indent(Indent + 1); 386c572e92cSDiego Novillo if (Loc.Discriminator == 0) 387c572e92cSDiego Novillo OS << Loc.LineOffset << ": "; 388c572e92cSDiego Novillo else 389c572e92cSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 390c572e92cSDiego Novillo 391c572e92cSDiego Novillo OS << Sample.getSamples(); 392c572e92cSDiego Novillo 3935adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) 3945adace35SWenlei He OS << " " << J.first << ":" << J.second; 395c572e92cSDiego Novillo OS << "\n"; 396c572e92cSDiego Novillo } 397c572e92cSDiego Novillo 3982c7ca9b5SDehao Chen SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 399ef548d29SDiego Novillo S.getCallsiteSamples()); 400aae1ed8eSDiego Novillo Indent += 1; 4012c7ca9b5SDehao Chen for (const auto &I : SortedCallsiteSamples.get()) 4022c7ca9b5SDehao Chen for (const auto &FS : I->second) { 40357d1dda5SDehao Chen LineLocation Loc = I->first; 4042c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 405aae1ed8eSDiego Novillo OS.indent(Indent); 406aae1ed8eSDiego Novillo if (Loc.Discriminator == 0) 407aae1ed8eSDiego Novillo OS << Loc.LineOffset << ": "; 408aae1ed8eSDiego Novillo else 409aae1ed8eSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 410be907324SWei Mi if (std::error_code EC = writeSample(CalleeSamples)) 411760c5a8fSDiego Novillo return EC; 412aae1ed8eSDiego Novillo } 413aae1ed8eSDiego Novillo Indent -= 1; 414aae1ed8eSDiego Novillo 415ac068e01SHongtao Yu if (Indent == 0) { 416ac068e01SHongtao Yu if (FunctionSamples::ProfileIsProbeBased) { 417ac068e01SHongtao Yu OS.indent(Indent + 1); 418ac068e01SHongtao Yu OS << "!CFGChecksum: " << S.getFunctionHash() << "\n"; 419ac068e01SHongtao Yu } 420ac068e01SHongtao Yu } 421ac068e01SHongtao Yu 422760c5a8fSDiego Novillo return sampleprof_error::success; 423c572e92cSDiego Novillo } 424c572e92cSDiego Novillo 425760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 426760c5a8fSDiego Novillo const auto &ret = NameTable.find(FName); 427760c5a8fSDiego Novillo if (ret == NameTable.end()) 428760c5a8fSDiego Novillo return sampleprof_error::truncated_name_table; 42951abea74SNathan Slingerland encodeULEB128(ret->second, *OutputStream); 430760c5a8fSDiego Novillo return sampleprof_error::success; 431760c5a8fSDiego Novillo } 432c572e92cSDiego Novillo 433760c5a8fSDiego Novillo void SampleProfileWriterBinary::addName(StringRef FName) { 4348d1c983fSDehao Chen NameTable.insert(std::make_pair(FName, 0)); 435760c5a8fSDiego Novillo } 436760c5a8fSDiego Novillo 437760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 438760c5a8fSDiego Novillo // Add all the names in indirect call targets. 439760c5a8fSDiego Novillo for (const auto &I : S.getBodySamples()) { 440760c5a8fSDiego Novillo const SampleRecord &Sample = I.second; 441760c5a8fSDiego Novillo for (const auto &J : Sample.getCallTargets()) 442760c5a8fSDiego Novillo addName(J.first()); 443760c5a8fSDiego Novillo } 444760c5a8fSDiego Novillo 445760c5a8fSDiego Novillo // Recursively add all the names for inlined callsites. 4462c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 4472c7ca9b5SDehao Chen for (const auto &FS : J.second) { 4482c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 44957d1dda5SDehao Chen addName(CalleeSamples.getName()); 450760c5a8fSDiego Novillo addNames(CalleeSamples); 451760c5a8fSDiego Novillo } 452760c5a8fSDiego Novillo } 453760c5a8fSDiego Novillo 454a0c0857eSWei Mi void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) { 455a0c0857eSWei Mi // Sort the names to make NameTable deterministic. 456a0c0857eSWei Mi for (const auto &I : NameTable) 457a0c0857eSWei Mi V.insert(I.first); 458a0c0857eSWei Mi int i = 0; 459a0c0857eSWei Mi for (const StringRef &N : V) 460a0c0857eSWei Mi NameTable[N] = i++; 461a0c0857eSWei Mi } 46251abea74SNathan Slingerland 463be907324SWei Mi std::error_code SampleProfileWriterBinary::writeNameTable() { 464a0c0857eSWei Mi auto &OS = *OutputStream; 465a0c0857eSWei Mi std::set<StringRef> V; 466a0c0857eSWei Mi stablizeNameTable(V); 467a0c0857eSWei Mi 468a0c0857eSWei Mi // Write out the name table. 469a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 470a0c0857eSWei Mi for (auto N : V) { 471a0c0857eSWei Mi OS << N; 472a0c0857eSWei Mi encodeULEB128(0, OS); 473a0c0857eSWei Mi } 474a0c0857eSWei Mi return sampleprof_error::success; 475a0c0857eSWei Mi } 476a0c0857eSWei Mi 4776a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { 4786a14325dSWei Mi auto &OS = *OutputStream; 4796a14325dSWei Mi 4806a14325dSWei Mi // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. 4816a14325dSWei Mi auto &OFS = static_cast<raw_fd_ostream &>(OS); 4826a14325dSWei Mi uint64_t FuncOffsetTableStart = OS.tell(); 4836a14325dSWei Mi if (OFS.seek(TableOffset) == (uint64_t)-1) 4846a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 4856a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 4866a14325dSWei Mi Writer.write(FuncOffsetTableStart); 4876a14325dSWei Mi if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) 4886a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 4896a14325dSWei Mi 4906a14325dSWei Mi // Write out the table size. 4916a14325dSWei Mi encodeULEB128(FuncOffsetTable.size(), OS); 4926a14325dSWei Mi 4936a14325dSWei Mi // Write out FuncOffsetTable. 4946a14325dSWei Mi for (auto entry : FuncOffsetTable) { 4956a14325dSWei Mi writeNameIdx(entry.first); 4966a14325dSWei Mi encodeULEB128(entry.second, OS); 4976a14325dSWei Mi } 4986a14325dSWei Mi return sampleprof_error::success; 4996a14325dSWei Mi } 5006a14325dSWei Mi 501a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() { 502a0c0857eSWei Mi auto &OS = *OutputStream; 503a0c0857eSWei Mi std::set<StringRef> V; 504a0c0857eSWei Mi stablizeNameTable(V); 505a0c0857eSWei Mi 506a0c0857eSWei Mi // Write out the name table. 507a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 508a0c0857eSWei Mi for (auto N : V) { 509a0c0857eSWei Mi encodeULEB128(MD5Hash(N), OS); 510a0c0857eSWei Mi } 511a0c0857eSWei Mi return sampleprof_error::success; 512a0c0857eSWei Mi } 513a0c0857eSWei Mi 514be907324SWei Mi std::error_code 515be907324SWei Mi SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { 516a0c0857eSWei Mi auto &OS = *OutputStream; 517760c5a8fSDiego Novillo // Write file magic identifier. 518be907324SWei Mi encodeULEB128(SPMagic(Format), OS); 519a0c0857eSWei Mi encodeULEB128(SPVersion(), OS); 520a0c0857eSWei Mi return sampleprof_error::success; 521a0c0857eSWei Mi } 522a0c0857eSWei Mi 523a0c0857eSWei Mi std::error_code SampleProfileWriterBinary::writeHeader( 524a0c0857eSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 525be907324SWei Mi writeMagicIdent(Format); 526760c5a8fSDiego Novillo 52740ee23dbSEaswaran Raman computeSummary(ProfileMap); 52840ee23dbSEaswaran Raman if (auto EC = writeSummary()) 52940ee23dbSEaswaran Raman return EC; 53040ee23dbSEaswaran Raman 531760c5a8fSDiego Novillo // Generate the name table for all the functions referenced in the profile. 532760c5a8fSDiego Novillo for (const auto &I : ProfileMap) { 533760c5a8fSDiego Novillo addName(I.first()); 534760c5a8fSDiego Novillo addNames(I.second); 535760c5a8fSDiego Novillo } 536760c5a8fSDiego Novillo 537a0c0857eSWei Mi writeNameTable(); 538760c5a8fSDiego Novillo return sampleprof_error::success; 539c572e92cSDiego Novillo } 540c572e92cSDiego Novillo 541b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressAllSections() { 54209dcfe68SWei Mi for (auto &Entry : SectionHdrLayout) 543ebad6788SWei Mi addSecFlag(Entry, SecCommonFlags::SecFlagCompress); 544b523790aSWei Mi } 545b523790aSWei Mi 546b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) { 547ebad6788SWei Mi addSectionFlag(Type, SecCommonFlags::SecFlagCompress); 548b523790aSWei Mi } 549b523790aSWei Mi 550be907324SWei Mi void SampleProfileWriterExtBinaryBase::allocSecHdrTable() { 551be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 552be907324SWei Mi 55309dcfe68SWei Mi Writer.write(static_cast<uint64_t>(SectionHdrLayout.size())); 554be907324SWei Mi SecHdrTableOffset = OutputStream->tell(); 55509dcfe68SWei Mi for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 556be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 557be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 558be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 559be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 560be907324SWei Mi } 561be907324SWei Mi } 562be907324SWei Mi 563be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { 564be907324SWei Mi auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream); 565be907324SWei Mi uint64_t Saved = OutputStream->tell(); 566be907324SWei Mi 567be907324SWei Mi // Set OutputStream to the location saved in SecHdrTableOffset. 568be907324SWei Mi if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1) 569be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 570be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 571be907324SWei Mi 572a906e3ecSWei Mi assert(SecHdrTable.size() == SectionHdrLayout.size() && 573a906e3ecSWei Mi "SecHdrTable entries doesn't match SectionHdrLayout"); 574a906e3ecSWei Mi SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1); 575a906e3ecSWei Mi for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) { 576a906e3ecSWei Mi IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx; 577be907324SWei Mi } 578be907324SWei Mi 57909dcfe68SWei Mi // Write the section header table in the order specified in 580a906e3ecSWei Mi // SectionHdrLayout. SectionHdrLayout specifies the sections 581a906e3ecSWei Mi // order in which profile reader expect to read, so the section 582a906e3ecSWei Mi // header table should be written in the order in SectionHdrLayout. 583a906e3ecSWei Mi // Note that the section order in SecHdrTable may be different 584a906e3ecSWei Mi // from the order in SectionHdrLayout, for example, SecFuncOffsetTable 585a906e3ecSWei Mi // needs to be computed after SecLBRProfile (the order in SecHdrTable), 586a906e3ecSWei Mi // but it needs to be read before SecLBRProfile (the order in 587a906e3ecSWei Mi // SectionHdrLayout). So we use IndexMap above to switch the order. 588a906e3ecSWei Mi for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size(); 589a906e3ecSWei Mi LayoutIdx++) { 590a906e3ecSWei Mi assert(IndexMap[LayoutIdx] < SecHdrTable.size() && 591a906e3ecSWei Mi "Incorrect LayoutIdx in SecHdrTable"); 592a906e3ecSWei Mi auto Entry = SecHdrTable[IndexMap[LayoutIdx]]; 593a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Type)); 594a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Flags)); 595a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Offset)); 596a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Size)); 597be907324SWei Mi } 598be907324SWei Mi 599be907324SWei Mi // Reset OutputStream. 600be907324SWei Mi if (OFS.seek(Saved) == (uint64_t)-1) 601be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 602be907324SWei Mi 603be907324SWei Mi return sampleprof_error::success; 604be907324SWei Mi } 605be907324SWei Mi 606be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeHeader( 607be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 608be907324SWei Mi auto &OS = *OutputStream; 609be907324SWei Mi FileStart = OS.tell(); 610be907324SWei Mi writeMagicIdent(Format); 611be907324SWei Mi 612be907324SWei Mi allocSecHdrTable(); 613be907324SWei Mi return sampleprof_error::success; 614be907324SWei Mi } 615be907324SWei Mi 6166a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader( 6176a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 6186a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 6196a14325dSWei Mi if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) 6206a14325dSWei Mi return EC; 6216a14325dSWei Mi 6226a14325dSWei Mi // Reserve a slot for the offset of function offset table. The slot will 6236a14325dSWei Mi // be populated with the offset of FuncOffsetTable later. 6246a14325dSWei Mi TableOffset = OutputStream->tell(); 6256a14325dSWei Mi Writer.write(static_cast<uint64_t>(-2)); 6266a14325dSWei Mi return sampleprof_error::success; 6276a14325dSWei Mi } 6286a14325dSWei Mi 62940ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() { 63040ee23dbSEaswaran Raman auto &OS = *OutputStream; 6317cefdb81SEaswaran Raman encodeULEB128(Summary->getTotalCount(), OS); 6327cefdb81SEaswaran Raman encodeULEB128(Summary->getMaxCount(), OS); 6336f4903d9SEaswaran Raman encodeULEB128(Summary->getMaxFunctionCount(), OS); 6347cefdb81SEaswaran Raman encodeULEB128(Summary->getNumCounts(), OS); 63540ee23dbSEaswaran Raman encodeULEB128(Summary->getNumFunctions(), OS); 63640ee23dbSEaswaran Raman std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 63740ee23dbSEaswaran Raman encodeULEB128(Entries.size(), OS); 63840ee23dbSEaswaran Raman for (auto Entry : Entries) { 63940ee23dbSEaswaran Raman encodeULEB128(Entry.Cutoff, OS); 64040ee23dbSEaswaran Raman encodeULEB128(Entry.MinCount, OS); 64140ee23dbSEaswaran Raman encodeULEB128(Entry.NumCounts, OS); 64240ee23dbSEaswaran Raman } 64340ee23dbSEaswaran Raman return sampleprof_error::success; 64440ee23dbSEaswaran Raman } 64557d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 64651abea74SNathan Slingerland auto &OS = *OutputStream; 64751abea74SNathan Slingerland 6487e99bddfSHongtao Yu if (std::error_code EC = writeNameIdx(S.getNameWithContext(true))) 649760c5a8fSDiego Novillo return EC; 650760c5a8fSDiego Novillo 651c572e92cSDiego Novillo encodeULEB128(S.getTotalSamples(), OS); 652a7f1e8efSDiego Novillo 653a7f1e8efSDiego Novillo // Emit all the body samples. 654b93483dbSDiego Novillo encodeULEB128(S.getBodySamples().size(), OS); 655d5336ae2SDiego Novillo for (const auto &I : S.getBodySamples()) { 656d5336ae2SDiego Novillo LineLocation Loc = I.first; 657d5336ae2SDiego Novillo const SampleRecord &Sample = I.second; 658c572e92cSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 659c572e92cSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 660c572e92cSDiego Novillo encodeULEB128(Sample.getSamples(), OS); 661c572e92cSDiego Novillo encodeULEB128(Sample.getCallTargets().size(), OS); 6625adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) { 6635adace35SWenlei He StringRef Callee = J.first; 66438be3330SDiego Novillo uint64_t CalleeSamples = J.second; 665760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(Callee)) 666760c5a8fSDiego Novillo return EC; 667c572e92cSDiego Novillo encodeULEB128(CalleeSamples, OS); 668c572e92cSDiego Novillo } 669c572e92cSDiego Novillo } 670c572e92cSDiego Novillo 671a7f1e8efSDiego Novillo // Recursively emit all the callsite samples. 6722c27daf7SDehao Chen uint64_t NumCallsites = 0; 6732c27daf7SDehao Chen for (const auto &J : S.getCallsiteSamples()) 6742c27daf7SDehao Chen NumCallsites += J.second.size(); 6752c27daf7SDehao Chen encodeULEB128(NumCallsites, OS); 6762c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 6772c7ca9b5SDehao Chen for (const auto &FS : J.second) { 67857d1dda5SDehao Chen LineLocation Loc = J.first; 6792c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 680a7f1e8efSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 681a7f1e8efSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 68257d1dda5SDehao Chen if (std::error_code EC = writeBody(CalleeSamples)) 683760c5a8fSDiego Novillo return EC; 684a7f1e8efSDiego Novillo } 685a7f1e8efSDiego Novillo 686760c5a8fSDiego Novillo return sampleprof_error::success; 687c572e92cSDiego Novillo } 688d5336ae2SDiego Novillo 6895f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file. 690b93483dbSDiego Novillo /// 691b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise. 692be907324SWei Mi std::error_code 693be907324SWei Mi SampleProfileWriterBinary::writeSample(const FunctionSamples &S) { 69451abea74SNathan Slingerland encodeULEB128(S.getHeadSamples(), *OutputStream); 69557d1dda5SDehao Chen return writeBody(S); 696b93483dbSDiego Novillo } 697b93483dbSDiego Novillo 6986a14325dSWei Mi std::error_code 699be907324SWei Mi SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) { 7006a14325dSWei Mi uint64_t Offset = OutputStream->tell(); 7016a14325dSWei Mi StringRef Name = S.getName(); 7026a14325dSWei Mi FuncOffsetTable[Name] = Offset; 7036a14325dSWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream); 7046a14325dSWei Mi return writeBody(S); 7056a14325dSWei Mi } 7066a14325dSWei Mi 7075f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format. 708d5336ae2SDiego Novillo /// 709d5336ae2SDiego Novillo /// \param Filename The file to create. 710d5336ae2SDiego Novillo /// 711d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file. 712d5336ae2SDiego Novillo /// 713d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer. 714fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>> 715fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 716d5336ae2SDiego Novillo std::error_code EC; 71751abea74SNathan Slingerland std::unique_ptr<raw_ostream> OS; 718be907324SWei Mi if (Format == SPF_Binary || Format == SPF_Ext_Binary || 719be907324SWei Mi Format == SPF_Compact_Binary) 720d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None)); 72151abea74SNathan Slingerland else 722d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text)); 72351abea74SNathan Slingerland if (EC) 72451abea74SNathan Slingerland return EC; 72551abea74SNathan Slingerland 72651abea74SNathan Slingerland return create(OS, Format); 72751abea74SNathan Slingerland } 72851abea74SNathan Slingerland 7295f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format. 73051abea74SNathan Slingerland /// 73151abea74SNathan Slingerland /// \param OS The output stream to store the profile data to. 73251abea74SNathan Slingerland /// 73351abea74SNathan Slingerland /// \param Format Encoding format for the profile file. 73451abea74SNathan Slingerland /// 73551abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer. 73651abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>> 73751abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 73851abea74SNathan Slingerland SampleProfileFormat Format) { 73951abea74SNathan Slingerland std::error_code EC; 740fcd55607SDiego Novillo std::unique_ptr<SampleProfileWriter> Writer; 741d5336ae2SDiego Novillo 742d9be2c7eSWei Mi if (Format == SPF_Binary) 743a0c0857eSWei Mi Writer.reset(new SampleProfileWriterRawBinary(OS)); 744be907324SWei Mi else if (Format == SPF_Ext_Binary) 745be907324SWei Mi Writer.reset(new SampleProfileWriterExtBinary(OS)); 746a0c0857eSWei Mi else if (Format == SPF_Compact_Binary) 747a0c0857eSWei Mi Writer.reset(new SampleProfileWriterCompactBinary(OS)); 748d5336ae2SDiego Novillo else if (Format == SPF_Text) 74951abea74SNathan Slingerland Writer.reset(new SampleProfileWriterText(OS)); 750760c5a8fSDiego Novillo else if (Format == SPF_GCC) 751760c5a8fSDiego Novillo EC = sampleprof_error::unsupported_writing_format; 752d5336ae2SDiego Novillo else 753d5336ae2SDiego Novillo EC = sampleprof_error::unrecognized_format; 754d5336ae2SDiego Novillo 755fcd55607SDiego Novillo if (EC) 756d5336ae2SDiego Novillo return EC; 757fcd55607SDiego Novillo 758be907324SWei Mi Writer->Format = Format; 759c55cf4afSBill Wendling return std::move(Writer); 760d5336ae2SDiego Novillo } 76140ee23dbSEaswaran Raman 76240ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary( 76340ee23dbSEaswaran Raman const StringMap<FunctionSamples> &ProfileMap) { 764e5a17e3fSEaswaran Raman SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 765801d9cc7SWenlei He Summary = Builder.computeSummaryForProfiles(ProfileMap); 76640ee23dbSEaswaran Raman } 767