forked from qt-creator/qt-creator
QmlProfiler: V8 profiling
Change-Id: I926c5821d31453064f5dbed2b5a10f6195761f42 Reviewed-on: http://codereview.qt-project.org/5892 Reviewed-by: Kai Koehne <kai.koehne@nokia.com> Sanity-Review: Qt Sanity Bot <qt_sanity_bot@ovi.com>
This commit is contained in:
@@ -83,6 +83,7 @@ public:
|
||||
QmlProfilerEventsViewPrivate(QmlProfilerEventsView *qq) : q(qq) {}
|
||||
|
||||
void buildModelFromList(const QmlEventDescriptions &list, QStandardItem *parentItem, const QmlEventDescriptions &visitedFunctionsList = QmlEventDescriptions() );
|
||||
void buildV8ModelFromList( const QV8EventDescriptions &list );
|
||||
int getFieldCount();
|
||||
QString displayTime(double time) const;
|
||||
QString nameForType(int typeNumber) const;
|
||||
@@ -92,6 +93,7 @@ public:
|
||||
|
||||
QmlProfilerEventsView *q;
|
||||
|
||||
QmlProfilerEventsView::ViewTypes m_viewType;
|
||||
QmlProfilerEventList *m_eventStatistics;
|
||||
QStandardItemModel *m_model;
|
||||
QList<bool> m_fieldShown;
|
||||
@@ -137,7 +139,8 @@ void QmlProfilerEventsView::setEventStatisticsModel( QmlProfilerEventList *model
|
||||
if (d->m_eventStatistics)
|
||||
disconnect(d->m_eventStatistics,SIGNAL(dataReady()),this,SLOT(buildModel()));
|
||||
d->m_eventStatistics = model;
|
||||
connect(d->m_eventStatistics,SIGNAL(dataReady()),this,SLOT(buildModel()));
|
||||
if (model)
|
||||
connect(d->m_eventStatistics,SIGNAL(dataReady()),this,SLOT(buildModel()));
|
||||
}
|
||||
|
||||
void QmlProfilerEventsView::setFieldViewable(Fields field, bool show)
|
||||
@@ -154,6 +157,7 @@ void QmlProfilerEventsView::setFieldViewable(Fields field, bool show)
|
||||
|
||||
void QmlProfilerEventsView::setViewType(ViewTypes type)
|
||||
{
|
||||
d->m_viewType = type;
|
||||
switch (type) {
|
||||
case EventsView: {
|
||||
setObjectName("QmlProfilerEventsView");
|
||||
@@ -161,15 +165,18 @@ void QmlProfilerEventsView::setViewType(ViewTypes type)
|
||||
setFieldViewable(Type, true);
|
||||
setFieldViewable(Percent, true);
|
||||
setFieldViewable(TotalDuration, true);
|
||||
setFieldViewable(SelfPercent, false);
|
||||
setFieldViewable(SelfDuration, false);
|
||||
setFieldViewable(CallCount, true);
|
||||
setFieldViewable(TimePerCall, true);
|
||||
setFieldViewable(MaxTime, true);
|
||||
setFieldViewable(MinTime, true);
|
||||
setFieldViewable(MedianTime, true);
|
||||
setFieldViewable(Details, false);
|
||||
setFieldViewable(Details, true);
|
||||
setFieldViewable(Parents, false);
|
||||
setFieldViewable(Children, false);
|
||||
setShowAnonymousEvents(false);
|
||||
setToolTip(QString());
|
||||
break;
|
||||
}
|
||||
case CallersView: {
|
||||
@@ -178,6 +185,8 @@ void QmlProfilerEventsView::setViewType(ViewTypes type)
|
||||
setFieldViewable(Type, true);
|
||||
setFieldViewable(Percent, false);
|
||||
setFieldViewable(TotalDuration, false);
|
||||
setFieldViewable(SelfPercent, false);
|
||||
setFieldViewable(SelfDuration, false);
|
||||
setFieldViewable(CallCount, false);
|
||||
setFieldViewable(TimePerCall, false);
|
||||
setFieldViewable(MaxTime, false);
|
||||
@@ -187,6 +196,7 @@ void QmlProfilerEventsView::setViewType(ViewTypes type)
|
||||
setFieldViewable(Parents, true);
|
||||
setFieldViewable(Children, false);
|
||||
setShowAnonymousEvents(true);
|
||||
setToolTip(QString());
|
||||
break;
|
||||
}
|
||||
case CalleesView: {
|
||||
@@ -195,6 +205,8 @@ void QmlProfilerEventsView::setViewType(ViewTypes type)
|
||||
setFieldViewable(Type, true);
|
||||
setFieldViewable(Percent, false);
|
||||
setFieldViewable(TotalDuration, false);
|
||||
setFieldViewable(SelfPercent, false);
|
||||
setFieldViewable(SelfDuration, false);
|
||||
setFieldViewable(CallCount, false);
|
||||
setFieldViewable(TimePerCall, false);
|
||||
setFieldViewable(MaxTime, false);
|
||||
@@ -204,6 +216,27 @@ void QmlProfilerEventsView::setViewType(ViewTypes type)
|
||||
setFieldViewable(Parents, false);
|
||||
setFieldViewable(Children, true);
|
||||
setShowAnonymousEvents(true);
|
||||
setToolTip(QString());
|
||||
break;
|
||||
}
|
||||
case V8ProfileView: {
|
||||
setObjectName("QmlProfilerV8ProfileView");
|
||||
setFieldViewable(Name, true);
|
||||
setFieldViewable(Type, false);
|
||||
setFieldViewable(Percent, true);
|
||||
setFieldViewable(TotalDuration, true);
|
||||
setFieldViewable(SelfPercent, true);
|
||||
setFieldViewable(SelfDuration, true);
|
||||
setFieldViewable(CallCount, false);
|
||||
setFieldViewable(TimePerCall, false);
|
||||
setFieldViewable(MaxTime, false);
|
||||
setFieldViewable(MinTime, false);
|
||||
setFieldViewable(MedianTime, false);
|
||||
setFieldViewable(Details, true);
|
||||
setFieldViewable(Parents, false);
|
||||
setFieldViewable(Children, false);
|
||||
setShowAnonymousEvents(true);
|
||||
setToolTip(tr("Trace information from the v8 JavaScript engine. Available only in Qt5 based applications"));
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
@@ -234,6 +267,10 @@ void QmlProfilerEventsView::setHeaderLabels()
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Time in Percent")));
|
||||
if (d->m_fieldShown[TotalDuration])
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Total Time")));
|
||||
if (d->m_fieldShown[SelfPercent])
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Self Time in Percent")));
|
||||
if (d->m_fieldShown[SelfDuration])
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Self Time")));
|
||||
if (d->m_fieldShown[CallCount])
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Calls")));
|
||||
if (d->m_fieldShown[TimePerCall])
|
||||
@@ -270,7 +307,10 @@ void QmlProfilerEventsView::buildModel()
|
||||
{
|
||||
if (d->m_eventStatistics) {
|
||||
clear();
|
||||
d->buildModelFromList( d->m_eventStatistics->getEventDescriptions(), d->m_model->invisibleRootItem() );
|
||||
if (d->m_viewType == V8ProfileView)
|
||||
d->buildV8ModelFromList( d->m_eventStatistics->getV8Events() );
|
||||
else
|
||||
d->buildModelFromList( d->m_eventStatistics->getEventDescriptions(), d->m_model->invisibleRootItem() );
|
||||
|
||||
bool hasBranches = d->m_fieldShown[Parents] || d->m_fieldShown[Children];
|
||||
setRootIsDecorated(hasBranches);
|
||||
@@ -381,6 +421,56 @@ void QmlProfilerEventsView::QmlProfilerEventsViewPrivate::buildModelFromList( co
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEventsView::QmlProfilerEventsViewPrivate::buildV8ModelFromList(const QV8EventDescriptions &list)
|
||||
{
|
||||
foreach (QV8EventData *v8event, list) {
|
||||
|
||||
QList<QStandardItem *> newRow;
|
||||
|
||||
if (m_fieldShown[Name]) {
|
||||
newRow << new EventsViewItem(v8event->displayName);
|
||||
}
|
||||
|
||||
if (m_fieldShown[Percent]) {
|
||||
newRow << new EventsViewItem(QString::number(v8event->totalPercent,'f',2)+QLatin1String(" %"));
|
||||
newRow.last()->setData(QVariant(v8event->totalPercent));
|
||||
}
|
||||
|
||||
if (m_fieldShown[TotalDuration]) {
|
||||
newRow << new EventsViewItem(displayTime(v8event->totalTime));
|
||||
newRow.last()->setData(QVariant(v8event->totalTime));
|
||||
}
|
||||
|
||||
if (m_fieldShown[SelfPercent]) {
|
||||
newRow << new EventsViewItem(QString::number(v8event->selfPercent,'f',2)+QLatin1String(" %"));
|
||||
newRow.last()->setData(QVariant(v8event->selfPercent));
|
||||
}
|
||||
|
||||
if (m_fieldShown[SelfDuration]) {
|
||||
newRow << new EventsViewItem(displayTime(v8event->selfTime));
|
||||
newRow.last()->setData(QVariant(v8event->selfTime));
|
||||
}
|
||||
|
||||
if (m_fieldShown[Details]) {
|
||||
newRow << new EventsViewItem(v8event->functionName);
|
||||
newRow.last()->setData(QVariant(v8event->functionName));
|
||||
}
|
||||
|
||||
if (!newRow.isEmpty()) {
|
||||
// no edit
|
||||
foreach (QStandardItem *item, newRow)
|
||||
item->setEditable(false);
|
||||
|
||||
// metadata
|
||||
newRow.at(0)->setData(QVariant(v8event->filename),FilenameRole);
|
||||
newRow.at(0)->setData(QVariant(v8event->line),LineRole);
|
||||
|
||||
// append
|
||||
m_model->invisibleRootItem()->appendRow(newRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString QmlProfilerEventsView::QmlProfilerEventsViewPrivate::displayTime(double time) const
|
||||
{
|
||||
if (time < 1e6)
|
||||
|
||||
@@ -58,6 +58,8 @@ public:
|
||||
Type,
|
||||
Percent,
|
||||
TotalDuration,
|
||||
SelfPercent,
|
||||
SelfDuration,
|
||||
CallCount,
|
||||
TimePerCall,
|
||||
MaxTime,
|
||||
@@ -74,6 +76,7 @@ public:
|
||||
EventsView,
|
||||
CallersView,
|
||||
CalleesView,
|
||||
V8ProfileView,
|
||||
|
||||
MaxViewTypes
|
||||
};
|
||||
|
||||
@@ -102,6 +102,7 @@ public:
|
||||
QmlProfilerEventsView *m_eventsView;
|
||||
QmlProfilerEventsView *m_calleeView;
|
||||
QmlProfilerEventsView *m_callerView;
|
||||
QmlProfilerEventsView *m_v8profilerView;
|
||||
Project *m_project;
|
||||
Utils::FileInProjectFinder m_projectFinder;
|
||||
RunConfiguration *m_runConfiguration;
|
||||
@@ -305,6 +306,11 @@ QWidget *QmlProfilerTool::createWidgets()
|
||||
this, SLOT(gotoSourceLocation(QString,int)));
|
||||
connect(d->m_callerView, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
|
||||
|
||||
d->m_v8profilerView = new QmlProfilerEventsView(mw, d->m_traceWindow->getEventList());
|
||||
d->m_v8profilerView->setViewType(QmlProfilerEventsView::V8ProfileView);
|
||||
connect(d->m_v8profilerView, SIGNAL(gotoSourceLocation(QString,int)), this, SLOT(gotoSourceLocation(QString,int)));
|
||||
connect(d->m_v8profilerView, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
|
||||
|
||||
QDockWidget *eventsDock = AnalyzerManager::createDockWidget
|
||||
(this, tr("Events"), d->m_eventsView, Qt::BottomDockWidgetArea);
|
||||
QDockWidget *timelineDock = AnalyzerManager::createDockWidget
|
||||
@@ -313,16 +319,20 @@ QWidget *QmlProfilerTool::createWidgets()
|
||||
(this, tr("Callees"), d->m_calleeView, Qt::BottomDockWidgetArea);
|
||||
QDockWidget *callerDock = AnalyzerManager::createDockWidget
|
||||
(this, tr("Callers"), d->m_callerView, Qt::BottomDockWidgetArea);
|
||||
QDockWidget *v8profilerDock = AnalyzerManager::createDockWidget
|
||||
(this, tr("JavaScript"), d->m_v8profilerView, Qt::BottomDockWidgetArea);
|
||||
|
||||
eventsDock->show();
|
||||
timelineDock->show();
|
||||
calleeDock->show();
|
||||
callerDock->show();
|
||||
v8profilerDock->show();
|
||||
|
||||
mw->splitDockWidget(mw->toolBarDockWidget(), eventsDock, Qt::Vertical);
|
||||
mw->tabifyDockWidget(eventsDock, timelineDock);
|
||||
mw->tabifyDockWidget(timelineDock, calleeDock);
|
||||
mw->tabifyDockWidget(calleeDock, callerDock);
|
||||
mw->tabifyDockWidget(callerDock, v8profilerDock);
|
||||
|
||||
//
|
||||
// Toolbar
|
||||
@@ -484,6 +494,7 @@ void QmlProfilerTool::clearDisplay()
|
||||
d->m_eventsView->clear();
|
||||
d->m_calleeView->clear();
|
||||
d->m_callerView->clear();
|
||||
d->m_v8profilerView->clear();
|
||||
}
|
||||
|
||||
static void startRemoteTool(IAnalyzerTool *tool, StartMode mode)
|
||||
|
||||
@@ -109,6 +109,8 @@ TraceWindow::TraceWindow(QWidget *parent)
|
||||
connect(this,SIGNAL(viewUpdated()), m_eventList, SLOT(complete()));
|
||||
m_view->rootContext()->setContextProperty("qmlEventList", m_eventList);
|
||||
|
||||
connect(this, SIGNAL(v8range(int,QString,QString,int,double,double)), m_eventList, SLOT(addV8Event(int,QString,QString,int,double,double)));
|
||||
|
||||
// Minimum height: 5 rows of 20 pixels + scrollbar of 50 pixels + 20 pixels margin
|
||||
setMinimumHeight(170);
|
||||
}
|
||||
@@ -116,18 +118,28 @@ TraceWindow::TraceWindow(QWidget *parent)
|
||||
TraceWindow::~TraceWindow()
|
||||
{
|
||||
delete m_plugin.data();
|
||||
delete m_v8plugin.data();
|
||||
}
|
||||
|
||||
void TraceWindow::reset(QDeclarativeDebugConnection *conn)
|
||||
{
|
||||
if (m_plugin)
|
||||
disconnect(m_plugin.data(), SIGNAL(complete()), this, SIGNAL(viewUpdated()));
|
||||
disconnect(m_plugin.data(), SIGNAL(complete()), this, SLOT(qmlComplete()));
|
||||
delete m_plugin.data();
|
||||
m_plugin = new QmlProfilerTraceClient(conn);
|
||||
connect(m_plugin.data(), SIGNAL(complete()), this, SIGNAL(viewUpdated()));
|
||||
connect(m_plugin.data(), SIGNAL(complete()), this, SLOT(qmlComplete()));
|
||||
connect(m_plugin.data(), SIGNAL(range(int,qint64,qint64,QStringList,QString,int)),
|
||||
this, SIGNAL(range(int,qint64,qint64,QStringList,QString,int)));
|
||||
|
||||
if (m_v8plugin) {
|
||||
disconnect(m_v8plugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
|
||||
disconnect(m_v8plugin.data(), SIGNAL(v8range(int,QString,QString,int,double,double)), this, SIGNAL(v8range(int,QString,QString,int,double,double)));
|
||||
}
|
||||
delete m_v8plugin.data();
|
||||
m_v8plugin = new QV8ProfilerClient(conn);
|
||||
connect(m_v8plugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
|
||||
connect(m_v8plugin.data(), SIGNAL(v8range(int,QString,QString,int,double,double)), this, SIGNAL(v8range(int,QString,QString,int,double,double)));
|
||||
|
||||
m_view->rootContext()->setContextProperty("connection", m_plugin.data());
|
||||
m_view->setSource(QUrl("qrc:/qmlprofiler/MainView.qml"));
|
||||
|
||||
@@ -142,6 +154,9 @@ void TraceWindow::reset(QDeclarativeDebugConnection *conn)
|
||||
connect(this, SIGNAL(zoomOut()), m_view->rootObject(), SLOT(zoomOut()));
|
||||
|
||||
connect(this, SIGNAL(internalClearDisplay()), m_view->rootObject(), SLOT(clearAll()));
|
||||
|
||||
m_v8DataReady = false;
|
||||
m_qmlDataReady = false;
|
||||
}
|
||||
|
||||
QmlProfilerEventList *TraceWindow::getEventList() const
|
||||
@@ -171,6 +186,8 @@ void TraceWindow::clearDisplay()
|
||||
|
||||
if (m_plugin)
|
||||
m_plugin.data()->clearData();
|
||||
if (m_v8plugin)
|
||||
m_v8plugin.data()->clearData();
|
||||
|
||||
emit internalClearDisplay();
|
||||
}
|
||||
@@ -182,8 +199,14 @@ void TraceWindow::updateToolbar()
|
||||
|
||||
void TraceWindow::setRecording(bool recording)
|
||||
{
|
||||
if (recording) {
|
||||
m_v8DataReady = false;
|
||||
m_qmlDataReady = false;
|
||||
}
|
||||
if (m_plugin)
|
||||
m_plugin.data()->setRecording(recording);
|
||||
if (m_v8plugin)
|
||||
m_v8plugin.data()->setRecording(recording);
|
||||
}
|
||||
|
||||
bool TraceWindow::isRecording() const
|
||||
@@ -191,5 +214,20 @@ bool TraceWindow::isRecording() const
|
||||
return m_plugin.data()->isRecording();
|
||||
}
|
||||
|
||||
void TraceWindow::qmlComplete()
|
||||
{
|
||||
m_qmlDataReady = true;
|
||||
|
||||
if (!m_v8plugin || m_v8plugin.data()->status() != QDeclarativeDebugClient::Enabled || m_v8DataReady)
|
||||
emit viewUpdated();
|
||||
}
|
||||
|
||||
void TraceWindow::v8Complete()
|
||||
{
|
||||
m_v8DataReady = true;
|
||||
if (!m_plugin || m_plugin.data()->status() != QDeclarativeDebugClient::Enabled || m_qmlDataReady)
|
||||
emit viewUpdated();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include <qmljsdebugclient/qmlprofilertraceclient.h>
|
||||
#include <qmljsdebugclient/qmlprofilereventlist.h>
|
||||
|
||||
#include <qmljsdebugclient/qv8profilerclient.h>
|
||||
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
@@ -68,12 +70,18 @@ public slots:
|
||||
void clearDisplay();
|
||||
void updateToolbar();
|
||||
|
||||
void qmlComplete();
|
||||
void v8Complete();
|
||||
|
||||
signals:
|
||||
void viewUpdated();
|
||||
void gotoSourceLocation(const QString &fileUrl, int lineNumber);
|
||||
void timeChanged(qreal newTime);
|
||||
void range(int type, qint64 startTime, qint64 length, const QStringList &data, const QString &fileName, int line);
|
||||
|
||||
void v8range(int depth,const QString &function,const QString &filename,
|
||||
int lineNumber, double totalTime, double selfTime);
|
||||
|
||||
void internalClearDisplay();
|
||||
void jumpToPrev();
|
||||
void jumpToNext();
|
||||
@@ -88,10 +96,13 @@ private:
|
||||
|
||||
private:
|
||||
QWeakPointer<QmlJsDebugClient::QmlProfilerTraceClient> m_plugin;
|
||||
QWeakPointer<QmlJsDebugClient::QV8ProfilerClient> m_v8plugin;
|
||||
QSize m_sizeHint;
|
||||
|
||||
QDeclarativeView *m_view;
|
||||
QmlJsDebugClient::QmlProfilerEventList *m_eventList;
|
||||
bool m_qmlDataReady;
|
||||
bool m_v8DataReady;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
Reference in New Issue
Block a user