SampleProfWriter.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file implements the class that writes LLVM sample profiles. It
  10. // supports two file formats: text and binary. The textual representation
  11. // is useful for debugging and testing purposes. The binary representation
  12. // is more compact, resulting in smaller file sizes. However, they can
  13. // both be used interchangeably.
  14. //
  15. // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
  16. // supported formats.
  17. //
  18. //===----------------------------------------------------------------------===//
  19. #include "llvm/ProfileData/SampleProfWriter.h"
  20. #include "llvm/ADT/StringRef.h"
  21. #include "llvm/ADT/StringSet.h"
  22. #include "llvm/ProfileData/ProfileCommon.h"
  23. #include "llvm/ProfileData/SampleProf.h"
  24. #include "llvm/Support/Compression.h"
  25. #include "llvm/Support/Endian.h"
  26. #include "llvm/Support/EndianStream.h"
  27. #include "llvm/Support/ErrorOr.h"
  28. #include "llvm/Support/FileSystem.h"
  29. #include "llvm/Support/LEB128.h"
  30. #include "llvm/Support/MD5.h"
  31. #include "llvm/Support/raw_ostream.h"
  32. #include <algorithm>
  33. #include <cstdint>
  34. #include <memory>
  35. #include <set>
  36. #include <system_error>
  37. #include <utility>
  38. #include <vector>
  39. using namespace llvm;
  40. using namespace sampleprof;
  41. std::error_code
  42. SampleProfileWriter::writeFuncProfiles(const SampleProfileMap &ProfileMap) {
  43. std::vector<NameFunctionSamples> V;
  44. sortFuncProfiles(ProfileMap, V);
  45. for (const auto &I : V) {
  46. if (std::error_code EC = writeSample(*I.second))
  47. return EC;
  48. }
  49. return sampleprof_error::success;
  50. }
  51. std::error_code SampleProfileWriter::write(const SampleProfileMap &ProfileMap) {
  52. if (std::error_code EC = writeHeader(ProfileMap))
  53. return EC;
  54. if (std::error_code EC = writeFuncProfiles(ProfileMap))
  55. return EC;
  56. return sampleprof_error::success;
  57. }
  58. /// Return the current position and prepare to use it as the start
  59. /// position of a section given the section type \p Type and its position
  60. /// \p LayoutIdx in SectionHdrLayout.
  61. uint64_t
  62. SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type,
  63. uint32_t LayoutIdx) {
  64. uint64_t SectionStart = OutputStream->tell();
  65. assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
  66. const auto &Entry = SectionHdrLayout[LayoutIdx];
  67. assert(Entry.Type == Type && "Unexpected section type");
  68. // Use LocalBuf as a temporary output for writting data.
  69. if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
  70. LocalBufStream.swap(OutputStream);
  71. return SectionStart;
  72. }
  73. std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
  74. if (!llvm::zlib::isAvailable())
  75. return sampleprof_error::zlib_unavailable;
  76. std::string &UncompressedStrings =
  77. static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
  78. if (UncompressedStrings.size() == 0)
  79. return sampleprof_error::success;
  80. auto &OS = *OutputStream;
  81. SmallString<128> CompressedStrings;
  82. llvm::Error E = zlib::compress(UncompressedStrings, CompressedStrings,
  83. zlib::BestSizeCompression);
  84. if (E)
  85. return sampleprof_error::compress_failed;
  86. encodeULEB128(UncompressedStrings.size(), OS);
  87. encodeULEB128(CompressedStrings.size(), OS);
  88. OS << CompressedStrings.str();
  89. UncompressedStrings.clear();
  90. return sampleprof_error::success;
  91. }
  92. /// Add a new section into section header table given the section type
  93. /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the
  94. /// location \p SectionStart where the section should be written to.
  95. std::error_code SampleProfileWriterExtBinaryBase::addNewSection(
  96. SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) {
  97. assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
  98. const auto &Entry = SectionHdrLayout[LayoutIdx];
  99. assert(Entry.Type == Type && "Unexpected section type");
  100. if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) {
  101. LocalBufStream.swap(OutputStream);
  102. if (std::error_code EC = compressAndOutput())
  103. return EC;
  104. }
  105. SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
  106. OutputStream->tell() - SectionStart, LayoutIdx});
  107. return sampleprof_error::success;
  108. }
  109. std::error_code
  110. SampleProfileWriterExtBinaryBase::write(const SampleProfileMap &ProfileMap) {
  111. if (std::error_code EC = writeHeader(ProfileMap))
  112. return EC;
  113. std::string LocalBuf;
  114. LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
  115. if (std::error_code EC = writeSections(ProfileMap))
  116. return EC;
  117. if (std::error_code EC = writeSecHdrTable())
  118. return EC;
  119. return sampleprof_error::success;
  120. }
  121. std::error_code SampleProfileWriterExtBinaryBase::writeContextIdx(
  122. const SampleContext &Context) {
  123. if (Context.hasContext())
  124. return writeCSNameIdx(Context);
  125. else
  126. return SampleProfileWriterBinary::writeNameIdx(Context.getName());
  127. }
  128. std::error_code
  129. SampleProfileWriterExtBinaryBase::writeCSNameIdx(const SampleContext &Context) {
  130. const auto &Ret = CSNameTable.find(Context);
  131. if (Ret == CSNameTable.end())
  132. return sampleprof_error::truncated_name_table;
  133. encodeULEB128(Ret->second, *OutputStream);
  134. return sampleprof_error::success;
  135. }
  136. std::error_code
  137. SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) {
  138. uint64_t Offset = OutputStream->tell();
  139. auto &Context = S.getContext();
  140. FuncOffsetTable[Context] = Offset - SecLBRProfileStart;
  141. encodeULEB128(S.getHeadSamples(), *OutputStream);
  142. return writeBody(S);
  143. }
  144. std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() {
  145. auto &OS = *OutputStream;
  146. // Write out the table size.
  147. encodeULEB128(FuncOffsetTable.size(), OS);
  148. // Write out FuncOffsetTable.
  149. auto WriteItem = [&](const SampleContext &Context, uint64_t Offset) {
  150. if (std::error_code EC = writeContextIdx(Context))
  151. return EC;
  152. encodeULEB128(Offset, OS);
  153. return (std::error_code)sampleprof_error::success;
  154. };
  155. if (FunctionSamples::ProfileIsCSFlat) {
  156. // Sort the contexts before writing them out. This is to help fast load all
  157. // context profiles for a function as well as their callee contexts which
  158. // can help profile-guided importing for ThinLTO.
  159. std::map<SampleContext, uint64_t> OrderedFuncOffsetTable(
  160. FuncOffsetTable.begin(), FuncOffsetTable.end());
  161. for (const auto &Entry : OrderedFuncOffsetTable) {
  162. if (std::error_code EC = WriteItem(Entry.first, Entry.second))
  163. return EC;
  164. }
  165. addSectionFlag(SecFuncOffsetTable, SecFuncOffsetFlags::SecFlagOrdered);
  166. } else {
  167. for (const auto &Entry : FuncOffsetTable) {
  168. if (std::error_code EC = WriteItem(Entry.first, Entry.second))
  169. return EC;
  170. }
  171. }
  172. FuncOffsetTable.clear();
  173. return sampleprof_error::success;
  174. }
  175. std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
  176. const FunctionSamples &FunctionProfile) {
  177. auto &OS = *OutputStream;
  178. if (std::error_code EC = writeContextIdx(FunctionProfile.getContext()))
  179. return EC;
  180. if (FunctionSamples::ProfileIsProbeBased)
  181. encodeULEB128(FunctionProfile.getFunctionHash(), OS);
  182. if (FunctionSamples::ProfileIsCSFlat || FunctionSamples::ProfileIsCSNested) {
  183. encodeULEB128(FunctionProfile.getContext().getAllAttributes(), OS);
  184. }
  185. if (!FunctionSamples::ProfileIsCSFlat) {
  186. // Recursively emit attributes for all callee samples.
  187. uint64_t NumCallsites = 0;
  188. for (const auto &J : FunctionProfile.getCallsiteSamples())
  189. NumCallsites += J.second.size();
  190. encodeULEB128(NumCallsites, OS);
  191. for (const auto &J : FunctionProfile.getCallsiteSamples()) {
  192. for (const auto &FS : J.second) {
  193. LineLocation Loc = J.first;
  194. encodeULEB128(Loc.LineOffset, OS);
  195. encodeULEB128(Loc.Discriminator, OS);
  196. if (std::error_code EC = writeFuncMetadata(FS.second))
  197. return EC;
  198. }
  199. }
  200. }
  201. return sampleprof_error::success;
  202. }
  203. std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
  204. const SampleProfileMap &Profiles) {
  205. if (!FunctionSamples::ProfileIsProbeBased &&
  206. !FunctionSamples::ProfileIsCSFlat && !FunctionSamples::ProfileIsCSNested)
  207. return sampleprof_error::success;
  208. for (const auto &Entry : Profiles) {
  209. if (std::error_code EC = writeFuncMetadata(Entry.second))
  210. return EC;
  211. }
  212. return sampleprof_error::success;
  213. }
  214. std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() {
  215. if (!UseMD5)
  216. return SampleProfileWriterBinary::writeNameTable();
  217. auto &OS = *OutputStream;
  218. std::set<StringRef> V;
  219. stablizeNameTable(NameTable, V);
  220. // Write out the MD5 name table. We wrote unencoded MD5 so reader can
  221. // retrieve the name using the name index without having to read the
  222. // whole name table.
  223. encodeULEB128(NameTable.size(), OS);
  224. support::endian::Writer Writer(OS, support::little);
  225. for (auto N : V)
  226. Writer.write(MD5Hash(N));
  227. return sampleprof_error::success;
  228. }
  229. std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection(
  230. const SampleProfileMap &ProfileMap) {
  231. for (const auto &I : ProfileMap) {
  232. assert(I.first == I.second.getContext() && "Inconsistent profile map");
  233. addContext(I.second.getContext());
  234. addNames(I.second);
  235. }
  236. // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag
  237. // so compiler won't strip the suffix during profile matching after
  238. // seeing the flag in the profile.
  239. for (const auto &I : NameTable) {
  240. if (I.first.contains(FunctionSamples::UniqSuffix)) {
  241. addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix);
  242. break;
  243. }
  244. }
  245. if (auto EC = writeNameTable())
  246. return EC;
  247. return sampleprof_error::success;
  248. }
  249. std::error_code SampleProfileWriterExtBinaryBase::writeCSNameTableSection() {
  250. // Sort the names to make CSNameTable deterministic.
  251. std::set<SampleContext> OrderedContexts;
  252. for (const auto &I : CSNameTable)
  253. OrderedContexts.insert(I.first);
  254. assert(OrderedContexts.size() == CSNameTable.size() &&
  255. "Unmatched ordered and unordered contexts");
  256. uint64_t I = 0;
  257. for (auto &Context : OrderedContexts)
  258. CSNameTable[Context] = I++;
  259. auto &OS = *OutputStream;
  260. encodeULEB128(OrderedContexts.size(), OS);
  261. support::endian::Writer Writer(OS, support::little);
  262. for (auto Context : OrderedContexts) {
  263. auto Frames = Context.getContextFrames();
  264. encodeULEB128(Frames.size(), OS);
  265. for (auto &Callsite : Frames) {
  266. if (std::error_code EC = writeNameIdx(Callsite.FuncName))
  267. return EC;
  268. encodeULEB128(Callsite.Location.LineOffset, OS);
  269. encodeULEB128(Callsite.Location.Discriminator, OS);
  270. }
  271. }
  272. return sampleprof_error::success;
  273. }
  274. std::error_code
  275. SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() {
  276. if (ProfSymList && ProfSymList->size() > 0)
  277. if (std::error_code EC = ProfSymList->write(*OutputStream))
  278. return EC;
  279. return sampleprof_error::success;
  280. }
  281. std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
  282. SecType Type, uint32_t LayoutIdx, const SampleProfileMap &ProfileMap) {
  283. // The setting of SecFlagCompress should happen before markSectionStart.
  284. if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress())
  285. setToCompressSection(SecProfileSymbolList);
  286. if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased)
  287. addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased);
  288. if (Type == SecFuncMetadata &&
  289. (FunctionSamples::ProfileIsCSFlat || FunctionSamples::ProfileIsCSNested))
  290. addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagHasAttribute);
  291. if (Type == SecProfSummary && FunctionSamples::ProfileIsCSFlat)
  292. addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext);
  293. if (Type == SecProfSummary && FunctionSamples::ProfileIsCSNested)
  294. addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagIsCSNested);
  295. if (Type == SecProfSummary && FunctionSamples::ProfileIsFS)
  296. addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFSDiscriminator);
  297. uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
  298. switch (Type) {
  299. case SecProfSummary:
  300. computeSummary(ProfileMap);
  301. if (auto EC = writeSummary())
  302. return EC;
  303. break;
  304. case SecNameTable:
  305. if (auto EC = writeNameTableSection(ProfileMap))
  306. return EC;
  307. break;
  308. case SecCSNameTable:
  309. if (auto EC = writeCSNameTableSection())
  310. return EC;
  311. break;
  312. case SecLBRProfile:
  313. SecLBRProfileStart = OutputStream->tell();
  314. if (std::error_code EC = writeFuncProfiles(ProfileMap))
  315. return EC;
  316. break;
  317. case SecFuncOffsetTable:
  318. if (auto EC = writeFuncOffsetTable())
  319. return EC;
  320. break;
  321. case SecFuncMetadata:
  322. if (std::error_code EC = writeFuncMetadata(ProfileMap))
  323. return EC;
  324. break;
  325. case SecProfileSymbolList:
  326. if (auto EC = writeProfileSymbolListSection())
  327. return EC;
  328. break;
  329. default:
  330. if (auto EC = writeCustomSection(Type))
  331. return EC;
  332. break;
  333. }
  334. if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart))
  335. return EC;
  336. return sampleprof_error::success;
  337. }
  338. std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
  339. const SampleProfileMap &ProfileMap) {
  340. // The const indices passed to writeOneSection below are specifying the
  341. // positions of the sections in SectionHdrLayout. Look at
  342. // initSectionHdrLayout to find out where each section is located in
  343. // SectionHdrLayout.
  344. if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
  345. return EC;
  346. if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
  347. return EC;
  348. if (auto EC = writeOneSection(SecCSNameTable, 2, ProfileMap))
  349. return EC;
  350. if (auto EC = writeOneSection(SecLBRProfile, 4, ProfileMap))
  351. return EC;
  352. if (auto EC = writeOneSection(SecProfileSymbolList, 5, ProfileMap))
  353. return EC;
  354. if (auto EC = writeOneSection(SecFuncOffsetTable, 3, ProfileMap))
  355. return EC;
  356. if (auto EC = writeOneSection(SecFuncMetadata, 6, ProfileMap))
  357. return EC;
  358. return sampleprof_error::success;
  359. }
  360. static void splitProfileMapToTwo(const SampleProfileMap &ProfileMap,
  361. SampleProfileMap &ContextProfileMap,
  362. SampleProfileMap &NoContextProfileMap) {
  363. for (const auto &I : ProfileMap) {
  364. if (I.second.getCallsiteSamples().size())
  365. ContextProfileMap.insert({I.first, I.second});
  366. else
  367. NoContextProfileMap.insert({I.first, I.second});
  368. }
  369. }
  370. std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
  371. const SampleProfileMap &ProfileMap) {
  372. SampleProfileMap ContextProfileMap, NoContextProfileMap;
  373. splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap);
  374. if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
  375. return EC;
  376. if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
  377. return EC;
  378. if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap))
  379. return EC;
  380. if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap))
  381. return EC;
  382. // Mark the section to have no context. Note section flag needs to be set
  383. // before writing the section.
  384. addSectionFlag(5, SecCommonFlags::SecFlagFlat);
  385. if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap))
  386. return EC;
  387. // Mark the section to have no context. Note section flag needs to be set
  388. // before writing the section.
  389. addSectionFlag(4, SecCommonFlags::SecFlagFlat);
  390. if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap))
  391. return EC;
  392. if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap))
  393. return EC;
  394. if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap))
  395. return EC;
  396. return sampleprof_error::success;
  397. }
  398. std::error_code SampleProfileWriterExtBinary::writeSections(
  399. const SampleProfileMap &ProfileMap) {
  400. std::error_code EC;
  401. if (SecLayout == DefaultLayout)
  402. EC = writeDefaultLayout(ProfileMap);
  403. else if (SecLayout == CtxSplitLayout)
  404. EC = writeCtxSplitLayout(ProfileMap);
  405. else
  406. llvm_unreachable("Unsupported layout");
  407. return EC;
  408. }
  409. std::error_code
  410. SampleProfileWriterCompactBinary::write(const SampleProfileMap &ProfileMap) {
  411. if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
  412. return EC;
  413. if (std::error_code EC = writeFuncOffsetTable())
  414. return EC;
  415. return sampleprof_error::success;
  416. }
  417. /// Write samples to a text file.
  418. ///
  419. /// Note: it may be tempting to implement this in terms of
  420. /// FunctionSamples::print(). Please don't. The dump functionality is intended
  421. /// for debugging and has no specified form.
  422. ///
  423. /// The format used here is more structured and deliberate because
  424. /// it needs to be parsed by the SampleProfileReaderText class.
  425. std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
  426. auto &OS = *OutputStream;
  427. if (FunctionSamples::ProfileIsCSFlat)
  428. OS << "[" << S.getContext().toString() << "]:" << S.getTotalSamples();
  429. else
  430. OS << S.getName() << ":" << S.getTotalSamples();
  431. if (Indent == 0)
  432. OS << ":" << S.getHeadSamples();
  433. OS << "\n";
  434. SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
  435. for (const auto &I : SortedSamples.get()) {
  436. LineLocation Loc = I->first;
  437. const SampleRecord &Sample = I->second;
  438. OS.indent(Indent + 1);
  439. if (Loc.Discriminator == 0)
  440. OS << Loc.LineOffset << ": ";
  441. else
  442. OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
  443. OS << Sample.getSamples();
  444. for (const auto &J : Sample.getSortedCallTargets())
  445. OS << " " << J.first << ":" << J.second;
  446. OS << "\n";
  447. }
  448. SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
  449. S.getCallsiteSamples());
  450. Indent += 1;
  451. for (const auto &I : SortedCallsiteSamples.get())
  452. for (const auto &FS : I->second) {
  453. LineLocation Loc = I->first;
  454. const FunctionSamples &CalleeSamples = FS.second;
  455. OS.indent(Indent);
  456. if (Loc.Discriminator == 0)
  457. OS << Loc.LineOffset << ": ";
  458. else
  459. OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
  460. if (std::error_code EC = writeSample(CalleeSamples))
  461. return EC;
  462. }
  463. Indent -= 1;
  464. if (FunctionSamples::ProfileIsProbeBased) {
  465. OS.indent(Indent + 1);
  466. OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
  467. }
  468. if (S.getContext().getAllAttributes()) {
  469. OS.indent(Indent + 1);
  470. OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n";
  471. }
  472. return sampleprof_error::success;
  473. }
  474. std::error_code
  475. SampleProfileWriterBinary::writeContextIdx(const SampleContext &Context) {
  476. assert(!Context.hasContext() && "cs profile is not supported");
  477. return writeNameIdx(Context.getName());
  478. }
  479. std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
  480. auto &NTable = getNameTable();
  481. const auto &Ret = NTable.find(FName);
  482. if (Ret == NTable.end())
  483. return sampleprof_error::truncated_name_table;
  484. encodeULEB128(Ret->second, *OutputStream);
  485. return sampleprof_error::success;
  486. }
  487. void SampleProfileWriterBinary::addName(StringRef FName) {
  488. auto &NTable = getNameTable();
  489. NTable.insert(std::make_pair(FName, 0));
  490. }
  491. void SampleProfileWriterBinary::addContext(const SampleContext &Context) {
  492. addName(Context.getName());
  493. }
  494. void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
  495. // Add all the names in indirect call targets.
  496. for (const auto &I : S.getBodySamples()) {
  497. const SampleRecord &Sample = I.second;
  498. for (const auto &J : Sample.getCallTargets())
  499. addName(J.first());
  500. }
  501. // Recursively add all the names for inlined callsites.
  502. for (const auto &J : S.getCallsiteSamples())
  503. for (const auto &FS : J.second) {
  504. const FunctionSamples &CalleeSamples = FS.second;
  505. addName(CalleeSamples.getName());
  506. addNames(CalleeSamples);
  507. }
  508. }
  509. void SampleProfileWriterExtBinaryBase::addContext(
  510. const SampleContext &Context) {
  511. if (Context.hasContext()) {
  512. for (auto &Callsite : Context.getContextFrames())
  513. SampleProfileWriterBinary::addName(Callsite.FuncName);
  514. CSNameTable.insert(std::make_pair(Context, 0));
  515. } else {
  516. SampleProfileWriterBinary::addName(Context.getName());
  517. }
  518. }
  519. void SampleProfileWriterBinary::stablizeNameTable(
  520. MapVector<StringRef, uint32_t> &NameTable, std::set<StringRef> &V) {
  521. // Sort the names to make NameTable deterministic.
  522. for (const auto &I : NameTable)
  523. V.insert(I.first);
  524. int i = 0;
  525. for (const StringRef &N : V)
  526. NameTable[N] = i++;
  527. }
  528. std::error_code SampleProfileWriterBinary::writeNameTable() {
  529. auto &OS = *OutputStream;
  530. std::set<StringRef> V;
  531. stablizeNameTable(NameTable, V);
  532. // Write out the name table.
  533. encodeULEB128(NameTable.size(), OS);
  534. for (auto N : V) {
  535. OS << N;
  536. encodeULEB128(0, OS);
  537. }
  538. return sampleprof_error::success;
  539. }
  540. std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
  541. auto &OS = *OutputStream;
  542. // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
  543. auto &OFS = static_cast<raw_fd_ostream &>(OS);
  544. uint64_t FuncOffsetTableStart = OS.tell();
  545. if (OFS.seek(TableOffset) == (uint64_t)-1)
  546. return sampleprof_error::ostream_seek_unsupported;
  547. support::endian::Writer Writer(*OutputStream, support::little);
  548. Writer.write(FuncOffsetTableStart);
  549. if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
  550. return sampleprof_error::ostream_seek_unsupported;
  551. // Write out the table size.
  552. encodeULEB128(FuncOffsetTable.size(), OS);
  553. // Write out FuncOffsetTable.
  554. for (auto Entry : FuncOffsetTable) {
  555. if (std::error_code EC = writeNameIdx(Entry.first))
  556. return EC;
  557. encodeULEB128(Entry.second, OS);
  558. }
  559. return sampleprof_error::success;
  560. }
  561. std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
  562. auto &OS = *OutputStream;
  563. std::set<StringRef> V;
  564. stablizeNameTable(NameTable, V);
  565. // Write out the name table.
  566. encodeULEB128(NameTable.size(), OS);
  567. for (auto N : V) {
  568. encodeULEB128(MD5Hash(N), OS);
  569. }
  570. return sampleprof_error::success;
  571. }
  572. std::error_code
  573. SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
  574. auto &OS = *OutputStream;
  575. // Write file magic identifier.
  576. encodeULEB128(SPMagic(Format), OS);
  577. encodeULEB128(SPVersion(), OS);
  578. return sampleprof_error::success;
  579. }
  580. std::error_code
  581. SampleProfileWriterBinary::writeHeader(const SampleProfileMap &ProfileMap) {
  582. writeMagicIdent(Format);
  583. computeSummary(ProfileMap);
  584. if (auto EC = writeSummary())
  585. return EC;
  586. // Generate the name table for all the functions referenced in the profile.
  587. for (const auto &I : ProfileMap) {
  588. assert(I.first == I.second.getContext() && "Inconsistent profile map");
  589. addContext(I.first);
  590. addNames(I.second);
  591. }
  592. writeNameTable();
  593. return sampleprof_error::success;
  594. }
  595. void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
  596. for (auto &Entry : SectionHdrLayout)
  597. addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
  598. }
  599. void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
  600. addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
  601. }
  602. void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
  603. support::endian::Writer Writer(*OutputStream, support::little);
  604. Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
  605. SecHdrTableOffset = OutputStream->tell();
  606. for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
  607. Writer.write(static_cast<uint64_t>(-1));
  608. Writer.write(static_cast<uint64_t>(-1));
  609. Writer.write(static_cast<uint64_t>(-1));
  610. Writer.write(static_cast<uint64_t>(-1));
  611. }
  612. }
  613. std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
  614. auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
  615. uint64_t Saved = OutputStream->tell();
  616. // Set OutputStream to the location saved in SecHdrTableOffset.
  617. if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
  618. return sampleprof_error::ostream_seek_unsupported;
  619. support::endian::Writer Writer(*OutputStream, support::little);
  620. assert(SecHdrTable.size() == SectionHdrLayout.size() &&
  621. "SecHdrTable entries doesn't match SectionHdrLayout");
  622. SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
  623. for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
  624. IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
  625. }
  626. // Write the section header table in the order specified in
  627. // SectionHdrLayout. SectionHdrLayout specifies the sections
  628. // order in which profile reader expect to read, so the section
  629. // header table should be written in the order in SectionHdrLayout.
  630. // Note that the section order in SecHdrTable may be different
  631. // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
  632. // needs to be computed after SecLBRProfile (the order in SecHdrTable),
  633. // but it needs to be read before SecLBRProfile (the order in
  634. // SectionHdrLayout). So we use IndexMap above to switch the order.
  635. for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
  636. LayoutIdx++) {
  637. assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
  638. "Incorrect LayoutIdx in SecHdrTable");
  639. auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
  640. Writer.write(static_cast<uint64_t>(Entry.Type));
  641. Writer.write(static_cast<uint64_t>(Entry.Flags));
  642. Writer.write(static_cast<uint64_t>(Entry.Offset));
  643. Writer.write(static_cast<uint64_t>(Entry.Size));
  644. }
  645. // Reset OutputStream.
  646. if (OFS.seek(Saved) == (uint64_t)-1)
  647. return sampleprof_error::ostream_seek_unsupported;
  648. return sampleprof_error::success;
  649. }
  650. std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
  651. const SampleProfileMap &ProfileMap) {
  652. auto &OS = *OutputStream;
  653. FileStart = OS.tell();
  654. writeMagicIdent(Format);
  655. allocSecHdrTable();
  656. return sampleprof_error::success;
  657. }
  658. std::error_code SampleProfileWriterCompactBinary::writeHeader(
  659. const SampleProfileMap &ProfileMap) {
  660. support::endian::Writer Writer(*OutputStream, support::little);
  661. if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
  662. return EC;
  663. // Reserve a slot for the offset of function offset table. The slot will
  664. // be populated with the offset of FuncOffsetTable later.
  665. TableOffset = OutputStream->tell();
  666. Writer.write(static_cast<uint64_t>(-2));
  667. return sampleprof_error::success;
  668. }
  669. std::error_code SampleProfileWriterBinary::writeSummary() {
  670. auto &OS = *OutputStream;
  671. encodeULEB128(Summary->getTotalCount(), OS);
  672. encodeULEB128(Summary->getMaxCount(), OS);
  673. encodeULEB128(Summary->getMaxFunctionCount(), OS);
  674. encodeULEB128(Summary->getNumCounts(), OS);
  675. encodeULEB128(Summary->getNumFunctions(), OS);
  676. const std::vector<ProfileSummaryEntry> &Entries =
  677. Summary->getDetailedSummary();
  678. encodeULEB128(Entries.size(), OS);
  679. for (auto Entry : Entries) {
  680. encodeULEB128(Entry.Cutoff, OS);
  681. encodeULEB128(Entry.MinCount, OS);
  682. encodeULEB128(Entry.NumCounts, OS);
  683. }
  684. return sampleprof_error::success;
  685. }
  686. std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
  687. auto &OS = *OutputStream;
  688. if (std::error_code EC = writeContextIdx(S.getContext()))
  689. return EC;
  690. encodeULEB128(S.getTotalSamples(), OS);
  691. // Emit all the body samples.
  692. encodeULEB128(S.getBodySamples().size(), OS);
  693. for (const auto &I : S.getBodySamples()) {
  694. LineLocation Loc = I.first;
  695. const SampleRecord &Sample = I.second;
  696. encodeULEB128(Loc.LineOffset, OS);
  697. encodeULEB128(Loc.Discriminator, OS);
  698. encodeULEB128(Sample.getSamples(), OS);
  699. encodeULEB128(Sample.getCallTargets().size(), OS);
  700. for (const auto &J : Sample.getSortedCallTargets()) {
  701. StringRef Callee = J.first;
  702. uint64_t CalleeSamples = J.second;
  703. if (std::error_code EC = writeNameIdx(Callee))
  704. return EC;
  705. encodeULEB128(CalleeSamples, OS);
  706. }
  707. }
  708. // Recursively emit all the callsite samples.
  709. uint64_t NumCallsites = 0;
  710. for (const auto &J : S.getCallsiteSamples())
  711. NumCallsites += J.second.size();
  712. encodeULEB128(NumCallsites, OS);
  713. for (const auto &J : S.getCallsiteSamples())
  714. for (const auto &FS : J.second) {
  715. LineLocation Loc = J.first;
  716. const FunctionSamples &CalleeSamples = FS.second;
  717. encodeULEB128(Loc.LineOffset, OS);
  718. encodeULEB128(Loc.Discriminator, OS);
  719. if (std::error_code EC = writeBody(CalleeSamples))
  720. return EC;
  721. }
  722. return sampleprof_error::success;
  723. }
  724. /// Write samples of a top-level function to a binary file.
  725. ///
  726. /// \returns true if the samples were written successfully, false otherwise.
  727. std::error_code
  728. SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
  729. encodeULEB128(S.getHeadSamples(), *OutputStream);
  730. return writeBody(S);
  731. }
  732. std::error_code
  733. SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
  734. uint64_t Offset = OutputStream->tell();
  735. StringRef Name = S.getName();
  736. FuncOffsetTable[Name] = Offset;
  737. encodeULEB128(S.getHeadSamples(), *OutputStream);
  738. return writeBody(S);
  739. }
  740. /// Create a sample profile file writer based on the specified format.
  741. ///
  742. /// \param Filename The file to create.
  743. ///
  744. /// \param Format Encoding format for the profile file.
  745. ///
  746. /// \returns an error code indicating the status of the created writer.
  747. ErrorOr<std::unique_ptr<SampleProfileWriter>>
  748. SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
  749. std::error_code EC;
  750. std::unique_ptr<raw_ostream> OS;
  751. if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
  752. Format == SPF_Compact_Binary)
  753. OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
  754. else
  755. OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF));
  756. if (EC)
  757. return EC;
  758. return create(OS, Format);
  759. }
  760. /// Create a sample profile stream writer based on the specified format.
  761. ///
  762. /// \param OS The output stream to store the profile data to.
  763. ///
  764. /// \param Format Encoding format for the profile file.
  765. ///
  766. /// \returns an error code indicating the status of the created writer.
  767. ErrorOr<std::unique_ptr<SampleProfileWriter>>
  768. SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
  769. SampleProfileFormat Format) {
  770. std::error_code EC;
  771. std::unique_ptr<SampleProfileWriter> Writer;
  772. // Currently only Text and Extended Binary format are supported for CSSPGO.
  773. if ((FunctionSamples::ProfileIsCSFlat ||
  774. FunctionSamples::ProfileIsProbeBased) &&
  775. (Format == SPF_Binary || Format == SPF_Compact_Binary))
  776. return sampleprof_error::unsupported_writing_format;
  777. if (Format == SPF_Binary)
  778. Writer.reset(new SampleProfileWriterRawBinary(OS));
  779. else if (Format == SPF_Ext_Binary)
  780. Writer.reset(new SampleProfileWriterExtBinary(OS));
  781. else if (Format == SPF_Compact_Binary)
  782. Writer.reset(new SampleProfileWriterCompactBinary(OS));
  783. else if (Format == SPF_Text)
  784. Writer.reset(new SampleProfileWriterText(OS));
  785. else if (Format == SPF_GCC)
  786. EC = sampleprof_error::unsupported_writing_format;
  787. else
  788. EC = sampleprof_error::unrecognized_format;
  789. if (EC)
  790. return EC;
  791. Writer->Format = Format;
  792. return std::move(Writer);
  793. }
  794. void SampleProfileWriter::computeSummary(const SampleProfileMap &ProfileMap) {
  795. SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
  796. Summary = Builder.computeSummaryForProfiles(ProfileMap);
  797. }