forked from 1b-agent/opencadstudio-upstream
perf: account for the device memory the renderer holds
Stage 0 of the roadmap asks for a memory baseline before any more
optimisation, and explicitly not from RSS: the allocator and the driver
both retain high-water memory that RSS cannot tell apart from live
resources.
`gpu-live` counts from the sizes this renderer allocated, in the
categories large enough to decide where the next fix goes:
slots total shadow targets text_atlas wire_arena block_geometry
It is partial by construction and says so, rather than presenting itself
as a total. Hatches, images, meshes and Face3D are not counted yet.
Three of the numbers needed a size that was not reachable before: the
block-geometry chunk records its bytes at build because in storage mode
the buffer belongs to the bind group, the arena exposes its allocation
rather than its occupied prefix — headroom is what a budget has to answer
for — and the text atlas reports its `R8` texel count.
Emitted only when a number moves. `prepare` runs thousands of times in a
session and these change a handful of times, so a per-frame line would
bury the log it is meant to explain.
This answers the question the previous fix left open: whether the arena's
52 MiB per slot, the 16 MiB shadow map every slot allocates whether or not
shadows are on, or the render targets dominate once a paper layout has
four or five viewports on screen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a9a2c82478
commit
d81a858040
5 files changed
+142
No files matched your search
@@ -1217,6 +1217,7 @@ impl shader::Primitive for Primitive {
|
||||
self.viewports.len(),
|
||||
);
|
||||
}
|
||||
report_gpu_live(pipeline);
|
||||
}
|
||||
|
||||
fn render(
|
||||
@@ -1568,6 +1569,42 @@ fn solar_direction(
|
||||
|
||||
// ── Render-style helpers (impl Scene) ────────────────────────────────────
|
||||
|
||||
/// Report what the renderer is holding on the device, when it changes.
|
||||
///
|
||||
/// Only on change: `prepare` runs thousands of times a session and these
|
||||
/// numbers move a handful of times. RSS is deliberately not used — the
|
||||
/// allocator and the driver both retain high-water memory that RSS cannot tell
|
||||
/// apart from live resources.
|
||||
fn report_gpu_live(pipeline: &crate::scene::pipeline::MultiPipeline) {
|
||||
use std::cell::Cell;
|
||||
if !crate::perf::enabled() {
|
||||
return;
|
||||
}
|
||||
thread_local! {
|
||||
static LAST: Cell<Option<crate::scene::pipeline::GpuLiveBytes>> = const { Cell::new(None) };
|
||||
}
|
||||
let now = pipeline.gpu_live_bytes();
|
||||
LAST.with(|last| {
|
||||
if last.get() == Some(now) {
|
||||
return;
|
||||
}
|
||||
last.set(Some(now));
|
||||
const MIB: f64 = 1024.0 * 1024.0;
|
||||
let mib = |bytes: u64| bytes as f64 / MIB;
|
||||
crate::perf_record!(
|
||||
"[perf] gpu-live slots={} total={:.1}MiB shadow={:.1} targets={:.1} \
|
||||
text_atlas={:.1} wire_arena={:.1} block_geometry={:.1}",
|
||||
now.slots,
|
||||
mib(now.total()),
|
||||
mib(now.shadow),
|
||||
mib(now.render_targets),
|
||||
mib(now.text_atlas),
|
||||
mib(now.wire_arena),
|
||||
mib(now.block_geometry),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
fn model_tile_vport(&self, index: usize) -> Option<&acadrust::tables::VPort> {
|
||||
let rect = self.model_tiles.borrow().get(index)?.rect;
|
||||
|
||||
Reference in new issue
Block a user