mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-10 22:16:41 +00:00
wgpu: diagnostic instrumentation for cull/streaming perf
Adds three knobs and three new heartbeat numbers to support the ongoing perf-parity work. None affect behaviour in default runs. cull[wall|compute|upload] split timer The existing cull_timer wrapped both the parallel std::async dispatch and the sequential cullModelCpuUpload loop (queueWriteBuffer × 3 per resident chunk × ~120 chunks ≈ 360 wgpu calls per frame). Splitting them ruled upload out as the bottleneck on a 51-model federation scene: compute ≈ 16-17 ms, upload ≈ 1 ms. WGPU_CULL_THREADS=0 — force sequential cull std::async-per-model was already in place; this env var disables it so we can compare wall time vs sequential and confirm parallelism is working. On the federation scene with 52 models: sequential 74 ms vs parallel 17 ms = 4.4× speedup. Confirmed; the 17 ms floor is not a parallelism failure, it's the cost of culling the largest single model (model 43, 114k instances) ÷ no parallelism within that model. WGPU_STREAM_DEBUG=1 — per-frame [stream-debug] log Surfaces cands/enq/drained/ev_lru/ev_pri/blocked/resident/cycled/ max_load each frame from driveStreamingLoads. The "cycled" / "max_load" pair makes thrash vs eviction-churn vs just-loading distinguishable. Off by default; opt-in via the env var. Bench-warm timeout dump When [bench warm] times out (600 frames without 0-loads streak), prints a structured summary: resident/missing/total chunks, cycled count, pool usage, largest free run, avg missing chunk size, and an auto-classifier diagnosis (POOL FRAGMENTED vs WORKING SET > POOL vs FEW-CHUNK CYCLE vs still-loading). Caught a real fragmentation pattern (18 MB largest free run vs ~100 MB typical chunk) on a 51-model run where the dumb classifier would have called it a load-budget problem. LOD1 firing counter "lod1 X/Y (saved Z tris, N no-lod1)" suffix on the [frame] log. X = LOD1-selected this frame, Y = LOD1-eligible, Z = tris not drawn vs always-LOD0, N = visible instances with no baked LOD1 (mesh below IFC_LOD_MIN_TRIS). Confirmed LOD1 path is genuinely firing post the per-chunk LOD1-storage commit, and exposed that ~90% of instances in real scenes are no-lod1 meshes — relevant to the future LOD-tier-residency design. Chunk.load_count + Chunk.lod0/1 layout bookkeeping Per-chunk reload counter for the thrash detector. lod0/1 layout_count fields prep the data model for distance-tiered residency (Phase B of #31) but aren't acted on yet. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -400,6 +400,12 @@ private:
|
||||
float min_pixel_radius_ = 3.0f;
|
||||
float motion_min_pixel_radius_ = 15.0f;
|
||||
|
||||
// Whether driveCull dispatches per-model work via std::async. ON by
|
||||
// default; setting WGPU_CULL_THREADS=0 forces sequential cull for
|
||||
// measurement (does std::async actually parallelize on this libstdc++?
|
||||
// and is per-model the right granularity?).
|
||||
bool cull_threads_enabled_ = true;
|
||||
|
||||
public:
|
||||
// Master switch for HiZ occlusion. Set false to skip the depth resolve
|
||||
// + readback + cull test entirely (matches IFC_NO_HIZ in the GL backend).
|
||||
@@ -445,6 +451,16 @@ public:
|
||||
int streaming_loads_this_frame_ = 0;
|
||||
bool streaming_more_pending_ = false;
|
||||
|
||||
// Per-frame streaming counters for WGPU_STREAM_DEBUG. Mutated inside
|
||||
// driveStreamingLoads, consumed by the per-frame debug print and the
|
||||
// bench-warm timeout dump.
|
||||
int streaming_candidates_this_frame_ = 0;
|
||||
int streaming_evictions_lru_this_frame_ = 0;
|
||||
int streaming_evictions_pri_this_frame_ = 0;
|
||||
int streaming_drained_this_frame_ = 0;
|
||||
int streaming_blocked_oom_this_frame_ = 0;
|
||||
bool streaming_debug_ = false; // WGPU_STREAM_DEBUG=1
|
||||
|
||||
// Bench warm-phase counters. We wait until N consecutive frames with
|
||||
// 0 loads (convergence) before starting the orbit sweep, capped by
|
||||
// MAX_WARM_FRAMES so chronically thrashing scenes still produce
|
||||
@@ -534,6 +550,8 @@ private:
|
||||
// bench) so the periodic [frame] heartbeat log can show cull /
|
||||
// stream cost without needing the bench averaging machinery.
|
||||
double last_cull_ms_ = 0.0;
|
||||
double last_cull_compute_ms_ = 0.0; // parallel per-model cull
|
||||
double last_cull_upload_ms_ = 0.0; // sequential queueWriteBuffer pass
|
||||
double last_stream_ms_ = 0.0;
|
||||
|
||||
// Tick count for the interactive (non-bench) [frame] heartbeat log.
|
||||
|
||||
Reference in New Issue
Block a user