1 //===- unittest/ProfileData/InstrProfTest.cpp -------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/IR/Function.h"
10 #include "llvm/IR/IRBuilder.h"
11 #include "llvm/IR/LLVMContext.h"
12 #include "llvm/IR/Module.h"
13 #include "llvm/ProfileData/InstrProfReader.h"
14 #include "llvm/ProfileData/InstrProfWriter.h"
15 #include "llvm/ProfileData/MemProf.h"
16 #include "llvm/ProfileData/MemProfData.inc"
17 #include "llvm/Support/Compression.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include "llvm/Testing/Support/Error.h"
20 #include "gtest/gtest.h"
24 using ::testing::EndsWith
;
25 using ::testing::IsSubsetOf
;
26 using ::testing::SizeIs
;
27 using ::testing::UnorderedElementsAre
;
29 [[nodiscard
]] static ::testing::AssertionResult
30 ErrorEquals(instrprof_error Expected
, Error E
) {
31 instrprof_error Found
;
33 handleAllErrors(std::move(E
), [&](const InstrProfError
&IPE
) {
35 FoundMsg
= IPE
.message();
37 if (Expected
== Found
)
38 return ::testing::AssertionSuccess();
39 return ::testing::AssertionFailure() << "error: " << FoundMsg
<< "\n";
43 bool operator==(const TemporalProfTraceTy
&lhs
,
44 const TemporalProfTraceTy
&rhs
) {
45 return lhs
.Weight
== rhs
.Weight
&&
46 lhs
.FunctionNameRefs
== rhs
.FunctionNameRefs
;
48 } // end namespace llvm
52 struct InstrProfTest
: ::testing::Test
{
53 InstrProfWriter Writer
;
54 std::unique_ptr
<IndexedInstrProfReader
> Reader
;
56 void SetUp() override
{ Writer
.setOutputSparse(false); }
58 void readProfile(std::unique_ptr
<MemoryBuffer
> Profile
,
59 std::unique_ptr
<MemoryBuffer
> Remapping
= nullptr) {
60 auto ReaderOrErr
= IndexedInstrProfReader::create(std::move(Profile
),
61 std::move(Remapping
));
62 EXPECT_THAT_ERROR(ReaderOrErr
.takeError(), Succeeded());
63 Reader
= std::move(ReaderOrErr
.get());
67 struct SparseInstrProfTest
: public InstrProfTest
{
68 void SetUp() override
{ Writer
.setOutputSparse(true); }
71 struct InstrProfReaderWriterTest
72 : public InstrProfTest
,
73 public ::testing::WithParamInterface
<
74 std::tuple
<bool, uint64_t, llvm::endianness
>> {
75 void SetUp() override
{ Writer
.setOutputSparse(std::get
<0>(GetParam())); }
76 void TearDown() override
{
77 // Reset writer value profile data endianness after each test case. Note
78 // it's not necessary to reset reader value profile endianness for each test
79 // case. Each test case creates a new reader; at reader initialization time,
80 // it uses the endianness from hash table object (which is little by
82 Writer
.setValueProfDataEndianness(llvm::endianness::little
);
85 uint64_t getProfWeight() const { return std::get
<1>(GetParam()); }
87 llvm::endianness
getEndianness() const { return std::get
<2>(GetParam()); }
90 struct MaybeSparseInstrProfTest
: public InstrProfTest
,
91 public ::testing::WithParamInterface
<bool> {
92 void SetUp() override
{ Writer
.setOutputSparse(GetParam()); }
95 TEST_P(MaybeSparseInstrProfTest
, write_and_read_empty_profile
) {
96 auto Profile
= Writer
.writeBuffer();
97 readProfile(std::move(Profile
));
98 ASSERT_TRUE(Reader
->begin() == Reader
->end());
101 static const auto Err
= [](Error E
) {
102 consumeError(std::move(E
));
106 TEST_P(MaybeSparseInstrProfTest
, write_and_read_one_function
) {
107 Writer
.addRecord({"foo", 0x1234, {1, 2, 3, 4}}, Err
);
108 auto Profile
= Writer
.writeBuffer();
109 readProfile(std::move(Profile
));
111 auto I
= Reader
->begin(), E
= Reader
->end();
113 ASSERT_EQ(StringRef("foo"), I
->Name
);
114 ASSERT_EQ(0x1234U
, I
->Hash
);
115 ASSERT_EQ(4U, I
->Counts
.size());
116 ASSERT_EQ(1U, I
->Counts
[0]);
117 ASSERT_EQ(2U, I
->Counts
[1]);
118 ASSERT_EQ(3U, I
->Counts
[2]);
119 ASSERT_EQ(4U, I
->Counts
[3]);
120 ASSERT_TRUE(++I
== E
);
123 TEST_P(MaybeSparseInstrProfTest
, get_instr_prof_record
) {
124 Writer
.addRecord({"foo", 0x1234, {1, 2}}, Err
);
125 Writer
.addRecord({"foo", 0x1235, {3, 4}}, Err
);
126 auto Profile
= Writer
.writeBuffer();
127 readProfile(std::move(Profile
));
129 Expected
<InstrProfRecord
> R
= Reader
->getInstrProfRecord("foo", 0x1234);
130 EXPECT_THAT_ERROR(R
.takeError(), Succeeded());
131 ASSERT_EQ(2U, R
->Counts
.size());
132 ASSERT_EQ(1U, R
->Counts
[0]);
133 ASSERT_EQ(2U, R
->Counts
[1]);
135 R
= Reader
->getInstrProfRecord("foo", 0x1235);
136 EXPECT_THAT_ERROR(R
.takeError(), Succeeded());
137 ASSERT_EQ(2U, R
->Counts
.size());
138 ASSERT_EQ(3U, R
->Counts
[0]);
139 ASSERT_EQ(4U, R
->Counts
[1]);
141 R
= Reader
->getInstrProfRecord("foo", 0x5678);
142 ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch
, R
.takeError()));
144 R
= Reader
->getInstrProfRecord("bar", 0x1234);
145 ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function
, R
.takeError()));
148 TEST_P(MaybeSparseInstrProfTest
, get_function_counts
) {
149 Writer
.addRecord({"foo", 0x1234, {1, 2}}, Err
);
150 Writer
.addRecord({"foo", 0x1235, {3, 4}}, Err
);
151 auto Profile
= Writer
.writeBuffer();
152 readProfile(std::move(Profile
));
154 std::vector
<uint64_t> Counts
;
155 EXPECT_THAT_ERROR(Reader
->getFunctionCounts("foo", 0x1234, Counts
),
157 ASSERT_EQ(2U, Counts
.size());
158 ASSERT_EQ(1U, Counts
[0]);
159 ASSERT_EQ(2U, Counts
[1]);
161 EXPECT_THAT_ERROR(Reader
->getFunctionCounts("foo", 0x1235, Counts
),
163 ASSERT_EQ(2U, Counts
.size());
164 ASSERT_EQ(3U, Counts
[0]);
165 ASSERT_EQ(4U, Counts
[1]);
167 Error E1
= Reader
->getFunctionCounts("foo", 0x5678, Counts
);
168 ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch
, std::move(E1
)));
170 Error E2
= Reader
->getFunctionCounts("bar", 0x1234, Counts
);
171 ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function
, std::move(E2
)));
174 // Profile data is copied from general.proftext
175 TEST_F(InstrProfTest
, get_profile_summary
) {
176 Writer
.addRecord({"func1", 0x1234, {97531}}, Err
);
177 Writer
.addRecord({"func2", 0x1234, {0, 0}}, Err
);
181 {2305843009213693952, 1152921504606846976, 576460752303423488,
182 288230376151711744, 144115188075855872, 72057594037927936}},
184 Writer
.addRecord({"func4", 0x1234, {0}}, Err
);
185 auto Profile
= Writer
.writeBuffer();
186 readProfile(std::move(Profile
));
188 auto VerifySummary
= [](ProfileSummary
&IPS
) mutable {
189 ASSERT_EQ(ProfileSummary::PSK_Instr
, IPS
.getKind());
190 ASSERT_EQ(2305843009213693952U, IPS
.getMaxFunctionCount());
191 ASSERT_EQ(2305843009213693952U, IPS
.getMaxCount());
192 ASSERT_EQ(10U, IPS
.getNumCounts());
193 ASSERT_EQ(4539628424389557499U, IPS
.getTotalCount());
194 const std::vector
<ProfileSummaryEntry
> &Details
= IPS
.getDetailedSummary();
195 uint32_t Cutoff
= 800000;
196 auto Predicate
= [&Cutoff
](const ProfileSummaryEntry
&PE
) {
197 return PE
.Cutoff
== Cutoff
;
199 auto EightyPerc
= find_if(Details
, Predicate
);
201 auto NinetyPerc
= find_if(Details
, Predicate
);
203 auto NinetyFivePerc
= find_if(Details
, Predicate
);
205 auto NinetyNinePerc
= find_if(Details
, Predicate
);
206 ASSERT_EQ(576460752303423488U, EightyPerc
->MinCount
);
207 ASSERT_EQ(288230376151711744U, NinetyPerc
->MinCount
);
208 ASSERT_EQ(288230376151711744U, NinetyFivePerc
->MinCount
);
209 ASSERT_EQ(72057594037927936U, NinetyNinePerc
->MinCount
);
211 ProfileSummary
&PS
= Reader
->getSummary(/* IsCS */ false);
214 // Test that conversion of summary to and from Metadata works.
216 Metadata
*MD
= PS
.getMD(Context
);
218 ProfileSummary
*PSFromMD
= ProfileSummary::getFromMD(MD
);
219 ASSERT_TRUE(PSFromMD
);
220 VerifySummary(*PSFromMD
);
223 // Test that summary can be attached to and read back from module.
224 Module
M("my_module", Context
);
225 M
.setProfileSummary(MD
, ProfileSummary::PSK_Instr
);
226 MD
= M
.getProfileSummary(/* IsCS */ false);
228 PSFromMD
= ProfileSummary::getFromMD(MD
);
229 ASSERT_TRUE(PSFromMD
);
230 VerifySummary(*PSFromMD
);
234 TEST_F(InstrProfTest
, test_writer_merge
) {
235 Writer
.addRecord({"func1", 0x1234, {42}}, Err
);
237 InstrProfWriter Writer2
;
238 Writer2
.addRecord({"func2", 0x1234, {0, 0}}, Err
);
240 Writer
.mergeRecordsFromWriter(std::move(Writer2
), Err
);
242 auto Profile
= Writer
.writeBuffer();
243 readProfile(std::move(Profile
));
245 Expected
<InstrProfRecord
> R
= Reader
->getInstrProfRecord("func1", 0x1234);
246 EXPECT_THAT_ERROR(R
.takeError(), Succeeded());
247 ASSERT_EQ(1U, R
->Counts
.size());
248 ASSERT_EQ(42U, R
->Counts
[0]);
250 R
= Reader
->getInstrProfRecord("func2", 0x1234);
251 EXPECT_THAT_ERROR(R
.takeError(), Succeeded());
252 ASSERT_EQ(2U, R
->Counts
.size());
253 ASSERT_EQ(0U, R
->Counts
[0]);
254 ASSERT_EQ(0U, R
->Counts
[1]);
257 TEST_F(InstrProfTest
, test_merge_temporal_prof_traces_truncated
) {
258 uint64_t ReservoirSize
= 10;
259 uint64_t MaxTraceLength
= 2;
260 InstrProfWriter
Writer(/*Sparse=*/false, ReservoirSize
, MaxTraceLength
);
261 ASSERT_THAT_ERROR(Writer
.mergeProfileKind(InstrProfKind::TemporalProfile
),
264 TemporalProfTraceTy LargeTrace
, SmallTrace
;
265 LargeTrace
.FunctionNameRefs
= {IndexedInstrProf::ComputeHash("foo"),
266 IndexedInstrProf::ComputeHash("bar"),
267 IndexedInstrProf::ComputeHash("goo")};
268 SmallTrace
.FunctionNameRefs
= {IndexedInstrProf::ComputeHash("foo"),
269 IndexedInstrProf::ComputeHash("bar")};
271 SmallVector
<TemporalProfTraceTy
, 4> Traces
= {LargeTrace
, SmallTrace
};
272 Writer
.addTemporalProfileTraces(Traces
, 2);
274 auto Profile
= Writer
.writeBuffer();
275 readProfile(std::move(Profile
));
277 ASSERT_TRUE(Reader
->hasTemporalProfile());
278 EXPECT_EQ(Reader
->getTemporalProfTraceStreamSize(), 2U);
279 EXPECT_THAT(Reader
->getTemporalProfTraces(),
280 UnorderedElementsAre(SmallTrace
, SmallTrace
));
283 TEST_F(InstrProfTest
, test_merge_traces_from_writer
) {
284 uint64_t ReservoirSize
= 10;
285 uint64_t MaxTraceLength
= 10;
286 InstrProfWriter
Writer(/*Sparse=*/false, ReservoirSize
, MaxTraceLength
);
287 InstrProfWriter
Writer2(/*Sparse=*/false, ReservoirSize
, MaxTraceLength
);
288 ASSERT_THAT_ERROR(Writer
.mergeProfileKind(InstrProfKind::TemporalProfile
),
290 ASSERT_THAT_ERROR(Writer2
.mergeProfileKind(InstrProfKind::TemporalProfile
),
293 TemporalProfTraceTy FooTrace
, BarTrace
;
294 FooTrace
.FunctionNameRefs
= {IndexedInstrProf::ComputeHash("foo")};
295 BarTrace
.FunctionNameRefs
= {IndexedInstrProf::ComputeHash("bar")};
297 SmallVector
<TemporalProfTraceTy
, 4> Traces1({FooTrace
}), Traces2({BarTrace
});
298 Writer
.addTemporalProfileTraces(Traces1
, 1);
299 Writer2
.addTemporalProfileTraces(Traces2
, 1);
300 Writer
.mergeRecordsFromWriter(std::move(Writer2
), Err
);
302 auto Profile
= Writer
.writeBuffer();
303 readProfile(std::move(Profile
));
305 ASSERT_TRUE(Reader
->hasTemporalProfile());
306 EXPECT_EQ(Reader
->getTemporalProfTraceStreamSize(), 2U);
307 EXPECT_THAT(Reader
->getTemporalProfTraces(),
308 UnorderedElementsAre(FooTrace
, BarTrace
));
311 TEST_F(InstrProfTest
, test_merge_traces_sampled
) {
312 uint64_t ReservoirSize
= 3;
313 uint64_t MaxTraceLength
= 10;
314 InstrProfWriter
Writer(/*Sparse=*/false, ReservoirSize
, MaxTraceLength
);
315 ASSERT_THAT_ERROR(Writer
.mergeProfileKind(InstrProfKind::TemporalProfile
),
318 TemporalProfTraceTy FooTrace
, BarTrace
, GooTrace
;
319 FooTrace
.FunctionNameRefs
= {IndexedInstrProf::ComputeHash("foo")};
320 BarTrace
.FunctionNameRefs
= {IndexedInstrProf::ComputeHash("bar")};
321 GooTrace
.FunctionNameRefs
= {IndexedInstrProf::ComputeHash("Goo")};
323 // Add some sampled traces
324 SmallVector
<TemporalProfTraceTy
, 4> SampledTraces
= {FooTrace
, BarTrace
,
326 Writer
.addTemporalProfileTraces(SampledTraces
, 5);
327 // Add some unsampled traces
328 SmallVector
<TemporalProfTraceTy
, 4> UnsampledTraces
= {BarTrace
, GooTrace
};
329 Writer
.addTemporalProfileTraces(UnsampledTraces
, 2);
330 UnsampledTraces
= {FooTrace
};
331 Writer
.addTemporalProfileTraces(UnsampledTraces
, 1);
333 auto Profile
= Writer
.writeBuffer();
334 readProfile(std::move(Profile
));
336 ASSERT_TRUE(Reader
->hasTemporalProfile());
337 EXPECT_EQ(Reader
->getTemporalProfTraceStreamSize(), 8U);
338 // Check that we have a subset of all the traces we added
339 EXPECT_THAT(Reader
->getTemporalProfTraces(), SizeIs(ReservoirSize
));
341 Reader
->getTemporalProfTraces(),
342 IsSubsetOf({FooTrace
, BarTrace
, GooTrace
, BarTrace
, GooTrace
, FooTrace
}));
345 using ::llvm::memprof::IndexedMemProfRecord
;
346 using ::llvm::memprof::MemInfoBlock
;
348 llvm::DenseMap
<::llvm::memprof::FrameId
, ::llvm::memprof::Frame
>;
350 static FrameIdMapTy
getFrameMapping() {
351 FrameIdMapTy Mapping
;
352 Mapping
.insert({0, {0x123, 1, 2, false}});
353 Mapping
.insert({1, {0x345, 3, 4, true}});
354 Mapping
.insert({2, {0x125, 5, 6, false}});
355 Mapping
.insert({3, {0x567, 7, 8, true}});
356 Mapping
.insert({4, {0x124, 5, 6, false}});
357 Mapping
.insert({5, {0x789, 8, 9, true}});
361 IndexedMemProfRecord
makeRecord(
362 std::initializer_list
<std::initializer_list
<::llvm::memprof::FrameId
>>
364 std::initializer_list
<std::initializer_list
<::llvm::memprof::FrameId
>>
366 const MemInfoBlock
&Block
= MemInfoBlock()) {
367 llvm::memprof::IndexedMemProfRecord MR
;
368 for (const auto &Frames
: AllocFrames
)
369 MR
.AllocSites
.emplace_back(Frames
, Block
);
370 for (const auto &Frames
: CallSiteFrames
)
371 MR
.CallSites
.push_back(Frames
);
375 MATCHER_P(EqualsRecord
, Want
, "") {
376 const memprof::MemProfRecord
&Got
= arg
;
378 auto PrintAndFail
= [&]() {
380 llvm::raw_string_ostream
OS(Buffer
);
386 *result_listener
<< "MemProf Record differs!\n" << Buffer
;
390 if (Want
.AllocSites
.size() != Got
.AllocSites
.size())
391 return PrintAndFail();
392 if (Want
.CallSites
.size() != Got
.CallSites
.size())
393 return PrintAndFail();
395 for (size_t I
= 0; I
< Got
.AllocSites
.size(); I
++) {
396 if (Want
.AllocSites
[I
].Info
!= Got
.AllocSites
[I
].Info
)
397 return PrintAndFail();
398 if (Want
.AllocSites
[I
].CallStack
!= Got
.AllocSites
[I
].CallStack
)
399 return PrintAndFail();
402 for (size_t I
= 0; I
< Got
.CallSites
.size(); I
++) {
403 if (Want
.CallSites
[I
] != Got
.CallSites
[I
])
404 return PrintAndFail();
409 TEST_F(InstrProfTest
, test_memprof
) {
410 ASSERT_THAT_ERROR(Writer
.mergeProfileKind(InstrProfKind::MemProf
),
413 const IndexedMemProfRecord IndexedMR
= makeRecord(
422 const FrameIdMapTy IdToFrameMap
= getFrameMapping();
423 for (const auto &I
: IdToFrameMap
) {
424 Writer
.addMemProfFrame(I
.first
, I
.getSecond(), Err
);
426 Writer
.addMemProfRecord(/*Id=*/0x9999, IndexedMR
);
428 auto Profile
= Writer
.writeBuffer();
429 readProfile(std::move(Profile
));
431 auto RecordOr
= Reader
->getMemProfRecord(0x9999);
432 ASSERT_THAT_ERROR(RecordOr
.takeError(), Succeeded());
433 const memprof::MemProfRecord
&Record
= RecordOr
.get();
435 memprof::FrameId LastUnmappedFrameId
= 0;
436 bool HasFrameMappingError
= false;
437 auto IdToFrameCallback
= [&](const memprof::FrameId Id
) {
438 auto Iter
= IdToFrameMap
.find(Id
);
439 if (Iter
== IdToFrameMap
.end()) {
440 LastUnmappedFrameId
= Id
;
441 HasFrameMappingError
= true;
442 return memprof::Frame(0, 0, 0, false);
447 const memprof::MemProfRecord
WantRecord(IndexedMR
, IdToFrameCallback
);
448 ASSERT_FALSE(HasFrameMappingError
)
449 << "could not map frame id: " << LastUnmappedFrameId
;
450 EXPECT_THAT(WantRecord
, EqualsRecord(Record
));
453 TEST_F(InstrProfTest
, test_memprof_getrecord_error
) {
454 ASSERT_THAT_ERROR(Writer
.mergeProfileKind(InstrProfKind::MemProf
),
457 const IndexedMemProfRecord IndexedMR
= makeRecord(
466 // We skip adding the frame mappings here unlike the test_memprof unit test
467 // above to exercise the failure path when getMemProfRecord is invoked.
468 Writer
.addMemProfRecord(/*Id=*/0x9999, IndexedMR
);
470 auto Profile
= Writer
.writeBuffer();
471 readProfile(std::move(Profile
));
473 // Missing frames give a hash_mismatch error.
474 auto RecordOr
= Reader
->getMemProfRecord(0x9999);
476 ErrorEquals(instrprof_error::hash_mismatch
, RecordOr
.takeError()));
478 // Missing functions give a unknown_function error.
479 RecordOr
= Reader
->getMemProfRecord(0x1111);
481 ErrorEquals(instrprof_error::unknown_function
, RecordOr
.takeError()));
484 TEST_F(InstrProfTest
, test_memprof_merge
) {
485 Writer
.addRecord({"func1", 0x1234, {42}}, Err
);
487 InstrProfWriter Writer2
;
488 ASSERT_THAT_ERROR(Writer2
.mergeProfileKind(InstrProfKind::MemProf
),
491 const IndexedMemProfRecord IndexedMR
= makeRecord(
501 const FrameIdMapTy IdToFrameMap
= getFrameMapping();
502 for (const auto &I
: IdToFrameMap
) {
503 Writer
.addMemProfFrame(I
.first
, I
.getSecond(), Err
);
505 Writer2
.addMemProfRecord(/*Id=*/0x9999, IndexedMR
);
507 ASSERT_THAT_ERROR(Writer
.mergeProfileKind(Writer2
.getProfileKind()),
509 Writer
.mergeRecordsFromWriter(std::move(Writer2
), Err
);
511 auto Profile
= Writer
.writeBuffer();
512 readProfile(std::move(Profile
));
514 Expected
<InstrProfRecord
> R
= Reader
->getInstrProfRecord("func1", 0x1234);
515 EXPECT_THAT_ERROR(R
.takeError(), Succeeded());
516 ASSERT_EQ(1U, R
->Counts
.size());
517 ASSERT_EQ(42U, R
->Counts
[0]);
519 auto RecordOr
= Reader
->getMemProfRecord(0x9999);
520 ASSERT_THAT_ERROR(RecordOr
.takeError(), Succeeded());
521 const memprof::MemProfRecord
&Record
= RecordOr
.get();
523 memprof::FrameId LastUnmappedFrameId
= 0;
524 bool HasFrameMappingError
= false;
526 auto IdToFrameCallback
= [&](const memprof::FrameId Id
) {
527 auto Iter
= IdToFrameMap
.find(Id
);
528 if (Iter
== IdToFrameMap
.end()) {
529 LastUnmappedFrameId
= Id
;
530 HasFrameMappingError
= true;
531 return memprof::Frame(0, 0, 0, false);
536 const memprof::MemProfRecord
WantRecord(IndexedMR
, IdToFrameCallback
);
537 ASSERT_FALSE(HasFrameMappingError
)
538 << "could not map frame id: " << LastUnmappedFrameId
;
539 EXPECT_THAT(WantRecord
, EqualsRecord(Record
));
542 TEST_F(InstrProfTest
, test_irpgo_function_name
) {
544 auto M
= std::make_unique
<Module
>("MyModule.cpp", Ctx
);
545 auto *FTy
= FunctionType::get(Type::getVoidTy(Ctx
), /*isVarArg=*/false);
547 std::vector
<std::tuple
<StringRef
, Function::LinkageTypes
, StringRef
>> Data
;
548 Data
.emplace_back("ExternalFoo", Function::ExternalLinkage
, "ExternalFoo");
549 Data
.emplace_back("InternalFoo", Function::InternalLinkage
,
550 "MyModule.cpp;InternalFoo");
551 Data
.emplace_back("\01-[C dynamicFoo:]", Function::ExternalLinkage
,
553 Data
.emplace_back("\01-[C internalFoo:]", Function::InternalLinkage
,
554 "MyModule.cpp;-[C internalFoo:]");
556 for (auto &[Name
, Linkage
, ExpectedIRPGOFuncName
] : Data
)
557 Function::Create(FTy
, Linkage
, Name
, M
.get());
559 for (auto &[Name
, Linkage
, ExpectedIRPGOFuncName
] : Data
) {
560 auto *F
= M
->getFunction(Name
);
561 auto IRPGOFuncName
= getIRPGOFuncName(*F
);
562 EXPECT_EQ(IRPGOFuncName
, ExpectedIRPGOFuncName
);
564 auto [Filename
, ParsedIRPGOFuncName
] =
565 getParsedIRPGOFuncName(IRPGOFuncName
);
566 StringRef ExpectedParsedIRPGOFuncName
= IRPGOFuncName
;
567 if (ExpectedParsedIRPGOFuncName
.consume_front("MyModule.cpp;")) {
568 EXPECT_EQ(Filename
, "MyModule.cpp");
570 EXPECT_EQ(Filename
, "");
572 EXPECT_EQ(ParsedIRPGOFuncName
, ExpectedParsedIRPGOFuncName
);
576 TEST_F(InstrProfTest
, test_pgo_function_name
) {
578 auto M
= std::make_unique
<Module
>("MyModule.cpp", Ctx
);
579 auto *FTy
= FunctionType::get(Type::getVoidTy(Ctx
), /*isVarArg=*/false);
581 std::vector
<std::tuple
<StringRef
, Function::LinkageTypes
, StringRef
>> Data
;
582 Data
.emplace_back("ExternalFoo", Function::ExternalLinkage
, "ExternalFoo");
583 Data
.emplace_back("InternalFoo", Function::InternalLinkage
,
584 "MyModule.cpp:InternalFoo");
585 Data
.emplace_back("\01-[C externalFoo:]", Function::ExternalLinkage
,
586 "-[C externalFoo:]");
587 Data
.emplace_back("\01-[C internalFoo:]", Function::InternalLinkage
,
588 "MyModule.cpp:-[C internalFoo:]");
590 for (auto &[Name
, Linkage
, ExpectedPGOFuncName
] : Data
)
591 Function::Create(FTy
, Linkage
, Name
, M
.get());
593 for (auto &[Name
, Linkage
, ExpectedPGOFuncName
] : Data
) {
594 auto *F
= M
->getFunction(Name
);
595 EXPECT_EQ(getPGOFuncName(*F
), ExpectedPGOFuncName
);
599 TEST_F(InstrProfTest
, test_irpgo_read_deprecated_names
) {
601 auto M
= std::make_unique
<Module
>("MyModule.cpp", Ctx
);
602 auto *FTy
= FunctionType::get(Type::getVoidTy(Ctx
), /*isVarArg=*/false);
604 Function::Create(FTy
, Function::InternalLinkage
, "InternalFoo", M
.get());
606 Function::Create(FTy
, Function::ExternalLinkage
, "ExternalFoo", M
.get());
609 Function::Create(FTy
, Function::InternalLinkage
, "InternalBar", M
.get());
611 Function::Create(FTy
, Function::ExternalLinkage
, "ExternalBar", M
.get());
613 Writer
.addRecord({getIRPGOFuncName(*InternalFooF
), 0x1234, {1}}, Err
);
614 Writer
.addRecord({getIRPGOFuncName(*ExternalFooF
), 0x5678, {1}}, Err
);
615 // Write a record with a deprecated name
616 Writer
.addRecord({getPGOFuncName(*InternalBarF
), 0x1111, {2}}, Err
);
617 Writer
.addRecord({getPGOFuncName(*ExternalBarF
), 0x2222, {2}}, Err
);
619 auto Profile
= Writer
.writeBuffer();
620 readProfile(std::move(Profile
));
622 EXPECT_THAT_EXPECTED(
623 Reader
->getInstrProfRecord(getIRPGOFuncName(*InternalFooF
), 0x1234,
624 getPGOFuncName(*InternalFooF
)),
626 EXPECT_THAT_EXPECTED(
627 Reader
->getInstrProfRecord(getIRPGOFuncName(*ExternalFooF
), 0x5678,
628 getPGOFuncName(*ExternalFooF
)),
630 // Ensure we can still read this old record name
631 EXPECT_THAT_EXPECTED(
632 Reader
->getInstrProfRecord(getIRPGOFuncName(*InternalBarF
), 0x1111,
633 getPGOFuncName(*InternalBarF
)),
635 EXPECT_THAT_EXPECTED(
636 Reader
->getInstrProfRecord(getIRPGOFuncName(*ExternalBarF
), 0x2222,
637 getPGOFuncName(*ExternalBarF
)),
641 static const char callee1
[] = "callee1";
642 static const char callee2
[] = "callee2";
643 static const char callee3
[] = "callee3";
644 static const char callee4
[] = "callee4";
645 static const char callee5
[] = "callee5";
646 static const char callee6
[] = "callee6";
648 TEST_P(InstrProfReaderWriterTest
, icall_data_read_write
) {
649 NamedInstrProfRecord
Record1("caller", 0x1234, {1, 2});
652 Record1
.reserveSites(IPVK_IndirectCallTarget
, 4);
653 InstrProfValueData VD0
[] = {
654 {(uint64_t)callee1
, 1}, {(uint64_t)callee2
, 2}, {(uint64_t)callee3
, 3}};
655 Record1
.addValueData(IPVK_IndirectCallTarget
, 0, VD0
, 3, nullptr);
656 // No value profile data at the second site.
657 Record1
.addValueData(IPVK_IndirectCallTarget
, 1, nullptr, 0, nullptr);
658 InstrProfValueData VD2
[] = {{(uint64_t)callee1
, 1}, {(uint64_t)callee2
, 2}};
659 Record1
.addValueData(IPVK_IndirectCallTarget
, 2, VD2
, 2, nullptr);
660 InstrProfValueData VD3
[] = {{(uint64_t)callee1
, 1}};
661 Record1
.addValueData(IPVK_IndirectCallTarget
, 3, VD3
, 1, nullptr);
663 Writer
.addRecord(std::move(Record1
), getProfWeight(), Err
);
664 Writer
.addRecord({"callee1", 0x1235, {3, 4}}, Err
);
665 Writer
.addRecord({"callee2", 0x1235, {3, 4}}, Err
);
666 Writer
.addRecord({"callee3", 0x1235, {3, 4}}, Err
);
668 // Set writer value prof data endianness.
669 Writer
.setValueProfDataEndianness(getEndianness());
671 auto Profile
= Writer
.writeBuffer();
672 readProfile(std::move(Profile
));
674 // Set reader value prof data endianness.
675 Reader
->setValueProfDataEndianness(getEndianness());
677 Expected
<InstrProfRecord
> R
= Reader
->getInstrProfRecord("caller", 0x1234);
678 ASSERT_THAT_ERROR(R
.takeError(), Succeeded());
679 ASSERT_EQ(4U, R
->getNumValueSites(IPVK_IndirectCallTarget
));
680 EXPECT_EQ(3U, R
->getNumValueDataForSite(IPVK_IndirectCallTarget
, 0));
681 EXPECT_EQ(0U, R
->getNumValueDataForSite(IPVK_IndirectCallTarget
, 1));
682 EXPECT_EQ(2U, R
->getNumValueDataForSite(IPVK_IndirectCallTarget
, 2));
683 EXPECT_EQ(1U, R
->getNumValueDataForSite(IPVK_IndirectCallTarget
, 3));
686 std::unique_ptr
<InstrProfValueData
[]> VD
=
687 R
->getValueForSite(IPVK_IndirectCallTarget
, 0, &TotalC
);
689 EXPECT_EQ(3U * getProfWeight(), VD
[0].Count
);
690 EXPECT_EQ(2U * getProfWeight(), VD
[1].Count
);
691 EXPECT_EQ(1U * getProfWeight(), VD
[2].Count
);
692 EXPECT_EQ(6U * getProfWeight(), TotalC
);
694 EXPECT_EQ(StringRef((const char *)VD
[0].Value
, 7), StringRef("callee3"));
695 EXPECT_EQ(StringRef((const char *)VD
[1].Value
, 7), StringRef("callee2"));
696 EXPECT_EQ(StringRef((const char *)VD
[2].Value
, 7), StringRef("callee1"));
699 INSTANTIATE_TEST_SUITE_P(
700 WeightAndEndiannessTest
, InstrProfReaderWriterTest
,
702 ::testing::Bool(), /* Sparse */
703 ::testing::Values(1U, 10U), /* ProfWeight */
704 ::testing::Values(llvm::endianness::big
,
705 llvm::endianness::little
) /* Endianness */
708 TEST_P(MaybeSparseInstrProfTest
, annotate_vp_data
) {
709 NamedInstrProfRecord
Record("caller", 0x1234, {1, 2});
710 Record
.reserveSites(IPVK_IndirectCallTarget
, 1);
711 InstrProfValueData VD0
[] = {{1000, 1}, {2000, 2}, {3000, 3}, {5000, 5},
712 {4000, 4}, {6000, 6}};
713 Record
.addValueData(IPVK_IndirectCallTarget
, 0, VD0
, 6, nullptr);
714 Writer
.addRecord(std::move(Record
), Err
);
715 auto Profile
= Writer
.writeBuffer();
716 readProfile(std::move(Profile
));
717 Expected
<InstrProfRecord
> R
= Reader
->getInstrProfRecord("caller", 0x1234);
718 EXPECT_THAT_ERROR(R
.takeError(), Succeeded());
721 std::unique_ptr
<Module
> M(new Module("MyModule", Ctx
));
722 FunctionType
*FTy
= FunctionType::get(Type::getVoidTy(Ctx
),
725 Function::Create(FTy
, Function::ExternalLinkage
, "caller", M
.get());
726 BasicBlock
*BB
= BasicBlock::Create(Ctx
, "", F
);
728 IRBuilder
<> Builder(BB
);
729 BasicBlock
*TBB
= BasicBlock::Create(Ctx
, "", F
);
730 BasicBlock
*FBB
= BasicBlock::Create(Ctx
, "", F
);
732 // Use branch instruction to annotate with value profile data for simplicity
733 Instruction
*Inst
= Builder
.CreateCondBr(Builder
.getTrue(), TBB
, FBB
);
734 Instruction
*Inst2
= Builder
.CreateCondBr(Builder
.getTrue(), TBB
, FBB
);
735 annotateValueSite(*M
, *Inst
, R
.get(), IPVK_IndirectCallTarget
, 0);
737 InstrProfValueData ValueData
[5];
740 bool Res
= getValueProfDataFromInst(*Inst
, IPVK_IndirectCallTarget
, 5,
745 // The result should be sorted already:
746 ASSERT_EQ(6000U, ValueData
[0].Value
);
747 ASSERT_EQ(6U, ValueData
[0].Count
);
748 ASSERT_EQ(5000U, ValueData
[1].Value
);
749 ASSERT_EQ(5U, ValueData
[1].Count
);
750 ASSERT_EQ(4000U, ValueData
[2].Value
);
751 ASSERT_EQ(4U, ValueData
[2].Count
);
752 Res
= getValueProfDataFromInst(*Inst
, IPVK_IndirectCallTarget
, 1, ValueData
,
758 Res
= getValueProfDataFromInst(*Inst2
, IPVK_IndirectCallTarget
, 5, ValueData
,
762 // Remove the MD_prof metadata
763 Inst
->setMetadata(LLVMContext::MD_prof
, 0);
764 // Annotate 5 records this time.
765 annotateValueSite(*M
, *Inst
, R
.get(), IPVK_IndirectCallTarget
, 0, 5);
766 Res
= getValueProfDataFromInst(*Inst
, IPVK_IndirectCallTarget
, 5,
771 ASSERT_EQ(6000U, ValueData
[0].Value
);
772 ASSERT_EQ(6U, ValueData
[0].Count
);
773 ASSERT_EQ(5000U, ValueData
[1].Value
);
774 ASSERT_EQ(5U, ValueData
[1].Count
);
775 ASSERT_EQ(4000U, ValueData
[2].Value
);
776 ASSERT_EQ(4U, ValueData
[2].Count
);
777 ASSERT_EQ(3000U, ValueData
[3].Value
);
778 ASSERT_EQ(3U, ValueData
[3].Count
);
779 ASSERT_EQ(2000U, ValueData
[4].Value
);
780 ASSERT_EQ(2U, ValueData
[4].Count
);
782 // Remove the MD_prof metadata
783 Inst
->setMetadata(LLVMContext::MD_prof
, 0);
784 // Annotate with 4 records.
785 InstrProfValueData VD0Sorted
[] = {{1000, 6}, {2000, 5}, {3000, 4}, {4000, 3},
786 {5000, 2}, {6000, 1}};
787 annotateValueSite(*M
, *Inst
, ArrayRef(VD0Sorted
).slice(2), 10,
788 IPVK_IndirectCallTarget
, 5);
789 Res
= getValueProfDataFromInst(*Inst
, IPVK_IndirectCallTarget
, 5,
794 ASSERT_EQ(3000U, ValueData
[0].Value
);
795 ASSERT_EQ(4U, ValueData
[0].Count
);
796 ASSERT_EQ(4000U, ValueData
[1].Value
);
797 ASSERT_EQ(3U, ValueData
[1].Count
);
798 ASSERT_EQ(5000U, ValueData
[2].Value
);
799 ASSERT_EQ(2U, ValueData
[2].Count
);
800 ASSERT_EQ(6000U, ValueData
[3].Value
);
801 ASSERT_EQ(1U, ValueData
[3].Count
);
804 TEST_P(MaybeSparseInstrProfTest
, icall_data_merge
) {
805 static const char caller
[] = "caller";
806 NamedInstrProfRecord
Record11(caller
, 0x1234, {1, 2});
807 NamedInstrProfRecord
Record12(caller
, 0x1234, {1, 2});
810 Record11
.reserveSites(IPVK_IndirectCallTarget
, 5);
811 InstrProfValueData VD0
[] = {{uint64_t(callee1
), 1},
812 {uint64_t(callee2
), 2},
813 {uint64_t(callee3
), 3},
814 {uint64_t(callee4
), 4}};
815 Record11
.addValueData(IPVK_IndirectCallTarget
, 0, VD0
, 4, nullptr);
817 // No value profile data at the second site.
818 Record11
.addValueData(IPVK_IndirectCallTarget
, 1, nullptr, 0, nullptr);
820 InstrProfValueData VD2
[] = {
821 {uint64_t(callee1
), 1}, {uint64_t(callee2
), 2}, {uint64_t(callee3
), 3}};
822 Record11
.addValueData(IPVK_IndirectCallTarget
, 2, VD2
, 3, nullptr);
824 InstrProfValueData VD3
[] = {{uint64_t(callee1
), 1}};
825 Record11
.addValueData(IPVK_IndirectCallTarget
, 3, VD3
, 1, nullptr);
827 InstrProfValueData VD4
[] = {{uint64_t(callee1
), 1},
828 {uint64_t(callee2
), 2},
829 {uint64_t(callee3
), 3}};
830 Record11
.addValueData(IPVK_IndirectCallTarget
, 4, VD4
, 3, nullptr);
832 // A different record for the same caller.
833 Record12
.reserveSites(IPVK_IndirectCallTarget
, 5);
834 InstrProfValueData VD02
[] = {{uint64_t(callee2
), 5}, {uint64_t(callee3
), 3}};
835 Record12
.addValueData(IPVK_IndirectCallTarget
, 0, VD02
, 2, nullptr);
837 // No value profile data at the second site.
838 Record12
.addValueData(IPVK_IndirectCallTarget
, 1, nullptr, 0, nullptr);
840 InstrProfValueData VD22
[] = {
841 {uint64_t(callee2
), 1}, {uint64_t(callee3
), 3}, {uint64_t(callee4
), 4}};
842 Record12
.addValueData(IPVK_IndirectCallTarget
, 2, VD22
, 3, nullptr);
844 Record12
.addValueData(IPVK_IndirectCallTarget
, 3, nullptr, 0, nullptr);
846 InstrProfValueData VD42
[] = {{uint64_t(callee1
), 1},
847 {uint64_t(callee2
), 2},
848 {uint64_t(callee3
), 3}};
849 Record12
.addValueData(IPVK_IndirectCallTarget
, 4, VD42
, 3, nullptr);
851 Writer
.addRecord(std::move(Record11
), Err
);
852 // Merge profile data.
853 Writer
.addRecord(std::move(Record12
), Err
);
855 Writer
.addRecord({callee1
, 0x1235, {3, 4}}, Err
);
856 Writer
.addRecord({callee2
, 0x1235, {3, 4}}, Err
);
857 Writer
.addRecord({callee3
, 0x1235, {3, 4}}, Err
);
858 Writer
.addRecord({callee3
, 0x1235, {3, 4}}, Err
);
859 Writer
.addRecord({callee4
, 0x1235, {3, 5}}, Err
);
860 auto Profile
= Writer
.writeBuffer();
861 readProfile(std::move(Profile
));
863 Expected
<InstrProfRecord
> R
= Reader
->getInstrProfRecord("caller", 0x1234);
864 EXPECT_THAT_ERROR(R
.takeError(), Succeeded());
865 ASSERT_EQ(5U, R
->getNumValueSites(IPVK_IndirectCallTarget
));
866 ASSERT_EQ(4U, R
->getNumValueDataForSite(IPVK_IndirectCallTarget
, 0));
867 ASSERT_EQ(0U, R
->getNumValueDataForSite(IPVK_IndirectCallTarget
, 1));
868 ASSERT_EQ(4U, R
->getNumValueDataForSite(IPVK_IndirectCallTarget
, 2));
869 ASSERT_EQ(1U, R
->getNumValueDataForSite(IPVK_IndirectCallTarget
, 3));
870 ASSERT_EQ(3U, R
->getNumValueDataForSite(IPVK_IndirectCallTarget
, 4));
872 std::unique_ptr
<InstrProfValueData
[]> VD
=
873 R
->getValueForSite(IPVK_IndirectCallTarget
, 0);
874 ASSERT_EQ(StringRef((const char *)VD
[0].Value
, 7), StringRef("callee2"));
875 ASSERT_EQ(7U, VD
[0].Count
);
876 ASSERT_EQ(StringRef((const char *)VD
[1].Value
, 7), StringRef("callee3"));
877 ASSERT_EQ(6U, VD
[1].Count
);
878 ASSERT_EQ(StringRef((const char *)VD
[2].Value
, 7), StringRef("callee4"));
879 ASSERT_EQ(4U, VD
[2].Count
);
880 ASSERT_EQ(StringRef((const char *)VD
[3].Value
, 7), StringRef("callee1"));
881 ASSERT_EQ(1U, VD
[3].Count
);
883 std::unique_ptr
<InstrProfValueData
[]> VD_2(
884 R
->getValueForSite(IPVK_IndirectCallTarget
, 2));
885 ASSERT_EQ(StringRef((const char *)VD_2
[0].Value
, 7), StringRef("callee3"));
886 ASSERT_EQ(6U, VD_2
[0].Count
);
887 ASSERT_EQ(StringRef((const char *)VD_2
[1].Value
, 7), StringRef("callee4"));
888 ASSERT_EQ(4U, VD_2
[1].Count
);
889 ASSERT_EQ(StringRef((const char *)VD_2
[2].Value
, 7), StringRef("callee2"));
890 ASSERT_EQ(3U, VD_2
[2].Count
);
891 ASSERT_EQ(StringRef((const char *)VD_2
[3].Value
, 7), StringRef("callee1"));
892 ASSERT_EQ(1U, VD_2
[3].Count
);
894 std::unique_ptr
<InstrProfValueData
[]> VD_3(
895 R
->getValueForSite(IPVK_IndirectCallTarget
, 3));
896 ASSERT_EQ(StringRef((const char *)VD_3
[0].Value
, 7), StringRef("callee1"));
897 ASSERT_EQ(1U, VD_3
[0].Count
);
899 std::unique_ptr
<InstrProfValueData
[]> VD_4(
900 R
->getValueForSite(IPVK_IndirectCallTarget
, 4));
901 ASSERT_EQ(StringRef((const char *)VD_4
[0].Value
, 7), StringRef("callee3"));
902 ASSERT_EQ(6U, VD_4
[0].Count
);
903 ASSERT_EQ(StringRef((const char *)VD_4
[1].Value
, 7), StringRef("callee2"));
904 ASSERT_EQ(4U, VD_4
[1].Count
);
905 ASSERT_EQ(StringRef((const char *)VD_4
[2].Value
, 7), StringRef("callee1"));
906 ASSERT_EQ(2U, VD_4
[2].Count
);
909 struct ValueProfileMergeEdgeCaseTest
910 : public InstrProfTest
,
911 public ::testing::WithParamInterface
<std::tuple
<bool, uint32_t>> {
912 void SetUp() override
{ Writer
.setOutputSparse(std::get
<0>(GetParam())); }
914 uint32_t getValueProfileKind() const { return std::get
<1>(GetParam()); }
917 TEST_P(ValueProfileMergeEdgeCaseTest
, value_profile_data_merge_saturation
) {
918 const uint32_t ValueKind
= getValueProfileKind();
919 static const char bar
[] = "bar";
920 const uint64_t ProfiledValue
= 0x5678;
922 const uint64_t MaxValCount
= std::numeric_limits
<uint64_t>::max();
923 const uint64_t MaxEdgeCount
= getInstrMaxCountValue();
925 instrprof_error Result
;
926 auto Err
= [&](Error E
) {
927 Result
= std::get
<0>(InstrProfError::take(std::move(E
)));
929 Result
= instrprof_error::success
;
930 Writer
.addRecord({"foo", 0x1234, {1}}, Err
);
931 ASSERT_EQ(Result
, instrprof_error::success
);
933 // Verify counter overflow.
934 Result
= instrprof_error::success
;
935 Writer
.addRecord({"foo", 0x1234, {MaxEdgeCount
}}, Err
);
936 ASSERT_EQ(Result
, instrprof_error::counter_overflow
);
938 Result
= instrprof_error::success
;
939 Writer
.addRecord({bar
, 0x9012, {8}}, Err
);
940 ASSERT_EQ(Result
, instrprof_error::success
);
942 NamedInstrProfRecord
Record4("baz", 0x5678, {3, 4});
943 Record4
.reserveSites(ValueKind
, 1);
944 InstrProfValueData VD4
[] = {{ProfiledValue
, 1}};
945 Record4
.addValueData(ValueKind
, 0, VD4
, 1, nullptr);
946 Result
= instrprof_error::success
;
947 Writer
.addRecord(std::move(Record4
), Err
);
948 ASSERT_EQ(Result
, instrprof_error::success
);
950 // Verify value data counter overflow.
951 NamedInstrProfRecord
Record5("baz", 0x5678, {5, 6});
952 Record5
.reserveSites(ValueKind
, 1);
953 InstrProfValueData VD5
[] = {{ProfiledValue
, MaxValCount
}};
954 Record5
.addValueData(ValueKind
, 0, VD5
, 1, nullptr);
955 Result
= instrprof_error::success
;
956 Writer
.addRecord(std::move(Record5
), Err
);
957 ASSERT_EQ(Result
, instrprof_error::counter_overflow
);
959 auto Profile
= Writer
.writeBuffer();
960 readProfile(std::move(Profile
));
962 // Verify saturation of counts.
963 Expected
<InstrProfRecord
> ReadRecord1
=
964 Reader
->getInstrProfRecord("foo", 0x1234);
965 ASSERT_THAT_ERROR(ReadRecord1
.takeError(), Succeeded());
966 EXPECT_EQ(MaxEdgeCount
, ReadRecord1
->Counts
[0]);
968 Expected
<InstrProfRecord
> ReadRecord2
=
969 Reader
->getInstrProfRecord("baz", 0x5678);
970 ASSERT_TRUE(bool(ReadRecord2
));
971 ASSERT_EQ(1U, ReadRecord2
->getNumValueSites(ValueKind
));
972 std::unique_ptr
<InstrProfValueData
[]> VD
=
973 ReadRecord2
->getValueForSite(ValueKind
, 0);
974 EXPECT_EQ(ProfiledValue
, VD
[0].Value
);
975 EXPECT_EQ(MaxValCount
, VD
[0].Count
);
978 // This test tests that when there are too many values for a given site, the
979 // merged results are properly truncated.
980 TEST_P(ValueProfileMergeEdgeCaseTest
, value_profile_data_merge_site_trunc
) {
981 const uint32_t ValueKind
= getValueProfileKind();
982 static const char caller
[] = "caller";
984 NamedInstrProfRecord
Record11(caller
, 0x1234, {1, 2});
985 NamedInstrProfRecord
Record12(caller
, 0x1234, {1, 2});
988 Record11
.reserveSites(ValueKind
, 2);
989 InstrProfValueData VD0
[255];
990 for (int I
= 0; I
< 255; I
++) {
991 VD0
[I
].Value
= 2 * I
;
992 VD0
[I
].Count
= 2 * I
+ 1000;
995 Record11
.addValueData(ValueKind
, 0, VD0
, 255, nullptr);
996 Record11
.addValueData(ValueKind
, 1, nullptr, 0, nullptr);
998 Record12
.reserveSites(ValueKind
, 2);
999 InstrProfValueData VD1
[255];
1000 for (int I
= 0; I
< 255; I
++) {
1001 VD1
[I
].Value
= 2 * I
+ 1;
1002 VD1
[I
].Count
= 2 * I
+ 1001;
1005 Record12
.addValueData(ValueKind
, 0, VD1
, 255, nullptr);
1006 Record12
.addValueData(ValueKind
, 1, nullptr, 0, nullptr);
1008 Writer
.addRecord(std::move(Record11
), Err
);
1009 // Merge profile data.
1010 Writer
.addRecord(std::move(Record12
), Err
);
1012 auto Profile
= Writer
.writeBuffer();
1013 readProfile(std::move(Profile
));
1015 Expected
<InstrProfRecord
> R
= Reader
->getInstrProfRecord("caller", 0x1234);
1016 ASSERT_THAT_ERROR(R
.takeError(), Succeeded());
1017 std::unique_ptr
<InstrProfValueData
[]> VD(R
->getValueForSite(ValueKind
, 0));
1018 ASSERT_EQ(2U, R
->getNumValueSites(ValueKind
));
1019 EXPECT_EQ(255U, R
->getNumValueDataForSite(ValueKind
, 0));
1020 for (unsigned I
= 0; I
< 255; I
++) {
1021 EXPECT_EQ(VD
[I
].Value
, 509 - I
);
1022 EXPECT_EQ(VD
[I
].Count
, 1509 - I
);
1026 INSTANTIATE_TEST_SUITE_P(
1027 EdgeCaseTest
, ValueProfileMergeEdgeCaseTest
,
1028 ::testing::Combine(::testing::Bool(), /* Sparse */
1029 ::testing::Values(IPVK_IndirectCallTarget
,
1030 IPVK_MemOPSize
) /* ValueKind */
1033 static void addValueProfData(InstrProfRecord
&Record
) {
1034 Record
.reserveSites(IPVK_IndirectCallTarget
, 5);
1035 InstrProfValueData VD0
[] = {{uint64_t(callee1
), 400},
1036 {uint64_t(callee2
), 1000},
1037 {uint64_t(callee3
), 500},
1038 {uint64_t(callee4
), 300},
1039 {uint64_t(callee5
), 100}};
1040 Record
.addValueData(IPVK_IndirectCallTarget
, 0, VD0
, 5, nullptr);
1041 InstrProfValueData VD1
[] = {{uint64_t(callee5
), 800},
1042 {uint64_t(callee3
), 1000},
1043 {uint64_t(callee2
), 2500},
1044 {uint64_t(callee1
), 1300}};
1045 Record
.addValueData(IPVK_IndirectCallTarget
, 1, VD1
, 4, nullptr);
1046 InstrProfValueData VD2
[] = {{uint64_t(callee6
), 800},
1047 {uint64_t(callee3
), 1000},
1048 {uint64_t(callee4
), 5500}};
1049 Record
.addValueData(IPVK_IndirectCallTarget
, 2, VD2
, 3, nullptr);
1050 InstrProfValueData VD3
[] = {{uint64_t(callee2
), 1800},
1051 {uint64_t(callee3
), 2000}};
1052 Record
.addValueData(IPVK_IndirectCallTarget
, 3, VD3
, 2, nullptr);
1053 Record
.addValueData(IPVK_IndirectCallTarget
, 4, nullptr, 0, nullptr);
1056 TEST(ValueProfileReadWriteTest
, value_prof_data_read_write
) {
1057 InstrProfRecord
SrcRecord({1ULL << 31, 2});
1058 addValueProfData(SrcRecord
);
1059 std::unique_ptr
<ValueProfData
> VPData
=
1060 ValueProfData::serializeFrom(SrcRecord
);
1062 InstrProfRecord
Record({1ULL << 31, 2});
1063 VPData
->deserializeTo(Record
, nullptr);
1065 // Now read data from Record and sanity check the data
1066 ASSERT_EQ(5U, Record
.getNumValueSites(IPVK_IndirectCallTarget
));
1067 ASSERT_EQ(5U, Record
.getNumValueDataForSite(IPVK_IndirectCallTarget
, 0));
1068 ASSERT_EQ(4U, Record
.getNumValueDataForSite(IPVK_IndirectCallTarget
, 1));
1069 ASSERT_EQ(3U, Record
.getNumValueDataForSite(IPVK_IndirectCallTarget
, 2));
1070 ASSERT_EQ(2U, Record
.getNumValueDataForSite(IPVK_IndirectCallTarget
, 3));
1071 ASSERT_EQ(0U, Record
.getNumValueDataForSite(IPVK_IndirectCallTarget
, 4));
1073 auto Cmp
= [](const InstrProfValueData
&VD1
, const InstrProfValueData
&VD2
) {
1074 return VD1
.Count
> VD2
.Count
;
1076 std::unique_ptr
<InstrProfValueData
[]> VD_0(
1077 Record
.getValueForSite(IPVK_IndirectCallTarget
, 0));
1078 llvm::sort(&VD_0
[0], &VD_0
[5], Cmp
);
1079 ASSERT_EQ(StringRef((const char *)VD_0
[0].Value
, 7), StringRef("callee2"));
1080 ASSERT_EQ(1000U, VD_0
[0].Count
);
1081 ASSERT_EQ(StringRef((const char *)VD_0
[1].Value
, 7), StringRef("callee3"));
1082 ASSERT_EQ(500U, VD_0
[1].Count
);
1083 ASSERT_EQ(StringRef((const char *)VD_0
[2].Value
, 7), StringRef("callee1"));
1084 ASSERT_EQ(400U, VD_0
[2].Count
);
1085 ASSERT_EQ(StringRef((const char *)VD_0
[3].Value
, 7), StringRef("callee4"));
1086 ASSERT_EQ(300U, VD_0
[3].Count
);
1087 ASSERT_EQ(StringRef((const char *)VD_0
[4].Value
, 7), StringRef("callee5"));
1088 ASSERT_EQ(100U, VD_0
[4].Count
);
1090 std::unique_ptr
<InstrProfValueData
[]> VD_1(
1091 Record
.getValueForSite(IPVK_IndirectCallTarget
, 1));
1092 llvm::sort(&VD_1
[0], &VD_1
[4], Cmp
);
1093 ASSERT_EQ(StringRef((const char *)VD_1
[0].Value
, 7), StringRef("callee2"));
1094 ASSERT_EQ(2500U, VD_1
[0].Count
);
1095 ASSERT_EQ(StringRef((const char *)VD_1
[1].Value
, 7), StringRef("callee1"));
1096 ASSERT_EQ(1300U, VD_1
[1].Count
);
1097 ASSERT_EQ(StringRef((const char *)VD_1
[2].Value
, 7), StringRef("callee3"));
1098 ASSERT_EQ(1000U, VD_1
[2].Count
);
1099 ASSERT_EQ(StringRef((const char *)VD_1
[3].Value
, 7), StringRef("callee5"));
1100 ASSERT_EQ(800U, VD_1
[3].Count
);
1102 std::unique_ptr
<InstrProfValueData
[]> VD_2(
1103 Record
.getValueForSite(IPVK_IndirectCallTarget
, 2));
1104 llvm::sort(&VD_2
[0], &VD_2
[3], Cmp
);
1105 ASSERT_EQ(StringRef((const char *)VD_2
[0].Value
, 7), StringRef("callee4"));
1106 ASSERT_EQ(5500U, VD_2
[0].Count
);
1107 ASSERT_EQ(StringRef((const char *)VD_2
[1].Value
, 7), StringRef("callee3"));
1108 ASSERT_EQ(1000U, VD_2
[1].Count
);
1109 ASSERT_EQ(StringRef((const char *)VD_2
[2].Value
, 7), StringRef("callee6"));
1110 ASSERT_EQ(800U, VD_2
[2].Count
);
1112 std::unique_ptr
<InstrProfValueData
[]> VD_3(
1113 Record
.getValueForSite(IPVK_IndirectCallTarget
, 3));
1114 llvm::sort(&VD_3
[0], &VD_3
[2], Cmp
);
1115 ASSERT_EQ(StringRef((const char *)VD_3
[0].Value
, 7), StringRef("callee3"));
1116 ASSERT_EQ(2000U, VD_3
[0].Count
);
1117 ASSERT_EQ(StringRef((const char *)VD_3
[1].Value
, 7), StringRef("callee2"));
1118 ASSERT_EQ(1800U, VD_3
[1].Count
);
1121 TEST(ValueProfileReadWriteTest
, symtab_mapping
) {
1122 NamedInstrProfRecord
SrcRecord("caller", 0x1234, {1ULL << 31, 2});
1123 addValueProfData(SrcRecord
);
1124 std::unique_ptr
<ValueProfData
> VPData
=
1125 ValueProfData::serializeFrom(SrcRecord
);
1127 NamedInstrProfRecord
Record("caller", 0x1234, {1ULL << 31, 2});
1128 InstrProfSymtab Symtab
;
1129 Symtab
.mapAddress(uint64_t(callee1
), 0x1000ULL
);
1130 Symtab
.mapAddress(uint64_t(callee2
), 0x2000ULL
);
1131 Symtab
.mapAddress(uint64_t(callee3
), 0x3000ULL
);
1132 Symtab
.mapAddress(uint64_t(callee4
), 0x4000ULL
);
1133 // Missing mapping for callee5
1135 VPData
->deserializeTo(Record
, &Symtab
);
1137 // Now read data from Record and sanity check the data
1138 ASSERT_EQ(5U, Record
.getNumValueSites(IPVK_IndirectCallTarget
));
1139 ASSERT_EQ(5U, Record
.getNumValueDataForSite(IPVK_IndirectCallTarget
, 0));
1141 auto Cmp
= [](const InstrProfValueData
&VD1
, const InstrProfValueData
&VD2
) {
1142 return VD1
.Count
> VD2
.Count
;
1144 std::unique_ptr
<InstrProfValueData
[]> VD_0(
1145 Record
.getValueForSite(IPVK_IndirectCallTarget
, 0));
1146 llvm::sort(&VD_0
[0], &VD_0
[5], Cmp
);
1147 ASSERT_EQ(VD_0
[0].Value
, 0x2000ULL
);
1148 ASSERT_EQ(1000U, VD_0
[0].Count
);
1149 ASSERT_EQ(VD_0
[1].Value
, 0x3000ULL
);
1150 ASSERT_EQ(500U, VD_0
[1].Count
);
1151 ASSERT_EQ(VD_0
[2].Value
, 0x1000ULL
);
1152 ASSERT_EQ(400U, VD_0
[2].Count
);
1154 // callee5 does not have a mapped value -- default to 0.
1155 ASSERT_EQ(VD_0
[4].Value
, 0ULL);
1158 TEST_P(MaybeSparseInstrProfTest
, get_max_function_count
) {
1159 Writer
.addRecord({"foo", 0x1234, {1ULL << 31, 2}}, Err
);
1160 Writer
.addRecord({"bar", 0, {1ULL << 63}}, Err
);
1161 Writer
.addRecord({"baz", 0x5678, {0, 0, 0, 0}}, Err
);
1162 auto Profile
= Writer
.writeBuffer();
1163 readProfile(std::move(Profile
));
1165 ASSERT_EQ(1ULL << 63, Reader
->getMaximumFunctionCount(/* IsCS */ false));
1168 TEST_P(MaybeSparseInstrProfTest
, get_weighted_function_counts
) {
1169 Writer
.addRecord({"foo", 0x1234, {1, 2}}, 3, Err
);
1170 Writer
.addRecord({"foo", 0x1235, {3, 4}}, 5, Err
);
1171 auto Profile
= Writer
.writeBuffer();
1172 readProfile(std::move(Profile
));
1174 std::vector
<uint64_t> Counts
;
1175 EXPECT_THAT_ERROR(Reader
->getFunctionCounts("foo", 0x1234, Counts
),
1177 ASSERT_EQ(2U, Counts
.size());
1178 ASSERT_EQ(3U, Counts
[0]);
1179 ASSERT_EQ(6U, Counts
[1]);
1181 EXPECT_THAT_ERROR(Reader
->getFunctionCounts("foo", 0x1235, Counts
),
1183 ASSERT_EQ(2U, Counts
.size());
1184 ASSERT_EQ(15U, Counts
[0]);
1185 ASSERT_EQ(20U, Counts
[1]);
1188 // Testing symtab creator interface used by indexed profile reader.
1189 TEST(SymtabTest
, instr_prof_symtab_test
) {
1190 std::vector
<StringRef
> FuncNames
;
1191 FuncNames
.push_back("func1");
1192 FuncNames
.push_back("func2");
1193 FuncNames
.push_back("func3");
1194 FuncNames
.push_back("bar1");
1195 FuncNames
.push_back("bar2");
1196 FuncNames
.push_back("bar3");
1197 InstrProfSymtab Symtab
;
1198 EXPECT_THAT_ERROR(Symtab
.create(FuncNames
), Succeeded());
1199 StringRef R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("func1"));
1200 ASSERT_EQ(StringRef("func1"), R
);
1201 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("func2"));
1202 ASSERT_EQ(StringRef("func2"), R
);
1203 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("func3"));
1204 ASSERT_EQ(StringRef("func3"), R
);
1205 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar1"));
1206 ASSERT_EQ(StringRef("bar1"), R
);
1207 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar2"));
1208 ASSERT_EQ(StringRef("bar2"), R
);
1209 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar3"));
1210 ASSERT_EQ(StringRef("bar3"), R
);
1213 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar4"));
1214 ASSERT_EQ(StringRef(), R
);
1215 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("foo4"));
1216 ASSERT_EQ(StringRef(), R
);
1218 // Now incrementally update the symtab
1219 EXPECT_THAT_ERROR(Symtab
.addFuncName("blah_1"), Succeeded());
1220 EXPECT_THAT_ERROR(Symtab
.addFuncName("blah_2"), Succeeded());
1221 EXPECT_THAT_ERROR(Symtab
.addFuncName("blah_3"), Succeeded());
1224 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("blah_1"));
1225 ASSERT_EQ(StringRef("blah_1"), R
);
1226 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("blah_2"));
1227 ASSERT_EQ(StringRef("blah_2"), R
);
1228 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("blah_3"));
1229 ASSERT_EQ(StringRef("blah_3"), R
);
1230 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("func1"));
1231 ASSERT_EQ(StringRef("func1"), R
);
1232 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("func2"));
1233 ASSERT_EQ(StringRef("func2"), R
);
1234 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("func3"));
1235 ASSERT_EQ(StringRef("func3"), R
);
1236 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar1"));
1237 ASSERT_EQ(StringRef("bar1"), R
);
1238 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar2"));
1239 ASSERT_EQ(StringRef("bar2"), R
);
1240 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar3"));
1241 ASSERT_EQ(StringRef("bar3"), R
);
1244 // Test that we get an error when creating a bogus symtab.
1245 TEST(SymtabTest
, instr_prof_bogus_symtab_empty_func_name
) {
1246 InstrProfSymtab Symtab
;
1247 EXPECT_TRUE(ErrorEquals(instrprof_error::malformed
, Symtab
.addFuncName("")));
1250 // Testing symtab creator interface used by value profile transformer.
1251 TEST(SymtabTest
, instr_prof_symtab_module_test
) {
1253 std::unique_ptr
<Module
> M
= std::make_unique
<Module
>("MyModule.cpp", Ctx
);
1254 FunctionType
*FTy
= FunctionType::get(Type::getVoidTy(Ctx
),
1255 /*isVarArg=*/false);
1256 Function::Create(FTy
, Function::ExternalLinkage
, "Gfoo", M
.get());
1257 Function::Create(FTy
, Function::ExternalLinkage
, "Gblah", M
.get());
1258 Function::Create(FTy
, Function::ExternalLinkage
, "Gbar", M
.get());
1259 Function::Create(FTy
, Function::InternalLinkage
, "Ifoo", M
.get());
1260 Function::Create(FTy
, Function::InternalLinkage
, "Iblah", M
.get());
1261 Function::Create(FTy
, Function::InternalLinkage
, "Ibar", M
.get());
1262 Function::Create(FTy
, Function::PrivateLinkage
, "Pfoo", M
.get());
1263 Function::Create(FTy
, Function::PrivateLinkage
, "Pblah", M
.get());
1264 Function::Create(FTy
, Function::PrivateLinkage
, "Pbar", M
.get());
1265 Function::Create(FTy
, Function::WeakODRLinkage
, "Wfoo", M
.get());
1266 Function::Create(FTy
, Function::WeakODRLinkage
, "Wblah", M
.get());
1267 Function::Create(FTy
, Function::WeakODRLinkage
, "Wbar", M
.get());
1269 InstrProfSymtab ProfSymtab
;
1270 EXPECT_THAT_ERROR(ProfSymtab
.create(*M
), Succeeded());
1272 StringRef Funcs
[] = {"Gfoo", "Gblah", "Gbar", "Ifoo", "Iblah", "Ibar",
1273 "Pfoo", "Pblah", "Pbar", "Wfoo", "Wblah", "Wbar"};
1275 for (unsigned I
= 0; I
< std::size(Funcs
); I
++) {
1276 Function
*F
= M
->getFunction(Funcs
[I
]);
1278 std::string IRPGOName
= getIRPGOFuncName(*F
);
1279 auto IRPGOFuncName
=
1280 ProfSymtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash(IRPGOName
));
1281 EXPECT_EQ(StringRef(IRPGOName
), IRPGOFuncName
);
1282 EXPECT_EQ(StringRef(Funcs
[I
]),
1283 getParsedIRPGOFuncName(IRPGOFuncName
).second
);
1284 // Ensure we can still read this old record name.
1285 std::string PGOName
= getPGOFuncName(*F
);
1287 ProfSymtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash(PGOName
));
1288 EXPECT_EQ(StringRef(PGOName
), PGOFuncName
);
1289 EXPECT_THAT(PGOFuncName
.str(), EndsWith(Funcs
[I
].str()));
1293 // Testing symtab serialization and creator/deserialization interface
1294 // used by coverage map reader, and raw profile reader.
1295 TEST(SymtabTest
, instr_prof_symtab_compression_test
) {
1296 std::vector
<std::string
> FuncNames1
;
1297 std::vector
<std::string
> FuncNames2
;
1298 for (int I
= 0; I
< 3; I
++) {
1300 raw_string_ostream
OS(str
);
1302 FuncNames1
.push_back(OS
.str());
1304 OS
<< "f oooooooooooooo_" << I
;
1305 FuncNames1
.push_back(OS
.str());
1308 FuncNames2
.push_back(OS
.str());
1310 OS
<< "BlahblahBlahblahBar_" << I
;
1311 FuncNames2
.push_back(OS
.str());
1314 for (bool DoCompression
: {false, true}) {
1316 std::string FuncNameStrings1
;
1317 EXPECT_THAT_ERROR(collectGlobalObjectNameStrings(
1319 (DoCompression
&& compression::zlib::isAvailable()),
1324 std::string FuncNameStrings2
;
1325 EXPECT_THAT_ERROR(collectGlobalObjectNameStrings(
1327 (DoCompression
&& compression::zlib::isAvailable()),
1331 for (int Padding
= 0; Padding
< 2; Padding
++) {
1332 // Join with paddings :
1333 std::string FuncNameStrings
= FuncNameStrings1
;
1334 for (int P
= 0; P
< Padding
; P
++) {
1335 FuncNameStrings
.push_back('\0');
1337 FuncNameStrings
+= FuncNameStrings2
;
1340 InstrProfSymtab Symtab
;
1341 EXPECT_THAT_ERROR(Symtab
.create(StringRef(FuncNameStrings
)), Succeeded());
1343 // Now do the checks:
1344 // First sampling some data points:
1346 Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash(FuncNames1
[0]));
1347 ASSERT_EQ(StringRef("func_0"), R
);
1348 R
= Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash(FuncNames1
[1]));
1349 ASSERT_EQ(StringRef("f oooooooooooooo_0"), R
);
1350 for (int I
= 0; I
< 3; I
++) {
1352 N
[0] = FuncNames1
[2 * I
];
1353 N
[1] = FuncNames1
[2 * I
+ 1];
1354 N
[2] = FuncNames2
[2 * I
];
1355 N
[3] = FuncNames2
[2 * I
+ 1];
1356 for (int J
= 0; J
< 4; J
++) {
1358 Symtab
.getFuncOrVarName(IndexedInstrProf::ComputeHash(N
[J
]));
1359 ASSERT_EQ(StringRef(N
[J
]), R
);
1366 TEST_P(MaybeSparseInstrProfTest
, remapping_test
) {
1367 Writer
.addRecord({"_Z3fooi", 0x1234, {1, 2, 3, 4}}, Err
);
1368 Writer
.addRecord({"file;_Z3barf", 0x567, {5, 6, 7}}, Err
);
1369 auto Profile
= Writer
.writeBuffer();
1370 readProfile(std::move(Profile
), llvm::MemoryBuffer::getMemBuffer(R
"(
1375 std::vector
<uint64_t> Counts
;
1376 for (StringRef FooName
: {"_Z3fooi", "_Z3fool"}) {
1377 EXPECT_THAT_ERROR(Reader
->getFunctionCounts(FooName
, 0x1234, Counts
),
1379 ASSERT_EQ(4u, Counts
.size());
1380 EXPECT_EQ(1u, Counts
[0]);
1381 EXPECT_EQ(2u, Counts
[1]);
1382 EXPECT_EQ(3u, Counts
[2]);
1383 EXPECT_EQ(4u, Counts
[3]);
1386 for (StringRef BarName
: {"file;_Z3barf", "file;_Z4quuxf"}) {
1387 EXPECT_THAT_ERROR(Reader
->getFunctionCounts(BarName
, 0x567, Counts
),
1389 ASSERT_EQ(3u, Counts
.size());
1390 EXPECT_EQ(5u, Counts
[0]);
1391 EXPECT_EQ(6u, Counts
[1]);
1392 EXPECT_EQ(7u, Counts
[2]);
1395 for (StringRef BadName
: {"_Z3foof", "_Z4quuxi", "_Z3barl", "", "_ZZZ",
1396 "_Z3barf", "otherfile:_Z4quuxf"}) {
1397 EXPECT_THAT_ERROR(Reader
->getFunctionCounts(BadName
, 0x1234, Counts
),
1399 EXPECT_THAT_ERROR(Reader
->getFunctionCounts(BadName
, 0x567, Counts
),
1404 TEST_F(SparseInstrProfTest
, preserve_no_records
) {
1405 Writer
.addRecord({"foo", 0x1234, {0}}, Err
);
1406 Writer
.addRecord({"bar", 0x4321, {0, 0}}, Err
);
1407 Writer
.addRecord({"baz", 0x4321, {0, 0, 0}}, Err
);
1409 auto Profile
= Writer
.writeBuffer();
1410 readProfile(std::move(Profile
));
1412 auto I
= Reader
->begin(), E
= Reader
->end();
1413 ASSERT_TRUE(I
== E
);
1416 INSTANTIATE_TEST_SUITE_P(MaybeSparse
, MaybeSparseInstrProfTest
,
1419 #if defined(_LP64) && defined(EXPENSIVE_CHECKS)
1420 TEST(ProfileReaderTest
, ReadsLargeFiles
) {
1421 const size_t LargeSize
= 1ULL << 32; // 4GB
1423 auto RawProfile
= WritableMemoryBuffer::getNewUninitMemBuffer(LargeSize
);
1426 auto RawProfileReaderOrErr
= InstrProfReader::create(std::move(RawProfile
));
1428 std::get
<0>(InstrProfError::take(RawProfileReaderOrErr
.takeError())) ==
1429 instrprof_error::unrecognized_format
);
1431 auto IndexedProfile
= WritableMemoryBuffer::getNewUninitMemBuffer(LargeSize
);
1432 if (!IndexedProfile
)
1434 auto IndexedReaderOrErr
=
1435 IndexedInstrProfReader::create(std::move(IndexedProfile
), nullptr);
1437 std::get
<0>(InstrProfError::take(IndexedReaderOrErr
.takeError())) ==
1438 instrprof_error::bad_magic
);
1442 } // end anonymous namespace