1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqmlprofilerservice_p.h"
44 #include <QtCore/qdatastream.h>
45 #include <QtCore/qurl.h>
46 #include <QtCore/qtimer.h>
47 #include <QtCore/qthread.h>
48 #include <QtCore/qcoreapplication.h>
50 // this contains QUnifiedTimer
51 #include <private/qabstractanimation_p.h>
55 // instance will be set, unset in constructor. Allows static methods to be inlined.
56 QQmlProfilerService *QQmlProfilerService::instance = 0;
57 Q_GLOBAL_STATIC(QQmlProfilerService, profilerInstance)
60 // convert to a QByteArray that can be sent to the debug client
61 // use of QDataStream can skew results
62 // (see tst_qqmldebugtrace::trace() benchmark)
63 QByteArray QQmlProfilerData::toByteArray() const
66 //### using QDataStream is relatively expensive
67 QDataStream ds(&data, QIODevice::WriteOnly);
68 ds << time << messageType << detailType;
69 if (messageType == (int)QQmlProfilerService::RangeData)
71 if (messageType == (int)QQmlProfilerService::RangeLocation)
72 ds << detailData << line << column;
73 if (messageType == (int)QQmlProfilerService::Event &&
74 detailType == (int)QQmlProfilerService::AnimationFrame)
75 ds << framerate << animationcount;
79 QQmlProfilerService::QQmlProfilerService()
80 : QQmlDebugService(QStringLiteral("CanvasFrameRate"), 1),
81 m_enabled(false), m_messageReceived(false)
85 if (registerService() == Enabled) {
86 // wait for first message indicating whether to trace or not
87 while (!m_messageReceived)
90 QUnifiedTimer::instance()->registerProfilerCallback( &animationFrame );
94 QQmlProfilerService::~QQmlProfilerService()
99 void QQmlProfilerService::initialize()
101 // just make sure that the service is properly registered
102 instance = profilerInstance();
105 bool QQmlProfilerService::startProfiling()
107 return profilerInstance()->startProfilingImpl();
110 bool QQmlProfilerService::stopProfiling()
112 return profilerInstance()->stopProfilingImpl();
115 void QQmlProfilerService::sendStartedProfilingMessage()
117 profilerInstance()->sendStartedProfilingMessageImpl();
120 void QQmlProfilerService::addEvent(EventType t)
122 profilerInstance()->addEventImpl(t);
125 void QQmlProfilerService::animationFrame(qint64 delta)
127 profilerInstance()->animationFrameImpl(delta);
130 void QQmlProfilerService::sendProfilingData()
132 profilerInstance()->sendMessages();
135 bool QQmlProfilerService::startProfilingImpl()
137 bool success = false;
138 if (!profilingEnabled()) {
139 setProfilingEnabled(true);
140 sendStartedProfilingMessageImpl();
146 bool QQmlProfilerService::stopProfilingImpl()
148 bool success = false;
149 if (profilingEnabled()) {
150 addEventImpl(EndTrace);
151 setProfilingEnabled(false);
157 void QQmlProfilerService::sendStartedProfilingMessageImpl()
159 if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
162 QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)StartTrace, QString(), -1, -1, 0, 0};
163 QQmlDebugService::sendMessage(ed.toByteArray());
166 void QQmlProfilerService::addEventImpl(EventType event)
168 if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
171 QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)event, QString(), -1, -1, 0, 0};
175 void QQmlProfilerService::startRange(RangeType range)
177 if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
180 QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeStart, (int)range, QString(), -1, -1, 0, 0};
184 void QQmlProfilerService::rangeData(RangeType range, const QString &rData)
186 if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
189 QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData, -1, -1, 0, 0};
193 void QQmlProfilerService::rangeData(RangeType range, const QUrl &rData)
195 if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
198 QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData.toString(), -1, -1, 0, 0};
202 void QQmlProfilerService::rangeLocation(RangeType range, const QString &fileName, int line, int column)
204 if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
207 QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName, line, column, 0, 0};
211 void QQmlProfilerService::rangeLocation(RangeType range, const QUrl &fileName, int line, int column)
213 if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
216 QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName.toString(), line, column, 0, 0};
220 void QQmlProfilerService::endRange(RangeType range)
222 if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
225 QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeEnd, (int)range, QString(), -1, -1, 0, 0};
229 void QQmlProfilerService::animationFrameImpl(qint64 delta)
231 Q_ASSERT(QQmlDebugService::isDebuggingEnabled());
235 int animCount = QUnifiedTimer::instance()->runningAnimationCount();
237 if (animCount > 0 && delta > 0) {
238 // trim fps to integer
239 int fps = 1000 / delta;
240 QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)AnimationFrame, QString(), -1, -1, fps, animCount};
246 Either send the message directly, or queue up
247 a list of messages to send later (via sendMessages)
249 void QQmlProfilerService::processMessage(const QQmlProfilerData &message)
251 QMutexLocker locker(&m_mutex);
252 m_data.append(message);
255 bool QQmlProfilerService::profilingEnabled()
260 void QQmlProfilerService::setProfilingEnabled(bool enable)
266 Send the messages queued up by processMessage
268 void QQmlProfilerService::sendMessages()
270 QMutexLocker locker(&m_mutex);
271 QList<QByteArray> messages;
272 for (int i = 0; i < m_data.count(); ++i)
273 messages << m_data.at(i).toByteArray();
276 //indicate completion
278 QDataStream ds(&data, QIODevice::WriteOnly);
279 ds << (qint64)-1 << (int)Complete;
282 QQmlDebugService::sendMessages(messages);
285 void QQmlProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
287 if (state() == newState)
290 if (state() == Enabled
297 void QQmlProfilerService::messageReceived(const QByteArray &message)
299 QByteArray rwData = message;
300 QDataStream stream(&rwData, QIODevice::ReadOnly);
305 m_messageReceived = true;
308 startProfilingImpl();
310 if (stopProfilingImpl())