diff --git a/VkLayer_profiler_layer/profiler_trace/profiler_trace.cpp b/VkLayer_profiler_layer/profiler_trace/profiler_trace.cpp index a7359979..5d60fbd0 100644 --- a/VkLayer_profiler_layer/profiler_trace/profiler_trace.cpp +++ b/VkLayer_profiler_layer/profiler_trace/profiler_trace.cpp @@ -93,6 +93,8 @@ namespace Profiler , m_pJsonSerializer( new DeviceProfilerJsonSerializer( m_pStringSerializer ) ) , m_pData( nullptr ) , m_CommandQueue( VK_NULL_HANDLE ) + , m_CommandQueueName() + , m_CommandQueueEventTracks() , m_Events() , m_DebugLabelStackDepth( 0 ) , m_HostTimeDomain( OSGetDefaultTimeDomain() ) @@ -147,12 +149,14 @@ namespace Profiler frameName, "Frames", frameGpuBeginTimestamp, - VK_NULL_HANDLE ) ); + "Frames" ) ); // Serialize the data for( const auto& submitBatchData : data.m_Submits ) { m_CommandQueue = submitBatchData.m_Handle; + m_CommandQueueName = m_pStringSerializer->GetName( m_CommandQueue ); + m_CommandQueueEventTracks.clear(); // Insert queue submission event m_Events.push_back( ApiTraceEvent( @@ -228,7 +232,7 @@ namespace Profiler m_Events.push_back( TraceCounterEvent( GetNormalizedGpuTimestamp( data.m_PerformanceCounters.m_StreamTimestamps[i] ), - m_CommandQueue, + m_CommandQueueName, performanceCountersCount, performanceCounterProperties.data(), performanceCounterSamples.data() ) ); @@ -237,7 +241,7 @@ namespace Profiler Fill( performanceCounterSamples, VkProfilerPerformanceCounterResultEXT{} ); m_Events.push_back( TraceCounterEvent( frameGpuEndTimestamp, - m_CommandQueue, + m_CommandQueueName, performanceCountersCount, performanceCounterProperties.data(), performanceCounterSamples.data() ) ); @@ -248,7 +252,7 @@ namespace Profiler frameName, "Frames", frameGpuEndTimestamp, - VK_NULL_HANDLE ) ); + "Frames" ) ); // Insert TIP events Serialize( data.m_TIP ); @@ -377,6 +381,7 @@ namespace Profiler void DeviceProfilerTraceSerializer::Serialize( const DeviceProfilerCommandBufferData& data ) { const std::string eventName = m_pStringSerializer->GetName( data ); + const std::string trackName = AssignTrackForEvent( data ); // Begin m_Events.push_back( TraceEvent( @@ -384,7 +389,7 @@ namespace Profiler eventName, "Command buffers", GetNormalizedGpuTimestamp( data.m_BeginTimestamp.m_Value ), - m_CommandQueue ) ); + trackName ) ); // Performance counters const uint32_t performanceCounterCount = static_cast( data.m_PerformanceCounters.m_Results.size() ); @@ -400,7 +405,7 @@ namespace Profiler m_Events.push_back( TraceCounterEvent( GetNormalizedGpuTimestamp( data.m_BeginTimestamp.m_Value ), - m_CommandQueue, + m_CommandQueueName, performanceCounterProperties.size(), performanceCounterProperties.data(), data.m_PerformanceCounters.m_Results.data() ) ); @@ -420,7 +425,7 @@ namespace Profiler { m_Events.push_back( TraceCounterEvent( GetNormalizedGpuTimestamp( data.m_EndTimestamp.m_Value ), - m_CommandQueue, + m_CommandQueueName, performanceCounterProperties.size(), performanceCounterProperties.data(), nullptr ) ); @@ -432,7 +437,7 @@ namespace Profiler eventName, "Command buffers", GetNormalizedGpuTimestamp( data.m_EndTimestamp.m_Value ), - m_CommandQueue ) ); + trackName ) ); } /*************************************************************************\ @@ -448,29 +453,40 @@ namespace Profiler { const bool isValidRenderPass = (data.m_Type != DeviceProfilerRenderPassType::eNone); const std::string eventName = m_pStringSerializer->GetName(data); + std::string trackName; if( isValidRenderPass ) { + trackName = AssignTrackForEvent( data ); + // Begin m_Events.push_back( TraceEvent( TraceEvent::Phase::eDurationBegin, eventName, "Render passes", GetNormalizedGpuTimestamp( data.m_BeginTimestamp.m_Value ), - m_CommandQueue ) ); + trackName ) ); if( (data.HasBeginCommand()) && (data.m_Begin.m_BeginTimestamp.m_Value != UINT64_MAX) ) { const std::string beginEventName = m_pStringSerializer->GetName( data.m_Begin, data.m_Dynamic ); + const std::string beginEventTrackName = AssignTrackForEvent( data.m_Begin ); // vkCmdBeginRenderPass - m_Events.push_back( TraceCompleteEvent( + m_Events.push_back( TraceEvent( + TraceEvent::Phase::eDurationBegin, beginEventName, "Drawcalls", GetNormalizedGpuTimestamp( data.m_Begin.m_BeginTimestamp.m_Value ), - GetDuration( data.m_Begin ), - m_CommandQueue ) ); + beginEventTrackName ) ); + + m_Events.push_back( TraceEvent( + TraceEvent::Phase::eDurationEnd, + beginEventName, + "Drawcalls", + GetNormalizedGpuTimestamp( data.m_Begin.m_EndTimestamp.m_Value ), + beginEventTrackName ) ); } } @@ -486,14 +502,22 @@ namespace Profiler (data.m_End.m_BeginTimestamp.m_Value != UINT64_MAX) ) { const std::string endEventName = m_pStringSerializer->GetName( data.m_End, data.m_Dynamic ); + const std::string endEventTrackName = AssignTrackForEvent( data.m_End ); // vkCmdEndRenderPass - m_Events.push_back( TraceCompleteEvent( + m_Events.push_back( TraceEvent( + TraceEvent::Phase::eDurationBegin, endEventName, "Drawcalls", GetNormalizedGpuTimestamp( data.m_End.m_BeginTimestamp.m_Value ), - GetDuration( data.m_End ), - m_CommandQueue ) ); + endEventTrackName ) ); + + m_Events.push_back( TraceEvent( + TraceEvent::Phase::eDurationEnd, + endEventName, + "Drawcalls", + GetNormalizedGpuTimestamp( data.m_End.m_EndTimestamp.m_Value ), + endEventTrackName ) ); } // End @@ -502,7 +526,7 @@ namespace Profiler eventName, "Render passes", GetNormalizedGpuTimestamp( data.m_EndTimestamp.m_Value ), - m_CommandQueue ) ); + trackName ) ); } } @@ -518,15 +542,18 @@ namespace Profiler void DeviceProfilerTraceSerializer::Serialize( const DeviceProfilerSubpassData& data, bool isOnlySubpassInRenderPass ) { const std::string eventName = m_pStringSerializer->GetName( data ); + std::string trackName; if( !isOnlySubpassInRenderPass ) { + trackName = AssignTrackForEvent( data ); + // Begin m_Events.push_back( TraceEvent( TraceEvent::Phase::eDurationBegin, eventName, "", GetNormalizedGpuTimestamp( data.m_BeginTimestamp.m_Value ), - m_CommandQueue ) ); + trackName ) ); } for( const auto& data : data.m_Data ) @@ -555,7 +582,7 @@ namespace Profiler TraceEvent::Phase::eDurationEnd, eventName, "", GetNormalizedGpuTimestamp( data.m_EndTimestamp.m_Value ), - m_CommandQueue ) ); + trackName ) ); } } @@ -572,6 +599,7 @@ namespace Profiler { const std::string eventName = m_pStringSerializer->GetName( data, true /*showEntryPoints*/ ); const nlohmann::json eventArgs = m_pJsonSerializer->GetPipelineArgs( data ); + std::string trackName; const bool isValidPipeline = (data.m_Handle || @@ -580,14 +608,16 @@ namespace Profiler if( isValidPipeline ) { + trackName = AssignTrackForEvent( data ); + // Begin m_Events.push_back( TraceEvent( TraceEvent::Phase::eDurationBegin, eventName, "Pipelines", GetNormalizedGpuTimestamp( data.m_BeginTimestamp.m_Value ), - m_CommandQueue, - {} , + trackName, + {}, eventArgs ) ); } @@ -608,7 +638,7 @@ namespace Profiler eventName, "Pipelines", GetNormalizedGpuTimestamp( data.m_EndTimestamp.m_Value ), - m_CommandQueue ) ); + trackName ) ); } } @@ -627,6 +657,7 @@ namespace Profiler { const std::string eventName = m_pStringSerializer->GetCommandName( data ); const nlohmann::json eventArgs = m_pJsonSerializer->GetCommandArgs( data ); + const std::string trackName = AssignTrackForEvent( data ); // Cannot use complete events due to loss of precision m_Events.push_back( TraceEvent( @@ -634,7 +665,7 @@ namespace Profiler eventName, "Drawcalls", GetNormalizedGpuTimestamp( data.m_BeginTimestamp.m_Value ), - m_CommandQueue, + trackName, {}, eventArgs ) ); @@ -643,7 +674,7 @@ namespace Profiler eventName, "Drawcalls", GetNormalizedGpuTimestamp( data.m_EndTimestamp.m_Value ), - m_CommandQueue ) ); + trackName ) ); } else @@ -711,6 +742,34 @@ namespace Profiler /*************************************************************************\ + Function: + AssignTrackForEvent + + \*************************************************************************/ + std::string DeviceProfilerTraceSerializer::AssignTrackForEvent( uint64_t beginTimestamp, uint64_t endTimestamp ) + { + if( beginTimestamp == UINT64_MAX || endTimestamp == UINT64_MAX ) + { + return std::string(); + } + + // Try to find an existing track which is not occupied during the event time + for( size_t i = 0; i < m_CommandQueueEventTracks.size(); ++i ) + { + if( beginTimestamp >= m_CommandQueueEventTracks[i] ) + { + m_CommandQueueEventTracks[i] = endTimestamp; + return m_CommandQueueName + " [" + std::to_string( i ) + "]"; + } + } + + // Create a new track + m_CommandQueueEventTracks.push_back( endTimestamp ); + return m_CommandQueueName + " [" + std::to_string( m_CommandQueueEventTracks.size() - 1 ) + "]"; + } + + /*************************************************************************\ + Function: ConstructTraceFileName diff --git a/VkLayer_profiler_layer/profiler_trace/profiler_trace.h b/VkLayer_profiler_layer/profiler_trace/profiler_trace.h index 759dc4f5..51f631ed 100644 --- a/VkLayer_profiler_layer/profiler_trace/profiler_trace.h +++ b/VkLayer_profiler_layer/profiler_trace/profiler_trace.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2025 Lukasz Stalmirski +// Copyright (c) 2019-2026 Lukasz Stalmirski // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -84,7 +84,9 @@ namespace Profiler const struct DeviceProfilerFrameData* m_pData; // Target command queue for the current batch - VkQueue m_CommandQueue; + VkQueueHandle m_CommandQueue; + std::string m_CommandQueueName; + std::vector m_CommandQueueEventTracks; // Serialized events nlohmann::json m_Events; @@ -110,6 +112,15 @@ namespace Profiler return (data.m_EndTimestamp.m_Value - data.m_BeginTimestamp.m_Value) * m_GpuTimestampPeriod; } + // Track management + std::string AssignTrackForEvent( uint64_t beginTimestamp, uint64_t endTimestamp ); + + template + inline std::string AssignTrackForEvent( const DataStructType& data ) + { + return AssignTrackForEvent( data.GetBeginTimestamp().m_Value, data.GetEndTimestamp().m_Value ); + } + // Serialization void Serialize( const struct DeviceProfilerCommandBufferData& ); void Serialize( const struct DeviceProfilerRenderPassData& ); diff --git a/VkLayer_profiler_layer/profiler_trace/profiler_trace_event.cpp b/VkLayer_profiler_layer/profiler_trace/profiler_trace_event.cpp index 18c4bd16..3c32ea05 100644 --- a/VkLayer_profiler_layer/profiler_trace/profiler_trace_event.cpp +++ b/VkLayer_profiler_layer/profiler_trace/profiler_trace_event.cpp @@ -34,18 +34,13 @@ namespace Profiler \*************************************************************************/ void TraceEvent::Serialize( nlohmann::json& jsonObject ) const { - using namespace std::literals; - - char queueHexHandle[ 32 ] = {}; - ProfilerStringFunctions::Hex( queueHexHandle, reinterpret_cast(m_Queue) ); - jsonObject = { { "name", m_Name }, { "cat", m_Category }, { "ph", std::string( 1, static_cast(m_Phase) ) }, { "ts", m_Timestamp.count() }, { "pid", 0 }, - { "tid", "VkQueue 0x"s + queueHexHandle } }; + { "tid", m_Track } }; if( !m_Color.empty() ) { diff --git a/VkLayer_profiler_layer/profiler_trace/profiler_trace_event.h b/VkLayer_profiler_layer/profiler_trace/profiler_trace_event.h index 44f49b94..822f3796 100644 --- a/VkLayer_profiler_layer/profiler_trace/profiler_trace_event.h +++ b/VkLayer_profiler_layer/profiler_trace/profiler_trace_event.h @@ -71,7 +71,7 @@ namespace Profiler std::string m_Name; std::string m_Category; Microseconds m_Timestamp; - VkQueue m_Queue; + std::string m_Track; nlohmann::json m_Color; nlohmann::json m_Args; @@ -83,14 +83,14 @@ namespace Profiler std::string_view name, std::string_view category, TimestampType timestamp, - VkQueue queue, + std::string_view track, const nlohmann::json& color = {}, const nlohmann::json& args = {} ) : m_Phase( phase ) , m_Name( name ) , m_Category( category ) , m_Timestamp( std::chrono::duration_cast(timestamp) ) - , m_Queue( queue ) + , m_Track( track ) , m_Color( color ) , m_Args( args ) { @@ -130,10 +130,10 @@ namespace Profiler std::string_view name, std::string_view category, TimestampType timestamp, - VkQueue queue, + std::string_view track, const nlohmann::json& color = {}, const nlohmann::json& args = {} ) - : TraceEvent( Phase::eInstant, name, category, timestamp, queue, color, args ) + : TraceEvent( Phase::eInstant, name, category, timestamp, track, color, args ) , m_Scope( scope ) { } @@ -166,10 +166,10 @@ namespace Profiler std::string_view name, std::string_view category, TimestampType timestamp, - VkQueue queue, + std::string_view track, const nlohmann::json& color = {}, const nlohmann::json& args = {} ) - : TraceEvent( phase, name, category, timestamp, queue, color, args ) + : TraceEvent( phase, name, category, timestamp, track, color, args ) , m_Id( id ) { assert( (m_Phase == Phase::eAsyncStart) @@ -204,10 +204,10 @@ namespace Profiler std::string_view category, TimestampType timestamp, DurationType duration, - VkQueue queue, + std::string_view track, const nlohmann::json& color = {}, const nlohmann::json& args = {} ) - : TraceEvent( Phase::eComplete, name, category, timestamp, queue, color, args ) + : TraceEvent( Phase::eComplete, name, category, timestamp, track, color, args ) , m_Duration( std::chrono::duration_cast(duration) ) { } @@ -238,12 +238,12 @@ namespace Profiler template inline TraceCounterEvent( TimestampType timestamp, - VkQueue queue, + std::string_view track, size_t counterCount, const VkProfilerPerformanceCounterProperties2EXT* pCounterProperties, const VkProfilerPerformanceCounterResultEXT* pCounterResults, const nlohmann::json& color = {} ) - : TraceEvent( Phase::eCounter, "", "", timestamp, queue, color ) + : TraceEvent( Phase::eCounter, "", "", timestamp, track, color ) , m_CounterCount( counterCount ) , m_pCounterProperties( pCounterProperties ) , m_pCounterResults( pCounterResults ) @@ -274,7 +274,7 @@ namespace Profiler TimestampType timestamp, const nlohmann::json& color = {}, const nlohmann::json& args = {} ) - : TraceEvent( phase, name, "Debug", timestamp, VK_NULL_HANDLE, color, args ) + : TraceEvent( phase, name, "Debug", timestamp, std::string_view(), color, args ) { } @@ -305,7 +305,7 @@ namespace Profiler TimestampType timestamp, const nlohmann::json& color = {}, const nlohmann::json& args = {} ) - : TraceEvent( phase, name, "API", timestamp, VK_NULL_HANDLE, color, args ) + : TraceEvent( phase, name, "API", timestamp, std::string_view(), color, args ) , m_ThreadId( threadId ) { }