ci(covr): install xml2 from r-lib/xml2#479 to fix multi-hour coverage runs#757
Merged
Conversation
covr::to_cobertura() appends one XML node per covered source line. With released xml2, xml_add_child() re-scans all existing siblings on every append, which is O(n^2) per file. For RSQLite's bundled sqlite3.c (~67k covered lines) this made the coverage job on GitHub Actions exceed 5 hours. r-lib/xml2#479 changes the default append to O(1). Install xml2 from that PR at the start of the covr action so the fix applies only to coverage runs; report generation drops from hours to ~25 seconds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dh6ePmbJHgSzUoVMWk7q1s
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The coverage job on GitHub Actions takes ~5 hours. The time is spent entirely after the last
Moving gcov outputs to covr directory.message — i.e. incovr::to_cobertura(cov), which the covr action runs afterpackage_coverage().to_cobertura()builds the Cobertura report by appending one<line>XML node per covered source line. With released xml2,xml_add_child()defaults to.where = length(xml_children(.x)), which re-enumerates all existing siblings on every append → O(n²) per file. For RSQLite's bundledsqlite3.c(~67k covered lines under a single<lines>node) that is ~4.5 billion operations.Evidence
Profiling the real coverage object (74,017 entries;
sqlite3.c= 67,619) showed everything up to and includingpackage_coverage()finishing in ~1.2 min, whileto_cobertura()dominated, withRprofattributing 94% of time toxml_add_child→xml_children/xml_nodeset.Fix
The root cause is in xml2 and is fixed upstream by r-lib/xml2#479, which makes the default append O(1).
This PR installs xml2 from that PR at the start of the covr action, so the fast path is used only for coverage runs:
pakis already provisioned bysetup-r-dependenciesin this job, so no extra setup is required.Verified
With xml2 installed from the PR, the unmodified, released
to_cobertura()processes the full RSQLite coverage data in ~25 seconds (down from ~5 hours).Note
This pins coverage to a PR build of xml2. Once r-lib/xml2#479 is merged and released, this step can be dropped (or switched to
r-lib/xml2/ the released version).🤖 Generated with Claude Code
Generated by Claude Code