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 } 207*ee35784aSWei Mi 208*ee35784aSWei Mi // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag 209*ee35784aSWei Mi // so compiler won't strip the suffix during profile matching after 210*ee35784aSWei Mi // seeing the flag in the profile. 211*ee35784aSWei Mi for (const auto &I : NameTable) { 212*ee35784aSWei Mi if (I.first.find(FunctionSamples::UniqSuffix) != StringRef::npos) { 213*ee35784aSWei Mi addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix); 214*ee35784aSWei Mi break; 215*ee35784aSWei Mi } 216*ee35784aSWei Mi } 217*ee35784aSWei 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); 24093953d41SWei Mi 241a906e3ecSWei Mi uint64_t SectionStart = markSectionStart(Type, LayoutIdx); 24293953d41SWei Mi switch (Type) { 24393953d41SWei Mi case SecProfSummary: 24493953d41SWei Mi computeSummary(ProfileMap); 24593953d41SWei Mi if (auto EC = writeSummary()) 24693953d41SWei Mi return EC; 24793953d41SWei Mi break; 24893953d41SWei Mi case SecNameTable: 24993953d41SWei Mi if (auto EC = writeNameTableSection(ProfileMap)) 25093953d41SWei Mi return EC; 25193953d41SWei Mi break; 25293953d41SWei Mi case SecLBRProfile: 25393953d41SWei Mi SecLBRProfileStart = OutputStream->tell(); 25493953d41SWei Mi if (std::error_code EC = writeFuncProfiles(ProfileMap)) 25593953d41SWei Mi return EC; 25693953d41SWei Mi break; 25793953d41SWei Mi case SecFuncOffsetTable: 25893953d41SWei Mi if (auto EC = writeFuncOffsetTable()) 25993953d41SWei Mi return EC; 26093953d41SWei Mi break; 261ac068e01SHongtao Yu case SecFuncMetadata: 262ac068e01SHongtao Yu if (std::error_code EC = writeFuncMetadata(ProfileMap)) 263ac068e01SHongtao Yu return EC; 264ac068e01SHongtao Yu break; 26593953d41SWei Mi case SecProfileSymbolList: 26693953d41SWei Mi if (auto EC = writeProfileSymbolListSection()) 26793953d41SWei Mi return EC; 26893953d41SWei Mi break; 26993953d41SWei Mi default: 27093953d41SWei Mi if (auto EC = writeCustomSection(Type)) 27193953d41SWei Mi return EC; 27293953d41SWei Mi break; 27393953d41SWei Mi } 274a906e3ecSWei Mi if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart)) 27593953d41SWei Mi return EC; 27693953d41SWei Mi return sampleprof_error::success; 27793953d41SWei Mi } 27893953d41SWei Mi 27921b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeDefaultLayout( 28093953d41SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 281a906e3ecSWei Mi // The const indices passed to writeOneSection below are specifying the 282a906e3ecSWei Mi // positions of the sections in SectionHdrLayout. Look at 283a906e3ecSWei Mi // initSectionHdrLayout to find out where each section is located in 284a906e3ecSWei Mi // SectionHdrLayout. 285a906e3ecSWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 28693953d41SWei Mi return EC; 287a906e3ecSWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 28893953d41SWei Mi return EC; 289a906e3ecSWei Mi if (auto EC = writeOneSection(SecLBRProfile, 3, ProfileMap)) 29093953d41SWei Mi return EC; 291a906e3ecSWei Mi if (auto EC = writeOneSection(SecProfileSymbolList, 4, ProfileMap)) 29293953d41SWei Mi return EC; 293a906e3ecSWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ProfileMap)) 29493953d41SWei Mi return EC; 295a906e3ecSWei Mi if (auto EC = writeOneSection(SecFuncMetadata, 5, ProfileMap)) 296ac068e01SHongtao Yu return EC; 297be907324SWei Mi return sampleprof_error::success; 298be907324SWei Mi } 299be907324SWei Mi 30021b1ad03SWei Mi static void 30121b1ad03SWei Mi splitProfileMapToTwo(const StringMap<FunctionSamples> &ProfileMap, 30221b1ad03SWei Mi StringMap<FunctionSamples> &ContextProfileMap, 30321b1ad03SWei Mi StringMap<FunctionSamples> &NoContextProfileMap) { 30421b1ad03SWei Mi for (const auto &I : ProfileMap) { 30521b1ad03SWei Mi if (I.second.getCallsiteSamples().size()) 30621b1ad03SWei Mi ContextProfileMap.insert({I.first(), I.second}); 30721b1ad03SWei Mi else 30821b1ad03SWei Mi NoContextProfileMap.insert({I.first(), I.second}); 30921b1ad03SWei Mi } 31021b1ad03SWei Mi } 31121b1ad03SWei Mi 31221b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout( 31321b1ad03SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 31421b1ad03SWei Mi StringMap<FunctionSamples> ContextProfileMap, NoContextProfileMap; 31521b1ad03SWei Mi splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap); 31621b1ad03SWei Mi 31721b1ad03SWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 31821b1ad03SWei Mi return EC; 31921b1ad03SWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 32021b1ad03SWei Mi return EC; 32121b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap)) 32221b1ad03SWei Mi return EC; 32321b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap)) 32421b1ad03SWei Mi return EC; 32521b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set 32621b1ad03SWei Mi // before writing the section. 32721b1ad03SWei Mi addSectionFlag(5, SecCommonFlags::SecFlagFlat); 32821b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap)) 32921b1ad03SWei Mi return EC; 33021b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set 33121b1ad03SWei Mi // before writing the section. 33221b1ad03SWei Mi addSectionFlag(4, SecCommonFlags::SecFlagFlat); 33321b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap)) 33421b1ad03SWei Mi return EC; 33521b1ad03SWei Mi if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap)) 33621b1ad03SWei Mi return EC; 33721b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap)) 33821b1ad03SWei Mi return EC; 33921b1ad03SWei Mi 34021b1ad03SWei Mi return sampleprof_error::success; 34121b1ad03SWei Mi } 34221b1ad03SWei Mi 34321b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeSections( 34421b1ad03SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 34521b1ad03SWei Mi std::error_code EC; 34621b1ad03SWei Mi if (SecLayout == DefaultLayout) 34721b1ad03SWei Mi EC = writeDefaultLayout(ProfileMap); 34821b1ad03SWei Mi else if (SecLayout == CtxSplitLayout) 34921b1ad03SWei Mi EC = writeCtxSplitLayout(ProfileMap); 35021b1ad03SWei Mi else 35121b1ad03SWei Mi llvm_unreachable("Unsupported layout"); 35221b1ad03SWei Mi return EC; 35321b1ad03SWei Mi } 35421b1ad03SWei Mi 3556a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::write( 3566a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 3576a14325dSWei Mi if (std::error_code EC = SampleProfileWriter::write(ProfileMap)) 3586a14325dSWei Mi return EC; 3596a14325dSWei Mi if (std::error_code EC = writeFuncOffsetTable()) 3606a14325dSWei Mi return EC; 3616a14325dSWei Mi return sampleprof_error::success; 3626a14325dSWei Mi } 3636a14325dSWei Mi 3645f8f34e4SAdrian Prantl /// Write samples to a text file. 3658e415a82SDiego Novillo /// 3668e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of 367ef548d29SDiego Novillo /// FunctionSamples::print(). Please don't. The dump functionality is intended 3688e415a82SDiego Novillo /// for debugging and has no specified form. 3698e415a82SDiego Novillo /// 3708e415a82SDiego Novillo /// The format used here is more structured and deliberate because 3718e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class. 372be907324SWei Mi std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { 37351abea74SNathan Slingerland auto &OS = *OutputStream; 374c3aeabaeSwlei OS << S.getNameWithContext(true) << ":" << S.getTotalSamples(); 375aae1ed8eSDiego Novillo if (Indent == 0) 376aae1ed8eSDiego Novillo OS << ":" << S.getHeadSamples(); 377aae1ed8eSDiego Novillo OS << "\n"; 378c572e92cSDiego Novillo 379ef548d29SDiego Novillo SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 380ef548d29SDiego Novillo for (const auto &I : SortedSamples.get()) { 381ef548d29SDiego Novillo LineLocation Loc = I->first; 382ef548d29SDiego Novillo const SampleRecord &Sample = I->second; 383aae1ed8eSDiego Novillo OS.indent(Indent + 1); 384c572e92cSDiego Novillo if (Loc.Discriminator == 0) 385c572e92cSDiego Novillo OS << Loc.LineOffset << ": "; 386c572e92cSDiego Novillo else 387c572e92cSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 388c572e92cSDiego Novillo 389c572e92cSDiego Novillo OS << Sample.getSamples(); 390c572e92cSDiego Novillo 3915adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) 3925adace35SWenlei He OS << " " << J.first << ":" << J.second; 393c572e92cSDiego Novillo OS << "\n"; 394c572e92cSDiego Novillo } 395c572e92cSDiego Novillo 3962c7ca9b5SDehao Chen SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 397ef548d29SDiego Novillo S.getCallsiteSamples()); 398aae1ed8eSDiego Novillo Indent += 1; 3992c7ca9b5SDehao Chen for (const auto &I : SortedCallsiteSamples.get()) 4002c7ca9b5SDehao Chen for (const auto &FS : I->second) { 40157d1dda5SDehao Chen LineLocation Loc = I->first; 4022c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 403aae1ed8eSDiego Novillo OS.indent(Indent); 404aae1ed8eSDiego Novillo if (Loc.Discriminator == 0) 405aae1ed8eSDiego Novillo OS << Loc.LineOffset << ": "; 406aae1ed8eSDiego Novillo else 407aae1ed8eSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 408be907324SWei Mi if (std::error_code EC = writeSample(CalleeSamples)) 409760c5a8fSDiego Novillo return EC; 410aae1ed8eSDiego Novillo } 411aae1ed8eSDiego Novillo Indent -= 1; 412aae1ed8eSDiego Novillo 413ac068e01SHongtao Yu if (Indent == 0) { 414ac068e01SHongtao Yu if (FunctionSamples::ProfileIsProbeBased) { 415ac068e01SHongtao Yu OS.indent(Indent + 1); 416ac068e01SHongtao Yu OS << "!CFGChecksum: " << S.getFunctionHash() << "\n"; 417ac068e01SHongtao Yu } 418ac068e01SHongtao Yu } 419ac068e01SHongtao Yu 420760c5a8fSDiego Novillo return sampleprof_error::success; 421c572e92cSDiego Novillo } 422c572e92cSDiego Novillo 423760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 424760c5a8fSDiego Novillo const auto &ret = NameTable.find(FName); 425760c5a8fSDiego Novillo if (ret == NameTable.end()) 426760c5a8fSDiego Novillo return sampleprof_error::truncated_name_table; 42751abea74SNathan Slingerland encodeULEB128(ret->second, *OutputStream); 428760c5a8fSDiego Novillo return sampleprof_error::success; 429760c5a8fSDiego Novillo } 430c572e92cSDiego Novillo 431760c5a8fSDiego Novillo void SampleProfileWriterBinary::addName(StringRef FName) { 4328d1c983fSDehao Chen NameTable.insert(std::make_pair(FName, 0)); 433760c5a8fSDiego Novillo } 434760c5a8fSDiego Novillo 435760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 436760c5a8fSDiego Novillo // Add all the names in indirect call targets. 437760c5a8fSDiego Novillo for (const auto &I : S.getBodySamples()) { 438760c5a8fSDiego Novillo const SampleRecord &Sample = I.second; 439760c5a8fSDiego Novillo for (const auto &J : Sample.getCallTargets()) 440760c5a8fSDiego Novillo addName(J.first()); 441760c5a8fSDiego Novillo } 442760c5a8fSDiego Novillo 443760c5a8fSDiego Novillo // Recursively add all the names for inlined callsites. 4442c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 4452c7ca9b5SDehao Chen for (const auto &FS : J.second) { 4462c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 44757d1dda5SDehao Chen addName(CalleeSamples.getName()); 448760c5a8fSDiego Novillo addNames(CalleeSamples); 449760c5a8fSDiego Novillo } 450760c5a8fSDiego Novillo } 451760c5a8fSDiego Novillo 452a0c0857eSWei Mi void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) { 453a0c0857eSWei Mi // Sort the names to make NameTable deterministic. 454a0c0857eSWei Mi for (const auto &I : NameTable) 455a0c0857eSWei Mi V.insert(I.first); 456a0c0857eSWei Mi int i = 0; 457a0c0857eSWei Mi for (const StringRef &N : V) 458a0c0857eSWei Mi NameTable[N] = i++; 459a0c0857eSWei Mi } 46051abea74SNathan Slingerland 461be907324SWei Mi std::error_code SampleProfileWriterBinary::writeNameTable() { 462a0c0857eSWei Mi auto &OS = *OutputStream; 463a0c0857eSWei Mi std::set<StringRef> V; 464a0c0857eSWei Mi stablizeNameTable(V); 465a0c0857eSWei Mi 466a0c0857eSWei Mi // Write out the name table. 467a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 468a0c0857eSWei Mi for (auto N : V) { 469a0c0857eSWei Mi OS << N; 470a0c0857eSWei Mi encodeULEB128(0, OS); 471a0c0857eSWei Mi } 472a0c0857eSWei Mi return sampleprof_error::success; 473a0c0857eSWei Mi } 474a0c0857eSWei Mi 4756a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { 4766a14325dSWei Mi auto &OS = *OutputStream; 4776a14325dSWei Mi 4786a14325dSWei Mi // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. 4796a14325dSWei Mi auto &OFS = static_cast<raw_fd_ostream &>(OS); 4806a14325dSWei Mi uint64_t FuncOffsetTableStart = OS.tell(); 4816a14325dSWei Mi if (OFS.seek(TableOffset) == (uint64_t)-1) 4826a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 4836a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 4846a14325dSWei Mi Writer.write(FuncOffsetTableStart); 4856a14325dSWei Mi if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) 4866a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 4876a14325dSWei Mi 4886a14325dSWei Mi // Write out the table size. 4896a14325dSWei Mi encodeULEB128(FuncOffsetTable.size(), OS); 4906a14325dSWei Mi 4916a14325dSWei Mi // Write out FuncOffsetTable. 4926a14325dSWei Mi for (auto entry : FuncOffsetTable) { 4936a14325dSWei Mi writeNameIdx(entry.first); 4946a14325dSWei Mi encodeULEB128(entry.second, OS); 4956a14325dSWei Mi } 4966a14325dSWei Mi return sampleprof_error::success; 4976a14325dSWei Mi } 4986a14325dSWei Mi 499a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() { 500a0c0857eSWei Mi auto &OS = *OutputStream; 501a0c0857eSWei Mi std::set<StringRef> V; 502a0c0857eSWei Mi stablizeNameTable(V); 503a0c0857eSWei Mi 504a0c0857eSWei Mi // Write out the name table. 505a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 506a0c0857eSWei Mi for (auto N : V) { 507a0c0857eSWei Mi encodeULEB128(MD5Hash(N), OS); 508a0c0857eSWei Mi } 509a0c0857eSWei Mi return sampleprof_error::success; 510a0c0857eSWei Mi } 511a0c0857eSWei Mi 512be907324SWei Mi std::error_code 513be907324SWei Mi SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { 514a0c0857eSWei Mi auto &OS = *OutputStream; 515760c5a8fSDiego Novillo // Write file magic identifier. 516be907324SWei Mi encodeULEB128(SPMagic(Format), OS); 517a0c0857eSWei Mi encodeULEB128(SPVersion(), OS); 518a0c0857eSWei Mi return sampleprof_error::success; 519a0c0857eSWei Mi } 520a0c0857eSWei Mi 521a0c0857eSWei Mi std::error_code SampleProfileWriterBinary::writeHeader( 522a0c0857eSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 523be907324SWei Mi writeMagicIdent(Format); 524760c5a8fSDiego Novillo 52540ee23dbSEaswaran Raman computeSummary(ProfileMap); 52640ee23dbSEaswaran Raman if (auto EC = writeSummary()) 52740ee23dbSEaswaran Raman return EC; 52840ee23dbSEaswaran Raman 529760c5a8fSDiego Novillo // Generate the name table for all the functions referenced in the profile. 530760c5a8fSDiego Novillo for (const auto &I : ProfileMap) { 531760c5a8fSDiego Novillo addName(I.first()); 532760c5a8fSDiego Novillo addNames(I.second); 533760c5a8fSDiego Novillo } 534760c5a8fSDiego Novillo 535a0c0857eSWei Mi writeNameTable(); 536760c5a8fSDiego Novillo return sampleprof_error::success; 537c572e92cSDiego Novillo } 538c572e92cSDiego Novillo 539b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressAllSections() { 54009dcfe68SWei Mi for (auto &Entry : SectionHdrLayout) 541ebad6788SWei Mi addSecFlag(Entry, SecCommonFlags::SecFlagCompress); 542b523790aSWei Mi } 543b523790aSWei Mi 544b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) { 545ebad6788SWei Mi addSectionFlag(Type, SecCommonFlags::SecFlagCompress); 546b523790aSWei Mi } 547b523790aSWei Mi 548be907324SWei Mi void SampleProfileWriterExtBinaryBase::allocSecHdrTable() { 549be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 550be907324SWei Mi 55109dcfe68SWei Mi Writer.write(static_cast<uint64_t>(SectionHdrLayout.size())); 552be907324SWei Mi SecHdrTableOffset = OutputStream->tell(); 55309dcfe68SWei Mi for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 554be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 555be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 556be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 557be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 558be907324SWei Mi } 559be907324SWei Mi } 560be907324SWei Mi 561be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { 562be907324SWei Mi auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream); 563be907324SWei Mi uint64_t Saved = OutputStream->tell(); 564be907324SWei Mi 565be907324SWei Mi // Set OutputStream to the location saved in SecHdrTableOffset. 566be907324SWei Mi if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1) 567be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 568be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 569be907324SWei Mi 570a906e3ecSWei Mi assert(SecHdrTable.size() == SectionHdrLayout.size() && 571a906e3ecSWei Mi "SecHdrTable entries doesn't match SectionHdrLayout"); 572a906e3ecSWei Mi SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1); 573a906e3ecSWei Mi for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) { 574a906e3ecSWei Mi IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx; 575be907324SWei Mi } 576be907324SWei Mi 57709dcfe68SWei Mi // Write the section header table in the order specified in 578a906e3ecSWei Mi // SectionHdrLayout. SectionHdrLayout specifies the sections 579a906e3ecSWei Mi // order in which profile reader expect to read, so the section 580a906e3ecSWei Mi // header table should be written in the order in SectionHdrLayout. 581a906e3ecSWei Mi // Note that the section order in SecHdrTable may be different 582a906e3ecSWei Mi // from the order in SectionHdrLayout, for example, SecFuncOffsetTable 583a906e3ecSWei Mi // needs to be computed after SecLBRProfile (the order in SecHdrTable), 584a906e3ecSWei Mi // but it needs to be read before SecLBRProfile (the order in 585a906e3ecSWei Mi // SectionHdrLayout). So we use IndexMap above to switch the order. 586a906e3ecSWei Mi for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size(); 587a906e3ecSWei Mi LayoutIdx++) { 588a906e3ecSWei Mi assert(IndexMap[LayoutIdx] < SecHdrTable.size() && 589a906e3ecSWei Mi "Incorrect LayoutIdx in SecHdrTable"); 590a906e3ecSWei Mi auto Entry = SecHdrTable[IndexMap[LayoutIdx]]; 591a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Type)); 592a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Flags)); 593a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Offset)); 594a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Size)); 595be907324SWei Mi } 596be907324SWei Mi 597be907324SWei Mi // Reset OutputStream. 598be907324SWei Mi if (OFS.seek(Saved) == (uint64_t)-1) 599be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 600be907324SWei Mi 601be907324SWei Mi return sampleprof_error::success; 602be907324SWei Mi } 603be907324SWei Mi 604be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeHeader( 605be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 606be907324SWei Mi auto &OS = *OutputStream; 607be907324SWei Mi FileStart = OS.tell(); 608be907324SWei Mi writeMagicIdent(Format); 609be907324SWei Mi 610be907324SWei Mi allocSecHdrTable(); 611be907324SWei Mi return sampleprof_error::success; 612be907324SWei Mi } 613be907324SWei Mi 6146a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader( 6156a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 6166a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 6176a14325dSWei Mi if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) 6186a14325dSWei Mi return EC; 6196a14325dSWei Mi 6206a14325dSWei Mi // Reserve a slot for the offset of function offset table. The slot will 6216a14325dSWei Mi // be populated with the offset of FuncOffsetTable later. 6226a14325dSWei Mi TableOffset = OutputStream->tell(); 6236a14325dSWei Mi Writer.write(static_cast<uint64_t>(-2)); 6246a14325dSWei Mi return sampleprof_error::success; 6256a14325dSWei Mi } 6266a14325dSWei Mi 62740ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() { 62840ee23dbSEaswaran Raman auto &OS = *OutputStream; 6297cefdb81SEaswaran Raman encodeULEB128(Summary->getTotalCount(), OS); 6307cefdb81SEaswaran Raman encodeULEB128(Summary->getMaxCount(), OS); 6316f4903d9SEaswaran Raman encodeULEB128(Summary->getMaxFunctionCount(), OS); 6327cefdb81SEaswaran Raman encodeULEB128(Summary->getNumCounts(), OS); 63340ee23dbSEaswaran Raman encodeULEB128(Summary->getNumFunctions(), OS); 63440ee23dbSEaswaran Raman std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 63540ee23dbSEaswaran Raman encodeULEB128(Entries.size(), OS); 63640ee23dbSEaswaran Raman for (auto Entry : Entries) { 63740ee23dbSEaswaran Raman encodeULEB128(Entry.Cutoff, OS); 63840ee23dbSEaswaran Raman encodeULEB128(Entry.MinCount, OS); 63940ee23dbSEaswaran Raman encodeULEB128(Entry.NumCounts, OS); 64040ee23dbSEaswaran Raman } 64140ee23dbSEaswaran Raman return sampleprof_error::success; 64240ee23dbSEaswaran Raman } 64357d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 64451abea74SNathan Slingerland auto &OS = *OutputStream; 64551abea74SNathan Slingerland 6467e99bddfSHongtao Yu if (std::error_code EC = writeNameIdx(S.getNameWithContext(true))) 647760c5a8fSDiego Novillo return EC; 648760c5a8fSDiego Novillo 649c572e92cSDiego Novillo encodeULEB128(S.getTotalSamples(), OS); 650a7f1e8efSDiego Novillo 651a7f1e8efSDiego Novillo // Emit all the body samples. 652b93483dbSDiego Novillo encodeULEB128(S.getBodySamples().size(), OS); 653d5336ae2SDiego Novillo for (const auto &I : S.getBodySamples()) { 654d5336ae2SDiego Novillo LineLocation Loc = I.first; 655d5336ae2SDiego Novillo const SampleRecord &Sample = I.second; 656c572e92cSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 657c572e92cSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 658c572e92cSDiego Novillo encodeULEB128(Sample.getSamples(), OS); 659c572e92cSDiego Novillo encodeULEB128(Sample.getCallTargets().size(), OS); 6605adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) { 6615adace35SWenlei He StringRef Callee = J.first; 66238be3330SDiego Novillo uint64_t CalleeSamples = J.second; 663760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(Callee)) 664760c5a8fSDiego Novillo return EC; 665c572e92cSDiego Novillo encodeULEB128(CalleeSamples, OS); 666c572e92cSDiego Novillo } 667c572e92cSDiego Novillo } 668c572e92cSDiego Novillo 669a7f1e8efSDiego Novillo // Recursively emit all the callsite samples. 6702c27daf7SDehao Chen uint64_t NumCallsites = 0; 6712c27daf7SDehao Chen for (const auto &J : S.getCallsiteSamples()) 6722c27daf7SDehao Chen NumCallsites += J.second.size(); 6732c27daf7SDehao Chen encodeULEB128(NumCallsites, OS); 6742c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 6752c7ca9b5SDehao Chen for (const auto &FS : J.second) { 67657d1dda5SDehao Chen LineLocation Loc = J.first; 6772c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 678a7f1e8efSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 679a7f1e8efSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 68057d1dda5SDehao Chen if (std::error_code EC = writeBody(CalleeSamples)) 681760c5a8fSDiego Novillo return EC; 682a7f1e8efSDiego Novillo } 683a7f1e8efSDiego Novillo 684760c5a8fSDiego Novillo return sampleprof_error::success; 685c572e92cSDiego Novillo } 686d5336ae2SDiego Novillo 6875f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file. 688b93483dbSDiego Novillo /// 689b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise. 690be907324SWei Mi std::error_code 691be907324SWei Mi SampleProfileWriterBinary::writeSample(const FunctionSamples &S) { 69251abea74SNathan Slingerland encodeULEB128(S.getHeadSamples(), *OutputStream); 69357d1dda5SDehao Chen return writeBody(S); 694b93483dbSDiego Novillo } 695b93483dbSDiego Novillo 6966a14325dSWei Mi std::error_code 697be907324SWei Mi SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) { 6986a14325dSWei Mi uint64_t Offset = OutputStream->tell(); 6996a14325dSWei Mi StringRef Name = S.getName(); 7006a14325dSWei Mi FuncOffsetTable[Name] = Offset; 7016a14325dSWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream); 7026a14325dSWei Mi return writeBody(S); 7036a14325dSWei Mi } 7046a14325dSWei Mi 7055f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format. 706d5336ae2SDiego Novillo /// 707d5336ae2SDiego Novillo /// \param Filename The file to create. 708d5336ae2SDiego Novillo /// 709d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file. 710d5336ae2SDiego Novillo /// 711d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer. 712fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>> 713fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 714d5336ae2SDiego Novillo std::error_code EC; 71551abea74SNathan Slingerland std::unique_ptr<raw_ostream> OS; 716be907324SWei Mi if (Format == SPF_Binary || Format == SPF_Ext_Binary || 717be907324SWei Mi Format == SPF_Compact_Binary) 718d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None)); 71951abea74SNathan Slingerland else 720d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text)); 72151abea74SNathan Slingerland if (EC) 72251abea74SNathan Slingerland return EC; 72351abea74SNathan Slingerland 72451abea74SNathan Slingerland return create(OS, Format); 72551abea74SNathan Slingerland } 72651abea74SNathan Slingerland 7275f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format. 72851abea74SNathan Slingerland /// 72951abea74SNathan Slingerland /// \param OS The output stream to store the profile data to. 73051abea74SNathan Slingerland /// 73151abea74SNathan Slingerland /// \param Format Encoding format for the profile file. 73251abea74SNathan Slingerland /// 73351abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer. 73451abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>> 73551abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 73651abea74SNathan Slingerland SampleProfileFormat Format) { 73751abea74SNathan Slingerland std::error_code EC; 738fcd55607SDiego Novillo std::unique_ptr<SampleProfileWriter> Writer; 739d5336ae2SDiego Novillo 740d9be2c7eSWei Mi if (Format == SPF_Binary) 741a0c0857eSWei Mi Writer.reset(new SampleProfileWriterRawBinary(OS)); 742be907324SWei Mi else if (Format == SPF_Ext_Binary) 743be907324SWei Mi Writer.reset(new SampleProfileWriterExtBinary(OS)); 744a0c0857eSWei Mi else if (Format == SPF_Compact_Binary) 745a0c0857eSWei Mi Writer.reset(new SampleProfileWriterCompactBinary(OS)); 746d5336ae2SDiego Novillo else if (Format == SPF_Text) 74751abea74SNathan Slingerland Writer.reset(new SampleProfileWriterText(OS)); 748760c5a8fSDiego Novillo else if (Format == SPF_GCC) 749760c5a8fSDiego Novillo EC = sampleprof_error::unsupported_writing_format; 750d5336ae2SDiego Novillo else 751d5336ae2SDiego Novillo EC = sampleprof_error::unrecognized_format; 752d5336ae2SDiego Novillo 753fcd55607SDiego Novillo if (EC) 754d5336ae2SDiego Novillo return EC; 755fcd55607SDiego Novillo 756be907324SWei Mi Writer->Format = Format; 757c55cf4afSBill Wendling return std::move(Writer); 758d5336ae2SDiego Novillo } 75940ee23dbSEaswaran Raman 76040ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary( 76140ee23dbSEaswaran Raman const StringMap<FunctionSamples> &ProfileMap) { 762e5a17e3fSEaswaran Raman SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 763801d9cc7SWenlei He Summary = Builder.computeSummaryForProfiles(ProfileMap); 76440ee23dbSEaswaran Raman } 765