From b4c065a0b018848399137ee4d1673cbe7f3fbff4 Mon Sep 17 00:00:00 2001 From: ParantezTech <12572227+par274@users.noreply.github.com> Date: Mon, 28 Sep 2026 04:37:46 +0300 Subject: [PATCH] [GPU] performance: negative interval filter --- .../Gpu/Images/GuestImageCache.Tracking.cs | 2 +- .../Gpu/Images/ImagePageOwnerTable.cs | 24 ++++++++++++++++++- .../Gpu/Images/ImagePageOwnerTableTests.cs | 13 ++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/SharpEmu.Libs/Gpu/Images/GuestImageCache.Tracking.cs b/src/SharpEmu.Libs/Gpu/Images/GuestImageCache.Tracking.cs index a4a4541..f44ace5 100644 --- a/src/SharpEmu.Libs/Gpu/Images/GuestImageCache.Tracking.cs +++ b/src/SharpEmu.Libs/Gpu/Images/GuestImageCache.Tracking.cs @@ -363,7 +363,7 @@ public sealed partial class GuestImageCache bool IGuestImageStore.MarkCpuWrite(ulong address, ulong size) { GpuMemoryAccessProfile.CountImageCpuWrite(); - if (!IsValidRange(address, size)) + if (!IsValidRange(address, size) || !_pageOwners.MayHaveOwners(address, size)) { return false; } diff --git a/src/SharpEmu.Libs/Gpu/Images/ImagePageOwnerTable.cs b/src/SharpEmu.Libs/Gpu/Images/ImagePageOwnerTable.cs index 96e1606..455a626 100644 --- a/src/SharpEmu.Libs/Gpu/Images/ImagePageOwnerTable.cs +++ b/src/SharpEmu.Libs/Gpu/Images/ImagePageOwnerTable.cs @@ -107,6 +107,7 @@ public sealed class ImagePageOwnerTable public const ulong AddressSpaceSize = 1UL << AddressSpaceBits; private readonly PageOwnerList?[]?[] _firstLevel = new PageOwnerList?[]?[1 << FirstLevelBits]; + private readonly long[] _everOwnedPages = new long[PageCount / 64]; public int AllocatedBucketCount { get; private set; } @@ -129,7 +130,28 @@ public sealed class ImagePageOwnerTable AllocatedBucketCount++; } - return bucket[page & (BucketEntries - 1)] ??= new PageOwnerList(); + var owners = bucket[page & (BucketEntries - 1)] ??= new PageOwnerList(); + Interlocked.Or(ref _everOwnedPages[page / 64], 1L << (int)(page % 64)); + return owners; + } + + // Bits are never cleared: a false result can safely bypass the image-cache lock. + public bool MayHaveOwners(ulong address, ulong size) + { + if (!TryGetPageRange(address, size, out var first, out var lastExclusive)) + { + return false; + } + + for (var page = first; page < lastExclusive; page++) + { + if ((Volatile.Read(ref _everOwnedPages[page / 64]) & (1L << (int)(page % 64))) != 0) + { + return true; + } + } + + return false; } // The half-open page interval of a non-empty byte range inside the address space. diff --git a/tests/SharpEmu.Libs.Tests/Gpu/Images/ImagePageOwnerTableTests.cs b/tests/SharpEmu.Libs.Tests/Gpu/Images/ImagePageOwnerTableTests.cs index 03a3e48..a166666 100644 --- a/tests/SharpEmu.Libs.Tests/Gpu/Images/ImagePageOwnerTableTests.cs +++ b/tests/SharpEmu.Libs.Tests/Gpu/Images/ImagePageOwnerTableTests.cs @@ -11,6 +11,19 @@ namespace SharpEmu.Libs.Tests.Gpu.Images; [Collection(SchedulingStateCollection.Name)] public sealed class ImagePageOwnerTableTests { + [Fact] + public void OwnerSummaryRejectsOnlyPagesThatNeverHadAnOwner() + { + var table = new ImagePageOwnerTable(); + var page = ImagePageOwnerTable.BucketEntries; + var address = (ulong)page << ImagePageOwnerTable.PageBits; + Assert.False(table.MayHaveOwners(address, 4)); + table.GetOrCreate((ulong)page).Add(Owner(1)); + Assert.True(table.MayHaveOwners(address, 4)); + Assert.True(table.MayHaveOwners(address - 4, 8)); + Assert.False(table.MayHaveOwners(address - 4, 4)); + } + private static ResourceSlotIdentifier Owner(uint index) => new(index, 1); [Fact]