Skip to content

Improve performance of pytest discovery for large test suites#25974

Merged
eleanorjboyd merged 6 commits into
microsoft:mainfrom
vaclavHala:pytest-discovery-perf
May 29, 2026
Merged

Improve performance of pytest discovery for large test suites#25974
eleanorjboyd merged 6 commits into
microsoft:mainfrom
vaclavHala:pytest-discovery-perf

Conversation

@vaclavHala

@vaclavHala vaclavHala commented May 25, 2026

Copy link
Copy Markdown

Fixes #25973

At the moment this PR demonstrates how to fix the problem, however I'll be happy to change the code however you see fit.

…covery by dicts to improve discovery performance for large, flat test suites
@vaclavHala

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree company="Codasip"

@eleanorjboyd
eleanorjboyd requested a review from Copilot May 29, 2026 16:20
@eleanorjboyd eleanorjboyd self-assigned this May 29, 2026
@eleanorjboyd eleanorjboyd added the bug Issue identified by VS Code Team member as probable bug label May 29, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses #25973 by optimizing how the vscode_pytest plugin builds the pytest discovery tree for very large suites (especially heavily-parameterized tests), reducing the pathological O(n^2) behavior caused by repeated list membership scans during tree construction.

Changes:

  • Replaced per-node children lists with a Children container backed by a dict keyed by id_ to make repeated inserts/deduplication effectively O(1).
  • Updated tree-building code paths to use Children.add() instead of list membership checks + append().
  • Switched discovery JSON serialization to a custom encoder that also knows how to serialize Children containers back to JSON arrays (preserving the expected payload shape).
Show a summary per file
File Description
python_files/vscode_pytest/init.py Reworks test-tree child storage to a dict-backed container and updates JSON encoding to keep discovery output compatible while improving performance.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment thread python_files/vscode_pytest/__init__.py
@eleanorjboyd

Copy link
Copy Markdown
Member

Thanks for putting together this PR! Just this one comment by copilot and then I think we are good and I can approve. Appreciate it!

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@eleanorjboyd
eleanorjboyd enabled auto-merge (squash) May 29, 2026 20:58
Yoyokrazy
Yoyokrazy previously approved these changes May 29, 2026
eleanorjboyd
eleanorjboyd previously approved these changes May 29, 2026
@eleanorjboyd
eleanorjboyd dismissed stale reviews from Yoyokrazy and themself via 228e0d4 May 29, 2026 21:19
@eleanorjboyd
eleanorjboyd merged commit 03f6e24 into microsoft:main May 29, 2026
47 checks passed
eleanorjboyd added a commit that referenced this pull request Jul 24, 2026
## Problem

The discovery/run testing telemetry added in #25980 emitted its numeric
performance fields — `totalDurationMs`, `testCount`
(`UNITTEST.DISCOVERY.DONE`) and `durationMs`, `requestedCount`
(`UNITTEST.RUN.DONE`) — in the **properties** bag instead of the
**measures** argument of `sendTelemetryEvent`.

These fields are annotated `isMeasurement: true`, and telemetry
ingestion drops measurement-annotated fields that arrive as properties.
Verified against production telemetry: across ~46M
`unittest.discovery.done` events in the last 14 days, **zero** carried
`totalDurationMs` or `testCount` (in either `Properties` or `Measures`),
while the string categoricals (`mode`, `trigger`, `failureCategory`)
came through fine. The `mode`/`trigger` fields survive because they're
strings; the numeric ones silently vanish.

This means there is currently **no duration signal** to evaluate the
recent pytest discovery performance work (#25974, #25982) — the
measurements were never actually recorded.

The correct pattern is confirmed by `NATIVE_FINDER_PERF`, which passes
its numbers via the measures (2nd) argument and lands them cleanly in
the `Measures` column.

## Fix

Move the numeric measurement fields to the `measures` (2nd) argument of
`sendTelemetryEvent` at all five emit sites:

- `resultResolver.ts` — `DISCOVERY.DONE` success path
(`totalDurationMs`, `testCount`)
- `controller.ts` — `DISCOVERY.DONE` project-error path
(`totalDurationMs`) and `RUN.DONE` legacy path (`durationMs`,
`requestedCount`)
- `workspaceTestAdapter.ts` — `DISCOVERY.DONE` legacy-error path
(`totalDurationMs`)
- `projectTestExecution.ts` — `RUN.DONE` project path (`durationMs`,
`requestedCount`)

Also removed these fields from the event **property** type definitions
(the `__GDPR__` annotations are unchanged and already correctly mark
them `isMeasurement: true`) and added notes so they aren't reintroduced
as properties.

## Verification

- `tsc`: no new type errors from these changes.
- `eslint` + `prettier`: clean on all changed files.
- Unit tests pass: `resolveDiscovery` (5), project `RUN.DONE` telemetry
(2), and workspace discovery (5).

## Impact

Once a build with this fix ships,
`totalDurationMs`/`testCount`/`durationMs`/`requestedCount` will
populate in the `Measures` column, enabling the before/after
discovery-performance comparison (sliced by `testCount` bucket ×
`mode`). No user-facing behavior change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Issue identified by VS Code Team member as probable bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extremely slow test discovery when using pytest for large test suite

6 participants