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