aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/tracing/flamegraph.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2018-05-03 09:50:11 +0200
committerUlf Hermann <ulf.hermann@qt.io>2018-05-04 14:08:47 +0000
commit734611131dc20283b118353130bdd5e16ce0aeaf (patch)
tree91adf7b62f98765a46bc5c544a1808cde1b1bf82 /src/libs/tracing/flamegraph.cpp
parentb9b2f2c1875030b8259d22cba69161304ada7011 (diff)
Move Timeline and FlameGraph into a common "Tracing" library
This allows us to share code between the two, in particular the QML code for the Details window, and the theme code. This way we can potentially deduplicate some code. Change-Id: I3a0d26b18488bd2a46b5b077b5b5d79ac2dfc5ce Reviewed-by: Christian Kandeler <christian.kandeler@qt.io> Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Diffstat (limited to 'src/libs/tracing/flamegraph.cpp')
-rw-r--r--src/libs/tracing/flamegraph.cpp197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/libs/tracing/flamegraph.cpp b/src/libs/tracing/flamegraph.cpp
new file mode 100644
index 0000000000..2fa38313ed
--- /dev/null
+++ b/src/libs/tracing/flamegraph.cpp
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** 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 FlameGraph {
+
+FlameGraph::FlameGraph(QQuickItem *parent) :
+ QQuickItem(parent)
+{
+ // Queue the rebuild in this case so that a delegate can set the root without getting deleted
+ // during the call.
+ connect(this, &FlameGraph::rootChanged, this, &FlameGraph::rebuild, Qt::QueuedConnection);
+}
+
+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;
+ if (m_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<FlameGraphAttached *>(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<QQuickItem *>(childObject);
+ if (childItem)
+ childItem->setParentItem(parentItem);
+ }
+ childObject->setParent(parentObject);
+ FlameGraphAttached *attached = FlameGraph::qmlAttachedProperties(childObject);
+ attached->setRelativePosition(position);
+ attached->setRelativeSize(size);
+ attached->setModelIndex(childIndex);
+ connect(m_model, &QAbstractItemModel::dataChanged,
+ attached, &FlameGraphAttached::modelIndexChanged);
+ m_delegate->completeCreate();
+ return childObject;
+}
+
+
+int FlameGraph::buildNode(const QModelIndex &parentIndex, QObject *parentObject, int depth,
+ int maximumDepth)
+{
+ qreal position = 0;
+ qreal skipped = 0;
+ qreal parentSize = m_model->data(parentIndex, m_sizeRole).toReal();
+ QQuickItem *parentItem = qobject_cast<QQuickItem *>(parentObject);
+ QQmlContext *context = qmlContext(this);
+ int rowCount = m_model->rowCount(parentIndex);
+ int childrenDepth = depth;
+ if (depth == maximumDepth - 1) {
+ skipped = parentSize;
+ } else {
+ 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(m_root, 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,
+ maximumDepth));
+ }
+ }
+
+ // Invisible Root object: attribute all remaining width to "others"
+ if (!parentIndex.isValid())
+ skipped = parentSize - position;
+
+ 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;
+ }
+
+ if (m_root.isValid()) {
+ QObject *parentObject = appendChild(this, this, qmlContext(this), m_root, 0, 1);
+ m_depth = buildNode(m_root, parentObject, 1, m_maximumDepth);
+ } else {
+ m_depth = buildNode(m_root, this, 0, m_maximumDepth);
+ }
+
+ emit depthChanged(m_depth);
+}
+
+} // namespace FlameGraph