From 23abc82aa0f1eb7dd42c1c6e066be46537967a54 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 12 Dec 2017 10:29:17 +0100 Subject: [PATCH] [dxvk] Added performance counter class --- src/dxvk/dxvk_device.cpp | 9 +++- src/dxvk/dxvk_device.h | 13 ++++- src/dxvk/dxvk_stats.cpp | 41 +++++++++++++++ src/dxvk/dxvk_stats.h | 108 +++++++++++++++++++++++++++++++++++++++ src/dxvk/meson.build | 1 + 5 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 src/dxvk/dxvk_stats.cpp create mode 100644 src/dxvk/dxvk_stats.h diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index 681324411..d0012824d 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -101,6 +101,8 @@ namespace dxvk { Rc DxvkDevice::createBuffer( const DxvkBufferCreateInfo& createInfo, VkMemoryPropertyFlags memoryType) { + m_statCounters.increment(DxvkStat::ResBufferCreations, 1); + return new DxvkBuffer(m_vkd, createInfo, *m_memory, memoryType); } @@ -116,6 +118,8 @@ namespace dxvk { Rc DxvkDevice::createImage( const DxvkImageCreateInfo& createInfo, VkMemoryPropertyFlags memoryType) { + m_statCounters.increment(DxvkStat::ResImageCreations, 1); + return new DxvkImage(m_vkd, createInfo, *m_memory, memoryType); } @@ -200,11 +204,14 @@ namespace dxvk { // FIXME this must go away once the ring buffer is implemented m_recycledCommandLists.returnObject(commandList); + m_statCounters.increment(DxvkStat::DevQueueSubmissions, 1); return fence; } - void DxvkDevice::waitForIdle() const { + void DxvkDevice::waitForIdle() { + m_statCounters.increment(DxvkStat::DevSynchronizations, 1); + if (m_vkd->vkDeviceWaitIdle(m_vkd->device()) != VK_SUCCESS) throw DxvkError("DxvkDevice::waitForIdle: Operation failed"); } diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index d23fdf2e3..be091c9a9 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -13,6 +13,7 @@ #include "dxvk_renderpass.h" #include "dxvk_sampler.h" #include "dxvk_shader.h" +#include "dxvk_stats.h" #include "dxvk_swapchain.h" #include "dxvk_sync.h" @@ -255,7 +256,15 @@ namespace dxvk { * used to ensure that resources that were previously * used by the GPU can be safely destroyed. */ - void waitForIdle() const; + void waitForIdle(); + + /** + * \brief Retrieves stat counters + * \returns Stat counters + */ + DxvkStatCounters queryCounters() const { + return m_statCounters; + } private: @@ -274,6 +283,8 @@ namespace dxvk { DxvkRecycler m_recycledCommandLists; DxvkRecycler m_recycledStagingBuffers; + DxvkStatCounters m_statCounters; + }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_stats.cpp b/src/dxvk/dxvk_stats.cpp new file mode 100644 index 000000000..988874c1d --- /dev/null +++ b/src/dxvk/dxvk_stats.cpp @@ -0,0 +1,41 @@ +#include "dxvk_stats.h" + +namespace dxvk { + + DxvkStatCounters:: DxvkStatCounters() { } + DxvkStatCounters::~DxvkStatCounters() { } + + + DxvkStatCounters::DxvkStatCounters(const DxvkStatCounters& other) { + for (size_t i = 0; i < m_counters.size(); i++) + m_counters.at(i) = other.m_counters.at(i).load(); + } + + + DxvkStatCounters& DxvkStatCounters::operator = (const DxvkStatCounters& other) { + for (size_t i = 0; i < m_counters.size(); i++) + m_counters.at(i) = other.m_counters.at(i).load(); + return *this; + } + + + DxvkStatCounters DxvkStatCounters::delta(const DxvkStatCounters& oldState) const { + DxvkStatCounters result; + for (size_t i = 0; i < m_counters.size(); i++) + result.m_counters.at(i) = m_counters.at(i) - oldState.m_counters.at(i);; + return result; + } + + + void DxvkStatCounters::addCounters(const DxvkStatCounters& counters) { + for (size_t i = 0; i < m_counters.size(); i++) + m_counters.at(i) += counters.m_counters.at(i); + } + + + void DxvkStatCounters::clear() { + for (size_t i = 0; i < m_counters.size(); i++) + m_counters.at(i) = 0; + } + +} diff --git a/src/dxvk/dxvk_stats.h b/src/dxvk/dxvk_stats.h new file mode 100644 index 000000000..df2606d65 --- /dev/null +++ b/src/dxvk/dxvk_stats.h @@ -0,0 +1,108 @@ +#pragma once + +#include +#include + +#include "dxvk_include.h" + +namespace dxvk { + + /** + * \brief Statistics counter + */ + enum class DxvkStat : uint32_t { + CtxDescriptorUpdates, ///< # of descriptor set writes + CtxDrawCalls, ///< # of vkCmdDraw/vkCmdDrawIndexed + CtxDispatchCalls, ///< # of vkCmdDispatch + CtxFramebufferBinds, ///< # of render pass begin/end + CtxPipelineBinds, ///< # of vkCmdBindPipeline + DevQueueSubmissions, ///< # of vkQueueSubmit + DevQueuePresents, ///< # of vkQueuePresentKHR (aka frames) + DevSynchronizations, ///< # of vkDeviceWaitIdle + ResBufferCreations, ///< # of buffer creations + ResBufferUpdates, ///< # of unmapped buffer updates + ResImageCreations, ///< # of image creations + ResImageUpdates, ///< # of unmapped image updates + // Do not remove + MaxCounterId + }; + + + /** + * \brief Device statistics + * + * Stores a bunch of counters that may be useful + * for performance evaluation and optimization. + */ + class DxvkStatCounters { + + public: + + DxvkStatCounters(); + ~DxvkStatCounters(); + + DxvkStatCounters( + const DxvkStatCounters& other); + + DxvkStatCounters& operator = (const DxvkStatCounters& other); + + /** + * \brief Increments a counter by a given value + * + * \param [in] counter The counter to increment + * \param [in] amount Number to add to the counter + */ + void increment(DxvkStat counter, uint32_t amount) { + m_counters.at(counterId(counter)) += amount; + } + + /** + * \brief Returns a counter + * + * \param [in] counter The counter to retrieve + * \returns Current value of the counter + */ + uint32_t get(DxvkStat counter) const { + return m_counters.at(counterId(counter)); + } + + /** + * \brief Computes delta to a previous state + * + * \param [in] oldState previous state + * \returns Difference to previous state + */ + DxvkStatCounters delta( + const DxvkStatCounters& oldState) const; + + /** + * \brief Adds counters from another source + * + * Adds each counter from the source operand to the + * corresponding counter in this set. Useful to merge + * context counters and device counters. + * \param [in] counters Counters to add + */ + void addCounters( + const DxvkStatCounters& counters); + + /** + * \brief Clears counters + * + * Should be used to clear per-context counters. + * Do not clear the global device counters. + */ + void clear(); + + private: + + std::array, + static_cast(DxvkStat::MaxCounterId)> m_counters; + + static size_t counterId(DxvkStat counter) { + return static_cast(counter); + } + + }; + +} diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 814b0590b..cb20499ee 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -23,6 +23,7 @@ dxvk_src = files([ 'dxvk_sampler.cpp', 'dxvk_shader.cpp', 'dxvk_staging.cpp', + 'dxvk_stats.cpp', 'dxvk_surface.cpp', 'dxvk_swapchain.cpp', 'dxvk_sync.cpp',