perf: split the arena patch's post-work into its three steps

With the selection-filter rebuild gone, a drawn point costs 98 ms and
`prepare` is 93 % of it:

    wire  73.0ms  arena-patch  wires=236961 gpu_instances=405551
    wire-cull      5.1ms
    face3d-upload  3.9ms
    text-upload    3.0ms
    resident-patch 1.0ms  changes=1
    draw-depth-patch 0.0ms

`arena-base ok=true patch=Some(16) changes=1` — the arena patches
incrementally, one entity, and still takes 73 ms. The patch itself is
careful; the three steps that follow it are not, and all three are
O(resident set) rather than O(changes):

    partition_wires(&vp_wires, …)          236 961 wires, every frame
    upload_block_wires(…instanced…)         10 719 placements rebuilt
    upload_circles/ellipses_from_instances

`arena-post partition= blocks= curves=` says which dominates. Guessing
between three plausible candidates is what the earlier rounds of this work
paid for repeatedly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
PanosandClaude Opus 5 committed 2026-09-08 16:42:38 +03:00
1 parent 6f01d4215b
commit feb3ca4d28
1 file changed
+21
+21
View File
@@ -839,8 +839,15 @@ impl shader::Primitive for Primitive {
gpus.extend(arena.wire_gpus());
}
inner.gpu_wires = std::sync::Arc::new(gpus);
// A one-entity patch costs 73 ms in this block, and the
// three steps below are all O(resident set) rather than
// O(changes). Which of them dominates decides the fix.
let t_part = _perf.then(iced::time::Instant::now);
let partitioned =
wire_arena::partition_wires(&vp_wires, &draw_depths);
let part_ms = t_part
.map_or(0.0, |t| t.elapsed().as_secs_f64() * 1000.0);
let t_blk = _perf.then(iced::time::Instant::now);
inner.gpu_block_wires = std::sync::Arc::new(
inner.upload_block_wires(
device,
@@ -850,6 +857,9 @@ impl shader::Primitive for Primitive {
&mut pipeline.block_geometry,
),
);
let blk_ms = t_blk
.map_or(0.0, |t| t.elapsed().as_secs_f64() * 1000.0);
let t_curve = _perf.then(iced::time::Instant::now);
inner.gpu_circles = std::sync::Arc::new(
inner.upload_circles_from_instances(
device,
@@ -864,6 +874,17 @@ impl shader::Primitive for Primitive {
&partitioned.ellipse_instances,
),
);
if _perf {
crate::perf_record!(
"[perf] arena-post partition={part_ms:.1}ms blocks={blk_ms:.1}ms \
curves={:.1}ms wires={} instanced={} circles={} ellipses={}",
t_curve.map_or(0.0, |t| t.elapsed().as_secs_f64() * 1000.0),
vp_wires.len(),
partitioned.instanced.len(),
partitioned.circle_instances.len(),
partitioned.ellipse_instances.len(),
);
}
if _patched {
wire_arena::patch_handle_index(
&mut inner.wire_handle_index,