1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQUICKPROFILER_P_H
5#define QQUICKPROFILER_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/private/qabstractanimation_p.h>
19#include <QtQuick/private/qtquickglobal_p.h>
20
21#if QT_CONFIG(qml_debug)
22#include <QtQml/private/qqmlprofilerdefinitions_p.h>
23#endif
24
25#include <QtCore/qurl.h>
26#include <QtCore/qsize.h>
27#include <QtCore/qmutex.h>
28#include <QtCore/qthreadstorage.h>
29
30QT_BEGIN_NAMESPACE
31
32#if !QT_CONFIG(qml_debug)
33
34#define Q_QUICK_PROFILE_IF_ENABLED(feature, Code)
35
36struct QQuickProfiler {
37 static void registerAnimationCallback() {}
38};
39
40#else
41
42#define Q_QUICK_PROFILE_IF_ENABLED(feature, Code)\
43 if (QQuickProfiler::featuresEnabled & (1 << feature)) {\
44 Code;\
45 } else\
46 (void)0
47
48// This struct is somewhat dangerous to use:
49// You can save values either with 32 or 64 bit precision. toByteArrays will
50// guess the precision from messageType. If you state the wrong messageType
51// you will get undefined results.
52// The messageType is itself a bit field. You can pack multiple messages into
53// one object, e.g. RangeStart and RangeLocation. Each one will be read
54// independently by toByteArrays. Thus you can only pack messages if their data
55// doesn't overlap. Again, it's up to you to figure that out.
56struct Q_AUTOTEST_EXPORT QQuickProfilerData
57{
58 QQuickProfilerData() {}
59
60 QQuickProfilerData(qint64 time, int messageType, int detailType, const QUrl &url, int x = 0,
61 int y = 0, int framerate = 0, int count = 0) :
62 time(time), messageType(messageType), detailType(detailType), detailUrl(url), x(x), y(y),
63 framerate(framerate), count(count) {}
64
65 QQuickProfilerData(qint64 time, int messageType, int detailType, int framerateOrInputType = 0,
66 int countOrInputA = 0, int threadIdOrInputB = 0) :
67 time(time), messageType(messageType), detailType(detailType),
68 framerate(framerateOrInputType), count(countOrInputA), threadId(threadIdOrInputB) {}
69
70 // Special ctor for scenegraph frames. Note that it's missing the QString/QUrl params.
71 // This is slightly ugly, but makes it easier to disambiguate between int and qint64 params.
72 QQuickProfilerData(qint64 time, int messageType, int detailType, qint64 d1, qint64 d2,
73 qint64 d3, qint64 d4, qint64 d5) :
74 time(time), messageType(messageType), detailType(detailType), subtime_1(d1), subtime_2(d2),
75 subtime_3(d3), subtime_4(d4), subtime_5(d5) {}
76
77
78 qint64 time;
79 int messageType; //bit field of Message
80 int detailType;
81
82 QUrl detailUrl;
83
84 union {
85 qint64 subtime_1;
86 int x; //used for pixmaps
87 };
88
89 union {
90 qint64 subtime_2;
91 int y; //used for pixmaps
92 };
93
94 union {
95 qint64 subtime_3;
96 int framerate; //used by animation events
97 int inputType;
98 };
99
100 union {
101 qint64 subtime_4;
102 int count; //used by animation events and for pixmaps
103 int inputA; //used by input events
104 };
105
106 union {
107 qint64 subtime_5;
108 int threadId;
109 int inputB; //used by input events
110 };
111};
112
113Q_DECLARE_TYPEINFO(QQuickProfilerData, Q_RELOCATABLE_TYPE);
114
115class QQuickProfilerSceneGraphData : public QQmlProfilerDefinitions {
116private:
117 static const uint s_numSceneGraphTimings = 5;
118
119 template<uint size>
120 struct TimingData {
121 qint64 values[size][s_numSceneGraphTimings + 1];
122 };
123
124 QThreadStorage<TimingData<NumRenderThreadFrameTypes> > renderThreadTimings;
125 TimingData<NumGUIThreadFrameTypes> guiThreadTimings;
126
127public:
128 template<SceneGraphFrameType type>
129 qint64 *timings()
130 {
131 if (type < NumRenderThreadFrameTypes)
132 return renderThreadTimings.localData().values[type];
133 else
134 return guiThreadTimings.values[type - NumRenderThreadFrameTypes];
135 }
136};
137
138class Q_QUICK_PRIVATE_EXPORT QQuickProfiler : public QObject, public QQmlProfilerDefinitions {
139 Q_OBJECT
140public:
141
142 enum AnimationThread {
143 GuiThread,
144 RenderThread
145 };
146
147 enum SceneGraphContextStage {
148 SceneGraphContextStart,
149 SceneGraphContextMaterialCompile
150 };
151
152 enum SceneGraphRendererStage {
153 SceneGraphRendererStart,
154 SceneGraphRendererPreprocess,
155 SceneGraphRendererUpdate,
156 SceneGraphRendererBinding,
157 SceneGraphRendererRender
158 };
159
160 enum SceneGraphAdaptationLayerStage {
161 SceneGraphAdaptationLayerStart,
162 SceneGraphAdaptationLayerGlyphRender,
163 SceneGraphAdaptationLayerGlyphStore
164 };
165
166 enum SceneGraphRenderLoopStage {
167 SceneGraphRenderLoopStart,
168 SceneGraphRenderLoopSync,
169 SceneGraphRenderLoopRender,
170 SceneGraphRenderLoopSwap
171 };
172
173 enum SceneGraphPolishStage {
174 SceneGraphPolishStart,
175 SceneGraphPolishPolish
176 };
177
178 enum SceneGraphPolishAndSyncStage {
179 SceneGraphPolishAndSyncStart,
180 SceneGraphPolishAndSyncPolish,
181 SceneGraphPolishAndSyncWait,
182 SceneGraphPolishAndSyncSync,
183 SceneGraphPolishAndSyncAnimations
184 };
185
186 enum SceneGraphTexturePrepareStage {
187 SceneGraphTexturePrepareStart,
188 SceneGraphTexturePrepareBind,
189 SceneGraphTexturePrepareConvert,
190 SceneGraphTexturePrepareSwizzle,
191 SceneGraphTexturePrepareUpload,
192 SceneGraphTexturePrepareMipmap
193 };
194
195 enum SceneGraphTextureDeletionStage {
196 SceneGraphTextureDeletionStart,
197 SceneGraphTextureDeletionDelete
198 };
199
200 template<EventType DetailType, InputEventType InputType>
201 static void inputEvent(int x, int y = 0)
202 {
203 s_instance->processMessage(message: QQuickProfilerData(s_instance->timestamp(), 1 << Event,
204 1 << DetailType, InputType, x, y));
205 }
206
207 static void animationFrame(qint64 delta, AnimationThread threadId)
208 {
209 int animCount = QUnifiedTimer::instance()->runningAnimationCount();
210
211 if (animCount > 0 && delta > 0) {
212 s_instance->processMessage(message: QQuickProfilerData(s_instance->timestamp(), 1 << Event,
213 1 << AnimationFrame, 1000 / (int)delta /* trim fps to integer */, animCount,
214 threadId));
215 }
216 }
217
218 template<SceneGraphFrameType FrameType1, SceneGraphFrameType FrameType2>
219 static void startSceneGraphFrame()
220 {
221 startSceneGraphFrame<FrameType1>();
222 s_instance->m_sceneGraphData.timings<FrameType2>()[0] =
223 s_instance->m_sceneGraphData.timings<FrameType1>()[0];
224 }
225
226 template<SceneGraphFrameType FrameType>
227 static void startSceneGraphFrame()
228 {
229 s_instance->m_sceneGraphData.timings<FrameType>()[0] = s_instance->timestamp();
230 }
231
232 template<SceneGraphFrameType FrameType>
233 static void recordSceneGraphTimestamp(uint position)
234 {
235 s_instance->m_sceneGraphData.timings<FrameType>()[position] = s_instance->timestamp();
236 }
237
238 template<SceneGraphFrameType FrameType, uint Skip>
239 static void skipSceneGraphTimestamps(uint position)
240 {
241 qint64 *timings = s_instance->m_sceneGraphData.timings<FrameType>();
242 const qint64 last = timings[position];
243 for (uint i = 0; i < Skip; ++i)
244 timings[++position] = last;
245 }
246
247 template<SceneGraphFrameType FrameType, bool Record>
248 static void reportSceneGraphFrame(uint position, quint64 payload = ~0)
249 {
250 qint64 *timings = s_instance->m_sceneGraphData.timings<FrameType>();
251 if (Record)
252 timings[position] = s_instance->timestamp();
253 s_instance->processMessage(message: QQuickProfilerData(
254 timings[position], 1 << SceneGraphFrame, 1 << FrameType,
255 position > 0 ? timings[1] - timings[0] : payload,
256 position > 1 ? timings[2] - timings[1] : payload,
257 position > 2 ? timings[3] - timings[2] : payload,
258 position > 3 ? timings[4] - timings[3] : payload,
259 position > 4 ? timings[5] - timings[4] : payload));
260 }
261
262 template<SceneGraphFrameType FrameType, bool Record, SceneGraphFrameType SwitchTo>
263 static void reportSceneGraphFrame(uint position, quint64 payload = ~0)
264 {
265 reportSceneGraphFrame<FrameType, Record>(position, payload);
266 s_instance->m_sceneGraphData.timings<SwitchTo>()[0] =
267 s_instance->m_sceneGraphData.timings<FrameType>()[position];
268 }
269
270 template<PixmapEventType PixmapState>
271 static void pixmapStateChanged(const QUrl &url)
272 {
273 s_instance->processMessage(message: QQuickProfilerData(s_instance->timestamp(),
274 1 << PixmapCacheEvent, 1 << PixmapState, url));
275 }
276
277 static void pixmapLoadingFinished(const QUrl &url, const QSize &size)
278 {
279 s_instance->processMessage(message: QQuickProfilerData(s_instance->timestamp(),
280 1 << PixmapCacheEvent,
281 (1 << PixmapLoadingFinished) | ((size.width() > 0 && size.height() > 0) ? (1 << PixmapSizeKnown) : 0),
282 url, size.width(), size.height()));
283 }
284
285 template<PixmapEventType CountType>
286 static void pixmapCountChanged(const QUrl &url, int count)
287 {
288 s_instance->processMessage(message: QQuickProfilerData(s_instance->timestamp(),
289 1 << PixmapCacheEvent, 1 << CountType, url, 0, 0, 0, count));
290 }
291
292 static void registerAnimationCallback();
293
294 qint64 timestamp() { return m_timer.nsecsElapsed(); }
295
296 static quint64 featuresEnabled;
297
298 static void initialize(QObject *parent);
299
300 ~QQuickProfiler() override;
301
302Q_SIGNALS:
303 void dataReady(const QVector<QQuickProfilerData> &data);
304
305protected:
306 friend class QQuickProfilerAdapter;
307
308 static QQuickProfiler *s_instance;
309 QMutex m_dataMutex;
310 QElapsedTimer m_timer;
311 QVector<QQuickProfilerData> m_data;
312 QQuickProfilerSceneGraphData m_sceneGraphData;
313
314 QQuickProfiler(QObject *parent);
315
316 void processMessage(const QQuickProfilerData &message)
317 {
318 QMutexLocker lock(&m_dataMutex);
319 m_data.append(t: message);
320 }
321
322 void startProfilingImpl(quint64 features);
323 void stopProfilingImpl();
324 void reportDataImpl();
325 void setTimer(const QElapsedTimer &t);
326};
327
328#endif // QT_CONFIG(qml_debug)
329
330#define Q_QUICK_PROFILE(feature, Method)\
331 Q_QUICK_PROFILE_IF_ENABLED(feature, QQuickProfiler::Method)
332
333// Record current timestamp for \a Type at position 0.
334#define Q_QUICK_SG_PROFILE_START(Type)\
335 Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
336 (QQuickProfiler::startSceneGraphFrame<Type>()))
337
338// Record current timestamp for \a Type at \a position.
339#define Q_QUICK_SG_PROFILE_RECORD(Type, position)\
340 Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
341 (QQuickProfiler::recordSceneGraphTimestamp<Type>(position)))
342
343// Use the timestamp for \a Type at position \a position and repeat it \a Skip times in subsequent
344// positions.
345#define Q_QUICK_SG_PROFILE_SKIP(Type, position, Skip)\
346 Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
347 (QQuickProfiler::skipSceneGraphTimestamps<Type, Skip>(position)))
348
349// Record current timestamp for both \a Type1 and \a Type2 at position 0.
350#define Q_QUICK_SG_PROFILE_START_SYNCHRONIZED(Type1, Type2)\
351 Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
352 (QQuickProfiler::startSceneGraphFrame<Type1, Type2>()))
353
354// report \a Type1, using the current timestamp at \a position, and switch to \a Typ2, using
355// the current timestamp at position 0.
356#define Q_QUICK_SG_PROFILE_SWITCH(Type1, Type2, position)\
357 Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
358 (QQuickProfiler::reportSceneGraphFrame<Type1, true, Type2>(\
359 position)))
360
361// report \a Type, using data points 0 to \a position, including \a position.
362#define Q_QUICK_SG_PROFILE_REPORT(Type, position)\
363 Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
364 (QQuickProfiler::reportSceneGraphFrame<Type, false>(position)))
365
366// report \a Type, using data points 0 to \a position, including \a position, and setting the
367// timestamp at \a position to the current one.
368#define Q_QUICK_SG_PROFILE_END(Type, position)\
369 Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
370 (QQuickProfiler::reportSceneGraphFrame<Type, true>(position)))
371
372// report \a Type, using data points 0 to \a position, including \a position, and setting the
373// timestamp at \a position to the current one. Remaining data points up to position 5 are filled
374// with \a Payload.
375#define Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(Type, position, Payload)\
376 Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
377 (QQuickProfiler::reportSceneGraphFrame<Type, true>(position,\
378 Payload)))
379
380#define Q_QUICK_INPUT_PROFILE(Type, DetailType, A, B)\
381 Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileInputEvents,\
382 (QQuickProfiler::inputEvent<Type, DetailType>(A, B)))
383
384QT_END_NAMESPACE
385
386#endif
387

source code of qtdeclarative/src/quick/util/qquickprofiler_p.h