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" 22e78d131aSEugene Zelenko #include "llvm/ProfileData/ProfileCommon.h" 23e78d131aSEugene Zelenko #include "llvm/ProfileData/SampleProf.h" 246a14325dSWei Mi #include "llvm/Support/Endian.h" 256a14325dSWei Mi #include "llvm/Support/EndianStream.h" 26c572e92cSDiego Novillo #include "llvm/Support/ErrorOr.h" 27e78d131aSEugene Zelenko #include "llvm/Support/FileSystem.h" 28c572e92cSDiego Novillo #include "llvm/Support/LEB128.h" 29a0c0857eSWei Mi #include "llvm/Support/MD5.h" 30e78d131aSEugene Zelenko #include "llvm/Support/raw_ostream.h" 31e78d131aSEugene Zelenko #include <algorithm> 32e78d131aSEugene Zelenko #include <cstdint> 33e78d131aSEugene Zelenko #include <memory> 348d1c983fSDehao Chen #include <set> 35e78d131aSEugene Zelenko #include <system_error> 36e78d131aSEugene Zelenko #include <utility> 37e78d131aSEugene Zelenko #include <vector> 38c572e92cSDiego Novillo 39c572e92cSDiego Novillo using namespace llvm; 40e78d131aSEugene Zelenko using namespace sampleprof; 41c572e92cSDiego Novillo 428d1c983fSDehao Chen std::error_code 438d1c983fSDehao Chen SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) { 448d1c983fSDehao Chen if (std::error_code EC = writeHeader(ProfileMap)) 458d1c983fSDehao Chen return EC; 468d1c983fSDehao Chen 478d1c983fSDehao Chen // Sort the ProfileMap by total samples. 488d1c983fSDehao Chen typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples; 498d1c983fSDehao Chen std::vector<NameFunctionSamples> V; 508d1c983fSDehao Chen for (const auto &I : ProfileMap) 518d1c983fSDehao Chen V.push_back(std::make_pair(I.getKey(), &I.second)); 528d1c983fSDehao Chen 53*efd94c56SFangrui Song llvm::stable_sort( 54*efd94c56SFangrui Song V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) { 558d1c983fSDehao Chen if (A.second->getTotalSamples() == B.second->getTotalSamples()) 568d1c983fSDehao Chen return A.first > B.first; 578d1c983fSDehao Chen return A.second->getTotalSamples() > B.second->getTotalSamples(); 588d1c983fSDehao Chen }); 598d1c983fSDehao Chen 608d1c983fSDehao Chen for (const auto &I : V) { 618d1c983fSDehao Chen if (std::error_code EC = write(*I.second)) 628d1c983fSDehao Chen return EC; 638d1c983fSDehao Chen } 648d1c983fSDehao Chen return sampleprof_error::success; 658d1c983fSDehao Chen } 668d1c983fSDehao Chen 676a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::write( 686a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 696a14325dSWei Mi if (std::error_code EC = SampleProfileWriter::write(ProfileMap)) 706a14325dSWei Mi return EC; 716a14325dSWei Mi if (std::error_code EC = writeFuncOffsetTable()) 726a14325dSWei Mi return EC; 736a14325dSWei Mi return sampleprof_error::success; 746a14325dSWei Mi } 756a14325dSWei Mi 765f8f34e4SAdrian Prantl /// Write samples to a text file. 778e415a82SDiego Novillo /// 788e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of 79ef548d29SDiego Novillo /// FunctionSamples::print(). Please don't. The dump functionality is intended 808e415a82SDiego Novillo /// for debugging and has no specified form. 818e415a82SDiego Novillo /// 828e415a82SDiego Novillo /// The format used here is more structured and deliberate because 838e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class. 8457d1dda5SDehao Chen std::error_code SampleProfileWriterText::write(const FunctionSamples &S) { 8551abea74SNathan Slingerland auto &OS = *OutputStream; 8657d1dda5SDehao Chen OS << S.getName() << ":" << S.getTotalSamples(); 87aae1ed8eSDiego Novillo if (Indent == 0) 88aae1ed8eSDiego Novillo OS << ":" << S.getHeadSamples(); 89aae1ed8eSDiego Novillo OS << "\n"; 90c572e92cSDiego Novillo 91ef548d29SDiego Novillo SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 92ef548d29SDiego Novillo for (const auto &I : SortedSamples.get()) { 93ef548d29SDiego Novillo LineLocation Loc = I->first; 94ef548d29SDiego Novillo const SampleRecord &Sample = I->second; 95aae1ed8eSDiego Novillo OS.indent(Indent + 1); 96c572e92cSDiego Novillo if (Loc.Discriminator == 0) 97c572e92cSDiego Novillo OS << Loc.LineOffset << ": "; 98c572e92cSDiego Novillo else 99c572e92cSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 100c572e92cSDiego Novillo 101c572e92cSDiego Novillo OS << Sample.getSamples(); 102c572e92cSDiego Novillo 103d5336ae2SDiego Novillo for (const auto &J : Sample.getCallTargets()) 104d5336ae2SDiego Novillo OS << " " << J.first() << ":" << J.second; 105c572e92cSDiego Novillo OS << "\n"; 106c572e92cSDiego Novillo } 107c572e92cSDiego Novillo 1082c7ca9b5SDehao Chen SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 109ef548d29SDiego Novillo S.getCallsiteSamples()); 110aae1ed8eSDiego Novillo Indent += 1; 1112c7ca9b5SDehao Chen for (const auto &I : SortedCallsiteSamples.get()) 1122c7ca9b5SDehao Chen for (const auto &FS : I->second) { 11357d1dda5SDehao Chen LineLocation Loc = I->first; 1142c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 115aae1ed8eSDiego Novillo OS.indent(Indent); 116aae1ed8eSDiego Novillo if (Loc.Discriminator == 0) 117aae1ed8eSDiego Novillo OS << Loc.LineOffset << ": "; 118aae1ed8eSDiego Novillo else 119aae1ed8eSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 12057d1dda5SDehao Chen if (std::error_code EC = write(CalleeSamples)) 121760c5a8fSDiego Novillo return EC; 122aae1ed8eSDiego Novillo } 123aae1ed8eSDiego Novillo Indent -= 1; 124aae1ed8eSDiego Novillo 125760c5a8fSDiego Novillo return sampleprof_error::success; 126c572e92cSDiego Novillo } 127c572e92cSDiego Novillo 128760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 129760c5a8fSDiego Novillo const auto &ret = NameTable.find(FName); 130760c5a8fSDiego Novillo if (ret == NameTable.end()) 131760c5a8fSDiego Novillo return sampleprof_error::truncated_name_table; 13251abea74SNathan Slingerland encodeULEB128(ret->second, *OutputStream); 133760c5a8fSDiego Novillo return sampleprof_error::success; 134760c5a8fSDiego Novillo } 135c572e92cSDiego Novillo 136760c5a8fSDiego Novillo void SampleProfileWriterBinary::addName(StringRef FName) { 1378d1c983fSDehao Chen NameTable.insert(std::make_pair(FName, 0)); 138760c5a8fSDiego Novillo } 139760c5a8fSDiego Novillo 140760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 141760c5a8fSDiego Novillo // Add all the names in indirect call targets. 142760c5a8fSDiego Novillo for (const auto &I : S.getBodySamples()) { 143760c5a8fSDiego Novillo const SampleRecord &Sample = I.second; 144760c5a8fSDiego Novillo for (const auto &J : Sample.getCallTargets()) 145760c5a8fSDiego Novillo addName(J.first()); 146760c5a8fSDiego Novillo } 147760c5a8fSDiego Novillo 148760c5a8fSDiego Novillo // Recursively add all the names for inlined callsites. 1492c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 1502c7ca9b5SDehao Chen for (const auto &FS : J.second) { 1512c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 15257d1dda5SDehao Chen addName(CalleeSamples.getName()); 153760c5a8fSDiego Novillo addNames(CalleeSamples); 154760c5a8fSDiego Novillo } 155760c5a8fSDiego Novillo } 156760c5a8fSDiego Novillo 157a0c0857eSWei Mi void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) { 158a0c0857eSWei Mi // Sort the names to make NameTable deterministic. 159a0c0857eSWei Mi for (const auto &I : NameTable) 160a0c0857eSWei Mi V.insert(I.first); 161a0c0857eSWei Mi int i = 0; 162a0c0857eSWei Mi for (const StringRef &N : V) 163a0c0857eSWei Mi NameTable[N] = i++; 164a0c0857eSWei Mi } 16551abea74SNathan Slingerland 166a0c0857eSWei Mi std::error_code SampleProfileWriterRawBinary::writeNameTable() { 167a0c0857eSWei Mi auto &OS = *OutputStream; 168a0c0857eSWei Mi std::set<StringRef> V; 169a0c0857eSWei Mi stablizeNameTable(V); 170a0c0857eSWei Mi 171a0c0857eSWei Mi // Write out the name table. 172a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 173a0c0857eSWei Mi for (auto N : V) { 174a0c0857eSWei Mi OS << N; 175a0c0857eSWei Mi encodeULEB128(0, OS); 176a0c0857eSWei Mi } 177a0c0857eSWei Mi return sampleprof_error::success; 178a0c0857eSWei Mi } 179a0c0857eSWei Mi 1806a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { 1816a14325dSWei Mi auto &OS = *OutputStream; 1826a14325dSWei Mi 1836a14325dSWei Mi // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. 1846a14325dSWei Mi auto &OFS = static_cast<raw_fd_ostream &>(OS); 1856a14325dSWei Mi uint64_t FuncOffsetTableStart = OS.tell(); 1866a14325dSWei Mi if (OFS.seek(TableOffset) == (uint64_t)-1) 1876a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 1886a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 1896a14325dSWei Mi Writer.write(FuncOffsetTableStart); 1906a14325dSWei Mi if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) 1916a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 1926a14325dSWei Mi 1936a14325dSWei Mi // Write out the table size. 1946a14325dSWei Mi encodeULEB128(FuncOffsetTable.size(), OS); 1956a14325dSWei Mi 1966a14325dSWei Mi // Write out FuncOffsetTable. 1976a14325dSWei Mi for (auto entry : FuncOffsetTable) { 1986a14325dSWei Mi writeNameIdx(entry.first); 1996a14325dSWei Mi encodeULEB128(entry.second, OS); 2006a14325dSWei Mi } 2016a14325dSWei Mi return sampleprof_error::success; 2026a14325dSWei Mi } 2036a14325dSWei Mi 204a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() { 205a0c0857eSWei Mi auto &OS = *OutputStream; 206a0c0857eSWei Mi std::set<StringRef> V; 207a0c0857eSWei Mi stablizeNameTable(V); 208a0c0857eSWei Mi 209a0c0857eSWei Mi // Write out the name table. 210a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 211a0c0857eSWei Mi for (auto N : V) { 212a0c0857eSWei Mi encodeULEB128(MD5Hash(N), OS); 213a0c0857eSWei Mi } 214a0c0857eSWei Mi return sampleprof_error::success; 215a0c0857eSWei Mi } 216a0c0857eSWei Mi 217a0c0857eSWei Mi std::error_code SampleProfileWriterRawBinary::writeMagicIdent() { 218a0c0857eSWei Mi auto &OS = *OutputStream; 219760c5a8fSDiego Novillo // Write file magic identifier. 220c572e92cSDiego Novillo encodeULEB128(SPMagic(), OS); 221c572e92cSDiego Novillo encodeULEB128(SPVersion(), OS); 222a0c0857eSWei Mi return sampleprof_error::success; 223a0c0857eSWei Mi } 224a0c0857eSWei Mi 225a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeMagicIdent() { 226a0c0857eSWei Mi auto &OS = *OutputStream; 227a0c0857eSWei Mi // Write file magic identifier. 228a0c0857eSWei Mi encodeULEB128(SPMagic(SPF_Compact_Binary), OS); 229a0c0857eSWei Mi encodeULEB128(SPVersion(), OS); 230a0c0857eSWei Mi return sampleprof_error::success; 231a0c0857eSWei Mi } 232a0c0857eSWei Mi 233a0c0857eSWei Mi std::error_code SampleProfileWriterBinary::writeHeader( 234a0c0857eSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 235a0c0857eSWei Mi writeMagicIdent(); 236760c5a8fSDiego Novillo 23740ee23dbSEaswaran Raman computeSummary(ProfileMap); 23840ee23dbSEaswaran Raman if (auto EC = writeSummary()) 23940ee23dbSEaswaran Raman return EC; 24040ee23dbSEaswaran Raman 241760c5a8fSDiego Novillo // Generate the name table for all the functions referenced in the profile. 242760c5a8fSDiego Novillo for (const auto &I : ProfileMap) { 243760c5a8fSDiego Novillo addName(I.first()); 244760c5a8fSDiego Novillo addNames(I.second); 245760c5a8fSDiego Novillo } 246760c5a8fSDiego Novillo 247a0c0857eSWei Mi writeNameTable(); 248760c5a8fSDiego Novillo return sampleprof_error::success; 249c572e92cSDiego Novillo } 250c572e92cSDiego Novillo 2516a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader( 2526a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 2536a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 2546a14325dSWei Mi if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) 2556a14325dSWei Mi return EC; 2566a14325dSWei Mi 2576a14325dSWei Mi // Reserve a slot for the offset of function offset table. The slot will 2586a14325dSWei Mi // be populated with the offset of FuncOffsetTable later. 2596a14325dSWei Mi TableOffset = OutputStream->tell(); 2606a14325dSWei Mi Writer.write(static_cast<uint64_t>(-2)); 2616a14325dSWei Mi return sampleprof_error::success; 2626a14325dSWei Mi } 2636a14325dSWei Mi 26440ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() { 26540ee23dbSEaswaran Raman auto &OS = *OutputStream; 2667cefdb81SEaswaran Raman encodeULEB128(Summary->getTotalCount(), OS); 2677cefdb81SEaswaran Raman encodeULEB128(Summary->getMaxCount(), OS); 2686f4903d9SEaswaran Raman encodeULEB128(Summary->getMaxFunctionCount(), OS); 2697cefdb81SEaswaran Raman encodeULEB128(Summary->getNumCounts(), OS); 27040ee23dbSEaswaran Raman encodeULEB128(Summary->getNumFunctions(), OS); 27140ee23dbSEaswaran Raman std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 27240ee23dbSEaswaran Raman encodeULEB128(Entries.size(), OS); 27340ee23dbSEaswaran Raman for (auto Entry : Entries) { 27440ee23dbSEaswaran Raman encodeULEB128(Entry.Cutoff, OS); 27540ee23dbSEaswaran Raman encodeULEB128(Entry.MinCount, OS); 27640ee23dbSEaswaran Raman encodeULEB128(Entry.NumCounts, OS); 27740ee23dbSEaswaran Raman } 27840ee23dbSEaswaran Raman return sampleprof_error::success; 27940ee23dbSEaswaran Raman } 28057d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 28151abea74SNathan Slingerland auto &OS = *OutputStream; 28251abea74SNathan Slingerland 28357d1dda5SDehao Chen if (std::error_code EC = writeNameIdx(S.getName())) 284760c5a8fSDiego Novillo return EC; 285760c5a8fSDiego Novillo 286c572e92cSDiego Novillo encodeULEB128(S.getTotalSamples(), OS); 287a7f1e8efSDiego Novillo 288a7f1e8efSDiego Novillo // Emit all the body samples. 289b93483dbSDiego Novillo encodeULEB128(S.getBodySamples().size(), OS); 290d5336ae2SDiego Novillo for (const auto &I : S.getBodySamples()) { 291d5336ae2SDiego Novillo LineLocation Loc = I.first; 292d5336ae2SDiego Novillo const SampleRecord &Sample = I.second; 293c572e92cSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 294c572e92cSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 295c572e92cSDiego Novillo encodeULEB128(Sample.getSamples(), OS); 296c572e92cSDiego Novillo encodeULEB128(Sample.getCallTargets().size(), OS); 297d5336ae2SDiego Novillo for (const auto &J : Sample.getCallTargets()) { 298760c5a8fSDiego Novillo StringRef Callee = J.first(); 29938be3330SDiego Novillo uint64_t CalleeSamples = J.second; 300760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(Callee)) 301760c5a8fSDiego Novillo return EC; 302c572e92cSDiego Novillo encodeULEB128(CalleeSamples, OS); 303c572e92cSDiego Novillo } 304c572e92cSDiego Novillo } 305c572e92cSDiego Novillo 306a7f1e8efSDiego Novillo // Recursively emit all the callsite samples. 3072c27daf7SDehao Chen uint64_t NumCallsites = 0; 3082c27daf7SDehao Chen for (const auto &J : S.getCallsiteSamples()) 3092c27daf7SDehao Chen NumCallsites += J.second.size(); 3102c27daf7SDehao Chen encodeULEB128(NumCallsites, OS); 3112c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 3122c7ca9b5SDehao Chen for (const auto &FS : J.second) { 31357d1dda5SDehao Chen LineLocation Loc = J.first; 3142c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 315a7f1e8efSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 316a7f1e8efSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 31757d1dda5SDehao Chen if (std::error_code EC = writeBody(CalleeSamples)) 318760c5a8fSDiego Novillo return EC; 319a7f1e8efSDiego Novillo } 320a7f1e8efSDiego Novillo 321760c5a8fSDiego Novillo return sampleprof_error::success; 322c572e92cSDiego Novillo } 323d5336ae2SDiego Novillo 3245f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file. 325b93483dbSDiego Novillo /// 326b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise. 32757d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::write(const FunctionSamples &S) { 32851abea74SNathan Slingerland encodeULEB128(S.getHeadSamples(), *OutputStream); 32957d1dda5SDehao Chen return writeBody(S); 330b93483dbSDiego Novillo } 331b93483dbSDiego Novillo 3326a14325dSWei Mi std::error_code 3336a14325dSWei Mi SampleProfileWriterCompactBinary::write(const FunctionSamples &S) { 3346a14325dSWei Mi uint64_t Offset = OutputStream->tell(); 3356a14325dSWei Mi StringRef Name = S.getName(); 3366a14325dSWei Mi FuncOffsetTable[Name] = Offset; 3376a14325dSWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream); 3386a14325dSWei Mi return writeBody(S); 3396a14325dSWei Mi } 3406a14325dSWei Mi 3415f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format. 342d5336ae2SDiego Novillo /// 343d5336ae2SDiego Novillo /// \param Filename The file to create. 344d5336ae2SDiego Novillo /// 345d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file. 346d5336ae2SDiego Novillo /// 347d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer. 348fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>> 349fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 350d5336ae2SDiego Novillo std::error_code EC; 35151abea74SNathan Slingerland std::unique_ptr<raw_ostream> OS; 352d9be2c7eSWei Mi if (Format == SPF_Binary || Format == SPF_Compact_Binary) 35351abea74SNathan Slingerland OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None)); 35451abea74SNathan Slingerland else 35551abea74SNathan Slingerland OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text)); 35651abea74SNathan Slingerland if (EC) 35751abea74SNathan Slingerland return EC; 35851abea74SNathan Slingerland 35951abea74SNathan Slingerland return create(OS, Format); 36051abea74SNathan Slingerland } 36151abea74SNathan Slingerland 3625f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format. 36351abea74SNathan Slingerland /// 36451abea74SNathan Slingerland /// \param OS The output stream to store the profile data to. 36551abea74SNathan Slingerland /// 36651abea74SNathan Slingerland /// \param Format Encoding format for the profile file. 36751abea74SNathan Slingerland /// 36851abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer. 36951abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>> 37051abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 37151abea74SNathan Slingerland SampleProfileFormat Format) { 37251abea74SNathan Slingerland std::error_code EC; 373fcd55607SDiego Novillo std::unique_ptr<SampleProfileWriter> Writer; 374d5336ae2SDiego Novillo 375d9be2c7eSWei Mi if (Format == SPF_Binary) 376a0c0857eSWei Mi Writer.reset(new SampleProfileWriterRawBinary(OS)); 377a0c0857eSWei Mi else if (Format == SPF_Compact_Binary) 378a0c0857eSWei Mi Writer.reset(new SampleProfileWriterCompactBinary(OS)); 379d5336ae2SDiego Novillo else if (Format == SPF_Text) 38051abea74SNathan Slingerland Writer.reset(new SampleProfileWriterText(OS)); 381760c5a8fSDiego Novillo else if (Format == SPF_GCC) 382760c5a8fSDiego Novillo EC = sampleprof_error::unsupported_writing_format; 383d5336ae2SDiego Novillo else 384d5336ae2SDiego Novillo EC = sampleprof_error::unrecognized_format; 385d5336ae2SDiego Novillo 386fcd55607SDiego Novillo if (EC) 387d5336ae2SDiego Novillo return EC; 388fcd55607SDiego Novillo 389fcd55607SDiego Novillo return std::move(Writer); 390d5336ae2SDiego Novillo } 39140ee23dbSEaswaran Raman 39240ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary( 39340ee23dbSEaswaran Raman const StringMap<FunctionSamples> &ProfileMap) { 394e5a17e3fSEaswaran Raman SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 39540ee23dbSEaswaran Raman for (const auto &I : ProfileMap) { 39640ee23dbSEaswaran Raman const FunctionSamples &Profile = I.second; 397e5a17e3fSEaswaran Raman Builder.addRecord(Profile); 39840ee23dbSEaswaran Raman } 39938de59e4SBenjamin Kramer Summary = Builder.getSummary(); 40040ee23dbSEaswaran Raman } 401