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