mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-07 13:39:55 +00:00
Merge pull request #8913 from Celegans12/perf/agc-pool-exact-size-hit
perf(agc): prefer a pooled buffer of the requested exact size
This commit is contained in:
3 files changed
+37
-3
No files matched your search
@@ -184,6 +184,7 @@ private:
|
||||
static constexpr std::size_t classLimit = std::size_t{1} << 20u;
|
||||
static constexpr unsigned deviceClassBits = 3;
|
||||
static constexpr std::size_t defaultSlots = 4096;
|
||||
static constexpr std::size_t exactSizeScan = 64;
|
||||
};
|
||||
|
||||
std::shared_ptr<BufferPool> GetBufferPool(const Context& context);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
|
||||
namespace AgcDriver::Graphics {
|
||||
@@ -411,9 +412,14 @@ std::optional<BufferAllocation> BufferPool::Take(std::size_t bytes, VkBufferUsag
|
||||
++tier.misses;
|
||||
return std::nullopt;
|
||||
}
|
||||
auto result = found->second.back().allocation;
|
||||
found->second.pop_back();
|
||||
if (found->second.empty()) tier.free.erase(found);
|
||||
auto& slots = found->second;
|
||||
const auto newest = std::prev(slots.end());
|
||||
auto chosen = newest;
|
||||
for (std::size_t scanned = 1; chosen->allocation.bufferBytes != bytes && scanned < exactSizeScan && chosen != slots.begin(); ++scanned) --chosen;
|
||||
if (chosen->allocation.bufferBytes != bytes) chosen = newest;
|
||||
auto result = chosen->allocation;
|
||||
slots.erase(chosen);
|
||||
if (slots.empty()) tier.free.erase(found);
|
||||
--tier.slots;
|
||||
tier.retainedBytes -= result.allocationBytes;
|
||||
++tier.hits;
|
||||
|
||||
@@ -350,6 +350,32 @@ void LargerClass() {
|
||||
Expect(MemoryOf(best.Handle()) != twelve && ClassOf(best.Handle()) == 5 * MiB, "a 4 MiB + 1 request did not take the smallest retained class that fits (5 MiB)");
|
||||
}
|
||||
|
||||
void ExactSizeReuse() {
|
||||
mock = MockDevice{};
|
||||
{
|
||||
auto context = mockContext();
|
||||
VkBuffer first = VK_NULL_HANDLE;
|
||||
VkBuffer second = VK_NULL_HANDLE;
|
||||
{
|
||||
auto a = std::make_unique<Buffer>(context, 3000, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, HostVisible);
|
||||
auto b = std::make_unique<Buffer>(context, 4000, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, HostVisible);
|
||||
first = a->Handle();
|
||||
second = b->Handle();
|
||||
a.reset();
|
||||
b.reset();
|
||||
}
|
||||
const auto destroyed = mock.destroyedBuffers;
|
||||
{
|
||||
Buffer again(context, 3000, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, HostVisible);
|
||||
Expect(again.Handle() == first && mock.destroyedBuffers == destroyed, "a pooled buffer of the requested exact size was passed over for a newer one that had to be rebuilt");
|
||||
Expect(mock.sizes.at(again.Handle()) == 3000 && again.Bytes().size() == 3000, "a reused buffer does not have the requested size");
|
||||
}
|
||||
Buffer other(context, 4000, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, HostVisible);
|
||||
Expect(other.Handle() == second && mock.sizes.at(other.Handle()) == 4000, "the other exact size was not kept for its own request");
|
||||
}
|
||||
Expect(mock.liveBytes == 0 && mock.liveBuffers.empty(), "exact-size reuse leaked Vulkan objects");
|
||||
}
|
||||
|
||||
void KeptUntilFence() {
|
||||
mock = MockDevice{};
|
||||
auto context = mockContext();
|
||||
@@ -1168,6 +1194,7 @@ int main(int argc, char** argv) {
|
||||
Expect(mock.liveBytes == 0, "slab return test leaked memory");
|
||||
SizeClassesAndDirections();
|
||||
LargerClass();
|
||||
ExactSizeReuse();
|
||||
KeptUntilFence();
|
||||
SmallDeviceRetention();
|
||||
Budget();
|
||||
|
||||
Reference in new issue
Block a user