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#include "qv4profileradapter.h"
41#include "qqmlprofilerservice.h"
42
43QT_BEGIN_NAMESPACE
44
45QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::ExecutionEngine *engine) :
46 m_functionCallPos(0), m_memoryPos(0)
47{
48 setService(service);
49 engine->setProfiler(new QV4::Profiling::Profiler(engine));
50 connect(sender: this, signal: &QQmlAbstractProfilerAdapter::profilingEnabled,
51 receiver: this, slot: &QV4ProfilerAdapter::forwardEnabled);
52 connect(sender: this, signal: &QQmlAbstractProfilerAdapter::profilingEnabledWhileWaiting,
53 receiver: this, slot: &QV4ProfilerAdapter::forwardEnabledWhileWaiting, type: Qt::DirectConnection);
54 connect(sender: this, signal: &QV4ProfilerAdapter::v4ProfilingEnabled,
55 receiver: engine->profiler(), slot: &QV4::Profiling::Profiler::startProfiling);
56 connect(sender: this, signal: &QV4ProfilerAdapter::v4ProfilingEnabledWhileWaiting,
57 receiver: engine->profiler(), slot: &QV4::Profiling::Profiler::startProfiling, type: Qt::DirectConnection);
58 connect(sender: this, signal: &QQmlAbstractProfilerAdapter::profilingDisabled,
59 receiver: engine->profiler(), slot: &QV4::Profiling::Profiler::stopProfiling);
60 connect(sender: this, signal: &QQmlAbstractProfilerAdapter::profilingDisabledWhileWaiting,
61 receiver: engine->profiler(), slot: &QV4::Profiling::Profiler::stopProfiling,
62 type: Qt::DirectConnection);
63 connect(sender: this, signal: &QQmlAbstractProfilerAdapter::dataRequested,
64 receiver: engine->profiler(), slot: &QV4::Profiling::Profiler::reportData);
65 connect(sender: this, signal: &QQmlAbstractProfilerAdapter::referenceTimeKnown,
66 receiver: engine->profiler(), slot: &QV4::Profiling::Profiler::setTimer);
67 connect(sender: engine->profiler(), signal: &QV4::Profiling::Profiler::dataReady,
68 receiver: this, slot: &QV4ProfilerAdapter::receiveData);
69}
70
71qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages,
72 QQmlDebugPacket &d)
73{
74 // Make it const, so that we cannot accidentally detach it.
75 const QVector<QV4::Profiling::MemoryAllocationProperties> &memoryData = m_memoryData;
76
77 while (memoryData.length() > m_memoryPos && memoryData[m_memoryPos].timestamp <= until) {
78 const QV4::Profiling::MemoryAllocationProperties &props = memoryData[m_memoryPos];
79 d << props.timestamp << int(MemoryAllocation) << int(props.type) << props.size;
80 ++m_memoryPos;
81 messages.append(t: d.squeezedData());
82 d.clear();
83 }
84 return memoryData.length() == m_memoryPos ? -1 : memoryData[m_memoryPos].timestamp;
85}
86
87qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &messages,
88 qint64 callNext, QQmlDebugPacket &d)
89{
90 qint64 memoryNext = -1;
91
92 if (callNext == -1) {
93 m_functionLocations.clear();
94 m_functionCallData.clear();
95 m_functionCallPos = 0;
96 memoryNext = appendMemoryEvents(until, messages, d);
97 } else {
98 memoryNext = appendMemoryEvents(until: qMin(a: callNext, b: until), messages, d);
99 }
100
101 if (memoryNext == -1) {
102 m_memoryData.clear();
103 m_memoryPos = 0;
104 return callNext;
105 }
106
107 return callNext == -1 ? memoryNext : qMin(a: callNext, b: memoryNext);
108}
109
110qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
111{
112 QQmlDebugPacket d;
113
114 // Make it const, so that we cannot accidentally detach it.
115 const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData = m_functionCallData;
116
117 while (true) {
118 while (!m_stack.isEmpty() &&
119 (m_functionCallPos == functionCallData.length() ||
120 m_stack.top() <= functionCallData[m_functionCallPos].start)) {
121 if (m_stack.top() > until || messages.length() > s_numMessagesPerBatch)
122 return finalizeMessages(until, messages, callNext: m_stack.top(), d);
123
124 appendMemoryEvents(until: m_stack.top(), messages, d);
125 d << m_stack.pop() << int(RangeEnd) << int(Javascript);
126 messages.append(t: d.squeezedData());
127 d.clear();
128 }
129 while (m_functionCallPos != functionCallData.length() &&
130 (m_stack.empty() || functionCallData[m_functionCallPos].start < m_stack.top())) {
131 const QV4::Profiling::FunctionCallProperties &props =
132 functionCallData[m_functionCallPos];
133 if (props.start > until || messages.length() > s_numMessagesPerBatch)
134 return finalizeMessages(until, messages, callNext: props.start, d);
135
136 appendMemoryEvents(until: props.start, messages, d);
137 auto location = m_functionLocations.find(key: props.id);
138
139 d << props.start << int(RangeStart) << int(Javascript) << static_cast<qint64>(props.id);
140 if (location != m_functionLocations.end()) {
141 messages.push_back(t: d.squeezedData());
142 d.clear();
143 d << props.start << int(RangeLocation) << int(Javascript) << location->file << location->line
144 << location->column << static_cast<qint64>(props.id);
145 messages.push_back(t: d.squeezedData());
146 d.clear();
147 d << props.start << int(RangeData) << int(Javascript) << location->name
148 << static_cast<qint64>(props.id);
149 m_functionLocations.erase(it: location);
150 }
151 messages.push_back(t: d.squeezedData());
152 d.clear();
153 m_stack.push(t: props.end);
154 ++m_functionCallPos;
155 }
156 if (m_stack.empty() && m_functionCallPos == functionCallData.length())
157 return finalizeMessages(until, messages, callNext: -1, d);
158 }
159}
160
161void QV4ProfilerAdapter::receiveData(
162 const QV4::Profiling::FunctionLocationHash &locations,
163 const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData,
164 const QVector<QV4::Profiling::MemoryAllocationProperties> &memoryData)
165{
166 // In rare cases it could be that another flush or stop event is processed while data from
167 // the previous one is still pending. In that case we just append the data.
168 if (m_functionLocations.isEmpty())
169 m_functionLocations = locations;
170 else
171 m_functionLocations.insert(hash: locations);
172
173 if (m_functionCallData.isEmpty())
174 m_functionCallData = functionCallData;
175 else
176 m_functionCallData.append(l: functionCallData);
177
178 if (m_memoryData.isEmpty())
179 m_memoryData = memoryData;
180 else
181 m_memoryData.append(l: memoryData);
182
183 service->dataReady(profiler: this);
184}
185
186quint64 QV4ProfilerAdapter::translateFeatures(quint64 qmlFeatures)
187{
188 quint64 v4Features = 0;
189 const quint64 one = 1;
190 if (qmlFeatures & (one << ProfileJavaScript))
191 v4Features |= (one << QV4::Profiling::FeatureFunctionCall);
192 if (qmlFeatures & (one << ProfileMemory))
193 v4Features |= (one << QV4::Profiling::FeatureMemoryAllocation);
194 return v4Features;
195}
196
197void QV4ProfilerAdapter::forwardEnabled(quint64 features)
198{
199 emit v4ProfilingEnabled(v4Features: translateFeatures(qmlFeatures: features));
200}
201
202void QV4ProfilerAdapter::forwardEnabledWhileWaiting(quint64 features)
203{
204 emit v4ProfilingEnabledWhileWaiting(v4Features: translateFeatures(qmlFeatures: features));
205}
206
207QT_END_NAMESPACE
208
209#include "moc_qv4profileradapter.cpp"
210

source code of qtdeclarative/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp