Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsruntimeprofiler.h
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 : : #ifndef QGSRUNTIMEPROFILER_H
16 : : #define QGSRUNTIMEPROFILER_H
17 : :
18 : : #include <QTime>
19 : : #include <QElapsedTimer>
20 : : #include "qgis_sip.h"
21 : : #include <QPair>
22 : : #include <QStack>
23 : : #include <QList>
24 : : #include <QAbstractItemModel>
25 : : #include <memory>
26 : : #include <deque>
27 : : #include <QSet>
28 : : #include "qgis_core.h"
29 : :
30 : : #ifndef SIP_RUN
31 : :
32 : : /**
33 : : * \ingroup core
34 : : * \class QgsRuntimeProfilerNode
35 : : * \brief A node representing an entry in a QgsRuntimeProfiler.
36 : : *
37 : : * \since QGIS 3.16
38 : : */
39 : : class CORE_EXPORT QgsRuntimeProfilerNode
40 : : {
41 : : public:
42 : :
43 : : //! Custom node data roles
44 : : enum Roles
45 : : {
46 : : Name = Qt::UserRole + 1, //!< Profile item name
47 : : Group, //!< Node group
48 : : Elapsed, //!< Node elapsed time
49 : : ParentElapsed, //!< Total elapsed time for node's parent
50 : : };
51 : :
52 : : /**
53 : : * Constructor for QgsRuntimeProfilerNode, with the specified \a group and \a name.
54 : : */
55 : : QgsRuntimeProfilerNode( const QString &group, const QString &name );
56 : :
57 : : //! QgsRuntimeProfilerNode cannot be copied
58 : : QgsRuntimeProfilerNode( const QgsRuntimeProfilerNode &other ) = delete;
59 : : //! QgsRuntimeProfilerNode cannot be copied
60 : : QgsRuntimeProfilerNode &operator=( const QgsRuntimeProfilerNode &other ) = delete;
61 : :
62 : : ~QgsRuntimeProfilerNode();
63 : :
64 : : /**
65 : : * Returns the node's parent node.
66 : : *
67 : : * If parent is NULLPTR, the node is a root node
68 : : */
69 : 23864 : QgsRuntimeProfilerNode *parent() { return mParent; }
70 : :
71 : : /**
72 : : * Returns the full path to the node's parent.
73 : : */
74 : : QStringList fullParentPath() const;
75 : :
76 : : /**
77 : : * Returns the node's data for the specified model \a role.
78 : : */
79 : : QVariant data( int role = Qt::DisplayRole ) const;
80 : :
81 : : /**
82 : : * Returns the number of child nodes owned by this node.
83 : : */
84 : 9458 : int childCount() const { return mChildren.size(); }
85 : :
86 : : /**
87 : : * Adds a \a child node to this node.
88 : : */
89 : : void addChild( std::unique_ptr< QgsRuntimeProfilerNode > child );
90 : :
91 : : /**
92 : : * Returns the index of the specified \a child node.
93 : : *
94 : : * \warning \a child must be a valid child of this node.
95 : : */
96 : : int indexOf( QgsRuntimeProfilerNode *child ) const;
97 : :
98 : : /**
99 : : * Finds the child with matching \a group and \a name. Returns NULLPTR if
100 : : * a matching child was not found.
101 : : */
102 : : QgsRuntimeProfilerNode *child( const QString &group, const QString &name );
103 : :
104 : : /**
105 : : * Returns the child at the specified \a index.
106 : : */
107 : : QgsRuntimeProfilerNode *childAt( int index );
108 : :
109 : : /**
110 : : * Clears the node, removing all its children.
111 : : */
112 : : void clear();
113 : :
114 : : /**
115 : : * Removes and deletes the child at the specified \a index.
116 : : */
117 : : void removeChildAt( int index );
118 : :
119 : : /**
120 : : * Starts the node timer.
121 : : * \see stop()
122 : : */
123 : : void start();
124 : :
125 : : /**
126 : : * Stops the node's timer, recording the elapsed time automatically.
127 : : */
128 : : void stop();
129 : :
130 : : /**
131 : : * Manually sets the node's elapsed \a time, in seconds.
132 : : */
133 : : void setElapsed( double time );
134 : :
135 : : /**
136 : : * Returns the node's elapsed time, in seconds.
137 : : *
138 : : * If the node is still running then 0 will be returned.
139 : : */
140 : : double elapsed() const;
141 : :
142 : : /**
143 : : * Returns the total elapsed time in seconds for all children
144 : : * of this node with matching \a group.
145 : : */
146 : : double totalElapsedTimeForChildren( const QString &group ) const;
147 : :
148 : : private:
149 : : std::deque< std::unique_ptr< QgsRuntimeProfilerNode > > mChildren;
150 : : QgsRuntimeProfilerNode *mParent = nullptr;
151 : : QElapsedTimer mProfileTime;
152 : : double mElapsed = 0;
153 : :
154 : : QString mName;
155 : : QString mGroup;
156 : :
157 : : };
158 : : #endif
159 : :
160 : : /**
161 : : * \ingroup core
162 : : * \class QgsRuntimeProfiler
163 : : *
164 : : * \brief Provides a method of recording run time profiles of operations, allowing
165 : : * easy recording of their overall run time.
166 : : *
167 : : * QgsRuntimeProfiler is not usually instantied manually, but rather accessed
168 : : * through QgsApplication::profiler().
169 : : *
170 : : * This class is thread-safe only if accessed through QgsApplication::profiler().
171 : : * If accessed in this way, operations can be profiled from non-main threads.
172 : : */
173 : : class CORE_EXPORT QgsRuntimeProfiler : public QAbstractItemModel
174 : : {
175 : 0 : Q_OBJECT
176 : :
177 : : public:
178 : :
179 : : /**
180 : : * Constructor to create a new runtime profiler.
181 : : *
182 : : * \warning QgsRuntimeProfiler is not usually instantied manually, but rather accessed
183 : : * through QgsApplication::profiler().
184 : : */
185 : : QgsRuntimeProfiler();
186 : : ~QgsRuntimeProfiler() override;
187 : :
188 : : /**
189 : : * \brief Begin the group for the profiler. Groups will append {GroupName}/ to the
190 : : * front of the profile tag set using start.
191 : : * \param name The name of the group.
192 : : *
193 : : * \deprecated use start() instead
194 : : */
195 : : Q_DECL_DEPRECATED void beginGroup( const QString &name ) SIP_DEPRECATED;
196 : :
197 : : /**
198 : : * \brief End the current active group.
199 : : *
200 : : * \deprecated use end() instead
201 : : */
202 : : Q_DECL_DEPRECATED void endGroup() SIP_DEPRECATED;
203 : :
204 : : /**
205 : : * Returns a list of all child groups with the specified \a parent.
206 : : * \since QGIS 3.14
207 : : */
208 : : QStringList childGroups( const QString &parent = QString(), const QString &group = "startup" ) const;
209 : :
210 : : /**
211 : : * \brief Start a profile event with the given name.
212 : : * The \a name of the profile event. Will have the name of
213 : : * the active \a group appended after ending.
214 : : */
215 : : void start( const QString &name, const QString &group = "startup" );
216 : :
217 : : /**
218 : : * \brief End the current profile event.
219 : : */
220 : : void end( const QString &group = "startup" );
221 : :
222 : : /**
223 : : * Returns the profile time for the specified \a name.
224 : : * \since QGIS 3.14
225 : : */
226 : : double profileTime( const QString &name, const QString &group = "startup" ) const;
227 : :
228 : : /**
229 : : * \brief clear Clear all profile data.
230 : : */
231 : : void clear( const QString &group = "startup" );
232 : :
233 : : /**
234 : : * \brief The current total time collected in the profiler.
235 : : * \returns The current total time collected in the profiler.
236 : : */
237 : : double totalTime( const QString &group = "startup" );
238 : :
239 : : /**
240 : : * Returns the set of known groups.
241 : : */
242 : : QSet< QString > groups() const { return mGroups; }
243 : :
244 : : /**
245 : : * Returns TRUE if the specified \a group is currently being logged,
246 : : * i.e. it has a entry which has started and not yet stopped.
247 : : *
248 : : * \since QGIS 3.14
249 : : */
250 : : bool groupIsActive( const QString &group ) const;
251 : :
252 : : /**
253 : : * Returns the translated name of a standard profile \a group.
254 : : */
255 : : static QString translateGroupName( const QString &group );
256 : :
257 : : // Implementation of virtual functions from QAbstractItemModel
258 : :
259 : : int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
260 : : int columnCount( const QModelIndex &parent = QModelIndex() ) const override;
261 : : QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const override;
262 : : QModelIndex parent( const QModelIndex &child ) const override;
263 : : QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
264 : : QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override;
265 : :
266 : : #ifndef SIP_RUN
267 : : ///@cond PRIVATE
268 : : signals:
269 : :
270 : : void started( const QString &group, const QStringList &path, const QString &name );
271 : : void ended( const QString &group, const QStringList &path, const QString &name, double elapsed );
272 : : ///@endcond
273 : : #endif
274 : :
275 : : /**
276 : : * Emitted when a new group has started being profiled.
277 : : */
278 : : void groupAdded( const QString &group );
279 : :
280 : : private slots:
281 : :
282 : : void otherProfilerStarted( const QString &group, const QStringList &path, const QString &name );
283 : : void otherProfilerEnded( const QString &group, const QStringList &path, const QString &name, double elapsed );
284 : :
285 : : private:
286 : :
287 : : static QgsRuntimeProfiler *threadLocalInstance();
288 : : static QgsRuntimeProfiler *sMainProfiler;
289 : : bool mInitialized = false;
290 : : void setupConnections();
291 : :
292 : : QgsRuntimeProfilerNode *pathToNode( const QString &group, const QString &path ) const;
293 : : QgsRuntimeProfilerNode *pathToNode( const QString &group, const QStringList &path ) const;
294 : : QModelIndex node2index( QgsRuntimeProfilerNode *node ) const;
295 : : QModelIndex indexOfParentNode( QgsRuntimeProfilerNode *parentNode ) const;
296 : :
297 : : /**
298 : : * Returns node for given index. Returns root node for invalid index.
299 : : */
300 : : QgsRuntimeProfilerNode *index2node( const QModelIndex &index ) const;
301 : :
302 : : QMap< QString, QStack< QgsRuntimeProfilerNode * > > mCurrentStack;
303 : : std::unique_ptr< QgsRuntimeProfilerNode > mRootNode;
304 : :
305 : : QSet< QString > mGroups;
306 : :
307 : : friend class QgsApplication;
308 : : };
309 : :
310 : :
311 : : /**
312 : : * \ingroup core
313 : : *
314 : : * \brief Scoped object for logging of the runtime for a single operation or group of operations.
315 : : *
316 : : * This class automatically takes care of registering an operation in the QgsApplication::profiler()
317 : : * registry upon construction, and recording of the elapsed runtime upon destruction.
318 : : *
319 : : * Python scripts should not use QgsScopedRuntimeProfile directly. Instead, use QgsRuntimeProfiler.profile()
320 : : * \code{.py}
321 : : * with QgsRuntimeProfiler.profile('My operation'):
322 : : * # do something
323 : : * \endcode
324 : : *
325 : : * \since QGIS 3.14
326 : : */
327 : : class CORE_EXPORT QgsScopedRuntimeProfile
328 : : {
329 : : public:
330 : :
331 : : /**
332 : : * Constructor for QgsScopedRuntimeProfile.
333 : : *
334 : : * Automatically registers the operation in the QgsApplication::profiler() instance
335 : : * and starts recording the run time of the operation.
336 : : */
337 : : QgsScopedRuntimeProfile( const QString &name, const QString &group = "startup" );
338 : :
339 : : /**
340 : : * Records the final runtime of the operation in the profiler instance.
341 : : */
342 : : ~QgsScopedRuntimeProfile();
343 : :
344 : : /**
345 : : * Switches the current task managed by the scoped profile to a new task with the given \a name.
346 : : * The current task will be finalised before switching.
347 : : *
348 : : * This is useful for reusing an existing scoped runtime profiler with multi-step processes.
349 : : *
350 : : * \since QGIS 3.14
351 : : */
352 : : void switchTask( const QString &name );
353 : :
354 : : private:
355 : :
356 : : QString mGroup;
357 : :
358 : : };
359 : :
360 : :
361 : : #endif // QGSRUNTIMEPROFILER_H
|