1c572e92cSDiego Novillo //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===// 2c572e92cSDiego Novillo // 3c572e92cSDiego Novillo // The LLVM Compiler Infrastructure 4c572e92cSDiego Novillo // 5c572e92cSDiego Novillo // This file is distributed under the University of Illinois Open Source 6c572e92cSDiego Novillo // License. See LICENSE.TXT for details. 7c572e92cSDiego Novillo // 8c572e92cSDiego Novillo //===----------------------------------------------------------------------===// 9c572e92cSDiego Novillo // 10c572e92cSDiego Novillo // This file implements the class that writes LLVM sample profiles. It 11c572e92cSDiego Novillo // supports two file formats: text and binary. The textual representation 12c572e92cSDiego Novillo // is useful for debugging and testing purposes. The binary representation 13c572e92cSDiego Novillo // is more compact, resulting in smaller file sizes. However, they can 14c572e92cSDiego Novillo // both be used interchangeably. 15c572e92cSDiego Novillo // 16c572e92cSDiego Novillo // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the 17c572e92cSDiego Novillo // supported formats. 18c572e92cSDiego Novillo // 19c572e92cSDiego Novillo //===----------------------------------------------------------------------===// 20c572e92cSDiego Novillo 21c572e92cSDiego Novillo #include "llvm/ProfileData/SampleProfWriter.h" 22c572e92cSDiego Novillo #include "llvm/Support/Debug.h" 23c572e92cSDiego Novillo #include "llvm/Support/ErrorOr.h" 24c572e92cSDiego Novillo #include "llvm/Support/LEB128.h" 25c572e92cSDiego Novillo #include "llvm/Support/LineIterator.h" 26d9903888SChandler Carruth #include "llvm/Support/MemoryBuffer.h" 27c572e92cSDiego Novillo #include "llvm/Support/Regex.h" 28c572e92cSDiego Novillo 29c572e92cSDiego Novillo using namespace llvm::sampleprof; 30c572e92cSDiego Novillo using namespace llvm; 31c572e92cSDiego Novillo 32c572e92cSDiego Novillo /// \brief Write samples to a text file. 338e415a82SDiego Novillo /// 348e415a82SDiego Novillo /// Note: it may be tempting to implement this in terms of 35ef548d29SDiego Novillo /// FunctionSamples::print(). Please don't. The dump functionality is intended 368e415a82SDiego Novillo /// for debugging and has no specified form. 378e415a82SDiego Novillo /// 388e415a82SDiego Novillo /// The format used here is more structured and deliberate because 398e415a82SDiego Novillo /// it needs to be parsed by the SampleProfileReaderText class. 4057d1dda5SDehao Chen std::error_code SampleProfileWriterText::write(const FunctionSamples &S) { 4151abea74SNathan Slingerland auto &OS = *OutputStream; 4257d1dda5SDehao Chen OS << S.getName() << ":" << S.getTotalSamples(); 43aae1ed8eSDiego Novillo if (Indent == 0) 44aae1ed8eSDiego Novillo OS << ":" << S.getHeadSamples(); 45aae1ed8eSDiego Novillo OS << "\n"; 46c572e92cSDiego Novillo 47ef548d29SDiego Novillo SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 48ef548d29SDiego Novillo for (const auto &I : SortedSamples.get()) { 49ef548d29SDiego Novillo LineLocation Loc = I->first; 50ef548d29SDiego Novillo const SampleRecord &Sample = I->second; 51aae1ed8eSDiego Novillo OS.indent(Indent + 1); 52c572e92cSDiego Novillo if (Loc.Discriminator == 0) 53c572e92cSDiego Novillo OS << Loc.LineOffset << ": "; 54c572e92cSDiego Novillo else 55c572e92cSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 56c572e92cSDiego Novillo 57c572e92cSDiego Novillo OS << Sample.getSamples(); 58c572e92cSDiego Novillo 59d5336ae2SDiego Novillo for (const auto &J : Sample.getCallTargets()) 60d5336ae2SDiego Novillo OS << " " << J.first() << ":" << J.second; 61c572e92cSDiego Novillo OS << "\n"; 62c572e92cSDiego Novillo } 63c572e92cSDiego Novillo 6457d1dda5SDehao Chen SampleSorter<LineLocation, FunctionSamples> SortedCallsiteSamples( 65ef548d29SDiego Novillo S.getCallsiteSamples()); 66aae1ed8eSDiego Novillo Indent += 1; 67ef548d29SDiego Novillo for (const auto &I : SortedCallsiteSamples.get()) { 6857d1dda5SDehao Chen LineLocation Loc = I->first; 69ef548d29SDiego Novillo const FunctionSamples &CalleeSamples = I->second; 70aae1ed8eSDiego Novillo OS.indent(Indent); 71aae1ed8eSDiego Novillo if (Loc.Discriminator == 0) 72aae1ed8eSDiego Novillo OS << Loc.LineOffset << ": "; 73aae1ed8eSDiego Novillo else 74aae1ed8eSDiego Novillo OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 7557d1dda5SDehao Chen if (std::error_code EC = write(CalleeSamples)) 76760c5a8fSDiego Novillo return EC; 77aae1ed8eSDiego Novillo } 78aae1ed8eSDiego Novillo Indent -= 1; 79aae1ed8eSDiego Novillo 80760c5a8fSDiego Novillo return sampleprof_error::success; 81c572e92cSDiego Novillo } 82c572e92cSDiego Novillo 83760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 84760c5a8fSDiego Novillo const auto &ret = NameTable.find(FName); 85760c5a8fSDiego Novillo if (ret == NameTable.end()) 86760c5a8fSDiego Novillo return sampleprof_error::truncated_name_table; 8751abea74SNathan Slingerland encodeULEB128(ret->second, *OutputStream); 88760c5a8fSDiego Novillo return sampleprof_error::success; 89760c5a8fSDiego Novillo } 90c572e92cSDiego Novillo 91760c5a8fSDiego Novillo void SampleProfileWriterBinary::addName(StringRef FName) { 92760c5a8fSDiego Novillo auto NextIdx = NameTable.size(); 93760c5a8fSDiego Novillo NameTable.insert(std::make_pair(FName, NextIdx)); 94760c5a8fSDiego Novillo } 95760c5a8fSDiego Novillo 96760c5a8fSDiego Novillo void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 97760c5a8fSDiego Novillo // Add all the names in indirect call targets. 98760c5a8fSDiego Novillo for (const auto &I : S.getBodySamples()) { 99760c5a8fSDiego Novillo const SampleRecord &Sample = I.second; 100760c5a8fSDiego Novillo for (const auto &J : Sample.getCallTargets()) 101760c5a8fSDiego Novillo addName(J.first()); 102760c5a8fSDiego Novillo } 103760c5a8fSDiego Novillo 104760c5a8fSDiego Novillo // Recursively add all the names for inlined callsites. 105760c5a8fSDiego Novillo for (const auto &J : S.getCallsiteSamples()) { 106760c5a8fSDiego Novillo const FunctionSamples &CalleeSamples = J.second; 10757d1dda5SDehao Chen addName(CalleeSamples.getName()); 108760c5a8fSDiego Novillo addNames(CalleeSamples); 109760c5a8fSDiego Novillo } 110760c5a8fSDiego Novillo } 111760c5a8fSDiego Novillo 112760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeHeader( 113760c5a8fSDiego Novillo const StringMap<FunctionSamples> &ProfileMap) { 11451abea74SNathan Slingerland auto &OS = *OutputStream; 11551abea74SNathan Slingerland 116760c5a8fSDiego Novillo // Write file magic identifier. 117c572e92cSDiego Novillo encodeULEB128(SPMagic(), OS); 118c572e92cSDiego Novillo encodeULEB128(SPVersion(), OS); 119760c5a8fSDiego Novillo 12040ee23dbSEaswaran Raman computeSummary(ProfileMap); 12140ee23dbSEaswaran Raman if (auto EC = writeSummary()) 12240ee23dbSEaswaran Raman return EC; 12340ee23dbSEaswaran Raman 124760c5a8fSDiego Novillo // Generate the name table for all the functions referenced in the profile. 125760c5a8fSDiego Novillo for (const auto &I : ProfileMap) { 126760c5a8fSDiego Novillo addName(I.first()); 127760c5a8fSDiego Novillo addNames(I.second); 128760c5a8fSDiego Novillo } 129760c5a8fSDiego Novillo 130760c5a8fSDiego Novillo // Write out the name table. 131760c5a8fSDiego Novillo encodeULEB128(NameTable.size(), OS); 132760c5a8fSDiego Novillo for (auto N : NameTable) { 133760c5a8fSDiego Novillo OS << N.first; 134760c5a8fSDiego Novillo encodeULEB128(0, OS); 135760c5a8fSDiego Novillo } 136760c5a8fSDiego Novillo return sampleprof_error::success; 137c572e92cSDiego Novillo } 138c572e92cSDiego Novillo 13940ee23dbSEaswaran Raman std::error_code SampleProfileWriterBinary::writeSummary() { 14040ee23dbSEaswaran Raman auto &OS = *OutputStream; 1417cefdb81SEaswaran Raman encodeULEB128(Summary->getTotalCount(), OS); 1427cefdb81SEaswaran Raman encodeULEB128(Summary->getMaxCount(), OS); 1436f4903d9SEaswaran Raman encodeULEB128(Summary->getMaxFunctionCount(), OS); 1447cefdb81SEaswaran Raman encodeULEB128(Summary->getNumCounts(), OS); 14540ee23dbSEaswaran Raman encodeULEB128(Summary->getNumFunctions(), OS); 14640ee23dbSEaswaran Raman std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 14740ee23dbSEaswaran Raman encodeULEB128(Entries.size(), OS); 14840ee23dbSEaswaran Raman for (auto Entry : Entries) { 14940ee23dbSEaswaran Raman encodeULEB128(Entry.Cutoff, OS); 15040ee23dbSEaswaran Raman encodeULEB128(Entry.MinCount, OS); 15140ee23dbSEaswaran Raman encodeULEB128(Entry.NumCounts, OS); 15240ee23dbSEaswaran Raman } 15340ee23dbSEaswaran Raman return sampleprof_error::success; 15440ee23dbSEaswaran Raman } 15557d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 15651abea74SNathan Slingerland auto &OS = *OutputStream; 15751abea74SNathan Slingerland 15857d1dda5SDehao Chen if (std::error_code EC = writeNameIdx(S.getName())) 159760c5a8fSDiego Novillo return EC; 160760c5a8fSDiego Novillo 161c572e92cSDiego Novillo encodeULEB128(S.getTotalSamples(), OS); 162a7f1e8efSDiego Novillo 163a7f1e8efSDiego Novillo // Emit all the body samples. 164b93483dbSDiego Novillo encodeULEB128(S.getBodySamples().size(), OS); 165d5336ae2SDiego Novillo for (const auto &I : S.getBodySamples()) { 166d5336ae2SDiego Novillo LineLocation Loc = I.first; 167d5336ae2SDiego Novillo const SampleRecord &Sample = I.second; 168c572e92cSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 169c572e92cSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 170c572e92cSDiego Novillo encodeULEB128(Sample.getSamples(), OS); 171c572e92cSDiego Novillo encodeULEB128(Sample.getCallTargets().size(), OS); 172d5336ae2SDiego Novillo for (const auto &J : Sample.getCallTargets()) { 173760c5a8fSDiego Novillo StringRef Callee = J.first(); 17438be3330SDiego Novillo uint64_t CalleeSamples = J.second; 175760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(Callee)) 176760c5a8fSDiego Novillo return EC; 177c572e92cSDiego Novillo encodeULEB128(CalleeSamples, OS); 178c572e92cSDiego Novillo } 179c572e92cSDiego Novillo } 180c572e92cSDiego Novillo 181a7f1e8efSDiego Novillo // Recursively emit all the callsite samples. 182a7f1e8efSDiego Novillo encodeULEB128(S.getCallsiteSamples().size(), OS); 183a7f1e8efSDiego Novillo for (const auto &J : S.getCallsiteSamples()) { 18457d1dda5SDehao Chen LineLocation Loc = J.first; 185a7f1e8efSDiego Novillo const FunctionSamples &CalleeSamples = J.second; 186a7f1e8efSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 187a7f1e8efSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 18857d1dda5SDehao Chen if (std::error_code EC = writeBody(CalleeSamples)) 189760c5a8fSDiego Novillo return EC; 190a7f1e8efSDiego Novillo } 191a7f1e8efSDiego Novillo 192760c5a8fSDiego Novillo return sampleprof_error::success; 193c572e92cSDiego Novillo } 194d5336ae2SDiego Novillo 195b93483dbSDiego Novillo /// \brief Write samples of a top-level function to a binary file. 196b93483dbSDiego Novillo /// 197b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise. 19857d1dda5SDehao Chen std::error_code SampleProfileWriterBinary::write(const FunctionSamples &S) { 19951abea74SNathan Slingerland encodeULEB128(S.getHeadSamples(), *OutputStream); 20057d1dda5SDehao Chen return writeBody(S); 201b93483dbSDiego Novillo } 202b93483dbSDiego Novillo 20351abea74SNathan Slingerland /// \brief Create a sample profile file writer based on the specified format. 204d5336ae2SDiego Novillo /// 205d5336ae2SDiego Novillo /// \param Filename The file to create. 206d5336ae2SDiego Novillo /// 207d5336ae2SDiego Novillo /// \param Writer The writer to instantiate according to the specified format. 208d5336ae2SDiego Novillo /// 209d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file. 210d5336ae2SDiego Novillo /// 211d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer. 212fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>> 213fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 214d5336ae2SDiego Novillo std::error_code EC; 21551abea74SNathan Slingerland std::unique_ptr<raw_ostream> OS; 21651abea74SNathan Slingerland if (Format == SPF_Binary) 21751abea74SNathan Slingerland OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None)); 21851abea74SNathan Slingerland else 21951abea74SNathan Slingerland OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text)); 22051abea74SNathan Slingerland if (EC) 22151abea74SNathan Slingerland return EC; 22251abea74SNathan Slingerland 22351abea74SNathan Slingerland return create(OS, Format); 22451abea74SNathan Slingerland } 22551abea74SNathan Slingerland 22651abea74SNathan Slingerland /// \brief Create a sample profile stream writer based on the specified format. 22751abea74SNathan Slingerland /// 22851abea74SNathan Slingerland /// \param OS The output stream to store the profile data to. 22951abea74SNathan Slingerland /// 23051abea74SNathan Slingerland /// \param Writer The writer to instantiate according to the specified format. 23151abea74SNathan Slingerland /// 23251abea74SNathan Slingerland /// \param Format Encoding format for the profile file. 23351abea74SNathan Slingerland /// 23451abea74SNathan Slingerland /// \returns an error code indicating the status of the created writer. 23551abea74SNathan Slingerland ErrorOr<std::unique_ptr<SampleProfileWriter>> 23651abea74SNathan Slingerland SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 23751abea74SNathan Slingerland SampleProfileFormat Format) { 23851abea74SNathan Slingerland std::error_code EC; 239fcd55607SDiego Novillo std::unique_ptr<SampleProfileWriter> Writer; 240d5336ae2SDiego Novillo 241d5336ae2SDiego Novillo if (Format == SPF_Binary) 24251abea74SNathan Slingerland Writer.reset(new SampleProfileWriterBinary(OS)); 243d5336ae2SDiego Novillo else if (Format == SPF_Text) 24451abea74SNathan Slingerland Writer.reset(new SampleProfileWriterText(OS)); 245760c5a8fSDiego Novillo else if (Format == SPF_GCC) 246760c5a8fSDiego Novillo EC = sampleprof_error::unsupported_writing_format; 247d5336ae2SDiego Novillo else 248d5336ae2SDiego Novillo EC = sampleprof_error::unrecognized_format; 249d5336ae2SDiego Novillo 250fcd55607SDiego Novillo if (EC) 251d5336ae2SDiego Novillo return EC; 252fcd55607SDiego Novillo 253fcd55607SDiego Novillo return std::move(Writer); 254d5336ae2SDiego Novillo } 25540ee23dbSEaswaran Raman 25640ee23dbSEaswaran Raman void SampleProfileWriter::computeSummary( 25740ee23dbSEaswaran Raman const StringMap<FunctionSamples> &ProfileMap) { 258e5a17e3fSEaswaran Raman SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 25940ee23dbSEaswaran Raman for (const auto &I : ProfileMap) { 26040ee23dbSEaswaran Raman const FunctionSamples &Profile = I.second; 261e5a17e3fSEaswaran Raman Builder.addRecord(Profile); 26240ee23dbSEaswaran Raman } 263*38de59e4SBenjamin Kramer Summary = Builder.getSummary(); 26440ee23dbSEaswaran Raman } 265