Move flame graph view from QmlProfiler to separate library

We want to use it for other profilers, too.

Change-Id: Ice4bd7fdfce6e0153d62a7c9a83dc7de6d5cba30
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Ulf Hermann
2016-07-18 11:19:00 +02:00
parent 97a465ae18
commit 392955488c
26 changed files with 413 additions and 261 deletions

View File

@@ -25,8 +25,7 @@
#include "flamegraph.h" #include "flamegraph.h"
namespace QmlProfiler { namespace FlameGraph {
namespace Internal {
FlameGraph::FlameGraph(QQuickItem *parent) : FlameGraph::FlameGraph(QQuickItem *parent) :
QQuickItem(parent) QQuickItem(parent)
@@ -180,10 +179,4 @@ void FlameGraph::rebuild()
emit depthChanged(m_depth); emit depthChanged(m_depth);
} }
QVariant FlameGraphAttached::data(int role) const } // namespace FlameGraph
{
return m_data.isValid() ? m_data.data(role) : QVariant();
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -25,82 +25,15 @@
#pragma once #pragma once
#include "flamegraph_global.h"
#include "flamegraphattached.h"
#include <QQuickItem> #include <QQuickItem>
#include <QAbstractItemModel> #include <QAbstractItemModel>
namespace QmlProfiler { namespace FlameGraph {
namespace Internal {
class FlameGraphAttached : public QObject class FLAMEGRAPH_EXPORT FlameGraph : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(qreal relativeSize READ relativeSize WRITE setRelativeSize
NOTIFY relativeSizeChanged)
Q_PROPERTY(qreal relativePosition READ relativePosition WRITE setRelativePosition
NOTIFY relativePositionChanged)
Q_PROPERTY(bool dataValid READ isDataValid NOTIFY dataValidChanged)
public:
FlameGraphAttached(QObject *parent = 0) :
QObject(parent), m_relativeSize(0), m_relativePosition(0) {}
Q_INVOKABLE QVariant data(int role) const;
bool isDataValid() const
{
return m_data.isValid();
}
qreal relativeSize() const
{
return m_relativeSize;
}
void setRelativeSize(qreal relativeSize)
{
if (relativeSize != m_relativeSize) {
m_relativeSize = relativeSize;
emit relativeSizeChanged();
}
}
qreal relativePosition() const
{
return m_relativePosition;
}
void setRelativePosition(qreal relativePosition)
{
if (relativePosition != m_relativePosition) {
m_relativePosition = relativePosition;
emit relativePositionChanged();
}
}
void setModelIndex(const QModelIndex &data)
{
if (data != m_data) {
bool validChanged = (data.isValid() != m_data.isValid());
m_data = data;
if (validChanged)
emit dataValidChanged();
emit dataChanged();
}
}
signals:
void dataChanged();
void dataValidChanged();
void relativeSizeChanged();
void relativePositionChanged();
private:
QPersistentModelIndex m_data;
qreal m_relativeSize;
qreal m_relativePosition;
};
class FlameGraph : public QQuickItem
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
@@ -169,7 +102,6 @@ private:
const QModelIndex &childIndex, qreal position, qreal size); const QModelIndex &childIndex, qreal position, qreal size);
}; };
} // namespace Internal } // namespace FlameGraph
} // namespace QmlProfiler
QML_DECLARE_TYPEINFO(QmlProfiler::Internal::FlameGraph, QML_HAS_ATTACHED_PROPERTIES) QML_DECLARE_TYPEINFO(FlameGraph::FlameGraph, QML_HAS_ATTACHED_PROPERTIES)

View File

@@ -0,0 +1,16 @@
QT += qml quick
DEFINES += FLAMEGRAPH_LIBRARY
include(../../qtcreatorlibrary.pri)
SOURCES += \
$$PWD/flamegraph.cpp
HEADERS += \
$$PWD/flamegraph.h \
$$PWD/flamegraph_global.h \
$$PWD/flamegraphattached.h
RESOURCES += \
$$PWD/qml/flamegraph.qrc

View File

@@ -0,0 +1,30 @@
import qbs 1.0
import QtcLibrary
Project {
name: "FlameGraph"
QtcDevHeaders { }
QtcLibrary {
Depends { name: "Qt"; submodules: ["qml", "quick", "gui"] }
Group {
name: "General"
files: [
"flamegraph.cpp", "flamegraph.h",
"flamegraph_global.h",
"flamegraphattached.h",
]
}
Group {
name: "QML"
prefix: "qml/"
files: ["flamegraph.qrc"]
}
cpp.defines: base.concat("FLAMEGRAPH_LIBRARY")
}
}

View File

@@ -0,0 +1,2 @@
QTC_LIB_NAME = FlameGraph

View File

@@ -25,45 +25,10 @@
#pragma once #pragma once
#include <qmlprofiler/flamegraph.h> #include <QtGlobal>
#include <QObject>
#include <QStandardItemModel>
#include <QQmlComponent>
#include <QQuickItem>
namespace QmlProfiler { #if defined(FLAMEGRAPH_LIBRARY)
namespace Internal { # define FLAMEGRAPH_EXPORT Q_DECL_EXPORT
#else
class DelegateObject : public QQuickItem # define FLAMEGRAPH_EXPORT Q_DECL_IMPORT
{ #endif
Q_OBJECT
};
class DelegateComponent : public QQmlComponent
{
Q_OBJECT
public:
QObject *create(QQmlContext *context) override;
QObject *beginCreate(QQmlContext *) override;
void completeCreate() override;
};
class FlameGraphTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void testRebuild();
void cleanupTestCase();
private:
static const int sizeRole = Qt::UserRole + 1;
static const int dataRole = Qt::UserRole + 2;
FlameGraph flameGraph;
QStandardItemModel model;
DelegateComponent delegate;
};
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -0,0 +1,107 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "flamegraph_global.h"
#include <QObject>
#include <QModelIndex>
#include <QVariant>
namespace FlameGraph {
class FLAMEGRAPH_EXPORT FlameGraphAttached : public QObject
{
Q_OBJECT
Q_PROPERTY(qreal relativeSize READ relativeSize WRITE setRelativeSize
NOTIFY relativeSizeChanged)
Q_PROPERTY(qreal relativePosition READ relativePosition WRITE setRelativePosition
NOTIFY relativePositionChanged)
Q_PROPERTY(bool dataValid READ isDataValid NOTIFY dataValidChanged)
public:
FlameGraphAttached(QObject *parent = 0) :
QObject(parent), m_relativeSize(0), m_relativePosition(0) {}
Q_INVOKABLE QVariant data(int role) const
{
return m_data.isValid() ? m_data.data(role) : QVariant();
}
bool isDataValid() const
{
return m_data.isValid();
}
qreal relativeSize() const
{
return m_relativeSize;
}
void setRelativeSize(qreal relativeSize)
{
if (relativeSize != m_relativeSize) {
m_relativeSize = relativeSize;
emit relativeSizeChanged();
}
}
qreal relativePosition() const
{
return m_relativePosition;
}
void setRelativePosition(qreal relativePosition)
{
if (relativePosition != m_relativePosition) {
m_relativePosition = relativePosition;
emit relativePositionChanged();
}
}
void setModelIndex(const QModelIndex &data)
{
if (data != m_data) {
bool validChanged = (data.isValid() != m_data.isValid());
m_data = data;
if (validChanged)
emit dataValidChanged();
emit dataChanged();
}
}
signals:
void dataChanged();
void dataValidChanged();
void relativeSizeChanged();
void relativePositionChanged();
private:
QPersistentModelIndex m_data;
qreal m_relativeSize;
qreal m_relativePosition;
};
} // namespace FlameGraph

View File

@@ -0,0 +1,82 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
import QtQuick 2.0
import FlameGraph 1.0
Item {
id: flamegraphItem
property color borderColor
property real borderWidth
property real itemHeight
property bool isSelected
property string text;
signal mouseEntered
signal mouseExited
signal clicked
property bool textVisible: width > 20 || isSelected
property int level: (parent.level !== undefined ? parent.level + 1 : -1)
+ (itemHeight > 0 ? 1 : 0)
height: parent === null ? 0 : parent.height - (level > 0 ? itemHeight : 0);
width: parent === null ? 0 : parent.width * FlameGraph.relativeSize
x: parent === null ? 0 : parent.width * FlameGraph.relativePosition
Rectangle {
border.color: borderColor
border.width: borderWidth
color: Qt.hsla((level % 12) / 72, 0.9 + Math.random() / 10,
0.45 + Math.random() / 10, 0.9 + Math.random() / 10);
height: itemHeight;
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
FlameGraphText {
id: text
visible: textVisible
anchors.fill: parent
anchors.margins: 5
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: flamegraphItem.text
elide: Text.ElideRight
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
font.bold: isSelected
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: flamegraphItem.mouseEntered()
onExited: flamegraphItem.mouseExited()
onClicked: flamegraphItem.clicked()
}
}
}

View File

@@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/flamegraph">
<file>FlameGraphText.qml</file>
<file>FlameGraphDetails.qml</file>
<file>FlameGraphDelegate.qml</file>
</qresource>
</RCC>

View File

@@ -16,7 +16,8 @@ SUBDIRS = \
ssh \ ssh \
timeline \ timeline \
sqlite \ sqlite \
clangbackendipc clangbackendipc \
flamegraph
for(l, SUBDIRS) { for(l, SUBDIRS) {
QTC_LIB_DEPENDS = QTC_LIB_DEPENDS =

View File

@@ -7,6 +7,7 @@ Project {
"clangbackendipc/clangbackendipc.qbs", "clangbackendipc/clangbackendipc.qbs",
"cplusplus/cplusplus.qbs", "cplusplus/cplusplus.qbs",
"extensionsystem/extensionsystem.qbs", "extensionsystem/extensionsystem.qbs",
"flamegraph/flamegraph.qbs",
"glsl/glsl.qbs", "glsl/glsl.qbs",
"languageutils/languageutils.qbs", "languageutils/languageutils.qbs",
"modelinglib/modelinglib.qbs", "modelinglib/modelinglib.qbs",

View File

@@ -24,10 +24,12 @@
****************************************************************************/ ****************************************************************************/
#include "flamegraphview.h" #include "flamegraphview.h"
#include "flamegraph.h"
#include "qmlprofilerconstants.h" #include "qmlprofilerconstants.h"
#include "qmlprofilertool.h" #include "qmlprofilertool.h"
#include <flamegraph/flamegraph.h>
#include <QQmlEngine>
#include <QQmlContext> #include <QQmlContext>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QMenu> #include <QMenu>
@@ -44,14 +46,15 @@ FlameGraphView::FlameGraphView(QmlProfilerModelManager *manager, QWidget *parent
// We cannot change this without breaking the settings. // We cannot change this without breaking the settings.
setObjectName(QStringLiteral("QmlProfilerFlamegraph")); setObjectName(QStringLiteral("QmlProfilerFlamegraph"));
qmlRegisterType<FlameGraph>("FlameGraph", 1, 0, "FlameGraph"); qmlRegisterType<FlameGraph::FlameGraph>("FlameGraph", 1, 0, "FlameGraph");
qmlRegisterUncreatableType<FlameGraphModel>("FlameGraphModel", 1, 0, "FlameGraphModel", qmlRegisterUncreatableType<FlameGraphModel>("QmlProfilerFlameGraphModel", 1, 0,
"QmlProfilerFlameGraphModel",
QLatin1String("use the context property")); QLatin1String("use the context property"));
qmlRegisterUncreatableType<QAbstractItemModel>("AbstractItemModel", 1, 0, "AbstractItemModel", qmlRegisterUncreatableType<QAbstractItemModel>("AbstractItemModel", 1, 0, "AbstractItemModel",
QLatin1String("only for Qt 5.4")); QLatin1String("only for Qt 5.4"));
m_content->rootContext()->setContextProperty(QStringLiteral("flameGraphModel"), m_model); m_content->rootContext()->setContextProperty(QStringLiteral("flameGraphModel"), m_model);
m_content->setSource(QUrl(QStringLiteral("qrc:/qmlprofiler/FlameGraphView.qml"))); m_content->setSource(QUrl(QStringLiteral("qrc:/qmlprofiler/QmlProfilerFlameGraphView.qml")));
m_content->setClearColor(QColor(0xdc, 0xdc, 0xdc)); m_content->setClearColor(QColor(0xdc, 0xdc, 0xdc));
m_content->setResizeMode(QQuickWidget::SizeRootObjectToView); m_content->setResizeMode(QQuickWidget::SizeRootObjectToView);

View File

@@ -26,7 +26,8 @@
import QtQuick 2.0 import QtQuick 2.0
import QtQuick.Controls 1.3 import QtQuick.Controls 1.3
import FlameGraph 1.0 import FlameGraph 1.0
import FlameGraphModel 1.0 import QmlProfilerFlameGraphModel 1.0
import "../flamegraph/"
ScrollView { ScrollView {
id: root id: root
@@ -45,7 +46,6 @@ ScrollView {
FlameGraph { FlameGraph {
property int itemHeight: Math.max(30, flickable.height / depth) property int itemHeight: Math.max(30, flickable.height / depth)
property int level: -1
property color blue: "blue" property color blue: "blue"
property color blue1: Qt.lighter(blue) property color blue1: Qt.lighter(blue)
property color blue2: Qt.rgba(0.375, 0, 1, 1) property color blue2: Qt.rgba(0.375, 0, 1, 1)
@@ -59,21 +59,42 @@ ScrollView {
width: parent.width width: parent.width
height: depth * itemHeight height: depth * itemHeight
model: flameGraphModel model: flameGraphModel
sizeRole: FlameGraphModel.DurationRole sizeRole: QmlProfilerFlameGraphModel.DurationRole
sizeThreshold: 0.002 sizeThreshold: 0.002
maximumDepth: 25 maximumDepth: 25
y: flickable.height > height ? flickable.height - height : 0 y: flickable.height > height ? flickable.height - height : 0
delegate: Item { delegate: FlameGraphDelegate {
id: flamegraphItem id: flamegraphItem
property int typeId: FlameGraph.data(FlameGraphModel.TypeIdRole) || -1 property int typeId: FlameGraph.data(QmlProfilerFlameGraphModel.TypeIdRole) || -1
property bool isBindingLoop: parent.checkBindingLoop(typeId) property bool isBindingLoop: parent.checkBindingLoop(typeId)
property int level: parent.level + (rangeTypeVisible ? 1 : 0)
property bool isSelected: typeId !== -1 && typeId === root.selectedTypeId
&& rangeTypeVisible
property bool rangeTypeVisible: property bool rangeTypeVisible:
root.visibleRangeTypes & (1 << FlameGraph.data(FlameGraphModel.RangeTypeRole)) root.visibleRangeTypes & (1 << FlameGraph.data(QmlProfilerFlameGraphModel.RangeTypeRole))
itemHeight: rangeTypeVisible ? flamegraph.itemHeight : 0
isSelected: typeId !== -1 && typeId === root.selectedTypeId && rangeTypeVisible
borderColor: {
if (isSelected)
return flamegraph.blue2;
else if (tooltip.hoveredNode === flamegraphItem)
return flamegraph.blue1;
else if (note() !== "" || isBindingLoop)
return flamegraph.orange;
else
return flamegraph.grey1;
}
borderWidth: {
if (tooltip.hoveredNode === flamegraphItem ||
tooltip.selectedNode === flamegraphItem) {
return 2;
} else if (note() !== "") {
return 3;
} else {
return 1;
}
}
onIsSelectedChanged: { onIsSelectedChanged: {
if (isSelected && (tooltip.selectedNode === null || if (isSelected && (tooltip.selectedNode === null ||
@@ -93,10 +114,45 @@ ScrollView {
} }
} }
function buildText() {
if (!FlameGraph.dataValid)
return "<others>";
return FlameGraph.data(QmlProfilerFlameGraphModel.DetailsRole) + " ("
+ FlameGraph.data(QmlProfilerFlameGraphModel.TypeRole) + ", "
+ FlameGraph.data(QmlProfilerFlameGraphModel.TimeInPercentRole) + "%)";
}
text: textVisible ? buildText() : ""
FlameGraph.onDataChanged: if (textVisible) text = buildText();
onMouseEntered: {
tooltip.hoveredNode = flamegraphItem;
}
onMouseExited: {
if (tooltip.hoveredNode === flamegraphItem)
tooltip.hoveredNode = null;
}
onClicked: {
if (flamegraphItem.FlameGraph.dataValid) {
tooltip.selectedNode = flamegraphItem;
root.typeSelected(flamegraphItem.FlameGraph.data(
QmlProfilerFlameGraphModel.TypeIdRole));
root.gotoSourceLocation(
flamegraphItem.FlameGraph.data(
QmlProfilerFlameGraphModel.FilenameRole),
flamegraphItem.FlameGraph.data(
QmlProfilerFlameGraphModel.LineRole),
flamegraphItem.FlameGraph.data(
QmlProfilerFlameGraphModel.ColumnRole));
}
}
// Functions, not properties to limit the initial overhead when creating the nodes, // Functions, not properties to limit the initial overhead when creating the nodes,
// and because FlameGraph.data(...) cannot be notified anyway. // and because FlameGraph.data(...) cannot be notified anyway.
function title() { return FlameGraph.data(FlameGraphModel.TypeRole) || ""; } function title() { return FlameGraph.data(QmlProfilerFlameGraphModel.TypeRole) || ""; }
function note() { return FlameGraph.data(FlameGraphModel.NoteRole) || ""; } function note() { return FlameGraph.data(QmlProfilerFlameGraphModel.NoteRole) || ""; }
function details() { function details() {
var model = []; var model = [];
function addDetail(name, index, format) { function addDetail(name, index, format) {
@@ -130,106 +186,17 @@ ScrollView {
model.push(qsTr("Details")); model.push(qsTr("Details"));
model.push(qsTr("Various Events")); model.push(qsTr("Various Events"));
} else { } else {
addDetail(qsTr("Details"), FlameGraphModel.DetailsRole, noop); addDetail(qsTr("Details"), QmlProfilerFlameGraphModel.DetailsRole, noop);
addDetail(qsTr("Type"), FlameGraphModel.TypeRole, noop); addDetail(qsTr("Type"), QmlProfilerFlameGraphModel.TypeRole, noop);
addDetail(qsTr("Calls"), FlameGraphModel.CallCountRole, noop); addDetail(qsTr("Calls"), QmlProfilerFlameGraphModel.CallCountRole, noop);
addDetail(qsTr("Total Time"), FlameGraphModel.DurationRole, printTime); addDetail(qsTr("Total Time"), QmlProfilerFlameGraphModel.DurationRole, printTime);
addDetail(qsTr("Mean Time"), FlameGraphModel.TimePerCallRole, printTime); addDetail(qsTr("Mean Time"), QmlProfilerFlameGraphModel.TimePerCallRole, printTime);
addDetail(qsTr("In Percent"), FlameGraphModel.TimeInPercentRole, addDetail(qsTr("In Percent"), QmlProfilerFlameGraphModel.TimeInPercentRole,
addPercent); addPercent);
addDetail(qsTr("Location"), FlameGraphModel.LocationRole, noop); addDetail(qsTr("Location"), QmlProfilerFlameGraphModel.LocationRole, noop);
} }
return model; return model;
} }
Rectangle {
border.color: {
if (flamegraphItem.isSelected)
return flamegraph.blue2;
else if (tooltip.hoveredNode === flamegraphItem)
return flamegraph.blue1;
else if (flamegraphItem.note() !== "" || flamegraphItem.isBindingLoop)
return flamegraph.orange;
else
return flamegraph.grey1;
}
border.width: {
if (tooltip.hoveredNode === flamegraphItem ||
tooltip.selectedNode === flamegraphItem) {
return 2;
} else if (flamegraphItem.note() !== "") {
return 3;
} else {
return 1;
}
}
color: Qt.hsla((level % 12) / 72, 0.9 + Math.random() / 10,
0.45 + Math.random() / 10, 0.9 + Math.random() / 10);
height: flamegraphItem.rangeTypeVisible ? flamegraph.itemHeight : 0;
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
FlameGraphText {
id: text
visible: width > 20 || flamegraphItem === tooltip.selectedNode
anchors.fill: parent
anchors.margins: 5
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: visible ? buildText() : ""
elide: Text.ElideRight
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
font.bold: flamegraphItem === tooltip.selectedNode
function buildText() {
if (!flamegraphItem.FlameGraph.dataValid)
return "<others>";
return flamegraphItem.FlameGraph.data(FlameGraphModel.DetailsRole)
+ " ("
+ flamegraphItem.FlameGraph.data(FlameGraphModel.TypeRole)
+ ", "
+ flamegraphItem.FlameGraph.data(
FlameGraphModel.TimeInPercentRole) + "%)";
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
tooltip.hoveredNode = flamegraphItem;
}
onExited: {
if (tooltip.hoveredNode === flamegraphItem)
tooltip.hoveredNode = null;
}
onClicked: {
if (flamegraphItem.FlameGraph.dataValid) {
tooltip.selectedNode = flamegraphItem;
root.typeSelected(flamegraphItem.FlameGraph.data(
FlameGraphModel.TypeIdRole));
root.gotoSourceLocation(
flamegraphItem.FlameGraph.data(
FlameGraphModel.FilenameRole),
flamegraphItem.FlameGraph.data(
FlameGraphModel.LineRole),
flamegraphItem.FlameGraph.data(
FlameGraphModel.ColumnRole));
}
}
}
}
FlameGraph.onDataChanged: if (text.visible) text.text = text.buildText();
height: flamegraph.height - level * flamegraph.itemHeight;
width: parent === null ? flamegraph.width : parent.width * FlameGraph.relativeSize
x: parent === null ? 0 : parent.width * FlameGraph.relativePosition
} }
} }

View File

@@ -2,8 +2,6 @@
<qresource prefix="/qmlprofiler"> <qresource prefix="/qmlprofiler">
<file>bindingloops.vert</file> <file>bindingloops.vert</file>
<file>bindingloops.frag</file> <file>bindingloops.frag</file>
<file>FlameGraphView.qml</file> <file>QmlProfilerFlameGraphView.qml</file>
<file>FlameGraphText.qml</file>
<file>FlameGraphDetails.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -6,7 +6,6 @@ include(../../qtcreatorplugin.pri)
SOURCES += \ SOURCES += \
debugmessagesmodel.cpp \ debugmessagesmodel.cpp \
flamegraph.cpp \
flamegraphmodel.cpp \ flamegraphmodel.cpp \
flamegraphview.cpp \ flamegraphview.cpp \
inputeventsmodel.cpp \ inputeventsmodel.cpp \
@@ -48,7 +47,6 @@ SOURCES += \
HEADERS += \ HEADERS += \
debugmessagesmodel.h \ debugmessagesmodel.h \
flamegraph.h \
flamegraphmodel.h \ flamegraphmodel.h \
flamegraphview.h \ flamegraphview.h \
inputeventsmodel.h \ inputeventsmodel.h \

View File

@@ -4,6 +4,8 @@ QtcPlugin {
name: "QmlProfiler" name: "QmlProfiler"
Depends { name: "Qt"; submodules: ["widgets", "network", "quick", "quickwidgets"] } Depends { name: "Qt"; submodules: ["widgets", "network", "quick", "quickwidgets"] }
Depends { name: "FlameGraph" }
Depends { name: "QmlJS" } Depends { name: "QmlJS" }
Depends { name: "QmlDebug" } Depends { name: "QmlDebug" }
Depends { name: "Utils" } Depends { name: "Utils" }
@@ -19,7 +21,6 @@ QtcPlugin {
name: "General" name: "General"
files: [ files: [
"debugmessagesmodel.cpp", "debugmessagesmodel.h", "debugmessagesmodel.cpp", "debugmessagesmodel.h",
"flamegraph.cpp", "flamegraph.h",
"flamegraphmodel.cpp", "flamegraphmodel.h", "flamegraphmodel.cpp", "flamegraphmodel.h",
"flamegraphview.cpp", "flamegraphview.h", "flamegraphview.cpp", "flamegraphview.h",
"inputeventsmodel.cpp", "inputeventsmodel.h", "inputeventsmodel.cpp", "inputeventsmodel.h",
@@ -77,7 +78,6 @@ QtcPlugin {
prefix: "tests/" prefix: "tests/"
files: [ files: [
"debugmessagesmodel_test.cpp", "debugmessagesmodel_test.h", "debugmessagesmodel_test.cpp", "debugmessagesmodel_test.h",
"flamegraph_test.cpp", "flamegraph_test.h",
"flamegraphmodel_test.cpp", "flamegraphmodel_test.h", "flamegraphmodel_test.cpp", "flamegraphmodel_test.h",
"flamegraphview_test.cpp", "flamegraphview_test.h", "flamegraphview_test.cpp", "flamegraphview_test.h",
"inputeventsmodel_test.cpp", "inputeventsmodel_test.h", "inputeventsmodel_test.cpp", "inputeventsmodel_test.h",

View File

@@ -1,6 +1,7 @@
QTC_PLUGIN_NAME = QmlProfiler QTC_PLUGIN_NAME = QmlProfiler
QTC_LIB_DEPENDS += \ QTC_LIB_DEPENDS += \
extensionsystem \ extensionsystem \
flamegraph \
qmldebug \ qmldebug \
qmljs \ qmljs \
timeline \ timeline \

View File

@@ -32,7 +32,6 @@
#ifdef WITH_TESTS #ifdef WITH_TESTS
#include "tests/debugmessagesmodel_test.h" #include "tests/debugmessagesmodel_test.h"
#include "tests/flamegraph_test.h"
#include "tests/flamegraphmodel_test.h" #include "tests/flamegraphmodel_test.h"
#include "tests/flamegraphview_test.h" #include "tests/flamegraphview_test.h"
#include "tests/inputeventsmodel_test.h" #include "tests/inputeventsmodel_test.h"
@@ -102,7 +101,6 @@ QList<QObject *> QmlProfiler::Internal::QmlProfilerPlugin::createTestObjects() c
QList<QObject *> tests; QList<QObject *> tests;
#ifdef WITH_TESTS #ifdef WITH_TESTS
tests << new DebugMessagesModelTest; tests << new DebugMessagesModelTest;
tests << new FlameGraphTest;
tests << new FlameGraphModelTest; tests << new FlameGraphModelTest;
tests << new FlameGraphViewTest; tests << new FlameGraphViewTest;
tests << new InputEventsModelTest; tests << new InputEventsModelTest;

View File

@@ -1,6 +1,5 @@
SOURCES += \ SOURCES += \
$$PWD/debugmessagesmodel_test.cpp \ $$PWD/debugmessagesmodel_test.cpp \
$$PWD/flamegraph_test.cpp \
$$PWD/flamegraphmodel_test.cpp \ $$PWD/flamegraphmodel_test.cpp \
$$PWD/flamegraphview_test.cpp \ $$PWD/flamegraphview_test.cpp \
$$PWD/inputeventsmodel_test.cpp \ $$PWD/inputeventsmodel_test.cpp \
@@ -18,7 +17,6 @@ SOURCES += \
HEADERS += \ HEADERS += \
$$PWD/debugmessagesmodel_test.h \ $$PWD/debugmessagesmodel_test.h \
$$PWD/flamegraph_test.h \
$$PWD/flamegraphmodel_test.h \ $$PWD/flamegraphmodel_test.h \
$$PWD/flamegraphview_test.h \ $$PWD/flamegraphview_test.h \
$$PWD/inputeventsmodel_test.h \ $$PWD/inputeventsmodel_test.h \

View File

@@ -24,4 +24,4 @@ SUBDIRS += \
valgrind valgrind
qtHaveModule(qml): SUBDIRS += qml qtHaveModule(qml): SUBDIRS += qml
qtHaveModule(quick): SUBDIRS += timeline qtHaveModule(quick): SUBDIRS += flamegraph timeline

View File

@@ -14,6 +14,7 @@ Project {
"extensionsystem/extensionsystem.qbs", "extensionsystem/extensionsystem.qbs",
"externaltool/externaltool.qbs", "externaltool/externaltool.qbs",
"filesearch/filesearch.qbs", "filesearch/filesearch.qbs",
"flamegraph/flamegraph.qbs",
"generichighlighter/generichighlighter.qbs", "generichighlighter/generichighlighter.qbs",
"json/json.qbs", "json/json.qbs",
"profilewriter/profilewriter.qbs", "profilewriter/profilewriter.qbs",

View File

@@ -0,0 +1,5 @@
QTC_LIB_DEPENDS += flamegraph
include(../qttest.pri)
QT += quick
SOURCES += tst_flamegraph.cpp

View File

@@ -0,0 +1,9 @@
import qbs
QtcAutotest {
name: "FlameGraph autotest"
Depends { name: "FlameGraph" }
Depends { name: "Qt.quick" }
Depends { name: "Qt.gui" }
files: "tst_flamegraph.cpp"
}

View File

@@ -23,14 +23,46 @@
** **
****************************************************************************/ ****************************************************************************/
#include "flamegraph_test.h" #include <flamegraph/flamegraph.h>
#include <flamegraph/flamegraphattached.h>
#include <QObject>
#include <QStandardItemModel>
#include <QQmlComponent>
#include <QQuickItem>
#include <QtTest> #include <QtTest>
#include <QQuickItem> #include <QQuickItem>
namespace QmlProfiler { class DelegateObject : public QQuickItem
namespace Internal { {
Q_OBJECT
};
void FlameGraphTest::initTestCase() class DelegateComponent : public QQmlComponent
{
Q_OBJECT
public:
QObject *create(QQmlContext *context) override;
QObject *beginCreate(QQmlContext *) override;
void completeCreate() override;
};
class tst_FlameGraph : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void testRebuild();
void cleanupTestCase();
private:
static const int sizeRole = Qt::UserRole + 1;
static const int dataRole = Qt::UserRole + 2;
FlameGraph::FlameGraph flameGraph;
QStandardItemModel model;
DelegateComponent delegate;
};
void tst_FlameGraph::initTestCase()
{ {
flameGraph.setDelegate(&delegate); flameGraph.setDelegate(&delegate);
flameGraph.setModel(&model); flameGraph.setModel(&model);
@@ -45,7 +77,7 @@ void FlameGraphTest::initTestCase()
QCOMPARE(flameGraph.sizeThreshold(), 0.01); QCOMPARE(flameGraph.sizeThreshold(), 0.01);
} }
void FlameGraphTest::testRebuild() void tst_FlameGraph::testRebuild()
{ {
flameGraph.setModel(nullptr); flameGraph.setModel(nullptr);
qreal sum = 0; qreal sum = 0;
@@ -75,7 +107,9 @@ void FlameGraphTest::testRebuild()
qreal i = 0; qreal i = 0;
qreal position = 0; qreal position = 0;
foreach (QQuickItem *child, flameGraph.childItems()) { foreach (QQuickItem *child, flameGraph.childItems()) {
FlameGraphAttached *attached = FlameGraph::qmlAttachedProperties(child); FlameGraph::FlameGraphAttached *attached =
FlameGraph::FlameGraph::qmlAttachedProperties(child);
QVERIFY(attached);
QCOMPARE(attached->relativeSize(), (++i) / sum); QCOMPARE(attached->relativeSize(), (++i) / sum);
QCOMPARE(attached->relativePosition(), position / sum); QCOMPARE(attached->relativePosition(), position / sum);
QCOMPARE(attached->data(dataRole).toInt(), 100 / static_cast<int>(i)); QCOMPARE(attached->data(dataRole).toInt(), 100 / static_cast<int>(i));
@@ -83,12 +117,15 @@ void FlameGraphTest::testRebuild()
qreal j = 0; qreal j = 0;
foreach (QQuickItem *grandchild, child->childItems()) { foreach (QQuickItem *grandchild, child->childItems()) {
FlameGraphAttached *attached2 = FlameGraph::qmlAttachedProperties(grandchild); FlameGraph::FlameGraphAttached *attached2 =
FlameGraph::FlameGraph::qmlAttachedProperties(grandchild);
QVERIFY(attached2);
QCOMPARE(attached2->relativeSize(), 1.0 / i); QCOMPARE(attached2->relativeSize(), 1.0 / i);
QCOMPARE(attached2->relativePosition(), (j++) / i); QCOMPARE(attached2->relativePosition(), (j++) / i);
QCOMPARE(grandchild->childItems().count(), 1); QCOMPARE(grandchild->childItems().count(), 1);
FlameGraphAttached *skipped = FlameGraph::FlameGraphAttached *skipped =
FlameGraph::qmlAttachedProperties(grandchild->childItems()[0]); FlameGraph::FlameGraph::qmlAttachedProperties(grandchild->childItems()[0]);
QVERIFY(skipped);
QCOMPARE(skipped->relativePosition(), 0.0); QCOMPARE(skipped->relativePosition(), 0.0);
QCOMPARE(skipped->relativeSize(), 0.001 * 10); QCOMPARE(skipped->relativeSize(), 0.001 * 10);
} }
@@ -98,7 +135,7 @@ void FlameGraphTest::testRebuild()
QCOMPARE(i, 9.0); QCOMPARE(i, 9.0);
} }
void FlameGraphTest::cleanupTestCase() void tst_FlameGraph::cleanupTestCase()
{ {
} }
@@ -119,5 +156,6 @@ void DelegateComponent::completeCreate()
{ {
} }
} // namespace Internal QTEST_MAIN(tst_FlameGraph)
} // namespace QmlProfiler
#include "tst_flamegraph.moc"