30
30
#include " llvm/Support/MD5.h"
31
31
#include " llvm/Support/raw_ostream.h"
32
32
#include < algorithm>
33
+ #include < cmath>
33
34
#include < cstdint>
34
35
#include < memory>
35
36
#include < set>
36
37
#include < system_error>
37
38
#include < utility>
38
39
#include < vector>
39
40
41
+ #define DEBUG_TYPE " llvm-profdata"
42
+
40
43
using namespace llvm ;
41
44
using namespace sampleprof ;
42
45
46
+ namespace llvm {
47
+ namespace support {
48
+ namespace endian {
49
+ namespace {
50
+
51
+ // Adapter class to llvm::support::endian::Writer for pwrite().
52
+ struct SeekableWriter {
53
+ raw_pwrite_stream &OS;
54
+ endianness Endian;
55
+ SeekableWriter (raw_pwrite_stream &OS, endianness Endian)
56
+ : OS(OS), Endian(Endian) {}
57
+
58
+ template <typename ValueType>
59
+ void pwrite (ValueType Val, size_t Offset) {
60
+ std::string StringBuf;
61
+ raw_string_ostream SStream (StringBuf);
62
+ Writer (SStream, Endian).write (Val);
63
+ OS.pwrite (StringBuf.data (), StringBuf.size (), Offset);
64
+ }
65
+ };
66
+
67
+ } // namespace
68
+ } // namespace endian
69
+ } // namespace support
70
+ } // namespace llvm
71
+
72
+ DefaultFunctionPruningStrategy::DefaultFunctionPruningStrategy (
73
+ SampleProfileMap &ProfileMap, size_t OutputSizeLimit)
74
+ : FunctionPruningStrategy(ProfileMap, OutputSizeLimit) {
75
+ sortFuncProfiles (ProfileMap, SortedFunctions);
76
+ }
77
+
78
+ void DefaultFunctionPruningStrategy::Erase (size_t CurrentOutputSize) {
79
+ double D = (double )OutputSizeLimit / CurrentOutputSize;
80
+ size_t NewSize = (size_t )round (ProfileMap.size () * D * D);
81
+ size_t NumToRemove = ProfileMap.size () - NewSize;
82
+ if (NumToRemove < 1 )
83
+ NumToRemove = 1 ;
84
+
85
+ assert (NumToRemove <= SortedFunctions.size ());
86
+ llvm::for_each (
87
+ llvm::make_range (SortedFunctions.begin () + SortedFunctions.size () -
88
+ NumToRemove,
89
+ SortedFunctions.end ()),
90
+ [&](const NameFunctionSamples &E) { ProfileMap.erase (E.first ); });
91
+ SortedFunctions.resize (SortedFunctions.size () - NumToRemove);
92
+ }
93
+
94
+ std::error_code SampleProfileWriter::writeWithSizeLimitInternal (
95
+ SampleProfileMap &ProfileMap, size_t OutputSizeLimit,
96
+ FunctionPruningStrategy *Strategy) {
97
+ if (OutputSizeLimit == 0 )
98
+ return write (ProfileMap);
99
+
100
+ size_t OriginalFunctionCount = ProfileMap.size ();
101
+
102
+ std::unique_ptr<raw_ostream> OriginalOutputStream;
103
+ OutputStream.swap (OriginalOutputStream);
104
+
105
+ size_t IterationCount = 0 ;
106
+ size_t TotalSize;
107
+
108
+ SmallVector<char > StringBuffer;
109
+ do {
110
+ StringBuffer.clear ();
111
+ OutputStream.reset (new raw_svector_ostream (StringBuffer));
112
+ if (std::error_code EC = write (ProfileMap))
113
+ return EC;
114
+
115
+ TotalSize = StringBuffer.size ();
116
+ // On Windows every "\n" is actually written as "\r\n" to disk but not to
117
+ // memory buffer, this difference should be added when considering the total
118
+ // output size.
119
+ #ifdef _WIN32
120
+ if (Format == SPF_Text)
121
+ TotalSize += LineCount;
122
+ #endif
123
+ if (TotalSize <= OutputSizeLimit)
124
+ break ;
125
+
126
+ Strategy->Erase (TotalSize);
127
+ IterationCount++;
128
+ } while (ProfileMap.size () != 0 );
129
+
130
+ if (ProfileMap.size () == 0 )
131
+ return sampleprof_error::too_large;
132
+
133
+ OutputStream.swap (OriginalOutputStream);
134
+ OutputStream->write (StringBuffer.data (), StringBuffer.size ());
135
+ LLVM_DEBUG (dbgs () << " Profile originally has " << OriginalFunctionCount
136
+ << " functions, reduced to " << ProfileMap.size () << " in "
137
+ << IterationCount << " iterations\n " );
138
+ // Silence warning on Release build.
139
+ (void )OriginalFunctionCount;
140
+ (void )IterationCount;
141
+ return sampleprof_error::success;
142
+ }
143
+
43
144
std::error_code
44
145
SampleProfileWriter::writeFuncProfiles (const SampleProfileMap &ProfileMap) {
45
146
std::vector<NameFunctionSamples> V;
@@ -116,6 +217,12 @@ std::error_code SampleProfileWriterExtBinaryBase::addNewSection(
116
217
117
218
std::error_code
118
219
SampleProfileWriterExtBinaryBase::write (const SampleProfileMap &ProfileMap) {
220
+ // When calling write on a different profile map, existing states should be
221
+ // cleared.
222
+ NameTable.clear ();
223
+ CSNameTable.clear ();
224
+ SecHdrTable.clear ();
225
+
119
226
if (std::error_code EC = writeHeader (ProfileMap))
120
227
return EC;
121
228
@@ -477,6 +584,7 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
477
584
if (Indent == 0 )
478
585
OS << " :" << S.getHeadSamples ();
479
586
OS << " \n " ;
587
+ LineCount++;
480
588
481
589
SampleSorter<LineLocation, SampleRecord> SortedSamples (S.getBodySamples ());
482
590
for (const auto &I : SortedSamples.get ()) {
@@ -493,6 +601,7 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
493
601
for (const auto &J : Sample.getSortedCallTargets ())
494
602
OS << " " << J.first << " :" << J.second ;
495
603
OS << " \n " ;
604
+ LineCount++;
496
605
}
497
606
498
607
SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples (
@@ -515,11 +624,13 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
515
624
if (FunctionSamples::ProfileIsProbeBased) {
516
625
OS.indent (Indent + 1 );
517
626
OS << " !CFGChecksum: " << S.getFunctionHash () << " \n " ;
627
+ LineCount++;
518
628
}
519
629
520
630
if (S.getContext ().getAllAttributes ()) {
521
631
OS.indent (Indent + 1 );
522
632
OS << " !Attributes: " << S.getContext ().getAllAttributes () << " \n " ;
633
+ LineCount++;
523
634
}
524
635
525
636
return sampleprof_error::success;
@@ -605,14 +716,10 @@ std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
605
716
auto &OS = *OutputStream;
606
717
607
718
// Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
608
- auto &OFS = static_cast <raw_fd_ostream &>(OS);
609
719
uint64_t FuncOffsetTableStart = OS.tell ();
610
- if (OFS.seek (TableOffset) == (uint64_t )-1 )
611
- return sampleprof_error::ostream_seek_unsupported;
612
- support::endian::Writer Writer (*OutputStream, support::little);
613
- Writer.write (FuncOffsetTableStart);
614
- if (OFS.seek (FuncOffsetTableStart) == (uint64_t )-1 )
615
- return sampleprof_error::ostream_seek_unsupported;
720
+ support::endian::SeekableWriter Writer (static_cast <raw_pwrite_stream &>(OS),
721
+ support::little);
722
+ Writer.pwrite (FuncOffsetTableStart, TableOffset);
616
723
617
724
// Write out the table size.
618
725
encodeULEB128 (FuncOffsetTable.size (), OS);
@@ -623,6 +730,7 @@ std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
623
730
return EC;
624
731
encodeULEB128 (Entry.second , OS);
625
732
}
733
+ FuncOffsetTable.clear ();
626
734
return sampleprof_error::success;
627
735
}
628
736
@@ -650,6 +758,10 @@ SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
650
758
651
759
std::error_code
652
760
SampleProfileWriterBinary::writeHeader (const SampleProfileMap &ProfileMap) {
761
+ // When calling write on a different profile map, existing names should be
762
+ // cleared.
763
+ NameTable.clear ();
764
+
653
765
writeMagicIdent (Format);
654
766
655
767
computeSummary (ProfileMap);
@@ -690,14 +802,6 @@ void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
690
802
}
691
803
692
804
std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable () {
693
- auto &OFS = static_cast <raw_fd_ostream &>(*OutputStream);
694
- uint64_t Saved = OutputStream->tell ();
695
-
696
- // Set OutputStream to the location saved in SecHdrTableOffset.
697
- if (OFS.seek (SecHdrTableOffset) == (uint64_t )-1 )
698
- return sampleprof_error::ostream_seek_unsupported;
699
- support::endian::Writer Writer (*OutputStream, support::little);
700
-
701
805
assert (SecHdrTable.size () == SectionHdrLayout.size () &&
702
806
" SecHdrTable entries doesn't match SectionHdrLayout" );
703
807
SmallVector<uint32_t , 16 > IndexMap (SecHdrTable.size (), -1 );
@@ -714,21 +818,23 @@ std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
714
818
// needs to be computed after SecLBRProfile (the order in SecHdrTable),
715
819
// but it needs to be read before SecLBRProfile (the order in
716
820
// SectionHdrLayout). So we use IndexMap above to switch the order.
821
+ support::endian::SeekableWriter Writer (
822
+ static_cast <raw_pwrite_stream &>(*OutputStream), support::little);
717
823
for (uint32_t LayoutIdx = 0 ; LayoutIdx < SectionHdrLayout.size ();
718
824
LayoutIdx++) {
719
825
assert (IndexMap[LayoutIdx] < SecHdrTable.size () &&
720
826
" Incorrect LayoutIdx in SecHdrTable" );
721
827
auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
722
- Writer.write (static_cast <uint64_t >(Entry.Type ));
723
- Writer.write (static_cast <uint64_t >(Entry.Flags ));
724
- Writer.write (static_cast <uint64_t >(Entry.Offset ));
725
- Writer.write (static_cast <uint64_t >(Entry.Size ));
828
+ Writer.pwrite (static_cast <uint64_t >(Entry.Type ),
829
+ SecHdrTableOffset + 4 * LayoutIdx * sizeof (uint64_t ));
830
+ Writer.pwrite (static_cast <uint64_t >(Entry.Flags ),
831
+ SecHdrTableOffset + (4 * LayoutIdx + 1 ) * sizeof (uint64_t ));
832
+ Writer.pwrite (static_cast <uint64_t >(Entry.Offset ),
833
+ SecHdrTableOffset + (4 * LayoutIdx + 2 ) * sizeof (uint64_t ));
834
+ Writer.pwrite (static_cast <uint64_t >(Entry.Size ),
835
+ SecHdrTableOffset + (4 * LayoutIdx + 3 ) * sizeof (uint64_t ));
726
836
}
727
837
728
- // Reset OutputStream.
729
- if (OFS.seek (Saved) == (uint64_t )-1 )
730
- return sampleprof_error::ostream_seek_unsupported;
731
-
732
838
return sampleprof_error::success;
733
839
}
734
840
0 commit comments