1
/****************************************************************************
3
** Copyright (C) 2013 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 "qv4profilerservice_p.h"
43
#include "qqmlconfigurabledebugservice_p_p.h"
45
#include <QtCore/QHash>
46
#include <QtCore/QMutex>
47
#include <QtCore/QWaitCondition>
51
Q_GLOBAL_STATIC(QV4ProfilerService, v4ProfilerInstance)
55
class DebugServiceOutputStream : public v8::OutputStream
58
DebugServiceOutputStream()
59
: v8::OutputStream() {}
61
WriteResult WriteAsciiChunk(char *rawData, int size)
64
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
65
ds << QV4ProfilerService::V4SnapshotChunk << QByteArray(rawData, size);
66
messages.append(data);
69
QList<QByteArray> messages;
73
// convert to a QByteArray that can be sent to the debug client
74
QByteArray QV4ProfilerData::toByteArray() const
77
//### using QDataStream is relatively expensive
78
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
79
ds << messageType << filename << functionname << lineNumber << totalTime << selfTime << treeLevel;
84
class QV4ProfilerServicePrivate : public QQmlConfigurableDebugServicePrivate
86
Q_DECLARE_PUBLIC(QV4ProfilerService)
89
QV4ProfilerServicePrivate()
95
// void takeSnapshot(v8::HeapSnapshot::Type);
96
// void printProfileTree(const v8::CpuProfileNode *node, int level = 0);
97
// void sendMessages();
99
QList<QV4ProfilerData> m_data;
102
QList<QString> m_ongoing;
105
QV4ProfilerService::QV4ProfilerService(QObject *parent)
106
: QQmlConfigurableDebugService(*(new QV4ProfilerServicePrivate()), QStringLiteral("V8Profiler"), 1, parent)
110
QV4ProfilerService::~QV4ProfilerService()
114
QV4ProfilerService *QV4ProfilerService::instance()
116
return v4ProfilerInstance();
119
void QV4ProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
121
Q_D(QV4ProfilerService);
122
QMutexLocker lock(configMutex());
124
if (state() == newState)
127
if (state() == Enabled) {
128
foreach (const QString &title, d->m_ongoing) {
129
QMetaObject::invokeMethod(this, "stopProfiling", Qt::BlockingQueuedConnection,
130
Q_ARG(QString, title));
132
QMetaObject::invokeMethod(this, "sendProfilingData", Qt::BlockingQueuedConnection);
136
void QV4ProfilerService::messageReceived(const QByteArray &message)
138
Q_D(QV4ProfilerService);
140
QQmlDebugStream ds(message);
144
ds >> command >> option;
146
QMutexLocker lock(configMutex());
148
if (command == "V8PROFILER") {
150
QString titleStr = QString::fromUtf8(title);
151
if (option == "start") {
152
QMetaObject::invokeMethod(this, "startProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
153
} else if (option == "stop" && d->initialized) {
154
QMetaObject::invokeMethod(this, "stopProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
155
QMetaObject::invokeMethod(this, "sendProfilingData", Qt::QueuedConnection);
157
d->initialized = true;
160
if (command == "V8SNAPSHOT") {
161
if (option == "full")
162
QMetaObject::invokeMethod(this, "takeSnapshot", Qt::QueuedConnection);
163
else if (option == "delete") {
164
QMetaObject::invokeMethod(this, "deleteSnapshots", Qt::QueuedConnection);
168
// wake up constructor in blocking mode
171
QQmlDebugService::messageReceived(message);
174
void QV4ProfilerService::startProfiling(const QString &title)
176
Q_D(QV4ProfilerService);
179
if (d->m_ongoing.contains(title))
182
// v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
184
// v8::CpuProfiler::StartProfiling(v8title);
186
d->m_ongoing.append(title);
188
// indicate profiling started
190
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
191
ds << (int)QV4ProfilerService::V4Started;
196
void QV4ProfilerService::stopProfiling(const QString &title)
198
Q_D(QV4ProfilerService);
201
if (!d->m_ongoing.contains(title))
203
d->m_ongoing.removeOne(title);
207
v8::HandleScope handle_scope;
208
v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
209
const v8::CpuProfile *cpuProfile = v8::CpuProfiler::StopProfiling(v8title);
211
// can happen at start
212
const v8::CpuProfileNode *rootNode = cpuProfile->GetTopDownRoot();
213
d->printProfileTree(rootNode);
216
// indicate completion, even without data
218
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
219
ds << (int)QV4ProfilerService::V4Complete;
227
void QV4ProfilerService::takeSnapshot()
229
// Q_D(QV4ProfilerService);
231
// d->takeSnapshot(v8::HeapSnapshot::kFull);
234
void QV4ProfilerService::deleteSnapshots()
237
// v8::HeapProfiler::DeleteAllSnapshots();
240
void QV4ProfilerService::sendProfilingData()
242
// Q_D(QV4ProfilerService);
243
// Send messages to client
245
// d->sendMessages();
250
void QV4ProfilerServicePrivate::printProfileTree(const v8::CpuProfileNode *node, int level)
252
for (int index = 0 ; index < node->GetChildrenCount() ; index++) {
253
const v8::CpuProfileNode* childNode = node->GetChild(index);
254
QString scriptResourceName = QJSConverter::toString(childNode->GetScriptResourceName());
255
if (scriptResourceName.length() > 0) {
257
QV4ProfilerData rd = {(int)QV4ProfilerService::V4Entry, scriptResourceName,
258
QJSConverter::toString(childNode->GetFunctionName()),
259
childNode->GetLineNumber(), childNode->GetTotalTime(), childNode->GetSelfTime(), level};
262
// different nodes might have common children: fix at client side
263
if (childNode->GetChildrenCount() > 0) {
264
printProfileTree(childNode, level+1);
270
void QV4ProfilerServicePrivate::takeSnapshot(v8::HeapSnapshot::Type snapshotType)
272
Q_Q(QV4ProfilerService);
274
v8::HandleScope scope;
275
v8::Handle<v8::String> title = v8::String::New("");
277
DebugServiceOutputStream outputStream;
278
const v8::HeapSnapshot *snapshot = v8::HeapProfiler::TakeSnapshot(title, snapshotType);
279
snapshot->Serialize(&outputStream, v8::HeapSnapshot::kJSON);
280
QList<QByteArray> messages = outputStream.messages;
282
//indicate completion
284
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
285
ds << (int)QV4ProfilerService::V4SnapshotComplete;
286
messages.append(data);
288
q->sendMessages(messages);
291
void QV4ProfilerServicePrivate::sendMessages()
293
Q_Q(QV4ProfilerService);
295
QList<QByteArray> messages;
296
for (int i = 0; i < m_data.count(); ++i)
297
messages.append(m_data.at(i).toByteArray());
300
//indicate completion
302
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
303
ds << (int)QV4ProfilerService::V4Complete;
304
messages.append(data);
306
q->sendMessages(messages);