Squash of 27 work commits (Sep 3–12):aa907caplatform: a frame trace on both desktop backends, and a window that cannot present stops ticking at 600 Hze3abf4dmap: the hosted-tile cache keeps the same ~2x-visible margin as the local one — a budget pinned at the visible set evicted the trailing edge of every pan on the next frame and refetched it a moment later8d542feplatform: a child pass orphaned by its attaching draw list is no longer painted — the window's gauss_scene pass stayed a live_with_parent child after the map went flat and re-encoded a frozen 400-item list every pan frame with stale geometry ids (new tile meshes × old instance counts, tens of millions of triangles into a texture nobody read); make_child_pass records the recording list + redraw id, stale passes are skipped, a cached View re-attaches on a cache hit; tests for the orphan gate and the pool generation contractbb49fe6map + platform: retained per-tile draw lists — each resident tile owns one DrawList2d per carto pass (fill, casing, stroke, icon, icon-high, shadow) and the label glyph batches are retained the same way, recorded when the bake, LOD ring, fringe/icon gates, flat/tilted or clip change and re-attached otherwise; a pan/zoom/tilt frame pushes this frame's uniforms onto the retained calls (DrawVars::update_uniforms_on_area, resolved slot table) and uploads zero instance bytes; the tilted per-pass depth is a pass_depth uniform; a held list's zbias resolves at entry (zbias_hold in every backend); the shimmer heartbeat patches shiny_time in place without a redraw; a freed/reused sub-list id is skipped by every draw-tree walker and the mask list re-records empty on the flat transition (contract test). Web pan tail 1,098 → 20 MiB/s, flat pan 2.4 → 0.43 MiB/frame; Metal grabs within the run-to-run noise floor 313265d Studio code atlas: geometry code views, live filter, 3D size lens, lanes as terminals 9c4e0cc Studio code atlas: performance round — retained uploads, worker labels, exact search, no forks 7235d7e Studio code atlas: stall fix, GPU working set, lens hard switch, filter masks, parallel index 56a6da5 platform: per-pass GPU counter timing on Metal; retained publications replace in place 72e2443 platform: present-path trace (1 Hz cause histograms), bounded drawable wait and retirement on macOS 1c5d583 platform: bounded retained maintenance on empty paint beats; republish actual backend debt edfed73 platform: retained residency high/low water and hysteresis; no distance eviction without pressure acab6a0 platform: critical upload class serves present-blocking items first; identical immediate re-records upload nothing 906c774 platform: uniform_range on DrawVars and patch_retained_uniforms on retained draw lists c29031c platform/draw/widgets: heap-keyed script resources and RecordingBuffer draw items — the files today's commits depend on cd0964f platform headless: homogeneous near-plane clipping before the perspective divide 61d424d platform: release retained bindings of released textures so pool evictions complete a00287a platform: texture-tile cache support — per-item instance ranges, painted pass receipts, display-dpi pass uniform, retained render targets, present gate on the drawable pool 74b63be platform: retained upload floor reverted, unconfirmed presents counted c03fcc5 platform: tile-cache round 3 support — O(1) demand on re-recorded lists, evictions counter, allocated_size, lost-button release, Vec2d::round e515d75 platform: shared instance publications — the DL-0/DL-1 contract, additive beside the retained path 142a337 platform: shared instance publications — close the seven review items (DL-1b) 6811a19 platform: Debug for SharedInstances, WeakSharedInstances and PublishReceipt c061e47 platform: Metal draws are resident by construction — the hole path and its gates are gone (DL-2) 0bdbb29 platform: drop the unreachable InstancesNotResident present cause de3c868 platform: `drawlist` trace names the holder of a stale draw-list id; the per-frame upload line moves to `gpu.upload` 721c3d8 platform: publication backends — Metal per-publication backings, lease-keyed uniform ring, receipts on every backend, Vulkan draws attached items (DL-3) 393de54 platform: integrated deletion — the draw-list system is generic again (DL-5) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
94 lines
4.7 KiB
Rust
94 lines
4.7 KiB
Rust
//! Cleanup DL-0 micro-probe: what a Metal buffer costs on this machine, as the
|
|
//! contract's "measured" section cites it. Cold allocation, first touch, a
|
|
//! CPU copy into shared storage, a warm re-allocation after a release, an
|
|
//! empty command-buffer round trip, a GPU blit of the same bytes, and the
|
|
//! release itself. Prints one line per size; asserts only sanity (non-null,
|
|
//! copied bytes readable back). Run with
|
|
//! `cargo test --release -p makepad-platform --test metal_alloc_probe -- --nocapture`.
|
|
|
|
#[cfg(all(target_os = "macos", not(gpusim)))]
|
|
fn main() {
|
|
use makepad_platform::os::apple::apple_sys::*;
|
|
use std::time::Instant;
|
|
|
|
fn median(v: &mut Vec<f64>) -> f64 {
|
|
v.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
|
v[v.len() / 2]
|
|
}
|
|
|
|
unsafe {
|
|
let pool: ObjcId = msg_send![class!(NSAutoreleasePool), new];
|
|
let device = MTLCreateSystemDefaultDevice();
|
|
assert!(!device.is_null(), "no Metal device");
|
|
let queue: ObjcId = msg_send![device, newCommandQueue];
|
|
assert!(!queue.is_null());
|
|
let page = 16384usize;
|
|
|
|
// Empty command buffer: the floor of one submission's commit + wait.
|
|
let mut empty = Vec::new();
|
|
for _ in 0..7 {
|
|
let t = Instant::now();
|
|
let cb: ObjcId = msg_send![queue, commandBuffer];
|
|
let () = msg_send![cb, commit];
|
|
let () = msg_send![cb, waitUntilCompleted];
|
|
empty.push(t.elapsed().as_secs_f64() * 1e6);
|
|
}
|
|
println!("probe: empty_cb_commit_wait_us={:.0} (median of 7)", median(&mut empty));
|
|
|
|
for &size in &[64usize << 10, 1 << 20, 4 << 20, 16 << 20] {
|
|
let source: Vec<u8> = (0..size).map(|i| (i % 251) as u8).collect();
|
|
let (mut cold, mut touch, mut copy, mut warm, mut blit, mut release) =
|
|
(Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
|
|
for _ in 0..5 {
|
|
let t = Instant::now();
|
|
let buffer: ObjcId = msg_send![device, newBufferWithLength: size as u64 options: MTLResourceOptions::StorageModeShared];
|
|
cold.push(t.elapsed().as_secs_f64() * 1e6);
|
|
assert!(!buffer.is_null());
|
|
let contents: *mut u8 = msg_send![buffer, contents];
|
|
let t = Instant::now();
|
|
let mut off = 0;
|
|
while off < size {
|
|
contents.add(off).write_volatile(1);
|
|
off += page;
|
|
}
|
|
touch.push(t.elapsed().as_secs_f64() * 1e6);
|
|
let t = Instant::now();
|
|
std::ptr::copy_nonoverlapping(source.as_ptr(), contents, size);
|
|
copy.push(t.elapsed().as_secs_f64() * 1e6);
|
|
assert_eq!(*contents.add(size - 1), source[size - 1]);
|
|
|
|
// GPU blit of the same bytes into a second buffer.
|
|
let target: ObjcId = msg_send![device, newBufferWithLength: size as u64 options: MTLResourceOptions::StorageModeShared];
|
|
let t = Instant::now();
|
|
let cb: ObjcId = msg_send![queue, commandBuffer];
|
|
let enc: ObjcId = msg_send![cb, blitCommandEncoder];
|
|
let () = msg_send![enc, copyFromBuffer: buffer sourceOffset: 0u64 toBuffer: target destinationOffset: 0u64 size: size as u64];
|
|
let () = msg_send![enc, endEncoding];
|
|
let () = msg_send![cb, commit];
|
|
let () = msg_send![cb, waitUntilCompleted];
|
|
blit.push(t.elapsed().as_secs_f64() * 1e6);
|
|
let tc: *const u8 = msg_send![target, contents];
|
|
assert_eq!(*tc.add(size - 1), source[size - 1]);
|
|
let () = msg_send![target, release];
|
|
|
|
let t = Instant::now();
|
|
let () = msg_send![buffer, release];
|
|
release.push(t.elapsed().as_secs_f64() * 1e6);
|
|
// Warm: the allocator has just seen a release of this size.
|
|
let t = Instant::now();
|
|
let again: ObjcId = msg_send![device, newBufferWithLength: size as u64 options: MTLResourceOptions::StorageModeShared];
|
|
warm.push(t.elapsed().as_secs_f64() * 1e6);
|
|
let () = msg_send![again, release];
|
|
}
|
|
println!(
|
|
"probe: size={} cold_alloc_us={:.0} first_touch_us={:.0} memcpy_us={:.0} warm_alloc_us={:.0} gpu_blit_commit_wait_us={:.0} release_us={:.0} (medians of 5)",
|
|
size, median(&mut cold), median(&mut touch), median(&mut copy), median(&mut warm), median(&mut blit), median(&mut release)
|
|
);
|
|
}
|
|
let () = msg_send![queue, release];
|
|
let () = msg_send![pool, release];
|
|
}
|
|
}
|
|
|
|
#[cfg(not(all(target_os = "macos", not(gpusim))))]
|
|
fn main() {}
|