20#include <QThreadStorage> 
   46    const QString parentId = mParent->
data( 
static_cast< int >( 
CustomRole::Id ) ).toString();
 
   47    if ( !parentId.isEmpty() )
 
   49    else if ( !parentName.isEmpty() )
 
 
   84  Q_ASSERT( !
child->mParent );
 
   85  child->mParent = 
this;
 
   87  mChildren.emplace_back( std::move( 
child ) );
 
 
   92  Q_ASSERT( 
child->mParent == 
this );
 
   93  const auto it = std::find_if( mChildren.begin(), mChildren.end(), [&]( 
const std::unique_ptr<QgsRuntimeProfilerNode> &p )
 
   95    return p.get() == child;
 
   97  if ( it != mChildren.end() )
 
   98    return std::distance( mChildren.begin(), it );
 
 
  104  for ( 
auto &it : mChildren )
 
  107         && ( ( !
id.isEmpty() && it->data( 
static_cast< int >( 
CustomRole::Id ) ) == id )
 
  108              || ( 
id.isEmpty() && !name.isEmpty() && it->data( 
static_cast< int >( 
CustomRole::Name ) ).toString() == name ) ) )
 
 
  116  Q_ASSERT( 
static_cast< std::size_t 
>( index ) < mChildren.size() );
 
  117  return mChildren[ index ].get();
 
 
  127  Q_ASSERT( 
static_cast< std::size_t 
>( index ) < mChildren.size() );
 
  128  mChildren.erase( mChildren.begin() + index );
 
 
  133  mProfileTime.restart();
 
 
  138  mElapsed = mProfileTime.elapsed() / 1000.0;
 
 
  154  for ( 
auto &it : mChildren )
 
  157      total += it->elapsed();
 
 
  176  static QThreadStorage<QgsRuntimeProfiler> sInstances;
 
  179  if ( !qApp || profiler->thread() == qApp->thread() )
 
  180    sMainProfiler = profiler;
 
  182  if ( !profiler->mInitialized )
 
  183    profiler->setupConnections();
 
  202    return QStringList();
 
  206  for ( 
int i = 0; i < parentNode->
childCount(); ++i )
 
 
  217  std::unique_ptr< QgsRuntimeProfilerNode > node = std::make_unique< QgsRuntimeProfilerNode >( group, name, 
id );
 
  221  if ( !mCurrentStack[ group ].empty() )
 
  225    const QModelIndex parentIndex = node2index( 
parent );
 
  226    beginInsertRows( parentIndex, 
parent->childCount(), 
parent->childCount() );
 
  227    parent->addChild( std::move( node ) );
 
  232    beginInsertRows( QModelIndex(), mRootNode->childCount(), mRootNode->childCount() );
 
  233    mRootNode->addChild( std::move( node ) );
 
  237  mCurrentStack[group].push( child );
 
  240  if ( !mGroups.contains( group ) )
 
  242    mGroups.insert( group );
 
 
  249  if ( mCurrentStack[group].empty() )
 
  253  mCurrentStack[group].pop();
 
  256  const QModelIndex nodeIndex = node2index( node );
 
  257  const QModelIndex col2Index = 
index( nodeIndex.row(), 1, nodeIndex.parent() );
 
  258  emit dataChanged( nodeIndex, nodeIndex );
 
  259  emit dataChanged( col2Index, col2Index );
 
  261  QModelIndex parentIndex = nodeIndex.parent();
 
  262  while ( parentIndex.isValid() )
 
  264    const QModelIndex parentCol2Index = 
index( parentIndex.row(), 1, parentIndex.parent() );
 
  265    emit dataChanged( parentIndex, parentIndex );
 
  266    emit dataChanged( parentCol2Index, parentCol2Index );
 
  267    parentIndex = parentIndex.parent();
 
 
  275  std::unique_ptr< QgsRuntimeProfilerNode > node = std::make_unique< QgsRuntimeProfilerNode >( group, name, 
id );
 
  278  if ( !mCurrentStack[ group ].empty() )
 
  282    const QModelIndex parentIndex = node2index( 
parent );
 
  283    beginInsertRows( parentIndex, 
parent->childCount(), 
parent->childCount() );
 
  284    parent->addChild( std::move( node ) );
 
  289    beginInsertRows( QModelIndex(), mRootNode->childCount(), mRootNode->childCount() );
 
  290    mRootNode->addChild( std::move( node ) );
 
  298  if ( !mGroups.contains( group ) )
 
  300    mGroups.insert( group );
 
 
  316  for ( 
int row = mRootNode->childCount() - 1; row >= 0; row-- )
 
  320      beginRemoveRows( QModelIndex(), row, row );
 
  321      mRootNode->removeChildAt( row );
 
 
  330    return node->elapsed();
 
 
  337  return !mCurrentStack.value( group ).empty();
 
 
  342  if ( group == QLatin1String( 
"startup" ) )
 
  343    return tr( 
"Startup" );
 
  344  else if ( group == QLatin1String( 
"projectload" ) )
 
  345    return tr( 
"Project Load" );
 
  346  else if ( group == QLatin1String( 
"rendering" ) )
 
  347    return tr( 
"Map Render" );
 
 
  370    return QModelIndex();
 
  374    return QModelIndex(); 
 
  376  return createIndex( row, column, n->
childAt( row ) );
 
 
  381  if ( !child.isValid() )
 
  382    return QModelIndex();
 
  386    return indexOfParentNode( n->parent() ); 
 
  391    return QModelIndex();
 
 
  404  switch ( 
index.column() )
 
  407      return node->
data( role );
 
  413        case Qt::DisplayRole:
 
  414        case Qt::InitialSortOrderRole:
 
  420      return node->
data( role );
 
 
  430    case Qt::DisplayRole:
 
  432      if ( orientation == Qt::Horizontal )
 
  439            return tr( 
"Time (seconds)" );
 
  451      return QAbstractItemModel::headerData( section, orientation, role );
 
 
  455void QgsRuntimeProfiler::otherProfilerStarted( 
const QString &group, 
const QStringList &path, 
const QString &name, 
const QString &
id )
 
  458  for ( 
const QString &part : path )
 
  463      child = parentNode->
child( group, part );
 
  467      std::unique_ptr< QgsRuntimeProfilerNode > newChild = std::make_unique< QgsRuntimeProfilerNode >( group, part );
 
  469      const QModelIndex parentIndex = node2index( parentNode );
 
  472      parentNode->
addChild( std::move( newChild ) );
 
  482  if ( parentNode->
child( group, name, 
id ) )
 
  485  const QModelIndex parentIndex = node2index( parentNode );
 
  487  parentNode->
addChild( std::make_unique< QgsRuntimeProfilerNode >( group, name, 
id ) );
 
  490  if ( !mGroups.contains( group ) )
 
  492    mGroups.insert( group );
 
  497void QgsRuntimeProfiler::otherProfilerEnded( 
const QString &group, 
const QStringList &path, 
const QString &name, 
const QString &
id, 
double elapsed )
 
  500  for ( 
const QString &part : path )
 
  505      child = parentNode->
child( group, part );
 
  509      std::unique_ptr< QgsRuntimeProfilerNode > newChild = std::make_unique< QgsRuntimeProfilerNode >( group, part );
 
  511      const QModelIndex parentIndex = node2index( parentNode );
 
  514      parentNode->
addChild( std::move( newChild ) );
 
  527    std::unique_ptr< QgsRuntimeProfilerNode > node = std::make_unique< QgsRuntimeProfilerNode >( group, name, 
id );
 
  528    destNode = node.get();
 
  529    const QModelIndex parentIndex = node2index( parentNode );
 
  531    parentNode->
addChild( std::move( node ) );
 
  537  const QModelIndex nodeIndex = node2index( destNode ); 
 
  538  const QModelIndex col2Index = 
index( nodeIndex.row(), 1, nodeIndex.parent() );
 
  539  emit dataChanged( nodeIndex, nodeIndex );
 
  540  emit dataChanged( col2Index, col2Index );
 
  542  QModelIndex parentIndex = nodeIndex.parent();
 
  543  while ( parentIndex.isValid() )
 
  545    const QModelIndex parentCol2Index = 
index( parentIndex.row(), 1, parentIndex.parent() );
 
  546    emit dataChanged( parentIndex, parentIndex );
 
  547    emit dataChanged( parentCol2Index, parentCol2Index );
 
  548    parentIndex = parentIndex.parent();
 
  552void QgsRuntimeProfiler::setupConnections()
 
  556  Q_ASSERT( sMainProfiler );
 
  558  if ( sMainProfiler != 
this )
 
  560    connect( 
this, &QgsRuntimeProfiler::started, sMainProfiler, &QgsRuntimeProfiler::otherProfilerStarted );
 
  561    connect( 
this, &QgsRuntimeProfiler::ended, sMainProfiler, &QgsRuntimeProfiler::otherProfilerEnded );
 
  567  const QStringList parts = path.split( 
'/' );
 
  569  for ( 
const QString &part : parts )
 
  571    if ( part.isEmpty() )
 
  577      child = res->
child( group, part );
 
  586QgsRuntimeProfilerNode *QgsRuntimeProfiler::pathToNode( 
const QString &group, 
const QStringList &path )
 const 
  589  for ( 
const QString &part : path )
 
  594      child = res->
child( group, part );
 
  605  if ( !node || !node->
parent() )
 
  606    return QModelIndex(); 
 
  608  const QModelIndex parentIndex = node2index( node->
parent() );
 
  611  Q_ASSERT( row >= 0 );
 
  612  return index( row, 0, parentIndex );
 
  617  Q_ASSERT( parentNode );
 
  620  if ( !grandParentNode )
 
  621    return QModelIndex();  
 
  623  const int row = grandParentNode->
indexOf( parentNode );
 
  624  Q_ASSERT( row >= 0 );
 
  626  return createIndex( row, 0, parentNode );
 
  631  if ( !
index.isValid() )
 
  632    return mRootNode.get();
 
  637void QgsRuntimeProfiler::extractModelAsText( QStringList &lines, 
const QString &group, 
const QModelIndex &parent, 
int level )
 
  641  for ( 
int r = 0; r < rc; r++ )
 
  648    for ( 
int c = 0; 
c < cc; 
c++ )
 
  651      cells << 
data( cellIndex ).toString();
 
  653    lines << QStringLiteral( 
"%1 %2" ).arg( QStringLiteral( 
"-" ).repeated( level + 1 ), cells.join( QLatin1String( 
": " ) ) );
 
  654    extractModelAsText( lines, group, rowIndex, level + 1 );
 
  661  for ( 
const QString &g : std::as_const( mGroups ) )
 
  663    if ( !group.isEmpty() && g != group )
 
  667    lines << ( !groupName.isEmpty() ? groupName : g );
 
  668    extractModelAsText( lines, g );
 
  670  return lines.join( QLatin1String( 
"\r\n" ) );
 
 
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
 
A node representing an entry in a QgsRuntimeProfiler.
 
void stop()
Stops the node's timer, recording the elapsed time automatically.
 
QgsRuntimeProfilerNode * child(const QString &group, const QString &name, const QString &id=QString())
Finds the child with matching group, name and id (since QGIS 3.34).
 
int indexOf(QgsRuntimeProfilerNode *child) const
Returns the index of the specified child node.
 
void clear()
Clears the node, removing all its children.
 
QgsRuntimeProfilerNode * childAt(int index)
Returns the child at the specified index.
 
double elapsed() const
Returns the node's elapsed time, in seconds.
 
void addChild(std::unique_ptr< QgsRuntimeProfilerNode > child)
Adds a child node to this node.
 
void removeChildAt(int index)
Removes and deletes the child at the specified index.
 
double totalElapsedTimeForChildren(const QString &group) const
Returns the total elapsed time in seconds for all children of this node with matching group.
 
@ Elapsed
Node elapsed time.
 
@ ParentElapsed
Total elapsed time for node's parent.
 
QgsRuntimeProfilerNode(const QString &group, const QString &name, const QString &id=QString())
Constructor for QgsRuntimeProfilerNode, with the specified group and name.
 
QgsRuntimeProfilerNode * parent()
Returns the node's parent node.
 
int childCount() const
Returns the number of child nodes owned by this node.
 
QStringList fullParentPath() const
Returns the full path to the node's parent.
 
void setElapsed(double time)
Manually sets the node's elapsed time, in seconds.
 
void start()
Starts the node timer.
 
QVariant data(int role=Qt::DisplayRole) const
Returns the node's data for the specified model role.
 
~QgsRuntimeProfilerNode()
 
Provides a method of recording run time profiles of operations, allowing easy recording of their over...
 
void groupAdded(const QString &group)
Emitted when a new group has started being profiled.
 
QModelIndex parent(const QModelIndex &child) const override
 
QString asText(const QString &group=QString())
Returns the model as a multi-line text string.
 
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
 
double profileTime(const QString &name, const QString &group="startup") const
Returns the profile time for the specified name.
 
QgsRuntimeProfiler()
Constructor to create a new runtime profiler.
 
void start(const QString &name, const QString &group="startup", const QString &id=QString())
Start a profile event with the given name.
 
QStringList childGroups(const QString &parent=QString(), const QString &group="startup") const
Returns a list of all child groups with the specified parent.
 
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
 
void end(const QString &group="startup")
End the current profile event.
 
int rowCount(const QModelIndex &parent=QModelIndex()) const override
 
double totalTime(const QString &group="startup")
The current total time collected in the profiler.
 
bool groupIsActive(const QString &group) const
Returns true if the specified group is currently being logged, i.e.
 
void clear(const QString &group="startup")
clear Clear all profile data.
 
Q_DECL_DEPRECATED void beginGroup(const QString &name)
Begin the group for the profiler.
 
~QgsRuntimeProfiler() override
 
Q_DECL_DEPRECATED void endGroup()
End the current active group.
 
void record(const QString &name, double time, const QString &group="startup", const QString &id=QString())
Manually adds a profile event with the given name and total time (in seconds).
 
static QString translateGroupName(const QString &group)
Returns the translated name of a standard profile group.
 
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
 
int columnCount(const QModelIndex &parent=QModelIndex()) const override
 
void switchTask(const QString &name)
Switches the current task managed by the scoped profile to a new task with the given name.
 
~QgsScopedRuntimeProfile()
Records the final runtime of the operation in the profiler instance.
 
QgsScopedRuntimeProfile(const QString &name, const QString &group="startup", const QString &id=QString())
Constructor for QgsScopedRuntimeProfile.
 
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c