diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2018-05-03 09:50:11 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2018-05-04 14:08:47 +0000 |
commit | 734611131dc20283b118353130bdd5e16ce0aeaf (patch) | |
tree | 91adf7b62f98765a46bc5c544a1808cde1b1bf82 /src/libs/tracing/flamegraph.cpp | |
parent | b9b2f2c1875030b8259d22cba69161304ada7011 (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.cpp | 197 |
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 |