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 "qv8profilerservice_p.h"
43
#include "qqmldebugservice_p_p.h"
44
#include <private/qv8profiler_p.h>
46
#include <QtCore/QHash>
47
#include <QtCore/QMutex>
48
#include <QtCore/QWaitCondition>
52
Q_GLOBAL_STATIC(QV8ProfilerService, v8ProfilerInstance)
56
class DebugServiceOutputStream : public v8::OutputStream
59
DebugServiceOutputStream()
60
: v8::OutputStream() {}
62
WriteResult WriteAsciiChunk(char *rawData, int size)
65
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
66
ds << QV8ProfilerService::V8SnapshotChunk << QByteArray(rawData, size);
67
messages.append(data);
70
QList<QByteArray> messages;
74
// convert to a QByteArray that can be sent to the debug client
75
QByteArray QV8ProfilerData::toByteArray() const
78
//### using QDataStream is relatively expensive
79
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
80
ds << messageType << filename << functionname << lineNumber << totalTime << selfTime << treeLevel;
85
class QV8ProfilerServicePrivate : public QQmlDebugServicePrivate
87
Q_DECLARE_PUBLIC(QV8ProfilerService)
90
QV8ProfilerServicePrivate()
96
// void takeSnapshot(v8::HeapSnapshot::Type);
97
// void printProfileTree(const v8::CpuProfileNode *node, int level = 0);
98
// void sendMessages();
100
QList<QV8ProfilerData> m_data;
103
QMutex initializeMutex;
104
QWaitCondition initializeCondition;
105
QList<QString> m_ongoing;
108
QV8ProfilerService::QV8ProfilerService(QObject *parent)
109
: QQmlDebugService(*(new QV8ProfilerServicePrivate()), QStringLiteral("V8Profiler"), 1, parent)
111
Q_D(QV8ProfilerService);
113
QMutexLocker lock(&d->initializeMutex);
115
if (registerService() == Enabled
116
&& QQmlDebugService::blockingMode()) {
117
// let's wait for first message ...
118
d->initializeCondition.wait(&d->initializeMutex);
122
QV8ProfilerService::~QV8ProfilerService()
126
QV8ProfilerService *QV8ProfilerService::instance()
128
return v8ProfilerInstance();
131
void QV8ProfilerService::initialize()
133
// just make sure that the service is properly registered
134
v8ProfilerInstance();
137
void QV8ProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
139
Q_D(QV8ProfilerService);
141
if (state() == newState)
144
if (state() == Enabled) {
145
foreach (const QString &title, d->m_ongoing) {
146
QMetaObject::invokeMethod(this, "stopProfiling", Qt::BlockingQueuedConnection,
147
Q_ARG(QString, title));
149
QMetaObject::invokeMethod(this, "sendProfilingData", Qt::BlockingQueuedConnection);
151
// wake up constructor in blocking mode
152
// (we might got disabled before first message arrived)
153
d->initializeCondition.wakeAll();
157
void QV8ProfilerService::messageReceived(const QByteArray &message)
159
Q_D(QV8ProfilerService);
161
QQmlDebugStream ds(message);
165
ds >> command >> option;
167
QMutexLocker lock(&d->initializeMutex);
169
if (command == "V8PROFILER") {
171
QString titleStr = QString::fromUtf8(title);
172
if (option == "start") {
173
QMetaObject::invokeMethod(this, "startProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
174
} else if (option == "stop" && d->initialized) {
175
QMetaObject::invokeMethod(this, "stopProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
176
QMetaObject::invokeMethod(this, "sendProfilingData", Qt::QueuedConnection);
178
d->initialized = true;
181
if (command == "V8SNAPSHOT") {
182
if (option == "full")
183
QMetaObject::invokeMethod(this, "takeSnapshot", Qt::QueuedConnection);
184
else if (option == "delete") {
185
QMetaObject::invokeMethod(this, "deleteSnapshots", Qt::QueuedConnection);
189
// wake up constructor in blocking mode
190
d->initializeCondition.wakeAll();
192
QQmlDebugService::messageReceived(message);
195
void QV8ProfilerService::startProfiling(const QString &title)
197
Q_D(QV8ProfilerService);
200
if (d->m_ongoing.contains(title))
203
// v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
205
// v8::CpuProfiler::StartProfiling(v8title);
207
d->m_ongoing.append(title);
209
// indicate profiling started
211
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
212
ds << (int)QV8ProfilerService::V8Started;
217
void QV8ProfilerService::stopProfiling(const QString &title)
219
Q_D(QV8ProfilerService);
222
if (!d->m_ongoing.contains(title))
224
d->m_ongoing.removeOne(title);
228
v8::HandleScope handle_scope;
229
v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
230
const v8::CpuProfile *cpuProfile = v8::CpuProfiler::StopProfiling(v8title);
232
// can happen at start
233
const v8::CpuProfileNode *rootNode = cpuProfile->GetTopDownRoot();
234
d->printProfileTree(rootNode);
237
// indicate completion, even without data
239
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
240
ds << (int)QV8ProfilerService::V8Complete;
248
void QV8ProfilerService::takeSnapshot()
250
// Q_D(QV8ProfilerService);
252
// d->takeSnapshot(v8::HeapSnapshot::kFull);
255
void QV8ProfilerService::deleteSnapshots()
258
// v8::HeapProfiler::DeleteAllSnapshots();
261
void QV8ProfilerService::sendProfilingData()
263
// Q_D(QV8ProfilerService);
264
// Send messages to client
266
// d->sendMessages();
271
void QV8ProfilerServicePrivate::printProfileTree(const v8::CpuProfileNode *node, int level)
273
for (int index = 0 ; index < node->GetChildrenCount() ; index++) {
274
const v8::CpuProfileNode* childNode = node->GetChild(index);
275
QString scriptResourceName = QJSConverter::toString(childNode->GetScriptResourceName());
276
if (scriptResourceName.length() > 0) {
278
QV8ProfilerData rd = {(int)QV8ProfilerService::V8Entry, scriptResourceName,
279
QJSConverter::toString(childNode->GetFunctionName()),
280
childNode->GetLineNumber(), childNode->GetTotalTime(), childNode->GetSelfTime(), level};
283
// different nodes might have common children: fix at client side
284
if (childNode->GetChildrenCount() > 0) {
285
printProfileTree(childNode, level+1);
291
void QV8ProfilerServicePrivate::takeSnapshot(v8::HeapSnapshot::Type snapshotType)
293
Q_Q(QV8ProfilerService);
295
v8::HandleScope scope;
296
v8::Handle<v8::String> title = v8::String::New("");
298
DebugServiceOutputStream outputStream;
299
const v8::HeapSnapshot *snapshot = v8::HeapProfiler::TakeSnapshot(title, snapshotType);
300
snapshot->Serialize(&outputStream, v8::HeapSnapshot::kJSON);
301
QList<QByteArray> messages = outputStream.messages;
303
//indicate completion
305
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
306
ds << (int)QV8ProfilerService::V8SnapshotComplete;
307
messages.append(data);
309
q->sendMessages(messages);
312
void QV8ProfilerServicePrivate::sendMessages()
314
Q_Q(QV8ProfilerService);
316
QList<QByteArray> messages;
317
for (int i = 0; i < m_data.count(); ++i)
318
messages.append(m_data.at(i).toByteArray());
321
//indicate completion
323
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
324
ds << (int)QV8ProfilerService::V8Complete;
325
messages.append(data);
327
q->sendMessages(messages);