2016-06-26 22:34:51 +03:00
/************************************************************************
* file name : blocks_tree_widget . cpp
* - - - - - - - - - - - - - - - - - :
* creation time : 2016 / 06 / 26
* copyright : ( c ) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v . s . zarubkin @ gmail . com
* - - - - - - - - - - - - - - - - - :
* description : The file contains implementation of TreeWidget and it ' s auxiliary classes
* : for displyaing easy_profiler blocks tree .
* - - - - - - - - - - - - - - - - - :
2016-06-27 22:11:26 +03:00
* change log : * 2016 / 06 / 26 Victor Zarubkin : Moved sources from tree_view . h
2016-06-26 22:34:51 +03:00
* : and renamed classes from My * to Prof * .
2016-06-30 02:57:57 +03:00
* :
2016-06-27 22:11:26 +03:00
* : * 2016 / 06 / 27 Victor Zarubkin : Added possibility to colorize rows
* : with profiler blocks ' colors .
* : Also added displaying frame statistics for blocks .
2016-06-27 23:24:04 +03:00
* : Disabled sorting by name to save order of threads displayed on graphics view .
2016-06-30 02:57:57 +03:00
* :
* : * 2016 / 06 / 29 Victor Zarubkin : Added clearSilent ( ) method .
* :
2016-06-27 22:11:26 +03:00
* : *
2016-06-26 22:34:51 +03:00
* - - - - - - - - - - - - - - - - - :
* license : TODO : add license text
2016-06-26 18:56:40 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-06-26 18:46:51 +03:00
2016-08-01 22:21:59 +03:00
# include <algorithm>
2016-06-26 18:46:51 +03:00
# include <QMenu>
# include <QContextMenuEvent>
2016-06-27 22:11:26 +03:00
# include <QSignalBlocker>
2016-08-04 23:12:41 +03:00
# include <QSettings>
2016-08-04 23:46:04 +03:00
# include <QTextCodec>
2016-06-26 18:46:51 +03:00
# include "blocks_tree_widget.h"
2016-08-08 22:45:57 +03:00
# include "globals.h"
2016-06-26 18:46:51 +03:00
2016-08-14 16:05:10 +03:00
# ifdef max
# undef max
# endif
# ifdef min
# undef min
# endif
2016-06-26 18:46:51 +03:00
//////////////////////////////////////////////////////////////////////////
2016-06-27 22:11:26 +03:00
enum ColumnsIndexes
{
COL_UNKNOWN = - 1 ,
COL_NAME = 0 ,
2016-08-07 19:38:31 +03:00
2016-06-27 22:11:26 +03:00
COL_BEGIN ,
2016-08-07 19:38:31 +03:00
2016-07-31 18:48:41 +03:00
COL_DURATION ,
2016-08-03 23:00:04 +03:00
COL_SELF_DURATION ,
2016-08-07 19:38:31 +03:00
COL_DURATION_SUM_PER_PARENT ,
COL_DURATION_SUM_PER_FRAME ,
COL_DURATION_SUM_PER_THREAD ,
2016-08-03 23:00:04 +03:00
COL_SELF_DURATION_PERCENT ,
2016-08-07 19:38:31 +03:00
COL_PERCENT_PER_PARENT ,
COL_PERCENT_PER_FRAME ,
COL_PERCENT_SUM_PER_PARENT ,
COL_PERCENT_SUM_PER_FRAME ,
COL_PERCENT_SUM_PER_THREAD ,
2016-06-27 22:11:26 +03:00
COL_END ,
2016-08-07 19:38:31 +03:00
COL_MIN_PER_FRAME ,
COL_MAX_PER_FRAME ,
COL_AVERAGE_PER_FRAME ,
COL_NCALLS_PER_FRAME ,
COL_MIN_PER_THREAD ,
COL_MAX_PER_THREAD ,
COL_AVERAGE_PER_THREAD ,
COL_NCALLS_PER_THREAD ,
2016-06-27 22:11:26 +03:00
2016-08-09 00:14:58 +03:00
COL_MIN_PER_PARENT ,
COL_MAX_PER_PARENT ,
COL_AVERAGE_PER_PARENT ,
COL_NCALLS_PER_PARENT ,
2016-06-27 22:11:26 +03:00
COL_COLUMNS_NUMBER
} ;
//////////////////////////////////////////////////////////////////////////
2016-08-03 23:00:04 +03:00
ProfTreeWidgetItem : : ProfTreeWidgetItem ( const : : profiler : : BlocksTree * _treeBlock , Parent * _parent )
2016-06-27 22:11:26 +03:00
: Parent ( _parent )
, m_block ( _treeBlock )
2016-08-03 23:00:04 +03:00
, m_customBGColor ( 0 )
, m_customTextColor ( 0 )
2016-06-26 18:46:51 +03:00
{
2016-08-04 23:12:41 +03:00
2016-06-26 18:46:51 +03:00
}
2016-06-26 20:54:16 +03:00
ProfTreeWidgetItem : : ~ ProfTreeWidgetItem ( )
{
}
2016-06-27 22:11:26 +03:00
bool ProfTreeWidgetItem : : operator < ( const Parent & _other ) const
{
const auto col = treeWidget ( ) - > sortColumn ( ) ;
switch ( col )
{
2016-08-03 23:00:04 +03:00
//case COL_UNKNOWN:
2016-07-31 18:48:41 +03:00
case COL_NAME :
{
if ( parent ( ) = = nullptr )
2016-08-03 23:00:04 +03:00
return false ; // Do not sort topLevelItems by name
2016-07-31 18:48:41 +03:00
return Parent : : operator < ( _other ) ;
}
2016-06-27 22:11:26 +03:00
2016-08-07 19:38:31 +03:00
case COL_NCALLS_PER_THREAD :
case COL_NCALLS_PER_PARENT :
case COL_NCALLS_PER_FRAME :
2016-06-27 22:11:26 +03:00
{
return data ( col , Qt : : UserRole ) . toUInt ( ) < _other . data ( col , Qt : : UserRole ) . toUInt ( ) ;
}
2016-08-03 23:00:04 +03:00
case COL_SELF_DURATION_PERCENT :
2016-08-07 19:38:31 +03:00
case COL_PERCENT_PER_PARENT :
case COL_PERCENT_PER_FRAME :
case COL_PERCENT_SUM_PER_PARENT :
case COL_PERCENT_SUM_PER_FRAME :
case COL_PERCENT_SUM_PER_THREAD :
2016-08-03 23:00:04 +03:00
{
return data ( col , Qt : : UserRole ) . toInt ( ) < _other . data ( col , Qt : : UserRole ) . toInt ( ) ;
}
2016-06-27 22:11:26 +03:00
default :
{
2016-08-03 23:00:04 +03:00
// durations min, max, average
2016-06-27 22:11:26 +03:00
return data ( col , Qt : : UserRole ) . toULongLong ( ) < _other . data ( col , Qt : : UserRole ) . toULongLong ( ) ;
}
}
return false ;
}
2016-08-03 23:00:04 +03:00
const : : profiler : : BlocksTree * ProfTreeWidgetItem : : block ( ) const
2016-06-26 18:46:51 +03:00
{
return m_block ;
}
2016-08-03 23:00:04 +03:00
: : profiler : : timestamp_t ProfTreeWidgetItem : : duration ( ) const
{
if ( m_block - > node )
return m_block - > node - > block ( ) - > duration ( ) ;
return data ( COL_DURATION , Qt : : UserRole ) . toULongLong ( ) ;
}
2016-08-07 19:38:31 +03:00
: : profiler : : timestamp_t ProfTreeWidgetItem : : selfDuration ( ) const
{
return data ( COL_SELF_DURATION , Qt : : UserRole ) . toULongLong ( ) ;
}
2016-08-09 00:14:58 +03:00
void ProfTreeWidgetItem : : setTimeSmart ( int _column , const : : profiler : : timestamp_t & _time , const QString & _prefix )
2016-06-26 18:46:51 +03:00
{
2016-08-01 22:21:59 +03:00
const : : profiler : : timestamp_t nanosecondsTime = PROF_NANOSECONDS ( _time ) ;
2016-06-26 18:46:51 +03:00
2016-08-01 22:21:59 +03:00
setData ( _column , Qt : : UserRole , ( quint64 ) nanosecondsTime ) ;
setToolTip ( _column , QString ( " %1 ns " ) . arg ( nanosecondsTime ) ) ;
2016-06-26 18:46:51 +03:00
if ( _time < 1e3 )
{
2016-08-09 00:14:58 +03:00
setText ( _column , QString ( " %1%2 ns " ) . arg ( _prefix ) . arg ( nanosecondsTime ) ) ;
2016-06-26 18:46:51 +03:00
}
else if ( _time < 1e6 )
{
2016-08-09 00:14:58 +03:00
setText ( _column , QString ( " %1%2 us " ) . arg ( _prefix ) . arg ( double ( nanosecondsTime ) * 1e-3 , 0 , ' f ' , 3 ) ) ;
2016-06-26 18:46:51 +03:00
}
else if ( _time < 1e9 )
{
2016-08-09 00:14:58 +03:00
setText ( _column , QString ( " %1%2 ms " ) . arg ( _prefix ) . arg ( double ( nanosecondsTime ) * 1e-6 , 0 , ' f ' , 3 ) ) ;
2016-06-26 18:46:51 +03:00
}
else
{
2016-08-09 00:14:58 +03:00
setText ( _column , QString ( " %1%2 s " ) . arg ( _prefix ) . arg ( double ( nanosecondsTime ) * 1e-9 , 0 , ' f ' , 3 ) ) ;
2016-06-26 18:46:51 +03:00
}
}
2016-06-26 19:06:53 +03:00
void ProfTreeWidgetItem : : setTimeMs ( int _column , const : : profiler : : timestamp_t & _time )
2016-06-26 18:46:51 +03:00
{
2016-08-01 22:21:59 +03:00
const : : profiler : : timestamp_t nanosecondsTime = PROF_NANOSECONDS ( _time ) ;
setData ( _column , Qt : : UserRole , ( quint64 ) nanosecondsTime ) ;
setToolTip ( _column , QString ( " %1 ns " ) . arg ( nanosecondsTime ) ) ;
setText ( _column , QString : : number ( double ( nanosecondsTime ) * 1e-6 , ' g ' , 9 ) ) ;
2016-06-26 18:46:51 +03:00
}
2016-08-09 00:14:58 +03:00
void ProfTreeWidgetItem : : setTimeMs ( int _column , const : : profiler : : timestamp_t & _time , const QString & _prefix )
{
const : : profiler : : timestamp_t nanosecondsTime = PROF_NANOSECONDS ( _time ) ;
setData ( _column , Qt : : UserRole , ( quint64 ) nanosecondsTime ) ;
setToolTip ( _column , QString ( " %1 ns " ) . arg ( nanosecondsTime ) ) ;
setText ( _column , QString ( " %1%2 " ) . arg ( _prefix ) . arg ( double ( nanosecondsTime ) * 1e-6 , 0 , ' g ' , 9 ) ) ;
}
2016-08-03 23:00:04 +03:00
void ProfTreeWidgetItem : : setBackgroundColor ( QRgb _color )
2016-06-27 22:11:26 +03:00
{
m_customBGColor = _color ;
}
2016-08-03 23:00:04 +03:00
void ProfTreeWidgetItem : : setTextColor ( QRgb _color )
2016-06-27 22:11:26 +03:00
{
m_customTextColor = _color ;
}
void ProfTreeWidgetItem : : colorize ( bool _colorize )
{
if ( _colorize )
{
for ( int i = 0 ; i < COL_COLUMNS_NUMBER ; + + i )
{
2016-08-03 23:00:04 +03:00
setBackground ( i , QColor : : fromRgb ( m_customBGColor ) ) ;
setForeground ( i , QColor : : fromRgb ( m_customTextColor ) ) ;
2016-06-27 22:11:26 +03:00
}
}
else
{
const QBrush nobrush ;
for ( int i = 0 ; i < COL_COLUMNS_NUMBER ; + + i )
{
setBackground ( i , nobrush ) ;
setForeground ( i , nobrush ) ;
}
}
}
2016-07-31 18:48:41 +03:00
void ProfTreeWidgetItem : : collapseAll ( )
{
for ( int i = 0 , childrenNumber = childCount ( ) ; i < childrenNumber ; + + i )
{
static_cast < ProfTreeWidgetItem * > ( child ( i ) ) - > collapseAll ( ) ;
}
setExpanded ( false ) ;
}
void ProfTreeWidgetItem : : expandAll ( )
{
for ( int i = 0 , childrenNumber = childCount ( ) ; i < childrenNumber ; + + i )
{
static_cast < ProfTreeWidgetItem * > ( child ( i ) ) - > expandAll ( ) ;
}
setExpanded ( true ) ;
}
2016-06-26 18:46:51 +03:00
//////////////////////////////////////////////////////////////////////////
2016-08-11 23:43:34 +03:00
ProfTreeWidget : : ProfTreeWidget ( QWidget * _parent ) : Parent ( _parent ) , m_beginTime ( : : std : : numeric_limits < decltype ( m_beginTime ) > : : max ( ) ) , m_bColorRows ( true )
2016-06-26 18:46:51 +03:00
{
2016-06-27 22:11:26 +03:00
setAutoFillBackground ( false ) ;
2016-06-26 18:46:51 +03:00
setAlternatingRowColors ( true ) ;
setItemsExpandable ( true ) ;
setAnimated ( true ) ;
setSortingEnabled ( false ) ;
2016-06-27 22:11:26 +03:00
setColumnCount ( COL_COLUMNS_NUMBER ) ;
2016-06-26 18:46:51 +03:00
auto header = new QTreeWidgetItem ( ) ;
2016-08-07 19:38:31 +03:00
2016-06-27 22:11:26 +03:00
header - > setText ( COL_NAME , " Name " ) ;
2016-08-07 19:38:31 +03:00
2016-06-27 22:11:26 +03:00
header - > setText ( COL_BEGIN , " Begin, ms " ) ;
2016-08-07 19:38:31 +03:00
2016-08-03 23:00:04 +03:00
header - > setText ( COL_DURATION , " Duration " ) ;
header - > setText ( COL_SELF_DURATION , " Self Dur. " ) ;
2016-08-08 22:17:56 +03:00
//header->setToolTip(COL_SELF_DURATION, "");
2016-08-07 19:38:31 +03:00
header - > setText ( COL_DURATION_SUM_PER_PARENT , " Tot. Dur./Parent " ) ;
header - > setText ( COL_DURATION_SUM_PER_FRAME , " Tot. Dur./Frame " ) ;
header - > setText ( COL_DURATION_SUM_PER_THREAD , " Tot. Dur./Thread " ) ;
2016-08-03 23:00:04 +03:00
header - > setText ( COL_SELF_DURATION_PERCENT , " Self % " ) ;
2016-08-07 19:38:31 +03:00
header - > setText ( COL_PERCENT_PER_PARENT , " % / Parent " ) ;
header - > setText ( COL_PERCENT_PER_FRAME , " % / Frame " ) ;
header - > setText ( COL_PERCENT_SUM_PER_FRAME , " Tot. % / Frame " ) ;
header - > setText ( COL_PERCENT_SUM_PER_PARENT , " Tot. % / Parent " ) ;
header - > setText ( COL_PERCENT_SUM_PER_THREAD , " Tot. % / Thread " ) ;
2016-06-27 22:11:26 +03:00
header - > setText ( COL_END , " End, ms " ) ;
2016-08-03 23:00:04 +03:00
2016-08-07 19:38:31 +03:00
header - > setText ( COL_MIN_PER_FRAME , " Min dur./Frame " ) ;
header - > setText ( COL_MAX_PER_FRAME , " Max dur./Frame " ) ;
header - > setText ( COL_AVERAGE_PER_FRAME , " Average dur./Frame " ) ;
header - > setText ( COL_NCALLS_PER_FRAME , " N Calls/Frame " ) ;
2016-08-04 23:12:41 +03:00
2016-08-07 19:38:31 +03:00
header - > setText ( COL_MIN_PER_PARENT , " Min dur./Parent " ) ;
header - > setText ( COL_MAX_PER_PARENT , " Max dur./Parent " ) ;
header - > setText ( COL_AVERAGE_PER_PARENT , " Average dur./Parent " ) ;
header - > setText ( COL_NCALLS_PER_PARENT , " N Calls/Parent " ) ;
2016-08-04 23:46:04 +03:00
2016-08-07 19:38:31 +03:00
header - > setText ( COL_MIN_PER_THREAD , " Min dur./Thread " ) ;
header - > setText ( COL_MAX_PER_THREAD , " Max dur./Thread " ) ;
header - > setText ( COL_AVERAGE_PER_THREAD , " Average dur./Thread " ) ;
header - > setText ( COL_NCALLS_PER_THREAD , " N Calls/Thread " ) ;
2016-08-04 23:12:41 +03:00
2016-08-07 19:38:31 +03:00
setHeaderItem ( header ) ;
2016-08-04 23:12:41 +03:00
2016-08-07 19:38:31 +03:00
connect ( & : : profiler_gui : : EASY_GLOBALS . events , & : : profiler_gui : : ProfGlobalSignals : : selectedThreadChanged , this , & This : : onSelectedThreadChange ) ;
2016-08-08 22:17:56 +03:00
connect ( & : : profiler_gui : : EASY_GLOBALS . events , & : : profiler_gui : : ProfGlobalSignals : : selectedBlockChanged , this , & This : : onSelectedBlockChange ) ;
2016-08-07 19:38:31 +03:00
loadSettings ( ) ;
2016-06-26 20:54:16 +03:00
}
2016-06-26 18:46:51 +03:00
2016-06-26 20:54:16 +03:00
ProfTreeWidget : : ~ ProfTreeWidget ( )
{
2016-08-04 23:12:41 +03:00
saveSettings ( ) ;
2016-06-26 20:54:16 +03:00
}
2016-07-31 18:48:41 +03:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2016-08-03 23:00:04 +03:00
void ProfTreeWidget : : setTree ( const unsigned int _blocksNumber , const : : profiler : : thread_blocks_tree_t & _blocksTree )
2016-06-26 18:46:51 +03:00
{
2016-06-30 02:57:57 +03:00
clearSilent ( ) ;
2016-06-26 18:46:51 +03:00
2016-06-27 22:11:26 +03:00
setTreeInternal ( _blocksNumber , _blocksTree ) ;
2016-06-26 18:46:51 +03:00
setSortingEnabled ( true ) ;
2016-06-27 22:11:26 +03:00
sortByColumn ( COL_BEGIN , Qt : : AscendingOrder ) ;
2016-08-03 00:06:36 +03:00
resizeColumnToContents ( COL_NAME ) ;
2016-06-26 18:46:51 +03:00
2016-06-27 22:11:26 +03:00
connect ( this , & Parent : : itemExpanded , this , & This : : onItemExpand ) ;
2016-06-26 18:46:51 +03:00
}
2016-08-03 23:00:04 +03:00
void ProfTreeWidget : : setTreeBlocks ( const : : profiler_gui : : TreeBlocks & _blocks , : : profiler : : timestamp_t _session_begin_time , : : profiler : : timestamp_t _left , : : profiler : : timestamp_t _right , bool _strict )
2016-07-31 18:48:41 +03:00
{
clearSilent ( ) ;
2016-08-01 22:21:59 +03:00
m_beginTime = _session_begin_time ;
_left + = m_beginTime ; // - ::std::min(m_beginTime, 1000ULL);
_right + = m_beginTime ; // + 1000;
2016-08-14 16:05:10 +03:00
2016-08-01 22:21:59 +03:00
setTreeInternal ( _blocks , _left , _right , _strict ) ;
2016-07-31 18:48:41 +03:00
setSortingEnabled ( true ) ;
sortByColumn ( COL_BEGIN , Qt : : AscendingOrder ) ;
2016-08-03 00:06:36 +03:00
resizeColumnToContents ( COL_NAME ) ;
2016-07-31 18:48:41 +03:00
connect ( this , & Parent : : itemExpanded , this , & This : : onItemExpand ) ;
2016-08-08 22:17:56 +03:00
onSelectedBlockChange ( : : profiler_gui : : EASY_GLOBALS . selected_block ) ;
2016-07-31 18:48:41 +03:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2016-08-04 22:38:45 +03:00
void ProfTreeWidget : : clearSilent ( bool _global )
2016-06-30 02:57:57 +03:00
{
2016-08-11 23:43:34 +03:00
m_beginTime = : : std : : numeric_limits < decltype ( m_beginTime ) > : : max ( ) ;
2016-06-30 02:57:57 +03:00
setSortingEnabled ( false ) ;
disconnect ( this , & Parent : : itemExpanded , this , & This : : onItemExpand ) ;
2016-08-04 22:38:45 +03:00
if ( ! _global )
{
for ( auto item : m_items )
{
2016-08-11 23:43:34 +03:00
: : profiler_gui : : set_max ( : : profiler_gui : : EASY_GLOBALS . gui_blocks [ item - > block ( ) - > block_index ] . tree_item ) ;
2016-08-04 22:38:45 +03:00
}
}
2016-06-30 02:57:57 +03:00
m_items . clear ( ) ;
2016-08-07 19:38:31 +03:00
m_roots . clear ( ) ;
2016-06-30 02:57:57 +03:00
const QSignalBlocker b ( this ) ;
clear ( ) ;
}
2016-07-31 18:48:41 +03:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2016-08-03 23:00:04 +03:00
size_t ProfTreeWidget : : setTreeInternal ( const unsigned int _blocksNumber , const : : profiler : : thread_blocks_tree_t & _blocksTree )
2016-06-26 18:46:51 +03:00
{
2016-06-27 22:11:26 +03:00
m_items . reserve ( _blocksNumber + _blocksTree . size ( ) ) ; // _blocksNumber does not include Thread root blocks
2016-08-01 22:21:59 +03:00
decltype ( m_beginTime ) finishtime = 0 ;
2016-06-26 18:46:51 +03:00
for ( const auto & threadTree : _blocksTree )
{
2016-08-03 23:00:04 +03:00
const auto node_block = threadTree . second . tree . children . front ( ) . node - > block ( ) ;
2016-08-01 22:21:59 +03:00
const auto startTime = node_block - > getBegin ( ) ;
const auto endTime = node_block - > getEnd ( ) ;
if ( m_beginTime > startTime )
{
m_beginTime = startTime ;
}
if ( finishtime < endTime )
2016-06-26 18:46:51 +03:00
{
2016-08-01 22:21:59 +03:00
finishtime = endTime ;
2016-06-26 18:46:51 +03:00
}
}
2016-08-01 22:21:59 +03:00
size_t total_items = 0 ;
2016-06-30 02:57:57 +03:00
const QSignalBlocker b ( this ) ;
2016-06-26 18:46:51 +03:00
for ( const auto & threadTree : _blocksTree )
{
2016-08-03 23:00:04 +03:00
auto & block = threadTree . second . tree ;
2016-08-02 22:22:41 +03:00
auto item = new ProfTreeWidgetItem ( & block ) ;
2016-08-03 23:00:04 +03:00
if ( threadTree . second . thread_name & & threadTree . second . thread_name [ 0 ] ! = 0 )
2016-08-02 22:22:41 +03:00
{
2016-08-03 23:00:04 +03:00
item - > setText ( COL_NAME , QString ( " %1 Thread %2 " ) . arg ( threadTree . second . thread_name ) . arg ( threadTree . first ) ) ;
2016-08-02 22:22:41 +03:00
}
else
{
item - > setText ( COL_NAME , QString ( " Thread %1 " ) . arg ( threadTree . first ) ) ;
}
2016-07-31 18:48:41 +03:00
2016-08-03 23:00:04 +03:00
: : profiler : : timestamp_t duration = 0 ;
if ( ! block . children . empty ( ) )
{
duration = block . children . back ( ) . node - > block ( ) - > getEnd ( ) - block . children . front ( ) . node - > block ( ) - > getBegin ( ) ;
}
item - > setTimeSmart ( COL_DURATION , duration ) ;
item - > setBackgroundColor ( : : profiler_gui : : SELECTED_THREAD_BACKGROUND ) ;
item - > setTextColor ( : : profiler_gui : : SELECTED_THREAD_FOREGROUND ) ;
2016-06-27 22:11:26 +03:00
m_items . push_back ( item ) ;
2016-07-31 18:48:41 +03:00
2016-08-07 19:38:31 +03:00
// TODO: Optimize children duration calculation (it must be calculated before setTreeInternal now)
2016-08-04 22:38:45 +03:00
: : profiler : : timestamp_t children_duration = 0 ;
2016-08-07 19:38:31 +03:00
for ( const auto & child : block . children )
children_duration + = child . node - > block ( ) - > duration ( ) ;
item - > setTimeSmart ( COL_SELF_DURATION , children_duration ) ;
children_duration = 0 ;
const auto children_items_number = setTreeInternal ( block . children , item , nullptr , item , m_beginTime , finishtime + 1000000000ULL , false , children_duration ) ;
2016-07-31 18:48:41 +03:00
2016-08-01 22:21:59 +03:00
if ( children_items_number > 0 )
{
total_items + = children_items_number + 1 ;
addTopLevelItem ( item ) ;
2016-07-31 18:48:41 +03:00
2016-08-03 23:00:04 +03:00
if ( threadTree . first = = : : profiler_gui : : EASY_GLOBALS . selected_thread )
2016-08-01 22:21:59 +03:00
{
2016-08-03 23:00:04 +03:00
item - > colorize ( true ) ;
2016-08-01 22:21:59 +03:00
}
2016-08-03 23:00:04 +03:00
m_roots [ threadTree . first ] = item ;
2016-08-01 22:21:59 +03:00
}
else
2016-07-31 18:48:41 +03:00
{
2016-08-03 23:00:04 +03:00
m_items . pop_back ( ) ;
2016-08-01 22:21:59 +03:00
delete item ;
2016-07-31 18:48:41 +03:00
}
}
2016-08-01 22:21:59 +03:00
return total_items ;
2016-07-31 18:48:41 +03:00
}
2016-08-14 16:05:10 +03:00
auto calculateTotalChildrenNumber ( const : : profiler : : BlocksTree * _tree ) - > decltype ( _tree - > children . size ( ) )
{
auto children_number = _tree - > children . size ( ) ;
for ( const auto & child : _tree - > children )
children_number + = calculateTotalChildrenNumber ( & child ) ;
return children_number ;
}
2016-08-03 23:00:04 +03:00
size_t ProfTreeWidget : : setTreeInternal ( const : : profiler_gui : : TreeBlocks & _blocks , : : profiler : : timestamp_t _left , : : profiler : : timestamp_t _right , bool _strict )
2016-07-31 18:48:41 +03:00
{
if ( _blocks . empty ( ) )
{
2016-08-01 22:21:59 +03:00
return 0 ;
2016-07-31 18:48:41 +03:00
}
2016-08-14 16:05:10 +03:00
//size_t blocksNumber = 0;
//for (const auto& block : _blocks)
// blocksNumber += calculateTotalChildrenNumber(block.tree);
// //blocksNumber += block.tree->total_children_number;
//m_items.reserve(blocksNumber + _blocks.size()); // blocksNumber does not include root blocks
2016-07-31 18:48:41 +03:00
2016-08-03 23:00:04 +03:00
typedef : : std : : unordered_map < : : profiler : : thread_id_t , ProfTreeWidgetItem * , : : profiler_gui : : do_no_hash < : : profiler : : thread_id_t > : : hasher_t > ThreadsMap ;
2016-07-31 18:48:41 +03:00
ThreadsMap threadsMap ;
2016-08-01 22:21:59 +03:00
size_t total_items = 0 ;
2016-07-31 18:48:41 +03:00
const QSignalBlocker b ( this ) ;
for ( const auto & block : _blocks )
{
2016-08-01 22:21:59 +03:00
const auto startTime = block . tree - > node - > block ( ) - > getBegin ( ) ;
const auto endTime = block . tree - > node - > block ( ) - > getEnd ( ) ;
if ( startTime > _right | | endTime < _left )
{
continue ;
}
2016-08-03 23:00:04 +03:00
: : profiler : : timestamp_t duration = 0 ;
2016-07-31 18:48:41 +03:00
ProfTreeWidgetItem * thread_item = nullptr ;
2016-08-03 23:00:04 +03:00
auto thread_item_it = threadsMap . find ( block . root - > thread_id ) ;
2016-07-31 18:48:41 +03:00
if ( thread_item_it ! = threadsMap . end ( ) )
{
thread_item = thread_item_it - > second ;
}
else
{
2016-08-03 23:00:04 +03:00
thread_item = new ProfTreeWidgetItem ( & block . root - > tree ) ;
2016-08-02 22:22:41 +03:00
2016-08-03 23:00:04 +03:00
if ( block . root - > thread_name & & block . root - > thread_name [ 0 ] ! = 0 )
2016-08-02 22:22:41 +03:00
{
2016-08-03 23:00:04 +03:00
thread_item - > setText ( COL_NAME , QString ( " %1 Thread %2 " ) . arg ( block . root - > thread_name ) . arg ( block . root - > thread_id ) ) ;
2016-08-02 22:22:41 +03:00
}
else
{
2016-08-03 23:00:04 +03:00
thread_item - > setText ( COL_NAME , QString ( " Thread %1 " ) . arg ( block . root - > thread_id ) ) ;
2016-08-02 22:22:41 +03:00
}
2016-08-03 23:00:04 +03:00
if ( ! block . root - > tree . children . empty ( ) )
{
duration = block . root - > tree . children . back ( ) . node - > block ( ) - > getEnd ( ) - block . root - > tree . children . front ( ) . node - > block ( ) - > getBegin ( ) ;
}
thread_item - > setTimeSmart ( COL_DURATION , duration ) ;
thread_item - > setBackgroundColor ( : : profiler_gui : : SELECTED_THREAD_BACKGROUND ) ;
thread_item - > setTextColor ( : : profiler_gui : : SELECTED_THREAD_FOREGROUND ) ;
2016-08-07 19:38:31 +03:00
// Calculate clean duration (sum of all children durations)
: : profiler : : timestamp_t children_duration = 0 ;
for ( const auto & child : block . root - > tree . children )
children_duration + = child . node - > block ( ) - > duration ( ) ;
thread_item - > setTimeSmart ( COL_SELF_DURATION , children_duration ) ;
2016-08-03 23:00:04 +03:00
threadsMap . insert ( : : std : : make_pair ( block . root - > thread_id , thread_item ) ) ;
2016-07-31 18:48:41 +03:00
}
auto item = new ProfTreeWidgetItem ( block . tree , thread_item ) ;
2016-08-04 22:38:45 +03:00
duration = endTime - startTime ;
2016-08-03 23:00:04 +03:00
2016-08-09 00:45:45 +03:00
item - > setText ( COL_NAME , : : profiler_gui : : toUnicode ( block . tree - > node - > getBlockName ( ) ) ) ;
2016-08-03 23:00:04 +03:00
item - > setTimeSmart ( COL_DURATION , duration ) ;
2016-08-01 22:21:59 +03:00
item - > setTimeMs ( COL_BEGIN , startTime - m_beginTime ) ;
item - > setTimeMs ( COL_END , endTime - m_beginTime ) ;
2016-07-31 18:48:41 +03:00
2016-08-07 19:38:31 +03:00
item - > setData ( COL_PERCENT_PER_PARENT , Qt : : UserRole , 0 ) ;
item - > setText ( COL_PERCENT_PER_PARENT , " " ) ;
item - > setData ( COL_PERCENT_PER_FRAME , Qt : : UserRole , 0 ) ;
item - > setText ( COL_PERCENT_PER_FRAME , " " ) ;
2016-08-14 16:05:10 +03:00
if ( block . tree - > per_thread_stats ! = nullptr ) // if there is per_thread_stats then there are other stats also
2016-08-07 19:38:31 +03:00
{
2016-08-14 16:05:10 +03:00
const auto & per_thread_stats = block . tree - > per_thread_stats ;
const auto & per_parent_stats = block . tree - > per_parent_stats ;
const auto & per_frame_stats = block . tree - > per_frame_stats ;
if ( per_thread_stats - > calls_number > 1 | | ! : : profiler_gui : : EASY_GLOBALS . display_only_relevant_stats )
2016-08-09 00:14:58 +03:00
{
2016-08-14 16:05:10 +03:00
item - > setTimeSmart ( COL_MIN_PER_THREAD , per_thread_stats - > min_duration , " min " ) ;
item - > setTimeSmart ( COL_MAX_PER_THREAD , per_thread_stats - > max_duration , " max " ) ;
item - > setTimeSmart ( COL_AVERAGE_PER_THREAD , per_thread_stats - > average_duration ( ) ) ;
item - > setTimeSmart ( COL_DURATION_SUM_PER_THREAD , per_thread_stats - > total_duration ) ;
2016-08-09 00:14:58 +03:00
}
2016-08-07 19:38:31 +03:00
2016-08-14 16:05:10 +03:00
item - > setData ( COL_NCALLS_PER_THREAD , Qt : : UserRole , per_thread_stats - > calls_number ) ;
item - > setText ( COL_NCALLS_PER_THREAD , QString : : number ( per_thread_stats - > calls_number ) ) ;
2016-08-03 23:00:04 +03:00
2016-08-14 16:05:10 +03:00
auto percentage_per_thread = static_cast < int > ( 0.5 + 100. * static_cast < double > ( per_thread_stats - > total_duration ) / static_cast < double > ( thread_item - > selfDuration ( ) ) ) ;
2016-08-07 19:38:31 +03:00
item - > setData ( COL_PERCENT_SUM_PER_THREAD , Qt : : UserRole , percentage_per_thread ) ;
item - > setText ( COL_PERCENT_SUM_PER_THREAD , QString : : number ( percentage_per_thread ) ) ;
2016-08-03 23:00:04 +03:00
2016-08-14 16:05:10 +03:00
if ( per_parent_stats - > calls_number > 1 | | ! : : profiler_gui : : EASY_GLOBALS . display_only_relevant_stats )
2016-08-09 00:14:58 +03:00
{
2016-08-14 16:05:10 +03:00
item - > setTimeSmart ( COL_MIN_PER_PARENT , per_parent_stats - > min_duration , " min " ) ;
item - > setTimeSmart ( COL_MAX_PER_PARENT , per_parent_stats - > max_duration , " max " ) ;
item - > setTimeSmart ( COL_AVERAGE_PER_PARENT , per_parent_stats - > average_duration ( ) ) ;
item - > setTimeSmart ( COL_DURATION_SUM_PER_PARENT , per_parent_stats - > total_duration ) ;
2016-08-09 00:14:58 +03:00
}
2016-07-31 18:48:41 +03:00
2016-08-14 16:05:10 +03:00
item - > setData ( COL_NCALLS_PER_PARENT , Qt : : UserRole , per_parent_stats - > calls_number ) ;
item - > setText ( COL_NCALLS_PER_PARENT , QString : : number ( per_parent_stats - > calls_number ) ) ;
2016-07-31 18:48:41 +03:00
2016-08-14 16:05:10 +03:00
if ( per_frame_stats - > calls_number > 1 | | ! : : profiler_gui : : EASY_GLOBALS . display_only_relevant_stats )
2016-08-09 00:14:58 +03:00
{
2016-08-14 16:05:10 +03:00
item - > setTimeSmart ( COL_MIN_PER_FRAME , per_frame_stats - > min_duration , " min " ) ;
item - > setTimeSmart ( COL_MAX_PER_FRAME , per_frame_stats - > max_duration , " max " ) ;
item - > setTimeSmart ( COL_AVERAGE_PER_FRAME , per_frame_stats - > average_duration ( ) ) ;
item - > setTimeSmart ( COL_DURATION_SUM_PER_FRAME , per_frame_stats - > total_duration ) ;
2016-08-09 00:14:58 +03:00
}
2016-07-31 18:48:41 +03:00
2016-08-14 16:05:10 +03:00
item - > setData ( COL_NCALLS_PER_FRAME , Qt : : UserRole , per_frame_stats - > calls_number ) ;
item - > setText ( COL_NCALLS_PER_FRAME , QString : : number ( per_frame_stats - > calls_number ) ) ;
}
else
{
item - > setData ( COL_PERCENT_SUM_PER_THREAD , Qt : : UserRole , 0 ) ;
item - > setText ( COL_PERCENT_SUM_PER_THREAD , " " ) ;
2016-07-31 18:48:41 +03:00
}
const auto color = block . tree - > node - > block ( ) - > getColor ( ) ;
2016-08-07 19:38:31 +03:00
const auto bgColor = : : profiler_gui : : fromProfilerRgb ( : : profiler : : colors : : get_red ( color ) , : : profiler : : colors : : get_green ( color ) , : : profiler : : colors : : get_blue ( color ) ) ;
2016-08-03 23:00:04 +03:00
const auto fgColor = 0x00ffffff - bgColor ;
2016-07-31 18:48:41 +03:00
item - > setBackgroundColor ( bgColor ) ;
item - > setTextColor ( fgColor ) ;
m_items . push_back ( item ) ;
2016-08-01 22:21:59 +03:00
size_t children_items_number = 0 ;
2016-08-04 22:38:45 +03:00
: : profiler : : timestamp_t children_duration = 0 ;
2016-07-31 18:48:41 +03:00
if ( ! block . tree - > children . empty ( ) )
{
2016-08-07 19:38:31 +03:00
children_items_number = setTreeInternal ( block . tree - > children , item , item , thread_item , _left , _right , _strict , children_duration ) ;
2016-08-04 22:38:45 +03:00
}
int percentage = 100 ;
auto self_duration = duration - children_duration ;
if ( children_duration > 0 & & duration > 0 )
{
percentage = static_cast < int > ( 0.5 + 100. * static_cast < double > ( self_duration ) / static_cast < double > ( duration ) ) ;
2016-07-31 18:48:41 +03:00
}
2016-08-04 22:38:45 +03:00
item - > setTimeSmart ( COL_SELF_DURATION , self_duration ) ;
item - > setData ( COL_SELF_DURATION_PERCENT , Qt : : UserRole , percentage ) ;
item - > setText ( COL_SELF_DURATION_PERCENT , QString : : number ( percentage ) ) ;
2016-08-01 22:21:59 +03:00
if ( children_items_number > 0 | | ! _strict | | ( startTime > = _left & & endTime < = _right ) )
{
total_items + = children_items_number + 1 ;
2016-08-11 23:43:34 +03:00
: : profiler_gui : : EASY_GLOBALS . gui_blocks [ block . tree - > block_index ] . tree_item = static_cast < unsigned int > ( m_items . size ( ) - 1 ) ;
2016-08-01 22:21:59 +03:00
if ( m_bColorRows )
{
item - > colorize ( m_bColorRows ) ;
}
}
else
2016-07-31 18:48:41 +03:00
{
2016-08-01 22:21:59 +03:00
m_items . pop_back ( ) ;
delete item ;
2016-07-31 18:48:41 +03:00
}
}
2016-08-01 22:21:59 +03:00
for ( auto & it : threadsMap )
2016-07-31 18:48:41 +03:00
{
2016-08-04 22:38:45 +03:00
auto item = it . second ;
if ( item - > childCount ( ) > 0 )
2016-08-01 22:21:59 +03:00
{
2016-08-04 22:38:45 +03:00
addTopLevelItem ( item ) ;
2016-08-01 22:21:59 +03:00
2016-08-03 23:00:04 +03:00
if ( it . first = = : : profiler_gui : : EASY_GLOBALS . selected_thread )
2016-08-01 22:21:59 +03:00
{
2016-08-04 22:38:45 +03:00
item - > colorize ( true ) ;
2016-08-01 22:21:59 +03:00
}
2016-07-31 18:48:41 +03:00
2016-08-04 22:38:45 +03:00
m_roots [ it . first ] = item ;
m_items . push_back ( item ) ;
2016-08-01 22:21:59 +03:00
+ + total_items ;
}
else
2016-07-31 18:48:41 +03:00
{
2016-08-04 22:38:45 +03:00
delete item ;
2016-07-31 18:48:41 +03:00
}
2016-06-26 18:46:51 +03:00
}
2016-08-01 22:21:59 +03:00
return total_items ;
2016-06-26 18:46:51 +03:00
}
2016-08-07 19:38:31 +03:00
size_t ProfTreeWidget : : setTreeInternal ( const : : profiler : : BlocksTree : : children_t & _children , ProfTreeWidgetItem * _parent , ProfTreeWidgetItem * _frame , ProfTreeWidgetItem * _thread , : : profiler : : timestamp_t _left , : : profiler : : timestamp_t _right , bool _strict , : : profiler : : timestamp_t & _duration )
2016-06-26 18:46:51 +03:00
{
2016-08-01 22:21:59 +03:00
size_t total_items = 0 ;
2016-06-26 18:46:51 +03:00
for ( const auto & child : _children )
{
2016-08-01 22:21:59 +03:00
const auto startTime = child . node - > block ( ) - > getBegin ( ) ;
const auto endTime = child . node - > block ( ) - > getEnd ( ) ;
2016-08-04 22:38:45 +03:00
const auto duration = endTime - startTime ;
_duration + = duration ;
2016-08-01 22:21:59 +03:00
if ( startTime > _right | | endTime < _left )
{
continue ;
}
2016-06-26 19:06:53 +03:00
auto item = new ProfTreeWidgetItem ( & child , _parent ) ;
2016-08-09 00:45:45 +03:00
item - > setText ( COL_NAME , : : profiler_gui : : toUnicode ( child . node - > getBlockName ( ) ) ) ;
2016-08-03 23:00:04 +03:00
item - > setTimeSmart ( COL_DURATION , duration ) ;
2016-08-01 22:21:59 +03:00
item - > setTimeMs ( COL_BEGIN , startTime - m_beginTime ) ;
item - > setTimeMs ( COL_END , endTime - m_beginTime ) ;
2016-08-07 19:38:31 +03:00
item - > setData ( COL_PERCENT_SUM_PER_THREAD , Qt : : UserRole , 0 ) ;
2016-08-14 16:05:10 +03:00
if ( child . per_thread_stats ! = nullptr ) // if there is per_thread_stats then there are other stats also
2016-08-03 23:00:04 +03:00
{
2016-08-14 16:05:10 +03:00
const auto & per_thread_stats = child . per_thread_stats ;
const auto & per_parent_stats = child . per_parent_stats ;
const auto & per_frame_stats = child . per_frame_stats ;
auto percentage = duration = = 0 ? 0 : static_cast < int > ( 0.5 + 100. * static_cast < double > ( duration ) / static_cast < double > ( _parent - > duration ( ) ) ) ;
auto percentage_sum = static_cast < int > ( 0.5 + 100. * static_cast < double > ( per_parent_stats - > total_duration ) / static_cast < double > ( _parent - > duration ( ) ) ) ;
item - > setData ( COL_PERCENT_PER_PARENT , Qt : : UserRole , percentage ) ;
item - > setText ( COL_PERCENT_PER_PARENT , QString : : number ( percentage ) ) ;
item - > setData ( COL_PERCENT_SUM_PER_PARENT , Qt : : UserRole , percentage_sum ) ;
item - > setText ( COL_PERCENT_SUM_PER_PARENT , QString : : number ( percentage_sum ) ) ;
if ( _frame ! = nullptr )
2016-08-07 19:38:31 +03:00
{
2016-08-14 16:05:10 +03:00
if ( _parent ! = _frame )
{
percentage = duration = = 0 ? 0 : static_cast < int > ( 0.5 + 100. * static_cast < double > ( duration ) / static_cast < double > ( _frame - > duration ( ) ) ) ;
percentage_sum = static_cast < int > ( 0.5 + 100. * static_cast < double > ( per_frame_stats - > total_duration ) / static_cast < double > ( _frame - > duration ( ) ) ) ;
}
item - > setData ( COL_PERCENT_PER_FRAME , Qt : : UserRole , percentage ) ;
item - > setText ( COL_PERCENT_PER_FRAME , QString : : number ( percentage ) ) ;
item - > setData ( COL_PERCENT_SUM_PER_FRAME , Qt : : UserRole , percentage_sum ) ;
item - > setText ( COL_PERCENT_SUM_PER_FRAME , QString : : number ( percentage_sum ) ) ;
}
else
{
item - > setData ( COL_PERCENT_PER_FRAME , Qt : : UserRole , 0 ) ;
item - > setText ( COL_PERCENT_PER_FRAME , " " ) ;
item - > setData ( COL_PERCENT_SUM_PER_FRAME , Qt : : UserRole , 0 ) ;
item - > setText ( COL_PERCENT_SUM_PER_FRAME , " " ) ;
2016-08-07 19:38:31 +03:00
}
2016-08-14 16:05:10 +03:00
if ( per_thread_stats - > calls_number > 1 | | ! : : profiler_gui : : EASY_GLOBALS . display_only_relevant_stats )
2016-08-09 00:14:58 +03:00
{
2016-08-14 16:05:10 +03:00
item - > setTimeSmart ( COL_MIN_PER_THREAD , per_thread_stats - > min_duration , " min " ) ;
item - > setTimeSmart ( COL_MAX_PER_THREAD , per_thread_stats - > max_duration , " max " ) ;
item - > setTimeSmart ( COL_AVERAGE_PER_THREAD , per_thread_stats - > average_duration ( ) ) ;
item - > setTimeSmart ( COL_DURATION_SUM_PER_THREAD , per_thread_stats - > total_duration ) ;
2016-08-09 00:14:58 +03:00
}
2016-08-07 19:38:31 +03:00
2016-08-14 16:05:10 +03:00
item - > setData ( COL_NCALLS_PER_THREAD , Qt : : UserRole , per_thread_stats - > calls_number ) ;
item - > setText ( COL_NCALLS_PER_THREAD , QString : : number ( per_thread_stats - > calls_number ) ) ;
2016-08-03 23:00:04 +03:00
2016-08-07 19:38:31 +03:00
if ( _thread )
{
2016-08-14 16:05:10 +03:00
auto percentage_per_thread = static_cast < int > ( 0.5 + 100. * static_cast < double > ( per_thread_stats - > total_duration ) / static_cast < double > ( _thread - > selfDuration ( ) ) ) ;
2016-08-07 19:38:31 +03:00
item - > setData ( COL_PERCENT_SUM_PER_THREAD , Qt : : UserRole , percentage_per_thread ) ;
item - > setText ( COL_PERCENT_SUM_PER_THREAD , QString : : number ( percentage_per_thread ) ) ;
}
2016-08-03 23:00:04 +03:00
2016-08-14 16:05:10 +03:00
if ( per_parent_stats - > calls_number > 1 | | ! : : profiler_gui : : EASY_GLOBALS . display_only_relevant_stats )
2016-08-09 00:14:58 +03:00
{
2016-08-14 16:05:10 +03:00
item - > setTimeSmart ( COL_MIN_PER_PARENT , per_parent_stats - > min_duration , " min " ) ;
item - > setTimeSmart ( COL_MAX_PER_PARENT , per_parent_stats - > max_duration , " max " ) ;
item - > setTimeSmart ( COL_AVERAGE_PER_PARENT , per_parent_stats - > average_duration ( ) ) ;
item - > setTimeSmart ( COL_DURATION_SUM_PER_PARENT , per_parent_stats - > total_duration ) ;
2016-08-09 00:14:58 +03:00
}
2016-06-27 22:11:26 +03:00
2016-08-14 16:05:10 +03:00
item - > setData ( COL_NCALLS_PER_PARENT , Qt : : UserRole , per_parent_stats - > calls_number ) ;
item - > setText ( COL_NCALLS_PER_PARENT , QString : : number ( per_parent_stats - > calls_number ) ) ;
2016-06-27 22:11:26 +03:00
2016-08-14 16:05:10 +03:00
if ( per_frame_stats - > calls_number > 1 | | ! : : profiler_gui : : EASY_GLOBALS . display_only_relevant_stats )
2016-08-09 00:14:58 +03:00
{
2016-08-14 16:05:10 +03:00
item - > setTimeSmart ( COL_MIN_PER_FRAME , per_frame_stats - > min_duration , " min " ) ;
item - > setTimeSmart ( COL_MAX_PER_FRAME , per_frame_stats - > max_duration , " max " ) ;
item - > setTimeSmart ( COL_AVERAGE_PER_FRAME , per_frame_stats - > average_duration ( ) ) ;
item - > setTimeSmart ( COL_DURATION_SUM_PER_FRAME , per_frame_stats - > total_duration ) ;
2016-08-09 00:14:58 +03:00
}
2016-06-27 22:11:26 +03:00
2016-08-14 16:05:10 +03:00
item - > setData ( COL_NCALLS_PER_FRAME , Qt : : UserRole , per_frame_stats - > calls_number ) ;
item - > setText ( COL_NCALLS_PER_FRAME , QString : : number ( per_frame_stats - > calls_number ) ) ;
}
else
{
item - > setData ( COL_PERCENT_PER_PARENT , Qt : : UserRole , 0 ) ;
item - > setText ( COL_PERCENT_PER_PARENT , " " ) ;
item - > setData ( COL_PERCENT_SUM_PER_PARENT , Qt : : UserRole , 0 ) ;
item - > setText ( COL_PERCENT_SUM_PER_PARENT , " " ) ;
item - > setData ( COL_PERCENT_SUM_PER_THREAD , Qt : : UserRole , 0 ) ;
item - > setText ( COL_PERCENT_SUM_PER_THREAD , " " ) ;
2016-06-26 18:46:51 +03:00
}
2016-06-27 22:11:26 +03:00
const auto color = child . node - > block ( ) - > getColor ( ) ;
2016-08-07 19:38:31 +03:00
const auto bgColor = : : profiler_gui : : fromProfilerRgb ( : : profiler : : colors : : get_red ( color ) , : : profiler : : colors : : get_green ( color ) , : : profiler : : colors : : get_blue ( color ) ) ;
2016-08-03 23:00:04 +03:00
const auto fgColor = 0x00ffffff - bgColor ;
2016-06-27 22:11:26 +03:00
item - > setBackgroundColor ( bgColor ) ;
item - > setTextColor ( fgColor ) ;
m_items . push_back ( item ) ;
2016-06-26 18:46:51 +03:00
2016-08-02 21:21:12 +03:00
size_t children_items_number = 0 ;
2016-08-04 22:38:45 +03:00
: : profiler : : timestamp_t children_duration = 0 ;
2016-06-26 18:46:51 +03:00
if ( ! child . children . empty ( ) )
{
2016-08-07 19:38:31 +03:00
children_items_number = setTreeInternal ( child . children , item , _frame ? _frame : item , _thread , _left , _right , _strict , children_duration ) ;
2016-06-26 18:46:51 +03:00
}
2016-07-31 18:48:41 +03:00
2016-08-14 16:05:10 +03:00
int percentage = 100 ;
2016-08-04 22:38:45 +03:00
auto self_duration = duration - children_duration ;
if ( children_duration > 0 & & duration > 0 )
{
percentage = static_cast < int > ( 0.5 + 100. * static_cast < double > ( self_duration ) / static_cast < double > ( duration ) ) ;
}
item - > setTimeSmart ( COL_SELF_DURATION , self_duration ) ;
item - > setData ( COL_SELF_DURATION_PERCENT , Qt : : UserRole , percentage ) ;
item - > setText ( COL_SELF_DURATION_PERCENT , QString : : number ( percentage ) ) ;
2016-08-01 22:21:59 +03:00
if ( children_items_number > 0 | | ! _strict | | ( startTime > = _left & & endTime < = _right ) )
2016-07-31 18:48:41 +03:00
{
2016-08-01 22:21:59 +03:00
total_items + = children_items_number + 1 ;
2016-08-11 23:43:34 +03:00
: : profiler_gui : : EASY_GLOBALS . gui_blocks [ child . block_index ] . tree_item = static_cast < unsigned int > ( m_items . size ( ) - 1 ) ;
2016-08-01 22:21:59 +03:00
if ( m_bColorRows )
{
item - > colorize ( m_bColorRows ) ;
}
}
else
{
m_items . pop_back ( ) ;
delete item ;
2016-07-31 18:48:41 +03:00
}
2016-06-26 18:46:51 +03:00
}
2016-08-01 22:21:59 +03:00
return total_items ;
2016-06-26 18:46:51 +03:00
}
2016-07-31 18:48:41 +03:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2016-06-26 19:06:53 +03:00
void ProfTreeWidget : : contextMenuEvent ( QContextMenuEvent * _event )
2016-06-26 18:46:51 +03:00
{
const auto col = currentColumn ( ) ;
2016-06-26 19:06:53 +03:00
auto item = static_cast < ProfTreeWidgetItem * > ( currentItem ( ) ) ;
2016-06-26 18:46:51 +03:00
QMenu menu ;
auto action = new QAction ( " Expand all " , nullptr ) ;
2016-06-27 22:11:26 +03:00
connect ( action , & QAction : : triggered , this , & This : : onExpandAllClicked ) ;
2016-06-26 18:46:51 +03:00
menu . addAction ( action ) ;
action = new QAction ( " Collapse all " , nullptr ) ;
2016-06-27 22:11:26 +03:00
connect ( action , & QAction : : triggered , this , & This : : onCollapseAllClicked ) ;
menu . addAction ( action ) ;
2016-08-01 22:21:59 +03:00
if ( item ! = nullptr & & col > = 0 )
{
menu . addSeparator ( ) ;
2016-06-27 22:11:26 +03:00
2016-08-01 22:21:59 +03:00
action = new QAction ( " Expand all children " , nullptr ) ;
connect ( action , & QAction : : triggered , this , & This : : onExpandAllChildrenClicked ) ;
menu . addAction ( action ) ;
2016-07-31 18:48:41 +03:00
2016-08-01 22:21:59 +03:00
action = new QAction ( " Collapse all children " , nullptr ) ;
connect ( action , & QAction : : triggered , this , & This : : onCollapseAllChildrenClicked ) ;
menu . addAction ( action ) ;
}
2016-07-31 18:48:41 +03:00
menu . addSeparator ( ) ;
2016-06-27 22:11:26 +03:00
action = new QAction ( " Color rows " , nullptr ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( m_bColorRows ) ;
connect ( action , & QAction : : triggered , this , & This : : onColorizeRowsTriggered ) ;
2016-06-26 18:46:51 +03:00
menu . addAction ( action ) ;
2016-08-08 22:17:56 +03:00
if ( item ! = nullptr )
2016-06-26 18:46:51 +03:00
{
2016-08-08 22:17:56 +03:00
auto itemAction = new ProfItemAction ( " Show this item on scene " , item - > block ( ) - > block_index ) ;
itemAction - > setToolTip ( " Scroll graphics scene to current item in the tree " ) ;
connect ( itemAction , & ProfItemAction : : clicked , this , & This : : onJumpToItemClicked ) ;
menu . addAction ( itemAction ) ;
2016-08-01 22:21:59 +03:00
2016-08-08 22:17:56 +03:00
if ( col > = 0 )
{
switch ( col )
2016-08-01 22:21:59 +03:00
{
2016-08-08 22:17:56 +03:00
case COL_MIN_PER_THREAD :
case COL_MIN_PER_PARENT :
case COL_MIN_PER_FRAME :
case COL_MAX_PER_THREAD :
case COL_MAX_PER_PARENT :
case COL_MAX_PER_FRAME :
{
2016-08-14 16:05:10 +03:00
auto block = item - > block ( ) ;
2016-08-11 23:43:34 +03:00
auto i = : : profiler_gui : : numeric_max < unsigned int > ( ) ;
2016-08-08 22:17:56 +03:00
switch ( col )
{
2016-08-14 16:05:10 +03:00
case COL_MIN_PER_THREAD : i = block - > per_thread_stats - > min_duration_block ; break ;
case COL_MIN_PER_PARENT : i = block - > per_parent_stats - > min_duration_block ; break ;
case COL_MIN_PER_FRAME : i = block - > per_frame_stats - > min_duration_block ; break ;
case COL_MAX_PER_THREAD : i = block - > per_thread_stats - > max_duration_block ; break ;
case COL_MAX_PER_PARENT : i = block - > per_parent_stats - > max_duration_block ; break ;
case COL_MAX_PER_FRAME : i = block - > per_frame_stats - > max_duration_block ; break ;
2016-08-08 22:17:56 +03:00
}
2016-08-11 23:43:34 +03:00
if ( i ! = : : profiler_gui : : numeric_max ( i ) )
2016-08-08 22:17:56 +03:00
{
menu . addSeparator ( ) ;
itemAction = new ProfItemAction ( " Jump to such item " , i ) ;
itemAction - > setToolTip ( " Jump to item with min/max duration (depending on clicked column) " ) ;
connect ( itemAction , & ProfItemAction : : clicked , this , & This : : onJumpToItemClicked ) ;
menu . addAction ( itemAction ) ;
}
break ;
}
2016-08-01 22:21:59 +03:00
}
2016-06-26 18:46:51 +03:00
}
}
2016-08-03 23:00:04 +03:00
menu . addSeparator ( ) ;
auto hidemenu = menu . addMenu ( " Select columns " ) ;
auto hdr = headerItem ( ) ;
2016-08-04 23:12:41 +03:00
for ( int i = 0 ; i < COL_COLUMNS_NUMBER ; + + i )
2016-08-03 23:00:04 +03:00
{
auto columnAction = new ProfHideShowColumnAction ( hdr - > text ( i ) , i ) ;
columnAction - > setCheckable ( true ) ;
2016-08-04 23:12:41 +03:00
columnAction - > setChecked ( ! isColumnHidden ( i ) ) ;
2016-08-03 23:00:04 +03:00
connect ( columnAction , & ProfHideShowColumnAction : : clicked , this , & This : : onHideShowColumn ) ;
hidemenu - > addAction ( columnAction ) ;
}
2016-06-26 18:46:51 +03:00
menu . exec ( QCursor : : pos ( ) ) ;
_event - > accept ( ) ;
}
2016-07-31 18:48:41 +03:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2016-08-08 22:17:56 +03:00
void ProfTreeWidget : : onJumpToItemClicked ( unsigned int _block_index )
2016-06-26 18:46:51 +03:00
{
2016-08-08 22:17:56 +03:00
: : profiler_gui : : EASY_GLOBALS . selected_block = _block_index ;
emit : : profiler_gui : : EASY_GLOBALS . events . selectedBlockChanged ( _block_index ) ;
2016-06-26 18:46:51 +03:00
}
2016-06-26 19:06:53 +03:00
void ProfTreeWidget : : onCollapseAllClicked ( bool )
2016-06-26 18:46:51 +03:00
{
collapseAll ( ) ;
}
2016-06-26 19:06:53 +03:00
void ProfTreeWidget : : onExpandAllClicked ( bool )
2016-06-26 18:46:51 +03:00
{
2016-06-27 22:11:26 +03:00
disconnect ( this , & Parent : : itemExpanded , this , & This : : onItemExpand ) ;
2016-06-26 18:46:51 +03:00
expandAll ( ) ;
2016-08-03 23:00:04 +03:00
//resizeColumnToContents(COL_NAME);
resizeColumnsToContents ( ) ;
2016-06-27 22:11:26 +03:00
connect ( this , & Parent : : itemExpanded , this , & This : : onItemExpand ) ;
2016-06-26 18:46:51 +03:00
}
2016-07-31 18:48:41 +03:00
void ProfTreeWidget : : onCollapseAllChildrenClicked ( bool )
{
auto current = static_cast < ProfTreeWidgetItem * > ( currentItem ( ) ) ;
if ( current ! = nullptr )
{
current - > collapseAll ( ) ;
}
}
void ProfTreeWidget : : onExpandAllChildrenClicked ( bool )
{
auto current = static_cast < ProfTreeWidgetItem * > ( currentItem ( ) ) ;
if ( current ! = nullptr )
{
disconnect ( this , & Parent : : itemExpanded , this , & This : : onItemExpand ) ;
current - > expandAll ( ) ;
2016-08-03 23:00:04 +03:00
//resizeColumnToContents(COL_NAME);
resizeColumnsToContents ( ) ;
2016-07-31 18:48:41 +03:00
connect ( this , & Parent : : itemExpanded , this , & This : : onItemExpand ) ;
}
}
2016-06-26 19:06:53 +03:00
void ProfTreeWidget : : onItemExpand ( QTreeWidgetItem * )
2016-06-26 18:46:51 +03:00
{
2016-08-03 23:00:04 +03:00
//resizeColumnToContents(COL_NAME);
resizeColumnsToContents ( ) ;
2016-06-27 22:11:26 +03:00
}
void ProfTreeWidget : : onColorizeRowsTriggered ( bool _colorize )
{
const QSignalBlocker b ( this ) ;
m_bColorRows = _colorize ;
auto current = currentItem ( ) ;
collapseAll ( ) ; // Without collapseAll() changing items process is VERY VERY SLOW.
// TODO: Find the reason of such behavior. QSignalBlocker(this) does not help. QSignalBlocker(item) does not work, because items are not inherited from QObject.
for ( auto item : m_items )
{
2016-08-03 23:00:04 +03:00
if ( item - > parent ( ) ! = nullptr )
item - > colorize ( m_bColorRows ) ;
2016-06-27 22:11:26 +03:00
}
// Scroll back to previously selected item
if ( current )
{
scrollToItem ( current , QAbstractItemView : : PositionAtCenter ) ;
setCurrentItem ( current ) ;
}
2016-06-26 18:46:51 +03:00
}
//////////////////////////////////////////////////////////////////////////
2016-08-03 23:00:04 +03:00
void ProfTreeWidget : : onSelectedThreadChange ( : : profiler : : thread_id_t _id )
{
for ( auto & it : m_roots )
{
it . second - > colorize ( it . first = = _id ) ;
}
}
2016-08-08 22:17:56 +03:00
void ProfTreeWidget : : onSelectedBlockChange ( unsigned int _block_index )
{
2016-08-11 23:43:34 +03:00
ProfTreeWidgetItem * item = nullptr ;
2016-08-08 22:17:56 +03:00
if ( _block_index < : : profiler_gui : : EASY_GLOBALS . gui_blocks . size ( ) )
{
2016-08-11 23:43:34 +03:00
const auto i = : : profiler_gui : : EASY_GLOBALS . gui_blocks [ _block_index ] . tree_item ;
if ( i < m_items . size ( ) )
item = m_items [ i ] ;
2016-08-08 22:17:56 +03:00
}
2016-08-11 23:43:34 +03:00
if ( item ! = nullptr )
scrollToItem ( item , QAbstractItemView : : PositionAtCenter ) ;
setCurrentItem ( item ) ;
2016-08-08 22:17:56 +03:00
}
2016-08-03 23:00:04 +03:00
//////////////////////////////////////////////////////////////////////////
void ProfTreeWidget : : resizeColumnsToContents ( )
{
for ( int i = 0 ; i < COL_COLUMNS_NUMBER ; + + i )
{
resizeColumnToContents ( i ) ;
}
}
//////////////////////////////////////////////////////////////////////////
void ProfTreeWidget : : onHideShowColumn ( int _column )
{
if ( isColumnHidden ( _column ) )
{
showColumn ( _column ) ;
}
else
{
hideColumn ( _column ) ;
}
}
//////////////////////////////////////////////////////////////////////////
2016-08-04 23:12:41 +03:00
2016-08-07 19:38:31 +03:00
void ProfTreeWidget : : loadSettings ( )
{
QSettings settings ( : : profiler_gui : : ORGANAZATION_NAME , : : profiler_gui : : APPLICATION_NAME ) ;
settings . beginGroup ( " tree_widget " ) ;
auto color_rows_set = settings . value ( " color_rows " ) ;
if ( ! color_rows_set . isNull ( ) )
m_bColorRows = color_rows_set . toBool ( ) ;
for ( int i = 0 ; i < columnCount ( ) ; i + + )
{
if ( settings . value ( QString ( " Column " ) + QString : : number ( i ) ) . toBool ( ) )
hideColumn ( i ) ;
}
settings . endGroup ( ) ;
}
2016-08-04 23:12:41 +03:00
void ProfTreeWidget : : saveSettings ( )
{
2016-08-07 19:38:31 +03:00
QSettings settings ( : : profiler_gui : : ORGANAZATION_NAME , : : profiler_gui : : APPLICATION_NAME ) ;
2016-08-04 23:12:41 +03:00
settings . beginGroup ( " tree_widget " ) ;
settings . setValue ( " color_rows " , m_bColorRows ) ;
for ( int i = 0 ; i < columnCount ( ) ; i + + )
{
settings . setValue ( QString ( " Column " ) + QString : : number ( i ) , isColumnHidden ( i ) ) ;
}
settings . endGroup ( ) ;
}
2016-08-07 19:38:31 +03:00
//////////////////////////////////////////////////////////////////////////