llvm.org GIT mirror llvm / 6ef59a4
[SampleFDO] Add ExtBinary format to support extension of binary profile. This is a patch split from https://reviews.llvm.org/D66374. It tries to add a new format of profile called ExtBinary. The format adds a section header table to the profile and organize the profile in sections, so the future extension like adding a new section or extending an existing section will be easier while keeping backward compatiblity feasible. Differential Revision: https://reviews.llvm.org/D66513 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@369798 91177308-0d34-0410-b5e6-96231b3b80d8 Wei Mi 22 days ago
11 changed file(s) with 577 addition(s) and 202 deletion(s). Raw diff Collapse all Expand all
8383 SPF_Text = 0x1,
8484 SPF_Compact_Binary = 0x2,
8585 SPF_GCC = 0x3,
86 SPF_Ext_Binary = 0x4,
8687 SPF_Binary = 0xff
8788 };
8889
104105 }
105106
106107 static inline uint64_t SPVersion() { return 103; }
108
109 // Section Type used by SampleProfileExtBinaryBaseReader and
110 // SampleProfileExtBinaryBaseWriter. Never change the existing
111 // value of enum. Only append new ones.
112 enum SecType {
113 SecInValid = 0,
114 SecProfSummary = 1,
115 SecNameTable = 2,
116 // marker for the first type of profile.
117 SecFuncProfileFirst = 32,
118 SecLBRProfile = SecFuncProfileFirst
119 };
120
121 // Entry type of section header table used by SampleProfileExtBinaryBaseReader
122 // and SampleProfileExtBinaryBaseWriter.
123 struct SecHdrTableEntry {
124 SecType Type;
125 uint64_t Flag;
126 uint64_t Offset;
127 uint64_t Size;
128 };
107129
108130 /// Represents the relative location of an instruction.
109131 ///
415415 /// Read the contents of the given profile instance.
416416 std::error_code readProfile(FunctionSamples &FProfile);
417417
418 /// Read the contents of Magic number and Version number.
419 std::error_code readMagicIdent();
420
421 /// Read profile summary.
422 std::error_code readSummary();
423
424 /// Read the whole name table.
425 virtual std::error_code readNameTable();
426
418427 /// Points to the current location in the buffer.
419428 const uint8_t *Data = nullptr;
420429
421430 /// Points to the end of the buffer.
422431 const uint8_t *End = nullptr;
432
433 /// Function name table.
434 std::vector NameTable;
435
436 /// Read a string indirectly via the name table.
437 virtual ErrorOr readStringFromTable();
423438
424439 private:
425440 std::error_code readSummaryEntry(std::vector &Entries);
426441 virtual std::error_code verifySPMagic(uint64_t Magic) = 0;
427
428 /// Read profile summary.
429 std::error_code readSummary();
430
431 /// Read the whole name table.
432 virtual std::error_code readNameTable() = 0;
433
434 /// Read a string indirectly via the name table.
435 virtual ErrorOr readStringFromTable() = 0;
436442 };
437443
438444 class SampleProfileReaderRawBinary : public SampleProfileReaderBinary {
439445 private:
440 /// Function name table.
441 std::vector NameTable;
442446 virtual std::error_code verifySPMagic(uint64_t Magic) override;
443 virtual std::error_code readNameTable() override;
444 /// Read a string indirectly via the name table.
445 virtual ErrorOr readStringFromTable() override;
446
447 public:
448 SampleProfileReaderRawBinary(std::unique_ptr B, LLVMContext &C)
449 : SampleProfileReaderBinary(std::move(B), C, SPF_Binary) {}
447
448 public:
449 SampleProfileReaderRawBinary(std::unique_ptr B, LLVMContext &C,
450 SampleProfileFormat Format = SPF_Binary)
451 : SampleProfileReaderBinary(std::move(B), C, Format) {}
452
453 /// \brief Return true if \p Buffer is in the format supported by this class.
454 static bool hasFormat(const MemoryBuffer &Buffer);
455 };
456
457 /// SampleProfileReaderExtBinaryBase/SampleProfileWriterExtBinaryBase defines
458 /// the basic structure of the extensible binary format.
459 /// The format is organized in sections except the magic and version number
460 /// at the beginning. There is a section table before all the sections, and
461 /// each entry in the table describes the entry type, start, size and
462 /// attributes. The format in each section is defined by the section itself.
463 ///
464 /// It is easy to add a new section while maintaining the backward
465 /// compatibility of the profile. Nothing extra needs to be done. If we want
466 /// to extend an existing section, like add cache misses information in
467 /// addition to the sample count in the profile body, we can add a new section
468 /// with the extension and retire the existing section, and we could choose
469 /// to keep the parser of the old section if we want the reader to be able
470 /// to read both new and old format profile.
471 ///
472 /// SampleProfileReaderExtBinary/SampleProfileWriterExtBinary define the
473 /// commonly used sections of a profile in extensible binary format. It is
474 /// possible to define other types of profile inherited from
475 /// SampleProfileReaderExtBinaryBase/SampleProfileWriterExtBinaryBase.
476 class SampleProfileReaderExtBinaryBase : public SampleProfileReaderBinary {
477 protected:
478 std::vector SecHdrTable;
479 std::error_code readSecHdrTableEntry();
480 std::error_code readSecHdrTable();
481 virtual std::error_code readHeader() override;
482 virtual std::error_code verifySPMagic(uint64_t Magic) = 0;
483
484 public:
485 SampleProfileReaderExtBinaryBase(std::unique_ptr B,
486 LLVMContext &C, SampleProfileFormat Format)
487 : SampleProfileReaderBinary(std::move(B), C, Format) {}
488
489 /// Read sample profiles in extensible format from the associated file.
490 std::error_code read() override;
491 };
492
493 class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase {
494 private:
495 virtual std::error_code verifySPMagic(uint64_t Magic) override;
496
497 public:
498 SampleProfileReaderExtBinary(std::unique_ptr B, LLVMContext &C,
499 SampleProfileFormat Format = SPF_Ext_Binary)
500 : SampleProfileReaderExtBinaryBase(std::move(B), C, Format) {}
450501
451502 /// \brief Return true if \p Buffer is in the format supported by this class.
452503 static bool hasFormat(const MemoryBuffer &Buffer);
3535 /// Write sample profiles in \p S.
3636 ///
3737 /// \returns status code of the file update operation.
38 virtual std::error_code write(const FunctionSamples &S) = 0;
38 virtual std::error_code writeSample(const FunctionSamples &S) = 0;
3939
4040 /// Write all the sample profiles in the given map of samples.
4141 ///
6363 virtual std::error_code
6464 writeHeader(const StringMap &ProfileMap) = 0;
6565
66 // Write function profiles to the profile file.
67 virtual std::error_code
68 writeFuncProfiles(const StringMap &ProfileMap);
69
6670 /// Output stream where to emit the profile to.
6771 std::unique_ptr OutputStream;
6872
7175
7276 /// Compute summary for this profile.
7377 void computeSummary(const StringMap &ProfileMap);
78
79 /// Profile format.
80 SampleProfileFormat Format;
7481 };
7582
7683 /// Sample-based profile writer (text format).
7784 class SampleProfileWriterText : public SampleProfileWriter {
7885 public:
79 std::error_code write(const FunctionSamples &S) override;
86 std::error_code writeSample(const FunctionSamples &S) override;
8087
8188 protected:
8289 SampleProfileWriterText(std::unique_ptr &OS)
101108 /// Sample-based profile writer (binary format).
102109 class SampleProfileWriterBinary : public SampleProfileWriter {
103110 public:
104 virtual std::error_code write(const FunctionSamples &S) override;
111 virtual std::error_code writeSample(const FunctionSamples &S) override;
112
113 protected:
105114 SampleProfileWriterBinary(std::unique_ptr &OS)
106115 : SampleProfileWriter(OS) {}
107116
108 protected:
109 virtual std::error_code writeNameTable() = 0;
110 virtual std::error_code writeMagicIdent() = 0;
117 virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
118 virtual std::error_code writeNameTable();
111119 virtual std::error_code
112120 writeHeader(const StringMap &ProfileMap) override;
113121 std::error_code writeSummary();
117125
118126 MapVector NameTable;
119127
120 private:
121128 void addName(StringRef FName);
122129 void addNames(const FunctionSamples &S);
123130
131 private:
124132 friend ErrorOr>
125133 SampleProfileWriter::create(std::unique_ptr &OS,
126134 SampleProfileFormat Format);
128136
129137 class SampleProfileWriterRawBinary : public SampleProfileWriterBinary {
130138 using SampleProfileWriterBinary::SampleProfileWriterBinary;
131
132 protected:
133 virtual std::error_code writeNameTable() override;
134 virtual std::error_code writeMagicIdent() override;
139 };
140
141 class SampleProfileWriterExtBinaryBase : public SampleProfileWriterBinary {
142 using SampleProfileWriterBinary::SampleProfileWriterBinary;
143
144 public:
145 virtual std::error_code
146 write(const StringMap &ProfileMap) override;
147
148 protected:
149 uint64_t markSectionStart();
150 uint64_t addNewSection(SecType Sec, uint64_t SectionStart);
151 virtual void initSectionLayout() = 0;
152 virtual std::error_code
153 writeSections(const StringMap &ProfileMap) = 0;
154
155 // Specifiy the section layout in the profile. Note that the order in
156 // SecHdrTable (order to collect sections) may be different from the
157 // order in SectionLayout (order to write out sections into profile).
158 SmallVector SectionLayout;
159
160 private:
161 void allocSecHdrTable();
162 std::error_code writeSecHdrTable();
163 virtual std::error_code
164 writeHeader(const StringMap &ProfileMap) override;
165
166 // The location where the output stream starts.
167 uint64_t FileStart;
168 // The location in the output stream where the SecHdrTable should be
169 // written to.
170 uint64_t SecHdrTableOffset;
171 std::vector SecHdrTable;
172 };
173
174 class SampleProfileWriterExtBinary : public SampleProfileWriterExtBinaryBase {
175 using SampleProfileWriterExtBinaryBase::SampleProfileWriterExtBinaryBase;
176
177 private:
178 virtual void initSectionLayout() {
179 SectionLayout = {SecProfSummary, SecNameTable, SecLBRProfile};
180 };
181 virtual std::error_code
182 writeSections(const StringMap &ProfileMap) override;
135183 };
136184
137185 // CompactBinary is a compact format of binary profile which both reduces
168216 using SampleProfileWriterBinary::SampleProfileWriterBinary;
169217
170218 public:
171 virtual std::error_code write(const FunctionSamples &S) override;
219 virtual std::error_code writeSample(const FunctionSamples &S) override;
172220 virtual std::error_code
173221 write(const StringMap &ProfileMap) override;
174222
180228 /// towards profile start.
181229 uint64_t TableOffset;
182230 virtual std::error_code writeNameTable() override;
183 virtual std::error_code writeMagicIdent() override;
184231 virtual std::error_code
185232 writeHeader(const StringMap &ProfileMap) override;
186233 std::error_code writeFuncOffsetTable();
344344 return *Idx;
345345 }
346346
347 ErrorOr SampleProfileReaderRawBinary::readStringFromTable() {
347 ErrorOr SampleProfileReaderBinary::readStringFromTable() {
348348 auto Idx = readStringIndex(NameTable);
349349 if (std::error_code EC = Idx.getError())
350350 return EC;
461461 while (!at_eof()) {
462462 if (std::error_code EC = readFuncProfile())
463463 return EC;
464 }
465
466 return sampleprof_error::success;
467 }
468
469 std::error_code SampleProfileReaderExtBinaryBase::read() {
470 const uint8_t *BufStart =
471 reinterpret_cast(Buffer->getBufferStart());
472
473 for (auto &Entry : SecHdrTable) {
474 // Skip empty section.
475 if (!Entry.Size)
476 continue;
477 Data = BufStart + Entry.Offset;
478 switch (Entry.Type) {
479 case SecProfSummary:
480 if (std::error_code EC = readSummary())
481 return EC;
482 break;
483 case SecNameTable:
484 if (std::error_code EC = readNameTable())
485 return EC;
486 break;
487 case SecLBRProfile:
488 while (Data < BufStart + Entry.Offset + Entry.Size) {
489 if (std::error_code EC = readFuncProfile())
490 return EC;
491 }
492 break;
493 default:
494 continue;
495 }
496 if (Data != BufStart + Entry.Offset + Entry.Size)
497 return sampleprof_error::malformed;
464498 }
465499
466500 return sampleprof_error::success;
500534 return sampleprof_error::bad_magic;
501535 }
502536
537 std::error_code SampleProfileReaderExtBinary::verifySPMagic(uint64_t Magic) {
538 if (Magic == SPMagic(SPF_Ext_Binary))
539 return sampleprof_error::success;
540 return sampleprof_error::bad_magic;
541 }
542
503543 std::error_code
504544 SampleProfileReaderCompactBinary::verifySPMagic(uint64_t Magic) {
505545 if (Magic == SPMagic(SPF_Compact_Binary))
507547 return sampleprof_error::bad_magic;
508548 }
509549
510 std::error_code SampleProfileReaderRawBinary::readNameTable() {
550 std::error_code SampleProfileReaderBinary::readNameTable() {
511551 auto Size = readNumber();
512552 if (std::error_code EC = Size.getError())
513553 return EC;
536576 return sampleprof_error::success;
537577 }
538578
579 std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTableEntry() {
580 SecHdrTableEntry Entry;
581 auto Type = readUnencodedNumber();
582 if (std::error_code EC = Type.getError())
583 return EC;
584 Entry.Type = static_cast(*Type);
585
586 auto Flag = readUnencodedNumber();
587 if (std::error_code EC = Flag.getError())
588 return EC;
589 Entry.Flag = *Flag;
590
591 auto Offset = readUnencodedNumber();
592 if (std::error_code EC = Offset.getError())
593 return EC;
594 Entry.Offset = *Offset;
595
596 auto Size = readUnencodedNumber();
597 if (std::error_code EC = Size.getError())
598 return EC;
599 Entry.Size = *Size;
600
601 SecHdrTable.push_back(std::move(Entry));
602 return sampleprof_error::success;
603 }
604
605 std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTable() {
606 auto EntryNum = readUnencodedNumber();
607 if (std::error_code EC = EntryNum.getError())
608 return EC;
609
610 for (uint32_t i = 0; i < (*EntryNum); i++)
611 if (std::error_code EC = readSecHdrTableEntry())
612 return EC;
613
614 return sampleprof_error::success;
615 }
616
617 std::error_code SampleProfileReaderExtBinaryBase::readHeader() {
618 const uint8_t *BufStart =
619 reinterpret_cast(Buffer->getBufferStart());
620 Data = BufStart;
621 End = BufStart + Buffer->getBufferSize();
622
623 if (std::error_code EC = readMagicIdent())
624 return EC;
625
626 if (std::error_code EC = readSecHdrTable())
627 return EC;
628
629 return sampleprof_error::success;
630 }
631
632 std::error_code SampleProfileReaderBinary::readMagicIdent() {
633 // Read and check the magic identifier.
634 auto Magic = readNumber();
635 if (std::error_code EC = Magic.getError())
636 return EC;
637 else if (std::error_code EC = verifySPMagic(*Magic))
638 return EC;
639
640 // Read the version number.
641 auto Version = readNumber();
642 if (std::error_code EC = Version.getError())
643 return EC;
644 else if (*Version != SPVersion())
645 return sampleprof_error::unsupported_version;
646
647 return sampleprof_error::success;
648 }
649
539650 std::error_code SampleProfileReaderBinary::readHeader() {
540651 Data = reinterpret_cast(Buffer->getBufferStart());
541652 End = Data + Buffer->getBufferSize();
542653
543 // Read and check the magic identifier.
544 auto Magic = readNumber();
545 if (std::error_code EC = Magic.getError())
546 return EC;
547 else if (std::error_code EC = verifySPMagic(*Magic))
548 return EC;
549
550 // Read the version number.
551 auto Version = readNumber();
552 if (std::error_code EC = Version.getError())
553 return EC;
554 else if (*Version != SPVersion())
555 return sampleprof_error::unsupported_version;
654 if (std::error_code EC = readMagicIdent())
655 return EC;
556656
557657 if (std::error_code EC = readSummary())
558658 return EC;
671771 reinterpret_cast(Buffer.getBufferStart());
672772 uint64_t Magic = decodeULEB128(Data);
673773 return Magic == SPMagic();
774 }
775
776 bool SampleProfileReaderExtBinary::hasFormat(const MemoryBuffer &Buffer) {
777 const uint8_t *Data =
778 reinterpret_cast(Buffer.getBufferStart());
779 uint64_t Magic = decodeULEB128(Data);
780 return Magic == SPMagic(SPF_Ext_Binary);
674781 }
675782
676783 bool SampleProfileReaderCompactBinary::hasFormat(const MemoryBuffer &Buffer) {
10221129 std::unique_ptr Reader;
10231130 if (SampleProfileReaderRawBinary::hasFormat(*B))
10241131 Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C));
1132 else if (SampleProfileReaderExtBinary::hasFormat(*B))
1133 Reader.reset(new SampleProfileReaderExtBinary(std::move(B), C));
10251134 else if (SampleProfileReaderCompactBinary::hasFormat(*B))
10261135 Reader.reset(new SampleProfileReaderCompactBinary(std::move(B), C));
10271136 else if (SampleProfileReaderGCC::hasFormat(*B))
10321141 return sampleprof_error::unrecognized_format;
10331142
10341143 FunctionSamples::Format = Reader->getFormat();
1035 if (std::error_code EC = Reader->readHeader())
1036 return EC;
1144 if (std::error_code EC = Reader->readHeader()) {
1145 return EC;
1146 }
10371147
10381148 return std::move(Reader);
10391149 }
3838 using namespace llvm;
3939 using namespace sampleprof;
4040
41 std::error_code
42 SampleProfileWriter::write(const StringMap &ProfileMap) {
43 if (std::error_code EC = writeHeader(ProfileMap))
44 return EC;
45
41 std::error_code SampleProfileWriter::writeFuncProfiles(
42 const StringMap &ProfileMap) {
4643 // Sort the ProfileMap by total samples.
4744 typedef std::pair NameFunctionSamples;
4845 std::vector V;
5754 });
5855
5956 for (const auto &I : V) {
60 if (std::error_code EC = write(*I.second))
57 if (std::error_code EC = writeSample(*I.second))
6158 return EC;
6259 }
60 return sampleprof_error::success;
61 }
62
63 std::error_code
64 SampleProfileWriter::write(const StringMap &ProfileMap) {
65 if (std::error_code EC = writeHeader(ProfileMap))
66 return EC;
67
68 if (std::error_code EC = writeFuncProfiles(ProfileMap))
69 return EC;
70
71 return sampleprof_error::success;
72 }
73
74 /// Return the current position and prepare to use it as the start
75 /// position of a section.
76 uint64_t SampleProfileWriterExtBinaryBase::markSectionStart() {
77 return OutputStream->tell();
78 }
79
80 /// Add a new section into section header table. Return the position
81 /// of SectionEnd.
82 uint64_t
83 SampleProfileWriterExtBinaryBase::addNewSection(SecType Sec,
84 uint64_t SectionStart) {
85 uint64_t SectionEnd = OutputStream->tell();
86 SecHdrTable.push_back(
87 {Sec, 0, SectionStart - FileStart, SectionEnd - SectionStart});
88 return SectionEnd;
89 }
90
91 std::error_code SampleProfileWriterExtBinaryBase::write(
92 const StringMap &ProfileMap) {
93 if (std::error_code EC = writeHeader(ProfileMap))
94 return EC;
95
96 if (std::error_code EC = writeSections(ProfileMap))
97 return EC;
98
99 if (std::error_code EC = writeSecHdrTable())
100 return EC;
101
102 return sampleprof_error::success;
103 }
104
105 std::error_code SampleProfileWriterExtBinary::writeSections(
106 const StringMap &ProfileMap) {
107 uint64_t SectionStart = markSectionStart();
108 computeSummary(ProfileMap);
109 if (auto EC = writeSummary())
110 return EC;
111 SectionStart = addNewSection(SecProfSummary, SectionStart);
112
113 // Generate the name table for all the functions referenced in the profile.
114 for (const auto &I : ProfileMap) {
115 addName(I.first());
116 addNames(I.second);
117 }
118 writeNameTable();
119 SectionStart = addNewSection(SecNameTable, SectionStart);
120
121 if (std::error_code EC = writeFuncProfiles(ProfileMap))
122 return EC;
123 addNewSection(SecLBRProfile, SectionStart);
124
63125 return sampleprof_error::success;
64126 }
65127
80142 ///
81143 /// The format used here is more structured and deliberate because
82144 /// it needs to be parsed by the SampleProfileReaderText class.
83 std::error_code SampleProfileWriterText::write(const FunctionSamples &S) {
145 std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
84146 auto &OS = *OutputStream;
85147 OS << S.getName() << ":" << S.getTotalSamples();
86148 if (Indent == 0)
116178 OS << Loc.LineOffset << ": ";
117179 else
118180 OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
119 if (std::error_code EC = write(CalleeSamples))
181 if (std::error_code EC = writeSample(CalleeSamples))
120182 return EC;
121183 }
122184 Indent -= 1;
162224 NameTable[N] = i++;
163225 }
164226
165 std::error_code SampleProfileWriterRawBinary::writeNameTable() {
227 std::error_code SampleProfileWriterBinary::writeNameTable() {
166228 auto &OS = *OutputStream;
167229 std::set V;
168230 stablizeNameTable(V);
213275 return sampleprof_error::success;
214276 }
215277
216 std::error_code SampleProfileWriterRawBinary::writeMagicIdent() {
278 std::error_code
279 SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
217280 auto &OS = *OutputStream;
218281 // Write file magic identifier.
219 encodeULEB128(SPMagic(), OS);
282 encodeULEB128(SPMagic(Format), OS);
220283 encodeULEB128(SPVersion(), OS);
221284 return sampleprof_error::success;
222285 }
223286
224 std::error_code SampleProfileWriterCompactBinary::writeMagicIdent() {
225 auto &OS = *OutputStream;
226 // Write file magic identifier.
227 encodeULEB128(SPMagic(SPF_Compact_Binary), OS);
228 encodeULEB128(SPVersion(), OS);
229 return sampleprof_error::success;
230 }
231
232287 std::error_code SampleProfileWriterBinary::writeHeader(
233288 const StringMap &ProfileMap) {
234 writeMagicIdent();
289 writeMagicIdent(Format);
235290
236291 computeSummary(ProfileMap);
237292 if (auto EC = writeSummary())
244299 }
245300
246301 writeNameTable();
302 return sampleprof_error::success;
303 }
304
305 void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
306 support::endian::Writer Writer(*OutputStream, support::little);
307
308 Writer.write(static_cast(SectionLayout.size()));
309 SecHdrTableOffset = OutputStream->tell();
310 for (uint32_t i = 0; i < SectionLayout.size(); i++) {
311 Writer.write(static_cast(-1));
312 Writer.write(static_cast(-1));
313 Writer.write(static_cast(-1));
314 Writer.write(static_cast(-1));
315 }
316 }
317
318 std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
319 auto &OFS = static_cast(*OutputStream);
320 uint64_t Saved = OutputStream->tell();
321
322 // Set OutputStream to the location saved in SecHdrTableOffset.
323 if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
324 return sampleprof_error::ostream_seek_unsupported;
325 support::endian::Writer Writer(*OutputStream, support::little);
326
327 DenseMap IndexMap;
328 for (uint32_t i = 0; i < SecHdrTable.size(); i++) {
329 IndexMap.insert({static_cast(SecHdrTable[i].Type), i});
330 }
331
332 // Write the sections in the order specified in SectionLayout.
333 // That is the sections order Reader will see. Note that the
334 // sections order in which Reader expects to read may be different
335 // from the order in which Writer is able to write, so we need
336 // to adjust the order in SecHdrTable to be consistent with
337 // SectionLayout when we write SecHdrTable to the memory.
338 for (uint32_t i = 0; i < SectionLayout.size(); i++) {
339 uint32_t idx = IndexMap[static_cast(SectionLayout[i])];
340 Writer.write(static_cast(SecHdrTable[idx].Type));
341 Writer.write(static_cast(SecHdrTable[idx].Flag));
342 Writer.write(static_cast(SecHdrTable[idx].Offset));
343 Writer.write(static_cast(SecHdrTable[idx].Size));
344 }
345
346 // Reset OutputStream.
347 if (OFS.seek(Saved) == (uint64_t)-1)
348 return sampleprof_error::ostream_seek_unsupported;
349
350 return sampleprof_error::success;
351 }
352
353 std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
354 const StringMap &ProfileMap) {
355 auto &OS = *OutputStream;
356 FileStart = OS.tell();
357 writeMagicIdent(Format);
358
359 initSectionLayout();
360 allocSecHdrTable();
247361 return sampleprof_error::success;
248362 }
249363
323437 /// Write samples of a top-level function to a binary file.
324438 ///
325439 /// \returns true if the samples were written successfully, false otherwise.
326 std::error_code SampleProfileWriterBinary::write(const FunctionSamples &S) {
440 std::error_code
441 SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
327442 encodeULEB128(S.getHeadSamples(), *OutputStream);
328443 return writeBody(S);
329444 }
330445
331446 std::error_code
332 SampleProfileWriterCompactBinary::write(const FunctionSamples &S) {
447 SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
333448 uint64_t Offset = OutputStream->tell();
334449 StringRef Name = S.getName();
335450 FuncOffsetTable[Name] = Offset;
348463 SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
349464 std::error_code EC;
350465 std::unique_ptr OS;
351 if (Format == SPF_Binary || Format == SPF_Compact_Binary)
466 if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
467 Format == SPF_Compact_Binary)
352468 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
353469 else
354470 OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text));
373489
374490 if (Format == SPF_Binary)
375491 Writer.reset(new SampleProfileWriterRawBinary(OS));
492 else if (Format == SPF_Ext_Binary)
493 Writer.reset(new SampleProfileWriterExtBinary(OS));
376494 else if (Format == SPF_Compact_Binary)
377495 Writer.reset(new SampleProfileWriterCompactBinary(OS));
378496 else if (Format == SPF_Text)
385503 if (EC)
386504 return EC;
387505
506 Writer->Format = Format;
388507 return std::move(Writer);
389508 }
390509
+0
-121
test/Transforms/SampleProfile/compact-binary-profile.ll less more
None ; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.prof -S | FileCheck %s
1 ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.prof -S | FileCheck %s
2 ; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s
3 ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s
4
5 ; Original C++ test case
6 ;
7 ; #include
8 ;
9 ; int sum(int x, int y) {
10 ; return x + y;
11 ; }
12 ;
13 ; int main() {
14 ; int s, i = 0;
15 ; while (i++ < 20000 * 20000)
16 ; if (i != 100) s = sum(i, s); else s = 30;
17 ; printf("sum is %d\n", s);
18 ; return 0;
19 ; }
20 ;
21 @.str = private unnamed_addr constant [11 x i8] c"sum is %d\0A\00", align 1
22
23 ; Check sample-profile phase using compactbinary format profile will annotate
24 ; the IR with exactly the same result as using text format.
25 ; CHECK: br i1 %cmp, label %while.body, label %while.end{{.*}} !prof ![[IDX1:[0-9]*]]
26 ; CHECK: br i1 %cmp1, label %if.then, label %if.else{{.*}} !prof ![[IDX2:[0-9]*]]
27 ; CHECK: call i32 (i8*, ...) @printf{{.*}} !prof ![[IDX3:[0-9]*]]
28 ; CHECK: = !{!"TotalCount", i64 26781}
29 ; CHECK: = !{!"MaxCount", i64 5553}
30 ; CHECK: ![[IDX1]] = !{!"branch_weights", i32 5392, i32 163}
31 ; CHECK: ![[IDX2]] = !{!"branch_weights", i32 5280, i32 113}
32 ; CHECK: ![[IDX3]] = !{!"branch_weights", i32 1}
33
34 ; Function Attrs: nounwind uwtable
35 define i32 @_Z3sumii(i32 %x, i32 %y) !dbg !4 {
36 entry:
37 %x.addr = alloca i32, align 4
38 %y.addr = alloca i32, align 4
39 store i32 %x, i32* %x.addr, align 4
40 store i32 %y, i32* %y.addr, align 4
41 %0 = load i32, i32* %x.addr, align 4, !dbg !11
42 %1 = load i32, i32* %y.addr, align 4, !dbg !11
43 %add = add nsw i32 %0, %1, !dbg !11
44 ret i32 %add, !dbg !11
45 }
46
47 ; Function Attrs: uwtable
48 define i32 @main() !dbg !7 {
49 entry:
50 %retval = alloca i32, align 4
51 %s = alloca i32, align 4
52 %i = alloca i32, align 4
53 store i32 0, i32* %retval
54 store i32 0, i32* %i, align 4, !dbg !12
55 br label %while.cond, !dbg !13
56
57 while.cond: ; preds = %if.end, %entry
58 %0 = load i32, i32* %i, align 4, !dbg !14
59 %inc = add nsw i32 %0, 1, !dbg !14
60 store i32 %inc, i32* %i, align 4, !dbg !14
61 %cmp = icmp slt i32 %0, 400000000, !dbg !14
62 br i1 %cmp, label %while.body, label %while.end, !dbg !14
63
64 while.body: ; preds = %while.cond
65 %1 = load i32, i32* %i, align 4, !dbg !16
66 %cmp1 = icmp ne i32 %1, 100, !dbg !16
67 br i1 %cmp1, label %if.then, label %if.else, !dbg !16
68
69
70 if.then: ; preds = %while.body
71 %2 = load i32, i32* %i, align 4, !dbg !18
72 %3 = load i32, i32* %s, align 4, !dbg !18
73 %call = call i32 @_Z3sumii(i32 %2, i32 %3), !dbg !18
74 store i32 %call, i32* %s, align 4, !dbg !18
75 br label %if.end, !dbg !18
76
77 if.else: ; preds = %while.body
78 store i32 30, i32* %s, align 4, !dbg !20
79 br label %if.end
80
81 if.end: ; preds = %if.else, %if.then
82 br label %while.cond, !dbg !22
83
84 while.end: ; preds = %while.cond
85 %4 = load i32, i32* %s, align 4, !dbg !24
86 %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), i32 %4), !dbg !24
87 ret i32 0, !dbg !25
88 }
89
90 declare i32 @printf(i8*, ...) #2
91
92 !llvm.dbg.cu = !{!0}
93 !llvm.module.flags = !{!8, !9}
94 !llvm.ident = !{!10}
95
96 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5 ", isOptimized: false, emissionKind: NoDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
97 !1 = !DIFile(filename: "calls.cc", directory: ".")
98 !2 = !{}
99 !4 = distinct !DISubprogram(name: "sum", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 3, file: !1, scope: !5, type: !6, retainedNodes: !2)
100 !5 = !DIFile(filename: "calls.cc", directory: ".")
101 !6 = !DISubroutineType(types: !2)
102 !7 = distinct !DISubprogram(name: "main", line: 7, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 7, file: !1, scope: !5, type: !6, retainedNodes: !2)
103 !8 = !{i32 2, !"Dwarf Version", i32 4}
104 !9 = !{i32 1, !"Debug Info Version", i32 3}
105 !10 = !{!"clang version 3.5 "}
106 !11 = !DILocation(line: 4, scope: !4)
107 !12 = !DILocation(line: 8, scope: !7)
108 !13 = !DILocation(line: 9, scope: !7)
109 !14 = !DILocation(line: 9, scope: !15)
110 !15 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !7)
111 !16 = !DILocation(line: 10, scope: !17)
112 !17 = distinct !DILexicalBlock(line: 10, column: 0, file: !1, scope: !7)
113 !18 = !DILocation(line: 10, scope: !19)
114 !19 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !17)
115 !20 = !DILocation(line: 10, scope: !21)
116 !21 = !DILexicalBlockFile(discriminator: 4, file: !1, scope: !17)
117 !22 = !DILocation(line: 10, scope: !23)
118 !23 = !DILexicalBlockFile(discriminator: 6, file: !1, scope: !17)
119 !24 = !DILocation(line: 11, scope: !7)
120 !25 = !DILocation(line: 12, scope: !7)
0 ; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.prof -S | FileCheck %s
1 ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.prof -S | FileCheck %s
2 ; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s
3 ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s
4 ; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.extbinary.afdo -S | FileCheck %s
5 ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.extbinary.afdo -S | FileCheck %s
6
7 ; Original C++ test case
8 ;
9 ; #include
10 ;
11 ; int sum(int x, int y) {
12 ; return x + y;
13 ; }
14 ;
15 ; int main() {
16 ; int s, i = 0;
17 ; while (i++ < 20000 * 20000)
18 ; if (i != 100) s = sum(i, s); else s = 30;
19 ; printf("sum is %d\n", s);
20 ; return 0;
21 ; }
22 ;
23 @.str = private unnamed_addr constant [11 x i8] c"sum is %d\0A\00", align 1
24
25 ; Check sample-profile phase using compactbinary or extbinary format profile
26 ; will annotate the IR with exactly the same result as using text format.
27 ; CHECK: br i1 %cmp, label %while.body, label %while.end{{.*}} !prof ![[IDX1:[0-9]*]]
28 ; CHECK: br i1 %cmp1, label %if.then, label %if.else{{.*}} !prof ![[IDX2:[0-9]*]]
29 ; CHECK: call i32 (i8*, ...) @printf{{.*}} !prof ![[IDX3:[0-9]*]]
30 ; CHECK: = !{!"TotalCount", i64 26781}
31 ; CHECK: = !{!"MaxCount", i64 5553}
32 ; CHECK: ![[IDX1]] = !{!"branch_weights", i32 5392, i32 163}
33 ; CHECK: ![[IDX2]] = !{!"branch_weights", i32 5280, i32 113}
34 ; CHECK: ![[IDX3]] = !{!"branch_weights", i32 1}
35
36 ; Function Attrs: nounwind uwtable
37 define i32 @_Z3sumii(i32 %x, i32 %y) !dbg !4 {
38 entry:
39 %x.addr = alloca i32, align 4
40 %y.addr = alloca i32, align 4
41 store i32 %x, i32* %x.addr, align 4
42 store i32 %y, i32* %y.addr, align 4
43 %0 = load i32, i32* %x.addr, align 4, !dbg !11
44 %1 = load i32, i32* %y.addr, align 4, !dbg !11
45 %add = add nsw i32 %0, %1, !dbg !11
46 ret i32 %add, !dbg !11
47 }
48
49 ; Function Attrs: uwtable
50 define i32 @main() !dbg !7 {
51 entry:
52 %retval = alloca i32, align 4
53 %s = alloca i32, align 4
54 %i = alloca i32, align 4
55 store i32 0, i32* %retval
56 store i32 0, i32* %i, align 4, !dbg !12
57 br label %while.cond, !dbg !13
58
59 while.cond: ; preds = %if.end, %entry
60 %0 = load i32, i32* %i, align 4, !dbg !14
61 %inc = add nsw i32 %0, 1, !dbg !14
62 store i32 %inc, i32* %i, align 4, !dbg !14
63 %cmp = icmp slt i32 %0, 400000000, !dbg !14
64 br i1 %cmp, label %while.body, label %while.end, !dbg !14
65
66 while.body: ; preds = %while.cond
67 %1 = load i32, i32* %i, align 4, !dbg !16
68 %cmp1 = icmp ne i32 %1, 100, !dbg !16
69 br i1 %cmp1, label %if.then, label %if.else, !dbg !16
70
71
72 if.then: ; preds = %while.body
73 %2 = load i32, i32* %i, align 4, !dbg !18
74 %3 = load i32, i32* %s, align 4, !dbg !18
75 %call = call i32 @_Z3sumii(i32 %2, i32 %3), !dbg !18
76 store i32 %call, i32* %s, align 4, !dbg !18
77 br label %if.end, !dbg !18
78
79 if.else: ; preds = %while.body
80 store i32 30, i32* %s, align 4, !dbg !20
81 br label %if.end
82
83 if.end: ; preds = %if.else, %if.then
84 br label %while.cond, !dbg !22
85
86 while.end: ; preds = %while.cond
87 %4 = load i32, i32* %s, align 4, !dbg !24
88 %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), i32 %4), !dbg !24
89 ret i32 0, !dbg !25
90 }
91
92 declare i32 @printf(i8*, ...) #2
93
94 !llvm.dbg.cu = !{!0}
95 !llvm.module.flags = !{!8, !9}
96 !llvm.ident = !{!10}
97
98 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5 ", isOptimized: false, emissionKind: NoDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
99 !1 = !DIFile(filename: "calls.cc", directory: ".")
100 !2 = !{}
101 !4 = distinct !DISubprogram(name: "sum", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 3, file: !1, scope: !5, type: !6, retainedNodes: !2)
102 !5 = !DIFile(filename: "calls.cc", directory: ".")
103 !6 = !DISubroutineType(types: !2)
104 !7 = distinct !DISubprogram(name: "main", line: 7, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 7, file: !1, scope: !5, type: !6, retainedNodes: !2)
105 !8 = !{i32 2, !"Dwarf Version", i32 4}
106 !9 = !{i32 1, !"Debug Info Version", i32 3}
107 !10 = !{!"clang version 3.5 "}
108 !11 = !DILocation(line: 4, scope: !4)
109 !12 = !DILocation(line: 8, scope: !7)
110 !13 = !DILocation(line: 9, scope: !7)
111 !14 = !DILocation(line: 9, scope: !15)
112 !15 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !7)
113 !16 = !DILocation(line: 10, scope: !17)
114 !17 = distinct !DILexicalBlock(line: 10, column: 0, file: !1, scope: !7)
115 !18 = !DILocation(line: 10, scope: !19)
116 !19 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !17)
117 !20 = !DILocation(line: 10, scope: !21)
118 !21 = !DILexicalBlockFile(discriminator: 4, file: !1, scope: !17)
119 !22 = !DILocation(line: 10, scope: !23)
120 !23 = !DILexicalBlockFile(discriminator: 6, file: !1, scope: !17)
121 !24 = !DILocation(line: 11, scope: !7)
122 !25 = !DILocation(line: 12, scope: !7)
55 RUN: diff %t.1.proftext %S/Inputs/IR_profile.proftext
66 RUN: llvm-profdata merge --sample --binary -output=%t.2.profdata %S/Inputs/sample-profile.proftext
77 RUN: llvm-profdata merge --sample --text -output=%t.2.proftext %t.2.profdata
8 RUN: diff %t.2.proftext %S/Inputs/sample-profile.proftext
8 RUN: diff %t.2.proftext %S/Inputs/sample-profile.proftext
9 # Round trip from text --> extbinary --> text
10 RUN: llvm-profdata merge --sample --extbinary -output=%t.3.profdata %S/Inputs/sample-profile.proftext
11 RUN: llvm-profdata merge --sample --text -output=%t.3.proftext %t.3.profdata
12 RUN: diff %t.3.proftext %S/Inputs/sample-profile.proftext
13 # Round trip from text --> binary --> extbinary --> text
14 RUN: llvm-profdata merge --sample --binary -output=%t.4.profdata %S/Inputs/sample-profile.proftext
15 RUN: llvm-profdata merge --sample --extbinary -output=%t.5.profdata %t.4.profdata
16 RUN: llvm-profdata merge --sample --text -output=%t.4.proftext %t.5.profdata
17 RUN: diff %t.4.proftext %S/Inputs/sample-profile.proftext
3636 PF_None = 0,
3737 PF_Text,
3838 PF_Compact_Binary,
39 PF_Ext_Binary,
3940 PF_GCC,
4041 PF_Binary
4142 };
313314 exitWithError("Cannot write indexed profdata format to stdout.");
314315
315316 if (OutputFormat != PF_Binary && OutputFormat != PF_Compact_Binary &&
316 OutputFormat != PF_Text)
317 OutputFormat != PF_Ext_Binary && OutputFormat != PF_Text)
317318 exitWithError("Unknown format is specified.");
318319
319320 std::mutex ErrorLock;
424425 }
425426
426427 static sampleprof::SampleProfileFormat FormatMap[] = {
427 sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Compact_Binary,
428 sampleprof::SPF_GCC, sampleprof::SPF_Binary};
428 sampleprof::SPF_None,
429 sampleprof::SPF_Text,
430 sampleprof::SPF_Compact_Binary,
431 sampleprof::SPF_Ext_Binary,
432 sampleprof::SPF_GCC,
433 sampleprof::SPF_Binary};
429434
430435 static void mergeSampleProfile(const WeightedFileVector &Inputs,
431436 SymbolRemapper *Remapper,
582587 clEnumVal(sample, "Sample profile")));
583588 cl::opt OutputFormat(
584589 cl::desc("Format of output profile"), cl::init(PF_Binary),
585 cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"),
586 clEnumValN(PF_Compact_Binary, "compbinary",
587 "Compact binary encoding"),
588 clEnumValN(PF_Text, "text", "Text encoding"),
589 clEnumValN(PF_GCC, "gcc",
590 "GCC encoding (only meaningful for -sample)")));
590 cl::values(
591 clEnumValN(PF_Binary, "binary", "Binary encoding (default)"),
592 clEnumValN(PF_Compact_Binary, "compbinary",
593 "Compact binary encoding"),
594 clEnumValN(PF_Ext_Binary, "extbinary", "Extensible binary encoding"),
595 clEnumValN(PF_Text, "text", "Text encoding"),
596 clEnumValN(PF_GCC, "gcc",
597 "GCC encoding (only meaningful for -sample)")));
591598 cl::opt OutputSparse("sparse", cl::init(false),
592599 cl::desc("Generate a sparse profile (only meaningful for -instr)"));
593600 cl::opt NumThreads(
284284 testRoundTrip(SampleProfileFormat::SPF_Compact_Binary, false);
285285 }
286286
287 TEST_F(SampleProfTest, roundtrip_ext_binary_profile) {
288 testRoundTrip(SampleProfileFormat::SPF_Ext_Binary, false);
289 }
290
287291 TEST_F(SampleProfTest, remap_text_profile) {
288292 testRoundTrip(SampleProfileFormat::SPF_Text, true);
289293 }
290294
291295 TEST_F(SampleProfTest, remap_raw_binary_profile) {
292296 testRoundTrip(SampleProfileFormat::SPF_Binary, true);
297 }
298
299 TEST_F(SampleProfTest, remap_ext_binary_profile) {
300 testRoundTrip(SampleProfileFormat::SPF_Ext_Binary, true);
293301 }
294302
295303 TEST_F(SampleProfTest, sample_overflow_saturation) {