Skip to content

Commit 413647d

Browse files
committed
[Coverage] Speed up file-based queries for coverage info, NFC
Speed up queries for coverage info in a file by reducing the amount of time spent determining whether a function record corresponds to a file. This gives a 36% speedup when generating a coverage report for `llc`. The reduction is entirely in user time. rdar://54758110 Differential Revision: https://reviews.llvm.org/D67575 llvm-svn: 372025
1 parent 95de249 commit 413647d

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,12 @@ class CounterMappingContext {
301301
struct FunctionRecord {
302302
/// Raw function name.
303303
std::string Name;
304-
/// Associated files.
304+
/// Mapping from FileID (i.e. vector index) to filename. Used to support
305+
/// macro expansions within a function in which the macro and function are
306+
/// defined in separate files.
307+
///
308+
/// TODO: Uniquing filenames across all function records may be a performance
309+
/// optimization.
305310
std::vector<std::string> Filenames;
306311
/// Regions in the function along with their counts.
307312
std::vector<CountedRegion> CountedRegions;
@@ -508,6 +513,7 @@ class CoverageData {
508513
class CoverageMapping {
509514
DenseMap<size_t, DenseSet<size_t>> RecordProvenance;
510515
std::vector<FunctionRecord> Functions;
516+
DenseMap<size_t, SmallVector<unsigned, 0>> FilenameHash2RecordIndices;
511517
std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches;
512518

513519
CoverageMapping() = default;
@@ -516,6 +522,13 @@ class CoverageMapping {
516522
Error loadFunctionRecord(const CoverageMappingRecord &Record,
517523
IndexedInstrProfReader &ProfileReader);
518524

525+
/// Look up the indices for function records which are at least partially
526+
/// defined in the specified file. This is guaranteed to return a superset of
527+
/// such records: extra records not in the file may be included if there is
528+
/// a hash collision on the filename. Clients must be robust to collisions.
529+
ArrayRef<unsigned>
530+
getImpreciseRecordIndicesForFilename(StringRef Filename) const;
531+
519532
public:
520533
CoverageMapping(const CoverageMapping &) = delete;
521534
CoverageMapping &operator=(const CoverageMapping &) = delete;

llvm/lib/ProfileData/Coverage/CoverageMapping.cpp

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,15 @@ void FunctionRecordIterator::skipOtherFiles() {
194194
*this = FunctionRecordIterator();
195195
}
196196

197+
ArrayRef<unsigned> CoverageMapping::getImpreciseRecordIndicesForFilename(
198+
StringRef Filename) const {
199+
size_t FilenameHash = hash_value(Filename);
200+
auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
201+
if (RecordIt == FilenameHash2RecordIndices.end())
202+
return {};
203+
return RecordIt->second;
204+
}
205+
197206
Error CoverageMapping::loadFunctionRecord(
198207
const CoverageMappingRecord &Record,
199208
IndexedInstrProfReader &ProfileReader) {
@@ -249,6 +258,20 @@ Error CoverageMapping::loadFunctionRecord(
249258
return Error::success();
250259

251260
Functions.push_back(std::move(Function));
261+
262+
// Performance optimization: keep track of the indices of the function records
263+
// which correspond to each filename. This can be used to substantially speed
264+
// up queries for coverage info in a file.
265+
unsigned RecordIndex = Functions.size() - 1;
266+
for (StringRef Filename : Record.Filenames) {
267+
auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
268+
// Note that there may be duplicates in the filename set for a function
269+
// record, because of e.g. macro expansions in the function in which both
270+
// the macro and the function are defined in the same file.
271+
if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
272+
RecordIndices.push_back(RecordIndex);
273+
}
274+
252275
return Error::success();
253276
}
254277

@@ -626,7 +649,12 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
626649
CoverageData FileCoverage(Filename);
627650
std::vector<CountedRegion> Regions;
628651

629-
for (const auto &Function : Functions) {
652+
// Look up the function records in the given file. Due to hash collisions on
653+
// the filename, we may get back some records that are not in the file.
654+
ArrayRef<unsigned> RecordIndices =
655+
getImpreciseRecordIndicesForFilename(Filename);
656+
for (unsigned RecordIndex : RecordIndices) {
657+
const FunctionRecord &Function = Functions[RecordIndex];
630658
auto MainFileID = findMainViewFileID(Filename, Function);
631659
auto FileIDs = gatherFileIDs(Filename, Function);
632660
for (const auto &CR : Function.CountedRegions)
@@ -646,7 +674,12 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
646674
std::vector<InstantiationGroup>
647675
CoverageMapping::getInstantiationGroups(StringRef Filename) const {
648676
FunctionInstantiationSetCollector InstantiationSetCollector;
649-
for (const auto &Function : Functions) {
677+
// Look up the function records in the given file. Due to hash collisions on
678+
// the filename, we may get back some records that are not in the file.
679+
ArrayRef<unsigned> RecordIndices =
680+
getImpreciseRecordIndicesForFilename(Filename);
681+
for (unsigned RecordIndex : RecordIndices) {
682+
const FunctionRecord &Function = Functions[RecordIndex];
650683
auto MainFileID = findMainViewFileID(Filename, Function);
651684
if (!MainFileID)
652685
continue;

0 commit comments

Comments
 (0)