SampleProfWriter.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  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 SampleProfileWriter::writeFuncProfiles(
  42. const StringMap<FunctionSamples> &ProfileMap) {
  43. // Sort the ProfileMap by total samples.
  44. typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
  45. std::vector<NameFunctionSamples> V;
  46. for (const auto &I : ProfileMap)
  47. V.push_back(std::make_pair(I.getKey(), &I.second));
  48. llvm::stable_sort(
  49. V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
  50. if (A.second->getTotalSamples() == B.second->getTotalSamples())
  51. return A.first > B.first;
  52. return A.second->getTotalSamples() > B.second->getTotalSamples();
  53. });
  54. for (const auto &I : V) {
  55. if (std::error_code EC = writeSample(*I.second))
  56. return EC;
  57. }
  58. return sampleprof_error::success;
  59. }
  60. std::error_code
  61. SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
  62. if (std::error_code EC = writeHeader(ProfileMap))
  63. return EC;
  64. if (std::error_code EC = writeFuncProfiles(ProfileMap))
  65. return EC;
  66. return sampleprof_error::success;
  67. }
  68. /// Return the current position and prepare to use it as the start
  69. /// position of a section given the section type \p Type and its position
  70. /// \p LayoutIdx in SectionHdrLayout.
  71. uint64_t
  72. SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type,
  73. uint32_t LayoutIdx) {
  74. uint64_t SectionStart = OutputStream->tell();
  75. assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
  76. const auto &Entry = SectionHdrLayout[LayoutIdx];
  77. assert(Entry.Type == Type && "Unexpected section type");
  78. // Use LocalBuf as a temporary output for writting data.
  79. if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
  80. LocalBufStream.swap(OutputStream);
  81. return SectionStart;
  82. }
  83. std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
  84. if (!llvm::zlib::isAvailable())
  85. return sampleprof_error::zlib_unavailable;
  86. std::string &UncompressedStrings =
  87. static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
  88. if (UncompressedStrings.size() == 0)
  89. return sampleprof_error::success;
  90. auto &OS = *OutputStream;
  91. SmallString<128> CompressedStrings;
  92. llvm::Error E = zlib::compress(UncompressedStrings, CompressedStrings,
  93. zlib::BestSizeCompression);
  94. if (E)
  95. return sampleprof_error::compress_failed;
  96. encodeULEB128(UncompressedStrings.size(), OS);
  97. encodeULEB128(CompressedStrings.size(), OS);
  98. OS << CompressedStrings.str();
  99. UncompressedStrings.clear();
  100. return sampleprof_error::success;
  101. }
  102. /// Add a new section into section header table given the section type
  103. /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the
  104. /// location \p SectionStart where the section should be written to.
  105. std::error_code SampleProfileWriterExtBinaryBase::addNewSection(
  106. SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) {
  107. assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
  108. const auto &Entry = SectionHdrLayout[LayoutIdx];
  109. assert(Entry.Type == Type && "Unexpected section type");
  110. if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) {
  111. LocalBufStream.swap(OutputStream);
  112. if (std::error_code EC = compressAndOutput())
  113. return EC;
  114. }
  115. SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
  116. OutputStream->tell() - SectionStart, LayoutIdx});
  117. return sampleprof_error::success;
  118. }
  119. std::error_code SampleProfileWriterExtBinaryBase::write(
  120. const StringMap<FunctionSamples> &ProfileMap) {
  121. if (std::error_code EC = writeHeader(ProfileMap))
  122. return EC;
  123. std::string LocalBuf;
  124. LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
  125. if (std::error_code EC = writeSections(ProfileMap))
  126. return EC;
  127. if (std::error_code EC = writeSecHdrTable())
  128. return EC;
  129. return sampleprof_error::success;
  130. }
  131. std::error_code
  132. SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) {
  133. uint64_t Offset = OutputStream->tell();
  134. StringRef Name = S.getNameWithContext(true);
  135. FuncOffsetTable[Name] = Offset - SecLBRProfileStart;
  136. encodeULEB128(S.getHeadSamples(), *OutputStream);
  137. return writeBody(S);
  138. }
  139. std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() {
  140. auto &OS = *OutputStream;
  141. // Write out the table size.
  142. encodeULEB128(FuncOffsetTable.size(), OS);
  143. // Write out FuncOffsetTable.
  144. for (auto entry : FuncOffsetTable) {
  145. writeNameIdx(entry.first);
  146. encodeULEB128(entry.second, OS);
  147. }
  148. FuncOffsetTable.clear();
  149. return sampleprof_error::success;
  150. }
  151. std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata(
  152. const StringMap<FunctionSamples> &Profiles) {
  153. if (!FunctionSamples::ProfileIsProbeBased)
  154. return sampleprof_error::success;
  155. auto &OS = *OutputStream;
  156. for (const auto &Entry : Profiles) {
  157. writeNameIdx(Entry.first());
  158. encodeULEB128(Entry.second.getFunctionHash(), OS);
  159. }
  160. return sampleprof_error::success;
  161. }
  162. std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() {
  163. if (!UseMD5)
  164. return SampleProfileWriterBinary::writeNameTable();
  165. auto &OS = *OutputStream;
  166. std::set<StringRef> V;
  167. stablizeNameTable(V);
  168. // Write out the MD5 name table. We wrote unencoded MD5 so reader can
  169. // retrieve the name using the name index without having to read the
  170. // whole name table.
  171. encodeULEB128(NameTable.size(), OS);
  172. support::endian::Writer Writer(OS, support::little);
  173. for (auto N : V)
  174. Writer.write(MD5Hash(N));
  175. return sampleprof_error::success;
  176. }
  177. std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection(
  178. const StringMap<FunctionSamples> &ProfileMap) {
  179. for (const auto &I : ProfileMap) {
  180. addName(I.first());
  181. addNames(I.second);
  182. }
  183. if (auto EC = writeNameTable())
  184. return EC;
  185. return sampleprof_error::success;
  186. }
  187. std::error_code
  188. SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() {
  189. if (ProfSymList && ProfSymList->size() > 0)
  190. if (std::error_code EC = ProfSymList->write(*OutputStream))
  191. return EC;
  192. return sampleprof_error::success;
  193. }
  194. std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
  195. SecType Type, uint32_t LayoutIdx,
  196. const StringMap<FunctionSamples> &ProfileMap) {
  197. // The setting of SecFlagCompress should happen before markSectionStart.
  198. if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress())
  199. setToCompressSection(SecProfileSymbolList);
  200. if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased)
  201. addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased);
  202. uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
  203. switch (Type) {
  204. case SecProfSummary:
  205. computeSummary(ProfileMap);
  206. if (auto EC = writeSummary())
  207. return EC;
  208. break;
  209. case SecNameTable:
  210. if (auto EC = writeNameTableSection(ProfileMap))
  211. return EC;
  212. break;
  213. case SecLBRProfile:
  214. SecLBRProfileStart = OutputStream->tell();
  215. if (std::error_code EC = writeFuncProfiles(ProfileMap))
  216. return EC;
  217. break;
  218. case SecFuncOffsetTable:
  219. if (auto EC = writeFuncOffsetTable())
  220. return EC;
  221. break;
  222. case SecFuncMetadata:
  223. if (std::error_code EC = writeFuncMetadata(ProfileMap))
  224. return EC;
  225. break;
  226. case SecProfileSymbolList:
  227. if (auto EC = writeProfileSymbolListSection())
  228. return EC;
  229. break;
  230. default:
  231. if (auto EC = writeCustomSection(Type))
  232. return EC;
  233. break;
  234. }
  235. if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart))
  236. return EC;
  237. return sampleprof_error::success;
  238. }
  239. std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
  240. const StringMap<FunctionSamples> &ProfileMap) {
  241. // The const indices passed to writeOneSection below are specifying the
  242. // positions of the sections in SectionHdrLayout. Look at
  243. // initSectionHdrLayout to find out where each section is located in
  244. // SectionHdrLayout.
  245. if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
  246. return EC;
  247. if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
  248. return EC;
  249. if (auto EC = writeOneSection(SecLBRProfile, 3, ProfileMap))
  250. return EC;
  251. if (auto EC = writeOneSection(SecProfileSymbolList, 4, ProfileMap))
  252. return EC;
  253. if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ProfileMap))
  254. return EC;
  255. if (auto EC = writeOneSection(SecFuncMetadata, 5, ProfileMap))
  256. return EC;
  257. return sampleprof_error::success;
  258. }
  259. static void
  260. splitProfileMapToTwo(const StringMap<FunctionSamples> &ProfileMap,
  261. StringMap<FunctionSamples> &ContextProfileMap,
  262. StringMap<FunctionSamples> &NoContextProfileMap) {
  263. for (const auto &I : ProfileMap) {
  264. if (I.second.getCallsiteSamples().size())
  265. ContextProfileMap.insert({I.first(), I.second});
  266. else
  267. NoContextProfileMap.insert({I.first(), I.second});
  268. }
  269. }
  270. std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
  271. const StringMap<FunctionSamples> &ProfileMap) {
  272. StringMap<FunctionSamples> ContextProfileMap, NoContextProfileMap;
  273. splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap);
  274. if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
  275. return EC;
  276. if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
  277. return EC;
  278. if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap))
  279. return EC;
  280. if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap))
  281. return EC;
  282. // Mark the section to have no context. Note section flag needs to be set
  283. // before writing the section.
  284. addSectionFlag(5, SecCommonFlags::SecFlagFlat);
  285. if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap))
  286. return EC;
  287. // Mark the section to have no context. Note section flag needs to be set
  288. // before writing the section.
  289. addSectionFlag(4, SecCommonFlags::SecFlagFlat);
  290. if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap))
  291. return EC;
  292. if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap))
  293. return EC;
  294. if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap))
  295. return EC;
  296. return sampleprof_error::success;
  297. }
  298. std::error_code SampleProfileWriterExtBinary::writeSections(
  299. const StringMap<FunctionSamples> &ProfileMap) {
  300. std::error_code EC;
  301. if (SecLayout == DefaultLayout)
  302. EC = writeDefaultLayout(ProfileMap);
  303. else if (SecLayout == CtxSplitLayout)
  304. EC = writeCtxSplitLayout(ProfileMap);
  305. else
  306. llvm_unreachable("Unsupported layout");
  307. return EC;
  308. }
  309. std::error_code SampleProfileWriterCompactBinary::write(
  310. const StringMap<FunctionSamples> &ProfileMap) {
  311. if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
  312. return EC;
  313. if (std::error_code EC = writeFuncOffsetTable())
  314. return EC;
  315. return sampleprof_error::success;
  316. }
  317. /// Write samples to a text file.
  318. ///
  319. /// Note: it may be tempting to implement this in terms of
  320. /// FunctionSamples::print(). Please don't. The dump functionality is intended
  321. /// for debugging and has no specified form.
  322. ///
  323. /// The format used here is more structured and deliberate because
  324. /// it needs to be parsed by the SampleProfileReaderText class.
  325. std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
  326. auto &OS = *OutputStream;
  327. OS << S.getNameWithContext(true) << ":" << S.getTotalSamples();
  328. if (Indent == 0)
  329. OS << ":" << S.getHeadSamples();
  330. OS << "\n";
  331. SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
  332. for (const auto &I : SortedSamples.get()) {
  333. LineLocation Loc = I->first;
  334. const SampleRecord &Sample = I->second;
  335. OS.indent(Indent + 1);
  336. if (Loc.Discriminator == 0)
  337. OS << Loc.LineOffset << ": ";
  338. else
  339. OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
  340. OS << Sample.getSamples();
  341. for (const auto &J : Sample.getSortedCallTargets())
  342. OS << " " << J.first << ":" << J.second;
  343. OS << "\n";
  344. }
  345. SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
  346. S.getCallsiteSamples());
  347. Indent += 1;
  348. for (const auto &I : SortedCallsiteSamples.get())
  349. for (const auto &FS : I->second) {
  350. LineLocation Loc = I->first;
  351. const FunctionSamples &CalleeSamples = FS.second;
  352. OS.indent(Indent);
  353. if (Loc.Discriminator == 0)
  354. OS << Loc.LineOffset << ": ";
  355. else
  356. OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
  357. if (std::error_code EC = writeSample(CalleeSamples))
  358. return EC;
  359. }
  360. Indent -= 1;
  361. if (Indent == 0) {
  362. if (FunctionSamples::ProfileIsProbeBased) {
  363. OS.indent(Indent + 1);
  364. OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
  365. }
  366. }
  367. return sampleprof_error::success;
  368. }
  369. std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
  370. const auto &ret = NameTable.find(FName);
  371. if (ret == NameTable.end())
  372. return sampleprof_error::truncated_name_table;
  373. encodeULEB128(ret->second, *OutputStream);
  374. return sampleprof_error::success;
  375. }
  376. void SampleProfileWriterBinary::addName(StringRef FName) {
  377. NameTable.insert(std::make_pair(FName, 0));
  378. }
  379. void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
  380. // Add all the names in indirect call targets.
  381. for (const auto &I : S.getBodySamples()) {
  382. const SampleRecord &Sample = I.second;
  383. for (const auto &J : Sample.getCallTargets())
  384. addName(J.first());
  385. }
  386. // Recursively add all the names for inlined callsites.
  387. for (const auto &J : S.getCallsiteSamples())
  388. for (const auto &FS : J.second) {
  389. const FunctionSamples &CalleeSamples = FS.second;
  390. addName(CalleeSamples.getName());
  391. addNames(CalleeSamples);
  392. }
  393. }
  394. void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
  395. // Sort the names to make NameTable deterministic.
  396. for (const auto &I : NameTable)
  397. V.insert(I.first);
  398. int i = 0;
  399. for (const StringRef &N : V)
  400. NameTable[N] = i++;
  401. }
  402. std::error_code SampleProfileWriterBinary::writeNameTable() {
  403. auto &OS = *OutputStream;
  404. std::set<StringRef> V;
  405. stablizeNameTable(V);
  406. // Write out the name table.
  407. encodeULEB128(NameTable.size(), OS);
  408. for (auto N : V) {
  409. OS << N;
  410. encodeULEB128(0, OS);
  411. }
  412. return sampleprof_error::success;
  413. }
  414. std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
  415. auto &OS = *OutputStream;
  416. // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
  417. auto &OFS = static_cast<raw_fd_ostream &>(OS);
  418. uint64_t FuncOffsetTableStart = OS.tell();
  419. if (OFS.seek(TableOffset) == (uint64_t)-1)
  420. return sampleprof_error::ostream_seek_unsupported;
  421. support::endian::Writer Writer(*OutputStream, support::little);
  422. Writer.write(FuncOffsetTableStart);
  423. if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
  424. return sampleprof_error::ostream_seek_unsupported;
  425. // Write out the table size.
  426. encodeULEB128(FuncOffsetTable.size(), OS);
  427. // Write out FuncOffsetTable.
  428. for (auto entry : FuncOffsetTable) {
  429. writeNameIdx(entry.first);
  430. encodeULEB128(entry.second, OS);
  431. }
  432. return sampleprof_error::success;
  433. }
  434. std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
  435. auto &OS = *OutputStream;
  436. std::set<StringRef> V;
  437. stablizeNameTable(V);
  438. // Write out the name table.
  439. encodeULEB128(NameTable.size(), OS);
  440. for (auto N : V) {
  441. encodeULEB128(MD5Hash(N), OS);
  442. }
  443. return sampleprof_error::success;
  444. }
  445. std::error_code
  446. SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
  447. auto &OS = *OutputStream;
  448. // Write file magic identifier.
  449. encodeULEB128(SPMagic(Format), OS);
  450. encodeULEB128(SPVersion(), OS);
  451. return sampleprof_error::success;
  452. }
  453. std::error_code SampleProfileWriterBinary::writeHeader(
  454. const StringMap<FunctionSamples> &ProfileMap) {
  455. writeMagicIdent(Format);
  456. computeSummary(ProfileMap);
  457. if (auto EC = writeSummary())
  458. return EC;
  459. // Generate the name table for all the functions referenced in the profile.
  460. for (const auto &I : ProfileMap) {
  461. addName(I.first());
  462. addNames(I.second);
  463. }
  464. writeNameTable();
  465. return sampleprof_error::success;
  466. }
  467. void SampleProfileWriterExtBinaryBase::setToCompressAllSections() {
  468. for (auto &Entry : SectionHdrLayout)
  469. addSecFlag(Entry, SecCommonFlags::SecFlagCompress);
  470. }
  471. void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) {
  472. addSectionFlag(Type, SecCommonFlags::SecFlagCompress);
  473. }
  474. void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
  475. support::endian::Writer Writer(*OutputStream, support::little);
  476. Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
  477. SecHdrTableOffset = OutputStream->tell();
  478. for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
  479. Writer.write(static_cast<uint64_t>(-1));
  480. Writer.write(static_cast<uint64_t>(-1));
  481. Writer.write(static_cast<uint64_t>(-1));
  482. Writer.write(static_cast<uint64_t>(-1));
  483. }
  484. }
  485. std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
  486. auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
  487. uint64_t Saved = OutputStream->tell();
  488. // Set OutputStream to the location saved in SecHdrTableOffset.
  489. if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
  490. return sampleprof_error::ostream_seek_unsupported;
  491. support::endian::Writer Writer(*OutputStream, support::little);
  492. assert(SecHdrTable.size() == SectionHdrLayout.size() &&
  493. "SecHdrTable entries doesn't match SectionHdrLayout");
  494. SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
  495. for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
  496. IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
  497. }
  498. // Write the section header table in the order specified in
  499. // SectionHdrLayout. SectionHdrLayout specifies the sections
  500. // order in which profile reader expect to read, so the section
  501. // header table should be written in the order in SectionHdrLayout.
  502. // Note that the section order in SecHdrTable may be different
  503. // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
  504. // needs to be computed after SecLBRProfile (the order in SecHdrTable),
  505. // but it needs to be read before SecLBRProfile (the order in
  506. // SectionHdrLayout). So we use IndexMap above to switch the order.
  507. for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
  508. LayoutIdx++) {
  509. assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
  510. "Incorrect LayoutIdx in SecHdrTable");
  511. auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
  512. Writer.write(static_cast<uint64_t>(Entry.Type));
  513. Writer.write(static_cast<uint64_t>(Entry.Flags));
  514. Writer.write(static_cast<uint64_t>(Entry.Offset));
  515. Writer.write(static_cast<uint64_t>(Entry.Size));
  516. }
  517. // Reset OutputStream.
  518. if (OFS.seek(Saved) == (uint64_t)-1)
  519. return sampleprof_error::ostream_seek_unsupported;
  520. return sampleprof_error::success;
  521. }
  522. std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
  523. const StringMap<FunctionSamples> &ProfileMap) {
  524. auto &OS = *OutputStream;
  525. FileStart = OS.tell();
  526. writeMagicIdent(Format);
  527. allocSecHdrTable();
  528. return sampleprof_error::success;
  529. }
  530. std::error_code SampleProfileWriterCompactBinary::writeHeader(
  531. const StringMap<FunctionSamples> &ProfileMap) {
  532. support::endian::Writer Writer(*OutputStream, support::little);
  533. if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
  534. return EC;
  535. // Reserve a slot for the offset of function offset table. The slot will
  536. // be populated with the offset of FuncOffsetTable later.
  537. TableOffset = OutputStream->tell();
  538. Writer.write(static_cast<uint64_t>(-2));
  539. return sampleprof_error::success;
  540. }
  541. std::error_code SampleProfileWriterBinary::writeSummary() {
  542. auto &OS = *OutputStream;
  543. encodeULEB128(Summary->getTotalCount(), OS);
  544. encodeULEB128(Summary->getMaxCount(), OS);
  545. encodeULEB128(Summary->getMaxFunctionCount(), OS);
  546. encodeULEB128(Summary->getNumCounts(), OS);
  547. encodeULEB128(Summary->getNumFunctions(), OS);
  548. std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
  549. encodeULEB128(Entries.size(), OS);
  550. for (auto Entry : Entries) {
  551. encodeULEB128(Entry.Cutoff, OS);
  552. encodeULEB128(Entry.MinCount, OS);
  553. encodeULEB128(Entry.NumCounts, OS);
  554. }
  555. return sampleprof_error::success;
  556. }
  557. std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
  558. auto &OS = *OutputStream;
  559. if (std::error_code EC = writeNameIdx(S.getNameWithContext(true)))
  560. return EC;
  561. encodeULEB128(S.getTotalSamples(), OS);
  562. // Emit all the body samples.
  563. encodeULEB128(S.getBodySamples().size(), OS);
  564. for (const auto &I : S.getBodySamples()) {
  565. LineLocation Loc = I.first;
  566. const SampleRecord &Sample = I.second;
  567. encodeULEB128(Loc.LineOffset, OS);
  568. encodeULEB128(Loc.Discriminator, OS);
  569. encodeULEB128(Sample.getSamples(), OS);
  570. encodeULEB128(Sample.getCallTargets().size(), OS);
  571. for (const auto &J : Sample.getSortedCallTargets()) {
  572. StringRef Callee = J.first;
  573. uint64_t CalleeSamples = J.second;
  574. if (std::error_code EC = writeNameIdx(Callee))
  575. return EC;
  576. encodeULEB128(CalleeSamples, OS);
  577. }
  578. }
  579. // Recursively emit all the callsite samples.
  580. uint64_t NumCallsites = 0;
  581. for (const auto &J : S.getCallsiteSamples())
  582. NumCallsites += J.second.size();
  583. encodeULEB128(NumCallsites, OS);
  584. for (const auto &J : S.getCallsiteSamples())
  585. for (const auto &FS : J.second) {
  586. LineLocation Loc = J.first;
  587. const FunctionSamples &CalleeSamples = FS.second;
  588. encodeULEB128(Loc.LineOffset, OS);
  589. encodeULEB128(Loc.Discriminator, OS);
  590. if (std::error_code EC = writeBody(CalleeSamples))
  591. return EC;
  592. }
  593. return sampleprof_error::success;
  594. }
  595. /// Write samples of a top-level function to a binary file.
  596. ///
  597. /// \returns true if the samples were written successfully, false otherwise.
  598. std::error_code
  599. SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
  600. encodeULEB128(S.getHeadSamples(), *OutputStream);
  601. return writeBody(S);
  602. }
  603. std::error_code
  604. SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
  605. uint64_t Offset = OutputStream->tell();
  606. StringRef Name = S.getName();
  607. FuncOffsetTable[Name] = Offset;
  608. encodeULEB128(S.getHeadSamples(), *OutputStream);
  609. return writeBody(S);
  610. }
  611. /// Create a sample profile file writer based on the specified format.
  612. ///
  613. /// \param Filename The file to create.
  614. ///
  615. /// \param Format Encoding format for the profile file.
  616. ///
  617. /// \returns an error code indicating the status of the created writer.
  618. ErrorOr<std::unique_ptr<SampleProfileWriter>>
  619. SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
  620. std::error_code EC;
  621. std::unique_ptr<raw_ostream> OS;
  622. if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
  623. Format == SPF_Compact_Binary)
  624. OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
  625. else
  626. OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text));
  627. if (EC)
  628. return EC;
  629. return create(OS, Format);
  630. }
  631. /// Create a sample profile stream writer based on the specified format.
  632. ///
  633. /// \param OS The output stream to store the profile data to.
  634. ///
  635. /// \param Format Encoding format for the profile file.
  636. ///
  637. /// \returns an error code indicating the status of the created writer.
  638. ErrorOr<std::unique_ptr<SampleProfileWriter>>
  639. SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
  640. SampleProfileFormat Format) {
  641. std::error_code EC;
  642. std::unique_ptr<SampleProfileWriter> Writer;
  643. if (Format == SPF_Binary)
  644. Writer.reset(new SampleProfileWriterRawBinary(OS));
  645. else if (Format == SPF_Ext_Binary)
  646. Writer.reset(new SampleProfileWriterExtBinary(OS));
  647. else if (Format == SPF_Compact_Binary)
  648. Writer.reset(new SampleProfileWriterCompactBinary(OS));
  649. else if (Format == SPF_Text)
  650. Writer.reset(new SampleProfileWriterText(OS));
  651. else if (Format == SPF_GCC)
  652. EC = sampleprof_error::unsupported_writing_format;
  653. else
  654. EC = sampleprof_error::unrecognized_format;
  655. if (EC)
  656. return EC;
  657. Writer->Format = Format;
  658. return std::move(Writer);
  659. }
  660. void SampleProfileWriter::computeSummary(
  661. const StringMap<FunctionSamples> &ProfileMap) {
  662. SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
  663. Summary = Builder.computeSummaryForProfiles(ProfileMap);
  664. }