From 4893422b13a51dae9d960791ce7e0d50f7615f2a Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Wed, 23 Mar 2016 16:09:35 +0100 Subject: [PATCH] Make it possible to select different cost sources for the flame graph. Also put the bottom-down action into the new control toolbar. --- gui/flamegraph.cpp | 133 +++++++++++++++++++++++++++++++++++++++++++++-------- gui/flamegraph.h | 2 + 2 files changed, 116 insertions(+), 19 deletions(-) diff --git a/gui/flamegraph.cpp b/gui/flamegraph.cpp index 8d743a2..d1abc43 100644 --- a/gui/flamegraph.cpp +++ b/gui/flamegraph.cpp @@ -31,15 +31,28 @@ #include #include #include +#include +#include #include #include #include +enum CostType +{ + Allocations, + Temporary, + Peak, + Leaked, + Allocated +}; +Q_DECLARE_METATYPE(CostType) + class FrameGraphicsItem : public QGraphicsRectItem { public: - FrameGraphicsItem(const quint64 cost, const QString& function, FrameGraphicsItem* parent = nullptr); + FrameGraphicsItem(const quint64 cost, CostType costType, const QString& function, FrameGraphicsItem* parent = nullptr); + FrameGraphicsItem(const quint64 cost, const QString& function, FrameGraphicsItem* parent); quint64 cost() const; void setCost(quint64 cost); @@ -55,21 +68,28 @@ protected: private: quint64 m_cost; QString m_function; + CostType m_costType; bool m_isHovered; }; Q_DECLARE_METATYPE(FrameGraphicsItem*); -FrameGraphicsItem::FrameGraphicsItem(const quint64 cost, const QString& function, FrameGraphicsItem* parent) +FrameGraphicsItem::FrameGraphicsItem(const quint64 cost, CostType costType, const QString& function, FrameGraphicsItem* parent) : QGraphicsRectItem(parent) , m_cost(cost) , m_function(function) + , m_costType(costType) , m_isHovered(false) { setFlag(QGraphicsItem::ItemIsSelectable); setAcceptHoverEvents(true); } +FrameGraphicsItem::FrameGraphicsItem(const quint64 cost, const QString& function, FrameGraphicsItem* parent) + : FrameGraphicsItem(cost, parent->m_costType, function, parent) +{ +} + quint64 FrameGraphicsItem::cost() const { return m_cost; @@ -128,7 +148,31 @@ void FrameGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) void FrameGraphicsItem::showToolTip() const { // we build the tooltip text on demand, which is much faster than doing that for potentially thousands of items when we load the data - QToolTip::showText(QCursor::pos(), i18nc("%1: number of allocations, %2: function label", "%1 allocations in %2 and below.", m_cost, m_function)); + QString tooltip; + KFormat format; + switch (m_costType) { + case Allocations: + tooltip = i18nc("%1: number of allocations, %2: function label", + "%1 allocations in %2 and below.", m_cost, m_function); + break; + case Temporary: + tooltip = i18nc("%1: number of temporary allocations, %2: function label", + "%1 temporary allocations in %2 and below.", m_cost, m_function); + break; + case Peak: + tooltip = i18nc("%1: peak consumption in bytes, %2: function label", + "%1 peak consumption in %2 and below.", format.formatByteSize(m_cost), m_function); + break; + case Leaked: + tooltip = i18nc("%1: leaked bytes, %2: function label", + "%1 leaked in %2 and below.", format.formatByteSize(m_cost), m_function); + break; + case Allocated: + tooltip = i18nc("%1: allocated bytes, %2: function label", + "%1 allocated in %2 and below.", format.formatByteSize(m_cost), m_function); + break; + } + QToolTip::showText(QCursor::pos(), tooltip); } void FrameGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) @@ -198,35 +242,73 @@ FrameGraphicsItem* findItemByFunction(const QList& items, const /** * Convert the top-down graph into a tree of FrameGraphicsItem. */ -void toGraphicsItems(const QVector& data, FrameGraphicsItem *parent) +void toGraphicsItems(const QVector& data, FrameGraphicsItem *parent, quint64 RowData::* member) { foreach (const auto& row, data) { auto item = findItemByFunction(parent->childItems(), row.location->function); if (!item) { - item = new FrameGraphicsItem(row.allocations, row.location->function, parent); + item = new FrameGraphicsItem(row.*member, row.location->function, parent); item->setPen(parent->pen()); item->setBrush(brush()); } else { - item->setCost(item->cost() + row.allocations); + item->setCost(item->cost() + row.*member); } - toGraphicsItems(row.children, item); + toGraphicsItems(row.children, item, member); } } -FrameGraphicsItem* parseData(const QVector& topDownData) +quint64 RowData::* memberForType(CostType type) { + switch (type) { + case Allocations: + return &RowData::allocations; + case Temporary: + return &RowData::temporary; + case Peak: + return &RowData::peak; + case Leaked: + return &RowData::leaked; + case Allocated: + return &RowData::allocated; + } + Q_UNREACHABLE(); +} + +FrameGraphicsItem* parseData(const QVector& topDownData, CostType type) +{ + quint64 RowData::* member = memberForType(type); + double totalCost = 0; foreach(const auto& frame, topDownData) { - totalCost += frame.allocations; + totalCost += frame.*member; } KColorScheme scheme(QPalette::Active); const QPen pen(scheme.foreground().color()); - auto rootItem = new FrameGraphicsItem(totalCost, i18n("%1 allocations in total", totalCost)); + KFormat format; + QString label; + switch (type) { + case Allocations: + label = i18n("%1 allocations in total", totalCost); + break; + case Temporary: + label = i18n("%1 temporary allocations in total", totalCost); + break; + case Peak: + label = i18n("%1 peak consumption in total", format.formatByteSize(totalCost)); + break; + case Leaked: + label = i18n("%1 leaked in total", format.formatByteSize(totalCost)); + break; + case Allocated: + label = i18n("%1 allocated in total", format.formatByteSize(totalCost)); + break; + } + auto rootItem = new FrameGraphicsItem(totalCost, type, label); rootItem->setBrush(scheme.background()); rootItem->setPen(pen); - toGraphicsItems(topDownData, rootItem); + toGraphicsItems(topDownData, rootItem, member); return rootItem; } @@ -234,6 +316,7 @@ FrameGraphicsItem* parseData(const QVector& topDownData) FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags) : QWidget(parent, flags) + , m_costSource(new QComboBox(this)) , m_scene(new QGraphicsScene(this)) , m_view(new QGraphicsView(this)) , m_rootItem(nullptr) @@ -242,7 +325,13 @@ FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags) { qRegisterMetaType(); - setLayout(new QVBoxLayout); + m_costSource->addItem(i18n("Allocations"), QVariant::fromValue(Allocations)); + m_costSource->addItem(i18n("Temporary Allocations"), QVariant::fromValue(Temporary)); + m_costSource->addItem(i18n("Peak Consumption"), QVariant::fromValue(Peak)); + m_costSource->addItem(i18n("Leaked"), QVariant::fromValue(Leaked)); + m_costSource->addItem(i18n("Allocated"), QVariant::fromValue(Allocated)); + connect(m_costSource, static_cast(&QComboBox::currentIndexChanged), + this, &FlameGraph::showData); m_scene->setItemIndexMethod(QGraphicsScene::NoIndex); m_view->setScene(m_scene); @@ -250,14 +339,19 @@ FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags) m_view->viewport()->setMouseTracking(true); m_view->setFont(QFont(QStringLiteral("monospace"))); m_view->setContextMenuPolicy(Qt::ActionsContextMenu); - auto bottomUpViewAction = new QAction(i18n("Bottom-Down View"), this); - bottomUpViewAction->setCheckable(true); - connect(bottomUpViewAction, &QAction::toggled, this, [this, bottomUpViewAction] { - m_showBottomUpData = bottomUpViewAction->isChecked(); + auto bottomUpCheckbox = new QCheckBox(i18n("Bottom-Down View"), this); + connect(bottomUpCheckbox, &QCheckBox::toggled, this, [this, bottomUpCheckbox] { + m_showBottomUpData = bottomUpCheckbox->isChecked(); showData(); }); - m_view->addAction(bottomUpViewAction); + auto controls = new QWidget(this); + controls->setLayout(new QHBoxLayout); + controls->layout()->addWidget(m_costSource); + controls->layout()->addWidget(bottomUpCheckbox); + + setLayout(new QVBoxLayout); + layout()->addWidget(controls); layout()->addWidget(m_view); } @@ -304,8 +398,9 @@ void FlameGraph::showData() using namespace ThreadWeaver; auto data = m_showBottomUpData ? m_bottomUpData : m_topDownData; - stream() << make_job([data, this]() { - auto parsedData = parseData(data); + auto source = m_costSource->currentData().value(); + stream() << make_job([data, source, this]() { + auto parsedData = parseData(data, source); QMetaObject::invokeMethod(this, "setData", Qt::QueuedConnection, Q_ARG(FrameGraphicsItem*, parsedData)); }); diff --git a/gui/flamegraph.h b/gui/flamegraph.h index 0c08211..1997c8c 100644 --- a/gui/flamegraph.h +++ b/gui/flamegraph.h @@ -25,6 +25,7 @@ class QGraphicsScene; class QGraphicsView; +class QComboBox; class FrameGraphicsItem; @@ -51,6 +52,7 @@ private: TreeData m_topDownData; TreeData m_bottomUpData; + QComboBox* m_costSource; QGraphicsScene* m_scene; QGraphicsView* m_view; FrameGraphicsItem* m_rootItem; -- 2.7.4