SampleProfWriter.cpp 31 KB

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