1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-03 22:24:13 +01:00

[dxvk] Use worker to update adapter's memory statistics

Takes a bunch of pointer indirections and atomics off the hot path.
This commit is contained in:
Philip Rebohle 2024-09-21 12:52:15 +02:00 committed by Philip Rebohle
parent 27088beea8
commit d00ca261af
4 changed files with 59 additions and 60 deletions

View File

@ -55,14 +55,14 @@ namespace dxvk {
if (m_hasMemoryBudget) { if (m_hasMemoryBudget) {
// Handle DXVK's memory allocations separately so that // Handle DXVK's memory allocations separately so that
// freeing resources actually is visible to applications. // freeing resources actually is visible to applications.
VkDeviceSize allocated = m_memoryAllocated[i].load(); VkDeviceSize allocated = m_memoryStats[i].allocated.load();
VkDeviceSize used = m_memoryUsed[i].load(); VkDeviceSize used = m_memoryStats[i].used.load();
info.heaps[i].memoryBudget = memBudget.heapBudget[i]; info.heaps[i].memoryBudget = memBudget.heapBudget[i];
info.heaps[i].memoryAllocated = std::max(memBudget.heapUsage[i], allocated) - allocated + used; info.heaps[i].memoryAllocated = std::max(memBudget.heapUsage[i], allocated) - allocated + used;
} else { } else {
info.heaps[i].memoryBudget = memProps.memoryProperties.memoryHeaps[i].size; info.heaps[i].memoryBudget = memProps.memoryProperties.memoryHeaps[i].size;
info.heaps[i].memoryAllocated = m_memoryUsed[i].load(); info.heaps[i].memoryAllocated = m_memoryStats[i].used.load();
} }
} }
@ -654,19 +654,14 @@ namespace dxvk {
} }
void DxvkAdapter::notifyMemoryAlloc( void DxvkAdapter::notifyMemoryStats(
uint32_t heap, uint32_t heap,
int64_t bytes) { int64_t allocated,
if (heap < m_memoryAllocated.size()) int64_t used) {
m_memoryAllocated[heap] += bytes; if (heap < m_memoryStats.size()) {
} m_memoryStats[heap].allocated += allocated;
m_memoryStats[heap].used += used;
}
void DxvkAdapter::notifyMemoryUse(
uint32_t heap,
int64_t bytes) {
if (heap < m_memoryUsed.size())
m_memoryUsed[heap] += bytes;
} }

View File

@ -57,7 +57,19 @@ namespace dxvk {
uint32_t transfer; uint32_t transfer;
uint32_t sparse; uint32_t sparse;
}; };
/**
* \brief Adapter memory statistics
*
* Periodically updated by the devices using this adapter.
*/
struct DxvkAdapterMemoryStats {
std::atomic<uint64_t> allocated = { 0u };
std::atomic<uint64_t> used = { 0u };
};
/** /**
* \brief Device import info * \brief Device import info
*/ */
@ -228,22 +240,13 @@ namespace dxvk {
* *
* Updates memory alloc info accordingly. * Updates memory alloc info accordingly.
* \param [in] heap Memory heap index * \param [in] heap Memory heap index
* \param [in] bytes Allocation size * \param [in] allocated Allocated size delta
* \param [in] used Used size delta
*/ */
void notifyMemoryAlloc( void notifyMemoryStats(
uint32_t heap, uint32_t heap,
int64_t bytes); int64_t allocated,
int64_t used);
/**
* \brief Registers memory suballocation
*
* Updates memory alloc info accordingly.
* \param [in] heap Memory heap index
* \param [in] bytes Allocation size
*/
void notifyMemoryUse(
uint32_t heap,
int64_t bytes);
/** /**
* \brief Tests if the driver matches certain criteria * \brief Tests if the driver matches certain criteria
@ -328,8 +331,7 @@ namespace dxvk {
std::vector<VkQueueFamilyProperties> m_queueFamilies; std::vector<VkQueueFamilyProperties> m_queueFamilies;
std::array<std::atomic<uint64_t>, VK_MAX_MEMORY_HEAPS> m_memoryAllocated = { }; std::array<DxvkAdapterMemoryStats, VK_MAX_MEMORY_HEAPS> m_memoryStats = { };
std::array<std::atomic<uint64_t>, VK_MAX_MEMORY_HEAPS> m_memoryUsed = { };
void queryExtensions(); void queryExtensions();
void queryDeviceInfo(); void queryDeviceInfo();

View File

@ -418,27 +418,17 @@ namespace dxvk {
uint32_t getCurrentFrameId() const; uint32_t getCurrentFrameId() const;
/** /**
* \brief Notifies adapter about memory allocation * \brief Notifies adapter about memory allocation changes
* *
* \param [in] heap Memory heap index * \param [in] heap Memory heap index
* \param [in] bytes Allocation size * \param [in] allocated Allocated size delta
* \param [in] used Used size delta
*/ */
void notifyMemoryAlloc( void notifyMemoryStats(
uint32_t heap, uint32_t heap,
int64_t bytes) { int64_t allocated,
m_adapter->notifyMemoryAlloc(heap, bytes); int64_t used) {
} m_adapter->notifyMemoryStats(heap, allocated, used);
/**
* \brief Notifies adapter about memory suballocation
*
* \param [in] heap Memory heap index
* \param [in] bytes Allocation size
*/
void notifyMemoryUse(
uint32_t heap,
int64_t bytes) {
m_adapter->notifyMemoryUse(heap, bytes);
} }
/** /**

View File

@ -358,8 +358,6 @@ namespace dxvk {
} }
type.stats.memoryAllocated += size; type.stats.memoryAllocated += size;
m_device->notifyMemoryAlloc(type.properties.heapIndex, size);
return result; return result;
} }
@ -408,8 +406,6 @@ namespace dxvk {
VkDeviceSize size) { VkDeviceSize size) {
type.stats.memoryUsed += size; type.stats.memoryUsed += size;
m_device->notifyMemoryUse(type.properties.heapIndex, size);
uint32_t chunkIndex = address >> DxvkPageAllocator::ChunkAddressBits; uint32_t chunkIndex = address >> DxvkPageAllocator::ChunkAddressBits;
auto& chunk = pool.chunks[chunkIndex]; auto& chunk = pool.chunks[chunkIndex];
@ -429,8 +425,6 @@ namespace dxvk {
const DxvkDeviceMemory& memory) { const DxvkDeviceMemory& memory) {
type.stats.memoryUsed += memory.size; type.stats.memoryUsed += memory.size;
m_device->notifyMemoryUse(type.properties.heapIndex, memory.size);
return DxvkMemory(this, &type, memory.buffer, memory.memory, return DxvkMemory(this, &type, memory.buffer, memory.memory,
DedicatedChunkAddress, memory.size, memory.mapPtr); DedicatedChunkAddress, memory.size, memory.mapPtr);
} }
@ -441,8 +435,6 @@ namespace dxvk {
std::lock_guard<dxvk::mutex> lock(m_mutex); std::lock_guard<dxvk::mutex> lock(m_mutex);
memory.m_type->stats.memoryUsed -= memory.m_length; memory.m_type->stats.memoryUsed -= memory.m_length;
m_device->notifyMemoryUse(memory.m_type->properties.heapIndex, -memory.m_length);
if (unlikely(memory.m_address == DedicatedChunkAddress)) { if (unlikely(memory.m_address == DedicatedChunkAddress)) {
DxvkDeviceMemory devMem; DxvkDeviceMemory devMem;
devMem.buffer = memory.m_buffer; devMem.buffer = memory.m_buffer;
@ -470,7 +462,6 @@ namespace dxvk {
vk->vkFreeMemory(vk->device(), memory.memory, nullptr); vk->vkFreeMemory(vk->device(), memory.memory, nullptr);
type.stats.memoryAllocated -= memory.size; type.stats.memoryAllocated -= memory.size;
m_device->notifyMemoryAlloc(type.properties.heapIndex, memory.size);
} }
@ -967,6 +958,9 @@ namespace dxvk {
void DxvkMemoryAllocator::runWorker() { void DxvkMemoryAllocator::runWorker() {
env::setThreadName("dxvk-memory"); env::setThreadName("dxvk-memory");
// Local memory statistics that we use to compute stat deltas
std::array<DxvkMemoryStats, VK_MAX_MEMORY_HEAPS> heapStats = { };
std::unique_lock lock(m_mutex); std::unique_lock lock(m_mutex);
while (true) { while (true) {
@ -976,11 +970,29 @@ namespace dxvk {
if (m_stopWorker) if (m_stopWorker)
break; break;
// Periodically free unused memory chunks // Periodically free unused memory chunks and update
// memory allocation statistics for the adapter.
auto currentTime = high_resolution_clock::now(); auto currentTime = high_resolution_clock::now();
for (uint32_t i = 0; i < m_memHeapCount; i++) for (uint32_t i = 0; i < m_memHeapCount; i++) {
freeEmptyChunksInHeap(m_memHeaps[i], 0, currentTime); freeEmptyChunksInHeap(m_memHeaps[i], 0, currentTime);
DxvkMemoryStats stats = getMemoryStats(i);
m_device->notifyMemoryStats(i,
stats.memoryAllocated - heapStats[i].memoryAllocated,
stats.memoryUsed - heapStats[i].memoryUsed);
heapStats[i] = stats;
}
}
// Ensure adapter allocation statistics are consistent
// when the deivce is being destroyed
for (uint32_t i = 0; i < m_memHeapCount; i++) {
m_device->notifyMemoryStats(i,
-heapStats[i].memoryAllocated,
-heapStats[i].memoryUsed);
} }
} }