Home | History | Annotate | Download | only in ProfileData
      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 
     29 using namespace llvm::sampleprof;
     30 using 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.
     40 std::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 
     83 std::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 
     91 void SampleProfileWriterBinary::addName(StringRef FName) {
     92   auto NextIdx = NameTable.size();
     93   NameTable.insert(std::make_pair(FName, NextIdx));
     94 }
     95 
     96 void 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 
    112 std::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 
    139 std::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 }
    155 std::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.
    198 std::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.
    212 ErrorOr<std::unique_ptr<SampleProfileWriter>>
    213 SampleProfileWriter::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.
    235 ErrorOr<std::unique_ptr<SampleProfileWriter>>
    236 SampleProfileWriter::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 
    256 void 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