Speed up CodeGraphy graph load and interactions#294
Conversation
🦋 Changeset detectedLatest commit: 536ebb9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Iteration 1: measurement harness\n\n- Changed: added , a bounded JSON writer/parser for cold-index logs, and a reviewed baseline summary at .\n- Test:
TAP version 13 Subtest: core extension release declares platform-specific VSIX targetsok 1 - core extension release declares platform-specific VSIX targetsduration_ms: 1.435708 Subtest: package mode creates one target-specific vsce invocation per VSIX targetok 2 - package mode creates one target-specific vsce invocation per VSIX targetduration_ms: 0.290458 Subtest: publish mode publishes every target-specific VSIX targetok 3 - publish mode publishes every target-specific VSIX targetduration_ms: 0.123125 Subtest: resolves the VSIX target that matches the host native runtimeok 4 - resolves the VSIX target that matches the host native runtimeduration_ms: 0.096583 Subtest: rejects cross-target VSIX packaging for host-built Tree-sitter bindingsok 5 - rejects cross-target VSIX packaging for host-built Tree-sitter bindingsduration_ms: 0.237083 Subtest: allows one explicitly requested target when it matches the host native runtimeok 6 - allows one explicitly requested target when it matches the host native runtimeduration_ms: 0.05525 Subtest: stages the target LadybugDB native binary before packaging a target VSIXok 7 - stages the target LadybugDB native binary before packaging a target VSIXduration_ms: 2.629 Subtest: resolves target LadybugDB native binary from a fetched optional package when it is not installedok 8 - resolves target LadybugDB native binary from a fetched optional package when it is not installedduration_ms: 1.853 codegraphy.codegraphy-5.8.0-linux-x64.vsix: extension/dist/node_modules/@ladybugdb/core/lbugjs.node is ELF x86-64codegraphy.codegraphy-5.8.0-linux-x64.vsix: extension/dist/node_modules/@ladybugdb/core/lbugjs.node is ELF x86-64codegraphy.codegraphy-5.8.0-linux-x64.vsix: extension/dist/node_modules/tree-sitter/build/Release/tree_sitter_runtime_binding.node is ELF x86-64Subtest: identifies Linux x64 native binaries from ELF headersok 9 - identifies Linux x64 native binaries from ELF headersduration_ms: 0.961792 Subtest: identifies macOS Apple Silicon native binaries from Mach-O headersok 10 - identifies macOS Apple Silicon native binaries from Mach-O headersduration_ms: 0.225084 Subtest: identifies Windows x64 native binaries from PE headersok 11 - identifies Windows x64 native binaries from PE headersduration_ms: 0.206709 Subtest: rejects a linux x64 VSIX with a macOS Apple Silicon Tree-sitter bindingok 12 - rejects a linux x64 VSIX with a macOS Apple Silicon Tree-sitter bindingduration_ms: 24.754125 Subtest: validates only the requested VSIX artifact targetsok 13 - validates only the requested VSIX artifact targetsduration_ms: 11.116083 Subtest: performance runner writes bounded JSON metricsok 14 - performance runner writes bounded JSON metricsduration_ms: 7.251583 Subtest: uses the Turbo task hash as the Playwright cache hash for one packageok 15 - uses the Turbo task hash as the Playwright cache hash for one packageduration_ms: 0.753417 Subtest: combines multiple Playwright task hashes into a stable cache hashok 16 - combines multiple Playwright task hashes into a stable cache hashduration_ms: 8.738292 Subtest: reports Playwright tasks as cached only when every task can replayok 17 - reports Playwright tasks as cached only when every task can replayduration_ms: 0.109125 Subtest: builds a filtered turbo command for Playwright-owning packagesok 18 - builds a filtered turbo command for Playwright-owning packagesduration_ms: 1.531375 Subtest: passes Playwright args after the turbo passthrough delimiterok 19 - passes Playwright args after the turbo passthrough delimiterduration_ms: 0.081 Subtest: splits turbo args from Playwright passthrough argsok 20 - splits turbo args from Playwright passthrough argsduration_ms: 0.144875 tests 20suites 0pass 20fail 0cancelled 0skipped 0todo 0duration_ms 130.416042 passed all 20 tests;
|
|
Iteration 1 correction: measurement harness
|
|
Iteration 2: scoped refresh fast path
|
Measure cold monorepo indexing by phase: analysis 88321ms, graph build 62ms, and Graph Cache save 122757ms on the CodeGraphy monorepo fixture.
Iteration 3: cold-index phase timingsCommit: Verification:
Cold monorepo phase benchmark from no Graph Cache:
Takeaway: cold load is not graph construction. The measured hot spots are Graph Cache persistence first, then per-file/plugin analysis. |
Reduce cold CodeGraphy monorepo indexing from 213.93s to 111.03s by persisting FileAnalysis as the canonical cache row and deriving snapshot symbols/relations from it. Graph Cache save dropped from 122757ms to 15139ms and cache size from 64638976 bytes to 18153472 bytes.
Iteration 4: canonical Graph Cache persistenceCommit: Change:
Benchmark on the CodeGraphy monorepo cold index from no Graph Cache:
Verification:
|
Share file content reads between pre-analysis and cold file analysis. On the CodeGraphy monorepo cold benchmark, wall time moved from 111.03s to 104.81s and analyze-files moved from 92850ms to 87297ms.
Iteration 5: reuse content between pre-analysis and analysisCommit: Change:
Benchmark on the CodeGraphy monorepo cold index from no Graph Cache:
Verification:
Remaining cold-load bottleneck is still file/plugin analysis, now measured at |
|
Iteration update: Godot class name pre-analysis fast path Commit: 9e3294e ( What changed:
Why:
Branch-accurate benchmark note:
Exact local-plugin before/after, no Graph Cache:
Graph diff check:
Verification:
|
|
Iteration update: TypeScript alias config no-scan parse Commit: 595aa15 ( What changed:
Why:
Branch-accurate isolated-plugin benchmark, no Graph Cache:
Cumulative cold-index progress on the CodeGraphy monorepo:
Verification:
|
|
Measurement update: warm Graph Cache query proxy Commit: 6743acb ( Measured Result:
Caveat:
Takeaway:
|
Current settings projection improved from 775ms median / 933ms p95 to 22ms median / 26ms p95 on the CodeGraphy monorepo visible-graph benchmark. Folders-on projection improved from 1369ms median / 1445ms p95 to 31ms median / 32ms p95. Import-edge-hidden projection improved from 153ms median to 17ms median / 18ms p95.
|
Iteration: visible graph filter projection Changed:
Metric before:
Metric after, fresh verification on commit
Verification:
Next:
|
Adds an opt-in Extension Development Host performance runner for first graph render and Graph Scope Imports toggle latency. Latest measurements: first rendered graph stats 57.2s on the first run and 9.9s on a repeat run; Imports toggle around 3.0s median, which points the next bottleneck at graph surface/runtime rendering.
|
Iteration: VS Code graph-view latency harness Changed:
Metric baseline from commit
Verification:
Next:
|
When every interactive graph node already has finite coordinates, render the update without additional force-layout cooldown ticks. Fresh/unpositioned layouts and timeline mode keep their existing cooldowns. VS Code Graph Scope Imports toggle on the CodeGraphy monorepo improved from the repeat-run 2983ms median / 3079ms p95 baseline to 1925ms median / 2341ms p95 across 5 samples.
|
Iteration: settled graph cooldown
|
Evaluate the constant 2D arrow color and arrow position once per render/settings update instead of passing callbacks that force-graph invokes for every edge. VS Code Graph Scope Imports toggle on the CodeGraphy monorepo improved from 1925ms median / 2341ms p95 after the cooldown iteration to 1595ms median / 1620ms p95 across 5 samples.
|
Iteration: constant 2D arrow settings
|
Keep viewport overlay, tooltip, stats, and accessibility updates from re-rendering the force-graph surface when the surface inputs are unchanged. VS Code graph-view Imports toggle metric on the CodeGraphy monorepo: same-environment control 2891ms median / 3563ms p95; memoized surface 1628ms median / 2252ms p95. Verified with graph/webview vitest slice, typecheck, lint, and build:vscode.
|
Iteration: memoized viewport surface
Next: isolate the remaining ~1.6s between Graph Scope click and visible stats update with a webview-side timing mark so we can tell how much is force-graph graphData reset vs our runtime work. |
Add opt-in webview performance events to the VS Code graph-view benchmark, then use those timings to compile legend glob matchers once per visible graph update instead of compiling them for every node and edge check. VS Code graph-view Imports toggle metric on the CodeGraphy monorepo: instrumented pre-change run 1748ms median / 2272ms p95; compiled legend matchers rerun 835ms median / 846ms p95. applyLegendRules dropped from roughly 460-490ms per pass to roughly 79-83ms per pass. Verified with webview app/graph/graphScope/search slice 312 files / 1908 tests, pnpm run typecheck, pnpm run lint, build:vscode, and perf:vscode-graph-view.
Summary
Measured performance
Large CodeGraphy monorepo measurements captured during PR iteration:
Regression fix
cooldownTicks: 0, which rendered nodes but prevented the force simulation from behaving like a live physics graph.Validation
pnpm run testpassed.git diff --checkpassed.pnpm changeset status --since origin/mainpassed.pnpm run test:release.pnpm --filter @codegraphy-dev/extension run typecheck,pnpm --filter @codegraphy-dev/extension run lint, and full extension test suite, 1010 files / 6117 tests.pnpm --filter @codegraphy-dev/extension exec vitest run --config vitest.config.ts tests/webview/graph/rendering/sharedProps.test.ts.Caveats / follow-up