16#include "moc_qgsruntimeprofiler.cpp" 
   21#include <QThreadStorage> 
   47    const QString parentId = mParent->
data( 
static_cast< int >( 
CustomRole::Id ) ).toString();
 
   48    if ( !parentId.isEmpty() )
 
   50    else if ( !parentName.isEmpty() )
 
 
   85  Q_ASSERT( !
child->mParent );
 
   86  child->mParent = 
this;
 
   88  mChildren.emplace_back( std::move( 
child ) );
 
 
   93  Q_ASSERT( 
child->mParent == 
this );
 
   94  const auto it = std::find_if( mChildren.begin(), mChildren.end(), [&]( 
const std::unique_ptr<QgsRuntimeProfilerNode> &p )
 
   96    return p.get() == child;
 
   98  if ( it != mChildren.end() )
 
   99    return std::distance( mChildren.begin(), it );
 
 
  105  for ( 
auto &it : mChildren )
 
  108         && ( ( !
id.isEmpty() && it->data( 
static_cast< int >( 
CustomRole::Id ) ) == id )
 
  109              || ( 
id.isEmpty() && !name.isEmpty() && it->data( 
static_cast< int >( 
CustomRole::Name ) ).toString() == name ) ) )
 
 
  117  Q_ASSERT( 
static_cast< std::size_t 
>( index ) < mChildren.size() );
 
  118  return mChildren[ index ].get();
 
 
  128  Q_ASSERT( 
static_cast< std::size_t 
>( index ) < mChildren.size() );
 
  129  mChildren.erase( mChildren.begin() + index );
 
 
  134  mProfileTime.restart();
 
 
  139  mElapsed = mProfileTime.elapsed() / 1000.0;
 
 
  155  for ( 
auto &it : mChildren )
 
  158      total += it->elapsed();
 
 
  177  static QThreadStorage<QgsRuntimeProfiler> sInstances;
 
  180  if ( !qApp || profiler->thread() == qApp->thread() )
 
  181    sMainProfiler = profiler;
 
  183  if ( !profiler->mInitialized )
 
  184    profiler->setupConnections();
 
  203    return QStringList();
 
  207  for ( 
int i = 0; i < parentNode->
childCount(); ++i )
 
 
  218  auto node = std::make_unique< QgsRuntimeProfilerNode >( group, name, 
id );
 
  222  if ( !mCurrentStack[ group ].empty() )
 
  226    const QModelIndex parentIndex = node2index( 
parent );
 
  227    beginInsertRows( parentIndex, 
parent->childCount(), 
parent->childCount() );
 
  228    parent->addChild( std::move( node ) );
 
  233    beginInsertRows( QModelIndex(), mRootNode->childCount(), mRootNode->childCount() );
 
  234    mRootNode->addChild( std::move( node ) );
 
  238  mCurrentStack[group].push( child );
 
  241  if ( !mGroups.contains( group ) )
 
  243    mGroups.insert( group );
 
 
  250  if ( mCurrentStack[group].empty() )
 
  254  mCurrentStack[group].pop();
 
  257  const QModelIndex nodeIndex = node2index( node );
 
  258  const QModelIndex col2Index = 
index( nodeIndex.row(), 1, nodeIndex.parent() );
 
  259  emit dataChanged( nodeIndex, nodeIndex );
 
  260  emit dataChanged( col2Index, col2Index );
 
  262  QModelIndex parentIndex = nodeIndex.parent();
 
  263  while ( parentIndex.isValid() )
 
  265    const QModelIndex parentCol2Index = 
index( parentIndex.row(), 1, parentIndex.parent() );
 
  266    emit dataChanged( parentIndex, parentIndex );
 
  267    emit dataChanged( parentCol2Index, parentCol2Index );
 
  268    parentIndex = parentIndex.parent();
 
 
  276  auto node = std::make_unique< QgsRuntimeProfilerNode >( group, name, 
id );
 
  279  if ( !mCurrentStack[ group ].empty() )
 
  283    const QModelIndex parentIndex = node2index( 
parent );
 
  284    beginInsertRows( parentIndex, 
parent->childCount(), 
parent->childCount() );
 
  285    parent->addChild( std::move( node ) );
 
  290    beginInsertRows( QModelIndex(), mRootNode->childCount(), mRootNode->childCount() );
 
  291    mRootNode->addChild( std::move( node ) );
 
  299  if ( !mGroups.contains( group ) )
 
  301    mGroups.insert( group );
 
 
  317  for ( 
int row = mRootNode->childCount() - 1; row >= 0; row-- )
 
  321      beginRemoveRows( QModelIndex(), row, row );
 
  322      mRootNode->removeChildAt( row );
 
 
  331    return node->elapsed();
 
 
  338  return !mCurrentStack.value( group ).empty();
 
 
  343  if ( group == QLatin1String( 
"startup" ) )
 
  344    return tr( 
"Startup" );
 
  345  else if ( group == QLatin1String( 
"projectload" ) )
 
  346    return tr( 
"Project Load" );
 
  347  else if ( group == QLatin1String( 
"rendering" ) )
 
  348    return tr( 
"Map Render" );
 
 
  371    return QModelIndex();
 
  375    return QModelIndex(); 
 
  377  return createIndex( row, column, n->
childAt( row ) );
 
 
  382  if ( !child.isValid() )
 
  383    return QModelIndex();
 
  387    return indexOfParentNode( n->parent() ); 
 
  392    return QModelIndex();
 
 
  405  switch ( 
index.column() )
 
  408      return node->
data( role );
 
  414        case Qt::DisplayRole:
 
  415        case Qt::InitialSortOrderRole:
 
  421      return node->
data( role );
 
 
  431    case Qt::DisplayRole:
 
  433      if ( orientation == Qt::Horizontal )
 
  440            return tr( 
"Time (seconds)" );
 
  452      return QAbstractItemModel::headerData( section, orientation, role );
 
 
  456void QgsRuntimeProfiler::otherProfilerStarted( 
const QString &group, 
const QStringList &path, 
const QString &name, 
const QString &
id )
 
  459  for ( 
const QString &part : path )
 
  464      child = parentNode->
child( group, part );
 
  468      auto newChild = std::make_unique< QgsRuntimeProfilerNode >( group, part );
 
  470      const QModelIndex parentIndex = node2index( parentNode );
 
  473      parentNode->
addChild( std::move( newChild ) );
 
  483  if ( parentNode->
child( group, name, 
id ) )
 
  486  const QModelIndex parentIndex = node2index( parentNode );
 
  488  parentNode->
addChild( std::make_unique< QgsRuntimeProfilerNode >( group, name, 
id ) );
 
  491  if ( !mGroups.contains( group ) )
 
  493    mGroups.insert( group );
 
  498void QgsRuntimeProfiler::otherProfilerEnded( 
const QString &group, 
const QStringList &path, 
const QString &name, 
const QString &
id, 
double elapsed )
 
  501  for ( 
const QString &part : path )
 
  506      child = parentNode->
child( group, part );
 
  510      auto newChild = std::make_unique< QgsRuntimeProfilerNode >( group, part );
 
  512      const QModelIndex parentIndex = node2index( parentNode );
 
  515      parentNode->
addChild( std::move( newChild ) );
 
  528    auto node = std::make_unique< QgsRuntimeProfilerNode >( group, name, 
id );
 
  529    destNode = node.get();
 
  530    const QModelIndex parentIndex = node2index( parentNode );
 
  532    parentNode->
addChild( std::move( node ) );
 
  538  const QModelIndex nodeIndex = node2index( destNode ); 
 
  539  const QModelIndex col2Index = 
index( nodeIndex.row(), 1, nodeIndex.parent() );
 
  540  emit dataChanged( nodeIndex, nodeIndex );
 
  541  emit dataChanged( col2Index, col2Index );
 
  543  QModelIndex parentIndex = nodeIndex.parent();
 
  544  while ( parentIndex.isValid() )
 
  546    const QModelIndex parentCol2Index = 
index( parentIndex.row(), 1, parentIndex.parent() );
 
  547    emit dataChanged( parentIndex, parentIndex );
 
  548    emit dataChanged( parentCol2Index, parentCol2Index );
 
  549    parentIndex = parentIndex.parent();
 
  553void QgsRuntimeProfiler::setupConnections()
 
  557  Q_ASSERT( sMainProfiler );
 
  559  if ( sMainProfiler != 
this )
 
  561    connect( 
this, &QgsRuntimeProfiler::started, sMainProfiler, &QgsRuntimeProfiler::otherProfilerStarted );
 
  562    connect( 
this, &QgsRuntimeProfiler::ended, sMainProfiler, &QgsRuntimeProfiler::otherProfilerEnded );
 
  568  const QStringList parts = path.split( 
'/' );
 
  570  for ( 
const QString &part : parts )
 
  572    if ( part.isEmpty() )
 
  578      child = res->
child( group, part );
 
  587QgsRuntimeProfilerNode *QgsRuntimeProfiler::pathToNode( 
const QString &group, 
const QStringList &path )
 const 
  590  for ( 
const QString &part : path )
 
  595      child = res->
child( group, part );
 
  606  if ( !node || !node->
parent() )
 
  607    return QModelIndex(); 
 
  609  const QModelIndex parentIndex = node2index( node->
parent() );
 
  612  Q_ASSERT( row >= 0 );
 
  613  return index( row, 0, parentIndex );
 
  618  Q_ASSERT( parentNode );
 
  621  if ( !grandParentNode )
 
  622    return QModelIndex();  
 
  624  const int row = grandParentNode->
indexOf( parentNode );
 
  625  Q_ASSERT( row >= 0 );
 
  627  return createIndex( row, 0, parentNode );
 
  632  if ( !
index.isValid() )
 
  633    return mRootNode.get();
 
  638void QgsRuntimeProfiler::extractModelAsText( QStringList &lines, 
const QString &group, 
const QModelIndex &parent, 
int level )
 
  642  for ( 
int r = 0; r < rc; r++ )
 
  649    for ( 
int c = 0; 
c < cc; 
c++ )
 
  652      cells << 
data( cellIndex ).toString();
 
  654    lines << QStringLiteral( 
"%1 %2" ).arg( QStringLiteral( 
"-" ).repeated( level + 1 ), cells.join( QLatin1String( 
": " ) ) );
 
  655    extractModelAsText( lines, group, rowIndex, level + 1 );
 
  662  for ( 
const QString &g : std::as_const( mGroups ) )
 
  664    if ( !group.isEmpty() && g != group )
 
  668    lines << ( !groupName.isEmpty() ? groupName : g );
 
  669    extractModelAsText( lines, g );
 
  671  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