2017-09-14 19:28:40 +00:00
# include <algorithm>
2017-09-12 23:33:50 +00:00
# include <assert.h>
2017-10-21 11:32:51 +00:00
# include <chrono>
2017-09-22 20:11:30 +00:00
# include <inttypes.h>
2017-09-16 23:41:18 +00:00
# include <limits>
2017-10-06 00:19:25 +00:00
# include <math.h>
2017-11-15 20:49:41 +00:00
# include <mutex>
2018-03-13 15:23:10 +00:00
# include <stddef.h>
2017-09-18 23:24:31 +00:00
# include <stdlib.h>
2017-10-03 21:26:41 +00:00
# include <time.h>
2017-09-12 23:33:50 +00:00
# include "../common/TracySystem.hpp"
2017-12-08 22:11:08 +00:00
# include "tracy_pdqsort.h"
2018-04-21 22:52:33 +00:00
# include "TracyBadVersion.hpp"
# include "TracyFileRead.hpp"
2017-09-30 14:20:08 +00:00
# include "TracyFileWrite.hpp"
2017-09-17 22:18:36 +00:00
# include "TracyImGui.hpp"
2017-10-28 21:12:11 +00:00
# include "TracyPopcnt.hpp"
2017-09-12 23:33:50 +00:00
# include "TracyView.hpp"
2017-09-30 12:56:09 +00:00
# ifdef TRACY_FILESELECTOR
# include ".. / nfd / nfd.h"
# endif
2017-09-12 23:33:50 +00:00
namespace tracy
{
2017-10-22 15:47:40 +00:00
static const char * TimeToString ( int64_t ns )
{
enum { Pool = 8 } ;
static char bufpool [ Pool ] [ 64 ] ;
static int bufsel = 0 ;
char * buf = bufpool [ bufsel ] ;
bufsel = ( bufsel + 1 ) % Pool ;
const char * sign = " " ;
if ( ns < 0 )
2017-12-17 17:44:31 +00:00
{
2017-10-22 15:47:40 +00:00
sign = " - " ;
ns = - ns ;
2017-12-17 17:44:31 +00:00
}
2017-10-22 15:47:40 +00:00
if ( ns < 1000 )
2017-12-17 17:44:31 +00:00
{
2017-10-28 19:50:06 +00:00
sprintf ( buf , " %s% " PRIi64 " ns " , sign , ns ) ;
2017-12-17 17:44:31 +00:00
}
2017-10-28 19:50:06 +00:00
else if ( ns < 1000ll * 1000 )
2017-12-17 17:44:31 +00:00
{
2017-10-22 15:47:40 +00:00
sprintf ( buf , " %s%.2f us " , sign , ns / 1000. ) ;
2017-12-17 17:44:31 +00:00
}
2017-10-28 19:50:06 +00:00
else if ( ns < 1000ll * 1000 * 1000 )
2017-10-13 01:36:59 +00:00
{
2017-10-22 15:47:40 +00:00
sprintf ( buf , " %s%.2f ms " , sign , ns / ( 1000. * 1000. ) ) ;
2017-10-13 01:36:59 +00:00
}
2017-10-28 19:50:06 +00:00
else if ( ns < 1000ll * 1000 * 1000 * 60 )
2017-11-20 01:14:18 +00:00
{
2017-10-22 15:47:40 +00:00
sprintf ( buf , " %s%.2f s " , sign , ns / ( 1000. * 1000. * 1000. ) ) ;
2017-11-20 01:14:18 +00:00
}
2018-04-21 15:01:10 +00:00
else if ( ns < 1000ll * 1000 * 1000 * 60 * 60 )
2017-10-13 01:36:59 +00:00
{
2017-10-28 19:50:06 +00:00
const auto m = int64_t ( ns / ( 1000ll * 1000 * 1000 * 60 ) ) ;
const auto s = int64_t ( ns - m * ( 1000ll * 1000 * 1000 * 60 ) ) ;
sprintf ( buf , " %s% " PRIi64 " :%04.1f " , sign , m , s / ( 1000. * 1000. * 1000. ) ) ;
2017-10-13 01:36:59 +00:00
}
2018-04-21 15:01:10 +00:00
else
{
const auto h = int64_t ( ns / ( 1000ll * 1000 * 1000 * 60 * 60 ) ) ;
const auto m = int64_t ( ns / ( 1000ll * 1000 * 1000 * 60 ) - h * 60 ) ;
const auto s = int64_t ( ns - h * ( 1000ll * 1000 * 1000 * 60 * 60 ) - m * ( 1000ll * 1000 * 1000 * 60 ) ) ;
sprintf ( buf , " %s% " PRIi64 " :%02 " PRIi64 " :%02 " PRIi64 , sign , h , m , int64_t ( s / ( 1000ll * 1000 * 1000 ) ) ) ;
}
2017-10-22 15:47:40 +00:00
return buf ;
2017-10-13 01:36:59 +00:00
}
2018-02-28 14:38:32 +00:00
static const char * TimeToStringInteger ( int64_t ns )
{
enum { Pool = 8 } ;
static char bufpool [ Pool ] [ 64 ] ;
static int bufsel = 0 ;
char * buf = bufpool [ bufsel ] ;
bufsel = ( bufsel + 1 ) % Pool ;
const char * sign = " " ;
if ( ns < 0 )
{
sign = " - " ;
ns = - ns ;
}
if ( ns < 1000 )
{
sprintf ( buf , " %s% " PRIi64 " ns " , sign , ns ) ;
}
else if ( ns < 1000ll * 1000 )
{
sprintf ( buf , " %s%.0f us " , sign , ns / 1000. ) ;
}
else if ( ns < 1000ll * 1000 * 1000 )
{
sprintf ( buf , " %s%.0f ms " , sign , ns / ( 1000. * 1000. ) ) ;
}
else if ( ns < 1000ll * 1000 * 1000 * 60 )
{
sprintf ( buf , " %s%.0f s " , sign , ns / ( 1000. * 1000. * 1000. ) ) ;
}
else
{
const auto m = int64_t ( ns / ( 1000ll * 1000 * 1000 * 60 ) ) ;
const auto s = int64_t ( ns - m * ( 1000ll * 1000 * 1000 * 60 ) ) ;
sprintf ( buf , " %s% " PRIi64 " :%02.0f " , sign , m , s / ( 1000. * 1000. * 1000. ) ) ;
}
return buf ;
}
2017-10-22 15:47:40 +00:00
static const char * RealToString ( double val , bool separator )
2017-10-13 01:36:59 +00:00
{
2017-10-22 15:47:40 +00:00
enum { Pool = 8 } ;
static char bufpool [ Pool ] [ 64 ] ;
static int bufsel = 0 ;
char * buf = bufpool [ bufsel ] ;
bufsel = ( bufsel + 1 ) % Pool ;
2017-10-13 01:36:59 +00:00
2017-10-22 15:47:40 +00:00
sprintf ( buf , " %f " , val ) ;
auto ptr = buf ;
if ( * ptr = = ' - ' ) ptr + + ;
2017-11-10 18:41:37 +00:00
2017-10-22 15:47:40 +00:00
const auto vbegin = ptr ;
if ( separator )
2017-10-13 01:36:59 +00:00
{
2017-10-22 15:47:40 +00:00
while ( * ptr ! = ' \0 ' & & * ptr ! = ' , ' & & * ptr ! = ' . ' ) ptr + + ;
auto end = ptr ;
while ( * end ! = ' \0 ' ) end + + ;
auto sz = end - ptr ;
while ( ptr - vbegin > 3 )
2017-10-13 01:36:59 +00:00
{
2017-10-22 15:47:40 +00:00
ptr - = 3 ;
memmove ( ptr + 1 , ptr , sz ) ;
* ptr = ' , ' ;
sz + = 4 ;
2017-10-13 01:36:59 +00:00
}
2017-10-19 21:26:21 +00:00
}
2017-10-22 15:47:40 +00:00
while ( * ptr ! = ' \0 ' & & * ptr ! = ' , ' & & * ptr ! = ' . ' ) ptr + + ;
2017-09-18 19:26:22 +00:00
2017-10-22 15:47:40 +00:00
if ( * ptr = = ' \0 ' ) return buf ;
while ( * ptr ! = ' \0 ' ) ptr + + ;
ptr - - ;
while ( * ptr = = ' 0 ' & & * ptr ! = ' , ' & & * ptr ! = ' . ' ) ptr - - ;
if ( * ptr ! = ' . ' & & * ptr ! = ' , ' ) ptr + + ;
* ptr = ' \0 ' ;
return buf ;
2017-09-20 20:34:56 +00:00
}
2018-06-05 23:53:41 +00:00
tracy_force_inline float frexpf_fast ( float f , int & power )
{
float ret ;
int32_t fl ;
memcpy ( & fl , & f , 4 ) ;
power = ( fl > > 23 ) & 0x000000ff ;
power - = 0x7e ;
fl & = 0x807fffff ;
fl | = 0x3f000000 ;
memcpy ( & ret , & fl , 4 ) ;
return ret ;
}
2018-05-04 15:38:04 +00:00
tracy_force_inline float log2fast ( float x )
{
int e ;
2018-06-05 23:53:41 +00:00
auto f = frexpf_fast ( fabsf ( x ) , e ) ;
2018-05-04 15:53:46 +00:00
auto t0 = 1.23149591368684f * f - 4.11852516267426f ;
auto t1 = t0 * f + 6.02197014179219f ;
auto t2 = t1 * f - 3.13396450166353f ;
return t2 + e ;
2018-05-04 15:38:04 +00:00
}
tracy_force_inline float log10fast ( float x )
{
2018-06-05 23:52:46 +00:00
return log2fast ( x ) * 0.301029995663981195213738894724493026768189881462108541310f ; // 1/log2(10)
2018-05-04 15:38:04 +00:00
}
2017-09-18 00:22:59 +00:00
2017-10-06 16:25:30 +00:00
enum { MinVisSize = 3 } ;
2017-09-23 13:39:39 +00:00
2017-09-12 23:33:50 +00:00
static View * s_instance = nullptr ;
2017-11-11 21:56:05 +00:00
2017-09-12 23:33:50 +00:00
View : : View ( const char * addr )
2018-02-13 13:57:47 +00:00
: m_worker ( addr )
2017-09-30 14:58:02 +00:00
, m_staticView ( false )
2017-09-18 00:37:25 +00:00
, m_frameScale ( 0 )
2017-09-18 22:26:40 +00:00
, m_pause ( false )
, m_frameStart ( 0 )
2017-09-20 19:21:21 +00:00
, m_zvStart ( 0 )
, m_zvEnd ( 0 )
2017-10-12 20:27:17 +00:00
, m_zvHeight ( 0 )
, m_zvScroll ( 0 )
2017-09-29 19:49:14 +00:00
, m_zoneInfoWindow ( nullptr )
2017-10-08 21:03:38 +00:00
, m_lockHighlight { - 1 }
2017-11-12 00:25:44 +00:00
, m_gpuInfoWindow ( nullptr )
2017-11-15 23:33:10 +00:00
, m_gpuThread ( 0 )
, m_gpuStart ( 0 )
, m_gpuEnd ( 0 )
2017-10-13 11:32:23 +00:00
, m_showOptions ( false )
2017-10-14 12:36:30 +00:00
, m_showMessages ( false )
2018-03-24 13:40:48 +00:00
, m_showStatistics ( false )
2017-11-11 21:56:05 +00:00
, m_drawGpuZones ( true )
2017-10-13 11:32:23 +00:00
, m_drawZones ( true )
, m_drawLocks ( true )
2017-10-13 12:54:32 +00:00
, m_drawPlots ( true )
2017-10-22 11:32:27 +00:00
, m_onlyContendedLocks ( false )
2018-06-05 22:47:11 +00:00
, m_statSort ( 0 )
2018-06-05 22:47:16 +00:00
, m_statSelf ( false )
2017-10-22 11:56:05 +00:00
, m_namespace ( Namespace : : Full )
2017-09-21 00:10:20 +00:00
{
2017-09-12 23:33:50 +00:00
assert ( s_instance = = nullptr ) ;
s_instance = this ;
2017-09-21 00:10:20 +00:00
2017-09-19 22:46:30 +00:00
ImGuiStyle & style = ImGui : : GetStyle ( ) ;
style . FrameRounding = 2.f ;
2017-11-11 00:39:34 +00:00
}
2018-02-13 13:57:47 +00:00
View : : View ( FileRead & f )
: m_worker ( f )
, m_staticView ( true )
, m_frameScale ( 0 )
, m_pause ( false )
, m_frameStart ( 0 )
, m_zvStart ( 0 )
, m_zvEnd ( 0 )
, m_zvHeight ( 0 )
, m_zvScroll ( 0 )
, m_zoneInfoWindow ( nullptr )
, m_gpuInfoWindow ( nullptr )
, m_gpuThread ( 0 )
, m_gpuStart ( 0 )
, m_gpuEnd ( 0 )
, m_showOptions ( false )
, m_showMessages ( false )
2018-04-01 18:27:56 +00:00
, m_showStatistics ( false )
2018-02-13 13:57:47 +00:00
, m_drawGpuZones ( true )
, m_drawZones ( true )
, m_drawLocks ( true )
, m_drawPlots ( true )
, m_onlyContendedLocks ( false )
2018-03-24 16:28:10 +00:00
, m_statSort ( 0 )
2018-06-05 22:47:16 +00:00
, m_statSelf ( false )
2018-02-13 13:57:47 +00:00
, m_namespace ( Namespace : : Full )
2017-11-14 22:37:44 +00:00
{
2018-02-13 13:57:47 +00:00
assert ( s_instance = = nullptr ) ;
s_instance = this ;
2017-11-14 22:37:44 +00:00
}
2018-02-13 13:57:47 +00:00
View : : ~ View ( )
2017-09-21 23:30:57 +00:00
{
2018-02-13 13:57:47 +00:00
m_worker . Shutdown ( ) ;
2017-09-21 23:30:57 +00:00
2018-02-13 13:57:47 +00:00
assert ( s_instance ! = nullptr ) ;
s_instance = nullptr ;
2017-09-26 16:54:48 +00:00
}
2017-10-22 11:56:05 +00:00
const char * View : : ShortenNamespace ( const char * name ) const
{
if ( m_namespace = = Namespace : : Full ) return name ;
if ( m_namespace = = Namespace : : Short )
{
auto ptr = name ;
while ( * ptr ! = ' \0 ' ) ptr + + ;
while ( ptr > name & & * ptr ! = ' : ' ) ptr - - ;
if ( * ptr = = ' : ' ) ptr + + ;
return ptr ;
}
static char buf [ 1024 ] ;
auto dst = buf ;
auto ptr = name ;
for ( ; ; )
{
auto start = ptr ;
while ( * ptr ! = ' \0 ' & & * ptr ! = ' : ' ) ptr + + ;
if ( * ptr = = ' \0 ' )
{
memcpy ( dst , start , ptr - start + 1 ) ;
return buf ;
}
* dst + + = * start ;
* dst + + = ' : ' ;
while ( * ptr = = ' : ' ) ptr + + ;
}
}
2018-01-17 11:49:50 +00:00
void View : : DrawHelpMarker ( const char * desc ) const
{
ImGui : : TextDisabled ( " (?) " ) ;
2018-03-24 13:42:48 +00:00
if ( ImGui : : IsItemHovered ( ) )
2018-01-17 11:49:50 +00:00
{
ImGui : : BeginTooltip ( ) ;
ImGui : : PushTextWrapPos ( 450.0f ) ;
ImGui : : TextUnformatted ( desc ) ;
ImGui : : PopTextWrapPos ( ) ;
ImGui : : EndTooltip ( ) ;
}
}
2017-11-25 14:45:16 +00:00
void View : : DrawTextContrast ( ImDrawList * draw , const ImVec2 & pos , uint32_t color , const char * text )
{
draw - > AddText ( pos + ImVec2 ( 1 , 1 ) , 0x88000000 , text ) ;
draw - > AddText ( pos , color , text ) ;
}
2018-04-29 23:16:08 +00:00
bool View : : Draw ( )
2017-09-15 00:30:22 +00:00
{
2018-04-29 23:16:08 +00:00
return s_instance - > DrawImpl ( ) ;
2017-09-15 00:30:22 +00:00
}
2018-04-21 20:42:32 +00:00
static const char * MainWindowButtons [ ] = {
" Resume " ,
" Pause "
} ;
enum { MainWindowButtonsCount = sizeof ( MainWindowButtons ) / sizeof ( * MainWindowButtons ) } ;
2018-04-29 23:16:08 +00:00
bool View : : DrawImpl ( )
2017-09-15 00:30:22 +00:00
{
2018-02-13 13:57:47 +00:00
if ( ! m_worker . HasData ( ) )
2017-09-20 18:38:12 +00:00
{
2018-02-13 13:57:47 +00:00
ImGui : : Begin ( m_worker . GetAddr ( ) . c_str ( ) , nullptr , ImGuiWindowFlags_AlwaysAutoResize ) ;
2017-09-20 18:38:12 +00:00
ImGui : : Text ( " Waiting for connection... " ) ;
ImGui : : End ( ) ;
2018-04-29 23:16:08 +00:00
return true ;
2017-09-30 14:58:02 +00:00
}
2017-09-30 12:37:21 +00:00
2018-03-24 22:43:51 +00:00
const auto th = ImGui : : GetTextLineHeight ( ) ;
2018-04-21 20:42:32 +00:00
float bw = 0 ;
for ( int i = 0 ; i < MainWindowButtonsCount ; i + + )
{
bw = std : : max ( bw , ImGui : : CalcTextSize ( MainWindowButtons [ i ] ) . x ) ;
}
bw + = th ;
2018-03-24 22:43:51 +00:00
2018-04-29 23:16:08 +00:00
bool keepOpen = true ;
bool * keepOpenPtr = nullptr ;
if ( ! m_staticView )
{
DrawConnection ( ) ;
}
else
{
keepOpenPtr = & keepOpen ;
}
2018-05-07 23:25:16 +00:00
std : : lock_guard lock ( m_worker . GetDataLock ( ) ) ;
2018-04-29 23:16:08 +00:00
ImGui : : Begin ( m_worker . GetCaptureName ( ) . c_str ( ) , keepOpenPtr , ImVec2 ( 1550 , 800 ) , - 1 , ImGuiWindowFlags_NoScrollbar ) ;
2018-03-24 13:45:01 +00:00
if ( ! m_worker . IsDataStatic ( ) )
{
2018-04-21 20:42:32 +00:00
if ( ImGui : : Button ( m_pause ? MainWindowButtons [ 0 ] : MainWindowButtons [ 1 ] , ImVec2 ( bw , 0 ) ) ) m_pause = ! m_pause ;
2018-03-24 13:45:01 +00:00
ImGui : : SameLine ( ) ;
}
2018-04-21 20:42:32 +00:00
if ( ImGui : : Button ( " Options " ) ) m_showOptions = true ;
2017-09-30 12:37:21 +00:00
ImGui : : SameLine ( ) ;
2018-04-21 20:42:32 +00:00
if ( ImGui : : Button ( " Messages " ) ) m_showMessages = true ;
2017-10-14 12:36:30 +00:00
ImGui : : SameLine ( ) ;
2018-04-21 20:42:32 +00:00
if ( ImGui : : Button ( " Find Zone " ) ) m_findZone . show = true ;
2018-03-24 13:40:48 +00:00
ImGui : : SameLine ( ) ;
2018-04-21 20:42:32 +00:00
if ( ImGui : : Button ( " Statistics " ) ) m_showStatistics = true ;
2018-01-17 11:49:50 +00:00
ImGui : : SameLine ( ) ;
2018-04-21 20:42:32 +00:00
if ( ImGui : : Button ( " Memory " ) ) m_memInfo . show = true ;
2018-04-01 18:34:21 +00:00
ImGui : : SameLine ( ) ;
2018-04-21 22:52:33 +00:00
if ( ImGui : : Button ( " Compare " ) ) m_compare . show = true ;
ImGui : : SameLine ( ) ;
2018-06-02 20:27:35 +00:00
if ( ImGui : : SmallButton ( " < " ) ) ZoomToPrevFrame ( ) ;
ImGui : : SameLine ( ) ;
ImGui : : Text ( " Frames: % " PRIu64 , m_worker . GetFrameCount ( ) ) ;
ImGui : : SameLine ( ) ;
if ( ImGui : : SmallButton ( " > " ) ) ZoomToNextFrame ( ) ;
ImGui : : SameLine ( ) ;
ImGui : : Text ( " Time span: %-10s View span: %-10s Zones: %-13s Queue delay: %s Timer resolution: %s " , TimeToString ( m_worker . GetLastTime ( ) - m_worker . GetFrameBegin ( 0 ) ) , TimeToString ( m_zvEnd - m_zvStart ) , RealToString ( m_worker . GetZoneCount ( ) , true ) , TimeToString ( m_worker . GetDelay ( ) ) , TimeToString ( m_worker . GetResolution ( ) ) ) ;
2017-09-30 12:37:21 +00:00
DrawFrames ( ) ;
DrawZones ( ) ;
ImGui : : End ( ) ;
m_zoneHighlight = nullptr ;
2017-11-12 00:28:07 +00:00
m_gpuHighlight = nullptr ;
2017-11-12 00:25:44 +00:00
DrawInfoWindow ( ) ;
2017-11-12 00:28:07 +00:00
2017-10-13 11:32:23 +00:00
if ( m_showOptions ) DrawOptions ( ) ;
2017-10-14 12:36:30 +00:00
if ( m_showMessages ) DrawMessages ( ) ;
2018-01-17 11:49:50 +00:00
if ( m_findZone . show ) DrawFindZone ( ) ;
2018-03-24 13:40:48 +00:00
if ( m_showStatistics ) DrawStatistics ( ) ;
2018-04-01 19:24:30 +00:00
if ( m_memInfo . show ) DrawMemory ( ) ;
2018-04-21 22:52:33 +00:00
if ( m_compare . show ) DrawCompare ( ) ;
2017-09-30 12:37:21 +00:00
2017-11-27 21:41:30 +00:00
if ( m_zoomAnim . active )
2017-09-30 12:37:21 +00:00
{
2017-11-27 21:41:30 +00:00
const auto & io = ImGui : : GetIO ( ) ;
m_zoomAnim . progress + = io . DeltaTime * m_zoomAnim . lenMod ;
if ( m_zoomAnim . progress > = 1.f )
{
m_zoomAnim . active = false ;
m_zvStart = m_zoomAnim . start1 ;
m_zvEnd = m_zoomAnim . end1 ;
}
else
{
const auto v = sqrt ( sin ( M_PI_2 * m_zoomAnim . progress ) ) ;
m_zvStart = int64_t ( m_zoomAnim . start0 + ( m_zoomAnim . start1 - m_zoomAnim . start0 ) * v ) ;
m_zvEnd = int64_t ( m_zoomAnim . end0 + ( m_zoomAnim . end1 - m_zoomAnim . end0 ) * v ) ;
}
2017-09-30 12:37:21 +00:00
}
2018-04-29 23:16:08 +00:00
return keepOpen ;
2017-09-30 12:37:21 +00:00
}
void View : : DrawConnection ( )
{
2017-10-18 21:25:35 +00:00
const auto ty = ImGui : : GetFontSize ( ) ;
const auto cs = ty * 0.9f ;
2017-09-15 00:30:22 +00:00
{
2018-05-07 23:25:16 +00:00
std : : lock_guard lock ( m_worker . GetMbpsDataLock ( ) ) ;
2018-02-13 13:57:47 +00:00
ImGui : : Begin ( m_worker . GetAddr ( ) . c_str ( ) , nullptr , ImGuiWindowFlags_AlwaysAutoResize ) ;
const auto & mbpsVector = m_worker . GetMbpsData ( ) ;
const auto mbps = mbpsVector . back ( ) ;
2017-09-15 00:30:22 +00:00
char buf [ 64 ] ;
if ( mbps < 0.1f )
{
2017-09-16 23:41:18 +00:00
sprintf ( buf , " %6.2f Kbps " , mbps * 1000.f ) ;
2017-09-15 00:30:22 +00:00
}
else
{
2017-09-16 23:41:18 +00:00
sprintf ( buf , " %6.2f Mbps " , mbps ) ;
2017-09-15 00:30:22 +00:00
}
2017-10-18 21:25:35 +00:00
ImGui : : Dummy ( ImVec2 ( cs , 0 ) ) ;
2017-09-17 22:31:38 +00:00
ImGui : : SameLine ( ) ;
2018-02-13 13:57:47 +00:00
ImGui : : PlotLines ( buf , mbpsVector . data ( ) , mbpsVector . size ( ) , 0 , nullptr , 0 , std : : numeric_limits < float > : : max ( ) , ImVec2 ( 150 , 0 ) ) ;
ImGui : : Text ( " Ratio %.1f%% Real: %6.2f Mbps " , m_worker . GetCompRatio ( ) * 100.f , mbps / m_worker . GetCompRatio ( ) ) ;
2017-09-15 00:30:22 +00:00
}
2017-09-15 18:31:59 +00:00
2017-09-16 23:22:46 +00:00
ImGui : : Text ( " Memory usage: %.2f MB " , memUsage . load ( std : : memory_order_relaxed ) / ( 1024.f * 1024.f ) ) ;
2017-09-17 22:31:38 +00:00
const auto wpos = ImGui : : GetWindowPos ( ) + ImGui : : GetWindowContentRegionMin ( ) ;
2018-02-13 13:57:47 +00:00
ImGui : : GetWindowDrawList ( ) - > AddCircleFilled ( wpos + ImVec2 ( 1 + cs * 0.5 , 3 + ty * 0.5 ) , cs * 0.5 , m_worker . IsConnected ( ) ? 0xFF2222CC : 0xFF444444 , 10 ) ;
2017-09-17 22:31:38 +00:00
2018-05-07 23:25:16 +00:00
std : : lock_guard lock ( m_worker . GetDataLock ( ) ) ;
2017-09-15 22:57:50 +00:00
{
2018-02-13 13:57:47 +00:00
const auto sz = m_worker . GetFrameCount ( ) ;
2017-09-15 22:57:50 +00:00
if ( sz > 1 )
{
2018-02-13 13:57:47 +00:00
const auto dt = m_worker . GetFrameTime ( sz - 2 ) ;
2017-09-15 22:57:50 +00:00
const auto dtm = dt / 1000000.f ;
const auto fps = 1000.f / dtm ;
2017-09-16 23:41:18 +00:00
ImGui : : Text ( " FPS: %6.1f Frame time: %.2f ms " , fps , dtm ) ;
2017-09-15 22:57:50 +00:00
}
}
2017-09-18 00:37:25 +00:00
2017-09-30 12:56:09 +00:00
if ( ImGui : : Button ( " Save trace " ) )
{
# ifdef TRACY_FILESELECTOR
nfdchar_t * fn ;
auto res = NFD_SaveDialog ( " tracy " , nullptr , & fn ) ;
if ( res = = NFD_OKAY )
# else
const char * fn = " trace.tracy " ;
# endif
{
2017-10-12 20:38:11 +00:00
std : : unique_ptr < FileWrite > f ;
const auto sz = strlen ( fn ) ;
if ( sz < 7 | | memcmp ( fn + sz - 6 , " .tracy " , 6 ) ! = 0 )
{
char tmp [ 1024 ] ;
sprintf ( tmp , " %s.tracy " , fn ) ;
f . reset ( FileWrite : : Open ( tmp ) ) ;
}
else
{
f . reset ( FileWrite : : Open ( fn ) ) ;
}
2017-09-30 14:20:08 +00:00
if ( f )
{
2018-02-13 13:57:47 +00:00
m_worker . Write ( * f ) ;
2017-09-30 14:20:08 +00:00
}
2017-09-30 12:56:09 +00:00
}
}
2017-09-18 00:37:25 +00:00
ImGui : : End ( ) ;
}
static ImU32 GetFrameColor ( uint64_t frameTime )
{
enum { BestTime = 1000 * 1000 * 1000 / 143 } ;
enum { GoodTime = 1000 * 1000 * 1000 / 59 } ;
enum { BadTime = 1000 * 1000 * 1000 / 29 } ;
2017-09-18 17:03:29 +00:00
return frameTime > BadTime ? 0xFF2222DD :
frameTime > GoodTime ? 0xFF22DDDD :
frameTime > BestTime ? 0xFF22DD22 : 0xFFDD9900 ;
2017-09-18 00:37:25 +00:00
}
2017-09-19 22:05:45 +00:00
static int GetFrameWidth ( int frameScale )
{
2018-04-14 14:50:04 +00:00
return frameScale = = 0 ? 4 : ( frameScale < 0 ? 6 : 1 ) ;
2017-09-19 22:05:45 +00:00
}
static int GetFrameGroup ( int frameScale )
{
return frameScale < 2 ? 1 : ( 1 < < ( frameScale - 1 ) ) ;
}
2017-09-18 00:37:25 +00:00
void View : : DrawFrames ( )
{
2018-02-13 13:57:47 +00:00
assert ( m_worker . GetFrameCount ( ) ! = 0 ) ;
2017-09-20 19:21:21 +00:00
2017-09-18 00:37:25 +00:00
enum { Height = 40 } ;
enum { MaxFrameTime = 50 * 1000 * 1000 } ; // 50ms
ImGuiWindow * window = ImGui : : GetCurrentWindow ( ) ;
if ( window - > SkipItems ) return ;
2017-09-18 23:24:31 +00:00
auto & io = ImGui : : GetIO ( ) ;
2017-09-20 00:19:39 +00:00
const auto wpos = ImGui : : GetCursorScreenPos ( ) ;
2017-09-18 00:37:25 +00:00
const auto wspace = ImGui : : GetWindowContentRegionMax ( ) - ImGui : : GetWindowContentRegionMin ( ) ;
const auto w = wspace . x ;
auto draw = ImGui : : GetWindowDrawList ( ) ;
2017-09-20 00:19:39 +00:00
ImGui : : InvisibleButton ( " ##frames " , ImVec2 ( w , Height ) ) ;
bool hover = ImGui : : IsItemHovered ( ) ;
2017-09-18 00:37:25 +00:00
draw - > AddRectFilled ( wpos , wpos + ImVec2 ( w , Height ) , 0x33FFFFFF ) ;
2017-09-19 22:08:15 +00:00
const auto wheel = io . MouseWheel ;
const auto prevScale = m_frameScale ;
2017-09-18 20:12:39 +00:00
if ( hover )
2017-09-18 00:37:25 +00:00
{
if ( wheel > 0 )
{
2018-04-14 14:50:04 +00:00
if ( m_frameScale > = 0 ) m_frameScale - - ;
2017-09-18 00:37:25 +00:00
}
else if ( wheel < 0 )
{
if ( m_frameScale < 10 ) m_frameScale + + ;
}
}
2017-09-18 19:26:22 +00:00
2017-09-19 22:05:45 +00:00
const int fwidth = GetFrameWidth ( m_frameScale ) ;
const int group = GetFrameGroup ( m_frameScale ) ;
2018-02-13 13:57:47 +00:00
const int total = m_worker . GetFrameCount ( ) ;
2017-09-18 23:24:14 +00:00
const int onScreen = ( w - 2 ) / fwidth ;
2017-09-20 19:21:21 +00:00
if ( ! m_pause )
{
m_frameStart = ( total < onScreen * group ) ? 0 : total - onScreen * group ;
2018-02-13 13:57:47 +00:00
m_zvStart = m_worker . GetFrameBegin ( std : : max ( 0 , total - 4 ) ) ;
if ( total = = 1 )
2017-09-23 12:45:38 +00:00
{
2018-02-13 13:57:47 +00:00
m_zvEnd = m_worker . GetLastTime ( ) ;
2017-09-23 12:45:38 +00:00
}
else
{
2018-02-13 13:57:47 +00:00
m_zvEnd = m_worker . GetFrameBegin ( total - 1 ) ;
2017-09-23 12:45:38 +00:00
}
2017-09-20 19:21:21 +00:00
}
2017-09-18 19:26:22 +00:00
2017-09-19 19:10:31 +00:00
if ( hover )
2017-09-18 23:24:31 +00:00
{
2017-09-19 19:10:31 +00:00
if ( ImGui : : IsMouseDragging ( 1 , 0 ) )
{
m_pause = true ;
const auto delta = ImGui : : GetMouseDragDelta ( 1 , 0 ) . x ;
if ( abs ( delta ) > = fwidth )
{
const auto d = ( int ) delta / fwidth ;
m_frameStart = std : : max ( 0 , m_frameStart - d * group ) ;
io . MouseClickedPos [ 1 ] . x = io . MousePos . x + d * fwidth - delta ;
}
}
const auto mx = io . MousePos . x ;
if ( mx > wpos . x & & mx < wpos . x + w - 1 )
2017-09-18 23:24:31 +00:00
{
2017-09-19 19:10:31 +00:00
const auto mo = mx - ( wpos . x + 1 ) ;
const auto off = mo * group / fwidth ;
2017-09-19 22:08:15 +00:00
const int sel = m_frameStart + off ;
if ( sel < total )
{
2017-09-19 19:10:31 +00:00
ImGui : : BeginTooltip ( ) ;
if ( group > 1 )
{
2018-02-13 13:57:47 +00:00
auto f = m_worker . GetFrameTime ( sel ) ;
2017-09-19 19:10:31 +00:00
auto g = std : : min ( group , total - sel ) ;
for ( int j = 1 ; j < g ; j + + )
{
2018-02-13 13:57:47 +00:00
f = std : : max ( f , m_worker . GetFrameTime ( sel + j ) ) ;
2017-09-19 19:10:31 +00:00
}
ImGui : : Text ( " Frames: %i - %i (%i) " , sel , sel + g - 1 , g ) ;
2017-11-17 23:51:04 +00:00
ImGui : : Separator ( ) ;
2017-09-19 19:10:31 +00:00
ImGui : : Text ( " Max frame time: %s " , TimeToString ( f ) ) ;
}
else
{
2017-10-16 23:17:55 +00:00
if ( sel = = 0 )
{
2017-10-28 19:50:06 +00:00
ImGui : : Text ( " Tracy initialization " ) ;
2017-11-17 23:51:04 +00:00
ImGui : : Separator ( ) ;
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " Time: %s " , TimeToString ( m_worker . GetFrameTime ( sel ) ) ) ;
2017-10-16 23:17:55 +00:00
}
else
{
ImGui : : Text ( " Frame: %i " , sel ) ;
2017-11-17 23:51:04 +00:00
ImGui : : Separator ( ) ;
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " Frame time: %s " , TimeToString ( m_worker . GetFrameTime ( sel ) ) ) ;
2017-10-16 23:17:55 +00:00
}
2017-09-19 19:10:31 +00:00
}
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " Time from start of program: %s " , TimeToString ( m_worker . GetFrameBegin ( sel ) - m_worker . GetFrameBegin ( 0 ) ) ) ;
2017-09-19 19:10:31 +00:00
ImGui : : EndTooltip ( ) ;
2017-09-22 22:46:15 +00:00
if ( ImGui : : IsMouseClicked ( 0 ) )
{
m_pause = true ;
2018-02-13 13:57:47 +00:00
m_zvStart = m_worker . GetFrameBegin ( sel ) ;
m_zvEnd = m_worker . GetFrameEnd ( sel + group - 1 ) ;
2017-09-22 22:46:15 +00:00
if ( m_zvStart = = m_zvEnd ) m_zvStart - - ;
}
else if ( ImGui : : IsMouseDragging ( 0 ) )
{
2018-02-13 13:57:47 +00:00
m_zvStart = std : : min ( m_zvStart , m_worker . GetFrameBegin ( sel ) ) ;
m_zvEnd = std : : max ( m_zvEnd , m_worker . GetFrameEnd ( sel + group - 1 ) ) ;
2017-09-22 22:46:15 +00:00
}
2017-09-19 19:10:31 +00:00
}
2017-09-19 22:08:15 +00:00
if ( m_pause & & wheel ! = 0 )
{
const int pfwidth = GetFrameWidth ( prevScale ) ;
const int pgroup = GetFrameGroup ( prevScale ) ;
const auto oldoff = mo * pgroup / pfwidth ;
m_frameStart = std : : min ( total , std : : max ( 0 , m_frameStart - int ( off - oldoff ) ) ) ;
}
2017-09-18 23:24:31 +00:00
}
}
2017-09-18 19:32:26 +00:00
int i = 0 , idx = 0 ;
2017-09-18 22:26:40 +00:00
while ( i < onScreen & & m_frameStart + idx < total )
2017-09-18 00:37:25 +00:00
{
2018-02-13 13:57:47 +00:00
auto f = m_worker . GetFrameTime ( m_frameStart + idx ) ;
2017-09-18 20:12:39 +00:00
int g ;
2017-09-18 19:32:26 +00:00
if ( group > 1 )
{
2017-09-18 22:26:40 +00:00
g = std : : min ( group , total - ( m_frameStart + idx ) ) ;
2017-09-18 19:32:26 +00:00
for ( int j = 1 ; j < g ; j + + )
{
2018-02-13 13:57:47 +00:00
f = std : : max ( f , m_worker . GetFrameTime ( m_frameStart + idx + j ) ) ;
2017-09-18 19:32:26 +00:00
}
}
2017-09-18 00:37:25 +00:00
const auto h = float ( std : : min < uint64_t > ( MaxFrameTime , f ) ) / MaxFrameTime * ( Height - 2 ) ;
if ( fwidth ! = 1 )
{
2017-09-19 19:10:31 +00:00
draw - > AddRectFilled ( wpos + ImVec2 ( 1 + i * fwidth , Height - 1 - h ) , wpos + ImVec2 ( fwidth + i * fwidth , Height - 1 ) , GetFrameColor ( f ) ) ;
2017-09-18 00:37:25 +00:00
}
else
{
draw - > AddLine ( wpos + ImVec2 ( 1 + i , Height - 2 - h ) , wpos + ImVec2 ( 1 + i , Height - 2 ) , GetFrameColor ( f ) ) ;
}
2017-09-19 19:10:31 +00:00
2017-09-18 19:26:22 +00:00
i + + ;
2017-09-18 19:32:26 +00:00
idx + = group ;
2017-09-18 00:37:25 +00:00
}
2017-09-20 19:21:29 +00:00
2018-02-13 13:57:47 +00:00
const std : : pair < int , int > zrange = m_worker . GetFrameRange ( m_zvStart , m_zvEnd ) ;
2017-09-20 19:21:29 +00:00
2018-02-13 13:57:47 +00:00
if ( zrange . second > m_frameStart & & zrange . first < m_frameStart + onScreen * group )
2017-09-20 19:21:29 +00:00
{
2018-02-13 13:57:47 +00:00
auto x1 = std : : min ( onScreen * fwidth , ( zrange . second - m_frameStart ) * fwidth / group ) ;
auto x0 = std : : max ( 0 , ( zrange . first - m_frameStart ) * fwidth / group ) ;
2017-09-20 19:21:29 +00:00
if ( x0 = = x1 ) x1 = x0 + 1 ;
draw - > AddRectFilled ( wpos + ImVec2 ( 1 + x0 , 0 ) , wpos + ImVec2 ( 1 + x1 , Height ) , 0x55DD22DD ) ;
}
2017-09-15 00:30:22 +00:00
}
2017-10-12 20:27:17 +00:00
void View : : HandleZoneViewMouse ( int64_t timespan , const ImVec2 & wpos , float w , double & pxns )
2017-09-20 22:57:26 +00:00
{
2017-10-15 14:42:56 +00:00
assert ( timespan > 0 ) ;
2017-10-12 20:27:17 +00:00
auto & io = ImGui : : GetIO ( ) ;
2017-09-20 22:57:26 +00:00
2017-10-15 14:42:56 +00:00
const auto nspx = double ( timespan ) / w ;
if ( ImGui : : IsMouseClicked ( 0 ) )
{
2018-03-04 21:21:35 +00:00
m_highlight . active = true ;
m_highlight . start = m_highlight . end = m_zvStart + ( io . MousePos . x - wpos . x ) * nspx ;
2017-10-15 14:42:56 +00:00
}
else if ( ImGui : : IsMouseDragging ( 0 , 0 ) )
{
2018-03-04 21:21:35 +00:00
m_highlight . end = m_zvStart + ( io . MousePos . x - wpos . x ) * nspx ;
2017-10-15 14:42:56 +00:00
}
else
{
2018-03-04 21:21:35 +00:00
m_highlight . active = false ;
2017-10-15 14:42:56 +00:00
}
2017-10-12 20:27:17 +00:00
if ( ImGui : : IsMouseDragging ( 1 , 0 ) )
{
m_pause = true ;
2017-10-15 14:20:45 +00:00
const auto delta = ImGui : : GetMouseDragDelta ( 1 , 0 ) ;
const auto dpx = int64_t ( delta . x * nspx ) ;
2017-10-12 20:27:17 +00:00
if ( dpx ! = 0 )
{
m_zvStart - = dpx ;
m_zvEnd - = dpx ;
io . MouseClickedPos [ 1 ] . x = io . MousePos . x ;
}
2017-10-15 14:20:45 +00:00
if ( delta . y ! = 0 )
{
auto y = ImGui : : GetScrollY ( ) ;
ImGui : : SetScrollY ( y - delta . y ) ;
io . MouseClickedPos [ 1 ] . y = io . MousePos . y ;
}
2017-10-12 20:27:17 +00:00
}
2017-09-20 22:57:26 +00:00
2017-10-12 20:27:17 +00:00
const auto wheel = io . MouseWheel ;
if ( wheel ! = 0 )
{
m_pause = true ;
const double mouse = io . MousePos . x - wpos . x ;
const auto p = mouse / w ;
const auto p1 = timespan * p ;
const auto p2 = timespan - p1 ;
if ( wheel > 0 )
{
2017-11-06 00:04:49 +00:00
m_zvStart + = int64_t ( p1 * 0.25 ) ;
m_zvEnd - = int64_t ( p2 * 0.25 ) ;
2017-10-12 20:27:17 +00:00
}
2018-04-21 14:53:17 +00:00
else if ( timespan < 1000ll * 1000 * 1000 * 60 * 60 )
2017-10-12 20:27:17 +00:00
{
2017-11-06 00:04:49 +00:00
m_zvStart - = std : : max ( int64_t ( 1 ) , int64_t ( p1 * 0.25 ) ) ;
m_zvEnd + = std : : max ( int64_t ( 1 ) , int64_t ( p2 * 0.25 ) ) ;
2017-10-12 20:27:17 +00:00
}
timespan = m_zvEnd - m_zvStart ;
pxns = w / double ( timespan ) ;
}
}
2017-10-22 15:48:01 +00:00
static const char * GetFrameText ( int i , uint64_t ftime )
{
static char buf [ 128 ] ;
if ( i = = 0 )
{
sprintf ( buf , " Tracy init (%s) " , TimeToString ( ftime ) ) ;
}
else
{
sprintf ( buf , " Frame %i (%s) " , i , TimeToString ( ftime ) ) ;
}
return buf ;
}
2017-10-13 13:26:18 +00:00
bool View : : DrawZoneFrames ( )
2017-10-12 20:27:17 +00:00
{
2017-09-20 22:57:26 +00:00
const auto wpos = ImGui : : GetCursorScreenPos ( ) ;
2017-10-12 20:27:17 +00:00
const auto w = ImGui : : GetWindowContentRegionWidth ( ) - ImGui : : GetStyle ( ) . ScrollbarSize ;
const auto h = ImGui : : GetFontSize ( ) ;
const auto wh = ImGui : : GetContentRegionAvail ( ) . y ;
2017-09-20 22:57:26 +00:00
auto draw = ImGui : : GetWindowDrawList ( ) ;
2017-10-22 15:48:01 +00:00
const auto ty = ImGui : : GetFontSize ( ) ;
2017-11-26 01:18:17 +00:00
const auto fy = round ( h * 1.5 ) ;
2017-09-20 22:57:26 +00:00
2017-11-26 01:18:17 +00:00
ImGui : : InvisibleButton ( " ##zoneFrames " , ImVec2 ( w , h * 2.5 ) ) ;
2017-09-20 22:57:26 +00:00
bool hover = ImGui : : IsItemHovered ( ) ;
2017-09-20 23:39:07 +00:00
auto timespan = m_zvEnd - m_zvStart ;
auto pxns = w / double ( timespan ) ;
2017-09-20 22:57:26 +00:00
2017-10-12 20:27:17 +00:00
if ( hover ) HandleZoneViewMouse ( timespan , wpos , w , pxns ) ;
2017-09-20 23:13:23 +00:00
2017-11-26 01:18:17 +00:00
{
const auto nspx = 1.0 / pxns ;
const auto scale = std : : max ( 0.0 , round ( log10 ( nspx ) + 2 ) ) ;
const auto step = pow ( 10 , scale ) ;
const auto dx = step * pxns ;
double x = 0 ;
int tw = 0 ;
int tx = 0 ;
int64_t tt = 0 ;
while ( x < w )
{
draw - > AddLine ( wpos + ImVec2 ( x , 0 ) , wpos + ImVec2 ( x , round ( ty * 0.5 ) ) , 0x66FFFFFF ) ;
if ( tw = = 0 )
{
char buf [ 128 ] ;
2018-02-13 13:57:47 +00:00
const auto t = m_zvStart - m_worker . GetFrameBegin ( 0 ) ;
2017-11-26 01:24:13 +00:00
auto txt = TimeToString ( t ) ;
if ( t > = 0 )
{
sprintf ( buf , " +%s " , txt ) ;
txt = buf ;
}
draw - > AddText ( wpos + ImVec2 ( x , round ( ty * 0.5 ) ) , 0x66FFFFFF , txt ) ;
tw = ImGui : : CalcTextSize ( txt ) . x ;
2017-11-26 01:18:17 +00:00
}
else if ( x > tx + tw + ty * 2 )
{
tx = x ;
auto txt = TimeToString ( tt ) ;
draw - > AddText ( wpos + ImVec2 ( x , round ( ty * 0.5 ) ) , 0x66FFFFFF , txt ) ;
tw = ImGui : : CalcTextSize ( txt ) . x ;
}
for ( int i = 1 ; i < 5 ; i + + )
{
draw - > AddLine ( wpos + ImVec2 ( x + i * dx / 10 , 0 ) , wpos + ImVec2 ( x + i * dx / 10 , round ( ty * 0.25 ) ) , 0x33FFFFFF ) ;
}
draw - > AddLine ( wpos + ImVec2 ( x + 5 * dx / 10 , 0 ) , wpos + ImVec2 ( x + 5 * dx / 10 , round ( ty * 0.375 ) ) , 0x33FFFFFF ) ;
for ( int i = 6 ; i < 10 ; i + + )
{
draw - > AddLine ( wpos + ImVec2 ( x + i * dx / 10 , 0 ) , wpos + ImVec2 ( x + i * dx / 10 , round ( ty * 0.25 ) ) , 0x33FFFFFF ) ;
}
x + = dx ;
tt + = step ;
}
}
2018-02-13 13:57:47 +00:00
const std : : pair < int , int > zrange = m_worker . GetFrameRange ( m_zvStart , m_zvEnd ) ;
2018-04-14 14:50:04 +00:00
if ( zrange . first < 0 ) return hover ;
2017-09-20 22:57:26 +00:00
2018-02-13 13:57:47 +00:00
for ( int i = zrange . first ; i < zrange . second ; i + + )
2017-10-22 15:48:01 +00:00
{
2018-02-13 13:57:47 +00:00
const auto ftime = m_worker . GetFrameTime ( i ) ;
const auto fbegin = m_worker . GetFrameBegin ( i ) ;
const auto fend = m_worker . GetFrameEnd ( i ) ;
2017-10-22 15:48:01 +00:00
const auto fsz = pxns * ftime ;
2017-11-26 01:18:17 +00:00
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( ( fbegin - m_zvStart ) * pxns , fy ) , wpos + ImVec2 ( ( fend - m_zvStart ) * pxns , fy + ty ) ) )
2017-09-20 23:18:24 +00:00
{
2017-10-22 15:48:01 +00:00
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " %s " , GetFrameText ( i , ftime ) ) ;
2017-11-17 23:51:04 +00:00
ImGui : : Separator ( ) ;
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " Time from start of program: %s " , TimeToString ( m_worker . GetFrameBegin ( i ) - m_worker . GetFrameBegin ( 0 ) ) ) ;
2017-10-22 15:48:01 +00:00
ImGui : : EndTooltip ( ) ;
2017-09-20 23:18:24 +00:00
2017-10-22 15:48:01 +00:00
if ( ImGui : : IsMouseClicked ( 2 ) )
2017-10-16 23:17:55 +00:00
{
2017-11-27 21:12:26 +00:00
ZoomToRange ( fbegin , fend ) ;
2017-10-16 23:17:55 +00:00
}
2017-10-22 15:48:01 +00:00
}
if ( fsz < = 4 ) continue ;
if ( fbegin > = m_zvStart )
{
draw - > AddLine ( wpos + ImVec2 ( ( fbegin - m_zvStart ) * pxns , 0 ) , wpos + ImVec2 ( ( fbegin - m_zvStart ) * pxns , wh ) , 0x22FFFFFF ) ;
}
if ( fsz > = 5 )
{
auto buf = GetFrameText ( i , ftime ) ;
2017-10-28 19:55:01 +00:00
auto tx = ImGui : : CalcTextSize ( buf ) . x ;
2017-10-22 15:48:01 +00:00
uint32_t color = i = = 0 ? 0xFF4444FF : 0xFFFFFFFF ;
2017-10-28 19:55:01 +00:00
if ( fsz - 5 < = tx )
{
buf = TimeToString ( ftime ) ;
tx = ImGui : : CalcTextSize ( buf ) . x ;
}
2017-10-22 15:48:01 +00:00
if ( fbegin > = m_zvStart )
2017-10-16 23:17:55 +00:00
{
2017-11-26 01:18:17 +00:00
draw - > AddLine ( wpos + ImVec2 ( ( fbegin - m_zvStart ) * pxns + 2 , fy + 1 ) , wpos + ImVec2 ( ( fbegin - m_zvStart ) * pxns + 2 , fy + ty - 1 ) , color ) ;
2017-10-16 23:17:55 +00:00
}
2017-10-22 15:48:01 +00:00
if ( fend < = m_zvEnd )
2017-09-20 22:57:26 +00:00
{
2017-11-26 01:18:17 +00:00
draw - > AddLine ( wpos + ImVec2 ( ( fend - m_zvStart ) * pxns - 2 , fy + 1 ) , wpos + ImVec2 ( ( fend - m_zvStart ) * pxns - 2 , fy + ty - 1 ) , color ) ;
2017-09-20 22:57:26 +00:00
}
2017-10-22 15:48:01 +00:00
if ( fsz - 5 > tx )
2017-09-20 22:57:26 +00:00
{
2017-10-22 15:48:01 +00:00
const auto part = ( fsz - 5 - tx ) / 2 ;
2017-11-26 01:18:17 +00:00
draw - > AddLine ( wpos + ImVec2 ( std : : max ( - 10.0 , ( fbegin - m_zvStart ) * pxns + 2 ) , fy + round ( ty / 2 ) ) , wpos + ImVec2 ( std : : min ( w + 20.0 , ( fbegin - m_zvStart ) * pxns + part ) , fy + round ( ty / 2 ) ) , color ) ;
draw - > AddText ( wpos + ImVec2 ( ( fbegin - m_zvStart ) * pxns + 2 + part , fy ) , color , buf ) ;
draw - > AddLine ( wpos + ImVec2 ( std : : max ( - 10.0 , ( fbegin - m_zvStart ) * pxns + 2 + part + tx ) , fy + round ( ty / 2 ) ) , wpos + ImVec2 ( std : : min ( w + 20.0 , ( fend - m_zvStart ) * pxns - 2 ) , fy + round ( ty / 2 ) ) , color ) ;
2017-09-20 22:57:26 +00:00
}
2017-10-22 15:48:01 +00:00
else
2017-09-20 22:57:26 +00:00
{
2017-11-26 01:18:17 +00:00
draw - > AddLine ( wpos + ImVec2 ( std : : max ( - 10.0 , ( fbegin - m_zvStart ) * pxns + 2 ) , fy + round ( ty / 2 ) ) , wpos + ImVec2 ( std : : min ( w + 20.0 , ( fend - m_zvStart ) * pxns - 2 ) , fy + round ( ty / 2 ) ) , color ) ;
2017-09-20 22:57:26 +00:00
}
}
2017-10-22 15:48:01 +00:00
}
2017-09-20 22:57:26 +00:00
2018-02-13 13:57:47 +00:00
const auto fend = m_worker . GetFrameEnd ( zrange . second - 1 ) ;
2017-10-22 15:48:01 +00:00
if ( fend = = m_zvEnd )
{
draw - > AddLine ( wpos + ImVec2 ( ( fend - m_zvStart ) * pxns , 0 ) , wpos + ImVec2 ( ( fend - m_zvStart ) * pxns , wh ) , 0x22FFFFFF ) ;
2017-09-20 22:57:26 +00:00
}
2017-10-13 13:26:18 +00:00
return hover ;
2017-10-12 20:27:17 +00:00
}
void View : : DrawZones ( )
{
2017-10-14 13:47:06 +00:00
m_msgHighlight = nullptr ;
2017-10-12 20:27:17 +00:00
if ( m_zvStart = = m_zvEnd ) return ;
assert ( m_zvStart < m_zvEnd ) ;
ImGuiWindow * window = ImGui : : GetCurrentWindow ( ) ;
if ( window - > SkipItems ) return ;
2017-11-11 22:13:54 +00:00
m_gpuThread = 0 ;
m_gpuStart = 0 ;
m_gpuEnd = 0 ;
2017-10-13 13:26:18 +00:00
const auto linepos = ImGui : : GetCursorScreenPos ( ) ;
const auto lineh = ImGui : : GetContentRegionAvail ( ) . y ;
auto drawMouseLine = DrawZoneFrames ( ) ;
2017-10-12 20:27:17 +00:00
ImGui : : BeginChild ( " ##zoneWin " , ImVec2 ( ImGui : : GetWindowContentRegionWidth ( ) , ImGui : : GetContentRegionAvail ( ) . y ) , false , ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_NoScrollWithMouse ) ;
window = ImGui : : GetCurrentWindow ( ) ;
const auto wpos = ImGui : : GetCursorScreenPos ( ) ;
const auto w = ImGui : : GetWindowContentRegionWidth ( ) - 1 ;
const auto h = std : : max < float > ( m_zvHeight , ImGui : : GetContentRegionAvail ( ) . y - 4 ) ; // magic border value
auto draw = ImGui : : GetWindowDrawList ( ) ;
ImGui : : InvisibleButton ( " ##zones " , ImVec2 ( w , h ) ) ;
bool hover = ImGui : : IsItemHovered ( ) ;
2017-10-28 10:37:34 +00:00
const auto timespan = m_zvEnd - m_zvStart ;
2017-10-12 20:27:17 +00:00
auto pxns = w / double ( timespan ) ;
2017-10-13 13:26:18 +00:00
if ( hover )
{
drawMouseLine = true ;
HandleZoneViewMouse ( timespan , wpos , w , pxns ) ;
}
2017-09-21 00:16:01 +00:00
2017-10-28 10:37:34 +00:00
const auto nspx = 1.0 / pxns ;
2017-10-12 17:47:56 +00:00
const auto ty = ImGui : : GetFontSize ( ) ;
const auto ostep = ty + 1 ;
2017-10-12 20:27:17 +00:00
int offset = 0 ;
2017-10-12 17:47:56 +00:00
const auto to = 9.f ;
const auto th = ( ty - to ) * sqrt ( 3 ) * 0.5 ;
2017-11-11 21:56:05 +00:00
2018-04-20 20:45:29 +00:00
const auto yMin = linepos . y ;
const auto yMax = yMin + lineh ;
2017-11-11 21:56:05 +00:00
// gpu zones
if ( m_drawGpuZones )
{
2018-02-13 13:57:47 +00:00
for ( size_t i = 0 ; i < m_worker . GetGpuData ( ) . size ( ) ; i + + )
2017-11-11 21:56:05 +00:00
{
2018-02-13 13:57:47 +00:00
const auto & v = m_worker . GetGpuData ( ) [ i ] ;
if ( ! Visible ( v ) ) continue ;
bool & showFull = ShowFull ( v ) ;
2017-11-11 21:56:05 +00:00
2018-04-20 20:45:29 +00:00
const auto yPos = wpos . y + offset ;
if ( yPos + ostep > = yMin & & yPos < = yMax )
2017-11-11 21:56:05 +00:00
{
2018-04-20 20:45:29 +00:00
draw - > AddLine ( wpos + ImVec2 ( 0 , offset + ostep - 1 ) , wpos + ImVec2 ( w , offset + ostep - 1 ) , 0x33FFFFFF ) ;
if ( showFull )
2017-11-17 23:33:53 +00:00
{
2018-04-20 20:45:29 +00:00
draw - > AddTriangleFilled ( wpos + ImVec2 ( to / 2 , offset + to / 2 ) , wpos + ImVec2 ( ty - to / 2 , offset + to / 2 ) , wpos + ImVec2 ( ty * 0.5 , offset + to / 2 + th ) , 0xFFFFAAAA ) ;
2017-11-17 23:33:53 +00:00
}
2018-04-20 20:45:29 +00:00
else
{
draw - > AddTriangle ( wpos + ImVec2 ( to / 2 , offset + to / 2 ) , wpos + ImVec2 ( to / 2 , offset + ty - to / 2 ) , wpos + ImVec2 ( to / 2 + th , offset + ty * 0.5 ) , 0xFF886666 ) ;
}
2018-06-17 16:33:05 +00:00
const bool isVulkan = v - > thread = = 0 ;
2018-04-20 20:45:29 +00:00
char buf [ 64 ] ;
2018-06-17 16:33:05 +00:00
if ( isVulkan )
{
sprintf ( buf , " Vulkan context %zu " , i ) ;
}
else
{
sprintf ( buf , " OpenGL context %zu " , i ) ;
}
2018-04-20 20:45:29 +00:00
draw - > AddText ( wpos + ImVec2 ( ty , offset ) , showFull ? 0xFFFFAAAA : 0xFF886666 , buf ) ;
2017-11-17 23:33:53 +00:00
2018-04-20 20:45:29 +00:00
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( 0 , offset ) , wpos + ImVec2 ( ty + ImGui : : CalcTextSize ( buf ) . x , offset + ty ) ) )
2017-11-17 23:56:05 +00:00
{
2018-04-20 20:45:29 +00:00
if ( ImGui : : IsMouseClicked ( 0 ) )
2017-11-17 23:56:05 +00:00
{
2018-04-20 20:45:29 +00:00
showFull = ! showFull ;
2017-11-17 23:56:05 +00:00
}
2018-04-20 20:45:29 +00:00
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " %s " , buf ) ;
ImGui : : Separator ( ) ;
2018-06-17 16:33:05 +00:00
if ( ! isVulkan )
{
ImGui : : Text ( " Thread: %s " , m_worker . GetThreadString ( v - > thread ) ) ;
}
2018-04-20 20:45:29 +00:00
if ( ! v - > timeline . empty ( ) )
{
const auto t = v - > timeline . front ( ) - > gpuStart ;
if ( t ! = std : : numeric_limits < int64_t > : : max ( ) )
{
2018-06-17 16:37:38 +00:00
ImGui : : Text ( " Appeared at %s " , TimeToString ( t - m_worker . GetFrameBegin ( 0 ) ) ) ;
2018-04-20 20:45:29 +00:00
}
}
ImGui : : Text ( " Zone count: %s " , RealToString ( v - > count , true ) ) ;
ImGui : : Text ( " Top-level zones: %s " , RealToString ( v - > timeline . size ( ) , true ) ) ;
2018-06-17 16:33:05 +00:00
if ( isVulkan )
{
ImGui : : Text ( " Timestamp accuracy: %s " , TimeToString ( v - > period ) ) ;
}
else
{
ImGui : : Text ( " Query accuracy bits: %i " , v - > accuracyBits ) ;
}
2018-04-20 20:45:29 +00:00
ImGui : : EndTooltip ( ) ;
2017-11-17 23:56:05 +00:00
}
2017-11-11 21:56:05 +00:00
}
offset + = ostep ;
2018-02-13 13:57:47 +00:00
if ( showFull )
2017-11-11 21:56:05 +00:00
{
2018-04-20 21:28:19 +00:00
const auto depth = DispatchGpuZoneLevel ( v - > timeline , hover , pxns , wpos , offset , 0 , v - > thread , yMin , yMax ) ;
2017-11-11 21:56:05 +00:00
offset + = ostep * depth ;
}
offset + = ostep * 0.2f ;
}
}
// zones
LockHighlight nextLockHighlight { - 1 } ;
2018-02-13 13:57:47 +00:00
for ( const auto & v : m_worker . GetThreadData ( ) )
2017-09-21 00:16:01 +00:00
{
2018-02-13 13:57:47 +00:00
if ( ! Visible ( v ) ) continue ;
bool & showFull = ShowFull ( v ) ;
2017-10-14 13:03:28 +00:00
2018-04-20 20:45:29 +00:00
const auto yPos = wpos . y + offset ;
if ( yPos + ostep > = yMin & & yPos < = yMax )
{
draw - > AddLine ( wpos + ImVec2 ( 0 , offset + ostep - 1 ) , wpos + ImVec2 ( w , offset + ostep - 1 ) , 0x33FFFFFF ) ;
2017-10-14 13:03:28 +00:00
2018-04-20 20:45:29 +00:00
if ( showFull )
2017-10-14 13:03:28 +00:00
{
2018-04-20 20:45:29 +00:00
draw - > AddTriangleFilled ( wpos + ImVec2 ( to / 2 , offset + to / 2 ) , wpos + ImVec2 ( ty - to / 2 , offset + to / 2 ) , wpos + ImVec2 ( ty * 0.5 , offset + to / 2 + th ) , 0xFFFFFFFF ) ;
2017-10-28 10:37:34 +00:00
2018-04-20 20:45:29 +00:00
auto it = std : : lower_bound ( v - > messages . begin ( ) , v - > messages . end ( ) , m_zvStart , [ ] ( const auto & lhs , const auto & rhs ) { return lhs - > time < rhs ; } ) ;
auto end = std : : lower_bound ( it , v - > messages . end ( ) , m_zvEnd , [ ] ( const auto & lhs , const auto & rhs ) { return lhs - > time < rhs ; } ) ;
while ( it < end )
2017-10-14 13:03:28 +00:00
{
2018-04-20 20:45:29 +00:00
const auto next = std : : upper_bound ( it , v - > messages . end ( ) , ( * it ) - > time + MinVisSize * nspx , [ ] ( const auto & lhs , const auto & rhs ) { return lhs < rhs - > time ; } ) ;
const auto dist = std : : distance ( it , next ) ;
const auto px = ( ( * it ) - > time - m_zvStart ) * pxns ;
2017-10-28 10:37:34 +00:00
if ( dist > 1 )
{
2018-04-20 20:45:29 +00:00
draw - > AddTriangleFilled ( wpos + ImVec2 ( px - ( ty - to ) * 0.5 , offset + to ) , wpos + ImVec2 ( px + ( ty - to ) * 0.5 , offset + to ) , wpos + ImVec2 ( px , offset + to + th ) , 0xFFDDDDDD ) ;
2017-10-28 10:37:34 +00:00
}
2018-04-20 20:45:29 +00:00
draw - > AddTriangle ( wpos + ImVec2 ( px - ( ty - to ) * 0.5 , offset + to ) , wpos + ImVec2 ( px + ( ty - to ) * 0.5 , offset + to ) , wpos + ImVec2 ( px , offset + to + th ) , 0xFFDDDDDD ) ;
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( px - ( ty - to ) * 0.5 - 1 , offset ) , wpos + ImVec2 ( px + ( ty - to ) * 0.5 + 1 , offset + ty ) ) )
2017-10-28 10:37:34 +00:00
{
2018-04-20 20:45:29 +00:00
ImGui : : BeginTooltip ( ) ;
if ( dist > 1 )
{
ImGui : : Text ( " %i messages " , ( int ) dist ) ;
}
else
{
ImGui : : Text ( " %s " , TimeToString ( ( * it ) - > time - m_worker . GetFrameBegin ( 0 ) ) ) ;
ImGui : : Separator ( ) ;
ImGui : : Text ( " Message text: " ) ;
ImGui : : TextColored ( ImVec4 ( 0xCC / 255.f , 0xCC / 255.f , 0x22 / 255.f , 1.f ) , " %s " , m_worker . GetString ( ( * it ) - > ref ) ) ;
}
ImGui : : EndTooltip ( ) ;
m_msgHighlight = * it ;
2017-10-28 10:37:34 +00:00
}
2018-04-20 20:45:29 +00:00
it = next ;
2017-10-14 13:03:28 +00:00
}
}
2018-04-20 20:45:29 +00:00
else
2017-11-18 00:03:40 +00:00
{
2018-04-20 20:45:29 +00:00
draw - > AddTriangle ( wpos + ImVec2 ( to / 2 , offset + to / 2 ) , wpos + ImVec2 ( to / 2 , offset + ty - to / 2 ) , wpos + ImVec2 ( to / 2 + th , offset + ty * 0.5 ) , 0xFF888888 ) ;
2017-11-18 00:03:40 +00:00
}
2018-04-20 20:45:29 +00:00
const auto txt = m_worker . GetThreadString ( v - > id ) ;
const auto txtsz = ImGui : : CalcTextSize ( txt ) ;
if ( m_gpuThread = = v - > id )
2017-11-18 00:03:40 +00:00
{
2018-04-20 20:45:29 +00:00
draw - > AddRectFilled ( wpos + ImVec2 ( 0 , offset ) , wpos + ImVec2 ( ty + txtsz . x + 4 , offset + ty ) , 0x448888DD ) ;
draw - > AddRect ( wpos + ImVec2 ( 0 , offset ) , wpos + ImVec2 ( ty + txtsz . x + 4 , offset + ty ) , 0x888888DD ) ;
2017-11-18 00:03:40 +00:00
}
2018-04-20 20:45:29 +00:00
if ( m_gpuInfoWindow & & m_gpuInfoWindowThread = = v - > id )
{
draw - > AddRectFilled ( wpos + ImVec2 ( 0 , offset ) , wpos + ImVec2 ( ty + txtsz . x + 4 , offset + ty ) , 0x4488DD88 ) ;
draw - > AddRect ( wpos + ImVec2 ( 0 , offset ) , wpos + ImVec2 ( ty + txtsz . x + 4 , offset + ty ) , 0x8888DD88 ) ;
}
draw - > AddText ( wpos + ImVec2 ( ty , offset ) , showFull ? 0xFFFFFFFF : 0xFF888888 , txt ) ;
2017-11-18 00:03:40 +00:00
2018-04-20 20:45:29 +00:00
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( 0 , offset ) , wpos + ImVec2 ( ty + txtsz . x , offset + ty ) ) )
{
if ( ImGui : : IsMouseClicked ( 0 ) )
{
showFull = ! showFull ;
}
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " %s " , m_worker . GetThreadString ( v - > id ) ) ;
if ( ! v - > timeline . empty ( ) )
{
ImGui : : Separator ( ) ;
ImGui : : Text ( " Appeared at %s " , TimeToString ( v - > timeline . front ( ) - > start - m_worker . GetFrameBegin ( 0 ) ) ) ;
ImGui : : Text ( " Zone count: %s " , RealToString ( v - > count , true ) ) ;
ImGui : : Text ( " Top-level zones: %s " , RealToString ( v - > timeline . size ( ) , true ) ) ;
}
ImGui : : EndTooltip ( ) ;
}
2017-10-12 17:47:56 +00:00
}
2017-09-22 23:29:27 +00:00
offset + = ostep ;
2018-02-13 13:57:47 +00:00
if ( showFull )
2017-10-12 17:47:56 +00:00
{
m_lastCpu = - 1 ;
2017-10-13 11:32:23 +00:00
if ( m_drawZones )
{
2018-04-20 21:19:04 +00:00
const auto depth = DispatchZoneLevel ( v - > timeline , hover , pxns , wpos , offset , 0 , yMin , yMax ) ;
2017-10-13 11:32:23 +00:00
offset + = ostep * depth ;
}
2017-09-23 22:07:06 +00:00
2017-10-13 11:32:23 +00:00
if ( m_drawLocks )
{
2018-04-20 20:53:15 +00:00
const auto depth = DrawLocks ( v - > id , hover , pxns , wpos , offset , nextLockHighlight , yMin , yMax ) ;
2017-10-13 11:32:23 +00:00
offset + = ostep * depth ;
}
2017-10-12 17:47:56 +00:00
}
offset + = ostep * 0.2f ;
2017-09-23 22:07:06 +00:00
}
2017-10-06 00:19:25 +00:00
m_lockHighlight = nextLockHighlight ;
2017-10-12 20:27:17 +00:00
2017-10-13 12:54:32 +00:00
if ( m_drawPlots )
{
2018-04-20 21:00:26 +00:00
offset = DrawPlots ( offset , pxns , wpos , hover , yMin , yMax ) ;
2017-10-13 12:54:32 +00:00
}
2017-10-12 20:27:17 +00:00
const auto scrollPos = ImGui : : GetScrollY ( ) ;
if ( scrollPos = = 0 & & m_zvScroll ! = 0 )
{
m_zvHeight = 0 ;
}
else
{
if ( offset > m_zvHeight ) m_zvHeight = offset ;
}
m_zvScroll = scrollPos ;
ImGui : : EndChild ( ) ;
2017-10-13 13:26:18 +00:00
2017-11-18 12:40:49 +00:00
if ( m_gpuStart ! = 0 & & m_gpuEnd ! = 0 )
2017-11-11 22:13:54 +00:00
{
const auto px0 = ( m_gpuStart - m_zvStart ) * pxns ;
2017-11-18 12:40:49 +00:00
const auto px1 = std : : max ( px0 + std : : max ( 1.0 , pxns * 0.5 ) , ( m_gpuEnd - m_zvStart ) * pxns ) ;
2017-11-11 22:13:54 +00:00
draw - > AddRectFilled ( ImVec2 ( wpos . x + px0 , linepos . y ) , ImVec2 ( wpos . x + px1 , linepos . y + lineh ) , 0x228888DD ) ;
draw - > AddRect ( ImVec2 ( wpos . x + px0 , linepos . y ) , ImVec2 ( wpos . x + px1 , linepos . y + lineh ) , 0x448888DD ) ;
}
2017-11-12 00:32:21 +00:00
if ( m_gpuInfoWindow )
{
const auto px0 = ( m_gpuInfoWindow - > cpuStart - m_zvStart ) * pxns ;
2017-11-18 12:40:49 +00:00
const auto px1 = std : : max ( px0 + std : : max ( 1.0 , pxns * 0.5 ) , ( m_gpuInfoWindow - > cpuEnd - m_zvStart ) * pxns ) ;
2017-11-12 00:32:21 +00:00
draw - > AddRectFilled ( ImVec2 ( wpos . x + px0 , linepos . y ) , ImVec2 ( wpos . x + px1 , linepos . y + lineh ) , 0x2288DD88 ) ;
draw - > AddRect ( ImVec2 ( wpos . x + px0 , linepos . y ) , ImVec2 ( wpos . x + px1 , linepos . y + lineh ) , 0x4488DD88 ) ;
}
2017-11-11 22:13:54 +00:00
2018-03-04 21:21:35 +00:00
if ( m_highlight . active & & m_highlight . start ! = m_highlight . end )
2017-10-15 14:42:56 +00:00
{
2018-03-04 21:21:35 +00:00
const auto s = std : : min ( m_highlight . start , m_highlight . end ) ;
const auto e = std : : max ( m_highlight . start , m_highlight . end ) ;
2017-10-15 14:42:56 +00:00
draw - > AddRectFilled ( ImVec2 ( wpos . x + ( s - m_zvStart ) * pxns , linepos . y ) , ImVec2 ( wpos . x + ( e - m_zvStart ) * pxns , linepos . y + lineh ) , 0x22DD8888 ) ;
draw - > AddRect ( ImVec2 ( wpos . x + ( s - m_zvStart ) * pxns , linepos . y ) , ImVec2 ( wpos . x + ( e - m_zvStart ) * pxns , linepos . y + lineh ) , 0x44DD8888 ) ;
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " %s " , TimeToString ( e - s ) ) ;
ImGui : : EndTooltip ( ) ;
}
else if ( drawMouseLine )
2017-10-13 13:26:18 +00:00
{
auto & io = ImGui : : GetIO ( ) ;
draw - > AddLine ( ImVec2 ( io . MousePos . x , linepos . y ) , ImVec2 ( io . MousePos . x , linepos . y + lineh ) , 0x33FFFFFF ) ;
}
2018-04-02 14:21:24 +00:00
if ( m_memInfo . show & & m_memInfo . restrictTime )
{
const auto zvMid = ( m_zvEnd - m_zvStart ) / 2 ;
auto & io = ImGui : : GetIO ( ) ;
draw - > AddLine ( ImVec2 ( wpos . x + zvMid * pxns , linepos . y ) , ImVec2 ( wpos . x + zvMid * pxns , linepos . y + lineh ) , 0x88FF44FF ) ;
}
2017-09-23 22:07:06 +00:00
}
2018-04-20 21:19:04 +00:00
int View : : DispatchZoneLevel ( const Vector < ZoneEvent * > & vec , bool hover , double pxns , const ImVec2 & wpos , int _offset , int depth , float yMin , float yMax )
{
const auto ty = ImGui : : GetFontSize ( ) ;
const auto ostep = ty + 1 ;
const auto offset = _offset + ostep * depth ;
const auto yPos = wpos . y + offset ;
if ( yPos + ostep > = yMin & & yPos < = yMax )
{
return DrawZoneLevel ( vec , hover , pxns , wpos , _offset , depth , yMin , yMax ) ;
}
else
{
return SkipZoneLevel ( vec , hover , pxns , wpos , _offset , depth , yMin , yMax ) ;
}
}
int View : : DrawZoneLevel ( const Vector < ZoneEvent * > & vec , bool hover , double pxns , const ImVec2 & wpos , int _offset , int depth , float yMin , float yMax )
2017-09-23 22:07:06 +00:00
{
2018-02-13 13:57:47 +00:00
const auto delay = m_worker . GetDelay ( ) ;
const auto resolution = m_worker . GetResolution ( ) ;
2017-10-28 20:20:39 +00:00
// cast to uint64_t, so that unended zones (end = -1) are still drawn
2018-02-13 13:57:47 +00:00
auto it = std : : lower_bound ( vec . begin ( ) , vec . end ( ) , m_zvStart - delay , [ ] ( const auto & l , const auto & r ) { return ( uint64_t ) l - > end < ( uint64_t ) r ; } ) ;
2017-10-12 17:14:03 +00:00
if ( it = = vec . end ( ) ) return depth ;
2018-02-13 13:57:47 +00:00
const auto zitend = std : : lower_bound ( it , vec . end ( ) , m_zvEnd + resolution , [ ] ( const auto & l , const auto & r ) { return l - > start < r ; } ) ;
2017-10-12 17:14:03 +00:00
if ( it = = zitend ) return depth ;
2017-10-12 20:27:17 +00:00
const auto w = ImGui : : GetWindowContentRegionWidth ( ) - 1 ;
2017-10-12 17:14:03 +00:00
const auto ty = ImGui : : GetFontSize ( ) ;
const auto ostep = ty + 1 ;
const auto offset = _offset + ostep * depth ;
auto draw = ImGui : : GetWindowDrawList ( ) ;
2018-02-13 13:57:47 +00:00
const auto dsz = delay * pxns ;
const auto rsz = resolution * pxns ;
2017-10-12 17:14:03 +00:00
depth + + ;
int maxdepth = depth ;
while ( it < zitend )
2017-09-23 22:07:06 +00:00
{
2017-10-12 17:14:03 +00:00
auto & ev = * * it ;
2018-02-13 13:57:47 +00:00
auto & srcloc = m_worker . GetSourceLocation ( ev . srcloc ) ;
2017-11-11 21:56:05 +00:00
const auto color = GetZoneColor ( ev ) ;
2018-02-13 13:57:47 +00:00
const auto end = m_worker . GetZoneEnd ( ev ) ;
2017-11-18 12:40:49 +00:00
const auto zsz = std : : max ( ( end - ev . start ) * pxns , pxns * 0.5 ) ;
2017-10-12 17:14:03 +00:00
if ( zsz < MinVisSize )
2017-09-21 00:16:01 +00:00
{
2017-10-12 17:14:03 +00:00
int num = 1 ;
const auto px0 = ( ev . start - m_zvStart ) * pxns ;
auto px1 = ( end - m_zvStart ) * pxns ;
auto rend = end ;
for ( ; ; )
2017-09-21 20:12:19 +00:00
{
2017-10-12 17:14:03 +00:00
+ + it ;
if ( it = = zitend ) break ;
2018-02-13 13:57:47 +00:00
const auto nend = m_worker . GetZoneEnd ( * * it ) ;
2017-10-12 17:14:03 +00:00
const auto pxnext = ( nend - m_zvStart ) * pxns ;
if ( pxnext - px1 > = MinVisSize * 2 ) break ;
px1 = pxnext ;
rend = nend ;
num + + ;
}
2017-11-07 20:48:24 +00:00
draw - > AddRectFilled ( wpos + ImVec2 ( std : : max ( px0 , - 10.0 ) , offset ) , wpos + ImVec2 ( std : : min ( std : : max ( px1 , px0 + MinVisSize ) , double ( w + 10 ) ) , offset + ty ) , color ) ;
2017-10-28 14:14:52 +00:00
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( std : : max ( px0 , - 10.0 ) , offset ) , wpos + ImVec2 ( std : : min ( std : : max ( px1 , px0 + MinVisSize ) , double ( w + 10 ) ) , offset + ty ) ) )
2017-10-12 17:14:03 +00:00
{
2017-11-07 20:51:21 +00:00
if ( num > 1 )
{
ImGui : : BeginTooltip ( ) ;
2017-11-25 14:48:41 +00:00
ImGui : : Text ( " Zones too small to display: %s " , RealToString ( num , true ) ) ;
2017-11-17 23:51:04 +00:00
ImGui : : Separator ( ) ;
2017-11-07 20:51:21 +00:00
ImGui : : Text ( " Execution time: %s " , TimeToString ( rend - ev . start ) ) ;
ImGui : : EndTooltip ( ) ;
2017-09-26 20:08:58 +00:00
2017-11-07 20:51:21 +00:00
if ( ImGui : : IsMouseClicked ( 2 ) & & rend - ev . start > 0 )
{
2017-11-27 21:12:26 +00:00
ZoomToRange ( ev . start , rend ) ;
2017-11-07 20:51:21 +00:00
}
}
else
2017-09-29 17:13:53 +00:00
{
2017-11-07 20:51:21 +00:00
ZoneTooltip ( ev ) ;
if ( ImGui : : IsMouseClicked ( 2 ) & & rend - ev . start > 0 )
{
ZoomToZone ( ev ) ;
}
if ( ImGui : : IsMouseClicked ( 0 ) )
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( ev ) ;
2017-11-07 20:51:21 +00:00
}
2017-09-29 17:13:53 +00:00
}
2017-09-23 22:07:06 +00:00
}
2017-10-12 17:14:03 +00:00
char tmp [ 32 ] ;
sprintf ( tmp , " %i " , num ) ;
const auto tsz = ImGui : : CalcTextSize ( tmp ) ;
if ( tsz . x < px1 - px0 )
{
const auto x = px0 + ( px1 - px0 - tsz . x ) / 2 ;
2017-11-25 14:45:16 +00:00
DrawTextContrast ( draw , wpos + ImVec2 ( x , offset ) , 0xFF4488DD , tmp ) ;
2017-10-12 17:14:03 +00:00
}
}
else
{
const char * zoneName ;
2017-11-14 22:31:24 +00:00
if ( srcloc . name . active )
2017-10-12 17:14:03 +00:00
{
2018-02-13 13:57:47 +00:00
zoneName = m_worker . GetString ( srcloc . name ) ;
2017-10-12 17:14:03 +00:00
}
2017-09-23 22:07:06 +00:00
else
{
2018-02-13 13:57:47 +00:00
zoneName = m_worker . GetString ( srcloc . function ) ;
2017-10-12 17:14:03 +00:00
}
2017-09-28 17:31:27 +00:00
2017-11-14 22:31:24 +00:00
int dmul = ev . text . active ? 2 : 1 ;
2017-09-29 16:40:55 +00:00
2017-10-12 17:14:03 +00:00
bool migration = false ;
if ( m_lastCpu ! = ev . cpu_start )
{
2018-04-14 14:50:04 +00:00
if ( m_lastCpu > = 0 )
2017-10-01 17:58:53 +00:00
{
2017-10-12 17:14:03 +00:00
migration = true ;
2017-10-01 17:58:53 +00:00
}
2017-10-12 17:14:03 +00:00
m_lastCpu = ev . cpu_start ;
}
2017-10-01 17:58:53 +00:00
2017-10-12 17:14:03 +00:00
if ( ! ev . child . empty ( ) )
{
2018-04-20 21:19:04 +00:00
const auto d = DispatchZoneLevel ( ev . child , hover , pxns , wpos , _offset , depth , yMin , yMax ) ;
2017-10-12 17:14:03 +00:00
if ( d > maxdepth ) maxdepth = d ;
}
2017-10-01 17:58:53 +00:00
2018-03-24 01:00:20 +00:00
if ( ev . end > = 0 & & m_lastCpu ! = ev . cpu_end )
2017-10-12 17:14:03 +00:00
{
m_lastCpu = ev . cpu_end ;
migration = true ;
}
2017-10-01 17:58:53 +00:00
2017-10-22 11:56:05 +00:00
auto tsz = ImGui : : CalcTextSize ( zoneName ) ;
if ( tsz . x > zsz )
{
zoneName = ShortenNamespace ( zoneName ) ;
tsz = ImGui : : CalcTextSize ( zoneName ) ;
}
2017-10-12 17:14:03 +00:00
const auto pr0 = ( ev . start - m_zvStart ) * pxns ;
const auto pr1 = ( end - m_zvStart ) * pxns ;
const auto px0 = std : : max ( pr0 , - 10.0 ) ;
2017-11-18 12:40:49 +00:00
const auto px1 = std : : max ( { std : : min ( pr1 , double ( w + 10 ) ) , px0 + pxns * 0.5 , px0 + MinVisSize } ) ;
draw - > AddRectFilled ( wpos + ImVec2 ( px0 , offset ) , wpos + ImVec2 ( px1 , offset + tsz . y ) , color ) ;
draw - > AddRect ( wpos + ImVec2 ( px0 , offset ) , wpos + ImVec2 ( px1 , offset + tsz . y ) , GetZoneHighlight ( ev , migration ) , 0.f , - 1 , GetZoneThickness ( ev ) ) ;
2017-10-12 17:14:03 +00:00
if ( dsz * dmul > = MinVisSize )
{
2017-11-07 20:48:24 +00:00
draw - > AddRectFilled ( wpos + ImVec2 ( pr0 , offset ) , wpos + ImVec2 ( std : : min ( pr0 + dsz * dmul , pr1 ) , offset + tsz . y ) , 0x882222DD ) ;
draw - > AddRectFilled ( wpos + ImVec2 ( pr1 , offset ) , wpos + ImVec2 ( pr1 + dsz , offset + tsz . y ) , 0x882222DD ) ;
2017-10-12 17:14:03 +00:00
}
if ( rsz > = MinVisSize )
{
2017-11-07 21:02:27 +00:00
draw - > AddLine ( wpos + ImVec2 ( pr0 + rsz , offset + round ( tsz . y / 2 ) ) , wpos + ImVec2 ( pr0 - rsz , offset + round ( tsz . y / 2 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( pr0 + rsz , offset + round ( tsz . y / 4 ) ) , wpos + ImVec2 ( pr0 + rsz , offset + round ( 3 * tsz . y / 4 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( pr0 - rsz , offset + round ( tsz . y / 4 ) ) , wpos + ImVec2 ( pr0 - rsz , offset + round ( 3 * tsz . y / 4 ) ) , 0xAAFFFFFF ) ;
2017-09-29 16:55:21 +00:00
2017-11-07 21:02:27 +00:00
draw - > AddLine ( wpos + ImVec2 ( pr1 + rsz , offset + round ( tsz . y / 2 ) ) , wpos + ImVec2 ( pr1 - rsz , offset + round ( tsz . y / 2 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( pr1 + rsz , offset + round ( tsz . y / 4 ) ) , wpos + ImVec2 ( pr1 + rsz , offset + round ( 3 * tsz . y / 4 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( pr1 - rsz , offset + round ( tsz . y / 4 ) ) , wpos + ImVec2 ( pr1 - rsz , offset + round ( 3 * tsz . y / 4 ) ) , 0xAAFFFFFF ) ;
2017-10-12 17:14:03 +00:00
}
if ( tsz . x < zsz )
{
const auto x = ( ev . start - m_zvStart ) * pxns + ( ( end - ev . start ) * pxns - tsz . x ) / 2 ;
if ( x < 0 | | x > w - tsz . x )
2017-09-24 14:25:07 +00:00
{
2017-11-18 12:40:49 +00:00
ImGui : : PushClipRect ( wpos + ImVec2 ( px0 , offset ) , wpos + ImVec2 ( px1 , offset + tsz . y * 2 ) , true ) ;
2017-11-25 14:45:16 +00:00
DrawTextContrast ( draw , wpos + ImVec2 ( std : : max ( std : : max ( 0. , px0 ) , std : : min ( double ( w - tsz . x ) , x ) ) , offset ) , 0xFFFFFFFF , zoneName ) ;
2017-10-12 17:14:03 +00:00
ImGui : : PopClipRect ( ) ;
2017-09-24 14:25:07 +00:00
}
2017-11-18 12:40:49 +00:00
else if ( ev . start = = ev . end )
{
2017-11-25 14:45:16 +00:00
DrawTextContrast ( draw , wpos + ImVec2 ( px0 + ( px1 - px0 - tsz . x ) * 0.5 , offset ) , 0xFFFFFFFF , zoneName ) ;
2017-11-18 12:40:49 +00:00
}
2017-09-24 14:25:07 +00:00
else
{
2017-11-25 14:45:16 +00:00
DrawTextContrast ( draw , wpos + ImVec2 ( x , offset ) , 0xFFFFFFFF , zoneName ) ;
2017-09-24 14:25:07 +00:00
}
2017-10-12 17:14:03 +00:00
}
else
{
2017-11-18 12:40:49 +00:00
ImGui : : PushClipRect ( wpos + ImVec2 ( px0 , offset ) , wpos + ImVec2 ( px1 , offset + tsz . y * 2 ) , true ) ;
2017-11-25 14:45:16 +00:00
DrawTextContrast ( draw , wpos + ImVec2 ( ( ev . start - m_zvStart ) * pxns , offset ) , 0xFFFFFFFF , zoneName ) ;
2017-10-12 17:14:03 +00:00
ImGui : : PopClipRect ( ) ;
}
2017-09-21 00:16:01 +00:00
2017-11-18 12:40:49 +00:00
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( px0 , offset ) , wpos + ImVec2 ( px1 , offset + tsz . y ) ) )
2017-10-12 17:14:03 +00:00
{
ZoneTooltip ( ev ) ;
2017-09-26 19:49:50 +00:00
2017-11-27 21:41:30 +00:00
if ( ! m_zoomAnim . active & & ImGui : : IsMouseClicked ( 2 ) )
2017-10-12 17:14:03 +00:00
{
ZoomToZone ( ev ) ;
}
if ( ImGui : : IsMouseClicked ( 0 ) )
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( ev ) ;
2017-09-24 14:25:07 +00:00
}
}
2017-10-12 17:14:03 +00:00
+ + it ;
2017-09-23 22:07:06 +00:00
}
2017-09-21 00:16:01 +00:00
}
2017-09-23 22:12:26 +00:00
return maxdepth ;
2017-09-20 22:57:26 +00:00
}
2018-04-20 21:19:04 +00:00
int View : : SkipZoneLevel ( const Vector < ZoneEvent * > & vec , bool hover , double pxns , const ImVec2 & wpos , int _offset , int depth , float yMin , float yMax )
{
const auto delay = m_worker . GetDelay ( ) ;
const auto resolution = m_worker . GetResolution ( ) ;
// cast to uint64_t, so that unended zones (end = -1) are still drawn
auto it = std : : lower_bound ( vec . begin ( ) , vec . end ( ) , m_zvStart - delay , [ ] ( const auto & l , const auto & r ) { return ( uint64_t ) l - > end < ( uint64_t ) r ; } ) ;
if ( it = = vec . end ( ) ) return depth ;
const auto zitend = std : : lower_bound ( it , vec . end ( ) , m_zvEnd + resolution , [ ] ( const auto & l , const auto & r ) { return l - > start < r ; } ) ;
if ( it = = zitend ) return depth ;
depth + + ;
int maxdepth = depth ;
while ( it < zitend )
{
auto & ev = * * it ;
const auto end = m_worker . GetZoneEnd ( ev ) ;
const auto zsz = std : : max ( ( end - ev . start ) * pxns , pxns * 0.5 ) ;
if ( zsz < MinVisSize )
{
auto px1 = ( end - m_zvStart ) * pxns ;
for ( ; ; )
{
+ + it ;
if ( it = = zitend ) break ;
const auto nend = m_worker . GetZoneEnd ( * * it ) ;
const auto pxnext = ( nend - m_zvStart ) * pxns ;
if ( pxnext - px1 > = MinVisSize * 2 ) break ;
px1 = pxnext ;
}
}
else
{
m_lastCpu = ev . cpu_start ;
if ( ! ev . child . empty ( ) )
{
const auto d = DispatchZoneLevel ( ev . child , hover , pxns , wpos , _offset , depth , yMin , yMax ) ;
if ( d > maxdepth ) maxdepth = d ;
}
if ( ev . end > = 0 & & m_lastCpu ! = ev . cpu_end )
{
m_lastCpu = ev . cpu_end ;
}
+ + it ;
}
}
return maxdepth ;
}
2018-04-20 21:28:19 +00:00
int View : : DispatchGpuZoneLevel ( const Vector < GpuEvent * > & vec , bool hover , double pxns , const ImVec2 & wpos , int _offset , int depth , uint64_t thread , float yMin , float yMax )
{
const auto ty = ImGui : : GetFontSize ( ) ;
const auto ostep = ty + 1 ;
const auto offset = _offset + ostep * depth ;
const auto yPos = wpos . y + offset ;
if ( yPos + ostep > = yMin & & yPos < = yMax )
{
return DrawGpuZoneLevel ( vec , hover , pxns , wpos , _offset , depth , thread , yMin , yMax ) ;
}
else
{
return SkipGpuZoneLevel ( vec , hover , pxns , wpos , _offset , depth , thread , yMin , yMax ) ;
}
}
int View : : DrawGpuZoneLevel ( const Vector < GpuEvent * > & vec , bool hover , double pxns , const ImVec2 & wpos , int _offset , int depth , uint64_t thread , float yMin , float yMax )
2017-11-11 21:56:05 +00:00
{
2018-02-13 13:57:47 +00:00
const auto delay = m_worker . GetDelay ( ) ;
const auto resolution = m_worker . GetResolution ( ) ;
2017-11-11 21:56:05 +00:00
// cast to uint64_t, so that unended zones (end = -1) are still drawn
2018-02-13 13:57:47 +00:00
auto it = std : : lower_bound ( vec . begin ( ) , vec . end ( ) , m_zvStart - delay , [ ] ( const auto & l , const auto & r ) { return ( uint64_t ) l - > gpuEnd < ( uint64_t ) r ; } ) ;
2017-11-11 21:56:05 +00:00
if ( it = = vec . end ( ) ) return depth ;
2018-02-13 13:57:47 +00:00
const auto zitend = std : : lower_bound ( it , vec . end ( ) , m_zvEnd + resolution , [ ] ( const auto & l , const auto & r ) { return l - > gpuStart < r ; } ) ;
2017-11-11 21:56:05 +00:00
if ( it = = zitend ) return depth ;
const auto w = ImGui : : GetWindowContentRegionWidth ( ) - 1 ;
const auto ty = ImGui : : GetFontSize ( ) ;
const auto ostep = ty + 1 ;
const auto offset = _offset + ostep * depth ;
auto draw = ImGui : : GetWindowDrawList ( ) ;
2018-02-13 13:57:47 +00:00
const auto dsz = delay * pxns ;
const auto rsz = resolution * pxns ;
2017-11-11 21:56:05 +00:00
depth + + ;
int maxdepth = depth ;
while ( it < zitend )
{
auto & ev = * * it ;
2018-02-13 13:57:47 +00:00
auto & srcloc = m_worker . GetSourceLocation ( ev . srcloc ) ;
2017-11-11 21:56:05 +00:00
const auto color = GetZoneColor ( ev ) ;
2018-02-13 13:57:47 +00:00
const auto end = m_worker . GetZoneEnd ( ev ) ;
2017-11-14 23:08:21 +00:00
if ( end = = std : : numeric_limits < int64_t > : : max ( ) ) break ;
2017-11-18 12:40:49 +00:00
const auto zsz = std : : max ( ( end - ev . gpuStart ) * pxns , pxns * 0.5 ) ;
2017-11-11 21:56:05 +00:00
if ( zsz < MinVisSize )
{
int num = 1 ;
const auto px0 = ( ev . gpuStart - m_zvStart ) * pxns ;
auto px1 = ( end - m_zvStart ) * pxns ;
auto rend = end ;
for ( ; ; )
{
+ + it ;
if ( it = = zitend ) break ;
2018-02-13 13:57:47 +00:00
const auto nend = m_worker . GetZoneEnd ( * * it ) ;
2017-11-11 21:56:05 +00:00
const auto pxnext = ( nend - m_zvStart ) * pxns ;
if ( pxnext - px1 > = MinVisSize * 2 ) break ;
px1 = pxnext ;
rend = nend ;
num + + ;
}
draw - > AddRectFilled ( wpos + ImVec2 ( std : : max ( px0 , - 10.0 ) , offset ) , wpos + ImVec2 ( std : : min ( std : : max ( px1 , px0 + MinVisSize ) , double ( w + 10 ) ) , offset + ty ) , color ) ;
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( std : : max ( px0 , - 10.0 ) , offset ) , wpos + ImVec2 ( std : : min ( std : : max ( px1 , px0 + MinVisSize ) , double ( w + 10 ) ) , offset + ty ) ) )
{
if ( num > 1 )
{
ImGui : : BeginTooltip ( ) ;
2017-11-25 14:48:41 +00:00
ImGui : : Text ( " Zones too small to display: %s " , RealToString ( num , true ) ) ;
2017-11-17 23:51:04 +00:00
ImGui : : Separator ( ) ;
2017-11-11 21:56:05 +00:00
ImGui : : Text ( " Execution time: %s " , TimeToString ( rend - ev . gpuStart ) ) ;
ImGui : : EndTooltip ( ) ;
if ( ImGui : : IsMouseClicked ( 2 ) & & rend - ev . gpuStart > 0 )
{
2017-11-27 21:12:26 +00:00
ZoomToRange ( ev . gpuStart , rend ) ;
2017-11-11 21:56:05 +00:00
}
}
else
{
ZoneTooltip ( ev ) ;
if ( ImGui : : IsMouseClicked ( 2 ) & & rend - ev . gpuStart > 0 )
{
ZoomToZone ( ev ) ;
}
2017-11-12 00:25:44 +00:00
if ( ImGui : : IsMouseClicked ( 0 ) )
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( ev , thread ) ;
2017-11-12 00:25:44 +00:00
}
2017-11-11 22:13:54 +00:00
2017-11-13 23:48:26 +00:00
m_gpuThread = thread ;
2017-11-11 22:13:54 +00:00
m_gpuStart = ev . cpuStart ;
m_gpuEnd = ev . cpuEnd ;
2017-11-11 21:56:05 +00:00
}
}
char tmp [ 32 ] ;
sprintf ( tmp , " %i " , num ) ;
const auto tsz = ImGui : : CalcTextSize ( tmp ) ;
if ( tsz . x < px1 - px0 )
{
const auto x = px0 + ( px1 - px0 - tsz . x ) / 2 ;
2017-11-25 14:45:16 +00:00
DrawTextContrast ( draw , wpos + ImVec2 ( x , offset ) , 0xFF4488DD , tmp ) ;
2017-11-11 21:56:05 +00:00
}
}
else
{
if ( ! ev . child . empty ( ) )
{
2018-04-20 21:28:19 +00:00
const auto d = DispatchGpuZoneLevel ( ev . child , hover , pxns , wpos , _offset , depth , thread , yMin , yMax ) ;
2017-11-11 21:56:05 +00:00
if ( d > maxdepth ) maxdepth = d ;
}
2018-02-13 13:57:47 +00:00
const char * zoneName = m_worker . GetString ( srcloc . name ) ;
2017-11-11 21:56:05 +00:00
auto tsz = ImGui : : CalcTextSize ( zoneName ) ;
const auto pr0 = ( ev . gpuStart - m_zvStart ) * pxns ;
const auto pr1 = ( end - m_zvStart ) * pxns ;
const auto px0 = std : : max ( pr0 , - 10.0 ) ;
2017-11-18 12:40:49 +00:00
const auto px1 = std : : max ( { std : : min ( pr1 , double ( w + 10 ) ) , px0 + pxns * 0.5 , px0 + MinVisSize } ) ;
draw - > AddRectFilled ( wpos + ImVec2 ( px0 , offset ) , wpos + ImVec2 ( px1 , offset + tsz . y ) , color ) ;
draw - > AddRect ( wpos + ImVec2 ( px0 , offset ) , wpos + ImVec2 ( px1 , offset + tsz . y ) , GetZoneHighlight ( ev ) , 0.f , - 1 , GetZoneThickness ( ev ) ) ;
2017-11-11 21:56:05 +00:00
if ( dsz > = MinVisSize )
{
draw - > AddRectFilled ( wpos + ImVec2 ( pr0 , offset ) , wpos + ImVec2 ( std : : min ( pr0 + dsz , pr1 ) , offset + tsz . y ) , 0x882222DD ) ;
draw - > AddRectFilled ( wpos + ImVec2 ( pr1 , offset ) , wpos + ImVec2 ( pr1 + dsz , offset + tsz . y ) , 0x882222DD ) ;
}
if ( rsz > = MinVisSize )
{
draw - > AddLine ( wpos + ImVec2 ( pr0 + rsz , offset + round ( tsz . y / 2 ) ) , wpos + ImVec2 ( pr0 - rsz , offset + round ( tsz . y / 2 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( pr0 + rsz , offset + round ( tsz . y / 4 ) ) , wpos + ImVec2 ( pr0 + rsz , offset + round ( 3 * tsz . y / 4 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( pr0 - rsz , offset + round ( tsz . y / 4 ) ) , wpos + ImVec2 ( pr0 - rsz , offset + round ( 3 * tsz . y / 4 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( pr1 + rsz , offset + round ( tsz . y / 2 ) ) , wpos + ImVec2 ( pr1 - rsz , offset + round ( tsz . y / 2 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( pr1 + rsz , offset + round ( tsz . y / 4 ) ) , wpos + ImVec2 ( pr1 + rsz , offset + round ( 3 * tsz . y / 4 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( pr1 - rsz , offset + round ( tsz . y / 4 ) ) , wpos + ImVec2 ( pr1 - rsz , offset + round ( 3 * tsz . y / 4 ) ) , 0xAAFFFFFF ) ;
}
if ( tsz . x < zsz )
{
const auto x = ( ev . gpuStart - m_zvStart ) * pxns + ( ( end - ev . gpuStart ) * pxns - tsz . x ) / 2 ;
if ( x < 0 | | x > w - tsz . x )
{
2017-11-18 12:40:49 +00:00
ImGui : : PushClipRect ( wpos + ImVec2 ( px0 , offset ) , wpos + ImVec2 ( px1 , offset + tsz . y * 2 ) , true ) ;
2017-11-25 14:45:16 +00:00
DrawTextContrast ( draw , wpos + ImVec2 ( std : : max ( std : : max ( 0. , px0 ) , std : : min ( double ( w - tsz . x ) , x ) ) , offset ) , 0xFFFFFFFF , zoneName ) ;
2017-11-11 21:56:05 +00:00
ImGui : : PopClipRect ( ) ;
}
2017-11-18 12:40:49 +00:00
else if ( ev . gpuStart = = ev . gpuEnd )
{
2017-11-25 14:45:16 +00:00
DrawTextContrast ( draw , wpos + ImVec2 ( px0 + ( px1 - px0 - tsz . x ) * 0.5 , offset ) , 0xFFFFFFFF , zoneName ) ;
2017-11-18 12:40:49 +00:00
}
2017-11-11 21:56:05 +00:00
else
{
2017-11-25 14:45:16 +00:00
DrawTextContrast ( draw , wpos + ImVec2 ( x , offset ) , 0xFFFFFFFF , zoneName ) ;
2017-11-11 21:56:05 +00:00
}
}
else
{
2017-11-18 12:40:49 +00:00
ImGui : : PushClipRect ( wpos + ImVec2 ( px0 , offset ) , wpos + ImVec2 ( px1 , offset + tsz . y * 2 ) , true ) ;
2017-11-25 14:45:16 +00:00
DrawTextContrast ( draw , wpos + ImVec2 ( ( ev . gpuStart - m_zvStart ) * pxns , offset ) , 0xFFFFFFFF , zoneName ) ;
2017-11-11 21:56:05 +00:00
ImGui : : PopClipRect ( ) ;
}
2017-11-18 12:40:49 +00:00
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( px0 , offset ) , wpos + ImVec2 ( px1 , offset + tsz . y ) ) )
2017-11-11 21:56:05 +00:00
{
ZoneTooltip ( ev ) ;
2017-11-27 21:41:30 +00:00
if ( ! m_zoomAnim . active & & ImGui : : IsMouseClicked ( 2 ) )
2017-11-11 21:56:05 +00:00
{
ZoomToZone ( ev ) ;
}
2017-11-12 00:25:44 +00:00
if ( ImGui : : IsMouseClicked ( 0 ) )
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( ev , thread ) ;
2017-11-12 00:25:44 +00:00
}
2017-11-11 22:13:54 +00:00
2017-11-13 23:48:26 +00:00
m_gpuThread = thread ;
2017-11-11 22:13:54 +00:00
m_gpuStart = ev . cpuStart ;
m_gpuEnd = ev . cpuEnd ;
2017-11-11 21:56:05 +00:00
}
+ + it ;
}
}
return maxdepth ;
}
2018-04-20 21:28:19 +00:00
int View : : SkipGpuZoneLevel ( const Vector < GpuEvent * > & vec , bool hover , double pxns , const ImVec2 & wpos , int _offset , int depth , uint64_t thread , float yMin , float yMax )
{
const auto delay = m_worker . GetDelay ( ) ;
const auto resolution = m_worker . GetResolution ( ) ;
// cast to uint64_t, so that unended zones (end = -1) are still drawn
auto it = std : : lower_bound ( vec . begin ( ) , vec . end ( ) , m_zvStart - delay , [ ] ( const auto & l , const auto & r ) { return ( uint64_t ) l - > gpuEnd < ( uint64_t ) r ; } ) ;
if ( it = = vec . end ( ) ) return depth ;
const auto zitend = std : : lower_bound ( it , vec . end ( ) , m_zvEnd + resolution , [ ] ( const auto & l , const auto & r ) { return l - > gpuStart < r ; } ) ;
if ( it = = zitend ) return depth ;
depth + + ;
int maxdepth = depth ;
while ( it < zitend )
{
auto & ev = * * it ;
const auto end = m_worker . GetZoneEnd ( ev ) ;
if ( end = = std : : numeric_limits < int64_t > : : max ( ) ) break ;
const auto zsz = std : : max ( ( end - ev . gpuStart ) * pxns , pxns * 0.5 ) ;
if ( zsz < MinVisSize )
{
auto px1 = ( end - m_zvStart ) * pxns ;
for ( ; ; )
{
+ + it ;
if ( it = = zitend ) break ;
const auto nend = m_worker . GetZoneEnd ( * * it ) ;
const auto pxnext = ( nend - m_zvStart ) * pxns ;
if ( pxnext - px1 > = MinVisSize * 2 ) break ;
px1 = pxnext ;
}
}
else
{
if ( ! ev . child . empty ( ) )
{
const auto d = DispatchGpuZoneLevel ( ev . child , hover , pxns , wpos , _offset , depth , thread , yMin , yMax ) ;
if ( d > maxdepth ) maxdepth = d ;
}
+ + it ;
}
}
return maxdepth ;
}
2017-12-05 21:09:53 +00:00
static inline uint64_t GetThreadBit ( uint8_t thread )
2017-10-08 21:03:38 +00:00
{
2017-12-05 21:09:53 +00:00
return uint64_t ( 1 ) < < thread ;
2017-10-08 21:03:38 +00:00
}
2017-12-05 21:09:53 +00:00
static inline bool IsThreadWaiting ( uint64_t bitlist , uint64_t threadBit )
2017-10-28 10:48:05 +00:00
{
2017-12-05 21:09:53 +00:00
return ( bitlist & threadBit ) ! = 0 ;
}
static inline bool AreOtherWaiting ( uint64_t bitlist , uint64_t threadBit )
{
return ( bitlist & ~ threadBit ) ! = 0 ;
2017-10-28 10:48:05 +00:00
}
2017-10-28 11:44:46 +00:00
enum class LockState
{
2017-11-26 20:37:57 +00:00
Nothing ,
HasLock , // green
HasBlockingLock , // yellow
WaitLock // red
2017-10-28 11:44:46 +00:00
} ;
2018-02-13 13:57:47 +00:00
static Vector < LockEvent * > : : const_iterator GetNextLockEvent ( const Vector < LockEvent * > : : const_iterator & it , const Vector < LockEvent * > : : const_iterator & end , LockState & nextState , uint64_t threadBit )
2017-10-04 19:27:06 +00:00
{
2017-10-28 11:44:46 +00:00
auto next = it ;
next + + ;
2017-12-17 17:00:15 +00:00
switch ( nextState )
{
case LockState : : Nothing :
while ( next < end )
{
if ( ( * next ) - > lockCount ! = 0 )
{
if ( GetThreadBit ( ( * next ) - > lockingThread ) = = threadBit )
{
nextState = AreOtherWaiting ( ( * next ) - > waitList , threadBit ) ? LockState : : HasBlockingLock : LockState : : HasLock ;
break ;
}
else if ( IsThreadWaiting ( ( * next ) - > waitList , threadBit ) )
{
nextState = LockState : : WaitLock ;
break ;
}
}
next + + ;
}
break ;
case LockState : : HasLock :
while ( next < end )
{
if ( ( * next ) - > lockCount = = 0 )
{
nextState = LockState : : Nothing ;
break ;
}
if ( ( * next ) - > waitList ! = 0 )
{
if ( AreOtherWaiting ( ( * next ) - > waitList , threadBit ) )
{
nextState = LockState : : HasBlockingLock ;
}
break ;
}
if ( ( * next ) - > waitList ! = ( * it ) - > waitList | | ( * next ) - > lockCount ! = ( * it ) - > lockCount )
{
break ;
}
next + + ;
}
break ;
case LockState : : HasBlockingLock :
while ( next < end )
{
if ( ( * next ) - > lockCount = = 0 )
{
nextState = LockState : : Nothing ;
break ;
}
if ( ( * next ) - > waitList ! = ( * it ) - > waitList | | ( * next ) - > lockCount ! = ( * it ) - > lockCount )
{
break ;
}
next + + ;
}
break ;
case LockState : : WaitLock :
while ( next < end )
{
if ( GetThreadBit ( ( * next ) - > lockingThread ) = = threadBit )
{
nextState = AreOtherWaiting ( ( * next ) - > waitList , threadBit ) ? LockState : : HasBlockingLock : LockState : : HasLock ;
break ;
}
if ( ( * next ) - > lockingThread ! = ( * it ) - > lockingThread )
{
break ;
}
if ( ( * next ) - > lockCount = = 0 )
{
break ;
}
next + + ;
}
break ;
default :
assert ( false ) ;
break ;
}
return next ;
}
2018-02-13 13:57:47 +00:00
static Vector < LockEvent * > : : const_iterator GetNextLockEventShared ( const Vector < LockEvent * > : : const_iterator & it , const Vector < LockEvent * > : : const_iterator & end , LockState & nextState , uint64_t threadBit )
2017-12-17 17:00:15 +00:00
{
2017-12-17 17:44:31 +00:00
const auto itptr = ( const LockEventShared * ) * it ;
2017-12-17 17:00:15 +00:00
auto next = it ;
next + + ;
2017-12-09 18:28:12 +00:00
switch ( nextState )
2017-10-05 21:18:24 +00:00
{
2017-10-28 11:44:46 +00:00
case LockState : : Nothing :
while ( next < end )
{
2017-12-17 17:44:31 +00:00
const auto ptr = ( const LockEventShared * ) * next ;
if ( ptr - > lockCount ! = 0 )
2017-10-28 11:44:46 +00:00
{
2017-12-17 17:44:31 +00:00
const auto wait = ptr - > waitList | ptr - > waitShared ;
if ( GetThreadBit ( ptr - > lockingThread ) = = threadBit )
2017-10-28 11:44:46 +00:00
{
2017-12-10 22:33:39 +00:00
nextState = AreOtherWaiting ( wait , threadBit ) ? LockState : : HasBlockingLock : LockState : : HasLock ;
2017-10-28 11:44:46 +00:00
break ;
}
2017-12-10 22:33:39 +00:00
else if ( IsThreadWaiting ( wait , threadBit ) )
2017-10-28 11:44:46 +00:00
{
nextState = LockState : : WaitLock ;
break ;
}
}
2017-12-17 17:44:31 +00:00
else if ( IsThreadWaiting ( ptr - > sharedList , threadBit ) )
2017-12-10 22:30:13 +00:00
{
2017-12-17 17:44:31 +00:00
nextState = ( ptr - > waitList ! = 0 ) ? LockState : : HasBlockingLock : LockState : : HasLock ;
2017-12-10 22:30:13 +00:00
break ;
}
2017-12-17 17:44:31 +00:00
else if ( ptr - > sharedList ! = 0 & & IsThreadWaiting ( ptr - > waitList , threadBit ) )
2017-12-10 22:30:13 +00:00
{
nextState = LockState : : WaitLock ;
break ;
}
2017-10-28 11:44:46 +00:00
next + + ;
}
break ;
case LockState : : HasLock :
while ( next < end )
{
2017-12-17 17:44:31 +00:00
const auto ptr = ( const LockEventShared * ) * next ;
if ( ptr - > lockCount = = 0 & & ! IsThreadWaiting ( ptr - > sharedList , threadBit ) )
2017-10-28 11:44:46 +00:00
{
nextState = LockState : : Nothing ;
break ;
}
2017-12-17 17:44:31 +00:00
if ( ptr - > waitList ! = 0 )
2017-10-28 11:44:46 +00:00
{
2017-12-17 17:44:31 +00:00
if ( AreOtherWaiting ( ptr - > waitList , threadBit ) )
2017-10-28 11:44:46 +00:00
{
nextState = LockState : : HasBlockingLock ;
}
break ;
}
2017-12-17 17:44:31 +00:00
else if ( ! IsThreadWaiting ( ptr - > sharedList , threadBit ) & & ptr - > waitShared ! = 0 )
2017-12-10 22:30:13 +00:00
{
nextState = LockState : : HasBlockingLock ;
break ;
}
2017-12-17 17:44:31 +00:00
if ( ptr - > waitList ! = itptr - > waitList | | ptr - > waitShared ! = itptr - > waitShared | | ptr - > lockCount ! = itptr - > lockCount | | ptr - > sharedList ! = itptr - > sharedList )
2017-10-28 11:44:46 +00:00
{
break ;
}
next + + ;
}
break ;
case LockState : : HasBlockingLock :
while ( next < end )
{
2017-12-17 17:44:31 +00:00
const auto ptr = ( const LockEventShared * ) * next ;
if ( ptr - > lockCount = = 0 & & ! IsThreadWaiting ( ptr - > sharedList , threadBit ) )
2017-10-28 11:44:46 +00:00
{
nextState = LockState : : Nothing ;
break ;
}
2017-12-17 17:44:31 +00:00
if ( ptr - > waitList ! = itptr - > waitList | | ptr - > waitShared ! = itptr - > waitShared | | ptr - > lockCount ! = itptr - > lockCount | | ptr - > sharedList ! = itptr - > sharedList )
2017-10-28 11:44:46 +00:00
{
break ;
}
next + + ;
}
break ;
case LockState : : WaitLock :
while ( next < end )
{
2017-12-17 17:44:31 +00:00
const auto ptr = ( const LockEventShared * ) * next ;
if ( GetThreadBit ( ptr - > lockingThread ) = = threadBit )
2017-10-28 11:44:46 +00:00
{
2017-12-17 17:44:31 +00:00
const auto wait = ptr - > waitList | ptr - > waitShared ;
2017-12-10 22:33:39 +00:00
nextState = AreOtherWaiting ( wait , threadBit ) ? LockState : : HasBlockingLock : LockState : : HasLock ;
2017-12-10 22:30:13 +00:00
break ;
}
2017-12-17 17:44:31 +00:00
if ( IsThreadWaiting ( ptr - > sharedList , threadBit ) )
2017-12-10 22:30:13 +00:00
{
2017-12-17 17:44:31 +00:00
nextState = ( ptr - > waitList ! = 0 ) ? LockState : : HasBlockingLock : LockState : : HasLock ;
2017-10-28 11:44:46 +00:00
break ;
}
2017-12-17 17:44:31 +00:00
if ( ptr - > lockingThread ! = itptr - > lockingThread )
2017-10-28 11:44:46 +00:00
{
break ;
}
2017-12-17 17:44:31 +00:00
if ( ptr - > lockCount = = 0 & & ! IsThreadWaiting ( ptr - > waitShared , threadBit ) )
2017-10-28 11:44:46 +00:00
{
break ;
}
next + + ;
}
break ;
default :
assert ( false ) ;
break ;
}
return next ;
}
2017-10-05 21:18:24 +00:00
2017-10-28 13:15:07 +00:00
static LockState CombineLockState ( LockState state , LockState next )
{
2017-11-26 20:37:57 +00:00
return ( LockState ) std : : max ( ( int ) state , ( int ) next ) ;
2017-10-28 13:15:07 +00:00
}
2018-04-20 20:53:15 +00:00
int View : : DrawLocks ( uint64_t tid , bool hover , double pxns , const ImVec2 & wpos , int _offset , LockHighlight & highlight , float yMin , float yMax )
2017-10-28 11:44:46 +00:00
{
2018-02-13 13:57:47 +00:00
const auto delay = m_worker . GetDelay ( ) ;
const auto resolution = m_worker . GetResolution ( ) ;
2017-10-28 12:25:35 +00:00
const auto w = ImGui : : GetWindowContentRegionWidth ( ) ;
const auto ty = ImGui : : GetFontSize ( ) ;
const auto ostep = ty + 1 ;
auto draw = ImGui : : GetWindowDrawList ( ) ;
2018-02-13 13:57:47 +00:00
const auto dsz = delay * pxns ;
const auto rsz = resolution * pxns ;
2017-10-28 12:25:35 +00:00
2017-10-04 19:27:06 +00:00
int cnt = 0 ;
2018-02-13 13:57:47 +00:00
for ( const auto & v : m_worker . GetLockMap ( ) )
2017-10-04 19:27:06 +00:00
{
2018-02-13 13:57:47 +00:00
const auto & lockmap = v . second ;
2018-03-20 14:41:06 +00:00
if ( ! lockmap . valid | | ! Visible ( & lockmap ) ) continue ;
2017-10-22 11:25:58 +00:00
2017-10-08 21:03:38 +00:00
auto it = lockmap . threadMap . find ( tid ) ;
if ( it = = lockmap . threadMap . end ( ) ) continue ;
2018-02-13 13:57:47 +00:00
const auto & tl = lockmap . timeline ;
2017-10-05 21:18:24 +00:00
assert ( ! tl . empty ( ) ) ;
2017-10-06 16:52:52 +00:00
if ( tl . back ( ) - > time < m_zvStart ) continue ;
2017-10-08 21:03:38 +00:00
2017-12-17 17:00:15 +00:00
auto GetNextLockFunc = lockmap . type = = LockType : : Lockable ? GetNextLockEvent : GetNextLockEventShared ;
2017-10-08 21:03:38 +00:00
const auto thread = it - > second ;
2017-12-05 21:09:53 +00:00
const auto threadBit = GetThreadBit ( thread ) ;
2017-10-08 21:03:38 +00:00
2018-02-13 13:57:47 +00:00
auto vbegin = std : : lower_bound ( tl . begin ( ) , tl . end ( ) , m_zvStart - delay , [ ] ( const auto & l , const auto & r ) { return l - > time < r ; } ) ;
const auto vend = std : : lower_bound ( vbegin , tl . end ( ) , m_zvEnd + resolution , [ ] ( const auto & l , const auto & r ) { return l - > time < r ; } ) ;
2017-10-05 21:18:24 +00:00
if ( vbegin > tl . begin ( ) ) vbegin - - ;
2017-10-28 12:25:35 +00:00
const auto offset = _offset + ostep * cnt ;
2017-10-04 19:27:06 +00:00
2017-10-28 11:44:46 +00:00
LockState state = LockState : : Nothing ;
2017-12-17 17:00:15 +00:00
if ( lockmap . type = = LockType : : Lockable )
2017-10-08 21:03:38 +00:00
{
2017-12-17 17:00:15 +00:00
if ( ( * vbegin ) - > lockCount ! = 0 )
2017-10-08 21:03:38 +00:00
{
2017-12-17 17:00:15 +00:00
if ( ( * vbegin ) - > lockingThread = = thread )
{
state = AreOtherWaiting ( ( * vbegin ) - > waitList , threadBit ) ? LockState : : HasBlockingLock : LockState : : HasLock ;
}
else if ( IsThreadWaiting ( ( * vbegin ) - > waitList , threadBit ) )
{
state = LockState : : WaitLock ;
}
2017-10-08 21:03:38 +00:00
}
2017-12-17 17:00:15 +00:00
}
else
{
2017-12-17 17:44:31 +00:00
const auto ptr = ( LockEventShared * ) * vbegin ;
if ( ptr - > lockCount ! = 0 )
2017-12-17 17:00:15 +00:00
{
2017-12-17 17:44:31 +00:00
if ( ptr - > lockingThread = = thread )
2017-12-17 17:00:15 +00:00
{
2017-12-17 17:44:31 +00:00
state = ( AreOtherWaiting ( ptr - > waitList , threadBit ) | | AreOtherWaiting ( ptr - > waitShared , threadBit ) ) ? LockState : : HasBlockingLock : LockState : : HasLock ;
2017-12-17 17:00:15 +00:00
}
2017-12-17 17:44:31 +00:00
else if ( IsThreadWaiting ( ptr - > waitList , threadBit ) | | IsThreadWaiting ( ptr - > waitShared , threadBit ) )
2017-12-17 17:00:15 +00:00
{
state = LockState : : WaitLock ;
}
}
2017-12-17 17:44:31 +00:00
else if ( IsThreadWaiting ( ptr - > sharedList , threadBit ) )
2017-12-17 17:00:15 +00:00
{
2017-12-17 17:44:31 +00:00
state = ptr - > waitList ! = 0 ? LockState : : HasBlockingLock : LockState : : HasLock ;
2017-12-17 17:00:15 +00:00
}
2017-12-17 17:44:31 +00:00
else if ( ptr - > sharedList ! = 0 & & IsThreadWaiting ( ptr - > waitList , threadBit ) )
2017-10-08 21:03:38 +00:00
{
2017-10-28 11:44:46 +00:00
state = LockState : : WaitLock ;
2017-10-08 21:03:38 +00:00
}
}
2018-04-20 20:53:15 +00:00
const auto yPos = wpos . y + offset ;
if ( yPos + ostep > = yMin & & yPos < = yMax )
2017-10-05 21:18:24 +00:00
{
2018-04-20 20:53:15 +00:00
bool drawn = false ;
const auto & srcloc = m_worker . GetSourceLocation ( lockmap . srcloc ) ;
2017-10-28 13:15:07 +00:00
2018-04-20 20:53:15 +00:00
double pxend = 0 ;
2017-10-28 13:15:07 +00:00
for ( ; ; )
{
2018-04-20 20:53:15 +00:00
while ( vbegin < vend & & ( state = = LockState : : Nothing | | ( m_onlyContendedLocks & & state = = LockState : : HasLock ) ) )
2017-10-28 13:24:25 +00:00
{
2018-04-20 20:53:15 +00:00
vbegin = GetNextLockFunc ( vbegin , vend , state , threadBit ) ;
2017-10-28 13:24:25 +00:00
}
2018-04-20 20:53:15 +00:00
if ( vbegin > = vend ) break ;
2017-10-28 12:08:10 +00:00
2018-04-20 20:53:15 +00:00
assert ( state ! = LockState : : Nothing & & ( ! m_onlyContendedLocks | | state ! = LockState : : HasLock ) ) ;
drawn = true ;
2017-10-28 20:44:41 +00:00
2018-04-20 20:53:15 +00:00
LockState drawState = state ;
auto next = GetNextLockFunc ( vbegin , vend , state , threadBit ) ;
const auto t0 = ( * vbegin ) - > time ;
int64_t t1 = next = = tl . end ( ) ? m_lastTime : ( * next ) - > time ;
const auto px0 = std : : max ( pxend , ( t0 - m_zvStart ) * pxns ) ;
auto tx0 = px0 ;
double px1 = ( t1 - m_zvStart ) * pxns ;
uint64_t condensed = 0 ;
for ( ; ; )
2017-10-05 21:35:21 +00:00
{
2018-04-20 20:53:15 +00:00
if ( next > = vend | | px1 - tx0 > MinVisSize ) break ;
auto n = next ;
auto ns = state ;
while ( n < vend & & ( ns = = LockState : : Nothing | | ( m_onlyContendedLocks & & ns = = LockState : : HasLock ) ) )
{
n = GetNextLockFunc ( n , vend , ns , threadBit ) ;
}
if ( n > = vend ) break ;
if ( n = = next )
{
n = GetNextLockFunc ( n , vend , ns , threadBit ) ;
}
drawState = CombineLockState ( drawState , state ) ;
condensed + + ;
const auto t2 = n = = tl . end ( ) ? m_lastTime : ( * n ) - > time ;
const auto px2 = ( t2 - m_zvStart ) * pxns ;
if ( px2 - px1 > MinVisSize ) break ;
if ( drawState ! = ns & & px2 - px0 > MinVisSize & & ! ( ns = = LockState : : Nothing | | ( m_onlyContendedLocks & & ns = = LockState : : HasLock ) ) ) break ;
t1 = t2 ;
tx0 = px1 ;
px1 = px2 ;
next = n ;
state = ns ;
2017-10-28 12:08:10 +00:00
}
2018-04-20 20:53:15 +00:00
pxend = std : : max ( { px1 , px0 + MinVisSize , px0 + pxns * 0.5 } ) ;
bool itemHovered = hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( std : : max ( px0 , - 10.0 ) , offset ) , wpos + ImVec2 ( std : : min ( pxend , double ( w + 10 ) ) , offset + ty ) ) ;
if ( itemHovered )
2017-10-28 12:08:10 +00:00
{
2018-04-20 20:53:15 +00:00
if ( condensed > 1 )
2017-10-08 21:03:38 +00:00
{
2018-04-20 20:53:15 +00:00
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Multiple lock events (%s) " , RealToString ( condensed , true ) ) ;
ImGui : : EndTooltip ( ) ;
2017-10-08 21:03:38 +00:00
}
2017-10-28 13:33:34 +00:00
else
2017-10-08 21:03:38 +00:00
{
2018-04-20 20:53:15 +00:00
highlight . blocked = drawState = = LockState : : HasBlockingLock ;
if ( ! highlight . blocked )
2017-10-08 21:03:38 +00:00
{
2018-04-20 20:53:15 +00:00
highlight . id = v . first ;
highlight . begin = t0 ;
highlight . end = t1 ;
highlight . thread = thread ;
highlight . blocked = false ;
2017-10-08 21:03:38 +00:00
}
2018-04-20 20:53:15 +00:00
else
2017-10-08 21:03:38 +00:00
{
2018-04-20 20:53:15 +00:00
auto b = vbegin ;
while ( b ! = tl . begin ( ) )
2017-10-28 13:33:34 +00:00
{
2018-04-20 20:53:15 +00:00
if ( ( * b ) - > lockingThread ! = ( * vbegin ) - > lockingThread )
{
break ;
}
b - - ;
2017-10-28 13:33:34 +00:00
}
2018-04-20 20:53:15 +00:00
b + + ;
highlight . begin = ( * b ) - > time ;
2017-10-06 16:12:13 +00:00
2018-04-20 20:53:15 +00:00
auto e = next ;
while ( e ! = tl . end ( ) )
2017-10-28 13:33:34 +00:00
{
2018-04-20 20:53:15 +00:00
if ( ( * e ) - > lockingThread ! = ( * next ) - > lockingThread )
{
highlight . id = v . first ;
highlight . end = ( * e ) - > time ;
highlight . thread = thread ;
break ;
}
e + + ;
2017-10-28 13:33:34 +00:00
}
}
2018-04-20 20:53:15 +00:00
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Lock #% " PRIu32 " : %s " , v . first , m_worker . GetString ( srcloc . function ) ) ;
ImGui : : Separator ( ) ;
ImGui : : Text ( " %s:%i " , m_worker . GetString ( srcloc . file ) , srcloc . line ) ;
ImGui : : Text ( " Time: %s " , TimeToString ( t1 - t0 ) ) ;
2017-10-28 13:33:34 +00:00
ImGui : : Separator ( ) ;
2018-04-20 20:53:15 +00:00
uint32_t markloc = 0 ;
auto it = vbegin ;
for ( ; ; )
2017-10-28 13:33:34 +00:00
{
2018-04-20 20:53:15 +00:00
if ( ( * it ) - > thread = = thread )
2017-12-17 18:40:45 +00:00
{
2018-04-20 20:53:15 +00:00
if ( ( ( * it ) - > lockingThread = = thread | | IsThreadWaiting ( ( * it ) - > waitList , threadBit ) ) & & ( * it ) - > srcloc ! = 0 )
2017-12-17 18:40:45 +00:00
{
2018-04-20 20:53:15 +00:00
markloc = ( * it ) - > srcloc ;
break ;
2017-12-17 18:40:45 +00:00
}
}
2018-04-20 20:53:15 +00:00
if ( it = = tl . begin ( ) ) break ;
- - it ;
2017-10-28 13:33:34 +00:00
}
2018-04-20 20:53:15 +00:00
if ( markloc ! = 0 )
2017-10-28 13:33:34 +00:00
{
2018-04-20 20:53:15 +00:00
const auto & marklocdata = m_worker . GetSourceLocation ( markloc ) ;
ImGui : : Text ( " Lock event location: " ) ;
ImGui : : Text ( " %s " , m_worker . GetString ( marklocdata . function ) ) ;
ImGui : : Text ( " %s:%i " , m_worker . GetString ( marklocdata . file ) , marklocdata . line ) ;
ImGui : : Separator ( ) ;
2017-10-28 13:33:34 +00:00
}
2018-04-20 20:53:15 +00:00
if ( v . second . type = = LockType : : Lockable )
2017-10-28 13:33:34 +00:00
{
2018-04-20 20:53:15 +00:00
switch ( drawState )
2017-12-17 18:40:45 +00:00
{
2018-04-20 20:53:15 +00:00
case LockState : : HasLock :
if ( ( * vbegin ) - > lockCount = = 1 )
{
ImGui : : Text ( " Thread \" %s \" has lock. No other threads are waiting. " , m_worker . GetThreadString ( tid ) ) ;
}
else
{
ImGui : : Text ( " Thread \" %s \" has %i locks. No other threads are waiting. " , m_worker . GetThreadString ( tid ) , ( * vbegin ) - > lockCount ) ;
}
if ( ( * vbegin ) - > waitList ! = 0 )
{
assert ( ! AreOtherWaiting ( ( * next ) - > waitList , threadBit ) ) ;
ImGui : : Text ( " Recursive lock acquire in thread. " ) ;
}
break ;
case LockState : : HasBlockingLock :
2017-12-17 18:40:45 +00:00
{
2018-04-20 20:53:15 +00:00
if ( ( * vbegin ) - > lockCount = = 1 )
{
ImGui : : Text ( " Thread \" %s \" has lock. Blocked threads (%i): " , m_worker . GetThreadString ( tid ) , TracyCountBits ( ( * vbegin ) - > waitList ) ) ;
}
else
{
ImGui : : Text ( " Thread \" %s \" has %i locks. Blocked threads (%i): " , m_worker . GetThreadString ( tid ) , ( * vbegin ) - > lockCount , TracyCountBits ( ( * vbegin ) - > waitList ) ) ;
}
auto waitList = ( * vbegin ) - > waitList ;
2017-12-17 18:40:45 +00:00
int t = 0 ;
ImGui : : Indent ( ty ) ;
2018-04-20 20:53:15 +00:00
while ( waitList ! = 0 )
2017-12-17 18:40:45 +00:00
{
2018-04-20 20:53:15 +00:00
if ( waitList & 0x1 )
2017-12-17 18:40:45 +00:00
{
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " \" %s \" " , m_worker . GetThreadString ( lockmap . threadList [ t ] ) ) ;
2017-12-17 18:40:45 +00:00
}
2018-04-20 20:53:15 +00:00
waitList > > = 1 ;
2017-12-17 18:40:45 +00:00
t + + ;
}
ImGui : : Unindent ( ty ) ;
2018-04-20 20:53:15 +00:00
break ;
2017-12-17 18:40:45 +00:00
}
2018-04-20 20:53:15 +00:00
case LockState : : WaitLock :
2017-12-17 18:40:45 +00:00
{
2018-04-20 20:53:15 +00:00
if ( ( * vbegin ) - > lockCount > 0 )
{
ImGui : : Text ( " Thread \" %s \" is blocked by other thread: " , m_worker . GetThreadString ( tid ) ) ;
}
else
{
ImGui : : Text ( " Thread \" %s \" waits to obtain lock after release by thread: " , m_worker . GetThreadString ( tid ) ) ;
}
ImGui : : Indent ( ty ) ;
ImGui : : Text ( " \" %s \" " , m_worker . GetThreadString ( lockmap . threadList [ ( * vbegin ) - > lockingThread ] ) ) ;
ImGui : : Unindent ( ty ) ;
break ;
2017-12-17 18:40:45 +00:00
}
2018-04-20 20:53:15 +00:00
default :
assert ( false ) ;
break ;
2017-12-17 18:40:45 +00:00
}
2018-04-20 20:53:15 +00:00
}
else
{
const auto ptr = ( const LockEventShared * ) * vbegin ;
switch ( drawState )
2017-10-28 13:33:34 +00:00
{
2018-04-20 20:53:15 +00:00
case LockState : : HasLock :
assert ( ptr - > waitList = = 0 ) ;
if ( ptr - > sharedList = = 0 )
{
assert ( ptr - > lockCount = = 1 ) ;
ImGui : : Text ( " Thread \" %s \" has lock. No other threads are waiting. " , m_worker . GetThreadString ( tid ) ) ;
}
else if ( TracyCountBits ( ptr - > sharedList ) = = 1 )
{
ImGui : : Text ( " Thread \" %s \" has a sole shared lock. No other threads are waiting. " , m_worker . GetThreadString ( tid ) ) ;
}
else
{
ImGui : : Text ( " Thread \" %s \" has shared lock. No other threads are waiting. " , m_worker . GetThreadString ( tid ) ) ;
ImGui : : Text ( " Threads sharing the lock (%i): " , TracyCountBits ( ptr - > sharedList ) - 1 ) ;
auto sharedList = ptr - > sharedList ;
int t = 0 ;
ImGui : : Indent ( ty ) ;
while ( sharedList ! = 0 )
{
if ( sharedList & 0x1 & & t ! = thread )
{
ImGui : : Text ( " \" %s \" " , m_worker . GetThreadString ( lockmap . threadList [ t ] ) ) ;
}
sharedList > > = 1 ;
t + + ;
}
ImGui : : Unindent ( ty ) ;
}
break ;
case LockState : : HasBlockingLock :
{
if ( ptr - > sharedList = = 0 )
{
assert ( ptr - > lockCount = = 1 ) ;
ImGui : : Text ( " Thread \" %s \" has lock. Blocked threads (%i): " , m_worker . GetThreadString ( tid ) , TracyCountBits ( ptr - > waitList ) + TracyCountBits ( ptr - > waitShared ) ) ;
}
else if ( TracyCountBits ( ptr - > sharedList ) = = 1 )
{
ImGui : : Text ( " Thread \" %s \" has a sole shared lock. Blocked threads (%i): " , m_worker . GetThreadString ( tid ) , TracyCountBits ( ptr - > waitList ) + TracyCountBits ( ptr - > waitShared ) ) ;
}
else
{
ImGui : : Text ( " Thread \" %s \" has shared lock. " , m_worker . GetThreadString ( tid ) ) ;
ImGui : : Text ( " Threads sharing the lock (%i): " , TracyCountBits ( ptr - > sharedList ) - 1 ) ;
auto sharedList = ptr - > sharedList ;
int t = 0 ;
ImGui : : Indent ( ty ) ;
while ( sharedList ! = 0 )
{
if ( sharedList & 0x1 & & t ! = thread )
{
ImGui : : Text ( " \" %s \" " , m_worker . GetThreadString ( lockmap . threadList [ t ] ) ) ;
}
sharedList > > = 1 ;
t + + ;
}
ImGui : : Unindent ( ty ) ;
ImGui : : Text ( " Blocked threads (%i): " , TracyCountBits ( ptr - > waitList ) + TracyCountBits ( ptr - > waitShared ) ) ;
}
auto waitList = ptr - > waitList ;
2017-12-17 18:40:45 +00:00
int t = 0 ;
ImGui : : Indent ( ty ) ;
2018-04-20 20:53:15 +00:00
while ( waitList ! = 0 )
2017-12-17 18:40:45 +00:00
{
2018-04-20 20:53:15 +00:00
if ( waitList & 0x1 )
2017-12-17 18:40:45 +00:00
{
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " \" %s \" " , m_worker . GetThreadString ( lockmap . threadList [ t ] ) ) ;
2017-12-17 18:40:45 +00:00
}
2018-04-20 20:53:15 +00:00
waitList > > = 1 ;
t + + ;
}
auto waitShared = ptr - > waitShared ;
t = 0 ;
while ( waitShared ! = 0 )
{
if ( waitShared & 0x1 )
{
ImGui : : Text ( " \" %s \" " , m_worker . GetThreadString ( lockmap . threadList [ t ] ) ) ;
}
waitShared > > = 1 ;
2017-12-17 18:40:45 +00:00
t + + ;
}
ImGui : : Unindent ( ty ) ;
2018-04-20 20:53:15 +00:00
break ;
2017-10-28 13:33:34 +00:00
}
2018-04-20 20:53:15 +00:00
case LockState : : WaitLock :
2017-12-17 18:40:45 +00:00
{
2018-04-20 20:53:15 +00:00
assert ( ptr - > lockCount = = 0 | | ptr - > lockCount = = 1 ) ;
if ( ptr - > lockCount ! = 0 | | ptr - > sharedList ! = 0 )
2017-12-17 18:40:45 +00:00
{
2018-04-20 20:53:15 +00:00
ImGui : : Text ( " Thread \" %s \" is blocked by other threads (%i): " , m_worker . GetThreadString ( tid ) , ptr - > lockCount + TracyCountBits ( ptr - > sharedList ) ) ;
2017-12-17 18:40:45 +00:00
}
2018-04-20 20:53:15 +00:00
else
2017-12-17 18:40:45 +00:00
{
2018-04-20 20:53:15 +00:00
ImGui : : Text ( " Thread \" %s \" waits to obtain lock after release by thread: " , m_worker . GetThreadString ( tid ) ) ;
2017-12-17 18:40:45 +00:00
}
2018-04-20 20:53:15 +00:00
ImGui : : Indent ( ty ) ;
if ( ptr - > lockCount ! = 0 )
2017-12-17 18:40:45 +00:00
{
2018-04-20 20:53:15 +00:00
ImGui : : Text ( " \" %s \" " , m_worker . GetThreadString ( lockmap . threadList [ ptr - > lockingThread ] ) ) ;
}
auto sharedList = ptr - > sharedList ;
int t = 0 ;
while ( sharedList ! = 0 )
{
if ( sharedList & 0x1 )
{
ImGui : : Text ( " \" %s \" " , m_worker . GetThreadString ( lockmap . threadList [ t ] ) ) ;
}
sharedList > > = 1 ;
t + + ;
2017-12-17 18:40:45 +00:00
}
2018-04-20 20:53:15 +00:00
ImGui : : Unindent ( ty ) ;
break ;
}
default :
assert ( false ) ;
break ;
2017-12-17 18:40:45 +00:00
}
2017-12-10 19:53:20 +00:00
}
2018-04-20 20:53:15 +00:00
ImGui : : EndTooltip ( ) ;
2017-10-05 21:35:21 +00:00
}
2017-10-06 16:25:30 +00:00
}
2018-04-20 20:53:15 +00:00
const auto cfilled = drawState = = LockState : : HasLock ? 0xFF228A22 : ( drawState = = LockState : : HasBlockingLock ? 0xFF228A8A : 0xFF2222BD ) ;
draw - > AddRectFilled ( wpos + ImVec2 ( std : : max ( px0 , - 10.0 ) , offset ) , wpos + ImVec2 ( std : : min ( pxend , double ( w + 10 ) ) , offset + ty ) , cfilled ) ;
if ( m_lockHighlight . thread ! = thread & & ( drawState = = LockState : : HasBlockingLock ) ! = m_lockHighlight . blocked & & next ! = tl . end ( ) & & m_lockHighlight . id = = int64_t ( v . first ) & & m_lockHighlight . begin < = ( * vbegin ) - > time & & m_lockHighlight . end > = ( * next ) - > time )
{
const auto t = uint8_t ( ( sin ( std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : system_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) * 0.01 ) * 0.5 + 0.5 ) * 255 ) ;
draw - > AddRect ( wpos + ImVec2 ( std : : max ( px0 , - 10.0 ) , offset ) , wpos + ImVec2 ( std : : min ( pxend , double ( w + 10 ) ) , offset + ty ) , 0x00FFFFFF | ( t < < 24 ) , 0.f , - 1 , 2.f ) ;
}
else if ( condensed = = 0 )
{
const auto coutline = drawState = = LockState : : HasLock ? 0xFF3BA33B : ( drawState = = LockState : : HasBlockingLock ? 0xFF3BA3A3 : 0xFF3B3BD6 ) ;
draw - > AddRect ( wpos + ImVec2 ( std : : max ( px0 , - 10.0 ) , offset ) , wpos + ImVec2 ( std : : min ( pxend , double ( w + 10 ) ) , offset + ty ) , coutline ) ;
}
2017-11-07 00:51:30 +00:00
2018-04-20 20:53:15 +00:00
const auto rx0 = ( t0 - m_zvStart ) * pxns ;
if ( dsz > = MinVisSize )
{
draw - > AddRectFilled ( wpos + ImVec2 ( rx0 , offset ) , wpos + ImVec2 ( std : : min ( rx0 + dsz , px1 ) , offset + ty ) , 0x882222DD ) ;
}
if ( rsz > = MinVisSize )
{
draw - > AddLine ( wpos + ImVec2 ( rx0 + rsz , offset + round ( ty / 2 ) ) , wpos + ImVec2 ( rx0 - rsz , offset + round ( ty / 2 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( rx0 + rsz , offset + round ( ty / 4 ) ) , wpos + ImVec2 ( rx0 + rsz , offset + round ( 3 * ty / 4 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( rx0 - rsz , offset + round ( ty / 4 ) ) , wpos + ImVec2 ( rx0 - rsz , offset + round ( 3 * ty / 4 ) ) , 0xAAFFFFFF ) ;
2017-10-28 12:08:10 +00:00
2018-04-20 20:53:15 +00:00
draw - > AddLine ( wpos + ImVec2 ( px1 + rsz , offset + round ( ty / 2 ) ) , wpos + ImVec2 ( px1 - rsz , offset + round ( ty / 2 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( px1 + rsz , offset + round ( ty / 4 ) ) , wpos + ImVec2 ( px1 + rsz , offset + round ( 3 * ty / 4 ) ) , 0xAAFFFFFF ) ;
draw - > AddLine ( wpos + ImVec2 ( px1 - rsz , offset + round ( ty / 4 ) ) , wpos + ImVec2 ( px1 - rsz , offset + round ( 3 * ty / 4 ) ) , 0xAAFFFFFF ) ;
}
2017-10-05 21:18:24 +00:00
2018-04-20 20:53:15 +00:00
vbegin = next ;
}
2017-10-05 21:18:24 +00:00
2018-04-20 20:53:15 +00:00
if ( drawn )
2017-10-25 22:42:16 +00:00
{
2018-04-20 20:53:15 +00:00
char buf [ 1024 ] ;
sprintf ( buf , " % " PRIu32 " : %s " , v . first , m_worker . GetString ( srcloc . function ) ) ;
DrawTextContrast ( draw , wpos + ImVec2 ( 0 , offset ) , 0xFF8888FF , buf ) ;
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( 0 , offset ) , wpos + ImVec2 ( ty + ImGui : : CalcTextSize ( buf ) . x , offset + ty ) ) )
2017-10-25 22:42:16 +00:00
{
2018-04-20 20:53:15 +00:00
ImGui : : BeginTooltip ( ) ;
switch ( v . second . type )
{
case LockType : : Lockable :
ImGui : : Text ( " Type: lockable " ) ;
break ;
case LockType : : SharedLockable :
ImGui : : Text ( " Type: shared lockable " ) ;
break ;
default :
assert ( false ) ;
break ;
}
ImGui : : Text ( " Thread list: " ) ;
ImGui : : Separator ( ) ;
ImGui : : Indent ( ty ) ;
for ( const auto & t : v . second . threadList )
{
ImGui : : Text ( " %s " , m_worker . GetThreadString ( t ) ) ;
}
ImGui : : Unindent ( ty ) ;
ImGui : : Separator ( ) ;
ImGui : : Text ( " Lock events: %s " , RealToString ( v . second . timeline . size ( ) , true ) ) ;
ImGui : : EndTooltip ( ) ;
2017-10-25 22:42:16 +00:00
}
2018-04-20 20:53:15 +00:00
cnt + + ;
}
}
else
{
while ( vbegin < vend & & ( state = = LockState : : Nothing | | ( m_onlyContendedLocks & & state = = LockState : : HasLock ) ) )
{
vbegin = GetNextLockFunc ( vbegin , vend , state , threadBit ) ;
2017-10-25 22:42:16 +00:00
}
2018-04-20 20:53:15 +00:00
if ( vbegin < vend ) cnt + + ;
2017-10-04 19:27:06 +00:00
}
}
return cnt ;
}
2017-10-13 13:15:57 +00:00
enum { PlotHeight = 100 } ;
2017-10-13 12:54:32 +00:00
2018-04-20 21:00:26 +00:00
int View : : DrawPlots ( int offset , double pxns , const ImVec2 & wpos , bool hover , float yMin , float yMax )
2017-10-13 13:15:57 +00:00
{
2017-11-26 16:27:51 +00:00
enum { MaxPoints = 512 } ;
float tmpvec [ MaxPoints * 2 ] ;
2017-10-13 12:54:32 +00:00
const auto w = ImGui : : GetWindowContentRegionWidth ( ) - 1 ;
const auto ty = ImGui : : GetFontSize ( ) ;
auto draw = ImGui : : GetWindowDrawList ( ) ;
2017-10-13 13:41:20 +00:00
const auto to = 9.f ;
const auto th = ( ty - to ) * sqrt ( 3 ) * 0.5 ;
2017-10-18 20:29:59 +00:00
const auto nspx = 1.0 / pxns ;
2017-10-13 12:54:32 +00:00
2018-02-13 13:57:47 +00:00
for ( const auto & v : m_worker . GetPlots ( ) )
2017-10-13 12:54:32 +00:00
{
2018-02-13 13:57:47 +00:00
if ( ! Visible ( v ) ) continue ;
2017-10-13 13:36:16 +00:00
assert ( ! v - > data . empty ( ) ) ;
2018-02-13 13:57:47 +00:00
bool & showFull = ShowFull ( v ) ;
2017-10-13 12:54:32 +00:00
2018-04-28 14:44:36 +00:00
float txtx ;
2018-04-20 21:00:26 +00:00
auto yPos = wpos . y + offset ;
if ( yPos + ty > = yMin & & yPos < = yMax )
2017-10-13 13:41:20 +00:00
{
2018-04-20 21:00:26 +00:00
if ( showFull )
2017-10-13 13:44:24 +00:00
{
2018-04-20 21:00:26 +00:00
draw - > AddTriangleFilled ( wpos + ImVec2 ( to / 2 , offset + to / 2 ) , wpos + ImVec2 ( ty - to / 2 , offset + to / 2 ) , wpos + ImVec2 ( ty * 0.5 , offset + to / 2 + th ) , 0xFF44DDDD ) ;
2017-10-13 13:44:24 +00:00
}
2018-04-20 21:00:26 +00:00
else
{
draw - > AddTriangle ( wpos + ImVec2 ( to / 2 , offset + to / 2 ) , wpos + ImVec2 ( to / 2 , offset + ty - to / 2 ) , wpos + ImVec2 ( to / 2 + th , offset + ty * 0.5 ) , 0xFF226E6E ) ;
}
2018-04-28 13:49:51 +00:00
const auto txt = GetPlotName ( v ) ;
2018-04-28 14:44:36 +00:00
txtx = ImGui : : CalcTextSize ( txt ) . x ;
2018-04-20 21:00:26 +00:00
draw - > AddText ( wpos + ImVec2 ( ty , offset ) , showFull ? 0xFF44DDDD : 0xFF226E6E , txt ) ;
draw - > AddLine ( wpos + ImVec2 ( 0 , offset + ty - 1 ) , wpos + ImVec2 ( w , offset + ty - 1 ) , 0x8844DDDD ) ;
2017-10-13 13:44:24 +00:00
2018-04-28 14:44:36 +00:00
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( 0 , offset ) , wpos + ImVec2 ( ty + txtx , offset + ty ) ) )
2018-04-20 21:00:26 +00:00
{
if ( ImGui : : IsMouseClicked ( 0 ) )
{
showFull = ! showFull ;
}
2017-10-13 13:55:09 +00:00
2018-04-20 21:00:26 +00:00
const auto tr = v - > data . back ( ) . time - v - > data . front ( ) . time ;
2017-10-13 13:55:09 +00:00
2018-04-20 21:00:26 +00:00
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Plot \" %s \" " , txt ) ;
ImGui : : Separator ( ) ;
ImGui : : Text ( " Data points: %s " , RealToString ( v - > data . size ( ) , true ) ) ;
ImGui : : Text ( " Data range: %s " , RealToString ( v - > max - v - > min , true ) ) ;
ImGui : : Text ( " Min value: %s " , RealToString ( v - > min , true ) ) ;
ImGui : : Text ( " Max value: %s " , RealToString ( v - > max , true ) ) ;
ImGui : : Text ( " Time range: %s " , TimeToString ( tr ) ) ;
ImGui : : Text ( " Data/second: %s " , RealToString ( double ( v - > data . size ( ) ) / tr * 1000000000ll , true ) ) ;
const auto it = std : : lower_bound ( v - > data . begin ( ) , v - > data . end ( ) , v - > data . back ( ) . time - 1000000000ll * 10 , [ ] ( const auto & l , const auto & r ) { return l . time < r ; } ) ;
const auto tr10 = v - > data . back ( ) . time - it - > time ;
if ( tr10 ! = 0 )
{
ImGui : : Text ( " D/s (10s): %s " , RealToString ( double ( std : : distance ( it , v - > data . end ( ) ) ) / tr10 * 1000000000ll , true ) ) ;
}
2017-10-13 13:55:09 +00:00
2018-04-20 21:00:26 +00:00
ImGui : : EndTooltip ( ) ;
}
2017-10-13 13:41:20 +00:00
}
2017-10-13 12:54:32 +00:00
2017-10-13 13:41:20 +00:00
offset + = ty ;
2017-10-13 12:54:32 +00:00
2018-02-13 13:57:47 +00:00
if ( showFull )
2017-10-13 12:54:32 +00:00
{
2018-04-20 21:00:26 +00:00
auto yPos = wpos . y + offset ;
if ( yPos + PlotHeight > = yMin & & yPos < = yMax )
{
const auto & vec = v - > data ;
auto it = std : : lower_bound ( vec . begin ( ) , vec . end ( ) , m_zvStart - m_worker . GetDelay ( ) , [ ] ( const auto & l , const auto & r ) { return l . time < r ; } ) ;
auto end = std : : lower_bound ( it , vec . end ( ) , m_zvEnd + m_worker . GetResolution ( ) , [ ] ( const auto & l , const auto & r ) { return l . time < r ; } ) ;
2017-10-13 13:41:20 +00:00
2018-04-20 21:00:26 +00:00
if ( end ! = vec . end ( ) ) end + + ;
if ( it ! = vec . begin ( ) ) it - - ;
2017-10-13 13:41:20 +00:00
2018-04-20 21:00:26 +00:00
double min = it - > val ;
double max = it - > val ;
if ( std : : distance ( it , end ) > 1000000 )
2017-10-13 13:41:20 +00:00
{
2018-04-20 21:00:26 +00:00
min = v - > min ;
max = v - > max ;
}
else
{
auto tmp = it ;
+ + tmp ;
const auto sz = end - tmp ;
for ( ptrdiff_t i = 0 ; i < sz ; i + + )
{
min = tmp [ i ] . val < min ? tmp [ i ] . val : min ;
max = tmp [ i ] . val > max ? tmp [ i ] . val : max ;
}
tmp + = sz ;
2017-10-13 13:41:20 +00:00
}
2017-10-13 12:54:32 +00:00
2018-04-20 21:00:26 +00:00
const auto revrange = 1.0 / ( max - min ) ;
2017-10-19 19:04:57 +00:00
2018-04-20 21:00:26 +00:00
if ( it = = vec . begin ( ) )
2017-10-18 20:29:59 +00:00
{
2018-04-20 21:00:26 +00:00
const auto x = ( it - > time - m_zvStart ) * pxns ;
const auto y = PlotHeight - ( it - > val - min ) * revrange * PlotHeight ;
2018-05-27 17:51:45 +00:00
DrawPlotPoint ( wpos , x , y , offset , 0xFF44DDDD , hover , false , it , 0 , false , v - > type ) ;
2017-10-18 20:29:59 +00:00
}
2018-04-20 21:00:26 +00:00
auto prevx = it ;
auto prevy = it ;
+ + it ;
ptrdiff_t skip = 0 ;
while ( it < end )
2017-10-18 20:29:59 +00:00
{
2018-04-20 21:00:26 +00:00
const auto x0 = ( prevx - > time - m_zvStart ) * pxns ;
const auto x1 = ( it - > time - m_zvStart ) * pxns ;
const auto y0 = PlotHeight - ( prevy - > val - min ) * revrange * PlotHeight ;
const auto y1 = PlotHeight - ( it - > val - min ) * revrange * PlotHeight ;
2017-10-18 20:29:59 +00:00
2018-04-20 21:00:26 +00:00
draw - > AddLine ( wpos + ImVec2 ( x0 , offset + y0 ) , wpos + ImVec2 ( x1 , offset + y1 ) , 0xFF44DDDD ) ;
2017-10-19 17:43:27 +00:00
2018-04-20 21:00:26 +00:00
const auto rx = skip = = 0 ? 2.0 : ( skip = = 1 ? 2.5 : 4.0 ) ;
auto range = std : : upper_bound ( it , end , int64_t ( it - > time + nspx * rx ) , [ ] ( const auto & l , const auto & r ) { return l < r . time ; } ) ;
assert ( range > it ) ;
const auto rsz = std : : distance ( it , range ) ;
if ( rsz = = 1 )
2017-10-18 20:29:59 +00:00
{
2018-05-27 17:51:45 +00:00
DrawPlotPoint ( wpos , x1 , y1 , offset , 0xFF44DDDD , hover , true , it , prevy - > val , false , v - > type ) ;
2018-04-20 21:00:26 +00:00
prevx = it ;
prevy = it ;
+ + it ;
2017-10-18 20:29:59 +00:00
}
2018-04-20 21:00:26 +00:00
else
{
prevx = it ;
2017-10-18 20:29:59 +00:00
2018-04-20 21:00:26 +00:00
skip = rsz / MaxPoints ;
const auto skip1 = std : : max < ptrdiff_t > ( 1 , skip ) ;
const auto sz = rsz / skip1 + 1 ;
assert ( sz < = MaxPoints * 2 ) ;
2017-10-18 20:29:59 +00:00
2018-04-20 21:00:26 +00:00
auto dst = tmpvec ;
for ( ; ; )
2017-10-18 20:29:59 +00:00
{
2018-04-20 21:00:26 +00:00
* dst + + = float ( it - > val ) ;
if ( std : : distance ( it , range ) > skip1 )
{
it + = skip1 ;
}
else
{
break ;
}
2017-10-18 20:29:59 +00:00
}
2018-04-20 21:00:26 +00:00
pdqsort_branchless ( tmpvec , dst ) ;
draw - > AddLine ( wpos + ImVec2 ( x1 , offset + PlotHeight - ( tmpvec [ 0 ] - min ) * revrange * PlotHeight ) , wpos + ImVec2 ( x1 , offset + PlotHeight - ( dst [ - 1 ] - min ) * revrange * PlotHeight ) , 0xFF44DDDD ) ;
auto vit = tmpvec ;
while ( vit ! = dst )
2017-10-18 20:29:59 +00:00
{
2018-04-20 21:00:26 +00:00
auto vrange = std : : upper_bound ( vit , dst , * vit + 3.0 / ( revrange * PlotHeight ) , [ ] ( const auto & l , const auto & r ) { return l < r ; } ) ;
assert ( vrange > vit ) ;
if ( std : : distance ( vit , vrange ) = = 1 )
{
DrawPlotPoint ( wpos , x1 , PlotHeight - ( * vit - min ) * revrange * PlotHeight , offset , 0xFF44DDDD , hover , false , * vit , 0 , false ) ;
}
else
{
DrawPlotPoint ( wpos , x1 , PlotHeight - ( * vit - min ) * revrange * PlotHeight , offset , 0xFF44DDDD , hover , false , * vit , 0 , true ) ;
}
vit = vrange ;
2017-10-18 20:29:59 +00:00
}
2018-04-20 21:00:26 +00:00
prevy = it - 1 ;
}
2017-10-18 20:29:59 +00:00
}
2017-10-13 12:54:32 +00:00
2018-04-20 21:00:26 +00:00
char tmp [ 64 ] ;
2018-04-28 14:44:36 +00:00
if ( yPos + ty > = yMin & & yPos < = yMax )
{
sprintf ( tmp , " (y-range: %s) " , RealToString ( max - min , true ) ) ;
draw - > AddText ( wpos + ImVec2 ( ty * 1.5f + txtx , offset - ty ) , 0x8844DDDD , tmp ) ;
}
2018-04-20 21:00:26 +00:00
sprintf ( tmp , " %s " , RealToString ( max , true ) ) ;
DrawTextContrast ( draw , wpos + ImVec2 ( 0 , offset ) , 0x8844DDDD , tmp ) ;
offset + = PlotHeight - ty ;
sprintf ( tmp , " %s " , RealToString ( min , true ) ) ;
DrawTextContrast ( draw , wpos + ImVec2 ( 0 , offset ) , 0x8844DDDD , tmp ) ;
2017-11-26 01:31:48 +00:00
2018-04-20 21:00:26 +00:00
draw - > AddLine ( wpos + ImVec2 ( 0 , offset + ty - 1 ) , wpos + ImVec2 ( w , offset + ty - 1 ) , 0x8844DDDD ) ;
offset + = ty ;
}
else
{
offset + = PlotHeight ;
}
2017-10-13 12:54:32 +00:00
}
2017-10-13 13:41:20 +00:00
offset + = 0.2 * ty ;
2017-10-13 12:54:32 +00:00
}
return offset ;
}
2017-10-18 20:29:59 +00:00
void View : : DrawPlotPoint ( const ImVec2 & wpos , float x , float y , int offset , uint32_t color , bool hover , bool hasPrev , double val , double prev , bool merged )
2017-10-13 13:09:01 +00:00
{
auto draw = ImGui : : GetWindowDrawList ( ) ;
2017-10-18 20:29:59 +00:00
if ( merged )
{
draw - > AddRectFilled ( wpos + ImVec2 ( x - 1.5f , offset + y - 1.5f ) , wpos + ImVec2 ( x + 2.5f , offset + y + 2.5f ) , color ) ;
}
else
{
draw - > AddRect ( wpos + ImVec2 ( x - 1.5f , offset + y - 1.5f ) , wpos + ImVec2 ( x + 2.5f , offset + y + 2.5f ) , color ) ;
}
2017-10-13 13:15:57 +00:00
2017-10-21 11:47:32 +00:00
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( x - 2 , offset ) , wpos + ImVec2 ( x + 2 , offset + PlotHeight ) ) )
2017-10-13 13:15:57 +00:00
{
ImGui : : BeginTooltip ( ) ;
2017-10-18 18:33:49 +00:00
ImGui : : Text ( " Value: %s " , RealToString ( val , true ) ) ;
2017-10-13 13:15:57 +00:00
if ( hasPrev )
{
2017-10-18 18:33:49 +00:00
ImGui : : Text ( " Change: %s " , RealToString ( val - prev , true ) ) ;
2017-10-13 13:15:57 +00:00
}
ImGui : : EndTooltip ( ) ;
}
2017-10-13 13:09:01 +00:00
}
2018-05-27 17:51:45 +00:00
void View : : DrawPlotPoint ( const ImVec2 & wpos , float x , float y , int offset , uint32_t color , bool hover , bool hasPrev , const PlotItem * item , double prev , bool merged , PlotType type )
{
auto draw = ImGui : : GetWindowDrawList ( ) ;
if ( merged )
{
draw - > AddRectFilled ( wpos + ImVec2 ( x - 1.5f , offset + y - 1.5f ) , wpos + ImVec2 ( x + 2.5f , offset + y + 2.5f ) , color ) ;
}
else
{
draw - > AddRect ( wpos + ImVec2 ( x - 1.5f , offset + y - 1.5f ) , wpos + ImVec2 ( x + 2.5f , offset + y + 2.5f ) , color ) ;
}
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( x - 2 , offset ) , wpos + ImVec2 ( x + 2 , offset + PlotHeight ) ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Value: %s " , RealToString ( item - > val , true ) ) ;
if ( hasPrev )
{
2018-05-27 18:11:33 +00:00
const auto change = item - > val - prev ;
ImGui : : Text ( " Change: %s " , RealToString ( change , true ) ) ;
if ( type = = PlotType : : Memory )
{
auto & mem = m_worker . GetMemData ( ) ;
const MemEvent * ev = nullptr ;
if ( change > 0 )
{
auto it = std : : lower_bound ( mem . data . begin ( ) , mem . data . end ( ) , item - > time , [ ] ( const auto & lhs , const auto & rhs ) { return lhs . timeAlloc < rhs ; } ) ;
if ( it ! = mem . data . end ( ) & & it - > timeAlloc = = item - > time )
{
ev = it ;
}
}
else
{
const auto & data = mem . data ;
auto it = std : : lower_bound ( mem . frees . begin ( ) , mem . frees . end ( ) , item - > time , [ & data ] ( const auto & lhs , const auto & rhs ) { return data [ lhs ] . timeFree < rhs ; } ) ;
if ( it ! = mem . frees . end ( ) & & data [ * it ] . timeFree = = item - > time )
{
ev = & data [ * it ] ;
}
}
if ( ev )
{
ImGui : : Separator ( ) ;
ImGui : : Text ( " Address: 0x% " PRIx64 , ev - > ptr ) ;
2018-05-27 18:22:58 +00:00
ImGui : : Text ( " Appeared at %s " , TimeToString ( ev - > timeAlloc - m_worker . GetFrameBegin ( 0 ) ) ) ;
2018-05-27 18:11:33 +00:00
if ( change > 0 )
{
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (this event) " ) ;
}
if ( ev - > timeFree < 0 )
{
ImGui : : Text ( " Allocation still active " ) ;
}
else
{
2018-05-27 18:22:58 +00:00
ImGui : : Text ( " Freed at %s " , TimeToString ( ev - > timeFree - m_worker . GetFrameBegin ( 0 ) ) ) ;
2018-05-27 18:11:33 +00:00
if ( change < 0 )
{
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (this event) " ) ;
}
ImGui : : Text ( " Duration: %s " , TimeToString ( ev - > timeFree - ev - > timeAlloc ) ) ;
}
if ( change > 0 )
{
ImGui : : Text ( " Thread: %s " , m_worker . GetThreadString ( m_worker . DecompressThread ( ev - > threadAlloc ) ) ) ;
}
else
{
ImGui : : Text ( " Thread: %s " , m_worker . GetThreadString ( m_worker . DecompressThread ( ev - > threadFree ) ) ) ;
}
2018-05-27 18:17:20 +00:00
if ( ImGui : : IsMouseClicked ( 0 ) )
{
m_memInfo . show = true ;
sprintf ( m_memInfo . pattern , " 0x% " PRIx64 , ev - > ptr ) ;
m_memInfo . ptrFind = ev - > ptr ;
}
2018-05-27 18:11:33 +00:00
}
}
2018-05-27 17:51:45 +00:00
}
ImGui : : EndTooltip ( ) ;
}
}
2017-11-12 00:25:44 +00:00
void View : : DrawInfoWindow ( )
2017-09-29 19:49:14 +00:00
{
2017-11-12 00:25:44 +00:00
if ( m_zoneInfoWindow )
{
DrawZoneInfoWindow ( ) ;
}
else if ( m_gpuInfoWindow )
{
DrawGpuInfoWindow ( ) ;
}
}
2017-09-29 20:06:31 +00:00
2017-11-12 00:25:44 +00:00
void View : : DrawZoneInfoWindow ( )
{
2017-09-29 19:49:14 +00:00
auto & ev = * m_zoneInfoWindow ;
2017-09-29 20:06:31 +00:00
int dmul = 1 ;
2018-04-05 17:31:04 +00:00
const auto & srcloc = m_worker . GetSourceLocation ( ev . srcloc ) ;
2017-09-29 19:49:14 +00:00
bool show = true ;
2018-01-13 12:56:02 +00:00
ImGui : : Begin ( " Zone info " , & show ) ;
2017-09-29 20:13:22 +00:00
2017-09-29 20:01:30 +00:00
if ( ImGui : : Button ( " Zoom to zone " ) )
{
ZoomToZone ( ev ) ;
}
2017-09-30 11:41:03 +00:00
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Go to parent " ) )
{
2017-10-22 14:15:27 +00:00
auto parent = GetZoneParent ( ev ) ;
if ( parent )
2017-09-30 11:41:03 +00:00
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( * parent ) ;
2017-09-30 11:41:03 +00:00
}
}
2018-04-05 17:31:04 +00:00
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Statistics " ) )
{
m_findZone . ShowZone ( ev . srcloc , m_worker . GetString ( srcloc . name . active ? srcloc . name : srcloc . function ) ) ;
}
2018-05-02 17:25:52 +00:00
if ( ! m_zoneInfoStack . empty ( ) )
{
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Go back " ) )
{
m_zoneInfoWindow = m_zoneInfoStack . back_and_pop ( ) ;
}
}
2017-09-29 20:06:31 +00:00
ImGui : : Separator ( ) ;
2018-03-19 01:22:08 +00:00
const auto tid = GetZoneThread ( ev ) ;
2017-11-14 22:31:24 +00:00
if ( srcloc . name . active )
2017-09-29 19:49:14 +00:00
{
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " Zone name: %s " , m_worker . GetString ( srcloc . name ) ) ;
2017-09-29 19:49:14 +00:00
}
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " Function: %s " , m_worker . GetString ( srcloc . function ) ) ;
ImGui : : Text ( " Location: %s:%i " , m_worker . GetString ( srcloc . file ) , srcloc . line ) ;
2018-03-19 01:22:08 +00:00
ImGui : : Text ( " Thread: %s " , m_worker . GetThreadString ( tid ) ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (id) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " 0x% " PRIX64 , tid ) ;
ImGui : : EndTooltip ( ) ;
}
2017-11-14 22:31:24 +00:00
if ( ev . text . active )
2017-09-29 19:49:14 +00:00
{
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " User text: %s " , m_worker . GetString ( ev . text ) ) ;
2017-09-29 20:06:31 +00:00
dmul + + ;
2017-09-29 19:49:14 +00:00
}
2017-09-29 20:06:31 +00:00
ImGui : : Separator ( ) ;
2018-02-13 13:57:47 +00:00
const auto end = m_worker . GetZoneEnd ( ev ) ;
2017-09-29 20:13:22 +00:00
const auto ztime = end - ev . start ;
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " Time from start of program: %s " , TimeToString ( ev . start - m_worker . GetFrameBegin ( 0 ) ) ) ;
2017-09-29 20:13:22 +00:00
ImGui : : Text ( " Execution time: %s " , TimeToString ( ztime ) ) ;
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " Without profiling: %s " , TimeToString ( ztime - m_worker . GetDelay ( ) * dmul ) ) ;
2017-09-29 20:13:22 +00:00
2018-05-02 15:46:09 +00:00
auto & mem = m_worker . GetMemData ( ) ;
if ( mem . plot )
{
ImGui : : Separator ( ) ;
2018-05-02 16:13:13 +00:00
const auto thread = m_worker . CompressThread ( tid ) ;
2018-05-02 16:06:27 +00:00
auto ait = std : : lower_bound ( mem . data . begin ( ) , mem . data . end ( ) , ev . start , [ ] ( const auto & l , const auto & r ) { return l . timeAlloc < r ; } ) ;
const auto aend = std : : upper_bound ( mem . data . begin ( ) , mem . data . end ( ) , end , [ ] ( const auto & l , const auto & r ) { return l < r . timeAlloc ; } ) ;
2018-05-02 15:46:09 +00:00
2018-05-02 16:06:27 +00:00
auto fit = std : : lower_bound ( mem . frees . begin ( ) , mem . frees . end ( ) , ev . start , [ & mem ] ( const auto & l , const auto & r ) { return mem . data [ l ] . timeFree < r ; } ) ;
const auto fend = std : : upper_bound ( mem . frees . begin ( ) , mem . frees . end ( ) , end , [ & mem ] ( const auto & l , const auto & r ) { return l < mem . data [ r ] . timeFree ; } ) ;
const auto aDist = std : : distance ( ait , aend ) ;
const auto fDist = std : : distance ( fit , fend ) ;
if ( aDist = = 0 & & fDist = = 0 )
2018-05-02 15:46:09 +00:00
{
ImGui : : Text ( " No memory events. " ) ;
}
else
{
2018-05-02 16:06:27 +00:00
int64_t cAlloc = 0 ;
int64_t cFree = 0 ;
2018-05-02 16:13:13 +00:00
int64_t nAlloc = 0 ;
int64_t nFree = 0 ;
2018-05-02 16:06:27 +00:00
2018-05-02 17:03:34 +00:00
auto ait2 = ait ;
auto fit2 = fit ;
2018-05-02 16:06:27 +00:00
while ( ait ! = aend )
{
2018-05-02 16:13:13 +00:00
if ( ait - > threadAlloc = = thread )
{
cAlloc + = ait - > size ;
nAlloc + + ;
}
2018-05-02 16:06:27 +00:00
ait + + ;
}
while ( fit ! = fend )
{
2018-05-02 16:13:13 +00:00
if ( mem . data [ * fit ] . threadFree = = thread )
{
cFree + = mem . data [ * fit ] . size ;
nFree + + ;
}
2018-05-02 16:06:27 +00:00
fit + + ;
2018-05-02 15:46:09 +00:00
}
2018-05-02 16:13:13 +00:00
if ( nAlloc = = 0 & & nFree = = 0 )
{
ImGui : : Text ( " No memory events. " ) ;
}
else
{
ImGui : : Text ( " %s memory events. " , RealToString ( nAlloc + nFree , true ) ) ;
ImGui : : Text ( " %s allocs, %s frees. " , RealToString ( nAlloc , true ) , RealToString ( nFree , true ) ) ;
ImGui : : Text ( " Memory allocated: %s bytes " , RealToString ( cAlloc , true ) ) ;
ImGui : : Text ( " Memory freed: %s bytes " , RealToString ( cFree , true ) ) ;
2018-05-02 16:41:11 +00:00
ImGui : : Text ( " Overall change: %s bytes " , RealToString ( cAlloc - cFree , true ) ) ;
2018-05-02 17:03:34 +00:00
if ( ImGui : : TreeNode ( " Allocations list " ) )
{
std : : vector < const MemEvent * > v ;
v . reserve ( nAlloc + nFree ) ;
auto it = ait2 ;
while ( it ! = aend )
{
if ( it - > threadAlloc = = thread )
{
v . emplace_back ( it ) ;
}
it + + ;
}
while ( fit2 ! = fend )
{
const auto ptr = & mem . data [ * fit2 + + ] ;
if ( ptr - > threadFree = = thread )
{
if ( ptr < ait2 | | ptr > = aend )
{
v . emplace_back ( ptr ) ;
}
}
}
pdqsort_branchless ( v . begin ( ) , v . end ( ) , [ ] ( const auto & l , const auto & r ) { return l - > timeAlloc < r - > timeAlloc ; } ) ;
ListMemData < decltype ( v . begin ( ) ) > ( v . begin ( ) , v . end ( ) , [ ] ( auto & v ) {
ImGui : : Text ( " 0x% " PRIx64 , ( * v ) - > ptr ) ;
return * v ;
} ) ;
ImGui : : TreePop ( ) ;
}
2018-05-02 16:13:13 +00:00
}
2018-05-02 15:46:09 +00:00
}
}
2018-03-27 23:47:28 +00:00
ImGui : : Separator ( ) ;
std : : vector < const ZoneEvent * > zoneTrace ;
auto parent = GetZoneParent ( ev ) ;
while ( parent )
{
zoneTrace . emplace_back ( parent ) ;
parent = GetZoneParent ( * parent ) ;
}
if ( ! zoneTrace . empty ( ) )
{
bool expand = ImGui : : TreeNode ( " Zone trace " ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%s) " , RealToString ( zoneTrace . size ( ) , true ) ) ;
if ( expand )
{
2018-03-27 23:57:53 +00:00
int idx = 0 ;
2018-03-27 23:47:28 +00:00
for ( auto & v : zoneTrace )
{
const auto & srcloc = m_worker . GetSourceLocation ( v - > srcloc ) ;
const auto txt = srcloc . name . active ? m_worker . GetString ( srcloc . name ) : m_worker . GetString ( srcloc . function ) ;
2018-03-27 23:57:53 +00:00
ImGui : : PushID ( idx + + ) ;
2018-03-27 23:53:59 +00:00
auto sel = ImGui : : Selectable ( txt , false ) ;
auto hover = ImGui : : IsItemHovered ( ) ;
2018-03-27 23:47:28 +00:00
ImGui : : SameLine ( ) ;
2018-03-28 17:35:33 +00:00
ImGui : : TextDisabled ( " (%s) %s:%i " , TimeToString ( m_worker . GetZoneEnd ( * v ) - v - > start ) , m_worker . GetString ( srcloc . file ) , srcloc . line ) ;
2018-03-27 23:57:53 +00:00
ImGui : : PopID ( ) ;
2018-03-27 23:53:59 +00:00
if ( sel )
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( * v ) ;
2018-03-27 23:53:59 +00:00
}
if ( hover )
{
m_zoneHighlight = v ;
if ( ImGui : : IsMouseClicked ( 2 ) )
{
ZoomToZone ( * v ) ;
}
ZoneTooltip ( * v ) ;
}
2018-03-27 23:47:28 +00:00
}
ImGui : : TreePop ( ) ;
}
}
2017-09-29 20:32:03 +00:00
if ( ! ev . child . empty ( ) )
{
2018-03-27 23:47:20 +00:00
bool expand = ImGui : : TreeNode ( " Child zones " ) ;
2018-03-27 23:34:12 +00:00
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%s) " , RealToString ( ev . child . size ( ) , true ) ) ;
if ( expand )
2017-09-29 20:32:03 +00:00
{
2018-05-02 15:23:32 +00:00
auto ctt = std : : make_unique < uint64_t [ ] > ( ev . child . size ( ) ) ;
auto cti = std : : make_unique < uint32_t [ ] > ( ev . child . size ( ) ) ;
uint64_t ctime = 0 ;
for ( size_t i = 0 ; i < ev . child . size ( ) ; i + + )
{
const auto cend = m_worker . GetZoneEnd ( * ev . child [ i ] ) ;
const auto ct = cend - ev . child [ i ] - > start ;
ctime + = ct ;
ctt [ i ] = ct ;
cti [ i ] = uint32_t ( i ) ;
}
pdqsort_branchless ( cti . get ( ) , cti . get ( ) + ev . child . size ( ) , [ & ctt ] ( const auto & lhs , const auto & rhs ) { return ctt [ lhs ] > ctt [ rhs ] ; } ) ;
2018-03-27 23:34:12 +00:00
const auto ty = ImGui : : GetTextLineHeight ( ) ;
ImGui : : Columns ( 2 ) ;
2018-03-27 23:47:08 +00:00
ImGui : : TextColored ( ImVec4 ( 1.0f , 1.0f , 0.4f , 1.0f ) , " Self time " ) ;
2018-03-27 23:34:12 +00:00
ImGui : : NextColumn ( ) ;
char buf [ 128 ] ;
sprintf ( buf , " %s (%.2f%%) " , TimeToString ( ztime - ctime ) , double ( ztime - ctime ) / ztime * 100 ) ;
ImGui : : ProgressBar ( double ( ztime - ctime ) / ztime , ImVec2 ( - 1 , ty ) , buf ) ;
ImGui : : NextColumn ( ) ;
for ( size_t i = 0 ; i < ev . child . size ( ) ; i + + )
2017-09-29 20:38:38 +00:00
{
2018-03-27 23:34:12 +00:00
auto & cev = * ev . child [ cti [ i ] ] ;
const auto & csl = m_worker . GetSourceLocation ( cev . srcloc ) ;
const auto txt = csl . name . active ? m_worker . GetString ( csl . name ) : m_worker . GetString ( csl . function ) ;
bool b = false ;
2018-03-27 23:57:53 +00:00
ImGui : : PushID ( ( int ) i ) ;
2018-03-27 23:34:12 +00:00
if ( ImGui : : Selectable ( txt , & b , ImGuiSelectableFlags_SpanAllColumns ) )
2017-09-29 20:38:38 +00:00
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( cev ) ;
2017-09-29 20:38:38 +00:00
}
2018-03-27 23:34:12 +00:00
if ( ImGui : : IsItemHovered ( ) )
{
m_zoneHighlight = & cev ;
if ( ImGui : : IsMouseClicked ( 2 ) )
{
ZoomToZone ( cev ) ;
}
ZoneTooltip ( cev ) ;
}
2018-03-27 23:57:53 +00:00
ImGui : : PopID ( ) ;
2018-03-27 23:34:12 +00:00
ImGui : : NextColumn ( ) ;
const auto part = double ( ctt [ cti [ i ] ] ) / ztime ;
char buf [ 128 ] ;
sprintf ( buf , " %s (%.2f%%) " , TimeToString ( ctt [ cti [ i ] ] ) , part * 100 ) ;
ImGui : : ProgressBar ( part , ImVec2 ( - 1 , ty ) , buf ) ;
ImGui : : NextColumn ( ) ;
2017-09-29 20:38:38 +00:00
}
2018-03-27 23:34:12 +00:00
ImGui : : EndColumns ( ) ;
ImGui : : TreePop ( ) ;
2017-09-29 20:32:03 +00:00
}
}
2017-09-29 19:49:14 +00:00
ImGui : : End ( ) ;
2017-09-29 20:06:31 +00:00
2018-05-02 17:23:46 +00:00
if ( ! show )
{
m_zoneInfoWindow = nullptr ;
m_zoneInfoStack . clear ( ) ;
}
2017-09-29 19:49:14 +00:00
}
2017-11-12 00:25:44 +00:00
void View : : DrawGpuInfoWindow ( )
{
auto & ev = * m_gpuInfoWindow ;
bool show = true ;
2018-01-13 12:56:02 +00:00
ImGui : : Begin ( " Zone info " , & show ) ;
2017-11-12 00:25:44 +00:00
if ( ImGui : : Button ( " Zoom to zone " ) )
{
ZoomToZone ( ev ) ;
}
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Go to parent " ) )
{
auto parent = GetZoneParent ( ev ) ;
if ( parent )
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( * parent , m_gpuInfoWindowThread ) ;
2017-11-12 00:25:44 +00:00
}
}
2018-05-02 17:25:52 +00:00
if ( ! m_gpuInfoStack . empty ( ) )
{
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Go back " ) )
{
m_gpuInfoWindow = m_gpuInfoStack . back_and_pop ( ) ;
}
}
2017-11-12 00:25:44 +00:00
ImGui : : Separator ( ) ;
2018-03-19 15:11:44 +00:00
const auto tid = GetZoneThread ( ev ) ;
2018-02-13 13:57:47 +00:00
const auto & srcloc = m_worker . GetSourceLocation ( ev . srcloc ) ;
ImGui : : Text ( " Zone name: %s " , m_worker . GetString ( srcloc . name ) ) ;
ImGui : : Text ( " Function: %s " , m_worker . GetString ( srcloc . function ) ) ;
ImGui : : Text ( " Location: %s:%i " , m_worker . GetString ( srcloc . file ) , srcloc . line ) ;
2018-03-19 15:11:44 +00:00
ImGui : : Text ( " Thread: %s " , m_worker . GetThreadString ( tid ) ) ;
2018-03-19 01:22:08 +00:00
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (id) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
2018-03-19 15:11:44 +00:00
ImGui : : Text ( " 0x% " PRIX64 , tid ) ;
2018-03-19 01:22:08 +00:00
ImGui : : EndTooltip ( ) ;
}
2017-11-12 00:25:44 +00:00
ImGui : : Separator ( ) ;
2018-02-13 13:57:47 +00:00
const auto end = m_worker . GetZoneEnd ( ev ) ;
2017-11-12 00:25:44 +00:00
const auto ztime = end - ev . gpuStart ;
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " Time from start of program: %s " , TimeToString ( ev . gpuStart - m_worker . GetFrameBegin ( 0 ) ) ) ;
2017-11-12 00:25:44 +00:00
ImGui : : Text ( " GPU execution time: %s " , TimeToString ( ztime ) ) ;
ImGui : : Text ( " CPU command setup time: %s " , TimeToString ( ev . cpuEnd - ev . cpuStart ) ) ;
ImGui : : Text ( " Delay to execution: %s " , TimeToString ( ev . gpuStart - ev . cpuStart ) ) ;
2018-03-27 23:47:28 +00:00
ImGui : : Separator ( ) ;
std : : vector < const GpuEvent * > zoneTrace ;
auto parent = GetZoneParent ( ev ) ;
while ( parent )
{
zoneTrace . emplace_back ( parent ) ;
parent = GetZoneParent ( * parent ) ;
}
if ( ! zoneTrace . empty ( ) )
{
bool expand = ImGui : : TreeNode ( " Zone trace " ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%s) " , RealToString ( zoneTrace . size ( ) , true ) ) ;
if ( expand )
{
2018-03-27 23:57:53 +00:00
int idx = 0 ;
2018-03-27 23:47:28 +00:00
for ( auto & v : zoneTrace )
{
const auto & srcloc = m_worker . GetSourceLocation ( v - > srcloc ) ;
const auto txt = srcloc . name . active ? m_worker . GetString ( srcloc . name ) : m_worker . GetString ( srcloc . function ) ;
2018-03-27 23:57:53 +00:00
ImGui : : PushID ( idx + + ) ;
2018-03-27 23:53:59 +00:00
auto sel = ImGui : : Selectable ( txt , false ) ;
auto hover = ImGui : : IsItemHovered ( ) ;
2018-03-27 23:47:28 +00:00
ImGui : : SameLine ( ) ;
2018-03-28 17:35:33 +00:00
ImGui : : TextDisabled ( " (%s) %s:%i " , TimeToString ( m_worker . GetZoneEnd ( * v ) - v - > gpuStart ) , m_worker . GetString ( srcloc . file ) , srcloc . line ) ;
2018-03-27 23:57:53 +00:00
ImGui : : PopID ( ) ;
2018-03-27 23:53:59 +00:00
if ( sel )
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( * v , m_gpuInfoWindowThread ) ;
2018-03-27 23:53:59 +00:00
}
if ( hover )
{
m_gpuHighlight = v ;
if ( ImGui : : IsMouseClicked ( 2 ) )
{
ZoomToZone ( * v ) ;
}
ZoneTooltip ( * v ) ;
}
2018-03-27 23:47:28 +00:00
}
ImGui : : TreePop ( ) ;
}
}
2017-11-12 00:25:44 +00:00
if ( ! ev . child . empty ( ) )
{
2018-03-27 23:47:20 +00:00
bool expand = ImGui : : TreeNode ( " Child zones " ) ;
2018-03-27 23:34:12 +00:00
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%s) " , RealToString ( ev . child . size ( ) , true ) ) ;
if ( expand )
2017-11-12 00:25:44 +00:00
{
2018-05-02 15:23:32 +00:00
auto ctt = std : : make_unique < uint64_t [ ] > ( ev . child . size ( ) ) ;
auto cti = std : : make_unique < uint32_t [ ] > ( ev . child . size ( ) ) ;
uint64_t ctime = 0 ;
for ( size_t i = 0 ; i < ev . child . size ( ) ; i + + )
{
const auto cend = m_worker . GetZoneEnd ( * ev . child [ i ] ) ;
const auto ct = cend - ev . child [ i ] - > gpuStart ;
ctime + = ct ;
ctt [ i ] = ct ;
cti [ i ] = uint32_t ( i ) ;
}
pdqsort_branchless ( cti . get ( ) , cti . get ( ) + ev . child . size ( ) , [ & ctt ] ( const auto & lhs , const auto & rhs ) { return ctt [ lhs ] > ctt [ rhs ] ; } ) ;
2018-03-27 23:34:12 +00:00
const auto ty = ImGui : : GetTextLineHeight ( ) ;
ImGui : : Columns ( 2 ) ;
2018-03-27 23:47:08 +00:00
ImGui : : TextColored ( ImVec4 ( 1.0f , 1.0f , 0.4f , 1.0f ) , " Self time " ) ;
2018-03-27 23:34:12 +00:00
ImGui : : NextColumn ( ) ;
char buf [ 128 ] ;
sprintf ( buf , " %s (%.2f%%) " , TimeToString ( ztime - ctime ) , double ( ztime - ctime ) / ztime * 100 ) ;
ImGui : : ProgressBar ( double ( ztime - ctime ) / ztime , ImVec2 ( - 1 , ty ) , buf ) ;
ImGui : : NextColumn ( ) ;
for ( size_t i = 0 ; i < ev . child . size ( ) ; i + + )
2017-11-12 00:25:44 +00:00
{
2018-03-27 23:34:12 +00:00
auto & cev = * ev . child [ cti [ i ] ] ;
const auto & csl = m_worker . GetSourceLocation ( cev . srcloc ) ;
bool b = false ;
2018-03-27 23:57:53 +00:00
ImGui : : PushID ( ( int ) i ) ;
2018-03-27 23:34:12 +00:00
if ( ImGui : : Selectable ( m_worker . GetString ( csl . name ) , & b , ImGuiSelectableFlags_SpanAllColumns ) )
2017-11-12 00:25:44 +00:00
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( cev , m_gpuInfoWindowThread ) ;
2017-11-12 00:25:44 +00:00
}
2018-03-27 23:34:12 +00:00
if ( ImGui : : IsItemHovered ( ) )
{
m_gpuHighlight = & cev ;
if ( ImGui : : IsMouseClicked ( 2 ) )
{
ZoomToZone ( cev ) ;
}
ZoneTooltip ( cev ) ;
}
2018-03-27 23:57:53 +00:00
ImGui : : PopID ( ) ;
2018-03-27 23:34:12 +00:00
ImGui : : NextColumn ( ) ;
const auto part = double ( ctt [ cti [ i ] ] ) / ztime ;
char buf [ 128 ] ;
sprintf ( buf , " %s (%.2f%%) " , TimeToString ( ctt [ cti [ i ] ] ) , part * 100 ) ;
ImGui : : ProgressBar ( part , ImVec2 ( - 1 , ty ) , buf ) ;
ImGui : : NextColumn ( ) ;
2017-11-12 00:25:44 +00:00
}
2018-03-27 23:34:12 +00:00
ImGui : : EndColumns ( ) ;
ImGui : : TreePop ( ) ;
2017-11-12 00:25:44 +00:00
}
}
ImGui : : End ( ) ;
2018-05-02 17:23:46 +00:00
if ( ! show )
{
m_gpuInfoWindow = nullptr ;
m_gpuInfoStack . clear ( ) ;
}
2017-11-12 00:25:44 +00:00
}
2017-10-13 11:32:23 +00:00
void View : : DrawOptions ( )
{
2017-10-22 11:13:26 +00:00
const auto tw = ImGui : : GetFontSize ( ) ;
2018-01-13 12:56:02 +00:00
ImGui : : Begin ( " Options " , & m_showOptions , ImGuiWindowFlags_AlwaysAutoResize ) ;
2018-03-15 22:33:05 +00:00
2018-06-17 23:08:56 +00:00
const auto & gpuData = m_worker . GetGpuData ( ) ;
if ( ! gpuData . empty ( ) )
2017-11-30 14:34:52 +00:00
{
2018-03-15 22:33:05 +00:00
ImGui : : Checkbox ( " Draw GPU zones " , & m_drawGpuZones ) ;
const auto expand = ImGui : : TreeNode ( " GPU zones " ) ;
ImGui : : SameLine ( ) ;
2018-06-17 23:08:56 +00:00
ImGui : : TextDisabled ( " (%zu) " , gpuData . size ( ) ) ;
2018-03-15 22:33:05 +00:00
if ( expand )
{
2018-06-17 23:08:56 +00:00
for ( size_t i = 0 ; i < gpuData . size ( ) ; i + + )
2018-03-15 22:33:05 +00:00
{
2018-06-17 23:08:56 +00:00
const bool isVulkan = gpuData [ i ] - > thread = = 0 ;
2018-03-15 22:33:05 +00:00
char buf [ 1024 ] ;
2018-06-17 23:08:56 +00:00
if ( isVulkan )
{
sprintf ( buf , " Vulkan context %zu " , i ) ;
}
else
{
sprintf ( buf , " OpenGL context %zu " , i ) ;
}
ImGui : : Checkbox ( buf , & Visible ( gpuData [ i ] ) ) ;
2018-03-15 22:33:05 +00:00
}
ImGui : : TreePop ( ) ;
}
2017-11-30 14:34:52 +00:00
}
2018-03-15 22:33:05 +00:00
2017-11-11 21:56:05 +00:00
ImGui : : Checkbox ( " Draw CPU zones " , & m_drawZones ) ;
2017-10-22 11:56:05 +00:00
int ns = ( int ) m_namespace ;
2017-10-22 13:27:07 +00:00
ImGui : : Combo ( " Namespaces " , & ns , " Full \0 Shortened \0 None \0 " ) ;
2017-10-22 11:56:05 +00:00
m_namespace = ( Namespace ) ns ;
2018-03-15 22:33:05 +00:00
if ( ! m_worker . GetLockMap ( ) . empty ( ) )
2017-10-22 11:25:58 +00:00
{
2018-03-15 22:33:05 +00:00
ImGui : : Separator ( ) ;
ImGui : : Checkbox ( " Draw locks " , & m_drawLocks ) ;
ImGui : : SameLine ( ) ;
ImGui : : Checkbox ( " Only contended " , & m_onlyContendedLocks ) ;
const auto expand = ImGui : : TreeNode ( " Locks " ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%zu) " , m_worker . GetLockMap ( ) . size ( ) ) ;
if ( ImGui : : IsItemHovered ( ) )
2017-12-10 20:37:39 +00:00
{
2018-03-15 22:33:05 +00:00
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Locks with no recorded events are counted, but not listed. " ) ;
ImGui : : EndTooltip ( ) ;
}
if ( expand )
{
2018-04-09 14:15:40 +00:00
if ( ImGui : : SmallButton ( " Select all " ) )
{
for ( const auto & l : m_worker . GetLockMap ( ) )
{
Visible ( & l . second ) = true ;
}
}
ImGui : : SameLine ( ) ;
if ( ImGui : : SmallButton ( " Unselect all " ) )
{
for ( const auto & l : m_worker . GetLockMap ( ) )
{
Visible ( & l . second ) = false ;
}
}
2018-03-15 22:33:05 +00:00
for ( const auto & l : m_worker . GetLockMap ( ) )
{
if ( l . second . valid )
{
char buf [ 1024 ] ;
sprintf ( buf , " % " PRIu32 " : %s " , l . first , m_worker . GetString ( m_worker . GetSourceLocation ( l . second . srcloc ) . function ) ) ;
ImGui : : Checkbox ( buf , & Visible ( & l . second ) ) ;
}
}
ImGui : : TreePop ( ) ;
2017-12-10 20:37:39 +00:00
}
2017-10-22 11:25:58 +00:00
}
2018-03-15 22:33:05 +00:00
if ( ! m_worker . GetPlots ( ) . empty ( ) )
2017-10-22 11:17:34 +00:00
{
2018-03-15 22:33:05 +00:00
ImGui : : Separator ( ) ;
ImGui : : Checkbox ( " Draw plots " , & m_drawPlots ) ;
const auto expand = ImGui : : TreeNode ( " Plots " ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%zu) " , m_worker . GetPlots ( ) . size ( ) ) ;
if ( expand )
{
for ( const auto & p : m_worker . GetPlots ( ) )
{
2018-04-28 13:49:51 +00:00
ImGui : : Checkbox ( GetPlotName ( p ) , & Visible ( p ) ) ;
2018-03-15 22:33:05 +00:00
}
ImGui : : TreePop ( ) ;
}
2017-10-22 11:17:34 +00:00
}
2018-03-15 22:33:05 +00:00
2017-10-22 11:13:26 +00:00
ImGui : : Separator ( ) ;
2018-03-15 22:33:05 +00:00
const auto expand = ImGui : : TreeNode ( " Visible threads: " ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%zu) " , m_worker . GetThreadData ( ) . size ( ) ) ;
if ( expand )
2017-10-22 11:13:26 +00:00
{
2018-03-15 22:33:05 +00:00
int idx = 0 ;
for ( const auto & t : m_worker . GetThreadData ( ) )
{
ImGui : : PushID ( idx + + ) ;
ImGui : : Checkbox ( m_worker . GetThreadString ( t - > id ) , & Visible ( t ) ) ;
ImGui : : PopID ( ) ;
}
ImGui : : TreePop ( ) ;
2017-10-22 11:13:26 +00:00
}
2017-10-13 11:32:23 +00:00
ImGui : : End ( ) ;
}
2017-10-14 12:36:30 +00:00
void View : : DrawMessages ( )
{
2018-01-13 12:56:02 +00:00
ImGui : : Begin ( " Messages " , & m_showMessages ) ;
2018-05-25 19:13:56 +00:00
ImGui : : Columns ( 3 ) ;
2018-05-25 18:53:26 +00:00
ImGui : : Text ( " Time " ) ;
ImGui : : NextColumn ( ) ;
2018-05-25 19:13:56 +00:00
ImGui : : Text ( " Thread " ) ;
ImGui : : NextColumn ( ) ;
2018-05-25 18:53:26 +00:00
ImGui : : Text ( " Message " ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Separator ( ) ;
2018-02-13 13:57:47 +00:00
for ( const auto & v : m_worker . GetMessages ( ) )
2017-10-14 12:36:30 +00:00
{
2018-05-25 18:53:26 +00:00
ImGui : : PushID ( v ) ;
if ( ImGui : : Selectable ( TimeToString ( v - > time - m_worker . GetFrameBegin ( 0 ) ) , m_msgHighlight = = v , ImGuiSelectableFlags_SpanAllColumns ) )
2017-10-14 12:36:30 +00:00
{
2017-10-14 16:34:18 +00:00
const auto hr = std : : max < uint64_t > ( 1 , ( m_zvEnd - m_zvStart ) / 2 ) ;
2017-11-27 21:12:26 +00:00
ZoomToRange ( v - > time - hr , v - > time + hr ) ;
2017-10-14 12:36:30 +00:00
}
2018-05-25 18:53:26 +00:00
ImGui : : PopID ( ) ;
ImGui : : NextColumn ( ) ;
2018-05-25 19:13:56 +00:00
ImGui : : Text ( " %s " , m_worker . GetThreadString ( v - > thread ) ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (0x% " PRIX64 " ) " , v - > thread ) ;
ImGui : : NextColumn ( ) ;
2018-05-25 18:53:26 +00:00
ImGui : : TextWrapped ( " %s " , m_worker . GetString ( v - > ref ) ) ;
ImGui : : NextColumn ( ) ;
2017-10-14 12:36:30 +00:00
}
2018-05-25 18:53:26 +00:00
ImGui : : EndColumns ( ) ;
2017-10-14 12:36:30 +00:00
ImGui : : End ( ) ;
}
2018-01-17 11:49:50 +00:00
void View : : DrawFindZone ( )
{
ImGui : : Begin ( " Find Zone " , & m_findZone . show ) ;
2018-03-18 11:55:54 +00:00
# ifdef TRACY_NO_STATISTICS
ImGui : : TextWrapped ( " Collection of statistical data is disabled in this build. " ) ;
ImGui : : TextWrapped ( " Rebuild without the TRACY_NO_STATISTICS macro to enable zone search. " ) ;
# else
2018-04-30 01:54:09 +00:00
if ( ! m_worker . AreSourceLocationZonesReady ( ) )
{
ImGui : : TextWrapped ( " Please wait, computing data... " ) ;
ImGui : : End ( ) ;
return ;
}
2018-01-17 11:49:50 +00:00
ImGui : : InputText ( " " , m_findZone . pattern , 1024 ) ;
ImGui : : SameLine ( ) ;
2018-02-15 15:24:01 +00:00
const bool findClicked = ImGui : : Button ( " Find " ) ;
2018-01-17 11:49:50 +00:00
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Clear " ) )
{
2018-03-04 21:52:36 +00:00
m_findZone . Reset ( ) ;
2018-01-17 11:49:50 +00:00
}
2018-02-15 15:24:01 +00:00
if ( findClicked )
2018-01-17 11:49:50 +00:00
{
2018-03-04 21:52:36 +00:00
m_findZone . Reset ( ) ;
2018-01-17 11:49:50 +00:00
FindZones ( ) ;
}
2018-03-04 20:10:10 +00:00
if ( ! m_findZone . match . empty ( ) )
{
ImGui : : Separator ( ) ;
2018-03-24 01:45:24 +00:00
bool expand = ImGui : : TreeNodeEx ( " Matched source locations " , ImGuiTreeNodeFlags_DefaultOpen ) ;
2018-03-20 19:18:23 +00:00
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%zu) " , m_findZone . match . size ( ) ) ;
if ( expand )
2018-03-04 20:10:10 +00:00
{
2018-03-18 15:41:58 +00:00
auto prev = m_findZone . selMatch ;
2018-03-04 21:11:50 +00:00
int idx = 0 ;
for ( auto & v : m_findZone . match )
2018-03-04 20:10:10 +00:00
{
2018-03-18 15:07:07 +00:00
auto & srcloc = m_worker . GetSourceLocation ( v ) ;
2018-03-18 19:20:24 +00:00
auto & zones = m_worker . GetZonesForSourceLocation ( v ) . zones ;
2018-03-18 15:07:07 +00:00
ImGui : : PushID ( idx ) ;
ImGui : : RadioButton ( m_worker . GetString ( srcloc . name . active ? srcloc . name : srcloc . function ) , & m_findZone . selMatch , idx + + ) ;
2018-03-04 20:10:10 +00:00
ImGui : : SameLine ( ) ;
2018-03-18 15:11:08 +00:00
ImGui : : TextColored ( ImVec4 ( 0.5 , 0.5 , 0.5 , 1 ) , " (%s) %s:%i " , RealToString ( zones . size ( ) , true ) , m_worker . GetString ( srcloc . file ) , srcloc . line ) ;
2018-03-04 20:10:10 +00:00
ImGui : : PopID ( ) ;
}
ImGui : : TreePop ( ) ;
2018-03-18 15:41:58 +00:00
if ( m_findZone . selMatch ! = prev )
{
m_findZone . ResetThreads ( ) ;
}
2018-03-04 20:10:10 +00:00
}
2018-02-15 16:25:16 +00:00
ImGui : : Separator ( ) ;
2018-02-15 15:17:16 +00:00
2018-03-24 01:45:24 +00:00
if ( ImGui : : TreeNodeEx ( " Histogram " , ImGuiTreeNodeFlags_DefaultOpen ) )
2018-01-17 11:49:50 +00:00
{
2018-02-20 15:01:33 +00:00
const auto ty = ImGui : : GetFontSize ( ) ;
2018-03-18 19:20:24 +00:00
auto & zoneData = m_worker . GetZonesForSourceLocation ( m_findZone . match [ m_findZone . selMatch ] ) ;
auto & zones = zoneData . zones ;
2018-06-06 21:00:03 +00:00
const auto tmin = zoneData . min ;
const auto tmax = zoneData . max ;
2018-06-06 21:00:18 +00:00
const auto timeTotal = zoneData . total ;
2018-02-15 16:25:16 +00:00
2018-03-18 01:43:17 +00:00
if ( tmin ! = std : : numeric_limits < int64_t > : : max ( ) )
2018-03-05 19:15:18 +00:00
{
2018-03-18 01:43:17 +00:00
ImGui : : Checkbox ( " Log values " , & m_findZone . logVal ) ;
ImGui : : SameLine ( ) ;
ImGui : : Checkbox ( " Log time " , & m_findZone . logTime ) ;
ImGui : : SameLine ( ) ;
ImGui : : Checkbox ( " Cumulate time " , & m_findZone . cumulateTime ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (?) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Show total time taken by calls in each bin instead of call counts. " ) ;
ImGui : : EndTooltip ( ) ;
}
2018-02-16 12:28:40 +00:00
2018-03-18 01:43:17 +00:00
ImGui : : Text ( " Time range: %s - %s (%s) " , TimeToString ( tmin ) , TimeToString ( tmax ) , TimeToString ( tmax - tmin ) ) ;
2018-01-17 11:49:50 +00:00
2018-03-18 01:43:17 +00:00
const auto dt = double ( tmax - tmin ) ;
2018-03-20 15:28:55 +00:00
const auto selThread = m_findZone . selThread ;
const auto showThreads = m_findZone . showThreads ;
const auto cumulateTime = m_findZone . cumulateTime ;
2018-02-15 16:25:16 +00:00
2018-03-18 01:43:17 +00:00
if ( dt > 0 )
2018-02-16 12:09:24 +00:00
{
2018-03-18 01:43:17 +00:00
const auto w = ImGui : : GetContentRegionAvail ( ) . x ;
2018-02-16 13:42:16 +00:00
2018-03-18 01:43:17 +00:00
const auto numBins = int64_t ( w - 4 ) ;
if ( numBins > 1 )
2018-02-15 16:25:16 +00:00
{
2018-06-06 21:06:00 +00:00
if ( numBins ! = m_findZone . numBins )
{
m_findZone . numBins = numBins ;
m_findZone . bins = std : : make_unique < int64_t [ ] > ( numBins ) ;
m_findZone . binTime = std : : make_unique < int64_t [ ] > ( numBins ) ;
m_findZone . selBin = std : : make_unique < int64_t [ ] > ( numBins ) ;
}
2018-03-05 19:23:58 +00:00
2018-06-06 21:06:00 +00:00
const auto & bins = m_findZone . bins ;
const auto & binTime = m_findZone . binTime ;
const auto & selBin = m_findZone . selBin ;
2018-03-18 01:43:17 +00:00
2018-06-06 21:06:00 +00:00
memset ( bins . get ( ) , 0 , sizeof ( int64_t ) * numBins ) ;
memset ( binTime . get ( ) , 0 , sizeof ( int64_t ) * numBins ) ;
2018-03-20 13:37:58 +00:00
memset ( selBin . get ( ) , 0 , sizeof ( int64_t ) * numBins ) ;
2018-03-20 15:56:11 +00:00
int64_t selBinTime = 0 ;
2018-03-18 01:43:17 +00:00
int64_t selectionTime = 0 ;
if ( m_findZone . highlight . active )
2018-02-16 12:09:24 +00:00
{
2018-03-18 01:43:17 +00:00
const auto s = std : : min ( m_findZone . highlight . start , m_findZone . highlight . end ) ;
const auto e = std : : max ( m_findZone . highlight . start , m_findZone . highlight . end ) ;
2018-03-20 15:28:55 +00:00
if ( selThread ! = m_findZone . Unselected )
2018-02-16 14:34:22 +00:00
{
2018-03-20 13:37:58 +00:00
if ( m_findZone . logTime )
2018-03-05 19:23:58 +00:00
{
2018-06-05 23:54:17 +00:00
const auto tMinLog = log10fast ( tmin ) ;
const auto idt = numBins / ( log10fast ( tmax ) - tMinLog ) ;
2018-03-20 13:37:58 +00:00
for ( auto & ev : zones )
2018-03-18 01:43:17 +00:00
{
2018-03-20 13:37:58 +00:00
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
2018-06-05 23:54:17 +00:00
const auto bin = std : : min ( numBins - 1 , int64_t ( ( log10fast ( timeSpan ) - tMinLog ) * idt ) ) ;
2018-03-20 13:37:58 +00:00
bins [ bin ] + + ;
binTime [ bin ] + = timeSpan ;
2018-03-20 15:28:55 +00:00
if ( selThread = = ( showThreads ? ev . thread : ( ev . zone - > text . active ? ev . zone - > text . idx : std : : numeric_limits < uint64_t > : : max ( ) ) ) )
2018-03-20 13:37:58 +00:00
{
2018-03-20 15:28:55 +00:00
if ( cumulateTime ) selBin [ bin ] + = timeSpan ; else selBin [ bin ] + + ;
2018-03-20 15:56:11 +00:00
selBinTime + = timeSpan ;
2018-03-20 13:37:58 +00:00
}
if ( timeSpan > = s & & timeSpan < = e ) selectionTime + = timeSpan ;
}
}
}
else
{
const auto idt = numBins / dt ;
for ( auto & ev : zones )
{
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
const auto bin = std : : min ( numBins - 1 , int64_t ( ( timeSpan - tmin ) * idt ) ) ;
bins [ bin ] + + ;
binTime [ bin ] + = timeSpan ;
2018-03-20 15:28:55 +00:00
if ( selThread = = ( showThreads ? ev . thread : ( ev . zone - > text . active ? ev . zone - > text . idx : std : : numeric_limits < uint64_t > : : max ( ) ) ) )
2018-03-20 13:37:58 +00:00
{
2018-03-20 15:28:55 +00:00
if ( cumulateTime ) selBin [ bin ] + = timeSpan ; else selBin [ bin ] + + ;
2018-03-20 15:56:11 +00:00
selBinTime + = timeSpan ;
2018-03-20 13:37:58 +00:00
}
if ( timeSpan > = s & & timeSpan < = e ) selectionTime + = timeSpan ;
}
2018-03-18 01:43:17 +00:00
}
2018-03-05 19:23:58 +00:00
}
}
2018-03-18 01:43:17 +00:00
else
2018-03-05 19:23:58 +00:00
{
2018-03-20 13:37:58 +00:00
if ( m_findZone . logTime )
{
2018-06-05 23:54:17 +00:00
const auto tMinLog = log10fast ( tmin ) ;
const auto idt = numBins / ( log10fast ( tmax ) - tMinLog ) ;
2018-03-20 13:37:58 +00:00
for ( auto & ev : zones )
{
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
2018-06-05 23:54:17 +00:00
const auto bin = std : : min ( numBins - 1 , int64_t ( ( log10fast ( timeSpan ) - tMinLog ) * idt ) ) ;
2018-03-20 13:37:58 +00:00
bins [ bin ] + + ;
binTime [ bin ] + = timeSpan ;
if ( timeSpan > = s & & timeSpan < = e ) selectionTime + = timeSpan ;
}
}
}
else
2018-03-05 19:23:58 +00:00
{
2018-03-20 13:37:58 +00:00
const auto idt = numBins / dt ;
for ( auto & ev : zones )
2018-03-18 01:43:17 +00:00
{
2018-03-20 13:37:58 +00:00
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
const auto bin = std : : min ( numBins - 1 , int64_t ( ( timeSpan - tmin ) * idt ) ) ;
bins [ bin ] + + ;
binTime [ bin ] + = timeSpan ;
if ( timeSpan > = s & & timeSpan < = e ) selectionTime + = timeSpan ;
}
2018-03-18 01:43:17 +00:00
}
2018-03-05 19:23:58 +00:00
}
2018-02-16 14:34:22 +00:00
}
}
2018-03-18 01:43:17 +00:00
else
2018-02-16 14:34:22 +00:00
{
2018-03-20 15:28:55 +00:00
if ( selThread ! = m_findZone . Unselected )
2018-02-16 14:34:22 +00:00
{
2018-03-20 13:37:58 +00:00
if ( m_findZone . logTime )
{
2018-06-05 23:54:17 +00:00
const auto tMinLog = log10fast ( tmin ) ;
const auto idt = numBins / ( log10fast ( tmax ) - tMinLog ) ;
2018-03-20 13:37:58 +00:00
for ( auto & ev : zones )
{
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
2018-06-05 23:54:17 +00:00
const auto bin = std : : min ( numBins - 1 , int64_t ( ( log10fast ( timeSpan ) - tMinLog ) * idt ) ) ;
2018-03-20 13:37:58 +00:00
bins [ bin ] + + ;
binTime [ bin ] + = timeSpan ;
2018-03-20 15:28:55 +00:00
if ( selThread = = ( showThreads ? ev . thread : ( ev . zone - > text . active ? ev . zone - > text . idx : std : : numeric_limits < uint64_t > : : max ( ) ) ) )
2018-03-20 13:37:58 +00:00
{
2018-03-20 15:28:55 +00:00
if ( cumulateTime ) selBin [ bin ] + = timeSpan ; else selBin [ bin ] + + ;
2018-03-20 15:56:11 +00:00
selBinTime + = timeSpan ;
2018-03-20 13:37:58 +00:00
}
}
}
}
else
2018-03-05 19:23:58 +00:00
{
2018-03-20 13:37:58 +00:00
const auto idt = numBins / dt ;
for ( auto & ev : zones )
2018-03-18 01:43:17 +00:00
{
2018-03-20 13:37:58 +00:00
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
const auto bin = std : : min ( numBins - 1 , int64_t ( ( timeSpan - tmin ) * idt ) ) ;
bins [ bin ] + + ;
binTime [ bin ] + = timeSpan ;
2018-03-20 15:28:55 +00:00
if ( selThread = = ( showThreads ? ev . thread : ( ev . zone - > text . active ? ev . zone - > text . idx : std : : numeric_limits < uint64_t > : : max ( ) ) ) )
2018-03-20 13:37:58 +00:00
{
2018-03-20 15:28:55 +00:00
if ( cumulateTime ) selBin [ bin ] + = timeSpan ; else selBin [ bin ] + + ;
2018-03-20 15:56:11 +00:00
selBinTime + = timeSpan ;
2018-03-20 13:37:58 +00:00
}
}
2018-03-18 01:43:17 +00:00
}
2018-03-05 19:23:58 +00:00
}
}
2018-03-18 01:43:17 +00:00
else
2018-03-05 19:23:58 +00:00
{
2018-03-20 13:37:58 +00:00
if ( m_findZone . logTime )
2018-03-05 19:23:58 +00:00
{
2018-06-05 23:54:17 +00:00
const auto tMinLog = log10fast ( tmin ) ;
const auto idt = numBins / ( log10fast ( tmax ) - tMinLog ) ;
2018-03-20 13:37:58 +00:00
for ( auto & ev : zones )
2018-03-18 01:43:17 +00:00
{
2018-03-20 13:37:58 +00:00
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
2018-06-05 23:54:17 +00:00
const auto bin = std : : min ( numBins - 1 , int64_t ( ( log10fast ( timeSpan ) - tMinLog ) * idt ) ) ;
2018-03-20 13:37:58 +00:00
bins [ bin ] + + ;
binTime [ bin ] + = timeSpan ;
}
}
}
else
{
const auto idt = numBins / dt ;
for ( auto & ev : zones )
{
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
const auto bin = std : : min ( numBins - 1 , int64_t ( ( timeSpan - tmin ) * idt ) ) ;
bins [ bin ] + + ;
binTime [ bin ] + = timeSpan ;
}
2018-03-18 01:43:17 +00:00
}
2018-03-05 19:23:58 +00:00
}
2018-02-16 14:34:22 +00:00
}
2018-02-16 12:09:24 +00:00
}
2018-01-17 11:49:50 +00:00
2018-03-18 01:43:17 +00:00
int64_t maxVal ;
2018-03-20 15:28:55 +00:00
if ( cumulateTime )
2018-03-05 19:15:18 +00:00
{
2018-03-18 01:43:17 +00:00
maxVal = binTime [ 0 ] ;
for ( int i = 1 ; i < numBins ; i + + )
{
maxVal = std : : max ( maxVal , binTime [ i ] ) ;
}
2018-03-05 19:15:18 +00:00
}
2018-03-18 01:43:17 +00:00
else
2018-03-05 19:15:18 +00:00
{
2018-03-18 01:43:17 +00:00
maxVal = bins [ 0 ] ;
for ( int i = 1 ; i < numBins ; i + + )
{
maxVal = std : : max ( maxVal , bins [ i ] ) ;
}
2018-03-05 19:15:18 +00:00
}
2018-02-15 16:25:16 +00:00
2018-03-18 01:43:17 +00:00
ImGui : : Text ( " Total time: %s " , TimeToString ( timeTotal ) ) ;
ImGui : : SameLine ( ) ;
ImGui : : Spacing ( ) ;
ImGui : : SameLine ( ) ;
2018-03-20 15:28:55 +00:00
ImGui : : Text ( " Max counts: %s " , cumulateTime ? TimeToString ( maxVal ) : RealToString ( maxVal , true ) ) ;
2018-02-16 15:19:31 +00:00
2018-03-18 01:43:17 +00:00
if ( m_findZone . highlight . active )
{
const auto s = std : : min ( m_findZone . highlight . start , m_findZone . highlight . end ) ;
const auto e = std : : max ( m_findZone . highlight . start , m_findZone . highlight . end ) ;
ImGui : : Text ( " Selection range: %s - %s (%s) " , TimeToString ( s ) , TimeToString ( e ) , TimeToString ( e - s ) ) ;
}
else
{
ImGui : : Text ( " Selection range: none " ) ;
}
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (?) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Left draw on histogram to select range. Right click to clear selection. " ) ;
ImGui : : EndTooltip ( ) ;
}
if ( m_findZone . highlight . active )
{
ImGui : : Text ( " Selection time: %s " , TimeToString ( selectionTime ) ) ;
}
else
{
ImGui : : Text ( " Selection time: none " ) ;
}
2018-03-20 15:56:11 +00:00
if ( selThread ! = m_findZone . Unselected )
{
ImGui : : Text ( " Zone group time: %s " , TimeToString ( selBinTime ) ) ;
}
else
{
ImGui : : Text ( " Zone group time: none " ) ;
}
2018-03-05 19:23:58 +00:00
2018-03-18 01:43:17 +00:00
enum { Height = 200 } ;
const auto wpos = ImGui : : GetCursorScreenPos ( ) ;
2018-02-16 15:19:31 +00:00
2018-03-18 01:43:17 +00:00
ImGui : : InvisibleButton ( " ##histogram " , ImVec2 ( w , Height + round ( ty * 1.5 ) ) ) ;
const bool hover = ImGui : : IsItemHovered ( ) ;
2018-02-16 15:19:31 +00:00
2018-03-18 01:43:17 +00:00
auto draw = ImGui : : GetWindowDrawList ( ) ;
draw - > AddRectFilled ( wpos , wpos + ImVec2 ( w , Height ) , 0x22FFFFFF ) ;
draw - > AddRect ( wpos , wpos + ImVec2 ( w , Height ) , 0x88FFFFFF ) ;
2018-02-16 15:19:31 +00:00
2018-03-18 01:43:17 +00:00
if ( m_findZone . logVal )
2018-02-16 12:28:40 +00:00
{
2018-06-05 23:54:17 +00:00
const auto hAdj = double ( Height - 4 ) / log10fast ( maxVal + 1 ) ;
2018-03-18 01:43:17 +00:00
for ( int i = 0 ; i < numBins ; i + + )
2018-02-16 12:28:40 +00:00
{
2018-03-20 15:28:55 +00:00
const auto val = cumulateTime ? binTime [ i ] : bins [ i ] ;
2018-03-18 01:43:17 +00:00
if ( val > 0 )
{
2018-06-05 23:54:17 +00:00
draw - > AddLine ( wpos + ImVec2 ( 2 + i , Height - 3 ) , wpos + ImVec2 ( 2 + i , Height - 3 - log10fast ( val + 1 ) * hAdj ) , 0xFF22DDDD ) ;
2018-03-20 13:37:58 +00:00
if ( selBin [ i ] > 0 )
{
2018-06-05 23:54:17 +00:00
draw - > AddLine ( wpos + ImVec2 ( 2 + i , Height - 3 ) , wpos + ImVec2 ( 2 + i , Height - 3 - log10fast ( selBin [ i ] + 1 ) * hAdj ) , 0xFFDD7777 ) ;
2018-03-20 13:37:58 +00:00
}
2018-03-18 01:43:17 +00:00
}
2018-02-16 12:28:40 +00:00
}
}
2018-03-18 01:43:17 +00:00
else
2018-02-16 12:09:24 +00:00
{
2018-03-18 01:43:17 +00:00
const auto hAdj = double ( Height - 4 ) / maxVal ;
for ( int i = 0 ; i < numBins ; i + + )
2018-02-16 12:28:40 +00:00
{
2018-03-20 15:28:55 +00:00
const auto val = cumulateTime ? binTime [ i ] : bins [ i ] ;
2018-03-18 01:43:17 +00:00
if ( val > 0 )
{
draw - > AddLine ( wpos + ImVec2 ( 2 + i , Height - 3 ) , wpos + ImVec2 ( 2 + i , Height - 3 - val * hAdj ) , 0xFF22DDDD ) ;
2018-03-20 13:37:58 +00:00
if ( selBin [ i ] > 0 )
{
draw - > AddLine ( wpos + ImVec2 ( 2 + i , Height - 3 ) , wpos + ImVec2 ( 2 + i , Height - 3 - selBin [ i ] * hAdj ) , 0xFFDD7777 ) ;
}
2018-03-18 01:43:17 +00:00
}
2018-02-16 12:28:40 +00:00
}
2018-02-16 12:09:24 +00:00
}
2018-02-20 15:01:33 +00:00
2018-03-18 01:43:17 +00:00
const auto xoff = 2 ;
const auto yoff = Height + 1 ;
2018-02-20 15:01:33 +00:00
2018-03-18 01:43:17 +00:00
if ( m_findZone . logTime )
{
2018-06-05 23:54:17 +00:00
const auto ltmin = log10fast ( tmin ) ;
const auto ltmax = log10fast ( tmax ) ;
2018-03-18 01:43:17 +00:00
const auto start = int ( floor ( ltmin ) ) ;
const auto end = int ( ceil ( ltmax ) ) ;
2018-02-28 14:20:52 +00:00
2018-03-18 01:43:17 +00:00
const auto range = ltmax - ltmin ;
const auto step = w / range ;
auto offset = start - ltmin ;
int tw = 0 ;
int tx = 0 ;
2018-02-28 14:20:52 +00:00
2018-03-18 01:43:17 +00:00
auto tt = int64_t ( pow ( 10 , start ) ) ;
2018-02-28 14:20:52 +00:00
2018-03-18 01:43:17 +00:00
static const double logticks [ ] = { log10 ( 2 ) , log10 ( 3 ) , log10 ( 4 ) , log10 ( 5 ) , log10 ( 6 ) , log10 ( 7 ) , log10 ( 8 ) , log10 ( 9 ) } ;
2018-02-28 14:20:52 +00:00
2018-03-18 01:43:17 +00:00
for ( int i = start ; i < = end ; i + + )
2018-02-28 14:20:52 +00:00
{
2018-03-18 01:43:17 +00:00
const auto x = ( i - start + offset ) * step ;
if ( x > = 0 )
2018-02-28 14:20:52 +00:00
{
2018-03-18 01:43:17 +00:00
draw - > AddLine ( wpos + ImVec2 ( x , yoff ) , wpos + ImVec2 ( x , yoff + round ( ty * 0.5 ) ) , 0x66FFFFFF ) ;
if ( tw = = 0 | | x > tx + tw + ty * 1.1 )
{
tx = x ;
auto txt = TimeToStringInteger ( tt ) ;
draw - > AddText ( wpos + ImVec2 ( x , yoff + round ( ty * 0.5 ) ) , 0x66FFFFFF , txt ) ;
tw = ImGui : : CalcTextSize ( txt ) . x ;
}
2018-02-28 14:20:52 +00:00
}
2018-03-18 01:43:17 +00:00
for ( int j = 0 ; j < 8 ; j + + )
2018-02-28 14:20:52 +00:00
{
2018-03-18 01:43:17 +00:00
const auto xoff = x + logticks [ j ] * step ;
if ( xoff > = 0 )
{
draw - > AddLine ( wpos + ImVec2 ( xoff , yoff ) , wpos + ImVec2 ( xoff , yoff + round ( ty * 0.25 ) ) , 0x66FFFFFF ) ;
}
2018-02-28 14:20:52 +00:00
}
2018-03-18 01:43:17 +00:00
tt * = 10 ;
}
2018-02-28 14:20:52 +00:00
}
2018-03-18 01:43:17 +00:00
else
{
const auto pxns = numBins / dt ;
const auto nspx = 1.0 / pxns ;
2018-06-05 23:54:17 +00:00
const auto scale = std : : max ( 0.0f , round ( log10fast ( nspx ) + 2 ) ) ;
2018-03-18 01:43:17 +00:00
const auto step = pow ( 10 , scale ) ;
2018-02-20 15:01:33 +00:00
2018-03-18 01:43:17 +00:00
const auto dx = step * pxns ;
double x = 0 ;
int tw = 0 ;
int tx = 0 ;
2018-02-20 15:01:33 +00:00
2018-03-18 01:43:17 +00:00
const auto sstep = step / 10.0 ;
const auto sdx = dx / 10.0 ;
2018-02-20 15:01:33 +00:00
2018-03-18 01:43:17 +00:00
static const double linelen [ ] = { 0.5 , 0.25 , 0.25 , 0.25 , 0.25 , 0.375 , 0.25 , 0.25 , 0.25 , 0.25 } ;
2018-02-20 15:01:33 +00:00
2018-03-18 01:43:17 +00:00
int64_t tt = int64_t ( ceil ( tmin / sstep ) * sstep ) ;
const auto diff = tmin / sstep - int64_t ( tmin / sstep ) ;
const auto xo = ( diff = = 0 ? 0 : ( ( 1 - diff ) * sstep * pxns ) ) + xoff ;
int iter = int ( ceil ( ( tmin - int64_t ( tmin / step ) * step ) / sstep ) ) ;
2018-02-21 14:18:30 +00:00
2018-03-18 01:43:17 +00:00
while ( x < numBins )
2018-02-20 15:01:33 +00:00
{
2018-03-18 01:43:17 +00:00
draw - > AddLine ( wpos + ImVec2 ( xo + x , yoff ) , wpos + ImVec2 ( xo + x , yoff + round ( ty * linelen [ iter ] ) ) , 0x66FFFFFF ) ;
if ( iter = = 0 & & ( tw = = 0 | | x > tx + tw + ty * 1.1 ) )
{
tx = x ;
auto txt = TimeToStringInteger ( tt ) ;
draw - > AddText ( wpos + ImVec2 ( xo + x , yoff + round ( ty * 0.5 ) ) , 0x66FFFFFF , txt ) ;
tw = ImGui : : CalcTextSize ( txt ) . x ;
}
2018-02-20 15:01:33 +00:00
2018-03-18 01:43:17 +00:00
iter = ( iter + 1 ) % 10 ;
x + = sdx ;
tt + = sstep ;
}
2018-02-20 15:01:33 +00:00
}
2018-03-18 01:43:17 +00:00
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( 2 , 2 ) , wpos + ImVec2 ( w - 2 , Height + round ( ty * 1.5 ) ) ) )
{
2018-06-05 23:54:17 +00:00
const auto ltmin = log10fast ( tmin ) ;
const auto ltmax = log10fast ( tmax ) ;
2018-03-05 12:20:24 +00:00
2018-03-18 01:43:17 +00:00
auto & io = ImGui : : GetIO ( ) ;
draw - > AddLine ( ImVec2 ( io . MousePos . x , wpos . y ) , ImVec2 ( io . MousePos . x , wpos . y + Height - 2 ) , 0x33FFFFFF ) ;
2018-02-16 13:31:57 +00:00
2018-03-18 01:43:17 +00:00
const auto bin = double ( io . MousePos . x - wpos . x - 2 ) ;
int64_t t0 , t1 ;
if ( m_findZone . logTime )
{
t0 = int64_t ( pow ( 10 , ltmin + bin / numBins * ( ltmax - ltmin ) ) ) ;
2018-06-06 21:36:21 +00:00
// Hackfix for inability to select data in last bin.
// A proper solution would be nice.
if ( bin + 1 = = numBins )
{
t1 = tmax ;
}
else
{
t1 = int64_t ( pow ( 10 , ltmin + ( bin + 1 ) / numBins * ( ltmax - ltmin ) ) ) ;
}
2018-03-18 01:43:17 +00:00
}
else
{
t0 = int64_t ( tmin + bin / numBins * ( tmax - tmin ) ) ;
t1 = int64_t ( tmin + ( bin + 1 ) / numBins * ( tmax - tmin ) ) ;
}
2018-02-16 13:31:57 +00:00
2018-03-18 01:43:17 +00:00
int64_t tBefore = 0 ;
for ( int i = 0 ; i < bin ; i + + )
{
tBefore + = binTime [ i ] ;
}
2018-02-16 13:42:16 +00:00
2018-03-18 01:43:17 +00:00
int64_t tAfter = 0 ;
for ( int i = bin + 1 ; i < numBins ; i + + )
{
tAfter + = binTime [ i ] ;
}
2018-02-16 13:42:16 +00:00
2018-03-18 01:43:17 +00:00
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Time range: %s - %s " , TimeToString ( t0 ) , TimeToString ( t1 ) ) ;
ImGui : : Text ( " Count: % " PRIu64 , bins [ bin ] ) ;
ImGui : : Text ( " Time spent in bin: %s " , TimeToString ( binTime [ bin ] ) ) ;
ImGui : : Text ( " Time spent in the left bins: %s " , TimeToString ( tBefore ) ) ;
ImGui : : Text ( " Time spent in the right bins: %s " , TimeToString ( tAfter ) ) ;
ImGui : : EndTooltip ( ) ;
2018-03-04 21:52:36 +00:00
2018-03-18 01:43:17 +00:00
if ( ImGui : : IsMouseClicked ( 1 ) )
{
m_findZone . highlight . active = false ;
2018-03-18 15:41:58 +00:00
m_findZone . ResetThreads ( ) ;
2018-03-18 01:43:17 +00:00
}
else if ( ImGui : : IsMouseClicked ( 0 ) )
{
m_findZone . highlight . active = true ;
m_findZone . highlight . start = t0 ;
m_findZone . highlight . end = t1 ;
}
else if ( ImGui : : IsMouseDragging ( 0 , 0 ) )
{
m_findZone . highlight . end = t1 > m_findZone . highlight . start ? t1 : t0 ;
2018-03-18 15:41:58 +00:00
m_findZone . ResetThreads ( ) ;
2018-03-18 01:43:17 +00:00
}
2018-03-04 21:52:36 +00:00
}
2018-03-18 01:43:17 +00:00
if ( m_findZone . highlight . active & & m_findZone . highlight . start ! = m_findZone . highlight . end )
2018-03-04 21:52:36 +00:00
{
2018-03-18 01:43:17 +00:00
const auto s = std : : min ( m_findZone . highlight . start , m_findZone . highlight . end ) ;
const auto e = std : : max ( m_findZone . highlight . start , m_findZone . highlight . end ) ;
2018-03-04 21:52:36 +00:00
2018-03-18 01:43:17 +00:00
float t0 , t1 ;
if ( m_findZone . logTime )
{
2018-06-05 23:54:17 +00:00
const auto ltmin = log10fast ( tmin ) ;
const auto ltmax = log10fast ( tmax ) ;
2018-03-04 21:52:36 +00:00
2018-06-05 23:54:17 +00:00
t0 = ( log10fast ( s ) - ltmin ) / float ( ltmax - ltmin ) * numBins ;
t1 = ( log10fast ( e ) - ltmin ) / float ( ltmax - ltmin ) * numBins ;
2018-03-18 01:43:17 +00:00
}
else
{
t0 = ( s - tmin ) / float ( tmax - tmin ) * numBins ;
t1 = ( e - tmin ) / float ( tmax - tmin ) * numBins ;
}
2018-03-05 12:20:24 +00:00
2018-03-18 01:43:17 +00:00
draw - > AddRectFilled ( wpos + ImVec2 ( 2 + t0 , 1 ) , wpos + ImVec2 ( 2 + t1 , Height - 1 ) , 0x22DD8888 ) ;
draw - > AddRect ( wpos + ImVec2 ( 2 + t0 , 1 ) , wpos + ImVec2 ( 2 + t1 , Height - 1 ) , 0x44DD8888 ) ;
2018-03-04 21:52:36 +00:00
}
2018-02-16 13:31:57 +00:00
}
2018-02-15 16:25:16 +00:00
}
}
ImGui : : TreePop ( ) ;
}
ImGui : : Separator ( ) ;
2018-03-04 17:44:33 +00:00
ImGui : : Text ( " Found zones: " ) ;
2018-03-19 15:01:36 +00:00
ImGui : : SameLine ( ) ;
if ( m_findZone . showThreads )
{
if ( ImGui : : SmallButton ( " Group by user text " ) )
{
m_findZone . showThreads = false ;
2018-03-20 13:37:58 +00:00
m_findZone . selThread = m_findZone . Unselected ;
2018-03-19 15:01:36 +00:00
m_findZone . ResetThreads ( ) ;
}
}
else
{
if ( ImGui : : SmallButton ( " Group by threads " ) )
{
m_findZone . showThreads = true ;
2018-03-20 13:37:58 +00:00
m_findZone . selThread = m_findZone . Unselected ;
2018-03-19 15:01:36 +00:00
m_findZone . ResetThreads ( ) ;
}
}
2018-03-20 16:19:48 +00:00
ImGui : : SameLine ( ) ;
if ( m_findZone . sortByCounts )
{
if ( ImGui : : SmallButton ( " Sort by order " ) )
{
m_findZone . sortByCounts = false ;
}
}
else
{
if ( ImGui : : SmallButton ( " Sort by counts " ) )
{
m_findZone . sortByCounts = true ;
}
}
2018-04-14 13:21:22 +00:00
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (?) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Left click to highlight entry. Right click to clear selection. " ) ;
ImGui : : EndTooltip ( ) ;
}
2018-03-04 17:44:33 +00:00
2018-03-18 19:20:24 +00:00
auto & zones = m_worker . GetZonesForSourceLocation ( m_findZone . match [ m_findZone . selMatch ] ) . zones ;
2018-03-18 15:41:58 +00:00
auto sz = zones . size ( ) ;
2018-03-18 20:03:36 +00:00
auto processed = m_findZone . processed ;
2018-03-20 15:28:55 +00:00
const auto hmin = std : : min ( m_findZone . highlight . start , m_findZone . highlight . end ) ;
const auto hmax = std : : max ( m_findZone . highlight . start , m_findZone . highlight . end ) ;
const auto showThreads = m_findZone . showThreads ;
const auto highlightActive = m_findZone . highlight . active ;
2018-03-18 20:03:36 +00:00
while ( processed < sz )
2018-02-15 16:25:16 +00:00
{
2018-03-18 20:03:36 +00:00
auto & ev = zones [ processed ] ;
2018-03-24 01:00:20 +00:00
if ( ev . zone - > end < 0 ) break ;
2018-03-18 15:41:58 +00:00
2018-03-18 19:45:49 +00:00
const auto end = m_worker . GetZoneEndDirect ( * ev . zone ) ;
const auto timespan = end - ev . zone - > start ;
2018-03-18 20:03:36 +00:00
if ( timespan = = 0 )
{
processed + + ;
continue ;
}
2018-03-18 15:41:58 +00:00
2018-03-20 15:28:55 +00:00
if ( highlightActive )
2018-03-18 15:41:58 +00:00
{
2018-03-20 15:28:55 +00:00
if ( timespan < hmin | | timespan > hmax )
2018-03-18 20:03:36 +00:00
{
processed + + ;
continue ;
}
2018-03-18 15:41:58 +00:00
}
2018-03-04 22:17:36 +00:00
2018-03-18 20:03:36 +00:00
processed + + ;
2018-03-20 15:28:55 +00:00
if ( showThreads )
2018-03-19 15:01:36 +00:00
{
m_findZone . threads [ ev . thread ] . push_back ( ev . zone ) ;
}
else
{
const uint64_t id = ev . zone - > text . active ? ev . zone - > text . idx : std : : numeric_limits < uint64_t > : : max ( ) ;
m_findZone . threads [ id ] . push_back ( ev . zone ) ;
}
2018-03-18 15:41:58 +00:00
}
2018-03-18 20:03:36 +00:00
m_findZone . processed = processed ;
2018-03-18 15:41:58 +00:00
2018-03-20 16:19:48 +00:00
Vector < decltype ( m_findZone . threads ) : : iterator > threads ;
threads . reserve_and_use ( m_findZone . threads . size ( ) ) ;
2018-03-18 15:41:58 +00:00
int idx = 0 ;
2018-03-20 16:19:48 +00:00
for ( auto it = m_findZone . threads . begin ( ) ; it ! = m_findZone . threads . end ( ) ; + + it )
{
threads [ idx + + ] = it ;
}
if ( m_findZone . sortByCounts )
{
2018-04-02 14:09:44 +00:00
pdqsort_branchless ( threads . begin ( ) , threads . end ( ) , [ ] ( const auto & lhs , const auto & rhs ) { return lhs - > second . size ( ) > rhs - > second . size ( ) ; } ) ;
2018-03-20 16:19:48 +00:00
}
ImGui : : BeginChild ( " ##zonesScroll " , ImVec2 ( ImGui : : GetWindowContentRegionWidth ( ) , std : : max ( 200.f , ImGui : : GetContentRegionAvail ( ) . y ) ) ) ;
for ( auto & v : threads )
2018-03-18 15:41:58 +00:00
{
2018-03-19 15:01:36 +00:00
const char * hdrString ;
2018-03-20 15:28:55 +00:00
if ( showThreads )
2018-03-19 15:01:36 +00:00
{
2018-03-20 16:19:48 +00:00
hdrString = m_worker . GetThreadString ( m_worker . DecompressThread ( v - > first ) ) ;
2018-03-19 15:01:36 +00:00
}
else
{
2018-03-20 16:19:48 +00:00
hdrString = v - > first = = std : : numeric_limits < uint64_t > : : max ( ) ? " No user text " : m_worker . GetString ( StringIdx ( v - > first ) ) ;
2018-03-19 15:01:36 +00:00
}
2018-03-20 16:19:48 +00:00
ImGui : : PushID ( v - > first ) ;
const bool expand = ImGui : : TreeNodeEx ( hdrString , ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ( v - > first = = m_findZone . selThread ? ImGuiTreeNodeFlags_Selected : 0 ) ) ;
2018-03-20 13:37:58 +00:00
if ( ImGui : : IsItemClicked ( ) )
{
2018-03-20 16:19:48 +00:00
m_findZone . selThread = v - > first ;
2018-03-20 13:37:58 +00:00
}
2018-03-04 17:52:32 +00:00
ImGui : : PopID ( ) ;
2018-02-15 16:25:16 +00:00
ImGui : : SameLine ( ) ;
2018-03-20 16:19:48 +00:00
ImGui : : TextColored ( ImVec4 ( 0.5f , 0.5f , 0.5f , 1.0f ) , " (%s) " , RealToString ( v - > second . size ( ) , true ) ) ;
2018-02-15 16:25:16 +00:00
if ( expand )
{
2018-04-21 20:33:30 +00:00
ImGui : : Columns ( 2 , hdrString ) ;
2018-02-15 16:25:16 +00:00
ImGui : : Separator ( ) ;
ImGui : : Text ( " Time from start " ) ;
2018-01-17 11:49:50 +00:00
ImGui : : NextColumn ( ) ;
2018-02-15 16:25:16 +00:00
ImGui : : Text ( " Execution time " ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Separator ( ) ;
2018-03-20 16:19:48 +00:00
for ( auto & ev : v - > second )
2018-02-15 16:25:16 +00:00
{
2018-03-18 01:53:16 +00:00
const auto end = m_worker . GetZoneEndDirect ( * ev ) ;
2018-03-04 22:07:38 +00:00
const auto timespan = end - ev - > start ;
2018-02-15 16:25:16 +00:00
ImGui : : PushID ( ev ) ;
2018-02-13 13:57:47 +00:00
auto & srcloc = m_worker . GetSourceLocation ( ev - > srcloc ) ;
2018-04-21 20:33:30 +00:00
if ( ImGui : : Selectable ( TimeToString ( ev - > start - m_worker . GetFrameBegin ( 0 ) ) , m_zoneInfoWindow = = ev , ImGuiSelectableFlags_SpanAllColumns ) )
2018-02-15 16:25:16 +00:00
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( * ev ) ;
2018-02-15 16:25:16 +00:00
}
2018-03-04 17:42:18 +00:00
if ( ImGui : : IsItemHovered ( ) )
2018-03-04 17:35:40 +00:00
{
2018-03-04 17:42:18 +00:00
m_zoneHighlight = ev ;
if ( ImGui : : IsMouseClicked ( 2 ) )
{
ZoomToZone ( * ev ) ;
}
ZoneTooltip ( * ev ) ;
2018-03-04 17:35:40 +00:00
}
2018-01-17 11:49:50 +00:00
2018-02-15 16:25:16 +00:00
ImGui : : NextColumn ( ) ;
2018-04-21 17:26:55 +00:00
ImGui : : Text ( " %s " , TimeToString ( timespan ) ) ;
2018-02-15 16:25:16 +00:00
ImGui : : NextColumn ( ) ;
ImGui : : PopID ( ) ;
}
ImGui : : Columns ( 1 ) ;
ImGui : : Separator ( ) ;
ImGui : : TreePop ( ) ;
2018-01-17 11:49:50 +00:00
}
}
2018-03-20 11:56:26 +00:00
ImGui : : EndChild ( ) ;
2018-04-14 13:21:22 +00:00
if ( ImGui : : IsItemHovered ( ) & & ImGui : : IsMouseClicked ( 1 ) )
{
m_findZone . selThread = m_findZone . Unselected ;
}
2018-01-17 11:49:50 +00:00
}
2018-03-18 11:55:54 +00:00
# endif
2018-01-17 11:49:50 +00:00
ImGui : : End ( ) ;
}
2018-04-21 22:52:33 +00:00
void View : : DrawCompare ( )
{
ImGui : : Begin ( " Compare traces " , & m_compare . show ) ;
# ifdef TRACY_NO_STATISTICS
ImGui : : TextWrapped ( " Collection of statistical data is disabled in this build. " ) ;
ImGui : : TextWrapped ( " Rebuild without the TRACY_NO_STATISTICS macro to enable trace comparison. " ) ;
# elif !defined TRACY_FILESELECTOR
ImGui : : TextWrapped ( " File selector is disabled in this build. " ) ;
ImGui : : TextWrapped ( " Rebuild with the TRACY_FILESELECTOR macro to enable trace comparison. " ) ;
# else
if ( ! m_compare . second )
{
ImGui : : TextWrapped ( " Please load a second trace to compare results. " ) ;
if ( ImGui : : Button ( " Open second trace " ) )
{
nfdchar_t * fn ;
auto res = NFD_OpenDialog ( " tracy " , nullptr , & fn ) ;
if ( res = = NFD_OKAY )
{
try
{
auto f = std : : unique_ptr < tracy : : FileRead > ( tracy : : FileRead : : Open ( fn ) ) ;
if ( f )
{
2018-04-21 23:00:17 +00:00
m_compare . second = std : : make_unique < Worker > ( * f , EventType : : None ) ;
2018-04-21 22:52:33 +00:00
}
}
catch ( const tracy : : UnsupportedVersion & e )
{
m_compare . badVer = e . version ;
}
catch ( const tracy : : NotTracyDump & e )
{
m_compare . badVer = - 1 ;
}
}
}
tracy : : BadVersion ( m_compare . badVer ) ;
ImGui : : End ( ) ;
return ;
}
2018-04-30 01:54:09 +00:00
if ( ! m_worker . AreSourceLocationZonesReady ( ) | | ! m_compare . second - > AreSourceLocationZonesReady ( ) )
{
ImGui : : TextWrapped ( " Please wait, computing data... " ) ;
ImGui : : End ( ) ;
return ;
}
2018-04-21 22:52:33 +00:00
ImGui : : TextDisabled ( " This trace: " ) ;
ImGui : : SameLine ( ) ;
ImGui : : Text ( " %s " , m_worker . GetCaptureName ( ) . c_str ( ) ) ;
ImGui : : TextDisabled ( " External trace: " ) ;
ImGui : : SameLine ( ) ;
ImGui : : Text ( " %s " , m_compare . second - > GetCaptureName ( ) . c_str ( ) ) ;
ImGui : : SameLine ( ) ;
if ( ImGui : : SmallButton ( " Unload " ) )
{
m_compare . Reset ( ) ;
m_compare . second . reset ( ) ;
ImGui : : End ( ) ;
return ;
}
ImGui : : InputText ( " " , m_compare . pattern , 1024 ) ;
ImGui : : SameLine ( ) ;
const bool findClicked = ImGui : : Button ( " Find " ) ;
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Clear " ) )
{
m_compare . Reset ( ) ;
}
if ( findClicked )
{
m_compare . Reset ( ) ;
FindZonesCompare ( ) ;
}
if ( m_compare . match [ 0 ] . empty ( ) & & m_compare . match [ 1 ] . empty ( ) )
{
ImGui : : End ( ) ;
return ;
}
if ( ImGui : : TreeNodeEx ( " Matched source locations " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
ImGui : : Separator ( ) ;
ImGui : : Columns ( 2 ) ;
ImGui : : Text ( " This capture " ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%zu) " , m_compare . match [ 0 ] . size ( ) ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " External capture " ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%zu) " , m_compare . match [ 1 ] . size ( ) ) ;
ImGui : : Separator ( ) ;
ImGui : : NextColumn ( ) ;
auto prev = m_compare . selMatch [ 0 ] ;
int idx = 0 ;
for ( auto & v : m_compare . match [ 0 ] )
{
auto & srcloc = m_worker . GetSourceLocation ( v ) ;
auto & zones = m_worker . GetZonesForSourceLocation ( v ) . zones ;
ImGui : : PushID ( idx ) ;
ImGui : : RadioButton ( m_worker . GetString ( srcloc . name . active ? srcloc . name : srcloc . function ) , & m_compare . selMatch [ 0 ] , idx + + ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextColored ( ImVec4 ( 0.5 , 0.5 , 0.5 , 1 ) , " (%s) %s:%i " , RealToString ( zones . size ( ) , true ) , m_worker . GetString ( srcloc . file ) , srcloc . line ) ;
ImGui : : PopID ( ) ;
}
ImGui : : NextColumn ( ) ;
prev = m_compare . selMatch [ 1 ] ;
idx = 0 ;
for ( auto & v : m_compare . match [ 1 ] )
{
auto & srcloc = m_compare . second - > GetSourceLocation ( v ) ;
auto & zones = m_compare . second - > GetZonesForSourceLocation ( v ) . zones ;
ImGui : : PushID ( - 1 - idx ) ;
ImGui : : RadioButton ( m_compare . second - > GetString ( srcloc . name . active ? srcloc . name : srcloc . function ) , & m_compare . selMatch [ 1 ] , idx + + ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextColored ( ImVec4 ( 0.5 , 0.5 , 0.5 , 1 ) , " (%s) %s:%i " , RealToString ( zones . size ( ) , true ) , m_compare . second - > GetString ( srcloc . file ) , srcloc . line ) ;
ImGui : : PopID ( ) ;
}
ImGui : : NextColumn ( ) ;
ImGui : : EndColumns ( ) ;
ImGui : : TreePop ( ) ;
}
ImGui : : Separator ( ) ;
if ( m_compare . match [ 0 ] . empty ( ) | | m_compare . match [ 1 ] . empty ( ) )
{
ImGui : : TextWrapped ( " Both traces must have matches. " ) ;
ImGui : : End ( ) ;
return ;
}
if ( ImGui : : TreeNodeEx ( " Histogram " , ImGuiTreeNodeFlags_DefaultOpen ) )
{
const auto ty = ImGui : : GetFontSize ( ) ;
auto & zoneData0 = m_worker . GetZonesForSourceLocation ( m_compare . match [ 0 ] [ m_compare . selMatch [ 0 ] ] ) ;
auto & zoneData1 = m_compare . second - > GetZonesForSourceLocation ( m_compare . match [ 1 ] [ m_compare . selMatch [ 1 ] ] ) ;
auto & zones0 = zoneData0 . zones ;
auto & zones1 = zoneData1 . zones ;
auto tmin = std : : min ( zoneData0 . min , zoneData1 . min ) ;
auto tmax = std : : max ( zoneData0 . max , zoneData1 . max ) ; ;
if ( tmin ! = std : : numeric_limits < int64_t > : : max ( ) )
{
ImGui : : Checkbox ( " Log values " , & m_compare . logVal ) ;
ImGui : : SameLine ( ) ;
ImGui : : Checkbox ( " Log time " , & m_compare . logTime ) ;
ImGui : : SameLine ( ) ;
ImGui : : Checkbox ( " Cumulate time " , & m_compare . cumulateTime ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (?) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Show total time taken by calls in each bin instead of call counts. " ) ;
ImGui : : EndTooltip ( ) ;
}
2018-04-22 00:19:22 +00:00
ImGui : : SameLine ( ) ;
ImGui : : Checkbox ( " Normalize values " , & m_compare . normalize ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (?) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Normalization will fudge reported data values! " ) ;
ImGui : : EndTooltip ( ) ;
}
2018-04-21 22:52:33 +00:00
ImGui : : Text ( " Time range: %s - %s (%s) " , TimeToString ( tmin ) , TimeToString ( tmax ) , TimeToString ( tmax - tmin ) ) ;
const auto dt = double ( tmax - tmin ) ;
const auto cumulateTime = m_compare . cumulateTime ;
if ( dt > 0 )
{
const auto w = ImGui : : GetContentRegionAvail ( ) . x ;
const auto numBins = int64_t ( w - 4 ) ;
if ( numBins > 1 )
{
2018-06-06 21:09:46 +00:00
if ( numBins ! = m_compare . numBins )
{
m_compare . numBins = numBins ;
m_compare . bins = std : : make_unique < CompVal [ ] > ( numBins ) ;
m_compare . binTime = std : : make_unique < CompVal [ ] > ( numBins ) ;
}
2018-04-21 22:52:33 +00:00
2018-06-06 21:09:46 +00:00
const auto & bins = m_compare . bins ;
const auto & binTime = m_compare . binTime ;
memset ( bins . get ( ) , 0 , sizeof ( CompVal ) * numBins ) ;
2018-04-21 22:52:33 +00:00
memset ( binTime . get ( ) , 0 , sizeof ( CompVal ) * numBins ) ;
2018-06-06 21:17:13 +00:00
double adj0 = 1 ;
double adj1 = 1 ;
2018-04-22 00:19:22 +00:00
if ( m_compare . normalize )
2018-04-21 22:52:33 +00:00
{
2018-04-22 00:19:22 +00:00
if ( zones0 . size ( ) > zones1 . size ( ) )
{
adj1 = double ( zones0 . size ( ) ) / zones1 . size ( ) ;
}
else
{
adj0 = double ( zones1 . size ( ) ) / zones0 . size ( ) ;
}
if ( m_compare . logTime )
2018-04-21 22:52:33 +00:00
{
2018-06-05 23:54:17 +00:00
const auto tMinLog = log10fast ( tmin ) ;
const auto idt = numBins / ( log10fast ( tmax ) - tMinLog ) ;
2018-04-22 00:19:22 +00:00
for ( auto & ev : zones0 )
2018-04-21 22:52:33 +00:00
{
2018-04-22 00:19:22 +00:00
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
2018-06-05 23:54:17 +00:00
const auto bin = std : : min ( numBins - 1 , int64_t ( ( log10fast ( timeSpan ) - tMinLog ) * idt ) ) ;
2018-04-22 00:19:22 +00:00
bins [ bin ] . v0 + = adj0 ;
binTime [ bin ] . v0 + = timeSpan * adj0 ;
}
}
for ( auto & ev : zones1 )
{
const auto timeSpan = m_compare . second - > GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
2018-06-05 23:54:17 +00:00
const auto bin = std : : min ( numBins - 1 , int64_t ( ( log10fast ( timeSpan ) - tMinLog ) * idt ) ) ;
2018-04-22 00:19:22 +00:00
bins [ bin ] . v1 + = adj1 ;
binTime [ bin ] . v1 + = timeSpan * adj1 ;
}
2018-04-21 22:52:33 +00:00
}
}
2018-04-22 00:19:22 +00:00
else
2018-04-21 22:52:33 +00:00
{
2018-04-22 00:19:22 +00:00
const auto idt = numBins / dt ;
for ( auto & ev : zones0 )
2018-04-21 22:52:33 +00:00
{
2018-04-22 00:19:22 +00:00
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
const auto bin = std : : min ( numBins - 1 , int64_t ( ( timeSpan - tmin ) * idt ) ) ;
bins [ bin ] . v0 + = adj0 ;
binTime [ bin ] . v0 + = timeSpan * adj0 ;
}
}
for ( auto & ev : zones1 )
{
const auto timeSpan = m_compare . second - > GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
const auto bin = std : : min ( numBins - 1 , int64_t ( ( timeSpan - tmin ) * idt ) ) ;
bins [ bin ] . v1 + = adj1 ;
binTime [ bin ] . v1 + = timeSpan * adj1 ;
}
2018-04-21 22:52:33 +00:00
}
}
}
else
{
2018-04-22 00:19:22 +00:00
if ( m_compare . logTime )
2018-04-21 22:52:33 +00:00
{
2018-06-05 23:54:17 +00:00
const auto tMinLog = log10fast ( tmin ) ;
const auto idt = numBins / ( log10fast ( tmax ) - tMinLog ) ;
2018-04-22 00:19:22 +00:00
for ( auto & ev : zones0 )
2018-04-21 22:52:33 +00:00
{
2018-04-22 00:19:22 +00:00
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
2018-06-05 23:54:17 +00:00
const auto bin = std : : min ( numBins - 1 , int64_t ( ( log10fast ( timeSpan ) - tMinLog ) * idt ) ) ;
2018-04-22 00:19:22 +00:00
bins [ bin ] . v0 + + ;
binTime [ bin ] . v0 + = timeSpan ;
}
}
for ( auto & ev : zones1 )
{
const auto timeSpan = m_compare . second - > GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
2018-06-05 23:54:17 +00:00
const auto bin = std : : min ( numBins - 1 , int64_t ( ( log10fast ( timeSpan ) - tMinLog ) * idt ) ) ;
2018-04-22 00:19:22 +00:00
bins [ bin ] . v1 + + ;
binTime [ bin ] . v1 + = timeSpan ;
}
2018-04-21 22:52:33 +00:00
}
}
2018-04-22 00:19:22 +00:00
else
2018-04-21 22:52:33 +00:00
{
2018-04-22 00:19:22 +00:00
const auto idt = numBins / dt ;
for ( auto & ev : zones0 )
{
const auto timeSpan = m_worker . GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
const auto bin = std : : min ( numBins - 1 , int64_t ( ( timeSpan - tmin ) * idt ) ) ;
bins [ bin ] . v0 + + ;
binTime [ bin ] . v0 + = timeSpan ;
}
}
for ( auto & ev : zones1 )
2018-04-21 22:52:33 +00:00
{
2018-04-22 00:19:22 +00:00
const auto timeSpan = m_compare . second - > GetZoneEndDirect ( * ev . zone ) - ev . zone - > start ;
if ( timeSpan ! = 0 )
{
const auto bin = std : : min ( numBins - 1 , int64_t ( ( timeSpan - tmin ) * idt ) ) ;
bins [ bin ] . v1 + + ;
binTime [ bin ] . v1 + = timeSpan ;
}
2018-04-21 22:52:33 +00:00
}
}
}
2018-04-22 00:19:22 +00:00
double maxVal ;
2018-04-21 22:52:33 +00:00
if ( cumulateTime )
{
maxVal = std : : max ( binTime [ 0 ] . v0 , binTime [ 0 ] . v1 ) ;
for ( int i = 1 ; i < numBins ; i + + )
{
maxVal = std : : max ( { maxVal , binTime [ i ] . v0 , binTime [ i ] . v1 } ) ;
}
}
else
{
maxVal = std : : max ( bins [ 0 ] . v0 , bins [ 0 ] . v1 ) ;
for ( int i = 1 ; i < numBins ; i + + )
{
maxVal = std : : max ( { maxVal , bins [ i ] . v0 , bins [ i ] . v1 } ) ;
}
}
2018-06-06 21:17:13 +00:00
ImGui : : Text ( " Total time (this): %s " , TimeToString ( zoneData0 . total * adj0 ) ) ;
ImGui : : Text ( " Total time (external): %s " , TimeToString ( zoneData1 . total * adj1 ) ) ;
2018-04-22 00:19:22 +00:00
ImGui : : Text ( " Max counts: %s " , cumulateTime ? TimeToString ( maxVal ) : RealToString ( floor ( maxVal ) , true ) ) ;
2018-04-21 22:52:33 +00:00
ImGui : : ColorButton ( " c1 " , ImVec4 ( 0xDD / 255.f , 0xDD / 255.f , 0x22 / 255.f , 1.f ) , ImGuiColorEditFlags_NoTooltip ) ;
ImGui : : SameLine ( ) ;
ImGui : : Text ( " This trace " ) ;
ImGui : : SameLine ( ) ;
ImGui : : Spacing ( ) ;
ImGui : : SameLine ( ) ;
ImGui : : ColorButton ( " c2 " , ImVec4 ( 0xDD / 255.f , 0x22 / 255.f , 0x22 / 255.f , 1.f ) , ImGuiColorEditFlags_NoTooltip ) ;
ImGui : : SameLine ( ) ;
ImGui : : Text ( " External trace " ) ;
ImGui : : SameLine ( ) ;
ImGui : : Spacing ( ) ;
ImGui : : SameLine ( ) ;
ImGui : : ColorButton ( " c3 " , ImVec4 ( 0x44 / 255.f , 0xBB / 255.f , 0xBB / 255.f , 1.f ) , ImGuiColorEditFlags_NoTooltip ) ;
ImGui : : SameLine ( ) ;
ImGui : : Text ( " Overlap " ) ;
enum { Height = 200 } ;
const auto wpos = ImGui : : GetCursorScreenPos ( ) ;
ImGui : : InvisibleButton ( " ##histogram " , ImVec2 ( w , Height + round ( ty * 1.5 ) ) ) ;
const bool hover = ImGui : : IsItemHovered ( ) ;
auto draw = ImGui : : GetWindowDrawList ( ) ;
draw - > AddRectFilled ( wpos , wpos + ImVec2 ( w , Height ) , 0x22FFFFFF ) ;
draw - > AddRect ( wpos , wpos + ImVec2 ( w , Height ) , 0x88FFFFFF ) ;
if ( m_compare . logVal )
{
2018-06-05 23:54:17 +00:00
const auto hAdj = double ( Height - 4 ) / log10fast ( maxVal + 1 ) ;
2018-04-21 22:52:33 +00:00
for ( int i = 0 ; i < numBins ; i + + )
{
const auto val0 = cumulateTime ? binTime [ i ] . v0 : bins [ i ] . v0 ;
const auto val1 = cumulateTime ? binTime [ i ] . v1 : bins [ i ] . v1 ;
if ( val0 > 0 | | val1 > 0 )
{
const auto val = std : : min ( val0 , val1 ) ;
if ( val > 0 )
{
2018-06-05 23:54:17 +00:00
draw - > AddLine ( wpos + ImVec2 ( 2 + i , Height - 3 ) , wpos + ImVec2 ( 2 + i , Height - 3 - log10fast ( val + 1 ) * hAdj ) , 0xFFBBBB44 ) ;
2018-04-21 22:52:33 +00:00
}
if ( val1 = = val )
{
2018-06-05 23:54:17 +00:00
draw - > AddLine ( wpos + ImVec2 ( 2 + i , Height - 3 - log10fast ( val + 1 ) * hAdj ) , wpos + ImVec2 ( 2 + i , Height - 3 - log10fast ( val0 + 1 ) * hAdj ) , 0xFF22DDDD ) ;
2018-04-21 22:52:33 +00:00
}
else
{
2018-06-05 23:54:17 +00:00
draw - > AddLine ( wpos + ImVec2 ( 2 + i , Height - 3 - log10fast ( val + 1 ) * hAdj ) , wpos + ImVec2 ( 2 + i , Height - 3 - log10fast ( val1 + 1 ) * hAdj ) , 0xFF2222DD ) ;
2018-04-21 22:52:33 +00:00
}
}
}
}
else
{
const auto hAdj = double ( Height - 4 ) / maxVal ;
for ( int i = 0 ; i < numBins ; i + + )
{
const auto val0 = cumulateTime ? binTime [ i ] . v0 : bins [ i ] . v0 ;
const auto val1 = cumulateTime ? binTime [ i ] . v1 : bins [ i ] . v1 ;
if ( val0 > 0 | | val1 > 0 )
{
const auto val = std : : min ( val0 , val1 ) ;
if ( val > 0 )
{
draw - > AddLine ( wpos + ImVec2 ( 2 + i , Height - 3 ) , wpos + ImVec2 ( 2 + i , Height - 3 - val * hAdj ) , 0xFFBBBB44 ) ;
}
if ( val1 = = val )
{
draw - > AddLine ( wpos + ImVec2 ( 2 + i , Height - 3 - val * hAdj ) , wpos + ImVec2 ( 2 + i , Height - 3 - val0 * hAdj ) , 0xFF22DDDD ) ;
}
else
{
draw - > AddLine ( wpos + ImVec2 ( 2 + i , Height - 3 - val * hAdj ) , wpos + ImVec2 ( 2 + i , Height - 3 - val1 * hAdj ) , 0xFF2222DD ) ;
}
}
}
}
const auto xoff = 2 ;
const auto yoff = Height + 1 ;
if ( m_compare . logTime )
{
2018-06-05 23:54:17 +00:00
const auto ltmin = log10fast ( tmin ) ;
const auto ltmax = log10fast ( tmax ) ;
2018-04-21 22:52:33 +00:00
const auto start = int ( floor ( ltmin ) ) ;
const auto end = int ( ceil ( ltmax ) ) ;
const auto range = ltmax - ltmin ;
const auto step = w / range ;
auto offset = start - ltmin ;
int tw = 0 ;
int tx = 0 ;
auto tt = int64_t ( pow ( 10 , start ) ) ;
static const double logticks [ ] = { log10 ( 2 ) , log10 ( 3 ) , log10 ( 4 ) , log10 ( 5 ) , log10 ( 6 ) , log10 ( 7 ) , log10 ( 8 ) , log10 ( 9 ) } ;
for ( int i = start ; i < = end ; i + + )
{
const auto x = ( i - start + offset ) * step ;
if ( x > = 0 )
{
draw - > AddLine ( wpos + ImVec2 ( x , yoff ) , wpos + ImVec2 ( x , yoff + round ( ty * 0.5 ) ) , 0x66FFFFFF ) ;
if ( tw = = 0 | | x > tx + tw + ty * 1.1 )
{
tx = x ;
auto txt = TimeToStringInteger ( tt ) ;
draw - > AddText ( wpos + ImVec2 ( x , yoff + round ( ty * 0.5 ) ) , 0x66FFFFFF , txt ) ;
tw = ImGui : : CalcTextSize ( txt ) . x ;
}
}
for ( int j = 0 ; j < 8 ; j + + )
{
const auto xoff = x + logticks [ j ] * step ;
if ( xoff > = 0 )
{
draw - > AddLine ( wpos + ImVec2 ( xoff , yoff ) , wpos + ImVec2 ( xoff , yoff + round ( ty * 0.25 ) ) , 0x66FFFFFF ) ;
}
}
tt * = 10 ;
}
}
else
{
const auto pxns = numBins / dt ;
const auto nspx = 1.0 / pxns ;
2018-06-05 23:54:17 +00:00
const auto scale = std : : max ( 0.0f , round ( log10fast ( nspx ) + 2 ) ) ;
2018-04-21 22:52:33 +00:00
const auto step = pow ( 10 , scale ) ;
const auto dx = step * pxns ;
double x = 0 ;
int tw = 0 ;
int tx = 0 ;
const auto sstep = step / 10.0 ;
const auto sdx = dx / 10.0 ;
static const double linelen [ ] = { 0.5 , 0.25 , 0.25 , 0.25 , 0.25 , 0.375 , 0.25 , 0.25 , 0.25 , 0.25 } ;
int64_t tt = int64_t ( ceil ( tmin / sstep ) * sstep ) ;
const auto diff = tmin / sstep - int64_t ( tmin / sstep ) ;
const auto xo = ( diff = = 0 ? 0 : ( ( 1 - diff ) * sstep * pxns ) ) + xoff ;
int iter = int ( ceil ( ( tmin - int64_t ( tmin / step ) * step ) / sstep ) ) ;
while ( x < numBins )
{
draw - > AddLine ( wpos + ImVec2 ( xo + x , yoff ) , wpos + ImVec2 ( xo + x , yoff + round ( ty * linelen [ iter ] ) ) , 0x66FFFFFF ) ;
if ( iter = = 0 & & ( tw = = 0 | | x > tx + tw + ty * 1.1 ) )
{
tx = x ;
auto txt = TimeToStringInteger ( tt ) ;
draw - > AddText ( wpos + ImVec2 ( xo + x , yoff + round ( ty * 0.5 ) ) , 0x66FFFFFF , txt ) ;
tw = ImGui : : CalcTextSize ( txt ) . x ;
}
iter = ( iter + 1 ) % 10 ;
x + = sdx ;
tt + = sstep ;
}
}
if ( hover & & ImGui : : IsMouseHoveringRect ( wpos + ImVec2 ( 2 , 2 ) , wpos + ImVec2 ( w - 2 , Height + round ( ty * 1.5 ) ) ) )
{
2018-06-05 23:54:17 +00:00
const auto ltmin = log10fast ( tmin ) ;
const auto ltmax = log10fast ( tmax ) ;
2018-04-21 22:52:33 +00:00
auto & io = ImGui : : GetIO ( ) ;
draw - > AddLine ( ImVec2 ( io . MousePos . x , wpos . y ) , ImVec2 ( io . MousePos . x , wpos . y + Height - 2 ) , 0x33FFFFFF ) ;
const auto bin = double ( io . MousePos . x - wpos . x - 2 ) ;
int64_t t0 , t1 ;
if ( m_compare . logTime )
{
t0 = int64_t ( pow ( 10 , ltmin + bin / numBins * ( ltmax - ltmin ) ) ) ;
t1 = int64_t ( pow ( 10 , ltmin + ( bin + 1 ) / numBins * ( ltmax - ltmin ) ) ) ;
}
else
{
t0 = int64_t ( tmin + bin / numBins * ( tmax - tmin ) ) ;
t1 = int64_t ( tmin + ( bin + 1 ) / numBins * ( tmax - tmin ) ) ;
}
int64_t tBefore [ 2 ] = { 0 , 0 } ;
for ( int i = 0 ; i < bin ; i + + )
{
tBefore [ 0 ] + = binTime [ i ] . v0 ;
tBefore [ 1 ] + = binTime [ i ] . v1 ;
}
int64_t tAfter [ 2 ] = { 0 , 0 } ;
for ( int i = bin + 1 ; i < numBins ; i + + )
{
tAfter [ 0 ] + = binTime [ i ] . v0 ;
tAfter [ 1 ] + = binTime [ i ] . v1 ;
}
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Time range: %s - %s " , TimeToString ( t0 ) , TimeToString ( t1 ) ) ;
2018-04-22 00:19:22 +00:00
ImGui : : Text ( " Count: %g / %g " , floor ( bins [ bin ] . v0 ) , floor ( bins [ bin ] . v1 ) ) ;
2018-04-21 22:52:33 +00:00
ImGui : : Text ( " Time spent in bin: %s / %s " , TimeToString ( binTime [ bin ] . v0 ) , TimeToString ( binTime [ bin ] . v1 ) ) ;
ImGui : : Text ( " Time spent in the left bins: %s / %s " , TimeToString ( tBefore [ 0 ] ) , TimeToString ( tBefore [ 1 ] ) ) ;
ImGui : : Text ( " Time spent in the right bins: %s / %s " , TimeToString ( tAfter [ 0 ] ) , TimeToString ( tAfter [ 1 ] ) ) ;
ImGui : : TextDisabled ( " (Data is displayed as: [this trace] / [external trace]) " ) ;
ImGui : : EndTooltip ( ) ;
}
}
}
}
2018-04-21 23:28:55 +00:00
ImGui : : TreePop ( ) ;
2018-04-21 22:52:33 +00:00
}
# endif
ImGui : : End ( ) ;
}
2018-03-24 13:40:48 +00:00
void View : : DrawStatistics ( )
{
ImGui : : Begin ( " Statistics " , & m_showStatistics ) ;
# ifdef TRACY_NO_STATISTICS
ImGui : : TextWrapped ( " Collection of statistical data is disabled in this build. " ) ;
ImGui : : TextWrapped ( " Rebuild without the TRACY_NO_STATISTICS macro to enable statistics view. " ) ;
# else
2018-04-30 01:54:09 +00:00
if ( ! m_worker . AreSourceLocationZonesReady ( ) )
{
ImGui : : TextWrapped ( " Please wait, computing data... " ) ;
ImGui : : End ( ) ;
return ;
}
2018-06-05 22:47:16 +00:00
ImGui : : Checkbox ( " Show self times " , & m_statSelf ) ;
2018-03-24 14:16:43 +00:00
auto & slz = m_worker . GetSourceLocationZones ( ) ;
Vector < decltype ( slz . begin ( ) ) > srcloc ;
srcloc . reserve ( slz . size ( ) ) ;
for ( auto it = slz . begin ( ) ; it ! = slz . end ( ) ; + + it )
{
if ( it - > second . total ! = 0 )
{
srcloc . push_back_no_space_check ( it ) ;
}
}
2018-06-05 22:47:16 +00:00
2018-03-24 16:28:10 +00:00
switch ( m_statSort )
{
case 0 :
2018-06-05 22:47:16 +00:00
if ( m_statSelf )
{
pdqsort_branchless ( srcloc . begin ( ) , srcloc . end ( ) , [ ] ( const auto & lhs , const auto & rhs ) { return lhs - > second . selfTotal > rhs - > second . selfTotal ; } ) ;
}
else
{
pdqsort_branchless ( srcloc . begin ( ) , srcloc . end ( ) , [ ] ( const auto & lhs , const auto & rhs ) { return lhs - > second . total > rhs - > second . total ; } ) ;
}
2018-03-24 16:28:10 +00:00
break ;
case 1 :
pdqsort_branchless ( srcloc . begin ( ) , srcloc . end ( ) , [ ] ( const auto & lhs , const auto & rhs ) { return lhs - > second . zones . size ( ) > rhs - > second . zones . size ( ) ; } ) ;
break ;
case 2 :
2018-06-05 22:47:16 +00:00
if ( m_statSelf )
{
pdqsort_branchless ( srcloc . begin ( ) , srcloc . end ( ) , [ ] ( const auto & lhs , const auto & rhs ) { return lhs - > second . selfTotal / lhs - > second . zones . size ( ) > rhs - > second . selfTotal / rhs - > second . zones . size ( ) ; } ) ;
}
else
{
pdqsort_branchless ( srcloc . begin ( ) , srcloc . end ( ) , [ ] ( const auto & lhs , const auto & rhs ) { return lhs - > second . total / lhs - > second . zones . size ( ) > rhs - > second . total / rhs - > second . zones . size ( ) ; } ) ;
}
2018-03-24 16:28:10 +00:00
break ;
default :
assert ( false ) ;
break ;
}
2018-03-24 14:16:43 +00:00
ImGui : : Text ( " Recorded source locations: %s " , RealToString ( srcloc . size ( ) , true ) ) ;
ImGui : : Columns ( 5 ) ;
ImGui : : Separator ( ) ;
ImGui : : Text ( " Name " ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " Location " ) ;
ImGui : : NextColumn ( ) ;
2018-04-21 12:17:42 +00:00
if ( ImGui : : SmallButton ( " Total time " ) ) m_statSort = 0 ;
2018-03-24 14:16:43 +00:00
ImGui : : NextColumn ( ) ;
2018-04-21 12:17:42 +00:00
if ( ImGui : : SmallButton ( " Counts " ) ) m_statSort = 1 ;
2018-03-24 14:16:43 +00:00
ImGui : : NextColumn ( ) ;
2018-04-21 12:17:42 +00:00
if ( ImGui : : SmallButton ( " MTPC " ) ) m_statSort = 2 ;
2018-03-24 14:16:43 +00:00
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (?) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Mean time per call " ) ;
ImGui : : EndTooltip ( ) ;
}
ImGui : : NextColumn ( ) ;
ImGui : : Separator ( ) ;
for ( auto & v : srcloc )
{
ImGui : : PushID ( v - > first ) ;
auto & srcloc = m_worker . GetSourceLocation ( v - > first ) ;
2018-03-24 14:20:39 +00:00
auto name = m_worker . GetString ( srcloc . name . active ? srcloc . name : srcloc . function ) ;
2018-03-24 16:32:27 +00:00
if ( ImGui : : Selectable ( name , m_findZone . show & & ! m_findZone . match . empty ( ) & & m_findZone . match [ m_findZone . selMatch ] = = v - > first , ImGuiSelectableFlags_SpanAllColumns ) )
2018-03-24 14:16:43 +00:00
{
2018-04-05 17:30:32 +00:00
m_findZone . ShowZone ( v - > first , name ) ;
2018-03-24 14:16:43 +00:00
}
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " %s:%i " , m_worker . GetString ( srcloc . file ) , srcloc . line ) ;
ImGui : : NextColumn ( ) ;
2018-06-05 22:47:16 +00:00
ImGui : : Text ( " %s " , TimeToString ( m_statSelf ? v - > second . selfTotal : v - > second . total ) ) ;
2018-03-24 14:16:43 +00:00
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " %s " , RealToString ( v - > second . zones . size ( ) , true ) ) ;
ImGui : : NextColumn ( ) ;
2018-06-05 22:47:16 +00:00
ImGui : : Text ( " %s " , TimeToString ( ( m_statSelf ? v - > second . selfTotal : v - > second . total ) / v - > second . zones . size ( ) ) ) ;
2018-03-24 14:16:43 +00:00
ImGui : : NextColumn ( ) ;
ImGui : : PopID ( ) ;
}
2018-03-24 13:40:48 +00:00
# endif
ImGui : : End ( ) ;
}
2018-04-02 00:19:46 +00:00
template < class T >
2018-04-03 12:17:51 +00:00
void View : : ListMemData ( T ptr , T end , std : : function < const MemEvent * ( T & ) > DrawAddress )
2018-04-02 00:19:46 +00:00
{
2018-05-02 17:40:35 +00:00
const auto & style = ImGui : : GetStyle ( ) ;
const auto dist = std : : distance ( ptr , end ) + 1 ;
const auto ty = ImGui : : GetTextLineHeight ( ) + style . ItemSpacing . y ;
ImGui : : BeginChild ( " ##memScroll " , ImVec2 ( 0 , std : : max ( ty * std : : min < int64_t > ( dist , 5 ) , std : : min ( ty * dist , ImGui : : GetContentRegionAvail ( ) . y ) ) ) ) ;
2018-06-19 20:19:33 +00:00
ImGui : : Columns ( 8 ) ;
2018-04-02 00:19:46 +00:00
ImGui : : Text ( " Address " ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " Size " ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " Appeared at " ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " Duration " ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (?) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Active allocations are displayed using green color. " ) ;
ImGui : : EndTooltip ( ) ;
}
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " Thread " ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (?) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " Shows one thread if alloc and free was performed on the same thread. " ) ;
ImGui : : Text ( " Otherwise two threads are displayed in order: alloc, free. " ) ;
ImGui : : EndTooltip ( ) ;
}
ImGui : : NextColumn ( ) ;
2018-04-02 12:29:56 +00:00
ImGui : : Text ( " Zone alloc " ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " Zone free " ) ;
2018-04-02 12:36:07 +00:00
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (?) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
ImGui : : Text ( " If alloc and free is performed in the same zone, it is displayed in yellow color. " ) ;
ImGui : : EndTooltip ( ) ;
}
2018-04-02 00:19:46 +00:00
ImGui : : NextColumn ( ) ;
2018-06-19 20:19:33 +00:00
ImGui : : Text ( " Callstack " ) ;
ImGui : : NextColumn ( ) ;
2018-04-02 00:19:46 +00:00
ImGui : : Separator ( ) ;
int idx = 0 ;
while ( ptr ! = end )
{
auto v = DrawAddress ( ptr ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " %s " , RealToString ( v - > size , true ) ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " %s " , TimeToString ( v - > timeAlloc - m_worker . GetFrameBegin ( 0 ) ) ) ;
ImGui : : NextColumn ( ) ;
if ( v - > timeFree < 0 )
{
ImGui : : TextColored ( ImVec4 ( 0.6f , 1.f , 0.6f , 1.f ) , " %s " , TimeToString ( m_worker . GetLastTime ( ) - v - > timeAlloc ) ) ;
ImGui : : NextColumn ( ) ;
ImGui : : Text ( " %s " , m_worker . GetThreadString ( m_worker . DecompressThread ( v - > threadAlloc ) ) ) ;
}
else
{
ImGui : : Text ( " %s " , TimeToString ( v - > timeFree - v - > timeAlloc ) ) ;
ImGui : : NextColumn ( ) ;
2018-05-02 17:07:34 +00:00
if ( v - > threadAlloc = = v - > threadFree )
{
ImGui : : Text ( " %s " , m_worker . GetThreadString ( m_worker . DecompressThread ( v - > threadAlloc ) ) ) ;
}
else
2018-04-02 00:19:46 +00:00
{
2018-05-02 17:07:34 +00:00
ImGui : : Text ( " %s / %s " , m_worker . GetThreadString ( m_worker . DecompressThread ( v - > threadAlloc ) ) , m_worker . GetThreadString ( m_worker . DecompressThread ( v - > threadFree ) ) ) ;
2018-04-02 00:19:46 +00:00
}
}
ImGui : : NextColumn ( ) ;
auto zone = FindZoneAtTime ( m_worker . DecompressThread ( v - > threadAlloc ) , v - > timeAlloc ) ;
if ( ! zone )
{
ImGui : : Text ( " - " ) ;
}
else
{
const auto & srcloc = m_worker . GetSourceLocation ( zone - > srcloc ) ;
const auto txt = srcloc . name . active ? m_worker . GetString ( srcloc . name ) : m_worker . GetString ( srcloc . function ) ;
ImGui : : PushID ( idx + + ) ;
2018-04-02 12:38:08 +00:00
auto sel = ImGui : : Selectable ( txt , m_zoneInfoWindow = = zone ) ;
2018-04-02 00:19:46 +00:00
auto hover = ImGui : : IsItemHovered ( ) ;
ImGui : : PopID ( ) ;
if ( sel )
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( * zone ) ;
2018-04-02 00:19:46 +00:00
}
if ( hover )
{
m_zoneHighlight = zone ;
if ( ImGui : : IsMouseClicked ( 2 ) )
{
ZoomToZone ( * zone ) ;
}
ZoneTooltip ( * zone ) ;
}
}
ImGui : : NextColumn ( ) ;
2018-04-02 12:29:56 +00:00
if ( v - > timeFree < 0 )
{
ImGui : : TextColored ( ImVec4 ( 0.6f , 1.f , 0.6f , 1.f ) , " active " ) ;
}
else
{
2018-04-02 12:36:07 +00:00
auto zoneFree = FindZoneAtTime ( m_worker . DecompressThread ( v - > threadFree ) , v - > timeFree ) ;
if ( ! zoneFree )
2018-04-02 12:29:56 +00:00
{
ImGui : : Text ( " - " ) ;
}
else
{
2018-04-02 12:36:07 +00:00
const auto & srcloc = m_worker . GetSourceLocation ( zoneFree - > srcloc ) ;
2018-04-02 12:29:56 +00:00
const auto txt = srcloc . name . active ? m_worker . GetString ( srcloc . name ) : m_worker . GetString ( srcloc . function ) ;
ImGui : : PushID ( idx + + ) ;
2018-04-02 12:36:07 +00:00
bool sel ;
if ( zoneFree = = zone )
{
2018-04-02 12:38:08 +00:00
sel = ImGui : : Selectable ( " " , m_zoneInfoWindow = = zoneFree ) ;
2018-04-02 12:36:07 +00:00
ImGui : : SameLine ( ) ;
2018-04-21 17:26:55 +00:00
ImGui : : TextColored ( ImVec4 ( 1.f , 1.f , 0.6f , 1.f ) , " %s " , txt ) ;
2018-04-02 12:36:07 +00:00
}
else
{
2018-04-02 12:38:08 +00:00
sel = ImGui : : Selectable ( txt , m_zoneInfoWindow = = zoneFree ) ;
2018-04-02 12:36:07 +00:00
}
2018-04-02 12:29:56 +00:00
auto hover = ImGui : : IsItemHovered ( ) ;
ImGui : : PopID ( ) ;
if ( sel )
{
2018-05-02 17:23:46 +00:00
ShowZoneInfo ( * zoneFree ) ;
2018-04-02 12:29:56 +00:00
}
if ( hover )
{
2018-04-02 12:36:07 +00:00
m_zoneHighlight = zoneFree ;
2018-04-02 12:29:56 +00:00
if ( ImGui : : IsMouseClicked ( 2 ) )
{
2018-04-02 12:36:07 +00:00
ZoomToZone ( * zoneFree ) ;
2018-04-02 12:29:56 +00:00
}
2018-04-02 12:36:07 +00:00
ZoneTooltip ( * zoneFree ) ;
2018-04-02 12:29:56 +00:00
}
}
}
ImGui : : NextColumn ( ) ;
2018-06-19 20:19:33 +00:00
if ( v - > csAlloc = = 0 )
{
ImGui : : TextDisabled ( " [alloc] " ) ;
}
else
{
ImGui : : Text ( " [alloc] " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
CallstackTooltip ( v - > csAlloc ) ;
}
}
ImGui : : SameLine ( ) ;
ImGui : : Spacing ( ) ;
ImGui : : SameLine ( ) ;
if ( v - > csFree = = 0 )
{
ImGui : : TextDisabled ( " [free] " ) ;
}
else
{
ImGui : : Text ( " [free] " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
CallstackTooltip ( v - > csFree ) ;
}
}
ImGui : : NextColumn ( ) ;
2018-04-02 00:19:46 +00:00
ptr + + ;
}
ImGui : : EndColumns ( ) ;
2018-04-02 12:44:45 +00:00
ImGui : : EndChild ( ) ;
2018-04-02 00:19:46 +00:00
}
2018-04-02 16:40:59 +00:00
enum { ChunkBits = 10 } ;
enum { PageBits = 10 } ;
2018-04-02 17:57:46 +00:00
enum { PageSize = 1 < < PageBits } ;
2018-04-02 16:40:59 +00:00
enum { PageChunkBits = ChunkBits + PageBits } ;
2018-04-02 17:57:46 +00:00
enum { PageChunkSize = 1 < < PageChunkBits } ;
2018-04-02 16:40:59 +00:00
2018-04-04 20:24:38 +00:00
uint32_t MemDecayColor [ 256 ] = {
0x0 , 0xFF077F07 , 0xFF078007 , 0xFF078207 , 0xFF078307 , 0xFF078507 , 0xFF078707 , 0xFF078807 ,
0xFF078A07 , 0xFF078B07 , 0xFF078D07 , 0xFF078F07 , 0xFF079007 , 0xFF089208 , 0xFF089308 , 0xFF089508 ,
0xFF089708 , 0xFF089808 , 0xFF089A08 , 0xFF089B08 , 0xFF089D08 , 0xFF089F08 , 0xFF08A008 , 0xFF08A208 ,
0xFF09A309 , 0xFF09A509 , 0xFF09A709 , 0xFF09A809 , 0xFF09AA09 , 0xFF09AB09 , 0xFF09AD09 , 0xFF09AF09 ,
0xFF09B009 , 0xFF09B209 , 0xFF09B309 , 0xFF09B509 , 0xFF0AB70A , 0xFF0AB80A , 0xFF0ABA0A , 0xFF0ABB0A ,
0xFF0ABD0A , 0xFF0ABF0A , 0xFF0AC00A , 0xFF0AC20A , 0xFF0AC30A , 0xFF0AC50A , 0xFF0AC70A , 0xFF0BC80B ,
0xFF0BCA0B , 0xFF0BCB0B , 0xFF0BCD0B , 0xFF0BCF0B , 0xFF0BD00B , 0xFF0BD20B , 0xFF0BD30B , 0xFF0BD50B ,
0xFF0BD70B , 0xFF0BD80B , 0xFF0BDA0B , 0xFF0CDB0C , 0xFF0CDD0C , 0xFF0CDF0C , 0xFF0CE00C , 0xFF0CE20C ,
0xFF0CE30C , 0xFF0CE50C , 0xFF0CE70C , 0xFF0CE80C , 0xFF0CEA0C , 0xFF0CEB0C , 0xFF0DED0D , 0xFF0DEF0D ,
0xFF0DF00D , 0xFF0DF20D , 0xFF0DF30D , 0xFF0DF50D , 0xFF0DF70D , 0xFF0DF80D , 0xFF0DFA0D , 0xFF0DFB0D ,
0xFF0DFD0D , 0xFF0EFF0E , 0xFF0EFF0E , 0xFF0EFF0E , 0xFF0EFF0E , 0xFF0EFF0E , 0xFF0EFF0E , 0xFF0EFF0E ,
0xFF0EFF0E , 0xFF0EFF0E , 0xFF0EFF0E , 0xFF0EFF0E , 0xFF0EFF0E , 0xFF0FFF0F , 0xFF0FFF0F , 0xFF0FFF0F ,
0xFF0FFF0F , 0xFF0FFF0F , 0xFF0FFF0F , 0xFF0FFF0F , 0xFF0FFF0F , 0xFF0FFF0F , 0xFF0FFF0F , 0xFF0FFF0F ,
0xFF10FF10 , 0xFF10FF10 , 0xFF10FF10 , 0xFF10FF10 , 0xFF10FF10 , 0xFF10FF10 , 0xFF10FF10 , 0xFF10FF10 ,
0xFF10FF10 , 0xFF10FF10 , 0xFF10FF10 , 0xFF10FF10 , 0xFF11FF11 , 0xFF11FF11 , 0xFF11FF11 , 0xFF11FF11 ,
0xFF11FF11 , 0xFF11FF11 , 0xFF11FF11 , 0xFF11FF11 , 0xFF11FF11 , 0xFF11FF11 , 0xFF11FF11 , 0xFF12FF12 ,
0x0 , 0xFF1212FF , 0xFF1111FF , 0xFF1111FF , 0xFF1111FF , 0xFF1111FF , 0xFF1111FF , 0xFF1111FF ,
0xFF1111FF , 0xFF1111FF , 0xFF1111FF , 0xFF1111FF , 0xFF1111FF , 0xFF1010FF , 0xFF1010FF , 0xFF1010FF ,
0xFF1010FF , 0xFF1010FF , 0xFF1010FF , 0xFF1010FF , 0xFF1010FF , 0xFF1010FF , 0xFF1010FF , 0xFF1010FF ,
0xFF1010FF , 0xFF0F0FFF , 0xFF0F0FFF , 0xFF0F0FFF , 0xFF0F0FFF , 0xFF0F0FFF , 0xFF0F0FFF , 0xFF0F0FFF ,
0xFF0F0FFF , 0xFF0F0FFF , 0xFF0F0FFF , 0xFF0F0FFF , 0xFF0E0EFF , 0xFF0E0EFF , 0xFF0E0EFF , 0xFF0E0EFF ,
0xFF0E0EFF , 0xFF0E0EFF , 0xFF0E0EFF , 0xFF0E0EFF , 0xFF0E0EFF , 0xFF0E0EFF , 0xFF0E0EFF , 0xFF0E0EFF ,
0xFF0D0DFD , 0xFF0D0DFB , 0xFF0D0DFA , 0xFF0D0DF8 , 0xFF0D0DF7 , 0xFF0D0DF5 , 0xFF0D0DF3 , 0xFF0D0DF2 ,
0xFF0D0DF0 , 0xFF0D0DEF , 0xFF0D0DED , 0xFF0C0CEB , 0xFF0C0CEA , 0xFF0C0CE8 , 0xFF0C0CE7 , 0xFF0C0CE5 ,
0xFF0C0CE3 , 0xFF0C0CE2 , 0xFF0C0CE0 , 0xFF0C0CDF , 0xFF0C0CDD , 0xFF0C0CDB , 0xFF0B0BDA , 0xFF0B0BD8 ,
0xFF0B0BD7 , 0xFF0B0BD5 , 0xFF0B0BD3 , 0xFF0B0BD2 , 0xFF0B0BD0 , 0xFF0B0BCF , 0xFF0B0BCD , 0xFF0B0BCB ,
0xFF0B0BCA , 0xFF0B0BC8 , 0xFF0A0AC7 , 0xFF0A0AC5 , 0xFF0A0AC3 , 0xFF0A0AC2 , 0xFF0A0AC0 , 0xFF0A0ABF ,
0xFF0A0ABD , 0xFF0A0ABB , 0xFF0A0ABA , 0xFF0A0AB8 , 0xFF0A0AB7 , 0xFF0909B5 , 0xFF0909B3 , 0xFF0909B2 ,
0xFF0909B0 , 0xFF0909AF , 0xFF0909AD , 0xFF0909AB , 0xFF0909AA , 0xFF0909A8 , 0xFF0909A7 , 0xFF0909A5 ,
0xFF0909A3 , 0xFF0808A2 , 0xFF0808A0 , 0xFF08089F , 0xFF08089D , 0xFF08089B , 0xFF08089A , 0xFF080898 ,
0xFF080897 , 0xFF080895 , 0xFF080893 , 0xFF080892 , 0xFF070790 , 0xFF07078F , 0xFF07078D , 0xFF07078B ,
0xFF07078A , 0xFF070788 , 0xFF070787 , 0xFF070785 , 0xFF070783 , 0xFF070782 , 0xFF070780 , 0xFF07077F ,
} ;
2018-04-01 18:34:21 +00:00
void View : : DrawMemory ( )
{
auto & mem = m_worker . GetMemData ( ) ;
2018-04-01 19:24:30 +00:00
ImGui : : Begin ( " Memory " , & m_memInfo . show ) ;
2018-05-01 15:28:02 +00:00
if ( mem . data . empty ( ) )
{
ImGui : : TextWrapped ( " No memory data collected. " ) ;
ImGui : : End ( ) ;
return ;
}
2018-04-02 12:58:40 +00:00
ImGui : : Text ( " Total allocations: %-15s Active allocations: %-15s Memory usage: %-15s Memory span: %s " ,
RealToString ( mem . data . size ( ) , true ) ,
RealToString ( mem . active . size ( ) , true ) ,
RealToString ( mem . usage , true ) ,
RealToString ( mem . high - mem . low , true ) ) ;
2018-04-01 19:24:30 +00:00
ImGui : : InputText ( " " , m_memInfo . pattern , 1024 ) ;
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Find " ) )
{
m_memInfo . ptrFind = strtoull ( m_memInfo . pattern , nullptr , 0 ) ;
}
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Clear " ) )
{
m_memInfo . ptrFind = 0 ;
m_memInfo . pattern [ 0 ] = ' \0 ' ;
}
2018-04-02 14:07:33 +00:00
ImGui : : SameLine ( ) ;
ImGui : : Checkbox ( " Restrict time " , & m_memInfo . restrictTime ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (?) " ) ;
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
2018-04-02 14:21:24 +00:00
ImGui : : Text ( " Don't show allocations beyond the middle of timeline display. " ) ;
2018-04-02 14:07:33 +00:00
ImGui : : EndTooltip ( ) ;
}
2018-04-01 19:24:30 +00:00
2018-04-02 14:21:24 +00:00
const auto zvMid = m_zvStart + ( m_zvEnd - m_zvStart ) / 2 ;
2018-04-02 14:07:33 +00:00
ImGui : : Separator ( ) ;
if ( ImGui : : TreeNodeEx ( " Allocations " , ImGuiTreeNodeFlags_DefaultOpen ) )
2018-04-01 19:24:30 +00:00
{
2018-04-02 14:07:33 +00:00
if ( m_memInfo . ptrFind ! = 0 )
2018-04-01 19:24:30 +00:00
{
2018-04-03 12:17:51 +00:00
std : : vector < const MemEvent * > match ;
2018-04-02 14:07:33 +00:00
match . reserve ( mem . active . size ( ) ) ; // heuristic
if ( m_memInfo . restrictTime )
2018-04-01 19:24:30 +00:00
{
2018-04-02 14:07:33 +00:00
for ( auto & v : mem . data )
{
2018-04-03 12:17:51 +00:00
if ( v . ptr < = m_memInfo . ptrFind & & v . ptr + v . size > m_memInfo . ptrFind & & v . timeAlloc < zvMid )
2018-04-02 14:07:33 +00:00
{
2018-04-03 12:17:51 +00:00
match . emplace_back ( & v ) ;
2018-04-02 14:07:33 +00:00
}
}
}
else
{
for ( auto & v : mem . data )
{
2018-04-03 12:17:51 +00:00
if ( v . ptr < = m_memInfo . ptrFind & & v . ptr + v . size > m_memInfo . ptrFind )
2018-04-02 14:07:33 +00:00
{
2018-04-03 12:17:51 +00:00
match . emplace_back ( & v ) ;
2018-04-02 14:07:33 +00:00
}
}
2018-04-01 19:24:30 +00:00
}
2018-04-02 14:07:33 +00:00
if ( match . empty ( ) )
2018-04-01 19:24:30 +00:00
{
2018-04-02 14:07:33 +00:00
ImGui : : Text ( " Found no allocations at given address " ) ;
}
else
{
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%s) " , RealToString ( match . size ( ) , true ) ) ;
2018-04-02 00:19:46 +00:00
ListMemData < decltype ( match . begin ( ) ) > ( match . begin ( ) , match . end ( ) , [ this ] ( auto & it ) {
auto & v = * it ;
2018-04-01 19:24:30 +00:00
if ( v - > ptr = = m_memInfo . ptrFind )
{
2018-04-01 20:00:57 +00:00
ImGui : : Text ( " 0x% " PRIx64 , m_memInfo . ptrFind ) ;
2018-04-01 19:24:30 +00:00
}
else
{
2018-04-01 20:00:57 +00:00
ImGui : : Text ( " 0x% " PRIx64 " +% " PRIu64 , v - > ptr , m_memInfo . ptrFind - v - > ptr ) ;
2018-04-01 19:24:30 +00:00
}
2018-04-02 00:19:46 +00:00
return v ;
} ) ;
2018-04-01 19:24:30 +00:00
}
}
2018-04-02 14:07:33 +00:00
ImGui : : TreePop ( ) ;
2018-04-01 19:24:30 +00:00
}
2018-04-02 00:37:40 +00:00
ImGui : : Separator ( ) ;
if ( ImGui : : TreeNode ( " Active allocations " ) )
{
2018-04-02 14:30:03 +00:00
uint64_t total = 0 ;
2018-04-03 12:17:51 +00:00
std : : vector < const MemEvent * > items ;
2018-04-02 13:45:11 +00:00
items . reserve ( mem . active . size ( ) ) ;
2018-04-02 14:07:33 +00:00
if ( m_memInfo . restrictTime )
2018-04-02 13:45:11 +00:00
{
2018-04-02 14:07:33 +00:00
for ( auto & v : mem . data )
{
2018-04-03 12:17:51 +00:00
if ( v . timeAlloc < zvMid & & ( v . timeFree > zvMid | | v . timeFree < 0 ) )
2018-04-02 14:07:33 +00:00
{
2018-04-03 12:17:51 +00:00
items . emplace_back ( & v ) ;
total + = v . size ;
2018-04-02 14:07:33 +00:00
}
}
2018-04-02 13:45:11 +00:00
}
2018-04-02 14:07:33 +00:00
else
{
2018-04-03 12:17:51 +00:00
auto ptr = mem . data . data ( ) ;
2018-04-02 14:07:33 +00:00
for ( auto & v : mem . active )
{
2018-04-03 12:17:51 +00:00
items . emplace_back ( ptr + v . second ) ;
2018-04-02 14:07:33 +00:00
}
2018-04-02 14:09:44 +00:00
pdqsort_branchless ( items . begin ( ) , items . end ( ) , [ ] ( const auto & lhs , const auto & rhs ) { return lhs - > timeAlloc < rhs - > timeAlloc ; } ) ;
2018-04-02 14:30:03 +00:00
total = mem . usage ;
2018-04-02 14:07:33 +00:00
}
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (%s) " , RealToString ( items . size ( ) , true ) ) ;
2018-04-02 14:30:03 +00:00
ImGui : : Text ( " Memory usage: %s " , RealToString ( total , true ) ) ;
2018-04-02 13:45:11 +00:00
ListMemData < decltype ( items . begin ( ) ) > ( items . begin ( ) , items . end ( ) , [ ] ( auto & v ) {
ImGui : : Text ( " 0x% " PRIx64 , ( * v ) - > ptr ) ;
return * v ;
2018-04-02 00:37:40 +00:00
} ) ;
ImGui : : TreePop ( ) ;
}
2018-04-02 16:40:59 +00:00
ImGui : : Separator ( ) ;
if ( ImGui : : TreeNode ( " Memory map " ) )
{
2018-04-02 18:00:05 +00:00
ImGui : : Text ( " Single pixel: %s KB Single line: %s KB " , RealToString ( ( 1 < < ChunkBits ) / 1024 , true ) , RealToString ( PageChunkSize / 1024 , true ) ) ;
2018-04-02 16:40:59 +00:00
auto pages = GetMemoryPages ( ) ;
2018-04-03 17:17:32 +00:00
const int8_t empty [ PageSize ] = { } ;
2018-05-01 15:26:34 +00:00
const auto sz = pages . second / PageSize ;
auto pgptr = pages . first ;
2018-04-03 17:17:32 +00:00
const auto end = pgptr + sz * PageSize ;
size_t lines = sz ;
while ( pgptr ! = end )
2018-04-02 16:40:59 +00:00
{
2018-04-03 17:17:32 +00:00
if ( memcmp ( empty , pgptr , PageSize ) = = 0 )
2018-04-02 16:40:59 +00:00
{
2018-04-03 17:17:32 +00:00
pgptr + = PageSize ;
while ( pgptr ! = end & & memcmp ( empty , pgptr , PageSize ) = = 0 )
2018-04-02 16:40:59 +00:00
{
lines - - ;
2018-04-03 17:17:32 +00:00
pgptr + = PageSize ;
2018-04-02 16:40:59 +00:00
}
}
else
{
2018-04-03 17:17:32 +00:00
pgptr + = PageSize ;
2018-04-02 16:40:59 +00:00
}
}
2018-04-02 17:57:46 +00:00
ImGui : : BeginChild ( " ##memMap " , ImVec2 ( PageSize + 2 , lines + 2 ) , false ) ;
2018-04-02 16:40:59 +00:00
auto draw = ImGui : : GetWindowDrawList ( ) ;
const auto wpos = ImGui : : GetCursorScreenPos ( ) + ImVec2 ( 1 , 1 ) ;
2018-04-03 18:38:50 +00:00
draw - > AddRect ( wpos - ImVec2 ( 1 , 1 ) , wpos + ImVec2 ( PageSize + 1 , lines + 1 ) , 0xFF666666 ) ;
draw - > AddRectFilled ( wpos , wpos + ImVec2 ( PageSize , lines ) , 0xFF444444 ) ;
2018-04-02 16:40:59 +00:00
size_t line = 0 ;
2018-05-01 15:26:34 +00:00
pgptr = pages . first ;
2018-04-03 17:17:32 +00:00
while ( pgptr ! = end )
2018-04-02 16:40:59 +00:00
{
2018-04-03 17:17:32 +00:00
if ( memcmp ( empty , pgptr , PageSize ) = = 0 )
2018-04-02 16:40:59 +00:00
{
2018-04-03 17:17:32 +00:00
pgptr + = PageSize ;
2018-04-03 18:38:50 +00:00
draw - > AddLine ( wpos + ImVec2 ( 0 , line ) , wpos + ImVec2 ( PageSize , line ) , 0x11000000 ) ;
2018-04-02 16:40:59 +00:00
line + + ;
2018-04-03 17:17:32 +00:00
while ( pgptr ! = end & & memcmp ( empty , pgptr , PageSize ) = = 0 ) pgptr + = PageSize ;
2018-04-02 16:40:59 +00:00
}
else
{
size_t idx = 0 ;
2018-04-02 17:57:46 +00:00
while ( idx < PageSize )
2018-04-02 16:40:59 +00:00
{
2018-04-03 17:17:32 +00:00
if ( pgptr [ idx ] = = 0 )
2018-04-02 16:40:59 +00:00
{
do
{
idx + + ;
}
2018-04-03 17:17:32 +00:00
while ( idx < PageSize & & pgptr [ idx ] = = 0 ) ;
2018-04-02 16:40:59 +00:00
}
else
{
2018-04-03 17:17:32 +00:00
auto val = pgptr [ idx ] ;
2018-04-02 16:40:59 +00:00
const auto i0 = idx ;
do
{
idx + + ;
}
2018-04-03 17:17:32 +00:00
while ( idx < PageSize & & pgptr [ idx ] = = val ) ;
2018-04-04 20:24:38 +00:00
draw - > AddLine ( wpos + ImVec2 ( i0 , line ) , wpos + ImVec2 ( idx , line ) , MemDecayColor [ ( uint8_t ) val ] ) ;
2018-04-02 16:40:59 +00:00
}
}
line + + ;
2018-04-03 17:17:32 +00:00
pgptr + = PageSize ;
2018-04-02 16:40:59 +00:00
}
}
2018-05-01 15:26:34 +00:00
delete [ ] pages . first ;
2018-04-02 16:40:59 +00:00
ImGui : : EndChild ( ) ;
ImGui : : TreePop ( ) ;
}
2018-04-01 18:34:21 +00:00
ImGui : : End ( ) ;
}
2018-05-01 15:26:34 +00:00
std : : pair < int8_t * , size_t > View : : GetMemoryPages ( ) const
2018-04-03 11:30:56 +00:00
{
2018-04-02 16:14:59 +00:00
const auto & mem = m_worker . GetMemData ( ) ;
const auto span = mem . high - mem . low ;
2018-04-02 17:57:46 +00:00
const auto pages = ( span / PageChunkSize ) + 1 ;
2018-04-02 16:14:59 +00:00
2018-05-01 15:26:34 +00:00
const auto datasz = pages * PageSize ;
int8_t * data = new int8_t [ datasz ] ;
auto pgptr = data ;
2018-04-03 17:17:32 +00:00
memset ( pgptr , 0 , pages * PageSize ) ;
2018-04-02 16:14:59 +00:00
2018-04-03 17:35:43 +00:00
const auto memlow = mem . low ;
2018-04-03 17:34:48 +00:00
if ( m_memInfo . restrictTime )
2018-04-02 16:14:59 +00:00
{
2018-04-03 17:34:48 +00:00
const auto zvMid = m_zvStart + ( m_zvEnd - m_zvStart ) / 2 ;
for ( auto & alloc : mem . data )
{
2018-04-03 17:40:06 +00:00
if ( m_memInfo . restrictTime & & alloc . timeAlloc > zvMid ) break ;
2018-04-02 16:57:24 +00:00
2018-04-03 17:35:43 +00:00
const auto a0 = alloc . ptr - memlow ;
2018-04-03 17:34:48 +00:00
const auto a1 = a0 + alloc . size ;
2018-04-03 18:38:50 +00:00
int8_t val = alloc . timeFree < 0 ?
int8_t ( std : : max ( int64_t ( 1 ) , 127 - ( ( zvMid - alloc . timeAlloc ) > > 24 ) ) ) :
( alloc . timeFree > zvMid ?
int8_t ( std : : max ( int64_t ( 1 ) , 127 - ( ( zvMid - alloc . timeAlloc ) > > 24 ) ) ) :
int8_t ( - std : : max ( int64_t ( 1 ) , 127 - ( ( zvMid - alloc . timeFree ) > > 24 ) ) ) ) ;
2018-04-03 17:35:28 +00:00
2018-04-03 17:39:19 +00:00
const auto c0 = a0 > > ChunkBits ;
const auto c1 = a1 > > ChunkBits ;
2018-04-02 16:14:59 +00:00
2018-04-03 17:39:19 +00:00
if ( c0 = = c1 )
2018-04-03 11:23:53 +00:00
{
2018-04-03 17:39:19 +00:00
pgptr [ c0 ] = val ;
2018-04-03 11:23:53 +00:00
}
else
{
2018-04-03 17:39:19 +00:00
memset ( pgptr + c0 , val , c1 - c0 + 1 ) ;
2018-04-03 11:23:53 +00:00
}
2018-04-02 16:14:59 +00:00
}
2018-04-03 17:34:48 +00:00
}
else
{
2018-04-03 18:38:50 +00:00
const auto lastTime = m_worker . GetLastTime ( ) ;
2018-04-03 17:34:48 +00:00
for ( auto & alloc : mem . data )
2018-04-02 16:14:59 +00:00
{
2018-04-03 17:35:43 +00:00
const auto a0 = alloc . ptr - memlow ;
2018-04-03 17:34:48 +00:00
const auto a1 = a0 + alloc . size ;
2018-04-03 18:38:50 +00:00
const int8_t val = alloc . timeFree < 0 ?
int8_t ( std : : max ( int64_t ( 1 ) , 127 - ( ( lastTime - std : : min ( lastTime , alloc . timeAlloc ) ) > > 24 ) ) ) :
int8_t ( - std : : max ( int64_t ( 1 ) , 127 - ( ( lastTime - std : : min ( lastTime , alloc . timeFree ) ) > > 24 ) ) ) ;
2018-04-03 17:35:28 +00:00
2018-04-03 17:39:19 +00:00
const auto c0 = a0 > > ChunkBits ;
const auto c1 = a1 > > ChunkBits ;
2018-04-03 17:34:48 +00:00
2018-04-03 17:39:19 +00:00
if ( c0 = = c1 )
2018-04-03 17:34:48 +00:00
{
2018-04-03 17:39:19 +00:00
pgptr [ c0 ] = val ;
2018-04-03 17:34:48 +00:00
}
else
{
2018-04-03 17:39:19 +00:00
memset ( pgptr + c0 , val , c1 - c0 + 1 ) ;
2018-04-03 17:34:48 +00:00
}
2018-04-02 16:14:59 +00:00
}
}
2018-05-01 15:26:34 +00:00
return std : : make_pair ( data , datasz ) ;
2018-04-02 16:14:59 +00:00
}
2018-04-28 13:49:51 +00:00
const char * View : : GetPlotName ( const PlotData * plot ) const
{
switch ( plot - > type )
{
case PlotType : : User :
return m_worker . GetString ( plot - > name ) ;
case PlotType : : Memory :
return " Memory usage " ;
default :
assert ( false ) ;
return nullptr ;
}
}
2017-10-22 13:37:24 +00:00
uint32_t View : : GetZoneColor ( const ZoneEvent & ev )
2017-10-01 17:31:22 +00:00
{
2018-02-13 13:57:47 +00:00
const auto & srcloc = m_worker . GetSourceLocation ( ev . srcloc ) ;
2017-11-11 21:56:05 +00:00
const auto color = srcloc . color ;
return color ! = 0 ? ( color | 0xFF000000 ) : 0xFFCC5555 ;
2017-10-01 17:31:22 +00:00
}
2017-11-11 21:56:05 +00:00
uint32_t View : : GetZoneColor ( const GpuEvent & ev )
2017-10-01 17:31:22 +00:00
{
2018-02-13 13:57:47 +00:00
const auto & srcloc = m_worker . GetSourceLocation ( ev . srcloc ) ;
2017-11-05 19:54:49 +00:00
const auto color = srcloc . color ;
2017-11-11 21:56:05 +00:00
return color ! = 0 ? ( color | 0xFF000000 ) : 0xFF222288 ;
2017-10-01 17:31:22 +00:00
}
2017-10-22 13:37:24 +00:00
uint32_t View : : GetZoneHighlight ( const ZoneEvent & ev , bool migration )
2017-09-29 19:57:00 +00:00
{
if ( m_zoneInfoWindow = = & ev )
{
return 0xFF44DD44 ;
}
2017-09-29 20:38:38 +00:00
else if ( m_zoneHighlight = = & ev )
{
return 0xFF4444FF ;
}
2017-10-01 17:58:53 +00:00
else if ( migration )
{
return 0xFFDD22DD ;
}
2017-09-29 19:57:00 +00:00
else
{
2017-10-01 17:38:45 +00:00
const auto color = GetZoneColor ( ev ) ;
return 0xFF000000 |
( std : : min < int > ( 0xFF , ( ( ( color & 0x00FF0000 ) > > 16 ) + 25 ) ) < < 16 ) |
( std : : min < int > ( 0xFF , ( ( ( color & 0x0000FF00 ) > > 8 ) + 25 ) ) < < 8 ) |
( std : : min < int > ( 0xFF , ( ( ( color & 0x000000FF ) ) + 25 ) ) ) ;
2017-09-29 19:57:00 +00:00
}
}
2017-11-11 21:56:05 +00:00
uint32_t View : : GetZoneHighlight ( const GpuEvent & ev )
{
2017-11-12 00:25:44 +00:00
if ( m_gpuInfoWindow = = & ev )
{
return 0xFF44DD44 ;
}
2017-11-12 00:28:07 +00:00
else if ( m_gpuHighlight = = & ev )
{
return 0xFF4444FF ;
}
2017-11-12 00:25:44 +00:00
else
{
const auto color = GetZoneColor ( ev ) ;
return 0xFF000000 |
( std : : min < int > ( 0xFF , ( ( ( color & 0x00FF0000 ) > > 16 ) + 25 ) ) < < 16 ) |
( std : : min < int > ( 0xFF , ( ( ( color & 0x0000FF00 ) > > 8 ) + 25 ) ) < < 8 ) |
( std : : min < int > ( 0xFF , ( ( ( color & 0x000000FF ) ) + 25 ) ) ) ;
}
2017-11-11 21:56:05 +00:00
}
2017-10-22 13:37:24 +00:00
float View : : GetZoneThickness ( const ZoneEvent & ev )
2017-09-30 11:45:02 +00:00
{
if ( m_zoneInfoWindow = = & ev | | m_zoneHighlight = = & ev )
{
return 3.f ;
}
else
{
return 1.f ;
}
}
2017-11-11 21:56:05 +00:00
float View : : GetZoneThickness ( const GpuEvent & ev )
{
2017-11-12 00:28:07 +00:00
if ( m_gpuInfoWindow = = & ev | | m_gpuHighlight = = & ev )
2017-11-12 00:25:44 +00:00
{
return 3.f ;
}
else
{
return 1.f ;
}
2017-11-11 21:56:05 +00:00
}
2017-10-22 13:37:24 +00:00
void View : : ZoomToZone ( const ZoneEvent & ev )
2017-09-29 20:01:30 +00:00
{
2018-02-13 13:57:47 +00:00
const auto end = m_worker . GetZoneEnd ( ev ) ;
2017-10-08 09:38:03 +00:00
if ( end - ev . start < = 0 ) return ;
2017-11-27 21:12:26 +00:00
ZoomToRange ( ev . start , end ) ;
2017-09-29 20:01:30 +00:00
}
2017-11-11 21:56:05 +00:00
void View : : ZoomToZone ( const GpuEvent & ev )
{
2018-02-13 13:57:47 +00:00
const auto end = m_worker . GetZoneEnd ( ev ) ;
2017-11-11 21:56:05 +00:00
if ( end - ev . gpuStart < = 0 ) return ;
2017-11-27 21:12:26 +00:00
ZoomToRange ( ev . gpuStart , end ) ;
}
void View : : ZoomToRange ( int64_t start , int64_t end )
{
2017-11-27 21:41:30 +00:00
m_pause = true ;
m_zoomAnim . active = true ;
m_zoomAnim . start0 = m_zvStart ;
m_zoomAnim . start1 = start ;
m_zoomAnim . end0 = m_zvEnd ;
m_zoomAnim . end1 = end ;
m_zoomAnim . progress = 0 ;
const auto d0 = double ( m_zoomAnim . end0 - m_zoomAnim . start0 ) ;
const auto d1 = double ( m_zoomAnim . end1 - m_zoomAnim . start1 ) ;
const auto diff = d0 > d1 ? d0 / d1 : d1 / d0 ;
m_zoomAnim . lenMod = 10.0 / log10 ( diff ) ;
2017-11-11 21:56:05 +00:00
}
2018-06-02 20:27:35 +00:00
void View : : ZoomToPrevFrame ( )
{
if ( m_zvStart > = m_worker . GetFrameBegin ( 0 ) )
{
auto frame = m_worker . GetFrameRange ( m_zvStart , m_zvStart ) . first ;
if ( frame > 0 )
{
frame - - ;
const auto fbegin = m_worker . GetFrameBegin ( frame ) ;
const auto fend = m_worker . GetFrameEnd ( frame ) ;
ZoomToRange ( fbegin , fend ) ;
}
}
}
void View : : ZoomToNextFrame ( )
{
int frame ;
if ( m_zvStart < m_worker . GetFrameBegin ( 0 ) )
{
frame = - 1 ;
}
else
{
frame = m_worker . GetFrameRange ( m_zvStart , m_zvStart ) . first ;
if ( frame = = - 1 ) return ;
}
frame + + ;
if ( frame > = m_worker . GetFrameCount ( ) ) return ;
const auto fbegin = m_worker . GetFrameBegin ( frame ) ;
const auto fend = m_worker . GetFrameEnd ( frame ) ;
ZoomToRange ( fbegin , fend ) ;
}
2018-05-02 17:23:46 +00:00
void View : : ShowZoneInfo ( const ZoneEvent & ev )
{
if ( m_zoneInfoWindow )
{
m_zoneInfoStack . push_back ( m_zoneInfoWindow ) ;
}
m_zoneInfoWindow = & ev ;
if ( m_gpuInfoWindow )
{
m_gpuInfoWindow = nullptr ;
m_gpuInfoStack . clear ( ) ;
}
}
void View : : ShowZoneInfo ( const GpuEvent & ev , uint64_t thread )
{
if ( m_gpuInfoWindow )
{
m_gpuInfoStack . push_back ( m_gpuInfoWindow ) ;
}
m_gpuInfoWindow = & ev ;
m_gpuInfoWindowThread = thread ;
if ( m_zoneInfoWindow )
{
m_zoneInfoWindow = nullptr ;
m_zoneInfoStack . clear ( ) ;
}
}
2017-10-22 13:37:24 +00:00
void View : : ZoneTooltip ( const ZoneEvent & ev )
2017-09-29 20:55:24 +00:00
{
2017-11-14 22:31:24 +00:00
int dmul = ev . text . active ? 2 : 1 ;
2017-09-29 20:55:24 +00:00
2018-03-19 15:08:50 +00:00
const auto tid = GetZoneThread ( ev ) ;
2018-02-13 13:57:47 +00:00
auto & srcloc = m_worker . GetSourceLocation ( ev . srcloc ) ;
2017-09-29 20:55:24 +00:00
2018-02-13 13:57:47 +00:00
const auto filename = m_worker . GetString ( srcloc . file ) ;
2017-09-29 20:55:24 +00:00
const auto line = srcloc . line ;
const char * func ;
const char * zoneName ;
2017-11-14 22:31:24 +00:00
if ( srcloc . name . active )
2017-09-29 20:55:24 +00:00
{
2018-02-13 13:57:47 +00:00
zoneName = m_worker . GetString ( srcloc . name ) ;
func = m_worker . GetString ( srcloc . function ) ;
2017-09-29 20:55:24 +00:00
}
else
{
2018-02-13 13:57:47 +00:00
func = zoneName = m_worker . GetString ( srcloc . function ) ;
2017-09-29 20:55:24 +00:00
}
2018-02-13 13:57:47 +00:00
const auto end = m_worker . GetZoneEnd ( ev ) ;
2017-09-29 20:55:24 +00:00
ImGui : : BeginTooltip ( ) ;
2017-11-17 23:51:04 +00:00
if ( srcloc . name . active )
{
ImGui : : Text ( " %s " , zoneName ) ;
ImGui : : Text ( " %s " , func ) ;
}
else
{
ImGui : : Text ( " %s " , func ) ;
}
2017-11-18 12:47:05 +00:00
ImGui : : Separator ( ) ;
2017-09-29 20:55:24 +00:00
ImGui : : Text ( " %s:%i " , filename , line ) ;
2018-03-19 15:08:50 +00:00
ImGui : : Text ( " Thread: %s " , m_worker . GetThreadString ( tid ) ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (0x% " PRIX64 " ) " , tid ) ;
2018-03-19 15:14:01 +00:00
ImGui : : Separator ( ) ;
2017-09-29 20:55:24 +00:00
ImGui : : Text ( " Execution time: %s " , TimeToString ( end - ev . start ) ) ;
2018-02-13 13:57:47 +00:00
ImGui : : Text ( " Without profiling: %s " , TimeToString ( end - ev . start - m_worker . GetDelay ( ) * dmul ) ) ;
2018-04-14 14:50:04 +00:00
if ( ev . cpu_start > = 0 )
2017-10-01 17:21:25 +00:00
{
2018-03-24 01:00:20 +00:00
if ( ev . end < 0 | | ev . cpu_start = = ev . cpu_end )
2017-10-01 17:21:25 +00:00
{
ImGui : : Text ( " CPU: %i " , ev . cpu_start ) ;
}
else
{
ImGui : : Text ( " CPU: %i -> %i " , ev . cpu_start , ev . cpu_end ) ;
}
}
2017-11-14 22:31:24 +00:00
if ( ev . text . active )
2017-09-29 20:55:24 +00:00
{
2017-10-28 19:50:06 +00:00
ImGui : : NewLine ( ) ;
2018-02-13 13:57:47 +00:00
ImGui : : TextColored ( ImVec4 ( 0xCC / 255.f , 0xCC / 255.f , 0x22 / 255.f , 1.f ) , " %s " , m_worker . GetString ( ev . text ) ) ;
2017-09-29 20:55:24 +00:00
}
ImGui : : EndTooltip ( ) ;
}
2017-11-11 21:56:05 +00:00
void View : : ZoneTooltip ( const GpuEvent & ev )
{
2018-03-19 15:13:12 +00:00
const auto tid = GetZoneThread ( ev ) ;
2018-02-13 13:57:47 +00:00
const auto & srcloc = m_worker . GetSourceLocation ( ev . srcloc ) ;
2017-11-11 21:56:05 +00:00
2018-02-13 13:57:47 +00:00
const auto name = m_worker . GetString ( srcloc . name ) ;
const auto filename = m_worker . GetString ( srcloc . file ) ;
2017-11-11 21:56:05 +00:00
const auto line = srcloc . line ;
2018-02-13 13:57:47 +00:00
const auto func = m_worker . GetString ( srcloc . function ) ;
2017-11-11 21:56:05 +00:00
2018-02-13 13:57:47 +00:00
const auto end = m_worker . GetZoneEnd ( ev ) ;
2017-11-11 21:56:05 +00:00
ImGui : : BeginTooltip ( ) ;
2017-11-18 12:47:05 +00:00
ImGui : : Text ( " %s " , name ) ;
2017-11-11 21:56:05 +00:00
ImGui : : Text ( " %s " , func ) ;
2017-11-17 23:51:04 +00:00
ImGui : : Separator ( ) ;
2017-11-11 21:56:05 +00:00
ImGui : : Text ( " %s:%i " , filename , line ) ;
2018-03-19 15:13:12 +00:00
ImGui : : Text ( " Thread: %s " , m_worker . GetThreadString ( tid ) ) ;
ImGui : : SameLine ( ) ;
ImGui : : TextDisabled ( " (0x% " PRIX64 " ) " , tid ) ;
2018-03-19 15:14:01 +00:00
ImGui : : Separator ( ) ;
2017-11-11 21:56:05 +00:00
ImGui : : Text ( " GPU execution time: %s " , TimeToString ( end - ev . gpuStart ) ) ;
ImGui : : Text ( " CPU command setup time: %s " , TimeToString ( ev . cpuEnd - ev . cpuStart ) ) ;
ImGui : : Text ( " Delay to execution: %s " , TimeToString ( ev . gpuStart - ev . cpuStart ) ) ;
ImGui : : EndTooltip ( ) ;
}
2018-06-19 20:19:33 +00:00
void View : : CallstackTooltip ( uint32_t idx )
{
auto & cs = m_worker . GetCallstack ( idx ) ;
ImGui : : BeginTooltip ( ) ;
for ( auto & entry : cs )
{
ImGui : : Text ( " 0x% " PRIX64 , entry ) ;
}
ImGui : : EndTooltip ( ) ;
}
2017-10-22 14:15:27 +00:00
const ZoneEvent * View : : GetZoneParent ( const ZoneEvent & zone ) const
{
2018-02-13 13:57:47 +00:00
for ( const auto & thread : m_worker . GetThreadData ( ) )
2017-10-22 14:15:27 +00:00
{
const ZoneEvent * parent = nullptr ;
const Vector < ZoneEvent * > * timeline = & thread - > timeline ;
if ( timeline - > empty ( ) ) continue ;
for ( ; ; )
{
auto it = std : : upper_bound ( timeline - > begin ( ) , timeline - > end ( ) , zone . start , [ ] ( const auto & l , const auto & r ) { return l < r - > start ; } ) ;
if ( it ! = timeline - > begin ( ) ) - - it ;
2018-03-24 01:00:20 +00:00
if ( zone . end > = 0 & & ( * it ) - > start > zone . end ) break ;
2017-10-22 14:15:27 +00:00
if ( * it = = & zone ) return parent ;
if ( ( * it ) - > child . empty ( ) ) break ;
parent = * it ;
timeline = & parent - > child ;
}
}
return nullptr ;
}
2017-11-12 00:25:44 +00:00
const GpuEvent * View : : GetZoneParent ( const GpuEvent & zone ) const
{
2018-02-13 13:57:47 +00:00
for ( const auto & ctx : m_worker . GetGpuData ( ) )
2017-11-12 00:25:44 +00:00
{
const GpuEvent * parent = nullptr ;
const Vector < GpuEvent * > * timeline = & ctx - > timeline ;
if ( timeline - > empty ( ) ) continue ;
for ( ; ; )
{
auto it = std : : upper_bound ( timeline - > begin ( ) , timeline - > end ( ) , zone . gpuStart , [ ] ( const auto & l , const auto & r ) { return l < r - > gpuStart ; } ) ;
if ( it ! = timeline - > begin ( ) ) - - it ;
2018-03-24 01:00:20 +00:00
if ( zone . gpuEnd > = 0 & & ( * it ) - > gpuStart > zone . gpuEnd ) break ;
2017-11-12 00:25:44 +00:00
if ( * it = = & zone ) return parent ;
if ( ( * it ) - > child . empty ( ) ) break ;
parent = * it ;
timeline = & parent - > child ;
}
}
return nullptr ;
}
2018-03-18 15:38:42 +00:00
uint64_t View : : GetZoneThread ( const ZoneEvent & zone ) const
{
for ( const auto & thread : m_worker . GetThreadData ( ) )
{
const Vector < ZoneEvent * > * timeline = & thread - > timeline ;
if ( timeline - > empty ( ) ) continue ;
for ( ; ; )
{
auto it = std : : upper_bound ( timeline - > begin ( ) , timeline - > end ( ) , zone . start , [ ] ( const auto & l , const auto & r ) { return l < r - > start ; } ) ;
if ( it ! = timeline - > begin ( ) ) - - it ;
2018-03-24 01:00:20 +00:00
if ( zone . end > = 0 & & ( * it ) - > start > zone . end ) break ;
2018-03-18 15:38:42 +00:00
if ( * it = = & zone ) return thread - > id ;
if ( ( * it ) - > child . empty ( ) ) break ;
timeline = & ( * it ) - > child ;
}
}
return 0 ;
}
2018-03-19 15:11:37 +00:00
uint64_t View : : GetZoneThread ( const GpuEvent & zone ) const
{
2018-06-17 17:09:33 +00:00
if ( zone . thread = = 0 )
2018-03-19 15:11:37 +00:00
{
2018-06-17 17:09:33 +00:00
for ( const auto & ctx : m_worker . GetGpuData ( ) )
2018-03-19 15:11:37 +00:00
{
2018-06-17 17:09:33 +00:00
const Vector < GpuEvent * > * timeline = & ctx - > timeline ;
if ( timeline - > empty ( ) ) continue ;
for ( ; ; )
{
auto it = std : : upper_bound ( timeline - > begin ( ) , timeline - > end ( ) , zone . gpuStart , [ ] ( const auto & l , const auto & r ) { return l < r - > gpuStart ; } ) ;
if ( it ! = timeline - > begin ( ) ) - - it ;
if ( zone . gpuEnd > = 0 & & ( * it ) - > gpuStart > zone . gpuEnd ) break ;
if ( * it = = & zone ) return ctx - > thread ;
if ( ( * it ) - > child . empty ( ) ) break ;
timeline = & ( * it ) - > child ;
}
2018-03-19 15:11:37 +00:00
}
2018-06-17 17:09:33 +00:00
return 0 ;
}
else
{
return m_worker . DecompressThread ( zone . thread ) ;
2018-03-19 15:11:37 +00:00
}
}
2018-04-01 19:47:08 +00:00
const ZoneEvent * View : : FindZoneAtTime ( uint64_t thread , int64_t time ) const
{
// TODO add thread rev-map
ThreadData * td = nullptr ;
for ( const auto & t : m_worker . GetThreadData ( ) )
{
if ( t - > id = = thread )
{
td = t ;
break ;
}
}
if ( ! td ) return nullptr ;
const Vector < ZoneEvent * > * timeline = & td - > timeline ;
if ( timeline - > empty ( ) ) return nullptr ;
ZoneEvent * ret = nullptr ;
for ( ; ; )
{
auto it = std : : upper_bound ( timeline - > begin ( ) , timeline - > end ( ) , time , [ ] ( const auto & l , const auto & r ) { return l < r - > start ; } ) ;
if ( it ! = timeline - > begin ( ) ) - - it ;
if ( ( * it ) - > start > time | | ( ( * it ) - > end > = 0 & & ( * it ) - > end < time ) ) return ret ;
ret = * it ;
if ( ( * it ) - > child . empty ( ) ) return ret ;
timeline = & ( * it ) - > child ;
}
}
2018-03-18 11:55:54 +00:00
# ifndef TRACY_NO_STATISTICS
2018-01-17 11:49:50 +00:00
void View : : FindZones ( )
{
2018-03-18 15:07:07 +00:00
m_findZone . match = m_worker . GetMatchingSourceLocation ( m_findZone . pattern ) ;
if ( m_findZone . match . empty ( ) ) return ;
2018-03-04 20:10:10 +00:00
2018-03-18 15:07:07 +00:00
auto it = m_findZone . match . begin ( ) ;
while ( it ! = m_findZone . match . end ( ) )
2018-03-04 21:11:50 +00:00
{
2018-03-18 19:20:24 +00:00
if ( m_worker . GetZonesForSourceLocation ( * it ) . zones . empty ( ) )
2018-02-15 15:24:01 +00:00
{
2018-03-18 15:07:07 +00:00
it = m_findZone . match . erase ( it ) ;
}
else
{
+ + it ;
2018-02-15 15:24:01 +00:00
}
2018-01-17 11:49:50 +00:00
}
}
2018-04-21 22:52:33 +00:00
void View : : FindZonesCompare ( )
{
m_compare . match [ 0 ] = m_worker . GetMatchingSourceLocation ( m_compare . pattern ) ;
if ( ! m_compare . match [ 0 ] . empty ( ) )
{
auto it = m_compare . match [ 0 ] . begin ( ) ;
while ( it ! = m_compare . match [ 0 ] . end ( ) )
{
if ( m_worker . GetZonesForSourceLocation ( * it ) . zones . empty ( ) )
{
it = m_compare . match [ 0 ] . erase ( it ) ;
}
else
{
+ + it ;
}
}
}
m_compare . match [ 1 ] = m_compare . second - > GetMatchingSourceLocation ( m_compare . pattern ) ;
if ( ! m_compare . match [ 1 ] . empty ( ) )
{
auto it = m_compare . match [ 1 ] . begin ( ) ;
while ( it ! = m_compare . match [ 1 ] . end ( ) )
{
if ( m_compare . second - > GetZonesForSourceLocation ( * it ) . zones . empty ( ) )
{
it = m_compare . match [ 1 ] . erase ( it ) ;
}
else
{
+ + it ;
}
}
}
}
2018-03-18 11:55:54 +00:00
# endif
2018-01-17 11:49:50 +00:00
2017-09-12 23:33:50 +00:00
}