forked from qt-creator/qt-creator
QmlProfiler: reworked
Change-Id: I66a236a024d76e7bef6edfb91ae30b5dd098b76b Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
@@ -6,6 +6,7 @@ QtcLibrary {
|
||||
|
||||
cpp.defines: base.concat("QMLDEBUG_LIB")
|
||||
|
||||
Depends { name: "cpp" }
|
||||
Depends { name: "Qt"; submodules: ["gui", "network"] }
|
||||
|
||||
files: [
|
||||
|
@@ -38,6 +38,8 @@ enum QmlEventType {
|
||||
Creating,
|
||||
Binding,
|
||||
HandlingSignal,
|
||||
PixmapCacheEvent,
|
||||
SceneGraphFrameEvent,
|
||||
|
||||
MaximumQmlEventType
|
||||
};
|
||||
@@ -46,6 +48,8 @@ enum BindingType {
|
||||
QmlBinding,
|
||||
V8Binding,
|
||||
OptimizedBinding,
|
||||
QPainterEvent,
|
||||
AnimationFrame,
|
||||
|
||||
MaximumBindingType
|
||||
};
|
||||
|
@@ -170,7 +170,8 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
|
||||
} else if (event == AnimationFrame) {
|
||||
int frameRate, animationCount;
|
||||
stream >> frameRate >> animationCount;
|
||||
emit this->frame(time, frameRate, animationCount);
|
||||
emit rangedEvent(QmlDebug::Painting, QmlDebug::AnimationFrame, time, 0,
|
||||
QStringList(), QmlDebug::QmlEventLocation(), frameRate, animationCount, 0,0,0);
|
||||
d->maximumTime = qMax(time, d->maximumTime);
|
||||
} else if (event == StartTrace) {
|
||||
emit this->traceStarted(time);
|
||||
@@ -181,6 +182,32 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
|
||||
}
|
||||
} else if (messageType == Complete) {
|
||||
emit complete();
|
||||
} else if (messageType == SceneGraphFrame) {
|
||||
int sgEventType;
|
||||
int count = 0;
|
||||
qint64 params[5];
|
||||
|
||||
stream >> sgEventType;
|
||||
while (!stream.atEnd()) {
|
||||
stream >> params[count++];
|
||||
}
|
||||
while (count<5)
|
||||
params[count++] = 0;
|
||||
emit rangedEvent(SceneGraphFrameEvent, sgEventType,time, 0, QStringList(),
|
||||
QmlDebug::QmlEventLocation(), params[0], params[1], params[2], params[3], params[4]);
|
||||
} else if (messageType == PixmapCacheEvent) {
|
||||
int pixEvTy, width = 0, height = 0, refcount = 0;
|
||||
QString pixUrl;
|
||||
stream >> pixEvTy >> pixUrl;
|
||||
if (pixEvTy == (int)PixmapReferenceCountChanged || pixEvTy == (int)PixmapCacheCountChanged) {
|
||||
stream >> refcount;
|
||||
} else if (pixEvTy == (int)PixmapSizeKnown) {
|
||||
stream >> width >> height;
|
||||
refcount = 1;
|
||||
}
|
||||
emit rangedEvent(QmlDebug::PixmapCacheEvent, pixEvTy, time, 0, QStringList(),
|
||||
QmlDebug::QmlEventLocation(pixUrl,0,0), width, height, refcount, 0, 0);
|
||||
d->maximumTime = qMax(time, d->maximumTime);
|
||||
} else {
|
||||
int range;
|
||||
stream >> range;
|
||||
@@ -240,7 +267,10 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
|
||||
BindingType bindingType = QmlBinding;
|
||||
if ((QmlEventType)range == Binding)
|
||||
bindingType = d->bindingTypes.pop();
|
||||
emit this->range((QmlEventType)range, bindingType, startTime, time - startTime, data, location);
|
||||
if ((QmlEventType)range == Painting)
|
||||
bindingType = QPainterEvent;
|
||||
emit rangedEvent((QmlEventType)range, bindingType, startTime, time - startTime, data,
|
||||
location, 0, 0, 0, 0, 0);
|
||||
if (d->rangeCount[range] == 0) {
|
||||
int count = d->rangeDatas[range].count() +
|
||||
d->rangeStartTimes[range].count() +
|
||||
|
@@ -71,10 +71,23 @@ public:
|
||||
RangeLocation,
|
||||
RangeEnd,
|
||||
Complete,
|
||||
PixmapCacheEvent,
|
||||
SceneGraphFrame,
|
||||
|
||||
MaximumMessage
|
||||
};
|
||||
|
||||
enum PixmapEventType {
|
||||
PixmapSizeKnown,
|
||||
PixmapReferenceCountChanged,
|
||||
PixmapCacheCountChanged,
|
||||
PixmapLoadingStarted,
|
||||
PixmapLoadingFinished,
|
||||
PixmapLoadingError,
|
||||
|
||||
MaximumPixmapEventType
|
||||
};
|
||||
|
||||
bool isEnabled() const;
|
||||
bool isRecording() const;
|
||||
void setRecording(bool);
|
||||
@@ -89,10 +102,9 @@ signals:
|
||||
void event(int event, qint64 time);
|
||||
void traceFinished( qint64 time );
|
||||
void traceStarted( qint64 time );
|
||||
void range(int type, int bindingType, qint64 startTime, qint64 length,
|
||||
const QStringList &data, const QmlDebug::QmlEventLocation &location);
|
||||
void frame(qint64 time, int frameRate, int animationCount);
|
||||
|
||||
void rangedEvent(int type, int bindingType, qint64 startTime, qint64 length,
|
||||
const QStringList &data, const QmlDebug::QmlEventLocation &location,
|
||||
qint64 param1, qint64 param2, qint64 param3, qint64 param4, qint64 param5);
|
||||
void recordingChanged(bool arg);
|
||||
|
||||
void enabledChanged();
|
||||
|
82
src/plugins/qmlprofiler/abstracttimelinemodel.cpp
Normal file
82
src/plugins/qmlprofiler/abstracttimelinemodel.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "abstracttimelinemodel.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
|
||||
AbstractTimelineModel::AbstractTimelineModel(QObject *parent) : QObject(parent), m_modelManager(0)
|
||||
{}
|
||||
|
||||
AbstractTimelineModel::~AbstractTimelineModel()
|
||||
{}
|
||||
|
||||
void AbstractTimelineModel::setModelManager(QmlProfilerModelManager *modelManager)
|
||||
{
|
||||
m_modelManager = modelManager;
|
||||
connect(modelManager->simpleModel(),SIGNAL(changed()),this,SLOT(dataChanged()));
|
||||
m_modelId = modelManager->registerModelProxy();
|
||||
}
|
||||
|
||||
qint64 AbstractTimelineModel::traceStartTime() const
|
||||
{
|
||||
return m_modelManager->traceTime()->startTime();
|
||||
}
|
||||
|
||||
qint64 AbstractTimelineModel::traceEndTime() const
|
||||
{
|
||||
return m_modelManager->traceTime()->endTime();
|
||||
}
|
||||
|
||||
qint64 AbstractTimelineModel::traceDuration() const
|
||||
{
|
||||
return m_modelManager->traceTime()->duration();
|
||||
}
|
||||
|
||||
int AbstractTimelineModel::getState() const
|
||||
{
|
||||
return (int)m_modelManager->state();
|
||||
}
|
||||
|
||||
int AbstractTimelineModel::rowCount() const
|
||||
{
|
||||
int count = 0;
|
||||
for (int i=0; i<categoryCount(); i++)
|
||||
count += categoryDepth(i);
|
||||
return count;
|
||||
}
|
||||
|
||||
int AbstractTimelineModel::getBindingLoopDest(int index) const
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
}
|
113
src/plugins/qmlprofiler/abstracttimelinemodel.h
Normal file
113
src/plugins/qmlprofiler/abstracttimelinemodel.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef ABSTRACTTIMELINEMODEL_H
|
||||
#define ABSTRACTTIMELINEMODEL_H
|
||||
|
||||
|
||||
#include "qmlprofiler_global.h"
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilersimplemodel.h"
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
#include <QColor>
|
||||
|
||||
namespace QmlProfiler {
|
||||
|
||||
class QMLPROFILER_EXPORT AbstractTimelineModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AbstractTimelineModel(QObject *parent = 0);
|
||||
~AbstractTimelineModel();
|
||||
|
||||
void setModelManager(QmlProfilerModelManager *modelManager);
|
||||
|
||||
virtual int categories() const = 0;
|
||||
virtual QStringList categoryTitles() const = 0;
|
||||
virtual QString name() const = 0;
|
||||
virtual int count() const = 0;
|
||||
|
||||
virtual bool isEmpty() const = 0;
|
||||
|
||||
virtual bool eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const = 0;
|
||||
|
||||
Q_INVOKABLE virtual qint64 lastTimeMark() const = 0;
|
||||
Q_INVOKABLE qint64 traceStartTime() const;
|
||||
Q_INVOKABLE qint64 traceEndTime() const;
|
||||
Q_INVOKABLE qint64 traceDuration() const;
|
||||
Q_INVOKABLE int getState() const;
|
||||
|
||||
Q_INVOKABLE virtual bool expanded(int category) const = 0;
|
||||
Q_INVOKABLE virtual void setExpanded(int category, bool expanded) = 0;
|
||||
Q_INVOKABLE virtual int categoryDepth(int categoryIndex) const = 0;
|
||||
Q_INVOKABLE virtual int categoryCount() const = 0;
|
||||
Q_INVOKABLE virtual int rowCount() const;
|
||||
Q_INVOKABLE virtual const QString categoryLabel(int categoryIndex) const = 0;
|
||||
|
||||
virtual int findFirstIndex(qint64 startTime) const = 0;
|
||||
virtual int findFirstIndexNoParents(qint64 startTime) const = 0;
|
||||
virtual int findLastIndex(qint64 endTime) const = 0;
|
||||
|
||||
virtual int getEventType(int index) const = 0;
|
||||
virtual int getEventCategory(int index) const = 0;
|
||||
virtual int getEventRow(int index) const = 0;
|
||||
Q_INVOKABLE virtual qint64 getDuration(int index) const = 0;
|
||||
Q_INVOKABLE virtual qint64 getStartTime(int index) const = 0;
|
||||
Q_INVOKABLE virtual qint64 getEndTime(int index) const = 0;
|
||||
Q_INVOKABLE virtual int getEventId(int index) const = 0;
|
||||
Q_INVOKABLE virtual int getBindingLoopDest(int index) const;
|
||||
Q_INVOKABLE virtual QColor getColor(int index) const = 0;
|
||||
Q_INVOKABLE virtual float getHeight(int index) const = 0;
|
||||
|
||||
Q_INVOKABLE virtual const QVariantList getLabelsForCategory(int category) const = 0;
|
||||
|
||||
Q_INVOKABLE virtual const QVariantList getEventDetails(int index) const = 0;
|
||||
|
||||
// returned map should contain "file", "line", "column" properties, or be empty
|
||||
Q_INVOKABLE virtual const QVariantMap getEventLocation(int index) const = 0;
|
||||
Q_INVOKABLE virtual int getEventIdForHash(const QString &eventHash) const = 0;
|
||||
Q_INVOKABLE virtual int getEventIdForLocation(const QString &filename, int line, int column) const = 0;
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
void dataAvailable();
|
||||
void stateChanged();
|
||||
void emptyChanged();
|
||||
void expandedChanged();
|
||||
|
||||
protected:
|
||||
QmlProfilerModelManager *m_modelManager;
|
||||
int m_modelId;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ABSTRACTTIMELINEMODEL_H
|
@@ -34,7 +34,6 @@ Item {
|
||||
id: detail
|
||||
property string label
|
||||
property string content
|
||||
signal linkActivated(string url)
|
||||
|
||||
height: childrenRect.height+2
|
||||
width: childrenRect.width
|
||||
@@ -55,7 +54,6 @@ Item {
|
||||
font.pixelSize: 12
|
||||
anchors.baseline: lbl.baseline
|
||||
anchors.left: guideline.right
|
||||
onLinkActivated: detail.linkActivated(link)
|
||||
textFormat: Text.PlainText
|
||||
}
|
||||
}
|
||||
|
@@ -31,23 +31,24 @@ import QtQuick 1.0
|
||||
|
||||
Item {
|
||||
id: labelContainer
|
||||
property alias text: txt.text
|
||||
property string text: qmlProfilerModelProxy.categoryLabel(modelIndex, categoryIndex)
|
||||
property bool expanded: false
|
||||
property int typeIndex: index
|
||||
property int categoryIndex: qmlProfilerModelProxy.correctedCategoryIndexForModel(modelIndex, index)
|
||||
property int modelIndex: qmlProfilerModelProxy.modelIndexForCategory(index);
|
||||
|
||||
property variant descriptions: []
|
||||
property variant extdescriptions: []
|
||||
property variant eventIds: []
|
||||
|
||||
visible: qmlProfilerModelProxy.categoryDepth(modelIndex, categoryIndex) > 0;
|
||||
|
||||
height: root.singleRowHeight
|
||||
width: 150
|
||||
|
||||
onExpandedChanged: {
|
||||
var rE = labels.rowExpanded;
|
||||
rE[typeIndex] = expanded;
|
||||
labels.rowExpanded = rE;
|
||||
qmlProfilerModelProxy.setExpanded(modelIndex, categoryIndex, expanded);
|
||||
backgroundMarks.requestRedraw();
|
||||
view.setRowExpanded(typeIndex, expanded);
|
||||
getDescriptions();
|
||||
updateHeight();
|
||||
}
|
||||
|
||||
@@ -56,20 +57,24 @@ Item {
|
||||
}
|
||||
|
||||
function updateHeight() {
|
||||
height = root.singleRowHeight * (1 +
|
||||
(expanded ? qmlProfilerDataModel.uniqueEventsOfType(typeIndex) :
|
||||
qmlProfilerDataModel.maxNestingForType(typeIndex)));
|
||||
if (expanded != qmlProfilerModelProxy.expanded(modelIndex, categoryIndex))
|
||||
expanded = qmlProfilerModelProxy.expanded(modelIndex, categoryIndex);
|
||||
height = root.singleRowHeight * qmlProfilerModelProxy.categoryDepth(modelIndex, categoryIndex);
|
||||
}
|
||||
|
||||
function getDescriptions() {
|
||||
visible = qmlProfilerModelProxy.categoryDepth(modelIndex, categoryIndex) > 0;
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
var desc=[];
|
||||
var ids=[];
|
||||
var extdesc=[];
|
||||
for (var i=0; i<qmlProfilerDataModel.uniqueEventsOfType(typeIndex); i++) {
|
||||
desc[i] = qmlProfilerDataModel.eventTextForType(typeIndex, i);
|
||||
ids[i] = qmlProfilerDataModel.eventIdForType(typeIndex, i);
|
||||
extdesc[i] = qmlProfilerDataModel.eventDisplayNameForType(typeIndex, i) +
|
||||
" : " + desc[i];
|
||||
var labelList = qmlProfilerModelProxy.getLabelsForCategory(modelIndex, categoryIndex);
|
||||
for (var i = 0; i < labelList.length; i++ ) {
|
||||
desc[i] = labelList[i].description;
|
||||
ids[i] = labelList[i].id;
|
||||
extdesc[i] = labelList[i].displayName + ":" + labelList[i].description;
|
||||
}
|
||||
descriptions = desc;
|
||||
eventIds = ids;
|
||||
@@ -78,20 +83,13 @@ Item {
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: qmlProfilerDataModel
|
||||
onReloadDetailLabels: getDescriptions();
|
||||
target: qmlProfilerModelProxy
|
||||
onExpandedChanged: {
|
||||
updateHeight();
|
||||
}
|
||||
|
||||
onStateChanged: {
|
||||
// Empty
|
||||
if (qmlProfilerDataModel.getCurrentStateFromQml() == 0) {
|
||||
descriptions = [];
|
||||
eventIds = [];
|
||||
extdescriptions = [];
|
||||
updateHeight();
|
||||
} else
|
||||
// Done
|
||||
if (qmlProfilerDataModel.getCurrentStateFromQml() == 3) {
|
||||
getDescriptions();
|
||||
}
|
||||
getDescriptions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +97,7 @@ Item {
|
||||
id: txt
|
||||
x: 5
|
||||
font.pixelSize: 12
|
||||
text: labelContainer.text
|
||||
color: "#232323"
|
||||
height: root.singleRowHeight
|
||||
width: 140
|
||||
@@ -140,9 +139,9 @@ Item {
|
||||
onExited: changeToolTip("");
|
||||
onClicked: {
|
||||
if (mouse.modifiers & Qt.ShiftModifier)
|
||||
view.selectPrevFromId(eventIds[index]);
|
||||
view.selectPrevFromId(modelIndex,eventIds[index]);
|
||||
else
|
||||
view.selectNextFromId(eventIds[index]);
|
||||
view.selectNextFromId(modelIndex,eventIds[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,7 +149,6 @@ Item {
|
||||
}
|
||||
|
||||
Image {
|
||||
visible: descriptions.length > 0
|
||||
source: expanded ? "arrow_down.png" : "arrow_right.png"
|
||||
x: parent.width - 12
|
||||
y: root.singleRowHeight / 2 - height / 2
|
||||
|
@@ -51,14 +51,6 @@ Rectangle {
|
||||
signal selectedEventChanged(int eventId)
|
||||
property bool lockItemSelection : false
|
||||
|
||||
property variant names: [ qsTr("Painting"),
|
||||
qsTr("Compiling"),
|
||||
qsTr("Creating"),
|
||||
qsTr("Binding"),
|
||||
qsTr("Handling Signal")]
|
||||
property variant colors : [ "#99CCB3", "#99CCCC", "#99B3CC",
|
||||
"#9999CC", "#CC99B3", "#CC99CC", "#CCCC99", "#CCB399" ]
|
||||
|
||||
property variant mainviewTimePerPixel : 0
|
||||
|
||||
signal updateCursorPosition
|
||||
@@ -95,7 +87,7 @@ Rectangle {
|
||||
backgroundMarks.updateMarks(startTime, endTime);
|
||||
view.updateFlickRange(startTime, endTime);
|
||||
if (duration > 0) {
|
||||
var candidateWidth = qmlProfilerDataModel.traceDuration() *
|
||||
var candidateWidth = qmlProfilerModelProxy.traceDuration() *
|
||||
flick.width / duration;
|
||||
if (flick.contentWidth !== candidateWidth)
|
||||
flick.contentWidth = candidateWidth;
|
||||
@@ -104,22 +96,23 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Connections {
|
||||
target: qmlProfilerDataModel
|
||||
target: qmlProfilerModelProxy
|
||||
onCountChanged: {
|
||||
eventCount = qmlProfilerDataModel.count();
|
||||
eventCount = qmlProfilerModelProxy.count();
|
||||
if (eventCount === 0)
|
||||
root.clearAll();
|
||||
if (eventCount > 1) {
|
||||
root.progress = Math.min(1.0,
|
||||
(qmlProfilerDataModel.lastTimeMark() -
|
||||
qmlProfilerDataModel.traceStartTime()) / root.elapsedTime * 1e-9 );
|
||||
(qmlProfilerModelProxy.lastTimeMark() -
|
||||
qmlProfilerModelProxy.traceStartTime()) / root.elapsedTime * 1e-9 );
|
||||
} else {
|
||||
root.progress = 0;
|
||||
}
|
||||
}
|
||||
onStateChanged: {
|
||||
switch (qmlProfilerDataModel.getCurrentStateFromQml()) {
|
||||
switch (qmlProfilerModelProxy.getState()) {
|
||||
case 0: {
|
||||
root.clearAll();
|
||||
break;
|
||||
@@ -132,27 +125,30 @@ Rectangle {
|
||||
root.progress = 0.9; // jump to 90%
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
view.clearData();
|
||||
progress = 1.0;
|
||||
dataAvailable = true;
|
||||
view.visible = true;
|
||||
view.requestPaint();
|
||||
zoomControl.setRange(qmlProfilerDataModel.traceStartTime(),
|
||||
qmlProfilerDataModel.traceStartTime() +
|
||||
qmlProfilerDataModel.traceDuration()/10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
onDataAvailable: {
|
||||
view.clearData();
|
||||
zoomControl.setRange(0,0);
|
||||
progress = 1.0;
|
||||
dataAvailable = true;
|
||||
view.visible = true;
|
||||
view.requestPaint();
|
||||
zoomControl.setRange(qmlProfilerModelProxy.traceStartTime(),
|
||||
qmlProfilerModelProxy.traceStartTime() +
|
||||
qmlProfilerModelProxy.traceDuration()/10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ***** functions
|
||||
function gotoSourceLocation(file,line,column) {
|
||||
root.fileName = file;
|
||||
root.lineNumber = line;
|
||||
root.columnNumber = column;
|
||||
root.updateCursorPosition();
|
||||
if (file !== undefined) {
|
||||
root.fileName = file;
|
||||
root.lineNumber = line;
|
||||
root.columnNumber = column;
|
||||
root.updateCursorPosition();
|
||||
}
|
||||
}
|
||||
|
||||
function clearData() {
|
||||
@@ -186,10 +182,10 @@ Rectangle {
|
||||
|
||||
function updateWindowLength(absoluteFactor) {
|
||||
var windowLength = view.endTime - view.startTime;
|
||||
if (qmlProfilerDataModel.traceEndTime() <= qmlProfilerDataModel.traceStartTime() ||
|
||||
if (qmlProfilerModelProxy.traceEndTime() <= qmlProfilerModelProxy.traceStartTime() ||
|
||||
windowLength <= 0)
|
||||
return;
|
||||
var currentFactor = windowLength / qmlProfilerDataModel.traceDuration();
|
||||
var currentFactor = windowLength / qmlProfilerModelProxy.traceDuration();
|
||||
updateZoom(absoluteFactor / currentFactor);
|
||||
}
|
||||
|
||||
@@ -200,8 +196,8 @@ Rectangle {
|
||||
windowLength = min_length;
|
||||
var newWindowLength = windowLength * relativeFactor;
|
||||
|
||||
if (newWindowLength > qmlProfilerDataModel.traceDuration()) {
|
||||
newWindowLength = qmlProfilerDataModel.traceDuration();
|
||||
if (newWindowLength > qmlProfilerModelProxy.traceDuration()) {
|
||||
newWindowLength = qmlProfilerModelProxy.traceDuration();
|
||||
relativeFactor = newWindowLength / windowLength;
|
||||
}
|
||||
if (newWindowLength < min_length) {
|
||||
@@ -210,13 +206,15 @@ Rectangle {
|
||||
}
|
||||
|
||||
var fixedPoint = (view.startTime + view.endTime) / 2;
|
||||
|
||||
if (view.selectedItem !== -1) {
|
||||
// center on selected item if it's inside the current screen
|
||||
var newFixedPoint = qmlProfilerDataModel.getStartTime(view.selectedItem);
|
||||
var newFixedPoint = qmlProfilerModelProxy.getStartTime(view.selectedModel, view.selectedItem);
|
||||
if (newFixedPoint >= view.startTime && newFixedPoint < view.endTime)
|
||||
fixedPoint = newFixedPoint;
|
||||
}
|
||||
|
||||
|
||||
var startTime = fixedPoint - relativeFactor*(fixedPoint - view.startTime);
|
||||
zoomControl.setRange(startTime, startTime + newWindowLength);
|
||||
}
|
||||
@@ -229,8 +227,8 @@ Rectangle {
|
||||
windowLength = min_length;
|
||||
var newWindowLength = windowLength * relativeFactor;
|
||||
|
||||
if (newWindowLength > qmlProfilerDataModel.traceDuration()) {
|
||||
newWindowLength = qmlProfilerDataModel.traceDuration();
|
||||
if (newWindowLength > qmlProfilerModelProxy.traceDuration()) {
|
||||
newWindowLength = qmlProfilerModelProxy.traceDuration();
|
||||
relativeFactor = newWindowLength / windowLength;
|
||||
}
|
||||
if (newWindowLength < min_length) {
|
||||
@@ -248,26 +246,27 @@ Rectangle {
|
||||
var newStart = Math.floor(centerPoint - windowLength/2);
|
||||
if (newStart < 0)
|
||||
newStart = 0;
|
||||
if (newStart + windowLength > qmlProfilerDataModel.traceEndTime())
|
||||
newStart = qmlProfilerDataModel.traceEndTime() - windowLength;
|
||||
if (newStart + windowLength > qmlProfilerModelProxy.traceEndTime())
|
||||
newStart = qmlProfilerModelProxy.traceEndTime() - windowLength;
|
||||
zoomControl.setRange(newStart, newStart + windowLength);
|
||||
}
|
||||
|
||||
function recenterOnItem( itemIndex )
|
||||
function recenterOnItem( modelIndex, itemIndex )
|
||||
{
|
||||
if (itemIndex === -1)
|
||||
return;
|
||||
|
||||
// if item is outside of the view, jump back to its position
|
||||
if (qmlProfilerDataModel.getEndTime(itemIndex) < view.startTime ||
|
||||
qmlProfilerDataModel.getStartTime(itemIndex) > view.endTime) {
|
||||
recenter((qmlProfilerDataModel.getStartTime(itemIndex) +
|
||||
qmlProfilerDataModel.getEndTime(itemIndex)) / 2);
|
||||
if (qmlProfilerModelProxy.getEndTime(modelIndex, itemIndex) < view.startTime ||
|
||||
qmlProfilerModelProxy.getStartTime(modelIndex, itemIndex) > view.endTime) {
|
||||
recenter((qmlProfilerModelProxy.getStartTime(modelIndex, itemIndex) +
|
||||
qmlProfilerModelProxy.getEndTime(modelIndex, itemIndex)) / 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function wheelZoom(wheelCenter, wheelDelta) {
|
||||
if (qmlProfilerDataModel.traceEndTime() > qmlProfilerDataModel.traceStartTime() &&
|
||||
if (qmlProfilerModelProxy.traceEndTime() > qmlProfilerModelProxy.traceStartTime() &&
|
||||
wheelDelta !== 0) {
|
||||
if (wheelDelta>0)
|
||||
updateZoomCentered(wheelCenter, 1/1.2);
|
||||
@@ -280,24 +279,35 @@ Rectangle {
|
||||
rangeDetails.visible = false;
|
||||
rangeDetails.duration = "";
|
||||
rangeDetails.label = "";
|
||||
rangeDetails.type = "";
|
||||
//rangeDetails.type = "";
|
||||
rangeDetails.file = "";
|
||||
rangeDetails.line = -1;
|
||||
rangeDetails.column = 0;
|
||||
rangeDetails.isBindingLoop = false;
|
||||
}
|
||||
|
||||
function selectNextWithId( eventId )
|
||||
function selectNextByHash(hash) {
|
||||
var eventId = qmlProfilerModelProxy.getEventIdForHash(hash);
|
||||
if (eventId !== -1) {
|
||||
selectNextById(eventId);
|
||||
}
|
||||
}
|
||||
|
||||
function selectNextById(eventId)
|
||||
{
|
||||
// this is a slot responding to events from the other pane
|
||||
// which tracks only events from the basic model
|
||||
if (!lockItemSelection) {
|
||||
lockItemSelection = true;
|
||||
var itemIndex = view.nextItemFromId( eventId );
|
||||
var modelIndex = qmlProfilerModelProxy.basicModelIndex();
|
||||
var itemIndex = view.nextItemFromId( modelIndex, eventId );
|
||||
// select an item, lock to it, and recenter if necessary
|
||||
if (view.selectedItem != itemIndex) {
|
||||
if (view.selectedItem != itemIndex || view.selectedModel != modelIndex) {
|
||||
view.selectedModel = modelIndex;
|
||||
view.selectedItem = itemIndex;
|
||||
if (itemIndex !== -1) {
|
||||
view.selectionLocked = true;
|
||||
recenterOnItem(itemIndex);
|
||||
recenterOnItem(modelIndex, itemIndex);
|
||||
}
|
||||
}
|
||||
lockItemSelection = false;
|
||||
@@ -317,7 +327,9 @@ Rectangle {
|
||||
onSelectedItemChanged: {
|
||||
if (selectedItem != -1 && !lockItemSelection) {
|
||||
lockItemSelection = true;
|
||||
selectedEventChanged( qmlProfilerDataModel.getEventId(selectedItem) );
|
||||
// update in other views
|
||||
var eventLocation = qmlProfilerModelProxy.getEventLocation(view.selectedModel, view.selectedItem);
|
||||
gotoSourceLocation(eventLocation.file, eventLocation.line, eventLocation.column);
|
||||
lockItemSelection = false;
|
||||
}
|
||||
}
|
||||
@@ -392,7 +404,7 @@ Rectangle {
|
||||
TimelineRenderer {
|
||||
id: view
|
||||
|
||||
profilerDataModel: qmlProfilerDataModel
|
||||
profilerModelProxy: qmlProfilerModelProxy
|
||||
|
||||
x: flick.contentX
|
||||
width: flick.width
|
||||
@@ -401,12 +413,12 @@ Rectangle {
|
||||
property variant startX: 0
|
||||
onStartXChanged: {
|
||||
var newStartTime = Math.round(startX * (endTime - startTime) / flick.width) +
|
||||
qmlProfilerDataModel.traceStartTime();
|
||||
qmlProfilerModelProxy.traceStartTime();
|
||||
if (Math.abs(newStartTime - startTime) > 1) {
|
||||
var newEndTime = Math.round((startX+flick.width) *
|
||||
(endTime - startTime) /
|
||||
flick.width) +
|
||||
qmlProfilerDataModel.traceStartTime();
|
||||
qmlProfilerModelProxy.traceStartTime();
|
||||
zoomControl.setRange(newStartTime, newEndTime);
|
||||
}
|
||||
|
||||
@@ -418,7 +430,7 @@ Rectangle {
|
||||
if (start !== startTime || end !== endTime) {
|
||||
startTime = start;
|
||||
endTime = end;
|
||||
var newStartX = (startTime - qmlProfilerDataModel.traceStartTime()) *
|
||||
var newStartX = (startTime - qmlProfilerModelProxy.traceStartTime()) *
|
||||
flick.width / (endTime-startTime);
|
||||
if (Math.abs(newStartX - startX) >= 1)
|
||||
startX = newStartX;
|
||||
@@ -428,32 +440,26 @@ Rectangle {
|
||||
onSelectedItemChanged: {
|
||||
if (selectedItem !== -1) {
|
||||
// display details
|
||||
rangeDetails.duration = qmlProfilerDataModel.getDuration(selectedItem)/1000.0;
|
||||
rangeDetails.label = qmlProfilerDataModel.getDetails(selectedItem);
|
||||
rangeDetails.file = qmlProfilerDataModel.getFilename(selectedItem);
|
||||
rangeDetails.line = qmlProfilerDataModel.getLine(selectedItem);
|
||||
rangeDetails.column = qmlProfilerDataModel.getColumn(selectedItem);
|
||||
rangeDetails.type = root.names[qmlProfilerDataModel.getType(selectedItem)];
|
||||
rangeDetails.isBindingLoop = qmlProfilerDataModel.getBindingLoopDest(selectedItem)!==-1;
|
||||
|
||||
rangeDetails.visible = true;
|
||||
rangeDetails.showInfo(qmlProfilerModelProxy.getEventDetails(selectedModel, selectedItem));
|
||||
rangeDetails.setLocation(qmlProfilerModelProxy.getEventLocation(selectedModel, selectedItem));
|
||||
|
||||
// center view (horizontally)
|
||||
var windowLength = view.endTime - view.startTime;
|
||||
var eventStartTime = qmlProfilerDataModel.getStartTime(selectedItem);
|
||||
var eventStartTime = qmlProfilerModelProxy.getStartTime(selectedModel, selectedItem);
|
||||
var eventEndTime = eventStartTime +
|
||||
qmlProfilerDataModel.getDuration(selectedItem);
|
||||
qmlProfilerModelProxy.getDuration(selectedModel, selectedItem);
|
||||
|
||||
if (eventEndTime < view.startTime || eventStartTime > view.endTime) {
|
||||
var center = (eventStartTime + eventEndTime)/2;
|
||||
var from = Math.min(qmlProfilerDataModel.traceEndTime()-windowLength,
|
||||
var from = Math.min(qmlProfilerModelProxy.traceEndTime()-windowLength,
|
||||
Math.max(0, Math.floor(center - windowLength/2)));
|
||||
|
||||
zoomControl.setRange(from, from + windowLength);
|
||||
|
||||
}
|
||||
|
||||
// center view (vertically)
|
||||
var itemY = view.getYPosition(selectedItem);
|
||||
var itemY = view.getYPosition(selectedModel, selectedItem);
|
||||
if (itemY < root.scrollY) {
|
||||
root.updateVerticalScroll(itemY);
|
||||
} else
|
||||
@@ -462,17 +468,16 @@ Rectangle {
|
||||
root.updateVerticalScroll(itemY + root.singleRowHeight -
|
||||
root.candidateHeight);
|
||||
}
|
||||
|
||||
} else {
|
||||
root.hideRangeDetails();
|
||||
}
|
||||
}
|
||||
|
||||
onItemPressed: {
|
||||
if (pressedItem !== -1) {
|
||||
root.gotoSourceLocation(qmlProfilerDataModel.getFilename(pressedItem),
|
||||
qmlProfilerDataModel.getLine(pressedItem),
|
||||
qmlProfilerDataModel.getColumn(pressedItem));
|
||||
}
|
||||
var location = qmlProfilerModelProxy.getEventLocation(modelIndex, pressedItem);
|
||||
if (location.hasOwnProperty("file")) // not empty
|
||||
root.gotoSourceLocation(location.file, location.line, location.column);
|
||||
}
|
||||
|
||||
// hack to pass mouse events to the other mousearea if enabled
|
||||
@@ -522,17 +527,13 @@ Rectangle {
|
||||
color: "#dcdcdc"
|
||||
height: col.height
|
||||
|
||||
property int rowCount: 5
|
||||
property variant rowExpanded: [false,false,false,false,false];
|
||||
property int rowCount: qmlProfilerModelProxy.categories();
|
||||
|
||||
Column {
|
||||
id: col
|
||||
Repeater {
|
||||
model: labels.rowCount
|
||||
delegate: Label {
|
||||
text: root.names[index]
|
||||
height: labels.height/labels.rowCount
|
||||
}
|
||||
delegate: Label { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@
|
||||
|
||||
.pragma library
|
||||
|
||||
var qmlProfilerDataModel = 0;
|
||||
var qmlProfilerModelProxy = 0;
|
||||
|
||||
//draw background of the graph
|
||||
function drawGraph(canvas, ctxt, region)
|
||||
@@ -41,89 +41,82 @@ function drawGraph(canvas, ctxt, region)
|
||||
//draw the actual data to be graphed
|
||||
function drawData(canvas, ctxt, region)
|
||||
{
|
||||
if ((!qmlProfilerDataModel) || qmlProfilerDataModel.count() == 0)
|
||||
if ((!qmlProfilerModelProxy) || qmlProfilerModelProxy.count() == 0)
|
||||
return;
|
||||
|
||||
var typeCount = 5;
|
||||
var width = canvas.width;
|
||||
var bump = 10;
|
||||
var height = canvas.height - bump;
|
||||
|
||||
var typeCount = qmlProfilerModelProxy.visibleCategories();
|
||||
var blockHeight = height / typeCount;
|
||||
|
||||
var spacing = width / qmlProfilerDataModel.traceDuration();
|
||||
var spacing = width / qmlProfilerModelProxy.traceDuration();
|
||||
|
||||
var highest = [0,0,0,0,0]; // note: change if typeCount changes
|
||||
var modelRowStart = 0;
|
||||
for (var modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); modelIndex++) {
|
||||
for (var ii = 0; ii < qmlProfilerModelProxy.count(modelIndex); ++ii) {
|
||||
|
||||
for (var ii = 0; ii < qmlProfilerDataModel.count(); ++ii) {
|
||||
var xx = (qmlProfilerModelProxy.getStartTime(modelIndex,ii) -
|
||||
qmlProfilerModelProxy.traceStartTime()) * spacing;
|
||||
if (xx > region.x + region.width)
|
||||
continue;
|
||||
|
||||
var xx = (qmlProfilerDataModel.getStartTime(ii) -
|
||||
qmlProfilerDataModel.traceStartTime()) * spacing;
|
||||
if (xx > region.x + region.width)
|
||||
continue;
|
||||
var eventWidth = qmlProfilerModelProxy.getDuration(modelIndex,ii) * spacing;
|
||||
if (xx + eventWidth < region.x)
|
||||
continue;
|
||||
|
||||
var eventWidth = qmlProfilerDataModel.getDuration(ii) * spacing;
|
||||
if (xx + eventWidth < region.x)
|
||||
continue;
|
||||
if (eventWidth < 1)
|
||||
eventWidth = 1;
|
||||
|
||||
if (eventWidth < 1)
|
||||
eventWidth = 1;
|
||||
xx = Math.round(xx);
|
||||
|
||||
xx = Math.round(xx);
|
||||
var ty = qmlProfilerDataModel.getType(ii);
|
||||
if (xx + eventWidth > highest[ty]) {
|
||||
// special: animations
|
||||
if (ty === 0 && qmlProfilerDataModel.getAnimationCount(ii) >= 0) {
|
||||
var vertScale = qmlProfilerDataModel.getMaximumAnimationCount() -
|
||||
qmlProfilerDataModel.getMinimumAnimationCount();
|
||||
if (vertScale < 1)
|
||||
vertScale = 1;
|
||||
var fraction = (qmlProfilerDataModel.getAnimationCount(ii) -
|
||||
qmlProfilerDataModel.getMinimumAnimationCount()) / vertScale;
|
||||
var eventHeight = blockHeight * (fraction * 0.85 + 0.15);
|
||||
var yy = bump + ty*blockHeight + blockHeight - eventHeight;
|
||||
var rowNumber = modelRowStart + qmlProfilerModelProxy.getEventCategoryInModel(modelIndex, ii);
|
||||
|
||||
var fpsFraction = qmlProfilerDataModel.getFramerate(ii) / 60.0;
|
||||
if (fpsFraction > 1.0)
|
||||
fpsFraction = 1.0;
|
||||
ctxt.fillStyle = "hsl("+(fpsFraction*0.27+0.028)+",0.3,0.65)";
|
||||
ctxt.fillRect(xx, yy, eventWidth, eventHeight);
|
||||
} else {
|
||||
var hue = ( qmlProfilerDataModel.getEventId(ii) * 25 ) % 360;
|
||||
ctxt.fillStyle = "hsl("+(hue/360.0+0.001)+",0.3,0.65)";
|
||||
ctxt.fillRect(xx, bump + ty*blockHeight, eventWidth, blockHeight);
|
||||
}
|
||||
highest[ty] = xx+eventWidth;
|
||||
var itemHeight = qmlProfilerModelProxy.getHeight(modelIndex,ii) * blockHeight;
|
||||
var yy = (rowNumber + 1) * blockHeight - itemHeight ;
|
||||
|
||||
var itemColor = qmlProfilerModelProxy.getColorRGB(modelIndex, ii);
|
||||
ctxt.fillStyle = "rgb("+itemColor[0]+","+itemColor[1]+","+itemColor[2]+")";
|
||||
ctxt.fillRect(xx, bump + yy, eventWidth, itemHeight);
|
||||
}
|
||||
modelRowStart += qmlProfilerModelProxy.categoryCount(modelIndex);
|
||||
}
|
||||
|
||||
// binding loops
|
||||
ctxt.strokeStyle = "orange";
|
||||
ctxt.lineWidth = 2;
|
||||
var radius = 1;
|
||||
for (var ii = 0; ii < qmlProfilerDataModel.count(); ++ii) {
|
||||
if (qmlProfilerDataModel.getBindingLoopDest(ii) >= 0) {
|
||||
var xcenter = Math.round(qmlProfilerDataModel.getStartTime(ii) +
|
||||
qmlProfilerDataModel.getDuration(ii) -
|
||||
qmlProfilerDataModel.traceStartTime()) * spacing;
|
||||
var ycenter = Math.round(bump + qmlProfilerDataModel.getType(ii) *
|
||||
blockHeight + blockHeight/2);
|
||||
ctxt.arc(xcenter, ycenter, radius, 0, 2*Math.PI, true);
|
||||
ctxt.stroke();
|
||||
modelRowStart = 0;
|
||||
for (modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); modelIndex++) {
|
||||
for (ii = 0; ii < qmlProfilerModelProxy.count(modelIndex); ++ii) {
|
||||
if (qmlProfilerModelProxy.getBindingLoopDest(modelIndex,ii) >= 0) {
|
||||
var xcenter = Math.round(qmlProfilerModelProxy.getStartTime(modelIndex,ii) +
|
||||
qmlProfilerModelProxy.getDuration(modelIndex,ii) -
|
||||
qmlProfilerModelProxy.traceStartTime()) * spacing;
|
||||
var ycenter = Math.round(bump + (modelRowStart +
|
||||
qmlProfilerModelProxy.getEventCategoryInModel(modelIndex, ii)) *
|
||||
blockHeight + blockHeight/2);
|
||||
ctxt.arc(xcenter, ycenter, radius, 0, 2*Math.PI, true);
|
||||
ctxt.stroke();
|
||||
}
|
||||
}
|
||||
modelRowStart += qmlProfilerModelProxy.categoryCount(modelIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function drawTimeBar(canvas, ctxt, region)
|
||||
{
|
||||
if (!qmlProfilerDataModel)
|
||||
if (!qmlProfilerModelProxy)
|
||||
return;
|
||||
|
||||
var width = canvas.width;
|
||||
var height = 10;
|
||||
var startTime = qmlProfilerDataModel.traceStartTime();
|
||||
var endTime = qmlProfilerDataModel.traceEndTime();
|
||||
var startTime = qmlProfilerModelProxy.traceStartTime();
|
||||
var endTime = qmlProfilerModelProxy.traceEndTime();
|
||||
|
||||
var totalTime = qmlProfilerDataModel.traceDuration();
|
||||
var totalTime = qmlProfilerModelProxy.traceDuration();
|
||||
var spacing = width / totalTime;
|
||||
|
||||
var initialBlockLength = 120;
|
||||
|
@@ -36,36 +36,37 @@ Canvas2D {
|
||||
|
||||
// ***** properties
|
||||
height: 50
|
||||
property bool dataAvailable: false
|
||||
property bool dataReady: false
|
||||
property variant startTime : 0
|
||||
property variant endTime : 0
|
||||
|
||||
// ***** functions
|
||||
function clearDisplay()
|
||||
{
|
||||
dataAvailable = false;
|
||||
dataReady = false;
|
||||
requestRedraw();
|
||||
}
|
||||
|
||||
function updateRange() {
|
||||
var newStartTime = Math.round(rangeMover.x * qmlProfilerDataModel.traceDuration() / width) + qmlProfilerDataModel.traceStartTime();
|
||||
var newEndTime = Math.round((rangeMover.x + rangeMover.width) * qmlProfilerDataModel.traceDuration() / width) + qmlProfilerDataModel.traceStartTime();
|
||||
var newStartTime = Math.round(rangeMover.x * qmlProfilerModelProxy.traceDuration() / width) + qmlProfilerModelProxy.traceStartTime();
|
||||
var newEndTime = Math.round((rangeMover.x + rangeMover.width) * qmlProfilerModelProxy.traceDuration() / width) + qmlProfilerModelProxy.traceStartTime();
|
||||
if (startTime !== newStartTime || endTime !== newEndTime) {
|
||||
zoomControl.setRange(newStartTime, newEndTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ***** connections to external objects
|
||||
Connections {
|
||||
target: zoomControl
|
||||
onRangeChanged: {
|
||||
if (qmlProfilerDataModel) {
|
||||
if (qmlProfilerModelProxy) {
|
||||
startTime = zoomControl.startTime();
|
||||
endTime = zoomControl.endTime();
|
||||
var newRangeX = (startTime - qmlProfilerDataModel.traceStartTime()) * width / qmlProfilerDataModel.traceDuration();
|
||||
var newRangeX = (startTime - qmlProfilerModelProxy.traceStartTime()) * width / qmlProfilerModelProxy.traceDuration();
|
||||
if (rangeMover.x !== newRangeX)
|
||||
rangeMover.x = newRangeX;
|
||||
var newWidth = (endTime-startTime) * width / qmlProfilerDataModel.traceDuration();
|
||||
var newWidth = (endTime-startTime) * width / qmlProfilerModelProxy.traceDuration();
|
||||
if (rangeMover.width !== newWidth)
|
||||
rangeMover.width = newWidth;
|
||||
}
|
||||
@@ -73,20 +74,18 @@ Canvas2D {
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: qmlProfilerDataModel
|
||||
onStateChanged: {
|
||||
// State is "done"
|
||||
if (qmlProfilerDataModel.getCurrentStateFromQml() == 3) {
|
||||
dataAvailable = true;
|
||||
target: qmlProfilerModelProxy
|
||||
onDataAvailable: {
|
||||
dataReady = true;
|
||||
requestRedraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ***** slots
|
||||
onDrawRegion: {
|
||||
Plotter.qmlProfilerDataModel = qmlProfilerDataModel;
|
||||
if (dataAvailable) {
|
||||
Plotter.qmlProfilerModelProxy = qmlProfilerModelProxy;
|
||||
if (dataReady) {
|
||||
Plotter.plot(canvas, ctxt, region);
|
||||
} else {
|
||||
Plotter.drawGraph(canvas, ctxt, region) //just draw the background
|
||||
@@ -116,7 +115,7 @@ Canvas2D {
|
||||
|
||||
RangeMover {
|
||||
id: rangeMover
|
||||
visible: dataAvailable
|
||||
visible: dataReady
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
@@ -35,7 +35,7 @@ Item {
|
||||
|
||||
property string duration
|
||||
property string label
|
||||
property string type
|
||||
property string dialogTitle
|
||||
property string file
|
||||
property int line
|
||||
property int column
|
||||
@@ -65,6 +65,36 @@ Item {
|
||||
onCandidateHeightChanged: fitInView();
|
||||
}
|
||||
|
||||
//property variant eventInfo
|
||||
|
||||
ListModel {
|
||||
id: eventInfo
|
||||
}
|
||||
|
||||
function showInfo(eventData) {
|
||||
eventInfo.clear();
|
||||
rangeDetails.dialogTitle = eventData[0]["title"];
|
||||
for (var i = 1; i < eventData.length; i++) {
|
||||
for (var k in eventData[i]) {
|
||||
eventInfo.append({"key": k, "value":eventData[i][k]});
|
||||
}
|
||||
}
|
||||
rangeDetails.visible = true;
|
||||
}
|
||||
|
||||
function setLocation(location) {
|
||||
if (location.hasOwnProperty("file")) { // not empty
|
||||
file = location.file;
|
||||
line = location.line;
|
||||
column = location.column;
|
||||
} else {
|
||||
// reset to default values
|
||||
file = "";
|
||||
line = 0;
|
||||
column = -1;
|
||||
}
|
||||
}
|
||||
|
||||
function fitInView() {
|
||||
// don't reposition if it does not fit
|
||||
if (root.width < width || root.candidateHeight < height)
|
||||
@@ -122,7 +152,7 @@ Item {
|
||||
//title
|
||||
Text {
|
||||
id: typeTitle
|
||||
text: " "+rangeDetails.type
|
||||
text: " "+rangeDetails.dialogTitle
|
||||
font.bold: true
|
||||
height: 18
|
||||
y: 2
|
||||
@@ -145,42 +175,14 @@ Item {
|
||||
id: col
|
||||
x: 10
|
||||
y: 5
|
||||
Detail {
|
||||
label: qsTr("Duration:")
|
||||
content: rangeDetails.duration < 1000 ? rangeDetails.duration + "μs" : Math.floor(rangeDetails.duration/10)/100 + "ms"
|
||||
}
|
||||
Detail {
|
||||
opacity: content.length !== 0 ? 1 : 0
|
||||
label: qsTr("Details:")
|
||||
content: {
|
||||
var inputString = rangeDetails.label;
|
||||
if (inputString.length > 7 && inputString.substring(0,7) == "file://") {
|
||||
var pos = inputString.lastIndexOf("/");
|
||||
return inputString.substr(pos+1);
|
||||
}
|
||||
var maxLen = 40;
|
||||
if (inputString.length > maxLen)
|
||||
inputString = inputString.substring(0,maxLen)+"...";
|
||||
|
||||
return inputString;
|
||||
Repeater {
|
||||
model: eventInfo
|
||||
Detail {
|
||||
label: key
|
||||
content: value
|
||||
}
|
||||
}
|
||||
Detail {
|
||||
opacity: content.length !== 0 ? 1 : 0
|
||||
label: qsTr("Location:")
|
||||
content: {
|
||||
var file = rangeDetails.file;
|
||||
var pos = file.lastIndexOf("/");
|
||||
if (pos != -1)
|
||||
file = file.substr(pos+1);
|
||||
return (file.length !== 0) ? (file + ":" + rangeDetails.line) : "";
|
||||
}
|
||||
}
|
||||
Detail {
|
||||
visible: isBindingLoop
|
||||
opacity: content.length != 0 ? 1 : 0
|
||||
label: qsTr("Binding loop detected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +196,7 @@ Item {
|
||||
drag.maximumY: root.candidateHeight - parent.height + yoffset
|
||||
onClicked: {
|
||||
root.gotoSourceLocation(file, line, column);
|
||||
root.recenterOnItem(view.selectedItem);
|
||||
root.recenterOnItem(view.selectedModel, view.selectedItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -47,7 +47,7 @@ Rectangle {
|
||||
property string endTimeString: detailedPrintTime(startTime+duration)
|
||||
property string durationString: detailedPrintTime(duration)
|
||||
|
||||
property variant startTime: x * selectionRange.viewTimePerPixel + qmlProfilerDataModel.traceStartTime()
|
||||
property variant startTime: x * selectionRange.viewTimePerPixel + qmlProfilerModelProxy.traceStartTime()
|
||||
property variant duration: width * selectionRange.viewTimePerPixel
|
||||
property variant viewTimePerPixel: 1
|
||||
property variant creationState : 0
|
||||
|
@@ -48,6 +48,11 @@ Canvas2D {
|
||||
requestRedraw();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: labels
|
||||
onHeightChanged: { requestRedraw(); }
|
||||
}
|
||||
|
||||
onDrawRegion: {
|
||||
drawBackgroundBars( ctxt, region );
|
||||
|
||||
@@ -86,19 +91,21 @@ Canvas2D {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// gray off out-of-bounds areas
|
||||
var rectWidth;
|
||||
if (startTime < qmlProfilerDataModel.traceStartTime()) {
|
||||
if (startTime < qmlProfilerModelProxy.traceStartTime()) {
|
||||
ctxt.fillStyle = "rgba(127,127,127,0.2)";
|
||||
rectWidth = (qmlProfilerDataModel.traceStartTime() - startTime) * spacing;
|
||||
rectWidth = (qmlProfilerModelProxy.traceStartTime() - startTime) * spacing;
|
||||
ctxt.fillRect(0, 0, rectWidth, height);
|
||||
}
|
||||
if (endTime > qmlProfilerDataModel.traceEndTime()) {
|
||||
if (endTime > qmlProfilerModelProxy.traceEndTime()) {
|
||||
ctxt.fillStyle = "rgba(127,127,127,0.2)";
|
||||
var rectX = (qmlProfilerDataModel.traceEndTime() - startTime) * spacing;
|
||||
rectWidth = (endTime - qmlProfilerDataModel.traceEndTime()) * spacing;
|
||||
var rectX = (qmlProfilerModelProxy.traceEndTime() - startTime) * spacing;
|
||||
rectWidth = (endTime - qmlProfilerModelProxy.traceEndTime()) * spacing;
|
||||
ctxt.fillRect(rectX, 0, rectWidth, height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function updateMarks(start, end) {
|
||||
@@ -121,16 +128,16 @@ Canvas2D {
|
||||
|
||||
// separators
|
||||
var cumulatedHeight = 0;
|
||||
for (var i=0; i<labels.rowCount; i++) {
|
||||
cumulatedHeight += root.singleRowHeight + (labels.rowExpanded[i] ?
|
||||
qmlProfilerDataModel.uniqueEventsOfType(i) * root.singleRowHeight :
|
||||
qmlProfilerDataModel.maxNestingForType(i) * root.singleRowHeight);
|
||||
for (var modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); modelIndex++) {
|
||||
for (var i=0; i<qmlProfilerModelProxy.categoryCount(modelIndex); i++) {
|
||||
cumulatedHeight += root.singleRowHeight * qmlProfilerModelProxy.categoryDepth(modelIndex, i);
|
||||
|
||||
ctxt.strokeStyle = "#B0B0B0";
|
||||
ctxt.beginPath();
|
||||
ctxt.moveTo(0, cumulatedHeight);
|
||||
ctxt.lineTo(width, cumulatedHeight);
|
||||
ctxt.stroke();
|
||||
ctxt.strokeStyle = "#B0B0B0";
|
||||
ctxt.beginPath();
|
||||
ctxt.moveTo(0, cumulatedHeight);
|
||||
ctxt.lineTo(width, cumulatedHeight);
|
||||
ctxt.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// bottom
|
||||
|
@@ -12,16 +12,26 @@ SOURCES += \
|
||||
qmlprofilerattachdialog.cpp \
|
||||
localqmlprofilerrunner.cpp \
|
||||
qmlprofilereventview.cpp \
|
||||
qv8profilereventview.cpp \
|
||||
qmlprofilerdetailsrewriter.cpp \
|
||||
qmlprofilertraceview.cpp \
|
||||
timelinerenderer.cpp \
|
||||
qmlprofilerstatemanager.cpp \
|
||||
qv8profilerdatamodel.cpp \
|
||||
qmlprofilerdatamodel.cpp \
|
||||
qmlprofilerclientmanager.cpp \
|
||||
qmlprofilerviewmanager.cpp \
|
||||
qmlprofilerstatewidget.cpp \
|
||||
qmlprofilerruncontrolfactory.cpp
|
||||
qmlprofilerruncontrolfactory.cpp \
|
||||
qmlprofilermodelmanager.cpp \
|
||||
qmlprofilersimplemodel.cpp \
|
||||
qmlprofilerprocessedmodel.cpp \
|
||||
qmlprofilereventsmodelproxy.cpp \
|
||||
qmlprofilertimelinemodelproxy.cpp \
|
||||
qmlprofilertreeview.cpp \
|
||||
qmlprofilertracefile.cpp \
|
||||
abstracttimelinemodel.cpp \
|
||||
timelinemodelaggregator.cpp \
|
||||
qmlprofilerpainteventsmodelproxy.cpp
|
||||
|
||||
HEADERS += \
|
||||
qmlprofilerconstants.h \
|
||||
@@ -33,16 +43,26 @@ HEADERS += \
|
||||
abstractqmlprofilerrunner.h \
|
||||
localqmlprofilerrunner.h \
|
||||
qmlprofilereventview.h \
|
||||
qv8profilereventview.h \
|
||||
qmlprofilerdetailsrewriter.h \
|
||||
qmlprofilertraceview.h \
|
||||
timelinerenderer.h \
|
||||
qmlprofilerstatemanager.h \
|
||||
qv8profilerdatamodel.h \
|
||||
qmlprofilerdatamodel.h \
|
||||
qmlprofilerclientmanager.h \
|
||||
qmlprofilerviewmanager.h \
|
||||
qmlprofilerstatewidget.h \
|
||||
qmlprofilerruncontrolfactory.h
|
||||
qmlprofilerruncontrolfactory.h \
|
||||
qmlprofilermodelmanager.h \
|
||||
qmlprofilersimplemodel.h \
|
||||
qmlprofilerprocessedmodel.h \
|
||||
qmlprofilereventsmodelproxy.h \
|
||||
qmlprofilertimelinemodelproxy.h \
|
||||
qmlprofilertreeview.h \
|
||||
qmlprofilertracefile.h \
|
||||
abstracttimelinemodel.h \
|
||||
timelinemodelaggregator.h \
|
||||
qmlprofilerpainteventsmodelproxy.h
|
||||
|
||||
RESOURCES += \
|
||||
qml/qmlprofiler.qrc
|
||||
|
@@ -22,6 +22,8 @@ QtcPlugin {
|
||||
cpp.includePaths: base.concat("canvas")
|
||||
|
||||
files: [
|
||||
"abstracttimelinemodel.h",
|
||||
"abstracttimelinemodel.cpp",
|
||||
"abstractqmlprofilerrunner.h",
|
||||
"localqmlprofilerrunner.cpp",
|
||||
"localqmlprofilerrunner.h",
|
||||
@@ -31,32 +33,50 @@ QtcPlugin {
|
||||
"qmlprofilerclientmanager.cpp",
|
||||
"qmlprofilerclientmanager.h",
|
||||
"qmlprofilerconstants.h",
|
||||
"qmlprofilerdatamodel.cpp",
|
||||
"qmlprofilerdatamodel.h",
|
||||
"qmlprofilerdetailsrewriter.cpp",
|
||||
"qmlprofilerdetailsrewriter.h",
|
||||
"qmlprofilerengine.cpp",
|
||||
"qmlprofilerengine.h",
|
||||
"qmlprofilereventsmodelproxy.cpp",
|
||||
"qmlprofilereventsmodelproxy.h",
|
||||
"qmlprofilereventview.cpp",
|
||||
"qmlprofilereventview.h",
|
||||
"qmlprofilermodelmanager.cpp",
|
||||
"qmlprofilermodelmanager.h",
|
||||
"qmlprofilerplugin.cpp",
|
||||
"qmlprofilerplugin.h",
|
||||
"qmlprofilerruncontrolfactory.cpp",
|
||||
"qmlprofilerruncontrolfactory.h",
|
||||
"qmlprofilerprocessedmodel.cpp",
|
||||
"qmlprofilerprocessedmodel.h",
|
||||
"qmlprofilersimplemodel.cpp",
|
||||
"qmlprofilersimplemodel.h",
|
||||
"qmlprofilerstatemanager.cpp",
|
||||
"qmlprofilerstatemanager.h",
|
||||
"qmlprofilerstatewidget.cpp",
|
||||
"qmlprofilerstatewidget.h",
|
||||
"qmlprofilertimelinemodelproxy.cpp",
|
||||
"qmlprofilertimelinemodelproxy.h",
|
||||
"qmlprofilertool.cpp",
|
||||
"qmlprofilertool.h",
|
||||
"qmlprofilertreeview.cpp",
|
||||
"qmlprofilertreeview.h",
|
||||
"qmlprofilertracefile.cpp",
|
||||
"qmlprofilertracefile.h",
|
||||
"qmlprofilertraceview.cpp",
|
||||
"qmlprofilertraceview.h",
|
||||
"qmlprofilerviewmanager.cpp",
|
||||
"qmlprofilerviewmanager.h",
|
||||
"qv8profilereventview.h",
|
||||
"qv8profilereventview.cpp",
|
||||
"qv8profilerdatamodel.cpp",
|
||||
"qv8profilerdatamodel.h",
|
||||
"timelinemodelaggregator.cpp",
|
||||
"timelinemodelaggregator.h",
|
||||
"timelinerenderer.cpp",
|
||||
"timelinerenderer.h",
|
||||
"qmlprofilerpainteventsmodelproxy.h",
|
||||
"qmlprofilerpainteventsmodelproxy.cpp",
|
||||
"canvas/qdeclarativecanvas.cpp",
|
||||
"canvas/qdeclarativecanvas_p.h",
|
||||
"canvas/qdeclarativecanvastimer.cpp",
|
||||
|
@@ -40,16 +40,19 @@
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
|
||||
using namespace QmlDebug;
|
||||
using namespace Core;
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerClientManager::QmlProfilerClientManagerPrivate
|
||||
{
|
||||
class QmlProfilerClientManager::QmlProfilerClientManagerPrivate {
|
||||
public:
|
||||
QmlProfilerStateManager *profilerState;
|
||||
QmlProfilerClientManagerPrivate(QmlProfilerClientManager *qq) { Q_UNUSED(qq); }
|
||||
|
||||
QmlProfilerStateManager* profilerState;
|
||||
|
||||
QmlDebugConnection *connection;
|
||||
QPointer<QmlProfilerTraceClient> qmlclientplugin;
|
||||
@@ -58,7 +61,9 @@ public:
|
||||
QTimer connectionTimer;
|
||||
int connectionAttempts;
|
||||
|
||||
enum ConnectMode { TcpConnection, OstConnection };
|
||||
enum ConnectMode {
|
||||
TcpConnection, OstConnection
|
||||
};
|
||||
ConnectMode connectMode;
|
||||
QString tcpHost;
|
||||
quint64 tcpPort;
|
||||
@@ -67,10 +72,12 @@ public:
|
||||
|
||||
bool v8DataReady;
|
||||
bool qmlDataReady;
|
||||
|
||||
QmlProfilerModelManager *modelManager;
|
||||
};
|
||||
|
||||
QmlProfilerClientManager::QmlProfilerClientManager(QObject *parent) :
|
||||
QObject(parent), d(new QmlProfilerClientManagerPrivate)
|
||||
QObject(parent), d(new QmlProfilerClientManagerPrivate(this))
|
||||
{
|
||||
setObjectName(QLatin1String("QML Profiler Connections"));
|
||||
|
||||
@@ -81,6 +88,8 @@ QmlProfilerClientManager::QmlProfilerClientManager(QObject *parent) :
|
||||
d->v8DataReady = false;
|
||||
d->qmlDataReady = false;
|
||||
|
||||
d->modelManager = 0;
|
||||
|
||||
d->connectionTimer.setInterval(200);
|
||||
connect(&d->connectionTimer, SIGNAL(timeout()), SLOT(tryToConnect()));
|
||||
}
|
||||
@@ -95,6 +104,17 @@ QmlProfilerClientManager::~QmlProfilerClientManager()
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QmlProfilerClientManager::setModelManager(QmlProfilerModelManager *m)
|
||||
{
|
||||
if (d->modelManager) {
|
||||
disconnect(this,SIGNAL(dataReadyForProcessing()), d->modelManager, SLOT(complete()));
|
||||
}
|
||||
d->modelManager = m;
|
||||
if (d->modelManager) {
|
||||
connect(this,SIGNAL(dataReadyForProcessing()), d->modelManager, SLOT(complete()));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Interface
|
||||
void QmlProfilerClientManager::setTcpConnection(QString host, quint64 port)
|
||||
@@ -159,15 +179,15 @@ void QmlProfilerClientManager::connectClientSignals()
|
||||
connect(d->qmlclientplugin.data(), SIGNAL(complete()),
|
||||
this, SLOT(qmlComplete()));
|
||||
connect(d->qmlclientplugin.data(),
|
||||
SIGNAL(range(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation)),
|
||||
this,
|
||||
SIGNAL(addRangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation)));
|
||||
SIGNAL(rangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
|
||||
qint64,qint64,qint64,qint64,qint64)),
|
||||
d->modelManager,
|
||||
SLOT(addQmlEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
|
||||
qint64,qint64,qint64,qint64,qint64)));
|
||||
connect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
|
||||
this, SIGNAL(traceFinished(qint64)));
|
||||
d->modelManager->traceTime(), SLOT(setEndTime(qint64)));
|
||||
connect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
|
||||
this, SIGNAL(traceStarted(qint64)));
|
||||
connect(d->qmlclientplugin.data(), SIGNAL(frame(qint64,int,int)),
|
||||
this, SIGNAL(addFrameEvent(qint64,int,int)));
|
||||
d->modelManager->traceTime(), SLOT(setStartTime(qint64)));
|
||||
connect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
|
||||
d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
|
||||
// fixme: this should be unified for both clients
|
||||
@@ -178,8 +198,8 @@ void QmlProfilerClientManager::connectClientSignals()
|
||||
connect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
|
||||
connect(d->v8clientplugin.data(),
|
||||
SIGNAL(v8range(int,QString,QString,int,double,double)),
|
||||
this,
|
||||
SIGNAL(addV8Event(int,QString,QString,int,double,double)));
|
||||
d->modelManager,
|
||||
SLOT(addV8Event(int,QString,QString,int,double,double)));
|
||||
connect(d->v8clientplugin.data(), SIGNAL(enabledChanged()),
|
||||
d->v8clientplugin.data(), SLOT(sendRecordingStatus()));
|
||||
}
|
||||
@@ -191,15 +211,17 @@ void QmlProfilerClientManager::disconnectClientSignals()
|
||||
disconnect(d->qmlclientplugin.data(), SIGNAL(complete()),
|
||||
this, SLOT(qmlComplete()));
|
||||
disconnect(d->qmlclientplugin.data(),
|
||||
SIGNAL(range(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation)),
|
||||
this,
|
||||
SIGNAL(addRangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation)));
|
||||
SIGNAL(rangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
|
||||
qint64,qint64,qint64,qint64,qint64)),
|
||||
d->modelManager,
|
||||
SLOT(addQmlEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
|
||||
qint64,qint64,qint64,qint64,qint64)));
|
||||
disconnect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
|
||||
this, SIGNAL(traceFinished(qint64)));
|
||||
d->modelManager->traceTime(), SLOT(setEndTime(qint64)));
|
||||
disconnect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
|
||||
this, SIGNAL(traceStarted(qint64)));
|
||||
d->modelManager->traceTime(), SLOT(setStartTime(qint64)));
|
||||
disconnect(d->qmlclientplugin.data(), SIGNAL(frame(qint64,int,int)),
|
||||
this, SIGNAL(addFrameEvent(qint64,int,int)));
|
||||
d->modelManager, SLOT(addFrameEvent(qint64,int,int)));
|
||||
disconnect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
|
||||
d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
|
||||
// fixme: this should be unified for both clients
|
||||
@@ -210,8 +232,8 @@ void QmlProfilerClientManager::disconnectClientSignals()
|
||||
disconnect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
|
||||
disconnect(d->v8clientplugin.data(),
|
||||
SIGNAL(v8range(int,QString,QString,int,double,double)),
|
||||
this,
|
||||
SIGNAL(addV8Event(int,QString,QString,int,double,double)));
|
||||
d->modelManager,
|
||||
SLOT(addV8Event(int,QString,QString,int,double,double)));
|
||||
disconnect(d->v8clientplugin.data(), SIGNAL(enabledChanged()),
|
||||
d->v8clientplugin.data(), SLOT(sendRecordingStatus()));
|
||||
}
|
||||
|
@@ -37,12 +37,13 @@
|
||||
#include <QStringList>
|
||||
|
||||
namespace QmlProfiler {
|
||||
class QmlProfilerModelManager;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerClientManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QmlProfilerClientManager(QObject *parent = 0);
|
||||
~QmlProfilerClientManager();
|
||||
@@ -56,16 +57,10 @@ public:
|
||||
void discardPendingData();
|
||||
bool isConnected() const;
|
||||
|
||||
void setModelManager(QmlProfilerModelManager *m);
|
||||
signals:
|
||||
void connectionFailed();
|
||||
void connectionClosed();
|
||||
|
||||
// data
|
||||
void addRangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation);
|
||||
void addV8Event(int,QString,QString,int,double,double);
|
||||
void addFrameEvent(qint64,int,int);
|
||||
void traceStarted(qint64);
|
||||
void traceFinished(qint64);
|
||||
void dataReadyForProcessing();
|
||||
|
||||
public slots:
|
||||
@@ -85,6 +80,9 @@ private slots:
|
||||
void serverRecordingChanged();
|
||||
|
||||
private:
|
||||
class QmlProfilerClientManagerPrivate;
|
||||
QmlProfilerClientManagerPrivate *d;
|
||||
|
||||
void connectToClient();
|
||||
|
||||
void enableServices();
|
||||
@@ -92,12 +90,9 @@ private:
|
||||
void disconnectClientSignals();
|
||||
|
||||
void stopClientsRecording();
|
||||
|
||||
class QmlProfilerClientManagerPrivate;
|
||||
QmlProfilerClientManagerPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
}
|
||||
}
|
||||
|
||||
#endif // QMLPROFILERCLIENTMANAGER_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,201 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QMLPROFILERDATAMODEL_H
|
||||
#define QMLPROFILERDATAMODEL_H
|
||||
|
||||
#include <qmldebug/qmlprofilereventtypes.h>
|
||||
#include <qmldebug/qmlprofilereventlocation.h>
|
||||
#include "qv8profilerdatamodel.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
// used for parents and children
|
||||
struct QmlRangeEventRelative;
|
||||
|
||||
struct QmlRangeEventData
|
||||
{
|
||||
QmlRangeEventData();
|
||||
~QmlRangeEventData();
|
||||
|
||||
int eventId;
|
||||
int bindingType;
|
||||
QString displayName;
|
||||
QString eventHashStr;
|
||||
QString details;
|
||||
QmlDebug::QmlEventLocation location;
|
||||
QmlDebug::QmlEventType eventType;
|
||||
|
||||
bool isBindingLoop;
|
||||
|
||||
QHash <QString, QmlRangeEventRelative *> parentHash;
|
||||
QHash <QString, QmlRangeEventRelative *> childrenHash;
|
||||
|
||||
qint64 duration;
|
||||
qint64 calls;
|
||||
qint64 minTime;
|
||||
qint64 maxTime;
|
||||
double timePerCall;
|
||||
double percentOfTime;
|
||||
qint64 medianTime;
|
||||
|
||||
QmlRangeEventData &operator=(const QmlRangeEventData &ref);
|
||||
};
|
||||
|
||||
struct QmlRangeEventRelative {
|
||||
QmlRangeEventRelative(QmlRangeEventData *from) : reference(from), duration(0), calls(0), inLoopPath(false) {}
|
||||
QmlRangeEventRelative(QmlRangeEventRelative *from) : reference(from->reference), duration(from->duration), calls(from->calls), inLoopPath(from->inLoopPath) {}
|
||||
QmlRangeEventData *reference;
|
||||
qint64 duration;
|
||||
qint64 calls;
|
||||
bool inLoopPath;
|
||||
};
|
||||
|
||||
class QmlProfilerDataModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum State {
|
||||
Empty,
|
||||
AcquiringData,
|
||||
ProcessingData,
|
||||
Done
|
||||
};
|
||||
|
||||
explicit QmlProfilerDataModel(QObject *parent = 0);
|
||||
~QmlProfilerDataModel();
|
||||
|
||||
QList<QmlRangeEventData *> getEventDescriptions() const;
|
||||
QmlRangeEventData *eventDescription(int eventId) const;
|
||||
QList<QV8EventData *> getV8Events() const;
|
||||
QV8EventData *v8EventDescription(int eventId) const;
|
||||
|
||||
static QString getHashStringForQmlEvent(const QmlDebug::QmlEventLocation &location, int eventType);
|
||||
static QString getHashStringForV8Event(const QString &displayName, const QString &function);
|
||||
static QString rootEventName();
|
||||
static QString rootEventDescription();
|
||||
static QString qmlEventTypeAsString(QmlDebug::QmlEventType typeEnum);
|
||||
static QmlDebug::QmlEventType qmlEventTypeAsEnum(const QString &typeString);
|
||||
|
||||
int findFirstIndex(qint64 startTime) const;
|
||||
int findFirstIndexNoParents(qint64 startTime) const;
|
||||
int findLastIndex(qint64 endTime) const;
|
||||
Q_INVOKABLE qint64 firstTimeMark() const;
|
||||
Q_INVOKABLE qint64 lastTimeMark() const;
|
||||
|
||||
// data access
|
||||
Q_INVOKABLE int count() const;
|
||||
Q_INVOKABLE bool isEmpty() const;
|
||||
Q_INVOKABLE qint64 getStartTime(int index) const;
|
||||
Q_INVOKABLE qint64 getEndTime(int index) const;
|
||||
Q_INVOKABLE qint64 getDuration(int index) const;
|
||||
Q_INVOKABLE int getType(int index) const;
|
||||
Q_INVOKABLE int getNestingLevel(int index) const;
|
||||
Q_INVOKABLE int getNestingDepth(int index) const;
|
||||
Q_INVOKABLE QString getFilename(int index) const;
|
||||
Q_INVOKABLE int getLine(int index) const;
|
||||
Q_INVOKABLE int getColumn(int index) const;
|
||||
Q_INVOKABLE QString getDetails(int index) const;
|
||||
Q_INVOKABLE int getEventId(int index) const;
|
||||
Q_INVOKABLE int getBindingLoopDest(int index) const;
|
||||
Q_INVOKABLE int getFramerate(int index) const;
|
||||
Q_INVOKABLE int getAnimationCount(int index) const;
|
||||
Q_INVOKABLE int getMaximumAnimationCount() const;
|
||||
Q_INVOKABLE int getMinimumAnimationCount() const;
|
||||
|
||||
|
||||
// per-type data
|
||||
Q_INVOKABLE int uniqueEventsOfType(int type) const;
|
||||
Q_INVOKABLE int maxNestingForType(int type) const;
|
||||
Q_INVOKABLE QString eventTextForType(int type, int index) const;
|
||||
Q_INVOKABLE QString eventDisplayNameForType(int type, int index) const;
|
||||
Q_INVOKABLE int eventIdForType(int type, int index) const;
|
||||
Q_INVOKABLE int eventPosInType(int index) const;
|
||||
|
||||
Q_INVOKABLE qint64 traceStartTime() const;
|
||||
Q_INVOKABLE qint64 traceEndTime() const;
|
||||
Q_INVOKABLE qint64 traceDuration() const;
|
||||
Q_INVOKABLE qint64 qmlMeasuredTime() const;
|
||||
Q_INVOKABLE qint64 v8MeasuredTime() const;
|
||||
|
||||
void compileStatistics(qint64 startTime, qint64 endTime);
|
||||
State currentState() const;
|
||||
Q_INVOKABLE int getCurrentStateFromQml() const;
|
||||
|
||||
signals:
|
||||
void stateChanged();
|
||||
void countChanged();
|
||||
void error(const QString &error);
|
||||
|
||||
void requestDetailsForLocation(int eventType, const QmlDebug::QmlEventLocation &location);
|
||||
void detailsChanged(int eventId, const QString &newString);
|
||||
void reloadDetailLabels();
|
||||
void reloadDocumentsForDetails();
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
|
||||
void prepareForWriting();
|
||||
void addRangedEvent(int type, int bindingType, qint64 startTime, qint64 length,
|
||||
const QStringList &data, const QmlDebug::QmlEventLocation &location);
|
||||
void addV8Event(int depth,const QString &function,const QString &filename, int lineNumber, double totalTime, double selfTime);
|
||||
void addFrameEvent(qint64 time, int framerate, int animationcount);
|
||||
void setTraceStartTime(qint64 time);
|
||||
void setTraceEndTime(qint64 time);
|
||||
|
||||
void complete();
|
||||
|
||||
bool save(const QString &filename);
|
||||
void load(const QString &filename);
|
||||
void setFilename(const QString &filename);
|
||||
void load();
|
||||
|
||||
void rewriteDetailsString(int eventType, const QmlDebug::QmlEventLocation &location, const QString &newString);
|
||||
void finishedRewritingDetails();
|
||||
|
||||
private:
|
||||
void setState(State state);
|
||||
void reloadDetails();
|
||||
|
||||
private:
|
||||
class QmlProfilerDataModelPrivate;
|
||||
QmlProfilerDataModelPrivate *d;
|
||||
|
||||
friend class QV8ProfilerDataModel;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
#endif // QMLPROFILERDATAMODEL_H
|
@@ -41,7 +41,7 @@ namespace Internal {
|
||||
struct PendingEvent {
|
||||
QmlDebug::QmlEventLocation location;
|
||||
QString localFile;
|
||||
int eventType;
|
||||
int requestId;
|
||||
};
|
||||
|
||||
class PropertyVisitor: protected QmlJS::AST::Visitor
|
||||
@@ -122,7 +122,7 @@ QmlProfilerDetailsRewriter::~QmlProfilerDetailsRewriter()
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QmlProfilerDetailsRewriter::requestDetailsForLocation(int type,
|
||||
void QmlProfilerDetailsRewriter::requestDetailsForLocation(int requestId,
|
||||
const QmlDebug::QmlEventLocation &location)
|
||||
{
|
||||
const QString localFile = d->m_projectFinder->findFile(location.filename);
|
||||
@@ -132,7 +132,7 @@ void QmlProfilerDetailsRewriter::requestDetailsForLocation(int type,
|
||||
if (!QmlJS::Document::isQmlLikeLanguage(QmlJSTools::languageOfFile(localFile)))
|
||||
return;
|
||||
|
||||
PendingEvent ev = {location, localFile, type};
|
||||
PendingEvent ev = {location, localFile, requestId};
|
||||
d->m_pendingEvents << ev;
|
||||
if (!d->m_pendingDocs.contains(localFile)) {
|
||||
if (d->m_pendingDocs.isEmpty())
|
||||
@@ -154,7 +154,7 @@ void QmlProfilerDetailsRewriter::reloadDocuments()
|
||||
}
|
||||
|
||||
void QmlProfilerDetailsRewriter::rewriteDetailsForLocation(QTextStream &textDoc,
|
||||
QmlJS::Document::Ptr doc, int type, const QmlDebug::QmlEventLocation &location)
|
||||
QmlJS::Document::Ptr doc, int requestId, const QmlDebug::QmlEventLocation &location)
|
||||
{
|
||||
PropertyVisitor propertyVisitor;
|
||||
QmlJS::AST::Node *node = propertyVisitor(doc->ast(), location.line, location.column);
|
||||
@@ -168,7 +168,12 @@ void QmlProfilerDetailsRewriter::rewriteDetailsForLocation(QTextStream &textDoc,
|
||||
textDoc.seek(startPos);
|
||||
QString details = textDoc.read(len).replace(QLatin1Char('\n'), QLatin1Char(' ')).simplified();
|
||||
|
||||
emit rewriteDetailsString(type, location, details);
|
||||
emit rewriteDetailsString(requestId, details);
|
||||
}
|
||||
|
||||
void QmlProfilerDetailsRewriter::clearRequests()
|
||||
{
|
||||
d->m_pendingDocs.clear();
|
||||
}
|
||||
|
||||
void QmlProfilerDetailsRewriter::documentReady(QmlJS::Document::Ptr doc)
|
||||
@@ -186,7 +191,7 @@ void QmlProfilerDetailsRewriter::documentReady(QmlJS::Document::Ptr doc)
|
||||
PendingEvent ev = d->m_pendingEvents[i];
|
||||
if (ev.localFile == doc->fileName()) {
|
||||
d->m_pendingEvents.removeAt(i);
|
||||
rewriteDetailsForLocation(st, doc, ev.eventType, ev.location);
|
||||
rewriteDetailsForLocation(st, doc, ev.requestId, ev.location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -46,16 +46,18 @@ public:
|
||||
explicit QmlProfilerDetailsRewriter(QObject *parent, Utils::FileInProjectFinder *fileFinder);
|
||||
~QmlProfilerDetailsRewriter();
|
||||
|
||||
void clearRequests();
|
||||
|
||||
private:
|
||||
void rewriteDetailsForLocation(QTextStream &textDoc,QmlJS::Document::Ptr doc, int type,
|
||||
void rewriteDetailsForLocation(QTextStream &textDoc, QmlJS::Document::Ptr doc, int requestId,
|
||||
const QmlDebug::QmlEventLocation &location);
|
||||
|
||||
public slots:
|
||||
void requestDetailsForLocation(int type, const QmlDebug::QmlEventLocation &location);
|
||||
void requestDetailsForLocation(int requestId, const QmlDebug::QmlEventLocation &location);
|
||||
void reloadDocuments();
|
||||
void documentReady(QmlJS::Document::Ptr doc);
|
||||
signals:
|
||||
void rewriteDetailsString(int type, const QmlDebug::QmlEventLocation &location,
|
||||
const QString &details);
|
||||
void rewriteDetailsString(int requestId, const QString &details);
|
||||
void eventDetailsChanged();
|
||||
private:
|
||||
class QmlProfilerDetailsRewriterPrivate;
|
||||
|
@@ -82,7 +82,7 @@ QmlProfilerRunControl::QmlProfilerRunControl(const Analyzer::AnalyzerStartParame
|
||||
{
|
||||
d->m_profilerState = 0;
|
||||
|
||||
// Only wait 4 seconds for the 'Waiting for connection' on application ouput, then just try to connect
|
||||
// Only wait 4 seconds for the 'Waiting for connection' on application output, then just try to connect
|
||||
// (application output might be redirected / blocked)
|
||||
d->m_noDebugOutputTimer.setSingleShot(true);
|
||||
d->m_noDebugOutputTimer.setInterval(4000);
|
||||
|
479
src/plugins/qmlprofiler/qmlprofilereventsmodelproxy.cpp
Normal file
479
src/plugins/qmlprofiler/qmlprofilereventsmodelproxy.cpp
Normal file
@@ -0,0 +1,479 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmlprofilereventsmodelproxy.h"
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilersimplemodel.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QVector>
|
||||
#include <QHash>
|
||||
#include <QUrl>
|
||||
#include <QString>
|
||||
#include <QStack>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerEventsModelProxy::QmlProfilerEventsModelProxyPrivate
|
||||
{
|
||||
public:
|
||||
QmlProfilerEventsModelProxyPrivate(QmlProfilerEventsModelProxy *qq) : q(qq) {}
|
||||
~QmlProfilerEventsModelProxyPrivate() {}
|
||||
|
||||
QHash<QString, QmlProfilerEventsModelProxy::QmlEventStats> data;
|
||||
|
||||
QmlProfilerModelManager *modelManager;
|
||||
QmlProfilerEventsModelProxy *q;
|
||||
|
||||
int modelId;
|
||||
|
||||
QVector<int> acceptedTypes;
|
||||
QSet<QString> eventsInBindingLoop;
|
||||
};
|
||||
|
||||
QmlProfilerEventsModelProxy::QmlProfilerEventsModelProxy(QmlProfilerModelManager *modelManager, QObject *parent)
|
||||
: QObject(parent), d(new QmlProfilerEventsModelProxyPrivate(this))
|
||||
{
|
||||
d->modelManager = modelManager;
|
||||
connect(modelManager->simpleModel(), SIGNAL(changed()), this, SLOT(dataChanged()));
|
||||
d->modelId = modelManager->registerModelProxy();
|
||||
|
||||
d->acceptedTypes << QmlDebug::Compiling << QmlDebug::Creating << QmlDebug::Binding << QmlDebug::HandlingSignal;
|
||||
}
|
||||
|
||||
QmlProfilerEventsModelProxy::~QmlProfilerEventsModelProxy()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
const QList<QmlProfilerEventsModelProxy::QmlEventStats> QmlProfilerEventsModelProxy::getData() const
|
||||
{
|
||||
return d->data.values();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsModelProxy::clear()
|
||||
{
|
||||
d->modelManager->modelProxyCountUpdated(d->modelId, 0, 1);
|
||||
d->data.clear();
|
||||
d->eventsInBindingLoop.clear();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsModelProxy::limitToRange(qint64 rangeStart, qint64 rangeEnd)
|
||||
{
|
||||
loadData(rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
void QmlProfilerEventsModelProxy::dataChanged()
|
||||
{
|
||||
if (d->modelManager->state() == QmlProfilerDataState::ProcessingData)
|
||||
loadData();
|
||||
|
||||
if (d->modelManager->state() == QmlProfilerDataState::Empty)
|
||||
clear();
|
||||
}
|
||||
|
||||
QSet<QString> QmlProfilerEventsModelProxy::eventsInBindingLoop() const
|
||||
{
|
||||
return d->eventsInBindingLoop;
|
||||
}
|
||||
|
||||
void QmlProfilerEventsModelProxy::loadData(qint64 rangeStart, qint64 rangeEnd)
|
||||
{
|
||||
clear();
|
||||
|
||||
qint64 qmlTime = 0;
|
||||
qint64 lastEndTime = 0;
|
||||
QHash <QString, QVector<qint64> > durations;
|
||||
|
||||
const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1);
|
||||
|
||||
const QVector<QmlProfilerSimpleModel::QmlEventData> eventList
|
||||
= d->modelManager->simpleModel()->getEvents();
|
||||
|
||||
// used by binding loop detection
|
||||
typedef QPair<QString, const QmlProfilerSimpleModel::QmlEventData*> CallStackEntry;
|
||||
QStack<CallStackEntry> callStack;
|
||||
callStack.push(CallStackEntry(QString(), 0)); // artificial root
|
||||
|
||||
for (int i = 0; i < eventList.size(); ++i) {
|
||||
const QmlProfilerSimpleModel::QmlEventData *event = &eventList[i];
|
||||
|
||||
if (!d->acceptedTypes.contains(event->eventType))
|
||||
continue;
|
||||
|
||||
if (checkRanges) {
|
||||
if ((event->startTime + event->duration < rangeStart)
|
||||
|| (event->startTime > rangeEnd))
|
||||
continue;
|
||||
}
|
||||
|
||||
// put event in hash
|
||||
QString hash = QmlProfilerSimpleModel::getHashString(*event);
|
||||
if (!d->data.contains(hash)) {
|
||||
QmlEventStats stats = {
|
||||
event->displayName,
|
||||
hash,
|
||||
event->data.join(QLatin1String(" ")),
|
||||
event->location,
|
||||
event->eventType,
|
||||
event->bindingType,
|
||||
event->duration,
|
||||
1, //calls
|
||||
event->duration, //minTime
|
||||
event->duration, // maxTime
|
||||
0, //timePerCall
|
||||
0, //percentOfTime
|
||||
0, //medianTime
|
||||
false //isBindingLoop
|
||||
};
|
||||
|
||||
d->data.insert(hash, stats);
|
||||
|
||||
// for median computing
|
||||
durations.insert(hash, QVector<qint64>());
|
||||
durations[hash].append(event->duration);
|
||||
} else {
|
||||
// update stats
|
||||
QmlEventStats *stats = &d->data[hash];
|
||||
|
||||
stats->duration += event->duration;
|
||||
if (event->duration < stats->minTime)
|
||||
stats->minTime = event->duration;
|
||||
if (event->duration > stats->maxTime)
|
||||
stats->maxTime = event->duration;
|
||||
stats->calls++;
|
||||
|
||||
// for median computing
|
||||
durations[hash].append(event->duration);
|
||||
}
|
||||
|
||||
// qml time computation
|
||||
if (event->startTime > lastEndTime) { // assume parent event if starts before last end
|
||||
qmlTime += event->duration;
|
||||
lastEndTime = event->startTime + event->duration;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// binding loop detection
|
||||
//
|
||||
const QmlProfilerSimpleModel::QmlEventData *potentialParent = callStack.top().second;
|
||||
while (potentialParent
|
||||
&& !(potentialParent->startTime + potentialParent->duration > event->startTime)) {
|
||||
callStack.pop();
|
||||
potentialParent = callStack.top().second;
|
||||
}
|
||||
|
||||
// check whether event is already in stack
|
||||
bool inLoop = false;
|
||||
for (int ii = 1; ii < callStack.size(); ++ii) {
|
||||
if (callStack.at(ii).first == hash)
|
||||
inLoop = true;
|
||||
if (inLoop)
|
||||
d->eventsInBindingLoop.insert(hash);
|
||||
}
|
||||
|
||||
|
||||
CallStackEntry newEntry(hash, event);
|
||||
callStack.push(newEntry);
|
||||
|
||||
d->modelManager->modelProxyCountUpdated(d->modelId, i, eventList.count()*2);
|
||||
}
|
||||
|
||||
// post-process: calc mean time, median time, percentoftime
|
||||
foreach (const QString &hash, d->data.keys()) {
|
||||
QmlEventStats* stats = &d->data[hash];
|
||||
if (stats->calls > 0)
|
||||
stats->timePerCall = stats->duration / (double)stats->calls;
|
||||
|
||||
QVector<qint64> eventDurations = durations.value(hash);
|
||||
if (!eventDurations.isEmpty()) {
|
||||
qSort(eventDurations);
|
||||
stats->medianTime = eventDurations.at(eventDurations.count()/2);
|
||||
}
|
||||
|
||||
stats->percentOfTime = stats->duration * 100.0 / qmlTime;
|
||||
}
|
||||
|
||||
// set binding loop flag
|
||||
foreach (const QString &eventHash, d->eventsInBindingLoop)
|
||||
d->data[eventHash].isBindingLoop = true;
|
||||
|
||||
QString rootEventName = tr("<program>");
|
||||
QmlDebug::QmlEventLocation rootEventLocation(rootEventName, 1, 1);
|
||||
|
||||
// insert root event
|
||||
QmlEventStats rootEvent = {
|
||||
rootEventName, //event.displayName,
|
||||
rootEventName, // hash
|
||||
tr("Main Program"), //event.details,
|
||||
rootEventLocation, // location
|
||||
(int)QmlDebug::Binding, // event type
|
||||
0, // binding type
|
||||
qmlTime + 1,
|
||||
1, //calls
|
||||
qmlTime + 1, //minTime
|
||||
qmlTime + 1, // maxTime
|
||||
qmlTime + 1, //timePerCall
|
||||
100.0, //percentOfTime
|
||||
qmlTime + 1, //medianTime;
|
||||
false
|
||||
};
|
||||
|
||||
d->data.insert(rootEventName, rootEvent);
|
||||
|
||||
d->modelManager->modelProxyCountUpdated(d->modelId, 1, 1);
|
||||
emit dataAvailable();
|
||||
}
|
||||
|
||||
int QmlProfilerEventsModelProxy::count() const
|
||||
{
|
||||
return d->data.count();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
QmlProfilerEventRelativesModelProxy::QmlProfilerEventRelativesModelProxy(QmlProfilerModelManager *modelManager,
|
||||
QmlProfilerEventsModelProxy *eventsModel,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
QTC_CHECK(modelManager);
|
||||
m_modelManager = modelManager;
|
||||
connect(modelManager->simpleModel(), SIGNAL(changed()), this, SLOT(dataChanged()));
|
||||
|
||||
QTC_CHECK(eventsModel);
|
||||
m_eventsModel = eventsModel;
|
||||
|
||||
m_acceptedTypes << QmlDebug::Compiling << QmlDebug::Creating << QmlDebug::Binding << QmlDebug::HandlingSignal;
|
||||
}
|
||||
|
||||
QmlProfilerEventRelativesModelProxy::~QmlProfilerEventRelativesModelProxy()
|
||||
{
|
||||
}
|
||||
|
||||
const QmlProfilerEventRelativesModelProxy::QmlEventRelativesMap QmlProfilerEventRelativesModelProxy::getData(const QString &hash) const
|
||||
{
|
||||
if (m_data.contains(hash))
|
||||
return m_data[hash];
|
||||
return QmlEventRelativesMap();
|
||||
}
|
||||
|
||||
int QmlProfilerEventRelativesModelProxy::count() const
|
||||
{
|
||||
return m_data.count();
|
||||
}
|
||||
|
||||
void QmlProfilerEventRelativesModelProxy::clear()
|
||||
{
|
||||
m_data.clear();
|
||||
}
|
||||
|
||||
void QmlProfilerEventRelativesModelProxy::dataChanged()
|
||||
{
|
||||
loadData();
|
||||
|
||||
emit dataAvailable();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
QmlProfilerEventParentsModelProxy::QmlProfilerEventParentsModelProxy(QmlProfilerModelManager *modelManager,
|
||||
QmlProfilerEventsModelProxy *eventsModel,
|
||||
QObject *parent)
|
||||
: QmlProfilerEventRelativesModelProxy(modelManager, eventsModel, parent)
|
||||
{}
|
||||
|
||||
QmlProfilerEventParentsModelProxy::~QmlProfilerEventParentsModelProxy()
|
||||
{}
|
||||
|
||||
void QmlProfilerEventParentsModelProxy::loadData()
|
||||
{
|
||||
clear();
|
||||
QmlProfilerSimpleModel *simpleModel = m_modelManager->simpleModel();
|
||||
if (simpleModel->isEmpty())
|
||||
return;
|
||||
|
||||
QHash<QString, QmlProfilerSimpleModel::QmlEventData> cachedEvents;
|
||||
QString rootEventName = tr("<program>");
|
||||
QmlProfilerSimpleModel::QmlEventData rootEvent = {
|
||||
rootEventName,
|
||||
QmlDebug::Binding,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
QStringList() << tr("Main Program"),
|
||||
QmlDebug::QmlEventLocation(rootEventName, 0, 0),
|
||||
0,0,0,0,0 // numericData fields
|
||||
};
|
||||
cachedEvents.insert(rootEventName, rootEvent);
|
||||
|
||||
// for level computation
|
||||
QHash<int, qint64> endtimesPerLevel;
|
||||
int level = QmlDebug::Constants::QML_MIN_LEVEL;
|
||||
endtimesPerLevel[0] = 0;
|
||||
|
||||
const QSet<QString> eventsInBindingLoop = m_eventsModel->eventsInBindingLoop();
|
||||
|
||||
// compute parent-child relationship and call count
|
||||
QHash<int, QString> lastParent;
|
||||
//for (int index = fromIndex; index <= toIndex; index++) {
|
||||
const QVector<QmlProfilerSimpleModel::QmlEventData> eventList = simpleModel->getEvents();
|
||||
foreach (const QmlProfilerSimpleModel::QmlEventData &event, eventList) {
|
||||
// whitelist
|
||||
if (!m_acceptedTypes.contains(event.eventType))
|
||||
continue;
|
||||
|
||||
// level computation
|
||||
if (endtimesPerLevel[level] > event.startTime) {
|
||||
level++;
|
||||
} else {
|
||||
while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= event.startTime)
|
||||
level--;
|
||||
}
|
||||
endtimesPerLevel[level] = event.startTime + event.duration;
|
||||
|
||||
|
||||
QString parentHash = rootEventName;
|
||||
QString eventHash = QmlProfilerSimpleModel::getHashString(event);
|
||||
|
||||
// save in cache
|
||||
if (!cachedEvents.contains(eventHash))
|
||||
cachedEvents.insert(eventHash, event);
|
||||
|
||||
if (level > QmlDebug::Constants::QML_MIN_LEVEL && lastParent.contains(level-1))
|
||||
parentHash = lastParent[level-1];
|
||||
|
||||
QmlProfilerSimpleModel::QmlEventData *parentEvent = &(cachedEvents[parentHash]);
|
||||
|
||||
// generate placeholder if needed
|
||||
if (!m_data.contains(eventHash))
|
||||
m_data.insert(eventHash, QmlEventRelativesMap());
|
||||
|
||||
if (m_data[eventHash].contains(parentHash)) {
|
||||
QmlEventRelativesData *parent = &(m_data[eventHash][parentHash]);
|
||||
parent->calls++;
|
||||
parent->duration += event.duration;
|
||||
} else {
|
||||
m_data[eventHash].insert(parentHash, QmlEventRelativesData());
|
||||
QmlEventRelativesData *parent = &(m_data[eventHash][parentHash]);
|
||||
parent->displayName = parentEvent->displayName;
|
||||
parent->eventType = parentEvent->eventType;
|
||||
parent->duration = event.duration;
|
||||
parent->calls = 1;
|
||||
parent->details = parentEvent->data.join(QLatin1String(""));
|
||||
parent->isBindingLoop = eventsInBindingLoop.contains(parentHash);
|
||||
}
|
||||
|
||||
// now lastparent is a string with the hash
|
||||
lastParent[level] = eventHash;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
QmlProfilerEventChildrenModelProxy::QmlProfilerEventChildrenModelProxy(QmlProfilerModelManager *modelManager,
|
||||
QmlProfilerEventsModelProxy *eventsModel,
|
||||
QObject *parent)
|
||||
: QmlProfilerEventRelativesModelProxy(modelManager, eventsModel, parent)
|
||||
{}
|
||||
|
||||
QmlProfilerEventChildrenModelProxy::~QmlProfilerEventChildrenModelProxy()
|
||||
{}
|
||||
|
||||
void QmlProfilerEventChildrenModelProxy::loadData()
|
||||
{
|
||||
clear();
|
||||
QmlProfilerSimpleModel *simpleModel = m_modelManager->simpleModel();
|
||||
if (simpleModel->isEmpty())
|
||||
return;
|
||||
|
||||
QString rootEventName = tr("<program>");
|
||||
|
||||
// for level computation
|
||||
QHash<int, qint64> endtimesPerLevel;
|
||||
int level = QmlDebug::Constants::QML_MIN_LEVEL;
|
||||
endtimesPerLevel[0] = 0;
|
||||
|
||||
const QSet<QString> eventsInBindingLoop = m_eventsModel->eventsInBindingLoop();
|
||||
|
||||
// compute parent-child relationship and call count
|
||||
QHash<int, QString> lastParent;
|
||||
const QVector<QmlProfilerSimpleModel::QmlEventData> eventList = simpleModel->getEvents();
|
||||
foreach (const QmlProfilerSimpleModel::QmlEventData &event, eventList) {
|
||||
// whitelist
|
||||
if (!m_acceptedTypes.contains(event.eventType))
|
||||
continue;
|
||||
|
||||
// level computation
|
||||
if (endtimesPerLevel[level] > event.startTime) {
|
||||
level++;
|
||||
} else {
|
||||
while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= event.startTime)
|
||||
level--;
|
||||
}
|
||||
endtimesPerLevel[level] = event.startTime + event.duration;
|
||||
|
||||
QString parentHash = rootEventName;
|
||||
QString eventHash = QmlProfilerSimpleModel::getHashString(event);
|
||||
|
||||
if (level > QmlDebug::Constants::QML_MIN_LEVEL && lastParent.contains(level-1))
|
||||
parentHash = lastParent[level-1];
|
||||
|
||||
// generate placeholder if needed
|
||||
if (!m_data.contains(parentHash))
|
||||
m_data.insert(parentHash, QmlEventRelativesMap());
|
||||
|
||||
if (m_data[parentHash].contains(eventHash)) {
|
||||
QmlEventRelativesData *child = &(m_data[parentHash][eventHash]);
|
||||
child->calls++;
|
||||
child->duration += event.duration;
|
||||
} else {
|
||||
m_data[parentHash].insert(eventHash, QmlEventRelativesData());
|
||||
QmlEventRelativesData *child = &(m_data[parentHash][eventHash]);
|
||||
child->displayName = event.displayName;
|
||||
child->eventType = event.eventType;
|
||||
child->duration = event.duration;
|
||||
child->calls = 1;
|
||||
child->details = event.data.join(QLatin1String(""));
|
||||
child->isBindingLoop = eventsInBindingLoop.contains(parentHash);
|
||||
}
|
||||
|
||||
// now lastparent is a string with the hash
|
||||
lastParent[level] = eventHash;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
172
src/plugins/qmlprofiler/qmlprofilereventsmodelproxy.h
Normal file
172
src/plugins/qmlprofiler/qmlprofilereventsmodelproxy.h
Normal file
@@ -0,0 +1,172 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef QMLPROFILEREVENTSMODELPROXY_H
|
||||
#define QMLPROFILEREVENTSMODELPROXY_H
|
||||
|
||||
#include "qmlprofilersimplemodel.h"
|
||||
#include <QObject>
|
||||
#include <qmldebug/qmlprofilereventtypes.h>
|
||||
#include <qmldebug/qmlprofilereventlocation.h>
|
||||
#include <QHash>
|
||||
#include <QVector>
|
||||
|
||||
|
||||
namespace QmlProfiler {
|
||||
class QmlProfilerModelManager;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerEventsModelProxy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct QmlEventStats {
|
||||
QString displayName;
|
||||
QString eventHashStr;
|
||||
QString details;
|
||||
QmlDebug::QmlEventLocation location;
|
||||
int eventType;
|
||||
int bindingType;
|
||||
|
||||
qint64 duration;
|
||||
qint64 calls;
|
||||
qint64 minTime;
|
||||
qint64 maxTime;
|
||||
qint64 timePerCall;
|
||||
double percentOfTime;
|
||||
qint64 medianTime;
|
||||
|
||||
bool isBindingLoop;
|
||||
};
|
||||
|
||||
QmlProfilerEventsModelProxy(QmlProfilerModelManager *modelManager, QObject *parent = 0);
|
||||
~QmlProfilerEventsModelProxy();
|
||||
|
||||
const QList<QmlEventStats> getData() const;
|
||||
int count() const;
|
||||
void clear();
|
||||
|
||||
void limitToRange(qint64 rangeStart, qint64 rangeEnd);
|
||||
|
||||
signals:
|
||||
void dataAvailable();
|
||||
|
||||
private:
|
||||
void loadData(qint64 rangeStart = -1, qint64 rangeEnd = -1);
|
||||
|
||||
QSet<QString> eventsInBindingLoop() const;
|
||||
|
||||
private slots:
|
||||
void dataChanged();
|
||||
|
||||
private:
|
||||
class QmlProfilerEventsModelProxyPrivate;
|
||||
QmlProfilerEventsModelProxyPrivate *d;
|
||||
|
||||
friend class QmlProfilerEventParentsModelProxy;
|
||||
friend class QmlProfilerEventChildrenModelProxy;
|
||||
};
|
||||
|
||||
class QmlProfilerEventRelativesModelProxy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct QmlEventRelativesData {
|
||||
QString displayName;
|
||||
int eventType;
|
||||
qint64 duration;
|
||||
qint64 calls;
|
||||
QString details;
|
||||
bool isBindingLoop;
|
||||
};
|
||||
typedef QHash <QString, QmlEventRelativesData> QmlEventRelativesMap;
|
||||
|
||||
QmlProfilerEventRelativesModelProxy(QmlProfilerModelManager *modelManager,
|
||||
QmlProfilerEventsModelProxy *eventsModel,
|
||||
QObject *parent = 0);
|
||||
~QmlProfilerEventRelativesModelProxy();
|
||||
|
||||
|
||||
int count() const;
|
||||
void clear();
|
||||
|
||||
const QmlEventRelativesMap getData(const QString &hash) const;
|
||||
|
||||
protected:
|
||||
virtual void loadData() = 0;
|
||||
|
||||
signals:
|
||||
void dataAvailable();
|
||||
|
||||
protected slots:
|
||||
void dataChanged();
|
||||
|
||||
protected:
|
||||
QHash <QString, QmlEventRelativesMap> m_data;
|
||||
QmlProfilerModelManager *m_modelManager;
|
||||
QmlProfilerEventsModelProxy *m_eventsModel;
|
||||
QVector <int> m_acceptedTypes;
|
||||
};
|
||||
|
||||
class QmlProfilerEventParentsModelProxy : public QmlProfilerEventRelativesModelProxy
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QmlProfilerEventParentsModelProxy(QmlProfilerModelManager *modelManager,
|
||||
QmlProfilerEventsModelProxy *eventsModel,
|
||||
QObject *parent = 0);
|
||||
~QmlProfilerEventParentsModelProxy();
|
||||
|
||||
protected:
|
||||
virtual void loadData();
|
||||
signals:
|
||||
void dataAvailable();
|
||||
};
|
||||
|
||||
class QmlProfilerEventChildrenModelProxy : public QmlProfilerEventRelativesModelProxy
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QmlProfilerEventChildrenModelProxy(QmlProfilerModelManager *modelManager,
|
||||
QmlProfilerEventsModelProxy *eventsModel,
|
||||
QObject *parent = 0);
|
||||
~QmlProfilerEventChildrenModelProxy();
|
||||
|
||||
protected:
|
||||
virtual void loadData();
|
||||
signals:
|
||||
void dataAvailable();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -66,6 +66,9 @@ struct Colors {
|
||||
|
||||
Q_GLOBAL_STATIC(Colors, colors)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EventsViewItem : public QStandardItem
|
||||
@@ -104,46 +107,48 @@ public:
|
||||
QmlProfilerViewManager *m_viewContainer;
|
||||
|
||||
QmlProfilerEventsMainView *m_eventTree;
|
||||
QmlProfilerEventsParentsAndChildrenView *m_eventChildren;
|
||||
QmlProfilerEventsParentsAndChildrenView *m_eventParents;
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
QmlProfilerEventRelativesView *m_eventChildren;
|
||||
QmlProfilerEventRelativesView *m_eventParents;
|
||||
|
||||
bool m_globalStatsEnabled;
|
||||
QmlProfilerEventsModelProxy *modelProxy;
|
||||
bool globalStats;
|
||||
};
|
||||
|
||||
QmlProfilerEventsWidget::QmlProfilerEventsWidget(QWidget *parent,
|
||||
QmlProfilerTool *profilerTool,
|
||||
QmlProfilerViewManager *container,
|
||||
QmlProfilerDataModel *profilerDataModel )
|
||||
QmlProfilerModelManager *profilerModelManager )
|
||||
|
||||
: QWidget(parent), d(new QmlProfilerEventsWidgetPrivate(this))
|
||||
{
|
||||
setObjectName(QLatin1String("QmlProfilerEventsView"));
|
||||
|
||||
d->m_profilerDataModel = profilerDataModel;
|
||||
connect(d->m_profilerDataModel, SIGNAL(stateChanged()),
|
||||
d->modelProxy = new QmlProfilerEventsModelProxy(profilerModelManager, this);
|
||||
connect(profilerModelManager, SIGNAL(stateChanged()),
|
||||
this, SLOT(profilerDataModelStateChanged()));
|
||||
|
||||
d->m_eventTree = new QmlProfilerEventsMainView(QmlProfilerEventsMainView::EventsView, this, d->m_profilerDataModel);
|
||||
d->m_eventTree = new QmlProfilerEventsMainView(this, d->modelProxy);
|
||||
connect(d->m_eventTree, SIGNAL(gotoSourceLocation(QString,int,int)), this, SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
connect(d->m_eventTree, SIGNAL(showEventInTimeline(int)), this, SIGNAL(showEventInTimeline(int)));
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(QString)), this, SIGNAL(eventSelectedByHash(QString)));
|
||||
|
||||
d->m_eventChildren = new QmlProfilerEventsParentsAndChildrenView(
|
||||
QmlProfilerEventsParentsAndChildrenView::ChildrenView,
|
||||
this,
|
||||
d->m_profilerDataModel);
|
||||
d->m_eventParents = new QmlProfilerEventsParentsAndChildrenView(
|
||||
QmlProfilerEventsParentsAndChildrenView::ParentsView,
|
||||
this,
|
||||
d->m_profilerDataModel);
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventChildren, SLOT(displayEvent(int)));
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventParents, SLOT(displayEvent(int)));
|
||||
connect(d->m_eventChildren, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
|
||||
connect(d->m_eventParents, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
|
||||
d->m_eventChildren = new QmlProfilerEventRelativesView(
|
||||
profilerModelManager,
|
||||
new QmlProfilerEventChildrenModelProxy(profilerModelManager, d->modelProxy, this),
|
||||
this);
|
||||
d->m_eventParents = new QmlProfilerEventRelativesView(
|
||||
profilerModelManager,
|
||||
new QmlProfilerEventParentsModelProxy(profilerModelManager, d->modelProxy, this),
|
||||
this);
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(QString)), d->m_eventChildren, SLOT(displayEvent(QString)));
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(QString)), d->m_eventParents, SLOT(displayEvent(QString)));
|
||||
connect(d->m_eventChildren, SIGNAL(eventClicked(QString)), d->m_eventTree, SLOT(selectEvent(QString)));
|
||||
connect(d->m_eventParents, SIGNAL(eventClicked(QString)), d->m_eventTree, SLOT(selectEvent(QString)));
|
||||
|
||||
// widget arrangement
|
||||
QVBoxLayout *groupLayout = new QVBoxLayout;
|
||||
groupLayout->setContentsMargins(0,0,0,0);
|
||||
groupLayout->setSpacing(0);
|
||||
|
||||
Core::MiniSplitter *splitterVertical = new Core::MiniSplitter;
|
||||
splitterVertical->addWidget(d->m_eventTree);
|
||||
Core::MiniSplitter *splitterHorizontal = new Core::MiniSplitter;
|
||||
@@ -159,30 +164,17 @@ QmlProfilerEventsWidget::QmlProfilerEventsWidget(QWidget *parent,
|
||||
|
||||
d->m_profilerTool = profilerTool;
|
||||
d->m_viewContainer = container;
|
||||
d->m_globalStatsEnabled = true;
|
||||
d->globalStats = true;
|
||||
}
|
||||
|
||||
QmlProfilerEventsWidget::~QmlProfilerEventsWidget()
|
||||
{
|
||||
delete d->modelProxy;
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::profilerDataModelStateChanged()
|
||||
{
|
||||
if (d->m_profilerDataModel) {
|
||||
QmlProfilerDataModel::State newState = d->m_profilerDataModel->currentState();
|
||||
if (newState == QmlProfilerDataModel::Empty)
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::switchToV8View()
|
||||
{
|
||||
setObjectName(QLatin1String("QmlProfilerV8ProfileView"));
|
||||
d->m_eventTree->setViewType(QmlProfilerEventsMainView::V8ProfileView);
|
||||
d->m_eventParents->setViewType(QmlProfilerEventsParentsAndChildrenView::V8ParentsView);
|
||||
d->m_eventChildren->setViewType(QmlProfilerEventsParentsAndChildrenView::V8ChildrenView);
|
||||
setToolTip(tr("Trace information from the v8 JavaScript engine. Available only in Qt5 based applications."));
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::clear()
|
||||
@@ -194,9 +186,8 @@ void QmlProfilerEventsWidget::clear()
|
||||
|
||||
void QmlProfilerEventsWidget::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
|
||||
{
|
||||
clear();
|
||||
d->m_eventTree->getStatisticsInRange(rangeStart, rangeEnd);
|
||||
d->m_globalStatsEnabled = d->m_eventTree->isRangeGlobal(rangeStart, rangeEnd);
|
||||
d->modelProxy->limitToRange(rangeStart, rangeEnd);
|
||||
d->globalStats = (rangeStart == -1) && (rangeEnd == -1);
|
||||
}
|
||||
|
||||
QModelIndex QmlProfilerEventsWidget::selectedItem() const
|
||||
@@ -230,23 +221,18 @@ void QmlProfilerEventsWidget::contextMenuEvent(QContextMenuEvent *ev)
|
||||
copyRowAction = menu.addAction(tr("Copy Row"));
|
||||
copyTableAction = menu.addAction(tr("Copy Table"));
|
||||
|
||||
if (isQml()) {
|
||||
// only for qml events view, not for v8
|
||||
showExtendedStatsAction = menu.addAction(tr("Extended Event Statistics"));
|
||||
showExtendedStatsAction->setCheckable(true);
|
||||
showExtendedStatsAction->setChecked(showExtendedStatistics());
|
||||
}
|
||||
showExtendedStatsAction = menu.addAction(tr("Extended Event Statistics"));
|
||||
showExtendedStatsAction->setCheckable(true);
|
||||
showExtendedStatsAction->setChecked(showExtendedStatistics());
|
||||
}
|
||||
|
||||
if (isQml()) {
|
||||
menu.addSeparator();
|
||||
getLocalStatsAction = menu.addAction(tr("Limit Events Pane to Current Range"));
|
||||
if (!d->m_viewContainer->hasValidSelection())
|
||||
getLocalStatsAction->setEnabled(false);
|
||||
getGlobalStatsAction = menu.addAction(tr("Reset Events Pane"));
|
||||
if (hasGlobalStats())
|
||||
getGlobalStatsAction->setEnabled(false);
|
||||
}
|
||||
menu.addSeparator();
|
||||
getLocalStatsAction = menu.addAction(tr("Limit Events Pane to Current Range"));
|
||||
if (!d->m_viewContainer->hasValidSelection())
|
||||
getLocalStatsAction->setEnabled(false);
|
||||
getGlobalStatsAction = menu.addAction(tr("Reset Events Pane"));
|
||||
if (hasGlobalStats())
|
||||
getGlobalStatsAction->setEnabled(false);
|
||||
|
||||
QAction *selectedAction = menu.exec(position);
|
||||
|
||||
@@ -259,12 +245,8 @@ void QmlProfilerEventsWidget::contextMenuEvent(QContextMenuEvent *ev)
|
||||
getStatisticsInRange(d->m_viewContainer->selectionStart(),
|
||||
d->m_viewContainer->selectionEnd());
|
||||
}
|
||||
if (selectedAction == getGlobalStatsAction) {
|
||||
if (d->m_profilerDataModel) {
|
||||
getStatisticsInRange(d->m_profilerDataModel->traceStartTime(),
|
||||
d->m_profilerDataModel->traceEndTime());
|
||||
}
|
||||
}
|
||||
if (selectedAction == getGlobalStatsAction)
|
||||
getStatisticsInRange(-1, -1);
|
||||
if (selectedAction == showExtendedStatsAction)
|
||||
setShowExtendedStatistics(!showExtendedStatistics());
|
||||
}
|
||||
@@ -293,24 +275,20 @@ void QmlProfilerEventsWidget::copyRowToClipboard() const
|
||||
d->m_eventTree->copyRowToClipboard();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::updateSelectedEvent(int eventId) const
|
||||
void QmlProfilerEventsWidget::updateSelectedEvent(const QString &eventHash) const
|
||||
{
|
||||
if (d->m_eventTree->selectedEventId() != eventId)
|
||||
d->m_eventTree->selectEvent(eventId);
|
||||
if (d->m_eventTree->selectedEventHash() != eventHash)
|
||||
d->m_eventTree->selectEvent(eventHash);
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::selectBySourceLocation(const QString &filename, int line, int column)
|
||||
{
|
||||
// This slot is used to connect the javascript pane with the qml events pane
|
||||
// Our javascript trace data does not store column information
|
||||
// thus we ignore it here
|
||||
Q_UNUSED(column);
|
||||
d->m_eventTree->selectEventByLocation(filename, line);
|
||||
d->m_eventTree->selectEventByLocation(filename, line, column);
|
||||
}
|
||||
|
||||
bool QmlProfilerEventsWidget::hasGlobalStats() const
|
||||
{
|
||||
return d->m_globalStatsEnabled;
|
||||
return d->globalStats;
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::setShowExtendedStatistics(bool show)
|
||||
@@ -323,15 +301,6 @@ bool QmlProfilerEventsWidget::showExtendedStatistics() const
|
||||
return d->m_eventTree->showExtendedStatistics();
|
||||
}
|
||||
|
||||
bool QmlProfilerEventsWidget::isQml() const
|
||||
{
|
||||
return d->m_eventTree->viewType() == QmlProfilerEventsMainView::EventsView;
|
||||
}
|
||||
bool QmlProfilerEventsWidget::isV8() const
|
||||
{
|
||||
return d->m_eventTree->viewType() == QmlProfilerEventsMainView::V8ProfileView;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate
|
||||
@@ -339,17 +308,14 @@ class QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate
|
||||
public:
|
||||
QmlProfilerEventsMainViewPrivate(QmlProfilerEventsMainView *qq) : q(qq) {}
|
||||
|
||||
void buildModelFromList(const QList<QmlRangeEventData *> &list, QStandardItem *parentItem );
|
||||
void buildV8ModelFromList( const QList<QV8EventData *> &list );
|
||||
int getFieldCount();
|
||||
|
||||
QString textForItem(QStandardItem *item, bool recursive) const;
|
||||
QString textForItem(QStandardItem *item, bool recursive = false) const;
|
||||
|
||||
|
||||
QmlProfilerEventsMainView *q;
|
||||
|
||||
QmlProfilerEventsMainView::ViewTypes m_viewType;
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
QmlProfilerEventsModelProxy *modelProxy;
|
||||
QStandardItemModel *m_model;
|
||||
QList<bool> m_fieldShown;
|
||||
QHash<int, int> m_columnIndex; // maps field enum to column index
|
||||
@@ -361,49 +327,52 @@ public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QmlProfilerEventsMainView::QmlProfilerEventsMainView(ViewTypes viewType,
|
||||
QWidget *parent,
|
||||
QmlProfilerDataModel *dataModel)
|
||||
: QTreeView(parent), d(new QmlProfilerEventsMainViewPrivate(this))
|
||||
QmlProfilerEventsMainView::QmlProfilerEventsMainView(QWidget *parent,
|
||||
QmlProfilerEventsModelProxy *modelProxy)
|
||||
: QmlProfilerTreeView(parent), d(new QmlProfilerEventsMainViewPrivate(this))
|
||||
{
|
||||
setObjectName(QLatin1String("QmlProfilerEventsTable"));
|
||||
header()->setResizeMode(QHeaderView::Interactive);
|
||||
header()->setDefaultSectionSize(100);
|
||||
header()->setMinimumSectionSize(50);
|
||||
|
||||
setSortingEnabled(false);
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
|
||||
d->m_model = new QStandardItemModel(this);
|
||||
setModel(d->m_model);
|
||||
connect(this,SIGNAL(clicked(QModelIndex)), this,SLOT(jumpToItem(QModelIndex)));
|
||||
|
||||
d->m_profilerDataModel = dataModel;
|
||||
connect(d->m_profilerDataModel,SIGNAL(stateChanged()),
|
||||
this,SLOT(profilerDataModelStateChanged()));
|
||||
connect(d->m_profilerDataModel,SIGNAL(detailsChanged(int,QString)),
|
||||
this,SLOT(changeDetailsForEvent(int,QString)));
|
||||
|
||||
d->modelProxy = modelProxy;
|
||||
connect(d->modelProxy,SIGNAL(dataAvailable()), this, SLOT(buildModel()));
|
||||
// connect(d->modelProxy,SIGNAL(stateChanged()),
|
||||
// this,SLOT(profilerDataModelStateChanged()));
|
||||
d->m_firstNumericColumn = 0;
|
||||
d->m_preventSelectBounce = false;
|
||||
d->m_showExtendedStatistics = false;
|
||||
|
||||
setViewType(viewType);
|
||||
setFieldViewable(Name, true);
|
||||
setFieldViewable(Type, true);
|
||||
setFieldViewable(TimeInPercent, true);
|
||||
setFieldViewable(TotalTime, true);
|
||||
setFieldViewable(SelfTimeInPercent, false);
|
||||
setFieldViewable(SelfTime, false);
|
||||
setFieldViewable(CallCount, true);
|
||||
setFieldViewable(TimePerCall, true);
|
||||
setFieldViewable(MaxTime, true);
|
||||
setFieldViewable(MinTime, true);
|
||||
setFieldViewable(MedianTime, true);
|
||||
setFieldViewable(Details, true);
|
||||
|
||||
buildModel();
|
||||
}
|
||||
|
||||
QmlProfilerEventsMainView::~QmlProfilerEventsMainView()
|
||||
{
|
||||
clear();
|
||||
//delete d->modelProxy;
|
||||
delete d->m_model;
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::profilerDataModelStateChanged()
|
||||
{
|
||||
if (d->m_profilerDataModel) {
|
||||
QmlProfilerDataModel::State newState = d->m_profilerDataModel->currentState();
|
||||
if (newState == QmlProfilerDataModel::Done)
|
||||
buildModel();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::setFieldViewable(Fields field, bool show)
|
||||
@@ -418,52 +387,6 @@ void QmlProfilerEventsMainView::setFieldViewable(Fields field, bool show)
|
||||
}
|
||||
}
|
||||
|
||||
QmlProfilerEventsMainView::ViewTypes QmlProfilerEventsMainView::viewType() const
|
||||
{
|
||||
return d->m_viewType;
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::setViewType(ViewTypes type)
|
||||
{
|
||||
d->m_viewType = type;
|
||||
switch (type) {
|
||||
case EventsView: {
|
||||
setObjectName(QLatin1String("QmlProfilerEventsTable"));
|
||||
setFieldViewable(Name, true);
|
||||
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, true);
|
||||
break;
|
||||
}
|
||||
case V8ProfileView: {
|
||||
setObjectName(QLatin1String("QmlProfilerV8ProfileTable"));
|
||||
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);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
buildModel();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::setHeaderLabels()
|
||||
{
|
||||
@@ -473,53 +396,53 @@ void QmlProfilerEventsMainView::setHeaderLabels()
|
||||
d->m_columnIndex.clear();
|
||||
if (d->m_fieldShown[Name]) {
|
||||
d->m_columnIndex[Name] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Location")));
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Location)));
|
||||
d->m_firstNumericColumn++;
|
||||
}
|
||||
if (d->m_fieldShown[Type]) {
|
||||
d->m_columnIndex[Type] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Type")));
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Type)));
|
||||
d->m_firstNumericColumn++;
|
||||
}
|
||||
if (d->m_fieldShown[Percent]) {
|
||||
d->m_columnIndex[Percent] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Time in Percent")));
|
||||
if (d->m_fieldShown[TimeInPercent]) {
|
||||
d->m_columnIndex[TimeInPercent] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TimeInPercent)));
|
||||
}
|
||||
if (d->m_fieldShown[TotalDuration]) {
|
||||
d->m_columnIndex[TotalDuration] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Total Time")));
|
||||
if (d->m_fieldShown[TotalTime]) {
|
||||
d->m_columnIndex[TotalTime] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TotalTime)));
|
||||
}
|
||||
if (d->m_fieldShown[SelfPercent]) {
|
||||
if (d->m_fieldShown[SelfTimeInPercent]) {
|
||||
d->m_columnIndex[Type] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Self Time in Percent")));
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(SelfTimeInPercent)));
|
||||
}
|
||||
if (d->m_fieldShown[SelfDuration]) {
|
||||
d->m_columnIndex[SelfDuration] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Self Time")));
|
||||
if (d->m_fieldShown[SelfTime]) {
|
||||
d->m_columnIndex[SelfTime] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(SelfTime)));
|
||||
}
|
||||
if (d->m_fieldShown[CallCount]) {
|
||||
d->m_columnIndex[CallCount] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Calls")));
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(CallCount)));
|
||||
}
|
||||
if (d->m_fieldShown[TimePerCall]) {
|
||||
d->m_columnIndex[TimePerCall] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Mean Time")));
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TimePerCall)));
|
||||
}
|
||||
if (d->m_fieldShown[MedianTime]) {
|
||||
d->m_columnIndex[MedianTime] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Median Time")));
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MedianTime)));
|
||||
}
|
||||
if (d->m_fieldShown[MaxTime]) {
|
||||
d->m_columnIndex[MaxTime] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Longest Time")));
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MaxTime)));
|
||||
}
|
||||
if (d->m_fieldShown[MinTime]) {
|
||||
d->m_columnIndex[MinTime] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Shortest Time")));
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MinTime)));
|
||||
}
|
||||
if (d->m_fieldShown[Details]) {
|
||||
d->m_columnIndex[Details] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(tr("Details")));
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Details)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,47 +492,41 @@ int QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::getFieldCount()
|
||||
|
||||
void QmlProfilerEventsMainView::buildModel()
|
||||
{
|
||||
if (d->m_profilerDataModel) {
|
||||
clear();
|
||||
if (d->m_viewType == V8ProfileView)
|
||||
d->buildV8ModelFromList( d->m_profilerDataModel->getV8Events() );
|
||||
else
|
||||
d->buildModelFromList( d->m_profilerDataModel->getEventDescriptions(), d->m_model->invisibleRootItem() );
|
||||
clear();
|
||||
parseModelProxy();
|
||||
setShowExtendedStatistics(d->m_showExtendedStatistics);
|
||||
|
||||
setShowExtendedStatistics(d->m_showExtendedStatistics);
|
||||
setRootIsDecorated(false);
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(d->m_firstNumericColumn,Qt::DescendingOrder);
|
||||
|
||||
setRootIsDecorated(false);
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(d->m_firstNumericColumn,Qt::DescendingOrder);
|
||||
expandAll();
|
||||
if (d->m_fieldShown[Name])
|
||||
resizeColumnToContents(0);
|
||||
|
||||
expandAll();
|
||||
if (d->m_fieldShown[Name])
|
||||
resizeColumnToContents(0);
|
||||
|
||||
if (d->m_fieldShown[Type])
|
||||
resizeColumnToContents(d->m_fieldShown[Name]?1:0);
|
||||
collapseAll();
|
||||
}
|
||||
if (d->m_fieldShown[Type])
|
||||
resizeColumnToContents(d->m_fieldShown[Name]?1:0);
|
||||
collapseAll();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFromList( const QList<QmlRangeEventData *> &list, QStandardItem *parentItem)
|
||||
void QmlProfilerEventsMainView::parseModelProxy()
|
||||
{
|
||||
foreach (QmlRangeEventData *binding, list) {
|
||||
if (binding->calls == 0)
|
||||
continue;
|
||||
|
||||
const QList <QmlProfilerEventsModelProxy::QmlEventStats> eventList = d->modelProxy->getData();
|
||||
foreach (const QmlProfilerEventsModelProxy::QmlEventStats &event, eventList) {
|
||||
QStandardItem *parentItem = d->m_model->invisibleRootItem();
|
||||
QList<QStandardItem *> newRow;
|
||||
if (m_fieldShown[Name])
|
||||
newRow << new EventsViewItem(binding->displayName);
|
||||
|
||||
if (m_fieldShown[Type]) {
|
||||
QString typeString = QmlProfilerEventsMainView::nameForType(binding->eventType);
|
||||
if (d->m_fieldShown[Name])
|
||||
newRow << new EventsViewItem(event.displayName);
|
||||
|
||||
if (d->m_fieldShown[Type]) {
|
||||
QString typeString = QmlProfilerEventsMainView::nameForType(event.eventType);
|
||||
QString toolTipText;
|
||||
if (binding->eventType == Binding) {
|
||||
if (binding->bindingType == (int)OptimizedBinding) {
|
||||
if (event.eventType == Binding) {
|
||||
if (event.bindingType == (int)OptimizedBinding) {
|
||||
typeString = typeString + tr(" (Opt)");
|
||||
toolTipText = tr("Binding is evaluated by the optimized engine.");
|
||||
} else if (binding->bindingType == (int)V8Binding) {
|
||||
} else if (event.bindingType == (int)V8Binding) {
|
||||
toolTipText = tr("Binding not optimized (e.g. has side effects or assignments,\n"
|
||||
"references to elements in other files, loops, etc.)");
|
||||
|
||||
@@ -621,44 +538,44 @@ void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFrom
|
||||
newRow.last()->setToolTip(toolTipText);
|
||||
}
|
||||
|
||||
if (m_fieldShown[Percent]) {
|
||||
newRow << new EventsViewItem(QString::number(binding->percentOfTime,'f',2)+QLatin1String(" %"));
|
||||
newRow.last()->setData(QVariant(binding->percentOfTime));
|
||||
if (d->m_fieldShown[TimeInPercent]) {
|
||||
newRow << new EventsViewItem(QString::number(event.percentOfTime,'f',2)+QLatin1String(" %"));
|
||||
newRow.last()->setData(QVariant(event.percentOfTime));
|
||||
}
|
||||
|
||||
if (m_fieldShown[TotalDuration]) {
|
||||
newRow << new EventsViewItem(displayTime(binding->duration));
|
||||
newRow.last()->setData(QVariant(binding->duration));
|
||||
if (d->m_fieldShown[TotalTime]) {
|
||||
newRow << new EventsViewItem(displayTime(event.duration));
|
||||
newRow.last()->setData(QVariant(event.duration));
|
||||
}
|
||||
|
||||
if (m_fieldShown[CallCount]) {
|
||||
newRow << new EventsViewItem(QString::number(binding->calls));
|
||||
newRow.last()->setData(QVariant(binding->calls));
|
||||
if (d->m_fieldShown[CallCount]) {
|
||||
newRow << new EventsViewItem(QString::number(event.calls));
|
||||
newRow.last()->setData(QVariant(event.calls));
|
||||
}
|
||||
|
||||
if (m_fieldShown[TimePerCall]) {
|
||||
newRow << new EventsViewItem(displayTime(binding->timePerCall));
|
||||
newRow.last()->setData(QVariant(binding->timePerCall));
|
||||
if (d->m_fieldShown[TimePerCall]) {
|
||||
newRow << new EventsViewItem(displayTime(event.timePerCall));
|
||||
newRow.last()->setData(QVariant(event.timePerCall));
|
||||
}
|
||||
|
||||
if (m_fieldShown[MedianTime]) {
|
||||
newRow << new EventsViewItem(displayTime(binding->medianTime));
|
||||
newRow.last()->setData(QVariant(binding->medianTime));
|
||||
if (d->m_fieldShown[MedianTime]) {
|
||||
newRow << new EventsViewItem(displayTime(event.medianTime));
|
||||
newRow.last()->setData(QVariant(event.medianTime));
|
||||
}
|
||||
|
||||
if (m_fieldShown[MaxTime]) {
|
||||
newRow << new EventsViewItem(displayTime(binding->maxTime));
|
||||
newRow.last()->setData(QVariant(binding->maxTime));
|
||||
if (d->m_fieldShown[MaxTime]) {
|
||||
newRow << new EventsViewItem(displayTime(event.maxTime));
|
||||
newRow.last()->setData(QVariant(event.maxTime));
|
||||
}
|
||||
|
||||
if (m_fieldShown[MinTime]) {
|
||||
newRow << new EventsViewItem(displayTime(binding->minTime));
|
||||
newRow.last()->setData(QVariant(binding->minTime));
|
||||
if (d->m_fieldShown[MinTime]) {
|
||||
newRow << new EventsViewItem(displayTime(event.minTime));
|
||||
newRow.last()->setData(QVariant(event.minTime));
|
||||
}
|
||||
|
||||
if (m_fieldShown[Details]) {
|
||||
newRow << new EventsViewItem(binding->details);
|
||||
newRow.last()->setData(QVariant(binding->details));
|
||||
if (d->m_fieldShown[Details]) {
|
||||
newRow << new EventsViewItem(event.details);
|
||||
newRow.last()->setData(QVariant(event.details));
|
||||
}
|
||||
|
||||
|
||||
@@ -669,16 +586,17 @@ void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFrom
|
||||
item->setEditable(false);
|
||||
|
||||
// metadata
|
||||
newRow.at(0)->setData(QVariant(binding->eventHashStr),EventHashStrRole);
|
||||
newRow.at(0)->setData(QVariant(binding->location.filename),FilenameRole);
|
||||
newRow.at(0)->setData(QVariant(binding->location.line),LineRole);
|
||||
newRow.at(0)->setData(QVariant(binding->location.column),ColumnRole);
|
||||
newRow.at(0)->setData(QVariant(binding->eventId),EventIdRole);
|
||||
if (binding->isBindingLoop)
|
||||
newRow.at(0)->setData(QVariant(event.eventHashStr),EventHashStrRole);
|
||||
newRow.at(0)->setData(QVariant(event.location.filename),FilenameRole);
|
||||
newRow.at(0)->setData(QVariant(event.location.line),LineRole);
|
||||
newRow.at(0)->setData(QVariant(event.location.column),ColumnRole);
|
||||
|
||||
if (event.isBindingLoop) {
|
||||
foreach (QStandardItem *item, newRow) {
|
||||
item->setBackground(colors()->bindingLoopBackground);
|
||||
item->setToolTip(tr("Binding loop detected."));
|
||||
}
|
||||
}
|
||||
|
||||
// append
|
||||
parentItem->appendRow(newRow);
|
||||
@@ -686,58 +604,6 @@ void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFrom
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildV8ModelFromList(const QList<QV8EventData *> &list)
|
||||
{
|
||||
for (int index = 0; index < list.count(); index++) {
|
||||
QV8EventData *v8event = list.at(index);
|
||||
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(QString::fromLatin1("%1:%2").arg(v8event->filename, QString::number(v8event->line)), EventHashStrRole);
|
||||
newRow.at(0)->setData(QVariant(v8event->filename), FilenameRole);
|
||||
newRow.at(0)->setData(QVariant(v8event->line), LineRole);
|
||||
newRow.at(0)->setData(QVariant(0),ColumnRole); // v8 events have no column info
|
||||
newRow.at(0)->setData(QVariant(v8event->eventId), EventIdRole);
|
||||
|
||||
// append
|
||||
m_model->invisibleRootItem()->appendRow(newRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString QmlProfilerEventsMainView::displayTime(double time)
|
||||
{
|
||||
if (time < 1e6)
|
||||
@@ -762,26 +628,16 @@ QString QmlProfilerEventsMainView::nameForType(int typeNumber)
|
||||
|
||||
void QmlProfilerEventsMainView::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
|
||||
{
|
||||
if (d->m_profilerDataModel)
|
||||
d->m_profilerDataModel->compileStatistics(rangeStart, rangeEnd);
|
||||
buildModel();
|
||||
d->modelProxy->limitToRange(rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
bool QmlProfilerEventsMainView::isRangeGlobal(qint64 rangeStart, qint64 rangeEnd) const
|
||||
{
|
||||
if (d->m_profilerDataModel)
|
||||
return d->m_profilerDataModel->traceStartTime() == rangeStart && d->m_profilerDataModel->traceEndTime() == rangeEnd;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
int QmlProfilerEventsMainView::selectedEventId() const
|
||||
QString QmlProfilerEventsMainView::selectedEventHash() const
|
||||
{
|
||||
QModelIndex index = selectedItem();
|
||||
if (!index.isValid())
|
||||
return -1;
|
||||
return QString();
|
||||
QStandardItem *item = d->m_model->item(index.row(), 0);
|
||||
return item->data(EventIdRole).toInt();
|
||||
return item->data(EventHashStrRole).toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -806,20 +662,16 @@ void QmlProfilerEventsMainView::jumpToItem(const QModelIndex &index)
|
||||
emit gotoSourceLocation(fileName, line, column);
|
||||
|
||||
// show in callers/callees subwindow
|
||||
emit eventSelected(infoItem->data(EventIdRole).toInt());
|
||||
|
||||
// show in timelinerenderer
|
||||
if (d->m_viewType == EventsView)
|
||||
emit showEventInTimeline(infoItem->data(EventIdRole).toInt());
|
||||
emit eventSelected(infoItem->data(EventHashStrRole).toString());
|
||||
|
||||
d->m_preventSelectBounce = false;
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::selectEvent(int eventId)
|
||||
void QmlProfilerEventsMainView::selectEvent(const QString &eventHash)
|
||||
{
|
||||
for (int i=0; i<d->m_model->rowCount(); i++) {
|
||||
QStandardItem *infoItem = d->m_model->item(i, 0);
|
||||
if (infoItem->data(EventIdRole).toInt() == eventId) {
|
||||
if (infoItem->data(EventHashStrRole).toString() == eventHash) {
|
||||
setCurrentIndex(d->m_model->indexFromItem(infoItem));
|
||||
jumpToItem(currentIndex());
|
||||
return;
|
||||
@@ -827,14 +679,18 @@ void QmlProfilerEventsMainView::selectEvent(int eventId)
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::selectEventByLocation(const QString &filename, int line)
|
||||
void QmlProfilerEventsMainView::selectEventByLocation(const QString &filename, int line, int column)
|
||||
{
|
||||
if (d->m_preventSelectBounce)
|
||||
return;
|
||||
|
||||
for (int i=0; i<d->m_model->rowCount(); i++) {
|
||||
QStandardItem *infoItem = d->m_model->item(i, 0);
|
||||
if (currentIndex() != d->m_model->indexFromItem(infoItem) && infoItem->data(FilenameRole).toString() == filename && infoItem->data(LineRole).toInt() == line) {
|
||||
if (currentIndex() != d->m_model->indexFromItem(infoItem) &&
|
||||
infoItem->data(FilenameRole).toString() == filename &&
|
||||
infoItem->data(LineRole).toInt() == line &&
|
||||
(column == -1 ||
|
||||
infoItem->data(ColumnRole).toInt() == column)) {
|
||||
setCurrentIndex(d->m_model->indexFromItem(infoItem));
|
||||
jumpToItem(currentIndex());
|
||||
return;
|
||||
@@ -851,23 +707,7 @@ QModelIndex QmlProfilerEventsMainView::selectedItem() const
|
||||
return sel.first();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::changeDetailsForEvent(int eventId, const QString &newString)
|
||||
{
|
||||
// available only for QML
|
||||
if (d->m_viewType != EventsView)
|
||||
return;
|
||||
|
||||
for (int i=0; i<d->m_model->rowCount(); i++) {
|
||||
QStandardItem *infoItem = d->m_model->item(i, 0);
|
||||
if (infoItem->data(EventIdRole).toInt() == eventId) {
|
||||
d->m_model->item(i,d->m_columnIndex[Details])->setData(QVariant(newString),Qt::DisplayRole);
|
||||
d->m_model->item(i,d->m_columnIndex[Details])->setData(QVariant(newString));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::textForItem(QStandardItem *item, bool recursive = true) const
|
||||
QString QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::textForItem(QStandardItem *item, bool recursive) const
|
||||
{
|
||||
QString str;
|
||||
|
||||
@@ -931,114 +771,82 @@ void QmlProfilerEventsMainView::copyRowToClipboard() const
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QmlProfilerEventsParentsAndChildrenView::QmlProfilerEventsParentsAndChildrenView(
|
||||
SubViewType subtableType, QWidget *parent, QmlProfilerDataModel *model)
|
||||
: QTreeView(parent)
|
||||
class QmlProfilerEventRelativesView::QmlProfilerEventParentsViewPrivate
|
||||
{
|
||||
m_profilerDataModel = model;
|
||||
public:
|
||||
QmlProfilerEventParentsViewPrivate(QmlProfilerEventRelativesView *qq):q(qq) {}
|
||||
~QmlProfilerEventParentsViewPrivate() {}
|
||||
|
||||
QmlProfilerEventRelativesModelProxy *modelProxy;
|
||||
|
||||
QmlProfilerEventRelativesView *q;
|
||||
};
|
||||
|
||||
QmlProfilerEventRelativesView::QmlProfilerEventRelativesView(QmlProfilerModelManager *modelManager, QmlProfilerEventRelativesModelProxy *modelProxy, QWidget *parent)
|
||||
: QmlProfilerTreeView(parent), d(new QmlProfilerEventParentsViewPrivate(this))
|
||||
{
|
||||
Q_UNUSED(modelManager);
|
||||
setSortingEnabled(false);
|
||||
d->modelProxy = modelProxy;
|
||||
setModel(new QStandardItemModel(this));
|
||||
setRootIsDecorated(false);
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
m_subtableType = subtableType;
|
||||
updateHeader();
|
||||
|
||||
connect(this,SIGNAL(clicked(QModelIndex)), this,SLOT(jumpToItem(QModelIndex)));
|
||||
}
|
||||
|
||||
QmlProfilerEventsParentsAndChildrenView::~QmlProfilerEventsParentsAndChildrenView()
|
||||
QmlProfilerEventRelativesView::~QmlProfilerEventRelativesView()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QmlProfilerEventsParentsAndChildrenView::setViewType(SubViewType type)
|
||||
void QmlProfilerEventRelativesView::displayEvent(const QString &eventHash)
|
||||
{
|
||||
m_subtableType = type;
|
||||
updateHeader();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsParentsAndChildrenView::displayEvent(int eventId)
|
||||
{
|
||||
if (!m_profilerDataModel)
|
||||
return;
|
||||
|
||||
bool isV8 = m_subtableType == V8ParentsView || m_subtableType == V8ChildrenView;
|
||||
bool isChildren = m_subtableType == ChildrenView || m_subtableType == V8ChildrenView;
|
||||
|
||||
if (isV8) {
|
||||
QV8EventData *v8event = m_profilerDataModel->v8EventDescription(eventId);
|
||||
if (v8event) {
|
||||
if (isChildren) {
|
||||
QList <QV8EventSub *> childrenList = v8event->childrenHash.values();
|
||||
rebuildTree((QObject *)&childrenList);
|
||||
} else {
|
||||
QList <QV8EventSub *> parentList = v8event->parentHash.values();
|
||||
rebuildTree((QObject *)&parentList);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
QmlRangeEventData *qmlEvent = m_profilerDataModel->eventDescription(eventId);
|
||||
if (qmlEvent) {
|
||||
if (isChildren) {
|
||||
QList <QmlRangeEventRelative *> childrenList = qmlEvent->childrenHash.values();
|
||||
rebuildTree((QObject *)&childrenList);
|
||||
} else {
|
||||
QList <QmlRangeEventRelative *> parentList = qmlEvent->parentHash.values();
|
||||
rebuildTree((QObject *)&parentList);
|
||||
}
|
||||
}
|
||||
}
|
||||
rebuildTree(d->modelProxy->getData(eventHash));
|
||||
|
||||
updateHeader();
|
||||
resizeColumnToContents(0);
|
||||
setSortingEnabled(true);
|
||||
if (isV8)
|
||||
sortByColumn(1);
|
||||
else
|
||||
sortByColumn(2);
|
||||
sortByColumn(2);
|
||||
}
|
||||
|
||||
void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *profilerDataModel)
|
||||
void QmlProfilerEventRelativesView::rebuildTree(QmlProfilerEventRelativesModelProxy::QmlEventRelativesMap eventMap)
|
||||
{
|
||||
Q_ASSERT(treeModel());
|
||||
treeModel()->clear();
|
||||
|
||||
QStandardItem *topLevelItem = treeModel()->invisibleRootItem();
|
||||
bool isV8 = m_subtableType == V8ParentsView || m_subtableType == V8ChildrenView;
|
||||
|
||||
QList <QmlRangeEventRelative *> *qmlList = static_cast< QList <QmlRangeEventRelative *> *>(profilerDataModel);
|
||||
QList <QV8EventSub*> *v8List = static_cast< QList <QV8EventSub *> *>(profilerDataModel);
|
||||
|
||||
int listLength;
|
||||
if (!isV8)
|
||||
listLength = qmlList->length();
|
||||
else
|
||||
listLength = v8List->length();
|
||||
|
||||
for (int index=0; index < listLength; index++) {
|
||||
//foreach (const QmlProfilerEventParentsModelProxy::QmlEventParentData &event, eventMap.values()) {
|
||||
foreach (const QString &key, eventMap.keys()) {
|
||||
const QmlProfilerEventRelativesModelProxy::QmlEventRelativesData &event = eventMap[key];
|
||||
QList<QStandardItem *> newRow;
|
||||
if (!isV8) {
|
||||
QmlRangeEventRelative *event = qmlList->at(index);
|
||||
|
||||
newRow << new EventsViewItem(event->reference->displayName);
|
||||
newRow << new EventsViewItem(QmlProfilerEventsMainView::nameForType(event->reference->eventType));
|
||||
newRow << new EventsViewItem(QmlProfilerEventsMainView::displayTime(event->duration));
|
||||
newRow << new EventsViewItem(QString::number(event->calls));
|
||||
newRow << new EventsViewItem(event->reference->details);
|
||||
newRow.at(0)->setData(QVariant(event->reference->eventId), EventIdRole);
|
||||
newRow.at(2)->setData(QVariant(event->duration));
|
||||
newRow.at(3)->setData(QVariant(event->calls));
|
||||
if (event->inLoopPath)
|
||||
foreach (QStandardItem *item, newRow) {
|
||||
item->setBackground(colors()->bindingLoopBackground);
|
||||
item->setToolTip(tr("Part of binding loop."));
|
||||
}
|
||||
} else {
|
||||
QV8EventSub *event = v8List->at(index);
|
||||
newRow << new EventsViewItem(event->reference->displayName);
|
||||
newRow << new EventsViewItem(QmlProfilerEventsMainView::displayTime(event->totalTime));
|
||||
newRow << new EventsViewItem(event->reference->functionName);
|
||||
newRow.at(0)->setData(QVariant(event->reference->eventId), EventIdRole);
|
||||
newRow.at(1)->setData(QVariant(event->totalTime));
|
||||
// ToDo: here we were going to search for the data in the other modelproxy
|
||||
// maybe we should store the data in this proxy and get it here
|
||||
// no indirections at this level of abstraction!
|
||||
newRow << new EventsViewItem(event.displayName);
|
||||
newRow << new EventsViewItem(QmlProfilerEventsMainView::nameForType(event.eventType));
|
||||
newRow << new EventsViewItem(QmlProfilerEventsMainView::displayTime(event.duration));
|
||||
newRow << new EventsViewItem(QString::number(event.calls));
|
||||
newRow << new EventsViewItem(event.details);
|
||||
|
||||
// newRow << new EventsViewItem(event->reference->displayName);
|
||||
// newRow << new EventsViewItem(QmlProfilerEventsMainView::nameForType(event->reference->eventType));
|
||||
// newRow << new EventsViewItem(QmlProfilerEventsMainView::displayTime(event->duration));
|
||||
// newRow << new EventsViewItem(QString::number(event->calls));
|
||||
// newRow << new EventsViewItem(event->reference->details);
|
||||
newRow.at(0)->setData(QVariant(key), EventHashStrRole);
|
||||
newRow.at(2)->setData(QVariant(event.duration));
|
||||
newRow.at(3)->setData(QVariant(event.calls));
|
||||
|
||||
if (event.isBindingLoop) {
|
||||
foreach (QStandardItem *item, newRow) {
|
||||
item->setBackground(colors()->bindingLoopBackground);
|
||||
item->setToolTip(tr("Part of binding loop."));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (QStandardItem *item, newRow)
|
||||
item->setEditable(false);
|
||||
|
||||
@@ -1046,7 +854,7 @@ void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *profilerDataMode
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEventsParentsAndChildrenView::clear()
|
||||
void QmlProfilerEventRelativesView::clear()
|
||||
{
|
||||
if (treeModel()) {
|
||||
treeModel()->clear();
|
||||
@@ -1054,52 +862,43 @@ void QmlProfilerEventsParentsAndChildrenView::clear()
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEventsParentsAndChildrenView::updateHeader()
|
||||
void QmlProfilerEventRelativesView::updateHeader()
|
||||
{
|
||||
bool isV8 = m_subtableType == V8ParentsView || m_subtableType == V8ChildrenView;
|
||||
bool isChildren = m_subtableType == ChildrenView || m_subtableType == V8ChildrenView;
|
||||
|
||||
header()->setResizeMode(QHeaderView::Interactive);
|
||||
header()->setDefaultSectionSize(100);
|
||||
header()->setMinimumSectionSize(50);
|
||||
bool calleesView = qobject_cast<QmlProfilerEventChildrenModelProxy *>(d->modelProxy) != 0;
|
||||
|
||||
if (treeModel()) {
|
||||
if (isV8)
|
||||
treeModel()->setColumnCount(3);
|
||||
else
|
||||
treeModel()->setColumnCount(5);
|
||||
treeModel()->setColumnCount(5);
|
||||
|
||||
int columnIndex = 0;
|
||||
if (isChildren)
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Callee")));
|
||||
if (calleesView)
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Callee)));
|
||||
else
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Caller")));
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Caller)));
|
||||
|
||||
if (!isV8)
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Type")));
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Type)));
|
||||
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Total Time")));
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(TotalTime)));
|
||||
|
||||
if (!isV8)
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Calls")));
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CallCount)));
|
||||
|
||||
if (isChildren)
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Callee Description")));
|
||||
|
||||
if (calleesView)
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CalleeDescription)));
|
||||
else
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Caller Description")));
|
||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CallerDescription)));
|
||||
}
|
||||
}
|
||||
|
||||
QStandardItemModel *QmlProfilerEventsParentsAndChildrenView::treeModel()
|
||||
QStandardItemModel *QmlProfilerEventRelativesView::treeModel()
|
||||
{
|
||||
return qobject_cast<QStandardItemModel *>(model());
|
||||
}
|
||||
|
||||
void QmlProfilerEventsParentsAndChildrenView::jumpToItem(const QModelIndex &index)
|
||||
void QmlProfilerEventRelativesView::jumpToItem(const QModelIndex &index)
|
||||
{
|
||||
if (treeModel()) {
|
||||
QStandardItem *infoItem = treeModel()->item(index.row(), 0);
|
||||
emit eventClicked(infoItem->data(EventIdRole).toInt());
|
||||
emit eventClicked(infoItem->data(EventHashStrRole).toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -33,7 +33,9 @@
|
||||
#include <QTreeView>
|
||||
#include <QStandardItemModel>
|
||||
#include <qmldebug/qmlprofilereventtypes.h>
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilereventsmodelproxy.h"
|
||||
#include "qmlprofilertreeview.h"
|
||||
|
||||
#include <analyzerbase/ianalyzertool.h>
|
||||
|
||||
@@ -43,7 +45,8 @@ namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerEventsMainView;
|
||||
class QmlProfilerEventsParentsAndChildrenView;
|
||||
class QmlProfilerEventChildrenView;
|
||||
class QmlProfilerEventRelativesView;
|
||||
|
||||
enum ItemRole {
|
||||
EventHashStrRole = Qt::UserRole+1,
|
||||
@@ -60,10 +63,9 @@ public:
|
||||
explicit QmlProfilerEventsWidget(QWidget *parent,
|
||||
QmlProfilerTool *profilerTool,
|
||||
QmlProfilerViewManager *container,
|
||||
QmlProfilerDataModel *profilerDataModel );
|
||||
QmlProfilerModelManager *profilerModelManager );
|
||||
~QmlProfilerEventsWidget();
|
||||
|
||||
void switchToV8View();
|
||||
void clear();
|
||||
|
||||
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
|
||||
@@ -76,16 +78,14 @@ public:
|
||||
void setShowExtendedStatistics(bool show);
|
||||
bool showExtendedStatistics() const;
|
||||
|
||||
bool isQml() const;
|
||||
bool isV8() const;
|
||||
|
||||
signals:
|
||||
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||
void showEventInTimeline(int eventId);
|
||||
void eventSelectedByHash(const QString &eventHash);
|
||||
void resized();
|
||||
|
||||
public slots:
|
||||
void updateSelectedEvent(int eventId) const;
|
||||
void updateSelectedEvent(const QString &eventHash) const;
|
||||
void selectBySourceLocation(const QString &filename, int line, int column);
|
||||
|
||||
private slots:
|
||||
@@ -100,44 +100,15 @@ private:
|
||||
QmlProfilerEventsWidgetPrivate *d;
|
||||
};
|
||||
|
||||
class QmlProfilerEventsMainView : public QTreeView
|
||||
class QmlProfilerEventsMainView : public QmlProfilerTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Fields {
|
||||
Name,
|
||||
Type,
|
||||
Percent,
|
||||
TotalDuration,
|
||||
SelfPercent,
|
||||
SelfDuration,
|
||||
CallCount,
|
||||
TimePerCall,
|
||||
MaxTime,
|
||||
MinTime,
|
||||
MedianTime,
|
||||
Details,
|
||||
|
||||
MaxFields
|
||||
};
|
||||
|
||||
enum ViewTypes {
|
||||
EventsView,
|
||||
CallersView,
|
||||
CalleesView,
|
||||
V8ProfileView,
|
||||
|
||||
MaxViewTypes
|
||||
};
|
||||
|
||||
explicit QmlProfilerEventsMainView(ViewTypes viewType,
|
||||
QWidget *parent,
|
||||
QmlProfilerDataModel *dataModel);
|
||||
explicit QmlProfilerEventsMainView(QWidget *parent,
|
||||
QmlProfilerEventsModelProxy *modelProxy);
|
||||
~QmlProfilerEventsMainView();
|
||||
|
||||
void setFieldViewable(Fields field, bool show);
|
||||
void setViewType(ViewTypes type);
|
||||
ViewTypes viewType() const;
|
||||
void setShowAnonymousEvents( bool showThem );
|
||||
|
||||
QModelIndex selectedItem() const;
|
||||
@@ -148,30 +119,30 @@ public:
|
||||
static QString nameForType(int typeNumber);
|
||||
|
||||
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
|
||||
bool isRangeGlobal(qint64 rangeStart, qint64 rangeEnd) const;
|
||||
int selectedEventId() const;
|
||||
// int selectedEventId() const;
|
||||
QString selectedEventHash() const;
|
||||
|
||||
void setShowExtendedStatistics(bool);
|
||||
bool showExtendedStatistics() const;
|
||||
|
||||
|
||||
signals:
|
||||
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||
void eventSelected(int eventId);
|
||||
void showEventInTimeline(int eventId);
|
||||
void eventSelected(const QString &eventHash);
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
void jumpToItem(const QModelIndex &index);
|
||||
void selectEvent(int eventId);
|
||||
void selectEventByLocation(const QString &filename, int line);
|
||||
void selectEvent(const QString &eventHash);
|
||||
void selectEventByLocation(const QString &filename, int line, int column);
|
||||
void buildModel();
|
||||
void changeDetailsForEvent(int eventId, const QString &newString);
|
||||
|
||||
private slots:
|
||||
void profilerDataModelStateChanged();
|
||||
|
||||
private:
|
||||
void setHeaderLabels();
|
||||
void parseModelProxy();
|
||||
|
||||
private:
|
||||
class QmlProfilerEventsMainViewPrivate;
|
||||
@@ -179,40 +150,31 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class QmlProfilerEventsParentsAndChildrenView : public QTreeView
|
||||
class QmlProfilerEventRelativesView : public QmlProfilerTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum SubViewType {
|
||||
ParentsView,
|
||||
ChildrenView,
|
||||
V8ParentsView,
|
||||
V8ChildrenView,
|
||||
MaxSubtableTypes
|
||||
};
|
||||
|
||||
explicit QmlProfilerEventsParentsAndChildrenView(SubViewType subtableType,
|
||||
QWidget *parent,
|
||||
QmlProfilerDataModel *model);
|
||||
~QmlProfilerEventsParentsAndChildrenView();
|
||||
|
||||
void setViewType(SubViewType type);
|
||||
explicit QmlProfilerEventRelativesView(QmlProfilerModelManager *modelManager,
|
||||
QmlProfilerEventRelativesModelProxy *modelProxy,
|
||||
QWidget *parent );
|
||||
~QmlProfilerEventRelativesView();
|
||||
|
||||
signals:
|
||||
void eventClicked(int eventId);
|
||||
void eventClicked(const QString &eventHash);
|
||||
|
||||
public slots:
|
||||
void displayEvent(int eventId);
|
||||
void displayEvent(const QString &eventHash);
|
||||
void jumpToItem(const QModelIndex &);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
void rebuildTree(void *profilerDataModel);
|
||||
void rebuildTree(QmlProfilerEventParentsModelProxy::QmlEventRelativesMap eventMap);
|
||||
void updateHeader();
|
||||
QStandardItemModel *treeModel();
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
// QmlProfilerModelManager *m_profilerModelManager;
|
||||
|
||||
SubViewType m_subtableType;
|
||||
class QmlProfilerEventParentsViewPrivate;
|
||||
QmlProfilerEventParentsViewPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
364
src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp
Normal file
364
src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp
Normal file
@@ -0,0 +1,364 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilersimplemodel.h"
|
||||
#include "qmlprofilerprocessedmodel.h"
|
||||
#include "qv8profilerdatamodel.h"
|
||||
#include "qmlprofilertracefile.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
QmlProfilerDataState::QmlProfilerDataState(QmlProfilerModelManager *modelManager, QObject *parent)
|
||||
: QObject(parent), m_state(Empty), m_modelManager(modelManager)
|
||||
{
|
||||
connect(this, SIGNAL(error(QString)), m_modelManager, SIGNAL(error(QString)));
|
||||
connect(this, SIGNAL(stateChanged()), m_modelManager, SIGNAL(stateChanged()));
|
||||
}
|
||||
|
||||
void QmlProfilerDataState::setState(QmlProfilerDataState::State state)
|
||||
{
|
||||
// It's not an error, we are continuously calling "AcquiringData" for example
|
||||
if (m_state == state)
|
||||
return;
|
||||
|
||||
switch (state) {
|
||||
case Empty:
|
||||
// if it's not empty, complain but go on
|
||||
QTC_ASSERT(m_modelManager->isEmpty(), /**/);
|
||||
break;
|
||||
case AcquiringData:
|
||||
// we're not supposed to receive new data while processing older data
|
||||
QTC_ASSERT(m_state != ProcessingData, return);
|
||||
break;
|
||||
case ProcessingData:
|
||||
QTC_ASSERT(m_state == AcquiringData, return);
|
||||
break;
|
||||
case Done:
|
||||
QTC_ASSERT(m_state == ProcessingData || m_state == Empty, return);
|
||||
break;
|
||||
default:
|
||||
emit error(tr("Trying to set unknown state in events list"));
|
||||
break;
|
||||
}
|
||||
|
||||
m_state = state;
|
||||
emit stateChanged();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
QmlProfilerTraceTime::QmlProfilerTraceTime(QObject *parent) : QObject(parent)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
QmlProfilerTraceTime::~QmlProfilerTraceTime()
|
||||
{
|
||||
}
|
||||
|
||||
qint64 QmlProfilerTraceTime::startTime() const
|
||||
{
|
||||
return m_startTime;
|
||||
}
|
||||
|
||||
qint64 QmlProfilerTraceTime::endTime() const
|
||||
{
|
||||
return m_endTime;
|
||||
}
|
||||
|
||||
qint64 QmlProfilerTraceTime::duration() const
|
||||
{
|
||||
return endTime() - startTime();
|
||||
}
|
||||
|
||||
void QmlProfilerTraceTime::clear()
|
||||
{
|
||||
m_startTime = -1;
|
||||
m_endTime = 0;
|
||||
}
|
||||
|
||||
void QmlProfilerTraceTime::setStartTime(qint64 time)
|
||||
{
|
||||
m_startTime = time;
|
||||
}
|
||||
|
||||
void QmlProfilerTraceTime::setEndTime(qint64 time)
|
||||
{
|
||||
m_endTime = time;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
class QmlProfilerModelManager::QmlProfilerModelManagerPrivate
|
||||
{
|
||||
public:
|
||||
QmlProfilerModelManagerPrivate(QmlProfilerModelManager *qq) : q(qq) {}
|
||||
~QmlProfilerModelManagerPrivate() {}
|
||||
QmlProfilerModelManager *q;
|
||||
|
||||
QmlProfilerSimpleModel *model;
|
||||
QV8ProfilerDataModel *v8Model;
|
||||
QmlProfilerDataState *dataState;
|
||||
QmlProfilerTraceTime *traceTime;
|
||||
|
||||
QVector <double> partialCounts;
|
||||
double progress;
|
||||
qint64 estimatedTime;
|
||||
|
||||
// file to load
|
||||
QString fileName;
|
||||
};
|
||||
|
||||
|
||||
QmlProfilerModelManager::QmlProfilerModelManager(Utils::FileInProjectFinder *finder, QObject *parent) :
|
||||
QObject(parent), d(new QmlProfilerModelManagerPrivate(this))
|
||||
{
|
||||
d->model = new QmlProfilerProcessedModel(finder, this);
|
||||
d->v8Model = new QV8ProfilerDataModel(this);
|
||||
// d->model = new QmlProfilerSimpleModel(this);
|
||||
d->dataState = new QmlProfilerDataState(this, this);
|
||||
d->traceTime = new QmlProfilerTraceTime(this);
|
||||
}
|
||||
|
||||
QmlProfilerModelManager::~QmlProfilerModelManager()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QmlProfilerTraceTime *QmlProfilerModelManager::traceTime() const
|
||||
{
|
||||
return d->traceTime;
|
||||
}
|
||||
|
||||
QmlProfilerSimpleModel *QmlProfilerModelManager::simpleModel() const
|
||||
{
|
||||
return d->model;
|
||||
}
|
||||
|
||||
QV8ProfilerDataModel *QmlProfilerModelManager::v8Model() const
|
||||
{
|
||||
return d->v8Model;
|
||||
}
|
||||
|
||||
bool QmlProfilerModelManager::isEmpty() const
|
||||
{
|
||||
return d->model->isEmpty() && d->v8Model->isEmpty();
|
||||
}
|
||||
|
||||
int QmlProfilerModelManager::count() const
|
||||
{
|
||||
return d->model->count();
|
||||
}
|
||||
|
||||
double QmlProfilerModelManager::progress() const
|
||||
{
|
||||
return d->progress;
|
||||
}
|
||||
|
||||
int QmlProfilerModelManager::registerModelProxy()
|
||||
{
|
||||
d->partialCounts << 0;
|
||||
return d->partialCounts.count()-1;
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::modelProxyCountUpdated(int proxyId, qint64 count, qint64 max)
|
||||
{
|
||||
d->progress -= d->partialCounts[proxyId] / d->partialCounts.count();
|
||||
|
||||
if (max <= 0)
|
||||
d->partialCounts[proxyId] = 1;
|
||||
else
|
||||
d->partialCounts[proxyId] = (double)count / (double) max;
|
||||
|
||||
d->progress += d->partialCounts[proxyId] / d->partialCounts.count();
|
||||
|
||||
emit progressChanged();
|
||||
if (d->progress > 0.99)
|
||||
emit dataAvailable();
|
||||
}
|
||||
|
||||
qint64 QmlProfilerModelManager::estimatedProfilingTime() const
|
||||
{
|
||||
return d->estimatedTime;
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::newTimeEstimation(qint64 estimation)
|
||||
{
|
||||
d->estimatedTime = estimation;
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::addQmlEvent(int type,
|
||||
int bindingType,
|
||||
qint64 startTime,
|
||||
qint64 length,
|
||||
const QStringList &data,
|
||||
const QmlDebug::QmlEventLocation &location,
|
||||
qint64 ndata1,
|
||||
qint64 ndata2,
|
||||
qint64 ndata3,
|
||||
qint64 ndata4,
|
||||
qint64 ndata5)
|
||||
{
|
||||
// If trace start time was not explicitly set, use the first event
|
||||
if (d->traceTime->startTime() == -1)
|
||||
d->traceTime->setStartTime(startTime);
|
||||
|
||||
QTC_ASSERT(state() == QmlProfilerDataState::AcquiringData, /**/);
|
||||
d->model->addQmlEvent(type, bindingType, startTime, length, data, location, ndata1, ndata2, ndata3, ndata4, ndata5);
|
||||
emit countChanged();
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::addV8Event(int depth, const QString &function, const QString &filename,
|
||||
int lineNumber, double totalTime, double selfTime)
|
||||
{
|
||||
d->v8Model->addV8Event(depth, function, filename, lineNumber,totalTime, selfTime);
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::complete()
|
||||
{
|
||||
if (state() == QmlProfilerDataState::AcquiringData) {
|
||||
// If trace end time was not explicitly set, use the last event
|
||||
if (d->traceTime->endTime() == 0)
|
||||
d->traceTime->setEndTime(d->model->lastTimeMark());
|
||||
setState(QmlProfilerDataState::ProcessingData);
|
||||
d->model->complete();
|
||||
d->v8Model->complete();
|
||||
setState(QmlProfilerDataState::Done);
|
||||
} else
|
||||
if (state() == QmlProfilerDataState::Empty) {
|
||||
setState(QmlProfilerDataState::Done);
|
||||
} else
|
||||
if (state() == QmlProfilerDataState::Done) {
|
||||
// repeated Done states are ignored
|
||||
} else {
|
||||
emit error(tr("Unexpected complete signal in data model"));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::save(const QString &filename)
|
||||
{
|
||||
QFile file(filename);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
emit error(tr("Could not open %1 for writing.").arg(filename));
|
||||
return;
|
||||
}
|
||||
|
||||
QmlProfilerFileWriter writer;
|
||||
|
||||
writer.setTraceTime(traceTime()->startTime(), traceTime()->endTime(), traceTime()->duration());
|
||||
writer.setV8DataModel(d->v8Model);
|
||||
writer.setQmlEvents(d->model->getEvents());
|
||||
writer.save(&file);
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::load(const QString &filename)
|
||||
{
|
||||
d->fileName = filename;
|
||||
load();
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::setFilename(const QString &filename)
|
||||
{
|
||||
d->fileName = filename;
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::load()
|
||||
{
|
||||
QString filename = d->fileName;
|
||||
|
||||
QFile file(filename);
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
emit error(tr("Could not open %1 for reading.").arg(filename));
|
||||
return;
|
||||
}
|
||||
|
||||
// erase current
|
||||
clear();
|
||||
|
||||
setState(QmlProfilerDataState::AcquiringData);
|
||||
|
||||
QmlProfilerFileReader reader;
|
||||
connect(&reader, SIGNAL(error(QString)), this, SIGNAL(error(QString)));
|
||||
connect(&reader, SIGNAL(rangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
|
||||
qint64, qint64, qint64, qint64, qint64)),
|
||||
this, SLOT(addQmlEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation,
|
||||
qint64, qint64, qint64, qint64, qint64)));
|
||||
connect(&reader, SIGNAL(traceStartTime(qint64)), traceTime(), SLOT(setStartTime(qint64)));
|
||||
connect(&reader, SIGNAL(traceEndTime(qint64)), traceTime(), SLOT(setEndTime(qint64)));
|
||||
reader.setV8DataModel(d->v8Model);
|
||||
reader.load(&file);
|
||||
|
||||
complete();
|
||||
}
|
||||
|
||||
|
||||
void QmlProfilerModelManager::setState(QmlProfilerDataState::State state)
|
||||
{
|
||||
d->dataState->setState(state);
|
||||
}
|
||||
|
||||
QmlProfilerDataState::State QmlProfilerModelManager::state() const
|
||||
{
|
||||
return d->dataState->state();
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::clear()
|
||||
{
|
||||
for (int i = 0; i < d->partialCounts.count(); i++)
|
||||
d->partialCounts[i] = 0;
|
||||
d->progress = 0;
|
||||
d->model->clear();
|
||||
d->v8Model->clear();
|
||||
d->traceTime->clear();
|
||||
|
||||
emit countChanged();
|
||||
setState(QmlProfilerDataState::Empty);
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::prepareForWriting()
|
||||
{
|
||||
setState(QmlProfilerDataState::AcquiringData);
|
||||
}
|
||||
|
||||
} // namespace QmlProfiler
|
159
src/plugins/qmlprofiler/qmlprofilermodelmanager.h
Normal file
159
src/plugins/qmlprofiler/qmlprofilermodelmanager.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QMLPROFILERMODELMANAGER_H
|
||||
#define QMLPROFILERMODELMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include "qmlprofiler_global.h"
|
||||
#include "qmldebug/qmlprofilereventlocation.h"
|
||||
#include <utils/fileinprojectfinder.h>
|
||||
|
||||
namespace QmlProfiler {
|
||||
class QmlProfilerSimpleModel;
|
||||
class QmlProfilerModelManager;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class QV8ProfilerDataModel;
|
||||
class QmlProfilerDataState : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum State {
|
||||
Empty,
|
||||
AcquiringData,
|
||||
ProcessingData,
|
||||
Done
|
||||
};
|
||||
|
||||
explicit QmlProfilerDataState(QmlProfilerModelManager *modelManager, QObject *parent = 0);
|
||||
~QmlProfilerDataState() {}
|
||||
|
||||
State state() const { return m_state; }
|
||||
|
||||
signals:
|
||||
void stateChanged();
|
||||
void error(const QString &error);
|
||||
|
||||
private:
|
||||
void setState(State state);
|
||||
State m_state;
|
||||
QmlProfilerModelManager *m_modelManager;
|
||||
|
||||
friend class QmlProfiler::QmlProfilerModelManager;
|
||||
};
|
||||
|
||||
class QmlProfilerTraceTime : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlProfilerTraceTime(QObject *parent);
|
||||
~QmlProfilerTraceTime();
|
||||
|
||||
qint64 startTime() const;
|
||||
qint64 endTime() const;
|
||||
qint64 duration() const;
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
void setStartTime(qint64 time);
|
||||
void setEndTime(qint64 time);
|
||||
|
||||
private:
|
||||
qint64 m_startTime;
|
||||
qint64 m_endTime;
|
||||
};
|
||||
|
||||
} // End internal namespace
|
||||
|
||||
using namespace Internal;
|
||||
|
||||
// Interface between the Data Model and the Engine/Tool
|
||||
class QMLPROFILER_EXPORT QmlProfilerModelManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
explicit QmlProfilerModelManager(Utils::FileInProjectFinder *finder, QObject *parent = 0);
|
||||
~QmlProfilerModelManager();
|
||||
|
||||
QmlProfilerDataState::State state() const;
|
||||
QmlProfilerTraceTime *traceTime() const;
|
||||
QmlProfilerSimpleModel *simpleModel() const;
|
||||
QV8ProfilerDataModel *v8Model() const;
|
||||
|
||||
bool isEmpty() const;
|
||||
int count() const;
|
||||
|
||||
double progress() const;
|
||||
int registerModelProxy();
|
||||
void modelProxyCountUpdated(int proxyId, qint64 count, qint64 max);
|
||||
|
||||
qint64 estimatedProfilingTime() const;
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
void error(const QString &error);
|
||||
void stateChanged();
|
||||
void progressChanged();
|
||||
void dataAvailable();
|
||||
|
||||
void requestDetailsForLocation(int eventType, const QmlDebug::QmlEventLocation &location);
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
|
||||
void prepareForWriting();
|
||||
void addQmlEvent(int type, int bindingType, qint64 startTime, qint64 length,
|
||||
const QStringList &data, const QmlDebug::QmlEventLocation &location,
|
||||
qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5);
|
||||
void addV8Event(int depth, const QString &function,const QString &filename, int lineNumber,
|
||||
double totalTime, double selfTime);
|
||||
|
||||
void complete();
|
||||
|
||||
void save(const QString &filename);
|
||||
void load(const QString &filename);
|
||||
void setFilename(const QString &filename);
|
||||
void load();
|
||||
|
||||
void newTimeEstimation(qint64 estimation);
|
||||
private:
|
||||
void setState(QmlProfilerDataState::State state);
|
||||
|
||||
|
||||
private:
|
||||
class QmlProfilerModelManagerPrivate;
|
||||
QmlProfilerModelManagerPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
458
src/plugins/qmlprofiler/qmlprofilerpainteventsmodelproxy.cpp
Normal file
458
src/plugins/qmlprofiler/qmlprofilerpainteventsmodelproxy.cpp
Normal file
@@ -0,0 +1,458 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmlprofilerpainteventsmodelproxy.h"
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilersimplemodel.h"
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <QVector>
|
||||
#include <QHash>
|
||||
#include <QUrl>
|
||||
#include <QString>
|
||||
#include <QStack>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
struct CategorySpan {
|
||||
bool expanded;
|
||||
int expandedRows;
|
||||
int contractedRows;
|
||||
};
|
||||
|
||||
class PaintEventsModelProxy::PaintEventsModelProxyPrivate
|
||||
{
|
||||
public:
|
||||
PaintEventsModelProxyPrivate(PaintEventsModelProxy *qq) : q(qq) {}
|
||||
~PaintEventsModelProxyPrivate() {}
|
||||
|
||||
QString displayTime(double time);
|
||||
void computeAnimationCountLimit();
|
||||
|
||||
QVector <PaintEventsModelProxy::QmlPaintEventData> eventList;
|
||||
int minAnimationCount;
|
||||
int maxAnimationCount;
|
||||
bool expanded;
|
||||
|
||||
PaintEventsModelProxy *q;
|
||||
};
|
||||
|
||||
PaintEventsModelProxy::PaintEventsModelProxy(QObject *parent)
|
||||
: AbstractTimelineModel(parent), d(new PaintEventsModelProxyPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
PaintEventsModelProxy::~PaintEventsModelProxy()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::categories() const
|
||||
{
|
||||
return categoryCount();
|
||||
}
|
||||
|
||||
QStringList PaintEventsModelProxy::categoryTitles() const
|
||||
{
|
||||
QStringList retString;
|
||||
for (int i=0; i<categories(); i++)
|
||||
retString << categoryLabel(i);
|
||||
return retString;
|
||||
}
|
||||
|
||||
QString PaintEventsModelProxy::name() const
|
||||
{
|
||||
return QLatin1String("PaintEventsModelProxy");
|
||||
}
|
||||
|
||||
const QVector<PaintEventsModelProxy::QmlPaintEventData> PaintEventsModelProxy::getData() const
|
||||
{
|
||||
return d->eventList;
|
||||
}
|
||||
|
||||
const QVector<PaintEventsModelProxy::QmlPaintEventData> PaintEventsModelProxy::getData(qint64 fromTime, qint64 toTime) const
|
||||
{
|
||||
int fromIndex = findFirstIndex(fromTime);
|
||||
int toIndex = findLastIndex(toTime);
|
||||
if (fromIndex != -1 && toIndex > fromIndex)
|
||||
return d->eventList.mid(fromIndex, toIndex - fromIndex + 1);
|
||||
else
|
||||
return QVector<PaintEventsModelProxy::QmlPaintEventData>();
|
||||
}
|
||||
|
||||
void PaintEventsModelProxy::clear()
|
||||
{
|
||||
d->eventList.clear();
|
||||
d->minAnimationCount = 1;
|
||||
d->maxAnimationCount = 1;
|
||||
d->expanded = false;
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1);
|
||||
}
|
||||
|
||||
void PaintEventsModelProxy::dataChanged()
|
||||
{
|
||||
if (m_modelManager->state() == QmlProfilerDataState::ProcessingData)
|
||||
loadData();
|
||||
|
||||
if (m_modelManager->state() == QmlProfilerDataState::Empty)
|
||||
clear();
|
||||
|
||||
emit stateChanged();
|
||||
emit dataAvailable();
|
||||
emit emptyChanged();
|
||||
emit expandedChanged();
|
||||
}
|
||||
|
||||
bool compareStartTimes(const PaintEventsModelProxy::QmlPaintEventData &t1, const PaintEventsModelProxy::QmlPaintEventData &t2)
|
||||
{
|
||||
return t1.startTime < t2.startTime;
|
||||
}
|
||||
|
||||
bool PaintEventsModelProxy::eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const
|
||||
{
|
||||
return (event.eventType == QmlDebug::Painting && event.bindingType == QmlDebug::AnimationFrame);
|
||||
}
|
||||
|
||||
void PaintEventsModelProxy::loadData()
|
||||
{
|
||||
clear();
|
||||
QmlProfilerSimpleModel *simpleModel = m_modelManager->simpleModel();
|
||||
if (simpleModel->isEmpty())
|
||||
return;
|
||||
|
||||
// collect events
|
||||
const QVector<QmlProfilerSimpleModel::QmlEventData> referenceList = simpleModel->getEvents();
|
||||
foreach (const QmlProfilerSimpleModel::QmlEventData &event, referenceList) {
|
||||
if (!eventAccepted(event))
|
||||
continue;
|
||||
|
||||
qint64 estimatedDuration = 0;
|
||||
// initial estimation of the event duration: 1/framerate
|
||||
if (event.numericData1 > 0)
|
||||
estimatedDuration = 1e9/event.numericData1;
|
||||
|
||||
// the profiler registers the animation events at the end of them
|
||||
qint64 realStartTime = event.startTime - estimatedDuration;
|
||||
|
||||
// the duration of the events is estimated from the framerate
|
||||
// we need to correct it before appending a new event
|
||||
if (d->eventList.count() > 0) {
|
||||
QmlPaintEventData *lastEvent = &d->eventList[d->eventList.count()-1];
|
||||
if (lastEvent->startTime + lastEvent->duration >= realStartTime) {
|
||||
// 1 nanosecond less to prevent overlap
|
||||
lastEvent->duration = realStartTime - lastEvent->startTime - 1;
|
||||
lastEvent->framerate = 1e9/lastEvent->duration;
|
||||
}
|
||||
}
|
||||
|
||||
QmlPaintEventData newEvent = {
|
||||
realStartTime,
|
||||
estimatedDuration,
|
||||
(int)event.numericData1,
|
||||
(int)event.numericData2
|
||||
};
|
||||
|
||||
d->eventList.append(newEvent);
|
||||
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, d->eventList.count(), referenceList.count());
|
||||
}
|
||||
|
||||
d->computeAnimationCountLimit();
|
||||
|
||||
qSort(d->eventList.begin(), d->eventList.end(), compareStartTimes);
|
||||
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, 1, 1);
|
||||
|
||||
emit countChanged();
|
||||
}
|
||||
|
||||
/////////////////// QML interface
|
||||
|
||||
bool PaintEventsModelProxy::isEmpty() const
|
||||
{
|
||||
return count() == 0;
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::count() const
|
||||
{
|
||||
return d->eventList.count();
|
||||
}
|
||||
|
||||
qint64 PaintEventsModelProxy::lastTimeMark() const
|
||||
{
|
||||
return d->eventList.last().startTime + d->eventList.last().duration;
|
||||
}
|
||||
|
||||
bool PaintEventsModelProxy::expanded(int ) const
|
||||
{
|
||||
return d->expanded;
|
||||
}
|
||||
|
||||
void PaintEventsModelProxy::setExpanded(int category, bool expanded)
|
||||
{
|
||||
Q_UNUSED(category);
|
||||
d->expanded = expanded;
|
||||
emit expandedChanged();
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::categoryDepth(int categoryIndex) const
|
||||
{
|
||||
Q_UNUSED(categoryIndex);
|
||||
if (isEmpty())
|
||||
return 0;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::categoryCount() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const QString PaintEventsModelProxy::categoryLabel(int categoryIndex) const
|
||||
{
|
||||
Q_UNUSED(categoryIndex);
|
||||
return tr("Painting");
|
||||
}
|
||||
|
||||
|
||||
int PaintEventsModelProxy::findFirstIndex(qint64 startTime) const
|
||||
{
|
||||
return findFirstIndexNoParents(startTime);
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::findFirstIndexNoParents(qint64 startTime) const
|
||||
{
|
||||
if (d->eventList.isEmpty())
|
||||
return -1;
|
||||
if (d->eventList.count() == 1 || d->eventList.first().startTime+d->eventList.first().duration >= startTime)
|
||||
return 0;
|
||||
else
|
||||
if (d->eventList.last().startTime+d->eventList.last().duration <= startTime)
|
||||
return -1;
|
||||
|
||||
int fromIndex = 0;
|
||||
int toIndex = d->eventList.count()-1;
|
||||
while (toIndex - fromIndex > 1) {
|
||||
int midIndex = (fromIndex + toIndex)/2;
|
||||
if (d->eventList[midIndex].startTime + d->eventList[midIndex].duration < startTime)
|
||||
fromIndex = midIndex;
|
||||
else
|
||||
toIndex = midIndex;
|
||||
}
|
||||
return toIndex;
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::findLastIndex(qint64 endTime) const
|
||||
{
|
||||
if (d->eventList.isEmpty())
|
||||
return -1;
|
||||
if (d->eventList.first().startTime >= endTime)
|
||||
return -1;
|
||||
if (d->eventList.count() == 1)
|
||||
return 0;
|
||||
if (d->eventList.last().startTime <= endTime)
|
||||
return d->eventList.count()-1;
|
||||
|
||||
int fromIndex = 0;
|
||||
int toIndex = d->eventList.count()-1;
|
||||
while (toIndex - fromIndex > 1) {
|
||||
int midIndex = (fromIndex + toIndex)/2;
|
||||
if (d->eventList[midIndex].startTime < endTime)
|
||||
fromIndex = midIndex;
|
||||
else
|
||||
toIndex = midIndex;
|
||||
}
|
||||
|
||||
return fromIndex;
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::getEventType(int index) const
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
return (int)QmlDebug::Painting;
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::getEventCategory(int index) const
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
// there is only one category, all events belong to it
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::getEventRow(int index) const
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
return 1;
|
||||
}
|
||||
|
||||
qint64 PaintEventsModelProxy::getDuration(int index) const
|
||||
{
|
||||
return d->eventList[index].duration;
|
||||
}
|
||||
|
||||
qint64 PaintEventsModelProxy::getStartTime(int index) const
|
||||
{
|
||||
return d->eventList[index].startTime;
|
||||
}
|
||||
|
||||
qint64 PaintEventsModelProxy::getEndTime(int index) const
|
||||
{
|
||||
return d->eventList[index].startTime + d->eventList[index].duration;
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::getEventId(int index) const
|
||||
{
|
||||
// there is only one event Id for all painting events
|
||||
Q_UNUSED(index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
QColor PaintEventsModelProxy::getColor(int index) const
|
||||
{
|
||||
double fpsFraction = d->eventList[index].framerate / 60.0;
|
||||
if (fpsFraction > 1.0)
|
||||
fpsFraction = 1.0;
|
||||
if (fpsFraction < 0.0)
|
||||
fpsFraction = 0.0;
|
||||
return QColor::fromHsl((fpsFraction*96)+10, 76, 166);
|
||||
}
|
||||
|
||||
float PaintEventsModelProxy::getHeight(int index) const
|
||||
{
|
||||
float scale = d->maxAnimationCount - d->minAnimationCount;
|
||||
float fraction = 1.0f;
|
||||
if (scale > 1)
|
||||
fraction = (float)(d->eventList[index].animationcount -
|
||||
d->minAnimationCount) / scale;
|
||||
|
||||
return fraction * 0.85f + 0.15f;
|
||||
}
|
||||
|
||||
const QVariantList PaintEventsModelProxy::getLabelsForCategory(int category) const
|
||||
{
|
||||
Q_UNUSED(category);
|
||||
QVariantList result;
|
||||
|
||||
if (!isEmpty()) {
|
||||
QVariantMap element;
|
||||
element.insert(QLatin1String("displayName"), QVariant(QLatin1String("Animations")));
|
||||
element.insert(QLatin1String("description"), QVariant(QLatin1String("Animations")));
|
||||
element.insert(QLatin1String("id"), QVariant(0));
|
||||
result << element;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString PaintEventsModelProxy::PaintEventsModelProxyPrivate::displayTime(double time)
|
||||
{
|
||||
if (time < 1e6)
|
||||
return QString::number(time/1e3,'f',3) + trUtf8(" \xc2\xb5s");
|
||||
if (time < 1e9)
|
||||
return QString::number(time/1e6,'f',3) + tr(" ms");
|
||||
|
||||
return QString::number(time/1e9,'f',3) + tr(" s");
|
||||
}
|
||||
|
||||
void PaintEventsModelProxy::PaintEventsModelProxyPrivate::computeAnimationCountLimit()
|
||||
{
|
||||
minAnimationCount = 1;
|
||||
maxAnimationCount = 1;
|
||||
if (eventList.isEmpty())
|
||||
return;
|
||||
|
||||
for (int i=0; i < eventList.count(); i++) {
|
||||
if (eventList[i].animationcount < minAnimationCount)
|
||||
minAnimationCount = eventList[i].animationcount;
|
||||
if (eventList[i].animationcount > maxAnimationCount)
|
||||
maxAnimationCount = eventList[i].animationcount;
|
||||
}
|
||||
}
|
||||
|
||||
const QVariantList PaintEventsModelProxy::getEventDetails(int index) const
|
||||
{
|
||||
QVariantList result;
|
||||
// int eventId = getEventId(index);
|
||||
|
||||
static const char trContext[] = "RangeDetails";
|
||||
{
|
||||
QVariantMap valuePair;
|
||||
valuePair.insert(QLatin1String("title"), QVariant(categoryLabel(0)));
|
||||
result << valuePair;
|
||||
}
|
||||
|
||||
// duration
|
||||
{
|
||||
QVariantMap valuePair;
|
||||
valuePair.insert(QCoreApplication::translate(trContext, "Duration:"), QVariant(d->displayTime(d->eventList[index].duration)));
|
||||
result << valuePair;
|
||||
}
|
||||
|
||||
// duration
|
||||
{
|
||||
QVariantMap valuePair;
|
||||
valuePair.insert(QCoreApplication::translate(trContext, "Framerate:"), QVariant(QString::fromLatin1("%1 FPS").arg(d->eventList[index].framerate)));
|
||||
result << valuePair;
|
||||
}
|
||||
|
||||
// duration
|
||||
{
|
||||
QVariantMap valuePair;
|
||||
valuePair.insert(QCoreApplication::translate(trContext, "Animations:"), QVariant(QString::fromLatin1("%1").arg(d->eventList[index].animationcount)));
|
||||
result << valuePair;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const QVariantMap PaintEventsModelProxy::getEventLocation(int /*index*/) const
|
||||
{
|
||||
QVariantMap map;
|
||||
return map;
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::getEventIdForHash(const QString &/*eventHash*/) const
|
||||
{
|
||||
// paint events do not have an eventHash
|
||||
return -1;
|
||||
}
|
||||
|
||||
int PaintEventsModelProxy::getEventIdForLocation(const QString &/*filename*/, int /*line*/, int /*column*/) const
|
||||
{
|
||||
// paint events do not have a defined location
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
123
src/plugins/qmlprofiler/qmlprofilerpainteventsmodelproxy.h
Normal file
123
src/plugins/qmlprofiler/qmlprofilerpainteventsmodelproxy.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef QMLPROFILERPAINTEVENTSMODELPROXY_H
|
||||
#define QMLPROFILERPAINTEVENTSMODELPROXY_H
|
||||
|
||||
#include <QObject>
|
||||
#include "abstracttimelinemodel.h"
|
||||
#include <qmldebug/qmlprofilereventtypes.h>
|
||||
#include <qmldebug/qmlprofilereventlocation.h>
|
||||
//#include <QHash>
|
||||
//#include <QVector>
|
||||
#include <QVariantList>
|
||||
//#include <QVariantMap>
|
||||
#include "qmlprofilersimplemodel.h"
|
||||
#include <QColor>
|
||||
|
||||
|
||||
namespace QmlProfiler {
|
||||
class QmlProfilerModelManager;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class PaintEventsModelProxy : public AbstractTimelineModel
|
||||
{
|
||||
// Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged)
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
struct QmlPaintEventData {
|
||||
qint64 startTime;
|
||||
qint64 duration;
|
||||
int framerate;
|
||||
int animationcount;
|
||||
};
|
||||
|
||||
PaintEventsModelProxy(QObject *parent = 0);
|
||||
~PaintEventsModelProxy();
|
||||
|
||||
|
||||
int categories() const;
|
||||
QStringList categoryTitles() const;
|
||||
QString name() const;
|
||||
|
||||
const QVector<QmlPaintEventData> getData() const;
|
||||
const QVector<QmlPaintEventData> getData(qint64 fromTime, qint64 toTime) const;
|
||||
void loadData();
|
||||
Q_INVOKABLE int count() const;
|
||||
void clear();
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
Q_INVOKABLE qint64 lastTimeMark() const;
|
||||
|
||||
Q_INVOKABLE bool expanded(int category) const;
|
||||
Q_INVOKABLE void setExpanded(int category, bool expanded);
|
||||
Q_INVOKABLE int categoryDepth(int categoryIndex) const;
|
||||
Q_INVOKABLE int categoryCount() const;
|
||||
Q_INVOKABLE const QString categoryLabel(int categoryIndex) const;
|
||||
|
||||
int findFirstIndex(qint64 startTime) const;
|
||||
int findFirstIndexNoParents(qint64 startTime) const;
|
||||
int findLastIndex(qint64 endTime) const;
|
||||
|
||||
int getEventType(int index) const;
|
||||
Q_INVOKABLE int getEventCategory(int index) const;
|
||||
int getEventRow(int index) const;
|
||||
Q_INVOKABLE qint64 getDuration(int index) const;
|
||||
Q_INVOKABLE qint64 getStartTime(int index) const;
|
||||
Q_INVOKABLE qint64 getEndTime(int index) const;
|
||||
Q_INVOKABLE int getEventId(int index) const;
|
||||
Q_INVOKABLE QColor getColor(int index) const;
|
||||
Q_INVOKABLE float getHeight(int index) const;
|
||||
|
||||
Q_INVOKABLE const QVariantList getLabelsForCategory(int category) const;
|
||||
Q_INVOKABLE const QVariantList getEventDetails(int index) const;
|
||||
Q_INVOKABLE const QVariantMap getEventLocation(int index) const;
|
||||
Q_INVOKABLE int getEventIdForHash(const QString &eventHash) const;
|
||||
Q_INVOKABLE int getEventIdForLocation(const QString &filename, int line, int column) const;
|
||||
|
||||
private slots:
|
||||
bool eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const;
|
||||
protected slots:
|
||||
void dataChanged();
|
||||
|
||||
private:
|
||||
class PaintEventsModelProxyPrivate;
|
||||
PaintEventsModelProxyPrivate *d;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -31,8 +31,10 @@
|
||||
#include "qmlprofilerruncontrolfactory.h"
|
||||
|
||||
#include "qmlprofilertool.h"
|
||||
#include "abstracttimelinemodel.h"
|
||||
|
||||
#include <analyzerbase/analyzermanager.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <QtPlugin>
|
||||
|
||||
@@ -48,6 +50,7 @@ public:
|
||||
};
|
||||
|
||||
bool QmlProfilerPlugin::debugOutput = false;
|
||||
QmlProfilerPlugin *QmlProfilerPlugin::instance = 0;
|
||||
|
||||
bool QmlProfilerPlugin::initialize(const QStringList &arguments, QString *errorString)
|
||||
{
|
||||
@@ -81,15 +84,14 @@ bool QmlProfilerPlugin::initialize(const QStringList &arguments, QString *errorS
|
||||
AnalyzerManager::addAction(action);
|
||||
|
||||
addAutoReleasedObject(new QmlProfilerRunControlFactory());
|
||||
QmlProfilerPlugin::instance = this;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QmlProfilerPlugin::extensionsInitialized()
|
||||
{
|
||||
// Retrieve objects from the plugin manager's object pool.
|
||||
// "In the extensionsInitialized method, a plugin can be sure that all
|
||||
// plugins that depend on it are completely initialized."
|
||||
timelineModels = ExtensionSystem::PluginManager::getObjects<AbstractTimelineModel>();
|
||||
}
|
||||
|
||||
ExtensionSystem::IPlugin::ShutdownFlag QmlProfilerPlugin::aboutToShutdown()
|
||||
@@ -100,8 +102,12 @@ ExtensionSystem::IPlugin::ShutdownFlag QmlProfilerPlugin::aboutToShutdown()
|
||||
return SynchronousShutdown;
|
||||
}
|
||||
|
||||
QList<AbstractTimelineModel *> QmlProfilerPlugin::getModels() const
|
||||
{
|
||||
return timelineModels;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
Q_EXPORT_PLUGIN(QmlProfiler::Internal::QmlProfilerPlugin)
|
||||
|
||||
|
@@ -34,6 +34,8 @@
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
|
||||
#include "abstracttimelinemodel.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
@@ -50,6 +52,14 @@ public:
|
||||
ShutdownFlag aboutToShutdown();
|
||||
|
||||
static bool debugOutput;
|
||||
static QmlProfilerPlugin *instance;
|
||||
|
||||
QList<AbstractTimelineModel *> getModels() const;
|
||||
|
||||
private:
|
||||
QList<AbstractTimelineModel*> timelineModels;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
182
src/plugins/qmlprofiler/qmlprofilerprocessedmodel.cpp
Normal file
182
src/plugins/qmlprofiler/qmlprofilerprocessedmodel.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmlprofilerprocessedmodel.h"
|
||||
#include <qmldebug/qmlprofilereventtypes.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
QmlDebug::QmlEventLocation getLocation(const QmlProfilerSimpleModel::QmlEventData &event);
|
||||
QString getDisplayName(const QmlProfilerSimpleModel::QmlEventData &event);
|
||||
QString getInitialDetails(const QmlProfilerSimpleModel::QmlEventData &event);
|
||||
|
||||
QmlDebug::QmlEventLocation getLocation(const QmlProfilerSimpleModel::QmlEventData &event)
|
||||
{
|
||||
QmlDebug::QmlEventLocation eventLocation = event.location;
|
||||
if ((event.eventType == QmlDebug::Creating || event.eventType == QmlDebug::Compiling)
|
||||
&& eventLocation.filename.isEmpty()) {
|
||||
eventLocation.filename = getInitialDetails(event);
|
||||
eventLocation.line = 1;
|
||||
eventLocation.column = 1;
|
||||
}
|
||||
return eventLocation;
|
||||
}
|
||||
|
||||
QString getDisplayName(const QmlProfilerSimpleModel::QmlEventData &event)
|
||||
{
|
||||
const QmlDebug::QmlEventLocation eventLocation = getLocation(event);
|
||||
QString displayName;
|
||||
|
||||
// generate hash
|
||||
if (eventLocation.filename.isEmpty()) {
|
||||
displayName = QmlProfilerProcessedModel::tr("<bytecode>");
|
||||
} else {
|
||||
const QString filePath = QUrl(eventLocation.filename).path();
|
||||
displayName = filePath.mid(filePath.lastIndexOf(QLatin1Char('/')) + 1) + QLatin1Char(':') +
|
||||
QString::number(eventLocation.line);
|
||||
}
|
||||
|
||||
return displayName;
|
||||
}
|
||||
|
||||
QString getInitialDetails(const QmlProfilerSimpleModel::QmlEventData &event)
|
||||
{
|
||||
QString details;
|
||||
// generate details string
|
||||
if (event.data.isEmpty())
|
||||
details = QmlProfilerProcessedModel::tr("Source code not available.");
|
||||
else {
|
||||
details = event.data.join(QLatin1String(" ")).replace(QLatin1Char('\n'),QLatin1Char(' ')).simplified();
|
||||
QRegExp rewrite(QLatin1String("\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)"));
|
||||
bool match = rewrite.exactMatch(details);
|
||||
if (match)
|
||||
details = rewrite.cap(1) + QLatin1String(": ") + rewrite.cap(3);
|
||||
if (details.startsWith(QLatin1String("file://")))
|
||||
details = details.mid(details.lastIndexOf(QLatin1Char('/')) + 1);
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
|
||||
bool compareStartTimes(const QmlProfilerSimpleModel::QmlEventData &t1, const QmlProfilerSimpleModel::QmlEventData &t2)
|
||||
{
|
||||
return t1.startTime < t2.startTime;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QmlProfilerProcessedModel::QmlProfilerProcessedModel(Utils::FileInProjectFinder *fileFinder, QObject *parent)
|
||||
: QmlProfilerSimpleModel(parent)
|
||||
, m_detailsRewriter(new QmlProfilerDetailsRewriter(this, fileFinder))
|
||||
, m_emitChanged(false)
|
||||
{
|
||||
connect(m_detailsRewriter, SIGNAL(rewriteDetailsString(int,QString)),
|
||||
this, SLOT(detailsChanged(int,QString)));
|
||||
connect(m_detailsRewriter, SIGNAL(eventDetailsChanged()),
|
||||
this, SLOT(detailsDone()));
|
||||
}
|
||||
|
||||
QmlProfilerProcessedModel::~QmlProfilerProcessedModel()
|
||||
{
|
||||
}
|
||||
|
||||
void QmlProfilerProcessedModel::clear()
|
||||
{
|
||||
m_detailsRewriter->clearRequests();
|
||||
QmlProfilerSimpleModel::clear();
|
||||
|
||||
emit changed();
|
||||
m_emitChanged = false;
|
||||
}
|
||||
|
||||
void QmlProfilerProcessedModel::complete()
|
||||
{
|
||||
// post-processing
|
||||
|
||||
// sort events by start time
|
||||
qSort(eventList.begin(), eventList.end(), compareStartTimes);
|
||||
|
||||
// rewrite strings
|
||||
int n = eventList.count();
|
||||
for (int i = 0; i < n; i++) {
|
||||
QmlEventData *event = &eventList[i];
|
||||
event->location = getLocation(*event);
|
||||
event->displayName = getDisplayName(*event);
|
||||
event->data = QStringList() << getInitialDetails(*event);
|
||||
|
||||
//
|
||||
// request further details from files
|
||||
//
|
||||
|
||||
if (event->eventType != QmlDebug::Binding && event->eventType != QmlDebug::HandlingSignal)
|
||||
continue;
|
||||
|
||||
// This skips anonymous bindings in Qt4.8 (we don't have valid location data for them)
|
||||
if (event->location.filename.isEmpty())
|
||||
continue;
|
||||
|
||||
// Skip non-anonymous bindings from Qt4.8 (we already have correct details for them)
|
||||
if (event->location.column == -1)
|
||||
continue;
|
||||
|
||||
m_detailsRewriter->requestDetailsForLocation(i, event->location);
|
||||
}
|
||||
|
||||
m_detailsRewriter->reloadDocuments();
|
||||
|
||||
QmlProfilerSimpleModel::complete();
|
||||
emit changed();
|
||||
m_emitChanged = false;
|
||||
}
|
||||
|
||||
void QmlProfilerProcessedModel::detailsChanged(int requestId, const QString &newString)
|
||||
{
|
||||
QTC_ASSERT(requestId < eventList.count(), return);
|
||||
|
||||
QmlEventData *event = &eventList[requestId];
|
||||
event->data = QStringList(newString);
|
||||
|
||||
m_emitChanged = true;
|
||||
}
|
||||
|
||||
void QmlProfilerProcessedModel::detailsDone()
|
||||
{
|
||||
if (m_emitChanged) {
|
||||
emit changed();
|
||||
m_emitChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
62
src/plugins/qmlprofiler/qmlprofilerprocessedmodel.h
Normal file
62
src/plugins/qmlprofiler/qmlprofilerprocessedmodel.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QMLPROFILERPROCESSEDMODEL_H
|
||||
#define QMLPROFILERPROCESSEDMODEL_H
|
||||
|
||||
#include "qmlprofilersimplemodel.h"
|
||||
#include "qmlprofilerdetailsrewriter.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerProcessedModel : public QmlProfilerSimpleModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QmlProfilerProcessedModel(Utils::FileInProjectFinder *fileFinder, QObject *parent = 0);
|
||||
~QmlProfilerProcessedModel();
|
||||
|
||||
virtual void clear();
|
||||
virtual void complete();
|
||||
|
||||
private slots:
|
||||
void detailsChanged(int requestId, const QString &newString);
|
||||
void detailsDone();
|
||||
|
||||
private:
|
||||
QmlProfilerDetailsRewriter *m_detailsRewriter;
|
||||
bool m_emitChanged;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
114
src/plugins/qmlprofiler/qmlprofilersimplemodel.cpp
Normal file
114
src/plugins/qmlprofiler/qmlprofilersimplemodel.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmlprofilersimplemodel.h"
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include <QStringList>
|
||||
#include <QVector>
|
||||
#include <QDebug>
|
||||
#include "qmldebug/qmlprofilereventtypes.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
|
||||
QmlProfilerSimpleModel::QmlProfilerSimpleModel(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
m_modelManager = qobject_cast<QmlProfilerModelManager *>(parent);
|
||||
Q_ASSERT(m_modelManager);
|
||||
m_modelId = m_modelManager->registerModelProxy();
|
||||
}
|
||||
|
||||
QmlProfilerSimpleModel::~QmlProfilerSimpleModel()
|
||||
{
|
||||
}
|
||||
|
||||
void QmlProfilerSimpleModel::clear()
|
||||
{
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1);
|
||||
eventList.clear();
|
||||
emit changed();
|
||||
}
|
||||
|
||||
bool QmlProfilerSimpleModel::isEmpty() const
|
||||
{
|
||||
return eventList.isEmpty();
|
||||
}
|
||||
|
||||
const QVector<QmlProfilerSimpleModel::QmlEventData> &QmlProfilerSimpleModel::getEvents() const
|
||||
{
|
||||
return eventList;
|
||||
}
|
||||
|
||||
int QmlProfilerSimpleModel::count() const
|
||||
{
|
||||
return eventList.count();
|
||||
}
|
||||
|
||||
void QmlProfilerSimpleModel::addQmlEvent(int type, int bindingType, qint64 startTime, qint64 duration, const QStringList &data, const QmlDebug::QmlEventLocation &location, qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5)
|
||||
{
|
||||
QString displayName;
|
||||
if (type == QmlDebug::Painting && bindingType == QmlDebug::AnimationFrame) {
|
||||
displayName = tr("Animations");
|
||||
} else {
|
||||
displayName = QString::fromLatin1("%1:%2").arg(
|
||||
location.filename,
|
||||
QString::number(location.line));
|
||||
}
|
||||
|
||||
QmlEventData eventData = {displayName, type, bindingType, startTime, duration, data, location, ndata1, ndata2, ndata3, ndata4, ndata5};
|
||||
eventList.append(eventData);
|
||||
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, startTime, m_modelManager->estimatedProfilingTime());
|
||||
}
|
||||
|
||||
qint64 QmlProfilerSimpleModel::lastTimeMark() const
|
||||
{
|
||||
if (eventList.isEmpty())
|
||||
return 0;
|
||||
|
||||
return eventList.last().startTime + eventList.last().duration;
|
||||
}
|
||||
|
||||
void QmlProfilerSimpleModel::complete()
|
||||
{
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, 1, 1);
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QString QmlProfilerSimpleModel::getHashString(const QmlProfilerSimpleModel::QmlEventData &event)
|
||||
{
|
||||
return QString::fromLatin1("%1:%2:%3:%4:%5").arg(
|
||||
event.location.filename,
|
||||
QString::number(event.location.line),
|
||||
QString::number(event.location.column),
|
||||
QString::number(event.eventType),
|
||||
QString::number(event.bindingType));
|
||||
}
|
||||
|
||||
}
|
88
src/plugins/qmlprofiler/qmlprofilersimplemodel.h
Normal file
88
src/plugins/qmlprofiler/qmlprofilersimplemodel.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QMLPROFILERSIMPLEMODEL_H
|
||||
#define QMLPROFILERSIMPLEMODEL_H
|
||||
|
||||
#include "qmlprofiler_global.h"
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include <QStringList>
|
||||
#include "qmldebug/qmlprofilereventlocation.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
|
||||
class QmlProfilerModelManager;
|
||||
|
||||
// stores the data from the client as-is
|
||||
class QMLPROFILER_EXPORT QmlProfilerSimpleModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct QmlEventData {
|
||||
QString displayName;
|
||||
int eventType;
|
||||
int bindingType;
|
||||
qint64 startTime;
|
||||
qint64 duration;
|
||||
QStringList data;
|
||||
QmlDebug::QmlEventLocation location;
|
||||
qint64 numericData1;
|
||||
qint64 numericData2;
|
||||
qint64 numericData3;
|
||||
qint64 numericData4;
|
||||
qint64 numericData5;
|
||||
};
|
||||
|
||||
explicit QmlProfilerSimpleModel(QObject *parent = 0);
|
||||
~QmlProfilerSimpleModel();
|
||||
|
||||
virtual void clear();
|
||||
bool isEmpty() const;
|
||||
const QVector<QmlEventData> &getEvents() const;
|
||||
int count() const;
|
||||
void addQmlEvent(int type, int bindingType, qint64 startTime, qint64 duration, const QStringList &data, const QmlDebug::QmlEventLocation &location,
|
||||
qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5);
|
||||
qint64 lastTimeMark() const;
|
||||
virtual void complete();
|
||||
|
||||
static QString getHashString(const QmlProfilerSimpleModel::QmlEventData &event);
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
protected:
|
||||
QVector<QmlEventData> eventList;
|
||||
QmlProfilerModelManager *m_modelManager;
|
||||
int m_modelId;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -38,8 +38,7 @@
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
static QString stringForState(int state)
|
||||
{
|
||||
inline QString stringForState(int state) {
|
||||
switch (state) {
|
||||
case QmlProfilerStateManager::Idle: return QLatin1String("Idle");
|
||||
case QmlProfilerStateManager::AppStarting: return QLatin1String("AppStarting");
|
||||
@@ -54,79 +53,92 @@ static QString stringForState(int state)
|
||||
return QString();
|
||||
}
|
||||
|
||||
QmlProfilerStateManager::QmlProfilerStateManager(QObject *parent) :
|
||||
QObject(parent)
|
||||
class QmlProfilerStateManager::QmlProfilerStateManagerPrivate
|
||||
{
|
||||
m_currentState = Idle;
|
||||
m_clientRecording = true;
|
||||
m_serverRecording = false;
|
||||
public:
|
||||
QmlProfilerStateManagerPrivate(QmlProfilerStateManager *qq) : q(qq) {}
|
||||
~QmlProfilerStateManagerPrivate() {}
|
||||
|
||||
QmlProfilerStateManager *q;
|
||||
|
||||
QmlProfilerStateManager::QmlProfilerState m_currentState;
|
||||
bool m_clientRecording;
|
||||
bool m_serverRecording;
|
||||
};
|
||||
QmlProfilerStateManager::QmlProfilerStateManager(QObject *parent) :
|
||||
QObject(parent),d(new QmlProfilerStateManagerPrivate(this))
|
||||
{
|
||||
d->m_currentState = Idle;
|
||||
d->m_clientRecording = true;
|
||||
d->m_serverRecording = false;
|
||||
}
|
||||
|
||||
QmlProfilerStateManager::~QmlProfilerStateManager()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QmlProfilerStateManager::QmlProfilerState QmlProfilerStateManager::currentState() const
|
||||
QmlProfilerStateManager::QmlProfilerState QmlProfilerStateManager::currentState()
|
||||
{
|
||||
return m_currentState;
|
||||
return d->m_currentState;
|
||||
}
|
||||
|
||||
bool QmlProfilerStateManager::clientRecording() const
|
||||
bool QmlProfilerStateManager::clientRecording()
|
||||
{
|
||||
return m_clientRecording;
|
||||
return d->m_clientRecording;
|
||||
}
|
||||
|
||||
bool QmlProfilerStateManager::serverRecording() const
|
||||
bool QmlProfilerStateManager::serverRecording()
|
||||
{
|
||||
return m_serverRecording;
|
||||
return d->m_serverRecording;
|
||||
}
|
||||
|
||||
QString QmlProfilerStateManager::currentStateAsString() const
|
||||
QString QmlProfilerStateManager::currentStateAsString()
|
||||
{
|
||||
return stringForState(m_currentState);
|
||||
return stringForState(d->m_currentState);
|
||||
}
|
||||
|
||||
void QmlProfilerStateManager::setCurrentState(QmlProfilerState newState)
|
||||
{
|
||||
#ifdef _DEBUG_PROFILERSTATE_
|
||||
qDebug() << "Profiler state change request from" << currentStateAsString() << "to" << stringForState(newState);
|
||||
qDebug() << "Profiler state change request from" << stringForState(d->m_currentState) << "to" << stringForState(newState);
|
||||
#endif
|
||||
QTC_ASSERT(m_currentState != newState, /**/);
|
||||
QTC_ASSERT(d->m_currentState != newState, /**/);
|
||||
switch (newState) {
|
||||
case Idle:
|
||||
QTC_ASSERT(m_currentState == AppStarting ||
|
||||
m_currentState == AppStopped ||
|
||||
m_currentState == AppKilled,
|
||||
qDebug() << "from" << currentStateAsString());
|
||||
QTC_ASSERT(d->m_currentState == AppStarting ||
|
||||
d->m_currentState == AppStopped ||
|
||||
d->m_currentState == AppKilled,
|
||||
qDebug() << "from" << stringForState(d->m_currentState));
|
||||
break;
|
||||
case AppStarting:
|
||||
QTC_ASSERT(m_currentState == Idle,
|
||||
qDebug() << "from" << currentStateAsString());
|
||||
QTC_ASSERT(d->m_currentState == Idle,
|
||||
qDebug() << "from" << stringForState(d->m_currentState));
|
||||
break;
|
||||
case AppRunning:
|
||||
QTC_ASSERT(m_currentState == AppStarting,
|
||||
qDebug() << "from" << currentStateAsString());
|
||||
QTC_ASSERT(d->m_currentState == AppStarting,
|
||||
qDebug() << "from" << stringForState(d->m_currentState));
|
||||
break;
|
||||
case AppStopRequested:
|
||||
QTC_ASSERT(m_currentState == AppRunning,
|
||||
qDebug() << "from" << currentStateAsString());
|
||||
QTC_ASSERT(d->m_currentState == AppRunning,
|
||||
qDebug() << "from" << stringForState(d->m_currentState));
|
||||
break;
|
||||
case AppReadyToStop:
|
||||
QTC_ASSERT(m_currentState == AppStopRequested,
|
||||
qDebug() << "from" << currentStateAsString());
|
||||
QTC_ASSERT(d->m_currentState == AppStopRequested,
|
||||
qDebug() << "from" << stringForState(d->m_currentState));
|
||||
break;
|
||||
case AppStopped:
|
||||
QTC_ASSERT(m_currentState == AppReadyToStop ||
|
||||
m_currentState == AppDying,
|
||||
qDebug() << "from" << currentStateAsString());
|
||||
QTC_ASSERT(d->m_currentState == AppReadyToStop ||
|
||||
d->m_currentState == AppDying,
|
||||
qDebug() << "from" << stringForState(d->m_currentState));
|
||||
break;
|
||||
case AppDying:
|
||||
QTC_ASSERT(m_currentState == AppRunning,
|
||||
qDebug() << "from" << currentStateAsString());
|
||||
QTC_ASSERT(d->m_currentState == AppRunning,
|
||||
qDebug() << "from" << stringForState(d->m_currentState));
|
||||
break;
|
||||
case AppKilled:
|
||||
QTC_ASSERT(m_currentState == AppDying,
|
||||
qDebug() << "from" << currentStateAsString());
|
||||
QTC_ASSERT(d->m_currentState == AppDying,
|
||||
qDebug() << "from" << stringForState(d->m_currentState));
|
||||
break;
|
||||
default: {
|
||||
const QString message = QString::fromLatin1("Switching to unknown state in %1:%2").arg(QString::fromLatin1(__FILE__), QString::number(__LINE__));
|
||||
@@ -135,17 +147,17 @@ void QmlProfilerStateManager::setCurrentState(QmlProfilerState newState)
|
||||
break;
|
||||
}
|
||||
|
||||
m_currentState = newState;
|
||||
d->m_currentState = newState;
|
||||
emit stateChanged();
|
||||
}
|
||||
|
||||
void QmlProfilerStateManager::setClientRecording(bool recording)
|
||||
{
|
||||
#ifdef _DEBUG_PROFILERSTATE_
|
||||
qDebug() << "Setting client recording flag from" << m_serverRecording << "to" << recording;
|
||||
qDebug() << "Setting client recording flag from" << d->m_serverRecording << "to" << recording;
|
||||
#endif
|
||||
if (m_clientRecording != recording) {
|
||||
m_clientRecording = recording;
|
||||
if (d->m_clientRecording != recording) {
|
||||
d->m_clientRecording = recording;
|
||||
emit clientRecordingChanged();
|
||||
}
|
||||
}
|
||||
@@ -153,13 +165,13 @@ void QmlProfilerStateManager::setClientRecording(bool recording)
|
||||
void QmlProfilerStateManager::setServerRecording(bool recording)
|
||||
{
|
||||
#ifdef _DEBUG_PROFILERSTATE_
|
||||
qDebug() << "Setting server recording flag from" << m_serverRecording << "to" << recording;
|
||||
qDebug() << "Setting server recording flag from" << d->m_serverRecording << "to" << recording;
|
||||
#endif
|
||||
if (m_serverRecording != recording) {
|
||||
m_serverRecording = recording;
|
||||
if (d->m_serverRecording != recording) {
|
||||
d->m_serverRecording = recording;
|
||||
emit serverRecordingChanged();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
}
|
||||
}
|
||||
|
@@ -38,7 +38,6 @@ namespace Internal {
|
||||
class QmlProfilerStateManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum QmlProfilerState {
|
||||
Idle,
|
||||
@@ -54,11 +53,11 @@ public:
|
||||
explicit QmlProfilerStateManager(QObject *parent = 0);
|
||||
~QmlProfilerStateManager();
|
||||
|
||||
QmlProfilerState currentState() const;
|
||||
bool clientRecording() const;
|
||||
bool serverRecording() const;
|
||||
QmlProfilerState currentState();
|
||||
bool clientRecording();
|
||||
bool serverRecording();
|
||||
|
||||
QString currentStateAsString() const;
|
||||
QString currentStateAsString();
|
||||
|
||||
signals:
|
||||
void stateChanged();
|
||||
@@ -71,12 +70,11 @@ public slots:
|
||||
void setServerRecording(bool recording);
|
||||
|
||||
private:
|
||||
QmlProfilerStateManager::QmlProfilerState m_currentState;
|
||||
bool m_clientRecording;
|
||||
bool m_serverRecording;
|
||||
class QmlProfilerStateManagerPrivate;
|
||||
QmlProfilerStateManagerPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
}
|
||||
}
|
||||
|
||||
#endif // QMLPROFILERSTATEMANAGER_H
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include <QLabel>
|
||||
#include <QProgressBar>
|
||||
#include <QTime>
|
||||
#include <QDebug>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
@@ -49,7 +50,7 @@ class QmlProfilerStateWidget::QmlProfilerStateWidgetPrivate
|
||||
QPixmap shadowPic;
|
||||
|
||||
QmlProfilerStateManager *m_profilerState;
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
QmlProfilerModelManager *m_modelManager;
|
||||
|
||||
bool isRecording;
|
||||
bool appKilled;
|
||||
@@ -60,11 +61,9 @@ class QmlProfilerStateWidget::QmlProfilerStateWidgetPrivate
|
||||
qint64 estimatedProfilingTime;
|
||||
};
|
||||
|
||||
|
||||
|
||||
QmlProfilerStateWidget::QmlProfilerStateWidget(QmlProfilerStateManager *stateManager,
|
||||
QmlProfilerDataModel *dataModel, QWidget *parent) :
|
||||
QWidget(parent), d(new QmlProfilerStateWidgetPrivate(this))
|
||||
QmlProfilerModelManager *modelManager, QWidget *parent)
|
||||
: QWidget(parent), d(new QmlProfilerStateWidgetPrivate(this))
|
||||
{
|
||||
setObjectName(QLatin1String("QML Profiler State Display"));
|
||||
|
||||
@@ -80,6 +79,7 @@ QmlProfilerStateWidget::QmlProfilerStateWidget(QmlProfilerStateManager *stateMan
|
||||
|
||||
d->progressBar = new QProgressBar(this);
|
||||
layout->addWidget(d->progressBar);
|
||||
d->progressBar->setMaximum(1000);
|
||||
d->progressBar->setVisible(false);
|
||||
|
||||
setLayout(layout);
|
||||
@@ -92,9 +92,11 @@ QmlProfilerStateWidget::QmlProfilerStateWidget(QmlProfilerStateManager *stateMan
|
||||
d->emptyList = true;
|
||||
|
||||
// profiler state
|
||||
d->m_profilerDataModel = dataModel;
|
||||
connect(d->m_profilerDataModel,SIGNAL(stateChanged()), this, SLOT(dataStateChanged()));
|
||||
connect(d->m_profilerDataModel,SIGNAL(countChanged()), this, SLOT(dataStateChanged()));
|
||||
d->m_modelManager = modelManager;
|
||||
connect(d->m_modelManager,SIGNAL(stateChanged()), this, SLOT(dataStateChanged()));
|
||||
connect(d->m_modelManager,SIGNAL(countChanged()), this, SLOT(dataStateChanged()));
|
||||
connect(d->m_modelManager,SIGNAL(progressChanged()), this, SLOT(dataStateChanged()));
|
||||
connect(this, SIGNAL(newTimeEstimation(qint64)), d->m_modelManager, SLOT(newTimeEstimation(qint64)));
|
||||
d->m_profilerState = stateManager;
|
||||
connect(d->m_profilerState,SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
|
||||
connect(d->m_profilerState, SIGNAL(serverRecordingChanged()),
|
||||
@@ -196,9 +198,9 @@ void QmlProfilerStateWidget::updateDisplay()
|
||||
if (d->isRecording) {
|
||||
d->isRecording = false;
|
||||
d->estimatedProfilingTime = d->profilingTimer.elapsed();
|
||||
emit newTimeEstimation(d->estimatedProfilingTime);
|
||||
}
|
||||
d->progressBar->setMaximum(d->estimatedProfilingTime);
|
||||
d->progressBar->setValue(d->m_profilerDataModel->lastTimeMark() * 1e-6);
|
||||
d->progressBar->setValue(d->m_modelManager->progress() * 1000);
|
||||
d->progressBar->setVisible(true);
|
||||
resize(300,70);
|
||||
reposition();
|
||||
@@ -232,9 +234,9 @@ void QmlProfilerStateWidget::updateDisplay()
|
||||
if (d->isRecording) {
|
||||
d->isRecording = false;
|
||||
d->estimatedProfilingTime = d->profilingTimer.elapsed();
|
||||
emit newTimeEstimation(d->estimatedProfilingTime);
|
||||
}
|
||||
d->progressBar->setMaximum(d->estimatedProfilingTime);
|
||||
d->progressBar->setValue(d->m_profilerDataModel->lastTimeMark() * 1e-6);
|
||||
d->progressBar->setValue(d->m_modelManager->progress() * 1000);
|
||||
d->progressBar->setVisible(true);
|
||||
resize(300,70);
|
||||
reposition();
|
||||
@@ -252,15 +254,17 @@ void QmlProfilerStateWidget::updateDisplay()
|
||||
// }
|
||||
|
||||
// There is a trace on view, hide this dialog
|
||||
d->progressBar->setVisible(false);
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
void QmlProfilerStateWidget::dataStateChanged()
|
||||
{
|
||||
d->loadingDone = d->m_profilerDataModel->currentState() == QmlProfilerDataModel::Done ||
|
||||
d->m_profilerDataModel->currentState() == QmlProfilerDataModel::Empty;
|
||||
d->traceAvailable = d->m_profilerDataModel->traceDuration() > 0;
|
||||
d->emptyList = d->m_profilerDataModel->count() == 0;
|
||||
// consider possible rounding errors
|
||||
d->loadingDone = d->m_modelManager->progress() >= 0.99 ||
|
||||
d->m_modelManager->state() == QmlProfilerDataState::Empty;
|
||||
d->traceAvailable = d->m_modelManager->traceTime()->duration() > 0;
|
||||
d->emptyList = d->m_modelManager->isEmpty() || d->m_modelManager->progress() == 0;
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
@@ -275,8 +279,11 @@ void QmlProfilerStateWidget::profilerStateChanged()
|
||||
d->isRecording = d->m_profilerState->serverRecording();
|
||||
if (d->isRecording)
|
||||
d->profilingTimer.start();
|
||||
else
|
||||
d->estimatedProfilingTime = d->profilingTimer.elapsed();
|
||||
else {
|
||||
// estimated time in ns
|
||||
d->estimatedProfilingTime = d->profilingTimer.elapsed() * 1e6;
|
||||
emit newTimeEstimation(d->estimatedProfilingTime);
|
||||
}
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
|
@@ -33,7 +33,7 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "qmlprofilerstatemanager.h"
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
@@ -43,7 +43,7 @@ class QmlProfilerStateWidget : public QWidget
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlProfilerStateWidget(QmlProfilerStateManager *stateManager,
|
||||
QmlProfilerDataModel *dataModel, QWidget *parent = 0);
|
||||
QmlProfilerModelManager *modelManager, QWidget *parent = 0);
|
||||
~QmlProfilerStateWidget();
|
||||
|
||||
private slots:
|
||||
@@ -52,6 +52,9 @@ private slots:
|
||||
void profilerStateChanged();
|
||||
void reposition();
|
||||
|
||||
signals:
|
||||
void newTimeEstimation(qint64);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
|
||||
|
721
src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.cpp
Normal file
721
src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.cpp
Normal file
@@ -0,0 +1,721 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmlprofilertimelinemodelproxy.h"
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilersimplemodel.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QVector>
|
||||
#include <QHash>
|
||||
#include <QUrl>
|
||||
#include <QString>
|
||||
#include <QStack>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
struct CategorySpan {
|
||||
bool expanded;
|
||||
int expandedRows;
|
||||
int contractedRows;
|
||||
int rowStart;
|
||||
bool empty;
|
||||
};
|
||||
|
||||
class BasicTimelineModel::BasicTimelineModelPrivate
|
||||
{
|
||||
public:
|
||||
BasicTimelineModelPrivate(BasicTimelineModel *qq) : q(qq) {}
|
||||
~BasicTimelineModelPrivate() {}
|
||||
|
||||
// convenience functions
|
||||
void prepare();
|
||||
void computeNestingContracted();
|
||||
void computeExpandedLevels();
|
||||
void buildEndTimeList();
|
||||
void findBindingLoops();
|
||||
void computeRowStarts();
|
||||
|
||||
QString displayTime(double time);
|
||||
|
||||
QVector <BasicTimelineModel::QmlRangeEventData> eventDict;
|
||||
QVector <QString> eventHashes;
|
||||
QVector <BasicTimelineModel::QmlRangeEventStartInstance> startTimeData;
|
||||
QVector <BasicTimelineModel::QmlRangeEventEndInstance> endTimeData;
|
||||
QVector <CategorySpan> categorySpan;
|
||||
|
||||
BasicTimelineModel *q;
|
||||
};
|
||||
|
||||
BasicTimelineModel::BasicTimelineModel(QObject *parent)
|
||||
: AbstractTimelineModel(parent), d(new BasicTimelineModelPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
BasicTimelineModel::~BasicTimelineModel()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int BasicTimelineModel::categories() const
|
||||
{
|
||||
return categoryCount();
|
||||
}
|
||||
|
||||
QStringList BasicTimelineModel::categoryTitles() const
|
||||
{
|
||||
QStringList retString;
|
||||
for (int i=0; i<categories(); i++)
|
||||
retString << categoryLabel(i);
|
||||
return retString;
|
||||
}
|
||||
|
||||
QString BasicTimelineModel::name() const
|
||||
{
|
||||
return QLatin1String("BasicTimelineModel");
|
||||
}
|
||||
|
||||
const QVector<BasicTimelineModel::QmlRangeEventStartInstance> BasicTimelineModel::getData() const
|
||||
{
|
||||
return d->startTimeData;
|
||||
}
|
||||
|
||||
const QVector<BasicTimelineModel::QmlRangeEventStartInstance> BasicTimelineModel::getData(qint64 fromTime, qint64 toTime) const
|
||||
{
|
||||
int fromIndex = findFirstIndex(fromTime);
|
||||
int toIndex = findLastIndex(toTime);
|
||||
if (fromIndex != -1 && toIndex > fromIndex)
|
||||
return d->startTimeData.mid(fromIndex, toIndex - fromIndex + 1);
|
||||
else
|
||||
return QVector<BasicTimelineModel::QmlRangeEventStartInstance>();
|
||||
}
|
||||
|
||||
void BasicTimelineModel::clear()
|
||||
{
|
||||
d->eventDict.clear();
|
||||
d->eventHashes.clear();
|
||||
d->startTimeData.clear();
|
||||
d->endTimeData.clear();
|
||||
d->categorySpan.clear();
|
||||
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1);
|
||||
}
|
||||
|
||||
void BasicTimelineModel::dataChanged()
|
||||
{
|
||||
if (m_modelManager->state() == QmlProfilerDataState::ProcessingData)
|
||||
loadData();
|
||||
|
||||
if (m_modelManager->state() == QmlProfilerDataState::Empty)
|
||||
clear();
|
||||
|
||||
emit stateChanged();
|
||||
emit dataAvailable();
|
||||
emit emptyChanged();
|
||||
emit expandedChanged();
|
||||
}
|
||||
|
||||
void BasicTimelineModel::BasicTimelineModelPrivate::prepare()
|
||||
{
|
||||
categorySpan.clear();
|
||||
for (int i = 0; i < QmlDebug::MaximumQmlEventType; i++) {
|
||||
CategorySpan newCategory = {false, 1, 1, i, true};
|
||||
categorySpan << newCategory;
|
||||
}
|
||||
}
|
||||
|
||||
bool compareStartTimes(const BasicTimelineModel::QmlRangeEventStartInstance&t1, const BasicTimelineModel::QmlRangeEventStartInstance &t2)
|
||||
{
|
||||
return t1.startTime < t2.startTime;
|
||||
}
|
||||
|
||||
bool compareEndTimes(const BasicTimelineModel::QmlRangeEventEndInstance &t1, const BasicTimelineModel::QmlRangeEventEndInstance &t2)
|
||||
{
|
||||
return t1.endTime < t2.endTime;
|
||||
}
|
||||
|
||||
bool BasicTimelineModel::eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const
|
||||
{
|
||||
// only accept Qt4.x Painting events
|
||||
if (event.eventType == QmlDebug::Painting)
|
||||
return event.bindingType == QmlDebug::QPainterEvent;
|
||||
|
||||
return (event.eventType <= QmlDebug::HandlingSignal);
|
||||
}
|
||||
|
||||
void BasicTimelineModel::loadData()
|
||||
{
|
||||
clear();
|
||||
QmlProfilerSimpleModel *simpleModel = m_modelManager->simpleModel();
|
||||
if (simpleModel->isEmpty())
|
||||
return;
|
||||
|
||||
int lastEventId = 0;
|
||||
|
||||
d->prepare();
|
||||
|
||||
// collect events
|
||||
const QVector<QmlProfilerSimpleModel::QmlEventData> eventList = simpleModel->getEvents();
|
||||
foreach (const QmlProfilerSimpleModel::QmlEventData &event, eventList) {
|
||||
if (!eventAccepted(event))
|
||||
continue;
|
||||
|
||||
QString eventHash = QmlProfilerSimpleModel::getHashString(event);
|
||||
|
||||
// store in dictionary
|
||||
if (!d->eventHashes.contains(eventHash)) {
|
||||
QmlRangeEventData rangeEventData = {
|
||||
event.displayName,
|
||||
event.data.join(QLatin1String(" ")),
|
||||
event.location,
|
||||
(QmlDebug::QmlEventType)event.eventType,
|
||||
lastEventId++ // event id
|
||||
};
|
||||
d->eventDict << rangeEventData;
|
||||
d->eventHashes << eventHash;
|
||||
}
|
||||
|
||||
// store starttime-based instance
|
||||
QmlRangeEventStartInstance eventStartInstance = {
|
||||
event.startTime,
|
||||
event.duration,
|
||||
d->eventHashes.indexOf(eventHash), // event id
|
||||
QmlDebug::Constants::QML_MIN_LEVEL, // displayRowExpanded;
|
||||
QmlDebug::Constants::QML_MIN_LEVEL, // displayRowCollapsed;
|
||||
1,
|
||||
-1 // bindingLoopHead
|
||||
};
|
||||
d->startTimeData.append(eventStartInstance);
|
||||
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, d->startTimeData.count(), eventList.count() * 7);
|
||||
}
|
||||
|
||||
qSort(d->startTimeData.begin(), d->startTimeData.end(), compareStartTimes);
|
||||
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, 2, 7);
|
||||
|
||||
// compute nestingLevel - nonexpanded
|
||||
d->computeNestingContracted();
|
||||
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, 3, 7);
|
||||
|
||||
// compute nestingLevel - expanded
|
||||
d->computeExpandedLevels();
|
||||
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, 4, 7);
|
||||
|
||||
// populate endtimelist
|
||||
d->buildEndTimeList();
|
||||
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, 5, 7);
|
||||
|
||||
d->findBindingLoops();
|
||||
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, 6, 7);
|
||||
|
||||
d->computeRowStarts();
|
||||
|
||||
m_modelManager->modelProxyCountUpdated(m_modelId, 1, 1);
|
||||
|
||||
emit countChanged();
|
||||
}
|
||||
|
||||
void BasicTimelineModel::BasicTimelineModelPrivate::computeNestingContracted()
|
||||
{
|
||||
int i;
|
||||
int eventCount = startTimeData.count();
|
||||
|
||||
QHash<int, qint64> endtimesPerLevel;
|
||||
QList<int> nestingLevels;
|
||||
QList< QHash<int, qint64> > endtimesPerNestingLevel;
|
||||
int level = QmlDebug::Constants::QML_MIN_LEVEL;
|
||||
endtimesPerLevel[QmlDebug::Constants::QML_MIN_LEVEL] = 0;
|
||||
int lastBaseEventIndex = 0;
|
||||
qint64 lastBaseEventEndTime = q->m_modelManager->traceTime()->startTime();
|
||||
|
||||
for (i = 0; i < QmlDebug::MaximumQmlEventType; i++) {
|
||||
nestingLevels << QmlDebug::Constants::QML_MIN_LEVEL;
|
||||
QHash<int, qint64> dummyHash;
|
||||
dummyHash[QmlDebug::Constants::QML_MIN_LEVEL] = 0;
|
||||
endtimesPerNestingLevel << dummyHash;
|
||||
}
|
||||
|
||||
for (i = 0; i < eventCount; i++) {
|
||||
qint64 st = startTimeData[i].startTime;
|
||||
int type = q->getEventType(i);
|
||||
|
||||
// general level
|
||||
if (endtimesPerLevel[level] > st) {
|
||||
level++;
|
||||
} else {
|
||||
while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= st)
|
||||
level--;
|
||||
}
|
||||
endtimesPerLevel[level] = st + startTimeData[i].duration;
|
||||
|
||||
// per type
|
||||
if (endtimesPerNestingLevel[type][nestingLevels[type]] > st) {
|
||||
nestingLevels[type]++;
|
||||
} else {
|
||||
while (nestingLevels[type] > QmlDebug::Constants::QML_MIN_LEVEL &&
|
||||
endtimesPerNestingLevel[type][nestingLevels[type]-1] <= st)
|
||||
nestingLevels[type]--;
|
||||
}
|
||||
endtimesPerNestingLevel[type][nestingLevels[type]] =
|
||||
st + startTimeData[i].duration;
|
||||
|
||||
startTimeData[i].displayRowCollapsed = nestingLevels[type];
|
||||
|
||||
if (level == QmlDebug::Constants::QML_MIN_LEVEL) {
|
||||
if (lastBaseEventEndTime < startTimeData[i].startTime) {
|
||||
lastBaseEventIndex = i;
|
||||
lastBaseEventEndTime = startTimeData[i].startTime + startTimeData[i].duration;
|
||||
}
|
||||
}
|
||||
startTimeData[i].baseEventIndex = lastBaseEventIndex;
|
||||
}
|
||||
|
||||
// nestingdepth
|
||||
for (i = 0; i < eventCount; i++) {
|
||||
int eventType = q->getEventType(i);
|
||||
categorySpan[eventType].empty = false;
|
||||
if (categorySpan[eventType].contractedRows <= startTimeData[i].displayRowCollapsed)
|
||||
categorySpan[eventType].contractedRows = startTimeData[i].displayRowCollapsed + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void BasicTimelineModel::BasicTimelineModelPrivate::computeExpandedLevels()
|
||||
{
|
||||
QHash<int, int> eventRow;
|
||||
int eventCount = startTimeData.count();
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
int eventId = startTimeData[i].eventId;
|
||||
int eventType = eventDict[eventId].eventType;
|
||||
if (!eventRow.contains(eventId)) {
|
||||
categorySpan[eventType].empty = false;
|
||||
eventRow[eventId] = categorySpan[eventType].expandedRows++;
|
||||
}
|
||||
startTimeData[i].displayRowExpanded = eventRow[eventId];
|
||||
}
|
||||
}
|
||||
|
||||
void BasicTimelineModel::BasicTimelineModelPrivate::buildEndTimeList()
|
||||
{
|
||||
endTimeData.clear();
|
||||
|
||||
int eventCount = startTimeData.count();
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
BasicTimelineModel::QmlRangeEventEndInstance endInstance = {
|
||||
i,
|
||||
startTimeData[i].startTime + startTimeData[i].duration
|
||||
};
|
||||
|
||||
endTimeData << endInstance;
|
||||
}
|
||||
|
||||
qSort(endTimeData.begin(), endTimeData.end(), compareEndTimes);
|
||||
}
|
||||
|
||||
void BasicTimelineModel::BasicTimelineModelPrivate::findBindingLoops()
|
||||
{
|
||||
typedef QPair<QString, int> CallStackEntry;
|
||||
QStack<CallStackEntry> callStack;
|
||||
|
||||
for (int i = 0; i < startTimeData.size(); ++i) {
|
||||
QmlRangeEventStartInstance *event = &startTimeData[i];
|
||||
|
||||
BasicTimelineModel::QmlRangeEventData data = eventDict.at(event->eventId);
|
||||
|
||||
static QVector<QmlDebug::QmlEventType> acceptedTypes =
|
||||
QVector<QmlDebug::QmlEventType>() << QmlDebug::Compiling << QmlDebug::Creating
|
||||
<< QmlDebug::Binding << QmlDebug::HandlingSignal;
|
||||
|
||||
if (!acceptedTypes.contains(data.eventType))
|
||||
continue;
|
||||
|
||||
const QString eventHash = eventHashes.at(event->eventId);
|
||||
const QmlRangeEventStartInstance *potentialParent = callStack.isEmpty()
|
||||
? 0 : &startTimeData[callStack.top().second];
|
||||
|
||||
while (potentialParent
|
||||
&& !(potentialParent->startTime + potentialParent->duration > event->startTime)) {
|
||||
callStack.pop();
|
||||
potentialParent = callStack.isEmpty() ? 0
|
||||
: &startTimeData[callStack.top().second];
|
||||
}
|
||||
|
||||
// check whether event is already in stack
|
||||
for (int ii = 0; ii < callStack.size(); ++ii) {
|
||||
if (callStack.at(ii).first == eventHash) {
|
||||
event->bindingLoopHead = callStack.at(ii).second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CallStackEntry newEntry(eventHash, i);
|
||||
callStack.push(newEntry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BasicTimelineModel::BasicTimelineModelPrivate::computeRowStarts()
|
||||
{
|
||||
int rowStart = 0;
|
||||
for (int i = 0; i < categorySpan.count(); i++) {
|
||||
categorySpan[i].rowStart = rowStart;
|
||||
rowStart += q->categoryDepth(i);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////// QML interface
|
||||
|
||||
bool BasicTimelineModel::isEmpty() const
|
||||
{
|
||||
return count() == 0;
|
||||
}
|
||||
|
||||
int BasicTimelineModel::count() const
|
||||
{
|
||||
return d->startTimeData.count();
|
||||
}
|
||||
|
||||
qint64 BasicTimelineModel::lastTimeMark() const
|
||||
{
|
||||
return d->startTimeData.last().startTime + d->startTimeData.last().duration;
|
||||
}
|
||||
|
||||
bool BasicTimelineModel::expanded(int category) const
|
||||
{
|
||||
if (d->categorySpan.count() <= category)
|
||||
return false;
|
||||
return d->categorySpan[category].expanded;
|
||||
}
|
||||
|
||||
void BasicTimelineModel::setExpanded(int category, bool expanded)
|
||||
{
|
||||
if (d->categorySpan.count() <= category)
|
||||
return;
|
||||
|
||||
d->categorySpan[category].expanded = expanded;
|
||||
d->computeRowStarts();
|
||||
emit expandedChanged();
|
||||
}
|
||||
|
||||
int BasicTimelineModel::categoryDepth(int categoryIndex) const
|
||||
{
|
||||
if (d->categorySpan.count() <= categoryIndex)
|
||||
return 1;
|
||||
// special for paint events: show only when empty model or there's actual events
|
||||
if (categoryIndex == QmlDebug::Painting && d->categorySpan[categoryIndex].empty && !isEmpty())
|
||||
return 0;
|
||||
if (d->categorySpan[categoryIndex].expanded)
|
||||
return d->categorySpan[categoryIndex].expandedRows;
|
||||
else
|
||||
return d->categorySpan[categoryIndex].contractedRows;
|
||||
}
|
||||
|
||||
int BasicTimelineModel::categoryCount() const
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
const QString BasicTimelineModel::categoryLabel(int categoryIndex) const
|
||||
{
|
||||
switch (categoryIndex) {
|
||||
case 0: return QCoreApplication::translate("MainView", "Painting"); break;
|
||||
case 1: return QCoreApplication::translate("MainView", "Compiling"); break;
|
||||
case 2: return QCoreApplication::translate("MainView", "Creating"); break;
|
||||
case 3: return QCoreApplication::translate("MainView", "Binding"); break;
|
||||
case 4: return QCoreApplication::translate("MainView", "Handling Signal"); break;
|
||||
default: return QString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int BasicTimelineModel::findFirstIndex(qint64 startTime) const
|
||||
{
|
||||
int candidate = -1;
|
||||
// in the "endtime" list, find the first event that ends after startTime
|
||||
if (d->endTimeData.isEmpty())
|
||||
return -1;
|
||||
if (d->endTimeData.count() == 1 || d->endTimeData.first().endTime >= startTime)
|
||||
candidate = 0;
|
||||
else
|
||||
if (d->endTimeData.last().endTime <= startTime)
|
||||
return -1;
|
||||
|
||||
if (candidate == -1)
|
||||
{
|
||||
int fromIndex = 0;
|
||||
int toIndex = d->endTimeData.count()-1;
|
||||
while (toIndex - fromIndex > 1) {
|
||||
int midIndex = (fromIndex + toIndex)/2;
|
||||
if (d->endTimeData[midIndex].endTime < startTime)
|
||||
fromIndex = midIndex;
|
||||
else
|
||||
toIndex = midIndex;
|
||||
}
|
||||
|
||||
candidate = toIndex;
|
||||
}
|
||||
|
||||
int eventIndex = d->endTimeData[candidate].startTimeIndex;
|
||||
return d->startTimeData[eventIndex].baseEventIndex;
|
||||
|
||||
}
|
||||
|
||||
int BasicTimelineModel::findFirstIndexNoParents(qint64 startTime) const
|
||||
{
|
||||
int candidate = -1;
|
||||
// in the "endtime" list, find the first event that ends after startTime
|
||||
if (d->endTimeData.isEmpty())
|
||||
return -1;
|
||||
if (d->endTimeData.count() == 1 || d->endTimeData.first().endTime >= startTime)
|
||||
candidate = 0;
|
||||
else
|
||||
if (d->endTimeData.last().endTime <= startTime)
|
||||
return -1;
|
||||
|
||||
if (candidate == -1) {
|
||||
int fromIndex = 0;
|
||||
int toIndex = d->endTimeData.count()-1;
|
||||
while (toIndex - fromIndex > 1) {
|
||||
int midIndex = (fromIndex + toIndex)/2;
|
||||
if (d->endTimeData[midIndex].endTime < startTime)
|
||||
fromIndex = midIndex;
|
||||
else
|
||||
toIndex = midIndex;
|
||||
}
|
||||
|
||||
candidate = toIndex;
|
||||
}
|
||||
|
||||
int ndx = d->endTimeData[candidate].startTimeIndex;
|
||||
|
||||
return ndx;
|
||||
}
|
||||
|
||||
int BasicTimelineModel::findLastIndex(qint64 endTime) const
|
||||
{
|
||||
// in the "starttime" list, find the last event that starts before endtime
|
||||
if (d->startTimeData.isEmpty())
|
||||
return -1;
|
||||
if (d->startTimeData.first().startTime >= endTime)
|
||||
return -1;
|
||||
if (d->startTimeData.count() == 1)
|
||||
return 0;
|
||||
if (d->startTimeData.last().startTime <= endTime)
|
||||
return d->startTimeData.count()-1;
|
||||
|
||||
int fromIndex = 0;
|
||||
int toIndex = d->startTimeData.count()-1;
|
||||
while (toIndex - fromIndex > 1) {
|
||||
int midIndex = (fromIndex + toIndex)/2;
|
||||
if (d->startTimeData[midIndex].startTime < endTime)
|
||||
fromIndex = midIndex;
|
||||
else
|
||||
toIndex = midIndex;
|
||||
}
|
||||
|
||||
return fromIndex;
|
||||
}
|
||||
|
||||
int BasicTimelineModel::getEventType(int index) const
|
||||
{
|
||||
return d->eventDict[d->startTimeData[index].eventId].eventType;
|
||||
}
|
||||
|
||||
int BasicTimelineModel::getEventCategory(int index) const
|
||||
{
|
||||
int evTy = getEventType(index);
|
||||
// special: paint events shown?
|
||||
if (d->categorySpan[0].empty && !isEmpty())
|
||||
return evTy - 1;
|
||||
return evTy;
|
||||
}
|
||||
|
||||
int BasicTimelineModel::getEventRow(int index) const
|
||||
{
|
||||
if (d->categorySpan[getEventType(index)].expanded)
|
||||
return d->startTimeData[index].displayRowExpanded + d->categorySpan[getEventType(index)].rowStart;
|
||||
else
|
||||
return d->startTimeData[index].displayRowCollapsed + d->categorySpan[getEventType(index)].rowStart;
|
||||
}
|
||||
|
||||
qint64 BasicTimelineModel::getDuration(int index) const
|
||||
{
|
||||
return d->startTimeData[index].duration;
|
||||
}
|
||||
|
||||
qint64 BasicTimelineModel::getStartTime(int index) const
|
||||
{
|
||||
return d->startTimeData[index].startTime;
|
||||
}
|
||||
|
||||
qint64 BasicTimelineModel::getEndTime(int index) const
|
||||
{
|
||||
return d->startTimeData[index].startTime + d->startTimeData[index].duration;
|
||||
}
|
||||
|
||||
int BasicTimelineModel::getEventId(int index) const
|
||||
{
|
||||
return d->startTimeData[index].eventId;
|
||||
}
|
||||
|
||||
int BasicTimelineModel::getBindingLoopDest(int index) const
|
||||
{
|
||||
return d->startTimeData[index].bindingLoopHead;
|
||||
}
|
||||
|
||||
QColor BasicTimelineModel::getColor(int index) const
|
||||
{
|
||||
int ndx = getEventId(index);
|
||||
return QColor::fromHsl((ndx*25)%360, 76, 166);
|
||||
}
|
||||
|
||||
float BasicTimelineModel::getHeight(int index) const
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
// 100% height for regular events
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
const QVariantList BasicTimelineModel::getLabelsForCategory(int category) const
|
||||
{
|
||||
QVariantList result;
|
||||
|
||||
if (d->categorySpan.count() > category && d->categorySpan[category].expanded) {
|
||||
int eventCount = d->eventDict.count();
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
if (d->eventDict[i].eventType == category) {
|
||||
QVariantMap element;
|
||||
element.insert(QLatin1String("displayName"), QVariant(d->eventDict[i].displayName));
|
||||
element.insert(QLatin1String("description"), QVariant(d->eventDict[i].details));
|
||||
element.insert(QLatin1String("id"), QVariant(d->eventDict[i].eventId));
|
||||
result << element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString BasicTimelineModel::BasicTimelineModelPrivate::displayTime(double time)
|
||||
{
|
||||
if (time < 1e6)
|
||||
return QString::number(time/1e3,'f',3) + trUtf8(" \xc2\xb5s");
|
||||
if (time < 1e9)
|
||||
return QString::number(time/1e6,'f',3) + tr(" ms");
|
||||
|
||||
return QString::number(time/1e9,'f',3) + tr(" s");
|
||||
}
|
||||
|
||||
const QVariantList BasicTimelineModel::getEventDetails(int index) const
|
||||
{
|
||||
QVariantList result;
|
||||
int eventId = getEventId(index);
|
||||
|
||||
static const char trContext[] = "RangeDetails";
|
||||
{
|
||||
QVariantMap valuePair;
|
||||
valuePair.insert(QLatin1String("title"), QVariant(categoryLabel(d->eventDict[eventId].eventType)));
|
||||
result << valuePair;
|
||||
}
|
||||
|
||||
// duration
|
||||
{
|
||||
QVariantMap valuePair;
|
||||
valuePair.insert(QCoreApplication::translate(trContext, "Duration:"), QVariant(d->displayTime(d->startTimeData[index].duration)));
|
||||
result << valuePair;
|
||||
}
|
||||
|
||||
// details
|
||||
{
|
||||
QVariantMap valuePair;
|
||||
QString detailsString = d->eventDict[eventId].details;
|
||||
if (detailsString.length() > 40)
|
||||
detailsString = detailsString.left(40) + QLatin1String("...");
|
||||
valuePair.insert(QCoreApplication::translate(trContext, "Details:"), QVariant(detailsString));
|
||||
result << valuePair;
|
||||
}
|
||||
|
||||
// location
|
||||
{
|
||||
QVariantMap valuePair;
|
||||
valuePair.insert(QCoreApplication::translate(trContext, "Location:"), QVariant(d->eventDict[eventId].displayName));
|
||||
result << valuePair;
|
||||
}
|
||||
|
||||
// isbindingloop
|
||||
{}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const QVariantMap BasicTimelineModel::getEventLocation(int index) const
|
||||
{
|
||||
QVariantMap result;
|
||||
int eventId = getEventId(index);
|
||||
|
||||
QmlDebug::QmlEventLocation location
|
||||
= d->eventDict.at(eventId).location;
|
||||
|
||||
result.insert(QLatin1String("file"), location.filename);
|
||||
result.insert(QLatin1String("line"), location.line);
|
||||
result.insert(QLatin1String("column"), location.column);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int BasicTimelineModel::getEventIdForHash(const QString &eventHash) const
|
||||
{
|
||||
return d->eventHashes.indexOf(eventHash);
|
||||
}
|
||||
|
||||
int BasicTimelineModel::getEventIdForLocation(const QString &filename, int line, int column) const
|
||||
{
|
||||
// if this is called from v8 view, we don't have the column number, it will be -1
|
||||
foreach (const QmlRangeEventData &eventData, d->eventDict) {
|
||||
if (eventData.location.filename == filename &&
|
||||
eventData.location.line == line &&
|
||||
(column == -1 || eventData.location.column == column))
|
||||
return eventData.eventId;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
146
src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.h
Normal file
146
src/plugins/qmlprofiler/qmlprofilertimelinemodelproxy.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef QMLPROFILERTIMELINEMODELPROXY_H
|
||||
#define QMLPROFILERTIMELINEMODELPROXY_H
|
||||
|
||||
#include <QObject>
|
||||
#include "abstracttimelinemodel.h"
|
||||
#include <qmldebug/qmlprofilereventtypes.h>
|
||||
#include <qmldebug/qmlprofilereventlocation.h>
|
||||
//#include <QHash>
|
||||
//#include <QVector>
|
||||
#include <QVariantList>
|
||||
//#include <QVariantMap>
|
||||
#include "qmlprofilersimplemodel.h"
|
||||
#include <QColor>
|
||||
|
||||
|
||||
namespace QmlProfiler {
|
||||
class QmlProfilerModelManager;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class BasicTimelineModel : public AbstractTimelineModel
|
||||
{
|
||||
// Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged)
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct QmlRangeEventData
|
||||
{
|
||||
QString displayName;
|
||||
QString details;
|
||||
QmlDebug::QmlEventLocation location;
|
||||
QmlDebug::QmlEventType eventType;
|
||||
|
||||
int eventId; // separate
|
||||
};
|
||||
|
||||
struct QmlRangeEventStartInstance {
|
||||
qint64 startTime;
|
||||
qint64 duration;
|
||||
int eventId;
|
||||
|
||||
// not-expanded, per type
|
||||
int displayRowExpanded;
|
||||
int displayRowCollapsed;
|
||||
int baseEventIndex; // used by findfirstindex
|
||||
int bindingLoopHead;
|
||||
};
|
||||
|
||||
struct QmlRangeEventEndInstance {
|
||||
int startTimeIndex;
|
||||
qint64 endTime;
|
||||
};
|
||||
|
||||
BasicTimelineModel(QObject *parent = 0);
|
||||
~BasicTimelineModel();
|
||||
|
||||
|
||||
int categories() const;
|
||||
QStringList categoryTitles() const;
|
||||
QString name() const;
|
||||
|
||||
const QVector<QmlRangeEventStartInstance> getData() const;
|
||||
const QVector<QmlRangeEventStartInstance> getData(qint64 fromTime, qint64 toTime) const;
|
||||
void loadData();
|
||||
Q_INVOKABLE int count() const;
|
||||
void clear();
|
||||
|
||||
|
||||
// QML interface
|
||||
bool isEmpty() const;
|
||||
|
||||
Q_INVOKABLE qint64 lastTimeMark() const;
|
||||
|
||||
Q_INVOKABLE bool expanded(int category) const;
|
||||
Q_INVOKABLE void setExpanded(int category, bool expanded);
|
||||
Q_INVOKABLE int categoryDepth(int categoryIndex) const;
|
||||
Q_INVOKABLE int categoryCount() const;
|
||||
Q_INVOKABLE const QString categoryLabel(int categoryIndex) const;
|
||||
|
||||
int findFirstIndex(qint64 startTime) const;
|
||||
int findFirstIndexNoParents(qint64 startTime) const;
|
||||
int findLastIndex(qint64 endTime) const;
|
||||
|
||||
int getEventType(int index) const;
|
||||
int getEventCategory(int index) const;
|
||||
int getEventRow(int index) const;
|
||||
Q_INVOKABLE qint64 getDuration(int index) const;
|
||||
Q_INVOKABLE qint64 getStartTime(int index) const;
|
||||
Q_INVOKABLE qint64 getEndTime(int index) const;
|
||||
Q_INVOKABLE int getEventId(int index) const;
|
||||
int getBindingLoopDest(int index) const;
|
||||
Q_INVOKABLE QColor getColor(int index) const;
|
||||
Q_INVOKABLE float getHeight(int index) const;
|
||||
|
||||
Q_INVOKABLE const QVariantList getLabelsForCategory(int category) const;
|
||||
Q_INVOKABLE const QVariantList getEventDetails(int index) const;
|
||||
Q_INVOKABLE const QVariantMap getEventLocation(int index) const;
|
||||
|
||||
Q_INVOKABLE int getEventIdForHash(const QString &eventHash) const;
|
||||
Q_INVOKABLE int getEventIdForLocation(const QString &filename, int line, int column) const;
|
||||
|
||||
private slots:
|
||||
bool eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const;
|
||||
protected slots:
|
||||
void dataChanged();
|
||||
|
||||
private:
|
||||
class BasicTimelineModelPrivate;
|
||||
BasicTimelineModelPrivate *d;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -34,7 +34,7 @@
|
||||
#include "qmlprofilerattachdialog.h"
|
||||
#include "qmlprofilerviewmanager.h"
|
||||
#include "qmlprofilerclientmanager.h"
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilerdetailsrewriter.h"
|
||||
#include "timelinerenderer.h"
|
||||
|
||||
@@ -98,8 +98,7 @@ class QmlProfilerTool::QmlProfilerToolPrivate
|
||||
public:
|
||||
QmlProfilerStateManager *m_profilerState;
|
||||
QmlProfilerClientManager *m_profilerConnections;
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
QmlProfilerDetailsRewriter *m_detailsRewriter;
|
||||
QmlProfilerModelManager *m_profilerModelManager;
|
||||
|
||||
QmlProfilerViewManager *m_viewContainer;
|
||||
Utils::FileInProjectFinder m_projectFinder;
|
||||
@@ -138,31 +137,11 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
|
||||
d->m_profilerConnections->registerProfilerStateManager(d->m_profilerState);
|
||||
connect(d->m_profilerConnections, SIGNAL(connectionClosed()), this, SLOT(clientsDisconnected()));
|
||||
|
||||
d->m_profilerDataModel = new QmlProfilerDataModel(this);
|
||||
connect(d->m_profilerDataModel, SIGNAL(stateChanged()), this, SLOT(profilerDataModelStateChanged()));
|
||||
connect(d->m_profilerDataModel, SIGNAL(error(QString)), this, SLOT(showErrorDialog(QString)));
|
||||
connect(d->m_profilerConnections,
|
||||
SIGNAL(addRangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation)),
|
||||
d->m_profilerDataModel,
|
||||
SLOT(addRangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation)));
|
||||
connect(d->m_profilerConnections,
|
||||
SIGNAL(addV8Event(int,QString,QString,int,double,double)),
|
||||
d->m_profilerDataModel,
|
||||
SLOT(addV8Event(int,QString,QString,int,double,double)));
|
||||
connect(d->m_profilerConnections, SIGNAL(addFrameEvent(qint64,int,int)), d->m_profilerDataModel, SLOT(addFrameEvent(qint64,int,int)));
|
||||
connect(d->m_profilerConnections, SIGNAL(traceStarted(qint64)), d->m_profilerDataModel, SLOT(setTraceStartTime(qint64)));
|
||||
connect(d->m_profilerConnections, SIGNAL(traceFinished(qint64)), d->m_profilerDataModel, SLOT(setTraceEndTime(qint64)));
|
||||
connect(d->m_profilerConnections, SIGNAL(dataReadyForProcessing()), d->m_profilerDataModel, SLOT(complete()));
|
||||
|
||||
|
||||
d->m_detailsRewriter = new QmlProfilerDetailsRewriter(this, &d->m_projectFinder);
|
||||
connect(d->m_profilerDataModel, SIGNAL(requestDetailsForLocation(int,QmlDebug::QmlEventLocation)),
|
||||
d->m_detailsRewriter, SLOT(requestDetailsForLocation(int,QmlDebug::QmlEventLocation)));
|
||||
connect(d->m_detailsRewriter, SIGNAL(rewriteDetailsString(int,QmlDebug::QmlEventLocation,QString)),
|
||||
d->m_profilerDataModel, SLOT(rewriteDetailsString(int,QmlDebug::QmlEventLocation,QString)));
|
||||
connect(d->m_detailsRewriter, SIGNAL(eventDetailsChanged()), d->m_profilerDataModel, SLOT(finishedRewritingDetails()));
|
||||
connect(d->m_profilerDataModel, SIGNAL(reloadDocumentsForDetails()), d->m_detailsRewriter, SLOT(reloadDocuments()));
|
||||
d->m_profilerModelManager = new QmlProfilerModelManager(&d->m_projectFinder, this);
|
||||
connect(d->m_profilerModelManager, SIGNAL(stateChanged()), this, SLOT(profilerDataModelStateChanged()));
|
||||
connect(d->m_profilerModelManager, SIGNAL(error(QString)), this, SLOT(showErrorDialog(QString)));
|
||||
|
||||
d->m_profilerConnections->setModelManager(d->m_profilerModelManager);
|
||||
Command *command = 0;
|
||||
const Context globalContext(C_GLOBAL);
|
||||
|
||||
@@ -266,7 +245,7 @@ QWidget *QmlProfilerTool::createWidgets()
|
||||
|
||||
d->m_viewContainer = new QmlProfilerViewManager(this,
|
||||
this,
|
||||
d->m_profilerDataModel,
|
||||
d->m_profilerModelManager,
|
||||
d->m_profilerState);
|
||||
connect(d->m_viewContainer, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
this, SLOT(gotoSourceLocation(QString,int,int)));
|
||||
@@ -398,8 +377,9 @@ void QmlProfilerTool::updateTimeDisplay()
|
||||
if (d->m_profilerState->serverRecording() &&
|
||||
d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
|
||||
seconds = d->m_recordingElapsedTime.elapsed() / 1000.0;
|
||||
} else if (d->m_profilerDataModel->currentState() != QmlProfilerDataModel::Empty ) {
|
||||
seconds = (d->m_profilerDataModel->traceEndTime() - d->m_profilerDataModel->traceStartTime()) / 1.0e9;
|
||||
} else if (d->m_profilerModelManager->state() != QmlProfilerDataState::Empty ) {
|
||||
//seconds = d->m_profilerModelManager->traceDuration() / 1.0e9;
|
||||
seconds = d->m_profilerModelManager->traceTime()->duration() / 1.0e9;
|
||||
}
|
||||
QString timeString = QString::number(seconds,'f',1);
|
||||
QString profilerTimeStr = QmlProfilerTool::tr("%1 s").arg(timeString, 6);
|
||||
@@ -408,7 +388,7 @@ void QmlProfilerTool::updateTimeDisplay()
|
||||
|
||||
void QmlProfilerTool::clearData()
|
||||
{
|
||||
d->m_profilerDataModel->clear();
|
||||
d->m_profilerModelManager->clear();
|
||||
d->m_profilerConnections->discardPendingData();
|
||||
}
|
||||
|
||||
@@ -514,7 +494,7 @@ void QmlProfilerTool::showErrorDialog(const QString &error)
|
||||
|
||||
void QmlProfilerTool::showSaveOption()
|
||||
{
|
||||
d->m_saveQmlTrace->setEnabled(!d->m_profilerDataModel->isEmpty());
|
||||
d->m_saveQmlTrace->setEnabled(!d->m_profilerModelManager->isEmpty());
|
||||
}
|
||||
|
||||
void QmlProfilerTool::showSaveDialog()
|
||||
@@ -524,7 +504,7 @@ void QmlProfilerTool::showSaveDialog()
|
||||
if (!filename.isEmpty()) {
|
||||
if (!filename.endsWith(QLatin1String(TraceFileExtension)))
|
||||
filename += QLatin1String(TraceFileExtension);
|
||||
d->m_profilerDataModel->save(filename);
|
||||
d->m_profilerModelManager->save(filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,8 +520,8 @@ void QmlProfilerTool::showLoadDialog()
|
||||
|
||||
if (!filename.isEmpty()) {
|
||||
// delayed load (prevent graphical artifacts due to long load time)
|
||||
d->m_profilerDataModel->setFilename(filename);
|
||||
QTimer::singleShot(100, d->m_profilerDataModel, SLOT(load()));
|
||||
d->m_profilerModelManager->setFilename(filename);
|
||||
QTimer::singleShot(100, d->m_profilerModelManager, SLOT(load()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,7 +529,7 @@ void QmlProfilerTool::clientsDisconnected()
|
||||
{
|
||||
// If the application stopped by itself, check if we have all the data
|
||||
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppDying) {
|
||||
if (d->m_profilerDataModel->currentState() == QmlProfilerDataModel::AcquiringData)
|
||||
if (d->m_profilerModelManager->state() == QmlProfilerDataState::AcquiringData)
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppKilled);
|
||||
else
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppStopped);
|
||||
@@ -557,21 +537,20 @@ void QmlProfilerTool::clientsDisconnected()
|
||||
// ... and return to the "base" state
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
|
||||
}
|
||||
|
||||
// If the connection is closed while the app is still running, no special action is needed
|
||||
}
|
||||
|
||||
void QmlProfilerTool::profilerDataModelStateChanged()
|
||||
{
|
||||
switch (d->m_profilerDataModel->currentState()) {
|
||||
case QmlProfilerDataModel::Empty :
|
||||
switch (d->m_profilerModelManager->state()) {
|
||||
case QmlProfilerDataState::Empty :
|
||||
clearDisplay();
|
||||
break;
|
||||
case QmlProfilerDataModel::AcquiringData :
|
||||
case QmlProfilerDataModel::ProcessingData :
|
||||
case QmlProfilerDataState::AcquiringData :
|
||||
case QmlProfilerDataState::ProcessingData :
|
||||
// nothing to be done for these two
|
||||
break;
|
||||
case QmlProfilerDataModel::Done :
|
||||
case QmlProfilerDataState::Done :
|
||||
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppStopRequested)
|
||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppReadyToStop);
|
||||
showSaveOption();
|
||||
@@ -623,7 +602,7 @@ void QmlProfilerTool::profilerStateChanged()
|
||||
}
|
||||
case QmlProfilerStateManager::AppKilled : {
|
||||
showNonmodalWarning(tr("Application finished before loading profiled data.\nPlease use the stop button instead."));
|
||||
d->m_profilerDataModel->clear();
|
||||
d->m_profilerModelManager->clear();
|
||||
break;
|
||||
}
|
||||
case QmlProfilerStateManager::Idle :
|
||||
@@ -650,9 +629,13 @@ void QmlProfilerTool::serverRecordingChanged()
|
||||
setRecording(d->m_profilerState->serverRecording());
|
||||
// clear the old data each time we start a new profiling session
|
||||
if (d->m_profilerState->serverRecording()) {
|
||||
d->m_clearButton->setEnabled(false);
|
||||
clearData();
|
||||
d->m_profilerDataModel->prepareForWriting();
|
||||
d->m_profilerModelManager->prepareForWriting();
|
||||
} else {
|
||||
d->m_clearButton->setEnabled(true);
|
||||
}
|
||||
} else {
|
||||
d->m_clearButton->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
562
src/plugins/qmlprofiler/qmlprofilertracefile.cpp
Normal file
562
src/plugins/qmlprofiler/qmlprofilertracefile.cpp
Normal file
@@ -0,0 +1,562 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmlprofilertracefile.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QIODevice>
|
||||
#include <QStringList>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QDebug>
|
||||
|
||||
// import QmlEventType, QmlBindingType enums, QmlEventLocation
|
||||
using namespace QmlDebug;
|
||||
|
||||
|
||||
const char PROFILER_FILE_VERSION[] = "1.02";
|
||||
|
||||
const char TYPE_PAINTING_STR[] = "Painting";
|
||||
const char TYPE_COMPILING_STR[] = "Compiling";
|
||||
const char TYPE_CREATING_STR[] = "Creating";
|
||||
const char TYPE_BINDING_STR[] = "Binding";
|
||||
const char TYPE_HANDLINGSIGNAL_STR[] = "HandlingSignal";
|
||||
const char TYPE_PIXMAPCACHE_STR[] = "PixmapCache";
|
||||
const char TYPE_SCENEGRAPH_STR[] = "SceneGraph";
|
||||
|
||||
#define _(X) QLatin1String(X)
|
||||
|
||||
|
||||
//
|
||||
// "be strict in your output but tolerant in your inputs"
|
||||
//
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
static QmlEventType qmlEventTypeAsEnum(const QString &typeString)
|
||||
{
|
||||
if (typeString == _(TYPE_PAINTING_STR)) {
|
||||
return Painting;
|
||||
} else if (typeString == _(TYPE_COMPILING_STR)) {
|
||||
return Compiling;
|
||||
} else if (typeString == _(TYPE_CREATING_STR)) {
|
||||
return Creating;
|
||||
} else if (typeString == _(TYPE_BINDING_STR)) {
|
||||
return Binding;
|
||||
} else if (typeString == _(TYPE_HANDLINGSIGNAL_STR)) {
|
||||
return HandlingSignal;
|
||||
} else if (typeString == _(TYPE_PIXMAPCACHE_STR)) {
|
||||
return PixmapCacheEvent;
|
||||
} else if (typeString == _(TYPE_SCENEGRAPH_STR)) {
|
||||
return SceneGraphFrameEvent;
|
||||
} else {
|
||||
bool isNumber = false;
|
||||
int type = typeString.toUInt(&isNumber);
|
||||
if (isNumber)
|
||||
return (QmlEventType)type;
|
||||
else
|
||||
return MaximumQmlEventType;
|
||||
}
|
||||
}
|
||||
|
||||
static QString qmlEventTypeAsString(QmlEventType typeEnum)
|
||||
{
|
||||
switch (typeEnum) {
|
||||
case Painting:
|
||||
return _(TYPE_PAINTING_STR);
|
||||
break;
|
||||
case Compiling:
|
||||
return _(TYPE_COMPILING_STR);
|
||||
break;
|
||||
case Creating:
|
||||
return _(TYPE_CREATING_STR);
|
||||
break;
|
||||
case Binding:
|
||||
return _(TYPE_BINDING_STR);
|
||||
break;
|
||||
case HandlingSignal:
|
||||
return _(TYPE_HANDLINGSIGNAL_STR);
|
||||
break;
|
||||
case PixmapCacheEvent:
|
||||
return _(TYPE_PIXMAPCACHE_STR);
|
||||
break;
|
||||
case SceneGraphFrameEvent:
|
||||
return _(TYPE_SCENEGRAPH_STR);
|
||||
break;
|
||||
default:
|
||||
return QString::number((int)typeEnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QmlProfilerFileReader::QmlProfilerFileReader(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_v8Model(0)
|
||||
{
|
||||
}
|
||||
|
||||
void QmlProfilerFileReader::setV8DataModel(QV8ProfilerDataModel *dataModel)
|
||||
{
|
||||
m_v8Model = dataModel;
|
||||
}
|
||||
|
||||
bool QmlProfilerFileReader::load(QIODevice *device)
|
||||
{
|
||||
QXmlStreamReader stream(device);
|
||||
|
||||
bool validVersion = true;
|
||||
|
||||
while (validVersion && !stream.atEnd() && !stream.hasError()) {
|
||||
QXmlStreamReader::TokenType token = stream.readNext();
|
||||
QString elementName = stream.name().toString();
|
||||
switch (token) {
|
||||
case QXmlStreamReader::StartDocument : continue;
|
||||
case QXmlStreamReader::StartElement : {
|
||||
if (elementName == _("trace")) {
|
||||
QXmlStreamAttributes attributes = stream.attributes();
|
||||
if (attributes.hasAttribute(_("version")))
|
||||
validVersion = attributes.value(_("version")).toString()
|
||||
== _(PROFILER_FILE_VERSION);
|
||||
else
|
||||
validVersion = false;
|
||||
if (attributes.hasAttribute(_("traceStart")))
|
||||
emit traceStartTime(attributes.value(_("traceStart")).toString().toLongLong());
|
||||
if (attributes.hasAttribute(_("traceEnd")))
|
||||
emit traceEndTime(attributes.value(_("traceEnd")).toString().toLongLong());
|
||||
}
|
||||
|
||||
if (elementName == _("eventData")) {
|
||||
loadEventData(stream);
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("profilerDataModel")) {
|
||||
loadProfilerDataModel(stream);
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("v8profile")) {
|
||||
if (m_v8Model)
|
||||
m_v8Model->load(stream);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stream.hasError()) {
|
||||
emit error(tr("Error while parsing trace data file: %1").arg(stream.errorString()));
|
||||
return false;
|
||||
} else {
|
||||
processQmlEvents();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerFileReader::loadEventData(QXmlStreamReader &stream)
|
||||
{
|
||||
QTC_ASSERT(stream.name().toString() == _("eventData"), return);
|
||||
|
||||
QXmlStreamAttributes attributes = stream.attributes();
|
||||
if (attributes.hasAttribute(_("totalTime"))) {
|
||||
// not used any more
|
||||
}
|
||||
|
||||
int eventIndex = -1;
|
||||
QmlEvent event = {
|
||||
QString(), // displayname
|
||||
QString(), // filename
|
||||
QString(), // details
|
||||
Painting, // type
|
||||
QmlBinding, // bindingType, set for backwards compatibility
|
||||
0, // line
|
||||
0 // column
|
||||
};
|
||||
const QmlEvent defaultEvent = event;
|
||||
|
||||
while (!stream.atEnd() && !stream.hasError()) {
|
||||
QXmlStreamReader::TokenType token = stream.readNext();
|
||||
const QString elementName = stream.name().toString();
|
||||
|
||||
switch (token) {
|
||||
case QXmlStreamReader::StartElement: {
|
||||
if (elementName == _("event")) {
|
||||
event = defaultEvent;
|
||||
|
||||
const QXmlStreamAttributes attributes = stream.attributes();
|
||||
if (attributes.hasAttribute(_("index"))) {
|
||||
eventIndex = attributes.value(_("index")).toString().toInt();
|
||||
} else {
|
||||
// ignore event
|
||||
eventIndex = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
stream.readNext();
|
||||
if (stream.tokenType() != QXmlStreamReader::Characters)
|
||||
break;
|
||||
|
||||
const QString readData = stream.text().toString();
|
||||
|
||||
if (elementName == _("displayname")) {
|
||||
event.displayName = readData;
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("type")) {
|
||||
event.type = qmlEventTypeAsEnum(readData);
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("filename")) {
|
||||
event.filename = readData;
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("line")) {
|
||||
event.line = readData.toInt();
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("column")) {
|
||||
event.column = readData.toInt();
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("details")) {
|
||||
event.details = readData;
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("bindingType") ||
|
||||
elementName == _("animationFrame") ||
|
||||
elementName == _("cacheEventType") ||
|
||||
elementName == _("sgEventType")) {
|
||||
event.bindingType = readData.toInt();
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case QXmlStreamReader::EndElement: {
|
||||
if (elementName == _("event")) {
|
||||
if (eventIndex >= 0) {
|
||||
if (eventIndex >= m_qmlEvents.size())
|
||||
m_qmlEvents.resize(eventIndex + 1);
|
||||
m_qmlEvents[eventIndex] = event;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("eventData")) {
|
||||
// done reading eventData
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
} // switch
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerFileReader::loadProfilerDataModel(QXmlStreamReader &stream)
|
||||
{
|
||||
QTC_ASSERT(stream.name().toString() == _("profilerDataModel"), return);
|
||||
|
||||
while (!stream.atEnd() && !stream.hasError()) {
|
||||
QXmlStreamReader::TokenType token = stream.readNext();
|
||||
const QString elementName = stream.name().toString();
|
||||
|
||||
switch (token) {
|
||||
case QXmlStreamReader::StartElement: {
|
||||
if (elementName == _("range")) {
|
||||
Range range = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
const QXmlStreamAttributes attributes = stream.attributes();
|
||||
if (!attributes.hasAttribute(_("startTime"))
|
||||
|| !attributes.hasAttribute(_("eventIndex"))) {
|
||||
// ignore incomplete entry
|
||||
continue;
|
||||
}
|
||||
|
||||
range.startTime = attributes.value(_("startTime")).toString().toLongLong();
|
||||
if (attributes.hasAttribute(_("duration")))
|
||||
range.duration = attributes.value(_("duration")).toString().toLongLong();
|
||||
|
||||
// attributes for special events
|
||||
if (attributes.hasAttribute(_("framerate")))
|
||||
range.numericData1 = attributes.value(_("framerate")).toString().toLongLong();
|
||||
if (attributes.hasAttribute(_("animationcount")))
|
||||
range.numericData2 = attributes.value(_("animationcount")).toString().toLongLong();
|
||||
if (attributes.hasAttribute(_("width")))
|
||||
range.numericData1 = attributes.value(_("width")).toString().toLongLong();
|
||||
if (attributes.hasAttribute(_("height")))
|
||||
range.numericData2 = attributes.value(_("height")).toString().toLongLong();
|
||||
if (attributes.hasAttribute(_("refCount")))
|
||||
range.numericData3 = attributes.value(_("refCount")).toString().toLongLong();
|
||||
if (attributes.hasAttribute(_("timing1")))
|
||||
range.numericData1 = attributes.value(_("timing1")).toString().toLongLong();
|
||||
if (attributes.hasAttribute(_("timing2")))
|
||||
range.numericData2 = attributes.value(_("timing2")).toString().toLongLong();
|
||||
if (attributes.hasAttribute(_("timing3")))
|
||||
range.numericData3 = attributes.value(_("timing3")).toString().toLongLong();
|
||||
if (attributes.hasAttribute(_("timing4")))
|
||||
range.numericData4 = attributes.value(_("timing4")).toString().toLongLong();
|
||||
if (attributes.hasAttribute(_("timing5")))
|
||||
range.numericData5 = attributes.value(_("timing5")).toString().toLongLong();
|
||||
|
||||
|
||||
int eventIndex = attributes.value(_("eventIndex")).toString().toInt();
|
||||
|
||||
|
||||
m_ranges.append(QPair<Range,int>(range, eventIndex));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QXmlStreamReader::EndElement: {
|
||||
if (elementName == _("profilerDataModel")) {
|
||||
// done reading profilerDataModel
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
} // switch
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerFileReader::processQmlEvents()
|
||||
{
|
||||
for (int i = 0; i < m_ranges.size(); ++i) {
|
||||
Range range = m_ranges[i].first;
|
||||
int eventIndex = m_ranges[i].second;
|
||||
|
||||
if (eventIndex < 0 || eventIndex >= m_qmlEvents.size()) {
|
||||
qWarning() << ".qtd file - range index" << eventIndex
|
||||
<< "is outside of bounds (0, " << m_qmlEvents.size() << ")";
|
||||
continue;
|
||||
}
|
||||
|
||||
QmlEvent &event = m_qmlEvents[eventIndex];
|
||||
|
||||
emit rangedEvent(event.type, event.bindingType, range.startTime, range.duration,
|
||||
QStringList(event.displayName),
|
||||
QmlEventLocation(event.filename, event.line, event.column),
|
||||
range.numericData1,range.numericData2, range.numericData3, range.numericData4, range.numericData5);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
QmlProfilerFileWriter::QmlProfilerFileWriter(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_startTime(0),
|
||||
m_endTime(0),
|
||||
m_measuredTime(0),
|
||||
m_v8Model(0)
|
||||
{
|
||||
m_acceptedTypes << QmlDebug::Compiling << QmlDebug::Creating << QmlDebug::Binding << QmlDebug::HandlingSignal;
|
||||
}
|
||||
|
||||
void QmlProfilerFileWriter::setTraceTime(qint64 startTime, qint64 endTime, qint64 measuredTime)
|
||||
{
|
||||
m_startTime = startTime;
|
||||
m_endTime = endTime;
|
||||
m_measuredTime = measuredTime;
|
||||
}
|
||||
|
||||
void QmlProfilerFileWriter::setV8DataModel(QV8ProfilerDataModel *dataModel)
|
||||
{
|
||||
m_v8Model = dataModel;
|
||||
}
|
||||
|
||||
void QmlProfilerFileWriter::setQmlEvents(const QVector<QmlProfilerSimpleModel::QmlEventData> &events)
|
||||
{
|
||||
foreach (const QmlProfilerSimpleModel::QmlEventData &event, events) {
|
||||
const QString hashStr = QmlProfilerSimpleModel::getHashString(event);
|
||||
if (!m_qmlEvents.contains(hashStr)) {
|
||||
QmlEvent e = { event.displayName,
|
||||
event.location.filename,
|
||||
event.data.join(_("")),
|
||||
static_cast<QmlDebug::QmlEventType>(event.eventType),
|
||||
event.bindingType,
|
||||
event.location.line,
|
||||
event.location.column
|
||||
};
|
||||
m_qmlEvents.insert(hashStr, e);
|
||||
}
|
||||
|
||||
Range r = { event.startTime, event.duration, event.numericData1, event.numericData2, event.numericData3, event.numericData4, event.numericData5 };
|
||||
m_ranges.append(QPair<Range, QString>(r, hashStr));
|
||||
}
|
||||
|
||||
calculateMeasuredTime(events);
|
||||
}
|
||||
|
||||
void QmlProfilerFileWriter::save(QIODevice *device)
|
||||
{
|
||||
QXmlStreamWriter stream(device);
|
||||
|
||||
stream.setAutoFormatting(true);
|
||||
stream.writeStartDocument();
|
||||
|
||||
stream.writeStartElement(_("trace"));
|
||||
stream.writeAttribute(_("version"), _(PROFILER_FILE_VERSION));
|
||||
|
||||
stream.writeAttribute(_("traceStart"), QString::number(m_startTime));
|
||||
stream.writeAttribute(_("traceEnd"), QString::number(m_endTime));
|
||||
|
||||
stream.writeStartElement(_("eventData"));
|
||||
stream.writeAttribute(_("totalTime"), QString::number(m_measuredTime));
|
||||
|
||||
QHash<QString,QmlEvent>::const_iterator eventIter = m_qmlEvents.constBegin();
|
||||
for (; eventIter != m_qmlEvents.constEnd(); ++eventIter) {
|
||||
QmlEvent event = eventIter.value();
|
||||
|
||||
stream.writeStartElement(_("event"));
|
||||
stream.writeAttribute(_("index"), QString::number(m_qmlEvents.keys().indexOf(eventIter.key())));
|
||||
stream.writeTextElement(_("displayname"), event.displayName);
|
||||
stream.writeTextElement(_("type"), qmlEventTypeAsString(event.type));
|
||||
if (!event.filename.isEmpty()) {
|
||||
stream.writeTextElement(_("filename"), event.filename);
|
||||
stream.writeTextElement(_("line"), QString::number(event.line));
|
||||
stream.writeTextElement(_("column"), QString::number(event.column));
|
||||
}
|
||||
stream.writeTextElement(_("details"), event.details);
|
||||
if (event.type == Binding)
|
||||
stream.writeTextElement(_("bindingType"), QString::number(event.bindingType));
|
||||
if (event.type == Painting && event.bindingType == AnimationFrame)
|
||||
stream.writeTextElement(_("animationFrame"), QString::number(event.bindingType));
|
||||
if (event.type == PixmapCacheEvent)
|
||||
stream.writeTextElement(_("cacheEventType"), QString::number(event.bindingType));
|
||||
if (event.type == SceneGraphFrameEvent)
|
||||
stream.writeTextElement(_("sgEventType"), QString::number(event.bindingType));
|
||||
stream.writeEndElement();
|
||||
}
|
||||
stream.writeEndElement(); // eventData
|
||||
|
||||
stream.writeStartElement(_("profilerDataModel"));
|
||||
|
||||
QVector<QPair<Range, QString> >::const_iterator rangeIter = m_ranges.constBegin();
|
||||
for (; rangeIter != m_ranges.constEnd(); ++rangeIter) {
|
||||
Range range = rangeIter->first;
|
||||
QString eventHash = rangeIter->second;
|
||||
|
||||
stream.writeStartElement(_("range"));
|
||||
stream.writeAttribute(_("startTime"), QString::number(range.startTime));
|
||||
if (range.duration > 0) // no need to store duration of instantaneous events
|
||||
stream.writeAttribute(_("duration"), QString::number(range.duration));
|
||||
stream.writeAttribute(_("eventIndex"), QString::number(m_qmlEvents.keys().indexOf(eventHash)));
|
||||
|
||||
QmlEvent event = m_qmlEvents.value(eventHash);
|
||||
|
||||
// special: animation event
|
||||
if (event.type == QmlDebug::Painting && event.bindingType == QmlDebug::AnimationFrame) {
|
||||
|
||||
stream.writeAttribute(_("framerate"), QString::number(range.numericData1));
|
||||
stream.writeAttribute(_("animationcount"), QString::number(range.numericData2));
|
||||
}
|
||||
|
||||
// special: pixmap cache event
|
||||
if (event.type == QmlDebug::PixmapCacheEvent) {
|
||||
// pixmap image size
|
||||
if (event.bindingType == 0) {
|
||||
stream.writeAttribute(_("width"), QString::number(range.numericData1));
|
||||
stream.writeAttribute(_("height"), QString::number(range.numericData2));
|
||||
}
|
||||
|
||||
// reference count (1) / cache size changed (2)
|
||||
if (event.bindingType == 1 || event.bindingType == 2)
|
||||
stream.writeAttribute(_("refCount"), QString::number(range.numericData3));
|
||||
}
|
||||
|
||||
if (event.type == QmlDebug::SceneGraphFrameEvent) {
|
||||
// special: scenegraph frame events
|
||||
if (range.numericData1 > 0)
|
||||
stream.writeAttribute(_("timing1"), QString::number(range.numericData1));
|
||||
if (range.numericData2 > 0)
|
||||
stream.writeAttribute(_("timing2"), QString::number(range.numericData2));
|
||||
if (range.numericData3 > 0)
|
||||
stream.writeAttribute(_("timing3"), QString::number(range.numericData3));
|
||||
if (range.numericData4 > 0)
|
||||
stream.writeAttribute(_("timing4"), QString::number(range.numericData4));
|
||||
if (range.numericData5 > 0)
|
||||
stream.writeAttribute(_("timing5"), QString::number(range.numericData5));
|
||||
}
|
||||
stream.writeEndElement();
|
||||
}
|
||||
stream.writeEndElement(); // profilerDataModel
|
||||
|
||||
m_v8Model->save(stream);
|
||||
|
||||
stream.writeEndElement(); // trace
|
||||
stream.writeEndDocument();
|
||||
}
|
||||
|
||||
void QmlProfilerFileWriter::calculateMeasuredTime(const QVector<QmlProfilerSimpleModel::QmlEventData> &events)
|
||||
{
|
||||
// measured time isn't used, but old clients might still need it
|
||||
// -> we calculate it explicitly
|
||||
|
||||
qint64 duration = 0;
|
||||
|
||||
QHash<int, qint64> endtimesPerLevel;
|
||||
int level = QmlDebug::Constants::QML_MIN_LEVEL;
|
||||
endtimesPerLevel[0] = 0;
|
||||
|
||||
foreach (const QmlProfilerSimpleModel::QmlEventData &event, events) {
|
||||
// whitelist
|
||||
if (!m_acceptedTypes.contains(event.eventType))
|
||||
continue;
|
||||
|
||||
// level computation
|
||||
if (endtimesPerLevel[level] > event.startTime) {
|
||||
level++;
|
||||
} else {
|
||||
while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= event.startTime)
|
||||
level--;
|
||||
}
|
||||
endtimesPerLevel[level] = event.startTime + event.duration;
|
||||
if (level == QmlDebug::Constants::QML_MIN_LEVEL) {
|
||||
duration += event.duration;
|
||||
}
|
||||
}
|
||||
|
||||
m_measuredTime = duration;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
134
src/plugins/qmlprofiler/qmlprofilertracefile.h
Normal file
134
src/plugins/qmlprofiler/qmlprofilertracefile.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QMLPROFILERTRACEFILE_H
|
||||
#define QMLPROFILERTRACEFILE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include <QString>
|
||||
|
||||
#include <qmldebug/qmlprofilereventlocation.h>
|
||||
#include <qmldebug/qmlprofilereventtypes.h>
|
||||
|
||||
#include "qmlprofilersimplemodel.h"
|
||||
#include "qv8profilerdatamodel.h"
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QIODevice)
|
||||
QT_FORWARD_DECLARE_CLASS(QXmlStreamReader)
|
||||
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
|
||||
struct QmlEvent {
|
||||
QString displayName;
|
||||
QString filename;
|
||||
QString details;
|
||||
QmlDebug::QmlEventType type;
|
||||
int bindingType;
|
||||
int line;
|
||||
int column;
|
||||
};
|
||||
|
||||
struct Range {
|
||||
qint64 startTime;
|
||||
qint64 duration;
|
||||
|
||||
// numeric data used by animations, pixmap cache, scenegraph
|
||||
qint64 numericData1;
|
||||
qint64 numericData2;
|
||||
qint64 numericData3;
|
||||
qint64 numericData4;
|
||||
qint64 numericData5;
|
||||
};
|
||||
|
||||
class QmlProfilerFileReader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QmlProfilerFileReader(QObject *parent = 0);
|
||||
|
||||
void setV8DataModel(QV8ProfilerDataModel *dataModel);
|
||||
|
||||
bool load(QIODevice *device);
|
||||
|
||||
signals:
|
||||
void traceStartTime(qint64 traceStartTime);
|
||||
void traceEndTime(qint64 traceStartTime);
|
||||
|
||||
void rangedEvent(int type, int bindingType, qint64 startTime, qint64 length,
|
||||
const QStringList &data, const QmlDebug::QmlEventLocation &location,
|
||||
qint64 param1, qint64 param2, qint64 param3, qint64 param4, qint64 param5);
|
||||
void error(const QString &error);
|
||||
|
||||
private:
|
||||
void loadEventData(QXmlStreamReader &reader);
|
||||
void loadProfilerDataModel(QXmlStreamReader &reader);
|
||||
|
||||
void processQmlEvents();
|
||||
|
||||
|
||||
QV8ProfilerDataModel *m_v8Model;
|
||||
QVector<QmlEvent> m_qmlEvents;
|
||||
QVector<QPair<Range, int> > m_ranges;
|
||||
};
|
||||
|
||||
|
||||
class QmlProfilerFileWriter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QmlProfilerFileWriter(QObject *parent = 0);
|
||||
|
||||
void setTraceTime(qint64 startTime, qint64 endTime, qint64 measturedTime);
|
||||
void setV8DataModel(QV8ProfilerDataModel *dataModel);
|
||||
void setQmlEvents(const QVector<QmlProfilerSimpleModel::QmlEventData> &events);
|
||||
|
||||
void save(QIODevice *device);
|
||||
|
||||
private:
|
||||
void calculateMeasuredTime(const QVector<QmlProfilerSimpleModel::QmlEventData> &events);
|
||||
|
||||
|
||||
qint64 m_startTime, m_endTime, m_measuredTime;
|
||||
QV8ProfilerDataModel *m_v8Model;
|
||||
QHash<QString,QmlEvent> m_qmlEvents;
|
||||
QVector<QPair<Range, QString> > m_ranges;
|
||||
QVector <int> m_acceptedTypes;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
#endif // QMLPROFILERTRACEFILE_H
|
@@ -30,12 +30,14 @@
|
||||
#include "qmlprofilertraceview.h"
|
||||
#include "qmlprofilertool.h"
|
||||
#include "qmlprofilerstatemanager.h"
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilertimelinemodelproxy.h"
|
||||
#include "timelinemodelaggregator.h"
|
||||
|
||||
// Needed for the load&save actions in the context menu
|
||||
#include <analyzerbase/ianalyzertool.h>
|
||||
|
||||
// Comunication with the other views (limit events to range)
|
||||
// Communication with the other views (limit events to range)
|
||||
#include "qmlprofilerviewmanager.h"
|
||||
|
||||
#include <utils/styledbar.h>
|
||||
@@ -119,7 +121,9 @@ public:
|
||||
ScrollableDeclarativeView *m_mainView;
|
||||
QDeclarativeView *m_timebar;
|
||||
QDeclarativeView *m_overview;
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
QmlProfilerModelManager *m_modelManager;
|
||||
TimelineModelAggregator *m_modelProxy;
|
||||
|
||||
|
||||
ZoomControl *m_zoomControl;
|
||||
|
||||
@@ -129,7 +133,7 @@ public:
|
||||
int m_currentZoomLevel;
|
||||
};
|
||||
|
||||
QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerTool *profilerTool, QmlProfilerViewManager *container, QmlProfilerDataModel *model, QmlProfilerStateManager *profilerState)
|
||||
QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerTool *profilerTool, QmlProfilerViewManager *container, QmlProfilerModelManager *modelManager, QmlProfilerStateManager *profilerState)
|
||||
: QWidget(parent), d(new QmlProfilerTraceViewPrivate(this))
|
||||
{
|
||||
setObjectName(QLatin1String("QML Profiler"));
|
||||
@@ -180,13 +184,15 @@ QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerT
|
||||
|
||||
d->m_profilerTool = profilerTool;
|
||||
d->m_viewContainer = container;
|
||||
d->m_profilerDataModel = model;
|
||||
connect(d->m_profilerDataModel, SIGNAL(stateChanged()),
|
||||
d->m_modelManager = modelManager;
|
||||
d->m_modelProxy = new TimelineModelAggregator(this);
|
||||
d->m_modelProxy->setModelManager(modelManager);
|
||||
connect(d->m_modelManager, SIGNAL(stateChanged()),
|
||||
this, SLOT(profilerDataModelStateChanged()));
|
||||
d->m_mainView->rootContext()->setContextProperty(QLatin1String("qmlProfilerDataModel"),
|
||||
d->m_profilerDataModel);
|
||||
d->m_overview->rootContext()->setContextProperty(QLatin1String("qmlProfilerDataModel"),
|
||||
d->m_profilerDataModel);
|
||||
d->m_mainView->rootContext()->setContextProperty(QLatin1String("qmlProfilerModelProxy"),
|
||||
d->m_modelProxy);
|
||||
d->m_overview->rootContext()->setContextProperty(QLatin1String("qmlProfilerModelProxy"),
|
||||
d->m_modelProxy);
|
||||
|
||||
d->m_profilerState = profilerState;
|
||||
connect(d->m_profilerState, SIGNAL(stateChanged()),
|
||||
@@ -372,12 +378,25 @@ void QmlProfilerTraceView::clearDisplay()
|
||||
QMetaObject::invokeMethod(d->m_overview->rootObject(), "clearDisplay");
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::selectNextEventWithId(int eventId)
|
||||
void QmlProfilerTraceView::selectNextEventByHash(const QString &hash)
|
||||
{
|
||||
QGraphicsObject *rootObject = d->m_mainView->rootObject();
|
||||
|
||||
if (rootObject)
|
||||
QMetaObject::invokeMethod(rootObject, "selectNextWithId",
|
||||
Q_ARG(QVariant,QVariant(eventId)));
|
||||
QMetaObject::invokeMethod(rootObject, "selectNextByHash",
|
||||
Q_ARG(QVariant,QVariant(hash)));
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::selectNextEventByLocation(const QString &filename, const int line, const int column)
|
||||
{
|
||||
int eventId = d->m_modelProxy->getEventIdForLocation(filename, line, column);
|
||||
|
||||
if (eventId != -1) {
|
||||
QGraphicsObject *rootObject = d->m_mainView->rootObject();
|
||||
if (rootObject)
|
||||
QMetaObject::invokeMethod(rootObject, "selectNextById",
|
||||
Q_ARG(QVariant,QVariant(eventId)));
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
@@ -444,14 +463,14 @@ void QmlProfilerTraceView::setZoomLevel(int zoomLevel)
|
||||
|
||||
void QmlProfilerTraceView::updateRange()
|
||||
{
|
||||
if (!d->m_profilerDataModel)
|
||||
if (!d->m_modelManager)
|
||||
return;
|
||||
qreal duration = d->m_zoomControl->endTime() - d->m_zoomControl->startTime();
|
||||
if (duration <= 0)
|
||||
return;
|
||||
if (d->m_profilerDataModel->traceDuration() <= 0)
|
||||
if (d->m_modelManager->traceTime()->duration() <= 0)
|
||||
return;
|
||||
int newLevel = pow(duration / d->m_profilerDataModel->traceDuration(), 1/sliderExp) * sliderTicks;
|
||||
int newLevel = pow(duration / d->m_modelManager->traceTime()->duration(), 1/sliderExp) * sliderTicks;
|
||||
if (d->m_currentZoomLevel != newLevel) {
|
||||
d->m_currentZoomLevel = newLevel;
|
||||
emit zoomLevelChanged(newLevel);
|
||||
@@ -513,7 +532,7 @@ void QmlProfilerTraceView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
if (d->m_viewContainer->hasGlobalStats())
|
||||
getGlobalStatsAction->setEnabled(false);
|
||||
|
||||
if (d->m_profilerDataModel->count() > 0) {
|
||||
if (!d->m_modelProxy->isEmpty()) {
|
||||
menu.addSeparator();
|
||||
viewAllAction = menu.addAction(tr("Reset Zoom"));
|
||||
}
|
||||
@@ -523,8 +542,8 @@ void QmlProfilerTraceView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
if (selectedAction) {
|
||||
if (selectedAction == viewAllAction) {
|
||||
d->m_zoomControl->setRange(
|
||||
d->m_profilerDataModel->traceStartTime(),
|
||||
d->m_profilerDataModel->traceEndTime());
|
||||
d->m_modelManager->traceTime()->startTime(),
|
||||
d->m_modelManager->traceTime()->endTime());
|
||||
}
|
||||
if (selectedAction == getLocalStatsAction) {
|
||||
d->m_viewContainer->getStatisticsInRange(
|
||||
@@ -532,9 +551,7 @@ void QmlProfilerTraceView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
d->m_viewContainer->selectionEnd());
|
||||
}
|
||||
if (selectedAction == getGlobalStatsAction) {
|
||||
d->m_viewContainer->getStatisticsInRange(
|
||||
d->m_profilerDataModel->traceStartTime(),
|
||||
d->m_profilerDataModel->traceEndTime());
|
||||
d->m_viewContainer->getStatisticsInRange(-1, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -558,19 +575,15 @@ void QmlProfilerTraceView::setAppKilled()
|
||||
// Profiler State
|
||||
void QmlProfilerTraceView::profilerDataModelStateChanged()
|
||||
{
|
||||
switch (d->m_profilerDataModel->currentState()) {
|
||||
case QmlProfilerDataModel::Empty :
|
||||
emit enableToolbar(false);
|
||||
switch (d->m_modelManager->state()) {
|
||||
case QmlProfilerDataState::Empty:
|
||||
emit enableToolbar(false);
|
||||
break;
|
||||
case QmlProfilerDataModel::AcquiringData :
|
||||
// nothing to be done
|
||||
case QmlProfilerDataState::AcquiringData: break;
|
||||
case QmlProfilerDataState::ProcessingData: break;
|
||||
case QmlProfilerDataState::Done:
|
||||
emit enableToolbar(true);
|
||||
break;
|
||||
case QmlProfilerDataModel::ProcessingData :
|
||||
// nothing to be done
|
||||
break;
|
||||
case QmlProfilerDataModel::Done :
|
||||
emit enableToolbar(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -580,7 +593,7 @@ void QmlProfilerTraceView::profilerStateChanged()
|
||||
{
|
||||
switch (d->m_profilerState->currentState()) {
|
||||
case QmlProfilerStateManager::AppKilled : {
|
||||
if (d->m_profilerDataModel->currentState() == QmlProfilerDataModel::AcquiringData)
|
||||
if (d->m_modelManager->state() == QmlProfilerDataState::AcquiringData)
|
||||
setAppKilled();
|
||||
break;
|
||||
}
|
||||
|
@@ -37,11 +37,12 @@ class IAnalyzerTool;
|
||||
}
|
||||
|
||||
namespace QmlProfiler {
|
||||
|
||||
class QmlProfilerModelManager;
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerStateManager;
|
||||
class QmlProfilerViewManager;
|
||||
class QmlProfilerDataModel;
|
||||
|
||||
// capture mouse wheel events
|
||||
class MouseWheelResizer : public QObject {
|
||||
@@ -83,12 +84,13 @@ protected:
|
||||
void scrollContentsBy(int dx, int dy);
|
||||
};
|
||||
|
||||
|
||||
class QmlProfilerTraceView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerTool *profilerTool, QmlProfilerViewManager *container, QmlProfilerDataModel *model, QmlProfilerStateManager *profilerState);
|
||||
explicit QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerTool *profilerTool, QmlProfilerViewManager *container, QmlProfilerModelManager *modelManager, QmlProfilerStateManager *profilerState);
|
||||
~QmlProfilerTraceView();
|
||||
|
||||
void reset();
|
||||
@@ -99,7 +101,8 @@ public:
|
||||
|
||||
public slots:
|
||||
void clearDisplay();
|
||||
void selectNextEventWithId(int eventId);
|
||||
void selectNextEventByHash(const QString &eventHash);
|
||||
void selectNextEventByLocation(const QString &filename, const int line, const int column);
|
||||
|
||||
private slots:
|
||||
void updateCursorPosition();
|
||||
|
91
src/plugins/qmlprofiler/qmlprofilertreeview.cpp
Normal file
91
src/plugins/qmlprofiler/qmlprofilertreeview.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmlprofilertreeview.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QHeaderView>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
QmlProfilerTreeView::QmlProfilerTreeView(QWidget *parent)
|
||||
: QTreeView(parent)
|
||||
{
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
header()->setResizeMode(QHeaderView::Interactive);
|
||||
header()->setDefaultSectionSize(100);
|
||||
header()->setMinimumSectionSize(50);
|
||||
}
|
||||
|
||||
|
||||
// Translate from "old" context to keep 2.8 string freeze
|
||||
QString QmlProfilerTreeView::displayHeader(Fields header) const
|
||||
{
|
||||
static const char ctxt1[] = "QmlProfiler::Internal::QmlProfilerEventsParentsAndChildrenView";
|
||||
static const char ctxt2[] = "QmlProfiler::Internal::QmlProfilerEventsMainView";
|
||||
|
||||
switch (header) {
|
||||
case Callee:
|
||||
return QCoreApplication::translate(ctxt1, "Callee");
|
||||
case CalleeDescription:
|
||||
return QCoreApplication::translate(ctxt1, "Callee Description");
|
||||
case Caller:
|
||||
return QCoreApplication::translate(ctxt1, "Caller");
|
||||
case CallerDescription:
|
||||
return QCoreApplication::translate(ctxt1, "Caller Description");
|
||||
case CallCount:
|
||||
return QCoreApplication::translate(ctxt2, "Calls");
|
||||
case Details:
|
||||
return QCoreApplication::translate(ctxt2, "Details");
|
||||
case Location:
|
||||
return QCoreApplication::translate(ctxt2, "Location");
|
||||
case MaxTime:
|
||||
return QCoreApplication::translate(ctxt2, "Longest Time");
|
||||
case TimePerCall:
|
||||
return QCoreApplication::translate(ctxt2, "Mean Time");
|
||||
case SelfTime:
|
||||
return QCoreApplication::translate(ctxt2, "Self Time");
|
||||
case SelfTimeInPercent:
|
||||
return QCoreApplication::translate(ctxt2, "Self Time in Percent");
|
||||
case MinTime:
|
||||
return QCoreApplication::translate(ctxt2, "Shortest Time");
|
||||
case TimeInPercent:
|
||||
return QCoreApplication::translate(ctxt2, "Time in Percent");
|
||||
case TotalTime:
|
||||
return QCoreApplication::translate(ctxt2, "Total Time");
|
||||
case Type:
|
||||
return QCoreApplication::translate(ctxt2, "Type");
|
||||
case MedianTime:
|
||||
return QCoreApplication::translate(ctxt2, "Median Time");
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
72
src/plugins/qmlprofiler/qmlprofilertreeview.h
Normal file
72
src/plugins/qmlprofiler/qmlprofilertreeview.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QMLPROFILERTREEVIEW
|
||||
#define QMLPROFILERTREEVIEW
|
||||
|
||||
#include <QTreeView>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerTreeView : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
QmlProfilerTreeView(QWidget *parent = 0);
|
||||
|
||||
|
||||
enum Fields {
|
||||
Name,
|
||||
Callee,
|
||||
CalleeDescription,
|
||||
Caller,
|
||||
CallerDescription,
|
||||
CallCount,
|
||||
Details,
|
||||
Location,
|
||||
MaxTime,
|
||||
TimePerCall,
|
||||
SelfTime,
|
||||
SelfTimeInPercent,
|
||||
MinTime,
|
||||
TimeInPercent,
|
||||
TotalTime,
|
||||
Type,
|
||||
MedianTime,
|
||||
MaxFields
|
||||
};
|
||||
QString displayHeader(Fields header) const;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
#endif // QMLPROFILERTREEVIEW
|
1016
src/plugins/qmlprofiler/qmlprofilerv8eventsview.cpp
Normal file
1016
src/plugins/qmlprofiler/qmlprofilerv8eventsview.cpp
Normal file
File diff suppressed because it is too large
Load Diff
202
src/plugins/qmlprofiler/qmlprofilerv8eventsview.h
Normal file
202
src/plugins/qmlprofiler/qmlprofilerv8eventsview.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QMLPROFILEREVENTVIEW_H
|
||||
#define QMLPROFILEREVENTVIEW_H
|
||||
|
||||
#include <QTreeView>
|
||||
#include <QStandardItemModel>
|
||||
#include <qmldebug/qmlprofilereventtypes.h>
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilereventsmodelproxy.h"
|
||||
|
||||
#include <analyzerbase/ianalyzertool.h>
|
||||
|
||||
#include "qmlprofilerviewmanager.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerEventsMainView;
|
||||
class QmlProfilerEventChildrenView;
|
||||
class QmlProfilerEventRelativesView;
|
||||
|
||||
enum ItemRole {
|
||||
EventHashStrRole = Qt::UserRole+1,
|
||||
FilenameRole = Qt::UserRole+2,
|
||||
LineRole = Qt::UserRole+3,
|
||||
ColumnRole = Qt::UserRole+4,
|
||||
EventIdRole = Qt::UserRole+5
|
||||
};
|
||||
|
||||
class QmlProfilerEventsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlProfilerEventsWidget(QWidget *parent,
|
||||
Analyzer::IAnalyzerTool *profilerTool,
|
||||
QmlProfilerViewManager *container,
|
||||
QmlProfilerModelManager *profilerModelManager );
|
||||
~QmlProfilerEventsWidget();
|
||||
|
||||
void clear();
|
||||
|
||||
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
|
||||
QModelIndex selectedItem() const;
|
||||
bool mouseOnTable(const QPoint &position) const;
|
||||
void copyTableToClipboard() const;
|
||||
void copyRowToClipboard() const;
|
||||
|
||||
bool hasGlobalStats() const;
|
||||
void setShowExtendedStatistics(bool show);
|
||||
bool showExtendedStatistics() const;
|
||||
|
||||
|
||||
signals:
|
||||
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||
void showEventInTimeline(int eventId);
|
||||
void resized();
|
||||
|
||||
public slots:
|
||||
void updateSelectedEvent(const QString &eventHash) const;
|
||||
void selectBySourceLocation(const QString &filename, int line, int column);
|
||||
|
||||
private slots:
|
||||
void profilerDataModelStateChanged();
|
||||
|
||||
protected:
|
||||
void contextMenuEvent(QContextMenuEvent *ev);
|
||||
virtual void resizeEvent(QResizeEvent *event);
|
||||
|
||||
private:
|
||||
class QmlProfilerEventsWidgetPrivate;
|
||||
QmlProfilerEventsWidgetPrivate *d;
|
||||
};
|
||||
|
||||
class QmlProfilerEventsMainView : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Fields {
|
||||
Name,
|
||||
Type,
|
||||
Percent,
|
||||
TotalDuration,
|
||||
SelfPercent,
|
||||
SelfDuration,
|
||||
CallCount,
|
||||
TimePerCall,
|
||||
MaxTime,
|
||||
MinTime,
|
||||
MedianTime,
|
||||
Details,
|
||||
|
||||
MaxFields
|
||||
};
|
||||
|
||||
explicit QmlProfilerEventsMainView(QWidget *parent,
|
||||
QmlProfilerEventsModelProxy *modelProxy);
|
||||
~QmlProfilerEventsMainView();
|
||||
|
||||
void setFieldViewable(Fields field, bool show);
|
||||
void setShowAnonymousEvents( bool showThem );
|
||||
|
||||
QModelIndex selectedItem() const;
|
||||
void copyTableToClipboard() const;
|
||||
void copyRowToClipboard() const;
|
||||
|
||||
static QString displayTime(double time);
|
||||
static QString nameForType(int typeNumber);
|
||||
|
||||
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
|
||||
bool isRangeGlobal(qint64 rangeStart, qint64 rangeEnd) const;
|
||||
// int selectedEventId() const;
|
||||
const QString &selectedEventHash() const;
|
||||
|
||||
void setShowExtendedStatistics(bool);
|
||||
bool showExtendedStatistics() const;
|
||||
|
||||
|
||||
signals:
|
||||
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||
void eventSelected(const QString &eventHash);
|
||||
void showEventInTimeline(int eventId);
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
void jumpToItem(const QModelIndex &index);
|
||||
void selectEvent(const QString &eventHash);
|
||||
void selectEventByLocation(const QString &filename, int line);
|
||||
void buildModel();
|
||||
void changeDetailsForEvent(int eventId, const QString &newString);
|
||||
|
||||
private slots:
|
||||
void profilerDataModelStateChanged();
|
||||
|
||||
private:
|
||||
void setHeaderLabels();
|
||||
void parseModelProxy();
|
||||
|
||||
private:
|
||||
class QmlProfilerEventsMainViewPrivate;
|
||||
QmlProfilerEventsMainViewPrivate *d;
|
||||
|
||||
};
|
||||
|
||||
class QmlProfilerEventRelativesView : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlProfilerEventRelativesView(QmlProfilerModelManager *modelManager,
|
||||
QmlProfilerEventRelativesModelProxy *modelProxy,
|
||||
QWidget *parent );
|
||||
~QmlProfilerEventRelativesView();
|
||||
|
||||
signals:
|
||||
void eventClicked(const QString &eventHash);
|
||||
|
||||
public slots:
|
||||
void displayEvent(const QString &eventHash);
|
||||
void jumpToItem(const QModelIndex &);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
void rebuildTree(QmlProfilerEventParentsModelProxy::QmlEventRelativesMap eventMap);
|
||||
void updateHeader();
|
||||
QStandardItemModel *treeModel();
|
||||
// QmlProfilerModelManager *m_profilerModelManager;
|
||||
|
||||
class QmlProfilerEventParentsViewPrivate;
|
||||
QmlProfilerEventParentsViewPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
#endif // QMLPROFILEREVENTVIEW_H
|
@@ -33,8 +33,9 @@
|
||||
#include "qmlprofilereventview.h"
|
||||
#include "qmlprofilertool.h"
|
||||
#include "qmlprofilerstatemanager.h"
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilerstatewidget.h"
|
||||
#include "qv8profilereventview.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/fancymainwindow.h>
|
||||
@@ -53,15 +54,15 @@ public:
|
||||
|
||||
QmlProfilerTraceView *traceView;
|
||||
QmlProfilerEventsWidget *eventsView;
|
||||
QmlProfilerEventsWidget *v8profilerView;
|
||||
QV8ProfilerEventsWidget *v8profilerView;
|
||||
QmlProfilerStateManager *profilerState;
|
||||
QmlProfilerDataModel *profilerDataModel;
|
||||
QmlProfilerModelManager *profilerModelManager;
|
||||
QmlProfilerTool *profilerTool;
|
||||
};
|
||||
|
||||
QmlProfilerViewManager::QmlProfilerViewManager(QObject *parent,
|
||||
QmlProfilerTool *profilerTool,
|
||||
QmlProfilerDataModel *model,
|
||||
QmlProfilerModelManager *modelManager,
|
||||
QmlProfilerStateManager *profilerState)
|
||||
: QObject(parent), d(new QmlProfilerViewManagerPrivate(this))
|
||||
{
|
||||
@@ -70,7 +71,7 @@ QmlProfilerViewManager::QmlProfilerViewManager(QObject *parent,
|
||||
d->eventsView = 0;
|
||||
d->v8profilerView = 0;
|
||||
d->profilerState = profilerState;
|
||||
d->profilerDataModel = model;
|
||||
d->profilerModelManager = modelManager;
|
||||
d->profilerTool = profilerTool;
|
||||
createViews();
|
||||
}
|
||||
@@ -84,7 +85,8 @@ QmlProfilerViewManager::~QmlProfilerViewManager()
|
||||
// Views
|
||||
void QmlProfilerViewManager::createViews()
|
||||
{
|
||||
QTC_ASSERT(d->profilerDataModel, return);
|
||||
|
||||
QTC_ASSERT(d->profilerModelManager, return);
|
||||
QTC_ASSERT(d->profilerState, return);
|
||||
|
||||
Utils::FancyMainWindow *mw = AnalyzerManager::mainWindow();
|
||||
@@ -92,26 +94,28 @@ void QmlProfilerViewManager::createViews()
|
||||
d->traceView = new QmlProfilerTraceView(mw,
|
||||
d->profilerTool,
|
||||
this,
|
||||
d->profilerDataModel,
|
||||
d->profilerModelManager,
|
||||
d->profilerState);
|
||||
connect(d->traceView, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
this, SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
|
||||
d->traceView->reset();
|
||||
|
||||
d->eventsView = new QmlProfilerEventsWidget(mw, d->profilerTool, this, d->profilerDataModel);
|
||||
|
||||
d->eventsView = new QmlProfilerEventsWidget(mw, d->profilerTool, this,
|
||||
d->profilerModelManager);
|
||||
connect(d->eventsView, SIGNAL(gotoSourceLocation(QString,int,int)), this,
|
||||
SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
connect(d->eventsView, SIGNAL(showEventInTimeline(int)), d->traceView,
|
||||
SLOT(selectNextEventWithId(int)));
|
||||
connect(d->traceView, SIGNAL(selectedEventChanged(int)), d->eventsView,
|
||||
SLOT(updateSelectedEvent(int)));
|
||||
connect(d->eventsView, SIGNAL(eventSelectedByHash(QString)), d->traceView,
|
||||
SLOT(selectNextEventByHash(QString)));
|
||||
connect(d->traceView, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
d->eventsView, SLOT(selectBySourceLocation(QString,int,int)));
|
||||
|
||||
d->v8profilerView = new QmlProfilerEventsWidget(mw, d->profilerTool,
|
||||
this, d->profilerDataModel);
|
||||
d->v8profilerView->switchToV8View();
|
||||
d->v8profilerView = new QV8ProfilerEventsWidget(mw, d->profilerTool, this,
|
||||
d->profilerModelManager);
|
||||
connect(d->traceView, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
d->v8profilerView, SLOT(selectBySourceLocation(QString,int,int)));
|
||||
connect(d->v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
this, SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
d->traceView, SLOT(selectNextEventByLocation(QString,int,int)));
|
||||
connect(d->v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
d->eventsView, SLOT(selectBySourceLocation(QString,int,int)));
|
||||
connect(d->eventsView, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
@@ -121,8 +125,8 @@ void QmlProfilerViewManager::createViews()
|
||||
(d->profilerTool, tr("Events"), d->eventsView, Qt::BottomDockWidgetArea);
|
||||
QDockWidget *timelineDock = AnalyzerManager::createDockWidget
|
||||
(d->profilerTool, tr("Timeline"), d->traceView, Qt::BottomDockWidgetArea);
|
||||
QDockWidget *v8profilerDock = AnalyzerManager::createDockWidget
|
||||
(d->profilerTool, tr("JavaScript"), d->v8profilerView, Qt::BottomDockWidgetArea);
|
||||
QDockWidget *v8profilerDock = AnalyzerManager::createDockWidget(
|
||||
d->profilerTool, tr("JavaScript"), d->v8profilerView, Qt::BottomDockWidgetArea);
|
||||
|
||||
eventsDock->show();
|
||||
timelineDock->show();
|
||||
@@ -132,9 +136,9 @@ void QmlProfilerViewManager::createViews()
|
||||
mw->tabifyDockWidget(timelineDock, eventsDock);
|
||||
mw->tabifyDockWidget(eventsDock, v8profilerDock);
|
||||
|
||||
new QmlProfilerStateWidget(d->profilerState, d->profilerDataModel, d->traceView);
|
||||
new QmlProfilerStateWidget(d->profilerState, d->profilerDataModel, d->eventsView);
|
||||
new QmlProfilerStateWidget(d->profilerState, d->profilerDataModel, d->v8profilerView);
|
||||
new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, d->eventsView);
|
||||
new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, d->traceView);
|
||||
new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, d->v8profilerView);
|
||||
}
|
||||
|
||||
bool QmlProfilerViewManager::hasValidSelection() const
|
||||
|
@@ -33,10 +33,11 @@
|
||||
#include <QObject>
|
||||
|
||||
namespace QmlProfiler {
|
||||
class QmlProfilerModelManager;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerTool;
|
||||
class QmlProfilerDataModel;
|
||||
class QmlProfilerStateManager;
|
||||
|
||||
class QmlProfilerViewManager : public QObject
|
||||
@@ -45,7 +46,7 @@ class QmlProfilerViewManager : public QObject
|
||||
public:
|
||||
explicit QmlProfilerViewManager(QObject *parent,
|
||||
QmlProfilerTool *profilerTool,
|
||||
QmlProfilerDataModel *model,
|
||||
QmlProfilerModelManager *modelManager,
|
||||
QmlProfilerStateManager *profilerState);
|
||||
~QmlProfilerViewManager();
|
||||
|
||||
|
@@ -28,12 +28,9 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "qv8profilerdatamodel.h"
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
using namespace QmlDebug;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
Q_DECLARE_TYPEINFO(QmlProfiler::Internal::QV8EventData, Q_MOVABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QmlProfiler::Internal::QV8EventSub, Q_MOVABLE_TYPE);
|
||||
@@ -66,7 +63,7 @@ QV8EventData &QV8EventData::operator=(const QV8EventData &ref)
|
||||
totalTime = ref.totalTime;
|
||||
totalPercent = ref.totalPercent;
|
||||
selfTime = ref.selfTime;
|
||||
selfPercent = ref.selfPercent;
|
||||
SelfTimeInPercent = ref.SelfTimeInPercent;
|
||||
eventId = ref.eventId;
|
||||
|
||||
qDeleteAll(parentHash);
|
||||
@@ -85,7 +82,7 @@ QV8EventData::QV8EventData()
|
||||
totalTime = 0;
|
||||
selfTime = 0;
|
||||
totalPercent = 0;
|
||||
selfPercent = 0;
|
||||
SelfTimeInPercent = 0;
|
||||
}
|
||||
|
||||
QV8EventData::~QV8EventData()
|
||||
@@ -101,8 +98,6 @@ class QV8ProfilerDataModel::QV8ProfilerDataModelPrivate
|
||||
public:
|
||||
QV8ProfilerDataModelPrivate(QV8ProfilerDataModel *qq) {Q_UNUSED(qq);}
|
||||
|
||||
QmlProfilerDataModel *qmlProfilerDataModel;
|
||||
|
||||
void clearV8RootEvent();
|
||||
void collectV8Statistics();
|
||||
|
||||
@@ -112,13 +107,12 @@ public:
|
||||
qint64 v8MeasuredTime;
|
||||
};
|
||||
|
||||
QV8ProfilerDataModel::QV8ProfilerDataModel(QObject *parent,
|
||||
QmlProfilerDataModel *profilerDataModel)
|
||||
: QObject(parent), d(new QV8ProfilerDataModelPrivate(this))
|
||||
QV8ProfilerDataModel::QV8ProfilerDataModel(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new QV8ProfilerDataModelPrivate(this))
|
||||
{
|
||||
d->v8MeasuredTime = 0;
|
||||
d->clearV8RootEvent();
|
||||
d->qmlProfilerDataModel = profilerDataModel;
|
||||
}
|
||||
|
||||
QV8ProfilerDataModel::~QV8ProfilerDataModel()
|
||||
@@ -133,6 +127,8 @@ void QV8ProfilerDataModel::clear()
|
||||
d->v8parents.clear();
|
||||
d->clearV8RootEvent();
|
||||
d->v8MeasuredTime = 0;
|
||||
|
||||
emit changed();
|
||||
}
|
||||
|
||||
bool QV8ProfilerDataModel::isEmpty() const
|
||||
@@ -159,6 +155,11 @@ QList<QV8EventData *> QV8ProfilerDataModel::getV8Events() const
|
||||
return d->v8EventHash.values();
|
||||
}
|
||||
|
||||
QString getHashStringForV8Event(const QString &displayName, const QString &function)
|
||||
{
|
||||
return QString::fromLatin1("%1:%2").arg(displayName, function);
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::addV8Event(int depth,
|
||||
const QString &function,
|
||||
const QString &filename,
|
||||
@@ -168,9 +169,7 @@ void QV8ProfilerDataModel::addV8Event(int depth,
|
||||
{
|
||||
QString displayName = filename.mid(filename.lastIndexOf(QLatin1Char('/')) + 1) +
|
||||
QLatin1Char(':') + QString::number(lineNumber);
|
||||
QString hashStr = QmlProfilerDataModel::getHashStringForV8Event(displayName, function);
|
||||
|
||||
d->qmlProfilerDataModel->setState(QmlProfilerDataModel::AcquiringData);
|
||||
QString hashStr = getHashStringForV8Event(displayName, function);
|
||||
|
||||
// time is given in milliseconds, but internally we store it in microseconds
|
||||
totalTime *= 1e6;
|
||||
@@ -223,6 +222,7 @@ void QV8ProfilerDataModel::addV8Event(int depth,
|
||||
newChildSub->totalTime += totalTime;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::collectV8Statistics()
|
||||
@@ -250,9 +250,9 @@ void QV8ProfilerDataModel::QV8ProfilerDataModelPrivate::collectV8Statistics()
|
||||
v8RootEvent.totalTime = v8MeasuredTime + 1;
|
||||
v8RootEvent.selfTime = 0;
|
||||
|
||||
QString rootEventHash = QmlProfilerDataModel::getHashStringForV8Event(
|
||||
QmlProfilerDataModel::rootEventName(),
|
||||
QmlProfilerDataModel::rootEventDescription());
|
||||
QString rootEventHash = getHashStringForV8Event(
|
||||
tr("<program>"),
|
||||
tr("Main Program"));
|
||||
QV8EventData *v8RootEventPointer = v8EventHash[rootEventHash];
|
||||
if (v8RootEventPointer) {
|
||||
v8RootEvent = *v8RootEventPointer;
|
||||
@@ -263,7 +263,7 @@ void QV8ProfilerDataModel::QV8ProfilerDataModelPrivate::collectV8Statistics()
|
||||
|
||||
foreach (QV8EventData *v8event, v8EventHash.values()) {
|
||||
v8event->totalPercent = v8event->totalTime * 100.0 / totalTimes;
|
||||
v8event->selfPercent = v8event->selfTime * 100.0 / selfTimes;
|
||||
v8event->SelfTimeInPercent = v8event->selfTime * 100.0 / selfTimes;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
@@ -274,25 +274,20 @@ void QV8ProfilerDataModel::QV8ProfilerDataModelPrivate::collectV8Statistics()
|
||||
} else {
|
||||
// On empty data, still add a fake root event
|
||||
clearV8RootEvent();
|
||||
v8RootEvent.totalPercent = 100;
|
||||
QString rootEventHash = QmlProfilerDataModel::getHashStringForV8Event(
|
||||
QmlProfilerDataModel::rootEventName(),
|
||||
QmlProfilerDataModel::rootEventDescription());
|
||||
v8EventHash[rootEventHash] = new QV8EventData;
|
||||
*v8EventHash[rootEventHash] = v8RootEvent;
|
||||
}
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::QV8ProfilerDataModelPrivate::clearV8RootEvent()
|
||||
{
|
||||
v8RootEvent.displayName = QmlProfilerDataModel::rootEventName();
|
||||
v8RootEvent.eventHashStr = QmlProfilerDataModel::rootEventName();
|
||||
v8RootEvent.functionName = QmlProfilerDataModel::rootEventDescription();
|
||||
v8RootEvent.displayName = tr("<program>");
|
||||
v8RootEvent.eventHashStr = tr("<program>");
|
||||
v8RootEvent.functionName = tr("Main Program");
|
||||
|
||||
v8RootEvent.line = -1;
|
||||
v8RootEvent.totalTime = 0;
|
||||
v8RootEvent.totalPercent = 0;
|
||||
v8RootEvent.selfTime = 0;
|
||||
v8RootEvent.selfPercent = 0;
|
||||
v8RootEvent.SelfTimeInPercent = 0;
|
||||
v8RootEvent.eventId = -1;
|
||||
|
||||
qDeleteAll(v8RootEvent.parentHash.values());
|
||||
@@ -439,7 +434,7 @@ void QV8ProfilerDataModel::load(QXmlStreamReader &stream)
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// backwards compatibility
|
||||
if (d->v8MeasuredTime == 0)
|
||||
@@ -472,11 +467,10 @@ void QV8ProfilerDataModel::load(QXmlStreamReader &stream)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// store v8 events
|
||||
foreach (QV8EventData *storedV8Event, v8eventBuffer.values()) {
|
||||
storedV8Event->eventHashStr =
|
||||
QmlProfilerDataModel::getHashStringForV8Event(
|
||||
getHashStringForV8Event(
|
||||
storedV8Event->displayName, storedV8Event->functionName);
|
||||
d->v8EventHash[storedV8Event->eventHashStr] = storedV8Event;
|
||||
}
|
||||
@@ -485,5 +479,11 @@ void QV8ProfilerDataModel::load(QXmlStreamReader &stream)
|
||||
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::complete()
|
||||
{
|
||||
collectV8Statistics();
|
||||
emit changed();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
@@ -39,7 +39,6 @@
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QmlProfilerDataModel;
|
||||
struct QV8EventSub;
|
||||
|
||||
struct QV8EventData
|
||||
@@ -55,7 +54,7 @@ struct QV8EventData
|
||||
double totalTime; // given in milliseconds
|
||||
double totalPercent;
|
||||
double selfTime;
|
||||
double selfPercent;
|
||||
double SelfTimeInPercent;
|
||||
QHash <QString, QV8EventSub *> parentHash;
|
||||
QHash <QString, QV8EventSub *> childrenHash;
|
||||
int eventId;
|
||||
@@ -75,7 +74,7 @@ class QV8ProfilerDataModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QV8ProfilerDataModel(QObject *parent, QmlProfilerDataModel *profilerDataModel);
|
||||
QV8ProfilerDataModel(QObject *parent = 0);
|
||||
~QV8ProfilerDataModel();
|
||||
|
||||
void clear();
|
||||
@@ -89,6 +88,11 @@ public:
|
||||
void save(QXmlStreamWriter &stream);
|
||||
void load(QXmlStreamReader &stream);
|
||||
|
||||
void complete();
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
public slots:
|
||||
void addV8Event(int depth,
|
||||
const QString &function,
|
||||
|
725
src/plugins/qmlprofiler/qv8profilereventview.cpp
Normal file
725
src/plugins/qmlprofiler/qv8profilereventview.cpp
Normal file
@@ -0,0 +1,725 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qv8profilereventview.h"
|
||||
|
||||
#include <QUrl>
|
||||
#include <QHash>
|
||||
|
||||
#include <QStandardItem>
|
||||
#include <QHeaderView>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
|
||||
#include <QContextMenuEvent>
|
||||
#include <QDebug>
|
||||
|
||||
#include <coreplugin/minisplitter.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
#include "qmlprofilerviewmanager.h"
|
||||
#include "qmlprofilertool.h"
|
||||
#include "qv8profilerdatamodel.h"
|
||||
#include <QMenu>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
using namespace QmlDebug;
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
enum ItemRole {
|
||||
EventHashStrRole = Qt::UserRole+1,
|
||||
FilenameRole = Qt::UserRole+2,
|
||||
LineRole = Qt::UserRole+3,
|
||||
ColumnRole = Qt::UserRole+4,
|
||||
EventIdRole = Qt::UserRole+5
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EventsViewItem : public QStandardItem
|
||||
{
|
||||
public:
|
||||
EventsViewItem(const QString &text) : QStandardItem(text) {}
|
||||
|
||||
virtual bool operator<(const QStandardItem &other) const
|
||||
{
|
||||
if (data().type() == QVariant::String) {
|
||||
// first column
|
||||
if (column() == 0) {
|
||||
return data(FilenameRole).toString() == other.data(FilenameRole).toString() ?
|
||||
data(LineRole).toInt() < other.data(LineRole).toInt() :
|
||||
data(FilenameRole).toString() < other.data(FilenameRole).toString();
|
||||
} else {
|
||||
return data().toString().toLower() < other.data().toString().toLower();
|
||||
}
|
||||
}
|
||||
|
||||
return data().toDouble() < other.data().toDouble();
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class QV8ProfilerEventsWidget::QV8ProfilerEventsWidgetPrivate
|
||||
{
|
||||
public:
|
||||
QV8ProfilerEventsWidgetPrivate(QV8ProfilerEventsWidget *qq):q(qq) {}
|
||||
~QV8ProfilerEventsWidgetPrivate() {}
|
||||
|
||||
QV8ProfilerEventsWidget *q;
|
||||
|
||||
Analyzer::IAnalyzerTool *m_profilerTool;
|
||||
QmlProfilerViewManager *m_viewContainer;
|
||||
|
||||
QV8ProfilerEventsMainView *m_eventTree;
|
||||
QV8ProfilerEventRelativesView *m_eventChildren;
|
||||
QV8ProfilerEventRelativesView *m_eventParents;
|
||||
|
||||
QV8ProfilerDataModel *v8Model;
|
||||
};
|
||||
|
||||
QV8ProfilerEventsWidget::QV8ProfilerEventsWidget(QWidget *parent,
|
||||
Analyzer::IAnalyzerTool *profilerTool,
|
||||
QmlProfilerViewManager *container,
|
||||
QmlProfilerModelManager *profilerModelManager )
|
||||
: QWidget(parent), d(new QV8ProfilerEventsWidgetPrivate(this))
|
||||
{
|
||||
setObjectName(QLatin1String("QmlProfilerV8ProfileView"));
|
||||
|
||||
d->v8Model = profilerModelManager->v8Model();
|
||||
|
||||
d->m_eventTree = new QV8ProfilerEventsMainView(this, d->v8Model);
|
||||
connect(d->m_eventTree, SIGNAL(gotoSourceLocation(QString,int,int)), this, SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
|
||||
d->m_eventChildren = new QV8ProfilerEventRelativesView(d->v8Model,
|
||||
QV8ProfilerEventRelativesView::ChildrenView,
|
||||
this);
|
||||
d->m_eventParents = new QV8ProfilerEventRelativesView(d->v8Model,
|
||||
QV8ProfilerEventRelativesView::ParentsView,
|
||||
this);
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventChildren, SLOT(displayEvent(int)));
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventParents, SLOT(displayEvent(int)));
|
||||
connect(d->m_eventChildren, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
|
||||
connect(d->m_eventParents, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
|
||||
|
||||
// widget arrangement
|
||||
QVBoxLayout *groupLayout = new QVBoxLayout;
|
||||
groupLayout->setContentsMargins(0,0,0,0);
|
||||
groupLayout->setSpacing(0);
|
||||
|
||||
Core::MiniSplitter *splitterVertical = new Core::MiniSplitter;
|
||||
splitterVertical->addWidget(d->m_eventTree);
|
||||
Core::MiniSplitter *splitterHorizontal = new Core::MiniSplitter;
|
||||
splitterHorizontal->addWidget(d->m_eventParents);
|
||||
splitterHorizontal->addWidget(d->m_eventChildren);
|
||||
splitterHorizontal->setOrientation(Qt::Horizontal);
|
||||
splitterVertical->addWidget(splitterHorizontal);
|
||||
splitterVertical->setOrientation(Qt::Vertical);
|
||||
splitterVertical->setStretchFactor(0,5);
|
||||
splitterVertical->setStretchFactor(1,2);
|
||||
groupLayout->addWidget(splitterVertical);
|
||||
setLayout(groupLayout);
|
||||
|
||||
d->m_profilerTool = profilerTool;
|
||||
d->m_viewContainer = container;
|
||||
|
||||
}
|
||||
|
||||
QV8ProfilerEventsWidget::~QV8ProfilerEventsWidget()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsWidget::clear()
|
||||
{
|
||||
d->m_eventTree->clear();
|
||||
d->m_eventChildren->clear();
|
||||
d->m_eventParents->clear();
|
||||
}
|
||||
|
||||
QModelIndex QV8ProfilerEventsWidget::selectedItem() const
|
||||
{
|
||||
return d->m_eventTree->selectedItem();
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsWidget::contextMenuEvent(QContextMenuEvent *ev)
|
||||
{
|
||||
QTC_ASSERT(d->m_viewContainer, return;);
|
||||
|
||||
QMenu menu;
|
||||
QAction *copyRowAction = 0;
|
||||
QAction *copyTableAction = 0;
|
||||
|
||||
QmlProfilerTool *profilerTool = qobject_cast<QmlProfilerTool *>(d->m_profilerTool);
|
||||
QPoint position = ev->globalPos();
|
||||
|
||||
if (profilerTool) {
|
||||
QList <QAction *> commonActions = profilerTool->profilerContextMenuActions();
|
||||
foreach (QAction *act, commonActions) {
|
||||
menu.addAction(act);
|
||||
}
|
||||
}
|
||||
|
||||
if (mouseOnTable(position)) {
|
||||
menu.addSeparator();
|
||||
if (selectedItem().isValid())
|
||||
copyRowAction = menu.addAction(QCoreApplication::translate("QmlProfiler::Internal::QmlProfilerEventsWidget", "Copy Row"));
|
||||
copyTableAction = menu.addAction(QCoreApplication::translate("QmlProfiler::Internal::QmlProfilerEventsWidget", "Copy Table"));
|
||||
}
|
||||
|
||||
QAction *selectedAction = menu.exec(position);
|
||||
|
||||
if (selectedAction) {
|
||||
if (selectedAction == copyRowAction)
|
||||
copyRowToClipboard();
|
||||
if (selectedAction == copyTableAction)
|
||||
copyTableToClipboard();
|
||||
}
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
emit resized();
|
||||
}
|
||||
|
||||
bool QV8ProfilerEventsWidget::mouseOnTable(const QPoint &position) const
|
||||
{
|
||||
QPoint tableTopLeft = d->m_eventTree->mapToGlobal(QPoint(0,0));
|
||||
QPoint tableBottomRight = d->m_eventTree->mapToGlobal(QPoint(d->m_eventTree->width(), d->m_eventTree->height()));
|
||||
return (position.x() >= tableTopLeft.x() && position.x() <= tableBottomRight.x() && position.y() >= tableTopLeft.y() && position.y() <= tableBottomRight.y());
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsWidget::copyTableToClipboard() const
|
||||
{
|
||||
d->m_eventTree->copyTableToClipboard();
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsWidget::copyRowToClipboard() const
|
||||
{
|
||||
d->m_eventTree->copyRowToClipboard();
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsWidget::updateSelectedEvent(int eventId) const
|
||||
{
|
||||
if (d->m_eventTree->selectedEventId() != eventId)
|
||||
d->m_eventTree->selectEvent(eventId);
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsWidget::selectBySourceLocation(const QString &filename, int line, int column)
|
||||
{
|
||||
// This slot is used to connect the javascript pane with the qml events pane
|
||||
// Our javascript trace data does not store column information
|
||||
// thus we ignore it here
|
||||
Q_UNUSED(column);
|
||||
d->m_eventTree->selectEventByLocation(filename, line);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class QV8ProfilerEventsMainView::QV8ProfilerEventsMainViewPrivate
|
||||
{
|
||||
public:
|
||||
QV8ProfilerEventsMainViewPrivate(QV8ProfilerEventsMainView *qq) : q(qq) {}
|
||||
|
||||
void buildV8ModelFromList( const QList<QV8EventData *> &list );
|
||||
int getFieldCount();
|
||||
|
||||
QString textForItem(QStandardItem *item, bool recursive) const;
|
||||
|
||||
|
||||
QV8ProfilerEventsMainView *q;
|
||||
|
||||
QV8ProfilerDataModel *m_v8Model;
|
||||
QStandardItemModel *m_model;
|
||||
QList<bool> m_fieldShown;
|
||||
QHash<int, int> m_columnIndex; // maps field enum to column index
|
||||
int m_firstNumericColumn;
|
||||
bool m_preventSelectBounce;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QV8ProfilerEventsMainView::QV8ProfilerEventsMainView(QWidget *parent,
|
||||
QV8ProfilerDataModel *v8Model)
|
||||
: QmlProfilerTreeView(parent), d(new QV8ProfilerEventsMainViewPrivate(this))
|
||||
{
|
||||
setObjectName(QLatin1String("QmlProfilerEventsTable"));
|
||||
setSortingEnabled(false);
|
||||
|
||||
d->m_model = new QStandardItemModel(this);
|
||||
setModel(d->m_model);
|
||||
connect(this,SIGNAL(clicked(QModelIndex)), this,SLOT(jumpToItem(QModelIndex)));
|
||||
|
||||
d->m_v8Model = v8Model;
|
||||
connect(d->m_v8Model, SIGNAL(changed()), this, SLOT(buildModel()));
|
||||
d->m_firstNumericColumn = 0;
|
||||
d->m_preventSelectBounce = false;
|
||||
|
||||
setFieldViewable(Name, true);
|
||||
setFieldViewable(Type, false);
|
||||
setFieldViewable(TimeInPercent, true);
|
||||
setFieldViewable(TotalTime, true);
|
||||
setFieldViewable(SelfTimeInPercent, true);
|
||||
setFieldViewable(SelfTime, true);
|
||||
setFieldViewable(CallCount, false);
|
||||
setFieldViewable(TimePerCall, false);
|
||||
setFieldViewable(MaxTime, false);
|
||||
setFieldViewable(MinTime, false);
|
||||
setFieldViewable(MedianTime, false);
|
||||
setFieldViewable(Details, true);
|
||||
|
||||
buildModel();
|
||||
}
|
||||
|
||||
QV8ProfilerEventsMainView::~QV8ProfilerEventsMainView()
|
||||
{
|
||||
clear();
|
||||
delete d->m_model;
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsMainView::setFieldViewable(Fields field, bool show)
|
||||
{
|
||||
if (field < MaxFields) {
|
||||
int length = d->m_fieldShown.count();
|
||||
if (field >= length) {
|
||||
for (int i=length; i<MaxFields; i++)
|
||||
d->m_fieldShown << false;
|
||||
}
|
||||
d->m_fieldShown[field] = show;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QV8ProfilerEventsMainView::setHeaderLabels()
|
||||
{
|
||||
int fieldIndex = 0;
|
||||
d->m_firstNumericColumn = 0;
|
||||
|
||||
d->m_columnIndex.clear();
|
||||
if (d->m_fieldShown[Name]) {
|
||||
d->m_columnIndex[Name] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Location)));
|
||||
d->m_firstNumericColumn++;
|
||||
}
|
||||
if (d->m_fieldShown[Type]) {
|
||||
d->m_columnIndex[Type] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Type)));
|
||||
d->m_firstNumericColumn++;
|
||||
}
|
||||
if (d->m_fieldShown[TimeInPercent]) {
|
||||
d->m_columnIndex[TimeInPercent] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TimeInPercent)));
|
||||
}
|
||||
if (d->m_fieldShown[TotalTime]) {
|
||||
d->m_columnIndex[TotalTime] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TotalTime)));
|
||||
}
|
||||
if (d->m_fieldShown[SelfTimeInPercent]) {
|
||||
d->m_columnIndex[Type] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(SelfTimeInPercent)));
|
||||
}
|
||||
if (d->m_fieldShown[SelfTime]) {
|
||||
d->m_columnIndex[SelfTime] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(SelfTime)));
|
||||
}
|
||||
if (d->m_fieldShown[CallCount]) {
|
||||
d->m_columnIndex[CallCount] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(CallCount)));
|
||||
}
|
||||
if (d->m_fieldShown[TimePerCall]) {
|
||||
d->m_columnIndex[TimePerCall] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(TimePerCall)));
|
||||
}
|
||||
if (d->m_fieldShown[MedianTime]) {
|
||||
d->m_columnIndex[MedianTime] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MedianTime)));
|
||||
}
|
||||
if (d->m_fieldShown[MaxTime]) {
|
||||
d->m_columnIndex[MaxTime] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MaxTime)));
|
||||
}
|
||||
if (d->m_fieldShown[MinTime]) {
|
||||
d->m_columnIndex[MinTime] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(MinTime)));
|
||||
}
|
||||
if (d->m_fieldShown[Details]) {
|
||||
d->m_columnIndex[Details] = fieldIndex;
|
||||
d->m_model->setHeaderData(fieldIndex++, Qt::Horizontal, QVariant(displayHeader(Details)));
|
||||
}
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsMainView::clear()
|
||||
{
|
||||
d->m_model->clear();
|
||||
d->m_model->setColumnCount(d->getFieldCount());
|
||||
|
||||
setHeaderLabels();
|
||||
setSortingEnabled(false);
|
||||
}
|
||||
|
||||
int QV8ProfilerEventsMainView::QV8ProfilerEventsMainViewPrivate::getFieldCount()
|
||||
{
|
||||
int count = 0;
|
||||
for (int i=0; i < m_fieldShown.count(); ++i)
|
||||
if (m_fieldShown[i])
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsMainView::buildModel()
|
||||
{
|
||||
clear();
|
||||
d->buildV8ModelFromList( d->m_v8Model->getV8Events() );
|
||||
|
||||
setRootIsDecorated(false);
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(d->m_firstNumericColumn,Qt::DescendingOrder);
|
||||
|
||||
expandAll();
|
||||
if (d->m_fieldShown[Name])
|
||||
resizeColumnToContents(0);
|
||||
|
||||
if (d->m_fieldShown[Type])
|
||||
resizeColumnToContents(d->m_fieldShown[Name]?1:0);
|
||||
collapseAll();
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsMainView::QV8ProfilerEventsMainViewPrivate::buildV8ModelFromList(const QList<QV8EventData *> &list)
|
||||
{
|
||||
for (int index = 0; index < list.count(); index++) {
|
||||
QV8EventData *v8event = list.at(index);
|
||||
QList<QStandardItem *> newRow;
|
||||
|
||||
if (m_fieldShown[Name])
|
||||
newRow << new EventsViewItem(v8event->displayName);
|
||||
|
||||
if (m_fieldShown[TimeInPercent]) {
|
||||
newRow << new EventsViewItem(QString::number(v8event->totalPercent,'f',2)+QLatin1String(" %"));
|
||||
newRow.last()->setData(QVariant(v8event->totalPercent));
|
||||
}
|
||||
|
||||
if (m_fieldShown[TotalTime]) {
|
||||
newRow << new EventsViewItem(displayTime(v8event->totalTime));
|
||||
newRow.last()->setData(QVariant(v8event->totalTime));
|
||||
}
|
||||
|
||||
if (m_fieldShown[SelfTimeInPercent]) {
|
||||
newRow << new EventsViewItem(QString::number(v8event->SelfTimeInPercent,'f',2)+QLatin1String(" %"));
|
||||
newRow.last()->setData(QVariant(v8event->SelfTimeInPercent));
|
||||
}
|
||||
|
||||
if (m_fieldShown[SelfTime]) {
|
||||
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(QString::fromLatin1("%1:%2").arg(v8event->filename, QString::number(v8event->line)), EventHashStrRole);
|
||||
newRow.at(0)->setData(QVariant(v8event->filename), FilenameRole);
|
||||
newRow.at(0)->setData(QVariant(v8event->line), LineRole);
|
||||
newRow.at(0)->setData(QVariant(-1),ColumnRole); // v8 events have no column info
|
||||
newRow.at(0)->setData(QVariant(v8event->eventId), EventIdRole);
|
||||
|
||||
// append
|
||||
m_model->invisibleRootItem()->appendRow(newRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString QV8ProfilerEventsMainView::displayTime(double time)
|
||||
{
|
||||
if (time < 1e6)
|
||||
return QString::number(time/1e3,'f',3) + trUtf8(" \xc2\xb5s");
|
||||
if (time < 1e9)
|
||||
return QString::number(time/1e6,'f',3) + tr(" ms");
|
||||
|
||||
return QString::number(time/1e9,'f',3) + tr(" s");
|
||||
}
|
||||
|
||||
QString QV8ProfilerEventsMainView::nameForType(int typeNumber)
|
||||
{
|
||||
switch (typeNumber) {
|
||||
case 0: return QV8ProfilerEventsMainView::tr("Paint");
|
||||
case 1: return QV8ProfilerEventsMainView::tr("Compile");
|
||||
case 2: return QV8ProfilerEventsMainView::tr("Create");
|
||||
case 3: return QV8ProfilerEventsMainView::tr("Binding");
|
||||
case 4: return QV8ProfilerEventsMainView::tr("Signal");
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
int QV8ProfilerEventsMainView::selectedEventId() const
|
||||
{
|
||||
QModelIndex index = selectedItem();
|
||||
if (!index.isValid())
|
||||
return -1;
|
||||
QStandardItem *item = d->m_model->item(index.row(), 0);
|
||||
return item->data(EventIdRole).toInt();
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsMainView::jumpToItem(const QModelIndex &index)
|
||||
{
|
||||
if (d->m_preventSelectBounce)
|
||||
return;
|
||||
|
||||
d->m_preventSelectBounce = true;
|
||||
QStandardItem *clickedItem = d->m_model->itemFromIndex(index);
|
||||
QStandardItem *infoItem;
|
||||
if (clickedItem->parent())
|
||||
infoItem = clickedItem->parent()->child(clickedItem->row(), 0);
|
||||
else
|
||||
infoItem = d->m_model->item(index.row(), 0);
|
||||
|
||||
// show in editor
|
||||
int line = infoItem->data(LineRole).toInt();
|
||||
int column = infoItem->data(ColumnRole).toInt();
|
||||
QString fileName = infoItem->data(FilenameRole).toString();
|
||||
if (line!=-1 && !fileName.isEmpty())
|
||||
emit gotoSourceLocation(fileName, line, column);
|
||||
|
||||
// show in callers/callees subwindow
|
||||
emit eventSelected(infoItem->data(EventIdRole).toInt());
|
||||
|
||||
d->m_preventSelectBounce = false;
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsMainView::selectEvent(int eventId)
|
||||
{
|
||||
for (int i=0; i<d->m_model->rowCount(); i++) {
|
||||
QStandardItem *infoItem = d->m_model->item(i, 0);
|
||||
if (infoItem->data(EventIdRole).toInt() == eventId) {
|
||||
setCurrentIndex(d->m_model->indexFromItem(infoItem));
|
||||
jumpToItem(currentIndex());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsMainView::selectEventByLocation(const QString &filename, int line)
|
||||
{
|
||||
if (d->m_preventSelectBounce)
|
||||
return;
|
||||
|
||||
for (int i=0; i<d->m_model->rowCount(); i++) {
|
||||
QStandardItem *infoItem = d->m_model->item(i, 0);
|
||||
if (currentIndex() != d->m_model->indexFromItem(infoItem) &&
|
||||
infoItem->data(FilenameRole).toString() == filename &&
|
||||
infoItem->data(LineRole).toInt() == line) {
|
||||
setCurrentIndex(d->m_model->indexFromItem(infoItem));
|
||||
jumpToItem(currentIndex());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex QV8ProfilerEventsMainView::selectedItem() const
|
||||
{
|
||||
QModelIndexList sel = selectedIndexes();
|
||||
if (sel.isEmpty())
|
||||
return QModelIndex();
|
||||
else
|
||||
return sel.first();
|
||||
}
|
||||
|
||||
QString QV8ProfilerEventsMainView::QV8ProfilerEventsMainViewPrivate::textForItem(QStandardItem *item, bool recursive = true) const
|
||||
{
|
||||
QString str;
|
||||
|
||||
if (recursive) {
|
||||
// indentation
|
||||
QStandardItem *itemParent = item->parent();
|
||||
while (itemParent) {
|
||||
str += QLatin1String(" ");
|
||||
itemParent = itemParent->parent();
|
||||
}
|
||||
}
|
||||
|
||||
// item's data
|
||||
int colCount = m_model->columnCount();
|
||||
for (int j = 0; j < colCount; ++j) {
|
||||
QStandardItem *colItem = item->parent() ? item->parent()->child(item->row(),j) : m_model->item(item->row(),j);
|
||||
str += colItem->data(Qt::DisplayRole).toString();
|
||||
if (j < colCount-1) str += QLatin1Char('\t');
|
||||
}
|
||||
str += QLatin1Char('\n');
|
||||
|
||||
// recursively print children
|
||||
if (recursive && item->child(0))
|
||||
for (int j = 0; j != item->rowCount(); j++)
|
||||
str += textForItem(item->child(j));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsMainView::copyTableToClipboard() const
|
||||
{
|
||||
QString str;
|
||||
// headers
|
||||
int columnCount = d->m_model->columnCount();
|
||||
for (int i = 0; i < columnCount; ++i) {
|
||||
str += d->m_model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
|
||||
if (i < columnCount - 1)
|
||||
str += QLatin1Char('\t');
|
||||
else
|
||||
str += QLatin1Char('\n');
|
||||
}
|
||||
// data
|
||||
int rowCount = d->m_model->rowCount();
|
||||
for (int i = 0; i != rowCount; ++i) {
|
||||
str += d->textForItem(d->m_model->item(i));
|
||||
}
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(str, QClipboard::Selection);
|
||||
clipboard->setText(str, QClipboard::Clipboard);
|
||||
}
|
||||
|
||||
void QV8ProfilerEventsMainView::copyRowToClipboard() const
|
||||
{
|
||||
QString str;
|
||||
str = d->textForItem(d->m_model->itemFromIndex(selectedItem()), false);
|
||||
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(str, QClipboard::Selection);
|
||||
clipboard->setText(str, QClipboard::Clipboard);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QV8ProfilerEventRelativesView::QV8ProfilerEventRelativesView(QV8ProfilerDataModel *model,
|
||||
SubViewType viewType,
|
||||
QWidget *parent)
|
||||
: QmlProfilerTreeView(parent)
|
||||
, m_type(viewType)
|
||||
, m_v8Model(model)
|
||||
, m_model(new QStandardItemModel(this))
|
||||
{
|
||||
setModel(m_model);
|
||||
|
||||
updateHeader();
|
||||
setSortingEnabled(false);
|
||||
|
||||
connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(jumpToItem(QModelIndex)));
|
||||
}
|
||||
|
||||
QV8ProfilerEventRelativesView::~QV8ProfilerEventRelativesView()
|
||||
{
|
||||
}
|
||||
|
||||
void QV8ProfilerEventRelativesView::displayEvent(int index)
|
||||
{
|
||||
QV8EventData *event = m_v8Model->v8EventDescription(index);
|
||||
QTC_CHECK(event);
|
||||
|
||||
QList<QV8EventSub*> events;
|
||||
if (m_type == ParentsView)
|
||||
events = event->parentHash.values();
|
||||
else
|
||||
events = event->childrenHash.values();
|
||||
|
||||
rebuildTree(events);
|
||||
|
||||
updateHeader();
|
||||
resizeColumnToContents(0);
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(1);
|
||||
}
|
||||
|
||||
void QV8ProfilerEventRelativesView::rebuildTree(QList<QV8EventSub*> events)
|
||||
{
|
||||
clear();
|
||||
|
||||
QStandardItem *topLevelItem = m_model->invisibleRootItem();
|
||||
|
||||
foreach (QV8EventSub *event, events) {
|
||||
QList<QStandardItem *> newRow;
|
||||
newRow << new EventsViewItem(event->reference->displayName);
|
||||
newRow << new EventsViewItem(QV8ProfilerEventsMainView::displayTime(event->totalTime));
|
||||
newRow << new EventsViewItem(event->reference->functionName);
|
||||
newRow.at(0)->setData(QVariant(event->reference->eventId), EventIdRole);
|
||||
newRow.at(1)->setData(QVariant(event->totalTime));
|
||||
|
||||
foreach (QStandardItem *item, newRow)
|
||||
item->setEditable(false);
|
||||
|
||||
topLevelItem->appendRow(newRow);
|
||||
}
|
||||
}
|
||||
|
||||
void QV8ProfilerEventRelativesView::clear()
|
||||
{
|
||||
m_model->clear();
|
||||
}
|
||||
|
||||
void QV8ProfilerEventRelativesView::updateHeader()
|
||||
{
|
||||
m_model->setColumnCount(3);
|
||||
|
||||
int columnIndex = 0;
|
||||
if (m_type == ChildrenView)
|
||||
m_model->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Callee)));
|
||||
else
|
||||
m_model->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(Caller)));
|
||||
|
||||
m_model->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(TotalTime)));
|
||||
|
||||
if (m_type == ChildrenView)
|
||||
m_model->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CalleeDescription)));
|
||||
else
|
||||
m_model->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(displayHeader(CallerDescription)));
|
||||
}
|
||||
|
||||
void QV8ProfilerEventRelativesView::jumpToItem(const QModelIndex &index)
|
||||
{
|
||||
QStandardItem *infoItem = m_model->item(index.row(), 0);
|
||||
emit eventClicked(infoItem->data(EventIdRole).toInt());
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
163
src/plugins/qmlprofiler/qv8profilereventview.h
Normal file
163
src/plugins/qmlprofiler/qv8profilereventview.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QV8PROFILEREVENTVIEW_H
|
||||
#define QV8PROFILEREVENTVIEW_H
|
||||
|
||||
#include <QStandardItemModel>
|
||||
#include <qmldebug/qmlprofilereventtypes.h>
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilereventsmodelproxy.h"
|
||||
#include "qmlprofilertreeview.h"
|
||||
|
||||
#include <analyzerbase/ianalyzertool.h>
|
||||
|
||||
#include "qmlprofilerviewmanager.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class QV8ProfilerEventsMainView;
|
||||
class QV8ProfilerEventRelativesView;
|
||||
struct QV8EventSub;
|
||||
|
||||
|
||||
class QV8ProfilerEventsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QV8ProfilerEventsWidget(QWidget *parent,
|
||||
Analyzer::IAnalyzerTool *profilerTool,
|
||||
QmlProfilerViewManager *container,
|
||||
QmlProfilerModelManager *profilerModelManager );
|
||||
~QV8ProfilerEventsWidget();
|
||||
|
||||
void clear();
|
||||
|
||||
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
|
||||
QModelIndex selectedItem() const;
|
||||
bool mouseOnTable(const QPoint &position) const;
|
||||
void copyTableToClipboard() const;
|
||||
void copyRowToClipboard() const;
|
||||
|
||||
signals:
|
||||
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||
void showEventInTimeline(int eventId);
|
||||
void resized();
|
||||
|
||||
public slots:
|
||||
void updateSelectedEvent(int eventId) const;
|
||||
void selectBySourceLocation(const QString &filename, int line, int column);
|
||||
|
||||
protected:
|
||||
void contextMenuEvent(QContextMenuEvent *ev);
|
||||
virtual void resizeEvent(QResizeEvent *event);
|
||||
|
||||
private:
|
||||
class QV8ProfilerEventsWidgetPrivate;
|
||||
QV8ProfilerEventsWidgetPrivate *d;
|
||||
};
|
||||
|
||||
class QV8ProfilerEventsMainView : public QmlProfilerTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
explicit QV8ProfilerEventsMainView(QWidget *parent,
|
||||
QV8ProfilerDataModel *v8Model);
|
||||
~QV8ProfilerEventsMainView();
|
||||
|
||||
void setFieldViewable(Fields field, bool show);
|
||||
void setShowAnonymousEvents( bool showThem );
|
||||
|
||||
QModelIndex selectedItem() const;
|
||||
void copyTableToClipboard() const;
|
||||
void copyRowToClipboard() const;
|
||||
|
||||
static QString displayTime(double time);
|
||||
static QString nameForType(int typeNumber);
|
||||
|
||||
int selectedEventId() const;
|
||||
|
||||
void setShowExtendedStatistics(bool);
|
||||
bool showExtendedStatistics() const;
|
||||
|
||||
signals:
|
||||
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||
void eventSelected(int eventId);
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
void jumpToItem(const QModelIndex &index);
|
||||
void selectEvent(int eventId);
|
||||
void selectEventByLocation(const QString &filename, int line);
|
||||
void buildModel();
|
||||
|
||||
private:
|
||||
void setHeaderLabels();
|
||||
|
||||
private:
|
||||
class QV8ProfilerEventsMainViewPrivate;
|
||||
QV8ProfilerEventsMainViewPrivate *d;
|
||||
};
|
||||
|
||||
class QV8ProfilerEventRelativesView : public QmlProfilerTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum SubViewType {
|
||||
ParentsView,
|
||||
ChildrenView
|
||||
};
|
||||
|
||||
QV8ProfilerEventRelativesView(QV8ProfilerDataModel *model, SubViewType viewType,
|
||||
QWidget *parent);
|
||||
~QV8ProfilerEventRelativesView();
|
||||
|
||||
signals:
|
||||
void eventClicked(int eventId);
|
||||
|
||||
public slots:
|
||||
void displayEvent(int eventId);
|
||||
void jumpToItem(const QModelIndex &);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
void rebuildTree(QList<QV8EventSub*> events);
|
||||
void updateHeader();
|
||||
|
||||
QV8ProfilerEventRelativesView::SubViewType m_type;
|
||||
QV8ProfilerDataModel *m_v8Model;
|
||||
QStandardItemModel *m_model;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
#endif // QV8PROFILEREVENTVIEW_H
|
373
src/plugins/qmlprofiler/timelinemodelaggregator.cpp
Normal file
373
src/plugins/qmlprofiler/timelinemodelaggregator.cpp
Normal file
@@ -0,0 +1,373 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "timelinemodelaggregator.h"
|
||||
|
||||
#include "qmlprofilertimelinemodelproxy.h"
|
||||
#include "qmlprofilerpainteventsmodelproxy.h"
|
||||
#include "qmlprofilerplugin.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
|
||||
class TimelineModelAggregator::TimelineModelAggregatorPrivate {
|
||||
public:
|
||||
TimelineModelAggregatorPrivate(TimelineModelAggregator *qq):q(qq) {}
|
||||
~TimelineModelAggregatorPrivate() {}
|
||||
|
||||
TimelineModelAggregator *q;
|
||||
|
||||
int basicModelIndex;
|
||||
QList <AbstractTimelineModel *> modelList;
|
||||
QmlProfilerModelManager *modelManager;
|
||||
};
|
||||
|
||||
TimelineModelAggregator::TimelineModelAggregator(QObject *parent)
|
||||
: QObject(parent), d(new TimelineModelAggregatorPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
TimelineModelAggregator::~TimelineModelAggregator()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void TimelineModelAggregator::setModelManager(QmlProfilerModelManager *modelManager)
|
||||
{
|
||||
d->modelManager = modelManager;
|
||||
connect(modelManager,SIGNAL(stateChanged()),this,SLOT(dataChanged()));
|
||||
connect(modelManager,SIGNAL(countChanged()),this,SIGNAL(countChanged()));
|
||||
connect(modelManager,SIGNAL(dataAvailable()),this,SIGNAL(dataAvailable()));
|
||||
|
||||
// external models pushed on top
|
||||
foreach (AbstractTimelineModel *timelineModel, QmlProfilerPlugin::instance->getModels()) {
|
||||
timelineModel->setModelManager(modelManager);
|
||||
addModel(timelineModel);
|
||||
}
|
||||
|
||||
PaintEventsModelProxy *paintEventsModelProxy = new PaintEventsModelProxy(this);
|
||||
paintEventsModelProxy->setModelManager(modelManager);
|
||||
addModel(paintEventsModelProxy);
|
||||
|
||||
BasicTimelineModel *basicTimelineModel = new BasicTimelineModel(this);
|
||||
basicTimelineModel->setModelManager(modelManager);
|
||||
addModel(basicTimelineModel);
|
||||
// the basic model is the last one here
|
||||
d->basicModelIndex = d->modelList.count() - 1;
|
||||
|
||||
}
|
||||
|
||||
void TimelineModelAggregator::addModel(AbstractTimelineModel *m)
|
||||
{
|
||||
d->modelList << m;
|
||||
connect(m,SIGNAL(countChanged()),this,SIGNAL(countChanged()));
|
||||
connect(m,SIGNAL(emptyChanged()),this,SIGNAL(emptyChanged()));
|
||||
connect(m,SIGNAL(expandedChanged()),this,SIGNAL(expandedChanged()));
|
||||
connect(m,SIGNAL(stateChanged()),this,SIGNAL(stateChanged()));
|
||||
}
|
||||
|
||||
// order?
|
||||
int TimelineModelAggregator::categories() const
|
||||
{
|
||||
int categoryCount = 0;
|
||||
foreach (const AbstractTimelineModel *modelProxy, d->modelList)
|
||||
categoryCount += modelProxy->categories();
|
||||
return categoryCount;
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::visibleCategories() const
|
||||
{
|
||||
int categoryCount = 0;
|
||||
foreach (const AbstractTimelineModel *modelProxy, d->modelList) {
|
||||
for (int i = 0; i < modelProxy->categories(); i++)
|
||||
if (modelProxy->categoryDepth(i) > 0)
|
||||
categoryCount ++;
|
||||
}
|
||||
return categoryCount;
|
||||
}
|
||||
|
||||
QStringList TimelineModelAggregator::categoryTitles() const
|
||||
{
|
||||
QStringList retString;
|
||||
foreach (const AbstractTimelineModel *modelProxy, d->modelList)
|
||||
retString += modelProxy->categoryTitles();
|
||||
return retString;
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::count(int modelIndex) const
|
||||
{
|
||||
if (modelIndex == -1) {
|
||||
int totalCount = 0;
|
||||
foreach (const AbstractTimelineModel *modelProxy, d->modelList)
|
||||
totalCount += modelProxy->count();
|
||||
|
||||
return totalCount;
|
||||
} else {
|
||||
return d->modelList[modelIndex]->count();
|
||||
}
|
||||
}
|
||||
|
||||
bool TimelineModelAggregator::isEmpty() const
|
||||
{
|
||||
foreach (const AbstractTimelineModel *modelProxy, d->modelList)
|
||||
if (!modelProxy->isEmpty())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TimelineModelAggregator::eventAccepted(const QmlProfilerSimpleModel::QmlEventData &/*event*/) const
|
||||
{
|
||||
// accept all events
|
||||
return true;
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::basicModelIndex() const
|
||||
{
|
||||
return d->basicModelIndex;
|
||||
}
|
||||
|
||||
qint64 TimelineModelAggregator::lastTimeMark() const
|
||||
{
|
||||
qint64 mark = -1;
|
||||
foreach (const AbstractTimelineModel *modelProxy, d->modelList) {
|
||||
if (!modelProxy->isEmpty()) {
|
||||
qint64 mk = modelProxy->lastTimeMark();
|
||||
if (mark > mk)
|
||||
mark = mk;
|
||||
}
|
||||
}
|
||||
return mark;
|
||||
}
|
||||
|
||||
bool TimelineModelAggregator::expanded(int modelIndex, int category) const
|
||||
{
|
||||
return d->modelList[modelIndex]->expanded(category);
|
||||
}
|
||||
|
||||
void TimelineModelAggregator::setExpanded(int modelIndex, int category, bool expanded)
|
||||
{
|
||||
// int modelIndex = modelIndexForCategory(category);
|
||||
// category = correctedCategoryIndexForModel(modelIndex, categoryIndex);
|
||||
d->modelList[modelIndex]->setExpanded(category, expanded);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::categoryDepth(int modelIndex, int categoryIndex) const
|
||||
{
|
||||
return d->modelList[modelIndex]->categoryDepth(categoryIndex);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::categoryCount(int modelIndex) const
|
||||
{
|
||||
return d->modelList[modelIndex]->categoryCount();
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::rowCount(int modelIndex) const
|
||||
{
|
||||
return d->modelList[modelIndex]->rowCount();
|
||||
}
|
||||
|
||||
const QString TimelineModelAggregator::categoryLabel(int modelIndex, int categoryIndex) const
|
||||
{
|
||||
// int modelIndex = modelIndexForCategory(categoryIndex);
|
||||
// categoryIndex = correctedCategoryIndexForModel(modelIndex, categoryIndex);
|
||||
return d->modelList[modelIndex]->categoryLabel(categoryIndex);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::modelIndexForCategory(int absoluteCategoryIndex) const
|
||||
{
|
||||
int categoryIndex = absoluteCategoryIndex;
|
||||
for (int modelIndex = 0; modelIndex < d->modelList.count(); modelIndex++)
|
||||
if (categoryIndex < d->modelList[modelIndex]->categoryCount()) {
|
||||
return modelIndex;
|
||||
} else {
|
||||
categoryIndex -= d->modelList[modelIndex]->categoryCount();
|
||||
}
|
||||
|
||||
return modelCount()-1;
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::correctedCategoryIndexForModel(int modelIndex, int absoluteCategoryIndex) const
|
||||
{
|
||||
int categoryIndex = absoluteCategoryIndex;
|
||||
for (int mi = 0; mi < modelIndex; mi++)
|
||||
categoryIndex -= d->modelList[mi]->categoryCount();
|
||||
return categoryIndex;
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::findFirstIndex(int modelIndex, qint64 startTime) const
|
||||
{
|
||||
return d->modelList[modelIndex]->findFirstIndex(startTime);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::findFirstIndexNoParents(int modelIndex, qint64 startTime) const
|
||||
{
|
||||
return d->modelList[modelIndex]->findFirstIndexNoParents(startTime);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::findLastIndex(int modelIndex, qint64 endTime) const
|
||||
{
|
||||
return d->modelList[modelIndex]->findLastIndex(endTime);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::getEventType(int modelIndex, int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getEventType(index);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::getEventCategoryInModel(int modelIndex, int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getEventCategory(index);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::getEventRow(int modelIndex, int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getEventRow(index);
|
||||
}
|
||||
|
||||
qint64 TimelineModelAggregator::getDuration(int modelIndex, int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getDuration(index);
|
||||
}
|
||||
|
||||
qint64 TimelineModelAggregator::getStartTime(int modelIndex, int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getStartTime(index);
|
||||
}
|
||||
|
||||
qint64 TimelineModelAggregator::getEndTime(int modelIndex, int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getEndTime(index);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::getEventId(int modelIndex, int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getEventId(index);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::getBindingLoopDest(int modelIndex,int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getBindingLoopDest(index);
|
||||
}
|
||||
|
||||
QColor TimelineModelAggregator::getColor(int modelIndex, int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getColor(index);
|
||||
}
|
||||
|
||||
QVariantList TimelineModelAggregator::getColorRGB(int modelIndex, int itemIndex) const
|
||||
{
|
||||
// return color as RGB list, for use in Qml
|
||||
QColor c = getColor(modelIndex, itemIndex);
|
||||
QVariantList res;
|
||||
res.append(QVariant(c.red()));
|
||||
res.append(QVariant(c.green()));
|
||||
res.append(QVariant(c.blue()));
|
||||
return res;
|
||||
}
|
||||
|
||||
float TimelineModelAggregator::getHeight(int modelIndex, int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getHeight(index);
|
||||
}
|
||||
|
||||
const QVariantList TimelineModelAggregator::getLabelsForCategory(int modelIndex, int category) const
|
||||
{
|
||||
// int modelIndex = modelIndexForCategory(category);
|
||||
// category = correctedCategoryIndexForModel(modelIndex, category);
|
||||
return d->modelList[modelIndex]->getLabelsForCategory(category);
|
||||
}
|
||||
|
||||
const QVariantList TimelineModelAggregator::getEventDetails(int modelIndex, int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getEventDetails(index);
|
||||
}
|
||||
|
||||
const QVariantMap TimelineModelAggregator::getEventLocation(int modelIndex, int index) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getEventLocation(index);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::getEventIdForHash(const QString &hash) const
|
||||
{
|
||||
foreach (const AbstractTimelineModel *model, d->modelList) {
|
||||
int eventId = model->getEventIdForHash(hash);
|
||||
if (eventId != -1)
|
||||
return eventId;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::getEventIdForLocation(const QString &filename, int line, int column) const
|
||||
{
|
||||
foreach (const AbstractTimelineModel *model, d->modelList) {
|
||||
int eventId = model->getEventIdForLocation(filename, line, column);
|
||||
if (eventId != -1)
|
||||
return eventId;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void TimelineModelAggregator::dataChanged()
|
||||
{
|
||||
// this is a slot connected for every modelproxy
|
||||
// nothing to do here, each model will take care of itself
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::modelCount() const
|
||||
{
|
||||
return d->modelList.count();
|
||||
}
|
||||
|
||||
qint64 TimelineModelAggregator::traceStartTime() const
|
||||
{
|
||||
return d->modelManager->traceTime()->startTime();
|
||||
}
|
||||
|
||||
qint64 TimelineModelAggregator::traceEndTime() const
|
||||
{
|
||||
return d->modelManager->traceTime()->endTime();
|
||||
}
|
||||
|
||||
qint64 TimelineModelAggregator::traceDuration() const
|
||||
{
|
||||
return d->modelManager->traceTime()->duration();
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::getState() const
|
||||
{
|
||||
return (int)d->modelManager->state();
|
||||
}
|
||||
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
122
src/plugins/qmlprofiler/timelinemodelaggregator.h
Normal file
122
src/plugins/qmlprofiler/timelinemodelaggregator.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef TIMELINEMODELAGGREGATOR_H
|
||||
#define TIMELINEMODELAGGREGATOR_H
|
||||
|
||||
#include "abstracttimelinemodel.h"
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
class TimelineModelAggregator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TimelineModelAggregator(QObject *parent = 0);
|
||||
~TimelineModelAggregator();
|
||||
|
||||
void setModelManager(QmlProfilerModelManager *modelManager);
|
||||
void addModel(AbstractTimelineModel *m);
|
||||
|
||||
|
||||
Q_INVOKABLE int categories() const;
|
||||
Q_INVOKABLE int visibleCategories() const;
|
||||
Q_INVOKABLE QStringList categoryTitles() const;
|
||||
Q_INVOKABLE int count(int modelIndex = -1) const;
|
||||
void clear();
|
||||
Q_INVOKABLE int modelCount() const;
|
||||
|
||||
Q_INVOKABLE qint64 traceStartTime() const;
|
||||
Q_INVOKABLE qint64 traceEndTime() const;
|
||||
Q_INVOKABLE qint64 traceDuration() const;
|
||||
Q_INVOKABLE int getState() const;
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
bool eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const;
|
||||
|
||||
Q_INVOKABLE int basicModelIndex() const;
|
||||
|
||||
Q_INVOKABLE qint64 lastTimeMark() const;
|
||||
|
||||
Q_INVOKABLE bool expanded(int modelIndex, int category) const;
|
||||
Q_INVOKABLE void setExpanded(int modelIndex, int category, bool expanded);
|
||||
Q_INVOKABLE int categoryDepth(int modelIndex, int categoryIndex) const;
|
||||
Q_INVOKABLE int categoryCount(int modelIndex) const;
|
||||
Q_INVOKABLE int rowCount(int modelIndex) const;
|
||||
Q_INVOKABLE const QString categoryLabel(int modelIndex, int categoryIndex) const;
|
||||
|
||||
int findFirstIndex(int modelIndex, qint64 startTime) const;
|
||||
int findFirstIndexNoParents(int modelIndex, qint64 startTime) const;
|
||||
int findLastIndex(int modelIndex, qint64 endTime) const;
|
||||
|
||||
int getEventType(int modelIndex, int index) const;
|
||||
Q_INVOKABLE int getEventCategoryInModel(int modelIndex, int index) const;
|
||||
int getEventRow(int modelIndex, int index) const;
|
||||
Q_INVOKABLE qint64 getDuration(int modelIndex, int index) const;
|
||||
Q_INVOKABLE qint64 getStartTime(int modelIndex, int index) const;
|
||||
Q_INVOKABLE qint64 getEndTime(int modelIndex, int index) const;
|
||||
Q_INVOKABLE int getEventId(int modelIndex, int index) const;
|
||||
Q_INVOKABLE int getBindingLoopDest(int modelIndex, int index) const;
|
||||
Q_INVOKABLE QColor getColor(int modelIndex, int index) const;
|
||||
Q_INVOKABLE QVariantList getColorRGB(int modelIndex, int itemIndex) const;
|
||||
Q_INVOKABLE float getHeight(int modelIndex, int index) const;
|
||||
|
||||
Q_INVOKABLE const QVariantList getLabelsForCategory(int modelIndex, int category) const;
|
||||
|
||||
Q_INVOKABLE const QVariantList getEventDetails(int modelIndex, int index) const;
|
||||
Q_INVOKABLE const QVariantMap getEventLocation(int modelIndex, int index) const;
|
||||
|
||||
Q_INVOKABLE int getEventIdForHash(const QString &hash) const;
|
||||
Q_INVOKABLE int getEventIdForLocation(const QString &filename, int line, int column) const;
|
||||
|
||||
Q_INVOKABLE int modelIndexForCategory(int absoluteCategoryIndex) const;
|
||||
Q_INVOKABLE int correctedCategoryIndexForModel(int modelIndex, int absoluteCategoryIndex) const;
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
void dataAvailable();
|
||||
void stateChanged();
|
||||
void emptyChanged();
|
||||
void expandedChanged();
|
||||
|
||||
protected slots:
|
||||
void dataChanged();
|
||||
|
||||
private:
|
||||
class TimelineModelAggregatorPrivate;
|
||||
TimelineModelAggregatorPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TIMELINEMODELAGGREGATOR_H
|
@@ -35,6 +35,7 @@
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QVarLengthArray>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@@ -44,14 +45,26 @@ const int DefaultRowHeight = 30;
|
||||
|
||||
TimelineRenderer::TimelineRenderer(QDeclarativeItem *parent) :
|
||||
QDeclarativeItem(parent), m_startTime(0), m_endTime(0), m_spacing(0),
|
||||
m_lastStartTime(0), m_lastEndTime(0), m_profilerDataModel(0)
|
||||
m_lastStartTime(0), m_lastEndTime(0)
|
||||
, m_profilerModelProxy(0)
|
||||
{
|
||||
clearData();
|
||||
setFlag(QGraphicsItem::ItemHasNoContents, false);
|
||||
setAcceptedMouseButtons(Qt::LeftButton);
|
||||
setAcceptHoverEvents(true);
|
||||
for (int i=0; i<QmlDebug::MaximumQmlEventType; i++)
|
||||
m_rowsExpanded << false;
|
||||
}
|
||||
|
||||
void TimelineRenderer::setProfilerModelProxy(QObject *profilerModelProxy)
|
||||
{
|
||||
if (m_profilerModelProxy) {
|
||||
disconnect(m_profilerModelProxy, SIGNAL(expandedChanged()), this, SLOT(requestPaint()));
|
||||
}
|
||||
m_profilerModelProxy = qobject_cast<TimelineModelAggregator *>(profilerModelProxy);
|
||||
|
||||
if (m_profilerModelProxy) {
|
||||
connect(m_profilerModelProxy, SIGNAL(expandedChanged()), this, SLOT(requestPaint()));
|
||||
}
|
||||
emit profilerModelProxyChanged(m_profilerModelProxy);
|
||||
}
|
||||
|
||||
void TimelineRenderer::componentComplete()
|
||||
@@ -80,105 +93,68 @@ void TimelineRenderer::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWid
|
||||
|
||||
m_spacing = qreal(width()) / windowDuration;
|
||||
|
||||
m_rowWidths.clear();
|
||||
// The "1+" is because the reference screenshot features an empty row per type, in order to leave space for the title
|
||||
for (int i=0; i<QmlDebug::MaximumQmlEventType; i++) {
|
||||
m_rowWidths << 1 + (m_rowsExpanded[i] ? m_profilerDataModel->uniqueEventsOfType(i) :
|
||||
m_profilerDataModel->maxNestingForType(i));
|
||||
}
|
||||
|
||||
// event rows
|
||||
m_rowStarts.clear();
|
||||
int pos = 0;
|
||||
for (int i=0; i<QmlDebug::MaximumQmlEventType; i++) {
|
||||
m_rowStarts << pos;
|
||||
pos += DefaultRowHeight * m_rowWidths[i];
|
||||
}
|
||||
|
||||
p->setPen(Qt::transparent);
|
||||
|
||||
// speedup: don't draw overlapping events, just skip them
|
||||
m_rowLastX.clear();
|
||||
for (int i=0; i<QmlDebug::MaximumQmlEventType; i++)
|
||||
for (int j=0; j<m_rowWidths[i]; j++)
|
||||
m_rowLastX << -m_startTime * m_spacing;
|
||||
|
||||
int firstIndex = m_profilerDataModel->findFirstIndex(m_startTime);
|
||||
int lastIndex = m_profilerDataModel->findLastIndex(m_endTime);
|
||||
|
||||
if (lastIndex < m_profilerDataModel->count()) {
|
||||
drawItemsToPainter(p, firstIndex, lastIndex);
|
||||
drawSelectionBoxes(p, firstIndex, lastIndex);
|
||||
drawBindingLoopMarkers(p, firstIndex, lastIndex);
|
||||
}
|
||||
|
||||
m_lastStartTime = m_startTime;
|
||||
m_lastEndTime = m_endTime;
|
||||
}
|
||||
|
||||
QColor TimelineRenderer::colorForItem(int itemIndex)
|
||||
{
|
||||
int ndx = m_profilerDataModel->getEventId(itemIndex);
|
||||
return QColor::fromHsl((ndx*25)%360, 76, 166);
|
||||
}
|
||||
|
||||
void TimelineRenderer::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
|
||||
{
|
||||
int x, y, width, height, rowNumber, eventType;
|
||||
for (int i = fromIndex; i <= toIndex; i++) {
|
||||
x = (m_profilerDataModel->getStartTime(i) - m_startTime) * m_spacing;
|
||||
|
||||
eventType = m_profilerDataModel->getType(i);
|
||||
if (m_rowsExpanded[eventType])
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
(m_profilerDataModel->eventPosInType(i) + 1);
|
||||
else
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
m_profilerDataModel->getNestingLevel(i);
|
||||
|
||||
width = m_profilerDataModel->getDuration(i)*m_spacing;
|
||||
if (width<1)
|
||||
width = 1;
|
||||
|
||||
rowNumber = y/DefaultRowHeight;
|
||||
if (m_rowLastX[rowNumber] > x+width)
|
||||
continue;
|
||||
m_rowLastX[rowNumber] = x+width;
|
||||
|
||||
// special: animations
|
||||
if (eventType == 0 && m_profilerDataModel->getAnimationCount(i) >= 0) {
|
||||
double scale = m_profilerDataModel->getMaximumAnimationCount() -
|
||||
m_profilerDataModel->getMinimumAnimationCount();
|
||||
double fraction;
|
||||
if (scale > 1)
|
||||
fraction = (double)(m_profilerDataModel->getAnimationCount(i) -
|
||||
m_profilerDataModel->getMinimumAnimationCount()) / scale;
|
||||
else
|
||||
fraction = 1.0;
|
||||
height = DefaultRowHeight * (fraction * 0.85 + 0.15);
|
||||
y += DefaultRowHeight - height;
|
||||
|
||||
double fpsFraction = m_profilerDataModel->getFramerate(i) / 60.0;
|
||||
if (fpsFraction > 1.0)
|
||||
fpsFraction = 1.0;
|
||||
p->setBrush(QColor::fromHsl((fpsFraction*96)+10, 76, 166));
|
||||
p->drawRect(x, y, width, height);
|
||||
} else {
|
||||
// normal events
|
||||
p->setBrush(colorForItem(i));
|
||||
p->drawRect(x, y, width, DefaultRowHeight);
|
||||
for (int modelIndex = 0; modelIndex < m_profilerModelProxy->modelCount(); modelIndex++) {
|
||||
int lastIndex = m_profilerModelProxy->findLastIndex(modelIndex, m_endTime);
|
||||
if (lastIndex >= 0 && lastIndex < m_profilerModelProxy->count(modelIndex)) {
|
||||
int firstIndex = m_profilerModelProxy->findFirstIndex(modelIndex, m_startTime);
|
||||
if (firstIndex >= 0) {
|
||||
drawItemsToPainter(p, modelIndex, firstIndex, lastIndex);
|
||||
if (m_selectedModel == modelIndex)
|
||||
drawSelectionBoxes(p, modelIndex, firstIndex, lastIndex);
|
||||
drawBindingLoopMarkers(p, modelIndex, firstIndex, lastIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_lastStartTime = m_startTime;
|
||||
m_lastEndTime = m_endTime;
|
||||
|
||||
}
|
||||
|
||||
void TimelineRenderer::drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex)
|
||||
void TimelineRenderer::drawItemsToPainter(QPainter *p, int modelIndex, int fromIndex, int toIndex)
|
||||
{
|
||||
p->save();
|
||||
p->setPen(Qt::transparent);
|
||||
int modelRowStart = 0;
|
||||
for (int mi = 0; mi < modelIndex; mi++)
|
||||
modelRowStart += m_profilerModelProxy->rowCount(mi);
|
||||
|
||||
for (int i = fromIndex; i <= toIndex; i++) {
|
||||
int x, y, width, height;
|
||||
x = (m_profilerModelProxy->getStartTime(modelIndex, i) - m_startTime) * m_spacing;
|
||||
|
||||
int rowNumber = m_profilerModelProxy->getEventRow(modelIndex, i);
|
||||
y = (modelRowStart + rowNumber) * DefaultRowHeight;
|
||||
|
||||
width = m_profilerModelProxy->getDuration(modelIndex, i) * m_spacing;
|
||||
if (width < 1)
|
||||
width = 1;
|
||||
|
||||
height = DefaultRowHeight * m_profilerModelProxy->getHeight(modelIndex, i);
|
||||
y += DefaultRowHeight - height;
|
||||
|
||||
// normal events
|
||||
p->setBrush(m_profilerModelProxy->getColor(modelIndex, i));
|
||||
p->drawRect(x, y, width, height);
|
||||
}
|
||||
p->restore();
|
||||
}
|
||||
|
||||
void TimelineRenderer::drawSelectionBoxes(QPainter *p, int modelIndex, int fromIndex, int toIndex)
|
||||
{
|
||||
if (m_selectedItem == -1)
|
||||
return;
|
||||
|
||||
int id = m_profilerDataModel->getEventId(m_selectedItem);
|
||||
|
||||
p->setBrush(Qt::transparent);
|
||||
int id = m_profilerModelProxy->getEventId(modelIndex, m_selectedItem);
|
||||
|
||||
int modelRowStart = 0;
|
||||
for (int mi = 0; mi < modelIndex; mi++)
|
||||
modelRowStart += m_profilerModelProxy->rowCount(mi);
|
||||
|
||||
p->save();
|
||||
|
||||
QColor selectionColor = Qt::blue;
|
||||
if (m_selectionLocked)
|
||||
selectionColor = QColor(96,0,255);
|
||||
@@ -186,25 +162,18 @@ void TimelineRenderer::drawSelectionBoxes(QPainter *p, int fromIndex, int toInde
|
||||
QPen lightPen(QBrush(selectionColor.lighter(130)), 2);
|
||||
lightPen.setJoinStyle(Qt::MiterJoin);
|
||||
p->setPen(lightPen);
|
||||
p->setBrush(Qt::transparent);
|
||||
|
||||
int x, y, width, eventType;
|
||||
p->setPen(lightPen);
|
||||
|
||||
int x, y, width;
|
||||
QRect selectedItemRect(0,0,0,0);
|
||||
for (int i = fromIndex; i <= toIndex; i++) {
|
||||
if (m_profilerDataModel->getEventId(i) != id)
|
||||
if (m_profilerModelProxy->getEventId(modelIndex, i) != id)
|
||||
continue;
|
||||
|
||||
x = (m_profilerDataModel->getStartTime(i) - m_startTime) * m_spacing;
|
||||
eventType = m_profilerDataModel->getType(i);
|
||||
if (m_rowsExpanded[eventType])
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
(m_profilerDataModel->eventPosInType(i) + 1);
|
||||
else
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
m_profilerDataModel->getNestingLevel(i);
|
||||
x = (m_profilerModelProxy->getStartTime(modelIndex, i) - m_startTime) * m_spacing;
|
||||
y = (modelRowStart + m_profilerModelProxy->getEventRow(modelIndex, i)) * DefaultRowHeight;
|
||||
|
||||
width = m_profilerDataModel->getDuration(i)*m_spacing;
|
||||
width = m_profilerModelProxy->getDuration(modelIndex, i)*m_spacing;
|
||||
if (width<1)
|
||||
width = 1;
|
||||
|
||||
@@ -219,12 +188,14 @@ void TimelineRenderer::drawSelectionBoxes(QPainter *p, int fromIndex, int toInde
|
||||
p->setPen(strongPen);
|
||||
p->drawRect(selectedItemRect);
|
||||
}
|
||||
|
||||
p->restore();
|
||||
}
|
||||
|
||||
void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int fromIndex, int toIndex)
|
||||
void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int modelIndex, int fromIndex, int toIndex)
|
||||
{
|
||||
int destindex;
|
||||
int xfrom, xto, eventType;
|
||||
int xfrom, xto;
|
||||
int yfrom, yto;
|
||||
int radius = DefaultRowHeight / 3;
|
||||
QPen shadowPen = QPen(QColor("grey"),2);
|
||||
@@ -234,38 +205,24 @@ void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int fromIndex, int to
|
||||
|
||||
p->save();
|
||||
for (int i = fromIndex; i <= toIndex; i++) {
|
||||
destindex = m_profilerDataModel->getBindingLoopDest(i);
|
||||
destindex = m_profilerModelProxy->getBindingLoopDest(modelIndex, i);
|
||||
if (destindex >= 0) {
|
||||
// from
|
||||
xfrom = (m_profilerDataModel->getStartTime(i) +
|
||||
m_profilerDataModel->getDuration(i)/2 -
|
||||
xfrom = (m_profilerModelProxy->getStartTime(modelIndex, i) +
|
||||
m_profilerModelProxy->getDuration(modelIndex, i)/2 -
|
||||
m_startTime) * m_spacing;
|
||||
eventType = m_profilerDataModel->getType(i);
|
||||
if (m_rowsExpanded[eventType])
|
||||
yfrom = m_rowStarts[eventType] + DefaultRowHeight*
|
||||
(m_profilerDataModel->eventPosInType(i) + 1);
|
||||
else
|
||||
yfrom = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
m_profilerDataModel->getNestingLevel(i);
|
||||
|
||||
yfrom = getYPosition(modelIndex, i);
|
||||
yfrom += DefaultRowHeight / 2;
|
||||
|
||||
// to
|
||||
xto = (m_profilerDataModel->getStartTime(destindex) +
|
||||
m_profilerDataModel->getDuration(destindex)/2 -
|
||||
xto = (m_profilerModelProxy->getStartTime(modelIndex, destindex) +
|
||||
m_profilerModelProxy->getDuration(modelIndex, destindex)/2 -
|
||||
m_startTime) * m_spacing;
|
||||
eventType = m_profilerDataModel->getType(destindex);
|
||||
if (m_rowsExpanded[eventType])
|
||||
yto = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
(m_profilerDataModel->eventPosInType(destindex) + 1);
|
||||
else
|
||||
yto = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
m_profilerDataModel->getNestingLevel(destindex);
|
||||
|
||||
yto = getYPosition(modelIndex, destindex);
|
||||
yto += DefaultRowHeight / 2;
|
||||
|
||||
// radius
|
||||
int eventWidth = m_profilerDataModel->getDuration(i) * m_spacing;
|
||||
int eventWidth = m_profilerModelProxy->getDuration(modelIndex, i) * m_spacing;
|
||||
radius = 5;
|
||||
if (radius * 2 > eventWidth)
|
||||
radius = eventWidth / 2;
|
||||
@@ -292,6 +249,17 @@ void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int fromIndex, int to
|
||||
p->restore();
|
||||
}
|
||||
|
||||
int TimelineRenderer::modelFromPosition(int y)
|
||||
{
|
||||
y = y / DefaultRowHeight;
|
||||
for (int modelIndex = 0; modelIndex < m_profilerModelProxy->modelCount(); modelIndex++) {
|
||||
y -= m_profilerModelProxy->rowCount(modelIndex);
|
||||
if (y < 0)
|
||||
return modelIndex;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TimelineRenderer::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
// special case: if there is a drag area below me, don't accept the
|
||||
@@ -326,15 +294,17 @@ void TimelineRenderer::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
|
||||
void TimelineRenderer::manageClicked()
|
||||
{
|
||||
if (m_currentSelection.eventIndex != -1) {
|
||||
if (m_currentSelection.eventIndex == m_selectedItem)
|
||||
if (m_currentSelection.eventIndex == m_selectedItem && m_currentSelection.modelIndex == m_selectedModel)
|
||||
setSelectionLocked(!m_selectionLocked);
|
||||
else
|
||||
setSelectionLocked(true);
|
||||
emit itemPressed(m_currentSelection.eventIndex);
|
||||
emit itemPressed(m_currentSelection.modelIndex, m_currentSelection.eventIndex);
|
||||
} else {
|
||||
// setSelectionLocked(false);
|
||||
setSelectionLocked(false);
|
||||
}
|
||||
setSelectedModel(m_currentSelection.modelIndex);
|
||||
setSelectedItem(m_currentSelection.eventIndex);
|
||||
|
||||
}
|
||||
|
||||
void TimelineRenderer::manageHovered(int x, int y)
|
||||
@@ -344,6 +314,7 @@ void TimelineRenderer::manageHovered(int x, int y)
|
||||
|
||||
qint64 time = x * (m_endTime - m_startTime) / width() + m_startTime;
|
||||
int row = y / DefaultRowHeight;
|
||||
int modelIndex = modelFromPosition(y);
|
||||
|
||||
// already covered? nothing to do
|
||||
if (m_currentSelection.eventIndex != -1 &&
|
||||
@@ -354,34 +325,37 @@ void TimelineRenderer::manageHovered(int x, int y)
|
||||
}
|
||||
|
||||
// find if there's items in the time range
|
||||
int eventFrom = m_profilerDataModel->findFirstIndex(time);
|
||||
int eventTo = m_profilerDataModel->findLastIndex(time);
|
||||
if (eventTo < eventFrom || eventTo >= m_profilerDataModel->count()) {
|
||||
int eventFrom = m_profilerModelProxy->findFirstIndex(modelIndex, time);
|
||||
int eventTo = m_profilerModelProxy->findLastIndex(modelIndex, time);
|
||||
if (eventFrom == -1 ||
|
||||
eventTo < eventFrom || eventTo >= m_profilerModelProxy->count()) {
|
||||
m_currentSelection.eventIndex = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int modelRowStart = 0;
|
||||
for (int mi = 0; mi < modelIndex; mi++)
|
||||
modelRowStart += m_profilerModelProxy->rowCount(mi);
|
||||
|
||||
// find if we are in the right column
|
||||
int itemRow, eventType;
|
||||
int itemRow;
|
||||
for (int i=eventTo; i>=eventFrom; --i) {
|
||||
if (ceil(m_profilerDataModel->getEndTime(i)*m_spacing) < floor(time*m_spacing))
|
||||
if (ceil(m_profilerModelProxy->getEndTime(modelIndex, i)*m_spacing) < floor(time*m_spacing))
|
||||
continue;
|
||||
|
||||
eventType = m_profilerDataModel->getType(i);
|
||||
if (m_rowsExpanded[eventType])
|
||||
itemRow = m_rowStarts[eventType]/DefaultRowHeight +
|
||||
m_profilerDataModel->eventPosInType(i) + 1;
|
||||
else
|
||||
itemRow = m_rowStarts[eventType]/DefaultRowHeight +
|
||||
m_profilerDataModel->getNestingLevel(i);
|
||||
itemRow = modelRowStart + m_profilerModelProxy->getEventRow(modelIndex, i);
|
||||
|
||||
if (itemRow == row) {
|
||||
// match
|
||||
m_currentSelection.eventIndex = i;
|
||||
m_currentSelection.startTime = m_profilerDataModel->getStartTime(i);
|
||||
m_currentSelection.endTime = m_profilerDataModel->getEndTime(i);
|
||||
m_currentSelection.startTime = m_profilerModelProxy->getStartTime(modelIndex, i);
|
||||
m_currentSelection.endTime = m_profilerModelProxy->getEndTime(modelIndex, i);
|
||||
m_currentSelection.row = row;
|
||||
if (!m_selectionLocked)
|
||||
m_currentSelection.modelIndex = modelIndex;
|
||||
if (!m_selectionLocked) {
|
||||
setSelectedModel(modelIndex);
|
||||
setSelectedItem(i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -400,131 +374,189 @@ void TimelineRenderer::clearData()
|
||||
m_currentSelection.endTime = -1;
|
||||
m_currentSelection.row = -1;
|
||||
m_currentSelection.eventIndex = -1;
|
||||
m_currentSelection.modelIndex = -1;
|
||||
m_selectedItem = -1;
|
||||
m_selectedModel = -1;
|
||||
m_selectionLocked = true;
|
||||
}
|
||||
|
||||
qint64 TimelineRenderer::getDuration(int index) const
|
||||
int TimelineRenderer::getYPosition(int modelIndex, int index) const
|
||||
{
|
||||
Q_ASSERT(m_profilerDataModel);
|
||||
return m_profilerDataModel->getEndTime(index) -
|
||||
m_profilerDataModel->getStartTime(index);
|
||||
}
|
||||
|
||||
QString TimelineRenderer::getFilename(int index) const
|
||||
{
|
||||
Q_ASSERT(m_profilerDataModel);
|
||||
return m_profilerDataModel->getFilename(index);
|
||||
}
|
||||
|
||||
int TimelineRenderer::getLine(int index) const
|
||||
{
|
||||
Q_ASSERT(m_profilerDataModel);
|
||||
return m_profilerDataModel->getLine(index);
|
||||
}
|
||||
|
||||
QString TimelineRenderer::getDetails(int index) const
|
||||
{
|
||||
Q_ASSERT(m_profilerDataModel);
|
||||
return m_profilerDataModel->getDetails(index);
|
||||
}
|
||||
|
||||
int TimelineRenderer::getYPosition(int index) const
|
||||
{
|
||||
Q_ASSERT(m_profilerDataModel);
|
||||
if (index >= m_profilerDataModel->count() || m_rowStarts.isEmpty())
|
||||
Q_ASSERT(m_profilerModelProxy);
|
||||
if (index >= m_profilerModelProxy->count())
|
||||
return 0;
|
||||
int y, eventType = m_profilerDataModel->getType(index);
|
||||
if (m_rowsExpanded[eventType])
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
(m_profilerDataModel->eventPosInType(index) + 1);
|
||||
else
|
||||
y = m_rowStarts[eventType] + DefaultRowHeight *
|
||||
m_profilerDataModel->getNestingLevel(index);
|
||||
return y;
|
||||
}
|
||||
|
||||
void TimelineRenderer::setRowExpanded(int rowIndex, bool expanded)
|
||||
{
|
||||
m_rowsExpanded[rowIndex] = expanded;
|
||||
update();
|
||||
int modelRowStart = 0;
|
||||
for (int mi = 0; mi < modelIndex; mi++)
|
||||
modelRowStart += m_profilerModelProxy->rowCount(mi);
|
||||
|
||||
int y = DefaultRowHeight * (modelRowStart + m_profilerModelProxy->getEventRow(modelIndex, index));
|
||||
return y;
|
||||
}
|
||||
|
||||
void TimelineRenderer::selectNext()
|
||||
{
|
||||
if (m_profilerDataModel->count() == 0)
|
||||
if (m_profilerModelProxy->count() == 0)
|
||||
return;
|
||||
|
||||
// select next in view or after
|
||||
int newIndex = m_selectedItem+1;
|
||||
if (newIndex >= m_profilerDataModel->count())
|
||||
newIndex = 0;
|
||||
if (m_profilerDataModel->getEndTime(newIndex) < m_startTime)
|
||||
newIndex = m_profilerDataModel->findFirstIndexNoParents(m_startTime);
|
||||
setSelectedItem(newIndex);
|
||||
qint64 searchTime = m_startTime;
|
||||
if (m_selectedItem != -1)
|
||||
searchTime = m_profilerModelProxy->getStartTime(m_selectedModel, m_selectedItem);
|
||||
|
||||
QVarLengthArray<int> itemIndexes(m_profilerModelProxy->modelCount());
|
||||
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++) {
|
||||
if (m_profilerModelProxy->count(i) > 0) {
|
||||
if (m_selectedModel == i) {
|
||||
itemIndexes[i] = (m_selectedItem + 1) % m_profilerModelProxy->count(i);
|
||||
} else {
|
||||
if (m_profilerModelProxy->getStartTime(i, 0) > searchTime)
|
||||
itemIndexes[i] = 0;
|
||||
else
|
||||
itemIndexes[i] = (m_profilerModelProxy->findLastIndex(i, searchTime) + 1) % m_profilerModelProxy->count(i);
|
||||
}
|
||||
} else {
|
||||
itemIndexes[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int candidateModelIndex = -1;
|
||||
qint64 candidateStartTime = m_profilerModelProxy->traceEndTime();
|
||||
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++) {
|
||||
if (itemIndexes[i] == -1)
|
||||
continue;
|
||||
qint64 newStartTime = m_profilerModelProxy->getStartTime(i, itemIndexes[i]);
|
||||
if (newStartTime > searchTime && newStartTime < candidateStartTime) {
|
||||
candidateStartTime = newStartTime;
|
||||
candidateModelIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
int itemIndex;
|
||||
if (candidateModelIndex != -1) {
|
||||
itemIndex = itemIndexes[candidateModelIndex];
|
||||
} else {
|
||||
// find the first index of them all (todo: the modelproxy should do this)
|
||||
itemIndex = -1;
|
||||
candidateStartTime = m_profilerModelProxy->traceEndTime();
|
||||
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++)
|
||||
if (m_profilerModelProxy->count(i) > 0 &&
|
||||
m_profilerModelProxy->getStartTime(i,0) < candidateStartTime) {
|
||||
candidateModelIndex = i;
|
||||
itemIndex = 0;
|
||||
candidateStartTime = m_profilerModelProxy->getStartTime(i,0);
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedModel(candidateModelIndex);
|
||||
setSelectedItem(itemIndex);
|
||||
}
|
||||
|
||||
void TimelineRenderer::selectPrev()
|
||||
{
|
||||
if (m_profilerDataModel->count() == 0)
|
||||
if (m_profilerModelProxy->count() == 0)
|
||||
return;
|
||||
|
||||
// select last in view or before
|
||||
int newIndex = m_selectedItem-1;
|
||||
if (newIndex < 0)
|
||||
newIndex = m_profilerDataModel->count()-1;
|
||||
if (m_profilerDataModel->getStartTime(newIndex) > m_endTime)
|
||||
newIndex = m_profilerDataModel->findLastIndex(m_endTime);
|
||||
setSelectedItem(newIndex);
|
||||
qint64 searchTime = m_endTime;
|
||||
if (m_selectedItem != -1)
|
||||
searchTime = m_profilerModelProxy->getEndTime(m_selectedModel, m_selectedItem);
|
||||
|
||||
QVarLengthArray<int> itemIndexes(m_profilerModelProxy->modelCount());
|
||||
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++) {
|
||||
if (m_selectedModel == i) {
|
||||
itemIndexes[i] = m_selectedItem - 1;
|
||||
if (itemIndexes[i] < 0)
|
||||
itemIndexes[i] = m_profilerModelProxy->count(m_selectedModel) -1;
|
||||
}
|
||||
else
|
||||
itemIndexes[i] = m_profilerModelProxy->findLastIndex(i, searchTime);
|
||||
}
|
||||
|
||||
int candidateModelIndex = -1;
|
||||
qint64 candidateStartTime = m_profilerModelProxy->traceStartTime();
|
||||
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++) {
|
||||
if (itemIndexes[i] == -1
|
||||
|| itemIndexes[i] >= m_profilerModelProxy->count(i))
|
||||
continue;
|
||||
qint64 newStartTime = m_profilerModelProxy->getStartTime(i, itemIndexes[i]);
|
||||
if (newStartTime < searchTime && newStartTime > candidateStartTime) {
|
||||
candidateStartTime = newStartTime;
|
||||
candidateModelIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
int itemIndex = -1;
|
||||
if (candidateModelIndex != -1) {
|
||||
itemIndex = itemIndexes[candidateModelIndex];
|
||||
} else {
|
||||
// find the last index of them all (todo: the modelproxy should do this)
|
||||
candidateModelIndex = 0;
|
||||
candidateStartTime = m_profilerModelProxy->traceStartTime();
|
||||
for (int i = 0; i < m_profilerModelProxy->modelCount(); i++)
|
||||
if (m_profilerModelProxy->count(i) > 0 &&
|
||||
m_profilerModelProxy->getStartTime(i,m_profilerModelProxy->count(i)-1) > candidateStartTime) {
|
||||
candidateModelIndex = i;
|
||||
itemIndex = m_profilerModelProxy->count(candidateModelIndex) - 1;
|
||||
candidateStartTime = m_profilerModelProxy->getStartTime(i,m_profilerModelProxy->count(i)-1);
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedModel(candidateModelIndex);
|
||||
setSelectedItem(itemIndex);
|
||||
}
|
||||
|
||||
int TimelineRenderer::nextItemFromId(int eventId) const
|
||||
int TimelineRenderer::nextItemFromId(int modelIndex, int eventId) const
|
||||
{
|
||||
int ndx = -1;
|
||||
if (m_selectedItem == -1)
|
||||
ndx = m_profilerDataModel->findFirstIndexNoParents(m_startTime);
|
||||
ndx = m_profilerModelProxy->findFirstIndexNoParents(modelIndex, m_startTime);
|
||||
else
|
||||
ndx = m_selectedItem + 1;
|
||||
if (ndx >= m_profilerDataModel->count())
|
||||
if (ndx < 0)
|
||||
return -1;
|
||||
if (ndx >= m_profilerModelProxy->count(modelIndex))
|
||||
ndx = 0;
|
||||
int startIndex = ndx;
|
||||
do {
|
||||
if (m_profilerDataModel->getEventId(ndx) == eventId)
|
||||
if (m_profilerModelProxy->getEventId(modelIndex, ndx) == eventId)
|
||||
return ndx;
|
||||
ndx = (ndx + 1) % m_profilerDataModel->count();
|
||||
ndx = (ndx + 1) % m_profilerModelProxy->count(modelIndex);
|
||||
} while (ndx != startIndex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int TimelineRenderer::prevItemFromId(int eventId) const
|
||||
int TimelineRenderer::prevItemFromId(int modelIndex, int eventId) const
|
||||
{
|
||||
int ndx = -1;
|
||||
if (m_selectedItem == -1)
|
||||
ndx = m_profilerDataModel->findFirstIndexNoParents(m_startTime);
|
||||
ndx = m_profilerModelProxy->findFirstIndexNoParents(modelIndex, m_startTime);
|
||||
else
|
||||
ndx = m_selectedItem - 1;
|
||||
if (ndx < 0)
|
||||
ndx = m_profilerDataModel->count() - 1;
|
||||
ndx = m_profilerModelProxy->count(modelIndex) - 1;
|
||||
int startIndex = ndx;
|
||||
do {
|
||||
if (m_profilerDataModel->getEventId(ndx) == eventId)
|
||||
if (m_profilerModelProxy->getEventId(modelIndex, ndx) == eventId)
|
||||
return ndx;
|
||||
if (--ndx < 0)
|
||||
ndx = m_profilerDataModel->count()-1;
|
||||
ndx = m_profilerModelProxy->count(modelIndex)-1;
|
||||
} while (ndx != startIndex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void TimelineRenderer::selectNextFromId(int eventId)
|
||||
void TimelineRenderer::selectNextFromId(int modelIndex, int eventId)
|
||||
{
|
||||
int eventIndex = nextItemFromId(eventId);
|
||||
if (eventIndex != -1)
|
||||
int eventIndex = nextItemFromId(modelIndex, eventId);
|
||||
if (eventIndex != -1) {
|
||||
setSelectedModel(modelIndex);
|
||||
setSelectedItem(eventIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineRenderer::selectPrevFromId(int eventId)
|
||||
void TimelineRenderer::selectPrevFromId(int modelIndex, int eventId)
|
||||
{
|
||||
int eventIndex = prevItemFromId(eventId);
|
||||
if (eventIndex != -1)
|
||||
int eventIndex = prevItemFromId(modelIndex, eventId);
|
||||
if (eventIndex != -1) {
|
||||
setSelectedModel(modelIndex);
|
||||
setSelectedItem(eventIndex);
|
||||
}
|
||||
}
|
||||
|
@@ -32,7 +32,8 @@
|
||||
|
||||
#include <QDeclarativeItem>
|
||||
#include <QScriptValue>
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
#include "qmlprofilertimelinemodelproxy.h"
|
||||
#include "timelinemodelaggregator.h"
|
||||
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
@@ -42,9 +43,10 @@ class TimelineRenderer : public QDeclarativeItem
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(qint64 startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
|
||||
Q_PROPERTY(qint64 endTime READ endTime WRITE setEndTime NOTIFY endTimeChanged)
|
||||
Q_PROPERTY(QObject* profilerDataModel READ profilerDataModel WRITE setProfilerDataModel NOTIFY profilerDataModelChanged)
|
||||
Q_PROPERTY(QObject *profilerModelProxy READ profilerModelProxy WRITE setProfilerModelProxy NOTIFY profilerModelProxyChanged)
|
||||
Q_PROPERTY(bool selectionLocked READ selectionLocked WRITE setSelectionLocked NOTIFY selectionLockedChanged)
|
||||
Q_PROPERTY(int selectedItem READ selectedItem WRITE setSelectedItem NOTIFY selectedItemChanged)
|
||||
Q_PROPERTY(int selectedModel READ selectedModel WRITE setSelectedModel NOTIFY selectedModelChanged)
|
||||
Q_PROPERTY(int startDragArea READ startDragArea WRITE setStartDragArea NOTIFY startDragAreaChanged)
|
||||
Q_PROPERTY(int endDragArea READ endDragArea WRITE setEndDragArea NOTIFY endDragAreaChanged)
|
||||
|
||||
@@ -71,6 +73,11 @@ public:
|
||||
return m_selectedItem;
|
||||
}
|
||||
|
||||
int selectedModel() const
|
||||
{
|
||||
return m_selectedModel;
|
||||
}
|
||||
|
||||
int startDragArea() const
|
||||
{
|
||||
return m_startDragArea;
|
||||
@@ -81,37 +88,28 @@ public:
|
||||
return m_endDragArea;
|
||||
}
|
||||
|
||||
QmlProfilerDataModel *profilerDataModel() const { return m_profilerDataModel; }
|
||||
void setProfilerDataModel(QObject *profilerDataModel)
|
||||
{
|
||||
m_profilerDataModel = qobject_cast<QmlProfilerDataModel *>(profilerDataModel);
|
||||
emit profilerDataModelChanged(m_profilerDataModel);
|
||||
}
|
||||
TimelineModelAggregator *profilerModelProxy() const { return m_profilerModelProxy; }
|
||||
void setProfilerModelProxy(QObject *profilerModelProxy);
|
||||
|
||||
Q_INVOKABLE qint64 getDuration(int index) const;
|
||||
Q_INVOKABLE QString getFilename(int index) const;
|
||||
Q_INVOKABLE int getLine(int index) const;
|
||||
Q_INVOKABLE QString getDetails(int index) const;
|
||||
Q_INVOKABLE int getYPosition(int index) const;
|
||||
|
||||
Q_INVOKABLE void setRowExpanded(int rowIndex, bool expanded);
|
||||
Q_INVOKABLE int getYPosition(int modelIndex, int index) const;
|
||||
|
||||
Q_INVOKABLE void selectNext();
|
||||
Q_INVOKABLE void selectPrev();
|
||||
Q_INVOKABLE int nextItemFromId(int eventId) const;
|
||||
Q_INVOKABLE int prevItemFromId(int eventId) const;
|
||||
Q_INVOKABLE void selectNextFromId(int eventId);
|
||||
Q_INVOKABLE void selectPrevFromId(int eventId);
|
||||
Q_INVOKABLE int nextItemFromId(int modelIndex, int eventId) const;
|
||||
Q_INVOKABLE int prevItemFromId(int modelIndex, int eventId) const;
|
||||
Q_INVOKABLE void selectNextFromId(int modelIndex, int eventId);
|
||||
Q_INVOKABLE void selectPrevFromId(int modelIndex, int eventId);
|
||||
|
||||
signals:
|
||||
void startTimeChanged(qint64 arg);
|
||||
void endTimeChanged(qint64 arg);
|
||||
void profilerDataModelChanged(QmlProfilerDataModel *list);
|
||||
void profilerModelProxyChanged(TimelineModelAggregator *list);
|
||||
void selectionLockedChanged(bool locked);
|
||||
void selectedItemChanged(int itemIndex);
|
||||
void selectedItemChanged(int modelIndex, int itemIndex);
|
||||
void selectedModelChanged(int modelIndex);
|
||||
void startDragAreaChanged(int startDragArea);
|
||||
void endDragAreaChanged(int endDragArea);
|
||||
void itemPressed(int pressedItem);
|
||||
void itemPressed(int modelIndex, int pressedItem);
|
||||
|
||||
public slots:
|
||||
void clearData();
|
||||
@@ -148,7 +146,16 @@ public slots:
|
||||
if (m_selectedItem != itemIndex) {
|
||||
m_selectedItem = itemIndex;
|
||||
update();
|
||||
emit selectedItemChanged(itemIndex);
|
||||
emit selectedItemChanged(m_selectedModel, itemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void setSelectedModel(int modelIndex)
|
||||
{
|
||||
if (m_selectedModel != modelIndex) {
|
||||
m_selectedModel = modelIndex;
|
||||
update();
|
||||
emit selectedModelChanged(modelIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,10 +184,10 @@ protected:
|
||||
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
|
||||
|
||||
private:
|
||||
QColor colorForItem(int itemIndex);
|
||||
void drawItemsToPainter(QPainter *p, int fromIndex, int toIndex);
|
||||
void drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex);
|
||||
void drawBindingLoopMarkers(QPainter *p, int fromIndex, int toIndex);
|
||||
void drawItemsToPainter(QPainter *p, int modelIndex, int fromIndex, int toIndex);
|
||||
void drawSelectionBoxes(QPainter *p, int modelIndex, int fromIndex, int toIndex);
|
||||
void drawBindingLoopMarkers(QPainter *p, int modelIndex, int fromIndex, int toIndex);
|
||||
int modelFromPosition(int y);
|
||||
|
||||
void manageClicked();
|
||||
void manageHovered(int x, int y);
|
||||
@@ -192,21 +199,18 @@ private:
|
||||
qint64 m_lastStartTime;
|
||||
qint64 m_lastEndTime;
|
||||
|
||||
QmlProfilerDataModel *m_profilerDataModel;
|
||||
|
||||
QList<int> m_rowLastX;
|
||||
QList<int> m_rowStarts;
|
||||
QList<int> m_rowWidths;
|
||||
QList<bool> m_rowsExpanded;
|
||||
TimelineModelAggregator *m_profilerModelProxy;
|
||||
|
||||
struct {
|
||||
qint64 startTime;
|
||||
qint64 endTime;
|
||||
int row;
|
||||
int eventIndex;
|
||||
int modelIndex;
|
||||
} m_currentSelection;
|
||||
|
||||
int m_selectedItem;
|
||||
int m_selectedModel;
|
||||
bool m_selectionLocked;
|
||||
int m_startDragArea;
|
||||
int m_endDragArea;
|
||||
|
Reference in New Issue
Block a user