//----------------------------------------------------------------------------- /// Return GPU-time in text format, to be parsed by the Client and displayed as its own timeline. /// \return A line-delimited, ASCII-encoded, version of the GPU Trace data. //----------------------------------------------------------------------------- std::string VktTraceAnalyzerLayer::GetGPUTraceTXT() { gtASCIIString appendString = ""; VktFrameProfilerLayer* pProfilerLayer = VktFrameProfilerLayer::Instance(); WaitAndFetchResults(pProfilerLayer); // During QueueSubmit we stored ProfilerResults in mEntriesWithProfilingResults. Form a response using it here. ProfilerResultsMap& profiledCmdBufResultsMap = pProfilerLayer->GetCmdBufProfilerResultsMap(); // Gather all profiler results if (!profiledCmdBufResultsMap.empty()) { std::vector<ProfilerResult*> flatResults; for (ProfilerResultsMap::iterator profIt = profiledCmdBufResultsMap.begin(); profIt != profiledCmdBufResultsMap.end(); ++profIt) { QueueWrapperToProfilingResultsMap& resultsPerThread = profIt->second; for (QueueWrapperToProfilingResultsMap::iterator queuesIt = resultsPerThread.begin(); queuesIt != resultsPerThread.end(); ++queuesIt) { // This structure holds all of the profiler results that were collected at QueueSubmit. The form is LinkId->ProfilerResult. const SampleIdToProfilerResultMap* pResults = queuesIt->second; for (SampleIdToProfilerResultMap::const_iterator sampleIdIt = pResults->begin(); sampleIdIt != pResults->end(); ++sampleIdIt) { ProfilerResult* pResult = sampleIdIt->second; pResult->measurementInfo.idInfo.pWrappedQueue = queuesIt->first; flatResults.push_back(pResult); } } } const UINT numResults = (UINT)flatResults.size(); // We'll need to insert the GPU Trace section header before the response data, even if there aren't any results. appendString += "//==GPU Trace=="; appendString += "\n"; appendString += "//API="; appendString += GetAPIString(); appendString += "\n"; appendString += "//CommandBufEventCount="; appendString += IntToString((INT)numResults); appendString += "\n"; #ifdef WIN32 sort(flatResults.begin(), flatResults.end(), SortByStartTime); for (UINT i = 0; i < numResults; i++) { ProfilerResultToStr(flatResults[i], appendString); } #else ProfilerResult* pFlatResults = new ProfilerResult[numResults]; for (UINT i = 0; i < numResults; i++) { pFlatResults[i] = *(flatResults[i]); } qsort(pFlatResults, numResults, sizeof(ProfilerResult), (compfn)SortByStartTime); for (UINT i = 0; i < numResults; i++) { ProfilerResultToStr(&pFlatResults[i], appendString); } delete[] pFlatResults; pFlatResults = nullptr; #endif } else { appendString += "NODATA"; } return appendString.asCharArray(); }
//----------------------------------------------------------------------------- /// Return GPU-time in text format, to be parsed by the Client and displayed as its own timeline. /// \return A line-delimited, ASCII-encoded, version of the GPU Trace data. //----------------------------------------------------------------------------- std::string VktTraceAnalyzerLayer::GetGPUTraceTXT() { gtASCIIString appendString = ""; VktFrameProfilerLayer* pProfilerLayer = VktFrameProfilerLayer::Instance(); WaitAndFetchResults(pProfilerLayer); // Query the CPU clock frequency so we can accurately convert to wall clock time. GPS_TIMESTAMP cpuClockFrequency; QueryPerformanceFrequency(&cpuClockFrequency); // During QueueSubmit we stored ProfilerResults in mEntriesWithProfilingResults. Form a response using it here. ProfilerResultsMap& profiledCmdBufResultsMap = pProfilerLayer->GetCmdBufProfilerResultsMap(); // During QueueSubmit we stored ProfilerResults in mEntriesWithProfilingResults. Form a response using it here. if (!profiledCmdBufResultsMap.empty()) { // Keep a count of the number of lines that we'll write in the response string. UINT numResponseLines = 0; gtASCIIString profiledCommandsLinesStr; ProfilerResultsMap::iterator profIt; for (profIt = profiledCmdBufResultsMap.begin(); profIt != profiledCmdBufResultsMap.end(); ++profIt) { QueueWrapperToProfilingResultsMap::iterator queuesWithProfilingResults; QueueWrapperToProfilingResultsMap& resultsPerThread = profIt->second; for (queuesWithProfilingResults = resultsPerThread.begin(); queuesWithProfilingResults != resultsPerThread.end(); ++queuesWithProfilingResults) { VktWrappedQueue* pWrappedQueue = queuesWithProfilingResults->first; const double timestampFrequency = pWrappedQueue->GetTimestampFrequency(); // This structure holds all of the profiler results that were collected at QueueSubmit. The form is LinkId->ProfilerResult. const SampleIdToProfilerResultMap* pQueueResults = queuesWithProfilingResults->second; SampleIdToProfilerResultMap::const_iterator queueResultsIterInner; for (queueResultsIterInner = pQueueResults->begin(); queueResultsIterInner != pQueueResults->end(); ++queueResultsIterInner) { UINT64 sampleId = queueResultsIterInner->first; const ProfilerResult* pResult = queueResultsIterInner->second; // Convert timestamps to milliseconds by using the clock frequency. #ifndef CODEXL_GRAPHICS double preStartTimestamp = (pResult->timestampResult.rawClocks.preStart / timestampFrequency) * 1000.0; #endif double startTimestamp = (pResult->timestampResult.rawClocks.start / timestampFrequency) * 1000.0; double endTimestamp = (pResult->timestampResult.rawClocks.end / timestampFrequency) * 1000.0; FuncId funcId = (FuncId)pResult->measurementInfo.idInfo.funcId; gtASCIIString funcName = GetFunctionNameFromId(funcId); gtASCIIString retVal = "void"; gtASCIIString params = ""; if (pResult->measurementInfo.idInfo.funcId != FuncId_WholeCmdBuf) { VktAPIEntry* pResultEntry = pProfilerLayer->FindInvocationBySampleId(sampleId); if (pResultEntry != nullptr) { // Convert the functionID and return values from integers into full strings that we can use in the response. funcName = GetFunctionNameFromId(pResultEntry->mFunctionId); retVal = (pResultEntry->m_returnValue != -1) ? VktUtil::WriteResultCodeEnumAsString(pResultEntry->m_returnValue) : "void"; params = pResultEntry->mParameters.asCharArray(); } } UINT queueIndex = pWrappedQueue->GetQueueIndex(); #ifndef CODEXL_GRAPHICS std::string queueInfo = ""; #else std::string queueInfo = "0"; #endif // Vulkan Response line format: // CommandQueuePtr CommandBufferType CommandBufferPtr APIType FuncId Vulkan_FuncName(Args) = ReturnValue StartTime EndTime SampleId profiledCommandsLinesStr += "0x"; profiledCommandsLinesStr += IntToString(queueIndex); profiledCommandsLinesStr += " "; profiledCommandsLinesStr += queueInfo.c_str(); profiledCommandsLinesStr += " "; profiledCommandsLinesStr += "0x"; profiledCommandsLinesStr += UINT64ToHexString((UINT64)pResult->measurementInfo.idInfo.pWrappedCmdBuf->AppHandle()); profiledCommandsLinesStr += " "; profiledCommandsLinesStr += IntToString(VktTraceAnalyzerLayer::Instance()->GetAPIGroupFromAPI(funcId)); profiledCommandsLinesStr += " "; profiledCommandsLinesStr += IntToString(funcId); profiledCommandsLinesStr += " "; profiledCommandsLinesStr += "Vulkan_"; profiledCommandsLinesStr += funcName; profiledCommandsLinesStr += "("; profiledCommandsLinesStr += params; profiledCommandsLinesStr += ") = "; profiledCommandsLinesStr += retVal; #ifndef CODEXL_GRAPHICS profiledCommandsLinesStr += " "; profiledCommandsLinesStr += DoubleToString(preStartTimestamp); #endif profiledCommandsLinesStr += " "; profiledCommandsLinesStr += DoubleToString(startTimestamp); profiledCommandsLinesStr += " "; profiledCommandsLinesStr += DoubleToString(endTimestamp); profiledCommandsLinesStr += " "; profiledCommandsLinesStr += UINT64ToString(pResult->measurementInfo.idInfo.sampleId); profiledCommandsLinesStr += "\n"; // We just added another line to our response buffer. Increment the count that the client will read. numResponseLines++; } } } // We'll need to insert the GPU Trace section header before the response data, even if there aren't any results. appendString += "//==GPU Trace=="; appendString += "\n"; appendString += "//CommandBufEventCount="; appendString += DWORDToString(numResponseLines); appendString += "\n"; // Include the response lines after the section header. if (numResponseLines > 0) { appendString += profiledCommandsLinesStr; } } else { appendString += "NODATA"; } return appendString.asCharArray(); }