SampleProfWriter.cpp 8.5 KB

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