Skip to content

Commit 72fca84

Browse files
committed
[Coverage] Speed up function record iteration
When iterating over function records, filtered by file name, currently, the iteration goes over all the function records, repeatedly for each source file, essentially giving quadratic behavior. 413647d sped up some cases by keeping track of the indices of the function records corresponding to each file name. This change expands the use of that map to FunctionRecordIterator. On a test case with Firefox's libxul.so and a 2.5MB profile, this brings down the runtime of `llvm-cov export $lib --instr-profile $prof -t lcov` from 12 minutes with 90% spent in skipOtherFiles to 19 seconds with no samples in skipOtherFiles at all under a sampling profiler (with a sampling interval of 1ms). Fixes #62079
1 parent 9184c42 commit 72fca84

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

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

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -739,10 +739,15 @@ struct FunctionRecord {
739739
};
740740

741741
/// Iterator over Functions, optionally filtered to a single file.
742+
/// When filtering to a single file, the iterator requires a list of potential
743+
/// indices where to find the desired records to avoid quadratic behavior when
744+
/// repeatedly iterating over functions from different files.
742745
class FunctionRecordIterator
743746
: public iterator_facade_base<FunctionRecordIterator,
744747
std::forward_iterator_tag, FunctionRecord> {
745748
ArrayRef<FunctionRecord> Records;
749+
ArrayRef<unsigned> RecordIndices;
750+
ArrayRef<unsigned>::iterator CurrentIndex;
746751
ArrayRef<FunctionRecord>::iterator Current;
747752
StringRef Filename;
748753

@@ -751,8 +756,17 @@ class FunctionRecordIterator
751756

752757
public:
753758
FunctionRecordIterator(ArrayRef<FunctionRecord> Records_,
754-
StringRef Filename = "")
755-
: Records(Records_), Current(Records.begin()), Filename(Filename) {
759+
StringRef Filename = "",
760+
ArrayRef<unsigned> RecordIndices_ = {})
761+
: Records(Records_), RecordIndices(RecordIndices_),
762+
CurrentIndex(RecordIndices.begin()),
763+
// If `RecordIndices` is provided, we can skip directly to the first
764+
// index it provides.
765+
Current(CurrentIndex == RecordIndices.end() ? Records.begin()
766+
: &Records[*CurrentIndex]),
767+
Filename(Filename) {
768+
assert(Filename.empty() == RecordIndices_.empty() &&
769+
"If `Filename` is specified, `RecordIndices` must also be provided");
756770
skipOtherFiles();
757771
}
758772

@@ -765,11 +779,29 @@ class FunctionRecordIterator
765779
const FunctionRecord &operator*() const { return *Current; }
766780

767781
FunctionRecordIterator &operator++() {
768-
assert(Current != Records.end() && "incremented past end");
769-
++Current;
782+
advanceOne();
770783
skipOtherFiles();
771784
return *this;
772785
}
786+
787+
private:
788+
void advanceOne() {
789+
if (RecordIndices.empty()) {
790+
// Iteration over all entries, advance in the list of records.
791+
assert(Current != Records.end() && "incremented past end");
792+
++Current;
793+
} else {
794+
// Iterator over entries filtered by file name. Advance in the list of
795+
// indices, and adjust the cursor in the list of records accordingly.
796+
assert(CurrentIndex != RecordIndices.end() && "incremented past end");
797+
++CurrentIndex;
798+
if (CurrentIndex == RecordIndices.end()) {
799+
Current = Records.end();
800+
} else {
801+
Current = &Records[*CurrentIndex];
802+
}
803+
}
804+
}
773805
};
774806

775807
/// Coverage information for a macro expansion or #included file.
@@ -1028,8 +1060,10 @@ class CoverageMapping {
10281060
/// Gets all of the functions in a particular file.
10291061
iterator_range<FunctionRecordIterator>
10301062
getCoveredFunctions(StringRef Filename) const {
1031-
return make_range(FunctionRecordIterator(Functions, Filename),
1032-
FunctionRecordIterator());
1063+
return make_range(
1064+
FunctionRecordIterator(Functions, Filename,
1065+
getImpreciseRecordIndicesForFilename(Filename)),
1066+
FunctionRecordIterator());
10331067
}
10341068

10351069
/// Get the list of function instantiation groups in a particular file.

llvm/lib/ProfileData/Coverage/CoverageMapping.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ unsigned CounterMappingContext::getMaxCounterID(const Counter &C) const {
593593
void FunctionRecordIterator::skipOtherFiles() {
594594
while (Current != Records.end() && !Filename.empty() &&
595595
Filename != Current->Filenames[0])
596-
++Current;
596+
advanceOne();
597597
if (Current == Records.end())
598598
*this = FunctionRecordIterator();
599599
}

0 commit comments

Comments
 (0)