Skip to content

Parallelize session discovery and file-processing loops#533

Merged
rajbos merged 3 commits intomainfrom
feat/parallelize-session-discovery-loading
Apr 1, 2026
Merged

Parallelize session discovery and file-processing loops#533
rajbos merged 3 commits intomainfrom
feat/parallelize-session-discovery-loading

Conversation

@rajbos
Copy link
Copy Markdown
Owner

@rajbos rajbos commented Mar 31, 2026

Why

With many supported IDEs (VS Code, Cursor, VSCodium, OpenCode, Crush, Continue, Visual Studio, Claude Code) and potentially hundreds of session files, the initial load and every 5-minute refresh was bottlenecked by fully sequential I/O: every path-existence check, every directory scan, and every file stat+parse waited for the one before it. On machines with many workspaces this added seconds of unnecessary wall-clock time.

What changed

Discovery phase (vscode-extension/src/sessionDiscovery.ts)

All four sequential discovery loops are now parallel:

  • VS Code path checks — the 10 pathExists() calls for editor variants (stable, insiders, VSCodium, Cursor, remote paths) now run as a single Promise.all() instead of one-at-a-time.
  • Workspace/globalStorage scanning — each found VS Code variant is scanned concurrently, and within each variant all workspace subdirs are scanned in parallel too (was a nested sequential for loop).
  • Copilot CLI subdirsevents.jsonl stat checks across all UUID subdirs now run as a single Promise.all().
  • Crush projects — each discoverSessionsInDb() call runs concurrently across all known projects.

Loading phase (extension.ts + cli/src/helpers.ts)

Added a small runWithConcurrency<R>(files, fn, limit = 20) worker-pool helper (no new dependencies) that processes up to 20 files at a time. Four sequential loops are replaced:

Method Change
calculateTokenUsage Parallel stat + cache lookup
calculateDetailedStats Parallel stat + cache + details fetch; sequential aggregation
calculateDailyStats Parallel stat + cache lookup; sequential aggregation
calculateUsageAnalysis Parallel stat + cache lookup; sequential aggregation
CLI calculateDetailedStats Same pattern

The two-phase approach (parallel gather → sequential aggregate) keeps all Map/counter mutations on the single JS thread — no races, no locks needed.

Trade-offs

  • Concurrency limit of 20 — enough to saturate typical SSD I/O without loading hundreds of large JSONL files into memory simultaneously. Can be tuned if needed.
  • Discovery uses unbounded Promise.all() because the counts are small (≤10 paths, ≤N workspace dirs per path) and each operation is a cheap syscall.
  • The existing two-layer cache (60s file-list TTL + per-file mtime+size) remains untouched — these changes only speed up the work that still needs to happen on a cache miss or first load.

rajbos and others added 3 commits March 31, 2026 09:30
Discovery (sessionDiscovery.ts):
- Replace sequential VS Code path-existence checks with Promise.all
- Replace nested sequential workspace/globalStorage scan loops with
  Promise.all per variant and per workspace dir
- Replace sequential CLI subdir events.jsonl stat checks with Promise.all
- Replace sequential Crush project DB queries with Promise.all

Stats calculation (extension.ts + cli/src/helpers.ts):
- Add runWithConcurrency<R>(files, fn, limit=20) helper to both files
  -- worker-pool pattern, no new dependencies
- Parallelize calculateTokenUsage, calculateDetailedStats,
  calculateDailyStats, and calculateUsageAnalysis loops in extension.ts
- Parallelize calculateDetailedStats loop in cli/src/helpers.ts
- Two-phase approach: gather stat+cache data in parallel, aggregate
  results synchronously (safe in Node.js single-threaded model)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@rajbos rajbos enabled auto-merge April 1, 2026 19:36
@rajbos rajbos merged commit 7f735e0 into main Apr 1, 2026
17 checks passed
@rajbos rajbos deleted the feat/parallelize-session-discovery-loading branch April 1, 2026 19:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant