Change qFatal to qWarning
[profile/ivi/qtdeclarative.git] / tools / qmlprofiler / qmlprofilerclient.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 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.
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 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.
24 **
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.
28 **
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.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qmlprofilerclient.h"
43
44 #include <QtCore/QStack>
45 #include <QtCore/QStringList>
46
47 ProfilerClient::ProfilerClient(const QString &clientName,
48                              QQmlDebugConnection *client)
49     : QQmlDebugClient(clientName, client),
50       m_recording(false),
51       m_enabled(false)
52 {
53 }
54
55 ProfilerClient::~ProfilerClient()
56 {
57     //Disable profiling if started by client
58     //Profiling data will be lost!!
59     if (isRecording())
60         setRecording(false);
61 }
62
63 void ProfilerClient::clearData()
64 {
65     emit cleared();
66 }
67
68 bool ProfilerClient::isEnabled() const
69 {
70     return m_enabled;
71 }
72
73 void ProfilerClient::sendRecordingStatus()
74 {
75 }
76
77 bool ProfilerClient::isRecording() const
78 {
79     return m_recording;
80 }
81
82 void ProfilerClient::setRecording(bool v)
83 {
84     if (v == m_recording)
85         return;
86
87     m_recording = v;
88
89     if (state() == Enabled) {
90         sendRecordingStatus();
91     }
92
93     emit recordingChanged(v);
94 }
95
96 void ProfilerClient::stateChanged(State status)
97 {
98     if ((m_enabled && status != Enabled) ||
99             (!m_enabled && status == Enabled))
100         emit enabledChanged();
101
102     m_enabled = status == Enabled;
103
104 }
105
106 class QmlProfilerClientPrivate
107 {
108 public:
109     QmlProfilerClientPrivate()
110         : inProgressRanges(0)
111         , maximumTime(0)
112     {
113         ::memset(rangeCount, 0,
114                  QQmlProfilerService::MaximumRangeType * sizeof(int));
115     }
116
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];
123     qint64 maximumTime;
124 };
125
126 QmlProfilerClient::QmlProfilerClient(
127         QQmlDebugConnection *client)
128     : ProfilerClient(QStringLiteral("CanvasFrameRate"), client),
129       d(new QmlProfilerClientPrivate)
130 {
131 }
132
133 QmlProfilerClient::~QmlProfilerClient()
134 {
135     delete d;
136 }
137
138 void QmlProfilerClient::clearData()
139 {
140     ::memset(d->rangeCount, 0,
141              QQmlProfilerService::MaximumRangeType * sizeof(int));
142     d->bindingTypes.clear();
143     ProfilerClient::clearData();
144 }
145
146 void QmlProfilerClient::sendRecordingStatus()
147 {
148     QByteArray ba;
149     QDataStream stream(&ba, QIODevice::WriteOnly);
150     stream << isRecording();
151     sendMessage(ba);
152 }
153
154 void QmlProfilerClient::messageReceived(const QByteArray &data)
155 {
156     QByteArray rwData = data;
157     QDataStream stream(&rwData, QIODevice::ReadOnly);
158
159     qint64 time;
160     int messageType;
161
162     stream >> time >> messageType;
163
164     if (messageType >= QQmlProfilerService::MaximumMessage)
165         return;
166
167     if (messageType == QQmlProfilerService::Event) {
168         int event;
169         stream >> event;
170
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);
185         }
186     } else if (messageType == QQmlProfilerService::Complete) {
187         emit complete();
188
189     } else {
190         int range;
191         stream >> range;
192
193         if (range >= QQmlProfilerService::MaximumRangeType)
194             return;
195
196         if (messageType == QQmlProfilerService::RangeStart) {
197             d->rangeStartTimes[range].push(time);
198             d->inProgressRanges |= (static_cast<qint64>(1) << range);
199             ++d->rangeCount[range];
200
201             // read binding type
202             if (range == (int)QQmlProfilerService::Binding) {
203                 int bindingType = (int)QQmlProfilerService::QmlBinding;
204                 if (!stream.atEnd())
205                     stream >> bindingType;
206                 d->bindingTypes.push((QQmlProfilerService::BindingType)bindingType);
207             }
208         } else if (messageType == QQmlProfilerService::RangeData) {
209             QString data;
210             stream >> data;
211
212             int count = d->rangeCount[range];
213             if (count > 0) {
214                 while (d->rangeDatas[range].count() < count)
215                     d->rangeDatas[range].push(QStringList());
216                 d->rangeDatas[range][count-1] << data;
217             }
218
219         } else if (messageType == QQmlProfilerService::RangeLocation) {
220             QString fileName;
221             int line;
222             int column = -1;
223             stream >> fileName >> line;
224
225             if (!stream.atEnd())
226                 stream >> column;
227
228             if (d->rangeCount[range] > 0) {
229                 d->rangeLocations[range].push(QmlEventLocation(fileName, line,
230                                                             column));
231             }
232         } else {
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);
237
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();
243
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();
254                     if (count != 0)
255                         qWarning() << "incorrectly nested data";
256                 }
257             }
258         }
259     }
260 }
261
262 V8ProfilerClient::V8ProfilerClient(QQmlDebugConnection *client)
263     : ProfilerClient(QStringLiteral("V8Profiler"), client)
264 {
265 }
266
267 V8ProfilerClient::~V8ProfilerClient()
268 {
269 }
270
271 void V8ProfilerClient::sendRecordingStatus()
272 {
273     QByteArray ba;
274     QDataStream stream(&ba, QIODevice::WriteOnly);
275     QByteArray cmd("V8PROFILER");
276     QByteArray option("");
277     QByteArray title("");
278
279     if (m_recording) {
280         option = "start";
281     } else {
282         option = "stop";
283     }
284     stream << cmd << option << title;
285     sendMessage(ba);
286 }
287
288 void V8ProfilerClient::messageReceived(const QByteArray &data)
289 {
290     QByteArray rwData = data;
291     QDataStream stream(&rwData, QIODevice::ReadOnly);
292
293     int messageType;
294
295     stream >> messageType;
296
297     if (messageType == V8Complete) {
298         emit complete();
299     } else if (messageType == V8Entry) {
300         QString filename;
301         QString function;
302         int lineNumber;
303         double totalTime;
304         double selfTime;
305         int depth;
306
307         stream  >> filename >> function >> lineNumber >> totalTime >>
308                    selfTime >> depth;
309         emit this->range(depth, function, filename, lineNumber, totalTime,
310                          selfTime);
311     }
312 }
313