1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QV4PROFILING_H
41#define QV4PROFILING_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include "qv4global_p.h"
55#include "qv4engine_p.h"
56#include "qv4function_p.h"
57
58#include <QElapsedTimer>
59
60#if !QT_CONFIG(qml_debug)
61
62#define Q_V4_PROFILE_ALLOC(engine, size, type) (!engine)
63#define Q_V4_PROFILE_DEALLOC(engine, size, type) (!engine)
64
65QT_BEGIN_NAMESPACE
66
67namespace QV4 {
68namespace Profiling {
69class Profiler {};
70class FunctionCallProfiler {
71public:
72 FunctionCallProfiler(ExecutionEngine *, Function *) {}
73};
74}
75}
76
77QT_END_NAMESPACE
78
79#else
80
81#define Q_V4_PROFILE_ALLOC(engine, size, type)\
82 (engine->profiler() &&\
83 (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
84 engine->profiler()->trackAlloc(size, type) : false)
85
86#define Q_V4_PROFILE_DEALLOC(engine, size, type) \
87 (engine->profiler() &&\
88 (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
89 engine->profiler()->trackDealloc(size, type) : false)
90
91QT_BEGIN_NAMESPACE
92
93namespace QV4 {
94
95namespace Profiling {
96
97enum Features {
98 FeatureFunctionCall,
99 FeatureMemoryAllocation
100};
101
102enum MemoryType {
103 HeapPage,
104 LargeItem,
105 SmallItem
106};
107
108struct FunctionCallProperties {
109 qint64 start;
110 qint64 end;
111 quintptr id;
112};
113
114struct FunctionLocation {
115 FunctionLocation(const QString &name = QString(), const QString &file = QString(),
116 int line = -1, int column = -1) :
117 name(name), file(file), line(line), column(column)
118 {}
119
120 bool isValid()
121 {
122 return !name.isEmpty();
123 }
124
125 QString name;
126 QString file;
127 int line;
128 int column;
129};
130
131typedef QHash<quintptr, QV4::Profiling::FunctionLocation> FunctionLocationHash;
132
133struct MemoryAllocationProperties {
134 qint64 timestamp;
135 qint64 size;
136 MemoryType type;
137};
138
139class FunctionCall {
140public:
141
142 FunctionCall() : m_function(nullptr), m_start(0), m_end(0)
143 { Q_ASSERT_X(false, Q_FUNC_INFO, "Cannot construct a function call without function"); }
144
145 FunctionCall(Function *function, qint64 start, qint64 end) :
146 m_function(function), m_start(start), m_end(end)
147 { m_function->executableCompilationUnit()->addref(); }
148
149 FunctionCall(const FunctionCall &other) :
150 m_function(other.m_function), m_start(other.m_start), m_end(other.m_end)
151 { m_function->executableCompilationUnit()->addref(); }
152
153 ~FunctionCall()
154 { m_function->executableCompilationUnit()->release(); }
155
156 FunctionCall &operator=(const FunctionCall &other) {
157 if (&other != this) {
158 other.m_function->executableCompilationUnit()->addref();
159 m_function->executableCompilationUnit()->release();
160 m_function = other.m_function;
161 m_start = other.m_start;
162 m_end = other.m_end;
163 }
164 return *this;
165 }
166
167 Function *function() const
168 {
169 return m_function;
170 }
171
172 FunctionLocation resolveLocation() const;
173 FunctionCallProperties properties() const;
174
175private:
176 friend bool operator<(const FunctionCall &call1, const FunctionCall &call2);
177
178 Function *m_function;
179 qint64 m_start;
180 qint64 m_end;
181};
182
183class Q_QML_EXPORT Profiler : public QObject {
184 Q_OBJECT
185public:
186 struct SentMarker {
187 SentMarker() : m_function(nullptr) {}
188
189 SentMarker(const SentMarker &other) : m_function(other.m_function)
190 {
191 if (m_function)
192 m_function->executableCompilationUnit()->addref();
193 }
194
195 ~SentMarker()
196 {
197 if (m_function)
198 m_function->executableCompilationUnit()->release();
199 }
200
201 SentMarker &operator=(const SentMarker &other)
202 {
203 if (&other != this) {
204 if (m_function)
205 m_function->executableCompilationUnit()->release();
206 m_function = other.m_function;
207 m_function->executableCompilationUnit()->addref();
208 }
209 return *this;
210 }
211
212 void setFunction(Function *function)
213 {
214 Q_ASSERT(m_function == nullptr);
215 m_function = function;
216 m_function->executableCompilationUnit()->addref();
217 }
218
219 bool isValid() const
220 { return m_function != nullptr; }
221
222 private:
223 Function *m_function;
224 };
225
226 Profiler(QV4::ExecutionEngine *engine);
227
228 bool trackAlloc(size_t size, MemoryType type)
229 {
230 if (size) {
231 MemoryAllocationProperties allocation = {.timestamp: m_timer.nsecsElapsed(), .size: (qint64)size, .type: type};
232 m_memory_data.append(t: allocation);
233 return true;
234 } else {
235 return false;
236 }
237 }
238
239 bool trackDealloc(size_t size, MemoryType type)
240 {
241 if (size) {
242 MemoryAllocationProperties allocation = {.timestamp: m_timer.nsecsElapsed(), .size: -(qint64)size, .type: type};
243 m_memory_data.append(t: allocation);
244 return true;
245 } else {
246 return false;
247 }
248 }
249
250 quint64 featuresEnabled;
251
252 void stopProfiling();
253 void startProfiling(quint64 features);
254 void reportData();
255 void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
256
257signals:
258 void dataReady(const QV4::Profiling::FunctionLocationHash &,
259 const QVector<QV4::Profiling::FunctionCallProperties> &,
260 const QVector<QV4::Profiling::MemoryAllocationProperties> &);
261
262private:
263 QV4::ExecutionEngine *m_engine;
264 QElapsedTimer m_timer;
265 QVector<FunctionCall> m_data;
266 QVector<MemoryAllocationProperties> m_memory_data;
267 QHash<quintptr, SentMarker> m_sentLocations;
268
269 friend class FunctionCallProfiler;
270};
271
272class FunctionCallProfiler {
273 Q_DISABLE_COPY(FunctionCallProfiler)
274public:
275
276 // It's enough to ref() the function in the destructor as it will probably not disappear while
277 // it's executing ...
278 FunctionCallProfiler(ExecutionEngine *engine, Function *f)
279 : profiler(nullptr)
280 {
281 Profiler *p = engine->profiler();
282 if (Q_UNLIKELY(p) && (p->featuresEnabled & (1 << Profiling::FeatureFunctionCall))) {
283 profiler = p;
284 function = f;
285 startTime = profiler->m_timer.nsecsElapsed();
286 }
287 }
288
289 ~FunctionCallProfiler()
290 {
291 if (profiler)
292 profiler->m_data.append(t: FunctionCall(function, startTime, profiler->m_timer.nsecsElapsed()));
293 }
294
295 Profiler *profiler;
296 Function *function;
297 qint64 startTime;
298};
299
300
301} // namespace Profiling
302} // namespace QV4
303
304Q_DECLARE_TYPEINFO(QV4::Profiling::MemoryAllocationProperties, Q_MOVABLE_TYPE);
305Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE);
306Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE);
307Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionLocation, Q_MOVABLE_TYPE);
308Q_DECLARE_TYPEINFO(QV4::Profiling::Profiler::SentMarker, Q_MOVABLE_TYPE);
309
310QT_END_NAMESPACE
311Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash)
312Q_DECLARE_METATYPE(QVector<QV4::Profiling::FunctionCallProperties>)
313Q_DECLARE_METATYPE(QVector<QV4::Profiling::MemoryAllocationProperties>)
314
315#endif // QT_CONFIG(qml_debug)
316
317#endif // QV4PROFILING_H
318

source code of qtdeclarative/src/qml/jsruntime/qv4profiling_p.h