1 //===- unittest/ProfileData/InstrProfTest.cpp -------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ADT/STLExtras.h" 10 #include "llvm/IR/DerivedTypes.h" 11 #include "llvm/IR/Function.h" 12 #include "llvm/IR/IRBuilder.h" 13 #include "llvm/IR/LLVMContext.h" 14 #include "llvm/IR/Module.h" 15 #include "llvm/ProfileData/InstrProfReader.h" 16 #include "llvm/ProfileData/InstrProfWriter.h" 17 #include "llvm/ProfileData/MemProf.h" 18 #include "llvm/ProfileData/MemProfData.inc" 19 #include "llvm/Support/Compression.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include "llvm/Testing/Support/Error.h" 22 #include "gtest/gtest.h" 23 #include <cstdarg> 24 #include <initializer_list> 25 #include <optional> 26 27 using namespace llvm; 28 using ::llvm::memprof::LineLocation; 29 using ::testing::ElementsAre; 30 using ::testing::EndsWith; 31 using ::testing::IsSubsetOf; 32 using ::testing::Pair; 33 using ::testing::SizeIs; 34 using ::testing::UnorderedElementsAre; 35 36 [[nodiscard]] static ::testing::AssertionResult 37 ErrorEquals(instrprof_error Expected, Error E) { 38 instrprof_error Found; 39 std::string FoundMsg; 40 handleAllErrors(std::move(E), [&](const InstrProfError &IPE) { 41 Found = IPE.get(); 42 FoundMsg = IPE.message(); 43 }); 44 if (Expected == Found) 45 return ::testing::AssertionSuccess(); 46 return ::testing::AssertionFailure() << "error: " << FoundMsg << "\n"; 47 } 48 49 namespace llvm { 50 bool operator==(const TemporalProfTraceTy &lhs, 51 const TemporalProfTraceTy &rhs) { 52 return lhs.Weight == rhs.Weight && 53 lhs.FunctionNameRefs == rhs.FunctionNameRefs; 54 } 55 } // end namespace llvm 56 57 namespace { 58 59 struct InstrProfTest : ::testing::Test { 60 InstrProfWriter Writer; 61 std::unique_ptr<IndexedInstrProfReader> Reader; 62 63 void SetUp() override { Writer.setOutputSparse(false); } 64 65 void readProfile(std::unique_ptr<MemoryBuffer> Profile, 66 std::unique_ptr<MemoryBuffer> Remapping = nullptr) { 67 auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile), 68 std::move(Remapping)); 69 EXPECT_THAT_ERROR(ReaderOrErr.takeError(), Succeeded()); 70 Reader = std::move(ReaderOrErr.get()); 71 } 72 }; 73 74 struct SparseInstrProfTest : public InstrProfTest { 75 void SetUp() override { Writer.setOutputSparse(true); } 76 }; 77 78 struct InstrProfReaderWriterTest 79 : public InstrProfTest, 80 public ::testing::WithParamInterface< 81 std::tuple<bool, uint64_t, llvm::endianness>> { 82 void SetUp() override { Writer.setOutputSparse(std::get<0>(GetParam())); } 83 void TearDown() override { 84 // Reset writer value profile data endianness after each test case. Note 85 // it's not necessary to reset reader value profile endianness for each test 86 // case. Each test case creates a new reader; at reader initialization time, 87 // it uses the endianness from hash table object (which is little by 88 // default). 89 Writer.setValueProfDataEndianness(llvm::endianness::little); 90 } 91 92 uint64_t getProfWeight() const { return std::get<1>(GetParam()); } 93 94 llvm::endianness getEndianness() const { return std::get<2>(GetParam()); } 95 }; 96 97 struct MaybeSparseInstrProfTest : public InstrProfTest, 98 public ::testing::WithParamInterface<bool> { 99 void SetUp() override { Writer.setOutputSparse(GetParam()); } 100 }; 101 102 TEST_P(MaybeSparseInstrProfTest, write_and_read_empty_profile) { 103 auto Profile = Writer.writeBuffer(); 104 readProfile(std::move(Profile)); 105 ASSERT_TRUE(Reader->begin() == Reader->end()); 106 } 107 108 static const auto Err = [](Error E) { 109 consumeError(std::move(E)); 110 FAIL(); 111 }; 112 113 TEST_P(MaybeSparseInstrProfTest, write_and_read_one_function) { 114 Writer.addRecord({"foo", 0x1234, {1, 2, 3, 4}}, Err); 115 auto Profile = Writer.writeBuffer(); 116 readProfile(std::move(Profile)); 117 118 auto I = Reader->begin(), E = Reader->end(); 119 ASSERT_TRUE(I != E); 120 ASSERT_EQ(StringRef("foo"), I->Name); 121 ASSERT_EQ(0x1234U, I->Hash); 122 ASSERT_EQ(4U, I->Counts.size()); 123 ASSERT_EQ(1U, I->Counts[0]); 124 ASSERT_EQ(2U, I->Counts[1]); 125 ASSERT_EQ(3U, I->Counts[2]); 126 ASSERT_EQ(4U, I->Counts[3]); 127 ASSERT_TRUE(++I == E); 128 } 129 130 TEST_P(MaybeSparseInstrProfTest, get_instr_prof_record) { 131 Writer.addRecord({"foo", 0x1234, {1, 2}}, Err); 132 Writer.addRecord({"foo", 0x1235, {3, 4}}, Err); 133 auto Profile = Writer.writeBuffer(); 134 readProfile(std::move(Profile)); 135 136 Expected<InstrProfRecord> R = Reader->getInstrProfRecord("foo", 0x1234); 137 EXPECT_THAT_ERROR(R.takeError(), Succeeded()); 138 ASSERT_EQ(2U, R->Counts.size()); 139 ASSERT_EQ(1U, R->Counts[0]); 140 ASSERT_EQ(2U, R->Counts[1]); 141 142 R = Reader->getInstrProfRecord("foo", 0x1235); 143 EXPECT_THAT_ERROR(R.takeError(), Succeeded()); 144 ASSERT_EQ(2U, R->Counts.size()); 145 ASSERT_EQ(3U, R->Counts[0]); 146 ASSERT_EQ(4U, R->Counts[1]); 147 148 R = Reader->getInstrProfRecord("foo", 0x5678); 149 ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, R.takeError())); 150 151 R = Reader->getInstrProfRecord("bar", 0x1234); 152 ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, R.takeError())); 153 } 154 155 TEST_P(MaybeSparseInstrProfTest, get_function_counts) { 156 Writer.addRecord({"foo", 0x1234, {1, 2}}, Err); 157 Writer.addRecord({"foo", 0x1235, {3, 4}}, Err); 158 auto Profile = Writer.writeBuffer(); 159 readProfile(std::move(Profile)); 160 161 std::vector<uint64_t> Counts; 162 EXPECT_THAT_ERROR(Reader->getFunctionCounts("foo", 0x1234, Counts), 163 Succeeded()); 164 ASSERT_EQ(2U, Counts.size()); 165 ASSERT_EQ(1U, Counts[0]); 166 ASSERT_EQ(2U, Counts[1]); 167 168 EXPECT_THAT_ERROR(Reader->getFunctionCounts("foo", 0x1235, Counts), 169 Succeeded()); 170 ASSERT_EQ(2U, Counts.size()); 171 ASSERT_EQ(3U, Counts[0]); 172 ASSERT_EQ(4U, Counts[1]); 173 174 Error E1 = Reader->getFunctionCounts("foo", 0x5678, Counts); 175 ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, std::move(E1))); 176 177 Error E2 = Reader->getFunctionCounts("bar", 0x1234, Counts); 178 ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, std::move(E2))); 179 } 180 181 // Profile data is copied from general.proftext 182 TEST_F(InstrProfTest, get_profile_summary) { 183 Writer.addRecord({"func1", 0x1234, {97531}}, Err); 184 Writer.addRecord({"func2", 0x1234, {0, 0}}, Err); 185 Writer.addRecord( 186 {"func3", 187 0x1234, 188 {2305843009213693952, 1152921504606846976, 576460752303423488, 189 288230376151711744, 144115188075855872, 72057594037927936}}, 190 Err); 191 Writer.addRecord({"func4", 0x1234, {0}}, Err); 192 auto Profile = Writer.writeBuffer(); 193 readProfile(std::move(Profile)); 194 195 auto VerifySummary = [](ProfileSummary &IPS) mutable { 196 ASSERT_EQ(ProfileSummary::PSK_Instr, IPS.getKind()); 197 ASSERT_EQ(2305843009213693952U, IPS.getMaxFunctionCount()); 198 ASSERT_EQ(2305843009213693952U, IPS.getMaxCount()); 199 ASSERT_EQ(10U, IPS.getNumCounts()); 200 ASSERT_EQ(4539628424389557499U, IPS.getTotalCount()); 201 const std::vector<ProfileSummaryEntry> &Details = IPS.getDetailedSummary(); 202 uint32_t Cutoff = 800000; 203 auto Predicate = [&Cutoff](const ProfileSummaryEntry &PE) { 204 return PE.Cutoff == Cutoff; 205 }; 206 auto EightyPerc = find_if(Details, Predicate); 207 Cutoff = 900000; 208 auto NinetyPerc = find_if(Details, Predicate); 209 Cutoff = 950000; 210 auto NinetyFivePerc = find_if(Details, Predicate); 211 Cutoff = 990000; 212 auto NinetyNinePerc = find_if(Details, Predicate); 213 ASSERT_EQ(576460752303423488U, EightyPerc->MinCount); 214 ASSERT_EQ(288230376151711744U, NinetyPerc->MinCount); 215 ASSERT_EQ(288230376151711744U, NinetyFivePerc->MinCount); 216 ASSERT_EQ(72057594037927936U, NinetyNinePerc->MinCount); 217 }; 218 ProfileSummary &PS = Reader->getSummary(/* IsCS */ false); 219 VerifySummary(PS); 220 221 // Test that conversion of summary to and from Metadata works. 222 LLVMContext Context; 223 Metadata *MD = PS.getMD(Context); 224 ASSERT_TRUE(MD); 225 ProfileSummary *PSFromMD = ProfileSummary::getFromMD(MD); 226 ASSERT_TRUE(PSFromMD); 227 VerifySummary(*PSFromMD); 228 delete PSFromMD; 229 230 // Test that summary can be attached to and read back from module. 231 Module M("my_module", Context); 232 M.setProfileSummary(MD, ProfileSummary::PSK_Instr); 233 MD = M.getProfileSummary(/* IsCS */ false); 234 ASSERT_TRUE(MD); 235 PSFromMD = ProfileSummary::getFromMD(MD); 236 ASSERT_TRUE(PSFromMD); 237 VerifySummary(*PSFromMD); 238 delete PSFromMD; 239 } 240 241 TEST_F(InstrProfTest, test_writer_merge) { 242 Writer.addRecord({"func1", 0x1234, {42}}, Err); 243 244 InstrProfWriter Writer2; 245 Writer2.addRecord({"func2", 0x1234, {0, 0}}, Err); 246 247 Writer.mergeRecordsFromWriter(std::move(Writer2), Err); 248 249 auto Profile = Writer.writeBuffer(); 250 readProfile(std::move(Profile)); 251 252 Expected<InstrProfRecord> R = Reader->getInstrProfRecord("func1", 0x1234); 253 EXPECT_THAT_ERROR(R.takeError(), Succeeded()); 254 ASSERT_EQ(1U, R->Counts.size()); 255 ASSERT_EQ(42U, R->Counts[0]); 256 257 R = Reader->getInstrProfRecord("func2", 0x1234); 258 EXPECT_THAT_ERROR(R.takeError(), Succeeded()); 259 ASSERT_EQ(2U, R->Counts.size()); 260 ASSERT_EQ(0U, R->Counts[0]); 261 ASSERT_EQ(0U, R->Counts[1]); 262 } 263 264 TEST_F(InstrProfTest, test_merge_temporal_prof_traces_truncated) { 265 uint64_t ReservoirSize = 10; 266 uint64_t MaxTraceLength = 2; 267 InstrProfWriter Writer(/*Sparse=*/false, ReservoirSize, MaxTraceLength); 268 ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::TemporalProfile), 269 Succeeded()); 270 271 TemporalProfTraceTy LargeTrace, SmallTrace; 272 LargeTrace.FunctionNameRefs = {IndexedInstrProf::ComputeHash("foo"), 273 IndexedInstrProf::ComputeHash("bar"), 274 IndexedInstrProf::ComputeHash("goo")}; 275 SmallTrace.FunctionNameRefs = {IndexedInstrProf::ComputeHash("foo"), 276 IndexedInstrProf::ComputeHash("bar")}; 277 278 SmallVector<TemporalProfTraceTy, 4> Traces = {LargeTrace, SmallTrace}; 279 Writer.addTemporalProfileTraces(Traces, 2); 280 281 auto Profile = Writer.writeBuffer(); 282 readProfile(std::move(Profile)); 283 284 ASSERT_TRUE(Reader->hasTemporalProfile()); 285 EXPECT_EQ(Reader->getTemporalProfTraceStreamSize(), 2U); 286 EXPECT_THAT(Reader->getTemporalProfTraces(), 287 UnorderedElementsAre(SmallTrace, SmallTrace)); 288 } 289 290 TEST_F(InstrProfTest, test_merge_traces_from_writer) { 291 uint64_t ReservoirSize = 10; 292 uint64_t MaxTraceLength = 10; 293 InstrProfWriter Writer(/*Sparse=*/false, ReservoirSize, MaxTraceLength); 294 InstrProfWriter Writer2(/*Sparse=*/false, ReservoirSize, MaxTraceLength); 295 ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::TemporalProfile), 296 Succeeded()); 297 ASSERT_THAT_ERROR(Writer2.mergeProfileKind(InstrProfKind::TemporalProfile), 298 Succeeded()); 299 300 TemporalProfTraceTy FooTrace, BarTrace; 301 FooTrace.FunctionNameRefs = {IndexedInstrProf::ComputeHash("foo")}; 302 BarTrace.FunctionNameRefs = {IndexedInstrProf::ComputeHash("bar")}; 303 304 SmallVector<TemporalProfTraceTy, 4> Traces1({FooTrace}), Traces2({BarTrace}); 305 Writer.addTemporalProfileTraces(Traces1, 1); 306 Writer2.addTemporalProfileTraces(Traces2, 1); 307 Writer.mergeRecordsFromWriter(std::move(Writer2), Err); 308 309 auto Profile = Writer.writeBuffer(); 310 readProfile(std::move(Profile)); 311 312 ASSERT_TRUE(Reader->hasTemporalProfile()); 313 EXPECT_EQ(Reader->getTemporalProfTraceStreamSize(), 2U); 314 EXPECT_THAT(Reader->getTemporalProfTraces(), 315 UnorderedElementsAre(FooTrace, BarTrace)); 316 } 317 318 TEST_F(InstrProfTest, test_merge_traces_sampled) { 319 uint64_t ReservoirSize = 3; 320 uint64_t MaxTraceLength = 10; 321 InstrProfWriter Writer(/*Sparse=*/false, ReservoirSize, MaxTraceLength); 322 ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::TemporalProfile), 323 Succeeded()); 324 325 TemporalProfTraceTy FooTrace, BarTrace, GooTrace; 326 FooTrace.FunctionNameRefs = {IndexedInstrProf::ComputeHash("foo")}; 327 BarTrace.FunctionNameRefs = {IndexedInstrProf::ComputeHash("bar")}; 328 GooTrace.FunctionNameRefs = {IndexedInstrProf::ComputeHash("Goo")}; 329 330 // Add some sampled traces 331 SmallVector<TemporalProfTraceTy, 4> SampledTraces = {FooTrace, BarTrace, 332 GooTrace}; 333 Writer.addTemporalProfileTraces(SampledTraces, 5); 334 // Add some unsampled traces 335 SmallVector<TemporalProfTraceTy, 4> UnsampledTraces = {BarTrace, GooTrace}; 336 Writer.addTemporalProfileTraces(UnsampledTraces, 2); 337 UnsampledTraces = {FooTrace}; 338 Writer.addTemporalProfileTraces(UnsampledTraces, 1); 339 340 auto Profile = Writer.writeBuffer(); 341 readProfile(std::move(Profile)); 342 343 ASSERT_TRUE(Reader->hasTemporalProfile()); 344 EXPECT_EQ(Reader->getTemporalProfTraceStreamSize(), 8U); 345 // Check that we have a subset of all the traces we added 346 EXPECT_THAT(Reader->getTemporalProfTraces(), SizeIs(ReservoirSize)); 347 EXPECT_THAT( 348 Reader->getTemporalProfTraces(), 349 IsSubsetOf({FooTrace, BarTrace, GooTrace, BarTrace, GooTrace, FooTrace})); 350 } 351 352 using ::llvm::memprof::IndexedMemProfData; 353 using ::llvm::memprof::IndexedMemProfRecord; 354 using ::llvm::memprof::MemInfoBlock; 355 356 IndexedMemProfData getMemProfDataForTest() { 357 IndexedMemProfData MemProfData; 358 359 MemProfData.Frames.insert({0, {0x123, 1, 2, false}}); 360 MemProfData.Frames.insert({1, {0x345, 3, 4, true}}); 361 MemProfData.Frames.insert({2, {0x125, 5, 6, false}}); 362 MemProfData.Frames.insert({3, {0x567, 7, 8, true}}); 363 MemProfData.Frames.insert({4, {0x124, 5, 6, false}}); 364 MemProfData.Frames.insert({5, {0x789, 8, 9, true}}); 365 366 MemProfData.CallStacks.insert({0x111, {0, 1}}); 367 MemProfData.CallStacks.insert({0x222, {2, 3}}); 368 MemProfData.CallStacks.insert({0x333, {4, 5}}); 369 370 return MemProfData; 371 } 372 373 // Populate all of the fields of MIB. 374 MemInfoBlock makeFullMIB() { 375 MemInfoBlock MIB; 376 #define MIBEntryDef(NameTag, Name, Type) MIB.NameTag; 377 #include "llvm/ProfileData/MIBEntryDef.inc" 378 #undef MIBEntryDef 379 return MIB; 380 } 381 382 // Populate those fields returned by getHotColdSchema. 383 MemInfoBlock makePartialMIB() { 384 MemInfoBlock MIB; 385 MIB.AllocCount = 1; 386 MIB.TotalSize = 5; 387 MIB.TotalLifetime = 10; 388 MIB.TotalLifetimeAccessDensity = 23; 389 return MIB; 390 } 391 392 IndexedMemProfRecord 393 makeRecordV2(std::initializer_list<::llvm::memprof::CallStackId> AllocFrames, 394 std::initializer_list<::llvm::memprof::CallStackId> CallSiteFrames, 395 const MemInfoBlock &Block, const memprof::MemProfSchema &Schema) { 396 IndexedMemProfRecord MR; 397 for (const auto &CSId : AllocFrames) 398 MR.AllocSites.emplace_back(CSId, Block, Schema); 399 for (const auto &CSId : CallSiteFrames) 400 MR.CallSiteIds.push_back(CSId); 401 return MR; 402 } 403 404 MATCHER_P(EqualsRecord, Want, "") { 405 const memprof::MemProfRecord &Got = arg; 406 407 auto PrintAndFail = [&]() { 408 std::string Buffer; 409 llvm::raw_string_ostream OS(Buffer); 410 OS << "Want:\n"; 411 Want.print(OS); 412 OS << "Got:\n"; 413 Got.print(OS); 414 *result_listener << "MemProf Record differs!\n" << Buffer; 415 return false; 416 }; 417 418 if (Want.AllocSites.size() != Got.AllocSites.size()) 419 return PrintAndFail(); 420 if (Want.CallSites.size() != Got.CallSites.size()) 421 return PrintAndFail(); 422 423 for (size_t I = 0; I < Got.AllocSites.size(); I++) { 424 if (Want.AllocSites[I].Info != Got.AllocSites[I].Info) 425 return PrintAndFail(); 426 if (Want.AllocSites[I].CallStack != Got.AllocSites[I].CallStack) 427 return PrintAndFail(); 428 } 429 430 for (size_t I = 0; I < Got.CallSites.size(); I++) { 431 if (Want.CallSites[I] != Got.CallSites[I]) 432 return PrintAndFail(); 433 } 434 return true; 435 } 436 437 TEST_F(InstrProfTest, test_memprof_v2_full_schema) { 438 const MemInfoBlock MIB = makeFullMIB(); 439 440 Writer.setMemProfVersionRequested(memprof::Version2); 441 Writer.setMemProfFullSchema(true); 442 443 ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf), 444 Succeeded()); 445 446 const IndexedMemProfRecord IndexedMR = makeRecordV2( 447 /*AllocFrames=*/{0x111, 0x222}, 448 /*CallSiteFrames=*/{0x333}, MIB, memprof::getFullSchema()); 449 IndexedMemProfData MemProfData = getMemProfDataForTest(); 450 MemProfData.Records.try_emplace(0x9999, IndexedMR); 451 Writer.addMemProfData(MemProfData, Err); 452 453 auto Profile = Writer.writeBuffer(); 454 readProfile(std::move(Profile)); 455 456 auto RecordOr = Reader->getMemProfRecord(0x9999); 457 ASSERT_THAT_ERROR(RecordOr.takeError(), Succeeded()); 458 const memprof::MemProfRecord &Record = RecordOr.get(); 459 460 memprof::IndexedCallstackIdConveter CSIdConv(MemProfData); 461 462 const ::llvm::memprof::MemProfRecord WantRecord = 463 IndexedMR.toMemProfRecord(CSIdConv); 464 ASSERT_EQ(CSIdConv.FrameIdConv.LastUnmappedId, std::nullopt) 465 << "could not map frame id: " << *CSIdConv.FrameIdConv.LastUnmappedId; 466 ASSERT_EQ(CSIdConv.CSIdConv.LastUnmappedId, std::nullopt) 467 << "could not map call stack id: " << *CSIdConv.CSIdConv.LastUnmappedId; 468 EXPECT_THAT(WantRecord, EqualsRecord(Record)); 469 } 470 471 TEST_F(InstrProfTest, test_memprof_v2_partial_schema) { 472 const MemInfoBlock MIB = makePartialMIB(); 473 474 Writer.setMemProfVersionRequested(memprof::Version2); 475 Writer.setMemProfFullSchema(false); 476 477 ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf), 478 Succeeded()); 479 480 const IndexedMemProfRecord IndexedMR = makeRecordV2( 481 /*AllocFrames=*/{0x111, 0x222}, 482 /*CallSiteFrames=*/{0x333}, MIB, memprof::getHotColdSchema()); 483 IndexedMemProfData MemProfData = getMemProfDataForTest(); 484 MemProfData.Records.try_emplace(0x9999, IndexedMR); 485 Writer.addMemProfData(MemProfData, Err); 486 487 auto Profile = Writer.writeBuffer(); 488 readProfile(std::move(Profile)); 489 490 auto RecordOr = Reader->getMemProfRecord(0x9999); 491 ASSERT_THAT_ERROR(RecordOr.takeError(), Succeeded()); 492 const memprof::MemProfRecord &Record = RecordOr.get(); 493 494 memprof::IndexedCallstackIdConveter CSIdConv(MemProfData); 495 496 const ::llvm::memprof::MemProfRecord WantRecord = 497 IndexedMR.toMemProfRecord(CSIdConv); 498 ASSERT_EQ(CSIdConv.FrameIdConv.LastUnmappedId, std::nullopt) 499 << "could not map frame id: " << *CSIdConv.FrameIdConv.LastUnmappedId; 500 ASSERT_EQ(CSIdConv.CSIdConv.LastUnmappedId, std::nullopt) 501 << "could not map call stack id: " << *CSIdConv.CSIdConv.LastUnmappedId; 502 EXPECT_THAT(WantRecord, EqualsRecord(Record)); 503 } 504 505 TEST_F(InstrProfTest, test_caller_callee_pairs) { 506 const MemInfoBlock MIB = makePartialMIB(); 507 508 Writer.setMemProfVersionRequested(memprof::Version3); 509 Writer.setMemProfFullSchema(false); 510 511 ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf), 512 Succeeded()); 513 514 // Call Hierarchy 515 // 516 // Function GUID:0x123 517 // Line: 1, Column: 2 518 // Function GUID: 0x234 519 // Line: 3, Column: 4 520 // new(...) 521 // Line: 5, Column: 6 522 // Function GUID: 0x345 523 // Line: 7, Column: 8 524 // new(...) 525 526 const IndexedMemProfRecord IndexedMR = makeRecordV2( 527 /*AllocFrames=*/{0x111, 0x222}, 528 /*CallSiteFrames=*/{}, MIB, memprof::getHotColdSchema()); 529 530 IndexedMemProfData MemProfData; 531 MemProfData.Frames.try_emplace(0, 0x123, 1, 2, false); 532 MemProfData.Frames.try_emplace(1, 0x234, 3, 4, true); 533 MemProfData.Frames.try_emplace(2, 0x123, 5, 6, false); 534 MemProfData.Frames.try_emplace(3, 0x345, 7, 8, true); 535 MemProfData.CallStacks.try_emplace( 536 0x111, std::initializer_list<memprof::FrameId>{1, 0}); 537 MemProfData.CallStacks.try_emplace( 538 0x222, std::initializer_list<memprof::FrameId>{3, 2}); 539 MemProfData.Records.try_emplace(0x9999, IndexedMR); 540 Writer.addMemProfData(MemProfData, Err); 541 542 auto Profile = Writer.writeBuffer(); 543 readProfile(std::move(Profile)); 544 545 auto Pairs = Reader->getMemProfCallerCalleePairs(); 546 ASSERT_THAT(Pairs, SizeIs(3)); 547 548 auto It = Pairs.find(0x123); 549 ASSERT_NE(It, Pairs.end()); 550 EXPECT_THAT(It->second, ElementsAre(Pair(LineLocation(1, 2), 0x234U), 551 Pair(LineLocation(5, 6), 0x345U))); 552 553 It = Pairs.find(0x234); 554 ASSERT_NE(It, Pairs.end()); 555 EXPECT_THAT(It->second, ElementsAre(Pair(LineLocation(3, 4), 0U))); 556 557 It = Pairs.find(0x345); 558 ASSERT_NE(It, Pairs.end()); 559 EXPECT_THAT(It->second, ElementsAre(Pair(LineLocation(7, 8), 0U))); 560 } 561 562 TEST_F(InstrProfTest, test_memprof_getrecord_error) { 563 ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf), 564 Succeeded()); 565 566 Writer.setMemProfVersionRequested(memprof::Version3); 567 // Generate an empty profile. 568 auto Profile = Writer.writeBuffer(); 569 readProfile(std::move(Profile)); 570 571 // Missing functions give a unknown_function error. 572 auto RecordOr = Reader->getMemProfRecord(0x1111); 573 ASSERT_TRUE( 574 ErrorEquals(instrprof_error::unknown_function, RecordOr.takeError())); 575 } 576 577 TEST_F(InstrProfTest, test_memprof_merge) { 578 Writer.addRecord({"func1", 0x1234, {42}}, Err); 579 580 InstrProfWriter Writer2; 581 Writer2.setMemProfVersionRequested(memprof::Version3); 582 ASSERT_THAT_ERROR(Writer2.mergeProfileKind(InstrProfKind::MemProf), 583 Succeeded()); 584 585 const IndexedMemProfRecord IndexedMR = makeRecordV2( 586 /*AllocFrames=*/{0x111, 0x222}, 587 /*CallSiteFrames=*/{}, makePartialMIB(), memprof::getHotColdSchema()); 588 589 IndexedMemProfData MemProfData = getMemProfDataForTest(); 590 MemProfData.Records.try_emplace(0x9999, IndexedMR); 591 Writer2.addMemProfData(MemProfData, Err); 592 593 ASSERT_THAT_ERROR(Writer.mergeProfileKind(Writer2.getProfileKind()), 594 Succeeded()); 595 Writer.mergeRecordsFromWriter(std::move(Writer2), Err); 596 597 Writer.setMemProfVersionRequested(memprof::Version3); 598 auto Profile = Writer.writeBuffer(); 599 readProfile(std::move(Profile)); 600 601 Expected<InstrProfRecord> R = Reader->getInstrProfRecord("func1", 0x1234); 602 EXPECT_THAT_ERROR(R.takeError(), Succeeded()); 603 ASSERT_EQ(1U, R->Counts.size()); 604 ASSERT_EQ(42U, R->Counts[0]); 605 606 auto RecordOr = Reader->getMemProfRecord(0x9999); 607 ASSERT_THAT_ERROR(RecordOr.takeError(), Succeeded()); 608 const memprof::MemProfRecord &Record = RecordOr.get(); 609 610 std::optional<memprof::FrameId> LastUnmappedFrameId; 611 612 memprof::IndexedCallstackIdConveter CSIdConv(MemProfData); 613 614 const ::llvm::memprof::MemProfRecord WantRecord = 615 IndexedMR.toMemProfRecord(CSIdConv); 616 ASSERT_EQ(LastUnmappedFrameId, std::nullopt) 617 << "could not map frame id: " << *LastUnmappedFrameId; 618 EXPECT_THAT(WantRecord, EqualsRecord(Record)); 619 } 620 621 TEST_F(InstrProfTest, test_irpgo_function_name) { 622 LLVMContext Ctx; 623 auto M = std::make_unique<Module>("MyModule.cpp", Ctx); 624 auto *FTy = FunctionType::get(Type::getVoidTy(Ctx), /*isVarArg=*/false); 625 626 std::vector<std::tuple<StringRef, Function::LinkageTypes, StringRef>> Data; 627 Data.emplace_back("ExternalFoo", Function::ExternalLinkage, "ExternalFoo"); 628 Data.emplace_back("InternalFoo", Function::InternalLinkage, 629 "MyModule.cpp;InternalFoo"); 630 Data.emplace_back("\01-[C dynamicFoo:]", Function::ExternalLinkage, 631 "-[C dynamicFoo:]"); 632 Data.emplace_back("\01-[C internalFoo:]", Function::InternalLinkage, 633 "MyModule.cpp;-[C internalFoo:]"); 634 635 for (auto &[Name, Linkage, ExpectedIRPGOFuncName] : Data) 636 Function::Create(FTy, Linkage, Name, M.get()); 637 638 for (auto &[Name, Linkage, ExpectedIRPGOFuncName] : Data) { 639 auto *F = M->getFunction(Name); 640 auto IRPGOFuncName = getIRPGOFuncName(*F); 641 EXPECT_EQ(IRPGOFuncName, ExpectedIRPGOFuncName); 642 643 auto [Filename, ParsedIRPGOFuncName] = getParsedIRPGOName(IRPGOFuncName); 644 StringRef ExpectedParsedIRPGOFuncName = IRPGOFuncName; 645 if (ExpectedParsedIRPGOFuncName.consume_front("MyModule.cpp;")) { 646 EXPECT_EQ(Filename, "MyModule.cpp"); 647 } else { 648 EXPECT_EQ(Filename, ""); 649 } 650 EXPECT_EQ(ParsedIRPGOFuncName, ExpectedParsedIRPGOFuncName); 651 } 652 } 653 654 TEST_F(InstrProfTest, test_pgo_function_name) { 655 LLVMContext Ctx; 656 auto M = std::make_unique<Module>("MyModule.cpp", Ctx); 657 auto *FTy = FunctionType::get(Type::getVoidTy(Ctx), /*isVarArg=*/false); 658 659 std::vector<std::tuple<StringRef, Function::LinkageTypes, StringRef>> Data; 660 Data.emplace_back("ExternalFoo", Function::ExternalLinkage, "ExternalFoo"); 661 Data.emplace_back("InternalFoo", Function::InternalLinkage, 662 "MyModule.cpp:InternalFoo"); 663 Data.emplace_back("\01-[C externalFoo:]", Function::ExternalLinkage, 664 "-[C externalFoo:]"); 665 Data.emplace_back("\01-[C internalFoo:]", Function::InternalLinkage, 666 "MyModule.cpp:-[C internalFoo:]"); 667 668 for (auto &[Name, Linkage, ExpectedPGOFuncName] : Data) 669 Function::Create(FTy, Linkage, Name, M.get()); 670 671 for (auto &[Name, Linkage, ExpectedPGOFuncName] : Data) { 672 auto *F = M->getFunction(Name); 673 EXPECT_EQ(getPGOFuncName(*F), ExpectedPGOFuncName); 674 } 675 } 676 677 TEST_F(InstrProfTest, test_irpgo_read_deprecated_names) { 678 LLVMContext Ctx; 679 auto M = std::make_unique<Module>("MyModule.cpp", Ctx); 680 auto *FTy = FunctionType::get(Type::getVoidTy(Ctx), /*isVarArg=*/false); 681 auto *InternalFooF = 682 Function::Create(FTy, Function::InternalLinkage, "InternalFoo", M.get()); 683 auto *ExternalFooF = 684 Function::Create(FTy, Function::ExternalLinkage, "ExternalFoo", M.get()); 685 686 auto *InternalBarF = 687 Function::Create(FTy, Function::InternalLinkage, "InternalBar", M.get()); 688 auto *ExternalBarF = 689 Function::Create(FTy, Function::ExternalLinkage, "ExternalBar", M.get()); 690 691 Writer.addRecord({getIRPGOFuncName(*InternalFooF), 0x1234, {1}}, Err); 692 Writer.addRecord({getIRPGOFuncName(*ExternalFooF), 0x5678, {1}}, Err); 693 // Write a record with a deprecated name 694 Writer.addRecord({getPGOFuncName(*InternalBarF), 0x1111, {2}}, Err); 695 Writer.addRecord({getPGOFuncName(*ExternalBarF), 0x2222, {2}}, Err); 696 697 auto Profile = Writer.writeBuffer(); 698 readProfile(std::move(Profile)); 699 700 EXPECT_THAT_EXPECTED( 701 Reader->getInstrProfRecord(getIRPGOFuncName(*InternalFooF), 0x1234, 702 getPGOFuncName(*InternalFooF)), 703 Succeeded()); 704 EXPECT_THAT_EXPECTED( 705 Reader->getInstrProfRecord(getIRPGOFuncName(*ExternalFooF), 0x5678, 706 getPGOFuncName(*ExternalFooF)), 707 Succeeded()); 708 // Ensure we can still read this old record name 709 EXPECT_THAT_EXPECTED( 710 Reader->getInstrProfRecord(getIRPGOFuncName(*InternalBarF), 0x1111, 711 getPGOFuncName(*InternalBarF)), 712 Succeeded()); 713 EXPECT_THAT_EXPECTED( 714 Reader->getInstrProfRecord(getIRPGOFuncName(*ExternalBarF), 0x2222, 715 getPGOFuncName(*ExternalBarF)), 716 Succeeded()); 717 } 718 719 // callee1 to callee6 are from vtable1 to vtable6 respectively. 720 static const char callee1[] = "callee1"; 721 static const char callee2[] = "callee2"; 722 static const char callee3[] = "callee3"; 723 static const char callee4[] = "callee4"; 724 static const char callee5[] = "callee5"; 725 static const char callee6[] = "callee6"; 726 // callee7 and callee8 are not from any vtables. 727 static const char callee7[] = "callee7"; 728 static const char callee8[] = "callee8"; 729 // 'callee' is primarily used to create multiple-element vtables. 730 static const char callee[] = "callee"; 731 static const uint64_t vtable1[] = {uint64_t(callee), uint64_t(callee1)}; 732 static const uint64_t vtable2[] = {uint64_t(callee2), uint64_t(callee)}; 733 static const uint64_t vtable3[] = { 734 uint64_t(callee), 735 uint64_t(callee3), 736 }; 737 static const uint64_t vtable4[] = {uint64_t(callee4), uint64_t(callee)}; 738 static const uint64_t vtable5[] = {uint64_t(callee5), uint64_t(callee)}; 739 static const uint64_t vtable6[] = {uint64_t(callee6), uint64_t(callee)}; 740 741 // Returns the address of callee with a numbered suffix in vtable. 742 static uint64_t getCalleeAddress(const uint64_t *vtableAddr) { 743 uint64_t CalleeAddr; 744 // Callee with a numbered suffix is the 2nd element in vtable1 and vtable3, 745 // and the 1st element in the rest of vtables. 746 if (vtableAddr == vtable1 || vtableAddr == vtable3) 747 CalleeAddr = uint64_t(vtableAddr) + 8; 748 else 749 CalleeAddr = uint64_t(vtableAddr); 750 return CalleeAddr; 751 } 752 753 TEST_P(InstrProfReaderWriterTest, icall_and_vtable_data_read_write) { 754 NamedInstrProfRecord Record1("caller", 0x1234, {1, 2}); 755 756 // 4 indirect call value sites. 757 { 758 Record1.reserveSites(IPVK_IndirectCallTarget, 4); 759 InstrProfValueData VD0[] = { 760 {(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}, {(uint64_t)callee3, 3}}; 761 Record1.addValueData(IPVK_IndirectCallTarget, 0, VD0, nullptr); 762 // No value profile data at the second site. 763 Record1.addValueData(IPVK_IndirectCallTarget, 1, {}, nullptr); 764 InstrProfValueData VD2[] = {{(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}}; 765 Record1.addValueData(IPVK_IndirectCallTarget, 2, VD2, nullptr); 766 InstrProfValueData VD3[] = {{(uint64_t)callee7, 1}, {(uint64_t)callee8, 2}}; 767 Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, nullptr); 768 } 769 770 // 2 vtable value sites. 771 { 772 InstrProfValueData VD0[] = { 773 {getCalleeAddress(vtable1), 1}, 774 {getCalleeAddress(vtable2), 2}, 775 {getCalleeAddress(vtable3), 3}, 776 }; 777 InstrProfValueData VD2[] = { 778 {getCalleeAddress(vtable1), 1}, 779 {getCalleeAddress(vtable2), 2}, 780 }; 781 Record1.addValueData(IPVK_VTableTarget, 0, VD0, nullptr); 782 Record1.addValueData(IPVK_VTableTarget, 1, VD2, nullptr); 783 } 784 785 Writer.addRecord(std::move(Record1), getProfWeight(), Err); 786 Writer.addRecord({"callee1", 0x1235, {3, 4}}, Err); 787 Writer.addRecord({"callee2", 0x1235, {3, 4}}, Err); 788 Writer.addRecord({"callee3", 0x1235, {3, 4}}, Err); 789 Writer.addRecord({"callee7", 0x1235, {3, 4}}, Err); 790 Writer.addRecord({"callee8", 0x1235, {3, 4}}, Err); 791 792 // Set writer value prof data endianness. 793 Writer.setValueProfDataEndianness(getEndianness()); 794 795 auto Profile = Writer.writeBuffer(); 796 readProfile(std::move(Profile)); 797 798 // Set reader value prof data endianness. 799 Reader->setValueProfDataEndianness(getEndianness()); 800 801 Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234); 802 ASSERT_THAT_ERROR(R.takeError(), Succeeded()); 803 804 // Test the number of instrumented indirect call sites and the number of 805 // profiled values at each site. 806 ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget)); 807 808 // Test the number of instrumented vtable sites and the number of profiled 809 // values at each site. 810 ASSERT_EQ(R->getNumValueSites(IPVK_VTableTarget), 2U); 811 812 // First indirect site. 813 { 814 auto VD = R->getValueArrayForSite(IPVK_IndirectCallTarget, 0); 815 ASSERT_THAT(VD, SizeIs(3)); 816 817 EXPECT_EQ(VD[0].Count, 3U * getProfWeight()); 818 EXPECT_EQ(VD[1].Count, 2U * getProfWeight()); 819 EXPECT_EQ(VD[2].Count, 1U * getProfWeight()); 820 821 EXPECT_STREQ((const char *)VD[0].Value, "callee3"); 822 EXPECT_STREQ((const char *)VD[1].Value, "callee2"); 823 EXPECT_STREQ((const char *)VD[2].Value, "callee1"); 824 } 825 826 EXPECT_THAT(R->getValueArrayForSite(IPVK_IndirectCallTarget, 1), SizeIs(0)); 827 EXPECT_THAT(R->getValueArrayForSite(IPVK_IndirectCallTarget, 2), SizeIs(2)); 828 EXPECT_THAT(R->getValueArrayForSite(IPVK_IndirectCallTarget, 3), SizeIs(2)); 829 830 // First vtable site. 831 { 832 auto VD = R->getValueArrayForSite(IPVK_VTableTarget, 0); 833 ASSERT_THAT(VD, SizeIs(3)); 834 835 EXPECT_EQ(VD[0].Count, 3U * getProfWeight()); 836 EXPECT_EQ(VD[1].Count, 2U * getProfWeight()); 837 EXPECT_EQ(VD[2].Count, 1U * getProfWeight()); 838 839 EXPECT_EQ(VD[0].Value, getCalleeAddress(vtable3)); 840 EXPECT_EQ(VD[1].Value, getCalleeAddress(vtable2)); 841 EXPECT_EQ(VD[2].Value, getCalleeAddress(vtable1)); 842 } 843 844 // Second vtable site. 845 { 846 auto VD = R->getValueArrayForSite(IPVK_VTableTarget, 1); 847 ASSERT_THAT(VD, SizeIs(2)); 848 849 EXPECT_EQ(VD[0].Count, 2U * getProfWeight()); 850 EXPECT_EQ(VD[1].Count, 1U * getProfWeight()); 851 852 EXPECT_EQ(VD[0].Value, getCalleeAddress(vtable2)); 853 EXPECT_EQ(VD[1].Value, getCalleeAddress(vtable1)); 854 } 855 } 856 857 INSTANTIATE_TEST_SUITE_P( 858 WeightAndEndiannessTest, InstrProfReaderWriterTest, 859 ::testing::Combine( 860 ::testing::Bool(), /* Sparse */ 861 ::testing::Values(1U, 10U), /* ProfWeight */ 862 ::testing::Values(llvm::endianness::big, 863 llvm::endianness::little) /* Endianness */ 864 )); 865 866 TEST_P(MaybeSparseInstrProfTest, annotate_vp_data) { 867 NamedInstrProfRecord Record("caller", 0x1234, {1, 2}); 868 Record.reserveSites(IPVK_IndirectCallTarget, 1); 869 InstrProfValueData VD0[] = {{1000, 1}, {2000, 2}, {3000, 3}, {5000, 5}, 870 {4000, 4}, {6000, 6}}; 871 Record.addValueData(IPVK_IndirectCallTarget, 0, VD0, nullptr); 872 Writer.addRecord(std::move(Record), Err); 873 auto Profile = Writer.writeBuffer(); 874 readProfile(std::move(Profile)); 875 Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234); 876 EXPECT_THAT_ERROR(R.takeError(), Succeeded()); 877 878 LLVMContext Ctx; 879 std::unique_ptr<Module> M(new Module("MyModule", Ctx)); 880 FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), 881 /*isVarArg=*/false); 882 Function *F = 883 Function::Create(FTy, Function::ExternalLinkage, "caller", M.get()); 884 BasicBlock *BB = BasicBlock::Create(Ctx, "", F); 885 886 IRBuilder<> Builder(BB); 887 BasicBlock *TBB = BasicBlock::Create(Ctx, "", F); 888 BasicBlock *FBB = BasicBlock::Create(Ctx, "", F); 889 890 // Use branch instruction to annotate with value profile data for simplicity 891 Instruction *Inst = Builder.CreateCondBr(Builder.getTrue(), TBB, FBB); 892 Instruction *Inst2 = Builder.CreateCondBr(Builder.getTrue(), TBB, FBB); 893 annotateValueSite(*M, *Inst, R.get(), IPVK_IndirectCallTarget, 0); 894 895 uint64_t T; 896 auto ValueData = 897 getValueProfDataFromInst(*Inst, IPVK_IndirectCallTarget, 5, T); 898 ASSERT_THAT(ValueData, SizeIs(3)); 899 ASSERT_EQ(21U, T); 900 // The result should be sorted already: 901 ASSERT_EQ(6000U, ValueData[0].Value); 902 ASSERT_EQ(6U, ValueData[0].Count); 903 ASSERT_EQ(5000U, ValueData[1].Value); 904 ASSERT_EQ(5U, ValueData[1].Count); 905 ASSERT_EQ(4000U, ValueData[2].Value); 906 ASSERT_EQ(4U, ValueData[2].Count); 907 ValueData = getValueProfDataFromInst(*Inst, IPVK_IndirectCallTarget, 1, T); 908 ASSERT_THAT(ValueData, SizeIs(1)); 909 ASSERT_EQ(21U, T); 910 911 ValueData = getValueProfDataFromInst(*Inst2, IPVK_IndirectCallTarget, 5, T); 912 ASSERT_THAT(ValueData, SizeIs(0)); 913 914 // Remove the MD_prof metadata 915 Inst->setMetadata(LLVMContext::MD_prof, 0); 916 // Annotate 5 records this time. 917 annotateValueSite(*M, *Inst, R.get(), IPVK_IndirectCallTarget, 0, 5); 918 ValueData = getValueProfDataFromInst(*Inst, IPVK_IndirectCallTarget, 5, T); 919 ASSERT_THAT(ValueData, SizeIs(5)); 920 ASSERT_EQ(21U, T); 921 ASSERT_EQ(6000U, ValueData[0].Value); 922 ASSERT_EQ(6U, ValueData[0].Count); 923 ASSERT_EQ(5000U, ValueData[1].Value); 924 ASSERT_EQ(5U, ValueData[1].Count); 925 ASSERT_EQ(4000U, ValueData[2].Value); 926 ASSERT_EQ(4U, ValueData[2].Count); 927 ASSERT_EQ(3000U, ValueData[3].Value); 928 ASSERT_EQ(3U, ValueData[3].Count); 929 ASSERT_EQ(2000U, ValueData[4].Value); 930 ASSERT_EQ(2U, ValueData[4].Count); 931 932 // Remove the MD_prof metadata 933 Inst->setMetadata(LLVMContext::MD_prof, 0); 934 // Annotate with 4 records. 935 InstrProfValueData VD0Sorted[] = {{1000, 6}, {2000, 5}, {3000, 4}, {4000, 3}, 936 {5000, 2}, {6000, 1}}; 937 annotateValueSite(*M, *Inst, ArrayRef(VD0Sorted).slice(2), 10, 938 IPVK_IndirectCallTarget, 5); 939 ValueData = getValueProfDataFromInst(*Inst, IPVK_IndirectCallTarget, 5, T); 940 ASSERT_THAT(ValueData, SizeIs(4)); 941 ASSERT_EQ(10U, T); 942 ASSERT_EQ(3000U, ValueData[0].Value); 943 ASSERT_EQ(4U, ValueData[0].Count); 944 ASSERT_EQ(4000U, ValueData[1].Value); 945 ASSERT_EQ(3U, ValueData[1].Count); 946 ASSERT_EQ(5000U, ValueData[2].Value); 947 ASSERT_EQ(2U, ValueData[2].Count); 948 ASSERT_EQ(6000U, ValueData[3].Value); 949 ASSERT_EQ(1U, ValueData[3].Count); 950 } 951 952 TEST_P(MaybeSparseInstrProfTest, icall_and_vtable_data_merge) { 953 static const char caller[] = "caller"; 954 NamedInstrProfRecord Record11(caller, 0x1234, {1, 2}); 955 NamedInstrProfRecord Record12(caller, 0x1234, {1, 2}); 956 957 // 5 value sites for indirect calls. 958 { 959 Record11.reserveSites(IPVK_IndirectCallTarget, 5); 960 InstrProfValueData VD0[] = {{uint64_t(callee1), 1}, 961 {uint64_t(callee2), 2}, 962 {uint64_t(callee3), 3}, 963 {uint64_t(callee4), 4}}; 964 Record11.addValueData(IPVK_IndirectCallTarget, 0, VD0, nullptr); 965 966 // No value profile data at the second site. 967 Record11.addValueData(IPVK_IndirectCallTarget, 1, {}, nullptr); 968 969 InstrProfValueData VD2[] = { 970 {uint64_t(callee1), 1}, {uint64_t(callee2), 2}, {uint64_t(callee3), 3}}; 971 Record11.addValueData(IPVK_IndirectCallTarget, 2, VD2, nullptr); 972 973 InstrProfValueData VD3[] = {{uint64_t(callee7), 1}, {uint64_t(callee8), 2}}; 974 Record11.addValueData(IPVK_IndirectCallTarget, 3, VD3, nullptr); 975 976 InstrProfValueData VD4[] = { 977 {uint64_t(callee1), 1}, {uint64_t(callee2), 2}, {uint64_t(callee3), 3}}; 978 Record11.addValueData(IPVK_IndirectCallTarget, 4, VD4, nullptr); 979 } 980 // 3 value sites for vtables. 981 { 982 Record11.reserveSites(IPVK_VTableTarget, 3); 983 InstrProfValueData VD0[] = {{getCalleeAddress(vtable1), 1}, 984 {getCalleeAddress(vtable2), 2}, 985 {getCalleeAddress(vtable3), 3}, 986 {getCalleeAddress(vtable4), 4}}; 987 Record11.addValueData(IPVK_VTableTarget, 0, VD0, nullptr); 988 989 InstrProfValueData VD2[] = {{getCalleeAddress(vtable1), 1}, 990 {getCalleeAddress(vtable2), 2}, 991 {getCalleeAddress(vtable3), 3}}; 992 Record11.addValueData(IPVK_VTableTarget, 1, VD2, nullptr); 993 994 InstrProfValueData VD4[] = {{getCalleeAddress(vtable1), 1}, 995 {getCalleeAddress(vtable2), 2}, 996 {getCalleeAddress(vtable3), 3}}; 997 Record11.addValueData(IPVK_VTableTarget, 2, VD4, nullptr); 998 } 999 1000 // A different record for the same caller. 1001 Record12.reserveSites(IPVK_IndirectCallTarget, 5); 1002 InstrProfValueData VD02[] = {{uint64_t(callee2), 5}, {uint64_t(callee3), 3}}; 1003 Record12.addValueData(IPVK_IndirectCallTarget, 0, VD02, nullptr); 1004 1005 // No value profile data at the second site. 1006 Record12.addValueData(IPVK_IndirectCallTarget, 1, {}, nullptr); 1007 1008 InstrProfValueData VD22[] = { 1009 {uint64_t(callee2), 1}, {uint64_t(callee3), 3}, {uint64_t(callee4), 4}}; 1010 Record12.addValueData(IPVK_IndirectCallTarget, 2, VD22, nullptr); 1011 1012 Record12.addValueData(IPVK_IndirectCallTarget, 3, {}, nullptr); 1013 1014 InstrProfValueData VD42[] = { 1015 {uint64_t(callee1), 1}, {uint64_t(callee2), 2}, {uint64_t(callee3), 3}}; 1016 Record12.addValueData(IPVK_IndirectCallTarget, 4, VD42, nullptr); 1017 1018 // 3 value sites for vtables. 1019 { 1020 Record12.reserveSites(IPVK_VTableTarget, 3); 1021 InstrProfValueData VD0[] = {{getCalleeAddress(vtable2), 5}, 1022 {getCalleeAddress(vtable3), 3}}; 1023 Record12.addValueData(IPVK_VTableTarget, 0, VD0, nullptr); 1024 1025 InstrProfValueData VD2[] = {{getCalleeAddress(vtable2), 1}, 1026 {getCalleeAddress(vtable3), 3}, 1027 {getCalleeAddress(vtable4), 4}}; 1028 Record12.addValueData(IPVK_VTableTarget, 1, VD2, nullptr); 1029 1030 InstrProfValueData VD4[] = {{getCalleeAddress(vtable1), 1}, 1031 {getCalleeAddress(vtable2), 2}, 1032 {getCalleeAddress(vtable3), 3}}; 1033 Record12.addValueData(IPVK_VTableTarget, 2, VD4, nullptr); 1034 } 1035 1036 Writer.addRecord(std::move(Record11), Err); 1037 // Merge profile data. 1038 Writer.addRecord(std::move(Record12), Err); 1039 1040 Writer.addRecord({callee1, 0x1235, {3, 4}}, Err); 1041 Writer.addRecord({callee2, 0x1235, {3, 4}}, Err); 1042 Writer.addRecord({callee3, 0x1235, {3, 4}}, Err); 1043 Writer.addRecord({callee3, 0x1235, {3, 4}}, Err); 1044 Writer.addRecord({callee4, 0x1235, {3, 5}}, Err); 1045 Writer.addRecord({callee7, 0x1235, {3, 5}}, Err); 1046 Writer.addRecord({callee8, 0x1235, {3, 5}}, Err); 1047 auto Profile = Writer.writeBuffer(); 1048 readProfile(std::move(Profile)); 1049 1050 // Test the number of instrumented value sites and the number of profiled 1051 // values for each site. 1052 Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234); 1053 EXPECT_THAT_ERROR(R.takeError(), Succeeded()); 1054 // For indirect calls. 1055 ASSERT_EQ(5U, R->getNumValueSites(IPVK_IndirectCallTarget)); 1056 // For vtables. 1057 ASSERT_EQ(R->getNumValueSites(IPVK_VTableTarget), 3U); 1058 1059 // Test the merged values for indirect calls. 1060 { 1061 auto VD = R->getValueArrayForSite(IPVK_IndirectCallTarget, 0); 1062 ASSERT_THAT(VD, SizeIs(4)); 1063 EXPECT_STREQ((const char *)VD[0].Value, "callee2"); 1064 EXPECT_EQ(VD[0].Count, 7U); 1065 EXPECT_STREQ((const char *)VD[1].Value, "callee3"); 1066 EXPECT_EQ(VD[1].Count, 6U); 1067 EXPECT_STREQ((const char *)VD[2].Value, "callee4"); 1068 EXPECT_EQ(VD[2].Count, 4U); 1069 EXPECT_STREQ((const char *)VD[3].Value, "callee1"); 1070 EXPECT_EQ(VD[3].Count, 1U); 1071 1072 ASSERT_THAT(R->getValueArrayForSite(IPVK_IndirectCallTarget, 1), SizeIs(0)); 1073 1074 auto VD_2 = R->getValueArrayForSite(IPVK_IndirectCallTarget, 2); 1075 ASSERT_THAT(VD_2, SizeIs(4)); 1076 EXPECT_STREQ((const char *)VD_2[0].Value, "callee3"); 1077 EXPECT_EQ(VD_2[0].Count, 6U); 1078 EXPECT_STREQ((const char *)VD_2[1].Value, "callee4"); 1079 EXPECT_EQ(VD_2[1].Count, 4U); 1080 EXPECT_STREQ((const char *)VD_2[2].Value, "callee2"); 1081 EXPECT_EQ(VD_2[2].Count, 3U); 1082 EXPECT_STREQ((const char *)VD_2[3].Value, "callee1"); 1083 EXPECT_EQ(VD_2[3].Count, 1U); 1084 1085 auto VD_3 = R->getValueArrayForSite(IPVK_IndirectCallTarget, 3); 1086 ASSERT_THAT(VD_3, SizeIs(2)); 1087 EXPECT_STREQ((const char *)VD_3[0].Value, "callee8"); 1088 EXPECT_EQ(VD_3[0].Count, 2U); 1089 EXPECT_STREQ((const char *)VD_3[1].Value, "callee7"); 1090 EXPECT_EQ(VD_3[1].Count, 1U); 1091 1092 auto VD_4 = R->getValueArrayForSite(IPVK_IndirectCallTarget, 4); 1093 ASSERT_THAT(VD_4, SizeIs(3)); 1094 EXPECT_STREQ((const char *)VD_4[0].Value, "callee3"); 1095 EXPECT_EQ(VD_4[0].Count, 6U); 1096 EXPECT_STREQ((const char *)VD_4[1].Value, "callee2"); 1097 EXPECT_EQ(VD_4[1].Count, 4U); 1098 EXPECT_STREQ((const char *)VD_4[2].Value, "callee1"); 1099 EXPECT_EQ(VD_4[2].Count, 2U); 1100 } 1101 1102 // Test the merged values for vtables 1103 { 1104 auto VD0 = R->getValueArrayForSite(IPVK_VTableTarget, 0); 1105 ASSERT_THAT(VD0, SizeIs(4)); 1106 EXPECT_EQ(VD0[0].Value, getCalleeAddress(vtable2)); 1107 EXPECT_EQ(VD0[0].Count, 7U); 1108 EXPECT_EQ(VD0[1].Value, getCalleeAddress(vtable3)); 1109 EXPECT_EQ(VD0[1].Count, 6U); 1110 EXPECT_EQ(VD0[2].Value, getCalleeAddress(vtable4)); 1111 EXPECT_EQ(VD0[2].Count, 4U); 1112 EXPECT_EQ(VD0[3].Value, getCalleeAddress(vtable1)); 1113 EXPECT_EQ(VD0[3].Count, 1U); 1114 1115 auto VD1 = R->getValueArrayForSite(IPVK_VTableTarget, 1); 1116 ASSERT_THAT(VD1, SizeIs(4)); 1117 EXPECT_EQ(VD1[0].Value, getCalleeAddress(vtable3)); 1118 EXPECT_EQ(VD1[0].Count, 6U); 1119 EXPECT_EQ(VD1[1].Value, getCalleeAddress(vtable4)); 1120 EXPECT_EQ(VD1[1].Count, 4U); 1121 EXPECT_EQ(VD1[2].Value, getCalleeAddress(vtable2)); 1122 EXPECT_EQ(VD1[2].Count, 3U); 1123 EXPECT_EQ(VD1[3].Value, getCalleeAddress(vtable1)); 1124 EXPECT_EQ(VD1[3].Count, 1U); 1125 1126 auto VD2 = R->getValueArrayForSite(IPVK_VTableTarget, 2); 1127 ASSERT_THAT(VD2, SizeIs(3)); 1128 EXPECT_EQ(VD2[0].Value, getCalleeAddress(vtable3)); 1129 EXPECT_EQ(VD2[0].Count, 6U); 1130 EXPECT_EQ(VD2[1].Value, getCalleeAddress(vtable2)); 1131 EXPECT_EQ(VD2[1].Count, 4U); 1132 EXPECT_EQ(VD2[2].Value, getCalleeAddress(vtable1)); 1133 EXPECT_EQ(VD2[2].Count, 2U); 1134 } 1135 } 1136 1137 struct ValueProfileMergeEdgeCaseTest 1138 : public InstrProfTest, 1139 public ::testing::WithParamInterface<std::tuple<bool, uint32_t>> { 1140 void SetUp() override { Writer.setOutputSparse(std::get<0>(GetParam())); } 1141 1142 uint32_t getValueProfileKind() const { return std::get<1>(GetParam()); } 1143 }; 1144 1145 TEST_P(ValueProfileMergeEdgeCaseTest, value_profile_data_merge_saturation) { 1146 const uint32_t ValueKind = getValueProfileKind(); 1147 static const char bar[] = "bar"; 1148 const uint64_t ProfiledValue = 0x5678; 1149 1150 const uint64_t MaxValCount = std::numeric_limits<uint64_t>::max(); 1151 const uint64_t MaxEdgeCount = getInstrMaxCountValue(); 1152 1153 instrprof_error Result; 1154 auto Err = [&](Error E) { 1155 Result = std::get<0>(InstrProfError::take(std::move(E))); 1156 }; 1157 Result = instrprof_error::success; 1158 Writer.addRecord({"foo", 0x1234, {1}}, Err); 1159 ASSERT_EQ(Result, instrprof_error::success); 1160 1161 // Verify counter overflow. 1162 Result = instrprof_error::success; 1163 Writer.addRecord({"foo", 0x1234, {MaxEdgeCount}}, Err); 1164 ASSERT_EQ(Result, instrprof_error::counter_overflow); 1165 1166 Result = instrprof_error::success; 1167 Writer.addRecord({bar, 0x9012, {8}}, Err); 1168 ASSERT_EQ(Result, instrprof_error::success); 1169 1170 NamedInstrProfRecord Record4("baz", 0x5678, {3, 4}); 1171 Record4.reserveSites(ValueKind, 1); 1172 InstrProfValueData VD4[] = {{ProfiledValue, 1}}; 1173 Record4.addValueData(ValueKind, 0, VD4, nullptr); 1174 Result = instrprof_error::success; 1175 Writer.addRecord(std::move(Record4), Err); 1176 ASSERT_EQ(Result, instrprof_error::success); 1177 1178 // Verify value data counter overflow. 1179 NamedInstrProfRecord Record5("baz", 0x5678, {5, 6}); 1180 Record5.reserveSites(ValueKind, 1); 1181 InstrProfValueData VD5[] = {{ProfiledValue, MaxValCount}}; 1182 Record5.addValueData(ValueKind, 0, VD5, nullptr); 1183 Result = instrprof_error::success; 1184 Writer.addRecord(std::move(Record5), Err); 1185 ASSERT_EQ(Result, instrprof_error::counter_overflow); 1186 1187 auto Profile = Writer.writeBuffer(); 1188 readProfile(std::move(Profile)); 1189 1190 // Verify saturation of counts. 1191 Expected<InstrProfRecord> ReadRecord1 = 1192 Reader->getInstrProfRecord("foo", 0x1234); 1193 ASSERT_THAT_ERROR(ReadRecord1.takeError(), Succeeded()); 1194 EXPECT_EQ(MaxEdgeCount, ReadRecord1->Counts[0]); 1195 1196 Expected<InstrProfRecord> ReadRecord2 = 1197 Reader->getInstrProfRecord("baz", 0x5678); 1198 ASSERT_TRUE(bool(ReadRecord2)); 1199 ASSERT_EQ(1U, ReadRecord2->getNumValueSites(ValueKind)); 1200 auto VD = ReadRecord2->getValueArrayForSite(ValueKind, 0); 1201 EXPECT_EQ(ProfiledValue, VD[0].Value); 1202 EXPECT_EQ(MaxValCount, VD[0].Count); 1203 } 1204 1205 // This test tests that when there are too many values for a given site, the 1206 // merged results are properly truncated. 1207 TEST_P(ValueProfileMergeEdgeCaseTest, value_profile_data_merge_site_trunc) { 1208 const uint32_t ValueKind = getValueProfileKind(); 1209 static const char caller[] = "caller"; 1210 1211 NamedInstrProfRecord Record11(caller, 0x1234, {1, 2}); 1212 NamedInstrProfRecord Record12(caller, 0x1234, {1, 2}); 1213 1214 // 2 value sites. 1215 Record11.reserveSites(ValueKind, 2); 1216 InstrProfValueData VD0[255]; 1217 for (int I = 0; I < 255; I++) { 1218 VD0[I].Value = 2 * I; 1219 VD0[I].Count = 2 * I + 1000; 1220 } 1221 1222 Record11.addValueData(ValueKind, 0, VD0, nullptr); 1223 Record11.addValueData(ValueKind, 1, {}, nullptr); 1224 1225 Record12.reserveSites(ValueKind, 2); 1226 InstrProfValueData VD1[255]; 1227 for (int I = 0; I < 255; I++) { 1228 VD1[I].Value = 2 * I + 1; 1229 VD1[I].Count = 2 * I + 1001; 1230 } 1231 1232 Record12.addValueData(ValueKind, 0, VD1, nullptr); 1233 Record12.addValueData(ValueKind, 1, {}, nullptr); 1234 1235 Writer.addRecord(std::move(Record11), Err); 1236 // Merge profile data. 1237 Writer.addRecord(std::move(Record12), Err); 1238 1239 auto Profile = Writer.writeBuffer(); 1240 readProfile(std::move(Profile)); 1241 1242 Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234); 1243 ASSERT_THAT_ERROR(R.takeError(), Succeeded()); 1244 ASSERT_EQ(2U, R->getNumValueSites(ValueKind)); 1245 auto VD = R->getValueArrayForSite(ValueKind, 0); 1246 EXPECT_THAT(VD, SizeIs(255)); 1247 for (unsigned I = 0; I < 255; I++) { 1248 EXPECT_EQ(VD[I].Value, 509 - I); 1249 EXPECT_EQ(VD[I].Count, 1509 - I); 1250 } 1251 } 1252 1253 INSTANTIATE_TEST_SUITE_P( 1254 EdgeCaseTest, ValueProfileMergeEdgeCaseTest, 1255 ::testing::Combine(::testing::Bool(), /* Sparse */ 1256 ::testing::Values(IPVK_IndirectCallTarget, 1257 IPVK_MemOPSize, 1258 IPVK_VTableTarget) /* ValueKind */ 1259 )); 1260 1261 static void addValueProfData(InstrProfRecord &Record) { 1262 // Add test data for indirect calls. 1263 { 1264 Record.reserveSites(IPVK_IndirectCallTarget, 6); 1265 InstrProfValueData VD0[] = {{uint64_t(callee1), 400}, 1266 {uint64_t(callee2), 1000}, 1267 {uint64_t(callee3), 500}, 1268 {uint64_t(callee4), 300}, 1269 {uint64_t(callee5), 100}}; 1270 Record.addValueData(IPVK_IndirectCallTarget, 0, VD0, nullptr); 1271 InstrProfValueData VD1[] = {{uint64_t(callee5), 800}, 1272 {uint64_t(callee3), 1000}, 1273 {uint64_t(callee2), 2500}, 1274 {uint64_t(callee1), 1300}}; 1275 Record.addValueData(IPVK_IndirectCallTarget, 1, VD1, nullptr); 1276 InstrProfValueData VD2[] = {{uint64_t(callee6), 800}, 1277 {uint64_t(callee3), 1000}, 1278 {uint64_t(callee4), 5500}}; 1279 Record.addValueData(IPVK_IndirectCallTarget, 2, VD2, nullptr); 1280 InstrProfValueData VD3[] = {{uint64_t(callee2), 1800}, 1281 {uint64_t(callee3), 2000}}; 1282 Record.addValueData(IPVK_IndirectCallTarget, 3, VD3, nullptr); 1283 Record.addValueData(IPVK_IndirectCallTarget, 4, {}, nullptr); 1284 InstrProfValueData VD5[] = {{uint64_t(callee7), 1234}, 1285 {uint64_t(callee8), 5678}}; 1286 Record.addValueData(IPVK_IndirectCallTarget, 5, VD5, nullptr); 1287 } 1288 1289 // Add test data for vtables 1290 { 1291 Record.reserveSites(IPVK_VTableTarget, 4); 1292 InstrProfValueData VD0[] = { 1293 {getCalleeAddress(vtable1), 400}, {getCalleeAddress(vtable2), 1000}, 1294 {getCalleeAddress(vtable3), 500}, {getCalleeAddress(vtable4), 300}, 1295 {getCalleeAddress(vtable5), 100}, 1296 }; 1297 InstrProfValueData VD1[] = {{getCalleeAddress(vtable5), 800}, 1298 {getCalleeAddress(vtable3), 1000}, 1299 {getCalleeAddress(vtable2), 2500}, 1300 {getCalleeAddress(vtable1), 1300}}; 1301 InstrProfValueData VD2[] = { 1302 {getCalleeAddress(vtable6), 800}, 1303 {getCalleeAddress(vtable3), 1000}, 1304 {getCalleeAddress(vtable4), 5500}, 1305 }; 1306 InstrProfValueData VD3[] = {{getCalleeAddress(vtable2), 1800}, 1307 {getCalleeAddress(vtable3), 2000}}; 1308 Record.addValueData(IPVK_VTableTarget, 0, VD0, nullptr); 1309 Record.addValueData(IPVK_VTableTarget, 1, VD1, nullptr); 1310 Record.addValueData(IPVK_VTableTarget, 2, VD2, nullptr); 1311 Record.addValueData(IPVK_VTableTarget, 3, VD3, nullptr); 1312 } 1313 } 1314 1315 TEST(ValueProfileReadWriteTest, value_prof_data_read_write) { 1316 InstrProfRecord SrcRecord({1ULL << 31, 2}); 1317 addValueProfData(SrcRecord); 1318 std::unique_ptr<ValueProfData> VPData = 1319 ValueProfData::serializeFrom(SrcRecord); 1320 1321 InstrProfRecord Record({1ULL << 31, 2}); 1322 VPData->deserializeTo(Record, nullptr); 1323 1324 // Now read data from Record and sanity check the data 1325 ASSERT_EQ(6U, Record.getNumValueSites(IPVK_IndirectCallTarget)); 1326 1327 auto Cmp = [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) { 1328 return VD1.Count > VD2.Count; 1329 }; 1330 1331 SmallVector<InstrProfValueData> VD_0( 1332 Record.getValueArrayForSite(IPVK_IndirectCallTarget, 0)); 1333 ASSERT_THAT(VD_0, SizeIs(5)); 1334 llvm::sort(VD_0, Cmp); 1335 EXPECT_STREQ((const char *)VD_0[0].Value, "callee2"); 1336 EXPECT_EQ(1000U, VD_0[0].Count); 1337 EXPECT_STREQ((const char *)VD_0[1].Value, "callee3"); 1338 EXPECT_EQ(500U, VD_0[1].Count); 1339 EXPECT_STREQ((const char *)VD_0[2].Value, "callee1"); 1340 EXPECT_EQ(400U, VD_0[2].Count); 1341 EXPECT_STREQ((const char *)VD_0[3].Value, "callee4"); 1342 EXPECT_EQ(300U, VD_0[3].Count); 1343 EXPECT_STREQ((const char *)VD_0[4].Value, "callee5"); 1344 EXPECT_EQ(100U, VD_0[4].Count); 1345 1346 SmallVector<InstrProfValueData> VD_1( 1347 Record.getValueArrayForSite(IPVK_IndirectCallTarget, 1)); 1348 ASSERT_THAT(VD_1, SizeIs(4)); 1349 llvm::sort(VD_1, Cmp); 1350 EXPECT_STREQ((const char *)VD_1[0].Value, "callee2"); 1351 EXPECT_EQ(VD_1[0].Count, 2500U); 1352 EXPECT_STREQ((const char *)VD_1[1].Value, "callee1"); 1353 EXPECT_EQ(VD_1[1].Count, 1300U); 1354 EXPECT_STREQ((const char *)VD_1[2].Value, "callee3"); 1355 EXPECT_EQ(VD_1[2].Count, 1000U); 1356 EXPECT_STREQ((const char *)VD_1[3].Value, "callee5"); 1357 EXPECT_EQ(VD_1[3].Count, 800U); 1358 1359 SmallVector<InstrProfValueData> VD_2( 1360 Record.getValueArrayForSite(IPVK_IndirectCallTarget, 2)); 1361 ASSERT_THAT(VD_2, SizeIs(3)); 1362 llvm::sort(VD_2, Cmp); 1363 EXPECT_STREQ((const char *)VD_2[0].Value, "callee4"); 1364 EXPECT_EQ(VD_2[0].Count, 5500U); 1365 EXPECT_STREQ((const char *)VD_2[1].Value, "callee3"); 1366 EXPECT_EQ(VD_2[1].Count, 1000U); 1367 EXPECT_STREQ((const char *)VD_2[2].Value, "callee6"); 1368 EXPECT_EQ(VD_2[2].Count, 800U); 1369 1370 SmallVector<InstrProfValueData> VD_3( 1371 Record.getValueArrayForSite(IPVK_IndirectCallTarget, 3)); 1372 ASSERT_THAT(VD_3, SizeIs(2)); 1373 llvm::sort(VD_3, Cmp); 1374 EXPECT_STREQ((const char *)VD_3[0].Value, "callee3"); 1375 EXPECT_EQ(VD_3[0].Count, 2000U); 1376 EXPECT_STREQ((const char *)VD_3[1].Value, "callee2"); 1377 EXPECT_EQ(VD_3[1].Count, 1800U); 1378 1379 ASSERT_THAT(Record.getValueArrayForSite(IPVK_IndirectCallTarget, 4), 1380 SizeIs(0)); 1381 ASSERT_THAT(Record.getValueArrayForSite(IPVK_IndirectCallTarget, 5), 1382 SizeIs(2)); 1383 1384 ASSERT_EQ(Record.getNumValueSites(IPVK_VTableTarget), 4U); 1385 1386 SmallVector<InstrProfValueData> VD0( 1387 Record.getValueArrayForSite(IPVK_VTableTarget, 0)); 1388 ASSERT_THAT(VD0, SizeIs(5)); 1389 llvm::sort(VD0, Cmp); 1390 EXPECT_EQ(VD0[0].Value, getCalleeAddress(vtable2)); 1391 EXPECT_EQ(VD0[0].Count, 1000U); 1392 EXPECT_EQ(VD0[1].Value, getCalleeAddress(vtable3)); 1393 EXPECT_EQ(VD0[1].Count, 500U); 1394 EXPECT_EQ(VD0[2].Value, getCalleeAddress(vtable1)); 1395 EXPECT_EQ(VD0[2].Count, 400U); 1396 EXPECT_EQ(VD0[3].Value, getCalleeAddress(vtable4)); 1397 EXPECT_EQ(VD0[3].Count, 300U); 1398 EXPECT_EQ(VD0[4].Value, getCalleeAddress(vtable5)); 1399 EXPECT_EQ(VD0[4].Count, 100U); 1400 1401 SmallVector<InstrProfValueData> VD1( 1402 Record.getValueArrayForSite(IPVK_VTableTarget, 1)); 1403 ASSERT_THAT(VD1, SizeIs(4)); 1404 llvm::sort(VD1, Cmp); 1405 EXPECT_EQ(VD1[0].Value, getCalleeAddress(vtable2)); 1406 EXPECT_EQ(VD1[0].Count, 2500U); 1407 EXPECT_EQ(VD1[1].Value, getCalleeAddress(vtable1)); 1408 EXPECT_EQ(VD1[1].Count, 1300U); 1409 EXPECT_EQ(VD1[2].Value, getCalleeAddress(vtable3)); 1410 EXPECT_EQ(VD1[2].Count, 1000U); 1411 EXPECT_EQ(VD1[3].Value, getCalleeAddress(vtable5)); 1412 EXPECT_EQ(VD1[3].Count, 800U); 1413 1414 SmallVector<InstrProfValueData> VD2( 1415 Record.getValueArrayForSite(IPVK_VTableTarget, 2)); 1416 ASSERT_THAT(VD2, SizeIs(3)); 1417 llvm::sort(VD2, Cmp); 1418 EXPECT_EQ(VD2[0].Value, getCalleeAddress(vtable4)); 1419 EXPECT_EQ(VD2[0].Count, 5500U); 1420 EXPECT_EQ(VD2[1].Value, getCalleeAddress(vtable3)); 1421 EXPECT_EQ(VD2[1].Count, 1000U); 1422 EXPECT_EQ(VD2[2].Value, getCalleeAddress(vtable6)); 1423 EXPECT_EQ(VD2[2].Count, 800U); 1424 1425 SmallVector<InstrProfValueData> VD3( 1426 Record.getValueArrayForSite(IPVK_VTableTarget, 3)); 1427 ASSERT_THAT(VD3, SizeIs(2)); 1428 llvm::sort(VD3, Cmp); 1429 EXPECT_EQ(VD3[0].Value, getCalleeAddress(vtable3)); 1430 EXPECT_EQ(VD3[0].Count, 2000U); 1431 EXPECT_EQ(VD3[1].Value, getCalleeAddress(vtable2)); 1432 EXPECT_EQ(VD3[1].Count, 1800U); 1433 } 1434 1435 TEST(ValueProfileReadWriteTest, symtab_mapping) { 1436 NamedInstrProfRecord SrcRecord("caller", 0x1234, {1ULL << 31, 2}); 1437 addValueProfData(SrcRecord); 1438 std::unique_ptr<ValueProfData> VPData = 1439 ValueProfData::serializeFrom(SrcRecord); 1440 1441 NamedInstrProfRecord Record("caller", 0x1234, {1ULL << 31, 2}); 1442 InstrProfSymtab Symtab; 1443 Symtab.mapAddress(uint64_t(callee1), 0x1000ULL); 1444 Symtab.mapAddress(uint64_t(callee2), 0x2000ULL); 1445 Symtab.mapAddress(uint64_t(callee3), 0x3000ULL); 1446 Symtab.mapAddress(uint64_t(callee4), 0x4000ULL); 1447 // Missing mapping for callee5 1448 1449 auto getVTableStartAddr = [](const uint64_t *vtable) -> uint64_t { 1450 return uint64_t(vtable); 1451 }; 1452 auto getVTableEndAddr = [](const uint64_t *vtable) -> uint64_t { 1453 return uint64_t(vtable) + 16; 1454 }; 1455 auto getVTableMidAddr = [](const uint64_t *vtable) -> uint64_t { 1456 return uint64_t(vtable) + 8; 1457 }; 1458 // vtable1, vtable2, vtable3, vtable4 get mapped; vtable5, vtable6 are not 1459 // mapped. 1460 Symtab.mapVTableAddress(getVTableStartAddr(vtable1), 1461 getVTableEndAddr(vtable1), MD5Hash("vtable1")); 1462 Symtab.mapVTableAddress(getVTableStartAddr(vtable2), 1463 getVTableEndAddr(vtable2), MD5Hash("vtable2")); 1464 Symtab.mapVTableAddress(getVTableStartAddr(vtable3), 1465 getVTableEndAddr(vtable3), MD5Hash("vtable3")); 1466 Symtab.mapVTableAddress(getVTableStartAddr(vtable4), 1467 getVTableEndAddr(vtable4), MD5Hash("vtable4")); 1468 1469 VPData->deserializeTo(Record, &Symtab); 1470 1471 // Now read data from Record and sanity check the data 1472 ASSERT_EQ(Record.getNumValueSites(IPVK_IndirectCallTarget), 6U); 1473 1474 // Look up the value correpsonding to the middle of a vtable in symtab and 1475 // test that it's the hash of the name. 1476 EXPECT_EQ(Symtab.getVTableHashFromAddress(getVTableMidAddr(vtable1)), 1477 MD5Hash("vtable1")); 1478 EXPECT_EQ(Symtab.getVTableHashFromAddress(getVTableMidAddr(vtable2)), 1479 MD5Hash("vtable2")); 1480 EXPECT_EQ(Symtab.getVTableHashFromAddress(getVTableMidAddr(vtable3)), 1481 MD5Hash("vtable3")); 1482 EXPECT_EQ(Symtab.getVTableHashFromAddress(getVTableMidAddr(vtable4)), 1483 MD5Hash("vtable4")); 1484 1485 auto Cmp = [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) { 1486 return VD1.Count > VD2.Count; 1487 }; 1488 SmallVector<InstrProfValueData> VD_0( 1489 Record.getValueArrayForSite(IPVK_IndirectCallTarget, 0)); 1490 ASSERT_THAT(VD_0, SizeIs(5)); 1491 llvm::sort(VD_0, Cmp); 1492 ASSERT_EQ(VD_0[0].Value, 0x2000ULL); 1493 ASSERT_EQ(VD_0[0].Count, 1000U); 1494 ASSERT_EQ(VD_0[1].Value, 0x3000ULL); 1495 ASSERT_EQ(VD_0[1].Count, 500U); 1496 ASSERT_EQ(VD_0[2].Value, 0x1000ULL); 1497 ASSERT_EQ(VD_0[2].Count, 400U); 1498 1499 // callee5 does not have a mapped value -- default to 0. 1500 ASSERT_EQ(VD_0[4].Value, 0ULL); 1501 1502 // Sanity check the vtable value data 1503 ASSERT_EQ(Record.getNumValueSites(IPVK_VTableTarget), 4U); 1504 1505 { 1506 // The first vtable site. 1507 SmallVector<InstrProfValueData> VD( 1508 Record.getValueArrayForSite(IPVK_VTableTarget, 0)); 1509 ASSERT_THAT(VD, SizeIs(5)); 1510 llvm::sort(VD, Cmp); 1511 EXPECT_EQ(VD[0].Count, 1000U); 1512 EXPECT_EQ(VD[0].Value, MD5Hash("vtable2")); 1513 EXPECT_EQ(VD[1].Count, 500U); 1514 EXPECT_EQ(VD[1].Value, MD5Hash("vtable3")); 1515 EXPECT_EQ(VD[2].Value, MD5Hash("vtable1")); 1516 EXPECT_EQ(VD[2].Count, 400U); 1517 EXPECT_EQ(VD[3].Value, MD5Hash("vtable4")); 1518 EXPECT_EQ(VD[3].Count, 300U); 1519 1520 // vtable5 isn't mapped -- default to 0. 1521 EXPECT_EQ(VD[4].Value, 0U); 1522 EXPECT_EQ(VD[4].Count, 100U); 1523 } 1524 1525 { 1526 // The second vtable site. 1527 SmallVector<InstrProfValueData> VD( 1528 Record.getValueArrayForSite(IPVK_VTableTarget, 1)); 1529 ASSERT_THAT(VD, SizeIs(4)); 1530 llvm::sort(VD, Cmp); 1531 EXPECT_EQ(VD[0].Value, MD5Hash("vtable2")); 1532 EXPECT_EQ(VD[0].Count, 2500U); 1533 EXPECT_EQ(VD[1].Value, MD5Hash("vtable1")); 1534 EXPECT_EQ(VD[1].Count, 1300U); 1535 1536 EXPECT_EQ(VD[2].Value, MD5Hash("vtable3")); 1537 EXPECT_EQ(VD[2].Count, 1000U); 1538 // vtable5 isn't mapped -- default to 0. 1539 EXPECT_EQ(VD[3].Value, 0U); 1540 EXPECT_EQ(VD[3].Count, 800U); 1541 } 1542 1543 { 1544 // The third vtable site. 1545 SmallVector<InstrProfValueData> VD( 1546 Record.getValueArrayForSite(IPVK_VTableTarget, 2)); 1547 ASSERT_THAT(VD, SizeIs(3)); 1548 llvm::sort(VD, Cmp); 1549 EXPECT_EQ(VD[0].Count, 5500U); 1550 EXPECT_EQ(VD[0].Value, MD5Hash("vtable4")); 1551 EXPECT_EQ(VD[1].Count, 1000U); 1552 EXPECT_EQ(VD[1].Value, MD5Hash("vtable3")); 1553 // vtable6 isn't mapped -- default to 0. 1554 EXPECT_EQ(VD[2].Value, 0U); 1555 EXPECT_EQ(VD[2].Count, 800U); 1556 } 1557 1558 { 1559 // The fourth vtable site. 1560 SmallVector<InstrProfValueData> VD( 1561 Record.getValueArrayForSite(IPVK_VTableTarget, 3)); 1562 ASSERT_THAT(VD, SizeIs(2)); 1563 llvm::sort(VD, Cmp); 1564 EXPECT_EQ(VD[0].Count, 2000U); 1565 EXPECT_EQ(VD[0].Value, MD5Hash("vtable3")); 1566 EXPECT_EQ(VD[1].Count, 1800U); 1567 EXPECT_EQ(VD[1].Value, MD5Hash("vtable2")); 1568 } 1569 } 1570 1571 TEST_P(MaybeSparseInstrProfTest, get_max_function_count) { 1572 Writer.addRecord({"foo", 0x1234, {1ULL << 31, 2}}, Err); 1573 Writer.addRecord({"bar", 0, {1ULL << 63}}, Err); 1574 Writer.addRecord({"baz", 0x5678, {0, 0, 0, 0}}, Err); 1575 auto Profile = Writer.writeBuffer(); 1576 readProfile(std::move(Profile)); 1577 1578 ASSERT_EQ(1ULL << 63, Reader->getMaximumFunctionCount(/* IsCS */ false)); 1579 } 1580 1581 TEST_P(MaybeSparseInstrProfTest, get_weighted_function_counts) { 1582 Writer.addRecord({"foo", 0x1234, {1, 2}}, 3, Err); 1583 Writer.addRecord({"foo", 0x1235, {3, 4}}, 5, Err); 1584 auto Profile = Writer.writeBuffer(); 1585 readProfile(std::move(Profile)); 1586 1587 std::vector<uint64_t> Counts; 1588 EXPECT_THAT_ERROR(Reader->getFunctionCounts("foo", 0x1234, Counts), 1589 Succeeded()); 1590 ASSERT_EQ(2U, Counts.size()); 1591 ASSERT_EQ(3U, Counts[0]); 1592 ASSERT_EQ(6U, Counts[1]); 1593 1594 EXPECT_THAT_ERROR(Reader->getFunctionCounts("foo", 0x1235, Counts), 1595 Succeeded()); 1596 ASSERT_EQ(2U, Counts.size()); 1597 ASSERT_EQ(15U, Counts[0]); 1598 ASSERT_EQ(20U, Counts[1]); 1599 } 1600 1601 // Testing symtab creator interface used by indexed profile reader. 1602 TEST(SymtabTest, instr_prof_symtab_test) { 1603 std::vector<StringRef> FuncNames; 1604 FuncNames.push_back("func1"); 1605 FuncNames.push_back("func2"); 1606 FuncNames.push_back("func3"); 1607 FuncNames.push_back("bar1"); 1608 FuncNames.push_back("bar2"); 1609 FuncNames.push_back("bar3"); 1610 InstrProfSymtab Symtab; 1611 EXPECT_THAT_ERROR(Symtab.create(FuncNames), Succeeded()); 1612 StringRef R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("func1")); 1613 ASSERT_EQ(StringRef("func1"), R); 1614 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("func2")); 1615 ASSERT_EQ(StringRef("func2"), R); 1616 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("func3")); 1617 ASSERT_EQ(StringRef("func3"), R); 1618 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar1")); 1619 ASSERT_EQ(StringRef("bar1"), R); 1620 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar2")); 1621 ASSERT_EQ(StringRef("bar2"), R); 1622 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar3")); 1623 ASSERT_EQ(StringRef("bar3"), R); 1624 1625 // negative tests 1626 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar4")); 1627 ASSERT_EQ(StringRef(), R); 1628 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("foo4")); 1629 ASSERT_EQ(StringRef(), R); 1630 1631 // Now incrementally update the symtab 1632 EXPECT_THAT_ERROR(Symtab.addFuncName("blah_1"), Succeeded()); 1633 EXPECT_THAT_ERROR(Symtab.addFuncName("blah_2"), Succeeded()); 1634 EXPECT_THAT_ERROR(Symtab.addFuncName("blah_3"), Succeeded()); 1635 1636 // Check again 1637 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("blah_1")); 1638 ASSERT_EQ(StringRef("blah_1"), R); 1639 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("blah_2")); 1640 ASSERT_EQ(StringRef("blah_2"), R); 1641 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("blah_3")); 1642 ASSERT_EQ(StringRef("blah_3"), R); 1643 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("func1")); 1644 ASSERT_EQ(StringRef("func1"), R); 1645 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("func2")); 1646 ASSERT_EQ(StringRef("func2"), R); 1647 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("func3")); 1648 ASSERT_EQ(StringRef("func3"), R); 1649 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar1")); 1650 ASSERT_EQ(StringRef("bar1"), R); 1651 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar2")); 1652 ASSERT_EQ(StringRef("bar2"), R); 1653 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash("bar3")); 1654 ASSERT_EQ(StringRef("bar3"), R); 1655 } 1656 1657 // Test that we get an error when creating a bogus symtab. 1658 TEST(SymtabTest, instr_prof_bogus_symtab_empty_func_name) { 1659 InstrProfSymtab Symtab; 1660 EXPECT_TRUE(ErrorEquals(instrprof_error::malformed, Symtab.addFuncName(""))); 1661 } 1662 1663 // Testing symtab creator interface used by value profile transformer. 1664 TEST(SymtabTest, instr_prof_symtab_module_test) { 1665 LLVMContext Ctx; 1666 std::unique_ptr<Module> M = std::make_unique<Module>("MyModule.cpp", Ctx); 1667 FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), 1668 /*isVarArg=*/false); 1669 Function::Create(FTy, Function::ExternalLinkage, "Gfoo", M.get()); 1670 Function::Create(FTy, Function::ExternalLinkage, "Gblah", M.get()); 1671 Function::Create(FTy, Function::ExternalLinkage, "Gbar", M.get()); 1672 Function::Create(FTy, Function::InternalLinkage, "Ifoo", M.get()); 1673 Function::Create(FTy, Function::InternalLinkage, "Iblah", M.get()); 1674 Function::Create(FTy, Function::InternalLinkage, "Ibar", M.get()); 1675 Function::Create(FTy, Function::PrivateLinkage, "Pfoo", M.get()); 1676 Function::Create(FTy, Function::PrivateLinkage, "Pblah", M.get()); 1677 Function::Create(FTy, Function::PrivateLinkage, "Pbar", M.get()); 1678 Function::Create(FTy, Function::WeakODRLinkage, "Wfoo", M.get()); 1679 Function::Create(FTy, Function::WeakODRLinkage, "Wblah", M.get()); 1680 Function::Create(FTy, Function::WeakODRLinkage, "Wbar", M.get()); 1681 1682 // [ptr, ptr, ptr] 1683 ArrayType *VTableArrayType = ArrayType::get( 1684 PointerType::get(Ctx, M->getDataLayout().getDefaultGlobalsAddressSpace()), 1685 3); 1686 Constant *Int32TyNull = 1687 llvm::ConstantExpr::getNullValue(PointerType::getUnqual(Ctx)); 1688 SmallVector<llvm::Type *, 1> tys = {VTableArrayType}; 1689 StructType *VTableType = llvm::StructType::get(Ctx, tys); 1690 1691 // Create two vtables in the module, one with external linkage and the other 1692 // with local linkage. 1693 for (auto [Name, Linkage] : 1694 {std::pair{"ExternalGV", GlobalValue::ExternalLinkage}, 1695 {"LocalGV", GlobalValue::InternalLinkage}}) { 1696 llvm::Twine FuncName(Name, StringRef("VFunc")); 1697 Function *VFunc = Function::Create(FTy, Linkage, FuncName, M.get()); 1698 GlobalVariable *GV = new llvm::GlobalVariable( 1699 *M, VTableType, /* isConstant= */ true, Linkage, 1700 llvm::ConstantStruct::get( 1701 VTableType, 1702 {llvm::ConstantArray::get(VTableArrayType, 1703 {Int32TyNull, Int32TyNull, VFunc})}), 1704 Name); 1705 // Add type metadata for the test data, since vtables with type metadata 1706 // are added to symtab. 1707 GV->addTypeMetadata(16, MDString::get(Ctx, Name)); 1708 } 1709 1710 InstrProfSymtab ProfSymtab; 1711 EXPECT_THAT_ERROR(ProfSymtab.create(*M), Succeeded()); 1712 1713 StringRef Funcs[] = {"Gfoo", "Gblah", "Gbar", "Ifoo", "Iblah", "Ibar", 1714 "Pfoo", "Pblah", "Pbar", "Wfoo", "Wblah", "Wbar"}; 1715 1716 for (unsigned I = 0; I < std::size(Funcs); I++) { 1717 Function *F = M->getFunction(Funcs[I]); 1718 1719 std::string IRPGOName = getIRPGOFuncName(*F); 1720 auto IRPGOFuncName = 1721 ProfSymtab.getFuncOrVarName(IndexedInstrProf::ComputeHash(IRPGOName)); 1722 EXPECT_EQ(IRPGOName, IRPGOFuncName); 1723 EXPECT_EQ(Funcs[I], getParsedIRPGOName(IRPGOFuncName).second); 1724 // Ensure we can still read this old record name. 1725 std::string PGOName = getPGOFuncName(*F); 1726 auto PGOFuncName = 1727 ProfSymtab.getFuncOrVarName(IndexedInstrProf::ComputeHash(PGOName)); 1728 EXPECT_EQ(PGOName, PGOFuncName); 1729 EXPECT_THAT(PGOFuncName.str(), EndsWith(Funcs[I].str())); 1730 } 1731 1732 for (auto [VTableName, PGOName] : {std::pair{"ExternalGV", "ExternalGV"}, 1733 {"LocalGV", "MyModule.cpp;LocalGV"}}) { 1734 GlobalVariable *GV = 1735 M->getGlobalVariable(VTableName, /* AllowInternal=*/true); 1736 1737 // Test that ProfSymtab returns the expected name given a hash. 1738 std::string IRPGOName = getPGOName(*GV); 1739 EXPECT_STREQ(IRPGOName.c_str(), PGOName); 1740 uint64_t GUID = IndexedInstrProf::ComputeHash(IRPGOName); 1741 EXPECT_EQ(IRPGOName, ProfSymtab.getFuncOrVarName(GUID)); 1742 EXPECT_EQ(VTableName, getParsedIRPGOName(IRPGOName).second); 1743 1744 // Test that ProfSymtab returns the expected global variable 1745 EXPECT_EQ(GV, ProfSymtab.getGlobalVariable(GUID)); 1746 } 1747 } 1748 1749 // Testing symtab serialization and creator/deserialization interface 1750 // used by coverage map reader, and raw profile reader. 1751 TEST(SymtabTest, instr_prof_symtab_compression_test) { 1752 std::vector<std::string> FuncNames1; 1753 std::vector<std::string> FuncNames2; 1754 for (int I = 0; I < 3; I++) { 1755 std::string str; 1756 raw_string_ostream OS(str); 1757 OS << "func_" << I; 1758 FuncNames1.push_back(OS.str()); 1759 str.clear(); 1760 OS << "f oooooooooooooo_" << I; 1761 FuncNames1.push_back(OS.str()); 1762 str.clear(); 1763 OS << "BAR_" << I; 1764 FuncNames2.push_back(OS.str()); 1765 str.clear(); 1766 OS << "BlahblahBlahblahBar_" << I; 1767 FuncNames2.push_back(OS.str()); 1768 } 1769 1770 for (bool DoCompression : {false, true}) { 1771 // Compressing: 1772 std::string FuncNameStrings1; 1773 EXPECT_THAT_ERROR(collectGlobalObjectNameStrings( 1774 FuncNames1, 1775 (DoCompression && compression::zlib::isAvailable()), 1776 FuncNameStrings1), 1777 Succeeded()); 1778 1779 // Compressing: 1780 std::string FuncNameStrings2; 1781 EXPECT_THAT_ERROR(collectGlobalObjectNameStrings( 1782 FuncNames2, 1783 (DoCompression && compression::zlib::isAvailable()), 1784 FuncNameStrings2), 1785 Succeeded()); 1786 1787 for (int Padding = 0; Padding < 2; Padding++) { 1788 // Join with paddings : 1789 std::string FuncNameStrings = FuncNameStrings1; 1790 for (int P = 0; P < Padding; P++) { 1791 FuncNameStrings.push_back('\0'); 1792 } 1793 FuncNameStrings += FuncNameStrings2; 1794 1795 // Now decompress: 1796 InstrProfSymtab Symtab; 1797 EXPECT_THAT_ERROR(Symtab.create(StringRef(FuncNameStrings)), Succeeded()); 1798 1799 // Now do the checks: 1800 // First sampling some data points: 1801 StringRef R = 1802 Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash(FuncNames1[0])); 1803 ASSERT_EQ(StringRef("func_0"), R); 1804 R = Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash(FuncNames1[1])); 1805 ASSERT_EQ(StringRef("f oooooooooooooo_0"), R); 1806 for (int I = 0; I < 3; I++) { 1807 std::string N[4]; 1808 N[0] = FuncNames1[2 * I]; 1809 N[1] = FuncNames1[2 * I + 1]; 1810 N[2] = FuncNames2[2 * I]; 1811 N[3] = FuncNames2[2 * I + 1]; 1812 for (int J = 0; J < 4; J++) { 1813 StringRef R = 1814 Symtab.getFuncOrVarName(IndexedInstrProf::ComputeHash(N[J])); 1815 ASSERT_EQ(StringRef(N[J]), R); 1816 } 1817 } 1818 } 1819 } 1820 } 1821 1822 TEST_P(MaybeSparseInstrProfTest, remapping_test) { 1823 Writer.addRecord({"_Z3fooi", 0x1234, {1, 2, 3, 4}}, Err); 1824 Writer.addRecord({"file;_Z3barf", 0x567, {5, 6, 7}}, Err); 1825 auto Profile = Writer.writeBuffer(); 1826 readProfile(std::move(Profile), llvm::MemoryBuffer::getMemBuffer(R"( 1827 type i l 1828 name 3bar 4quux 1829 )")); 1830 1831 std::vector<uint64_t> Counts; 1832 for (StringRef FooName : {"_Z3fooi", "_Z3fool"}) { 1833 EXPECT_THAT_ERROR(Reader->getFunctionCounts(FooName, 0x1234, Counts), 1834 Succeeded()); 1835 ASSERT_EQ(4u, Counts.size()); 1836 EXPECT_EQ(1u, Counts[0]); 1837 EXPECT_EQ(2u, Counts[1]); 1838 EXPECT_EQ(3u, Counts[2]); 1839 EXPECT_EQ(4u, Counts[3]); 1840 } 1841 1842 for (StringRef BarName : {"file;_Z3barf", "file;_Z4quuxf"}) { 1843 EXPECT_THAT_ERROR(Reader->getFunctionCounts(BarName, 0x567, Counts), 1844 Succeeded()); 1845 ASSERT_EQ(3u, Counts.size()); 1846 EXPECT_EQ(5u, Counts[0]); 1847 EXPECT_EQ(6u, Counts[1]); 1848 EXPECT_EQ(7u, Counts[2]); 1849 } 1850 1851 for (StringRef BadName : {"_Z3foof", "_Z4quuxi", "_Z3barl", "", "_ZZZ", 1852 "_Z3barf", "otherfile:_Z4quuxf"}) { 1853 EXPECT_THAT_ERROR(Reader->getFunctionCounts(BadName, 0x1234, Counts), 1854 Failed()); 1855 EXPECT_THAT_ERROR(Reader->getFunctionCounts(BadName, 0x567, Counts), 1856 Failed()); 1857 } 1858 } 1859 1860 TEST_F(SparseInstrProfTest, preserve_no_records) { 1861 Writer.addRecord({"foo", 0x1234, {0}}, Err); 1862 Writer.addRecord({"bar", 0x4321, {0, 0}}, Err); 1863 Writer.addRecord({"baz", 0x4321, {0, 0, 0}}, Err); 1864 1865 auto Profile = Writer.writeBuffer(); 1866 readProfile(std::move(Profile)); 1867 1868 auto I = Reader->begin(), E = Reader->end(); 1869 ASSERT_TRUE(I == E); 1870 } 1871 1872 INSTANTIATE_TEST_SUITE_P(MaybeSparse, MaybeSparseInstrProfTest, 1873 ::testing::Bool()); 1874 1875 #if defined(_LP64) && defined(EXPENSIVE_CHECKS) 1876 TEST(ProfileReaderTest, ReadsLargeFiles) { 1877 const size_t LargeSize = 1ULL << 32; // 4GB 1878 1879 auto RawProfile = WritableMemoryBuffer::getNewUninitMemBuffer(LargeSize); 1880 if (!RawProfile) 1881 GTEST_SKIP(); 1882 auto RawProfileReaderOrErr = InstrProfReader::create(std::move(RawProfile)); 1883 ASSERT_TRUE( 1884 std::get<0>(InstrProfError::take(RawProfileReaderOrErr.takeError())) == 1885 instrprof_error::unrecognized_format); 1886 1887 auto IndexedProfile = WritableMemoryBuffer::getNewUninitMemBuffer(LargeSize); 1888 if (!IndexedProfile) 1889 GTEST_SKIP(); 1890 auto IndexedReaderOrErr = 1891 IndexedInstrProfReader::create(std::move(IndexedProfile), nullptr); 1892 ASSERT_TRUE( 1893 std::get<0>(InstrProfError::take(IndexedReaderOrErr.takeError())) == 1894 instrprof_error::bad_magic); 1895 } 1896 #endif 1897 1898 } // end anonymous namespace 1899