From 9a77f5f429c88518793673e924bb81768796215c Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 21 Jan 2016 12:46:01 +0100 Subject: Prepare for merging into qtcreator Remove the licensechecker dependency, move everything into src/plugins/qmlprofilerextension, and adapt the build system. Change-Id: I58bf34ecd838514d02b5c50189cd8a5eb99793b0 Reviewed-by: Eike Ziller --- plugins/qmlprofiler/FlameGraphText.qml | 34 -- plugins/qmlprofiler/FlameGraphView.qml | 227 ---------- plugins/qmlprofiler/QmlProfilerExtension.json.in | 19 - plugins/qmlprofiler/debugmessagesmodel.cpp | 142 ------ plugins/qmlprofiler/debugmessagesmodel.h | 71 --- plugins/qmlprofiler/flamegraph.cpp | 182 -------- plugins/qmlprofiler/flamegraph.h | 160 ------- plugins/qmlprofiler/flamegraph.qrc | 6 - plugins/qmlprofiler/flamegraphmodel.cpp | 324 ------------- plugins/qmlprofiler/flamegraphmodel.h | 113 ----- plugins/qmlprofiler/flamegraphview.cpp | 116 ----- plugins/qmlprofiler/flamegraphview.h | 64 --- plugins/qmlprofiler/inputeventsmodel.cpp | 194 -------- plugins/qmlprofiler/inputeventsmodel.h | 71 --- plugins/qmlprofiler/memoryusagemodel.cpp | 280 ------------ plugins/qmlprofiler/memoryusagemodel.h | 85 ---- plugins/qmlprofiler/pixmapcachemodel.cpp | 500 --------------------- plugins/qmlprofiler/pixmapcachemodel.h | 130 ------ plugins/qmlprofiler/qmlprofiler.pro | 38 -- plugins/qmlprofiler/qmlprofiler.qbs | 36 -- plugins/qmlprofiler/qmlprofiler_dependencies.pri | 4 - plugins/qmlprofiler/qmlprofilerextension_global.h | 38 -- .../qmlprofiler/qmlprofilerextensionconstants.h | 39 -- plugins/qmlprofiler/qmlprofilerextensionplugin.cpp | 135 ------ plugins/qmlprofiler/qmlprofilerextensionplugin.h | 57 --- plugins/qmlprofiler/scenegraphtimelinemodel.cpp | 311 ------------- plugins/qmlprofiler/scenegraphtimelinemodel.h | 114 ----- qmlprofiler.pro | 6 - qtcreatorlibrary.pri | 7 - qtcreatorplugin.pri | 8 - .../qmlprofilerextension/FlameGraphText.qml | 34 ++ .../qmlprofilerextension/FlameGraphView.qml | 227 ++++++++++ .../QmlProfilerExtension.json.in | 19 + .../qmlprofilerextension/debugmessagesmodel.cpp | 142 ++++++ .../qmlprofilerextension/debugmessagesmodel.h | 71 +++ src/plugins/qmlprofilerextension/flamegraph.cpp | 182 ++++++++ src/plugins/qmlprofilerextension/flamegraph.h | 160 +++++++ src/plugins/qmlprofilerextension/flamegraph.qrc | 6 + .../qmlprofilerextension/flamegraphmodel.cpp | 324 +++++++++++++ src/plugins/qmlprofilerextension/flamegraphmodel.h | 113 +++++ .../qmlprofilerextension/flamegraphview.cpp | 116 +++++ src/plugins/qmlprofilerextension/flamegraphview.h | 64 +++ .../qmlprofilerextension/inputeventsmodel.cpp | 194 ++++++++ .../qmlprofilerextension/inputeventsmodel.h | 71 +++ .../qmlprofilerextension/memoryusagemodel.cpp | 280 ++++++++++++ .../qmlprofilerextension/memoryusagemodel.h | 85 ++++ .../qmlprofilerextension/pixmapcachemodel.cpp | 500 +++++++++++++++++++++ .../qmlprofilerextension/pixmapcachemodel.h | 130 ++++++ .../qmlprofilerextension/qmlprofilerextension.pro | 35 ++ .../qmlprofilerextension/qmlprofilerextension.qbs | 36 ++ .../qmlprofilerextension_dependencies.pri | 4 + .../qmlprofilerextension_global.h | 38 ++ .../qmlprofilerextensionconstants.h | 39 ++ .../qmlprofilerextensionplugin.cpp | 135 ++++++ .../qmlprofilerextensionplugin.h | 57 +++ .../scenegraphtimelinemodel.cpp | 311 +++++++++++++ .../qmlprofilerextension/scenegraphtimelinemodel.h | 114 +++++ 57 files changed, 3487 insertions(+), 3511 deletions(-) delete mode 100644 plugins/qmlprofiler/FlameGraphText.qml delete mode 100644 plugins/qmlprofiler/FlameGraphView.qml delete mode 100644 plugins/qmlprofiler/QmlProfilerExtension.json.in delete mode 100644 plugins/qmlprofiler/debugmessagesmodel.cpp delete mode 100644 plugins/qmlprofiler/debugmessagesmodel.h delete mode 100644 plugins/qmlprofiler/flamegraph.cpp delete mode 100644 plugins/qmlprofiler/flamegraph.h delete mode 100644 plugins/qmlprofiler/flamegraph.qrc delete mode 100644 plugins/qmlprofiler/flamegraphmodel.cpp delete mode 100644 plugins/qmlprofiler/flamegraphmodel.h delete mode 100644 plugins/qmlprofiler/flamegraphview.cpp delete mode 100644 plugins/qmlprofiler/flamegraphview.h delete mode 100644 plugins/qmlprofiler/inputeventsmodel.cpp delete mode 100644 plugins/qmlprofiler/inputeventsmodel.h delete mode 100644 plugins/qmlprofiler/memoryusagemodel.cpp delete mode 100644 plugins/qmlprofiler/memoryusagemodel.h delete mode 100644 plugins/qmlprofiler/pixmapcachemodel.cpp delete mode 100644 plugins/qmlprofiler/pixmapcachemodel.h delete mode 100644 plugins/qmlprofiler/qmlprofiler.pro delete mode 100644 plugins/qmlprofiler/qmlprofiler.qbs delete mode 100644 plugins/qmlprofiler/qmlprofiler_dependencies.pri delete mode 100644 plugins/qmlprofiler/qmlprofilerextension_global.h delete mode 100644 plugins/qmlprofiler/qmlprofilerextensionconstants.h delete mode 100644 plugins/qmlprofiler/qmlprofilerextensionplugin.cpp delete mode 100644 plugins/qmlprofiler/qmlprofilerextensionplugin.h delete mode 100644 plugins/qmlprofiler/scenegraphtimelinemodel.cpp delete mode 100644 plugins/qmlprofiler/scenegraphtimelinemodel.h delete mode 100644 qmlprofiler.pro delete mode 100644 qtcreatorlibrary.pri delete mode 100644 qtcreatorplugin.pri create mode 100644 src/plugins/qmlprofilerextension/FlameGraphText.qml create mode 100644 src/plugins/qmlprofilerextension/FlameGraphView.qml create mode 100644 src/plugins/qmlprofilerextension/QmlProfilerExtension.json.in create mode 100644 src/plugins/qmlprofilerextension/debugmessagesmodel.cpp create mode 100644 src/plugins/qmlprofilerextension/debugmessagesmodel.h create mode 100644 src/plugins/qmlprofilerextension/flamegraph.cpp create mode 100644 src/plugins/qmlprofilerextension/flamegraph.h create mode 100644 src/plugins/qmlprofilerextension/flamegraph.qrc create mode 100644 src/plugins/qmlprofilerextension/flamegraphmodel.cpp create mode 100644 src/plugins/qmlprofilerextension/flamegraphmodel.h create mode 100644 src/plugins/qmlprofilerextension/flamegraphview.cpp create mode 100644 src/plugins/qmlprofilerextension/flamegraphview.h create mode 100644 src/plugins/qmlprofilerextension/inputeventsmodel.cpp create mode 100644 src/plugins/qmlprofilerextension/inputeventsmodel.h create mode 100644 src/plugins/qmlprofilerextension/memoryusagemodel.cpp create mode 100644 src/plugins/qmlprofilerextension/memoryusagemodel.h create mode 100644 src/plugins/qmlprofilerextension/pixmapcachemodel.cpp create mode 100644 src/plugins/qmlprofilerextension/pixmapcachemodel.h create mode 100644 src/plugins/qmlprofilerextension/qmlprofilerextension.pro create mode 100644 src/plugins/qmlprofilerextension/qmlprofilerextension.qbs create mode 100644 src/plugins/qmlprofilerextension/qmlprofilerextension_dependencies.pri create mode 100644 src/plugins/qmlprofilerextension/qmlprofilerextension_global.h create mode 100644 src/plugins/qmlprofilerextension/qmlprofilerextensionconstants.h create mode 100644 src/plugins/qmlprofilerextension/qmlprofilerextensionplugin.cpp create mode 100644 src/plugins/qmlprofilerextension/qmlprofilerextensionplugin.h create mode 100644 src/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp create mode 100644 src/plugins/qmlprofilerextension/scenegraphtimelinemodel.h diff --git a/plugins/qmlprofiler/FlameGraphText.qml b/plugins/qmlprofiler/FlameGraphText.qml deleted file mode 100644 index a989b39355..0000000000 --- a/plugins/qmlprofiler/FlameGraphText.qml +++ /dev/null @@ -1,34 +0,0 @@ -/**************************************************************************** -** -** 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 - -Text { - font.pixelSize: 12 - font.family: "sans-serif" - textFormat: Text.PlainText - renderType: Text.NativeRendering -} - diff --git a/plugins/qmlprofiler/FlameGraphView.qml b/plugins/qmlprofiler/FlameGraphView.qml deleted file mode 100644 index 7cb4fb5f5f..0000000000 --- a/plugins/qmlprofiler/FlameGraphView.qml +++ /dev/null @@ -1,227 +0,0 @@ -/**************************************************************************** -** -** 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 QtQuick.Controls 1.4 -import FlameGraph 1.0 -import FlameGraphModel 1.0 - -ScrollView { - id: root - signal typeSelected(int typeIndex) - signal gotoSourceLocation(string filename, int line, int column) - - property int selectedTypeId: -1 - property int visibleRangeTypes: -1 - - Flickable { - id: flickable - contentHeight: flamegraph.height - boundsBehavior: Flickable.StopAtBounds - - FlameGraph { - property int itemHeight: Math.max(30, flickable.height / depth) - property int level: -1 - property color blue: "blue" - property color blue1: Qt.lighter(blue) - property color blue2: Qt.rgba(0.375, 0, 1, 1) - property color grey1: "#B0B0B0" - property color grey2: "#A0A0A0" - - id: flamegraph - width: parent.width - height: depth * itemHeight - model: flameGraphModel - sizeRole: FlameGraphModel.Duration - sizeThreshold: 0.002 - y: flickable.height > height ? flickable.height - height : 0 - - delegate: Item { - id: flamegraphItem - property int level: parent.level + (rangeTypeVisible ? 1 : 0) - property bool isSelected: flamegraphItem.FlameGraph.data(FlameGraphModel.TypeId) === - root.selectedTypeId - property bool rangeTypeVisible: root.visibleRangeTypes & - (1 << FlameGraph.data(FlameGraphModel.RangeType)) - - Rectangle { - border.color: { - if (flamegraphItem.isSelected) - return flamegraph.blue2; - else if (mouseArea.containsMouse) - return flamegraph.blue1; - else - return flamegraph.grey1 - } - border.width: (mouseArea.containsMouse || flamegraphItem.isSelected) ? 2 : 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 - anchors.fill: parent - anchors.margins: 5 - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - text: visible ? buildText() : "" - elide: Text.ElideRight - wrapMode: Text.WrapAtWordBoundaryOrAnywhere - - function buildText() { - if (!flamegraphItem.FlameGraph.dataValid) - return ""; - - return flamegraphItem.FlameGraph.data(FlameGraphModel.Details) + " (" + - flamegraphItem.FlameGraph.data(FlameGraphModel.Type) + ", " + - flamegraphItem.FlameGraph.data(FlameGraphModel.TimeInPercent) + "%)"; - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - - function printTime(t) - { - if (t <= 0) - return "0"; - if (t < 1000) - return t + " ns"; - t = Math.floor(t / 1000); - if (t < 1000) - return t + " μs"; - if (t < 1e6) - return (t / 1000) + " ms"; - return (t / 1e6) + " s"; - } - - onEntered: { - var model = []; - function addDetail(name, index, format) { - model.push(name + ":"); - model.push(format(flamegraphItem.FlameGraph.data(index))); - } - - function noop(a) { - return a; - } - - function addPercent(a) { - return a + "%"; - } - - if (!flamegraphItem.FlameGraph.dataValid) { - model.push(qsTr("Details") + ":"); - model.push(qsTr("Various Events")); - } else { - addDetail(qsTr("Details"), FlameGraphModel.Details, noop); - addDetail(qsTr("Type"), FlameGraphModel.Type, noop); - addDetail(qsTr("Calls"), FlameGraphModel.CallCount, noop); - addDetail(qsTr("Total Time"), FlameGraphModel.Duration, printTime); - addDetail(qsTr("Mean Time"), FlameGraphModel.TimePerCall, printTime); - addDetail(qsTr("In Percent"), FlameGraphModel.TimeInPercent, - addPercent); - - } - tooltip.model = model; - } - - onExited: { - tooltip.model = []; - } - - onClicked: { - if (flamegraphItem.FlameGraph.dataValid) { - root.typeSelected( - flamegraphItem.FlameGraph.data(FlameGraphModel.TypeId)); - root.gotoSourceLocation( - flamegraphItem.FlameGraph.data(FlameGraphModel.Filename), - flamegraphItem.FlameGraph.data(FlameGraphModel.Line), - flamegraphItem.FlameGraph.data(FlameGraphModel.Column)); - } - } - } - } - - 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 - } - } - - Rectangle { - color: "white" - border.width: 1 - border.color: flamegraph.grey2 - width: tooltip.model.length > 0 ? tooltip.width + 10 : 0 - height: tooltip.model.length > 0 ? tooltip.height + 10 : 0 - y: flickable.contentY - x: anchorRight ? parent.width - width : 0 - property bool anchorRight: true - - Grid { - id: tooltip - anchors.margins: 5 - anchors.top: parent.top - anchors.left: parent.left - spacing: 5 - columns: 2 - property var model: [ qsTr("No data available") ] - - Connections { - target: flameGraphModel - onModelReset: { - tooltip.model = (flameGraphModel.rowCount() === 0) ? - [ qsTr("No data available") ] : []; - } - } - - Repeater { - model: parent.model - FlameGraphText { - text: modelData - font.bold: (index % 2) === 0 - width: Math.min(implicitWidth, 200) - elide: Text.ElideRight - } - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: parent.anchorRight = !parent.anchorRight - } - } - } -} diff --git a/plugins/qmlprofiler/QmlProfilerExtension.json.in b/plugins/qmlprofiler/QmlProfilerExtension.json.in deleted file mode 100644 index 19639f4ecb..0000000000 --- a/plugins/qmlprofiler/QmlProfilerExtension.json.in +++ /dev/null @@ -1,19 +0,0 @@ -{ - \"Name\" : \"QmlProfilerExtension\", - \"Version\" : \"$$QTCREATOR_VERSION\", - \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", - \"Vendor\" : \"The Qt Company Ltd\", - \"Copyright\" : \"(C) 2015 The Qt Company Ltd\", - \"License\" : [ \"Commercial Usage\", - \"\", - \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\", - \"\", - \"GNU General Public License Usage\", - \"\", - \"Alternatively, this plugin may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. 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.\" - ], - \"Category\" : \"Qt Quick\", - \"Description\" : \"Qml Profiler Extension Plugin.\", - \"Url\" : \"http://www.qt.io\", - $$dependencyList -} diff --git a/plugins/qmlprofiler/debugmessagesmodel.cpp b/plugins/qmlprofiler/debugmessagesmodel.cpp deleted file mode 100644 index e0f3ec1c6d..0000000000 --- a/plugins/qmlprofiler/debugmessagesmodel.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#include "debugmessagesmodel.h" - -using namespace QmlProfiler; - -namespace QmlProfilerExtension { -namespace Internal { - -bool DebugMessagesModel::accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const -{ - return event.message == QmlDebug::DebugMessage; -} - -DebugMessagesModel::DebugMessagesModel(QmlProfilerModelManager *manager, QObject *parent) : - QmlProfilerTimelineModel(manager, QmlDebug::DebugMessage, QmlDebug::MaximumRangeType, - QmlDebug::ProfileDebugMessages, parent), m_maximumMsgType(-1) -{ -} - -int DebugMessagesModel::typeId(int index) const -{ - return m_data[index].typeId; -} - -QColor DebugMessagesModel::color(int index) const -{ - return colorBySelectionId(index); -} - -static const char *messageTypes[] = { - QT_TRANSLATE_NOOP("DebugMessagesModel", "Debug Message"), - QT_TRANSLATE_NOOP("DebugMessagesModel", "Warning Message"), - QT_TRANSLATE_NOOP("DebugMessagesModel", "Critical Message"), - QT_TRANSLATE_NOOP("DebugMessagesModel", "Fatal Message"), - QT_TRANSLATE_NOOP("DebugMessagesModel", "Info Message"), -}; - -QString DebugMessagesModel::messageType(uint i) -{ - return i < sizeof(messageTypes) / sizeof(char *) ? tr(messageTypes[i]) : - tr("Unknown Message %1").arg(i); -} - -QVariantList DebugMessagesModel::labels() const -{ - QVariantList result; - - for (int i = 0; i <= m_maximumMsgType; ++i) { - QVariantMap element; - element.insert(QLatin1String("description"), messageType(i)); - element.insert(QLatin1String("id"), i); - result << element; - } - return result; -} - -QVariantMap DebugMessagesModel::details(int index) const -{ - const QmlProfilerDataModel::QmlEventTypeData &type = - modelManager()->qmlModel()->getEventTypes()[m_data[index].typeId]; - - QVariantMap result; - result.insert(QLatin1String("displayName"), messageType(type.detailType)); - result.insert(tr("Timestamp"), QmlProfilerDataModel::formatTime(startTime(index))); - result.insert(tr("Message"), m_data[index].text); - result.insert(tr("Location"), type.displayName); - return result; -} - -int DebugMessagesModel::expandedRow(int index) const -{ - return selectionId(index) + 1; -} - -int DebugMessagesModel::collapsedRow(int index) const -{ - Q_UNUSED(index); - return 1; -} - -void DebugMessagesModel::loadData() -{ - QmlProfilerDataModel *simpleModel = modelManager()->qmlModel(); - if (simpleModel->isEmpty()) - return; - - const QVector &types = simpleModel->getEventTypes(); - - foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) { - const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex()]; - if (!accepted(type) || event.startTime() < 0) - continue; - - m_data.insert(insert(event.startTime(), 0, type.detailType), - MessageData(event.stringData(), event.typeIndex())); - if (type.detailType > m_maximumMsgType) - m_maximumMsgType = event.typeIndex(); - updateProgress(count(), simpleModel->getEvents().count()); - } - setCollapsedRowCount(2); - setExpandedRowCount(m_maximumMsgType + 2); - updateProgress(1, 1); -} - -void DebugMessagesModel::clear() -{ - m_data.clear(); - m_maximumMsgType = -1; - QmlProfilerTimelineModel::clear(); -} - -QVariantMap DebugMessagesModel::location(int index) const -{ - return locationFromTypeId(index); -} - -} -} diff --git a/plugins/qmlprofiler/debugmessagesmodel.h b/plugins/qmlprofiler/debugmessagesmodel.h deleted file mode 100644 index e5934e204d..0000000000 --- a/plugins/qmlprofiler/debugmessagesmodel.h +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#ifndef DEBUGMESSAGESMODEL_H -#define DEBUGMESSAGESMODEL_H - -#include "qmlprofiler/qmlprofilertimelinemodel.h" - -namespace QmlProfilerExtension { -namespace Internal { - -class DebugMessagesModel : public QmlProfiler::QmlProfilerTimelineModel -{ - Q_OBJECT - -protected: - bool accepted(const QmlProfiler::QmlProfilerDataModel::QmlEventTypeData &event) const override; - -public: - DebugMessagesModel(QmlProfiler::QmlProfilerModelManager *manager, QObject *parent = 0); - - int typeId(int index) const override; - QColor color(int index) const override; - QVariantList labels() const override; - QVariantMap details(int index) const override; - int expandedRow(int index) const override; - int collapsedRow(int index) const override; - void loadData() override; - void clear() override; - QVariantMap location(int index) const override; - -private: - static QString messageType(uint i); - - struct MessageData { - MessageData(const QString &text = QString(), int typeId = -1) : - text(text), typeId(typeId) {} - QString text; - int typeId; - }; - - int m_maximumMsgType; - QVector m_data; -}; - -} -} - -#endif // DEBUGMESSAGESMODEL_H diff --git a/plugins/qmlprofiler/flamegraph.cpp b/plugins/qmlprofiler/flamegraph.cpp deleted file mode 100644 index e2b8501bce..0000000000 --- a/plugins/qmlprofiler/flamegraph.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#include "flamegraph.h" - -namespace QmlProfilerExtension { -namespace Internal { - -FlameGraph::FlameGraph(QQuickItem *parent) : - QQuickItem(parent), m_delegate(0), m_model(0), m_depth(0), m_sizeThreshold(0) -{ -} - -QQmlComponent *FlameGraph::delegate() const -{ - return m_delegate; -} - -void FlameGraph::setDelegate(QQmlComponent *delegate) -{ - if (delegate != m_delegate) { - m_delegate = delegate; - emit delegateChanged(delegate); - } -} - -QAbstractItemModel *FlameGraph::model() const -{ - return m_model; -} - -void FlameGraph::setModel(QAbstractItemModel *model) -{ - if (model != m_model) { - if (m_model) - disconnect(m_model, &QAbstractItemModel::modelReset, this, &FlameGraph::rebuild); - - m_model = model; - connect(m_model, &QAbstractItemModel::modelReset, this, &FlameGraph::rebuild); - emit modelChanged(model); - rebuild(); - } -} - -int FlameGraph::sizeRole() const -{ - return m_sizeRole; -} - -void FlameGraph::setSizeRole(int sizeRole) -{ - if (sizeRole != m_sizeRole) { - m_sizeRole = sizeRole; - emit sizeRoleChanged(sizeRole); - rebuild(); - } -} - -qreal FlameGraph::sizeThreshold() const -{ - return m_sizeThreshold; -} - -void FlameGraph::setSizeThreshold(qreal sizeThreshold) -{ - if (sizeThreshold != m_sizeThreshold) { - m_sizeThreshold = sizeThreshold; - emit sizeThresholdChanged(sizeThreshold); - rebuild(); - } -} - -int FlameGraph::depth() const -{ - return m_depth; -} - -FlameGraphAttached *FlameGraph::qmlAttachedProperties(QObject *object) -{ - FlameGraphAttached *attached = - object->findChild(QString(), Qt::FindDirectChildrenOnly); - if (!attached) - attached = new FlameGraphAttached(object); - return attached; -} - -QObject *FlameGraph::appendChild(QObject *parentObject, QQuickItem *parentItem, - QQmlContext *context, const QModelIndex &childIndex, - qreal position, qreal size) -{ - QObject *childObject = m_delegate->beginCreate(context); - if (parentItem) { - QQuickItem *childItem = qobject_cast(childObject); - if (childItem) - childItem->setParentItem(parentItem); - } - childObject->setParent(parentObject); - FlameGraphAttached *attached = FlameGraph::qmlAttachedProperties(childObject); - attached->setRelativePosition(position); - attached->setRelativeSize(size); - attached->setModelIndex(childIndex); - m_delegate->completeCreate(); - return childObject; -} - - -int FlameGraph::buildNode(const QModelIndex &parentIndex, QObject *parentObject, int depth) -{ - qreal position = 0; - qreal skipped = 0; - qreal parentSize = m_model->data(parentIndex, m_sizeRole).toReal(); - QQuickItem *parentItem = qobject_cast(parentObject); - QQmlContext *context = qmlContext(this); - int rowCount = m_model->rowCount(parentIndex); - int childrenDepth = depth; - for (int row = 0; row < rowCount; ++row) { - QModelIndex childIndex = m_model->index(row, 0, parentIndex); - qreal size = m_model->data(childIndex, m_sizeRole).toReal(); - if (size / m_model->data(QModelIndex(), m_sizeRole).toReal() < m_sizeThreshold) { - skipped += size; - continue; - } - - QObject *childObject = appendChild(parentObject, parentItem, context, childIndex, - position / parentSize, size / parentSize); - position += size; - childrenDepth = qMax(childrenDepth, buildNode(childIndex, childObject, depth + 1)); - } - - if (skipped > 0) { - appendChild(parentObject, parentItem, context, QModelIndex(), position / parentSize, - skipped / parentSize); - childrenDepth = qMax(childrenDepth, depth + 1); - } - - return childrenDepth; -} - -void FlameGraph::rebuild() -{ - qDeleteAll(childItems()); - childItems().clear(); - m_depth = 0; - - if (!m_model) { - emit depthChanged(m_depth); - return; - } - - m_depth = buildNode(QModelIndex(), this, 0); - emit depthChanged(m_depth); -} - -QVariant FlameGraphAttached::data(int role) const -{ - return m_data.isValid() ? m_data.data(role) : QVariant(); -} - -} -} diff --git a/plugins/qmlprofiler/flamegraph.h b/plugins/qmlprofiler/flamegraph.h deleted file mode 100644 index d4b444fc87..0000000000 --- a/plugins/qmlprofiler/flamegraph.h +++ /dev/null @@ -1,160 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#ifndef FLAMEGRAPH_H -#define FLAMEGRAPH_H - -#include -#include - -namespace QmlProfilerExtension { -namespace Internal { - -class 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; - - 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_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) - Q_PROPERTY(QAbstractItemModel* model READ model WRITE setModel NOTIFY modelChanged) - Q_PROPERTY(int sizeRole READ sizeRole WRITE setSizeRole NOTIFY sizeRoleChanged) - Q_PROPERTY(qreal sizeThreshold READ sizeThreshold WRITE setSizeThreshold - NOTIFY sizeThresholdChanged) - Q_PROPERTY(int depth READ depth NOTIFY depthChanged) - -public: - FlameGraph(QQuickItem *parent = 0); - - QQmlComponent *delegate() const; - void setDelegate(QQmlComponent *delegate); - - QAbstractItemModel *model() const; - void setModel(QAbstractItemModel *model); - - int sizeRole() const; - void setSizeRole(int sizeRole); - - qreal sizeThreshold() const; - void setSizeThreshold(qreal sizeThreshold); - - int depth() const; - - static FlameGraphAttached *qmlAttachedProperties(QObject *object); - -signals: - void delegateChanged(QQmlComponent *delegate); - void modelChanged(QAbstractItemModel *model); - void sizeRoleChanged(int role); - void sizeThresholdChanged(qreal threshold); - void depthChanged(int depth); - -private slots: - void rebuild(); - -private: - QQmlComponent *m_delegate; - QAbstractItemModel *m_model; - int m_sizeRole; - int m_depth; - qreal m_sizeThreshold; - - int buildNode(const QModelIndex &parentIndex, QObject *parentObject, int depth); - QObject *appendChild(QObject *parentObject, QQuickItem *parentItem, QQmlContext *context, - const QModelIndex &childIndex, qreal position, qreal size); -}; - -} -} - -QML_DECLARE_TYPEINFO(QmlProfilerExtension::Internal::FlameGraph, QML_HAS_ATTACHED_PROPERTIES) - -#endif // FLAMEGRAPH_H diff --git a/plugins/qmlprofiler/flamegraph.qrc b/plugins/qmlprofiler/flamegraph.qrc deleted file mode 100644 index abf7393f4e..0000000000 --- a/plugins/qmlprofiler/flamegraph.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - FlameGraphView.qml - FlameGraphText.qml - - diff --git a/plugins/qmlprofiler/flamegraphmodel.cpp b/plugins/qmlprofiler/flamegraphmodel.cpp deleted file mode 100644 index e181a66109..0000000000 --- a/plugins/qmlprofiler/flamegraphmodel.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#include "flamegraphmodel.h" - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -namespace QmlProfilerExtension { -namespace Internal { - -FlameGraphModel::FlameGraphModel(QmlProfiler::QmlProfilerModelManager *modelManager, - QObject *parent) : QAbstractItemModel(parent) -{ - m_modelManager = modelManager; - connect(modelManager->qmlModel(), &QmlProfiler::QmlProfilerDataModel::changed, - this, [this](){loadData();}); - connect(modelManager->notesModel(), &Timeline::TimelineNotesModel::changed, - this, [this](int typeId, int, int){loadNotes(typeId, true);}); - m_modelId = modelManager->registerModelProxy(); - - // We're iterating twice in loadData. - modelManager->setProxyCountWeight(m_modelId, 2); - - m_acceptedTypes << QmlDebug::Compiling << QmlDebug::Creating << QmlDebug::Binding - << QmlDebug::HandlingSignal << QmlDebug::Javascript; - modelManager->announceFeatures(m_modelId, QmlDebug::Constants::QML_JS_RANGE_FEATURES); -} - -void FlameGraphModel::setEventTypeAccepted(QmlDebug::RangeType type, bool accepted) -{ - if (accepted && !m_acceptedTypes.contains(type)) - m_acceptedTypes << type; - else if (!accepted && m_acceptedTypes.contains(type)) - m_acceptedTypes.removeOne(type); -} - -bool FlameGraphModel::eventTypeAccepted(QmlDebug::RangeType type) const -{ - return m_acceptedTypes.contains(type); -} - -void FlameGraphModel::clear() -{ - m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1); - m_stackBottom = FlameGraphData(); - m_typeIdsWithNotes.clear(); -} - -void FlameGraphModel::loadNotes(int typeIndex, bool emitSignal) -{ - QSet changedNotes; - Timeline::TimelineNotesModel *notes = m_modelManager->notesModel(); - if (typeIndex == -1) { - changedNotes = m_typeIdsWithNotes; - m_typeIdsWithNotes.clear(); - for (int i = 0; i < notes->count(); ++i) - m_typeIdsWithNotes.insert(notes->typeId(i)); - changedNotes += m_typeIdsWithNotes; - } else { - changedNotes.insert(typeIndex); - if (notes->byTypeId(typeIndex).isEmpty()) - m_typeIdsWithNotes.remove(typeIndex); - else - m_typeIdsWithNotes.insert(typeIndex); - } - - if (!emitSignal) - return; - - QQueue queue; - queue.append(QModelIndex()); - - QVector roles = {Note}; - while (!queue.isEmpty()) { - QModelIndex index = queue.takeFirst(); - if (index.isValid()) { - FlameGraphData *data = static_cast(index.internalPointer()); - if (changedNotes.contains(data->typeIndex)) - emit dataChanged(index, index, roles); - for (int row = 0; row < rowCount(index); ++row) - queue.append(index.child(row, 0)); - } - - } -} - -void FlameGraphModel::loadData(qint64 rangeStart, qint64 rangeEnd) -{ - const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1); - if (m_modelManager->state() == QmlProfiler::QmlProfilerModelManager::ClearingData) { - beginResetModel(); - clear(); - endResetModel(); - return; - } else if (m_modelManager->state() != QmlProfiler::QmlProfilerModelManager::ProcessingData && - m_modelManager->state() != QmlProfiler::QmlProfilerModelManager::Done) { - return; - } - - beginResetModel(); - clear(); - - const QVector &eventList - = m_modelManager->qmlModel()->getEvents(); - const QVector &typesList - = m_modelManager->qmlModel()->getEventTypes(); - - // used by binding loop detection - QStack callStack; - callStack.append(0); - FlameGraphData *stackTop = &m_stackBottom; - - for (int i = 0; i < eventList.size(); ++i) { - const QmlProfiler::QmlProfilerDataModel::QmlEventData *event = &eventList[i]; - int typeIndex = event->typeIndex(); - const QmlProfiler::QmlProfilerDataModel::QmlEventTypeData *type = &typesList[typeIndex]; - - if (!m_acceptedTypes.contains(type->rangeType)) - continue; - - if (checkRanges) { - if ((event->startTime() + event->duration() < rangeStart) - || (event->startTime() > rangeEnd)) - continue; - } - - const QmlProfiler::QmlProfilerDataModel::QmlEventData *potentialParent = callStack.top(); - while (potentialParent && - potentialParent->startTime() + potentialParent->duration() <= event->startTime()) { - callStack.pop(); - stackTop = stackTop->parent; - potentialParent = callStack.top(); - } - - callStack.push(event); - stackTop = pushChild(stackTop, event); - - m_modelManager->modelProxyCountUpdated(m_modelId, i, eventList.count()); - } - - foreach (FlameGraphData *child, m_stackBottom.children) - m_stackBottom.duration += child->duration; - - loadNotes(-1, false); - - m_modelManager->modelProxyCountUpdated(m_modelId, 1, 1); - endResetModel(); -} - -static QString nameForType(QmlDebug::RangeType typeNumber) -{ - switch (typeNumber) { - case QmlDebug::Painting: return FlameGraphModel::tr("Paint"); - case QmlDebug::Compiling: return FlameGraphModel::tr("Compile"); - case QmlDebug::Creating: return FlameGraphModel::tr("Create"); - case QmlDebug::Binding: return FlameGraphModel::tr("Binding"); - case QmlDebug::HandlingSignal: return FlameGraphModel::tr("Signal"); - case QmlDebug::Javascript: return FlameGraphModel::tr("JavaScript"); - default: return QString(); - } -} - -QVariant FlameGraphModel::lookup(const FlameGraphData &stats, int role) const -{ - switch (role) { - case TypeId: return stats.typeIndex; - case Note: { - QString ret; - if (!m_typeIdsWithNotes.contains(stats.typeIndex)) - return ret; - QmlProfiler::QmlProfilerNotesModel *notes = m_modelManager->notesModel(); - foreach (const QVariant &item, notes->byTypeId(stats.typeIndex)) { - if (ret.isEmpty()) - ret = item.toString(); - else - ret += QChar::LineFeed + item.toString(); - } - return ret; - } - case Duration: return stats.duration; - case CallCount: return stats.calls; - case TimePerCall: return stats.duration / stats.calls; - case TimeInPercent: return stats.duration * 100 / m_stackBottom.duration; - default: break; - } - - if (stats.typeIndex != -1) { - const QVector &typeList = - m_modelManager->qmlModel()->getEventTypes(); - const QmlProfiler::QmlProfilerDataModel::QmlEventTypeData &type = typeList[stats.typeIndex]; - - switch (role) { - case Filename: return type.location.filename; - case Line: return type.location.line; - case Column: return type.location.column; - case Type: return nameForType(type.rangeType); - case RangeType: return type.rangeType; - case Details: return type.data.isEmpty() ? - FlameGraphModel::tr("Source code not available") : type.data; - default: return QVariant(); - } - } else { - return QVariant(); - } -} - -FlameGraphData::FlameGraphData(FlameGraphData *parent, int typeIndex, qint64 duration) : - duration(duration), calls(1), typeIndex(typeIndex), parent(parent) {} - -FlameGraphData::~FlameGraphData() -{ - qDeleteAll(children); -} - -FlameGraphData *FlameGraphModel::pushChild( - FlameGraphData *parent, const QmlProfiler::QmlProfilerDataModel::QmlEventData *data) -{ - foreach (FlameGraphData *child, parent->children) { - if (child->typeIndex == data->typeIndex()) { - ++child->calls; - child->duration += data->duration(); - return child; - } - } - - FlameGraphData *child = new FlameGraphData(parent, data->typeIndex(), data->duration()); - parent->children.append(child); - return child; -} - -QModelIndex FlameGraphModel::index(int row, int column, const QModelIndex &parent) const -{ - if (parent.isValid()) { - FlameGraphData *parentData = static_cast(parent.internalPointer()); - return createIndex(row, column, parentData->children[row]); - } else { - return createIndex(row, column, row >= 0 ? m_stackBottom.children[row] : 0); - } -} - -QModelIndex FlameGraphModel::parent(const QModelIndex &child) const -{ - if (child.isValid()) { - FlameGraphData *childData = static_cast(child.internalPointer()); - return createIndex(0, 0, childData->parent); - } else { - return QModelIndex(); - } -} - -int FlameGraphModel::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid()) { - FlameGraphData *parentData = static_cast(parent.internalPointer()); - return parentData->children.count(); - } else { - return m_stackBottom.children.count(); - } -} - -int FlameGraphModel::columnCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - return 1; -} - -QVariant FlameGraphModel::data(const QModelIndex &index, int role) const -{ - FlameGraphData *data = static_cast(index.internalPointer()); - return lookup(data ? *data : m_stackBottom, role); -} - -QHash FlameGraphModel::roleNames() const -{ - QHash names = QAbstractItemModel::roleNames(); - names[TypeId] = "typeId"; - names[Type] = "type"; - names[Duration] = "duration"; - names[CallCount] = "callCount"; - names[Details] = "details"; - names[Filename] = "filename"; - names[Line] = "line"; - names[Column] = "column"; - names[Note] = "note"; - names[TimePerCall] = "timePerCall"; - names[TimeInPercent] = "timeInPercent"; - names[RangeType] = "rangeType"; - return names; -} - -} // namespace Internal -} // namespace QmlProfilerExtension diff --git a/plugins/qmlprofiler/flamegraphmodel.h b/plugins/qmlprofiler/flamegraphmodel.h deleted file mode 100644 index 06b5b042e1..0000000000 --- a/plugins/qmlprofiler/flamegraphmodel.h +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#ifndef QMLPROFILEREVENTSMODEL_H -#define QMLPROFILEREVENTSMODEL_H - -#include -#include -#include -#include - -#include -#include -#include - -namespace QmlProfilerExtension { -namespace Internal { - -struct FlameGraphData { - FlameGraphData(FlameGraphData *parent = 0, int typeIndex = -1, qint64 duration = 0); - ~FlameGraphData(); - - qint64 duration; - qint64 calls; - int typeIndex; - - FlameGraphData *parent; - QVector children; -}; - -class FlameGraphModel : public QAbstractItemModel -{ - Q_OBJECT - Q_ENUMS(Role) -public: - enum Role { - TypeId = Qt::UserRole + 1, // Sort by data, not by displayed string - Type, - Duration, - CallCount, - Details, - Filename, - Line, - Column, - Note, - TimePerCall, - TimeInPercent, - RangeType, - MaxRole - }; - - FlameGraphModel(QmlProfiler::QmlProfilerModelManager *modelManager, QObject *parent = 0); - - void setEventTypeAccepted(QmlDebug::RangeType type, bool accepted); - bool eventTypeAccepted(QmlDebug::RangeType) const; - - QModelIndex index(int row, int column, const QModelIndex &parent) const override; - QModelIndex parent(const QModelIndex &child) const override; - int rowCount(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; - QHash roleNames() const override; - -public slots: - void loadData(qint64 rangeStart = -1, qint64 rangeEnd = -1); - void loadNotes(int typeId, bool emitSignal); - -private: - friend class FlameGraphRelativesModel; - friend class FlameGraphParentsModel; - friend class FlameGraphChildrenModel; - - QVariant lookup(const FlameGraphData &data, int role) const; - void clear(); - FlameGraphData *pushChild(FlameGraphData *parent, - const QmlProfiler::QmlProfilerDataModel::QmlEventData *data); - - int m_selectedTypeIndex; - FlameGraphData m_stackBottom; - - int m_modelId; - QmlProfiler::QmlProfilerModelManager *m_modelManager; - - QList m_acceptedTypes; - QSet m_typeIdsWithNotes; -}; - -} // namespace Internal -} // namespace QmlprofilerExtension - -#endif // QMLPROFILEREVENTSMODEL_H diff --git a/plugins/qmlprofiler/flamegraphview.cpp b/plugins/qmlprofiler/flamegraphview.cpp deleted file mode 100644 index 532f9718bb..0000000000 --- a/plugins/qmlprofiler/flamegraphview.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#include "flamegraphview.h" -#include "flamegraph.h" - -#include -#include - -#include -#include -#include - -namespace QmlProfilerExtension { -namespace Internal { - -FlameGraphView::FlameGraphView(QWidget *parent, QmlProfiler::QmlProfilerModelManager *manager) : - QmlProfilerEventsView(parent), m_content(new QQuickWidget(this)), - m_model(new FlameGraphModel(manager, this)), m_isRestrictedToRange(false) -{ - setWindowTitle(QStringLiteral("Flamegraph")); - setObjectName(QStringLiteral("QmlProfilerFlamegraph")); - - qmlRegisterType("FlameGraph", 1, 0, "FlameGraph"); - qmlRegisterUncreatableType("FlameGraphModel", 1, 0, "FlameGraphModel", - QLatin1String("use the context property")); - - m_content->rootContext()->setContextProperty(QStringLiteral("flameGraphModel"), m_model); - m_content->setSource(QUrl(QStringLiteral("qrc:/FlameGraphView.qml"))); - m_content->setClearColor(QColor(0xdc, 0xdc, 0xdc)); - - m_content->setResizeMode(QQuickWidget::SizeRootObjectToView); - m_content->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - QLayout *layout = new QVBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); - layout->addWidget(m_content); - setLayout(layout); - - connect(m_content->rootObject(), SIGNAL(typeSelected(int)), - this, SIGNAL(typeSelected(int))); - connect(m_content->rootObject(), SIGNAL(gotoSourceLocation(QString,int,int)), - this, SIGNAL(gotoSourceLocation(QString,int,int))); -} - -void FlameGraphView::clear() -{ -} - -void FlameGraphView::restrictToRange(qint64 rangeStart, qint64 rangeEnd) -{ - m_isRestrictedToRange = (rangeStart != -1 || rangeEnd != -1); - m_model->loadData(rangeStart, rangeEnd); -} - -bool FlameGraphView::isRestrictedToRange() const -{ - return m_isRestrictedToRange; -} - -void FlameGraphView::selectByTypeId(int typeIndex) -{ - m_content->rootObject()->setProperty("selectedTypeId", typeIndex); -} - -void FlameGraphView::onVisibleFeaturesChanged(quint64 features) -{ - int rangeTypeMask = 0; - for (int rangeType = 0; rangeType < QmlDebug::MaximumRangeType; ++rangeType) { - if (features & (1 << QmlDebug::featureFromRangeType(QmlDebug::RangeType(rangeType)))) - rangeTypeMask |= (1 << rangeType); - } - m_content->rootObject()->setProperty("visibleRangeTypes", rangeTypeMask); -} - -void FlameGraphView::contextMenuEvent(QContextMenuEvent *ev) -{ - QMenu menu; - QAction *getGlobalStatsAction = 0; - - QPoint position = ev->globalPos(); - - menu.addActions(QmlProfiler::QmlProfilerTool::profilerContextMenuActions()); - menu.addSeparator(); - getGlobalStatsAction = menu.addAction(tr("Show Full Range")); - if (!isRestrictedToRange()) - getGlobalStatsAction->setEnabled(false); - - if (menu.exec(position) == getGlobalStatsAction) - emit showFullRange(); -} - -} -} diff --git a/plugins/qmlprofiler/flamegraphview.h b/plugins/qmlprofiler/flamegraphview.h deleted file mode 100644 index b98b673152..0000000000 --- a/plugins/qmlprofiler/flamegraphview.h +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#ifndef FLAMEGRAPHVIEW_H -#define FLAMEGRAPHVIEW_H - -#include "flamegraphmodel.h" - -#include "qmlprofiler/qmlprofilereventsview.h" -#include -#include - -namespace QmlProfilerExtension { -namespace Internal { - -class FlameGraphView : public QmlProfiler::QmlProfilerEventsView -{ - Q_OBJECT -public: - FlameGraphView(QWidget *parent, QmlProfiler::QmlProfilerModelManager *manager); - - void clear() override; - void restrictToRange(qint64 rangeStart, qint64 rangeEnd) override; - bool isRestrictedToRange() const override; - -public slots: - void selectByTypeId(int typeIndex) override; - void onVisibleFeaturesChanged(quint64 features) override; - -protected: - void contextMenuEvent(QContextMenuEvent *ev) override; - -private: - QQuickWidget *m_content; - FlameGraphModel *m_model; - bool m_isRestrictedToRange; -}; - -} -} - -#endif // FLAMEGRAPHVIEW_H diff --git a/plugins/qmlprofiler/inputeventsmodel.cpp b/plugins/qmlprofiler/inputeventsmodel.cpp deleted file mode 100644 index a31aef7482..0000000000 --- a/plugins/qmlprofiler/inputeventsmodel.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#include "inputeventsmodel.h" -#include "qmldebug/qmlprofilereventtypes.h" -#include "qmlprofiler/qmlprofilermodelmanager.h" - -#include -#include -#include - -namespace QmlProfilerExtension { -namespace Internal { - -using namespace QmlProfiler; - -InputEventsModel::InputEventsModel(QmlProfilerModelManager *manager, QObject *parent) : - QmlProfilerTimelineModel(manager, QmlDebug::Event, QmlDebug::MaximumRangeType, - QmlDebug::ProfileInputEvents, parent), - m_keyTypeId(-1), m_mouseTypeId(-1) -{ -} - -int InputEventsModel::typeId(int index) const -{ - return selectionId(index) == QmlDebug::Mouse ? m_mouseTypeId : m_keyTypeId; -} - -QColor InputEventsModel::color(int index) const -{ - return colorBySelectionId(index); -} - -QVariantList InputEventsModel::labels() const -{ - QVariantList result; - - QVariantMap element; - element.insert(QLatin1String("description"), QVariant(tr("Mouse Events"))); - element.insert(QLatin1String("id"), QVariant(QmlDebug::Mouse)); - result << element; - - element.clear(); - element.insert(QLatin1String("description"), QVariant(tr("Keyboard Events"))); - element.insert(QLatin1String("id"), QVariant(QmlDebug::Key)); - result << element; - - return result; -} - -QMetaEnum InputEventsModel::metaEnum(const char *name) -{ - return staticQtMetaObject.enumerator(staticQtMetaObject.indexOfEnumerator(name)); -} - -QVariantMap InputEventsModel::details(int index) const -{ - QVariantMap result; - result.insert(tr("Timestamp"), QmlProfilerDataModel::formatTime(startTime(index))); - QString type; - const InputEvent &event = m_data[index]; - switch (event.type) { - case QmlDebug::InputKeyPress: - type = tr("Key Press"); - case QmlDebug::InputKeyRelease: - if (type.isEmpty()) - type = tr("Key Release"); - if (event.a != 0) { - result.insert(tr("Key"), QLatin1String(metaEnum("Key").valueToKey(event.a))); - } - if (event.b != 0) { - result.insert(tr("Modifiers"), - QLatin1String(metaEnum("KeyboardModifiers").valueToKeys(event.b))); - } - break; - case QmlDebug::InputMouseDoubleClick: - type = tr("Double Click"); - case QmlDebug::InputMousePress: - if (type.isEmpty()) - type = tr("Mouse Press"); - case QmlDebug::InputMouseRelease: - if (type.isEmpty()) - type = tr("Mouse Release"); - result.insert(tr("Button"), QLatin1String(metaEnum("MouseButtons").valueToKey(event.a))); - result.insert(tr("Result"), QLatin1String(metaEnum("MouseButtons").valueToKeys(event.b))); - break; - case QmlDebug::InputMouseMove: - type = tr("Mouse Move"); - result.insert(tr("X"), QString::number(event.a)); - result.insert(tr("Y"), QString::number(event.b)); - break; - case QmlDebug::InputMouseWheel: - type = tr("Mouse Wheel"); - result.insert(tr("Angle X"), QString::number(event.a)); - result.insert(tr("Angle Y"), QString::number(event.b)); - break; - case QmlDebug::InputKeyUnknown: - type = tr("Keyboard Event"); - break; - case QmlDebug::InputMouseUnknown: - type = tr("Mouse Event"); - break; - default: - Q_UNREACHABLE(); - break; - } - - result.insert(QLatin1String("displayName"), type); - - return result; -} - -int InputEventsModel::expandedRow(int index) const -{ - return selectionId(index) == QmlDebug::Mouse ? 1 : 2; -} - -int InputEventsModel::collapsedRow(int index) const -{ - Q_UNUSED(index) - return 1; -} - -void InputEventsModel::loadData() -{ - QmlProfilerDataModel *simpleModel = modelManager()->qmlModel(); - if (simpleModel->isEmpty()) - return; - - const QVector &types = simpleModel->getEventTypes(); - foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) { - const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex()]; - if (!accepted(type)) - continue; - - m_data.insert(insert(event.startTime(), 0, type.detailType), - InputEvent(static_cast(event.numericData(0)), - event.numericData(1), event.numericData(2))); - - if (type.detailType == QmlDebug::Mouse) { - if (m_mouseTypeId == -1) - m_mouseTypeId = event.typeIndex(); - } else if (m_keyTypeId == -1) { - m_keyTypeId = event.typeIndex(); - } - updateProgress(count(), simpleModel->getEvents().count()); - } - setCollapsedRowCount(2); - setExpandedRowCount(3); - updateProgress(1, 1); -} - -void InputEventsModel::clear() -{ - m_keyTypeId = m_mouseTypeId = -1; - m_data.clear(); - QmlProfilerTimelineModel::clear(); -} - -bool InputEventsModel::accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const -{ - return QmlProfilerTimelineModel::accepted(event) && - (event.detailType == QmlDebug::Mouse || event.detailType == QmlDebug::Key); -} - -InputEventsModel::InputEvent::InputEvent(QmlDebug::InputEventType type, int a, int b) : - type(type), a(a), b(b) -{ -} - -} -} diff --git a/plugins/qmlprofiler/inputeventsmodel.h b/plugins/qmlprofiler/inputeventsmodel.h deleted file mode 100644 index 72a58642dc..0000000000 --- a/plugins/qmlprofiler/inputeventsmodel.h +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#ifndef INPUTEVENTSMODEL_H -#define INPUTEVENTSMODEL_H - -#include "qmlprofiler/qmlprofilertimelinemodel.h" - -namespace QmlProfilerExtension { -namespace Internal { - -class InputEventsModel : public QmlProfiler::QmlProfilerTimelineModel -{ - Q_OBJECT - -protected: - bool accepted(const QmlProfiler::QmlProfilerDataModel::QmlEventTypeData &event) const; - -public: - struct InputEvent { - InputEvent(QmlDebug::InputEventType type = QmlDebug::MaximumInputEventType, int a = 0, - int b = 0); - QmlDebug::InputEventType type; - int a; - int b; - }; - - InputEventsModel(QmlProfiler::QmlProfilerModelManager *manager, QObject *parent = 0); - - int typeId(int index) const; - QColor color(int index) const; - QVariantList labels() const; - QVariantMap details(int index) const; - int expandedRow(int index) const; - int collapsedRow(int index) const; - void loadData(); - void clear(); - -private: - static QMetaEnum metaEnum(const char *name); - int m_keyTypeId; - int m_mouseTypeId; - - QVector m_data; -}; - -} -} -#endif // INPUTEVENTSMODEL_H diff --git a/plugins/qmlprofiler/memoryusagemodel.cpp b/plugins/qmlprofiler/memoryusagemodel.cpp deleted file mode 100644 index 115522bbd2..0000000000 --- a/plugins/qmlprofiler/memoryusagemodel.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#include "memoryusagemodel.h" -#include "qmldebug/qmlprofilereventtypes.h" -#include "qmlprofiler/qmlprofilermodelmanager.h" - -#include - -namespace QmlProfilerExtension { -namespace Internal { - -using namespace QmlProfiler; - -MemoryUsageModel::MemoryUsageModel(QmlProfilerModelManager *manager, QObject *parent) : - QmlProfilerTimelineModel(manager, QmlDebug::MemoryAllocation, QmlDebug::MaximumRangeType, - QmlDebug::ProfileMemory, parent) -{ - m_maxSize = 1; - announceFeatures((1ULL << mainFeature()) | QmlDebug::Constants::QML_JS_RANGE_FEATURES); -} - -int MemoryUsageModel::rowMaxValue(int rowNumber) const -{ - Q_UNUSED(rowNumber); - return m_maxSize; -} - -int MemoryUsageModel::expandedRow(int index) const -{ - int type = selectionId(index); - return (type == QmlDebug::HeapPage || type == QmlDebug::LargeItem) ? 1 : 2; -} - -int MemoryUsageModel::collapsedRow(int index) const -{ - return expandedRow(index); -} - -int MemoryUsageModel::typeId(int index) const -{ - return m_data[index].typeId; -} - -QColor MemoryUsageModel::color(int index) const -{ - return colorBySelectionId(index); -} - -float MemoryUsageModel::relativeHeight(int index) const -{ - return qMin(1.0f, (float)m_data[index].size / (float)m_maxSize); -} - -QVariantMap MemoryUsageModel::location(int index) const -{ - static const QLatin1String file("file"); - static const QLatin1String line("line"); - static const QLatin1String column("column"); - - QVariantMap result; - - int originType = m_data[index].originTypeIndex; - if (originType > -1) { - const QmlDebug::QmlEventLocation &location = - modelManager()->qmlModel()->getEventTypes().at(originType).location; - - result.insert(file, location.filename); - result.insert(line, location.line); - result.insert(column, location.column); - } - - return result; -} - -QVariantList MemoryUsageModel::labels() const -{ - QVariantList result; - - QVariantMap element; - element.insert(QLatin1String("description"), QVariant(tr("Memory Allocation"))); - element.insert(QLatin1String("id"), QVariant(QmlDebug::HeapPage)); - result << element; - - element.clear(); - element.insert(QLatin1String("description"), QVariant(tr("Memory Usage"))); - element.insert(QLatin1String("id"), QVariant(QmlDebug::SmallItem)); - result << element; - - return result; -} - -QVariantMap MemoryUsageModel::details(int index) const -{ - QVariantMap result; - const MemoryAllocation *ev = &m_data[index]; - - if (ev->allocated >= -ev->deallocated) - result.insert(QLatin1String("displayName"), tr("Memory Allocated")); - else - result.insert(QLatin1String("displayName"), tr("Memory Freed")); - - result.insert(tr("Total"), QString::fromLatin1("%1 bytes").arg(ev->size)); - if (ev->allocations > 0) { - result.insert(tr("Allocated"), QString::fromLatin1("%1 bytes").arg(ev->allocated)); - result.insert(tr("Allocations"), QString::number(ev->allocations)); - } - if (ev->deallocations > 0) { - result.insert(tr("Deallocated"), QString::fromLatin1("%1 bytes").arg(-ev->deallocated)); - result.insert(tr("Deallocations"), QString::number(ev->deallocations)); - } - result.insert(tr("Type"), QVariant(memoryTypeName(selectionId(index)))); - - if (ev->originTypeIndex != -1) { - result.insert(tr("Location"), - modelManager()->qmlModel()->getEventTypes().at(ev->originTypeIndex).displayName); - } - return result; -} - -struct RangeStackFrame { - RangeStackFrame() : originTypeIndex(-1), startTime(-1), endTime(-1) {} - RangeStackFrame(int originTypeIndex, qint64 startTime, qint64 endTime) : - originTypeIndex(originTypeIndex), startTime(startTime), endTime(endTime) {} - int originTypeIndex; - qint64 startTime; - qint64 endTime; -}; - -void MemoryUsageModel::loadData() -{ - QmlProfilerDataModel *simpleModel = modelManager()->qmlModel(); - if (simpleModel->isEmpty()) - return; - - qint64 currentSize = 0; - qint64 currentUsage = 0; - int currentUsageIndex = -1; - int currentJSHeapIndex = -1; - - QStack rangeStack; - - const QVector &types = simpleModel->getEventTypes(); - foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) { - const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex()]; - while (!rangeStack.empty() && rangeStack.top().endTime < event.startTime()) - rangeStack.pop(); - if (!accepted(type)) { - if (type.rangeType != QmlDebug::MaximumRangeType) { - rangeStack.push(RangeStackFrame(event.typeIndex(), event.startTime(), - event.startTime() + event.duration())); - } - continue; - } - - if (type.detailType == QmlDebug::SmallItem || type.detailType == QmlDebug::LargeItem) { - if (!rangeStack.empty() && currentUsageIndex > -1 && - type.detailType == selectionId(currentUsageIndex) && - m_data[currentUsageIndex].originTypeIndex == rangeStack.top().originTypeIndex && - rangeStack.top().startTime < startTime(currentUsageIndex)) { - m_data[currentUsageIndex].update(event.numericData(0)); - currentUsage = m_data[currentUsageIndex].size; - } else { - MemoryAllocation allocation(event.typeIndex(), currentUsage, - rangeStack.empty() ? -1 : rangeStack.top().originTypeIndex); - allocation.update(event.numericData(0)); - currentUsage = allocation.size; - - if (currentUsageIndex != -1) { - insertEnd(currentUsageIndex, - event.startTime() - startTime(currentUsageIndex) - 1); - } - currentUsageIndex = insertStart(event.startTime(), QmlDebug::SmallItem); - m_data.insert(currentUsageIndex, allocation); - } - } - - if (type.detailType == QmlDebug::HeapPage || type.detailType == QmlDebug::LargeItem) { - if (!rangeStack.empty() && currentJSHeapIndex > -1 && - type.detailType == selectionId(currentJSHeapIndex) && - m_data[currentJSHeapIndex].originTypeIndex == - rangeStack.top().originTypeIndex && - rangeStack.top().startTime < startTime(currentJSHeapIndex)) { - m_data[currentJSHeapIndex].update(event.numericData(0)); - currentSize = m_data[currentJSHeapIndex].size; - } else { - MemoryAllocation allocation(event.typeIndex(), currentSize, - rangeStack.empty() ? -1 : rangeStack.top().originTypeIndex); - allocation.update(event.numericData(0)); - currentSize = allocation.size; - - if (currentSize > m_maxSize) - m_maxSize = currentSize; - if (currentJSHeapIndex != -1) - insertEnd(currentJSHeapIndex, - event.startTime() - startTime(currentJSHeapIndex) - 1); - currentJSHeapIndex = insertStart(event.startTime(), type.detailType); - m_data.insert(currentJSHeapIndex, allocation); - } - } - - updateProgress(count(), simpleModel->getEvents().count()); - } - - if (currentJSHeapIndex != -1) - insertEnd(currentJSHeapIndex, modelManager()->traceTime()->endTime() - - startTime(currentJSHeapIndex) - 1); - if (currentUsageIndex != -1) - insertEnd(currentUsageIndex, modelManager()->traceTime()->endTime() - - startTime(currentUsageIndex) - 1); - - - computeNesting(); - setExpandedRowCount(3); - setCollapsedRowCount(3); - updateProgress(1, 1); -} - -void MemoryUsageModel::clear() -{ - m_data.clear(); - m_maxSize = 1; - QmlProfilerTimelineModel::clear(); -} - -QString MemoryUsageModel::memoryTypeName(int type) -{ - switch (type) { - case QmlDebug::HeapPage: return tr("Heap Allocation"); - case QmlDebug::LargeItem: return tr("Large Item Allocation"); - case QmlDebug::SmallItem: return tr("Heap Usage"); - case QmlDebug::MaximumMemoryType: return tr("Total"); - default: return tr("Unknown"); - } -} - -MemoryUsageModel::MemoryAllocation::MemoryAllocation(int type, qint64 baseAmount, - int originTypeIndex) : - typeId(type), size(baseAmount), allocated(0), deallocated(0), allocations(0), deallocations(0), - originTypeIndex(originTypeIndex) -{ -} - -void MemoryUsageModel::MemoryAllocation::update(qint64 amount) -{ - size += amount; - if (amount < 0) { - deallocated += amount; - ++deallocations; - } else { - allocated += amount; - ++allocations; - } -} - - -} // namespace Internal -} // namespace QmlProfilerExtension diff --git a/plugins/qmlprofiler/memoryusagemodel.h b/plugins/qmlprofiler/memoryusagemodel.h deleted file mode 100644 index bf7b557afa..0000000000 --- a/plugins/qmlprofiler/memoryusagemodel.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#ifndef MEMORYUSAGEMODEL_H -#define MEMORYUSAGEMODEL_H - -#include "qmlprofiler/qmlprofilertimelinemodel.h" -#include "qmlprofiler/qmlprofilerdatamodel.h" - -#include -#include - -namespace QmlProfilerExtension { -namespace Internal { - -class MemoryUsageModel : public QmlProfiler::QmlProfilerTimelineModel -{ - Q_OBJECT -public: - - struct MemoryAllocation { - int typeId; - qint64 size; - qint64 allocated; - qint64 deallocated; - int allocations; - int deallocations; - int originTypeIndex; - - MemoryAllocation(int typeId = -1, qint64 baseAmount = 0, int originTypeIndex = -1); - void update(qint64 amount); - }; - - MemoryUsageModel(QmlProfiler::QmlProfilerModelManager *manager, QObject *parent = 0); - - int rowMaxValue(int rowNumber) const; - - int expandedRow(int index) const; - int collapsedRow(int index) const; - int typeId(int index) const; - QColor color(int index) const; - float relativeHeight(int index) const; - - QVariantMap location(int index) const; - - QVariantList labels() const; - QVariantMap details(int index) const; - -protected: - void loadData(); - void clear(); - -private: - static QString memoryTypeName(int type); - - QVector m_data; - qint64 m_maxSize; -}; - -} // namespace Internal -} // namespace QmlProfilerExtension - -#endif // MEMORYUSAGEMODEL_H diff --git a/plugins/qmlprofiler/pixmapcachemodel.cpp b/plugins/qmlprofiler/pixmapcachemodel.cpp deleted file mode 100644 index b472fd8449..0000000000 --- a/plugins/qmlprofiler/pixmapcachemodel.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#include "pixmapcachemodel.h" -#include "qmldebug/qmlprofilereventtypes.h" -#include "qmlprofiler/qmlprofilermodelmanager.h" - -namespace QmlProfilerExtension { -namespace Internal { - -using namespace QmlProfiler; - -PixmapCacheModel::PixmapCacheModel(QmlProfilerModelManager *manager, QObject *parent) : - QmlProfilerTimelineModel(manager, QmlDebug::PixmapCacheEvent, QmlDebug::MaximumRangeType, - QmlDebug::ProfilePixmapCache, parent) -{ - m_maxCacheSize = 1; -} - -int PixmapCacheModel::rowMaxValue(int rowNumber) const -{ - if (rowNumber == 1) { - return m_maxCacheSize; - } else { - return QmlProfilerTimelineModel::rowMaxValue(rowNumber); - } -} - -int PixmapCacheModel::expandedRow(int index) const -{ - return selectionId(index) + 1; -} - -int PixmapCacheModel::collapsedRow(int index) const -{ - return m_data[index].rowNumberCollapsed; -} - -int PixmapCacheModel::typeId(int index) const -{ - return m_data[index].typeId; -} - -QColor PixmapCacheModel::color(int index) const -{ - if (m_data[index].pixmapEventType == PixmapCacheCountChanged) - return colorByHue(s_pixmapCacheCountHue); - - return colorBySelectionId(index); -} - -float PixmapCacheModel::relativeHeight(int index) const -{ - if (m_data[index].pixmapEventType == PixmapCacheCountChanged) - return (float)m_data[index].cacheSize / (float)m_maxCacheSize; - else - return 1.0f; -} - -QString getFilenameOnly(QString absUrl) -{ - int characterPos = absUrl.lastIndexOf(QLatin1Char('/'))+1; - if (characterPos < absUrl.length()) - absUrl = absUrl.mid(characterPos); - return absUrl; -} - -QVariantList PixmapCacheModel::labels() const -{ - QVariantList result; - - // Cache Size - QVariantMap element; - element.insert(QLatin1String("description"), QVariant(QLatin1String("Cache Size"))); - - element.insert(QLatin1String("id"), QVariant(0)); - result << element; - - for (int i=0; i < m_pixmaps.count(); i++) { - // Loading - QVariantMap element; - element.insert(QLatin1String("displayName"), m_pixmaps[i].url); - element.insert(QLatin1String("description"), - QVariant(getFilenameOnly(m_pixmaps[i].url))); - - element.insert(QLatin1String("id"), QVariant(i+1)); - result << element; - } - - return result; -} - -QVariantMap PixmapCacheModel::details(int index) const -{ - QVariantMap result; - const PixmapCacheEvent *ev = &m_data[index]; - - if (ev->pixmapEventType == PixmapCacheCountChanged) { - result.insert(QLatin1String("displayName"), tr("Image Cached")); - } else { - if (ev->pixmapEventType == PixmapLoadingStarted) { - result.insert(QLatin1String("displayName"), tr("Image Loaded")); - if (m_pixmaps[ev->urlIndex].sizes[ev->sizeIndex].loadState != Finished) - result.insert(tr("Result"), tr("Load Error")); - } - result.insert(tr("Duration"), QmlProfilerDataModel::formatTime(duration(index))); - } - - result.insert(tr("Cache Size"), QString::fromLatin1("%1 px").arg(ev->cacheSize)); - result.insert(tr("File"), getFilenameOnly(m_pixmaps[ev->urlIndex].url)); - result.insert(tr("Width"), QString::fromLatin1("%1 px") - .arg(m_pixmaps[ev->urlIndex].sizes[ev->sizeIndex].size.width())); - result.insert(tr("Height"), QString::fromLatin1("%1 px") - .arg(m_pixmaps[ev->urlIndex].sizes[ev->sizeIndex].size.height())); - return result; -} - -/* Ultimately there is no way to know which cache entry a given event refers to as long as we only - * receive the pixmap URL from the application. Multiple copies of different sizes may be cached - * for each URL. However, we can apply some heuristics to make the result somewhat plausible by - * using the following assumptions: - * - * - PixmapSizeKnown will happen at most once for every cache entry. - * - PixmapSizeKnown cannot happen for entries with PixmapLoadingError and vice versa. - * - PixmapCacheCountChanged can happen for entries with PixmapLoadingError but doesn't have to. - * - Decreasing PixmapCacheCountChanged events can only happen for entries that have seen an - * increasing PixmapCacheCountChanged (but that may have happened before the trace). - * - PixmapCacheCountChanged can happen before or after PixmapSizeKnown. - * - For every PixmapLoadingFinished or PixmapLoadingError there is exactly one - * PixmapLoadingStarted event, but it may be before the trace. - * - For every PixmapLoadingStarted there is exactly one PixmapLoadingFinished or - * PixmapLoadingError, but it may be after the trace. - * - Decreasing PixmapCacheCountChanged events in the presence of corrupt cache entries are more - * likely to clear those entries than other, correctly loaded ones. - * - Increasing PixmapCacheCountChanged events are more likely to refer to correctly loaded entries - * than to ones with PixmapLoadingError. - * - PixmapLoadingFinished and PixmapLoadingError are more likely to refer to cache entries that - * have seen a PixmapLoadingStarted than to ones that haven't. - * - * For each URL we keep an ordered list of pixmaps possibly being loaded and assign new events to - * the first entry that "fits". If multiple sizes of the same pixmap are being loaded concurrently - * we generally assume that the PixmapLoadingFinished and PixmapLoadingError events occur in the - * order we learn about the existence of these sizes, subject to the above constraints. This is not - * necessarily the order the pixmaps are really loaded but it's the best we can do with the given - * information. If they're loaded sequentially the representation is correct. - */ - -void PixmapCacheModel::loadData() -{ - QmlProfilerDataModel *simpleModel = modelManager()->qmlModel(); - if (simpleModel->isEmpty()) - return; - - int lastCacheSizeEvent = -1; - int cumulatedCount = 0; - - const QVector &types = simpleModel->getEventTypes(); - foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) { - const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex()]; - if (!accepted(type)) - continue; - - PixmapCacheEvent newEvent; - newEvent.pixmapEventType = static_cast(type.detailType); - qint64 pixmapStartTime = event.startTime(); - - newEvent.urlIndex = -1; - for (QVector::const_iterator it(m_pixmaps.cend()); it != m_pixmaps.cbegin();) { - if ((--it)->url == type.location.filename) { - newEvent.urlIndex = it - m_pixmaps.cbegin(); - break; - } - } - - newEvent.sizeIndex = -1; - if (newEvent.urlIndex == -1) { - newEvent.urlIndex = m_pixmaps.count(); - m_pixmaps << Pixmap(type.location.filename); - } - - Pixmap &pixmap = m_pixmaps[newEvent.urlIndex]; - switch (newEvent.pixmapEventType) { - case PixmapSizeKnown: {// pixmap size - // Look for pixmaps for which we don't know the size, yet and which have actually been - // loaded. - for (QVector::iterator i(pixmap.sizes.begin()); - i != pixmap.sizes.end(); ++i) { - if (i->size.isValid() || i->cacheState == Uncacheable || i->cacheState == Corrupt) - continue; - - // We can't have cached it before we knew the size - Q_ASSERT(i->cacheState != Cached); - - i->size.setWidth(event.numericData(0)); - i->size.setHeight(event.numericData(1)); - newEvent.sizeIndex = i - pixmap.sizes.begin(); - break; - } - - if (newEvent.sizeIndex == -1) { - newEvent.sizeIndex = pixmap.sizes.length(); - pixmap.sizes << PixmapState(event.numericData(0), event.numericData(1)); - } - - PixmapState &state = pixmap.sizes[newEvent.sizeIndex]; - if (state.cacheState == ToBeCached) { - lastCacheSizeEvent = updateCacheCount(lastCacheSizeEvent, pixmapStartTime, - state.size.width() * state.size.height(), newEvent, - event.typeIndex()); - state.cacheState = Cached; - } - break; - } - case PixmapCacheCountChanged: {// Cache Size Changed Event - pixmapStartTime = event.startTime() + 1; // delay 1 ns for proper sorting - - bool uncache = cumulatedCount > event.numericData(2); - cumulatedCount = event.numericData(2); - qint64 pixSize = 0; - - // First try to find a preferred pixmap, which either is Corrupt and will be uncached - // or is uncached and will be cached. - for (QVector::iterator i(pixmap.sizes.begin()); - i != pixmap.sizes.end(); ++i) { - if (uncache && i->cacheState == Corrupt) { - newEvent.sizeIndex = i - pixmap.sizes.begin(); - i->cacheState = Uncacheable; - break; - } else if (!uncache && i->cacheState == Uncached) { - newEvent.sizeIndex = i - pixmap.sizes.begin(); - if (i->size.isValid()) { - pixSize = i->size.width() * i->size.height(); - i->cacheState = Cached; - } else { - i->cacheState = ToBeCached; - } - break; - } - } - - // If none found, check for cached or ToBeCached pixmaps that shall be uncached or - // Error pixmaps that become corrupt cache entries. We also accept Initial to be - // uncached as we may have missed the matching PixmapCacheCountChanged that cached it. - if (newEvent.sizeIndex == -1) { - for (QVector::iterator i(pixmap.sizes.begin()); - i != pixmap.sizes.end(); ++i) { - if (uncache && (i->cacheState == Cached || i->cacheState == ToBeCached || - i->cacheState == Uncached)) { - newEvent.sizeIndex = i - pixmap.sizes.begin(); - if (i->size.isValid()) - pixSize = -i->size.width() * i->size.height(); - i->cacheState = Uncached; - break; - } else if (!uncache && i->cacheState == Uncacheable) { - newEvent.sizeIndex = i - pixmap.sizes.begin(); - i->cacheState = Corrupt; - break; - } - } - } - - // If that does't work, create a new entry. - if (newEvent.sizeIndex == -1) { - newEvent.sizeIndex = pixmap.sizes.length(); - pixmap.sizes << PixmapState(uncache ? Uncached : ToBeCached); - } - - lastCacheSizeEvent = updateCacheCount(lastCacheSizeEvent, pixmapStartTime, pixSize, - newEvent, event.typeIndex()); - break; - } - case PixmapLoadingStarted: { // Load - // Look for a pixmap that hasn't been started, yet. There may have been a refcount - // event, which we ignore. - for (QVector::const_iterator i(pixmap.sizes.cbegin()); - i != pixmap.sizes.cend(); ++i) { - if (i->loadState == Initial) { - newEvent.sizeIndex = i - pixmap.sizes.cbegin(); - break; - } - } - if (newEvent.sizeIndex == -1) { - newEvent.sizeIndex = pixmap.sizes.length(); - pixmap.sizes << PixmapState(); - } - - PixmapState &state = pixmap.sizes[newEvent.sizeIndex]; - state.loadState = Loading; - newEvent.typeId = event.typeIndex(); - state.started = insertStart(pixmapStartTime, newEvent.urlIndex + 1); - m_data.insert(state.started, newEvent); - break; - } - case PixmapLoadingFinished: - case PixmapLoadingError: { - // First try to find one that has already started - for (QVector::const_iterator i(pixmap.sizes.cbegin()); - i != pixmap.sizes.cend(); ++i) { - if (i->loadState != Loading) - continue; - // Pixmaps with known size cannot be errors and vice versa - if (newEvent.pixmapEventType == PixmapLoadingError && i->size.isValid()) - continue; - - newEvent.sizeIndex = i - pixmap.sizes.cbegin(); - break; - } - - // If none was found use any other compatible one - if (newEvent.sizeIndex == -1) { - for (QVector::const_iterator i(pixmap.sizes.cbegin()); - i != pixmap.sizes.cend(); ++i) { - if (i->loadState != Initial) - continue; - // Pixmaps with known size cannot be errors and vice versa - if (newEvent.pixmapEventType == PixmapLoadingError && i->size.isValid()) - continue; - - newEvent.sizeIndex = i - pixmap.sizes.cbegin(); - break; - } - } - - // If again none was found, create one. - if (newEvent.sizeIndex == -1) { - newEvent.sizeIndex = pixmap.sizes.length(); - pixmap.sizes << PixmapState(); - } - - PixmapState &state = pixmap.sizes[newEvent.sizeIndex]; - // If the pixmap loading wasn't started, start it at traceStartTime() - if (state.loadState == Initial) { - newEvent.pixmapEventType = PixmapLoadingStarted; - newEvent.typeId = event.typeIndex(); - qint64 traceStart = modelManager()->traceTime()->startTime(); - state.started = insert(traceStart, pixmapStartTime - traceStart, - newEvent.urlIndex + 1); - m_data.insert(state.started, newEvent); - - // All other indices are wrong now as we've prepended. Fix them ... - if (lastCacheSizeEvent >= state.started) - ++lastCacheSizeEvent; - - for (int pixmapIndex = 0; pixmapIndex < m_pixmaps.count(); ++pixmapIndex) { - Pixmap &brokenPixmap = m_pixmaps[pixmapIndex]; - for (int sizeIndex = 0; sizeIndex < brokenPixmap.sizes.count(); ++sizeIndex) { - PixmapState &brokenSize = brokenPixmap.sizes[sizeIndex]; - if ((pixmapIndex != newEvent.urlIndex || sizeIndex != newEvent.sizeIndex) && - brokenSize.started >= state.started) { - ++brokenSize.started; - } - } - } - } - - insertEnd(state.started, pixmapStartTime - startTime(state.started)); - if (newEvent.pixmapEventType == PixmapLoadingError) { - state.loadState = Error; - switch (state.cacheState) { - case Uncached: - state.cacheState = Uncacheable; - break; - case ToBeCached: - state.cacheState = Corrupt; - break; - default: - // Cached cannot happen as size would have to be known and Corrupt or - // Uncacheable cannot happen as we only accept one finish or error event per - // pixmap. - Q_ASSERT(false); - } - } else { - state.loadState = Finished; - } - break; - } - default: - break; - } - - updateProgress(count(), 2 * simpleModel->getEvents().count()); - } - - if (lastCacheSizeEvent != -1) - insertEnd(lastCacheSizeEvent, modelManager()->traceTime()->endTime() - - startTime(lastCacheSizeEvent)); - - resizeUnfinishedLoads(); - - computeMaxCacheSize(); - flattenLoads(); - computeNesting(); - - updateProgress(1, 1); -} - -void PixmapCacheModel::clear() -{ - m_pixmaps.clear(); - m_maxCacheSize = 1; - m_data.clear(); - QmlProfilerTimelineModel::clear(); -} - -void PixmapCacheModel::computeMaxCacheSize() -{ - m_maxCacheSize = 1; - foreach (const PixmapCacheModel::PixmapCacheEvent &event, m_data) { - if (event.pixmapEventType == PixmapCacheModel::PixmapCacheCountChanged) { - if (event.cacheSize > m_maxCacheSize) - m_maxCacheSize = event.cacheSize; - } - } -} - -void PixmapCacheModel::resizeUnfinishedLoads() -{ - // all the "load start" events with duration 0 continue till the end of the trace - for (int i = 0; i < count(); i++) { - if (m_data[i].pixmapEventType == PixmapCacheModel::PixmapLoadingStarted && - duration(i) == 0) { - insertEnd(i, modelManager()->traceTime()->endTime() - startTime(i)); - } - } -} - -void PixmapCacheModel::flattenLoads() -{ - int collapsedRowCount = 0; - - // computes "compressed row" - QVector eventEndTimes; - for (int i = 0; i < count(); i++) { - PixmapCacheModel::PixmapCacheEvent &event = m_data[i]; - if (event.pixmapEventType == PixmapCacheModel::PixmapLoadingStarted) { - event.rowNumberCollapsed = 0; - while (eventEndTimes.count() > event.rowNumberCollapsed && - eventEndTimes[event.rowNumberCollapsed] > startTime(i)) - event.rowNumberCollapsed++; - - if (eventEndTimes.count() == event.rowNumberCollapsed) - eventEndTimes << 0; // increase stack length, proper value added below - eventEndTimes[event.rowNumberCollapsed] = endTime(i); - - // readjust to account for category empty row and bargraph - event.rowNumberCollapsed += 2; - } - if (event.rowNumberCollapsed > collapsedRowCount) - collapsedRowCount = event.rowNumberCollapsed; - } - - // Starting from 0, count is maxIndex+1 - setCollapsedRowCount(collapsedRowCount + 1); - setExpandedRowCount(m_pixmaps.count() + 2); -} - -int PixmapCacheModel::updateCacheCount(int lastCacheSizeEvent, - qint64 pixmapStartTime, qint64 pixSize, PixmapCacheEvent &newEvent, int typeId) -{ - newEvent.pixmapEventType = PixmapCacheCountChanged; - newEvent.rowNumberCollapsed = 1; - - qint64 prevSize = 0; - if (lastCacheSizeEvent != -1) { - prevSize = m_data[lastCacheSizeEvent].cacheSize; - insertEnd(lastCacheSizeEvent, pixmapStartTime - startTime(lastCacheSizeEvent)); - } - - newEvent.cacheSize = prevSize + pixSize; - newEvent.typeId = typeId; - int index = insertStart(pixmapStartTime, 0); - m_data.insert(index, newEvent); - return index; -} - - -} // namespace Internal -} // namespace QmlProfilerExtension diff --git a/plugins/qmlprofiler/pixmapcachemodel.h b/plugins/qmlprofiler/pixmapcachemodel.h deleted file mode 100644 index 4d9fac2763..0000000000 --- a/plugins/qmlprofiler/pixmapcachemodel.h +++ /dev/null @@ -1,130 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#ifndef PIXMAPCACHEMODEL_H -#define PIXMAPCACHEMODEL_H - -#include "qmlprofiler/qmlprofilertimelinemodel.h" -#include "qmlprofiler/qmlprofilerdatamodel.h" - -#include -#include -#include - -namespace QmlProfilerExtension { -namespace Internal { - -class PixmapCacheModel : public QmlProfiler::QmlProfilerTimelineModel -{ - Q_OBJECT -public: - enum CacheState { - Uncached, // After loading started (or some other proof of existence) or after uncaching - ToBeCached, // After determining the pixmap is to be cached but before knowing its size - Cached, // After caching a pixmap or determining the size of a ToBeCached pixmap - Uncacheable, // If loading failed without ToBeCached or after a corrupt pixmap has been uncached - Corrupt // If after ToBeCached we learn that loading failed - }; - - enum LoadState { - Initial, - Loading, - Finished, - Error - }; - - struct PixmapState { - PixmapState(int width, int height, CacheState cache = Uncached) : - size(width, height), started(-1), loadState(Initial), cacheState(cache) {} - PixmapState(CacheState cache = Uncached) : started(-1), loadState(Initial), cacheState(cache) {} - QSize size; - int started; - LoadState loadState; - CacheState cacheState; - }; - - struct Pixmap { - Pixmap() {} - Pixmap(const QString &url) : url(url), sizes(1) {} - QString url; - QVector sizes; - }; - - enum PixmapEventType { - PixmapSizeKnown, - PixmapReferenceCountChanged, - PixmapCacheCountChanged, - PixmapLoadingStarted, - PixmapLoadingFinished, - PixmapLoadingError, - - MaximumPixmapEventType - }; - - struct PixmapCacheEvent { - int typeId; - PixmapEventType pixmapEventType; - int urlIndex; - int sizeIndex; - int rowNumberCollapsed; - qint64 cacheSize; - }; - - PixmapCacheModel(QmlProfiler::QmlProfilerModelManager *manager, QObject *parent = 0); - - int rowMaxValue(int rowNumber) const; - - int expandedRow(int index) const; - int collapsedRow(int index) const; - int typeId(int index) const; - QColor color(int index) const; - float relativeHeight(int index) const; - - QVariantList labels() const; - - QVariantMap details(int index) const; - -protected: - void loadData(); - void clear(); - -private: - void computeMaxCacheSize(); - void resizeUnfinishedLoads(); - void flattenLoads(); - int updateCacheCount(int lastCacheSizeEvent, qint64 startTime, qint64 pixSize, - PixmapCacheEvent &newEvent, int typeId); - - QVector m_data; - QVector m_pixmaps; - qint64 m_maxCacheSize; - - static const int s_pixmapCacheCountHue = 240; -}; - -} // namespace Internal -} // namespace QmlProfilerExtension - -#endif // PIXMAPCACHEMODEL_H diff --git a/plugins/qmlprofiler/qmlprofiler.pro b/plugins/qmlprofiler/qmlprofiler.pro deleted file mode 100644 index bf1e7f57ff..0000000000 --- a/plugins/qmlprofiler/qmlprofiler.pro +++ /dev/null @@ -1,38 +0,0 @@ -TARGET = QmlProfilerExtension -TEMPLATE = lib - -include(../../qtcreatorplugin.pri) - -QT += qml quick quickwidgets - -DEFINES += QMLPROFILEREXTENSION_LIBRARY - -# QmlProfilerExtension files - -SOURCES += qmlprofilerextensionplugin.cpp \ - scenegraphtimelinemodel.cpp \ - pixmapcachemodel.cpp \ - memoryusagemodel.cpp \ - inputeventsmodel.cpp \ - debugmessagesmodel.cpp \ - flamegraphmodel.cpp \ - flamegraphview.cpp \ - flamegraph.cpp - -HEADERS += qmlprofilerextensionplugin.h \ - qmlprofilerextension_global.h \ - qmlprofilerextensionconstants.h \ - scenegraphtimelinemodel.h \ - pixmapcachemodel.h \ - memoryusagemodel.h \ - inputeventsmodel.h \ - debugmessagesmodel.h \ - flamegraphmodel.h \ - flamegraphview.h \ - flamegraph.h - -OTHER_FILES += \ - QmlProfilerExtension.json.in - -RESOURCES += \ - flamegraph.qrc diff --git a/plugins/qmlprofiler/qmlprofiler.qbs b/plugins/qmlprofiler/qmlprofiler.qbs deleted file mode 100644 index 7196e64884..0000000000 --- a/plugins/qmlprofiler/qmlprofiler.qbs +++ /dev/null @@ -1,36 +0,0 @@ -import qbs - -QtcCommercialPlugin { - name: "QmlProfilerExtension" - - Depends { name: "Core" } - Depends { name: "QmlProfiler" } - Depends { name: "Timeline" } - - Depends { name: "Qt.quickwidgets" } - Depends { name: "Qt.widgets" } - - files: [ - "debugmessagesmodel.cpp", - "debugmessagesmodel.h", - "flamegraph.cpp", - "flamegraph.h", - "flamegraph.qrc", - "flamegraphmodel.cpp", - "flamegraphmodel.h", - "flamegraphview.cpp", - "flamegraphview.h", - "inputeventsmodel.cpp", - "inputeventsmodel.h", - "memoryusagemodel.cpp", - "memoryusagemodel.h", - "pixmapcachemodel.cpp", - "pixmapcachemodel.h", - "qmlprofilerextensionconstants.h", - "qmlprofilerextensionplugin.cpp", - "qmlprofilerextensionplugin.h", - "qmlprofilerextension_global.h", - "scenegraphtimelinemodel.cpp", - "scenegraphtimelinemodel.h", - ] -} diff --git a/plugins/qmlprofiler/qmlprofiler_dependencies.pri b/plugins/qmlprofiler/qmlprofiler_dependencies.pri deleted file mode 100644 index 638fd4c0c0..0000000000 --- a/plugins/qmlprofiler/qmlprofiler_dependencies.pri +++ /dev/null @@ -1,4 +0,0 @@ -QTC_PLUGIN_NAME = QmlProfilerExtension -QTC_PLUGIN_DEPENDS += \ - qmlprofiler - diff --git a/plugins/qmlprofiler/qmlprofilerextension_global.h b/plugins/qmlprofiler/qmlprofilerextension_global.h deleted file mode 100644 index a8faba9971..0000000000 --- a/plugins/qmlprofiler/qmlprofilerextension_global.h +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#ifndef QMLPROFILEREXTENSION_GLOBAL_H -#define QMLPROFILEREXTENSION_GLOBAL_H - -#include - -#if defined(QMLPROFILEREXTENSION_LIBRARY) -# define QMLPROFILEREXTENSIONSHARED_EXPORT Q_DECL_EXPORT -#else -# define QMLPROFILEREXTENSIONSHARED_EXPORT Q_DECL_IMPORT -#endif - -#endif // QMLPROFILEREXTENSION_GLOBAL_H - diff --git a/plugins/qmlprofiler/qmlprofilerextensionconstants.h b/plugins/qmlprofiler/qmlprofilerextensionconstants.h deleted file mode 100644 index e7c730c9d5..0000000000 --- a/plugins/qmlprofiler/qmlprofilerextensionconstants.h +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#ifndef QMLPROFILEREXTENSIONCONSTANTS_H -#define QMLPROFILEREXTENSIONCONSTANTS_H - -namespace QmlProfilerExtension { -namespace Constants { - -const char ACTION_ID[] = "QmlProfilerExtension.Action"; -const char MENU_ID[] = "QmlProfilerExtension.Menu"; - -} // namespace QmlProfilerExtension -} // namespace Constants - -#endif // QMLPROFILEREXTENSIONCONSTANTS_H - diff --git a/plugins/qmlprofiler/qmlprofilerextensionplugin.cpp b/plugins/qmlprofiler/qmlprofilerextensionplugin.cpp deleted file mode 100644 index 05c7ac9b9e..0000000000 --- a/plugins/qmlprofiler/qmlprofilerextensionplugin.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#include "qmlprofilerextensionplugin.h" -#include "qmlprofilerextensionconstants.h" -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include - -#include "scenegraphtimelinemodel.h" -#include "pixmapcachemodel.h" -#include "memoryusagemodel.h" -#include "inputeventsmodel.h" -#include "debugmessagesmodel.h" -#include "flamegraphview.h" - -using namespace QmlProfilerExtension::Internal; - -class ModelFactory : public QmlProfiler::QmlProfilerTimelineModelFactory { - Q_OBJECT -public: - QList create( - QmlProfiler::QmlProfilerModelManager *manager) - { - QList models; - models << new PixmapCacheModel(manager, this) - << new SceneGraphTimelineModel(manager, this) - << new MemoryUsageModel(manager, this) - << new InputEventsModel(manager, this) - << new DebugMessagesModel(manager, this); - return models; - } -}; - -class ViewFactory : public QmlProfiler::QmlProfilerEventsViewFactory { - Q_OBJECT -public: - QList create( - QWidget *parent, QmlProfiler::QmlProfilerModelManager *manager) override - { - QList views; - views << new FlameGraphView(parent, manager); - return views; - } -}; - -QmlProfilerExtensionPlugin::QmlProfilerExtensionPlugin() -{ - // Create your members -} - -QmlProfilerExtensionPlugin::~QmlProfilerExtensionPlugin() -{ - // Unregister objects from the plugin manager's object pool - // Delete members -} - -bool QmlProfilerExtensionPlugin::initialize(const QStringList &arguments, QString *errorString) -{ - // Register objects in the plugin manager's object pool - // Load settings - // Add actions to menus - // Connect to other plugins' signals - // In the initialize method, a plugin can be sure that the plugins it - // depends on have initialized their members. - - Q_UNUSED(arguments) - Q_UNUSED(errorString) - - addAutoReleasedObject(new ModelFactory); - addAutoReleasedObject(new ViewFactory); - - return true; -} - -void QmlProfilerExtensionPlugin::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. -} - -ExtensionSystem::IPlugin::ShutdownFlag QmlProfilerExtensionPlugin::aboutToShutdown() -{ - // Save settings - // Disconnect from signals that are not needed during shutdown - // Hide UI (if you add UI that is not in the main window directly) - return SynchronousShutdown; -} - -void QmlProfilerExtensionPlugin::triggerAction() -{ - QMessageBox::information(Core::ICore::mainWindow(), - tr("Action triggered"), - tr("This is an action from QmlProfilerExtension.")); -} - -#include "qmlprofilerextensionplugin.moc" diff --git a/plugins/qmlprofiler/qmlprofilerextensionplugin.h b/plugins/qmlprofiler/qmlprofilerextensionplugin.h deleted file mode 100644 index 63571cde69..0000000000 --- a/plugins/qmlprofiler/qmlprofilerextensionplugin.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#ifndef QMLPROFILEREXTENSION_H -#define QMLPROFILEREXTENSION_H - -#include "qmlprofilerextension_global.h" - -#include - -namespace QmlProfilerExtension { -namespace Internal { - -class QmlProfilerExtensionPlugin : public ExtensionSystem::IPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "QmlProfilerExtension.json") - -public: - QmlProfilerExtensionPlugin(); - ~QmlProfilerExtensionPlugin(); - - bool initialize(const QStringList &arguments, QString *errorString); - void extensionsInitialized(); - ShutdownFlag aboutToShutdown(); - -private slots: - void triggerAction(); -}; - -} // namespace Internal -} // namespace QmlProfilerExtension - -#endif // QMLPROFILEREXTENSION_H - diff --git a/plugins/qmlprofiler/scenegraphtimelinemodel.cpp b/plugins/qmlprofiler/scenegraphtimelinemodel.cpp deleted file mode 100644 index cb61bbf07e..0000000000 --- a/plugins/qmlprofiler/scenegraphtimelinemodel.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#include "scenegraphtimelinemodel.h" -#include "qmldebug/qmlprofilereventtypes.h" -#include "qmlprofiler/qmlprofilermodelmanager.h" - -#include -#include - -namespace QmlProfilerExtension { -namespace Internal { - -using namespace QmlProfiler; - -static const char *ThreadLabels[] = { - QT_TRANSLATE_NOOP("MainView", "GUI Thread"), - QT_TRANSLATE_NOOP("MainView", "Render Thread"), - QT_TRANSLATE_NOOP("MainView", "Render Thread Details") -}; - -static const char *StageLabels[] = { - QT_TRANSLATE_NOOP("MainView", "Polish"), - QT_TRANSLATE_NOOP("MainView", "Wait"), - QT_TRANSLATE_NOOP("MainView", "GUI Thread Sync"), - QT_TRANSLATE_NOOP("MainView", "Animations"), - QT_TRANSLATE_NOOP("MainView", "Render Thread Sync"), - QT_TRANSLATE_NOOP("MainView", "Render"), - QT_TRANSLATE_NOOP("MainView", "Swap"), - QT_TRANSLATE_NOOP("MainView", "Render Preprocess"), - QT_TRANSLATE_NOOP("MainView", "Render Update"), - QT_TRANSLATE_NOOP("MainView", "Render Bind"), - QT_TRANSLATE_NOOP("MainView", "Render Render"), - QT_TRANSLATE_NOOP("MainView", "Material Compile"), - QT_TRANSLATE_NOOP("MainView", "Glyph Render"), - QT_TRANSLATE_NOOP("MainView", "Glyph Upload"), - QT_TRANSLATE_NOOP("MainView", "Texture Bind"), - QT_TRANSLATE_NOOP("MainView", "Texture Convert"), - QT_TRANSLATE_NOOP("MainView", "Texture Swizzle"), - QT_TRANSLATE_NOOP("MainView", "Texture Upload"), - QT_TRANSLATE_NOOP("MainView", "Texture Mipmap"), - QT_TRANSLATE_NOOP("MainView", "Texture Delete") -}; - -enum SceneGraphCategoryType { - SceneGraphGUIThread, - SceneGraphRenderThread, - SceneGraphRenderThreadDetails, - - MaximumSceneGraphCategoryType -}; - -Q_STATIC_ASSERT(sizeof(StageLabels) == - SceneGraphTimelineModel::MaximumSceneGraphStage * sizeof(const char *)); - -SceneGraphTimelineModel::SceneGraphTimelineModel(QmlProfilerModelManager *manager, - QObject *parent) : - QmlProfilerTimelineModel(manager, QmlDebug::SceneGraphFrame, QmlDebug::MaximumRangeType, - QmlDebug::ProfileSceneGraph, parent) -{ -} - -int SceneGraphTimelineModel::expandedRow(int index) const -{ - return selectionId(index) + 1; -} - -int SceneGraphTimelineModel::collapsedRow(int index) const -{ - return m_data[index].rowNumberCollapsed; -} - -int SceneGraphTimelineModel::typeId(int index) const -{ - return m_data[index].typeId; -} - -QColor SceneGraphTimelineModel::color(int index) const -{ - return colorBySelectionId(index); -} - -QVariantList SceneGraphTimelineModel::labels() const -{ - QVariantList result; - - for (SceneGraphStage i = MinimumSceneGraphStage; i < MaximumSceneGraphStage; - i = static_cast(i + 1)) { - QVariantMap element; - element.insert(QLatin1String("displayName"), tr(threadLabel(i))); - element.insert(QLatin1String("description"), tr(StageLabels[i])); - element.insert(QLatin1String("id"), i); - result << element; - } - - return result; -} - -QVariantMap SceneGraphTimelineModel::details(int index) const -{ - QVariantMap result; - const SceneGraphStage stage = static_cast(selectionId(index)); - - result.insert(QLatin1String("displayName"), tr(threadLabel(stage))); - result.insert(tr("Stage"), tr(StageLabels[stage])); - result.insert(tr("Duration"), QmlProfilerDataModel::formatTime(duration(index))); - - const int glyphCount = m_data[index].glyphCount; - if (glyphCount >= 0) - result.insert(tr("Glyphs"), QString::number(glyphCount)); - - return result; -} - -void SceneGraphTimelineModel::loadData() -{ - QmlProfilerDataModel *simpleModel = modelManager()->qmlModel(); - if (simpleModel->isEmpty()) - return; - - // combine the data of several eventtypes into two rows - const QVector &types = simpleModel->getEventTypes(); - foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) { - const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex()]; - if (!accepted(type)) - continue; - - switch ((QmlDebug::SceneGraphFrameType)type.detailType) { - case QmlDebug::SceneGraphRendererFrame: { - // Breakdown of render times. We repeat "render" here as "net" render time. It would - // look incomplete if that was left out as the printf profiler lists it, too, and people - // are apparently comparing that. Unfortunately it is somewhat redundant as the other - // parts of the breakdown are usually very short. - qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) - - event.numericData(2) - event.numericData(3); - startTime += insert(startTime, event.numericData(0), event.typeIndex(), RenderPreprocess); - startTime += insert(startTime, event.numericData(1), event.typeIndex(), RenderUpdate); - startTime += insert(startTime, event.numericData(2), event.typeIndex(), RenderBind); - insert(startTime, event.numericData(3), event.typeIndex(), RenderRender); - break; - } - case QmlDebug::SceneGraphAdaptationLayerFrame: { - qint64 startTime = event.startTime() - event.numericData(1) - event.numericData(2); - startTime += insert(startTime, event.numericData(1), event.typeIndex(), GlyphRender, - event.numericData(0)); - insert(startTime, event.numericData(2), event.typeIndex(), GlyphStore, event.numericData(0)); - break; - } - case QmlDebug::SceneGraphContextFrame: { - insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(), - Material); - break; - } - case QmlDebug::SceneGraphRenderLoopFrame: { - qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) - - event.numericData(2); - startTime += insert(startTime, event.numericData(0), event.typeIndex(), - RenderThreadSync); - startTime += insert(startTime, event.numericData(1), event.typeIndex(), - Render); - insert(startTime, event.numericData(2), event.typeIndex(), Swap); - break; - } - case QmlDebug::SceneGraphTexturePrepare: { - qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) - - event.numericData(2) - event.numericData(3) - event.numericData(4); - startTime += insert(startTime, event.numericData(0), event.typeIndex(), TextureBind); - startTime += insert(startTime, event.numericData(1), event.typeIndex(), TextureConvert); - startTime += insert(startTime, event.numericData(2), event.typeIndex(), TextureSwizzle); - startTime += insert(startTime, event.numericData(3), event.typeIndex(), TextureUpload); - insert(startTime, event.numericData(4), event.typeIndex(), TextureMipmap); - break; - } - case QmlDebug::SceneGraphTextureDeletion: { - insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(), - TextureDeletion); - break; - } - case QmlDebug::SceneGraphPolishAndSync: { - qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) - - event.numericData(2) - event.numericData(3); - - startTime += insert(startTime, event.numericData(0), event.typeIndex(), Polish); - startTime += insert(startTime, event.numericData(1), event.typeIndex(), Wait); - startTime += insert(startTime, event.numericData(2), event.typeIndex(), GUIThreadSync); - insert(startTime, event.numericData(3), event.typeIndex(), Animations); - break; - } - case QmlDebug::SceneGraphWindowsAnimations: { - // GUI thread, separate animations stage - insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(), - Animations); - break; - } - case QmlDebug::SceneGraphPolishFrame: { - // GUI thread, separate polish stage - insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(), - Polish); - break; - } - default: break; - } - - updateProgress(count(), simpleModel->getEvents().count()); - } - - computeNesting(); - flattenLoads(); - updateProgress(1, 1); -} - -void SceneGraphTimelineModel::flattenLoads() -{ - int collapsedRowCount = 0; - - // computes "compressed row" - QVector eventEndTimes; - - for (int i = 0; i < count(); i++) { - SceneGraphEvent &event = m_data[i]; - int stage = selectionId(i); - // Don't try to put render thread events in GUI row and vice versa. - // Rows below those are free for all. - if (stage < MaximumGUIThreadStage) - event.rowNumberCollapsed = SceneGraphGUIThread; - else if (stage < MaximumRenderThreadStage) - event.rowNumberCollapsed = SceneGraphRenderThread; - else - event.rowNumberCollapsed = SceneGraphRenderThreadDetails; - - while (eventEndTimes.count() > event.rowNumberCollapsed && - eventEndTimes[event.rowNumberCollapsed] > startTime(i)) - ++event.rowNumberCollapsed; - - while (eventEndTimes.count() <= event.rowNumberCollapsed) - eventEndTimes << 0; // increase stack length, proper value added below - eventEndTimes[event.rowNumberCollapsed] = endTime(i); - - // readjust to account for category empty row - event.rowNumberCollapsed++; - if (event.rowNumberCollapsed > collapsedRowCount) - collapsedRowCount = event.rowNumberCollapsed; - } - - // Starting from 0, count is maxIndex+1 - setCollapsedRowCount(collapsedRowCount + 1); - setExpandedRowCount(MaximumSceneGraphStage + 1); -} - -/*! - * Inserts an event characterized by \a start time, \a duration, \a typeIndex, \a stage and possibly - * \a glyphCount (if it's a \c GlyphRender or \c GlyphStore event) into the scene graph model if its - * \a duration is greater than 0. Returns \a duration in that case; otherwise returns 0. - */ -qint64 SceneGraphTimelineModel::insert(qint64 start, qint64 duration, int typeIndex, - SceneGraphStage stage, int glyphCount) -{ - if (duration <= 0) - return 0; - - m_data.insert(QmlProfilerTimelineModel::insert(start, duration, stage), - SceneGraphEvent(typeIndex, glyphCount)); - return duration; -} - -const char *SceneGraphTimelineModel::threadLabel(SceneGraphStage stage) -{ - if (stage < MaximumGUIThreadStage) - return ThreadLabels[SceneGraphGUIThread]; - else if (stage < MaximumRenderThreadStage) - return ThreadLabels[SceneGraphRenderThread]; - else - return ThreadLabels[SceneGraphRenderThreadDetails]; - -} - -void SceneGraphTimelineModel::clear() -{ - m_data.clear(); - QmlProfilerTimelineModel::clear(); -} - -SceneGraphTimelineModel::SceneGraphEvent::SceneGraphEvent(int typeId, int glyphCount) : - typeId(typeId), rowNumberCollapsed(-1), glyphCount(glyphCount) -{ -} - -} // namespace Internal -} // namespace QmlProfilerExtension diff --git a/plugins/qmlprofiler/scenegraphtimelinemodel.h b/plugins/qmlprofiler/scenegraphtimelinemodel.h deleted file mode 100644 index 59782769dd..0000000000 --- a/plugins/qmlprofiler/scenegraphtimelinemodel.h +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#ifndef SCENEGRAPHTIMELINEMODEL_H -#define SCENEGRAPHTIMELINEMODEL_H - -#include "qmlprofiler/qmlprofilertimelinemodel.h" -#include "qmlprofiler/qmlprofilermodelmanager.h" -#include "qmlprofiler/qmlprofilerdatamodel.h" - -#include -#include - -namespace QmlProfilerExtension { -namespace Internal { - -class SceneGraphTimelineModel : public QmlProfiler::QmlProfilerTimelineModel -{ - Q_OBJECT -public: - enum SceneGraphStage { - MinimumSceneGraphStage = 0, - Polish = MinimumSceneGraphStage, - Wait, - GUIThreadSync, - Animations, - MaximumGUIThreadStage, - - RenderThreadSync = MaximumGUIThreadStage, - Render, - Swap, - MaximumRenderThreadStage, - - RenderPreprocess = MaximumRenderThreadStage, - RenderUpdate, - RenderBind, - RenderRender, - MaximumRenderStage, - - Material = MaximumRenderStage, - MaximumMaterialStage, - - GlyphRender = MaximumMaterialStage, - GlyphStore, - MaximumGlyphStage, - - TextureBind = MaximumGlyphStage, - TextureConvert, - TextureSwizzle, - TextureUpload, - TextureMipmap, - TextureDeletion, - MaximumTextureStage, - - MaximumSceneGraphStage = MaximumTextureStage - }; - - struct SceneGraphEvent { - SceneGraphEvent(int typeId = -1, int glyphCount = -1); - int typeId; - int rowNumberCollapsed; - int glyphCount; // only used for one event type - }; - - SceneGraphTimelineModel(QmlProfiler::QmlProfilerModelManager *manager, QObject *parent = 0); - - int expandedRow(int index) const; - int collapsedRow(int index) const; - int typeId(int index) const; - QColor color(int index) const; - - QVariantList labels() const; - - QVariantMap details(int index) const; - -protected: - void loadData(); - void clear(); - -private: - void flattenLoads(); - qint64 insert(qint64 start, qint64 duration, int typeIndex, SceneGraphStage stage, - int glyphCount = -1); - static const char *threadLabel(SceneGraphStage stage); - - QVector m_data; -}; - -} // namespace Internal -} // namespace QmlProfilerExtension - -#endif // SCENEGRAPHTIMELINEMODEL_H diff --git a/qmlprofiler.pro b/qmlprofiler.pro deleted file mode 100644 index 4cff3f101a..0000000000 --- a/qmlprofiler.pro +++ /dev/null @@ -1,6 +0,0 @@ -TEMPLATE = subdirs -CONFIG += ordered - -SUBDIRS += plugins/qmlprofiler - -QMAKE_EXTRA_TARGETS = docs install_docs # dummy targets for consistency diff --git a/qtcreatorlibrary.pri b/qtcreatorlibrary.pri deleted file mode 100644 index aa11abf700..0000000000 --- a/qtcreatorlibrary.pri +++ /dev/null @@ -1,7 +0,0 @@ -IDE_SOURCE_TREE=$$(QTC_SOURCE) -IDE_BUILD_TREE=$$(QTC_BUILD) - -isEmpty(IDE_SOURCE_TREE):error(Set QTC_SOURCE environment variable) -isEmpty(IDE_BUILD_TREE):error(Set QTC_BUILD environment variable) - -include($$IDE_SOURCE_TREE/src/qtcreatorlibrary.pri) diff --git a/qtcreatorplugin.pri b/qtcreatorplugin.pri deleted file mode 100644 index 190dbed1c3..0000000000 --- a/qtcreatorplugin.pri +++ /dev/null @@ -1,8 +0,0 @@ -isEmpty(IDE_SOURCE_TREE): IDE_SOURCE_TREE=$$(QTC_SOURCE) -isEmpty(IDE_BUILD_TREE): IDE_BUILD_TREE=$$(QTC_BUILD) - -isEmpty(IDE_SOURCE_TREE):error(Set QTC_SOURCE environment variable) -isEmpty(IDE_BUILD_TREE):error(Set QTC_BUILD environment variable) - -INCLUDEPATH+= $$PWD/plugins -include($$IDE_SOURCE_TREE/src/qtcreatorplugin.pri) diff --git a/src/plugins/qmlprofilerextension/FlameGraphText.qml b/src/plugins/qmlprofilerextension/FlameGraphText.qml new file mode 100644 index 0000000000..a989b39355 --- /dev/null +++ b/src/plugins/qmlprofilerextension/FlameGraphText.qml @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** 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 + +Text { + font.pixelSize: 12 + font.family: "sans-serif" + textFormat: Text.PlainText + renderType: Text.NativeRendering +} + diff --git a/src/plugins/qmlprofilerextension/FlameGraphView.qml b/src/plugins/qmlprofilerextension/FlameGraphView.qml new file mode 100644 index 0000000000..7cb4fb5f5f --- /dev/null +++ b/src/plugins/qmlprofilerextension/FlameGraphView.qml @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** 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 QtQuick.Controls 1.4 +import FlameGraph 1.0 +import FlameGraphModel 1.0 + +ScrollView { + id: root + signal typeSelected(int typeIndex) + signal gotoSourceLocation(string filename, int line, int column) + + property int selectedTypeId: -1 + property int visibleRangeTypes: -1 + + Flickable { + id: flickable + contentHeight: flamegraph.height + boundsBehavior: Flickable.StopAtBounds + + FlameGraph { + property int itemHeight: Math.max(30, flickable.height / depth) + property int level: -1 + property color blue: "blue" + property color blue1: Qt.lighter(blue) + property color blue2: Qt.rgba(0.375, 0, 1, 1) + property color grey1: "#B0B0B0" + property color grey2: "#A0A0A0" + + id: flamegraph + width: parent.width + height: depth * itemHeight + model: flameGraphModel + sizeRole: FlameGraphModel.Duration + sizeThreshold: 0.002 + y: flickable.height > height ? flickable.height - height : 0 + + delegate: Item { + id: flamegraphItem + property int level: parent.level + (rangeTypeVisible ? 1 : 0) + property bool isSelected: flamegraphItem.FlameGraph.data(FlameGraphModel.TypeId) === + root.selectedTypeId + property bool rangeTypeVisible: root.visibleRangeTypes & + (1 << FlameGraph.data(FlameGraphModel.RangeType)) + + Rectangle { + border.color: { + if (flamegraphItem.isSelected) + return flamegraph.blue2; + else if (mouseArea.containsMouse) + return flamegraph.blue1; + else + return flamegraph.grey1 + } + border.width: (mouseArea.containsMouse || flamegraphItem.isSelected) ? 2 : 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 + anchors.fill: parent + anchors.margins: 5 + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: visible ? buildText() : "" + elide: Text.ElideRight + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + + function buildText() { + if (!flamegraphItem.FlameGraph.dataValid) + return ""; + + return flamegraphItem.FlameGraph.data(FlameGraphModel.Details) + " (" + + flamegraphItem.FlameGraph.data(FlameGraphModel.Type) + ", " + + flamegraphItem.FlameGraph.data(FlameGraphModel.TimeInPercent) + "%)"; + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + function printTime(t) + { + if (t <= 0) + return "0"; + if (t < 1000) + return t + " ns"; + t = Math.floor(t / 1000); + if (t < 1000) + return t + " μs"; + if (t < 1e6) + return (t / 1000) + " ms"; + return (t / 1e6) + " s"; + } + + onEntered: { + var model = []; + function addDetail(name, index, format) { + model.push(name + ":"); + model.push(format(flamegraphItem.FlameGraph.data(index))); + } + + function noop(a) { + return a; + } + + function addPercent(a) { + return a + "%"; + } + + if (!flamegraphItem.FlameGraph.dataValid) { + model.push(qsTr("Details") + ":"); + model.push(qsTr("Various Events")); + } else { + addDetail(qsTr("Details"), FlameGraphModel.Details, noop); + addDetail(qsTr("Type"), FlameGraphModel.Type, noop); + addDetail(qsTr("Calls"), FlameGraphModel.CallCount, noop); + addDetail(qsTr("Total Time"), FlameGraphModel.Duration, printTime); + addDetail(qsTr("Mean Time"), FlameGraphModel.TimePerCall, printTime); + addDetail(qsTr("In Percent"), FlameGraphModel.TimeInPercent, + addPercent); + + } + tooltip.model = model; + } + + onExited: { + tooltip.model = []; + } + + onClicked: { + if (flamegraphItem.FlameGraph.dataValid) { + root.typeSelected( + flamegraphItem.FlameGraph.data(FlameGraphModel.TypeId)); + root.gotoSourceLocation( + flamegraphItem.FlameGraph.data(FlameGraphModel.Filename), + flamegraphItem.FlameGraph.data(FlameGraphModel.Line), + flamegraphItem.FlameGraph.data(FlameGraphModel.Column)); + } + } + } + } + + 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 + } + } + + Rectangle { + color: "white" + border.width: 1 + border.color: flamegraph.grey2 + width: tooltip.model.length > 0 ? tooltip.width + 10 : 0 + height: tooltip.model.length > 0 ? tooltip.height + 10 : 0 + y: flickable.contentY + x: anchorRight ? parent.width - width : 0 + property bool anchorRight: true + + Grid { + id: tooltip + anchors.margins: 5 + anchors.top: parent.top + anchors.left: parent.left + spacing: 5 + columns: 2 + property var model: [ qsTr("No data available") ] + + Connections { + target: flameGraphModel + onModelReset: { + tooltip.model = (flameGraphModel.rowCount() === 0) ? + [ qsTr("No data available") ] : []; + } + } + + Repeater { + model: parent.model + FlameGraphText { + text: modelData + font.bold: (index % 2) === 0 + width: Math.min(implicitWidth, 200) + elide: Text.ElideRight + } + } + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onEntered: parent.anchorRight = !parent.anchorRight + } + } + } +} diff --git a/src/plugins/qmlprofilerextension/QmlProfilerExtension.json.in b/src/plugins/qmlprofilerextension/QmlProfilerExtension.json.in new file mode 100644 index 0000000000..19639f4ecb --- /dev/null +++ b/src/plugins/qmlprofilerextension/QmlProfilerExtension.json.in @@ -0,0 +1,19 @@ +{ + \"Name\" : \"QmlProfilerExtension\", + \"Version\" : \"$$QTCREATOR_VERSION\", + \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", + \"Vendor\" : \"The Qt Company Ltd\", + \"Copyright\" : \"(C) 2015 The Qt Company Ltd\", + \"License\" : [ \"Commercial Usage\", + \"\", + \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\", + \"\", + \"GNU General Public License Usage\", + \"\", + \"Alternatively, this plugin may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. 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.\" + ], + \"Category\" : \"Qt Quick\", + \"Description\" : \"Qml Profiler Extension Plugin.\", + \"Url\" : \"http://www.qt.io\", + $$dependencyList +} diff --git a/src/plugins/qmlprofilerextension/debugmessagesmodel.cpp b/src/plugins/qmlprofilerextension/debugmessagesmodel.cpp new file mode 100644 index 0000000000..e0f3ec1c6d --- /dev/null +++ b/src/plugins/qmlprofilerextension/debugmessagesmodel.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "debugmessagesmodel.h" + +using namespace QmlProfiler; + +namespace QmlProfilerExtension { +namespace Internal { + +bool DebugMessagesModel::accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const +{ + return event.message == QmlDebug::DebugMessage; +} + +DebugMessagesModel::DebugMessagesModel(QmlProfilerModelManager *manager, QObject *parent) : + QmlProfilerTimelineModel(manager, QmlDebug::DebugMessage, QmlDebug::MaximumRangeType, + QmlDebug::ProfileDebugMessages, parent), m_maximumMsgType(-1) +{ +} + +int DebugMessagesModel::typeId(int index) const +{ + return m_data[index].typeId; +} + +QColor DebugMessagesModel::color(int index) const +{ + return colorBySelectionId(index); +} + +static const char *messageTypes[] = { + QT_TRANSLATE_NOOP("DebugMessagesModel", "Debug Message"), + QT_TRANSLATE_NOOP("DebugMessagesModel", "Warning Message"), + QT_TRANSLATE_NOOP("DebugMessagesModel", "Critical Message"), + QT_TRANSLATE_NOOP("DebugMessagesModel", "Fatal Message"), + QT_TRANSLATE_NOOP("DebugMessagesModel", "Info Message"), +}; + +QString DebugMessagesModel::messageType(uint i) +{ + return i < sizeof(messageTypes) / sizeof(char *) ? tr(messageTypes[i]) : + tr("Unknown Message %1").arg(i); +} + +QVariantList DebugMessagesModel::labels() const +{ + QVariantList result; + + for (int i = 0; i <= m_maximumMsgType; ++i) { + QVariantMap element; + element.insert(QLatin1String("description"), messageType(i)); + element.insert(QLatin1String("id"), i); + result << element; + } + return result; +} + +QVariantMap DebugMessagesModel::details(int index) const +{ + const QmlProfilerDataModel::QmlEventTypeData &type = + modelManager()->qmlModel()->getEventTypes()[m_data[index].typeId]; + + QVariantMap result; + result.insert(QLatin1String("displayName"), messageType(type.detailType)); + result.insert(tr("Timestamp"), QmlProfilerDataModel::formatTime(startTime(index))); + result.insert(tr("Message"), m_data[index].text); + result.insert(tr("Location"), type.displayName); + return result; +} + +int DebugMessagesModel::expandedRow(int index) const +{ + return selectionId(index) + 1; +} + +int DebugMessagesModel::collapsedRow(int index) const +{ + Q_UNUSED(index); + return 1; +} + +void DebugMessagesModel::loadData() +{ + QmlProfilerDataModel *simpleModel = modelManager()->qmlModel(); + if (simpleModel->isEmpty()) + return; + + const QVector &types = simpleModel->getEventTypes(); + + foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) { + const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex()]; + if (!accepted(type) || event.startTime() < 0) + continue; + + m_data.insert(insert(event.startTime(), 0, type.detailType), + MessageData(event.stringData(), event.typeIndex())); + if (type.detailType > m_maximumMsgType) + m_maximumMsgType = event.typeIndex(); + updateProgress(count(), simpleModel->getEvents().count()); + } + setCollapsedRowCount(2); + setExpandedRowCount(m_maximumMsgType + 2); + updateProgress(1, 1); +} + +void DebugMessagesModel::clear() +{ + m_data.clear(); + m_maximumMsgType = -1; + QmlProfilerTimelineModel::clear(); +} + +QVariantMap DebugMessagesModel::location(int index) const +{ + return locationFromTypeId(index); +} + +} +} diff --git a/src/plugins/qmlprofilerextension/debugmessagesmodel.h b/src/plugins/qmlprofilerextension/debugmessagesmodel.h new file mode 100644 index 0000000000..e5934e204d --- /dev/null +++ b/src/plugins/qmlprofilerextension/debugmessagesmodel.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef DEBUGMESSAGESMODEL_H +#define DEBUGMESSAGESMODEL_H + +#include "qmlprofiler/qmlprofilertimelinemodel.h" + +namespace QmlProfilerExtension { +namespace Internal { + +class DebugMessagesModel : public QmlProfiler::QmlProfilerTimelineModel +{ + Q_OBJECT + +protected: + bool accepted(const QmlProfiler::QmlProfilerDataModel::QmlEventTypeData &event) const override; + +public: + DebugMessagesModel(QmlProfiler::QmlProfilerModelManager *manager, QObject *parent = 0); + + int typeId(int index) const override; + QColor color(int index) const override; + QVariantList labels() const override; + QVariantMap details(int index) const override; + int expandedRow(int index) const override; + int collapsedRow(int index) const override; + void loadData() override; + void clear() override; + QVariantMap location(int index) const override; + +private: + static QString messageType(uint i); + + struct MessageData { + MessageData(const QString &text = QString(), int typeId = -1) : + text(text), typeId(typeId) {} + QString text; + int typeId; + }; + + int m_maximumMsgType; + QVector m_data; +}; + +} +} + +#endif // DEBUGMESSAGESMODEL_H diff --git a/src/plugins/qmlprofilerextension/flamegraph.cpp b/src/plugins/qmlprofilerextension/flamegraph.cpp new file mode 100644 index 0000000000..e2b8501bce --- /dev/null +++ b/src/plugins/qmlprofilerextension/flamegraph.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "flamegraph.h" + +namespace QmlProfilerExtension { +namespace Internal { + +FlameGraph::FlameGraph(QQuickItem *parent) : + QQuickItem(parent), m_delegate(0), m_model(0), m_depth(0), m_sizeThreshold(0) +{ +} + +QQmlComponent *FlameGraph::delegate() const +{ + return m_delegate; +} + +void FlameGraph::setDelegate(QQmlComponent *delegate) +{ + if (delegate != m_delegate) { + m_delegate = delegate; + emit delegateChanged(delegate); + } +} + +QAbstractItemModel *FlameGraph::model() const +{ + return m_model; +} + +void FlameGraph::setModel(QAbstractItemModel *model) +{ + if (model != m_model) { + if (m_model) + disconnect(m_model, &QAbstractItemModel::modelReset, this, &FlameGraph::rebuild); + + m_model = model; + connect(m_model, &QAbstractItemModel::modelReset, this, &FlameGraph::rebuild); + emit modelChanged(model); + rebuild(); + } +} + +int FlameGraph::sizeRole() const +{ + return m_sizeRole; +} + +void FlameGraph::setSizeRole(int sizeRole) +{ + if (sizeRole != m_sizeRole) { + m_sizeRole = sizeRole; + emit sizeRoleChanged(sizeRole); + rebuild(); + } +} + +qreal FlameGraph::sizeThreshold() const +{ + return m_sizeThreshold; +} + +void FlameGraph::setSizeThreshold(qreal sizeThreshold) +{ + if (sizeThreshold != m_sizeThreshold) { + m_sizeThreshold = sizeThreshold; + emit sizeThresholdChanged(sizeThreshold); + rebuild(); + } +} + +int FlameGraph::depth() const +{ + return m_depth; +} + +FlameGraphAttached *FlameGraph::qmlAttachedProperties(QObject *object) +{ + FlameGraphAttached *attached = + object->findChild(QString(), Qt::FindDirectChildrenOnly); + if (!attached) + attached = new FlameGraphAttached(object); + return attached; +} + +QObject *FlameGraph::appendChild(QObject *parentObject, QQuickItem *parentItem, + QQmlContext *context, const QModelIndex &childIndex, + qreal position, qreal size) +{ + QObject *childObject = m_delegate->beginCreate(context); + if (parentItem) { + QQuickItem *childItem = qobject_cast(childObject); + if (childItem) + childItem->setParentItem(parentItem); + } + childObject->setParent(parentObject); + FlameGraphAttached *attached = FlameGraph::qmlAttachedProperties(childObject); + attached->setRelativePosition(position); + attached->setRelativeSize(size); + attached->setModelIndex(childIndex); + m_delegate->completeCreate(); + return childObject; +} + + +int FlameGraph::buildNode(const QModelIndex &parentIndex, QObject *parentObject, int depth) +{ + qreal position = 0; + qreal skipped = 0; + qreal parentSize = m_model->data(parentIndex, m_sizeRole).toReal(); + QQuickItem *parentItem = qobject_cast(parentObject); + QQmlContext *context = qmlContext(this); + int rowCount = m_model->rowCount(parentIndex); + int childrenDepth = depth; + for (int row = 0; row < rowCount; ++row) { + QModelIndex childIndex = m_model->index(row, 0, parentIndex); + qreal size = m_model->data(childIndex, m_sizeRole).toReal(); + if (size / m_model->data(QModelIndex(), m_sizeRole).toReal() < m_sizeThreshold) { + skipped += size; + continue; + } + + QObject *childObject = appendChild(parentObject, parentItem, context, childIndex, + position / parentSize, size / parentSize); + position += size; + childrenDepth = qMax(childrenDepth, buildNode(childIndex, childObject, depth + 1)); + } + + if (skipped > 0) { + appendChild(parentObject, parentItem, context, QModelIndex(), position / parentSize, + skipped / parentSize); + childrenDepth = qMax(childrenDepth, depth + 1); + } + + return childrenDepth; +} + +void FlameGraph::rebuild() +{ + qDeleteAll(childItems()); + childItems().clear(); + m_depth = 0; + + if (!m_model) { + emit depthChanged(m_depth); + return; + } + + m_depth = buildNode(QModelIndex(), this, 0); + emit depthChanged(m_depth); +} + +QVariant FlameGraphAttached::data(int role) const +{ + return m_data.isValid() ? m_data.data(role) : QVariant(); +} + +} +} diff --git a/src/plugins/qmlprofilerextension/flamegraph.h b/src/plugins/qmlprofilerextension/flamegraph.h new file mode 100644 index 0000000000..d4b444fc87 --- /dev/null +++ b/src/plugins/qmlprofilerextension/flamegraph.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef FLAMEGRAPH_H +#define FLAMEGRAPH_H + +#include +#include + +namespace QmlProfilerExtension { +namespace Internal { + +class 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; + + 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_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) + Q_PROPERTY(QAbstractItemModel* model READ model WRITE setModel NOTIFY modelChanged) + Q_PROPERTY(int sizeRole READ sizeRole WRITE setSizeRole NOTIFY sizeRoleChanged) + Q_PROPERTY(qreal sizeThreshold READ sizeThreshold WRITE setSizeThreshold + NOTIFY sizeThresholdChanged) + Q_PROPERTY(int depth READ depth NOTIFY depthChanged) + +public: + FlameGraph(QQuickItem *parent = 0); + + QQmlComponent *delegate() const; + void setDelegate(QQmlComponent *delegate); + + QAbstractItemModel *model() const; + void setModel(QAbstractItemModel *model); + + int sizeRole() const; + void setSizeRole(int sizeRole); + + qreal sizeThreshold() const; + void setSizeThreshold(qreal sizeThreshold); + + int depth() const; + + static FlameGraphAttached *qmlAttachedProperties(QObject *object); + +signals: + void delegateChanged(QQmlComponent *delegate); + void modelChanged(QAbstractItemModel *model); + void sizeRoleChanged(int role); + void sizeThresholdChanged(qreal threshold); + void depthChanged(int depth); + +private slots: + void rebuild(); + +private: + QQmlComponent *m_delegate; + QAbstractItemModel *m_model; + int m_sizeRole; + int m_depth; + qreal m_sizeThreshold; + + int buildNode(const QModelIndex &parentIndex, QObject *parentObject, int depth); + QObject *appendChild(QObject *parentObject, QQuickItem *parentItem, QQmlContext *context, + const QModelIndex &childIndex, qreal position, qreal size); +}; + +} +} + +QML_DECLARE_TYPEINFO(QmlProfilerExtension::Internal::FlameGraph, QML_HAS_ATTACHED_PROPERTIES) + +#endif // FLAMEGRAPH_H diff --git a/src/plugins/qmlprofilerextension/flamegraph.qrc b/src/plugins/qmlprofilerextension/flamegraph.qrc new file mode 100644 index 0000000000..abf7393f4e --- /dev/null +++ b/src/plugins/qmlprofilerextension/flamegraph.qrc @@ -0,0 +1,6 @@ + + + FlameGraphView.qml + FlameGraphText.qml + + diff --git a/src/plugins/qmlprofilerextension/flamegraphmodel.cpp b/src/plugins/qmlprofilerextension/flamegraphmodel.cpp new file mode 100644 index 0000000000..e181a66109 --- /dev/null +++ b/src/plugins/qmlprofilerextension/flamegraphmodel.cpp @@ -0,0 +1,324 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "flamegraphmodel.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace QmlProfilerExtension { +namespace Internal { + +FlameGraphModel::FlameGraphModel(QmlProfiler::QmlProfilerModelManager *modelManager, + QObject *parent) : QAbstractItemModel(parent) +{ + m_modelManager = modelManager; + connect(modelManager->qmlModel(), &QmlProfiler::QmlProfilerDataModel::changed, + this, [this](){loadData();}); + connect(modelManager->notesModel(), &Timeline::TimelineNotesModel::changed, + this, [this](int typeId, int, int){loadNotes(typeId, true);}); + m_modelId = modelManager->registerModelProxy(); + + // We're iterating twice in loadData. + modelManager->setProxyCountWeight(m_modelId, 2); + + m_acceptedTypes << QmlDebug::Compiling << QmlDebug::Creating << QmlDebug::Binding + << QmlDebug::HandlingSignal << QmlDebug::Javascript; + modelManager->announceFeatures(m_modelId, QmlDebug::Constants::QML_JS_RANGE_FEATURES); +} + +void FlameGraphModel::setEventTypeAccepted(QmlDebug::RangeType type, bool accepted) +{ + if (accepted && !m_acceptedTypes.contains(type)) + m_acceptedTypes << type; + else if (!accepted && m_acceptedTypes.contains(type)) + m_acceptedTypes.removeOne(type); +} + +bool FlameGraphModel::eventTypeAccepted(QmlDebug::RangeType type) const +{ + return m_acceptedTypes.contains(type); +} + +void FlameGraphModel::clear() +{ + m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1); + m_stackBottom = FlameGraphData(); + m_typeIdsWithNotes.clear(); +} + +void FlameGraphModel::loadNotes(int typeIndex, bool emitSignal) +{ + QSet changedNotes; + Timeline::TimelineNotesModel *notes = m_modelManager->notesModel(); + if (typeIndex == -1) { + changedNotes = m_typeIdsWithNotes; + m_typeIdsWithNotes.clear(); + for (int i = 0; i < notes->count(); ++i) + m_typeIdsWithNotes.insert(notes->typeId(i)); + changedNotes += m_typeIdsWithNotes; + } else { + changedNotes.insert(typeIndex); + if (notes->byTypeId(typeIndex).isEmpty()) + m_typeIdsWithNotes.remove(typeIndex); + else + m_typeIdsWithNotes.insert(typeIndex); + } + + if (!emitSignal) + return; + + QQueue queue; + queue.append(QModelIndex()); + + QVector roles = {Note}; + while (!queue.isEmpty()) { + QModelIndex index = queue.takeFirst(); + if (index.isValid()) { + FlameGraphData *data = static_cast(index.internalPointer()); + if (changedNotes.contains(data->typeIndex)) + emit dataChanged(index, index, roles); + for (int row = 0; row < rowCount(index); ++row) + queue.append(index.child(row, 0)); + } + + } +} + +void FlameGraphModel::loadData(qint64 rangeStart, qint64 rangeEnd) +{ + const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1); + if (m_modelManager->state() == QmlProfiler::QmlProfilerModelManager::ClearingData) { + beginResetModel(); + clear(); + endResetModel(); + return; + } else if (m_modelManager->state() != QmlProfiler::QmlProfilerModelManager::ProcessingData && + m_modelManager->state() != QmlProfiler::QmlProfilerModelManager::Done) { + return; + } + + beginResetModel(); + clear(); + + const QVector &eventList + = m_modelManager->qmlModel()->getEvents(); + const QVector &typesList + = m_modelManager->qmlModel()->getEventTypes(); + + // used by binding loop detection + QStack callStack; + callStack.append(0); + FlameGraphData *stackTop = &m_stackBottom; + + for (int i = 0; i < eventList.size(); ++i) { + const QmlProfiler::QmlProfilerDataModel::QmlEventData *event = &eventList[i]; + int typeIndex = event->typeIndex(); + const QmlProfiler::QmlProfilerDataModel::QmlEventTypeData *type = &typesList[typeIndex]; + + if (!m_acceptedTypes.contains(type->rangeType)) + continue; + + if (checkRanges) { + if ((event->startTime() + event->duration() < rangeStart) + || (event->startTime() > rangeEnd)) + continue; + } + + const QmlProfiler::QmlProfilerDataModel::QmlEventData *potentialParent = callStack.top(); + while (potentialParent && + potentialParent->startTime() + potentialParent->duration() <= event->startTime()) { + callStack.pop(); + stackTop = stackTop->parent; + potentialParent = callStack.top(); + } + + callStack.push(event); + stackTop = pushChild(stackTop, event); + + m_modelManager->modelProxyCountUpdated(m_modelId, i, eventList.count()); + } + + foreach (FlameGraphData *child, m_stackBottom.children) + m_stackBottom.duration += child->duration; + + loadNotes(-1, false); + + m_modelManager->modelProxyCountUpdated(m_modelId, 1, 1); + endResetModel(); +} + +static QString nameForType(QmlDebug::RangeType typeNumber) +{ + switch (typeNumber) { + case QmlDebug::Painting: return FlameGraphModel::tr("Paint"); + case QmlDebug::Compiling: return FlameGraphModel::tr("Compile"); + case QmlDebug::Creating: return FlameGraphModel::tr("Create"); + case QmlDebug::Binding: return FlameGraphModel::tr("Binding"); + case QmlDebug::HandlingSignal: return FlameGraphModel::tr("Signal"); + case QmlDebug::Javascript: return FlameGraphModel::tr("JavaScript"); + default: return QString(); + } +} + +QVariant FlameGraphModel::lookup(const FlameGraphData &stats, int role) const +{ + switch (role) { + case TypeId: return stats.typeIndex; + case Note: { + QString ret; + if (!m_typeIdsWithNotes.contains(stats.typeIndex)) + return ret; + QmlProfiler::QmlProfilerNotesModel *notes = m_modelManager->notesModel(); + foreach (const QVariant &item, notes->byTypeId(stats.typeIndex)) { + if (ret.isEmpty()) + ret = item.toString(); + else + ret += QChar::LineFeed + item.toString(); + } + return ret; + } + case Duration: return stats.duration; + case CallCount: return stats.calls; + case TimePerCall: return stats.duration / stats.calls; + case TimeInPercent: return stats.duration * 100 / m_stackBottom.duration; + default: break; + } + + if (stats.typeIndex != -1) { + const QVector &typeList = + m_modelManager->qmlModel()->getEventTypes(); + const QmlProfiler::QmlProfilerDataModel::QmlEventTypeData &type = typeList[stats.typeIndex]; + + switch (role) { + case Filename: return type.location.filename; + case Line: return type.location.line; + case Column: return type.location.column; + case Type: return nameForType(type.rangeType); + case RangeType: return type.rangeType; + case Details: return type.data.isEmpty() ? + FlameGraphModel::tr("Source code not available") : type.data; + default: return QVariant(); + } + } else { + return QVariant(); + } +} + +FlameGraphData::FlameGraphData(FlameGraphData *parent, int typeIndex, qint64 duration) : + duration(duration), calls(1), typeIndex(typeIndex), parent(parent) {} + +FlameGraphData::~FlameGraphData() +{ + qDeleteAll(children); +} + +FlameGraphData *FlameGraphModel::pushChild( + FlameGraphData *parent, const QmlProfiler::QmlProfilerDataModel::QmlEventData *data) +{ + foreach (FlameGraphData *child, parent->children) { + if (child->typeIndex == data->typeIndex()) { + ++child->calls; + child->duration += data->duration(); + return child; + } + } + + FlameGraphData *child = new FlameGraphData(parent, data->typeIndex(), data->duration()); + parent->children.append(child); + return child; +} + +QModelIndex FlameGraphModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid()) { + FlameGraphData *parentData = static_cast(parent.internalPointer()); + return createIndex(row, column, parentData->children[row]); + } else { + return createIndex(row, column, row >= 0 ? m_stackBottom.children[row] : 0); + } +} + +QModelIndex FlameGraphModel::parent(const QModelIndex &child) const +{ + if (child.isValid()) { + FlameGraphData *childData = static_cast(child.internalPointer()); + return createIndex(0, 0, childData->parent); + } else { + return QModelIndex(); + } +} + +int FlameGraphModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + FlameGraphData *parentData = static_cast(parent.internalPointer()); + return parentData->children.count(); + } else { + return m_stackBottom.children.count(); + } +} + +int FlameGraphModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 1; +} + +QVariant FlameGraphModel::data(const QModelIndex &index, int role) const +{ + FlameGraphData *data = static_cast(index.internalPointer()); + return lookup(data ? *data : m_stackBottom, role); +} + +QHash FlameGraphModel::roleNames() const +{ + QHash names = QAbstractItemModel::roleNames(); + names[TypeId] = "typeId"; + names[Type] = "type"; + names[Duration] = "duration"; + names[CallCount] = "callCount"; + names[Details] = "details"; + names[Filename] = "filename"; + names[Line] = "line"; + names[Column] = "column"; + names[Note] = "note"; + names[TimePerCall] = "timePerCall"; + names[TimeInPercent] = "timeInPercent"; + names[RangeType] = "rangeType"; + return names; +} + +} // namespace Internal +} // namespace QmlProfilerExtension diff --git a/src/plugins/qmlprofilerextension/flamegraphmodel.h b/src/plugins/qmlprofilerextension/flamegraphmodel.h new file mode 100644 index 0000000000..06b5b042e1 --- /dev/null +++ b/src/plugins/qmlprofilerextension/flamegraphmodel.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef QMLPROFILEREVENTSMODEL_H +#define QMLPROFILEREVENTSMODEL_H + +#include +#include +#include +#include + +#include +#include +#include + +namespace QmlProfilerExtension { +namespace Internal { + +struct FlameGraphData { + FlameGraphData(FlameGraphData *parent = 0, int typeIndex = -1, qint64 duration = 0); + ~FlameGraphData(); + + qint64 duration; + qint64 calls; + int typeIndex; + + FlameGraphData *parent; + QVector children; +}; + +class FlameGraphModel : public QAbstractItemModel +{ + Q_OBJECT + Q_ENUMS(Role) +public: + enum Role { + TypeId = Qt::UserRole + 1, // Sort by data, not by displayed string + Type, + Duration, + CallCount, + Details, + Filename, + Line, + Column, + Note, + TimePerCall, + TimeInPercent, + RangeType, + MaxRole + }; + + FlameGraphModel(QmlProfiler::QmlProfilerModelManager *modelManager, QObject *parent = 0); + + void setEventTypeAccepted(QmlDebug::RangeType type, bool accepted); + bool eventTypeAccepted(QmlDebug::RangeType) const; + + QModelIndex index(int row, int column, const QModelIndex &parent) const override; + QModelIndex parent(const QModelIndex &child) const override; + int rowCount(const QModelIndex &parent) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; + +public slots: + void loadData(qint64 rangeStart = -1, qint64 rangeEnd = -1); + void loadNotes(int typeId, bool emitSignal); + +private: + friend class FlameGraphRelativesModel; + friend class FlameGraphParentsModel; + friend class FlameGraphChildrenModel; + + QVariant lookup(const FlameGraphData &data, int role) const; + void clear(); + FlameGraphData *pushChild(FlameGraphData *parent, + const QmlProfiler::QmlProfilerDataModel::QmlEventData *data); + + int m_selectedTypeIndex; + FlameGraphData m_stackBottom; + + int m_modelId; + QmlProfiler::QmlProfilerModelManager *m_modelManager; + + QList m_acceptedTypes; + QSet m_typeIdsWithNotes; +}; + +} // namespace Internal +} // namespace QmlprofilerExtension + +#endif // QMLPROFILEREVENTSMODEL_H diff --git a/src/plugins/qmlprofilerextension/flamegraphview.cpp b/src/plugins/qmlprofilerextension/flamegraphview.cpp new file mode 100644 index 0000000000..532f9718bb --- /dev/null +++ b/src/plugins/qmlprofilerextension/flamegraphview.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "flamegraphview.h" +#include "flamegraph.h" + +#include +#include + +#include +#include +#include + +namespace QmlProfilerExtension { +namespace Internal { + +FlameGraphView::FlameGraphView(QWidget *parent, QmlProfiler::QmlProfilerModelManager *manager) : + QmlProfilerEventsView(parent), m_content(new QQuickWidget(this)), + m_model(new FlameGraphModel(manager, this)), m_isRestrictedToRange(false) +{ + setWindowTitle(QStringLiteral("Flamegraph")); + setObjectName(QStringLiteral("QmlProfilerFlamegraph")); + + qmlRegisterType("FlameGraph", 1, 0, "FlameGraph"); + qmlRegisterUncreatableType("FlameGraphModel", 1, 0, "FlameGraphModel", + QLatin1String("use the context property")); + + m_content->rootContext()->setContextProperty(QStringLiteral("flameGraphModel"), m_model); + m_content->setSource(QUrl(QStringLiteral("qrc:/FlameGraphView.qml"))); + m_content->setClearColor(QColor(0xdc, 0xdc, 0xdc)); + + m_content->setResizeMode(QQuickWidget::SizeRootObjectToView); + m_content->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QLayout *layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(m_content); + setLayout(layout); + + connect(m_content->rootObject(), SIGNAL(typeSelected(int)), + this, SIGNAL(typeSelected(int))); + connect(m_content->rootObject(), SIGNAL(gotoSourceLocation(QString,int,int)), + this, SIGNAL(gotoSourceLocation(QString,int,int))); +} + +void FlameGraphView::clear() +{ +} + +void FlameGraphView::restrictToRange(qint64 rangeStart, qint64 rangeEnd) +{ + m_isRestrictedToRange = (rangeStart != -1 || rangeEnd != -1); + m_model->loadData(rangeStart, rangeEnd); +} + +bool FlameGraphView::isRestrictedToRange() const +{ + return m_isRestrictedToRange; +} + +void FlameGraphView::selectByTypeId(int typeIndex) +{ + m_content->rootObject()->setProperty("selectedTypeId", typeIndex); +} + +void FlameGraphView::onVisibleFeaturesChanged(quint64 features) +{ + int rangeTypeMask = 0; + for (int rangeType = 0; rangeType < QmlDebug::MaximumRangeType; ++rangeType) { + if (features & (1 << QmlDebug::featureFromRangeType(QmlDebug::RangeType(rangeType)))) + rangeTypeMask |= (1 << rangeType); + } + m_content->rootObject()->setProperty("visibleRangeTypes", rangeTypeMask); +} + +void FlameGraphView::contextMenuEvent(QContextMenuEvent *ev) +{ + QMenu menu; + QAction *getGlobalStatsAction = 0; + + QPoint position = ev->globalPos(); + + menu.addActions(QmlProfiler::QmlProfilerTool::profilerContextMenuActions()); + menu.addSeparator(); + getGlobalStatsAction = menu.addAction(tr("Show Full Range")); + if (!isRestrictedToRange()) + getGlobalStatsAction->setEnabled(false); + + if (menu.exec(position) == getGlobalStatsAction) + emit showFullRange(); +} + +} +} diff --git a/src/plugins/qmlprofilerextension/flamegraphview.h b/src/plugins/qmlprofilerextension/flamegraphview.h new file mode 100644 index 0000000000..b98b673152 --- /dev/null +++ b/src/plugins/qmlprofilerextension/flamegraphview.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef FLAMEGRAPHVIEW_H +#define FLAMEGRAPHVIEW_H + +#include "flamegraphmodel.h" + +#include "qmlprofiler/qmlprofilereventsview.h" +#include +#include + +namespace QmlProfilerExtension { +namespace Internal { + +class FlameGraphView : public QmlProfiler::QmlProfilerEventsView +{ + Q_OBJECT +public: + FlameGraphView(QWidget *parent, QmlProfiler::QmlProfilerModelManager *manager); + + void clear() override; + void restrictToRange(qint64 rangeStart, qint64 rangeEnd) override; + bool isRestrictedToRange() const override; + +public slots: + void selectByTypeId(int typeIndex) override; + void onVisibleFeaturesChanged(quint64 features) override; + +protected: + void contextMenuEvent(QContextMenuEvent *ev) override; + +private: + QQuickWidget *m_content; + FlameGraphModel *m_model; + bool m_isRestrictedToRange; +}; + +} +} + +#endif // FLAMEGRAPHVIEW_H diff --git a/src/plugins/qmlprofilerextension/inputeventsmodel.cpp b/src/plugins/qmlprofilerextension/inputeventsmodel.cpp new file mode 100644 index 0000000000..a31aef7482 --- /dev/null +++ b/src/plugins/qmlprofilerextension/inputeventsmodel.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "inputeventsmodel.h" +#include "qmldebug/qmlprofilereventtypes.h" +#include "qmlprofiler/qmlprofilermodelmanager.h" + +#include +#include +#include + +namespace QmlProfilerExtension { +namespace Internal { + +using namespace QmlProfiler; + +InputEventsModel::InputEventsModel(QmlProfilerModelManager *manager, QObject *parent) : + QmlProfilerTimelineModel(manager, QmlDebug::Event, QmlDebug::MaximumRangeType, + QmlDebug::ProfileInputEvents, parent), + m_keyTypeId(-1), m_mouseTypeId(-1) +{ +} + +int InputEventsModel::typeId(int index) const +{ + return selectionId(index) == QmlDebug::Mouse ? m_mouseTypeId : m_keyTypeId; +} + +QColor InputEventsModel::color(int index) const +{ + return colorBySelectionId(index); +} + +QVariantList InputEventsModel::labels() const +{ + QVariantList result; + + QVariantMap element; + element.insert(QLatin1String("description"), QVariant(tr("Mouse Events"))); + element.insert(QLatin1String("id"), QVariant(QmlDebug::Mouse)); + result << element; + + element.clear(); + element.insert(QLatin1String("description"), QVariant(tr("Keyboard Events"))); + element.insert(QLatin1String("id"), QVariant(QmlDebug::Key)); + result << element; + + return result; +} + +QMetaEnum InputEventsModel::metaEnum(const char *name) +{ + return staticQtMetaObject.enumerator(staticQtMetaObject.indexOfEnumerator(name)); +} + +QVariantMap InputEventsModel::details(int index) const +{ + QVariantMap result; + result.insert(tr("Timestamp"), QmlProfilerDataModel::formatTime(startTime(index))); + QString type; + const InputEvent &event = m_data[index]; + switch (event.type) { + case QmlDebug::InputKeyPress: + type = tr("Key Press"); + case QmlDebug::InputKeyRelease: + if (type.isEmpty()) + type = tr("Key Release"); + if (event.a != 0) { + result.insert(tr("Key"), QLatin1String(metaEnum("Key").valueToKey(event.a))); + } + if (event.b != 0) { + result.insert(tr("Modifiers"), + QLatin1String(metaEnum("KeyboardModifiers").valueToKeys(event.b))); + } + break; + case QmlDebug::InputMouseDoubleClick: + type = tr("Double Click"); + case QmlDebug::InputMousePress: + if (type.isEmpty()) + type = tr("Mouse Press"); + case QmlDebug::InputMouseRelease: + if (type.isEmpty()) + type = tr("Mouse Release"); + result.insert(tr("Button"), QLatin1String(metaEnum("MouseButtons").valueToKey(event.a))); + result.insert(tr("Result"), QLatin1String(metaEnum("MouseButtons").valueToKeys(event.b))); + break; + case QmlDebug::InputMouseMove: + type = tr("Mouse Move"); + result.insert(tr("X"), QString::number(event.a)); + result.insert(tr("Y"), QString::number(event.b)); + break; + case QmlDebug::InputMouseWheel: + type = tr("Mouse Wheel"); + result.insert(tr("Angle X"), QString::number(event.a)); + result.insert(tr("Angle Y"), QString::number(event.b)); + break; + case QmlDebug::InputKeyUnknown: + type = tr("Keyboard Event"); + break; + case QmlDebug::InputMouseUnknown: + type = tr("Mouse Event"); + break; + default: + Q_UNREACHABLE(); + break; + } + + result.insert(QLatin1String("displayName"), type); + + return result; +} + +int InputEventsModel::expandedRow(int index) const +{ + return selectionId(index) == QmlDebug::Mouse ? 1 : 2; +} + +int InputEventsModel::collapsedRow(int index) const +{ + Q_UNUSED(index) + return 1; +} + +void InputEventsModel::loadData() +{ + QmlProfilerDataModel *simpleModel = modelManager()->qmlModel(); + if (simpleModel->isEmpty()) + return; + + const QVector &types = simpleModel->getEventTypes(); + foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) { + const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex()]; + if (!accepted(type)) + continue; + + m_data.insert(insert(event.startTime(), 0, type.detailType), + InputEvent(static_cast(event.numericData(0)), + event.numericData(1), event.numericData(2))); + + if (type.detailType == QmlDebug::Mouse) { + if (m_mouseTypeId == -1) + m_mouseTypeId = event.typeIndex(); + } else if (m_keyTypeId == -1) { + m_keyTypeId = event.typeIndex(); + } + updateProgress(count(), simpleModel->getEvents().count()); + } + setCollapsedRowCount(2); + setExpandedRowCount(3); + updateProgress(1, 1); +} + +void InputEventsModel::clear() +{ + m_keyTypeId = m_mouseTypeId = -1; + m_data.clear(); + QmlProfilerTimelineModel::clear(); +} + +bool InputEventsModel::accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const +{ + return QmlProfilerTimelineModel::accepted(event) && + (event.detailType == QmlDebug::Mouse || event.detailType == QmlDebug::Key); +} + +InputEventsModel::InputEvent::InputEvent(QmlDebug::InputEventType type, int a, int b) : + type(type), a(a), b(b) +{ +} + +} +} diff --git a/src/plugins/qmlprofilerextension/inputeventsmodel.h b/src/plugins/qmlprofilerextension/inputeventsmodel.h new file mode 100644 index 0000000000..72a58642dc --- /dev/null +++ b/src/plugins/qmlprofilerextension/inputeventsmodel.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef INPUTEVENTSMODEL_H +#define INPUTEVENTSMODEL_H + +#include "qmlprofiler/qmlprofilertimelinemodel.h" + +namespace QmlProfilerExtension { +namespace Internal { + +class InputEventsModel : public QmlProfiler::QmlProfilerTimelineModel +{ + Q_OBJECT + +protected: + bool accepted(const QmlProfiler::QmlProfilerDataModel::QmlEventTypeData &event) const; + +public: + struct InputEvent { + InputEvent(QmlDebug::InputEventType type = QmlDebug::MaximumInputEventType, int a = 0, + int b = 0); + QmlDebug::InputEventType type; + int a; + int b; + }; + + InputEventsModel(QmlProfiler::QmlProfilerModelManager *manager, QObject *parent = 0); + + int typeId(int index) const; + QColor color(int index) const; + QVariantList labels() const; + QVariantMap details(int index) const; + int expandedRow(int index) const; + int collapsedRow(int index) const; + void loadData(); + void clear(); + +private: + static QMetaEnum metaEnum(const char *name); + int m_keyTypeId; + int m_mouseTypeId; + + QVector m_data; +}; + +} +} +#endif // INPUTEVENTSMODEL_H diff --git a/src/plugins/qmlprofilerextension/memoryusagemodel.cpp b/src/plugins/qmlprofilerextension/memoryusagemodel.cpp new file mode 100644 index 0000000000..115522bbd2 --- /dev/null +++ b/src/plugins/qmlprofilerextension/memoryusagemodel.cpp @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "memoryusagemodel.h" +#include "qmldebug/qmlprofilereventtypes.h" +#include "qmlprofiler/qmlprofilermodelmanager.h" + +#include + +namespace QmlProfilerExtension { +namespace Internal { + +using namespace QmlProfiler; + +MemoryUsageModel::MemoryUsageModel(QmlProfilerModelManager *manager, QObject *parent) : + QmlProfilerTimelineModel(manager, QmlDebug::MemoryAllocation, QmlDebug::MaximumRangeType, + QmlDebug::ProfileMemory, parent) +{ + m_maxSize = 1; + announceFeatures((1ULL << mainFeature()) | QmlDebug::Constants::QML_JS_RANGE_FEATURES); +} + +int MemoryUsageModel::rowMaxValue(int rowNumber) const +{ + Q_UNUSED(rowNumber); + return m_maxSize; +} + +int MemoryUsageModel::expandedRow(int index) const +{ + int type = selectionId(index); + return (type == QmlDebug::HeapPage || type == QmlDebug::LargeItem) ? 1 : 2; +} + +int MemoryUsageModel::collapsedRow(int index) const +{ + return expandedRow(index); +} + +int MemoryUsageModel::typeId(int index) const +{ + return m_data[index].typeId; +} + +QColor MemoryUsageModel::color(int index) const +{ + return colorBySelectionId(index); +} + +float MemoryUsageModel::relativeHeight(int index) const +{ + return qMin(1.0f, (float)m_data[index].size / (float)m_maxSize); +} + +QVariantMap MemoryUsageModel::location(int index) const +{ + static const QLatin1String file("file"); + static const QLatin1String line("line"); + static const QLatin1String column("column"); + + QVariantMap result; + + int originType = m_data[index].originTypeIndex; + if (originType > -1) { + const QmlDebug::QmlEventLocation &location = + modelManager()->qmlModel()->getEventTypes().at(originType).location; + + result.insert(file, location.filename); + result.insert(line, location.line); + result.insert(column, location.column); + } + + return result; +} + +QVariantList MemoryUsageModel::labels() const +{ + QVariantList result; + + QVariantMap element; + element.insert(QLatin1String("description"), QVariant(tr("Memory Allocation"))); + element.insert(QLatin1String("id"), QVariant(QmlDebug::HeapPage)); + result << element; + + element.clear(); + element.insert(QLatin1String("description"), QVariant(tr("Memory Usage"))); + element.insert(QLatin1String("id"), QVariant(QmlDebug::SmallItem)); + result << element; + + return result; +} + +QVariantMap MemoryUsageModel::details(int index) const +{ + QVariantMap result; + const MemoryAllocation *ev = &m_data[index]; + + if (ev->allocated >= -ev->deallocated) + result.insert(QLatin1String("displayName"), tr("Memory Allocated")); + else + result.insert(QLatin1String("displayName"), tr("Memory Freed")); + + result.insert(tr("Total"), QString::fromLatin1("%1 bytes").arg(ev->size)); + if (ev->allocations > 0) { + result.insert(tr("Allocated"), QString::fromLatin1("%1 bytes").arg(ev->allocated)); + result.insert(tr("Allocations"), QString::number(ev->allocations)); + } + if (ev->deallocations > 0) { + result.insert(tr("Deallocated"), QString::fromLatin1("%1 bytes").arg(-ev->deallocated)); + result.insert(tr("Deallocations"), QString::number(ev->deallocations)); + } + result.insert(tr("Type"), QVariant(memoryTypeName(selectionId(index)))); + + if (ev->originTypeIndex != -1) { + result.insert(tr("Location"), + modelManager()->qmlModel()->getEventTypes().at(ev->originTypeIndex).displayName); + } + return result; +} + +struct RangeStackFrame { + RangeStackFrame() : originTypeIndex(-1), startTime(-1), endTime(-1) {} + RangeStackFrame(int originTypeIndex, qint64 startTime, qint64 endTime) : + originTypeIndex(originTypeIndex), startTime(startTime), endTime(endTime) {} + int originTypeIndex; + qint64 startTime; + qint64 endTime; +}; + +void MemoryUsageModel::loadData() +{ + QmlProfilerDataModel *simpleModel = modelManager()->qmlModel(); + if (simpleModel->isEmpty()) + return; + + qint64 currentSize = 0; + qint64 currentUsage = 0; + int currentUsageIndex = -1; + int currentJSHeapIndex = -1; + + QStack rangeStack; + + const QVector &types = simpleModel->getEventTypes(); + foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) { + const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex()]; + while (!rangeStack.empty() && rangeStack.top().endTime < event.startTime()) + rangeStack.pop(); + if (!accepted(type)) { + if (type.rangeType != QmlDebug::MaximumRangeType) { + rangeStack.push(RangeStackFrame(event.typeIndex(), event.startTime(), + event.startTime() + event.duration())); + } + continue; + } + + if (type.detailType == QmlDebug::SmallItem || type.detailType == QmlDebug::LargeItem) { + if (!rangeStack.empty() && currentUsageIndex > -1 && + type.detailType == selectionId(currentUsageIndex) && + m_data[currentUsageIndex].originTypeIndex == rangeStack.top().originTypeIndex && + rangeStack.top().startTime < startTime(currentUsageIndex)) { + m_data[currentUsageIndex].update(event.numericData(0)); + currentUsage = m_data[currentUsageIndex].size; + } else { + MemoryAllocation allocation(event.typeIndex(), currentUsage, + rangeStack.empty() ? -1 : rangeStack.top().originTypeIndex); + allocation.update(event.numericData(0)); + currentUsage = allocation.size; + + if (currentUsageIndex != -1) { + insertEnd(currentUsageIndex, + event.startTime() - startTime(currentUsageIndex) - 1); + } + currentUsageIndex = insertStart(event.startTime(), QmlDebug::SmallItem); + m_data.insert(currentUsageIndex, allocation); + } + } + + if (type.detailType == QmlDebug::HeapPage || type.detailType == QmlDebug::LargeItem) { + if (!rangeStack.empty() && currentJSHeapIndex > -1 && + type.detailType == selectionId(currentJSHeapIndex) && + m_data[currentJSHeapIndex].originTypeIndex == + rangeStack.top().originTypeIndex && + rangeStack.top().startTime < startTime(currentJSHeapIndex)) { + m_data[currentJSHeapIndex].update(event.numericData(0)); + currentSize = m_data[currentJSHeapIndex].size; + } else { + MemoryAllocation allocation(event.typeIndex(), currentSize, + rangeStack.empty() ? -1 : rangeStack.top().originTypeIndex); + allocation.update(event.numericData(0)); + currentSize = allocation.size; + + if (currentSize > m_maxSize) + m_maxSize = currentSize; + if (currentJSHeapIndex != -1) + insertEnd(currentJSHeapIndex, + event.startTime() - startTime(currentJSHeapIndex) - 1); + currentJSHeapIndex = insertStart(event.startTime(), type.detailType); + m_data.insert(currentJSHeapIndex, allocation); + } + } + + updateProgress(count(), simpleModel->getEvents().count()); + } + + if (currentJSHeapIndex != -1) + insertEnd(currentJSHeapIndex, modelManager()->traceTime()->endTime() - + startTime(currentJSHeapIndex) - 1); + if (currentUsageIndex != -1) + insertEnd(currentUsageIndex, modelManager()->traceTime()->endTime() - + startTime(currentUsageIndex) - 1); + + + computeNesting(); + setExpandedRowCount(3); + setCollapsedRowCount(3); + updateProgress(1, 1); +} + +void MemoryUsageModel::clear() +{ + m_data.clear(); + m_maxSize = 1; + QmlProfilerTimelineModel::clear(); +} + +QString MemoryUsageModel::memoryTypeName(int type) +{ + switch (type) { + case QmlDebug::HeapPage: return tr("Heap Allocation"); + case QmlDebug::LargeItem: return tr("Large Item Allocation"); + case QmlDebug::SmallItem: return tr("Heap Usage"); + case QmlDebug::MaximumMemoryType: return tr("Total"); + default: return tr("Unknown"); + } +} + +MemoryUsageModel::MemoryAllocation::MemoryAllocation(int type, qint64 baseAmount, + int originTypeIndex) : + typeId(type), size(baseAmount), allocated(0), deallocated(0), allocations(0), deallocations(0), + originTypeIndex(originTypeIndex) +{ +} + +void MemoryUsageModel::MemoryAllocation::update(qint64 amount) +{ + size += amount; + if (amount < 0) { + deallocated += amount; + ++deallocations; + } else { + allocated += amount; + ++allocations; + } +} + + +} // namespace Internal +} // namespace QmlProfilerExtension diff --git a/src/plugins/qmlprofilerextension/memoryusagemodel.h b/src/plugins/qmlprofilerextension/memoryusagemodel.h new file mode 100644 index 0000000000..bf7b557afa --- /dev/null +++ b/src/plugins/qmlprofilerextension/memoryusagemodel.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef MEMORYUSAGEMODEL_H +#define MEMORYUSAGEMODEL_H + +#include "qmlprofiler/qmlprofilertimelinemodel.h" +#include "qmlprofiler/qmlprofilerdatamodel.h" + +#include +#include + +namespace QmlProfilerExtension { +namespace Internal { + +class MemoryUsageModel : public QmlProfiler::QmlProfilerTimelineModel +{ + Q_OBJECT +public: + + struct MemoryAllocation { + int typeId; + qint64 size; + qint64 allocated; + qint64 deallocated; + int allocations; + int deallocations; + int originTypeIndex; + + MemoryAllocation(int typeId = -1, qint64 baseAmount = 0, int originTypeIndex = -1); + void update(qint64 amount); + }; + + MemoryUsageModel(QmlProfiler::QmlProfilerModelManager *manager, QObject *parent = 0); + + int rowMaxValue(int rowNumber) const; + + int expandedRow(int index) const; + int collapsedRow(int index) const; + int typeId(int index) const; + QColor color(int index) const; + float relativeHeight(int index) const; + + QVariantMap location(int index) const; + + QVariantList labels() const; + QVariantMap details(int index) const; + +protected: + void loadData(); + void clear(); + +private: + static QString memoryTypeName(int type); + + QVector m_data; + qint64 m_maxSize; +}; + +} // namespace Internal +} // namespace QmlProfilerExtension + +#endif // MEMORYUSAGEMODEL_H diff --git a/src/plugins/qmlprofilerextension/pixmapcachemodel.cpp b/src/plugins/qmlprofilerextension/pixmapcachemodel.cpp new file mode 100644 index 0000000000..b472fd8449 --- /dev/null +++ b/src/plugins/qmlprofilerextension/pixmapcachemodel.cpp @@ -0,0 +1,500 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "pixmapcachemodel.h" +#include "qmldebug/qmlprofilereventtypes.h" +#include "qmlprofiler/qmlprofilermodelmanager.h" + +namespace QmlProfilerExtension { +namespace Internal { + +using namespace QmlProfiler; + +PixmapCacheModel::PixmapCacheModel(QmlProfilerModelManager *manager, QObject *parent) : + QmlProfilerTimelineModel(manager, QmlDebug::PixmapCacheEvent, QmlDebug::MaximumRangeType, + QmlDebug::ProfilePixmapCache, parent) +{ + m_maxCacheSize = 1; +} + +int PixmapCacheModel::rowMaxValue(int rowNumber) const +{ + if (rowNumber == 1) { + return m_maxCacheSize; + } else { + return QmlProfilerTimelineModel::rowMaxValue(rowNumber); + } +} + +int PixmapCacheModel::expandedRow(int index) const +{ + return selectionId(index) + 1; +} + +int PixmapCacheModel::collapsedRow(int index) const +{ + return m_data[index].rowNumberCollapsed; +} + +int PixmapCacheModel::typeId(int index) const +{ + return m_data[index].typeId; +} + +QColor PixmapCacheModel::color(int index) const +{ + if (m_data[index].pixmapEventType == PixmapCacheCountChanged) + return colorByHue(s_pixmapCacheCountHue); + + return colorBySelectionId(index); +} + +float PixmapCacheModel::relativeHeight(int index) const +{ + if (m_data[index].pixmapEventType == PixmapCacheCountChanged) + return (float)m_data[index].cacheSize / (float)m_maxCacheSize; + else + return 1.0f; +} + +QString getFilenameOnly(QString absUrl) +{ + int characterPos = absUrl.lastIndexOf(QLatin1Char('/'))+1; + if (characterPos < absUrl.length()) + absUrl = absUrl.mid(characterPos); + return absUrl; +} + +QVariantList PixmapCacheModel::labels() const +{ + QVariantList result; + + // Cache Size + QVariantMap element; + element.insert(QLatin1String("description"), QVariant(QLatin1String("Cache Size"))); + + element.insert(QLatin1String("id"), QVariant(0)); + result << element; + + for (int i=0; i < m_pixmaps.count(); i++) { + // Loading + QVariantMap element; + element.insert(QLatin1String("displayName"), m_pixmaps[i].url); + element.insert(QLatin1String("description"), + QVariant(getFilenameOnly(m_pixmaps[i].url))); + + element.insert(QLatin1String("id"), QVariant(i+1)); + result << element; + } + + return result; +} + +QVariantMap PixmapCacheModel::details(int index) const +{ + QVariantMap result; + const PixmapCacheEvent *ev = &m_data[index]; + + if (ev->pixmapEventType == PixmapCacheCountChanged) { + result.insert(QLatin1String("displayName"), tr("Image Cached")); + } else { + if (ev->pixmapEventType == PixmapLoadingStarted) { + result.insert(QLatin1String("displayName"), tr("Image Loaded")); + if (m_pixmaps[ev->urlIndex].sizes[ev->sizeIndex].loadState != Finished) + result.insert(tr("Result"), tr("Load Error")); + } + result.insert(tr("Duration"), QmlProfilerDataModel::formatTime(duration(index))); + } + + result.insert(tr("Cache Size"), QString::fromLatin1("%1 px").arg(ev->cacheSize)); + result.insert(tr("File"), getFilenameOnly(m_pixmaps[ev->urlIndex].url)); + result.insert(tr("Width"), QString::fromLatin1("%1 px") + .arg(m_pixmaps[ev->urlIndex].sizes[ev->sizeIndex].size.width())); + result.insert(tr("Height"), QString::fromLatin1("%1 px") + .arg(m_pixmaps[ev->urlIndex].sizes[ev->sizeIndex].size.height())); + return result; +} + +/* Ultimately there is no way to know which cache entry a given event refers to as long as we only + * receive the pixmap URL from the application. Multiple copies of different sizes may be cached + * for each URL. However, we can apply some heuristics to make the result somewhat plausible by + * using the following assumptions: + * + * - PixmapSizeKnown will happen at most once for every cache entry. + * - PixmapSizeKnown cannot happen for entries with PixmapLoadingError and vice versa. + * - PixmapCacheCountChanged can happen for entries with PixmapLoadingError but doesn't have to. + * - Decreasing PixmapCacheCountChanged events can only happen for entries that have seen an + * increasing PixmapCacheCountChanged (but that may have happened before the trace). + * - PixmapCacheCountChanged can happen before or after PixmapSizeKnown. + * - For every PixmapLoadingFinished or PixmapLoadingError there is exactly one + * PixmapLoadingStarted event, but it may be before the trace. + * - For every PixmapLoadingStarted there is exactly one PixmapLoadingFinished or + * PixmapLoadingError, but it may be after the trace. + * - Decreasing PixmapCacheCountChanged events in the presence of corrupt cache entries are more + * likely to clear those entries than other, correctly loaded ones. + * - Increasing PixmapCacheCountChanged events are more likely to refer to correctly loaded entries + * than to ones with PixmapLoadingError. + * - PixmapLoadingFinished and PixmapLoadingError are more likely to refer to cache entries that + * have seen a PixmapLoadingStarted than to ones that haven't. + * + * For each URL we keep an ordered list of pixmaps possibly being loaded and assign new events to + * the first entry that "fits". If multiple sizes of the same pixmap are being loaded concurrently + * we generally assume that the PixmapLoadingFinished and PixmapLoadingError events occur in the + * order we learn about the existence of these sizes, subject to the above constraints. This is not + * necessarily the order the pixmaps are really loaded but it's the best we can do with the given + * information. If they're loaded sequentially the representation is correct. + */ + +void PixmapCacheModel::loadData() +{ + QmlProfilerDataModel *simpleModel = modelManager()->qmlModel(); + if (simpleModel->isEmpty()) + return; + + int lastCacheSizeEvent = -1; + int cumulatedCount = 0; + + const QVector &types = simpleModel->getEventTypes(); + foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) { + const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex()]; + if (!accepted(type)) + continue; + + PixmapCacheEvent newEvent; + newEvent.pixmapEventType = static_cast(type.detailType); + qint64 pixmapStartTime = event.startTime(); + + newEvent.urlIndex = -1; + for (QVector::const_iterator it(m_pixmaps.cend()); it != m_pixmaps.cbegin();) { + if ((--it)->url == type.location.filename) { + newEvent.urlIndex = it - m_pixmaps.cbegin(); + break; + } + } + + newEvent.sizeIndex = -1; + if (newEvent.urlIndex == -1) { + newEvent.urlIndex = m_pixmaps.count(); + m_pixmaps << Pixmap(type.location.filename); + } + + Pixmap &pixmap = m_pixmaps[newEvent.urlIndex]; + switch (newEvent.pixmapEventType) { + case PixmapSizeKnown: {// pixmap size + // Look for pixmaps for which we don't know the size, yet and which have actually been + // loaded. + for (QVector::iterator i(pixmap.sizes.begin()); + i != pixmap.sizes.end(); ++i) { + if (i->size.isValid() || i->cacheState == Uncacheable || i->cacheState == Corrupt) + continue; + + // We can't have cached it before we knew the size + Q_ASSERT(i->cacheState != Cached); + + i->size.setWidth(event.numericData(0)); + i->size.setHeight(event.numericData(1)); + newEvent.sizeIndex = i - pixmap.sizes.begin(); + break; + } + + if (newEvent.sizeIndex == -1) { + newEvent.sizeIndex = pixmap.sizes.length(); + pixmap.sizes << PixmapState(event.numericData(0), event.numericData(1)); + } + + PixmapState &state = pixmap.sizes[newEvent.sizeIndex]; + if (state.cacheState == ToBeCached) { + lastCacheSizeEvent = updateCacheCount(lastCacheSizeEvent, pixmapStartTime, + state.size.width() * state.size.height(), newEvent, + event.typeIndex()); + state.cacheState = Cached; + } + break; + } + case PixmapCacheCountChanged: {// Cache Size Changed Event + pixmapStartTime = event.startTime() + 1; // delay 1 ns for proper sorting + + bool uncache = cumulatedCount > event.numericData(2); + cumulatedCount = event.numericData(2); + qint64 pixSize = 0; + + // First try to find a preferred pixmap, which either is Corrupt and will be uncached + // or is uncached and will be cached. + for (QVector::iterator i(pixmap.sizes.begin()); + i != pixmap.sizes.end(); ++i) { + if (uncache && i->cacheState == Corrupt) { + newEvent.sizeIndex = i - pixmap.sizes.begin(); + i->cacheState = Uncacheable; + break; + } else if (!uncache && i->cacheState == Uncached) { + newEvent.sizeIndex = i - pixmap.sizes.begin(); + if (i->size.isValid()) { + pixSize = i->size.width() * i->size.height(); + i->cacheState = Cached; + } else { + i->cacheState = ToBeCached; + } + break; + } + } + + // If none found, check for cached or ToBeCached pixmaps that shall be uncached or + // Error pixmaps that become corrupt cache entries. We also accept Initial to be + // uncached as we may have missed the matching PixmapCacheCountChanged that cached it. + if (newEvent.sizeIndex == -1) { + for (QVector::iterator i(pixmap.sizes.begin()); + i != pixmap.sizes.end(); ++i) { + if (uncache && (i->cacheState == Cached || i->cacheState == ToBeCached || + i->cacheState == Uncached)) { + newEvent.sizeIndex = i - pixmap.sizes.begin(); + if (i->size.isValid()) + pixSize = -i->size.width() * i->size.height(); + i->cacheState = Uncached; + break; + } else if (!uncache && i->cacheState == Uncacheable) { + newEvent.sizeIndex = i - pixmap.sizes.begin(); + i->cacheState = Corrupt; + break; + } + } + } + + // If that does't work, create a new entry. + if (newEvent.sizeIndex == -1) { + newEvent.sizeIndex = pixmap.sizes.length(); + pixmap.sizes << PixmapState(uncache ? Uncached : ToBeCached); + } + + lastCacheSizeEvent = updateCacheCount(lastCacheSizeEvent, pixmapStartTime, pixSize, + newEvent, event.typeIndex()); + break; + } + case PixmapLoadingStarted: { // Load + // Look for a pixmap that hasn't been started, yet. There may have been a refcount + // event, which we ignore. + for (QVector::const_iterator i(pixmap.sizes.cbegin()); + i != pixmap.sizes.cend(); ++i) { + if (i->loadState == Initial) { + newEvent.sizeIndex = i - pixmap.sizes.cbegin(); + break; + } + } + if (newEvent.sizeIndex == -1) { + newEvent.sizeIndex = pixmap.sizes.length(); + pixmap.sizes << PixmapState(); + } + + PixmapState &state = pixmap.sizes[newEvent.sizeIndex]; + state.loadState = Loading; + newEvent.typeId = event.typeIndex(); + state.started = insertStart(pixmapStartTime, newEvent.urlIndex + 1); + m_data.insert(state.started, newEvent); + break; + } + case PixmapLoadingFinished: + case PixmapLoadingError: { + // First try to find one that has already started + for (QVector::const_iterator i(pixmap.sizes.cbegin()); + i != pixmap.sizes.cend(); ++i) { + if (i->loadState != Loading) + continue; + // Pixmaps with known size cannot be errors and vice versa + if (newEvent.pixmapEventType == PixmapLoadingError && i->size.isValid()) + continue; + + newEvent.sizeIndex = i - pixmap.sizes.cbegin(); + break; + } + + // If none was found use any other compatible one + if (newEvent.sizeIndex == -1) { + for (QVector::const_iterator i(pixmap.sizes.cbegin()); + i != pixmap.sizes.cend(); ++i) { + if (i->loadState != Initial) + continue; + // Pixmaps with known size cannot be errors and vice versa + if (newEvent.pixmapEventType == PixmapLoadingError && i->size.isValid()) + continue; + + newEvent.sizeIndex = i - pixmap.sizes.cbegin(); + break; + } + } + + // If again none was found, create one. + if (newEvent.sizeIndex == -1) { + newEvent.sizeIndex = pixmap.sizes.length(); + pixmap.sizes << PixmapState(); + } + + PixmapState &state = pixmap.sizes[newEvent.sizeIndex]; + // If the pixmap loading wasn't started, start it at traceStartTime() + if (state.loadState == Initial) { + newEvent.pixmapEventType = PixmapLoadingStarted; + newEvent.typeId = event.typeIndex(); + qint64 traceStart = modelManager()->traceTime()->startTime(); + state.started = insert(traceStart, pixmapStartTime - traceStart, + newEvent.urlIndex + 1); + m_data.insert(state.started, newEvent); + + // All other indices are wrong now as we've prepended. Fix them ... + if (lastCacheSizeEvent >= state.started) + ++lastCacheSizeEvent; + + for (int pixmapIndex = 0; pixmapIndex < m_pixmaps.count(); ++pixmapIndex) { + Pixmap &brokenPixmap = m_pixmaps[pixmapIndex]; + for (int sizeIndex = 0; sizeIndex < brokenPixmap.sizes.count(); ++sizeIndex) { + PixmapState &brokenSize = brokenPixmap.sizes[sizeIndex]; + if ((pixmapIndex != newEvent.urlIndex || sizeIndex != newEvent.sizeIndex) && + brokenSize.started >= state.started) { + ++brokenSize.started; + } + } + } + } + + insertEnd(state.started, pixmapStartTime - startTime(state.started)); + if (newEvent.pixmapEventType == PixmapLoadingError) { + state.loadState = Error; + switch (state.cacheState) { + case Uncached: + state.cacheState = Uncacheable; + break; + case ToBeCached: + state.cacheState = Corrupt; + break; + default: + // Cached cannot happen as size would have to be known and Corrupt or + // Uncacheable cannot happen as we only accept one finish or error event per + // pixmap. + Q_ASSERT(false); + } + } else { + state.loadState = Finished; + } + break; + } + default: + break; + } + + updateProgress(count(), 2 * simpleModel->getEvents().count()); + } + + if (lastCacheSizeEvent != -1) + insertEnd(lastCacheSizeEvent, modelManager()->traceTime()->endTime() - + startTime(lastCacheSizeEvent)); + + resizeUnfinishedLoads(); + + computeMaxCacheSize(); + flattenLoads(); + computeNesting(); + + updateProgress(1, 1); +} + +void PixmapCacheModel::clear() +{ + m_pixmaps.clear(); + m_maxCacheSize = 1; + m_data.clear(); + QmlProfilerTimelineModel::clear(); +} + +void PixmapCacheModel::computeMaxCacheSize() +{ + m_maxCacheSize = 1; + foreach (const PixmapCacheModel::PixmapCacheEvent &event, m_data) { + if (event.pixmapEventType == PixmapCacheModel::PixmapCacheCountChanged) { + if (event.cacheSize > m_maxCacheSize) + m_maxCacheSize = event.cacheSize; + } + } +} + +void PixmapCacheModel::resizeUnfinishedLoads() +{ + // all the "load start" events with duration 0 continue till the end of the trace + for (int i = 0; i < count(); i++) { + if (m_data[i].pixmapEventType == PixmapCacheModel::PixmapLoadingStarted && + duration(i) == 0) { + insertEnd(i, modelManager()->traceTime()->endTime() - startTime(i)); + } + } +} + +void PixmapCacheModel::flattenLoads() +{ + int collapsedRowCount = 0; + + // computes "compressed row" + QVector eventEndTimes; + for (int i = 0; i < count(); i++) { + PixmapCacheModel::PixmapCacheEvent &event = m_data[i]; + if (event.pixmapEventType == PixmapCacheModel::PixmapLoadingStarted) { + event.rowNumberCollapsed = 0; + while (eventEndTimes.count() > event.rowNumberCollapsed && + eventEndTimes[event.rowNumberCollapsed] > startTime(i)) + event.rowNumberCollapsed++; + + if (eventEndTimes.count() == event.rowNumberCollapsed) + eventEndTimes << 0; // increase stack length, proper value added below + eventEndTimes[event.rowNumberCollapsed] = endTime(i); + + // readjust to account for category empty row and bargraph + event.rowNumberCollapsed += 2; + } + if (event.rowNumberCollapsed > collapsedRowCount) + collapsedRowCount = event.rowNumberCollapsed; + } + + // Starting from 0, count is maxIndex+1 + setCollapsedRowCount(collapsedRowCount + 1); + setExpandedRowCount(m_pixmaps.count() + 2); +} + +int PixmapCacheModel::updateCacheCount(int lastCacheSizeEvent, + qint64 pixmapStartTime, qint64 pixSize, PixmapCacheEvent &newEvent, int typeId) +{ + newEvent.pixmapEventType = PixmapCacheCountChanged; + newEvent.rowNumberCollapsed = 1; + + qint64 prevSize = 0; + if (lastCacheSizeEvent != -1) { + prevSize = m_data[lastCacheSizeEvent].cacheSize; + insertEnd(lastCacheSizeEvent, pixmapStartTime - startTime(lastCacheSizeEvent)); + } + + newEvent.cacheSize = prevSize + pixSize; + newEvent.typeId = typeId; + int index = insertStart(pixmapStartTime, 0); + m_data.insert(index, newEvent); + return index; +} + + +} // namespace Internal +} // namespace QmlProfilerExtension diff --git a/src/plugins/qmlprofilerextension/pixmapcachemodel.h b/src/plugins/qmlprofilerextension/pixmapcachemodel.h new file mode 100644 index 0000000000..4d9fac2763 --- /dev/null +++ b/src/plugins/qmlprofilerextension/pixmapcachemodel.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef PIXMAPCACHEMODEL_H +#define PIXMAPCACHEMODEL_H + +#include "qmlprofiler/qmlprofilertimelinemodel.h" +#include "qmlprofiler/qmlprofilerdatamodel.h" + +#include +#include +#include + +namespace QmlProfilerExtension { +namespace Internal { + +class PixmapCacheModel : public QmlProfiler::QmlProfilerTimelineModel +{ + Q_OBJECT +public: + enum CacheState { + Uncached, // After loading started (or some other proof of existence) or after uncaching + ToBeCached, // After determining the pixmap is to be cached but before knowing its size + Cached, // After caching a pixmap or determining the size of a ToBeCached pixmap + Uncacheable, // If loading failed without ToBeCached or after a corrupt pixmap has been uncached + Corrupt // If after ToBeCached we learn that loading failed + }; + + enum LoadState { + Initial, + Loading, + Finished, + Error + }; + + struct PixmapState { + PixmapState(int width, int height, CacheState cache = Uncached) : + size(width, height), started(-1), loadState(Initial), cacheState(cache) {} + PixmapState(CacheState cache = Uncached) : started(-1), loadState(Initial), cacheState(cache) {} + QSize size; + int started; + LoadState loadState; + CacheState cacheState; + }; + + struct Pixmap { + Pixmap() {} + Pixmap(const QString &url) : url(url), sizes(1) {} + QString url; + QVector sizes; + }; + + enum PixmapEventType { + PixmapSizeKnown, + PixmapReferenceCountChanged, + PixmapCacheCountChanged, + PixmapLoadingStarted, + PixmapLoadingFinished, + PixmapLoadingError, + + MaximumPixmapEventType + }; + + struct PixmapCacheEvent { + int typeId; + PixmapEventType pixmapEventType; + int urlIndex; + int sizeIndex; + int rowNumberCollapsed; + qint64 cacheSize; + }; + + PixmapCacheModel(QmlProfiler::QmlProfilerModelManager *manager, QObject *parent = 0); + + int rowMaxValue(int rowNumber) const; + + int expandedRow(int index) const; + int collapsedRow(int index) const; + int typeId(int index) const; + QColor color(int index) const; + float relativeHeight(int index) const; + + QVariantList labels() const; + + QVariantMap details(int index) const; + +protected: + void loadData(); + void clear(); + +private: + void computeMaxCacheSize(); + void resizeUnfinishedLoads(); + void flattenLoads(); + int updateCacheCount(int lastCacheSizeEvent, qint64 startTime, qint64 pixSize, + PixmapCacheEvent &newEvent, int typeId); + + QVector m_data; + QVector m_pixmaps; + qint64 m_maxCacheSize; + + static const int s_pixmapCacheCountHue = 240; +}; + +} // namespace Internal +} // namespace QmlProfilerExtension + +#endif // PIXMAPCACHEMODEL_H diff --git a/src/plugins/qmlprofilerextension/qmlprofilerextension.pro b/src/plugins/qmlprofilerextension/qmlprofilerextension.pro new file mode 100644 index 0000000000..bfe0d5996f --- /dev/null +++ b/src/plugins/qmlprofilerextension/qmlprofilerextension.pro @@ -0,0 +1,35 @@ +include(../../qtcreatorplugin.pri) + +QT += qml quick quickwidgets + +DEFINES += QMLPROFILEREXTENSION_LIBRARY + +# QmlProfilerExtension files + +SOURCES += qmlprofilerextensionplugin.cpp \ + scenegraphtimelinemodel.cpp \ + pixmapcachemodel.cpp \ + memoryusagemodel.cpp \ + inputeventsmodel.cpp \ + debugmessagesmodel.cpp \ + flamegraphmodel.cpp \ + flamegraphview.cpp \ + flamegraph.cpp + +HEADERS += qmlprofilerextensionplugin.h \ + qmlprofilerextension_global.h \ + qmlprofilerextensionconstants.h \ + scenegraphtimelinemodel.h \ + pixmapcachemodel.h \ + memoryusagemodel.h \ + inputeventsmodel.h \ + debugmessagesmodel.h \ + flamegraphmodel.h \ + flamegraphview.h \ + flamegraph.h + +OTHER_FILES += \ + QmlProfilerExtension.json.in + +RESOURCES += \ + flamegraph.qrc diff --git a/src/plugins/qmlprofilerextension/qmlprofilerextension.qbs b/src/plugins/qmlprofilerextension/qmlprofilerextension.qbs new file mode 100644 index 0000000000..193cdc3bfb --- /dev/null +++ b/src/plugins/qmlprofilerextension/qmlprofilerextension.qbs @@ -0,0 +1,36 @@ +import qbs + +QtcPlugin { + name: "QmlProfilerExtension" + + Depends { name: "Core" } + Depends { name: "QmlProfiler" } + Depends { name: "Timeline" } + + Depends { name: "Qt.quickwidgets" } + Depends { name: "Qt.widgets" } + + files: [ + "debugmessagesmodel.cpp", + "debugmessagesmodel.h", + "flamegraph.cpp", + "flamegraph.h", + "flamegraph.qrc", + "flamegraphmodel.cpp", + "flamegraphmodel.h", + "flamegraphview.cpp", + "flamegraphview.h", + "inputeventsmodel.cpp", + "inputeventsmodel.h", + "memoryusagemodel.cpp", + "memoryusagemodel.h", + "pixmapcachemodel.cpp", + "pixmapcachemodel.h", + "qmlprofilerextensionconstants.h", + "qmlprofilerextensionplugin.cpp", + "qmlprofilerextensionplugin.h", + "qmlprofilerextension_global.h", + "scenegraphtimelinemodel.cpp", + "scenegraphtimelinemodel.h", + ] +} diff --git a/src/plugins/qmlprofilerextension/qmlprofilerextension_dependencies.pri b/src/plugins/qmlprofilerextension/qmlprofilerextension_dependencies.pri new file mode 100644 index 0000000000..638fd4c0c0 --- /dev/null +++ b/src/plugins/qmlprofilerextension/qmlprofilerextension_dependencies.pri @@ -0,0 +1,4 @@ +QTC_PLUGIN_NAME = QmlProfilerExtension +QTC_PLUGIN_DEPENDS += \ + qmlprofiler + diff --git a/src/plugins/qmlprofilerextension/qmlprofilerextension_global.h b/src/plugins/qmlprofilerextension/qmlprofilerextension_global.h new file mode 100644 index 0000000000..a8faba9971 --- /dev/null +++ b/src/plugins/qmlprofilerextension/qmlprofilerextension_global.h @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef QMLPROFILEREXTENSION_GLOBAL_H +#define QMLPROFILEREXTENSION_GLOBAL_H + +#include + +#if defined(QMLPROFILEREXTENSION_LIBRARY) +# define QMLPROFILEREXTENSIONSHARED_EXPORT Q_DECL_EXPORT +#else +# define QMLPROFILEREXTENSIONSHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // QMLPROFILEREXTENSION_GLOBAL_H + diff --git a/src/plugins/qmlprofilerextension/qmlprofilerextensionconstants.h b/src/plugins/qmlprofilerextension/qmlprofilerextensionconstants.h new file mode 100644 index 0000000000..e7c730c9d5 --- /dev/null +++ b/src/plugins/qmlprofilerextension/qmlprofilerextensionconstants.h @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef QMLPROFILEREXTENSIONCONSTANTS_H +#define QMLPROFILEREXTENSIONCONSTANTS_H + +namespace QmlProfilerExtension { +namespace Constants { + +const char ACTION_ID[] = "QmlProfilerExtension.Action"; +const char MENU_ID[] = "QmlProfilerExtension.Menu"; + +} // namespace QmlProfilerExtension +} // namespace Constants + +#endif // QMLPROFILEREXTENSIONCONSTANTS_H + diff --git a/src/plugins/qmlprofilerextension/qmlprofilerextensionplugin.cpp b/src/plugins/qmlprofilerextension/qmlprofilerextensionplugin.cpp new file mode 100644 index 0000000000..05c7ac9b9e --- /dev/null +++ b/src/plugins/qmlprofilerextension/qmlprofilerextensionplugin.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "qmlprofilerextensionplugin.h" +#include "qmlprofilerextensionconstants.h" +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include "scenegraphtimelinemodel.h" +#include "pixmapcachemodel.h" +#include "memoryusagemodel.h" +#include "inputeventsmodel.h" +#include "debugmessagesmodel.h" +#include "flamegraphview.h" + +using namespace QmlProfilerExtension::Internal; + +class ModelFactory : public QmlProfiler::QmlProfilerTimelineModelFactory { + Q_OBJECT +public: + QList create( + QmlProfiler::QmlProfilerModelManager *manager) + { + QList models; + models << new PixmapCacheModel(manager, this) + << new SceneGraphTimelineModel(manager, this) + << new MemoryUsageModel(manager, this) + << new InputEventsModel(manager, this) + << new DebugMessagesModel(manager, this); + return models; + } +}; + +class ViewFactory : public QmlProfiler::QmlProfilerEventsViewFactory { + Q_OBJECT +public: + QList create( + QWidget *parent, QmlProfiler::QmlProfilerModelManager *manager) override + { + QList views; + views << new FlameGraphView(parent, manager); + return views; + } +}; + +QmlProfilerExtensionPlugin::QmlProfilerExtensionPlugin() +{ + // Create your members +} + +QmlProfilerExtensionPlugin::~QmlProfilerExtensionPlugin() +{ + // Unregister objects from the plugin manager's object pool + // Delete members +} + +bool QmlProfilerExtensionPlugin::initialize(const QStringList &arguments, QString *errorString) +{ + // Register objects in the plugin manager's object pool + // Load settings + // Add actions to menus + // Connect to other plugins' signals + // In the initialize method, a plugin can be sure that the plugins it + // depends on have initialized their members. + + Q_UNUSED(arguments) + Q_UNUSED(errorString) + + addAutoReleasedObject(new ModelFactory); + addAutoReleasedObject(new ViewFactory); + + return true; +} + +void QmlProfilerExtensionPlugin::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. +} + +ExtensionSystem::IPlugin::ShutdownFlag QmlProfilerExtensionPlugin::aboutToShutdown() +{ + // Save settings + // Disconnect from signals that are not needed during shutdown + // Hide UI (if you add UI that is not in the main window directly) + return SynchronousShutdown; +} + +void QmlProfilerExtensionPlugin::triggerAction() +{ + QMessageBox::information(Core::ICore::mainWindow(), + tr("Action triggered"), + tr("This is an action from QmlProfilerExtension.")); +} + +#include "qmlprofilerextensionplugin.moc" diff --git a/src/plugins/qmlprofilerextension/qmlprofilerextensionplugin.h b/src/plugins/qmlprofilerextension/qmlprofilerextensionplugin.h new file mode 100644 index 0000000000..63571cde69 --- /dev/null +++ b/src/plugins/qmlprofilerextension/qmlprofilerextensionplugin.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef QMLPROFILEREXTENSION_H +#define QMLPROFILEREXTENSION_H + +#include "qmlprofilerextension_global.h" + +#include + +namespace QmlProfilerExtension { +namespace Internal { + +class QmlProfilerExtensionPlugin : public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "QmlProfilerExtension.json") + +public: + QmlProfilerExtensionPlugin(); + ~QmlProfilerExtensionPlugin(); + + bool initialize(const QStringList &arguments, QString *errorString); + void extensionsInitialized(); + ShutdownFlag aboutToShutdown(); + +private slots: + void triggerAction(); +}; + +} // namespace Internal +} // namespace QmlProfilerExtension + +#endif // QMLPROFILEREXTENSION_H + diff --git a/src/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp b/src/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp new file mode 100644 index 0000000000..cb61bbf07e --- /dev/null +++ b/src/plugins/qmlprofilerextension/scenegraphtimelinemodel.cpp @@ -0,0 +1,311 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "scenegraphtimelinemodel.h" +#include "qmldebug/qmlprofilereventtypes.h" +#include "qmlprofiler/qmlprofilermodelmanager.h" + +#include +#include + +namespace QmlProfilerExtension { +namespace Internal { + +using namespace QmlProfiler; + +static const char *ThreadLabels[] = { + QT_TRANSLATE_NOOP("MainView", "GUI Thread"), + QT_TRANSLATE_NOOP("MainView", "Render Thread"), + QT_TRANSLATE_NOOP("MainView", "Render Thread Details") +}; + +static const char *StageLabels[] = { + QT_TRANSLATE_NOOP("MainView", "Polish"), + QT_TRANSLATE_NOOP("MainView", "Wait"), + QT_TRANSLATE_NOOP("MainView", "GUI Thread Sync"), + QT_TRANSLATE_NOOP("MainView", "Animations"), + QT_TRANSLATE_NOOP("MainView", "Render Thread Sync"), + QT_TRANSLATE_NOOP("MainView", "Render"), + QT_TRANSLATE_NOOP("MainView", "Swap"), + QT_TRANSLATE_NOOP("MainView", "Render Preprocess"), + QT_TRANSLATE_NOOP("MainView", "Render Update"), + QT_TRANSLATE_NOOP("MainView", "Render Bind"), + QT_TRANSLATE_NOOP("MainView", "Render Render"), + QT_TRANSLATE_NOOP("MainView", "Material Compile"), + QT_TRANSLATE_NOOP("MainView", "Glyph Render"), + QT_TRANSLATE_NOOP("MainView", "Glyph Upload"), + QT_TRANSLATE_NOOP("MainView", "Texture Bind"), + QT_TRANSLATE_NOOP("MainView", "Texture Convert"), + QT_TRANSLATE_NOOP("MainView", "Texture Swizzle"), + QT_TRANSLATE_NOOP("MainView", "Texture Upload"), + QT_TRANSLATE_NOOP("MainView", "Texture Mipmap"), + QT_TRANSLATE_NOOP("MainView", "Texture Delete") +}; + +enum SceneGraphCategoryType { + SceneGraphGUIThread, + SceneGraphRenderThread, + SceneGraphRenderThreadDetails, + + MaximumSceneGraphCategoryType +}; + +Q_STATIC_ASSERT(sizeof(StageLabels) == + SceneGraphTimelineModel::MaximumSceneGraphStage * sizeof(const char *)); + +SceneGraphTimelineModel::SceneGraphTimelineModel(QmlProfilerModelManager *manager, + QObject *parent) : + QmlProfilerTimelineModel(manager, QmlDebug::SceneGraphFrame, QmlDebug::MaximumRangeType, + QmlDebug::ProfileSceneGraph, parent) +{ +} + +int SceneGraphTimelineModel::expandedRow(int index) const +{ + return selectionId(index) + 1; +} + +int SceneGraphTimelineModel::collapsedRow(int index) const +{ + return m_data[index].rowNumberCollapsed; +} + +int SceneGraphTimelineModel::typeId(int index) const +{ + return m_data[index].typeId; +} + +QColor SceneGraphTimelineModel::color(int index) const +{ + return colorBySelectionId(index); +} + +QVariantList SceneGraphTimelineModel::labels() const +{ + QVariantList result; + + for (SceneGraphStage i = MinimumSceneGraphStage; i < MaximumSceneGraphStage; + i = static_cast(i + 1)) { + QVariantMap element; + element.insert(QLatin1String("displayName"), tr(threadLabel(i))); + element.insert(QLatin1String("description"), tr(StageLabels[i])); + element.insert(QLatin1String("id"), i); + result << element; + } + + return result; +} + +QVariantMap SceneGraphTimelineModel::details(int index) const +{ + QVariantMap result; + const SceneGraphStage stage = static_cast(selectionId(index)); + + result.insert(QLatin1String("displayName"), tr(threadLabel(stage))); + result.insert(tr("Stage"), tr(StageLabels[stage])); + result.insert(tr("Duration"), QmlProfilerDataModel::formatTime(duration(index))); + + const int glyphCount = m_data[index].glyphCount; + if (glyphCount >= 0) + result.insert(tr("Glyphs"), QString::number(glyphCount)); + + return result; +} + +void SceneGraphTimelineModel::loadData() +{ + QmlProfilerDataModel *simpleModel = modelManager()->qmlModel(); + if (simpleModel->isEmpty()) + return; + + // combine the data of several eventtypes into two rows + const QVector &types = simpleModel->getEventTypes(); + foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) { + const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex()]; + if (!accepted(type)) + continue; + + switch ((QmlDebug::SceneGraphFrameType)type.detailType) { + case QmlDebug::SceneGraphRendererFrame: { + // Breakdown of render times. We repeat "render" here as "net" render time. It would + // look incomplete if that was left out as the printf profiler lists it, too, and people + // are apparently comparing that. Unfortunately it is somewhat redundant as the other + // parts of the breakdown are usually very short. + qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) - + event.numericData(2) - event.numericData(3); + startTime += insert(startTime, event.numericData(0), event.typeIndex(), RenderPreprocess); + startTime += insert(startTime, event.numericData(1), event.typeIndex(), RenderUpdate); + startTime += insert(startTime, event.numericData(2), event.typeIndex(), RenderBind); + insert(startTime, event.numericData(3), event.typeIndex(), RenderRender); + break; + } + case QmlDebug::SceneGraphAdaptationLayerFrame: { + qint64 startTime = event.startTime() - event.numericData(1) - event.numericData(2); + startTime += insert(startTime, event.numericData(1), event.typeIndex(), GlyphRender, + event.numericData(0)); + insert(startTime, event.numericData(2), event.typeIndex(), GlyphStore, event.numericData(0)); + break; + } + case QmlDebug::SceneGraphContextFrame: { + insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(), + Material); + break; + } + case QmlDebug::SceneGraphRenderLoopFrame: { + qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) - + event.numericData(2); + startTime += insert(startTime, event.numericData(0), event.typeIndex(), + RenderThreadSync); + startTime += insert(startTime, event.numericData(1), event.typeIndex(), + Render); + insert(startTime, event.numericData(2), event.typeIndex(), Swap); + break; + } + case QmlDebug::SceneGraphTexturePrepare: { + qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) - + event.numericData(2) - event.numericData(3) - event.numericData(4); + startTime += insert(startTime, event.numericData(0), event.typeIndex(), TextureBind); + startTime += insert(startTime, event.numericData(1), event.typeIndex(), TextureConvert); + startTime += insert(startTime, event.numericData(2), event.typeIndex(), TextureSwizzle); + startTime += insert(startTime, event.numericData(3), event.typeIndex(), TextureUpload); + insert(startTime, event.numericData(4), event.typeIndex(), TextureMipmap); + break; + } + case QmlDebug::SceneGraphTextureDeletion: { + insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(), + TextureDeletion); + break; + } + case QmlDebug::SceneGraphPolishAndSync: { + qint64 startTime = event.startTime() - event.numericData(0) - event.numericData(1) - + event.numericData(2) - event.numericData(3); + + startTime += insert(startTime, event.numericData(0), event.typeIndex(), Polish); + startTime += insert(startTime, event.numericData(1), event.typeIndex(), Wait); + startTime += insert(startTime, event.numericData(2), event.typeIndex(), GUIThreadSync); + insert(startTime, event.numericData(3), event.typeIndex(), Animations); + break; + } + case QmlDebug::SceneGraphWindowsAnimations: { + // GUI thread, separate animations stage + insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(), + Animations); + break; + } + case QmlDebug::SceneGraphPolishFrame: { + // GUI thread, separate polish stage + insert(event.startTime() - event.numericData(0), event.numericData(0), event.typeIndex(), + Polish); + break; + } + default: break; + } + + updateProgress(count(), simpleModel->getEvents().count()); + } + + computeNesting(); + flattenLoads(); + updateProgress(1, 1); +} + +void SceneGraphTimelineModel::flattenLoads() +{ + int collapsedRowCount = 0; + + // computes "compressed row" + QVector eventEndTimes; + + for (int i = 0; i < count(); i++) { + SceneGraphEvent &event = m_data[i]; + int stage = selectionId(i); + // Don't try to put render thread events in GUI row and vice versa. + // Rows below those are free for all. + if (stage < MaximumGUIThreadStage) + event.rowNumberCollapsed = SceneGraphGUIThread; + else if (stage < MaximumRenderThreadStage) + event.rowNumberCollapsed = SceneGraphRenderThread; + else + event.rowNumberCollapsed = SceneGraphRenderThreadDetails; + + while (eventEndTimes.count() > event.rowNumberCollapsed && + eventEndTimes[event.rowNumberCollapsed] > startTime(i)) + ++event.rowNumberCollapsed; + + while (eventEndTimes.count() <= event.rowNumberCollapsed) + eventEndTimes << 0; // increase stack length, proper value added below + eventEndTimes[event.rowNumberCollapsed] = endTime(i); + + // readjust to account for category empty row + event.rowNumberCollapsed++; + if (event.rowNumberCollapsed > collapsedRowCount) + collapsedRowCount = event.rowNumberCollapsed; + } + + // Starting from 0, count is maxIndex+1 + setCollapsedRowCount(collapsedRowCount + 1); + setExpandedRowCount(MaximumSceneGraphStage + 1); +} + +/*! + * Inserts an event characterized by \a start time, \a duration, \a typeIndex, \a stage and possibly + * \a glyphCount (if it's a \c GlyphRender or \c GlyphStore event) into the scene graph model if its + * \a duration is greater than 0. Returns \a duration in that case; otherwise returns 0. + */ +qint64 SceneGraphTimelineModel::insert(qint64 start, qint64 duration, int typeIndex, + SceneGraphStage stage, int glyphCount) +{ + if (duration <= 0) + return 0; + + m_data.insert(QmlProfilerTimelineModel::insert(start, duration, stage), + SceneGraphEvent(typeIndex, glyphCount)); + return duration; +} + +const char *SceneGraphTimelineModel::threadLabel(SceneGraphStage stage) +{ + if (stage < MaximumGUIThreadStage) + return ThreadLabels[SceneGraphGUIThread]; + else if (stage < MaximumRenderThreadStage) + return ThreadLabels[SceneGraphRenderThread]; + else + return ThreadLabels[SceneGraphRenderThreadDetails]; + +} + +void SceneGraphTimelineModel::clear() +{ + m_data.clear(); + QmlProfilerTimelineModel::clear(); +} + +SceneGraphTimelineModel::SceneGraphEvent::SceneGraphEvent(int typeId, int glyphCount) : + typeId(typeId), rowNumberCollapsed(-1), glyphCount(glyphCount) +{ +} + +} // namespace Internal +} // namespace QmlProfilerExtension diff --git a/src/plugins/qmlprofilerextension/scenegraphtimelinemodel.h b/src/plugins/qmlprofilerextension/scenegraphtimelinemodel.h new file mode 100644 index 0000000000..59782769dd --- /dev/null +++ b/src/plugins/qmlprofilerextension/scenegraphtimelinemodel.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef SCENEGRAPHTIMELINEMODEL_H +#define SCENEGRAPHTIMELINEMODEL_H + +#include "qmlprofiler/qmlprofilertimelinemodel.h" +#include "qmlprofiler/qmlprofilermodelmanager.h" +#include "qmlprofiler/qmlprofilerdatamodel.h" + +#include +#include + +namespace QmlProfilerExtension { +namespace Internal { + +class SceneGraphTimelineModel : public QmlProfiler::QmlProfilerTimelineModel +{ + Q_OBJECT +public: + enum SceneGraphStage { + MinimumSceneGraphStage = 0, + Polish = MinimumSceneGraphStage, + Wait, + GUIThreadSync, + Animations, + MaximumGUIThreadStage, + + RenderThreadSync = MaximumGUIThreadStage, + Render, + Swap, + MaximumRenderThreadStage, + + RenderPreprocess = MaximumRenderThreadStage, + RenderUpdate, + RenderBind, + RenderRender, + MaximumRenderStage, + + Material = MaximumRenderStage, + MaximumMaterialStage, + + GlyphRender = MaximumMaterialStage, + GlyphStore, + MaximumGlyphStage, + + TextureBind = MaximumGlyphStage, + TextureConvert, + TextureSwizzle, + TextureUpload, + TextureMipmap, + TextureDeletion, + MaximumTextureStage, + + MaximumSceneGraphStage = MaximumTextureStage + }; + + struct SceneGraphEvent { + SceneGraphEvent(int typeId = -1, int glyphCount = -1); + int typeId; + int rowNumberCollapsed; + int glyphCount; // only used for one event type + }; + + SceneGraphTimelineModel(QmlProfiler::QmlProfilerModelManager *manager, QObject *parent = 0); + + int expandedRow(int index) const; + int collapsedRow(int index) const; + int typeId(int index) const; + QColor color(int index) const; + + QVariantList labels() const; + + QVariantMap details(int index) const; + +protected: + void loadData(); + void clear(); + +private: + void flattenLoads(); + qint64 insert(qint64 start, qint64 duration, int typeIndex, SceneGraphStage stage, + int glyphCount = -1); + static const char *threadLabel(SceneGraphStage stage); + + QVector m_data; +}; + +} // namespace Internal +} // namespace QmlProfilerExtension + +#endif // SCENEGRAPHTIMELINEMODEL_H -- cgit v1.2.3