1 //===- unittest/ProfileData/CoverageMappingTest.cpp -------------------------=// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/ProfileData/Coverage/CoverageMapping.h" 11 #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" 12 #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" 13 #include "llvm/ProfileData/InstrProfReader.h" 14 #include "llvm/ProfileData/InstrProfWriter.h" 15 #include "llvm/Support/raw_ostream.h" 16 #include "gtest/gtest.h" 17 18 #include <ostream> 19 #include <utility> 20 21 using namespace llvm; 22 using namespace coverage; 23 24 static ::testing::AssertionResult NoError(Error E) { 25 if (!E) 26 return ::testing::AssertionSuccess(); 27 return ::testing::AssertionFailure() << "error: " << toString(std::move(E)) 28 << "\n"; 29 } 30 31 namespace llvm { 32 namespace coverage { 33 void PrintTo(const Counter &C, ::std::ostream *os) { 34 if (C.isZero()) 35 *os << "Zero"; 36 else if (C.isExpression()) 37 *os << "Expression " << C.getExpressionID(); 38 else 39 *os << "Counter " << C.getCounterID(); 40 } 41 42 void PrintTo(const CoverageSegment &S, ::std::ostream *os) { 43 *os << "CoverageSegment(" << S.Line << ", " << S.Col << ", "; 44 if (S.HasCount) 45 *os << S.Count << ", "; 46 *os << (S.IsRegionEntry ? "true" : "false") << ")"; 47 } 48 } 49 } 50 51 namespace { 52 53 struct OutputFunctionCoverageData { 54 StringRef Name; 55 uint64_t Hash; 56 std::vector<StringRef> Filenames; 57 std::vector<CounterMappingRegion> Regions; 58 59 OutputFunctionCoverageData() : Hash(0) {} 60 61 OutputFunctionCoverageData(OutputFunctionCoverageData &&OFCD) 62 : Name(OFCD.Name), Hash(OFCD.Hash), Filenames(std::move(OFCD.Filenames)), 63 Regions(std::move(OFCD.Regions)) {} 64 65 OutputFunctionCoverageData(const OutputFunctionCoverageData &) = delete; 66 OutputFunctionCoverageData & 67 operator=(const OutputFunctionCoverageData &) = delete; 68 OutputFunctionCoverageData &operator=(OutputFunctionCoverageData &&) = delete; 69 70 void fillCoverageMappingRecord(CoverageMappingRecord &Record) const { 71 Record.FunctionName = Name; 72 Record.FunctionHash = Hash; 73 Record.Filenames = Filenames; 74 Record.Expressions = {}; 75 Record.MappingRegions = Regions; 76 } 77 }; 78 79 struct CoverageMappingReaderMock : CoverageMappingReader { 80 ArrayRef<OutputFunctionCoverageData> Functions; 81 82 CoverageMappingReaderMock(ArrayRef<OutputFunctionCoverageData> Functions) 83 : Functions(Functions) {} 84 85 Error readNextRecord(CoverageMappingRecord &Record) override { 86 if (Functions.empty()) 87 return make_error<CoverageMapError>(coveragemap_error::eof); 88 89 Functions.front().fillCoverageMappingRecord(Record); 90 Functions = Functions.slice(1); 91 92 return Error::success(); 93 } 94 }; 95 96 struct InputFunctionCoverageData { 97 // Maps the global file index from CoverageMappingTest.Files 98 // to the index of that file within this function. We can't just use 99 // global file indexes here because local indexes have to be dense. 100 // This map is used during serialization to create the virtual file mapping 101 // (from local fileId to global Index) in the head of the per-function 102 // coverage mapping data. 103 SmallDenseMap<unsigned, unsigned> ReverseVirtualFileMapping; 104 std::string Name; 105 uint64_t Hash; 106 std::vector<CounterMappingRegion> Regions; 107 108 InputFunctionCoverageData(std::string Name, uint64_t Hash) 109 : Name(std::move(Name)), Hash(Hash) {} 110 111 InputFunctionCoverageData(InputFunctionCoverageData &&IFCD) 112 : ReverseVirtualFileMapping(std::move(IFCD.ReverseVirtualFileMapping)), 113 Name(std::move(IFCD.Name)), Hash(IFCD.Hash), 114 Regions(std::move(IFCD.Regions)) {} 115 116 InputFunctionCoverageData(const InputFunctionCoverageData &) = delete; 117 InputFunctionCoverageData & 118 operator=(const InputFunctionCoverageData &) = delete; 119 InputFunctionCoverageData &operator=(InputFunctionCoverageData &&) = delete; 120 }; 121 122 struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> { 123 bool UseMultipleReaders; 124 StringMap<unsigned> Files; 125 std::vector<InputFunctionCoverageData> InputFunctions; 126 std::vector<OutputFunctionCoverageData> OutputFunctions; 127 128 InstrProfWriter ProfileWriter; 129 std::unique_ptr<IndexedInstrProfReader> ProfileReader; 130 131 std::unique_ptr<CoverageMapping> LoadedCoverage; 132 133 void SetUp() override { 134 ProfileWriter.setOutputSparse(GetParam().first); 135 UseMultipleReaders = GetParam().second; 136 } 137 138 unsigned getGlobalFileIndex(StringRef Name) { 139 auto R = Files.find(Name); 140 if (R != Files.end()) 141 return R->second; 142 unsigned Index = Files.size(); 143 Files.try_emplace(Name, Index); 144 return Index; 145 } 146 147 // Return the file index of file 'Name' for the current function. 148 // Add the file into the global map if necessary. 149 // See also InputFunctionCoverageData::ReverseVirtualFileMapping 150 // for additional comments. 151 unsigned getFileIndexForFunction(StringRef Name) { 152 unsigned GlobalIndex = getGlobalFileIndex(Name); 153 auto &CurrentFunctionFileMapping = 154 InputFunctions.back().ReverseVirtualFileMapping; 155 auto R = CurrentFunctionFileMapping.find(GlobalIndex); 156 if (R != CurrentFunctionFileMapping.end()) 157 return R->second; 158 unsigned IndexInFunction = CurrentFunctionFileMapping.size(); 159 CurrentFunctionFileMapping.insert( 160 std::make_pair(GlobalIndex, IndexInFunction)); 161 return IndexInFunction; 162 } 163 164 void startFunction(StringRef FuncName, uint64_t Hash) { 165 InputFunctions.emplace_back(FuncName.str(), Hash); 166 } 167 168 void addCMR(Counter C, StringRef File, unsigned LS, unsigned CS, unsigned LE, 169 unsigned CE) { 170 InputFunctions.back().Regions.push_back(CounterMappingRegion::makeRegion( 171 C, getFileIndexForFunction(File), LS, CS, LE, CE)); 172 } 173 174 void addExpansionCMR(StringRef File, StringRef ExpandedFile, unsigned LS, 175 unsigned CS, unsigned LE, unsigned CE) { 176 InputFunctions.back().Regions.push_back(CounterMappingRegion::makeExpansion( 177 getFileIndexForFunction(File), getFileIndexForFunction(ExpandedFile), 178 LS, CS, LE, CE)); 179 } 180 181 std::string writeCoverageRegions(InputFunctionCoverageData &Data) { 182 SmallVector<unsigned, 8> FileIDs(Data.ReverseVirtualFileMapping.size()); 183 for (const auto &E : Data.ReverseVirtualFileMapping) 184 FileIDs[E.second] = E.first; 185 std::string Coverage; 186 llvm::raw_string_ostream OS(Coverage); 187 CoverageMappingWriter(FileIDs, None, Data.Regions).write(OS); 188 return OS.str(); 189 } 190 191 void readCoverageRegions(const std::string &Coverage, 192 OutputFunctionCoverageData &Data) { 193 SmallVector<StringRef, 8> Filenames(Files.size()); 194 for (const auto &E : Files) 195 Filenames[E.getValue()] = E.getKey(); 196 std::vector<CounterExpression> Expressions; 197 RawCoverageMappingReader Reader(Coverage, Filenames, Data.Filenames, 198 Expressions, Data.Regions); 199 ASSERT_TRUE(NoError(Reader.read())); 200 } 201 202 void writeAndReadCoverageRegions(bool EmitFilenames = true) { 203 OutputFunctions.resize(InputFunctions.size()); 204 for (unsigned I = 0; I < InputFunctions.size(); ++I) { 205 std::string Regions = writeCoverageRegions(InputFunctions[I]); 206 readCoverageRegions(Regions, OutputFunctions[I]); 207 OutputFunctions[I].Name = InputFunctions[I].Name; 208 OutputFunctions[I].Hash = InputFunctions[I].Hash; 209 if (!EmitFilenames) 210 OutputFunctions[I].Filenames.clear(); 211 } 212 } 213 214 void readProfCounts() { 215 auto Profile = ProfileWriter.writeBuffer(); 216 auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile)); 217 ASSERT_TRUE(NoError(ReaderOrErr.takeError())); 218 ProfileReader = std::move(ReaderOrErr.get()); 219 } 220 221 Expected<std::unique_ptr<CoverageMapping>> readOutputFunctions() { 222 if (!UseMultipleReaders) { 223 CoverageMappingReaderMock CovReader(OutputFunctions); 224 return CoverageMapping::load(CovReader, *ProfileReader); 225 } 226 227 std::vector<std::unique_ptr<CoverageMappingReader>> CoverageReaders; 228 for (const auto &OF : OutputFunctions) { 229 ArrayRef<OutputFunctionCoverageData> Funcs(OF); 230 CoverageReaders.push_back(make_unique<CoverageMappingReaderMock>(Funcs)); 231 } 232 return CoverageMapping::load(CoverageReaders, *ProfileReader); 233 } 234 235 void loadCoverageMapping(bool EmitFilenames = true) { 236 readProfCounts(); 237 writeAndReadCoverageRegions(EmitFilenames); 238 auto CoverageOrErr = readOutputFunctions(); 239 ASSERT_TRUE(NoError(CoverageOrErr.takeError())); 240 LoadedCoverage = std::move(CoverageOrErr.get()); 241 } 242 }; 243 244 TEST_P(CoverageMappingTest, basic_write_read) { 245 startFunction("func", 0x1234); 246 addCMR(Counter::getCounter(0), "foo", 1, 1, 1, 1); 247 addCMR(Counter::getCounter(1), "foo", 2, 1, 2, 2); 248 addCMR(Counter::getZero(), "foo", 3, 1, 3, 4); 249 addCMR(Counter::getCounter(2), "foo", 4, 1, 4, 8); 250 addCMR(Counter::getCounter(3), "bar", 1, 2, 3, 4); 251 252 writeAndReadCoverageRegions(); 253 ASSERT_EQ(1u, InputFunctions.size()); 254 ASSERT_EQ(1u, OutputFunctions.size()); 255 InputFunctionCoverageData &Input = InputFunctions.back(); 256 OutputFunctionCoverageData &Output = OutputFunctions.back(); 257 258 size_t N = makeArrayRef(Input.Regions).size(); 259 ASSERT_EQ(N, Output.Regions.size()); 260 for (size_t I = 0; I < N; ++I) { 261 ASSERT_EQ(Input.Regions[I].Count, Output.Regions[I].Count); 262 ASSERT_EQ(Input.Regions[I].FileID, Output.Regions[I].FileID); 263 ASSERT_EQ(Input.Regions[I].startLoc(), Output.Regions[I].startLoc()); 264 ASSERT_EQ(Input.Regions[I].endLoc(), Output.Regions[I].endLoc()); 265 ASSERT_EQ(Input.Regions[I].Kind, Output.Regions[I].Kind); 266 } 267 } 268 269 TEST_P(CoverageMappingTest, correct_deserialize_for_more_than_two_files) { 270 const char *FileNames[] = {"bar", "baz", "foo"}; 271 static const unsigned N = array_lengthof(FileNames); 272 273 startFunction("func", 0x1234); 274 for (unsigned I = 0; I < N; ++I) 275 // Use LineStart to hold the index of the file name 276 // in order to preserve that information during possible sorting of CMRs. 277 addCMR(Counter::getCounter(0), FileNames[I], I, 1, I, 1); 278 279 writeAndReadCoverageRegions(); 280 ASSERT_EQ(1u, OutputFunctions.size()); 281 OutputFunctionCoverageData &Output = OutputFunctions.back(); 282 283 ASSERT_EQ(N, Output.Regions.size()); 284 ASSERT_EQ(N, Output.Filenames.size()); 285 286 for (unsigned I = 0; I < N; ++I) { 287 ASSERT_GT(N, Output.Regions[I].FileID); 288 ASSERT_GT(N, Output.Regions[I].LineStart); 289 EXPECT_EQ(FileNames[Output.Regions[I].LineStart], 290 Output.Filenames[Output.Regions[I].FileID]); 291 } 292 } 293 294 TEST_P(CoverageMappingTest, load_coverage_for_more_than_two_files) { 295 InstrProfRecord Record("func", 0x1234, {0}); 296 NoError(ProfileWriter.addRecord(std::move(Record))); 297 298 const char *FileNames[] = {"bar", "baz", "foo"}; 299 static const unsigned N = array_lengthof(FileNames); 300 301 startFunction("func", 0x1234); 302 for (unsigned I = 0; I < N; ++I) 303 // Use LineStart to hold the index of the file name 304 // in order to preserve that information during possible sorting of CMRs. 305 addCMR(Counter::getCounter(0), FileNames[I], I, 1, I, 1); 306 307 loadCoverageMapping(); 308 309 for (unsigned I = 0; I < N; ++I) { 310 CoverageData Data = LoadedCoverage->getCoverageForFile(FileNames[I]); 311 ASSERT_TRUE(!Data.empty()); 312 EXPECT_EQ(I, Data.begin()->Line); 313 } 314 } 315 316 TEST_P(CoverageMappingTest, load_coverage_for_several_functions) { 317 InstrProfRecord RecordFunc1("func1", 0x1234, {10}); 318 NoError(ProfileWriter.addRecord(std::move(RecordFunc1))); 319 InstrProfRecord RecordFunc2("func2", 0x2345, {20}); 320 NoError(ProfileWriter.addRecord(std::move(RecordFunc2))); 321 322 startFunction("func1", 0x1234); 323 addCMR(Counter::getCounter(0), "foo", 1, 1, 5, 5); 324 325 startFunction("func2", 0x2345); 326 addCMR(Counter::getCounter(0), "bar", 2, 2, 6, 6); 327 328 loadCoverageMapping(); 329 330 const auto FunctionRecords = LoadedCoverage->getCoveredFunctions(); 331 EXPECT_EQ(2, std::distance(FunctionRecords.begin(), FunctionRecords.end())); 332 for (const auto &FunctionRecord : FunctionRecords) { 333 CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord); 334 std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); 335 ASSERT_EQ(2U, Segments.size()); 336 if (FunctionRecord.Name == "func1") { 337 EXPECT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]); 338 EXPECT_EQ(CoverageSegment(5, 5, false), Segments[1]); 339 } else { 340 ASSERT_EQ("func2", FunctionRecord.Name); 341 EXPECT_EQ(CoverageSegment(2, 2, 20, true), Segments[0]); 342 EXPECT_EQ(CoverageSegment(6, 6, false), Segments[1]); 343 } 344 } 345 } 346 347 TEST_P(CoverageMappingTest, expansion_gets_first_counter) { 348 startFunction("func", 0x1234); 349 addCMR(Counter::getCounter(1), "foo", 10, 1, 10, 2); 350 // This starts earlier in "foo", so the expansion should get its counter. 351 addCMR(Counter::getCounter(2), "foo", 1, 1, 20, 1); 352 addExpansionCMR("bar", "foo", 3, 3, 3, 3); 353 354 writeAndReadCoverageRegions(); 355 ASSERT_EQ(1u, OutputFunctions.size()); 356 OutputFunctionCoverageData &Output = OutputFunctions.back(); 357 358 ASSERT_EQ(CounterMappingRegion::ExpansionRegion, Output.Regions[2].Kind); 359 ASSERT_EQ(Counter::getCounter(2), Output.Regions[2].Count); 360 ASSERT_EQ(3U, Output.Regions[2].LineStart); 361 } 362 363 TEST_P(CoverageMappingTest, basic_coverage_iteration) { 364 InstrProfRecord Record("func", 0x1234, {30, 20, 10, 0}); 365 NoError(ProfileWriter.addRecord(std::move(Record))); 366 367 startFunction("func", 0x1234); 368 addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); 369 addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7); 370 addCMR(Counter::getCounter(2), "file1", 5, 8, 9, 1); 371 addCMR(Counter::getCounter(3), "file1", 10, 10, 11, 11); 372 loadCoverageMapping(); 373 374 CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); 375 std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); 376 ASSERT_EQ(7U, Segments.size()); 377 ASSERT_EQ(CoverageSegment(1, 1, 20, true), Segments[0]); 378 ASSERT_EQ(CoverageSegment(4, 7, 30, false), Segments[1]); 379 ASSERT_EQ(CoverageSegment(5, 8, 10, true), Segments[2]); 380 ASSERT_EQ(CoverageSegment(9, 1, 30, false), Segments[3]); 381 ASSERT_EQ(CoverageSegment(9, 9, false), Segments[4]); 382 ASSERT_EQ(CoverageSegment(10, 10, 0, true), Segments[5]); 383 ASSERT_EQ(CoverageSegment(11, 11, false), Segments[6]); 384 } 385 386 TEST_P(CoverageMappingTest, uncovered_function) { 387 startFunction("func", 0x1234); 388 addCMR(Counter::getZero(), "file1", 1, 2, 3, 4); 389 loadCoverageMapping(); 390 391 CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); 392 std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); 393 ASSERT_EQ(2U, Segments.size()); 394 ASSERT_EQ(CoverageSegment(1, 2, 0, true), Segments[0]); 395 ASSERT_EQ(CoverageSegment(3, 4, false), Segments[1]); 396 } 397 398 TEST_P(CoverageMappingTest, uncovered_function_with_mapping) { 399 startFunction("func", 0x1234); 400 addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); 401 addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7); 402 loadCoverageMapping(); 403 404 CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); 405 std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); 406 ASSERT_EQ(3U, Segments.size()); 407 ASSERT_EQ(CoverageSegment(1, 1, 0, true), Segments[0]); 408 ASSERT_EQ(CoverageSegment(4, 7, 0, false), Segments[1]); 409 ASSERT_EQ(CoverageSegment(9, 9, false), Segments[2]); 410 } 411 412 TEST_P(CoverageMappingTest, combine_regions) { 413 InstrProfRecord Record("func", 0x1234, {10, 20, 30}); 414 NoError(ProfileWriter.addRecord(std::move(Record))); 415 416 startFunction("func", 0x1234); 417 addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); 418 addCMR(Counter::getCounter(1), "file1", 3, 3, 4, 4); 419 addCMR(Counter::getCounter(2), "file1", 3, 3, 4, 4); 420 loadCoverageMapping(); 421 422 CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); 423 std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); 424 ASSERT_EQ(4U, Segments.size()); 425 ASSERT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]); 426 ASSERT_EQ(CoverageSegment(3, 3, 50, true), Segments[1]); 427 ASSERT_EQ(CoverageSegment(4, 4, 10, false), Segments[2]); 428 ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]); 429 } 430 431 TEST_P(CoverageMappingTest, restore_combined_counter_after_nested_region) { 432 InstrProfRecord Record("func", 0x1234, {10, 20, 40}); 433 NoError(ProfileWriter.addRecord(std::move(Record))); 434 435 startFunction("func", 0x1234); 436 addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); 437 addCMR(Counter::getCounter(1), "file1", 1, 1, 9, 9); 438 addCMR(Counter::getCounter(2), "file1", 3, 3, 5, 5); 439 loadCoverageMapping(); 440 441 CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); 442 std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); 443 ASSERT_EQ(4U, Segments.size()); 444 EXPECT_EQ(CoverageSegment(1, 1, 30, true), Segments[0]); 445 EXPECT_EQ(CoverageSegment(3, 3, 40, true), Segments[1]); 446 EXPECT_EQ(CoverageSegment(5, 5, 30, false), Segments[2]); 447 EXPECT_EQ(CoverageSegment(9, 9, false), Segments[3]); 448 } 449 450 // If CodeRegions and ExpansionRegions cover the same area, 451 // only counts of CodeRegions should be used. 452 TEST_P(CoverageMappingTest, dont_combine_expansions) { 453 InstrProfRecord Record1("func", 0x1234, {10, 20}); 454 InstrProfRecord Record2("func", 0x1234, {0, 0}); 455 NoError(ProfileWriter.addRecord(std::move(Record1))); 456 NoError(ProfileWriter.addRecord(std::move(Record2))); 457 458 startFunction("func", 0x1234); 459 addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); 460 addCMR(Counter::getCounter(1), "file1", 3, 3, 4, 4); 461 addCMR(Counter::getCounter(1), "include1", 6, 6, 7, 7); 462 addExpansionCMR("file1", "include1", 3, 3, 4, 4); 463 loadCoverageMapping(); 464 465 CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); 466 std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); 467 ASSERT_EQ(4U, Segments.size()); 468 ASSERT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]); 469 ASSERT_EQ(CoverageSegment(3, 3, 20, true), Segments[1]); 470 ASSERT_EQ(CoverageSegment(4, 4, 10, false), Segments[2]); 471 ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]); 472 } 473 474 // If an area is covered only by ExpansionRegions, they should be combinated. 475 TEST_P(CoverageMappingTest, combine_expansions) { 476 InstrProfRecord Record("func", 0x1234, {2, 3, 7}); 477 NoError(ProfileWriter.addRecord(std::move(Record))); 478 479 startFunction("func", 0x1234); 480 addCMR(Counter::getCounter(1), "include1", 1, 1, 1, 10); 481 addCMR(Counter::getCounter(2), "include2", 1, 1, 1, 10); 482 addCMR(Counter::getCounter(0), "file", 1, 1, 5, 5); 483 addExpansionCMR("file", "include1", 3, 1, 3, 5); 484 addExpansionCMR("file", "include2", 3, 1, 3, 5); 485 486 loadCoverageMapping(); 487 488 CoverageData Data = LoadedCoverage->getCoverageForFile("file"); 489 std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); 490 ASSERT_EQ(4U, Segments.size()); 491 EXPECT_EQ(CoverageSegment(1, 1, 2, true), Segments[0]); 492 EXPECT_EQ(CoverageSegment(3, 1, 10, true), Segments[1]); 493 EXPECT_EQ(CoverageSegment(3, 5, 2, false), Segments[2]); 494 EXPECT_EQ(CoverageSegment(5, 5, false), Segments[3]); 495 } 496 497 TEST_P(CoverageMappingTest, strip_filename_prefix) { 498 InstrProfRecord Record("file1:func", 0x1234, {0}); 499 NoError(ProfileWriter.addRecord(std::move(Record))); 500 501 startFunction("file1:func", 0x1234); 502 addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); 503 loadCoverageMapping(); 504 505 std::vector<std::string> Names; 506 for (const auto &Func : LoadedCoverage->getCoveredFunctions()) 507 Names.push_back(Func.Name); 508 ASSERT_EQ(1U, Names.size()); 509 ASSERT_EQ("func", Names[0]); 510 } 511 512 TEST_P(CoverageMappingTest, strip_unknown_filename_prefix) { 513 InstrProfRecord Record("<unknown>:func", 0x1234, {0}); 514 NoError(ProfileWriter.addRecord(std::move(Record))); 515 516 startFunction("<unknown>:func", 0x1234); 517 addCMR(Counter::getCounter(0), "", 1, 1, 9, 9); 518 loadCoverageMapping(/*EmitFilenames=*/false); 519 520 std::vector<std::string> Names; 521 for (const auto &Func : LoadedCoverage->getCoveredFunctions()) 522 Names.push_back(Func.Name); 523 ASSERT_EQ(1U, Names.size()); 524 ASSERT_EQ("func", Names[0]); 525 } 526 527 TEST_P(CoverageMappingTest, dont_detect_false_instantiations) { 528 InstrProfRecord Record1("foo", 0x1234, {10}); 529 InstrProfRecord Record2("bar", 0x2345, {20}); 530 NoError(ProfileWriter.addRecord(std::move(Record1))); 531 NoError(ProfileWriter.addRecord(std::move(Record2))); 532 533 startFunction("foo", 0x1234); 534 addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10); 535 addExpansionCMR("main", "expanded", 4, 1, 4, 5); 536 537 startFunction("bar", 0x2345); 538 addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10); 539 addExpansionCMR("main", "expanded", 9, 1, 9, 5); 540 541 loadCoverageMapping(); 542 543 std::vector<const FunctionRecord *> Instantiations = 544 LoadedCoverage->getInstantiations("expanded"); 545 ASSERT_TRUE(Instantiations.empty()); 546 } 547 548 TEST_P(CoverageMappingTest, load_coverage_for_expanded_file) { 549 InstrProfRecord Record("func", 0x1234, {10}); 550 NoError(ProfileWriter.addRecord(std::move(Record))); 551 552 startFunction("func", 0x1234); 553 addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10); 554 addExpansionCMR("main", "expanded", 4, 1, 4, 5); 555 556 loadCoverageMapping(); 557 558 CoverageData Data = LoadedCoverage->getCoverageForFile("expanded"); 559 std::vector<CoverageSegment> Segments(Data.begin(), Data.end()); 560 ASSERT_EQ(2U, Segments.size()); 561 EXPECT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]); 562 EXPECT_EQ(CoverageSegment(1, 10, false), Segments[1]); 563 } 564 565 TEST_P(CoverageMappingTest, skip_duplicate_function_record) { 566 InstrProfRecord Record("func", 0x1234, {1}); 567 NoError(ProfileWriter.addRecord(std::move(Record))); 568 569 startFunction("func", 0x1234); 570 addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); 571 572 startFunction("func", 0x1234); 573 addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); 574 575 loadCoverageMapping(); 576 577 auto Funcs = LoadedCoverage->getCoveredFunctions(); 578 unsigned NumFuncs = std::distance(Funcs.begin(), Funcs.end()); 579 ASSERT_EQ(1U, NumFuncs); 580 } 581 582 // FIXME: Use ::testing::Combine() when llvm updates its copy of googletest. 583 INSTANTIATE_TEST_CASE_P(ParameterizedCovMapTest, CoverageMappingTest, 584 ::testing::Values(std::pair<bool, bool>({false, false}), 585 std::pair<bool, bool>({false, true}), 586 std::pair<bool, bool>({true, false}), 587 std::pair<bool, bool>({true, true})),); 588 589 } // end anonymous namespace 590