Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

.nornir/graph3d-rotate-perf-design.md

graph3d — rotate/spin performance: gatling projection + the GPU cloud paint lane — design

Class: design · Function axis: f0 the observed single-core rotation wall · f1 the rotate/spin decomposition bench + Loki numbers · f2 the gatling projection lane (project_all) · f3 the LIVE instanced GPU cloud paint (graph_gpu::cloud) · f4 the RED-when-broken tests. Strict: every claim points at a real file:line. rayon is FORBIDDEN — gatling only.

f0 — the wall Rickard saw

Rotating/navigating a 30 000-node 3-D graph in korp pegged one CPU core. The graph layout is already multicore + frozen (converge-once-then-freeze, see force-layout-twolane-design.md) — it does not recompute during rotation. What runs every frame while the camera spins is the per-node projection + the paint of the node/edge cloud. The prompt's hypothesis was that the projection (Graph3D::project_all, facett-graph3d/src/lib.rs) was the single-core cost.

The bench disproved that. examples/rotate_bench.rs decomposes the per-frame cost — (a) projection, (b) depth sort, (c) egui paint/tessellation, (d) total — and measures CPU cores busy from /proc/self/stat. The projection is trivially cheap; the egui CPU tessellation of 30k discs + edges is the ~99 % single-core wall. Measure first, then fix the dominant cost — not the assumed one.

f1 — the rotate bench + Loki numbers

facett-graph3d/examples/rotate_bench.rs spins the camera 120 frames for n ∈ {3k, 30k, 100k}. Loki (Ryzen 9 7900, 12c/24t, 64GB, RTX 5080), --release --features wgpu:

       n    proj serial   proj gatling   speedup   ser cores   par cores   sort ms   paint ms   total ms/f     tris/f
    3000       0.002 ms       0.211 ms     0.01x        0.0         3.2     0.055      3.337       3.603       246 880
   30000       0.020 ms       1.040 ms     0.02x        0.0         9.4     0.615     33.751      35.405     2 467 528
  100000       0.058 ms       3.172 ms     0.02x        1.4        10.2     2.584    112.418     118.173     8 224 016

Read it:

f2 — the gatling projection lane (project_all)

Graph3D::project_all (facett-graph3d/src/lib.rs) fans the per-node projection across every core through znippy's gatling_for_each above PROJ_PARALLEL_MIN (2048 nodes), serial below. The kernel is the shared free fn project_pt used by BOTH the serial Graph3D::project and the gatling lane, so the output is byte-identical to the old .iter().map().collect() (index-order preserved, no accumulation → FC-9 determinism intact, every snapshot golden byte-green). gpu_scene/gpu_scene_at and the FC-9 view projection both route through it (L5 — one projection seam). It is honest multicore projection, but the bench shows it is not where the frame goes — kept because it is the requested "projection across all cores" and is deterministic + free of golden risk, not because it moves the rotation wall.

f3 — the LIVE instanced GPU cloud paint (graph_gpu::cloud) — the real fix

The instanced GPU lane (graph_gpu::GraphGpu, node/edge instanced pipelines + bloom) already existed but was offscreen/readback only (test-proof path). Its own header called wiring it into an egui_wgpu callback "the follow-up". This is that follow-up.

facett-graph3d/src/graph_gpu.rs module cloud:

Wiring into the FC-9 view (facett-graph3d/src/lib.rs): Graph3D::with_gpu(true) opt-in

Net: with with_gpu(true) + the renderer installed, rotating a 30k cloud issues two instanced draw calls on the RTX 5080 instead of tessellating 2.47 M triangles on one core — the 33 ms/frame single-core wall leaves the CPU frame entirely.

f4 — RED-when-broken

korp

korp enables facett-graph3d/wgpu. To rotate multicore+GPU it must (1) call Graph3D::with_gpu(true) on its 3-D graph and (2) graph_gpu::cloud::install_cloud_renderer once with the eframe wgpu_render_state (like the demo installs the map renderers, facett-demo/src/main.rs:45). With both, the 30k rotation draws on the 5080 and the single-core tessellation wall is gone; projection also fans across cores (small, per the bench). Without the opt-in it renders exactly as today.