diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index d9e7c5da..436c8fae 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -235,8 +235,9 @@ namespace dxvk { } - void DxvkDevice::getMemoryAllocationStats(DxvkMemoryAllocationStats& stats) { - return m_objects.memoryManager().getAllocationStats(stats); + DxvkSharedAllocationCacheStats DxvkDevice::getMemoryAllocationStats(DxvkMemoryAllocationStats& stats) { + m_objects.memoryManager().getAllocationStats(stats); + return m_objects.memoryManager().getAllocationCacheStats(); } diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index cd4a08d2..131e7f60 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -408,8 +408,9 @@ namespace dxvk { * * Expensive, should be used with caution. * \param [out] stats Allocation statistics + * \returns Shared allocation cache stats */ - void getMemoryAllocationStats(DxvkMemoryAllocationStats& stats); + DxvkSharedAllocationCacheStats getMemoryAllocationStats(DxvkMemoryAllocationStats& stats); /** * \brief Retreves current frame ID diff --git a/src/dxvk/dxvk_memory.cpp b/src/dxvk/dxvk_memory.cpp index ef9624f2..bb95e0b9 100644 --- a/src/dxvk/dxvk_memory.cpp +++ b/src/dxvk/dxvk_memory.cpp @@ -286,14 +286,19 @@ namespace dxvk { // If there's a list ready for us, take the whole thing std::unique_lock poolLock(m_poolMutex); + m_numRequests += 1u; + auto& pool = m_pools[poolIndex]; - if (!pool.listCount) + if (!pool.listCount) { + m_numMisses += 1u; return nullptr; + } if (!(--pool.listCount)) pool.drainTime = high_resolution_clock::now(); + m_cacheSize -= PoolCapacityInBytes; return std::exchange(pool.lists[pool.listCount], nullptr); } @@ -323,6 +328,10 @@ namespace dxvk { if (likely(pool.listCount < PoolSize)) { pool.lists[pool.listCount++] = allocation; + + if ((m_cacheSize += PoolCapacityInBytes) > m_maxCacheSize) + m_maxCacheSize = m_cacheSize; + return nullptr; } @@ -332,6 +341,21 @@ namespace dxvk { } + DxvkSharedAllocationCacheStats DxvkSharedAllocationCache::getStats() { + std::unique_lock poolLock(m_poolMutex); + + DxvkSharedAllocationCacheStats result = { }; + result.requestCount = m_numRequests; + result.missCount = m_numMisses; + result.size = m_maxCacheSize; + + m_numRequests = 0u; + m_numMisses = 0u; + m_maxCacheSize = 0u; + return result; + } + + void DxvkSharedAllocationCache::cleanupUnusedFromLockedAllocator( high_resolution_clock::time_point time) { std::unique_lock poolLock(m_poolMutex); @@ -1571,6 +1595,24 @@ namespace dxvk { } + DxvkSharedAllocationCacheStats DxvkMemoryAllocator::getAllocationCacheStats() const { + DxvkSharedAllocationCacheStats result = { }; + + for (uint32_t i = 0; i < m_memTypeCount; i++) { + const auto& type = m_memTypes[i]; + + if (type.sharedCache) { + DxvkSharedAllocationCacheStats stats = type.sharedCache->getStats(); + result.requestCount += stats.requestCount; + result.missCount += stats.missCount; + result.size += stats.size; + } + } + + return result; + } + + bool DxvkMemoryAllocator::getBufferMemoryRequirements( const VkBufferCreateInfo& createInfo, VkMemoryRequirements2& memoryRequirements) const { diff --git a/src/dxvk/dxvk_memory.h b/src/dxvk/dxvk_memory.h index acac2bf0..190d8ab3 100644 --- a/src/dxvk/dxvk_memory.h +++ b/src/dxvk/dxvk_memory.h @@ -770,8 +770,6 @@ namespace dxvk { * context classes in order to reduce lock contention. */ class DxvkLocalAllocationCache { - constexpr static VkDeviceSize PoolCapacityInBytes = 4u * DxvkPageAllocator::PageSize; - friend DxvkMemoryAllocator; public: // Cache allocations up to 128 kiB @@ -780,6 +778,8 @@ namespace dxvk { constexpr static VkDeviceSize MinSize = DxvkPoolAllocator::MinSize; constexpr static VkDeviceSize MaxSize = MinSize << (PoolCount - 1u); + constexpr static VkDeviceSize PoolCapacityInBytes = 4u * DxvkPageAllocator::PageSize; + DxvkLocalAllocationCache() = default; DxvkLocalAllocationCache( @@ -860,6 +860,22 @@ namespace dxvk { }; + /** + * \brief Allocation cache stats + * + * Keeps track of the number of requests as + * well as the total size of the cache. + */ + struct DxvkSharedAllocationCacheStats { + /// Total number of requests + uint32_t requestCount = 0u; + /// Number of failed requests + uint32_t missCount = 0u; + /// Cache size, in bytes + VkDeviceSize size = 0u; + }; + + /** * \brief Shared allocation cache * @@ -870,6 +886,8 @@ namespace dxvk { constexpr static uint32_t PoolCount = DxvkLocalAllocationCache::PoolCount; constexpr static uint32_t PoolSize = env::is32BitHostPlatform() ? 6u : 12u; + constexpr static VkDeviceSize PoolCapacityInBytes = DxvkLocalAllocationCache::PoolCapacityInBytes; + friend DxvkMemoryAllocator; public: @@ -898,6 +916,22 @@ namespace dxvk { DxvkResourceAllocation* freeAllocation( DxvkResourceAllocation* allocation); + /** + * \brief Queries statistics + * \returns Cache statistics + */ + DxvkSharedAllocationCacheStats getStats(); + + /** + * \brief Frees unused memory + * + * Periodically called from the worker to free some + * memory that has not been used in some time. + * \param [in] time Current time + */ + void cleanupUnusedFromLockedAllocator( + high_resolution_clock::time_point time); + private: struct FreeList { @@ -923,8 +957,11 @@ namespace dxvk { dxvk::mutex m_poolMutex; std::array m_pools = { }; - void cleanupUnusedFromLockedAllocator( - high_resolution_clock::time_point time); + uint32_t m_numRequests = 0u; + uint32_t m_numMisses = 0u; + + VkDeviceSize m_cacheSize = 0u; + VkDeviceSize m_maxCacheSize = 0u; }; @@ -1056,7 +1093,7 @@ namespace dxvk { * \returns Memory stats for this heap */ DxvkMemoryStats getMemoryStats(uint32_t heap) const; - + /** * \brief Retrieves detailed memory statistics * @@ -1066,6 +1103,14 @@ namespace dxvk { */ void getAllocationStats(DxvkMemoryAllocationStats& stats); + /** + * \brief Queries shared cache stats + * + * Returns statistics for all shared caches. + * \returns Shared cache stats + */ + DxvkSharedAllocationCacheStats getAllocationCacheStats() const; + /** * \brief Queries buffer memory requirements *