Repository navigation
perf(coverage): remove quadratic work in lcov metrics and untested files - #1810
ricardodalarme wants to merge 4 commits into
Conversation
Experiment: accumulate uncovered lines in a mutable map instead of copying it per record, and match covered paths through a suffix set instead of a nested loop that normalizes inside the inner iteration.
📊 Cognitive Complexity AnalysisNet Delta: +13 | Added: 0 | Increased: 2 | Improved: 0 | Removed: 1 | Violations: 0
|
|
Heads up — I'm auto-updating this PR by merging the latest |
| totalFound += lines?.found ?? 0; | ||
| final file = record.file; | ||
| if (file == null) continue; | ||
| final missed = _uncoveredLineNumbersOf(record); |
There was a problem hiding this comment.
can we make uncoveredLineNumbers a property or getter of record?
There was a problem hiding this comment.
Do you mean an extension on Record? Personally, I prefer a private function, especially since we’re only using it here
There was a problem hiding this comment.
I meant a getter inside the class, no need for extensions, but not sure if we depend in variables inside coverage metrics for that
|
Heads up — I'm auto-updating this PR by merging the latest |
|
Heads up — I'm auto-updating this PR by merging the latest |
Description
Removes two sources of quadratic work in the coverage post-processing:
_addUntestedFiles(--collect-coverage-from all): matched every candidate file against every covered path, callingp.normalizeinside the inner loop. Covered paths are now normalized once and indexed by separator-aligned suffix, so each candidate is a single set lookup.CoverageMetrics.fromLcovRecords(--min-coverage/--show-uncovered): copied the whole uncovered-lines map for every record. It now accumulates into one mutable map.Results
Compiled harness around
FlutterCoverageReport.finalize, measured with hyperfine, lcov restored before each run. Synthetic packages: 40 lines per file, 2/3 of the files in the lcov, about a third of lines uncovered.main--collect-coverage-from all--min-coverage+--show-uncoveredapp, 914 files),allapp, 914 files), both optionsOn
main, theallscenario about quadruples each time the file count doubles; with this PR it grows roughly linearly. On a normal-sized project the gain is small (last two rows), so this mainly helps very large codebases.Correctness
mainin all three scenarios (all, metrics, both) on the real lcov and on two synthetic packages (9/9 comparisons).endsWithmatch had no path boundary, so a coveredxlib/a.dartalso counted as coveringlib/a.dart. Covered paths now match on a separator boundary. In a randomized comparison of the old and new matching (24,000 cases), 23,511 were identical. The other 489 were all cases where the old code reported "covered" and the new one doesn't, and all were explained by the missing boundary. The new code never marks a file covered that the old one didn't.Type of Change