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" 24b523790aSWei Mi #include "llvm/Support/Compression.h" 256a14325dSWei Mi #include "llvm/Support/Endian.h" 266a14325dSWei Mi #include "llvm/Support/EndianStream.h" 27c572e92cSDiego Novillo #include "llvm/Support/ErrorOr.h" 28e78d131aSEugene Zelenko #include "llvm/Support/FileSystem.h" 29c572e92cSDiego Novillo #include "llvm/Support/LEB128.h" 30a0c0857eSWei Mi #include "llvm/Support/MD5.h" 31e78d131aSEugene Zelenko #include "llvm/Support/raw_ostream.h" 32e78d131aSEugene Zelenko #include <algorithm> 33e78d131aSEugene Zelenko #include <cstdint> 34e78d131aSEugene Zelenko #include <memory> 358d1c983fSDehao Chen #include <set> 36e78d131aSEugene Zelenko #include <system_error> 37e78d131aSEugene Zelenko #include <utility> 38e78d131aSEugene Zelenko #include <vector> 39c572e92cSDiego Novillo 40c572e92cSDiego Novillo using namespace llvm; 41e78d131aSEugene Zelenko using namespace sampleprof; 42c572e92cSDiego Novillo 43be907324SWei Mi std::error_code SampleProfileWriter::writeFuncProfiles( 44be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 458d1c983fSDehao Chen // Sort the ProfileMap by total samples. 468d1c983fSDehao Chen typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples; 478d1c983fSDehao Chen std::vector<NameFunctionSamples> V; 488d1c983fSDehao Chen for (const auto &I : ProfileMap) 498d1c983fSDehao Chen V.push_back(std::make_pair(I.getKey(), &I.second)); 508d1c983fSDehao Chen 51efd94c56SFangrui Song llvm::stable_sort( 52efd94c56SFangrui Song V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) { 538d1c983fSDehao Chen if (A.second->getTotalSamples() == B.second->getTotalSamples()) 548d1c983fSDehao Chen return A.first > B.first; 558d1c983fSDehao Chen return A.second->getTotalSamples() > B.second->getTotalSamples(); 568d1c983fSDehao Chen }); 578d1c983fSDehao Chen 588d1c983fSDehao Chen for (const auto &I : V) { 59be907324SWei Mi if (std::error_code EC = writeSample(*I.second)) 608d1c983fSDehao Chen return EC; 618d1c983fSDehao Chen } 628d1c983fSDehao Chen return sampleprof_error::success; 638d1c983fSDehao Chen } 648d1c983fSDehao Chen 65be907324SWei Mi std::error_code 66be907324SWei Mi SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) { 67be907324SWei Mi if (std::error_code EC = writeHeader(ProfileMap)) 68be907324SWei Mi return EC; 69be907324SWei Mi 70be907324SWei Mi if (std::error_code EC = writeFuncProfiles(ProfileMap)) 71be907324SWei Mi return EC; 72be907324SWei Mi 73be907324SWei Mi return sampleprof_error::success; 74be907324SWei Mi } 75be907324SWei Mi 76b523790aSWei Mi SecHdrTableEntry & 77b523790aSWei Mi SampleProfileWriterExtBinaryBase::getEntryInLayout(SecType Type) { 78b523790aSWei Mi auto SecIt = std::find_if( 79*09dcfe68SWei Mi SectionHdrLayout.begin(), SectionHdrLayout.end(), 80b523790aSWei Mi [=](const auto &Entry) -> bool { return Entry.Type == Type; }); 81b523790aSWei Mi return *SecIt; 82be907324SWei Mi } 83be907324SWei Mi 84b523790aSWei Mi /// Return the current position and prepare to use it as the start 85b523790aSWei Mi /// position of a section. 86b523790aSWei Mi uint64_t SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type) { 87b523790aSWei Mi uint64_t SectionStart = OutputStream->tell(); 88b523790aSWei Mi auto &Entry = getEntryInLayout(Type); 89b523790aSWei Mi // Use LocalBuf as a temporary output for writting data. 90b523790aSWei Mi if (hasSecFlag(Entry, SecFlagCompress)) 91b523790aSWei Mi LocalBufStream.swap(OutputStream); 92b523790aSWei Mi return SectionStart; 93b523790aSWei Mi } 94b523790aSWei Mi 95b523790aSWei Mi std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() { 96b523790aSWei Mi if (!llvm::zlib::isAvailable()) 97b523790aSWei Mi return sampleprof_error::zlib_unavailable; 98b523790aSWei Mi std::string &UncompressedStrings = 99b523790aSWei Mi static_cast<raw_string_ostream *>(LocalBufStream.get())->str(); 100b523790aSWei Mi if (UncompressedStrings.size() == 0) 101b523790aSWei Mi return sampleprof_error::success; 102b523790aSWei Mi auto &OS = *OutputStream; 103b523790aSWei Mi SmallString<128> CompressedStrings; 104b523790aSWei Mi llvm::Error E = zlib::compress(UncompressedStrings, CompressedStrings, 105b523790aSWei Mi zlib::BestSizeCompression); 106b523790aSWei Mi if (E) 107b523790aSWei Mi return sampleprof_error::compress_failed; 108b523790aSWei Mi encodeULEB128(UncompressedStrings.size(), OS); 109b523790aSWei Mi encodeULEB128(CompressedStrings.size(), OS); 110b523790aSWei Mi OS << CompressedStrings.str(); 111b523790aSWei Mi UncompressedStrings.clear(); 112b523790aSWei Mi return sampleprof_error::success; 113b523790aSWei Mi } 114b523790aSWei Mi 115b523790aSWei Mi /// Add a new section into section header table. 116b523790aSWei Mi std::error_code 117b523790aSWei Mi SampleProfileWriterExtBinaryBase::addNewSection(SecType Type, 118be907324SWei Mi uint64_t SectionStart) { 119b523790aSWei Mi auto Entry = getEntryInLayout(Type); 120b523790aSWei Mi if (hasSecFlag(Entry, SecFlagCompress)) { 121b523790aSWei Mi LocalBufStream.swap(OutputStream); 122b523790aSWei Mi if (std::error_code EC = compressAndOutput()) 123b523790aSWei Mi return EC; 124b523790aSWei Mi } 125b523790aSWei Mi SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart, 126b523790aSWei Mi OutputStream->tell() - SectionStart}); 127b523790aSWei Mi return sampleprof_error::success; 128be907324SWei Mi } 129be907324SWei Mi 130be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::write( 131be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 132be907324SWei Mi if (std::error_code EC = writeHeader(ProfileMap)) 133be907324SWei Mi return EC; 134be907324SWei Mi 135b523790aSWei Mi std::string LocalBuf; 136b523790aSWei Mi LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf); 137be907324SWei Mi if (std::error_code EC = writeSections(ProfileMap)) 138be907324SWei Mi return EC; 139be907324SWei Mi 140be907324SWei Mi if (std::error_code EC = writeSecHdrTable()) 141be907324SWei Mi return EC; 142be907324SWei Mi 143be907324SWei Mi return sampleprof_error::success; 144be907324SWei Mi } 145be907324SWei Mi 146*09dcfe68SWei Mi std::error_code 147*09dcfe68SWei Mi SampleProfileWriterExtBinary::writeSample(const FunctionSamples &S) { 148*09dcfe68SWei Mi uint64_t Offset = OutputStream->tell(); 149*09dcfe68SWei Mi StringRef Name = S.getName(); 150*09dcfe68SWei Mi FuncOffsetTable[Name] = Offset - SecLBRProfileStart; 151*09dcfe68SWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream); 152*09dcfe68SWei Mi return writeBody(S); 153*09dcfe68SWei Mi } 154*09dcfe68SWei Mi 155*09dcfe68SWei Mi std::error_code SampleProfileWriterExtBinary::writeFuncOffsetTable() { 156*09dcfe68SWei Mi auto &OS = *OutputStream; 157*09dcfe68SWei Mi 158*09dcfe68SWei Mi // Write out the table size. 159*09dcfe68SWei Mi encodeULEB128(FuncOffsetTable.size(), OS); 160*09dcfe68SWei Mi 161*09dcfe68SWei Mi // Write out FuncOffsetTable. 162*09dcfe68SWei Mi for (auto entry : FuncOffsetTable) { 163*09dcfe68SWei Mi writeNameIdx(entry.first); 164*09dcfe68SWei Mi encodeULEB128(entry.second, OS); 165*09dcfe68SWei Mi } 166*09dcfe68SWei Mi return sampleprof_error::success; 167*09dcfe68SWei Mi } 168*09dcfe68SWei Mi 169be907324SWei Mi std::error_code SampleProfileWriterExtBinary::writeSections( 170be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 171b523790aSWei Mi uint64_t SectionStart = markSectionStart(SecProfSummary); 172be907324SWei Mi computeSummary(ProfileMap); 173be907324SWei Mi if (auto EC = writeSummary()) 174be907324SWei Mi return EC; 175b523790aSWei Mi if (std::error_code EC = addNewSection(SecProfSummary, SectionStart)) 176b523790aSWei Mi return EC; 177be907324SWei Mi 178be907324SWei Mi // Generate the name table for all the functions referenced in the profile. 179b523790aSWei Mi SectionStart = markSectionStart(SecNameTable); 180be907324SWei Mi for (const auto &I : ProfileMap) { 181be907324SWei Mi addName(I.first()); 182be907324SWei Mi addNames(I.second); 183be907324SWei Mi } 184be907324SWei Mi writeNameTable(); 185b523790aSWei Mi if (std::error_code EC = addNewSection(SecNameTable, SectionStart)) 186b523790aSWei Mi return EC; 187be907324SWei Mi 188b523790aSWei Mi SectionStart = markSectionStart(SecLBRProfile); 189*09dcfe68SWei Mi SecLBRProfileStart = OutputStream->tell(); 190be907324SWei Mi if (std::error_code EC = writeFuncProfiles(ProfileMap)) 191be907324SWei Mi return EC; 192b523790aSWei Mi if (std::error_code EC = addNewSection(SecLBRProfile, SectionStart)) 193b523790aSWei Mi return EC; 194798e59b8SWei Mi 195b523790aSWei Mi if (ProfSymList && ProfSymList->toCompress()) 196b523790aSWei Mi setToCompressSection(SecProfileSymbolList); 197b523790aSWei Mi 198b523790aSWei Mi SectionStart = markSectionStart(SecProfileSymbolList); 199798e59b8SWei Mi if (ProfSymList && ProfSymList->size() > 0) 200798e59b8SWei Mi if (std::error_code EC = ProfSymList->write(*OutputStream)) 201798e59b8SWei Mi return EC; 202b523790aSWei Mi if (std::error_code EC = addNewSection(SecProfileSymbolList, SectionStart)) 203b523790aSWei Mi return EC; 204be907324SWei Mi 205*09dcfe68SWei Mi SectionStart = markSectionStart(SecFuncOffsetTable); 206*09dcfe68SWei Mi if (std::error_code EC = writeFuncOffsetTable()) 207*09dcfe68SWei Mi return EC; 208*09dcfe68SWei Mi if (std::error_code EC = addNewSection(SecFuncOffsetTable, SectionStart)) 209*09dcfe68SWei Mi return EC; 210*09dcfe68SWei Mi 211be907324SWei Mi return sampleprof_error::success; 212be907324SWei Mi } 213be907324SWei Mi 2146a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::write( 2156a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 2166a14325dSWei Mi if (std::error_code EC = SampleProfileWriter::write(ProfileMap)) 2176a14325dSWei Mi return EC; 2186a14325dSWei Mi if (std::error_code EC = writeFuncOffsetTable()) 2196a14325dSWei Mi return EC; 2206a14325dSWei Mi return sampleprof_error::success; 2216a14325dSWei Mi } 2226a14325dSWei Mi 2235f8f34e4SAdrian Prantl /// Write samples to a text file. 2248e415a82SDiego Novillo /// 2258e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of 226ef548d29SDiego Novillo /// FunctionSamples::print(). Please don't. The dump functionality is intended 2278e415a82SDiego Novillo /// for debugging and has no specified form. 2288e415a82SDiego Novillo /// 2298e415a82SDiego Novillo /// The format used here is more structured and deliberate because 2308e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class. 231be907324SWei Mi std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { 23251abea74SNathan Slingerland auto &OS = *OutputStream; 23357d1dda5SDehao Chen OS << S.getName() << ":" << S.getTotalSamples(); 234aae1ed8eSDiego Novillo if (Indent == 0) 235aae1ed8eSDiego Novillo OS << ":" << S.getHeadSamples(); 236aae1ed8eSDiego Novillo OS << "\n"; 237c572e92cSDiego Novillo 238ef548d29SDiego Novillo SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 239ef548d29SDiego Novillo for (const auto &I : SortedSamples.get()) { 240ef548d29SDiego Novillo LineLocation Loc = I->first; 241ef548d29SDiego Novillo const SampleRecord &Sample = I->second; 242aae1ed8eSDiego Novillo OS.indent(Indent + 1); 243c572e92cSDiego Novillo if (Loc.Discriminator == 0) 244c572e92cSDiego Novillo OS << Loc.LineOffset << ": "; 245c572e92cSDiego Novillo else 246c572e92cSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 247c572e92cSDiego Novillo 248c572e92cSDiego Novillo OS << Sample.getSamples(); 249c572e92cSDiego Novillo 2505adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) 2515adace35SWenlei He OS << " " << J.first << ":" << J.second; 252c572e92cSDiego Novillo OS << "\n"; 253c572e92cSDiego Novillo } 254c572e92cSDiego Novillo 2552c7ca9b5SDehao Chen SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 256ef548d29SDiego Novillo S.getCallsiteSamples()); 257aae1ed8eSDiego Novillo Indent += 1; 2582c7ca9b5SDehao Chen for (const auto &I : SortedCallsiteSamples.get()) 2592c7ca9b5SDehao Chen for (const auto &FS : I->second) { 26057d1dda5SDehao Chen LineLocation Loc = I->first; 2612c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 262aae1ed8eSDiego Novillo OS.indent(Indent); 263aae1ed8eSDiego Novillo if (Loc.Discriminator == 0) 264aae1ed8eSDiego Novillo OS << Loc.LineOffset << ": "; 265aae1ed8eSDiego Novillo else 266aae1ed8eSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 267be907324SWei Mi if (std::error_code EC = writeSample(CalleeSamples)) 268760c5a8fSDiego Novillo return EC; 269aae1ed8eSDiego Novillo } 270aae1ed8eSDiego Novillo Indent -= 1; 271aae1ed8eSDiego Novillo 272760c5a8fSDiego Novillo return sampleprof_error::success; 273c572e92cSDiego Novillo } 274c572e92cSDiego Novillo 275760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 276760c5a8fSDiego Novillo const auto &ret = NameTable.find(FName); 277760c5a8fSDiego Novillo if (ret == NameTable.end()) 278760c5a8fSDiego Novillo return sampleprof_error::truncated_name_table; 27951abea74SNathan Slingerland encodeULEB128(ret->second, *OutputStream); 280760c5a8fSDiego Novillo return sampleprof_error::success; 281760c5a8fSDiego Novillo } 282c572e92cSDiego Novillo 283760c5a8fSDiego Novillo void SampleProfileWriterBinary::addName(StringRef FName) { 2848d1c983fSDehao Chen NameTable.insert(std::make_pair(FName, 0)); 285760c5a8fSDiego Novillo } 286760c5a8fSDiego Novillo 287760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 288760c5a8fSDiego Novillo // Add all the names in indirect call targets. 289760c5a8fSDiego Novillo for (const auto &I : S.getBodySamples()) { 290760c5a8fSDiego Novillo const SampleRecord &Sample = I.second; 291760c5a8fSDiego Novillo for (const auto &J : Sample.getCallTargets()) 292760c5a8fSDiego Novillo addName(J.first()); 293760c5a8fSDiego Novillo } 294760c5a8fSDiego Novillo 295760c5a8fSDiego Novillo // Recursively add all the names for inlined callsites. 2962c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 2972c7ca9b5SDehao Chen for (const auto &FS : J.second) { 2982c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 29957d1dda5SDehao Chen addName(CalleeSamples.getName()); 300760c5a8fSDiego Novillo addNames(CalleeSamples); 301760c5a8fSDiego Novillo } 302760c5a8fSDiego Novillo } 303760c5a8fSDiego Novillo 304a0c0857eSWei Mi void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) { 305a0c0857eSWei Mi // Sort the names to make NameTable deterministic. 306a0c0857eSWei Mi for (const auto &I : NameTable) 307a0c0857eSWei Mi V.insert(I.first); 308a0c0857eSWei Mi int i = 0; 309a0c0857eSWei Mi for (const StringRef &N : V) 310a0c0857eSWei Mi NameTable[N] = i++; 311a0c0857eSWei Mi } 31251abea74SNathan Slingerland 313be907324SWei Mi std::error_code SampleProfileWriterBinary::writeNameTable() { 314a0c0857eSWei Mi auto &OS = *OutputStream; 315a0c0857eSWei Mi std::set<StringRef> V; 316a0c0857eSWei Mi stablizeNameTable(V); 317a0c0857eSWei Mi 318a0c0857eSWei Mi // Write out the name table. 319a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 320a0c0857eSWei Mi for (auto N : V) { 321a0c0857eSWei Mi OS << N; 322a0c0857eSWei Mi encodeULEB128(0, OS); 323a0c0857eSWei Mi } 324a0c0857eSWei Mi return sampleprof_error::success; 325a0c0857eSWei Mi } 326a0c0857eSWei Mi 3276a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { 3286a14325dSWei Mi auto &OS = *OutputStream; 3296a14325dSWei Mi 3306a14325dSWei Mi // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. 3316a14325dSWei Mi auto &OFS = static_cast<raw_fd_ostream &>(OS); 3326a14325dSWei Mi uint64_t FuncOffsetTableStart = OS.tell(); 3336a14325dSWei Mi if (OFS.seek(TableOffset) == (uint64_t)-1) 3346a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 3356a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 3366a14325dSWei Mi Writer.write(FuncOffsetTableStart); 3376a14325dSWei Mi if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) 3386a14325dSWei Mi return sampleprof_error::ostream_seek_unsupported; 3396a14325dSWei Mi 3406a14325dSWei Mi // Write out the table size. 3416a14325dSWei Mi encodeULEB128(FuncOffsetTable.size(), OS); 3426a14325dSWei Mi 3436a14325dSWei Mi // Write out FuncOffsetTable. 3446a14325dSWei Mi for (auto entry : FuncOffsetTable) { 3456a14325dSWei Mi writeNameIdx(entry.first); 3466a14325dSWei Mi encodeULEB128(entry.second, OS); 3476a14325dSWei Mi } 3486a14325dSWei Mi return sampleprof_error::success; 3496a14325dSWei Mi } 3506a14325dSWei Mi 351a0c0857eSWei Mi std::error_code SampleProfileWriterCompactBinary::writeNameTable() { 352a0c0857eSWei Mi auto &OS = *OutputStream; 353a0c0857eSWei Mi std::set<StringRef> V; 354a0c0857eSWei Mi stablizeNameTable(V); 355a0c0857eSWei Mi 356a0c0857eSWei Mi // Write out the name table. 357a0c0857eSWei Mi encodeULEB128(NameTable.size(), OS); 358a0c0857eSWei Mi for (auto N : V) { 359a0c0857eSWei Mi encodeULEB128(MD5Hash(N), OS); 360a0c0857eSWei Mi } 361a0c0857eSWei Mi return sampleprof_error::success; 362a0c0857eSWei Mi } 363a0c0857eSWei Mi 364be907324SWei Mi std::error_code 365be907324SWei Mi SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { 366a0c0857eSWei Mi auto &OS = *OutputStream; 367760c5a8fSDiego Novillo // Write file magic identifier. 368be907324SWei Mi encodeULEB128(SPMagic(Format), OS); 369a0c0857eSWei Mi encodeULEB128(SPVersion(), OS); 370a0c0857eSWei Mi return sampleprof_error::success; 371a0c0857eSWei Mi } 372a0c0857eSWei Mi 373a0c0857eSWei Mi std::error_code SampleProfileWriterBinary::writeHeader( 374a0c0857eSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 375be907324SWei Mi writeMagicIdent(Format); 376760c5a8fSDiego Novillo 37740ee23dbSEaswaran Raman computeSummary(ProfileMap); 37840ee23dbSEaswaran Raman if (auto EC = writeSummary()) 37940ee23dbSEaswaran Raman return EC; 38040ee23dbSEaswaran Raman 381760c5a8fSDiego Novillo // Generate the name table for all the functions referenced in the profile. 382760c5a8fSDiego Novillo for (const auto &I : ProfileMap) { 383760c5a8fSDiego Novillo addName(I.first()); 384760c5a8fSDiego Novillo addNames(I.second); 385760c5a8fSDiego Novillo } 386760c5a8fSDiego Novillo 387a0c0857eSWei Mi writeNameTable(); 388760c5a8fSDiego Novillo return sampleprof_error::success; 389c572e92cSDiego Novillo } 390c572e92cSDiego Novillo 391b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressAllSections() { 392*09dcfe68SWei Mi for (auto &Entry : SectionHdrLayout) 393b523790aSWei Mi addSecFlags(Entry, SecFlagCompress); 394b523790aSWei Mi } 395b523790aSWei Mi 396b523790aSWei Mi void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) { 397b523790aSWei Mi addSectionFlags(Type, SecFlagCompress); 398b523790aSWei Mi } 399b523790aSWei Mi 400b523790aSWei Mi void SampleProfileWriterExtBinaryBase::addSectionFlags(SecType Type, 401b523790aSWei Mi SecFlags Flags) { 402*09dcfe68SWei Mi for (auto &Entry : SectionHdrLayout) { 403b523790aSWei Mi if (Entry.Type == Type) 404b523790aSWei Mi addSecFlags(Entry, Flags); 405b523790aSWei Mi } 406b523790aSWei Mi } 407b523790aSWei Mi 408be907324SWei Mi void SampleProfileWriterExtBinaryBase::allocSecHdrTable() { 409be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 410be907324SWei Mi 411*09dcfe68SWei Mi Writer.write(static_cast<uint64_t>(SectionHdrLayout.size())); 412be907324SWei Mi SecHdrTableOffset = OutputStream->tell(); 413*09dcfe68SWei Mi for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 414be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 415be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 416be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 417be907324SWei Mi Writer.write(static_cast<uint64_t>(-1)); 418be907324SWei Mi } 419be907324SWei Mi } 420be907324SWei Mi 421be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { 422be907324SWei Mi auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream); 423be907324SWei Mi uint64_t Saved = OutputStream->tell(); 424be907324SWei Mi 425be907324SWei Mi // Set OutputStream to the location saved in SecHdrTableOffset. 426be907324SWei Mi if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1) 427be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 428be907324SWei Mi support::endian::Writer Writer(*OutputStream, support::little); 429be907324SWei Mi 430be907324SWei Mi DenseMap<uint32_t, uint32_t> IndexMap; 431be907324SWei Mi for (uint32_t i = 0; i < SecHdrTable.size(); i++) { 432be907324SWei Mi IndexMap.insert({static_cast<uint32_t>(SecHdrTable[i].Type), i}); 433be907324SWei Mi } 434be907324SWei Mi 435*09dcfe68SWei Mi // Write the section header table in the order specified in 436*09dcfe68SWei Mi // SectionHdrLayout. That is the sections order Reader will see. 437*09dcfe68SWei Mi // Note that the sections order in which Reader expects to read 438*09dcfe68SWei Mi // may be different from the order in which Writer is able to 439*09dcfe68SWei Mi // write, so we need to adjust the order in SecHdrTable to be 440*09dcfe68SWei Mi // consistent with SectionHdrLayout when we write SecHdrTable 441*09dcfe68SWei Mi // to the memory. 442*09dcfe68SWei Mi for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 443*09dcfe68SWei Mi uint32_t idx = IndexMap[static_cast<uint32_t>(SectionHdrLayout[i].Type)]; 444be907324SWei Mi Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Type)); 445b523790aSWei Mi Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Flags)); 446be907324SWei Mi Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Offset)); 447be907324SWei Mi Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Size)); 448be907324SWei Mi } 449be907324SWei Mi 450be907324SWei Mi // Reset OutputStream. 451be907324SWei Mi if (OFS.seek(Saved) == (uint64_t)-1) 452be907324SWei Mi return sampleprof_error::ostream_seek_unsupported; 453be907324SWei Mi 454be907324SWei Mi return sampleprof_error::success; 455be907324SWei Mi } 456be907324SWei Mi 457be907324SWei Mi std::error_code SampleProfileWriterExtBinaryBase::writeHeader( 458be907324SWei Mi const StringMap<FunctionSamples> &ProfileMap) { 459be907324SWei Mi auto &OS = *OutputStream; 460be907324SWei Mi FileStart = OS.tell(); 461be907324SWei Mi writeMagicIdent(Format); 462be907324SWei Mi 463be907324SWei Mi allocSecHdrTable(); 464be907324SWei Mi return sampleprof_error::success; 465be907324SWei Mi } 466be907324SWei Mi 4676a14325dSWei Mi std::error_code SampleProfileWriterCompactBinary::writeHeader( 4686a14325dSWei Mi const StringMap<FunctionSamples> &ProfileMap) { 4696a14325dSWei Mi support::endian::Writer Writer(*OutputStream, support::little); 4706a14325dSWei Mi if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) 4716a14325dSWei Mi return EC; 4726a14325dSWei Mi 4736a14325dSWei Mi // Reserve a slot for the offset of function offset table. The slot will 4746a14325dSWei Mi // be populated with the offset of FuncOffsetTable later. 4756a14325dSWei Mi TableOffset = OutputStream->tell(); 4766a14325dSWei Mi Writer.write(static_cast<uint64_t>(-2)); 4776a14325dSWei Mi return sampleprof_error::success; 4786a14325dSWei Mi } 4796a14325dSWei Mi 48040ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() { 48140ee23dbSEaswaran Raman auto &OS = *OutputStream; 4827cefdb81SEaswaran Raman encodeULEB128(Summary->getTotalCount(), OS); 4837cefdb81SEaswaran Raman encodeULEB128(Summary->getMaxCount(), OS); 4846f4903d9SEaswaran Raman encodeULEB128(Summary->getMaxFunctionCount(), OS); 4857cefdb81SEaswaran Raman encodeULEB128(Summary->getNumCounts(), OS); 48640ee23dbSEaswaran Raman encodeULEB128(Summary->getNumFunctions(), OS); 48740ee23dbSEaswaran Raman std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 48840ee23dbSEaswaran Raman encodeULEB128(Entries.size(), OS); 48940ee23dbSEaswaran Raman for (auto Entry : Entries) { 49040ee23dbSEaswaran Raman encodeULEB128(Entry.Cutoff, OS); 49140ee23dbSEaswaran Raman encodeULEB128(Entry.MinCount, OS); 49240ee23dbSEaswaran Raman encodeULEB128(Entry.NumCounts, OS); 49340ee23dbSEaswaran Raman } 49440ee23dbSEaswaran Raman return sampleprof_error::success; 49540ee23dbSEaswaran Raman } 49657d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 49751abea74SNathan Slingerland auto &OS = *OutputStream; 49851abea74SNathan Slingerland 49957d1dda5SDehao Chen if (std::error_code EC = writeNameIdx(S.getName())) 500760c5a8fSDiego Novillo return EC; 501760c5a8fSDiego Novillo 502c572e92cSDiego Novillo encodeULEB128(S.getTotalSamples(), OS); 503a7f1e8efSDiego Novillo 504a7f1e8efSDiego Novillo // Emit all the body samples. 505b93483dbSDiego Novillo encodeULEB128(S.getBodySamples().size(), OS); 506d5336ae2SDiego Novillo for (const auto &I : S.getBodySamples()) { 507d5336ae2SDiego Novillo LineLocation Loc = I.first; 508d5336ae2SDiego Novillo const SampleRecord &Sample = I.second; 509c572e92cSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 510c572e92cSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 511c572e92cSDiego Novillo encodeULEB128(Sample.getSamples(), OS); 512c572e92cSDiego Novillo encodeULEB128(Sample.getCallTargets().size(), OS); 5135adace35SWenlei He for (const auto &J : Sample.getSortedCallTargets()) { 5145adace35SWenlei He StringRef Callee = J.first; 51538be3330SDiego Novillo uint64_t CalleeSamples = J.second; 516760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(Callee)) 517760c5a8fSDiego Novillo return EC; 518c572e92cSDiego Novillo encodeULEB128(CalleeSamples, OS); 519c572e92cSDiego Novillo } 520c572e92cSDiego Novillo } 521c572e92cSDiego Novillo 522a7f1e8efSDiego Novillo // Recursively emit all the callsite samples. 5232c27daf7SDehao Chen uint64_t NumCallsites = 0; 5242c27daf7SDehao Chen for (const auto &J : S.getCallsiteSamples()) 5252c27daf7SDehao Chen NumCallsites += J.second.size(); 5262c27daf7SDehao Chen encodeULEB128(NumCallsites, OS); 5272c7ca9b5SDehao Chen for (const auto &J : S.getCallsiteSamples()) 5282c7ca9b5SDehao Chen for (const auto &FS : J.second) { 52957d1dda5SDehao Chen LineLocation Loc = J.first; 5302c7ca9b5SDehao Chen const FunctionSamples &CalleeSamples = FS.second; 531a7f1e8efSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 532a7f1e8efSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 53357d1dda5SDehao Chen if (std::error_code EC = writeBody(CalleeSamples)) 534760c5a8fSDiego Novillo return EC; 535a7f1e8efSDiego Novillo } 536a7f1e8efSDiego Novillo 537760c5a8fSDiego Novillo return sampleprof_error::success; 538c572e92cSDiego Novillo } 539d5336ae2SDiego Novillo 5405f8f34e4SAdrian Prantl /// Write samples of a top-level function to a binary file. 541b93483dbSDiego Novillo /// 542b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise. 543be907324SWei Mi std::error_code 544be907324SWei Mi SampleProfileWriterBinary::writeSample(const FunctionSamples &S) { 54551abea74SNathan Slingerland encodeULEB128(S.getHeadSamples(), *OutputStream); 54657d1dda5SDehao Chen return writeBody(S); 547b93483dbSDiego Novillo } 548b93483dbSDiego Novillo 5496a14325dSWei Mi std::error_code 550be907324SWei Mi SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) { 5516a14325dSWei Mi uint64_t Offset = OutputStream->tell(); 5526a14325dSWei Mi StringRef Name = S.getName(); 5536a14325dSWei Mi FuncOffsetTable[Name] = Offset; 5546a14325dSWei Mi encodeULEB128(S.getHeadSamples(), *OutputStream); 5556a14325dSWei Mi return writeBody(S); 5566a14325dSWei Mi } 5576a14325dSWei Mi 5585f8f34e4SAdrian Prantl /// Create a sample profile file writer based on the specified format. 559d5336ae2SDiego Novillo /// 560d5336ae2SDiego Novillo /// \param Filename The file to create. 561d5336ae2SDiego Novillo /// 562d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file. 563d5336ae2SDiego Novillo /// 564d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer. 565fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>> 566fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 567d5336ae2SDiego Novillo std::error_code EC; 56851abea74SNathan Slingerland std::unique_ptr<raw_ostream> OS; 569be907324SWei Mi if (Format == SPF_Binary || Format == SPF_Ext_Binary || 570be907324SWei Mi Format == SPF_Compact_Binary) 571d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None)); 57251abea74SNathan Slingerland else 573d9b948b6SFangrui Song OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text)); 57451abea74SNathan Slingerland if (EC) 57551abea74SNathan Slingerland return EC; 57651abea74SNathan Slingerland 57751abea74SNathan Slingerland return create(OS, Format); 57851abea74SNathan Slingerland } 57951abea74SNathan Slingerland 5805f8f34e4SAdrian Prantl /// Create a sample profile stream writer based on the specified format. 58151abea74SNathan Slingerland /// 58251abea74SNathan Slingerland /// \param OS The output stream to store the profile data to. 58351abea74SNathan Slingerland /// 58451abea74SNathan Slingerland /// \param Format Encoding format for the profile file. 58551abea74SNathan Slingerland /// 58651abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer. 58751abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>> 58851abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 58951abea74SNathan Slingerland SampleProfileFormat Format) { 59051abea74SNathan Slingerland std::error_code EC; 591fcd55607SDiego Novillo std::unique_ptr<SampleProfileWriter> Writer; 592d5336ae2SDiego Novillo 593d9be2c7eSWei Mi if (Format == SPF_Binary) 594a0c0857eSWei Mi Writer.reset(new SampleProfileWriterRawBinary(OS)); 595be907324SWei Mi else if (Format == SPF_Ext_Binary) 596be907324SWei Mi Writer.reset(new SampleProfileWriterExtBinary(OS)); 597a0c0857eSWei Mi else if (Format == SPF_Compact_Binary) 598a0c0857eSWei Mi Writer.reset(new SampleProfileWriterCompactBinary(OS)); 599d5336ae2SDiego Novillo else if (Format == SPF_Text) 60051abea74SNathan Slingerland Writer.reset(new SampleProfileWriterText(OS)); 601760c5a8fSDiego Novillo else if (Format == SPF_GCC) 602760c5a8fSDiego Novillo EC = sampleprof_error::unsupported_writing_format; 603d5336ae2SDiego Novillo else 604d5336ae2SDiego Novillo EC = sampleprof_error::unrecognized_format; 605d5336ae2SDiego Novillo 606fcd55607SDiego Novillo if (EC) 607d5336ae2SDiego Novillo return EC; 608fcd55607SDiego Novillo 609be907324SWei Mi Writer->Format = Format; 610fcd55607SDiego Novillo return std::move(Writer); 611d5336ae2SDiego Novillo } 61240ee23dbSEaswaran Raman 61340ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary( 61440ee23dbSEaswaran Raman const StringMap<FunctionSamples> &ProfileMap) { 615e5a17e3fSEaswaran Raman SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 61640ee23dbSEaswaran Raman for (const auto &I : ProfileMap) { 61740ee23dbSEaswaran Raman const FunctionSamples &Profile = I.second; 618e5a17e3fSEaswaran Raman Builder.addRecord(Profile); 61940ee23dbSEaswaran Raman } 62038de59e4SBenjamin Kramer Summary = Builder.getSummary(); 62140ee23dbSEaswaran Raman } 622