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 35*ef548d29SDiego 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. 40760c5a8fSDiego Novillo std::error_code SampleProfileWriterText::write(StringRef FName, 41760c5a8fSDiego Novillo const FunctionSamples &S) { 42aae1ed8eSDiego Novillo OS << FName << ":" << S.getTotalSamples(); 43aae1ed8eSDiego Novillo if (Indent == 0) 44aae1ed8eSDiego Novillo OS << ":" << S.getHeadSamples(); 45aae1ed8eSDiego Novillo OS << "\n"; 46c572e92cSDiego Novillo 47*ef548d29SDiego Novillo SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 48*ef548d29SDiego Novillo for (const auto &I : SortedSamples.get()) { 49*ef548d29SDiego Novillo LineLocation Loc = I->first; 50*ef548d29SDiego 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 64*ef548d29SDiego Novillo SampleSorter<CallsiteLocation, FunctionSamples> SortedCallsiteSamples( 65*ef548d29SDiego Novillo S.getCallsiteSamples()); 66aae1ed8eSDiego Novillo Indent += 1; 67*ef548d29SDiego Novillo for (const auto &I : SortedCallsiteSamples.get()) { 68*ef548d29SDiego Novillo CallsiteLocation Loc = I->first; 69*ef548d29SDiego 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 << ": "; 75760c5a8fSDiego Novillo if (std::error_code EC = write(Loc.CalleeName, 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; 87760c5a8fSDiego Novillo encodeULEB128(ret->second, OS); 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 CallsiteLocation Loc = J.first; 107760c5a8fSDiego Novillo const FunctionSamples &CalleeSamples = J.second; 108760c5a8fSDiego Novillo addName(Loc.CalleeName); 109760c5a8fSDiego Novillo addNames(CalleeSamples); 110760c5a8fSDiego Novillo } 111760c5a8fSDiego Novillo } 112760c5a8fSDiego Novillo 113760c5a8fSDiego Novillo std::error_code SampleProfileWriterBinary::writeHeader( 114760c5a8fSDiego Novillo const StringMap<FunctionSamples> &ProfileMap) { 115760c5a8fSDiego Novillo // Write file magic identifier. 116c572e92cSDiego Novillo encodeULEB128(SPMagic(), OS); 117c572e92cSDiego Novillo encodeULEB128(SPVersion(), OS); 118760c5a8fSDiego Novillo 119760c5a8fSDiego Novillo // Generate the name table for all the functions referenced in the profile. 120760c5a8fSDiego Novillo for (const auto &I : ProfileMap) { 121760c5a8fSDiego Novillo addName(I.first()); 122760c5a8fSDiego Novillo addNames(I.second); 123760c5a8fSDiego Novillo } 124760c5a8fSDiego Novillo 125760c5a8fSDiego Novillo // Write out the name table. 126760c5a8fSDiego Novillo encodeULEB128(NameTable.size(), OS); 127760c5a8fSDiego Novillo for (auto N : NameTable) { 128760c5a8fSDiego Novillo OS << N.first; 129760c5a8fSDiego Novillo encodeULEB128(0, OS); 130760c5a8fSDiego Novillo } 131760c5a8fSDiego Novillo 132760c5a8fSDiego Novillo return sampleprof_error::success; 133c572e92cSDiego Novillo } 134c572e92cSDiego Novillo 135b93483dbSDiego Novillo std::error_code SampleProfileWriterBinary::writeBody(StringRef FName, 136c572e92cSDiego Novillo const FunctionSamples &S) { 137760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(FName)) 138760c5a8fSDiego Novillo return EC; 139760c5a8fSDiego Novillo 140c572e92cSDiego Novillo encodeULEB128(S.getTotalSamples(), OS); 141a7f1e8efSDiego Novillo 142a7f1e8efSDiego Novillo // Emit all the body samples. 143b93483dbSDiego Novillo encodeULEB128(S.getBodySamples().size(), OS); 144d5336ae2SDiego Novillo for (const auto &I : S.getBodySamples()) { 145d5336ae2SDiego Novillo LineLocation Loc = I.first; 146d5336ae2SDiego Novillo const SampleRecord &Sample = I.second; 147c572e92cSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 148c572e92cSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 149c572e92cSDiego Novillo encodeULEB128(Sample.getSamples(), OS); 150c572e92cSDiego Novillo encodeULEB128(Sample.getCallTargets().size(), OS); 151d5336ae2SDiego Novillo for (const auto &J : Sample.getCallTargets()) { 152760c5a8fSDiego Novillo StringRef Callee = J.first(); 15338be3330SDiego Novillo uint64_t CalleeSamples = J.second; 154760c5a8fSDiego Novillo if (std::error_code EC = writeNameIdx(Callee)) 155760c5a8fSDiego Novillo return EC; 156c572e92cSDiego Novillo encodeULEB128(CalleeSamples, OS); 157c572e92cSDiego Novillo } 158c572e92cSDiego Novillo } 159c572e92cSDiego Novillo 160a7f1e8efSDiego Novillo // Recursively emit all the callsite samples. 161a7f1e8efSDiego Novillo encodeULEB128(S.getCallsiteSamples().size(), OS); 162a7f1e8efSDiego Novillo for (const auto &J : S.getCallsiteSamples()) { 163a7f1e8efSDiego Novillo CallsiteLocation Loc = J.first; 164a7f1e8efSDiego Novillo const FunctionSamples &CalleeSamples = J.second; 165a7f1e8efSDiego Novillo encodeULEB128(Loc.LineOffset, OS); 166a7f1e8efSDiego Novillo encodeULEB128(Loc.Discriminator, OS); 167b93483dbSDiego Novillo if (std::error_code EC = writeBody(Loc.CalleeName, CalleeSamples)) 168760c5a8fSDiego Novillo return EC; 169a7f1e8efSDiego Novillo } 170a7f1e8efSDiego Novillo 171760c5a8fSDiego Novillo return sampleprof_error::success; 172c572e92cSDiego Novillo } 173d5336ae2SDiego Novillo 174b93483dbSDiego Novillo /// \brief Write samples of a top-level function to a binary file. 175b93483dbSDiego Novillo /// 176b93483dbSDiego Novillo /// \returns true if the samples were written successfully, false otherwise. 177b93483dbSDiego Novillo std::error_code SampleProfileWriterBinary::write(StringRef FName, 178b93483dbSDiego Novillo const FunctionSamples &S) { 179b93483dbSDiego Novillo encodeULEB128(S.getHeadSamples(), OS); 180b93483dbSDiego Novillo return writeBody(FName, S); 181b93483dbSDiego Novillo } 182b93483dbSDiego Novillo 183d5336ae2SDiego Novillo /// \brief Create a sample profile writer based on the specified format. 184d5336ae2SDiego Novillo /// 185d5336ae2SDiego Novillo /// \param Filename The file to create. 186d5336ae2SDiego Novillo /// 187d5336ae2SDiego Novillo /// \param Writer The writer to instantiate according to the specified format. 188d5336ae2SDiego Novillo /// 189d5336ae2SDiego Novillo /// \param Format Encoding format for the profile file. 190d5336ae2SDiego Novillo /// 191d5336ae2SDiego Novillo /// \returns an error code indicating the status of the created writer. 192fcd55607SDiego Novillo ErrorOr<std::unique_ptr<SampleProfileWriter>> 193fcd55607SDiego Novillo SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 194d5336ae2SDiego Novillo std::error_code EC; 195fcd55607SDiego Novillo std::unique_ptr<SampleProfileWriter> Writer; 196d5336ae2SDiego Novillo 197d5336ae2SDiego Novillo if (Format == SPF_Binary) 198d5336ae2SDiego Novillo Writer.reset(new SampleProfileWriterBinary(Filename, EC)); 199d5336ae2SDiego Novillo else if (Format == SPF_Text) 200d5336ae2SDiego Novillo Writer.reset(new SampleProfileWriterText(Filename, EC)); 201760c5a8fSDiego Novillo else if (Format == SPF_GCC) 202760c5a8fSDiego Novillo EC = sampleprof_error::unsupported_writing_format; 203d5336ae2SDiego Novillo else 204d5336ae2SDiego Novillo EC = sampleprof_error::unrecognized_format; 205d5336ae2SDiego Novillo 206fcd55607SDiego Novillo if (EC) 207d5336ae2SDiego Novillo return EC; 208fcd55607SDiego Novillo 209fcd55607SDiego Novillo return std::move(Writer); 210d5336ae2SDiego Novillo } 211