30
30
#include " llvm/Support/MD5.h"
31
31
#include " llvm/Support/raw_ostream.h"
32
32
#include < algorithm>
33
- #include < cmath>
34
33
#include < cstdint>
35
34
#include < memory>
36
35
#include < set>
37
36
#include < system_error>
38
37
#include < utility>
39
38
#include < vector>
40
39
41
- #define DEBUG_TYPE " llvm-profdata"
42
-
43
40
using namespace llvm ;
44
41
using namespace sampleprof ;
45
42
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
-
144
43
std::error_code
145
44
SampleProfileWriter::writeFuncProfiles (const SampleProfileMap &ProfileMap) {
146
45
std::vector<NameFunctionSamples> V;
@@ -217,12 +116,6 @@ std::error_code SampleProfileWriterExtBinaryBase::addNewSection(
217
116
218
117
std::error_code
219
118
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
-
226
119
if (std::error_code EC = writeHeader (ProfileMap))
227
120
return EC;
228
121
@@ -584,7 +477,6 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
584
477
if (Indent == 0 )
585
478
OS << " :" << S.getHeadSamples ();
586
479
OS << " \n " ;
587
- LineCount++;
588
480
589
481
SampleSorter<LineLocation, SampleRecord> SortedSamples (S.getBodySamples ());
590
482
for (const auto &I : SortedSamples.get ()) {
@@ -601,7 +493,6 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
601
493
for (const auto &J : Sample.getSortedCallTargets ())
602
494
OS << " " << J.first << " :" << J.second ;
603
495
OS << " \n " ;
604
- LineCount++;
605
496
}
606
497
607
498
SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples (
@@ -624,13 +515,11 @@ std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
624
515
if (FunctionSamples::ProfileIsProbeBased) {
625
516
OS.indent (Indent + 1 );
626
517
OS << " !CFGChecksum: " << S.getFunctionHash () << " \n " ;
627
- LineCount++;
628
518
}
629
519
630
520
if (S.getContext ().getAllAttributes ()) {
631
521
OS.indent (Indent + 1 );
632
522
OS << " !Attributes: " << S.getContext ().getAllAttributes () << " \n " ;
633
- LineCount++;
634
523
}
635
524
636
525
return sampleprof_error::success;
@@ -716,10 +605,14 @@ std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
716
605
auto &OS = *OutputStream;
717
606
718
607
// Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
608
+ auto &OFS = static_cast <raw_fd_ostream &>(OS);
719
609
uint64_t FuncOffsetTableStart = OS.tell ();
720
- support::endian::SeekableWriter Writer (static_cast <raw_pwrite_stream &>(OS),
721
- support::little);
722
- Writer.pwrite (FuncOffsetTableStart, TableOffset);
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;
723
616
724
617
// Write out the table size.
725
618
encodeULEB128 (FuncOffsetTable.size (), OS);
@@ -730,7 +623,6 @@ std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
730
623
return EC;
731
624
encodeULEB128 (Entry.second , OS);
732
625
}
733
- FuncOffsetTable.clear ();
734
626
return sampleprof_error::success;
735
627
}
736
628
@@ -758,10 +650,6 @@ SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
758
650
759
651
std::error_code
760
652
SampleProfileWriterBinary::writeHeader (const SampleProfileMap &ProfileMap) {
761
- // When calling write on a different profile map, existing names should be
762
- // cleared.
763
- NameTable.clear ();
764
-
765
653
writeMagicIdent (Format);
766
654
767
655
computeSummary (ProfileMap);
@@ -802,6 +690,14 @@ void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
802
690
}
803
691
804
692
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
+
805
701
assert (SecHdrTable.size () == SectionHdrLayout.size () &&
806
702
" SecHdrTable entries doesn't match SectionHdrLayout" );
807
703
SmallVector<uint32_t , 16 > IndexMap (SecHdrTable.size (), -1 );
@@ -818,23 +714,21 @@ std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
818
714
// needs to be computed after SecLBRProfile (the order in SecHdrTable),
819
715
// but it needs to be read before SecLBRProfile (the order in
820
716
// SectionHdrLayout). So we use IndexMap above to switch the order.
821
- support::endian::SeekableWriter Writer (
822
- static_cast <raw_pwrite_stream &>(*OutputStream), support::little);
823
717
for (uint32_t LayoutIdx = 0 ; LayoutIdx < SectionHdrLayout.size ();
824
718
LayoutIdx++) {
825
719
assert (IndexMap[LayoutIdx] < SecHdrTable.size () &&
826
720
" Incorrect LayoutIdx in SecHdrTable" );
827
721
auto Entry = SecHdrTable[IndexMap[LayoutIdx]];
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 ));
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 ));
836
726
}
837
727
728
+ // Reset OutputStream.
729
+ if (OFS.seek (Saved) == (uint64_t )-1 )
730
+ return sampleprof_error::ostream_seek_unsupported;
731
+
838
732
return sampleprof_error::success;
839
733
}
840
734
0 commit comments