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(); 150*7e99bddfSHongtao 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 } 20793953d41SWei Mi if (auto EC = writeNameTable()) 208b523790aSWei Mi return EC; 20993953d41SWei Mi return sampleprof_error::success; 21093953d41SWei Mi } 211be907324SWei Mi 21293953d41SWei Mi std::error_code 21393953d41SWei Mi SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() { 214798e59b8SWei Mi if (ProfSymList && ProfSymList->size() > 0) 215798e59b8SWei Mi if (std::error_code EC = ProfSymList->write(*OutputStream)) 216798e59b8SWei Mi return EC; 217be907324SWei Mi 21893953d41SWei Mi return sampleprof_error::success; 21993953d41SWei Mi } 22009dcfe68SWei Mi 22193953d41SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeOneSection( 222a906e3ecSWei Mi SecType Type, uint32_t LayoutIdx, 223a906e3ecSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 22493953d41SWei Mi // The setting of SecFlagCompress should happen before markSectionStart. 22593953d41SWei Mi if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress()) 22693953d41SWei Mi setToCompressSection(SecProfileSymbolList); 227ac068e01SHongtao Yu if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased) 228ac068e01SHongtao Yu addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased); 22993953d41SWei Mi 230a906e3ecSWei Mi uint64_t SectionStart = markSectionStart(Type, LayoutIdx); 23193953d41SWei Mi switch (Type) { 23293953d41SWei Mi case SecProfSummary: 23393953d41SWei Mi computeSummary(ProfileMap); 23493953d41SWei Mi if (auto EC = writeSummary()) 23593953d41SWei Mi return EC; 23693953d41SWei Mi break; 23793953d41SWei Mi case SecNameTable: 23893953d41SWei Mi if (auto EC = writeNameTableSection(ProfileMap)) 23993953d41SWei Mi return EC; 24093953d41SWei Mi break; 24193953d41SWei Mi case SecLBRProfile: 24293953d41SWei Mi SecLBRProfileStart = OutputStream->tell(); 24393953d41SWei Mi if (std::error_code EC = writeFuncProfiles(ProfileMap)) 24493953d41SWei Mi return EC; 24593953d41SWei Mi break; 24693953d41SWei Mi case SecFuncOffsetTable: 24793953d41SWei Mi if (auto EC = writeFuncOffsetTable()) 24893953d41SWei Mi return EC; 24993953d41SWei Mi break; 250ac068e01SHongtao Yu case SecFuncMetadata: 251ac068e01SHongtao Yu if (std::error_code EC = writeFuncMetadata(ProfileMap)) 252ac068e01SHongtao Yu return EC; 253ac068e01SHongtao Yu break; 25493953d41SWei Mi case SecProfileSymbolList: 25593953d41SWei Mi if (auto EC = writeProfileSymbolListSection()) 25693953d41SWei Mi return EC; 25793953d41SWei Mi break; 25893953d41SWei Mi default: 25993953d41SWei Mi if (auto EC = writeCustomSection(Type)) 26093953d41SWei Mi return EC; 26193953d41SWei Mi break; 26293953d41SWei Mi } 263a906e3ecSWei Mi if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart)) 26493953d41SWei Mi return EC; 26593953d41SWei Mi return sampleprof_error::success; 26693953d41SWei Mi } 26793953d41SWei Mi 26821b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeDefaultLayout( 26993953d41SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 270a906e3ecSWei Mi // The const indices passed to writeOneSection below are specifying the 271a906e3ecSWei Mi // positions of the sections in SectionHdrLayout. Look at 272a906e3ecSWei Mi // initSectionHdrLayout to find out where each section is located in 273a906e3ecSWei Mi // SectionHdrLayout. 274a906e3ecSWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 27593953d41SWei Mi return EC; 276a906e3ecSWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 27793953d41SWei Mi return EC; 278a906e3ecSWei Mi if (auto EC = writeOneSection(SecLBRProfile, 3, ProfileMap)) 27993953d41SWei Mi return EC; 280a906e3ecSWei Mi if (auto EC = writeOneSection(SecProfileSymbolList, 4, ProfileMap)) 28193953d41SWei Mi return EC; 282a906e3ecSWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ProfileMap)) 28393953d41SWei Mi return EC; 284a906e3ecSWei Mi if (auto EC = writeOneSection(SecFuncMetadata, 5, ProfileMap)) 285ac068e01SHongtao Yu return EC; 286be907324SWei Mi return sampleprof_error::success; 287be907324SWei Mi } 288be907324SWei Mi 28921b1ad03SWei Mi static void 29021b1ad03SWei Mi splitProfileMapToTwo(const StringMap<FunctionSamples> &ProfileMap, 29121b1ad03SWei Mi StringMap<FunctionSamples> &ContextProfileMap, 29221b1ad03SWei Mi StringMap<FunctionSamples> &NoContextProfileMap) { 29321b1ad03SWei Mi for (const auto &I : ProfileMap) { 29421b1ad03SWei Mi if (I.second.getCallsiteSamples().size()) 29521b1ad03SWei Mi ContextProfileMap.insert({I.first(), I.second}); 29621b1ad03SWei Mi else 29721b1ad03SWei Mi NoContextProfileMap.insert({I.first(), I.second}); 29821b1ad03SWei Mi } 29921b1ad03SWei Mi } 30021b1ad03SWei Mi 30121b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout( 30221b1ad03SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 30321b1ad03SWei Mi StringMap<FunctionSamples> ContextProfileMap, NoContextProfileMap; 30421b1ad03SWei Mi splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap); 30521b1ad03SWei Mi 30621b1ad03SWei Mi if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 30721b1ad03SWei Mi return EC; 30821b1ad03SWei Mi if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 30921b1ad03SWei Mi return EC; 31021b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap)) 31121b1ad03SWei Mi return EC; 31221b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap)) 31321b1ad03SWei Mi return EC; 31421b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set 31521b1ad03SWei Mi // before writing the section. 31621b1ad03SWei Mi addSectionFlag(5, SecCommonFlags::SecFlagFlat); 31721b1ad03SWei Mi if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap)) 31821b1ad03SWei Mi return EC; 31921b1ad03SWei Mi // Mark the section to have no context. Note section flag needs to be set 32021b1ad03SWei Mi // before writing the section. 32121b1ad03SWei Mi addSectionFlag(4, SecCommonFlags::SecFlagFlat); 32221b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap)) 32321b1ad03SWei Mi return EC; 32421b1ad03SWei Mi if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap)) 32521b1ad03SWei Mi return EC; 32621b1ad03SWei Mi if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap)) 32721b1ad03SWei Mi return EC; 32821b1ad03SWei Mi 32921b1ad03SWei Mi return sampleprof_error::success; 33021b1ad03SWei Mi } 33121b1ad03SWei Mi 33221b1ad03SWei Mi std::error_code SampleProfileWriterExtBinary::writeSections( 33321b1ad03SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 33421b1ad03SWei Mi std::error_code EC; 33521b1ad03SWei Mi if (SecLayout == DefaultLayout) 33621b1ad03SWei Mi EC = writeDefaultLayout(ProfileMap); 33721b1ad03SWei Mi else if (SecLayout == CtxSplitLayout) 33821b1ad03SWei Mi EC = writeCtxSplitLayout(ProfileMap); 33921b1ad03SWei Mi else 34021b1ad03SWei Mi llvm_unreachable("Unsupported layout"); 34121b1ad03SWei Mi return EC; 34221b1ad03SWei Mi } 34321b1ad03SWei Mi 3446a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::write( 3456a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 3466a14325dSWei Mi if (std::error_code EC = SampleProfileWriter::write(ProfileMap)) 3476a14325dSWei Mi return EC; 3486a14325dSWei Mi if (std::error_code EC = writeFuncOffsetTable()) 3496a14325dSWei Mi return EC; 3506a14325dSWei Mi return sampleprof_error::success; 3516a14325dSWei Mi } 3526a14325dSWei Mi 3535f8f34e4SAdrian Prantl /// Write samples to a text file. 3548e415a82SDiego Novillo /// 3558e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of 356ef548d29SDiego Novillo /// FunctionSamples::print(). Please don't. The dump functionality is intended 3578e415a82SDiego Novillo /// for debugging and has no specified form. 3588e415a82SDiego Novillo /// 3598e415a82SDiego Novillo /// The format used here is more structured and deliberate because 3608e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class. 361be907324SWei Mi std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { 36251abea74SNathan Slingerland auto &OS = *OutputStream; 3631f05b1a9Swlei if (FunctionSamples::ProfileIsCS) 3641f05b1a9Swlei OS << "[" << S.getNameWithContext() << "]:" << S.getTotalSamples(); 3651f05b1a9Swlei else 36657d1dda5SDehao Chen OS << S.getName() << ":" << S.getTotalSamples(); 367aae1ed8eSDiego Novillo if (Indent == 0) 368aae1ed8eSDiego Novillo OS << ":" << S.getHeadSamples(); 369aae1ed8eSDiego Novillo OS << "\n"; 370c572e92cSDiego Novillo 371ef548d29SDiego Novillo SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 372ef548d29SDiego Novillo for (const auto &I : SortedSamples.get()) { 373ef548d29SDiego Novillo LineLocation Loc = I->first; 374ef548d29SDiego Novillo const SampleRecord &Sample = I->second; 375aae1ed8eSDiego Novillo OS.indent(Indent + 1); 376c572e92cSDiego Novillo if (Loc.Discriminator == 0) 377c572e92cSDiego Novillo OS << Loc.LineOffset << ": "; 378c572e92cSDiego Novillo else 379c572e92cSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 380c572e92cSDiego Novillo 381c572e92cSDiego Novillo OS << Sample.getSamples(); 382c572e92cSDiego Novillo 3835adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) 3845adace35SWenlei He OS << " " << J.first << ":" << J.second; 385c572e92cSDiego Novillo OS << "\n"; 386c572e92cSDiego Novillo } 387c572e92cSDiego Novillo 3882c7ca9b5SDehao Chen SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 389ef548d29SDiego Novillo S.getCallsiteSamples()); 390aae1ed8eSDiego Novillo Indent += 1; 3912c7ca9b5SDehao Chen for (const auto &I : SortedCallsiteSamples.get()) 3922c7ca9b5SDehao Chen for (const auto &FS : I->second) { 39357d1dda5SDehao Chen LineLocation Loc = I->first; 3942c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 395aae1ed8eSDiego Novillo OS.indent(Indent); 396aae1ed8eSDiego Novillo if (Loc.Discriminator == 0) 397aae1ed8eSDiego Novillo OS << Loc.LineOffset << ": "; 398aae1ed8eSDiego Novillo else 399aae1ed8eSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 400be907324SWei Mi if (std::error_code EC = writeSample(CalleeSamples)) 401760c5a8fSDiego Novillo return EC; 402aae1ed8eSDiego Novillo } 403aae1ed8eSDiego Novillo Indent -= 1; 404aae1ed8eSDiego Novillo 405ac068e01SHongtao Yu if (Indent == 0) { 406ac068e01SHongtao Yu if (FunctionSamples::ProfileIsProbeBased) { 407ac068e01SHongtao Yu OS.indent(Indent + 1); 408ac068e01SHongtao Yu OS << "!CFGChecksum: " << S.getFunctionHash() << "\n"; 409ac068e01SHongtao Yu } 410ac068e01SHongtao Yu } 411ac068e01SHongtao Yu 412760c5a8fSDiego Novillo return sampleprof_error::success; 413c572e92cSDiego Novillo } 414c572e92cSDiego Novillo 415760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 416760c5a8fSDiego Novillo const auto &ret = NameTable.find(FName); 417760c5a8fSDiego Novillo if (ret == NameTable.end()) 418760c5a8fSDiego Novillo return sampleprof_error::truncated_name_table; 41951abea74SNathan Slingerland encodeULEB128(ret->second, *OutputStream); 420760c5a8fSDiego Novillo return sampleprof_error::success; 421760c5a8fSDiego Novillo } 422c572e92cSDiego Novillo 423760c5a8fSDiego Novillo void SampleProfileWriterBinary::addName(StringRef FName) { 4248d1c983fSDehao Chen NameTable.insert(std::make_pair(FName, 0)); 425760c5a8fSDiego Novillo } 426760c5a8fSDiego Novillo 427760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 428760c5a8fSDiego Novillo // Add all the names in indirect call targets. 429760c5a8fSDiego Novillo for (const auto &I : S.getBodySamples()) { 430760c5a8fSDiego Novillo const SampleRecord &Sample = I.second; 431760c5a8fSDiego Novillo for (const auto &J : Sample.getCallTargets()) 432760c5a8fSDiego Novillo addName(J.first()); 433760c5a8fSDiego Novillo } 434760c5a8fSDiego Novillo 435760c5a8fSDiego Novillo // Recursively add all the names for inlined callsites. 4362c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 4372c7ca9b5SDehao Chen for (const auto &FS : J.second) { 4382c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 43957d1dda5SDehao Chen addName(CalleeSamples.getName()); 440760c5a8fSDiego Novillo addNames(CalleeSamples); 441760c5a8fSDiego Novillo } 442760c5a8fSDiego Novillo } 443760c5a8fSDiego Novillo 444a0c0857eSWei Mi void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) { 445a0c0857eSWei Mi // Sort the names to make NameTable deterministic. 446a0c0857eSWei Mi for (const auto &I : NameTable) 447a0c0857eSWei Mi V.insert(I.first); 448a0c0857eSWei Mi int i = 0; 449a0c0857eSWei Mi for (const StringRef &N : V) 450a0c0857eSWei Mi NameTable[N] = i++; 451a0c0857eSWei Mi } 45251abea74SNathan Slingerland 453be907324SWei Mi std::error_code SampleProfileWriterBinary::writeNameTable() { 454a0c0857eSWei Mi auto &OS = *OutputStream; 455a0c0857eSWei Mi std::set<StringRef> V; 456a0c0857eSWei Mi stablizeNameTable(V); 457a0c0857eSWei Mi 458a0c0857eSWei Mi // Write out the name table. 459a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 460a0c0857eSWei Mi for (auto N : V) { 461a0c0857eSWei Mi OS << N; 462a0c0857eSWei Mi encodeULEB128(0, OS); 463a0c0857eSWei Mi } 464a0c0857eSWei Mi return sampleprof_error::success; 465a0c0857eSWei Mi } 466a0c0857eSWei Mi 4676a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { 4686a14325dSWei Mi auto &OS = *OutputStream; 4696a14325dSWei Mi 4706a14325dSWei Mi // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. 4716a14325dSWei Mi auto &OFS = static_cast<raw_fd_ostream &>(OS); 4726a14325dSWei Mi uint64_t FuncOffsetTableStart = OS.tell(); 4736a14325dSWei Mi if (OFS.seek(TableOffset) == (uint64_t)-1) 4746a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 4756a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 4766a14325dSWei Mi Writer.write(FuncOffsetTableStart); 4776a14325dSWei Mi if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) 4786a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 4796a14325dSWei Mi 4806a14325dSWei Mi // Write out the table size. 4816a14325dSWei Mi encodeULEB128(FuncOffsetTable.size(), OS); 4826a14325dSWei Mi 4836a14325dSWei Mi // Write out FuncOffsetTable. 4846a14325dSWei Mi for (auto entry : FuncOffsetTable) { 4856a14325dSWei Mi writeNameIdx(entry.first); 4866a14325dSWei Mi encodeULEB128(entry.second, OS); 4876a14325dSWei Mi } 4886a14325dSWei Mi return sampleprof_error::success; 4896a14325dSWei Mi } 4906a14325dSWei Mi 491a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() { 492a0c0857eSWei Mi auto &OS = *OutputStream; 493a0c0857eSWei Mi std::set<StringRef> V; 494a0c0857eSWei Mi stablizeNameTable(V); 495a0c0857eSWei Mi 496a0c0857eSWei Mi // Write out the name table. 497a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 498a0c0857eSWei Mi for (auto N : V) { 499a0c0857eSWei Mi encodeULEB128(MD5Hash(N), OS); 500a0c0857eSWei Mi } 501a0c0857eSWei Mi return sampleprof_error::success; 502a0c0857eSWei Mi } 503a0c0857eSWei Mi 504be907324SWei Mi std::error_code 505be907324SWei Mi SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { 506a0c0857eSWei Mi auto &OS = *OutputStream; 507760c5a8fSDiego Novillo // Write file magic identifier. 508be907324SWei Mi encodeULEB128(SPMagic(Format), OS); 509a0c0857eSWei Mi encodeULEB128(SPVersion(), OS); 510a0c0857eSWei Mi return sampleprof_error::success; 511a0c0857eSWei Mi } 512a0c0857eSWei Mi 513a0c0857eSWei Mi std::error_code SampleProfileWriterBinary::writeHeader( 514a0c0857eSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 515be907324SWei Mi writeMagicIdent(Format); 516760c5a8fSDiego Novillo 51740ee23dbSEaswaran Raman computeSummary(ProfileMap); 51840ee23dbSEaswaran Raman if (auto EC = writeSummary()) 51940ee23dbSEaswaran Raman return EC; 52040ee23dbSEaswaran Raman 521760c5a8fSDiego Novillo // Generate the name table for all the functions referenced in the profile. 522760c5a8fSDiego Novillo for (const auto &I : ProfileMap) { 523760c5a8fSDiego Novillo addName(I.first()); 524760c5a8fSDiego Novillo addNames(I.second); 525760c5a8fSDiego Novillo } 526760c5a8fSDiego Novillo 527a0c0857eSWei Mi writeNameTable(); 528760c5a8fSDiego Novillo return sampleprof_error::success; 529c572e92cSDiego Novillo } 530c572e92cSDiego Novillo 531b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressAllSections() { 53209dcfe68SWei Mi for (auto &Entry : SectionHdrLayout) 533ebad6788SWei Mi addSecFlag(Entry, SecCommonFlags::SecFlagCompress); 534b523790aSWei Mi } 535b523790aSWei Mi 536b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) { 537ebad6788SWei Mi addSectionFlag(Type, SecCommonFlags::SecFlagCompress); 538b523790aSWei Mi } 539b523790aSWei Mi 540be907324SWei Mi void SampleProfileWriterExtBinaryBase::allocSecHdrTable() { 541be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 542be907324SWei Mi 54309dcfe68SWei Mi Writer.write(static_cast<uint64_t>(SectionHdrLayout.size())); 544be907324SWei Mi SecHdrTableOffset = OutputStream->tell(); 54509dcfe68SWei Mi for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 546be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 547be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 548be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 549be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 550be907324SWei Mi } 551be907324SWei Mi } 552be907324SWei Mi 553be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { 554be907324SWei Mi auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream); 555be907324SWei Mi uint64_t Saved = OutputStream->tell(); 556be907324SWei Mi 557be907324SWei Mi // Set OutputStream to the location saved in SecHdrTableOffset. 558be907324SWei Mi if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1) 559be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 560be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 561be907324SWei Mi 562a906e3ecSWei Mi assert(SecHdrTable.size() == SectionHdrLayout.size() && 563a906e3ecSWei Mi "SecHdrTable entries doesn't match SectionHdrLayout"); 564a906e3ecSWei Mi SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1); 565a906e3ecSWei Mi for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) { 566a906e3ecSWei Mi IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx; 567be907324SWei Mi } 568be907324SWei Mi 56909dcfe68SWei Mi // Write the section header table in the order specified in 570a906e3ecSWei Mi // SectionHdrLayout. SectionHdrLayout specifies the sections 571a906e3ecSWei Mi // order in which profile reader expect to read, so the section 572a906e3ecSWei Mi // header table should be written in the order in SectionHdrLayout. 573a906e3ecSWei Mi // Note that the section order in SecHdrTable may be different 574a906e3ecSWei Mi // from the order in SectionHdrLayout, for example, SecFuncOffsetTable 575a906e3ecSWei Mi // needs to be computed after SecLBRProfile (the order in SecHdrTable), 576a906e3ecSWei Mi // but it needs to be read before SecLBRProfile (the order in 577a906e3ecSWei Mi // SectionHdrLayout). So we use IndexMap above to switch the order. 578a906e3ecSWei Mi for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size(); 579a906e3ecSWei Mi LayoutIdx++) { 580a906e3ecSWei Mi assert(IndexMap[LayoutIdx] < SecHdrTable.size() && 581a906e3ecSWei Mi "Incorrect LayoutIdx in SecHdrTable"); 582a906e3ecSWei Mi auto Entry = SecHdrTable[IndexMap[LayoutIdx]]; 583a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Type)); 584a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Flags)); 585a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Offset)); 586a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Size)); 587be907324SWei Mi } 588be907324SWei Mi 589be907324SWei Mi // Reset OutputStream. 590be907324SWei Mi if (OFS.seek(Saved) == (uint64_t)-1) 591be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 592be907324SWei Mi 593be907324SWei Mi return sampleprof_error::success; 594be907324SWei Mi } 595be907324SWei Mi 596be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeHeader( 597be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 598be907324SWei Mi auto &OS = *OutputStream; 599be907324SWei Mi FileStart = OS.tell(); 600be907324SWei Mi writeMagicIdent(Format); 601be907324SWei Mi 602be907324SWei Mi allocSecHdrTable(); 603be907324SWei Mi return sampleprof_error::success; 604be907324SWei Mi } 605be907324SWei Mi 6066a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader( 6076a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 6086a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 6096a14325dSWei Mi if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) 6106a14325dSWei Mi return EC; 6116a14325dSWei Mi 6126a14325dSWei Mi // Reserve a slot for the offset of function offset table. The slot will 6136a14325dSWei Mi // be populated with the offset of FuncOffsetTable later. 6146a14325dSWei Mi TableOffset = OutputStream->tell(); 6156a14325dSWei Mi Writer.write(static_cast<uint64_t>(-2)); 6166a14325dSWei Mi return sampleprof_error::success; 6176a14325dSWei Mi } 6186a14325dSWei Mi 61940ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() { 62040ee23dbSEaswaran Raman auto &OS = *OutputStream; 6217cefdb81SEaswaran Raman encodeULEB128(Summary->getTotalCount(), OS); 6227cefdb81SEaswaran Raman encodeULEB128(Summary->getMaxCount(), OS); 6236f4903d9SEaswaran Raman encodeULEB128(Summary->getMaxFunctionCount(), OS); 6247cefdb81SEaswaran Raman encodeULEB128(Summary->getNumCounts(), OS); 62540ee23dbSEaswaran Raman encodeULEB128(Summary->getNumFunctions(), OS); 62640ee23dbSEaswaran Raman std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 62740ee23dbSEaswaran Raman encodeULEB128(Entries.size(), OS); 62840ee23dbSEaswaran Raman for (auto Entry : Entries) { 62940ee23dbSEaswaran Raman encodeULEB128(Entry.Cutoff, OS); 63040ee23dbSEaswaran Raman encodeULEB128(Entry.MinCount, OS); 63140ee23dbSEaswaran Raman encodeULEB128(Entry.NumCounts, OS); 63240ee23dbSEaswaran Raman } 63340ee23dbSEaswaran Raman return sampleprof_error::success; 63440ee23dbSEaswaran Raman } 63557d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 63651abea74SNathan Slingerland auto &OS = *OutputStream; 63751abea74SNathan Slingerland 638*7e99bddfSHongtao Yu if (std::error_code EC = writeNameIdx(S.getNameWithContext(true))) 639760c5a8fSDiego Novillo return EC; 640760c5a8fSDiego Novillo 641c572e92cSDiego Novillo encodeULEB128(S.getTotalSamples(), OS); 642a7f1e8efSDiego Novillo 643a7f1e8efSDiego Novillo // Emit all the body samples. 644b93483dbSDiego Novillo encodeULEB128(S.getBodySamples().size(), OS); 645d5336ae2SDiego Novillo for (const auto &I : S.getBodySamples()) { 646d5336ae2SDiego Novillo LineLocation Loc = I.first; 647d5336ae2SDiego Novillo const SampleRecord &Sample = I.second; 648c572e92cSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 649c572e92cSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 650c572e92cSDiego Novillo encodeULEB128(Sample.getSamples(), OS); 651c572e92cSDiego Novillo encodeULEB128(Sample.getCallTargets().size(), OS); 6525adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) { 6535adace35SWenlei He StringRef Callee = J.first; 65438be3330SDiego Novillo uint64_t CalleeSamples = J.second; 655760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(Callee)) 656760c5a8fSDiego Novillo return EC; 657c572e92cSDiego Novillo encodeULEB128(CalleeSamples, OS); 658c572e92cSDiego Novillo } 659c572e92cSDiego Novillo } 660c572e92cSDiego Novillo 661a7f1e8efSDiego Novillo // Recursively emit all the callsite samples. 6622c27daf7SDehao Chen uint64_t NumCallsites = 0; 6632c27daf7SDehao Chen for (const auto &J : S.getCallsiteSamples()) 6642c27daf7SDehao Chen NumCallsites += J.second.size(); 6652c27daf7SDehao Chen encodeULEB128(NumCallsites, OS); 6662c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 6672c7ca9b5SDehao Chen for (const auto &FS : J.second) { 66857d1dda5SDehao Chen LineLocation Loc = J.first; 6692c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 670a7f1e8efSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 671a7f1e8efSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 67257d1dda5SDehao Chen if (std::error_code EC = writeBody(CalleeSamples)) 673760c5a8fSDiego Novillo return EC; 674a7f1e8efSDiego Novillo } 675a7f1e8efSDiego Novillo 676760c5a8fSDiego Novillo return sampleprof_error::success; 677c572e92cSDiego Novillo } 678d5336ae2SDiego Novillo 6795f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file. 680b93483dbSDiego Novillo /// 681b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise. 682be907324SWei Mi std::error_code 683be907324SWei Mi SampleProfileWriterBinary::writeSample(const FunctionSamples &S) { 68451abea74SNathan Slingerland encodeULEB128(S.getHeadSamples(), *OutputStream); 68557d1dda5SDehao Chen return writeBody(S); 686b93483dbSDiego Novillo } 687b93483dbSDiego Novillo 6886a14325dSWei Mi std::error_code 689be907324SWei Mi SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) { 6906a14325dSWei Mi uint64_t Offset = OutputStream->tell(); 6916a14325dSWei Mi StringRef Name = S.getName(); 6926a14325dSWei Mi FuncOffsetTable[Name] = Offset; 6936a14325dSWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream); 6946a14325dSWei Mi return writeBody(S); 6956a14325dSWei Mi } 6966a14325dSWei Mi 6975f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format. 698d5336ae2SDiego Novillo /// 699d5336ae2SDiego Novillo /// \param Filename The file to create. 700d5336ae2SDiego Novillo /// 701d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file. 702d5336ae2SDiego Novillo /// 703d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer. 704fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>> 705fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 706d5336ae2SDiego Novillo std::error_code EC; 70751abea74SNathan Slingerland std::unique_ptr<raw_ostream> OS; 708be907324SWei Mi if (Format == SPF_Binary || Format == SPF_Ext_Binary || 709be907324SWei Mi Format == SPF_Compact_Binary) 710d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None)); 71151abea74SNathan Slingerland else 712d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text)); 71351abea74SNathan Slingerland if (EC) 71451abea74SNathan Slingerland return EC; 71551abea74SNathan Slingerland 71651abea74SNathan Slingerland return create(OS, Format); 71751abea74SNathan Slingerland } 71851abea74SNathan Slingerland 7195f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format. 72051abea74SNathan Slingerland /// 72151abea74SNathan Slingerland /// \param OS The output stream to store the profile data to. 72251abea74SNathan Slingerland /// 72351abea74SNathan Slingerland /// \param Format Encoding format for the profile file. 72451abea74SNathan Slingerland /// 72551abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer. 72651abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>> 72751abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 72851abea74SNathan Slingerland SampleProfileFormat Format) { 72951abea74SNathan Slingerland std::error_code EC; 730fcd55607SDiego Novillo std::unique_ptr<SampleProfileWriter> Writer; 731d5336ae2SDiego Novillo 732d9be2c7eSWei Mi if (Format == SPF_Binary) 733a0c0857eSWei Mi Writer.reset(new SampleProfileWriterRawBinary(OS)); 734be907324SWei Mi else if (Format == SPF_Ext_Binary) 735be907324SWei Mi Writer.reset(new SampleProfileWriterExtBinary(OS)); 736a0c0857eSWei Mi else if (Format == SPF_Compact_Binary) 737a0c0857eSWei Mi Writer.reset(new SampleProfileWriterCompactBinary(OS)); 738d5336ae2SDiego Novillo else if (Format == SPF_Text) 73951abea74SNathan Slingerland Writer.reset(new SampleProfileWriterText(OS)); 740760c5a8fSDiego Novillo else if (Format == SPF_GCC) 741760c5a8fSDiego Novillo EC = sampleprof_error::unsupported_writing_format; 742d5336ae2SDiego Novillo else 743d5336ae2SDiego Novillo EC = sampleprof_error::unrecognized_format; 744d5336ae2SDiego Novillo 745fcd55607SDiego Novillo if (EC) 746d5336ae2SDiego Novillo return EC; 747fcd55607SDiego Novillo 748be907324SWei Mi Writer->Format = Format; 749c55cf4afSBill Wendling return std::move(Writer); 750d5336ae2SDiego Novillo } 75140ee23dbSEaswaran Raman 75240ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary( 75340ee23dbSEaswaran Raman const StringMap<FunctionSamples> &ProfileMap) { 754e5a17e3fSEaswaran Raman SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 75540ee23dbSEaswaran Raman for (const auto &I : ProfileMap) { 75640ee23dbSEaswaran Raman const FunctionSamples &Profile = I.second; 757e5a17e3fSEaswaran Raman Builder.addRecord(Profile); 75840ee23dbSEaswaran Raman } 75938de59e4SBenjamin Kramer Summary = Builder.getSummary(); 76040ee23dbSEaswaran Raman } 761