Skip to content

Performance Audit #925

Description

@PythonFZ

Tier 1 — User-visible, multi-second cost per interaction

# Finding Evidence Track
1 Initial bundle = 10.28 MB transferred on landing = 100 % of total gzipped bundle. Nothing is actually lazy-loaded despite manual chunks. dockview audit: transfer ≈ sum of all chunk gzipped sizes (within 70 KB) network/bundle
2 SmilesEditDialog (Ketcher) ships 6.7 MB gzip / 23 MB raw on every landing — only needed when editing molecules. src/zndraw/static/assets/SmilesEditDialog-*.js bundle
3 PUT /v1/rooms/{room_id}/step makes 212 sequential REST calls during 100-frame scrub = 1.4 s of round-trip wait per scrub (p50 14 ms × 100). Single biggest server-time consumer in the audit. network-results.md §1, total 3.2 s across audit network
4 TTI proxy = 3,489 ms in prod (canvas-visible). 2.65 s of that is post-FCP — bundle parse + hydration cost driven by 1. 2026-04-17-dockview-perf-audit-results.md headline client perf
5 plotly ships 1.5 MB gzip on every landing despite being in its own chunk. modulePreload exclusion list isn't preventing the import. bundle summary bundle

Tier 2 — Hundreds of ms per interaction or per-session

# Finding Evidence Track
6 room-switch triggers 117 React commits/iter — 3× cold-load baseline. 70 in dockview-layout, 47 in viewer. ~140 ms cumulative React work per switch. react-results.md §1 react
7 GET /v1/joblib/rooms/{room_id}/providers polled 133× across 24 runs (~5.5/run). 2.1 s server time. No socket-driven invalidation. network-results.md §2 network
8 GET /v1/rooms polled 100× (~4/run). 1.7 s total server time. network-results.md network
9 POST /v1/auth/guest p50 47 ms, p99 82 ms — blocks socket connect → blocks canvas mount on first visit. Function-level cause unknown (py-spy gap). network-results.md §3 network
10 Box key={remountKey} in ViewerView.tsx:51 forces Canvas remount on every room change — likely root cause of 6. WebGL context destroy/recreate on top of React unmount cascade. code inspection + react cascade signal react
11 GET /v1/rooms/{room_id}/geometries returns 132 KB on every call — no ETag, no diff. 7.4 MB transferred per audit (56 calls × 132 KB). network-results.md §4 network
12 POST /v1/rooms p99 = 133 ms, max 206 ms (vs p50 10 ms) — cold-path spike on first room create per server. network-results.md §6 network
13 scipy imported eagerly at startupscipy/integrate/_bvp.py 199 ms + scipy/special/__init__.py 180 ms = ~400 ms of cold-start time. python-results.md "What flames did surface" python
14 index.modern-BBJUX7oL.js (1.2 MB raw / 336 KB gzip) — second plotly fragment, also on landing. bundle summary bundle
15 index main chunk = 868 KB gzippanels/registry.tsx imports every panel synchronously (GeometryPanel, RoomsPanel, PlotsBrowserPanel, FilesystemPanel, ChatPanel, SelectionsPanel, plus SecondaryPanel + ViewerView). dockview audit §2 bundle

Tier 3 — Tens of ms per interaction, frequent enough to add up

# Finding Evidence Track
16 mui chunk = 249 KB gzip fuses x-data-grid + x-tree-view with core MUI — grid + tree are panel-scoped (Geometries/Rooms only) but co-bundled with site-wide MUI. dockview audit §3 bundle
17 open-rooms panel-open fires 50 ms long-task in prod / 346 ms in dev — DataGrid mount + /v1/rooms fetch on first open. dockview audit "open-rooms" client perf
18 open-geometries panel-open fires 51 ms long-task in prod / 239 ms in dev. dockview audit client perf
19 GET /v1/rooms/{room_id}/edit-lock polled 56× — 1.07 s total. Why is edit-lock fetched repeatedly per session? network-results.md network
20 GET /v1/rooms/{room_id}/frame-selection called 56× — 1.06 s total. Selection state currently REST-pulled, not socket-pushed. network-results.md network
21 PUT /.../sessions/{id}/active-camera called 43× — 927 ms total. Camera state syncs per interaction. network-results.md network
22 GET /v1/rooms/{room_id}/bookmarks called 56× — 873 ms. Refetched on most page loads. network-results.md network
23 GET /v1/rooms/{room_id}/selection-groups called 56× — 783 ms. Same pattern. network-results.md network
24 GET /v1/rooms/{room_id}/geometries/{key:path} called 56× — 690 ms. network-results.md network
25 socket.io + zndraw_socketio/wrapper.py add ~500 ms to startup. python-results.md python
26 include_router 257 ms during startup — 25 routers registered eagerly. Architectural. python-results.md python
27 <module> src/zndraw/app.py self-time 277 ms — top-level imports cascade. python-results.md python
28 resolve_or_refresh_token 176 ms during cold-load CLI — pre-flight token check is non-trivial. python-results.md python
29 selection flow triggers 51 React commits per iter for 5 clicks + 1 modifier (~9 commits per click). react-results.md §4 react
30 geometry_invalidate socket event fires 3-15× per flow — high frequency, likely triggers React cascades. network ws-frames network
31 room_join fires 6-21× per flow — every page navigation triggers a fresh join, with full state re-fetch downstream. network ws-frames network

Tier 4 — Single-digit ms or one-shot startup costs

# Finding Evidence Track
32 GET /v1/rooms/{room_id}/frames called 43× — 13 ms p50, 594 ms total. network-results.md network
33 GET /v1/rooms/{room_id}/frames/{index}/metadata called 43× — 7 ms p50, 349 ms. network-results.md network
34 GET /v1/server-settings/default-room called 36× — 5 ms p50, 305 ms. Frequently re-fetched. network-results.md network
35 GET /v1/auth/users/me called 70× — 3 ms p50, 283 ms. Re-checked constantly. network-results.md network
36 active_camera_update socket event fires 3-12× per flow — modest. network ws-frames network
37 Dev-mode heap = 139 MB after landing (2.6× prod) — HMR + source-map overhead. Dev only, not user-visible. dockview audit client perf
38 Dev-mode resource count = 250 (vs 33 prod) — per-module loads. Dev only. dockview audit client perf
39 Per React commit cost is consistently sub-ms (avg 0.5-0.9 ms). Good news — focus on count, not weight. react-results.md §2 react
40 frame-scrub triggers only 39 React commits for 100 keypresses — R3F + zustand bypass works. Previously suspected "Fix F" (R3F subscription patterns from the dockview spec) is rejected on data. react-results.md §3 react

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions