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

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