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 std::unique_ptr< QgsRuntimeProfilerNode > 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 std::unique_ptr< QgsRuntimeProfilerNode > 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 std::unique_ptr< QgsRuntimeProfilerNode > 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 std::unique_ptr< QgsRuntimeProfilerNode > newChild = std::make_unique< QgsRuntimeProfilerNode >( group, part );
512 const QModelIndex parentIndex = node2index( parentNode );
515 parentNode->
addChild( std::move( newChild ) );
528 std::unique_ptr< QgsRuntimeProfilerNode > 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