mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-06 01:49:47 +08:00
Fix GuestDataPool lease leak on non-GPU compute dispatch paths (#759)
ObserveComputeDispatch only returned evaluation's pooled arrays when evaluationHandledByCpu was set. Dispatches rejected before submission (empty resource tables, oversized workgroup, compile failure) or a compute submit that got dropped instead of enqueued (workSequence == 0) never handed those buffers to a consumer that would return them, leaking one lease per occurrence and growing GuestDataPool.Shared without bound over a long session. Adds GuestDataPool.DiagnosticStats() (outstanding lease count, idle cached bytes) surfaced in the periodic [LOADER][PERF] line, to catch this class of regression going forward. Verified on Ghost of Yotei and Demon's Souls: pool_leases grew unbounded before the fix (525 in 5 min on Demon's Souls, 1114 in 180s on Yotei) and stays flat/bounded after (0-6 and 2-18 respectively), with no behavioral regression observed.
This commit is contained in:
@@ -11307,7 +11307,9 @@ public static partial class AgcExports
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evaluationHandledByCpu)
|
// Rejected/CPU-handled dispatches never hand evaluation's pooled buffers to a
|
||||||
|
// consumer that would return them; reclaim here to keep GuestDataPool.Shared bounded.
|
||||||
|
if (evaluationHandledByCpu || !gpuDispatch)
|
||||||
{
|
{
|
||||||
ReturnPooledEvaluationArrays(evaluation);
|
ReturnPooledEvaluationArrays(evaluation);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ internal static class GuestDataPool
|
|||||||
|
|
||||||
public static void Trim() => ((BoundedByteArrayPool)Shared).Trim();
|
public static void Trim() => ((BoundedByteArrayPool)Shared).Trim();
|
||||||
|
|
||||||
|
/// <summary>Outstanding lease count and idle cached bytes, for leak diagnostics.</summary>
|
||||||
|
public static (int LeaseCount, ulong CachedBytes) DiagnosticStats() =>
|
||||||
|
((BoundedByteArrayPool)Shared).Stats();
|
||||||
|
|
||||||
private sealed class BoundedByteArrayPool : ArrayPool<byte>
|
private sealed class BoundedByteArrayPool : ArrayPool<byte>
|
||||||
{
|
{
|
||||||
private readonly object _gate = new();
|
private readonly object _gate = new();
|
||||||
@@ -119,6 +123,14 @@ internal static class GuestDataPool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public (int LeaseCount, ulong CachedBytes) Stats()
|
||||||
|
{
|
||||||
|
lock (_gate)
|
||||||
|
{
|
||||||
|
return (_leases.Count, _cachedBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int GetAllocationLength(int minimumLength)
|
private int GetAllocationLength(int minimumLength)
|
||||||
{
|
{
|
||||||
if (minimumLength <= 16)
|
if (minimumLength <= 16)
|
||||||
|
|||||||
@@ -1300,10 +1300,12 @@ public static class VideoOutExports
|
|||||||
var submitted = Interlocked.Exchange(ref _submittedFrameCount, 0);
|
var submitted = Interlocked.Exchange(ref _submittedFrameCount, 0);
|
||||||
var presentedCount = Interlocked.Exchange(ref _presentedFrameCount, 0);
|
var presentedCount = Interlocked.Exchange(ref _presentedFrameCount, 0);
|
||||||
var (draws, drawMs, pipelines, spirvCompiles) = GuestGpu.Current.ReadAndResetPerfCounters();
|
var (draws, drawMs, pipelines, spirvCompiles) = GuestGpu.Current.ReadAndResetPerfCounters();
|
||||||
|
var (poolLeases, poolCachedBytes) = SharpEmu.Libs.Gpu.GuestDataPool.DiagnosticStats();
|
||||||
Console.Error.WriteLine(
|
Console.Error.WriteLine(
|
||||||
$"[LOADER][PERF] videoout submitted_fps={submitted / elapsedSeconds:F1} " +
|
$"[LOADER][PERF] videoout submitted_fps={submitted / elapsedSeconds:F1} " +
|
||||||
$"presented_fps={presentedCount / elapsedSeconds:F1} " +
|
$"presented_fps={presentedCount / elapsedSeconds:F1} " +
|
||||||
$"draws={draws} draw_ms={drawMs:F0} pipelines={pipelines} spirv={spirvCompiles}");
|
$"draws={draws} draw_ms={drawMs:F0} pipelines={pipelines} spirv={spirvCompiles} " +
|
||||||
|
$"pool_leases={poolLeases} pool_cached_mb={poolCachedBytes / 1024.0 / 1024.0:F1}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly bool _flipPacingDisabled = string.Equals(
|
private static readonly bool _flipPacingDisabled = string.Equals(
|
||||||
|
|||||||
Reference in New Issue
Block a user