1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtQml module of the Qt Toolkit.
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qmlprofilerclient.h"
44 #include <QtCore/QStack>
45 #include <QtCore/QStringList>
47 ProfilerClient::ProfilerClient(const QString &clientName,
48 QQmlDebugConnection *client)
49 : QQmlDebugClient(clientName, client),
55 ProfilerClient::~ProfilerClient()
57 //Disable profiling if started by client
58 //Profiling data will be lost!!
63 void ProfilerClient::clearData()
68 bool ProfilerClient::isEnabled() const
73 void ProfilerClient::sendRecordingStatus()
77 bool ProfilerClient::isRecording() const
82 void ProfilerClient::setRecording(bool v)
89 if (state() == Enabled) {
90 sendRecordingStatus();
93 emit recordingChanged(v);
96 void ProfilerClient::stateChanged(State status)
98 if ((m_enabled && status != Enabled) ||
99 (!m_enabled && status == Enabled))
100 emit enabledChanged();
102 m_enabled = status == Enabled;
106 class QmlProfilerClientPrivate
109 QmlProfilerClientPrivate()
110 : inProgressRanges(0)
113 ::memset(rangeCount, 0,
114 QQmlProfilerService::MaximumRangeType * sizeof(int));
117 qint64 inProgressRanges;
118 QStack<qint64> rangeStartTimes[QQmlProfilerService::MaximumRangeType];
119 QStack<QStringList> rangeDatas[QQmlProfilerService::MaximumRangeType];
120 QStack<QmlEventLocation> rangeLocations[QQmlProfilerService::MaximumRangeType];
121 QStack<QQmlProfilerService::BindingType> bindingTypes;
122 int rangeCount[QQmlProfilerService::MaximumRangeType];
126 QmlProfilerClient::QmlProfilerClient(
127 QQmlDebugConnection *client)
128 : ProfilerClient(QStringLiteral("CanvasFrameRate"), client),
129 d(new QmlProfilerClientPrivate)
133 QmlProfilerClient::~QmlProfilerClient()
138 void QmlProfilerClient::clearData()
140 ::memset(d->rangeCount, 0,
141 QQmlProfilerService::MaximumRangeType * sizeof(int));
142 d->bindingTypes.clear();
143 ProfilerClient::clearData();
146 void QmlProfilerClient::sendRecordingStatus()
149 QDataStream stream(&ba, QIODevice::WriteOnly);
150 stream << isRecording();
154 void QmlProfilerClient::messageReceived(const QByteArray &data)
156 QByteArray rwData = data;
157 QDataStream stream(&rwData, QIODevice::ReadOnly);
162 stream >> time >> messageType;
164 if (messageType >= QQmlProfilerService::MaximumMessage)
167 if (messageType == QQmlProfilerService::Event) {
171 if (event == QQmlProfilerService::EndTrace) {
172 emit this->traceFinished(time);
173 d->maximumTime = time;
174 d->maximumTime = qMax(time, d->maximumTime);
175 } else if (event == QQmlProfilerService::AnimationFrame) {
176 int frameRate, animationCount;
177 stream >> frameRate >> animationCount;
178 emit this->frame(time, frameRate, animationCount);
179 d->maximumTime = qMax(time, d->maximumTime);
180 } else if (event == QQmlProfilerService::StartTrace) {
181 emit this->traceStarted(time);
182 d->maximumTime = time;
183 } else if (event < QQmlProfilerService::MaximumEventType) {
184 d->maximumTime = qMax(time, d->maximumTime);
186 } else if (messageType == QQmlProfilerService::Complete) {
193 if (range >= QQmlProfilerService::MaximumRangeType)
196 if (messageType == QQmlProfilerService::RangeStart) {
197 d->rangeStartTimes[range].push(time);
198 d->inProgressRanges |= (static_cast<qint64>(1) << range);
199 ++d->rangeCount[range];
202 if (range == (int)QQmlProfilerService::Binding) {
203 int bindingType = (int)QQmlProfilerService::QmlBinding;
205 stream >> bindingType;
206 d->bindingTypes.push((QQmlProfilerService::BindingType)bindingType);
208 } else if (messageType == QQmlProfilerService::RangeData) {
212 int count = d->rangeCount[range];
214 while (d->rangeDatas[range].count() < count)
215 d->rangeDatas[range].push(QStringList());
216 d->rangeDatas[range][count-1] << data;
219 } else if (messageType == QQmlProfilerService::RangeLocation) {
223 stream >> fileName >> line;
228 if (d->rangeCount[range] > 0) {
229 d->rangeLocations[range].push(QmlEventLocation(fileName, line,
233 if (d->rangeCount[range] > 0) {
234 --d->rangeCount[range];
235 if (d->inProgressRanges & (static_cast<qint64>(1) << range))
236 d->inProgressRanges &= ~(static_cast<qint64>(1) << range);
238 d->maximumTime = qMax(time, d->maximumTime);
239 QStringList data = d->rangeDatas[range].count() ?
240 d->rangeDatas[range].pop() : QStringList();
241 QmlEventLocation location = d->rangeLocations[range].count() ?
242 d->rangeLocations[range].pop() : QmlEventLocation();
244 qint64 startTime = d->rangeStartTimes[range].pop();
245 QQmlProfilerService::BindingType bindingType = QQmlProfilerService::QmlBinding;
246 if (range == (int)QQmlProfilerService::Binding)
247 bindingType = d->bindingTypes.pop();
248 emit this->range((QQmlProfilerService::RangeType)range,
249 bindingType, startTime, time - startTime, data, location);
250 if (d->rangeCount[range] == 0) {
251 int count = d->rangeDatas[range].count() +
252 d->rangeStartTimes[range].count() +
253 d->rangeLocations[range].count();
255 qWarning() << "incorrectly nested data";
262 V8ProfilerClient::V8ProfilerClient(QQmlDebugConnection *client)
263 : ProfilerClient(QStringLiteral("V8Profiler"), client)
267 V8ProfilerClient::~V8ProfilerClient()
271 void V8ProfilerClient::sendRecordingStatus()
274 QDataStream stream(&ba, QIODevice::WriteOnly);
275 QByteArray cmd("V8PROFILER");
276 QByteArray option("");
277 QByteArray title("");
284 stream << cmd << option << title;
288 void V8ProfilerClient::messageReceived(const QByteArray &data)
290 QByteArray rwData = data;
291 QDataStream stream(&rwData, QIODevice::ReadOnly);
295 stream >> messageType;
297 if (messageType == V8Complete) {
299 } else if (messageType == V8Entry) {
307 stream >> filename >> function >> lineNumber >> totalTime >>
309 emit this->range(depth, function, filename, lineNumber, totalTime,