Commit 0a3b20f5 authored by Christiaan Janssen's avatar Christiaan Janssen

QmlProfiler: reworked

Change-Id: I66a236a024d76e7bef6edfb91ae30b5dd098b76b
Reviewed-by: default avatarKai Koehne <kai.koehne@digia.com>
parent 7764f351
......@@ -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();
......
/****************************************************************************
**
** 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;
}
}
/****************************************************************************
**
** 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();
onStateChanged: {
// Empty
if (qmlProfilerDataModel.getCurrentStateFromQml() == 0) {
descriptions = [];
eventIds = [];
extdescriptions = [];
target: qmlProfilerModelProxy
onExpandedChanged: {
updateHeight();
} else
// Done
if (qmlProfilerDataModel.getCurrentStateFromQml() == 3) {
getDescriptions();
}
onStateChanged: {
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
......
This diff is collapsed.
......@@ -29,7 +29,7 @@
.pragma library
var qmlProfilerDataModel = 0;
var qmlProfilerModelProxy = 0;
//draw background of the graph
function drawGraph(canvas, ctxt, region)
......@@ -41,27 +41,28 @@ 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 blockHeight = height / typeCount;
var spacing = width / qmlProfilerDataModel.traceDuration();
var typeCount = qmlProfilerModelProxy.visibleCategories();
var blockHeight = height / typeCount;
var highest = [0,0,0,0,0]; // note: change if typeCount changes
var spacing = width / qmlProfilerModelProxy.traceDuration();
for (var ii = 0; ii < qmlProfilerDataModel.count(); ++ii) {
var modelRowStart = 0;
for (var modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); modelIndex++) {
for (var ii = 0; ii < qmlProfilerModelProxy.count(modelIndex); ++ii) {
var xx = (qmlProfilerDataModel.getStartTime(ii) -
qmlProfilerDataModel.traceStartTime()) * spacing;
var xx = (qmlProfilerModelProxy.getStartTime(modelIndex,ii) -
qmlProfilerModelProxy.traceStartTime()) * spacing;
if (xx > region.x + region.width)
continue;
var eventWidth = qmlProfilerDataModel.getDuration(ii) * spacing;
var eventWidth = qmlProfilerModelProxy.getDuration(modelIndex,ii) * spacing;
if (xx + eventWidth < region.x)
continue;
......@@ -69,61 +70,53 @@ function drawData(canvas, ctxt, region)
eventWidth = 1;
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 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 rowNumber = modelRowStart + qmlProfilerModelProxy.getEventCategoryInModel(modelIndex, ii);
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) *
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