Issue #22250 has been reported by sferik (Erik Berlin). ---------------------------------------- Bug #22250: Add an only: keyword to Coverage.peek_result https://bugs.ruby-lang.org/issues/22250 * Author: sferik (Erik Berlin) * Status: Open * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- I am a maintainer of SimpleCov and working on adding a feature that attributes coverage to individual tests (see https://github.com/simplecov-ruby/simplecov/pull/1277). This feature works by work by diffing `Coverage.peek_result` snapshots around each test. That means thousands of `peek_result` calls per test run, but each call only needs the line counters, since per-test attribution is computed from line execution count deltas. `peek_result` always builds the full result for every measured type. With branch and method coverage enabled, building the branch and method structures dominates the cost, so each snapshot is an order of magnitude more expensive than the lines the caller actually reads. On a real test suite measuring lines, branches, and methods, per-test tracking causes the test suite to run in ~30 seconds vs. ~3 seconds when it's disabled. Nearly all of this additional time is spent in `peek_result`, building results that are immediately discarded. Line-only filtering is significantly cheaper because the line result is a flat array dup, while branch and method results are rebuilt hashes. #### Proposal Allow callers to request only the types they need: ```ruby Coverage.start(lines: true, branches: true, methods: true) Coverage.peek_result(only: :lines) # => {"file.rb" => {lines: [1, 2, nil]}, ...} Coverage.peek_result(only: [:lines, :branches]) # => {"file.rb" => {lines: [1, 2, nil], branches: {...}}, ...} ``` `only:` should accept one of `:lines`, `:oneshot_lines`, `:branches`, or `:methods`, or an Array of them. Each file's hash then contains only the requested keys, and the result construction for the other measured types is skipped entirely (the branch structure walk and the method table iteration never run). Requesting a type that is not being measured should raise a `RuntimeError`, consistent with the existing "coverage measurement is not enabled" error. An unknown type should raise an `ArgumentError`. A patch with tests and documentation is at https://github.com/sferik/ruby-lang/tree/coverage-peek-result-only The change is confined to `ext/coverage/coverage.c`. The existing `coverage_peek_result_i` iteration takes a filter mask (defaulting to `current_mode`, so the unfiltered path is byte-for-byte the current behavior), and `Coverage.result` reuses the same internal function with the full mask. I am happy to open a pull request if this direction is acceptable. -- https://bugs.ruby-lang.org/