From f81c6752ab92fe23c8088d333c9f19567f9dc76c Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Fri, 6 Nov 2026 19:57:28 +0100 Subject: [PATCH] GPU Metal: do not let Metal track hazards on the memory buffers All memory of the reconstruction lives in three MTLBuffers, so with Metal's default hazard tracking every encoder that writes device memory conflicts with every other one, and Metal ordered them even across the streams' command queues: in a Metal System Trace the per-sector kernels the chain spreads over 8 streams did not overlap at all (kernel time summed to the GPU busy time). The backend orders the work itself, as CUDA streams do: a fence between the encoders of a stream, an event between its command buffers, and the chain's events between streams. So create the buffers untracked; the kernels of different streams now overlap by about 150 ms per event. On an M1 Max, interleaved over 3 rounds of 10 runs (load average 4 to 7), the 30-collision Pb-Pb time frame takes 975 ms per event instead of 1046, and a 10-collision Pb-Pb time frame dumped from the full system test 754 ms instead of 850. The clusters are byte-identical to the CPU's on the 30-collision time frame and on sim5pp. --- GPU/GPUTracking/Base/metal/GPUReconstructionMetal.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GPU/GPUTracking/Base/metal/GPUReconstructionMetal.mm b/GPU/GPUTracking/Base/metal/GPUReconstructionMetal.mm index 338a421df406b..4be4c83ebc262 100644 --- a/GPU/GPUTracking/Base/metal/GPUReconstructionMetal.mm +++ b/GPU/GPUTracking/Base/metal/GPUReconstructionMetal.mm @@ -116,14 +116,14 @@ uint32_t metalGPUCoreCount() } // We only support internal GPUs, so the ownership of the memory is always shared - mInternals->mem_gpu = [mInternals->device newBufferWithLength:mDeviceMemorySize options:MTLResourceStorageModeShared]; + mInternals->mem_gpu = [mInternals->device newBufferWithLength:mDeviceMemorySize options:MTLResourceStorageModeShared | MTLResourceHazardTrackingModeUntracked]; if (mInternals->mem_gpu == nil) { GPUErrorReturn("Metal Memory Allocation Error"); } // FIXME: until I understand how to enable the gGPUConstantMemBufferSize constexpr int32_t tmpGPUConstantMemBufferSize = 100000; // gGPUConstantMemBufferSize - mInternals->mem_constant = [mInternals->device newBufferWithLength:tmpGPUConstantMemBufferSize options:MTLResourceStorageModeShared]; + mInternals->mem_constant = [mInternals->device newBufferWithLength:tmpGPUConstantMemBufferSize options:MTLResourceStorageModeShared | MTLResourceHazardTrackingModeUntracked]; if (mInternals->mem_constant == nil) { GPUErrorReturn("Metal Constant Memory Allocation Error"); } @@ -143,7 +143,7 @@ uint32_t metalGPUCoreCount() mInternals->streamHasWork[i] = false; } - mInternals->mem_host = [mInternals->device newBufferWithLength:mHostMemorySize options:MTLResourceStorageModeShared]; + mInternals->mem_host = [mInternals->device newBufferWithLength:mHostMemorySize options:MTLResourceStorageModeShared | MTLResourceHazardTrackingModeUntracked]; if (mInternals->mem_host == nil) { GPUErrorReturn("Error allocating pinned host memory"); }