Summary
The WinPython locator scans the root of C:\, D:\, and E:\ (plus ~/Downloads, ~/Desktop, ~/Documents, Program Files, Program Files (x86), etc.) on every refresh RPC. There is no cache, no opt-in, and no equivalent locator on macOS/Linux. This is the most plausible single cause of the Windows-vs-macOS p90 gap (Windows p90 ~11.3s on the slow cohort vs ~0.8s on macOS).
Full investigation: docs/windows-perf-investigation.md (Issue 1).
Where
What it does today
for drive in ['C', 'D', 'E'] {
let drive_path = PathBuf::from(format!("{}:\\", drive));
paths.push(drive_path.clone()); // root of the drive
paths.push(drive_path.join("WinPython"));
paths.push(drive_path.join("Python"));
}
For each existing search path, find() calls fs::read_dir(...) then path.is_dir() on every entry, then a second fs::read_dir inside matching directories.
Why this hurts on Windows
- Drive roots commonly contain hundreds of unrelated folders. Every
is_dir() is a stat syscall that triggers Defender real-time scanning.
~/Downloads is a notorious slow path: large and full of zip/installer artifacts that Defender re-scans aggressively.
find() has no cache (unlike WindowsStore and WindowsRegistry), so this work runs on every refresh RPC.
- WinPython is a niche portable distribution — the cost-benefit of scanning every drive root on every machine is poor.
- There is no equivalent locator on macOS/Linux. This asymmetry alone could account for a significant chunk of the 5× p90 gap.
Proposed fix
- Drop drive-root and
Program Files entries from get_winpython_search_paths(). Keep only ~/WinPython and an opt-in env var (e.g. WINPYTHON_HOME).
- Add a per-process cache to
WinPython::find() mirroring WindowsStore / WindowsRegistry.
- Follow-up: make WinPython lazy — only run
find() when the user opts in or when a workspace path resolves into a WinPython tree.
Estimated change size: ~10 lines for (1), ~30 lines for (2).
Validation
The extension can confirm the impact today by attaching RefreshPerformance.locators["WinPython"] (already emitted via the RefreshPerformance telemetry notification) to its pet.refresh event and slicing the slow Windows cohort. A long tail concentrated on WinPython would confirm the diagnosis.
Summary
The
WinPythonlocator scans the root ofC:\,D:\, andE:\(plus~/Downloads,~/Desktop,~/Documents,Program Files,Program Files (x86), etc.) on everyrefreshRPC. There is no cache, no opt-in, and no equivalent locator on macOS/Linux. This is the most plausible single cause of the Windows-vs-macOS p90 gap (Windows p90 ~11.3s on the slow cohort vs ~0.8s on macOS).Full investigation:
docs/windows-perf-investigation.md(Issue 1).Where
crates/pet-winpython/src/lib.rs—get_winpython_search_paths(~L304–332) andfind(~L246–302)What it does today
For each existing search path,
find()callsfs::read_dir(...)thenpath.is_dir()on every entry, then a secondfs::read_dirinside matching directories.Why this hurts on Windows
is_dir()is a stat syscall that triggers Defender real-time scanning.~/Downloadsis a notorious slow path: large and full of zip/installer artifacts that Defender re-scans aggressively.find()has no cache (unlikeWindowsStoreandWindowsRegistry), so this work runs on everyrefreshRPC.Proposed fix
Program Filesentries fromget_winpython_search_paths(). Keep only~/WinPythonand an opt-in env var (e.g.WINPYTHON_HOME).WinPython::find()mirroringWindowsStore/WindowsRegistry.find()when the user opts in or when a workspace path resolves into a WinPython tree.Estimated change size: ~10 lines for (1), ~30 lines for (2).
Validation
The extension can confirm the impact today by attaching
RefreshPerformance.locators["WinPython"](already emitted via theRefreshPerformancetelemetry notification) to itspet.refreshevent and slicing the slow Windows cohort. A long tail concentrated onWinPythonwould confirm the diagnosis.