QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
qgsruntimeprofiler.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsruntimeprofiler.cpp
3 ---------------------
4 begin : June 2016
5 copyright : (C) 2016 by Nathan Woodrow
6 email : woodrow dot nathan at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15#include "qgsruntimeprofiler.h"
16
17#include "qgis.h"
18#include "qgsapplication.h"
19#include "qgslogger.h"
20
21#include <QSet>
22#include <QString>
23#include <QThreadStorage>
24
25#include "moc_qgsruntimeprofiler.cpp"
26
27using namespace Qt::StringLiterals;
28
29QgsRuntimeProfiler *QgsRuntimeProfiler::sMainProfiler = nullptr;
30
31
32//
33// QgsRuntimeProfilerNode
34//
35
36QgsRuntimeProfilerNode::QgsRuntimeProfilerNode( const QString &group, const QString &name, const QString &id )
37 : mId( id )
38 , mName( name )
39 , mGroup( group )
40{
41
42}
43
45
47{
48 QStringList res;
49 if ( mParent )
50 {
51 res = mParent->fullParentPath();
52 const QString parentName = mParent->data( static_cast< int >( CustomRole::Name ) ).toString();
53 const QString parentId = mParent->data( static_cast< int >( CustomRole::Id ) ).toString();
54 if ( !parentId.isEmpty() )
55 res << parentId;
56 else if ( !parentName.isEmpty() )
57 res << parentName;
58 }
59 return res;
60}
61
62QVariant QgsRuntimeProfilerNode::data( int role ) const
63{
64 switch ( role )
65 {
66 case Qt::DisplayRole:
67 case Qt::ToolTipRole:
68 case static_cast< int >( CustomRole::Name ):
69 return mName;
70
71 case static_cast< int >( CustomRole::Group ):
72 return mGroup;
73
74 case static_cast< int >( CustomRole::Id ):
75 return mId;
76
77 case static_cast< int >( CustomRole::Elapsed ):
78 return mElapsed;
79
80 case static_cast< int >( CustomRole::ParentElapsed ):
81 return mParent ? ( mParent->elapsed() > 0 ? mParent->elapsed() : mParent->totalElapsedTimeForChildren( mGroup ) ) : 0;
82 }
83 return QVariant();
84}
85
86void QgsRuntimeProfilerNode::addChild( std::unique_ptr<QgsRuntimeProfilerNode> child )
87{
88 if ( !child )
89 return;
90
91 Q_ASSERT( !child->mParent );
92 child->mParent = this;
93
94 mChildren.emplace_back( std::move( child ) );
95}
96
98{
99 Q_ASSERT( child->mParent == this );
100 const auto it = std::find_if( mChildren.begin(), mChildren.end(), [&]( const std::unique_ptr<QgsRuntimeProfilerNode> &p )
101 {
102 return p.get() == child;
103 } );
104 if ( it != mChildren.end() )
105 return std::distance( mChildren.begin(), it );
106 return -1;
107}
108
109QgsRuntimeProfilerNode *QgsRuntimeProfilerNode::child( const QString &group, const QString &name, const QString &id )
110{
111 for ( auto &it : mChildren )
112 {
113 if ( it->data( static_cast< int >( CustomRole::Group ) ).toString() == group
114 && ( ( !id.isEmpty() && it->data( static_cast< int >( CustomRole::Id ) ) == id )
115 || ( id.isEmpty() && !name.isEmpty() && it->data( static_cast< int >( CustomRole::Name ) ).toString() == name ) ) )
116 return it.get();
117 }
118 return nullptr;
119}
120
122{
123 Q_ASSERT( static_cast< std::size_t >( index ) < mChildren.size() );
124 return mChildren[ index ].get();
125}
126
128{
129 mChildren.clear();
130}
131
133{
134 Q_ASSERT( static_cast< std::size_t >( index ) < mChildren.size() );
135 mChildren.erase( mChildren.begin() + index );
136}
137
139{
140 mProfileTime.restart();
141}
142
144{
145 mElapsed = mProfileTime.elapsed() / 1000.0;
146}
147
149{
150 mElapsed = time;
151}
152
154{
155 return mElapsed;
156}
157
158double QgsRuntimeProfilerNode::totalElapsedTimeForChildren( const QString &group ) const
159{
160 double total = 0;
161 for ( auto &it : mChildren )
162 {
163 if ( it->data( static_cast< int >( CustomRole::Group ) ).toString() == group )
164 total += it->elapsed();
165 }
166 return total;
167}
168
169//
170// QgsRuntimeProfiler
171//
172
174 : mRootNode( std::make_unique< QgsRuntimeProfilerNode >( QString(), QString() ) )
175{
176
177}
178
180
181QgsRuntimeProfiler *QgsRuntimeProfiler::threadLocalInstance()
182{
183 static QThreadStorage<QgsRuntimeProfiler> sInstances;
184 QgsRuntimeProfiler *profiler = &sInstances.localData();
185
186 if ( !qApp || profiler->thread() == qApp->thread() )
187 sMainProfiler = profiler;
188
189 if ( !profiler->mInitialized )
190 profiler->setupConnections();
191
192 return profiler;
193}
194
195void QgsRuntimeProfiler::beginGroup( const QString &name )
196{
197 start( name );
198}
199
201{
202 end();
203}
204
205QStringList QgsRuntimeProfiler::childGroups( const QString &parent, const QString &group ) const
206{
207 QgsRuntimeProfilerNode *parentNode = pathToNode( group, parent );
208 if ( !parentNode )
209 return QStringList();
210
211 QStringList res;
212 res.reserve( parentNode->childCount() );
213 for ( int i = 0; i < parentNode->childCount(); ++i )
214 {
215 QgsRuntimeProfilerNode *child = parentNode->childAt( i );
216 if ( child->data( static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Group ) ).toString() == group )
217 res << child->data( static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Name ) ).toString();
218 }
219 return res;
220}
221
222void QgsRuntimeProfiler::start( const QString &name, const QString &group, const QString &id )
223{
224 auto node = std::make_unique< QgsRuntimeProfilerNode >( group, name, id );
225 node->start();
226
227 QgsRuntimeProfilerNode *child = node.get();
228 if ( !mCurrentStack[ group ].empty() )
229 {
230 QgsRuntimeProfilerNode *parent = mCurrentStack[group ].top();
231
232 const QModelIndex parentIndex = node2index( parent );
233 beginInsertRows( parentIndex, parent->childCount(), parent->childCount() );
234 parent->addChild( std::move( node ) );
235 endInsertRows();
236 }
237 else
238 {
239 beginInsertRows( QModelIndex(), mRootNode->childCount(), mRootNode->childCount() );
240 mRootNode->addChild( std::move( node ) );
241 endInsertRows();
242 }
243
244 mCurrentStack[group].push( child );
245 emit started( group, child->fullParentPath(), name, id );
246
247 if ( !mGroups.contains( group ) )
248 {
249 mGroups.insert( group );
250 emit groupAdded( group );
251 }
252}
253
254void QgsRuntimeProfiler::end( const QString &group )
255{
256 if ( mCurrentStack[group].empty() )
257 return;
258
259 QgsRuntimeProfilerNode *node = mCurrentStack[group].top();
260 mCurrentStack[group].pop();
261 node->stop();
262
263 const QModelIndex nodeIndex = node2index( node );
264 const QModelIndex col2Index = index( nodeIndex.row(), 1, nodeIndex.parent() );
265 emit dataChanged( nodeIndex, nodeIndex );
266 emit dataChanged( col2Index, col2Index );
267 // parent item has data changed too, cos the overall time elapsed will have changed!
268 QModelIndex parentIndex = nodeIndex.parent();
269 while ( parentIndex.isValid() )
270 {
271 const QModelIndex parentCol2Index = index( parentIndex.row(), 1, parentIndex.parent() );
272 emit dataChanged( parentIndex, parentIndex );
273 emit dataChanged( parentCol2Index, parentCol2Index );
274 parentIndex = parentIndex.parent();
275 }
276
277 emit ended( group, node->fullParentPath(), node->data( static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Name ) ).toString(), node->data( static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Id ) ).toString(), node->data( static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Elapsed ) ).toDouble() );
278}
279
280void QgsRuntimeProfiler::record( const QString &name, double time, const QString &group, const QString &id )
281{
282 auto node = std::make_unique< QgsRuntimeProfilerNode >( group, name, id );
283
284 QgsRuntimeProfilerNode *child = node.get();
285 if ( !mCurrentStack[ group ].empty() )
286 {
287 QgsRuntimeProfilerNode *parent = mCurrentStack[group ].top();
288
289 const QModelIndex parentIndex = node2index( parent );
290 beginInsertRows( parentIndex, parent->childCount(), parent->childCount() );
291 parent->addChild( std::move( node ) );
292 endInsertRows();
293 }
294 else
295 {
296 beginInsertRows( QModelIndex(), mRootNode->childCount(), mRootNode->childCount() );
297 mRootNode->addChild( std::move( node ) );
298 endInsertRows();
299 }
300
301 emit started( group, child->fullParentPath(), name, id );
302 child->setElapsed( time );
303 emit ended( group, child->fullParentPath(), child->data( static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Name ) ).toString(), child->data( static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Id ) ).toString(), child->data( static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Elapsed ) ).toDouble() );
304
305 if ( !mGroups.contains( group ) )
306 {
307 mGroups.insert( group );
308 emit groupAdded( group );
309 }
310}
311
312double QgsRuntimeProfiler::profileTime( const QString &name, const QString &group ) const
313{
314 QgsRuntimeProfilerNode *node = pathToNode( group, name );
315 if ( !node )
316 return 0;
317
318 return node->data( static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Elapsed ) ).toDouble();
319}
320
321void QgsRuntimeProfiler::clear( const QString &group )
322{
323 for ( int row = mRootNode->childCount() - 1; row >= 0; row-- )
324 {
325 if ( mRootNode->childAt( row )->data( static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Group ) ).toString() == group )
326 {
327 beginRemoveRows( QModelIndex(), row, row );
328 mRootNode->removeChildAt( row );
329 endRemoveRows();
330 }
331 }
332}
333
334double QgsRuntimeProfiler::totalTime( const QString &group )
335{
336 if ( QgsRuntimeProfilerNode *node = pathToNode( group, QString() ) )
337 return node->elapsed();
338
339 return 0;
340}
341
342bool QgsRuntimeProfiler::groupIsActive( const QString &group ) const
343{
344 return !mCurrentStack.value( group ).empty();
345}
346
347QString QgsRuntimeProfiler::translateGroupName( const QString &group )
348{
349 if ( group == "startup"_L1 )
350 return tr( "Startup" );
351 else if ( group == "projectload"_L1 )
352 return tr( "Project Load" );
353 else if ( group == "rendering"_L1 )
354 return tr( "Map Render" );
355 return QString();
356}
357
358int QgsRuntimeProfiler::rowCount( const QModelIndex &parent ) const
359{
360 QgsRuntimeProfilerNode *n = index2node( parent );
361 if ( !n )
362 return 0;
363
364 return n->childCount();
365}
366
367int QgsRuntimeProfiler::columnCount( const QModelIndex &parent ) const
368{
369 Q_UNUSED( parent )
370 return 2;
371}
372
373QModelIndex QgsRuntimeProfiler::index( int row, int column, const QModelIndex &parent ) const
374{
375 if ( column < 0 || column >= columnCount( parent ) ||
376 row < 0 || row >= rowCount( parent ) )
377 return QModelIndex();
378
379 QgsRuntimeProfilerNode *n = index2node( parent );
380 if ( !n )
381 return QModelIndex(); // have no children
382
383 return createIndex( row, column, n->childAt( row ) );
384}
385
386QModelIndex QgsRuntimeProfiler::parent( const QModelIndex &child ) const
387{
388 if ( !child.isValid() )
389 return QModelIndex();
390
391 if ( QgsRuntimeProfilerNode *n = index2node( child ) )
392 {
393 return indexOfParentNode( n->parent() ); // must not be null
394 }
395 else
396 {
397 Q_ASSERT( false );
398 return QModelIndex();
399 }
400}
401
402QVariant QgsRuntimeProfiler::data( const QModelIndex &index, int role ) const
403{
404 if ( !index.isValid() || index.column() > 2 )
405 return QVariant();
406
407 QgsRuntimeProfilerNode *node = index2node( index );
408 if ( !node )
409 return QVariant();
410
411 switch ( index.column() )
412 {
413 case 0:
414 return node->data( role );
415
416 case 1:
417 {
418 switch ( role )
419 {
420 case Qt::DisplayRole:
421 case Qt::InitialSortOrderRole:
422 return node->data( static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Elapsed ) );
423
424 default:
425 break;
426 }
427 return node->data( role );
428 }
429 }
430 return QVariant();
431}
432
433QVariant QgsRuntimeProfiler::headerData( int section, Qt::Orientation orientation, int role ) const
434{
435 switch ( role )
436 {
437 case Qt::DisplayRole:
438 {
439 if ( orientation == Qt::Horizontal )
440 {
441 switch ( section )
442 {
443 case 0:
444 return tr( "Task" );
445 case 1:
446 return tr( "Time (seconds)" );
447 default:
448 return QVariant();
449 }
450 }
451 else
452 {
453 return QVariant();
454 }
455 }
456
457 default:
458 return QAbstractItemModel::headerData( section, orientation, role );
459 }
460}
461
462void QgsRuntimeProfiler::otherProfilerStarted( const QString &group, const QStringList &path, const QString &name, const QString &id )
463{
464 QgsRuntimeProfilerNode *parentNode = mRootNode.get();
465 for ( const QString &part : path )
466 {
467 // part may be name or id. Prefer checking it as id
468 QgsRuntimeProfilerNode *child = parentNode->child( group, QString(), part ); // cppcheck-suppress invalidLifetime
469 if ( !child )
470 child = parentNode->child( group, part );
471
472 if ( !child )
473 {
474 auto newChild = std::make_unique< QgsRuntimeProfilerNode >( group, part );
475
476 const QModelIndex parentIndex = node2index( parentNode );
477 beginInsertRows( parentIndex, parentNode->childCount(), parentNode->childCount() );
478 QgsRuntimeProfilerNode *next = newChild.get();
479 parentNode->addChild( std::move( newChild ) );
480 endInsertRows();
481 parentNode = next;
482 }
483 else
484 {
485 parentNode = child;
486 }
487 }
488
489 if ( parentNode->child( group, name, id ) )
490 return;
491
492 const QModelIndex parentIndex = node2index( parentNode );
493 beginInsertRows( parentIndex, parentNode->childCount(), parentNode->childCount() );
494 parentNode->addChild( std::make_unique< QgsRuntimeProfilerNode >( group, name, id ) );
495 endInsertRows();
496
497 if ( !mGroups.contains( group ) )
498 {
499 mGroups.insert( group );
500 emit groupAdded( group );
501 }
502}
503
504void QgsRuntimeProfiler::otherProfilerEnded( const QString &group, const QStringList &path, const QString &name, const QString &id, double elapsed )
505{
506 QgsRuntimeProfilerNode *parentNode = mRootNode.get();
507 for ( const QString &part : path )
508 {
509 // part may be name or id. Prefer checking it as id
510 QgsRuntimeProfilerNode *child = parentNode->child( group, QString(), part ); // cppcheck-suppress invalidLifetime
511 if ( !child )
512 child = parentNode->child( group, part );
513
514 if ( !child )
515 {
516 auto newChild = std::make_unique< QgsRuntimeProfilerNode >( group, part );
517
518 const QModelIndex parentIndex = node2index( parentNode );
519 beginInsertRows( parentIndex, parentNode->childCount(), parentNode->childCount() );
520 QgsRuntimeProfilerNode *next = newChild.get();
521 parentNode->addChild( std::move( newChild ) );
522 endInsertRows();
523 parentNode = next;
524 }
525 else
526 {
527 parentNode = child;
528 }
529 }
530
531 QgsRuntimeProfilerNode *destNode = parentNode->child( group, name, id );
532 if ( !destNode )
533 {
534 auto node = std::make_unique< QgsRuntimeProfilerNode >( group, name, id );
535 destNode = node.get();
536 const QModelIndex parentIndex = node2index( parentNode );
537 beginInsertRows( parentIndex, parentNode->childCount(), parentNode->childCount() );
538 parentNode->addChild( std::move( node ) );
539 endInsertRows();
540 }
541
542 destNode->setElapsed( elapsed ); // cppcheck-suppress invalidLifetime
543
544 const QModelIndex nodeIndex = node2index( destNode ); // cppcheck-suppress invalidLifetime
545 const QModelIndex col2Index = index( nodeIndex.row(), 1, nodeIndex.parent() );
546 emit dataChanged( nodeIndex, nodeIndex );
547 emit dataChanged( col2Index, col2Index );
548 // parent item has data changed too, cos the overall time elapsed will have changed!
549 QModelIndex parentIndex = nodeIndex.parent();
550 while ( parentIndex.isValid() )
551 {
552 const QModelIndex parentCol2Index = index( parentIndex.row(), 1, parentIndex.parent() );
553 emit dataChanged( parentIndex, parentIndex );
554 emit dataChanged( parentCol2Index, parentCol2Index );
555 parentIndex = parentIndex.parent();
556 }
557}
558
559void QgsRuntimeProfiler::setupConnections()
560{
561 mInitialized = true;
562
563 Q_ASSERT( sMainProfiler );
564
565 if ( sMainProfiler != this )
566 {
567 connect( this, &QgsRuntimeProfiler::started, sMainProfiler, &QgsRuntimeProfiler::otherProfilerStarted );
568 connect( this, &QgsRuntimeProfiler::ended, sMainProfiler, &QgsRuntimeProfiler::otherProfilerEnded );
569 }
570}
571
572QgsRuntimeProfilerNode *QgsRuntimeProfiler::pathToNode( const QString &group, const QString &path ) const
573{
574 const QStringList parts = path.split( '/' );
575 QgsRuntimeProfilerNode *res = mRootNode.get();
576 for ( const QString &part : parts )
577 {
578 if ( part.isEmpty() )
579 continue;
580
581 // part may be name or id. Prefer checking it as id
582 QgsRuntimeProfilerNode *child = res->child( group, QString(), part );
583 if ( !child )
584 child = res->child( group, part );
585
586 res = child;
587 if ( !res )
588 break;
589 }
590 return res;
591}
592
593QgsRuntimeProfilerNode *QgsRuntimeProfiler::pathToNode( const QString &group, const QStringList &path ) const
594{
595 QgsRuntimeProfilerNode *res = mRootNode.get();
596 for ( const QString &part : path )
597 {
598 // part may be name or id. Prefer checking it as id
599 QgsRuntimeProfilerNode *child = res->child( group, QString(), part );
600 if ( !child )
601 child = res->child( group, part );
602
603 res = child;
604 if ( !res )
605 break;
606 }
607 return res;
608}
609
610QModelIndex QgsRuntimeProfiler::node2index( QgsRuntimeProfilerNode *node ) const
611{
612 if ( !node || !node->parent() )
613 return QModelIndex(); // this is the only root item -> invalid index
614
615 const QModelIndex parentIndex = node2index( node->parent() );
616
617 const int row = node->parent()->indexOf( node );
618 Q_ASSERT( row >= 0 );
619 return index( row, 0, parentIndex );
620}
621
622QModelIndex QgsRuntimeProfiler::indexOfParentNode( QgsRuntimeProfilerNode *parentNode ) const
623{
624 Q_ASSERT( parentNode );
625
626 QgsRuntimeProfilerNode *grandParentNode = parentNode->parent();
627 if ( !grandParentNode )
628 return QModelIndex(); // root node -> invalid index
629
630 const int row = grandParentNode->indexOf( parentNode );
631 Q_ASSERT( row >= 0 );
632
633 return createIndex( row, 0, parentNode );
634}
635
636QgsRuntimeProfilerNode *QgsRuntimeProfiler::index2node( const QModelIndex &index ) const
637{
638 if ( !index.isValid() )
639 return mRootNode.get();
640
641 return reinterpret_cast<QgsRuntimeProfilerNode *>( index.internalPointer() );
642}
643
644void QgsRuntimeProfiler::extractModelAsText( QStringList &lines, const QString &group, const QModelIndex &parent, int level )
645{
646 const int rc = rowCount( parent );
647 const int cc = columnCount( parent );
648 for ( int r = 0; r < rc; r++ )
649 {
650 QModelIndex rowIndex = index( r, 0, parent );
651 if ( data( rowIndex, static_cast< int >( QgsRuntimeProfilerNode::CustomRole::Group ) ).toString() != group )
652 continue;
653
654 QStringList cells;
655 for ( int c = 0; c < cc; c++ )
656 {
657 QModelIndex cellIndex = index( r, c, parent );
658 cells << data( cellIndex ).toString();
659 }
660 lines << u"%1 %2"_s.arg( u"-"_s.repeated( level + 1 ), cells.join( ": "_L1 ) );
661 extractModelAsText( lines, group, rowIndex, level + 1 );
662 }
663}
664
665QString QgsRuntimeProfiler::asText( const QString &group )
666{
667 QStringList lines;
668 for ( const QString &g : std::as_const( mGroups ) )
669 {
670 if ( !group.isEmpty() && g != group )
671 continue;
672
673 const QString groupName = translateGroupName( g );
674 lines << ( !groupName.isEmpty() ? groupName : g );
675 extractModelAsText( lines, g );
676 }
677 return lines.join( "\r\n"_L1 );
678}
679
680
681//
682// QgsScopedRuntimeProfile
683//
684
685QgsScopedRuntimeProfile::QgsScopedRuntimeProfile( const QString &name, const QString &group, const QString &id )
686 : mGroup( group )
687{
688 QgsApplication::profiler()->start( name, mGroup, id );
689}
690
695
696void QgsScopedRuntimeProfile::switchTask( const QString &name )
697{
698 QgsApplication::profiler()->end( mGroup );
699 QgsApplication::profiler()->start( name, mGroup );
700}
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.
@ 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.
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