mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-09 13:52:23 +00:00
ifcviewer: stop the live budget from over-shrinking and from going stale
A 66-model session showed the pool reach a 1938 MB ceiling, the next poll lower the budget to 1756, and the shrink drop 402 MB (73+73+256) for a 182 MB excess, which the pool then spent seconds re-growing. Two causes. The release granularity is whole sub-buffers but the shrink ran "until capacity ≤ target", so the last 36 MB of excess cost a 256 MB sub-buffer. shrinkToCapacity now never undershoots — it releases only while doing so keeps capacity ≥ target, leaving a sub-buffer's worth of excess for the margin to absorb — and the pressure path uses a separate releaseAtLeast(bytes), whose contract is the opposite: free at least what the failed allocation needs, whatever the granularity. Resident geometry is also only evicted once the pool is over budget by half the margin (GpuBudget::shrinkTarget), so report jitter does not trigger a shrink-and-reload. The ceiling was a second old when the pool grew into it, and the upload staging that rides on growth had pushed device free memory to ~74 MB — below the driver's observed refusal point — before the next scheduled poll. pollDeviceMemory now re-derives the budget immediately after any sub-buffer is added, so the next growth decision sees the device as it is. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+22
-10
@@ -137,18 +137,26 @@ public:
|
||||
void setMaxTotalCapacity(uint64_t max_bytes) { max_total_capacity_bytes_ = max_bytes; }
|
||||
uint64_t max_total_capacity_bytes() const { return max_total_capacity_bytes_; }
|
||||
|
||||
// Release whole sub-buffers, newest first, until total capacity is
|
||||
// ≤ target_bytes (or nothing is left). Before each sub-buffer is
|
||||
// dropped, `evict_sub_buffer(sub_idx)` is invoked so the owner can
|
||||
// free every slice that lives in it — the pool does not know what a
|
||||
// slice holds, and a sub-buffer is only released once it is empty.
|
||||
// Releasing from the back keeps every surviving Slice::sub_idx valid.
|
||||
// Returns the number of bytes released. This is how the cache yields
|
||||
// memory to the required tier (see GpuBudget); on web a provisional
|
||||
// sub-buffer that is still validating is left alone and the shrink is
|
||||
// retried once that resolves.
|
||||
// Release whole sub-buffers, newest first. Before each is dropped,
|
||||
// `evict_sub_buffer(sub_idx)` is invoked so the owner can free every
|
||||
// slice that lives in it — the pool does not know what a slice holds,
|
||||
// and a sub-buffer is only released once it is empty. Releasing from
|
||||
// the back keeps every surviving Slice::sub_idx valid. Both return the
|
||||
// bytes released. This is how the cache yields memory to the required
|
||||
// tier (see GpuBudget); on web a provisional sub-buffer that is still
|
||||
// validating is left alone and the caller retries once it resolves.
|
||||
//
|
||||
// shrinkToCapacity never goes *below* target_bytes: a sub-buffer is
|
||||
// released only while doing so keeps capacity ≥ target, so an excess
|
||||
// smaller than the newest sub-buffer releases nothing (the budget's
|
||||
// margin absorbs it) instead of dropping 256 MB for the last 36.
|
||||
uint64_t shrinkToCapacity(uint64_t target_bytes,
|
||||
const std::function<void(int sub_idx)>& evict_sub_buffer);
|
||||
// releaseAtLeast frees sub-buffers until at least `bytes` have gone
|
||||
// (or nothing is left) — for a failed required allocation that needs
|
||||
// that much back no matter the granularity.
|
||||
uint64_t releaseAtLeast(uint64_t bytes,
|
||||
const std::function<void(int sub_idx)>& evict_sub_buffer);
|
||||
|
||||
// Proactively add a sub-buffer (no allocation). On web this kicks off the
|
||||
// async provisional-validation cycle so validated free space appears a
|
||||
@@ -201,6 +209,10 @@ private:
|
||||
// ≥ MIN_SUB_BUFFER_BYTES; false only when even the minimum size is
|
||||
// refused, at which point growth_disabled_ latches.
|
||||
bool addSubBuffer();
|
||||
// Drop the newest sub-buffer after `evict_sub_buffer` empties it.
|
||||
// Returns its capacity; 0 when the pool is empty or the newest
|
||||
// sub-buffer is still provisional (web).
|
||||
uint64_t releaseNewestSubBuffer(const std::function<void(int sub_idx)>& evict_sub_buffer);
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
// Web-only async-growth resolver. Called from the AllowSpontaneous
|
||||
|
||||
Reference in New Issue
Block a user