2017-10-01 11:37:04 +02:00
|
|
|
#include "externals.hh"
|
2017-11-23 23:31:24 +01:00
|
|
|
#include "ui-profiling.hh"
|
2017-10-01 11:37:04 +02:00
|
|
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
|
2017-10-01 12:48:55 +02:00
|
|
|
constexpr uint32_t T_Profiler::Samples;
|
|
|
|
constexpr uint32_t T_Profiler::History;
|
|
|
|
constexpr uint32_t T_Profiler::Invalid;
|
|
|
|
|
2017-10-01 11:37:04 +02:00
|
|
|
|
2017-12-24 16:02:17 +01:00
|
|
|
T_Profiler::~T_Profiler( )
|
|
|
|
{
|
|
|
|
const auto iSize{ gpuQueries_.size( ) };
|
|
|
|
if ( iSize ) {
|
|
|
|
glDeleteQueries( iSize , &gpuQueries_[ 0 ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-01 11:37:04 +02:00
|
|
|
void T_Profiler::clear( )
|
|
|
|
{
|
|
|
|
sections_.clear( );
|
|
|
|
samples_.clear( );
|
2017-12-24 16:02:17 +01:00
|
|
|
cpuStarts_.clear( );
|
2017-10-01 11:37:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void T_Profiler::startFrame( )
|
|
|
|
{
|
2017-10-01 12:48:55 +02:00
|
|
|
previous_ = Invalid;
|
|
|
|
current_ = Invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
void T_Profiler::endFrame( )
|
|
|
|
{
|
2017-12-24 16:02:17 +01:00
|
|
|
const auto n{ sections_.size( ) };
|
|
|
|
if ( n ) {
|
|
|
|
int32_t done{ 0 };
|
|
|
|
while ( !done ) {
|
|
|
|
glGetQueryObjectiv( gpuQueries_[ n * 2 - 1 ] ,
|
|
|
|
GL_QUERY_RESULT_AVAILABLE ,
|
|
|
|
&done );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( gpuSamples_.size( ) < n ) {
|
|
|
|
gpuSamples_.resize( n );
|
|
|
|
}
|
|
|
|
for ( auto i = 0u ; i < n ; i ++ ) {
|
|
|
|
uint64_t a , b;
|
|
|
|
glGetQueryObjectui64v( gpuQueries_[ i * 2 ] ,
|
|
|
|
GL_QUERY_RESULT , &a );
|
|
|
|
glGetQueryObjectui64v( gpuQueries_[ i * 2 + 1 ] ,
|
|
|
|
GL_QUERY_RESULT , &b );
|
|
|
|
addSample( gpuSamples_[ i ] , b - a );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-01 12:48:55 +02:00
|
|
|
while ( secDurations_.size( ) < n ) {
|
2017-12-24 18:40:12 +01:00
|
|
|
secCPUDurations_.add( 0 );
|
|
|
|
secGPUDurations_.add( 0 );
|
2017-11-03 11:55:26 +01:00
|
|
|
secDurations_.add( 0 );
|
|
|
|
secStarts_.add( 0 );
|
2017-10-01 12:48:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for ( auto i = 0u ; i < n ; i ++ ) {
|
2017-12-24 16:02:17 +01:00
|
|
|
const float cpuD = computeDuration( samples_[ i ] );
|
|
|
|
const float gpuD = computeDuration( gpuSamples_[ i ] );
|
2017-12-24 18:40:12 +01:00
|
|
|
secCPUDurations_[ i ] = cpuD;
|
|
|
|
secGPUDurations_[ i ] = gpuD;
|
2017-12-24 16:02:17 +01:00
|
|
|
secDurations_[ i ] = std::max( cpuD , gpuD );
|
2017-10-01 12:48:55 +02:00
|
|
|
if ( parents_[ i ] != Invalid ) {
|
|
|
|
assert( parents_[ i ] < i );
|
|
|
|
secStarts_[ i ] = secStarts_[ parents_[ i ] ];
|
|
|
|
} else if ( chain_[ i ] != Invalid ) {
|
|
|
|
assert( chain_[ i ] < i );
|
|
|
|
secStarts_[ i ] = secStarts_[ chain_[ i ] ]
|
|
|
|
+ secDurations_[ chain_[ i ] ];
|
|
|
|
} else {
|
|
|
|
secStarts_[ i ] = 0;
|
|
|
|
}
|
|
|
|
}
|
2017-10-01 11:37:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void T_Profiler::start(
|
2017-11-03 11:55:26 +01:00
|
|
|
T_String const& section )
|
2017-10-01 11:37:04 +02:00
|
|
|
{
|
|
|
|
const auto n( sections_.size( ) );
|
|
|
|
const auto pos( find( section ) );
|
|
|
|
if ( pos == n ) {
|
2017-11-03 11:55:26 +01:00
|
|
|
sections_.add( section );
|
|
|
|
samples_.add( T_SamplesList_{ } );
|
2017-12-24 16:02:17 +01:00
|
|
|
cpuStarts_.add( 0u );
|
2017-11-03 11:55:26 +01:00
|
|
|
chain_.add( Invalid );
|
|
|
|
parents_.add( Invalid );
|
2017-10-01 11:37:04 +02:00
|
|
|
}
|
|
|
|
|
2017-10-01 12:48:55 +02:00
|
|
|
chain_[ pos ] = previous_;
|
|
|
|
if ( current_ != Invalid ) {
|
|
|
|
parents_[ pos ] = current_;
|
|
|
|
previous_ = Invalid;
|
|
|
|
} else {
|
|
|
|
parents_[ pos ] = Invalid;
|
|
|
|
}
|
|
|
|
current_ = pos;
|
|
|
|
|
2017-10-01 11:37:04 +02:00
|
|
|
struct timespec ts;
|
|
|
|
clock_gettime( CLOCK_MONOTONIC , &ts );
|
2017-12-24 16:02:17 +01:00
|
|
|
cpuStarts_[ pos ] = ts.tv_sec * 1000000000 + ts.tv_nsec;
|
|
|
|
|
|
|
|
if ( gpuQueries_.size( ) <= pos * 2 + 1 ) {
|
|
|
|
extendGPUQueries( );
|
|
|
|
}
|
|
|
|
glQueryCounter( gpuQueries_[ pos * 2 ] , GL_TIMESTAMP );
|
2017-10-01 11:37:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void T_Profiler::end(
|
2017-11-03 11:55:26 +01:00
|
|
|
T_String const& section )
|
2017-10-01 11:37:04 +02:00
|
|
|
{
|
|
|
|
const auto pos( find( section ) );
|
|
|
|
const auto n( sections_.size( ) );
|
|
|
|
if ( pos == n ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct timespec ts;
|
2017-12-24 16:02:17 +01:00
|
|
|
glQueryCounter( gpuQueries_[ pos * 2 + 1 ] , GL_TIMESTAMP );
|
2017-10-01 11:37:04 +02:00
|
|
|
clock_gettime( CLOCK_MONOTONIC , &ts );
|
|
|
|
|
|
|
|
const uint64_t ended = ts.tv_sec * 1000000000 + ts.tv_nsec;
|
2017-12-24 16:02:17 +01:00
|
|
|
addSample( samples_[ pos ] , ended - cpuStarts_[ pos ] );
|
2017-10-01 12:48:55 +02:00
|
|
|
|
|
|
|
previous_ = pos;
|
|
|
|
current_ = Invalid;
|
2017-10-01 11:37:04 +02:00
|
|
|
}
|
|
|
|
|
2017-10-01 14:10:00 +02:00
|
|
|
void T_Profiler::makeUI( )
|
|
|
|
{
|
|
|
|
if ( !uiEnabled_ ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto const n( sections_.size( ) );
|
|
|
|
if ( n != secDurations_.size( ) ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto const& dspSize( ImGui::GetIO( ).DisplaySize );
|
2017-11-21 16:30:15 +01:00
|
|
|
ImGui::SetNextWindowSize( ImVec2( dspSize.x , dspSize.y * .34f ) , ImGuiSetCond_Appearing );
|
|
|
|
ImGui::SetNextWindowPos( ImVec2( 0 , dspSize.y * .66f ) , ImGuiSetCond_Appearing );
|
2017-11-19 10:21:08 +01:00
|
|
|
ImGui::Begin( "Profiler" , &uiEnabled_ , ImGuiWindowFlags_NoCollapse );
|
2017-10-01 14:10:00 +02:00
|
|
|
|
2017-10-05 08:32:43 +02:00
|
|
|
ImGui::BeginChild( "left" , ImVec2( 180 , 0 ) , true );
|
2017-10-01 14:10:00 +02:00
|
|
|
float angle( 0 );
|
|
|
|
for ( auto i = 0u ; i < n ; i ++ ) {
|
|
|
|
if ( displayed_.size( ) == i ) {
|
2017-11-03 11:55:26 +01:00
|
|
|
displayed_.add( true );
|
2017-10-01 14:10:00 +02:00
|
|
|
}
|
|
|
|
angle = fmod( angle + 137 , 360 );
|
|
|
|
ImVec4 color( 0 , 0 , 0 , 1 );
|
|
|
|
ImGui::ColorConvertHSVtoRGB( angle / 360. , .5 , 1 ,
|
|
|
|
color.x , color.y , color.z );
|
|
|
|
ImGui::PushStyleColor( ImGuiCol_Text , color );
|
2017-10-05 08:32:43 +02:00
|
|
|
|
2017-11-03 11:55:26 +01:00
|
|
|
ebcl::T_StringBuilder sb;
|
2017-12-24 16:02:17 +01:00
|
|
|
char tms[ 12 ];
|
2017-12-24 18:40:12 +01:00
|
|
|
snprintf( tms , 12 , "%.1f" , secDurations_[ i ] );
|
|
|
|
sb << sections_[ i ] << " (" << tms << "ms)" << '\0';
|
2017-11-03 11:55:26 +01:00
|
|
|
ImGui::Checkbox( sb.data( ) , (bool*) &displayed_[ i ] );
|
2017-10-01 14:10:00 +02:00
|
|
|
ImGui::PopStyleColor( );
|
2017-12-24 18:40:12 +01:00
|
|
|
if ( ImGui::IsItemHovered( ) ) {
|
|
|
|
ImGui::BeginTooltip( );
|
|
|
|
|
|
|
|
snprintf( tms , 12 , "%.3f" , secDurations_[ i ] );
|
|
|
|
sb.clear( ) << sections_[ i ] << '\0';
|
|
|
|
ImGui::PushStyleColor( ImGuiCol_Text , color );
|
|
|
|
ImGui::Text( "%s" , sb.data( ) );
|
|
|
|
ImGui::PopStyleColor( );
|
|
|
|
|
|
|
|
sb.clear( ) << "\nTime: " << tms << "ms\n\nCPU: ";
|
|
|
|
snprintf( tms , 12 , "%.3f" , secCPUDurations_[ i ] );
|
|
|
|
sb << tms << "ms\nGPU: ";
|
|
|
|
snprintf( tms , 12 , "%.3f" , secGPUDurations_[ i ] );
|
|
|
|
sb << tms << "ms" << '\0';
|
|
|
|
ImGui::Text( "%s" , sb.data( ) );
|
|
|
|
|
|
|
|
ImGui::EndTooltip( );
|
|
|
|
}
|
2017-10-01 14:10:00 +02:00
|
|
|
}
|
|
|
|
ImGui::EndChild( );
|
|
|
|
ImGui::SameLine( );
|
|
|
|
|
|
|
|
auto* const dl( ImGui::GetWindowDrawList( ) );
|
|
|
|
const ImVec2 wp( ImGui::GetWindowPos( ) );
|
|
|
|
const ImVec2 pos( ImGui::GetCursorPos( ) );
|
|
|
|
const ImVec2 ws( ImGui::GetWindowContentRegionMax( ) );
|
|
|
|
const ImVec2 start( wp.x + pos.x , wp.y + pos.y );
|
|
|
|
auto& style( ImGui::GetStyle( ) );
|
|
|
|
const ImVec2 end( wp.x + ws.x + 1 - style.FramePadding.x ,
|
|
|
|
wp.y + ws.y + 1 - style.FramePadding.y );
|
|
|
|
dl->AddRectFilled( start , end ,
|
|
|
|
ImGui::GetColorU32( ImVec4( .5 , .5 , .5 , .8 ) ) );
|
|
|
|
|
|
|
|
// Ms marks
|
|
|
|
static constexpr float msWidth = 20;
|
|
|
|
float lp( 0 );
|
|
|
|
while ( lp < ws.x ) {
|
|
|
|
dl->AddLine( ImVec2( start.x + lp , start.y ) ,
|
|
|
|
ImVec2( start.x + lp , end.y ) ,
|
|
|
|
ImGui::GetColorU32( ImVec4( 0 , 0 , 0 , .8 ) ) );
|
|
|
|
lp += msWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 60/30FPS line
|
|
|
|
dl->AddLine( ImVec2( start.x + msWidth * 1000. / 60. , start.y ) ,
|
|
|
|
ImVec2( start.x + msWidth * 1000. / 60. , end.y ) ,
|
|
|
|
ImGui::GetColorU32( ImVec4( 0 , 1 , 0 , 1 ) ) );
|
|
|
|
dl->AddLine( ImVec2( start.x + msWidth * 1000. / 30. , start.y ) ,
|
|
|
|
ImVec2( start.x + msWidth * 1000. / 30. , end.y ) ,
|
|
|
|
ImGui::GetColorU32( ImVec4( 1 , 0 , 0 , 1 ) ) );
|
|
|
|
|
|
|
|
// Plot
|
|
|
|
static constexpr float plHeight = 5;
|
2017-10-06 14:42:51 +02:00
|
|
|
uint32_t dLine[ n ];
|
|
|
|
uint32_t cLine = 0;
|
2017-10-01 14:10:00 +02:00
|
|
|
angle = 0;
|
|
|
|
for ( auto i = 0u ; i < n ; i ++ ) {
|
|
|
|
angle = fmod( angle + 137 , 360 );
|
2017-10-06 14:42:51 +02:00
|
|
|
if ( i != 0 ) {
|
|
|
|
if ( chain_[ i ] == Invalid ) {
|
|
|
|
cLine ++;
|
|
|
|
} else {
|
|
|
|
cLine = dLine[ chain_[ i ] ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dLine[ i ] = cLine;
|
2017-10-01 14:10:00 +02:00
|
|
|
if ( !displayed_[ i ] ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const float lx0 = msWidth * secStarts_[ i ];
|
|
|
|
const float lx1 = msWidth * ( secStarts_[ i ] + secDurations_[ i ] );
|
2017-10-06 14:42:51 +02:00
|
|
|
const float lh = cLine * ( plHeight + 1 );
|
2017-10-01 14:10:00 +02:00
|
|
|
const float ly1 = lh + plHeight;
|
|
|
|
ImVec4 color( 0 , 0 , 0 , 1 );
|
|
|
|
ImGui::ColorConvertHSVtoRGB( angle / 360. , .5 , 1 ,
|
|
|
|
color.x , color.y , color.z );
|
|
|
|
dl->AddRectFilled( ImVec2( start.x + lx0 , start.y + lh ) ,
|
|
|
|
ImVec2( start.x + lx1 , start.y + ly1 ) ,
|
|
|
|
ImGui::GetColorU32( color ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::End( );
|
|
|
|
}
|
|
|
|
|
2017-12-24 16:02:17 +01:00
|
|
|
void T_Profiler::extendGPUQueries( ) noexcept
|
|
|
|
{
|
|
|
|
const auto iSize{ gpuQueries_.size( ) };
|
|
|
|
const auto iGrowth{ gpuQueries_.growth( ) };
|
|
|
|
gpuQueries_.resize( iSize + iGrowth , 0 );
|
|
|
|
glGenQueries( iGrowth , &gpuQueries_[ iSize ] );
|
|
|
|
}
|
|
|
|
|
|
|
|
void T_Profiler::addSample(
|
|
|
|
T_SamplesList_& list ,
|
|
|
|
const uint64_t duration
|
|
|
|
) noexcept
|
|
|
|
{
|
|
|
|
if ( list.size( ) == 0 || ( list.size( ) < History
|
|
|
|
&& list[ 0 ].nSamples == Samples ) ) {
|
|
|
|
list.insert( 0 , T_ProfilerSamples{ 0 , 0 } );
|
|
|
|
|
|
|
|
} else if ( list.size( ) == History && list[ 0 ].nSamples == Samples ) {
|
|
|
|
for ( auto i = 1u ; i < History ; i ++ ) {
|
|
|
|
list[ i ] = list[ i - 1 ];
|
|
|
|
}
|
|
|
|
list[ 0 ].sum = 0;
|
|
|
|
list[ 0 ].nSamples = 0;
|
|
|
|
}
|
|
|
|
list[ 0 ].sum += float( duration ) * 1e-6;
|
|
|
|
list[ 0 ].nSamples ++;
|
|
|
|
}
|
|
|
|
|
2017-10-01 12:48:55 +02:00
|
|
|
float T_Profiler::computeDuration(
|
2017-12-24 16:02:17 +01:00
|
|
|
T_SamplesList_ const& section
|
|
|
|
) noexcept
|
2017-10-01 11:37:04 +02:00
|
|
|
{
|
|
|
|
float total = 0;
|
|
|
|
float nSamples = 0;
|
2017-12-24 16:02:17 +01:00
|
|
|
const auto ns{ section.size( ) };
|
|
|
|
for ( auto i = 0u ; i < ns ; i ++ ) {
|
|
|
|
total += section[ i ].sum;
|
|
|
|
nSamples += section[ i ].nSamples;
|
2017-10-01 11:37:04 +02:00
|
|
|
}
|
|
|
|
return total / nSamples;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t T_Profiler::find(
|
2017-11-03 11:55:26 +01:00
|
|
|
T_String const& section ) const
|
2017-10-01 11:37:04 +02:00
|
|
|
{
|
|
|
|
const auto n( sections_.size( ) );
|
|
|
|
auto pos( 0u );
|
|
|
|
while ( pos < n && sections_[ pos ] != section ) {
|
|
|
|
pos ++;
|
|
|
|
}
|
|
|
|
return pos;
|
|
|
|
}
|