1//===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the class that writes LLVM sample profiles. It 11// supports two file formats: text and binary. The textual representation 12// is useful for debugging and testing purposes. The binary representation 13// is more compact, resulting in smaller file sizes. However, they can 14// both be used interchangeably. 15// 16// See lib/ProfileData/SampleProfReader.cpp for documentation on each of the 17// supported formats. 18// 19//===----------------------------------------------------------------------===// 20 21#include "llvm/ProfileData/SampleProfWriter.h" 22#include "llvm/Support/Debug.h" 23#include "llvm/Support/ErrorOr.h" 24#include "llvm/Support/LEB128.h" 25#include "llvm/Support/LineIterator.h" 26#include "llvm/Support/MemoryBuffer.h" 27#include "llvm/Support/Regex.h" 28 29using namespace llvm::sampleprof; 30using namespace llvm; 31 32/// \brief Write samples to a text file. 33/// 34/// Note: it may be tempting to implement this in terms of 35/// FunctionSamples::print(). Please don't. The dump functionality is intended 36/// for debugging and has no specified form. 37/// 38/// The format used here is more structured and deliberate because 39/// it needs to be parsed by the SampleProfileReaderText class. 40std::error_code SampleProfileWriterText::write(const FunctionSamples &S) { 41 auto &OS = *OutputStream; 42 OS << S.getName() << ":" << S.getTotalSamples(); 43 if (Indent == 0) 44 OS << ":" << S.getHeadSamples(); 45 OS << "\n"; 46 47 SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 48 for (const auto &I : SortedSamples.get()) { 49 LineLocation Loc = I->first; 50 const SampleRecord &Sample = I->second; 51 OS.indent(Indent + 1); 52 if (Loc.Discriminator == 0) 53 OS << Loc.LineOffset << ": "; 54 else 55 OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 56 57 OS << Sample.getSamples(); 58 59 for (const auto &J : Sample.getCallTargets()) 60 OS << " " << J.first() << ":" << J.second; 61 OS << "\n"; 62 } 63 64 SampleSorter<LineLocation, FunctionSamples> SortedCallsiteSamples( 65 S.getCallsiteSamples()); 66 Indent += 1; 67 for (const auto &I : SortedCallsiteSamples.get()) { 68 LineLocation Loc = I->first; 69 const FunctionSamples &CalleeSamples = I->second; 70 OS.indent(Indent); 71 if (Loc.Discriminator == 0) 72 OS << Loc.LineOffset << ": "; 73 else 74 OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 75 if (std::error_code EC = write(CalleeSamples)) 76 return EC; 77 } 78 Indent -= 1; 79 80 return sampleprof_error::success; 81} 82 83std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 84 const auto &ret = NameTable.find(FName); 85 if (ret == NameTable.end()) 86 return sampleprof_error::truncated_name_table; 87 encodeULEB128(ret->second, *OutputStream); 88 return sampleprof_error::success; 89} 90 91void SampleProfileWriterBinary::addName(StringRef FName) { 92 auto NextIdx = NameTable.size(); 93 NameTable.insert(std::make_pair(FName, NextIdx)); 94} 95 96void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 97 // Add all the names in indirect call targets. 98 for (const auto &I : S.getBodySamples()) { 99 const SampleRecord &Sample = I.second; 100 for (const auto &J : Sample.getCallTargets()) 101 addName(J.first()); 102 } 103 104 // Recursively add all the names for inlined callsites. 105 for (const auto &J : S.getCallsiteSamples()) { 106 const FunctionSamples &CalleeSamples = J.second; 107 addName(CalleeSamples.getName()); 108 addNames(CalleeSamples); 109 } 110} 111 112std::error_code SampleProfileWriterBinary::writeHeader( 113 const StringMap<FunctionSamples> &ProfileMap) { 114 auto &OS = *OutputStream; 115 116 // Write file magic identifier. 117 encodeULEB128(SPMagic(), OS); 118 encodeULEB128(SPVersion(), OS); 119 120 computeSummary(ProfileMap); 121 if (auto EC = writeSummary()) 122 return EC; 123 124 // Generate the name table for all the functions referenced in the profile. 125 for (const auto &I : ProfileMap) { 126 addName(I.first()); 127 addNames(I.second); 128 } 129 130 // Write out the name table. 131 encodeULEB128(NameTable.size(), OS); 132 for (auto N : NameTable) { 133 OS << N.first; 134 encodeULEB128(0, OS); 135 } 136 return sampleprof_error::success; 137} 138 139std::error_code SampleProfileWriterBinary::writeSummary() { 140 auto &OS = *OutputStream; 141 encodeULEB128(Summary->getTotalCount(), OS); 142 encodeULEB128(Summary->getMaxCount(), OS); 143 encodeULEB128(Summary->getMaxFunctionCount(), OS); 144 encodeULEB128(Summary->getNumCounts(), OS); 145 encodeULEB128(Summary->getNumFunctions(), OS); 146 std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 147 encodeULEB128(Entries.size(), OS); 148 for (auto Entry : Entries) { 149 encodeULEB128(Entry.Cutoff, OS); 150 encodeULEB128(Entry.MinCount, OS); 151 encodeULEB128(Entry.NumCounts, OS); 152 } 153 return sampleprof_error::success; 154} 155std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 156 auto &OS = *OutputStream; 157 158 if (std::error_code EC = writeNameIdx(S.getName())) 159 return EC; 160 161 encodeULEB128(S.getTotalSamples(), OS); 162 163 // Emit all the body samples. 164 encodeULEB128(S.getBodySamples().size(), OS); 165 for (const auto &I : S.getBodySamples()) { 166 LineLocation Loc = I.first; 167 const SampleRecord &Sample = I.second; 168 encodeULEB128(Loc.LineOffset, OS); 169 encodeULEB128(Loc.Discriminator, OS); 170 encodeULEB128(Sample.getSamples(), OS); 171 encodeULEB128(Sample.getCallTargets().size(), OS); 172 for (const auto &J : Sample.getCallTargets()) { 173 StringRef Callee = J.first(); 174 uint64_t CalleeSamples = J.second; 175 if (std::error_code EC = writeNameIdx(Callee)) 176 return EC; 177 encodeULEB128(CalleeSamples, OS); 178 } 179 } 180 181 // Recursively emit all the callsite samples. 182 encodeULEB128(S.getCallsiteSamples().size(), OS); 183 for (const auto &J : S.getCallsiteSamples()) { 184 LineLocation Loc = J.first; 185 const FunctionSamples &CalleeSamples = J.second; 186 encodeULEB128(Loc.LineOffset, OS); 187 encodeULEB128(Loc.Discriminator, OS); 188 if (std::error_code EC = writeBody(CalleeSamples)) 189 return EC; 190 } 191 192 return sampleprof_error::success; 193} 194 195/// \brief Write samples of a top-level function to a binary file. 196/// 197/// \returns true if the samples were written successfully, false otherwise. 198std::error_code SampleProfileWriterBinary::write(const FunctionSamples &S) { 199 encodeULEB128(S.getHeadSamples(), *OutputStream); 200 return writeBody(S); 201} 202 203/// \brief Create a sample profile file writer based on the specified format. 204/// 205/// \param Filename The file to create. 206/// 207/// \param Writer The writer to instantiate according to the specified format. 208/// 209/// \param Format Encoding format for the profile file. 210/// 211/// \returns an error code indicating the status of the created writer. 212ErrorOr<std::unique_ptr<SampleProfileWriter>> 213SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 214 std::error_code EC; 215 std::unique_ptr<raw_ostream> OS; 216 if (Format == SPF_Binary) 217 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None)); 218 else 219 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text)); 220 if (EC) 221 return EC; 222 223 return create(OS, Format); 224} 225 226/// \brief Create a sample profile stream writer based on the specified format. 227/// 228/// \param OS The output stream to store the profile data to. 229/// 230/// \param Writer The writer to instantiate according to the specified format. 231/// 232/// \param Format Encoding format for the profile file. 233/// 234/// \returns an error code indicating the status of the created writer. 235ErrorOr<std::unique_ptr<SampleProfileWriter>> 236SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 237 SampleProfileFormat Format) { 238 std::error_code EC; 239 std::unique_ptr<SampleProfileWriter> Writer; 240 241 if (Format == SPF_Binary) 242 Writer.reset(new SampleProfileWriterBinary(OS)); 243 else if (Format == SPF_Text) 244 Writer.reset(new SampleProfileWriterText(OS)); 245 else if (Format == SPF_GCC) 246 EC = sampleprof_error::unsupported_writing_format; 247 else 248 EC = sampleprof_error::unrecognized_format; 249 250 if (EC) 251 return EC; 252 253 return std::move(Writer); 254} 255 256void SampleProfileWriter::computeSummary( 257 const StringMap<FunctionSamples> &ProfileMap) { 258 SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 259 for (const auto &I : ProfileMap) { 260 const FunctionSamples &Profile = I.second; 261 Builder.addRecord(Profile); 262 } 263 Summary = Builder.getSummary(); 264} 265