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 } 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; 363*c3aeabaeSwlei OS << S.getNameWithContext(true) << ":" << S.getTotalSamples(); 364aae1ed8eSDiego Novillo if (Indent == 0) 365aae1ed8eSDiego Novillo OS << ":" << S.getHeadSamples(); 366aae1ed8eSDiego Novillo OS << "\n"; 367c572e92cSDiego Novillo 368ef548d29SDiego Novillo SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 369ef548d29SDiego Novillo for (const auto &I : SortedSamples.get()) { 370ef548d29SDiego Novillo LineLocation Loc = I->first; 371ef548d29SDiego Novillo const SampleRecord &Sample = I->second; 372aae1ed8eSDiego Novillo OS.indent(Indent + 1); 373c572e92cSDiego Novillo if (Loc.Discriminator == 0) 374c572e92cSDiego Novillo OS << Loc.LineOffset << ": "; 375c572e92cSDiego Novillo else 376c572e92cSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 377c572e92cSDiego Novillo 378c572e92cSDiego Novillo OS << Sample.getSamples(); 379c572e92cSDiego Novillo 3805adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) 3815adace35SWenlei He OS << " " << J.first << ":" << J.second; 382c572e92cSDiego Novillo OS << "\n"; 383c572e92cSDiego Novillo } 384c572e92cSDiego Novillo 3852c7ca9b5SDehao Chen SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 386ef548d29SDiego Novillo S.getCallsiteSamples()); 387aae1ed8eSDiego Novillo Indent += 1; 3882c7ca9b5SDehao Chen for (const auto &I : SortedCallsiteSamples.get()) 3892c7ca9b5SDehao Chen for (const auto &FS : I->second) { 39057d1dda5SDehao Chen LineLocation Loc = I->first; 3912c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 392aae1ed8eSDiego Novillo OS.indent(Indent); 393aae1ed8eSDiego Novillo if (Loc.Discriminator == 0) 394aae1ed8eSDiego Novillo OS << Loc.LineOffset << ": "; 395aae1ed8eSDiego Novillo else 396aae1ed8eSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 397be907324SWei Mi if (std::error_code EC = writeSample(CalleeSamples)) 398760c5a8fSDiego Novillo return EC; 399aae1ed8eSDiego Novillo } 400aae1ed8eSDiego Novillo Indent -= 1; 401aae1ed8eSDiego Novillo 402ac068e01SHongtao Yu if (Indent == 0) { 403ac068e01SHongtao Yu if (FunctionSamples::ProfileIsProbeBased) { 404ac068e01SHongtao Yu OS.indent(Indent + 1); 405ac068e01SHongtao Yu OS << "!CFGChecksum: " << S.getFunctionHash() << "\n"; 406ac068e01SHongtao Yu } 407ac068e01SHongtao Yu } 408ac068e01SHongtao Yu 409760c5a8fSDiego Novillo return sampleprof_error::success; 410c572e92cSDiego Novillo } 411c572e92cSDiego Novillo 412760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 413760c5a8fSDiego Novillo const auto &ret = NameTable.find(FName); 414760c5a8fSDiego Novillo if (ret == NameTable.end()) 415760c5a8fSDiego Novillo return sampleprof_error::truncated_name_table; 41651abea74SNathan Slingerland encodeULEB128(ret->second, *OutputStream); 417760c5a8fSDiego Novillo return sampleprof_error::success; 418760c5a8fSDiego Novillo } 419c572e92cSDiego Novillo 420760c5a8fSDiego Novillo void SampleProfileWriterBinary::addName(StringRef FName) { 4218d1c983fSDehao Chen NameTable.insert(std::make_pair(FName, 0)); 422760c5a8fSDiego Novillo } 423760c5a8fSDiego Novillo 424760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 425760c5a8fSDiego Novillo // Add all the names in indirect call targets. 426760c5a8fSDiego Novillo for (const auto &I : S.getBodySamples()) { 427760c5a8fSDiego Novillo const SampleRecord &Sample = I.second; 428760c5a8fSDiego Novillo for (const auto &J : Sample.getCallTargets()) 429760c5a8fSDiego Novillo addName(J.first()); 430760c5a8fSDiego Novillo } 431760c5a8fSDiego Novillo 432760c5a8fSDiego Novillo // Recursively add all the names for inlined callsites. 4332c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 4342c7ca9b5SDehao Chen for (const auto &FS : J.second) { 4352c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 43657d1dda5SDehao Chen addName(CalleeSamples.getName()); 437760c5a8fSDiego Novillo addNames(CalleeSamples); 438760c5a8fSDiego Novillo } 439760c5a8fSDiego Novillo } 440760c5a8fSDiego Novillo 441a0c0857eSWei Mi void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) { 442a0c0857eSWei Mi // Sort the names to make NameTable deterministic. 443a0c0857eSWei Mi for (const auto &I : NameTable) 444a0c0857eSWei Mi V.insert(I.first); 445a0c0857eSWei Mi int i = 0; 446a0c0857eSWei Mi for (const StringRef &N : V) 447a0c0857eSWei Mi NameTable[N] = i++; 448a0c0857eSWei Mi } 44951abea74SNathan Slingerland 450be907324SWei Mi std::error_code SampleProfileWriterBinary::writeNameTable() { 451a0c0857eSWei Mi auto &OS = *OutputStream; 452a0c0857eSWei Mi std::set<StringRef> V; 453a0c0857eSWei Mi stablizeNameTable(V); 454a0c0857eSWei Mi 455a0c0857eSWei Mi // Write out the name table. 456a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 457a0c0857eSWei Mi for (auto N : V) { 458a0c0857eSWei Mi OS << N; 459a0c0857eSWei Mi encodeULEB128(0, OS); 460a0c0857eSWei Mi } 461a0c0857eSWei Mi return sampleprof_error::success; 462a0c0857eSWei Mi } 463a0c0857eSWei Mi 4646a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { 4656a14325dSWei Mi auto &OS = *OutputStream; 4666a14325dSWei Mi 4676a14325dSWei Mi // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. 4686a14325dSWei Mi auto &OFS = static_cast<raw_fd_ostream &>(OS); 4696a14325dSWei Mi uint64_t FuncOffsetTableStart = OS.tell(); 4706a14325dSWei Mi if (OFS.seek(TableOffset) == (uint64_t)-1) 4716a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 4726a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 4736a14325dSWei Mi Writer.write(FuncOffsetTableStart); 4746a14325dSWei Mi if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) 4756a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 4766a14325dSWei Mi 4776a14325dSWei Mi // Write out the table size. 4786a14325dSWei Mi encodeULEB128(FuncOffsetTable.size(), OS); 4796a14325dSWei Mi 4806a14325dSWei Mi // Write out FuncOffsetTable. 4816a14325dSWei Mi for (auto entry : FuncOffsetTable) { 4826a14325dSWei Mi writeNameIdx(entry.first); 4836a14325dSWei Mi encodeULEB128(entry.second, OS); 4846a14325dSWei Mi } 4856a14325dSWei Mi return sampleprof_error::success; 4866a14325dSWei Mi } 4876a14325dSWei Mi 488a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() { 489a0c0857eSWei Mi auto &OS = *OutputStream; 490a0c0857eSWei Mi std::set<StringRef> V; 491a0c0857eSWei Mi stablizeNameTable(V); 492a0c0857eSWei Mi 493a0c0857eSWei Mi // Write out the name table. 494a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 495a0c0857eSWei Mi for (auto N : V) { 496a0c0857eSWei Mi encodeULEB128(MD5Hash(N), OS); 497a0c0857eSWei Mi } 498a0c0857eSWei Mi return sampleprof_error::success; 499a0c0857eSWei Mi } 500a0c0857eSWei Mi 501be907324SWei Mi std::error_code 502be907324SWei Mi SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { 503a0c0857eSWei Mi auto &OS = *OutputStream; 504760c5a8fSDiego Novillo // Write file magic identifier. 505be907324SWei Mi encodeULEB128(SPMagic(Format), OS); 506a0c0857eSWei Mi encodeULEB128(SPVersion(), OS); 507a0c0857eSWei Mi return sampleprof_error::success; 508a0c0857eSWei Mi } 509a0c0857eSWei Mi 510a0c0857eSWei Mi std::error_code SampleProfileWriterBinary::writeHeader( 511a0c0857eSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 512be907324SWei Mi writeMagicIdent(Format); 513760c5a8fSDiego Novillo 51440ee23dbSEaswaran Raman computeSummary(ProfileMap); 51540ee23dbSEaswaran Raman if (auto EC = writeSummary()) 51640ee23dbSEaswaran Raman return EC; 51740ee23dbSEaswaran Raman 518760c5a8fSDiego Novillo // Generate the name table for all the functions referenced in the profile. 519760c5a8fSDiego Novillo for (const auto &I : ProfileMap) { 520760c5a8fSDiego Novillo addName(I.first()); 521760c5a8fSDiego Novillo addNames(I.second); 522760c5a8fSDiego Novillo } 523760c5a8fSDiego Novillo 524a0c0857eSWei Mi writeNameTable(); 525760c5a8fSDiego Novillo return sampleprof_error::success; 526c572e92cSDiego Novillo } 527c572e92cSDiego Novillo 528b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressAllSections() { 52909dcfe68SWei Mi for (auto &Entry : SectionHdrLayout) 530ebad6788SWei Mi addSecFlag(Entry, SecCommonFlags::SecFlagCompress); 531b523790aSWei Mi } 532b523790aSWei Mi 533b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) { 534ebad6788SWei Mi addSectionFlag(Type, SecCommonFlags::SecFlagCompress); 535b523790aSWei Mi } 536b523790aSWei Mi 537be907324SWei Mi void SampleProfileWriterExtBinaryBase::allocSecHdrTable() { 538be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 539be907324SWei Mi 54009dcfe68SWei Mi Writer.write(static_cast<uint64_t>(SectionHdrLayout.size())); 541be907324SWei Mi SecHdrTableOffset = OutputStream->tell(); 54209dcfe68SWei Mi for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 543be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 544be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 545be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 546be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 547be907324SWei Mi } 548be907324SWei Mi } 549be907324SWei Mi 550be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { 551be907324SWei Mi auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream); 552be907324SWei Mi uint64_t Saved = OutputStream->tell(); 553be907324SWei Mi 554be907324SWei Mi // Set OutputStream to the location saved in SecHdrTableOffset. 555be907324SWei Mi if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1) 556be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 557be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 558be907324SWei Mi 559a906e3ecSWei Mi assert(SecHdrTable.size() == SectionHdrLayout.size() && 560a906e3ecSWei Mi "SecHdrTable entries doesn't match SectionHdrLayout"); 561a906e3ecSWei Mi SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1); 562a906e3ecSWei Mi for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) { 563a906e3ecSWei Mi IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx; 564be907324SWei Mi } 565be907324SWei Mi 56609dcfe68SWei Mi // Write the section header table in the order specified in 567a906e3ecSWei Mi // SectionHdrLayout. SectionHdrLayout specifies the sections 568a906e3ecSWei Mi // order in which profile reader expect to read, so the section 569a906e3ecSWei Mi // header table should be written in the order in SectionHdrLayout. 570a906e3ecSWei Mi // Note that the section order in SecHdrTable may be different 571a906e3ecSWei Mi // from the order in SectionHdrLayout, for example, SecFuncOffsetTable 572a906e3ecSWei Mi // needs to be computed after SecLBRProfile (the order in SecHdrTable), 573a906e3ecSWei Mi // but it needs to be read before SecLBRProfile (the order in 574a906e3ecSWei Mi // SectionHdrLayout). So we use IndexMap above to switch the order. 575a906e3ecSWei Mi for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size(); 576a906e3ecSWei Mi LayoutIdx++) { 577a906e3ecSWei Mi assert(IndexMap[LayoutIdx] < SecHdrTable.size() && 578a906e3ecSWei Mi "Incorrect LayoutIdx in SecHdrTable"); 579a906e3ecSWei Mi auto Entry = SecHdrTable[IndexMap[LayoutIdx]]; 580a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Type)); 581a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Flags)); 582a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Offset)); 583a906e3ecSWei Mi Writer.write(static_cast<uint64_t>(Entry.Size)); 584be907324SWei Mi } 585be907324SWei Mi 586be907324SWei Mi // Reset OutputStream. 587be907324SWei Mi if (OFS.seek(Saved) == (uint64_t)-1) 588be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 589be907324SWei Mi 590be907324SWei Mi return sampleprof_error::success; 591be907324SWei Mi } 592be907324SWei Mi 593be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeHeader( 594be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 595be907324SWei Mi auto &OS = *OutputStream; 596be907324SWei Mi FileStart = OS.tell(); 597be907324SWei Mi writeMagicIdent(Format); 598be907324SWei Mi 599be907324SWei Mi allocSecHdrTable(); 600be907324SWei Mi return sampleprof_error::success; 601be907324SWei Mi } 602be907324SWei Mi 6036a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader( 6046a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 6056a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 6066a14325dSWei Mi if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) 6076a14325dSWei Mi return EC; 6086a14325dSWei Mi 6096a14325dSWei Mi // Reserve a slot for the offset of function offset table. The slot will 6106a14325dSWei Mi // be populated with the offset of FuncOffsetTable later. 6116a14325dSWei Mi TableOffset = OutputStream->tell(); 6126a14325dSWei Mi Writer.write(static_cast<uint64_t>(-2)); 6136a14325dSWei Mi return sampleprof_error::success; 6146a14325dSWei Mi } 6156a14325dSWei Mi 61640ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() { 61740ee23dbSEaswaran Raman auto &OS = *OutputStream; 6187cefdb81SEaswaran Raman encodeULEB128(Summary->getTotalCount(), OS); 6197cefdb81SEaswaran Raman encodeULEB128(Summary->getMaxCount(), OS); 6206f4903d9SEaswaran Raman encodeULEB128(Summary->getMaxFunctionCount(), OS); 6217cefdb81SEaswaran Raman encodeULEB128(Summary->getNumCounts(), OS); 62240ee23dbSEaswaran Raman encodeULEB128(Summary->getNumFunctions(), OS); 62340ee23dbSEaswaran Raman std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 62440ee23dbSEaswaran Raman encodeULEB128(Entries.size(), OS); 62540ee23dbSEaswaran Raman for (auto Entry : Entries) { 62640ee23dbSEaswaran Raman encodeULEB128(Entry.Cutoff, OS); 62740ee23dbSEaswaran Raman encodeULEB128(Entry.MinCount, OS); 62840ee23dbSEaswaran Raman encodeULEB128(Entry.NumCounts, OS); 62940ee23dbSEaswaran Raman } 63040ee23dbSEaswaran Raman return sampleprof_error::success; 63140ee23dbSEaswaran Raman } 63257d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 63351abea74SNathan Slingerland auto &OS = *OutputStream; 63451abea74SNathan Slingerland 6357e99bddfSHongtao Yu if (std::error_code EC = writeNameIdx(S.getNameWithContext(true))) 636760c5a8fSDiego Novillo return EC; 637760c5a8fSDiego Novillo 638c572e92cSDiego Novillo encodeULEB128(S.getTotalSamples(), OS); 639a7f1e8efSDiego Novillo 640a7f1e8efSDiego Novillo // Emit all the body samples. 641b93483dbSDiego Novillo encodeULEB128(S.getBodySamples().size(), OS); 642d5336ae2SDiego Novillo for (const auto &I : S.getBodySamples()) { 643d5336ae2SDiego Novillo LineLocation Loc = I.first; 644d5336ae2SDiego Novillo const SampleRecord &Sample = I.second; 645c572e92cSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 646c572e92cSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 647c572e92cSDiego Novillo encodeULEB128(Sample.getSamples(), OS); 648c572e92cSDiego Novillo encodeULEB128(Sample.getCallTargets().size(), OS); 6495adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) { 6505adace35SWenlei He StringRef Callee = J.first; 65138be3330SDiego Novillo uint64_t CalleeSamples = J.second; 652760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(Callee)) 653760c5a8fSDiego Novillo return EC; 654c572e92cSDiego Novillo encodeULEB128(CalleeSamples, OS); 655c572e92cSDiego Novillo } 656c572e92cSDiego Novillo } 657c572e92cSDiego Novillo 658a7f1e8efSDiego Novillo // Recursively emit all the callsite samples. 6592c27daf7SDehao Chen uint64_t NumCallsites = 0; 6602c27daf7SDehao Chen for (const auto &J : S.getCallsiteSamples()) 6612c27daf7SDehao Chen NumCallsites += J.second.size(); 6622c27daf7SDehao Chen encodeULEB128(NumCallsites, OS); 6632c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 6642c7ca9b5SDehao Chen for (const auto &FS : J.second) { 66557d1dda5SDehao Chen LineLocation Loc = J.first; 6662c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 667a7f1e8efSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 668a7f1e8efSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 66957d1dda5SDehao Chen if (std::error_code EC = writeBody(CalleeSamples)) 670760c5a8fSDiego Novillo return EC; 671a7f1e8efSDiego Novillo } 672a7f1e8efSDiego Novillo 673760c5a8fSDiego Novillo return sampleprof_error::success; 674c572e92cSDiego Novillo } 675d5336ae2SDiego Novillo 6765f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file. 677b93483dbSDiego Novillo /// 678b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise. 679be907324SWei Mi std::error_code 680be907324SWei Mi SampleProfileWriterBinary::writeSample(const FunctionSamples &S) { 68151abea74SNathan Slingerland encodeULEB128(S.getHeadSamples(), *OutputStream); 68257d1dda5SDehao Chen return writeBody(S); 683b93483dbSDiego Novillo } 684b93483dbSDiego Novillo 6856a14325dSWei Mi std::error_code 686be907324SWei Mi SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) { 6876a14325dSWei Mi uint64_t Offset = OutputStream->tell(); 6886a14325dSWei Mi StringRef Name = S.getName(); 6896a14325dSWei Mi FuncOffsetTable[Name] = Offset; 6906a14325dSWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream); 6916a14325dSWei Mi return writeBody(S); 6926a14325dSWei Mi } 6936a14325dSWei Mi 6945f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format. 695d5336ae2SDiego Novillo /// 696d5336ae2SDiego Novillo /// \param Filename The file to create. 697d5336ae2SDiego Novillo /// 698d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file. 699d5336ae2SDiego Novillo /// 700d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer. 701fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>> 702fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 703d5336ae2SDiego Novillo std::error_code EC; 70451abea74SNathan Slingerland std::unique_ptr<raw_ostream> OS; 705be907324SWei Mi if (Format == SPF_Binary || Format == SPF_Ext_Binary || 706be907324SWei Mi Format == SPF_Compact_Binary) 707d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None)); 70851abea74SNathan Slingerland else 709d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text)); 71051abea74SNathan Slingerland if (EC) 71151abea74SNathan Slingerland return EC; 71251abea74SNathan Slingerland 71351abea74SNathan Slingerland return create(OS, Format); 71451abea74SNathan Slingerland } 71551abea74SNathan Slingerland 7165f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format. 71751abea74SNathan Slingerland /// 71851abea74SNathan Slingerland /// \param OS The output stream to store the profile data to. 71951abea74SNathan Slingerland /// 72051abea74SNathan Slingerland /// \param Format Encoding format for the profile file. 72151abea74SNathan Slingerland /// 72251abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer. 72351abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>> 72451abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 72551abea74SNathan Slingerland SampleProfileFormat Format) { 72651abea74SNathan Slingerland std::error_code EC; 727fcd55607SDiego Novillo std::unique_ptr<SampleProfileWriter> Writer; 728d5336ae2SDiego Novillo 729d9be2c7eSWei Mi if (Format == SPF_Binary) 730a0c0857eSWei Mi Writer.reset(new SampleProfileWriterRawBinary(OS)); 731be907324SWei Mi else if (Format == SPF_Ext_Binary) 732be907324SWei Mi Writer.reset(new SampleProfileWriterExtBinary(OS)); 733a0c0857eSWei Mi else if (Format == SPF_Compact_Binary) 734a0c0857eSWei Mi Writer.reset(new SampleProfileWriterCompactBinary(OS)); 735d5336ae2SDiego Novillo else if (Format == SPF_Text) 73651abea74SNathan Slingerland Writer.reset(new SampleProfileWriterText(OS)); 737760c5a8fSDiego Novillo else if (Format == SPF_GCC) 738760c5a8fSDiego Novillo EC = sampleprof_error::unsupported_writing_format; 739d5336ae2SDiego Novillo else 740d5336ae2SDiego Novillo EC = sampleprof_error::unrecognized_format; 741d5336ae2SDiego Novillo 742fcd55607SDiego Novillo if (EC) 743d5336ae2SDiego Novillo return EC; 744fcd55607SDiego Novillo 745be907324SWei Mi Writer->Format = Format; 746c55cf4afSBill Wendling return std::move(Writer); 747d5336ae2SDiego Novillo } 74840ee23dbSEaswaran Raman 74940ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary( 75040ee23dbSEaswaran Raman const StringMap<FunctionSamples> &ProfileMap) { 751e5a17e3fSEaswaran Raman SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 752801d9cc7SWenlei He Summary = Builder.computeSummaryForProfiles(ProfileMap); 75340ee23dbSEaswaran Raman } 754