LLVM 24.0.0git
SampleProfWriter.cpp
Go to the documentation of this file.
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
21#include "llvm/ADT/Eytzinger.h"
22#include "llvm/ADT/StringRef.h"
29#include "llvm/Support/LEB128.h"
30#include "llvm/Support/MD5.h"
33#include <array>
34#include <cmath>
35#include <cstdint>
36#include <memory>
37#include <system_error>
38#include <utility>
39#include <vector>
40
41#define DEBUG_TYPE "llvm-profdata"
42
43using namespace llvm;
44using namespace sampleprof;
45
46// To begin with, make this option off by default.
48 "extbinary-write-vtable-type-prof", cl::init(false), cl::Hidden,
49 cl::desc("Write vtable type profile in ext-binary sample profile writer"));
50
52 "sample-profile-format-version", cl::init(DefaultVersion), cl::Hidden,
53 cl::desc("Format version to write for extensible binary profiles"));
54
55static cl::opt<bool>
56 ExtBinaryCompositeProf("extbinary-composite-prof", cl::init(false),
58 cl::desc("Use the composite profile format"));
59
60namespace llvm {
61namespace support {
62namespace endian {
63namespace {
64
65// Adapter class to llvm::support::endian::Writer for pwrite().
66struct SeekableWriter {
68 endianness Endian;
69 SeekableWriter(raw_pwrite_stream &OS, endianness Endian)
70 : OS(OS), Endian(Endian) {}
71
72 template <typename ValueType> void pwrite(ValueType Val, size_t Offset) {
73 std::string StringBuf;
74 raw_string_ostream SStream(StringBuf);
75 Writer(SStream, Endian).write(Val);
76 OS.pwrite(StringBuf.data(), StringBuf.size(), Offset);
77 }
78};
79
80} // namespace
81} // namespace endian
82} // namespace support
83} // namespace llvm
84
90
91void DefaultFunctionPruningStrategy::Erase(size_t CurrentOutputSize) {
92 double D = (double)OutputSizeLimit / CurrentOutputSize;
93 size_t NewSize = (size_t)round(ProfileMap.size() * D * D);
94 size_t NumToRemove = ProfileMap.size() - NewSize;
95 if (NumToRemove < 1)
96 NumToRemove = 1;
97
98 assert(NumToRemove <= SortedFunctions.size());
99 for (const NameFunctionSamples &E :
100 llvm::drop_begin(SortedFunctions, SortedFunctions.size() - NumToRemove))
101 ProfileMap.erase(E.first);
102 SortedFunctions.resize(SortedFunctions.size() - NumToRemove);
103}
104
106 SampleProfileMap &ProfileMap, size_t OutputSizeLimit,
107 FunctionPruningStrategy *Strategy) {
108 if (OutputSizeLimit == 0)
109 return write(ProfileMap);
110
111 size_t OriginalFunctionCount = ProfileMap.size();
112
113 std::unique_ptr<raw_ostream> OriginalOutputStream;
114 OutputStream.swap(OriginalOutputStream);
115
116 size_t IterationCount = 0;
117 size_t TotalSize;
118
119 SmallVector<char> StringBuffer;
120 do {
121 StringBuffer.clear();
122 OutputStream.reset(new raw_svector_ostream(StringBuffer));
123 if (std::error_code EC = write(ProfileMap))
124 return EC;
125
126 TotalSize = StringBuffer.size();
127 // On Windows every "\n" is actually written as "\r\n" to disk but not to
128 // memory buffer, this difference should be added when considering the total
129 // output size.
130#ifdef _WIN32
131 if (Format == SPF_Text)
132 TotalSize += LineCount;
133#endif
134 if (TotalSize <= OutputSizeLimit)
135 break;
136
137 Strategy->Erase(TotalSize);
138 IterationCount++;
139 } while (ProfileMap.size() != 0);
140
141 if (ProfileMap.size() == 0)
143
144 OutputStream.swap(OriginalOutputStream);
145 OutputStream->write(StringBuffer.data(), StringBuffer.size());
146 LLVM_DEBUG(dbgs() << "Profile originally has " << OriginalFunctionCount
147 << " functions, reduced to " << ProfileMap.size() << " in "
148 << IterationCount << " iterations\n");
149 // Silence warning on Release build.
150 (void)OriginalFunctionCount;
151 (void)IterationCount;
153}
154
155std::error_code
157 std::vector<NameFunctionSamples> V;
158 sortFuncProfiles(ProfileMap, V);
159 for (const auto &I : V) {
160 if (std::error_code EC = writeSample(*I.second))
161 return EC;
162 }
164}
165
166std::error_code SampleProfileWriter::write(const SampleProfileMap &ProfileMap) {
167 if (std::error_code EC = writeHeader(ProfileMap))
168 return EC;
169
170 if (std::error_code EC = writeFuncProfiles(ProfileMap))
171 return EC;
172
174}
175
176/// Return the current position and prepare to use it as the start
177/// position of a section given the section type \p Type and its position
178/// \p LayoutIdx in SectionHdrLayout.
179uint64_t
181 uint32_t LayoutIdx) {
182 uint64_t SectionStart = OutputStream->tell();
183 assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
184 const auto &Entry = SectionHdrLayout[LayoutIdx];
185 assert(Entry.Type == Type && "Unexpected section type");
186 // Use LocalBuf as a temporary output for writing data.
188 LocalBufStream.swap(OutputStream);
189 return SectionStart;
190}
191
192std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
195 std::string &UncompressedStrings =
196 static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
197 if (UncompressedStrings.empty())
199 auto &OS = *OutputStream;
200 SmallVector<uint8_t, 128> CompressedStrings;
202 CompressedStrings,
204 encodeULEB128(UncompressedStrings.size(), OS);
205 encodeULEB128(CompressedStrings.size(), OS);
206 OS << toStringRef(CompressedStrings);
207 UncompressedStrings.clear();
209}
210
211/// Add a new section into section header table given the section type
212/// \p Type, its position \p LayoutIdx in SectionHdrLayout and the
213/// location \p SectionStart where the section should be written to.
215 SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) {
216 assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
217 const auto &Entry = SectionHdrLayout[LayoutIdx];
218 assert(Entry.Type == Type && "Unexpected section type");
220 LocalBufStream.swap(OutputStream);
221 if (std::error_code EC = compressAndOutput())
222 return EC;
223 }
224 SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
225 OutputStream->tell() - SectionStart, LayoutIdx});
227}
228
229std::error_code
231 // When calling write on a different profile map, existing states should be
232 // cleared.
233 NameTable.clear();
234 CSNameTable.clear();
235 SecHdrTable.clear();
236
237 if (std::error_code EC = writeHeader(ProfileMap))
238 return EC;
239
240 std::string LocalBuf;
241 LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
242 if (std::error_code EC = writeSections(ProfileMap))
243 return EC;
244
245 if (std::error_code EC = writeSecHdrTable())
246 return EC;
247
249}
250
252 const SampleContext &Context) {
253 if (Context.hasContext())
254 return writeCSNameIdx(Context);
255 else
256 return SampleProfileWriterBinary::writeNameIdx(Context.getFunction());
257}
258
259std::error_code
261 const auto &Ret = CSNameTable.find(Context);
262 if (Ret == CSNameTable.end())
264 encodeULEB128(Ret->second, *OutputStream);
266}
267
268std::error_code
270 uint64_t Offset = OutputStream->tell();
271 auto &Context = S.getContext();
272 FuncOffsetTable[Context] = Offset - SecLBRProfileStart;
275 return writeBody(S, /*IsNested=*/false);
276}
277
278std::error_code
280 bool IsNested) {
281 if (UseMD5IndexedTables) {
282 // Eytzinger layout requires MD5 representation and does not support
283 // multi-context Context-Sensitive profiles.
284 if (!UseMD5 || FunctionSamples::ProfileIsCS)
286 return writeEytzingerFuncOffsetTable(Type, IsNested);
287 }
289}
290
291std::error_code
293 bool IsNested) {
294 assert((NumNested + NumFlat > 0 || FuncOffsetTable.empty()) &&
295 "SecNameTable must be written before SecFuncOffsetTable to establish "
296 "Eytzinger indices!");
297
298 size_t SpanSize = IsNested ? NumNested : NumFlat;
299 size_t BaseIdx = IsNested ? 0 : NumNested;
300
301 std::vector<support::ulittle32_t> FuncOffsets(
302 SpanSize, support::ulittle32_t(UINT32_MAX));
303
304 // Populate the function offset array parallel to the Eytzinger span.
305 for (const auto &[Context, RelativeOffset] : FuncOffsetTable) {
306 if (RelativeOffset >= UINT32_MAX)
308
309 FunctionId FId = Context.getFunction();
310 auto It = NameTable.find(FId);
311 if (It == NameTable.end())
312 continue;
313
314 size_t GlobalIdx = It->second;
315 if (GlobalIdx < BaseIdx || (GlobalIdx - BaseIdx) >= SpanSize)
316 continue;
317
318 size_t LocalIdx = GlobalIdx - BaseIdx;
319 assert(
320 FuncOffsets[LocalIdx] == UINT32_MAX &&
321 "Function offset slot already populated; duplicate GUID or collision!");
322 FuncOffsets[LocalIdx] = static_cast<uint32_t>(RelativeOffset);
323 }
324
325 assert(!llvm::is_contained(FuncOffsets, support::ulittle32_t(UINT32_MAX)) &&
326 "Unpopulated slot in Eytzinger function offset array!");
327
328 OutputStream->write(reinterpret_cast<const char *>(FuncOffsets.data()),
329 SpanSize * sizeof(support::ulittle32_t));
330 // Type is SecFuncOffsetTable or SecCompositeFuncOffsetTable.
332 FuncOffsetTable.clear();
334}
335
336std::error_code
338 auto &OS = *OutputStream;
339
340 // Write out the table size.
341 encodeULEB128(FuncOffsetTable.size(), OS);
342
343 // Write out FuncOffsetTable.
344 auto WriteItem = [&](const SampleContext &Context, uint64_t Offset) {
345 if (std::error_code EC = writeContextIdx(Context))
346 return EC;
348 return (std::error_code)sampleprof_error::success;
349 };
350
352 // Sort the contexts before writing them out. This is to help fast load all
353 // context profiles for a function as well as their callee contexts which
354 // can help profile-guided importing for ThinLTO.
355 std::map<SampleContext, uint64_t> OrderedFuncOffsetTable(
356 FuncOffsetTable.begin(), FuncOffsetTable.end());
357 for (const auto &Entry : OrderedFuncOffsetTable) {
358 if (std::error_code EC = WriteItem(Entry.first, Entry.second))
359 return EC;
360 }
362 } else {
363 for (const auto &Entry : FuncOffsetTable) {
364 if (std::error_code EC = WriteItem(Entry.first, Entry.second))
365 return EC;
366 }
367 }
368
369 FuncOffsetTable.clear();
371}
372
374 const FunctionSamples &FunctionProfile) {
375 auto &OS = *OutputStream;
376 if (std::error_code EC = writeContextIdx(FunctionProfile.getContext()))
377 return EC;
378
380 encodeULEB128(FunctionProfile.getFunctionHash(), OS);
382 encodeULEB128(FunctionProfile.getContext().getAllAttributes(), OS);
383 }
384
386 // Recursively emit attributes for all callee samples.
387 uint64_t NumCallsites = 0;
388 for (const auto &J : FunctionProfile.getCallsiteSamples())
389 NumCallsites += J.second.size();
390 encodeULEB128(NumCallsites, OS);
391 for (const auto &J : FunctionProfile.getCallsiteSamples()) {
392 for (const auto &FS : J.second) {
393 LineLocation Loc = J.first;
394 encodeULEB128(Loc.LineOffset, OS);
395 encodeULEB128(Loc.Discriminator, OS);
396 if (std::error_code EC = writeFuncMetadata(FS.second))
397 return EC;
398 }
399 }
400 }
401
403}
404
406 const SampleProfileMap &Profiles) {
410 for (const auto &Entry : Profiles) {
411 if (std::error_code EC = writeFuncMetadata(Entry.second))
412 return EC;
413 }
415}
416
417template <class KeyT, class ValT>
422
423 llvm::sort(Entries,
424 [](const auto *L, const auto *R) { return L->first < R->first; });
425
426 for (const auto &[I, Entry] : llvm::enumerate(Entries))
427 Entry->second = I;
428
429 return Entries;
430}
431
433 if (!UseMD5)
435
436 auto &OS = *OutputStream;
437
438 // Write out the MD5 name table. We wrote unencoded MD5 so reader can
439 // retrieve the name using the name index without having to read the
440 // whole name table.
441 encodeULEB128(NameTable.size(), OS);
443 for (const auto *Entry : stabilizeTable(NameTable))
444 Writer.write(Entry->first.getHashCode());
446}
447
449 const SampleProfileMap &ProfileMap) {
450 for (const auto &I : ProfileMap) {
451 addContext(I.second.getContext());
452 addNames(I.second);
453 }
454
455 // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag
456 // so compiler won't strip the suffix during profile matching after
457 // seeing the flag in the profile.
458 // Original names are unavailable if using MD5, so this option has no use.
459 if (!UseMD5) {
460 for (const auto &I : NameTable) {
461 if (I.first.stringRef().contains(FunctionSamples::UniqSuffix)) {
463 break;
464 }
465 }
466 }
467
468 if (UseMD5 && UseMD5IndexedTables) {
469 // Eytzinger name tables do not support CSSPGO profiles
470 // (FunctionSamples::ProfileIsCS).
473 if (auto EC = writeEytzingerNameTableSection(ProfileMap))
474 return EC;
476 }
477
478 if (auto EC = writeNameTable())
479 return EC;
481}
482
483namespace {
484
485// Helper class to construct and write the SecNameTable section in Eytzinger
486// layout for ExtBinary MD5 profiles.
487//
488// The on-disk layout of the Eytzinger name table section consists of symbol
489// counts followed by three contiguous Eytzinger hash arrays:
490// - ULEB128 count of Nested top-level profile symbol keys
491// - ULEB128 count of Flat top-level profile symbol keys
492// - ULEB128 count of Inlinee and auxiliary profile symbol keys
493// - Array of 64-bit little-endian MD5 hash keys for Nested profiles in
494// Eytzinger order
495// - Array of 64-bit little-endian MD5 hash keys for Flat profiles in Eytzinger
496// order
497// - Array of 64-bit little-endian MD5 hash keys for Inlinees in Eytzinger order
498class EytzingerNameTable {
500 std::array<TableT, static_cast<size_t>(EytzingerSpan::NumSpans)> Spans;
501
502public:
503 EytzingerNameTable(std::vector<support::ulittle64_t> NestedKeys,
504 std::vector<support::ulittle64_t> FlatKeys,
505 std::vector<support::ulittle64_t> InlineeKeys)
506 : Spans{TableT::create(std::move(NestedKeys)),
507 TableT::create(std::move(FlatKeys)),
508 TableT::create(std::move(InlineeKeys))} {}
509
510 // Find the global index of GUID across the three Eytzinger table spans.
511 uint64_t findGlobalIdx(uint64_t GUID) const {
512 uint64_t BaseIdx = 0;
513 for (const auto &Table : Spans) {
514 if (std::optional<size_t> LocalIdx = Table.findIndex(GUID))
515 return BaseIdx + *LocalIdx;
516 BaseIdx += Table.size();
517 }
518 llvm_unreachable("Symbol in NameTable missing from Eytzinger spans");
519 }
520
521 void write(raw_ostream &OS) const {
522 for (const auto &Table : Spans)
523 encodeULEB128(uint64_t(Table.size()), OS);
524 for (const auto &Table : Spans)
525 OS.write(reinterpret_cast<const char *>(Table.data()),
526 Table.size() * sizeof(support::ulittle64_t));
527 }
528
529 size_t size(EytzingerSpan S) const {
530 return Spans[static_cast<size_t>(S)].size();
531 }
532};
533
534} // end anonymous namespace
535
536std::error_code
538 const SampleProfileMap &ProfileMap) {
539 DenseSet<uint64_t> TopLevelGUIDs;
540 std::vector<support::ulittle64_t> NestedKeys, FlatKeys, InlineeKeys;
541
542 // Collect top-level Nested and Flat keys directly from ProfileMap.
543 for (const auto &I : ProfileMap) {
544 const SampleContext &Ctx = I.second.getContext();
545 uint64_t GUID = Ctx.getFunction().getHashCode();
546 if (TopLevelGUIDs.insert(GUID).second) {
547 // In single-table default layouts, unify all top-level symbols in the
548 // Nested partition so they match the single unflagged function offset
549 // table.
550 if (SecLayout != CtxSplitLayout || I.second.hasCallsiteSamples())
551 NestedKeys.emplace_back(GUID);
552 else
553 FlatKeys.emplace_back(GUID);
554 }
555 }
556
557 // Collect remaining non-top-level symbols (inlinees, targets, vtables) from
558 // NameTable.
559 for (const auto &Entry : NameTable) {
560 uint64_t GUID = Entry.first.getHashCode();
561 if (!TopLevelGUIDs.contains(GUID))
562 InlineeKeys.emplace_back(GUID);
563 }
564
565 EytzingerNameTable Tables(std::move(NestedKeys), std::move(FlatKeys),
566 std::move(InlineeKeys));
567
568 // Assign each symbol its corresponding index in the Eytzinger layout.
569 for (auto &[FId, Idx] : NameTable)
570 Idx = Tables.findGlobalIdx(FId.getHashCode());
571
572 Tables.write(*OutputStream);
573 NumNested = Tables.size(EytzingerSpan::Nested);
574 NumFlat = Tables.size(EytzingerSpan::Flat);
575
577}
578
580 auto &OS = *OutputStream;
581 encodeULEB128(CSNameTable.size(), OS);
583 for (const auto *Entry : stabilizeTable(CSNameTable)) {
584 auto Frames = Entry->first.getContextFrames();
585 encodeULEB128(Frames.size(), OS);
586 for (auto &Callsite : Frames) {
587 if (std::error_code EC = writeNameIdx(Callsite.Func))
588 return EC;
589 encodeULEB128(Callsite.Location.LineOffset, OS);
590 encodeULEB128(Callsite.Location.Discriminator, OS);
591 }
592 }
593
595}
596
597std::error_code
603
604std::error_code
606 assert((!ProfSymList || !ProfSymList->isMD5()) &&
607 "Writing string-based ProfileSymbolListSection from MD5 table "
608 "not yet implemented");
609 if (ProfSymList && ProfSymList->size() > 0)
610 if (std::error_code EC = ProfSymList->write(*OutputStream))
611 return EC;
612
614}
615
616std::error_code
618 if (!ProfSymList || ProfSymList->size() == 0)
620 assert(!ProfSymList->isMD5() &&
621 "Writing MD5 ProfileSymbolListSection from existing MD5 "
622 "table not yet implemented");
623
624 auto &OS = *OutputStream;
625 std::vector<uint64_t> Keys = ProfSymList->collectGUIDs();
626
627 auto Table =
629
630 OS.write(reinterpret_cast<const char *>(Table.data()),
631 Table.size() * sizeof(support::ulittle64_t));
633}
634
636 auto WrittenIndices =
638 for (auto [I, Entry] : llvm::enumerate(SectionHdrLayout))
639 if (Entry.Type == Type && !llvm::is_contained(WrittenIndices, I))
640 return I;
641 llvm_unreachable("Matching section not found in SectionHdrLayout");
642}
643
645 SecType Type, const SampleProfileMap &ProfileMap) {
646 unsigned LayoutIdx = findUnwrittenEntry(Type);
647 SecHdrTableEntry &Entry = SectionHdrLayout[LayoutIdx];
648
649 // The setting of SecFlagCompress should happen before markSectionStart.
652 if (Type == SecFuncMetadata &&
664 if (Type == SecProfileSymbolList && UseMD5ProfSymList)
666 if (Type == SecNameTable && UseMD5IndexedTables && UseMD5)
668
669 uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
670 switch (Type) {
671 case SecProfSummary:
672 computeSummary(ProfileMap);
673 if (auto EC = writeSummary())
674 return EC;
675 break;
676 case SecNameTable:
677 if (auto EC = writeNameTableSection(ProfileMap))
678 return EC;
679 break;
680 case SecCSNameTable:
681 if (auto EC = writeCSNameTableSection())
682 return EC;
683 break;
684 case SecLBRProfile:
687 if (std::error_code EC = writeFuncProfiles(ProfileMap))
688 return EC;
689 break;
692 bool IsFlat = hasSecFlag(Entry, SecCommonFlags::SecFlagFlat);
693 // An unflagged function offset table inherently indexes the primary
694 // Nested symbol span.
695 bool IsNested = !IsFlat;
696 if (auto EC = writeFuncOffsetTable(Type, IsNested))
697 return EC;
698 break;
699 }
700 case SecFuncMetadata:
701 if (std::error_code EC = writeFuncMetadata(ProfileMap))
702 return EC;
703 break;
705 if (auto EC = writeProfileSymbolListSection())
706 return EC;
707 break;
708 default:
709 if (auto EC = writeCustomSection(Type))
710 return EC;
711 break;
712 }
713 if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart))
714 return EC;
716}
717
723
724std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
725 const SampleProfileMap &ProfileMap) {
726 // ProfSection / FuncOffsetSection are SecLBR* or SecComposite* after
727 // configureCompositeProfile.
728 const SecType Sections[] = {
730 SecProfileSymbolList, FuncOffsetSection, SecFuncMetadata,
731 };
732 for (SecType Type : Sections)
733 if (std::error_code EC = writeOneSection(Type, ProfileMap))
734 return EC;
736}
737
738static void splitProfileMapToTwo(const SampleProfileMap &ProfileMap,
739 SampleProfileMap &NestedProfileMap,
740 SampleProfileMap &FlatProfileMap) {
741 for (const auto &I : ProfileMap) {
742 if (I.second.hasCallsiteSamples())
743 NestedProfileMap.insert({I.first, I.second});
744 else
745 FlatProfileMap.insert({I.first, I.second});
746 }
747}
748
749std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
750 const SampleProfileMap &ProfileMap) {
751 SampleProfileMap NestedProfileMap, FlatProfileMap;
752 splitProfileMapToTwo(ProfileMap, NestedProfileMap, FlatProfileMap);
753
754 // Flat SecFlag is pre-set in ExtBinaryHdrLayoutTable; findUnwrittenEntry
755 // picks the matching unwritten ProfSection / FuncOffsetSection slot.
756 const std::pair<SecType, const SampleProfileMap &> Sections[] = {
757 {SecProfSummary, ProfileMap}, {SecNameTable, ProfileMap},
758 {ProfSection, NestedProfileMap}, {FuncOffsetSection, NestedProfileMap},
759 {ProfSection, FlatProfileMap}, {FuncOffsetSection, FlatProfileMap},
760 {SecProfileSymbolList, ProfileMap}, {SecFuncMetadata, ProfileMap},
761 };
762 for (const auto &[Type, Map] : Sections)
763 if (std::error_code EC = writeOneSection(Type, Map))
764 return EC;
765
767}
768
769void SampleProfileWriterExtBinary::configureCompositeProfile() {
771 FuncOffsetSection =
773
774 // Change the section types in place to avoid duplicating the whole layout and
775 // its handling. Rewrite both legacy and composite entries so repeated writes
776 // can switch formats without losing configured flags.
777 for (auto &Entry : SectionHdrLayout) {
778 if (Entry.Type == SecFuncOffsetTable ||
780 Entry.Type = FuncOffsetSection;
781 else if (Entry.Type == SecLBRProfile || Entry.Type == SecCompositeProfile)
782 Entry.Type = ProfSection;
783 }
784}
785
786std::error_code SampleProfileWriterExtBinary::writeSections(
787 const SampleProfileMap &ProfileMap) {
788 // Rewrite the final configured layout immediately before its section types
789 // are consumed. Earlier layout configuration may replace SectionHdrLayout.
790 configureCompositeProfile();
791
792 std::error_code EC;
794 EC = writeDefaultLayout(ProfileMap);
795 else if (SecLayout == CtxSplitLayout)
796 EC = writeCtxSplitLayout(ProfileMap);
797 else
798 llvm_unreachable("Unsupported layout");
799 return EC;
800}
801
802/// Write samples to a text file.
803///
804/// Note: it may be tempting to implement this in terms of
805/// FunctionSamples::print(). Please don't. The dump functionality is intended
806/// for debugging and has no specified form.
807///
808/// The format used here is more structured and deliberate because
809/// it needs to be parsed by the SampleProfileReaderText class.
811 auto &OS = *OutputStream;
813 OS << "[" << S.getContext().toString() << "]:" << S.getTotalSamples();
814 else
815 OS << S.getFunction() << ":" << S.getTotalSamples();
816
817 if (Indent == 0)
818 OS << ":" << S.getHeadSamples();
819 OS << "\n";
820 LineCount++;
821
822 for (const auto &[Loc, Sample] : S.getBodySamples()) {
823 OS.indent(Indent + 1);
824 Loc.print(OS);
825 OS << ": " << Sample.getSamples();
826
827 for (const auto &J : Sample.getSortedCallTargets())
828 OS << " " << J.first << ":" << J.second;
829 OS << "\n";
830 LineCount++;
831
832 if (const TypeCountMap *Map = S.findCallsiteTypeSamplesAt(Loc);
833 Map && !Map->empty()) {
834 OS.indent(Indent + 1);
835 Loc.print(OS);
836 OS << ": ";
837 OS << kVTableProfPrefix;
838 for (const auto &[TypeName, Count] : *Map) {
839 OS << TypeName << ":" << Count << " ";
840 }
841 OS << "\n";
842 LineCount++;
843 }
844 }
845
846 Indent += 1;
847 for (const auto &[Loc, FunctionSamplesMap] : S.getCallsiteSamples()) {
848 for (const FunctionSamples &CalleeSamples :
850 OS.indent(Indent);
851 Loc.print(OS);
852 OS << ": ";
853 if (std::error_code EC = writeSample(CalleeSamples))
854 return EC;
855 }
856
857 if (const TypeCountMap *Map = S.findCallsiteTypeSamplesAt(Loc);
858 Map && !Map->empty()) {
859 OS.indent(Indent);
860 Loc.print(OS);
861 OS << ": ";
862 OS << kVTableProfPrefix;
863 for (const auto &[TypeId, Count] : *Map) {
864 OS << TypeId << ":" << Count << " ";
865 }
866 OS << "\n";
867 LineCount++;
868 }
869 }
870
871 Indent -= 1;
872
874 OS.indent(Indent + 1);
875 OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
876 LineCount++;
877 }
878
879 if (S.getContext().getAllAttributes()) {
880 OS.indent(Indent + 1);
881 OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n";
882 LineCount++;
883 }
884
885 if (Indent == 0 && MarkFlatProfiles && S.getCallsiteSamples().size() == 0)
886 OS << " !Flat\n";
887
889}
890
891std::error_code
893 assert(!Context.hasContext() && "cs profile is not supported");
894 return writeNameIdx(Context.getFunction());
895}
896
898 auto &NTable = getNameTable();
899 const auto &Ret = NTable.find(FName);
900 if (Ret == NTable.end())
902 encodeULEB128(Ret->second, *OutputStream);
904}
905
907 auto &NTable = getNameTable();
908 NTable.insert(std::make_pair(FName, 0));
909}
910
912 addName(Context.getFunction());
913}
914
916 // Add all the names in indirect call targets.
917 for (const auto &I : S.getBodySamples()) {
918 const SampleRecord &Sample = I.second;
919 for (const auto &J : Sample.getCallTargets())
920 addName(J.first);
921 }
922
923 // Recursively add all the names for inlined callsites.
924 for (const auto &J : S.getCallsiteSamples())
925 for (const auto &FS : J.second) {
926 const FunctionSamples &CalleeSamples = FS.second;
927 addName(CalleeSamples.getFunction());
928 addNames(CalleeSamples);
929 }
930
931 if (!WriteVTableProf)
932 return;
933 // Add all the vtable names to NameTable.
934 for (const auto &VTableAccessCountMap :
936 // Add type name to NameTable.
937 for (const auto Type : llvm::make_first_range(VTableAccessCountMap)) {
938 addName(Type);
939 }
940 }
941}
942
944 const SampleContext &Context) {
945 if (Context.hasContext()) {
946 for (auto &Callsite : Context.getContextFrames())
948 CSNameTable.insert(std::make_pair(Context, 0));
949 } else {
950 SampleProfileWriterBinary::addName(Context.getFunction());
951 }
952}
953
955 auto &OS = *OutputStream;
956
957 // Write out the name table.
958 encodeULEB128(NameTable.size(), OS);
959 for (const auto *Entry : stabilizeTable(NameTable)) {
960 OS << Entry->first;
961 encodeULEB128(0, OS);
962 }
964}
965
966std::error_code
974
975std::error_code
977 // When calling write on a different profile map, existing names should be
978 // cleared.
979 NameTable.clear();
980
982
983 computeSummary(ProfileMap);
984 if (auto EC = writeSummary())
985 return EC;
986
987 // Generate the name table for all the functions referenced in the profile.
988 for (const auto &I : ProfileMap) {
989 addContext(I.second.getContext());
990 addNames(I.second);
991 }
992
995}
996
1001
1005
1006void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
1008
1009 Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
1010 SecHdrTableOffset = OutputStream->tell();
1011 for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
1012 Writer.write(static_cast<uint64_t>(-1));
1013 Writer.write(static_cast<uint64_t>(-1));
1014 Writer.write(static_cast<uint64_t>(-1));
1015 Writer.write(static_cast<uint64_t>(-1));
1016 }
1017}
1018
1019std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
1020 assert(SecHdrTable.size() == SectionHdrLayout.size() &&
1021 "SecHdrTable entries doesn't match SectionHdrLayout");
1022 SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
1023 for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
1024 IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
1025 }
1026
1027 // Write the section header table in the order specified in
1028 // SectionHdrLayout. SectionHdrLayout specifies the sections
1029 // order in which profile reader expect to read, so the section
1030 // header table should be written in the order in SectionHdrLayout.
1031 // Note that the section order in SecHdrTable may be different
1032 // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
1033 // needs to be computed after SecLBRProfile (the order in SecHdrTable),
1034 // but it needs to be read before SecLBRProfile (the order in
1035 // SectionHdrLayout). So we use IndexMap above to switch the order.
1036 support::endian::SeekableWriter Writer(
1037 static_cast<raw_pwrite_stream &>(*OutputStream),
1039 for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
1040 LayoutIdx++) {
1041 assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
1042 "Incorrect LayoutIdx in SecHdrTable");
1043 auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
1044 Writer.pwrite(static_cast<uint64_t>(Entry.Type),
1045 SecHdrTableOffset + 4 * LayoutIdx * sizeof(uint64_t));
1046 Writer.pwrite(static_cast<uint64_t>(Entry.Flags),
1047 SecHdrTableOffset + (4 * LayoutIdx + 1) * sizeof(uint64_t));
1048 Writer.pwrite(static_cast<uint64_t>(Entry.Offset),
1049 SecHdrTableOffset + (4 * LayoutIdx + 2) * sizeof(uint64_t));
1050 Writer.pwrite(static_cast<uint64_t>(Entry.Size),
1051 SecHdrTableOffset + (4 * LayoutIdx + 3) * sizeof(uint64_t));
1052 }
1053
1055}
1056
1057std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
1058 const SampleProfileMap &ProfileMap) {
1059 // Reject a version that cannot describe the selected profile encoding before
1060 // emitting any part of the header.
1063
1064 auto &OS = *OutputStream;
1065 FileStart = OS.tell();
1067
1068 allocSecHdrTable();
1070}
1071
1075 "writeCallsiteVTableProf should not be called if WriteVTableProf is "
1076 "false");
1077
1078 encodeULEB128(CallsiteTypeMap.size(), OS);
1079 for (const auto &[Loc, TypeMap] : CallsiteTypeMap) {
1080 Loc.serialize(OS);
1081 if (std::error_code EC = serializeTypeMap(TypeMap, getNameTable(), OS))
1082 return EC;
1083 }
1084
1086}
1087
1089 auto &OS = *OutputStream;
1090 encodeULEB128(Summary->getTotalCount(), OS);
1091 encodeULEB128(Summary->getMaxCount(), OS);
1092 encodeULEB128(Summary->getMaxFunctionCount(), OS);
1093 encodeULEB128(Summary->getNumCounts(), OS);
1094 encodeULEB128(Summary->getNumFunctions(), OS);
1095 ArrayRef<ProfileSummaryEntry> Entries = Summary->getDetailedSummary();
1096 encodeULEB128(Entries.size(), OS);
1097 for (auto Entry : Entries) {
1098 encodeULEB128(Entry.Cutoff, OS);
1099 encodeULEB128(Entry.MinCount, OS);
1100 encodeULEB128(Entry.NumCounts, OS);
1101 }
1103}
1104
1105std::error_code
1107 bool IsNested) {
1108 auto &OS = *OutputStream;
1109 if (WriteCompositeProf && !IsNested)
1113 for (const auto &I : S.getBodySamples()) {
1114 LineLocation Loc = I.first;
1115 const SampleRecord &Sample = I.second;
1116 Loc.serialize(OS);
1117 if (std::error_code EC = Sample.serialize(OS, getNameTable()))
1118 return EC;
1119 }
1121}
1122
1123namespace {
1124
1125/// A reusable stream that discards payload bytes while counting their size.
1126class PayloadSizeCountingStream final : public raw_ostream {
1127public:
1128 /// Avoid retaining payload data in raw_ostream's internal buffer.
1129 PayloadSizeCountingStream() { SetUnbuffered(); }
1130
1131 /// Prepare the stream to count another payload.
1132 void resetPayload() {
1133 PayloadSize = 0;
1134 Overflowed = false;
1135 }
1136
1137 /// Return whether the payload size exceeded the representable range.
1138 bool overflowed() const { return Overflowed; }
1139
1140 /// Return the complete payload size when overflowed() is false.
1141 uint64_t payloadSize() const { return PayloadSize; }
1142
1143private:
1144 /// Count incoming bytes without retaining their contents.
1145 void write_impl(const char *, size_t Size) override {
1146 if (Overflowed)
1147 return;
1148
1149 // Fail closed if the payload cannot be represented by its uint64_t size.
1150 if (Size > UINT64_MAX - PayloadSize) {
1151 Overflowed = true;
1152 return;
1153 }
1154 PayloadSize += Size;
1155 }
1156
1157 /// Report the number of bytes accepted from the current payload.
1158 uint64_t current_pos() const override { return PayloadSize; }
1159
1160 /// Number of bytes observed during the counting pass.
1161 uint64_t PayloadSize = 0;
1162 /// Whether the counted size no longer fits in uint64_t.
1163 bool Overflowed = false;
1164};
1165
1166} // namespace
1167
1169 ProfTypes Type, function_ref<std::error_code()> WritePayload) {
1170 // PayloadSizeStream temporarily owns the real output while the callback
1171 // writes through OutputStream. A nested call would therefore mistake the
1172 // real output for PayloadSizeCountingStream.
1175 SaveAndRestore RestoreWritingProfileType(WritingProfileType, true);
1176
1177 // A profile block stores its payload size before the payload, but that size
1178 // is not known until it has been serialized. Count one complete serialization
1179 // without retaining its bytes, then emit the header and serialize it again.
1180 // TODO: Avoid serializing each payload twice while retaining bounded memory
1181 // use and compatibility with compressed section output.
1182 if (!PayloadSizeStream)
1183 PayloadSizeStream = std::make_unique<PayloadSizeCountingStream>();
1184 auto *SizeStream =
1185 static_cast<PayloadSizeCountingStream *>(PayloadSizeStream.get());
1186 SizeStream->resetPayload();
1188 std::error_code EC = WritePayload();
1190 if (EC)
1191 return EC;
1192 if (SizeStream->overflowed())
1194
1195 // Emit the compact header followed by the second, materialized pass.
1196 auto &OS = *OutputStream;
1197 encodeULEB128(Type, OS);
1198 encodeULEB128(SizeStream->payloadSize(), OS);
1199 uint64_t PayloadStart = OS.tell();
1200 if (std::error_code SecondPassEC = WritePayload())
1201 return SecondPassEC;
1202
1203 // Reject a stateful callback that did not reproduce the counted payload.
1204 if (OS.tell() - PayloadStart != SizeStream->payloadSize())
1207}
1208
1209static bool hasNonEmptyLBRProfile(const FunctionSamples &S, bool IsNested) {
1210 return S.getTotalSamples() != 0 || (!IsNested && S.getHeadSamples() != 0) ||
1211 !S.getBodySamples().empty();
1212}
1213
1214std::error_code
1216 bool IsNested) {
1217 auto &OS = *OutputStream;
1218 bool WriteLBRProf = hasNonEmptyLBRProfile(S, IsNested);
1219 // Other profile types should be added here.
1220 uint32_t TypesNum = WriteLBRProf;
1221
1222 // Write the number of profile types for function.
1223 encodeULEB128(TypesNum, OS);
1224
1225 if (WriteLBRProf)
1227 [&] { return writeLBRProfile(S, IsNested); });
1229}
1230
1232 bool IsNested) {
1233 auto &OS = *OutputStream;
1234 if (std::error_code EC = writeContextIdx(S.getContext()))
1235 return EC;
1236
1237 // Emit all the body samples.
1238 if (WriteCompositeProf) {
1239 if (std::error_code EC = writeCompositeProfile(S, IsNested))
1240 return EC;
1241 } else {
1242 if (std::error_code EC = writeLBRProfile(S, IsNested))
1243 return EC;
1244 }
1245
1246 // Recursively emit all the callsite samples.
1247 uint64_t NumCallsites = 0;
1248 for (const auto &J : S.getCallsiteSamples())
1249 NumCallsites += J.second.size();
1250 encodeULEB128(NumCallsites, OS);
1251 for (const auto &J : S.getCallsiteSamples())
1252 for (const auto &FS : J.second) {
1253 J.first.serialize(OS);
1254 if (std::error_code EC = writeBody(FS.second, /*IsNested=*/true))
1255 return EC;
1256 }
1257
1258 if (WriteVTableProf)
1260
1262}
1263
1264/// Write samples of a top-level function to a binary file.
1265///
1266/// \returns true if the samples were written successfully, false otherwise.
1267std::error_code
1270 return writeBody(S, /*IsNested=*/false);
1271}
1272
1273/// Create a sample profile file writer based on the specified format.
1274///
1275/// \param Filename The file to create.
1276///
1277/// \param Format Encoding format for the profile file.
1278///
1279/// \returns an error code indicating the status of the created writer.
1282 std::error_code EC;
1283 std::unique_ptr<raw_ostream> OS;
1285 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
1286 else
1288 if (EC)
1289 return EC;
1290
1291 return create(OS, Format);
1292}
1293
1294/// Create a sample profile stream writer based on the specified format.
1295///
1296/// \param OS The output stream to store the profile data to.
1297///
1298/// \param Format Encoding format for the profile file.
1299///
1300/// \returns an error code indicating the status of the created writer.
1302SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
1304 std::error_code EC;
1305 std::unique_ptr<SampleProfileWriter> Writer;
1306
1307 // Currently only Text and Extended Binary format are supported for CSSPGO.
1309 Format == SPF_Binary)
1311
1312 if (Format == SPF_Binary)
1313 Writer.reset(new SampleProfileWriterRawBinary(OS));
1314 else if (Format == SPF_Ext_Binary)
1315 Writer.reset(new SampleProfileWriterExtBinary(OS));
1316 else if (Format == SPF_Text)
1317 Writer.reset(new SampleProfileWriterText(OS));
1318 else if (Format == SPF_GCC)
1320 else
1322
1323 if (EC)
1324 return EC;
1325
1326 Writer->Format = Format;
1327 if (Format != SPF_Ext_Binary) {
1328 Writer->setFormatVersion(DefaultVersion);
1329 } else {
1332
1333 // Composite output defaults to its first compatible format version.
1334 // Preserve a compatible version explicitly selected by the user.
1336 if (RequestedVersion.getNumOccurrences() == 0) {
1337 Writer->setFormatVersion(CompositeProfileVersion);
1338 } else {
1341 Writer->setFormatVersion(RequestedVersion);
1342 }
1343 // Keep subsequent writes independent of the global command-line option.
1344 Writer->setUseCompositeProfile(true);
1345 } else {
1346 Writer->setFormatVersion(RequestedVersion);
1347 }
1348 }
1349
1350 return std::move(Writer);
1351}
1352
1355 Summary = Builder.computeSummaryForProfiles(ProfileMap);
1356}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
Provides ErrorOr<T> smart pointer.
This file defines the EytzingerTableSpan class, a non-owning view of a buffer formatted as a complete...
static uint64_t round(uint64_t Acc, uint64_t Input)
Definition KCFIHash.cpp:29
#define I(x, y, z)
Definition MD5.cpp:57
static constexpr StringLiteral Filename
static bool hasNonEmptyLBRProfile(const FunctionSamples &S, bool IsNested)
static cl::opt< uint64_t > RequestedVersion("sample-profile-format-version", cl::init(DefaultVersion), cl::Hidden, cl::desc("Format version to write for extensible binary profiles"))
static void splitProfileMapToTwo(const SampleProfileMap &ProfileMap, SampleProfileMap &NestedProfileMap, SampleProfileMap &FlatProfileMap)
static SmallVector< std::pair< KeyT, ValT > *, 0 > stabilizeTable(MapVector< KeyT, ValT > &Table)
static cl::opt< bool > ExtBinaryCompositeProf("extbinary-composite-prof", cl::init(false), cl::Hidden, cl::desc("Use the composite profile format"))
static cl::opt< bool > ExtBinaryWriteVTableTypeProf("extbinary-write-vtable-type-prof", cl::init(false), cl::Hidden, cl::desc("Write vtable type profile in ext-binary sample profile writer"))
This file provides utility classes that use RAII to save and restore values.
#define LLVM_DEBUG(...)
Definition Debug.h:119
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
Represents either an error or a value T.
Definition ErrorOr.h:56
Owning container that stores elements in a complete binary search tree formatted in Eytzinger (breadt...
Definition Eytzinger.h:123
static EytzingerTable< T > create(std::vector< KeyT > Keys)
Construct an Eytzinger search tree from a vector of keys by sorting, deduplicating,...
Definition Eytzinger.h:139
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
static LLVM_ABI const ArrayRef< uint32_t > DefaultCutoffs
A vector of useful cutoff values for detailed summary.
pointer data()
Return a pointer to the vector's buffer, even if empty().
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
size_type size() const
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition DenseSet.h:182
An efficient, type-erasing, non-owning reference to a callable.
A raw_ostream that writes to a file descriptor.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
uint64_t tell() const
tell - Return the current offset with the file.
raw_ostream & write(unsigned char C)
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
An abstract base class for streams implementations that also support a pwrite operation.
A raw_ostream that writes to an std::string.
std::string & str()
Returns the string's reference.
A raw_ostream that writes to an SmallVector or SmallString.
DefaultFunctionPruningStrategy(SampleProfileMap &ProfileMap, size_t OutputSizeLimit)
void Erase(size_t CurrentOutputSize) override
In this default implementation, functions with fewest samples are dropped first.
This class represents a function that is read from a sample profile.
Definition FunctionId.h:36
When writing a profile with size limit, user may want to use a different strategy to reduce function ...
virtual void Erase(size_t CurrentOutputSize)=0
SampleProfileWriter::writeWithSizeLimit() calls this after every write iteration if the output size s...
FunctionPruningStrategy(SampleProfileMap &ProfileMap, size_t OutputSizeLimit)
ProfileMap A reference to the original profile map.
Representation of the samples collected for a function.
Definition SampleProf.h:853
static LLVM_ABI std::atomic< bool > ProfileIsFS
If this profile uses flow sensitive discriminators.
static LLVM_ABI std::atomic< bool > ProfileIsPreInlined
static constexpr const char * UniqSuffix
uint64_t getHeadSamples() const
For top-level functions, return the total number of branch samples that have the function as the bran...
const CallsiteSampleMap & getCallsiteSamples() const LLVM_LIFETIME_BOUND
Return all the callsite samples collected in the body of the function.
FunctionId getFunction() const
Return the function name.
SampleContext & getContext() const LLVM_LIFETIME_BOUND
const TypeCountMap * findCallsiteTypeSamplesAt(const LineLocation &Loc) const LLVM_LIFETIME_BOUND
Returns the TypeCountMap for inlined callsites at the given Loc.
static LLVM_ABI std::atomic< bool > ProfileIsProbeBased
const CallsiteTypeMap & getCallsiteTypeCounts() const LLVM_LIFETIME_BOUND
Returns vtable access samples for the C++ types collected in this function.
const BodySampleMap & getBodySamples() const LLVM_LIFETIME_BOUND
Return all the samples collected in the body of the function.
uint64_t getTotalSamples() const
Return the total number of samples collected inside the function.
static LLVM_ABI std::atomic< bool > ProfileIsCS
std::string toString() const
Definition SampleProf.h:741
This class provides operator overloads to the map container using MD5 as the key type,...
bool WritingProfileType
Whether a profile payload callback is currently being executed.
virtual void addContext(const SampleContext &Context)
virtual std::error_code writeMagicIdent(SampleProfileFormat Format)
std::error_code writeCompositeProfile(const FunctionSamples &S, bool IsNested)
Interfaces for composite profile writing.
MapVector< FunctionId, uint32_t > NameTable
std::error_code writeCallsiteVTableProf(const CallsiteTypeMap &CallsiteTypeMap, raw_ostream &OS)
Write CallsiteTypeMap to the output stream OS.
std::unique_ptr< raw_ostream > PayloadSizeStream
Reusable stream that counts payload bytes without retaining them.
virtual std::error_code writeContextIdx(const SampleContext &Context)
std::error_code writeBody(const FunctionSamples &S, bool IsNested)
std::error_code writeSample(const FunctionSamples &S) override
Write samples of a top-level function to a binary file.
std::error_code writeHeader(const SampleProfileMap &ProfileMap) override
Write a file header for the profile file.
std::error_code writeLBRProfile(const FunctionSamples &S, bool IsNested)
std::error_code writeProfileType(ProfTypes Type, function_ref< std::error_code()> WritePayload)
Write one Type and the size-prefixed payload emitted by WritePayload.
virtual MapVector< FunctionId, uint32_t > & getNameTable()
std::error_code writeNameIdx(FunctionId FName)
std::error_code writeNameTableSection(const SampleProfileMap &ProfileMap)
SmallVector< SecHdrTableEntry, 8 > SectionHdrLayout
std::error_code writeFuncMetadata(const SampleProfileMap &Profiles)
virtual std::error_code writeCustomSection(SecType Type)=0
virtual std::error_code writeOneSection(SecType Type, const SampleProfileMap &ProfileMap)
std::error_code writeCSNameIdx(const SampleContext &Context)
std::error_code writeEytzingerFuncOffsetTable(SecType Type, bool IsNested)
virtual std::error_code writeSections(const SampleProfileMap &ProfileMap)=0
std::error_code writeFuncOffsetTable(SecType Type, bool IsNested)
void addSectionFlag(SecType Type, SecFlagType Flag)
uint64_t markSectionStart(SecType Type, uint32_t LayoutIdx)
Return the current position and prepare to use it as the start position of a section given the sectio...
void addContext(const SampleContext &Context) override
std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx, uint64_t SectionStart)
Add a new section into section header table given the section type Type, its position LayoutIdx in Se...
std::error_code writeEytzingerNameTableSection(const SampleProfileMap &ProfileMap)
std::error_code write(const SampleProfileMap &ProfileMap) override
Write all the sample profiles in the given map of samples.
std::error_code writeContextIdx(const SampleContext &Context) override
std::error_code writeSample(const FunctionSamples &S) override
Write samples of a top-level function to a binary file.
SampleProfileWriterExtBinary(std::unique_ptr< raw_ostream > &OS)
Sample-based profile writer (text format).
std::error_code writeSample(const FunctionSamples &S) override
Write samples to a text file.
std::unique_ptr< ProfileSummary > Summary
Profile summary.
virtual std::error_code writeSample(const FunctionSamples &S)=0
Write sample profiles in S.
SampleProfileFormat Format
Profile format.
std::error_code writeWithSizeLimitInternal(SampleProfileMap &ProfileMap, size_t OutputSizeLimit, FunctionPruningStrategy *Strategy)
void computeSummary(const SampleProfileMap &ProfileMap)
Compute summary for this profile.
virtual std::error_code writeFuncProfiles(const SampleProfileMap &ProfileMap)
std::unique_ptr< raw_ostream > OutputStream
Output stream where to emit the profile to.
uint64_t FormatVersion
Format version to write.
size_t LineCount
For writeWithSizeLimit in text mode, each newline takes 1 additional byte on Windows when actually wr...
static ErrorOr< std::unique_ptr< SampleProfileWriter > > create(StringRef Filename, SampleProfileFormat Format)
Profile writer factory.
virtual std::error_code writeHeader(const SampleProfileMap &ProfileMap)=0
Write a file header for the profile file.
virtual std::error_code write(const SampleProfileMap &ProfileMap)
Write all the sample profiles in the given map of samples.
Representation of a single sample record.
Definition SampleProf.h:422
LLVM_ABI std::error_code serialize(raw_ostream &OS, const MapVector< FunctionId, uint32_t > &NameTable) const
Serialize the sample record to the output stream using ULEB128 encoding.
const CallTargetMap & getCallTargets() const LLVM_LIFETIME_BOUND
Return the call targets collected in this sample record.
Definition SampleProf.h:493
#define UINT64_MAX
Definition DataTypes.h:77
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Entry
Definition COFF.h:862
initializer< Ty > init(const Ty &Val)
LLVM_ABI void compress(ArrayRef< uint8_t > Input, SmallVectorImpl< uint8_t > &CompressedBuffer, int Level=DefaultCompression)
LLVM_ABI bool isAvailable()
constexpr int BestSizeCompression
Definition Compression.h:40
LLVM_ABI void sortFuncProfiles(const SampleProfileMap &ProfileMap, std::vector< NameFunctionSamples > &SortedProfiles)
static uint64_t SPMagic(SampleProfileFormat Format=SPF_Binary)
Definition SampleProf.h:114
static bool formatVersionIsSupported(uint64_t Version)
Definition SampleProf.h:136
SortedVectorMap< LineLocation, TypeCountMap, 0 > CallsiteTypeMap
Definition SampleProf.h:845
static void addSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag)
Definition SampleProf.h:319
static bool hasSecFlag(const SecHdrTableEntry &Entry, SecFlagType Flag)
Definition SampleProf.h:335
std::pair< hash_code, const FunctionSamples * > NameFunctionSamples
@ SecFlagIsPreInlined
SecFlagIsPreInlined means this profile contains ShouldBeInlined contexts thus this is CS preinliner c...
Definition SampleProf.h:263
@ SecFlagHasVTableTypeProf
SecFlagHasVTableTypeProf means this profile contains vtable type profiles.
Definition SampleProf.h:266
@ SecFlagFSDiscriminator
SecFlagFSDiscriminator means this profile uses flow-sensitive discriminators.
Definition SampleProf.h:260
@ SecFlagFullContext
SecFlagContext means this is context-sensitive flat profile for CSSPGO.
Definition SampleProf.h:257
std::map< FunctionId, FunctionSamples > FunctionSamplesMap
Definition SampleProf.h:843
static constexpr uint64_t DefaultVersion
Definition SampleProf.h:127
static constexpr uint64_t CompositeProfileVersion
Definition SampleProf.h:130
constexpr char kVTableProfPrefix[]
Definition SampleProf.h:97
LLVM_ABI std::error_code serializeTypeMap(const TypeCountMap &Map, const MapVector< FunctionId, uint32_t > &NameTable, raw_ostream &OS)
Write Map to the output stream.
SortedVectorMap< FunctionId, uint64_t, 0 > TypeCountMap
Key represents type of a C++ polymorphic class type by its vtable and value represents its counter.
Definition SampleProf.h:402
detail::packed_endian_specific_integral< uint64_t, llvm::endianness::little, unaligned > ulittle64_t
Definition Endian.h:273
detail::packed_endian_specific_integral< uint32_t, llvm::endianness::little, unaligned > ulittle32_t
Definition Endian.h:270
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
Definition FileSystem.h:804
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:315
@ Offset
Definition DWP.cpp:577
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1669
ArrayRef< CharT > arrayRefFromStringRef(StringRef Input)
Construct an array ref of bytes from a string ref.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2554
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
Definition STLExtras.h:365
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1636
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
auto make_first_range(ContainerTy &&c)
Given a container of pairs, return a range over the first elements.
Definition STLExtras.h:1399
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
auto make_second_range(ContainerTy &&c)
Given a container of pairs, return a range over the second elements.
Definition STLExtras.h:1409
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1917
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
Definition iterator.h:368
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a ULEB128 value to an output stream.
Definition LEB128.h:79
PointerUnion< const Value *, const PseudoSourceValue * > ValueType
endianness
Definition bit.h:71
StringRef toStringRef(bool B)
Construct a string ref from a boolean.
LLVM_ABI Error write(DWPWriter &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue, Dwarf64StrOffsetsPromotion StrOffsetsOptValue, raw_pwrite_stream *OS=nullptr)
Definition DWP.cpp:746
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
A utility class that uses RAII to save and restore the value of a variable.
Represents the relative location of an instruction.
Definition SampleProf.h:351
Adapter to write values to a stream in a particular byte order.
void write(ArrayRef< value_type > Val)