From 7347a11dff692cdfeb5e972f1bb9b1354ad2b975 Mon Sep 17 00:00:00 2001 From: reinsteam Date: Wed, 21 Mar 2018 17:53:08 +0900 Subject: [PATCH] Implemented data retrieval from selected NV counters --- renderdoc/driver/d3d11/d3d11_counters.cpp | 91 ++++++++ renderdoc/driver/ihv/nv/nv_counters.cpp | 243 +++++++++++++++++++--- renderdoc/driver/ihv/nv/nv_counters.h | 20 +- 3 files changed, 323 insertions(+), 31 deletions(-) diff --git a/renderdoc/driver/d3d11/d3d11_counters.cpp b/renderdoc/driver/d3d11/d3d11_counters.cpp index 6f88e618f..382012820 100644 --- a/renderdoc/driver/d3d11/d3d11_counters.cpp +++ b/renderdoc/driver/d3d11/d3d11_counters.cpp @@ -348,9 +348,71 @@ void D3D11Replay::FillTimersAMD(uint32_t &eventStartID, uint32_t &sampleIndex, } } +static void FlushGPU(WrappedID3D11Device *pDevice, WrappedID3D11DeviceContext *pImmediateContext) +{ + ID3D11Query *pAPIQuery = NULL; + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + if(FAILED(pDevice->CreateQuery(&queryDesc, &pAPIQuery))) + { + return; + } + + HRESULT hr; + pImmediateContext->Flush(); + pImmediateContext->End(pAPIQuery); + pImmediateContext->Flush(); + if(S_OK != (hr = pImmediateContext->GetData(pAPIQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH))) + { + do + { + if(FAILED(hr)) + { + return; + } + ::Sleep(0); // Give up time slice + } while(S_OK != + (hr = pImmediateContext->GetData(pAPIQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH))); + } + + if(pAPIQuery) + pAPIQuery->Release(); +} + void D3D11Replay::FillTimersNV(uint32_t &eventStartID, uint32_t &sampleIndex, vector &eventIDs, const DrawcallDescription &drawnode) { + if(drawnode.children.empty()) + return; + + for(size_t i = 0; i < drawnode.children.size(); i++) + { + const DrawcallDescription &d = drawnode.children[i]; + + FillTimersNV(eventStartID, sampleIndex, eventIDs, drawnode.children[i]); + + if(d.events.empty() || (!(drawnode.children[i].flags & DrawFlags::Drawcall) && + !(drawnode.children[i].flags & DrawFlags::Dispatch))) + continue; + + eventIDs.push_back(d.eventId); + + m_pDevice->ReplayLog(eventStartID, d.eventId, eReplay_WithoutDraw); + + FlushGPU(m_pDevice, m_pImmediateContext); + + m_pNVCounters->BeginSample(sampleIndex); + + m_pDevice->ReplayLog(eventStartID, d.eventId, eReplay_OnlyDraw); + + FlushGPU(m_pDevice, m_pImmediateContext); + + m_pNVCounters->EndSample(sampleIndex); + + eventStartID = d.eventId + 1; + sampleIndex++; + } } vector D3D11Replay::FetchCountersAMD(const vector &counters) @@ -398,7 +460,36 @@ vector D3D11Replay::FetchCountersAMD(const vector &co vector D3D11Replay::FetchCountersNV(const vector &counters) { + const FrameRecord &frameRecord = m_pDevice->GetFrameRecord(); + const FrameStatistics &frameStats = frameRecord.frameInfo.stats; + + const uint32_t objectsCount = frameStats.draws.calls + frameStats.dispatches.calls + 1; + vector ret; + + if(m_pNVCounters->PrepareExperiment(counters, objectsCount)) + { + FlushGPU(m_pDevice, m_pImmediateContext); + + uint32_t passCount = m_pNVCounters->BeginExperiment(); + uint32_t sampleIndex = 0; + vector eventIDs; + + for(uint32_t passIdx = 0; passIdx < passCount; ++passIdx) + { + m_pNVCounters->BeginPass(passIdx); + + uint32_t eventStartID = 0; + sampleIndex = 0; + eventIDs.clear(); + + FillTimersNV(eventStartID, sampleIndex, eventIDs, m_pImmediateContext->GetRootDraw()); + + m_pNVCounters->EndPass(passIdx); + } + + m_pNVCounters->EndExperiment(eventIDs, ret); + } return ret; } diff --git a/renderdoc/driver/ihv/nv/nv_counters.cpp b/renderdoc/driver/ihv/nv/nv_counters.cpp index fa62078f8..ee8c45fdc 100644 --- a/renderdoc/driver/ihv/nv/nv_counters.cpp +++ b/renderdoc/driver/ihv/nv/nv_counters.cpp @@ -5,11 +5,14 @@ #include "official/PerfKit/include/NvPmApi.h" #include "strings/string_utils.h" +#include + struct EnumCountersCtx { std::vector mExternalIds; std::vector mInternalIds; - std::vector mDescriptors; + std::vector mExternalDescriptors; + std::vector mInternalDescriptors; NvPmApi *mNvPmApi; @@ -18,7 +21,12 @@ struct EnumCountersCtx static bool NvPmResultFails(NVPMRESULT actual, char const *failMsg) { - return actual != NVPM_OK; + if(actual != NVPM_OK) + { + RDCWARN("NV GPU performance counters could not %s (code = %u)\n", failMsg, actual); + return true; + } + return false; } int NvPmCountCounters(NVPMCounterID unCounterID, const char *pcCounterName, void *pUserData) @@ -38,7 +46,7 @@ int NvPmGatherCounters(NVPMCounterID unCounterID, const char *pcCounterName, voi pEnumCtx->mExternalIds[i] = globalId; pEnumCtx->mInternalIds[i] = unCounterID; - CounterDescription &desc = pEnumCtx->mDescriptors[i]; + CounterDescription &desc = pEnumCtx->mExternalDescriptors[i]; NVPMUINT64 Attribute = 0; @@ -61,35 +69,41 @@ int NvPmGatherCounters(NVPMCounterID unCounterID, const char *pcCounterName, voi }; pEnumCtx->mNvPmApi->GetCounterAttribute(unCounterID, NVPMA_COUNTER_DISPLAY, &Attribute); - NVPMCOUNTERDISPLAY Display = static_cast(Attribute); - - switch(Display) - { - case NVPM_CD_RATIO: desc.unit = CounterUnit::Ratio; break; - - case NVPM_CD_RAW: desc.unit = CounterUnit::Cycles; break; - } + NVPMCOUNTERDISPLAY DisplayType = static_cast(Attribute); pEnumCtx->mNvPmApi->GetCounterAttribute(unCounterID, NVPMA_COUNTER_DOMAIN, &Attribute); pEnumCtx->mNvPmApi->GetCounterAttribute(unCounterID, NVPMA_COUNTER_VALUE_TYPE, &Attribute); NVPMCOUNTERVALUETYPE ValueType = static_cast(Attribute); - switch(ValueType) - { - case NVPM_VALUE_TYPE_UINT64: - { - desc.resultType = CompType::UInt; - desc.resultByteWidth = sizeof(uint64_t); - } - break; + pEnumCtx->mInternalDescriptors[i] = (DisplayType << 1) | ValueType; - case NVPM_VALUE_TYPE_FLOAT64: + if(ValueType == NVPM_VALUE_TYPE_UINT64) + { + if(DisplayType == NVPM_CD_RATIO) { + desc.unit = CounterUnit::Ratio; desc.resultType = CompType::Double; desc.resultByteWidth = sizeof(double); } - break; + else + { + desc.unit = CounterUnit::Absolute; + desc.resultType = CompType::UInt; + desc.resultByteWidth = sizeof(uint64_t); + } + } + else + { + if(DisplayType == NVPM_CD_RATIO) + { + RDCWARN( + " normalization for counters with DisplayType == NVPM_CD_RATIO and ValueType == " + "NVPM_VALUE_TYPE_FLOAT64 is unhandled"); + } + desc.unit = CounterUnit::Ratio; + desc.resultType = CompType::Double; + desc.resultByteWidth = sizeof(double); } char Description[512]; @@ -110,19 +124,28 @@ int NvPmGatherCounters(NVPMCounterID unCounterID, const char *pcCounterName, voi return NVPM_OK; } -NVCounters::NVCounters() : mNvPmLib(NULL), mNvPmApi(NULL), mNvPmCtx(static_cast(-1)) {} +NVCounters::NVCounters() + : mNvPmLib(NULL), mNvPmApi(NULL), mNvPmCtx(static_cast(-1)), mObjectsCount(0) +{ +} NVCounters::~NVCounters() { + if(mObjectsCount != 0) + { + NvPmResultFails(mNvPmApi->DeleteObjects(mNvPmCtx), "call to 'NvPmApi::DeleteObjects'"); + mObjectsCount = 0; + } + if(mNvPmCtx != static_cast(-1)) { - mNvPmApi->DestroyContext(mNvPmCtx); + NvPmResultFails(mNvPmApi->DestroyContext(mNvPmCtx), "call to 'NvPmApi::DestroyContext'"); mNvPmCtx = static_cast(-1); } if(mNvPmApi != 0) { - mNvPmApi->Shutdown(); + NvPmResultFails(mNvPmApi->Shutdown(), "call to 'NvPmApi::Shutdown'"); mNvPmApi = NULL; } mNvPmLib = NULL; @@ -138,6 +161,7 @@ bool NVCounters::Init() mNvPmLib = Process::LoadModule("NvPmApi.Core.dll"); if(mNvPmLib == NULL) { + RDCWARN("NV GPU performance counters could not locate 'NvPmApi.Core.dll'"); return false; } @@ -148,12 +172,12 @@ bool NVCounters::Init() return false; } - if(NvPmResultFails(pfnGetExportTable(&ETID_NvPmApi, (void **)&mNvPmApi), "Get 'NvPmApi' table")) + if(NvPmResultFails(pfnGetExportTable(&ETID_NvPmApi, (void **)&mNvPmApi), "get 'NvPmApi' table")) { return false; } - if(NvPmResultFails(mNvPmApi->Init(), "Init 'NvPmApi'")) + if(NvPmResultFails(mNvPmApi->Init(), "init 'NvPmApi'")) { return false; } @@ -168,7 +192,7 @@ bool NVCounters::Init(ID3D11Device *pDevice) } if(NvPmResultFails(mNvPmApi->CreateContextFromD3D11Device(pDevice, &mNvPmCtx), - "Init 'NVPMContext' from ID3D11Device")) + "init 'NVPMContext' from ID3D11Device")) { return false; } @@ -179,7 +203,8 @@ bool NVCounters::Init(ID3D11Device *pDevice) EnumCountersCtx ctx; ctx.mExternalIds.resize(NumCounters); ctx.mInternalIds.resize(NumCounters); - ctx.mDescriptors.resize(NumCounters); + ctx.mExternalDescriptors.resize(NumCounters); + ctx.mInternalDescriptors.resize(NumCounters); ctx.mNvPmApi = mNvPmApi; ctx.mCurrentCounterId = 0; @@ -187,7 +212,167 @@ bool NVCounters::Init(ID3D11Device *pDevice) ctx.mExternalIds.swap(mExternalIds); ctx.mInternalIds.swap(mInternalIds); - ctx.mDescriptors.swap(mDescriptors); + ctx.mExternalDescriptors.swap(mExternalDescriptors); + ctx.mInternalDescriptors.swap(mInternalDescriptors); + + mSelectedExternalIds.reserve(NumCounters); + mSelectedInternalIds.reserve(NumCounters); return true; } + +bool NVCounters::PrepareExperiment(const std::vector &counters, uint32_t objectsCount) +{ + if(NvPmResultFails(mNvPmApi->RemoveAllCounters(mNvPmCtx), "call to 'NvPmApi::RemoveAllCounters'")) + { + return false; + } + + mSelectedExternalIds.clear(); + mSelectedInternalIds.clear(); + + std::for_each(counters.begin(), counters.end(), + [&selExternalIds = mSelectedExternalIds, &selInternalIds = mSelectedInternalIds, + &internalIds = mInternalIds](GPUCounter counter) { + const uint32_t externalId = static_cast(counter) - + static_cast(GPUCounter::FirstNvidia); + selExternalIds.push_back(counter); + selInternalIds.push_back(internalIds[externalId]); + }); + + if(NvPmResultFails( + mNvPmApi->AddCounters(mNvPmCtx, static_cast(mSelectedInternalIds.size()), + mSelectedInternalIds.data()), + "call to 'NvPmApi::AddCounters'")) + { + return false; + } + + if(mObjectsCount != objectsCount) + { + if(mObjectsCount != 0) + { + NvPmResultFails(mNvPmApi->DeleteObjects(mNvPmCtx), "call to 'NvPmApi::DeleteObjects'"); + mObjectsCount = 0; + } + + if(NvPmResultFails(mNvPmApi->ReserveObjects(mNvPmCtx, objectsCount), + "call to 'NvPmApi::ReserveObjects'")) + { + return false; + } + mObjectsCount = objectsCount; + } + return true; +} + +uint32_t NVCounters::BeginExperiment() const +{ + NVPMUINT NumPasses = 0; + if(NvPmResultFails(mNvPmApi->BeginExperiment(mNvPmCtx, &NumPasses), + "call to 'NvPmApi::BeginExperiment'")) + { + return 0; + } + return NumPasses; +} + +void NVCounters::EndExperiment(const std::vector &eventIds, + std::vector &Result) const +{ + NvPmResultFails(mNvPmApi->EndExperiment(mNvPmCtx), "call to 'NvPmApi::EndExperiment'"); + + // NVPMUINT NumCounters = mObjectsCount; + // NVPMRESULT result = mNvPmApi->SampleEx(mNvPmCtx, Samples.data(), &NumCounters); + // NvPmResultFails(result, "call to 'NvPmApi::SampleEx'"); + // mNvPmApi->GetCounterValue(); + + Result.reserve(mSelectedExternalIds.size() * mObjectsCount); + + for(uint32_t counterIdx = 0; counterIdx < mSelectedExternalIds.size(); ++counterIdx) + { + const GPUCounter counter = mSelectedExternalIds[counterIdx]; + + const uint32_t externalId = + static_cast(counter) - static_cast(GPUCounter::FirstNvidia); + + const NVPMCounterID internalId = mInternalIds[externalId]; + + const uint32_t internalDesc = mInternalDescriptors[externalId]; + + const NVPMCOUNTERDISPLAY displayType = static_cast(internalDesc >> 1); + const NVPMCOUNTERTYPE counterType = static_cast(internalDesc & 1); + + if(counterType == NVPM_VALUE_TYPE_UINT64) + { + if(displayType == NVPM_CD_RATIO) + { + for(uint32_t i = 0; i < mObjectsCount; ++i) + { + NVPMUINT64 Value; + NVPMUINT64 Cycles; + NVPMUINT8 Overflow; + NVPMRESULT result = + mNvPmApi->GetCounterValueUint64(mNvPmCtx, internalId, i, &Value, &Cycles, &Overflow); + + double Ratio = static_cast(Value) / static_cast(Cycles); + Result.push_back(CounterResult(eventIds[i], counter, Ratio)); + + (void)result; + } + } + else + { + for(uint32_t i = 0; i < mObjectsCount; ++i) + { + NVPMUINT64 Value; + NVPMUINT64 Cycles; + NVPMUINT8 Overflow; + NVPMRESULT result = + mNvPmApi->GetCounterValueUint64(mNvPmCtx, internalId, i, &Value, &Cycles, &Overflow); + + Result.push_back(CounterResult(eventIds[i], counter, Value)); + + (void)result; + } + } + } + else + { + for(uint32_t i = 0; i < mObjectsCount; ++i) + { + NVPMFLOAT64 Value; + NVPMUINT64 Cycles; + NVPMUINT8 Overflow; + NVPMRESULT result = + mNvPmApi->GetCounterValueFloat64(mNvPmCtx, internalId, i, &Value, &Cycles, &Overflow); + + Result.push_back(CounterResult(eventIds[i], counter, Value)); + + (void)result; + } + } + } +} + +void NVCounters::BeginPass(uint32_t passIdx) const +{ + NvPmResultFails(mNvPmApi->BeginPass(mNvPmCtx, passIdx), "call to 'NvPmApi::BeginPass'"); +} + +void NVCounters::EndPass(uint32_t passIdx) const +{ + NvPmResultFails(mNvPmApi->EndPass(mNvPmCtx, passIdx), "call to 'NvPmApi::EndPass'"); +} + +void NVCounters::BeginSample(uint32_t sampleIdx) const +{ + RDCASSERT(sampleIdx < mObjectsCount); + NvPmResultFails(mNvPmApi->BeginObject(mNvPmCtx, sampleIdx), "call to 'NvPmApi::BeginObject'"); +} + +void NVCounters::EndSample(uint32_t sampleIdx) const +{ + RDCASSERT(sampleIdx < mObjectsCount); + NvPmResultFails(mNvPmApi->EndObject(mNvPmCtx, sampleIdx), "call to 'NvPmApi::EndObject'"); +} diff --git a/renderdoc/driver/ihv/nv/nv_counters.h b/renderdoc/driver/ihv/nv/nv_counters.h index 915ace6ac..c2e8b182d 100644 --- a/renderdoc/driver/ihv/nv/nv_counters.h +++ b/renderdoc/driver/ihv/nv/nv_counters.h @@ -20,17 +20,33 @@ public: { const uint32_t LocalId = static_cast(counterID) - static_cast(GPUCounter::FirstNvidia); - return mDescriptors[LocalId]; + return mExternalDescriptors[LocalId]; } + bool PrepareExperiment(const std::vector &counters, uint32_t objectsCount); + + // returns num passes + uint32_t BeginExperiment() const; + void EndExperiment(const std::vector &eventIds, std::vector &Result) const; + + void BeginPass(uint32_t passIdx) const; + void EndPass(uint32_t passIdx) const; + + void BeginSample(uint32_t sampleIdx) const; + void EndSample(uint32_t sampleIdx) const; + private: bool Init(void); void *mNvPmLib; struct _NvPmApi *mNvPmApi; uint64_t mNvPmCtx; + uint32_t mObjectsCount; std::vector mExternalIds; std::vector mInternalIds; - std::vector mDescriptors; + std::vector mSelectedExternalIds; + std::vector mSelectedInternalIds; + std::vector mExternalDescriptors; + std::vector mInternalDescriptors; };