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/StringRef.h"
28#include "llvm/Support/LEB128.h"
29#include "llvm/Support/MD5.h"
31#include <cmath>
32#include <cstdint>
33#include <memory>
34#include <system_error>
35#include <utility>
36#include <vector>
37
38#define DEBUG_TYPE "llvm-profdata"
39
40using namespace llvm;
41using namespace sampleprof;
42
43// To begin with, make this option off by default.
45 "extbinary-write-vtable-type-prof", cl::init(false), cl::Hidden,
46 cl::desc("Write vtable type profile in ext-binary sample profile writer"));
47
49 "sample-profile-format-version", cl::init(DefaultVersion), cl::Hidden,
50 cl::desc("Format version to write for extensible binary profiles"));
51
52static cl::opt<bool>
53 WriteMD5ProfSymList("md5-prof-sym-list", cl::init(false), cl::Hidden,
54 cl::desc("Write ProfileSymbolList (Cold Symbols) as "
55 "64-bit MD5 hashes in Eytzinger layout"));
56
57namespace llvm {
58namespace support {
59namespace endian {
60namespace {
61
62// Adapter class to llvm::support::endian::Writer for pwrite().
63struct SeekableWriter {
65 endianness Endian;
66 SeekableWriter(raw_pwrite_stream &OS, endianness Endian)
67 : OS(OS), Endian(Endian) {}
68
69 template <typename ValueType> void pwrite(ValueType Val, size_t Offset) {
70 std::string StringBuf;
71 raw_string_ostream SStream(StringBuf);
72 Writer(SStream, Endian).write(Val);
73 OS.pwrite(StringBuf.data(), StringBuf.size(), Offset);
74 }
75};
76
77} // namespace
78} // namespace endian
79} // namespace support
80} // namespace llvm
81
87
88void DefaultFunctionPruningStrategy::Erase(size_t CurrentOutputSize) {
89 double D = (double)OutputSizeLimit / CurrentOutputSize;
90 size_t NewSize = (size_t)round(ProfileMap.size() * D * D);
91 size_t NumToRemove = ProfileMap.size() - NewSize;
92 if (NumToRemove < 1)
93 NumToRemove = 1;
94
95 assert(NumToRemove <= SortedFunctions.size());
96 for (const NameFunctionSamples &E :
97 llvm::drop_begin(SortedFunctions, SortedFunctions.size() - NumToRemove))
98 ProfileMap.erase(E.first);
99 SortedFunctions.resize(SortedFunctions.size() - NumToRemove);
100}
101
103 SampleProfileMap &ProfileMap, size_t OutputSizeLimit,
104 FunctionPruningStrategy *Strategy) {
105 if (OutputSizeLimit == 0)
106 return write(ProfileMap);
107
108 size_t OriginalFunctionCount = ProfileMap.size();
109
110 std::unique_ptr<raw_ostream> OriginalOutputStream;
111 OutputStream.swap(OriginalOutputStream);
112
113 size_t IterationCount = 0;
114 size_t TotalSize;
115
116 SmallVector<char> StringBuffer;
117 do {
118 StringBuffer.clear();
119 OutputStream.reset(new raw_svector_ostream(StringBuffer));
120 if (std::error_code EC = write(ProfileMap))
121 return EC;
122
123 TotalSize = StringBuffer.size();
124 // On Windows every "\n" is actually written as "\r\n" to disk but not to
125 // memory buffer, this difference should be added when considering the total
126 // output size.
127#ifdef _WIN32
128 if (Format == SPF_Text)
129 TotalSize += LineCount;
130#endif
131 if (TotalSize <= OutputSizeLimit)
132 break;
133
134 Strategy->Erase(TotalSize);
135 IterationCount++;
136 } while (ProfileMap.size() != 0);
137
138 if (ProfileMap.size() == 0)
140
141 OutputStream.swap(OriginalOutputStream);
142 OutputStream->write(StringBuffer.data(), StringBuffer.size());
143 LLVM_DEBUG(dbgs() << "Profile originally has " << OriginalFunctionCount
144 << " functions, reduced to " << ProfileMap.size() << " in "
145 << IterationCount << " iterations\n");
146 // Silence warning on Release build.
147 (void)OriginalFunctionCount;
148 (void)IterationCount;
150}
151
152std::error_code
154 std::vector<NameFunctionSamples> V;
155 sortFuncProfiles(ProfileMap, V);
156 for (const auto &I : V) {
157 if (std::error_code EC = writeSample(*I.second))
158 return EC;
159 }
161}
162
163std::error_code SampleProfileWriter::write(const SampleProfileMap &ProfileMap) {
164 if (std::error_code EC = writeHeader(ProfileMap))
165 return EC;
166
167 if (std::error_code EC = writeFuncProfiles(ProfileMap))
168 return EC;
169
171}
172
173/// Return the current position and prepare to use it as the start
174/// position of a section given the section type \p Type and its position
175/// \p LayoutIdx in SectionHdrLayout.
178 uint32_t LayoutIdx) {
179 uint64_t SectionStart = OutputStream->tell();
180 assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
181 const auto &Entry = SectionHdrLayout[LayoutIdx];
182 assert(Entry.Type == Type && "Unexpected section type");
183 // Use LocalBuf as a temporary output for writting data.
185 LocalBufStream.swap(OutputStream);
186 return SectionStart;
187}
188
189std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() {
192 std::string &UncompressedStrings =
193 static_cast<raw_string_ostream *>(LocalBufStream.get())->str();
194 if (UncompressedStrings.size() == 0)
196 auto &OS = *OutputStream;
197 SmallVector<uint8_t, 128> CompressedStrings;
199 CompressedStrings,
201 encodeULEB128(UncompressedStrings.size(), OS);
202 encodeULEB128(CompressedStrings.size(), OS);
203 OS << toStringRef(CompressedStrings);
204 UncompressedStrings.clear();
206}
207
208/// Add a new section into section header table given the section type
209/// \p Type, its position \p LayoutIdx in SectionHdrLayout and the
210/// location \p SectionStart where the section should be written to.
212 SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) {
213 assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range");
214 const auto &Entry = SectionHdrLayout[LayoutIdx];
215 assert(Entry.Type == Type && "Unexpected section type");
217 LocalBufStream.swap(OutputStream);
218 if (std::error_code EC = compressAndOutput())
219 return EC;
220 }
221 SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart,
222 OutputStream->tell() - SectionStart, LayoutIdx});
224}
225
226std::error_code
228 // When calling write on a different profile map, existing states should be
229 // cleared.
230 NameTable.clear();
231 CSNameTable.clear();
232 SecHdrTable.clear();
233
234 if (std::error_code EC = writeHeader(ProfileMap))
235 return EC;
236
237 std::string LocalBuf;
238 LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf);
239 if (std::error_code EC = writeSections(ProfileMap))
240 return EC;
241
242 if (std::error_code EC = writeSecHdrTable())
243 return EC;
244
246}
247
249 const SampleContext &Context) {
250 if (Context.hasContext())
251 return writeCSNameIdx(Context);
252 else
253 return SampleProfileWriterBinary::writeNameIdx(Context.getFunction());
254}
255
256std::error_code
258 const auto &Ret = CSNameTable.find(Context);
259 if (Ret == CSNameTable.end())
261 encodeULEB128(Ret->second, *OutputStream);
263}
264
265std::error_code
267 uint64_t Offset = OutputStream->tell();
268 auto &Context = S.getContext();
269 FuncOffsetTable[Context] = Offset - SecLBRProfileStart;
271 return writeBody(S);
272}
273
275 auto &OS = *OutputStream;
276
277 // Write out the table size.
278 encodeULEB128(FuncOffsetTable.size(), OS);
279
280 // Write out FuncOffsetTable.
281 auto WriteItem = [&](const SampleContext &Context, uint64_t Offset) {
282 if (std::error_code EC = writeContextIdx(Context))
283 return EC;
285 return (std::error_code)sampleprof_error::success;
286 };
287
289 // Sort the contexts before writing them out. This is to help fast load all
290 // context profiles for a function as well as their callee contexts which
291 // can help profile-guided importing for ThinLTO.
292 std::map<SampleContext, uint64_t> OrderedFuncOffsetTable(
293 FuncOffsetTable.begin(), FuncOffsetTable.end());
294 for (const auto &Entry : OrderedFuncOffsetTable) {
295 if (std::error_code EC = WriteItem(Entry.first, Entry.second))
296 return EC;
297 }
299 } else {
300 for (const auto &Entry : FuncOffsetTable) {
301 if (std::error_code EC = WriteItem(Entry.first, Entry.second))
302 return EC;
303 }
304 }
305
306 FuncOffsetTable.clear();
308}
309
311 const FunctionSamples &FunctionProfile) {
312 auto &OS = *OutputStream;
313 if (std::error_code EC = writeContextIdx(FunctionProfile.getContext()))
314 return EC;
315
317 encodeULEB128(FunctionProfile.getFunctionHash(), OS);
319 encodeULEB128(FunctionProfile.getContext().getAllAttributes(), OS);
320 }
321
323 // Recursively emit attributes for all callee samples.
324 uint64_t NumCallsites = 0;
325 for (const auto &J : FunctionProfile.getCallsiteSamples())
326 NumCallsites += J.second.size();
327 encodeULEB128(NumCallsites, OS);
328 for (const auto &J : FunctionProfile.getCallsiteSamples()) {
329 for (const auto &FS : J.second) {
330 LineLocation Loc = J.first;
331 encodeULEB128(Loc.LineOffset, OS);
332 encodeULEB128(Loc.Discriminator, OS);
333 if (std::error_code EC = writeFuncMetadata(FS.second))
334 return EC;
335 }
336 }
337 }
338
340}
341
343 const SampleProfileMap &Profiles) {
347 for (const auto &Entry : Profiles) {
348 if (std::error_code EC = writeFuncMetadata(Entry.second))
349 return EC;
350 }
352}
353
354template <class KeyT, class ValT>
359
360 llvm::sort(Entries,
361 [](const auto *L, const auto *R) { return L->first < R->first; });
362
363 for (const auto &[I, Entry] : llvm::enumerate(Entries))
364 Entry->second = I;
365
366 return Entries;
367}
368
370 if (!UseMD5)
372
373 auto &OS = *OutputStream;
374
375 // Write out the MD5 name table. We wrote unencoded MD5 so reader can
376 // retrieve the name using the name index without having to read the
377 // whole name table.
378 encodeULEB128(NameTable.size(), OS);
380 for (const auto *Entry : stabilizeTable(NameTable))
381 Writer.write(Entry->first.getHashCode());
383}
384
386 const SampleProfileMap &ProfileMap) {
387 for (const auto &I : ProfileMap) {
388 addContext(I.second.getContext());
389 addNames(I.second);
390 }
391
392 // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag
393 // so compiler won't strip the suffix during profile matching after
394 // seeing the flag in the profile.
395 // Original names are unavailable if using MD5, so this option has no use.
396 if (!UseMD5) {
397 for (const auto &I : NameTable) {
398 if (I.first.stringRef().contains(FunctionSamples::UniqSuffix)) {
400 break;
401 }
402 }
403 }
404
405 if (auto EC = writeNameTable())
406 return EC;
408}
409
411 auto &OS = *OutputStream;
412 encodeULEB128(CSNameTable.size(), OS);
414 for (const auto *Entry : stabilizeTable(CSNameTable)) {
415 auto Frames = Entry->first.getContextFrames();
416 encodeULEB128(Frames.size(), OS);
417 for (auto &Callsite : Frames) {
418 if (std::error_code EC = writeNameIdx(Callsite.Func))
419 return EC;
420 encodeULEB128(Callsite.Location.LineOffset, OS);
421 encodeULEB128(Callsite.Location.Discriminator, OS);
422 }
423 }
424
426}
427
428std::error_code
434
435std::error_code
437 assert((!ProfSymList || !ProfSymList->isMD5()) &&
438 "Writing string-based ProfileSymbolListSection from MD5 table "
439 "not yet implemented");
440 if (ProfSymList && ProfSymList->size() > 0)
441 if (std::error_code EC = ProfSymList->write(*OutputStream))
442 return EC;
443
445}
446
447std::error_code
449 if (!ProfSymList || ProfSymList->size() == 0)
451 assert(!ProfSymList->isMD5() &&
452 "Writing MD5 ProfileSymbolListSection from existing MD5 "
453 "table not yet implemented");
454
455 auto &OS = *OutputStream;
456 std::vector<uint64_t> Keys = ProfSymList->collectGUIDs();
457
458 auto Table =
460
461 OS.write(reinterpret_cast<const char *>(Table.data()),
462 Table.size() * sizeof(support::ulittle64_t));
464}
465
467 SecType Type, uint32_t LayoutIdx, const SampleProfileMap &ProfileMap) {
468 // The setting of SecFlagCompress should happen before markSectionStart.
469 if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress())
473 if (Type == SecFuncMetadata &&
487
488 uint64_t SectionStart = markSectionStart(Type, LayoutIdx);
489 switch (Type) {
490 case SecProfSummary:
491 computeSummary(ProfileMap);
492 if (auto EC = writeSummary())
493 return EC;
494 break;
495 case SecNameTable:
496 if (auto EC = writeNameTableSection(ProfileMap))
497 return EC;
498 break;
499 case SecCSNameTable:
500 if (auto EC = writeCSNameTableSection())
501 return EC;
502 break;
503 case SecLBRProfile:
505 if (std::error_code EC = writeFuncProfiles(ProfileMap))
506 return EC;
507 break;
509 if (auto EC = writeFuncOffsetTable())
510 return EC;
511 break;
512 case SecFuncMetadata:
513 if (std::error_code EC = writeFuncMetadata(ProfileMap))
514 return EC;
515 break;
517 if (auto EC = writeProfileSymbolListSection())
518 return EC;
519 break;
520 default:
521 if (auto EC = writeCustomSection(Type))
522 return EC;
523 break;
524 }
525 if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart))
526 return EC;
528}
529
535
536std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
537 const SampleProfileMap &ProfileMap) {
538 // The const indices passed to writeOneSection below are specifying the
539 // positions of the sections in SectionHdrLayout. Look at
540 // initSectionHdrLayout to find out where each section is located in
541 // SectionHdrLayout.
542 if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
543 return EC;
544 if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
545 return EC;
546 if (auto EC = writeOneSection(SecCSNameTable, 2, ProfileMap))
547 return EC;
548 if (auto EC = writeOneSection(SecLBRProfile, 4, ProfileMap))
549 return EC;
550 if (auto EC = writeOneSection(SecProfileSymbolList, 5, ProfileMap))
551 return EC;
552 if (auto EC = writeOneSection(SecFuncOffsetTable, 3, ProfileMap))
553 return EC;
554 if (auto EC = writeOneSection(SecFuncMetadata, 6, ProfileMap))
555 return EC;
557}
558
559static void splitProfileMapToTwo(const SampleProfileMap &ProfileMap,
560 SampleProfileMap &ContextProfileMap,
561 SampleProfileMap &NoContextProfileMap) {
562 for (const auto &I : ProfileMap) {
563 if (I.second.getCallsiteSamples().size())
564 ContextProfileMap.insert({I.first, I.second});
565 else
566 NoContextProfileMap.insert({I.first, I.second});
567 }
568}
569
570std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
571 const SampleProfileMap &ProfileMap) {
572 SampleProfileMap ContextProfileMap, NoContextProfileMap;
573 splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap);
574
575 if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
576 return EC;
577 if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
578 return EC;
579 if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap))
580 return EC;
581 if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap))
582 return EC;
583 // Mark the section to have no context. Note section flag needs to be set
584 // before writing the section.
586 if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap))
587 return EC;
588 // Mark the section to have no context. Note section flag needs to be set
589 // before writing the section.
591 if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap))
592 return EC;
593 if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap))
594 return EC;
595 if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap))
596 return EC;
597
599}
600
601std::error_code SampleProfileWriterExtBinary::writeSections(
602 const SampleProfileMap &ProfileMap) {
603 std::error_code EC;
605 EC = writeDefaultLayout(ProfileMap);
606 else if (SecLayout == CtxSplitLayout)
607 EC = writeCtxSplitLayout(ProfileMap);
608 else
609 llvm_unreachable("Unsupported layout");
610 return EC;
611}
612
613/// Write samples to a text file.
614///
615/// Note: it may be tempting to implement this in terms of
616/// FunctionSamples::print(). Please don't. The dump functionality is intended
617/// for debugging and has no specified form.
618///
619/// The format used here is more structured and deliberate because
620/// it needs to be parsed by the SampleProfileReaderText class.
622 auto &OS = *OutputStream;
624 OS << "[" << S.getContext().toString() << "]:" << S.getTotalSamples();
625 else
626 OS << S.getFunction() << ":" << S.getTotalSamples();
627
628 if (Indent == 0)
629 OS << ":" << S.getHeadSamples();
630 OS << "\n";
631 LineCount++;
632
634 for (const auto &I : SortedSamples.get()) {
635 LineLocation Loc = I->first;
636 const SampleRecord &Sample = I->second;
637 OS.indent(Indent + 1);
638 Loc.print(OS);
639 OS << ": " << Sample.getSamples();
640
641 for (const auto &J : Sample.getSortedCallTargets())
642 OS << " " << J.first << ":" << J.second;
643 OS << "\n";
644 LineCount++;
645
646 if (const TypeCountMap *Map = S.findCallsiteTypeSamplesAt(Loc);
647 Map && !Map->empty()) {
648 OS.indent(Indent + 1);
649 Loc.print(OS);
650 OS << ": ";
651 OS << kVTableProfPrefix;
652 for (const auto [TypeName, Count] : *Map) {
653 OS << TypeName << ":" << Count << " ";
654 }
655 OS << "\n";
656 LineCount++;
657 }
658 }
659
662 Indent += 1;
663 for (const auto *Element : SortedCallsiteSamples.get()) {
664 // Element is a pointer to a pair of LineLocation and FunctionSamplesMap.
665 const auto &[Loc, FunctionSamplesMap] = *Element;
666 for (const FunctionSamples &CalleeSamples :
668 OS.indent(Indent);
669 Loc.print(OS);
670 OS << ": ";
671 if (std::error_code EC = writeSample(CalleeSamples))
672 return EC;
673 }
674
675 if (const TypeCountMap *Map = S.findCallsiteTypeSamplesAt(Loc);
676 Map && !Map->empty()) {
677 OS.indent(Indent);
678 Loc.print(OS);
679 OS << ": ";
680 OS << kVTableProfPrefix;
681 for (const auto [TypeId, Count] : *Map) {
682 OS << TypeId << ":" << Count << " ";
683 }
684 OS << "\n";
685 LineCount++;
686 }
687 }
688
689 Indent -= 1;
690
692 OS.indent(Indent + 1);
693 OS << "!CFGChecksum: " << S.getFunctionHash() << "\n";
694 LineCount++;
695 }
696
697 if (S.getContext().getAllAttributes()) {
698 OS.indent(Indent + 1);
699 OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n";
700 LineCount++;
701 }
702
703 if (Indent == 0 && MarkFlatProfiles && S.getCallsiteSamples().size() == 0)
704 OS << " !Flat\n";
705
707}
708
709std::error_code
711 assert(!Context.hasContext() && "cs profile is not supported");
712 return writeNameIdx(Context.getFunction());
713}
714
716 auto &NTable = getNameTable();
717 const auto &Ret = NTable.find(FName);
718 if (Ret == NTable.end())
720 encodeULEB128(Ret->second, *OutputStream);
722}
723
725 auto &NTable = getNameTable();
726 NTable.insert(std::make_pair(FName, 0));
727}
728
730 addName(Context.getFunction());
731}
732
734 // Add all the names in indirect call targets.
735 for (const auto &I : S.getBodySamples()) {
736 const SampleRecord &Sample = I.second;
737 for (const auto &J : Sample.getCallTargets())
738 addName(J.first);
739 }
740
741 // Recursively add all the names for inlined callsites.
742 for (const auto &J : S.getCallsiteSamples())
743 for (const auto &FS : J.second) {
744 const FunctionSamples &CalleeSamples = FS.second;
745 addName(CalleeSamples.getFunction());
746 addNames(CalleeSamples);
747 }
748
749 if (!WriteVTableProf)
750 return;
751 // Add all the vtable names to NameTable.
752 for (const auto &VTableAccessCountMap :
754 // Add type name to NameTable.
755 for (const auto Type : llvm::make_first_range(VTableAccessCountMap)) {
756 addName(Type);
757 }
758 }
759}
760
762 const SampleContext &Context) {
763 if (Context.hasContext()) {
764 for (auto &Callsite : Context.getContextFrames())
766 CSNameTable.insert(std::make_pair(Context, 0));
767 } else {
768 SampleProfileWriterBinary::addName(Context.getFunction());
769 }
770}
771
773 auto &OS = *OutputStream;
774
775 // Write out the name table.
776 encodeULEB128(NameTable.size(), OS);
777 for (const auto *Entry : stabilizeTable(NameTable)) {
778 OS << Entry->first;
779 encodeULEB128(0, OS);
780 }
782}
783
784std::error_code
792
793std::error_code
795 // When calling write on a different profile map, existing names should be
796 // cleared.
797 NameTable.clear();
798
800
801 computeSummary(ProfileMap);
802 if (auto EC = writeSummary())
803 return EC;
804
805 // Generate the name table for all the functions referenced in the profile.
806 for (const auto &I : ProfileMap) {
807 addContext(I.second.getContext());
808 addNames(I.second);
809 }
810
813}
814
819
823
824void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
826
827 Writer.write(static_cast<uint64_t>(SectionHdrLayout.size()));
828 SecHdrTableOffset = OutputStream->tell();
829 for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) {
830 Writer.write(static_cast<uint64_t>(-1));
831 Writer.write(static_cast<uint64_t>(-1));
832 Writer.write(static_cast<uint64_t>(-1));
833 Writer.write(static_cast<uint64_t>(-1));
834 }
835}
836
837std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
838 assert(SecHdrTable.size() == SectionHdrLayout.size() &&
839 "SecHdrTable entries doesn't match SectionHdrLayout");
840 SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1);
841 for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) {
842 IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx;
843 }
844
845 // Write the section header table in the order specified in
846 // SectionHdrLayout. SectionHdrLayout specifies the sections
847 // order in which profile reader expect to read, so the section
848 // header table should be written in the order in SectionHdrLayout.
849 // Note that the section order in SecHdrTable may be different
850 // from the order in SectionHdrLayout, for example, SecFuncOffsetTable
851 // needs to be computed after SecLBRProfile (the order in SecHdrTable),
852 // but it needs to be read before SecLBRProfile (the order in
853 // SectionHdrLayout). So we use IndexMap above to switch the order.
854 support::endian::SeekableWriter Writer(
855 static_cast<raw_pwrite_stream &>(*OutputStream),
857 for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size();
858 LayoutIdx++) {
859 assert(IndexMap[LayoutIdx] < SecHdrTable.size() &&
860 "Incorrect LayoutIdx in SecHdrTable");
861 auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
862 Writer.pwrite(static_cast<uint64_t>(Entry.Type),
863 SecHdrTableOffset + 4 * LayoutIdx * sizeof(uint64_t));
864 Writer.pwrite(static_cast<uint64_t>(Entry.Flags),
865 SecHdrTableOffset + (4 * LayoutIdx + 1) * sizeof(uint64_t));
866 Writer.pwrite(static_cast<uint64_t>(Entry.Offset),
867 SecHdrTableOffset + (4 * LayoutIdx + 2) * sizeof(uint64_t));
868 Writer.pwrite(static_cast<uint64_t>(Entry.Size),
869 SecHdrTableOffset + (4 * LayoutIdx + 3) * sizeof(uint64_t));
870 }
871
873}
874
875std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
876 const SampleProfileMap &ProfileMap) {
877 auto &OS = *OutputStream;
878 FileStart = OS.tell();
880
881 allocSecHdrTable();
883}
884
888 "writeCallsiteVTableProf should not be called if WriteVTableProf is "
889 "false");
890
891 encodeULEB128(CallsiteTypeMap.size(), OS);
892 for (const auto &[Loc, TypeMap] : CallsiteTypeMap) {
893 Loc.serialize(OS);
894 if (std::error_code EC = serializeTypeMap(TypeMap, getNameTable(), OS))
895 return EC;
896 }
897
899}
900
902 auto &OS = *OutputStream;
903 encodeULEB128(Summary->getTotalCount(), OS);
904 encodeULEB128(Summary->getMaxCount(), OS);
905 encodeULEB128(Summary->getMaxFunctionCount(), OS);
906 encodeULEB128(Summary->getNumCounts(), OS);
907 encodeULEB128(Summary->getNumFunctions(), OS);
908 ArrayRef<ProfileSummaryEntry> Entries = Summary->getDetailedSummary();
909 encodeULEB128(Entries.size(), OS);
910 for (auto Entry : Entries) {
911 encodeULEB128(Entry.Cutoff, OS);
912 encodeULEB128(Entry.MinCount, OS);
913 encodeULEB128(Entry.NumCounts, OS);
914 }
916}
918 auto &OS = *OutputStream;
919 if (std::error_code EC = writeContextIdx(S.getContext()))
920 return EC;
921
923
924 // Emit all the body samples.
925 encodeULEB128(S.getBodySamples().size(), OS);
926 for (const auto &I : S.getBodySamples()) {
927 LineLocation Loc = I.first;
928 const SampleRecord &Sample = I.second;
929 Loc.serialize(OS);
930 Sample.serialize(OS, getNameTable());
931 }
932
933 // Recursively emit all the callsite samples.
934 uint64_t NumCallsites = 0;
935 for (const auto &J : S.getCallsiteSamples())
936 NumCallsites += J.second.size();
937 encodeULEB128(NumCallsites, OS);
938 for (const auto &J : S.getCallsiteSamples())
939 for (const auto &FS : J.second) {
940 J.first.serialize(OS);
941 if (std::error_code EC = writeBody(FS.second))
942 return EC;
943 }
944
945 if (WriteVTableProf)
947
949}
950
951/// Write samples of a top-level function to a binary file.
952///
953/// \returns true if the samples were written successfully, false otherwise.
954std::error_code
959
960/// Create a sample profile file writer based on the specified format.
961///
962/// \param Filename The file to create.
963///
964/// \param Format Encoding format for the profile file.
965///
966/// \returns an error code indicating the status of the created writer.
969 std::error_code EC;
970 std::unique_ptr<raw_ostream> OS;
972 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
973 else
975 if (EC)
976 return EC;
977
978 return create(OS, Format);
979}
980
981/// Create a sample profile stream writer based on the specified format.
982///
983/// \param OS The output stream to store the profile data to.
984///
985/// \param Format Encoding format for the profile file.
986///
987/// \returns an error code indicating the status of the created writer.
989SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
991 std::error_code EC;
992 std::unique_ptr<SampleProfileWriter> Writer;
993
994 // Currently only Text and Extended Binary format are supported for CSSPGO.
998
999 if (Format == SPF_Binary)
1000 Writer.reset(new SampleProfileWriterRawBinary(OS));
1001 else if (Format == SPF_Ext_Binary)
1002 Writer.reset(new SampleProfileWriterExtBinary(OS));
1003 else if (Format == SPF_Text)
1004 Writer.reset(new SampleProfileWriterText(OS));
1005 else if (Format == SPF_GCC)
1007 else
1009
1010 if (EC)
1011 return EC;
1012
1013 Writer->Format = Format;
1014 if (Format != SPF_Ext_Binary)
1015 Writer->setFormatVersion(DefaultVersion);
1017 Writer->setFormatVersion(RequestedVersion);
1018 else
1020 return std::move(Writer);
1021}
1022
1025 Summary = Builder.computeSummaryForProfiles(ProfileMap);
1026}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
Provides ErrorOr<T> smart pointer.
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 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 SmallVector< std::pair< KeyT, ValT > *, 0 > stabilizeTable(MapVector< KeyT, ValT > &Table)
static void splitProfileMapToTwo(const SampleProfileMap &ProfileMap, SampleProfileMap &ContextProfileMap, SampleProfileMap &NoContextProfileMap)
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"))
static cl::opt< bool > WriteMD5ProfSymList("md5-prof-sym-list", cl::init(false), cl::Hidden, cl::desc("Write ProfileSymbolList (Cold Symbols) as " "64-bit MD5 hashes in Eytzinger layout"))
#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
Represents either an error or a value T.
Definition ErrorOr.h:56
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.
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
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
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:810
static LLVM_ABI 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...
static LLVM_ABI bool ProfileIsCS
FunctionId getFunction() const
Return the function name.
const CallsiteTypeMap & getCallsiteTypeCounts() const
Returns vtable access samples for the C++ types collected in this function.
const TypeCountMap * findCallsiteTypeSamplesAt(const LineLocation &Loc) const
Returns the TypeCountMap for inlined callsites at the given Loc.
Definition SampleProf.h:993
static LLVM_ABI bool ProfileIsProbeBased
static LLVM_ABI bool ProfileIsFS
If this profile uses flow sensitive discriminators.
SampleContext & getContext() const
uint64_t getTotalSamples() const
Return the total number of samples collected inside the function.
const CallsiteSampleMap & getCallsiteSamples() const
Return all the callsite samples collected in the body of the function.
const BodySampleMap & getBodySamples() const
Return all the samples collected in the body of the function.
std::string toString() const
Definition SampleProf.h:698
This class provides operator overloads to the map container using MD5 as the key type,...
virtual void addContext(const SampleContext &Context)
virtual std::error_code writeMagicIdent(SampleProfileFormat Format)
MapVector< FunctionId, uint32_t > NameTable
std::error_code writeCallsiteVTableProf(const CallsiteTypeMap &CallsiteTypeMap, raw_ostream &OS)
Write CallsiteTypeMap to the output stream OS.
virtual std::error_code writeContextIdx(const SampleContext &Context)
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.
virtual MapVector< FunctionId, uint32_t > & getNameTable()
std::error_code writeBody(const FunctionSamples &S)
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, uint32_t LayoutIdx, const SampleProfileMap &ProfileMap)
std::error_code writeCSNameIdx(const SampleContext &Context)
virtual std::error_code writeSections(const SampleProfileMap &ProfileMap)=0
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 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:384
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
Definition SampleProf.h:452
SortedCallTargetSet getSortedCallTargets() const
Definition SampleProf.h:453
Sort a LocationT->SampleT map by LocationT.
const SamplesWithLocList & get() const
#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:112
static bool formatVersionIsSupported(uint64_t Version)
Definition SampleProf.h:130
static void addSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag)
Definition SampleProf.h:281
static bool hasSecFlag(const SecHdrTableEntry &Entry, SecFlagType Flag)
Definition SampleProf.h:297
std::pair< hash_code, const FunctionSamples * > NameFunctionSamples
@ SecFlagIsPreInlined
SecFlagIsPreInlined means this profile contains ShouldBeInlined contexts thus this is CS preinliner c...
Definition SampleProf.h:230
@ SecFlagHasVTableTypeProf
SecFlagHasVTableTypeProf means this profile contains vtable type profiles.
Definition SampleProf.h:233
@ SecFlagFSDiscriminator
SecFlagFSDiscriminator means this profile uses flow-sensitive discriminators.
Definition SampleProf.h:227
@ SecFlagFullContext
SecFlagContext means this is context-sensitive flat profile for CSSPGO.
Definition SampleProf.h:224
std::map< FunctionId, FunctionSamples > FunctionSamplesMap
Definition SampleProf.h:800
static constexpr uint64_t DefaultVersion
Definition SampleProf.h:124
std::map< FunctionId, uint64_t > TypeCountMap
Key represents type of a C++ polymorphic class type by its vtable and value represents its counter.
Definition SampleProf.h:364
constexpr char kVTableProfPrefix[]
Definition SampleProf.h:95
LLVM_ABI std::error_code serializeTypeMap(const TypeCountMap &Map, const MapVector< FunctionId, uint32_t > &NameTable, raw_ostream &OS)
Write Map to the output stream.
std::map< LineLocation, TypeCountMap > CallsiteTypeMap
Definition SampleProf.h:802
detail::packed_endian_specific_integral< uint64_t, llvm::endianness::little, unaligned > ulittle64_t
Definition Endian.h:293
@ 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:578
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
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
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
Definition iterator.h:368
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.
Represents the relative location of an instruction.
Definition SampleProf.h:313
Adapter to write values to a stream in a particular byte order.
void write(ArrayRef< value_type > Val)