aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/debugger/qv4profilerservice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/debugger/qv4profilerservice.cpp')
-rw-r--r--src/qml/debugger/qv4profilerservice.cpp330
1 files changed, 330 insertions, 0 deletions
diff --git a/src/qml/debugger/qv4profilerservice.cpp b/src/qml/debugger/qv4profilerservice.cpp
new file mode 100644
index 0000000000..50bec8ec25
--- /dev/null
+++ b/src/qml/debugger/qv4profilerservice.cpp
@@ -0,0 +1,330 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4profilerservice_p.h"
+#include "qqmldebugservice_p_p.h"
+
+#include <QtCore/QHash>
+#include <QtCore/QMutex>
+#include <QtCore/QWaitCondition>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QV4ProfilerService, v4ProfilerInstance)
+
+#if 0
+// ### FIXME: v4
+class DebugServiceOutputStream : public v8::OutputStream
+{
+public:
+ DebugServiceOutputStream()
+ : v8::OutputStream() {}
+ void EndOfStream() {}
+ WriteResult WriteAsciiChunk(char *rawData, int size)
+ {
+ QByteArray data;
+ QQmlDebugStream ds(&data, QIODevice::WriteOnly);
+ ds << QV4ProfilerService::V4SnapshotChunk << QByteArray(rawData, size);
+ messages.append(data);
+ return kContinue;
+ }
+ QList<QByteArray> messages;
+};
+#endif
+
+// convert to a QByteArray that can be sent to the debug client
+QByteArray QV4ProfilerData::toByteArray() const
+{
+ QByteArray data;
+ //### using QDataStream is relatively expensive
+ QQmlDebugStream ds(&data, QIODevice::WriteOnly);
+ ds << messageType << filename << functionname << lineNumber << totalTime << selfTime << treeLevel;
+
+ return data;
+}
+
+class QV4ProfilerServicePrivate : public QQmlDebugServicePrivate
+{
+ Q_DECLARE_PUBLIC(QV4ProfilerService)
+
+public:
+ QV4ProfilerServicePrivate()
+ :initialized(false)
+ {
+ }
+
+ // ### FIXME: v4
+// void takeSnapshot(v8::HeapSnapshot::Type);
+// void printProfileTree(const v8::CpuProfileNode *node, int level = 0);
+// void sendMessages();
+
+ QList<QV4ProfilerData> m_data;
+
+ bool initialized;
+ QMutex initializeMutex;
+ QWaitCondition initializeCondition;
+ QList<QString> m_ongoing;
+};
+
+QV4ProfilerService::QV4ProfilerService(QObject *parent)
+ : QQmlDebugService(*(new QV4ProfilerServicePrivate()), QStringLiteral("V8Profiler"), 1, parent)
+{
+ Q_D(QV4ProfilerService);
+
+ QMutexLocker lock(&d->initializeMutex);
+
+ if (registerService() == Enabled
+ && QQmlDebugService::blockingMode()) {
+ // let's wait for first message ...
+ d->initializeCondition.wait(&d->initializeMutex);
+ }
+}
+
+QV4ProfilerService::~QV4ProfilerService()
+{
+}
+
+QV4ProfilerService *QV4ProfilerService::instance()
+{
+ return v4ProfilerInstance();
+}
+
+void QV4ProfilerService::initialize()
+{
+ // just make sure that the service is properly registered
+ v4ProfilerInstance();
+}
+
+void QV4ProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
+{
+ Q_D(QV4ProfilerService);
+
+ if (state() == newState)
+ return;
+
+ if (state() == Enabled) {
+ foreach (const QString &title, d->m_ongoing) {
+ QMetaObject::invokeMethod(this, "stopProfiling", Qt::BlockingQueuedConnection,
+ Q_ARG(QString, title));
+ }
+ QMetaObject::invokeMethod(this, "sendProfilingData", Qt::BlockingQueuedConnection);
+ } else {
+ // wake up constructor in blocking mode
+ // (we might got disabled before first message arrived)
+ d->initializeCondition.wakeAll();
+ }
+}
+
+void QV4ProfilerService::messageReceived(const QByteArray &message)
+{
+ Q_D(QV4ProfilerService);
+
+ QQmlDebugStream ds(message);
+ QByteArray command;
+ QByteArray option;
+ QByteArray title;
+ ds >> command >> option;
+
+ QMutexLocker lock(&d->initializeMutex);
+
+ if (command == "V8PROFILER") {
+ ds >> title;
+ QString titleStr = QString::fromUtf8(title);
+ if (option == "start") {
+ QMetaObject::invokeMethod(this, "startProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
+ } else if (option == "stop" && d->initialized) {
+ QMetaObject::invokeMethod(this, "stopProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
+ QMetaObject::invokeMethod(this, "sendProfilingData", Qt::QueuedConnection);
+ }
+ d->initialized = true;
+ }
+
+ if (command == "V8SNAPSHOT") {
+ if (option == "full")
+ QMetaObject::invokeMethod(this, "takeSnapshot", Qt::QueuedConnection);
+ else if (option == "delete") {
+ QMetaObject::invokeMethod(this, "deleteSnapshots", Qt::QueuedConnection);
+ }
+ }
+
+ // wake up constructor in blocking mode
+ d->initializeCondition.wakeAll();
+
+ QQmlDebugService::messageReceived(message);
+}
+
+void QV4ProfilerService::startProfiling(const QString &title)
+{
+ Q_D(QV4ProfilerService);
+ // Start Profiling
+
+ if (d->m_ongoing.contains(title))
+ return;
+
+// v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
+ // ### FIXME: v4
+// v8::CpuProfiler::StartProfiling(v8title);
+
+ d->m_ongoing.append(title);
+
+ // indicate profiling started
+ QByteArray data;
+ QQmlDebugStream ds(&data, QIODevice::WriteOnly);
+ ds << (int)QV4ProfilerService::V4Started;
+
+ sendMessage(data);
+}
+
+void QV4ProfilerService::stopProfiling(const QString &title)
+{
+ Q_D(QV4ProfilerService);
+ // Stop profiling
+
+ if (!d->m_ongoing.contains(title))
+ return;
+ d->m_ongoing.removeOne(title);
+
+#if 0
+ // ### FIXME: v4
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
+ const v8::CpuProfile *cpuProfile = v8::CpuProfiler::StopProfiling(v8title);
+ if (cpuProfile) {
+ // can happen at start
+ const v8::CpuProfileNode *rootNode = cpuProfile->GetTopDownRoot();
+ d->printProfileTree(rootNode);
+ } else {
+#endif
+ // indicate completion, even without data
+ QByteArray data;
+ QQmlDebugStream ds(&data, QIODevice::WriteOnly);
+ ds << (int)QV4ProfilerService::V4Complete;
+
+ sendMessage(data);
+#if 0
+ }
+#endif
+}
+
+void QV4ProfilerService::takeSnapshot()
+{
+// Q_D(QV4ProfilerService);
+ // ### FIXME: v4
+// d->takeSnapshot(v8::HeapSnapshot::kFull);
+}
+
+void QV4ProfilerService::deleteSnapshots()
+{
+ // ### FIXME: v4
+// v8::HeapProfiler::DeleteAllSnapshots();
+}
+
+void QV4ProfilerService::sendProfilingData()
+{
+// Q_D(QV4ProfilerService);
+ // Send messages to client
+ // ### FIXME: v4
+// d->sendMessages();
+}
+
+#if 0
+// ### FIXME: v4
+void QV4ProfilerServicePrivate::printProfileTree(const v8::CpuProfileNode *node, int level)
+{
+ for (int index = 0 ; index < node->GetChildrenCount() ; index++) {
+ const v8::CpuProfileNode* childNode = node->GetChild(index);
+ QString scriptResourceName = QJSConverter::toString(childNode->GetScriptResourceName());
+ if (scriptResourceName.length() > 0) {
+
+ QV4ProfilerData rd = {(int)QV4ProfilerService::V4Entry, scriptResourceName,
+ QJSConverter::toString(childNode->GetFunctionName()),
+ childNode->GetLineNumber(), childNode->GetTotalTime(), childNode->GetSelfTime(), level};
+ m_data.append(rd);
+
+ // different nodes might have common children: fix at client side
+ if (childNode->GetChildrenCount() > 0) {
+ printProfileTree(childNode, level+1);
+ }
+ }
+ }
+}
+
+void QV4ProfilerServicePrivate::takeSnapshot(v8::HeapSnapshot::Type snapshotType)
+{
+ Q_Q(QV4ProfilerService);
+
+ v8::HandleScope scope;
+ v8::Handle<v8::String> title = v8::String::New("");
+
+ DebugServiceOutputStream outputStream;
+ const v8::HeapSnapshot *snapshot = v8::HeapProfiler::TakeSnapshot(title, snapshotType);
+ snapshot->Serialize(&outputStream, v8::HeapSnapshot::kJSON);
+ QList<QByteArray> messages = outputStream.messages;
+
+ //indicate completion
+ QByteArray data;
+ QQmlDebugStream ds(&data, QIODevice::WriteOnly);
+ ds << (int)QV4ProfilerService::V4SnapshotComplete;
+ messages.append(data);
+
+ q->sendMessages(messages);
+}
+
+void QV4ProfilerServicePrivate::sendMessages()
+{
+ Q_Q(QV4ProfilerService);
+
+ QList<QByteArray> messages;
+ for (int i = 0; i < m_data.count(); ++i)
+ messages.append(m_data.at(i).toByteArray());
+ m_data.clear();
+
+ //indicate completion
+ QByteArray data;
+ QQmlDebugStream ds(&data, QIODevice::WriteOnly);
+ ds << (int)QV4ProfilerService::V4Complete;
+ messages.append(data);
+
+ q->sendMessages(messages);
+}
+#endif
+
+QT_END_NAMESPACE