7109286197c1906eb1dd84ed388255f3913241eb
[profile/ivi/qtdeclarative.git] / src / qml / debugger / qqmlprofilerservice.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlprofilerservice_p.h"
43
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>
49
50 // this contains QUnifiedTimer
51 #include <private/qabstractanimation_p.h>
52
53 QT_BEGIN_NAMESPACE
54
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)
58
59
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
64 {
65     QByteArray data;
66     //### using QDataStream is relatively expensive
67     QDataStream ds(&data, QIODevice::WriteOnly);
68     ds << time << messageType << detailType;
69     if (messageType == (int)QQmlProfilerService::RangeData)
70         ds << detailData;
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;
76     return data;
77 }
78
79 QQmlProfilerService::QQmlProfilerService()
80     : QQmlDebugService(QStringLiteral("CanvasFrameRate"), 1),
81       m_enabled(false), m_messageReceived(false)
82 {
83     m_timer.start();
84
85     if (registerService() == Enabled) {
86         // wait for first message indicating whether to trace or not
87         while (!m_messageReceived)
88             waitForMessage();
89
90         QUnifiedTimer::instance()->registerProfilerCallback( &animationFrame );
91     }
92 }
93
94 QQmlProfilerService::~QQmlProfilerService()
95 {
96     instance = 0;
97 }
98
99 void QQmlProfilerService::initialize()
100 {
101     // just make sure that the service is properly registered
102     instance = profilerInstance();
103 }
104
105 bool QQmlProfilerService::startProfiling()
106 {
107     return profilerInstance()->startProfilingImpl();
108 }
109
110 bool QQmlProfilerService::stopProfiling()
111 {
112     return profilerInstance()->stopProfilingImpl();
113 }
114
115 void QQmlProfilerService::sendStartedProfilingMessage()
116 {
117     profilerInstance()->sendStartedProfilingMessageImpl();
118 }
119
120 void QQmlProfilerService::addEvent(EventType t)
121 {
122     profilerInstance()->addEventImpl(t);
123 }
124
125 void QQmlProfilerService::animationFrame(qint64 delta)
126 {
127     profilerInstance()->animationFrameImpl(delta);
128 }
129
130 void QQmlProfilerService::sendProfilingData()
131 {
132     profilerInstance()->sendMessages();
133 }
134
135 bool QQmlProfilerService::startProfilingImpl()
136 {
137     bool success = false;
138     if (!profilingEnabled()) {
139         setProfilingEnabled(true);
140         sendStartedProfilingMessageImpl();
141         success = true;
142     }
143     return success;
144 }
145
146 bool QQmlProfilerService::stopProfilingImpl()
147 {
148     bool success = false;
149     if (profilingEnabled()) {
150         addEventImpl(EndTrace);
151         setProfilingEnabled(false);
152         success = true;
153     }
154     return success;
155 }
156
157 void QQmlProfilerService::sendStartedProfilingMessageImpl()
158 {
159     if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
160         return;
161
162     QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)StartTrace, QString(), -1, -1, 0, 0};
163     QQmlDebugService::sendMessage(ed.toByteArray());
164 }
165
166 void QQmlProfilerService::addEventImpl(EventType event)
167 {
168     if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
169         return;
170
171     QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)event, QString(), -1, -1, 0, 0};
172     processMessage(ed);
173 }
174
175 void QQmlProfilerService::startRange(RangeType range)
176 {
177     if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
178         return;
179
180     QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeStart, (int)range, QString(), -1, -1, 0, 0};
181     processMessage(rd);
182 }
183
184 void QQmlProfilerService::rangeData(RangeType range, const QString &rData)
185 {
186     if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
187         return;
188
189     QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData, -1, -1, 0, 0};
190     processMessage(rd);
191 }
192
193 void QQmlProfilerService::rangeData(RangeType range, const QUrl &rData)
194 {
195     if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
196         return;
197
198     QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData.toString(), -1, -1, 0, 0};
199     processMessage(rd);
200 }
201
202 void QQmlProfilerService::rangeLocation(RangeType range, const QString &fileName, int line, int column)
203 {
204     if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
205         return;
206
207     QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName, line, column, 0, 0};
208     processMessage(rd);
209 }
210
211 void QQmlProfilerService::rangeLocation(RangeType range, const QUrl &fileName, int line, int column)
212 {
213     if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
214         return;
215
216     QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName.toString(), line, column, 0, 0};
217     processMessage(rd);
218 }
219
220 void QQmlProfilerService::endRange(RangeType range)
221 {
222     if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
223         return;
224
225     QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeEnd, (int)range, QString(), -1, -1, 0, 0};
226     processMessage(rd);
227 }
228
229 void QQmlProfilerService::animationFrameImpl(qint64 delta)
230 {
231     Q_ASSERT(QQmlDebugService::isDebuggingEnabled());
232     if (!m_enabled)
233         return;
234
235     int animCount = QUnifiedTimer::instance()->runningAnimationCount();
236
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};
241         processMessage(ed);
242     }
243 }
244
245 /*
246     Either send the message directly, or queue up
247     a list of messages to send later (via sendMessages)
248 */
249 void QQmlProfilerService::processMessage(const QQmlProfilerData &message)
250 {
251     QMutexLocker locker(&m_mutex);
252     m_data.append(message);
253 }
254
255 bool QQmlProfilerService::profilingEnabled()
256 {
257     return m_enabled;
258 }
259
260 void QQmlProfilerService::setProfilingEnabled(bool enable)
261 {
262     m_enabled = enable;
263 }
264
265 /*
266     Send the messages queued up by processMessage
267 */
268 void QQmlProfilerService::sendMessages()
269 {
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();
274     m_data.clear();
275
276     //indicate completion
277     QByteArray data;
278     QDataStream ds(&data, QIODevice::WriteOnly);
279     ds << (qint64)-1 << (int)Complete;
280     messages << data;
281
282     QQmlDebugService::sendMessages(messages);
283 }
284
285 void QQmlProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
286 {
287     if (state() == newState)
288         return;
289
290     if (state() == Enabled
291             && m_enabled) {
292         stopProfilingImpl();
293         sendMessages();
294     }
295 }
296
297 void QQmlProfilerService::messageReceived(const QByteArray &message)
298 {
299     QByteArray rwData = message;
300     QDataStream stream(&rwData, QIODevice::ReadOnly);
301
302     bool enabled;
303     stream >> enabled;
304
305     m_messageReceived = true;
306
307     if (enabled) {
308         startProfilingImpl();
309     } else {
310         if (stopProfilingImpl())
311             sendMessages();
312     }
313 }
314
315 QT_END_NAMESPACE