[Profile] Classify what changed in stale resource cache entries

This commit is contained in:
ParantezTech 2026-10-11 06:11:32 +03:00
parent 7b730a51fc
commit 22ec74e085
1 changed files with 57 additions and 1 deletions

View File

@ -828,7 +828,61 @@ public sealed class ResourceMaterializationCache
var refusals = string.Join(",", RefreshRefusalNames.Select((name, index) => FormattableString.Invariant($"{name}:{Interlocked.Exchange(ref _refreshRefusals[index], 0)}")));
var total = hits + misses;
return FormattableString.Invariant(
$"[PERF][RESOURCE_CACHE] hits={hits} misses={misses} not_found={notFound} stale={stale} stale_unreadable={staleUnreadable} refreshes={refreshes} refused={refusals} uncacheable={uncacheable} hit_rate={(total == 0 ? 0 : hits * 100.0 / total):F1}% {RawReadPrefetch.TakeReport()}");
$"[PERF][RESOURCE_CACHE] hits={hits} misses={misses} not_found={notFound} stale={stale} stale_unreadable={staleUnreadable} refreshes={refreshes} refused={refusals} uncacheable={uncacheable} hit_rate={(total == 0 ? 0 : hits * 100.0 / total):F1}% {RawReadPrefetch.TakeReport()}") +
TakeStaleDifferenceReport();
}
private static readonly bool StaleDiffEnabled = Environment.GetEnvironmentVariable("SHARPEMU_PROFILE_PERFORMANCE") == "1";
private static readonly System.Collections.Concurrent.ConcurrentDictionary<string, long> _staleDifferences = new(StringComparer.Ordinal);
private static void NoteStaleDifference(Entry stale, Entry built)
{
var parts = new SortedSet<string>(StringComparer.Ordinal);
if (!stale.Specialization.Equals(built.Specialization))
parts.Add("spec");
DifferingWords("buf", stale.Snapshot.Buffers, built.Snapshot.Buffers, parts);
DifferingWords("img", stale.Snapshot.Images, built.Snapshot.Images, parts);
DifferingWords("smp", stale.Snapshot.Samplers, built.Snapshot.Samplers, parts);
if (!stale.Snapshot.FlattenedResourceTable.AsSpan().SequenceEqual(built.Snapshot.FlattenedResourceTable))
parts.Add("table");
if (!stale.Snapshot.DeviceAddressRanges.AsSpan().SequenceEqual(built.Snapshot.DeviceAddressRanges))
parts.Add("ranges");
if (stale.Bytes.Length != built.Bytes.Length || !stale.RangeAddresses.AsSpan().SequenceEqual(built.RangeAddresses))
parts.Add("reads_moved");
var signature = parts.Count == 0 ? "none" : string.Join("+", parts);
_staleDifferences.AddOrUpdate(signature, 1, static (_, count) => count + 1);
}
private static void DifferingWords(string name, uint[][] left, uint[][] right, SortedSet<string> parts)
{
if (left.Length != right.Length)
{
parts.Add($"{name}.count");
return;
}
for (var index = 0; index < left.Length; index++)
{
if (left[index].Length != right[index].Length)
{
parts.Add($"{name}.length");
continue;
}
for (var word = 0; word < left[index].Length; word++)
if (left[index][word] != right[index][word])
parts.Add($"{name}.w{word}");
}
}
private static string TakeStaleDifferenceReport()
{
if (_staleDifferences.IsEmpty)
return string.Empty;
var ranked = _staleDifferences.ToArray().OrderByDescending(pair => pair.Value).Take(10).ToArray();
_staleDifferences.Clear();
return Environment.NewLine + string.Join(Environment.NewLine,
ranked.Select(pair => FormattableString.Invariant($"[PERF][RESOURCE_STALE_DIFF] n={pair.Value} changed={pair.Key}")));
}
// The first part a cached result differs from a fresh one in, or null when they are the same.
@ -1007,6 +1061,8 @@ public sealed class ResourceMaterializationCache
}
var built = recorder.Build(plan, inputs, snapshot, specialization, rebase.MemoryBases);
if (StaleDiffEnabled && stale is not null && learning is null)
NoteStaleDifference(stale, built);
if (learning is { } pending)
{
var agrees = Difference(pending.Snapshot, pending.From.Specialization, built.Snapshot, built.Specialization) is null;