parser.cpp
flamegraph.cpp
stacksmodel.cpp
+ topproxy.cpp
${UIFILES}
)
#include "treemodel.h"
#include "treeproxy.h"
+#include "topproxy.h"
#include "parser.h"
#include "chartmodel.h"
#include "chartproxy.h"
namespace {
const int MAINWINDOW_VERSION = 1;
+
namespace Config {
namespace Groups {
const char MainWindow[] = "MainWindow";
const char State[] = "State";
}
}
+
+void setupTopView(TreeModel* source, QTreeView* view, TopProxy::Type type)
+{
+ auto proxy = new TopProxy(type, source);
+ proxy->setSourceModel(source);
+ proxy->setSortRole(TreeModel::SortRole);
+ view->setModel(proxy);
+ view->setRootIsDecorated(false);
+ view->setUniformRowHeights(true);
+ view->sortByColumn(0);
+ view->header()->setStretchLastSection(true);
+ view->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+}
}
MainWindow::MainWindow(QWidget* parent)
statusBar()->addWidget(m_ui->progressLabel, 1);
statusBar()->addWidget(m_ui->loadingProgress);
m_ui->pages->setCurrentWidget(m_ui->resultsPage);
- m_ui->stacksDock->setVisible(true);
});
connect(m_parser, &Parser::topDownDataAvailable,
this, [=] (const TreeData& data) {
m_ui->bottomUpResults->hideColumn(TreeModel::FileColumn);
m_ui->bottomUpResults->hideColumn(TreeModel::LineColumn);
m_ui->bottomUpResults->hideColumn(TreeModel::ModuleColumn);
-
connect(m_ui->bottomUpFilterFunction, &QLineEdit::textChanged,
bottomUpProxy, &TreeProxy::setFunctionFilter);
connect(m_ui->bottomUpFilterFile, &QLineEdit::textChanged,
auto openFile = KStandardAction::open(this, SLOT(openFile()), this);
m_ui->openFile->setDefaultAction(openFile);
+ setupStacks();
+
+ setupTopView(bottomUpModel, m_ui->topPeak, TopProxy::Peak);
+ setupTopView(bottomUpModel, m_ui->topLeaked, TopProxy::Leaked);
+ setupTopView(bottomUpModel, m_ui->topAllocations, TopProxy::Allocations);
+ setupTopView(bottomUpModel, m_ui->topTemporary, TopProxy::Temporary);
+ setupTopView(bottomUpModel, m_ui->topAllocated, TopProxy::Allocated);
+
+ setWindowTitle(i18n("Heaptrack"));
+}
+
+MainWindow::~MainWindow()
+{
+ auto state = saveState(MAINWINDOW_VERSION);
+ auto group = m_config->group(Config::Groups::MainWindow);
+ group.writeEntry(Config::Entries::State, state);
+}
+
+void MainWindow::loadFile(const QString& file)
+{
+ m_ui->loadingLabel->setText(i18n("Loading file %1, please wait...", file));
+ setWindowTitle(i18nc("%1: file name that is open", "Heaptrack - %1", file));
+ m_ui->pages->setCurrentWidget(m_ui->loadingPage);
+ m_parser->parse(file);
+}
+
+void MainWindow::openFile()
+{
+ auto dialog = new QFileDialog(this, i18n("Open Heaptrack Output File"), {}, i18n("Heaptrack data files (heaptrack.*)"));
+ dialog->setAttribute(Qt::WA_DeleteOnClose, true);
+ dialog->setFileMode(QFileDialog::ExistingFile);
+ connect(dialog, &QFileDialog::fileSelected,
+ this, &MainWindow::loadFile);
+ dialog->show();
+}
+
+void MainWindow::setupStacks()
+{
auto stacksModel = new StacksModel(this);
m_ui->stacksTree->setModel(stacksModel);
m_ui->stacksTree->setRootIsDecorated(false);
+
auto updateStackSpinner = [this] (int stacks) {
m_ui->stackSpinner->setMinimum(min(stacks, 1));
m_ui->stackSpinner->setSuffix(i18n(" / %1", stacks));
this, updateStackSpinner);
connect(m_ui->stackSpinner, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
stacksModel, &StacksModel::setStackIndex);
+
auto fillFromIndex = [stacksModel] (const QModelIndex& current) {
if (!current.isValid()) {
stacksModel->clear();
this, fillFromIndex);
connect(m_ui->topDownResults->selectionModel(), &QItemSelectionModel::currentChanged,
this, fillFromIndex);
- connect(m_ui->tabWidget, &QTabWidget::currentChanged, this, [this, fillFromIndex] (int tabIndex) {
+
+ auto tabChanged = [this, fillFromIndex] (int tabIndex) {
const auto widget = m_ui->tabWidget->widget(tabIndex);
const bool showDocks = (widget == m_ui->topDownTab || widget == m_ui->bottomUpTab);
m_ui->stacksDock->setVisible(showDocks);
auto tree = (widget == m_ui->topDownTab) ? m_ui->topDownResults : m_ui->bottomUpResults;
fillFromIndex(tree->selectionModel()->currentIndex());
}
- });
+ };
+ connect(m_ui->tabWidget, &QTabWidget::currentChanged,
+ this, tabChanged);
+ connect(m_parser, &Parser::bottomUpDataAvailable,
+ this, [tabChanged] () { tabChanged(0); });
+
m_ui->stacksDock->setVisible(false);
m_ui->stacksDock->setFeatures(QDockWidget::DockWidgetMovable);
-
- setWindowTitle(i18n("Heaptrack"));
-}
-
-MainWindow::~MainWindow()
-{
- auto state = saveState(MAINWINDOW_VERSION);
- auto group = m_config->group(Config::Groups::MainWindow);
- group.writeEntry(Config::Entries::State, state);
-}
-
-void MainWindow::loadFile(const QString& file)
-{
- m_ui->loadingLabel->setText(i18n("Loading file %1, please wait...", file));
- setWindowTitle(i18nc("%1: file name that is open", "Heaptrack - %1", file));
- m_ui->pages->setCurrentWidget(m_ui->loadingPage);
- m_parser->parse(file);
-}
-
-void MainWindow::openFile()
-{
- auto dialog = new QFileDialog(this, i18n("Open Heaptrack Output File"), {}, i18n("Heaptrack data files (heaptrack.*)"));
- dialog->setAttribute(Qt::WA_DeleteOnClose, true);
- dialog->setFileMode(QFileDialog::ExistingFile);
- connect(dialog, &QFileDialog::fileSelected,
- this, &MainWindow::loadFile);
- dialog->show();
}
void openFile();
private:
+ void setupStacks();
+
QScopedPointer<Ui::MainWindow> m_ui;
Parser* m_parser;
KSharedConfig::Ptr m_config;
<rect>
<x>0</x>
<y>0</y>
- <width>1128</width>
+ <width>1280</width>
<height>896</height>
</rect>
</property>
<widget class="QWidget" name="resultsPage">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
- <widget class="QLabel" name="summary">
- <property name="text">
- <string notr="true">summary goes here</string>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
- <number>7</number>
+ <number>0</number>
</property>
+ <widget class="QWidget" name="summaryTab">
+ <attribute name="title">
+ <string>Summary</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_7">
+ <item>
+ <widget class="QLabel" name="summary">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">summary goes here</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_4" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QWidget" name="widget_5" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_8">
+ <item>
+ <widget class="QLabel" name="topPeakLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string>List of functions that allocated the most memory at a given time.</string>
+ </property>
+ <property name="text">
+ <string>Highest Memory Peaks</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="topPeak">
+ <property name="toolTip">
+ <string>List of functions that allocated the most memory at a given time.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_6" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_9">
+ <item>
+ <widget class="QLabel" name="topLeakedLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string>List of functions that leak the most memory.</string>
+ </property>
+ <property name="text">
+ <string>Largest Memory Leaks</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="topLeaked">
+ <property name="toolTip">
+ <string>List of functions that leak the most memory.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_7" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_10">
+ <item>
+ <widget class="QLabel" name="topAllocationsLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string>List of functions that allocate memory most often.</string>
+ </property>
+ <property name="text">
+ <string>Most Memory Allocations</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="topAllocations">
+ <property name="toolTip">
+ <string>List of functions that allocate memory most often.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_8" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_11">
+ <item>
+ <widget class="QLabel" name="topTemporaryLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string>List of functions that produced the most temporary memory allocations.</string>
+ </property>
+ <property name="text">
+ <string>Most Temporary Allocations</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="topTemporary">
+ <property name="toolTip">
+ <string>List of functions that produced the most temporary memory allocations.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_9" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_12">
+ <item>
+ <widget class="QLabel" name="topAllocatedLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string>List of functions that allocated the most memory overall, ignoring deallocations.</string>
+ </property>
+ <property name="text">
+ <string>Most Memory Allocated</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="topAllocated">
+ <property name="toolTip">
+ <string>List of functions that allocated the most memory overall, ignoring deallocations.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ <zorder>summary</zorder>
+ <zorder>widget_5</zorder>
+ <zorder>widget_6</zorder>
+ <zorder>widget_7</zorder>
+ <zorder>widget_8</zorder>
+ <zorder>widget_9</zorder>
+ </widget>
+ </item>
+ </layout>
+ </widget>
<widget class="QWidget" name="bottomUpTab">
<attribute name="title">
<string>Bottom-Up</string>
KFormat format;
QTextStream stream(&ret);
const double totalTimeS = 0.001 * data.totalTime;
- stream << "<qt>"
- << i18n("<strong>debuggee</strong>: <code>%1</code>", QString::fromStdString(data.debuggee)) << "<br/>"
+ stream << "<qt><dl>"
+ << i18n("<dt><b>debuggee</b>:</dt><dd style='font-family:monospace;'>%1</dd>", QString::fromStdString(data.debuggee))
// xgettext:no-c-format
- << i18n("<strong>total runtime</strong>: %1s", totalTimeS) << "<br/>"
- << i18n("<strong>bytes allocated in total</strong> (ignoring deallocations): %1 (%2/s)",
- format.formatByteSize(data.totalAllocated, 2), format.formatByteSize(data.totalAllocated / totalTimeS)) << "<br/>"
- << i18n("<strong>calls to allocation functions</strong>: %1 (%2/s)",
- data.totalAllocations, quint64(data.totalAllocations / totalTimeS)) << "<br/>"
- << i18n("<strong>temporary allocations</strong>: %1 (%2%, %3/s)",
+ << i18n("<dt><b>total runtime</b>:</dt><dd>%1s</dd>", totalTimeS)
+ << i18n("<dt><b>bytes allocated in total</b> (ignoring deallocations):</dt><dd>%1 (%2/s)</dd>",
+ format.formatByteSize(data.totalAllocated, 2), format.formatByteSize(data.totalAllocated / totalTimeS))
+ << i18n("<dt><b>calls to allocation functions</b>:</dt><dd>%1 (%2/s)</dd>",
+ data.totalAllocations, quint64(data.totalAllocations / totalTimeS))
+ << i18n("<dt><b>temporary allocations</b>:</dt><dd>%1 (%2%, %3/s)</dd>",
data.totalTemporary, round(float(data.totalTemporary) * 100.f * 100.f / data.totalAllocations) / 100.f,
- quint64(data.totalTemporary / totalTimeS)) << "<br/>"
- << i18n("<strong>peak heap memory consumption</strong>: %1", format.formatByteSize(data.peak)) << "<br/>"
- << i18n("<strong>total memory leaked</strong>: %1", format.formatByteSize(data.leaked)) << "<br/>";
- stream << "</qt>";
+ quint64(data.totalTemporary / totalTimeS))
+ << i18n("<dt><b>peak heap memory consumption</b>:</dt><dd>%1</dd>", format.formatByteSize(data.peak))
+ << i18n("<dt><b>total memory leaked</b>:</dt><dd>%1</dd>", format.formatByteSize(data.leaked));
+ stream << "</dl></qt>";
return ret;
}
--- /dev/null
+/*
+ * Copyright 2016 Milian Wolff <mail@milianw.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "topproxy.h"
+
+#include <KLocalizedString>
+
+namespace {
+TreeModel::Columns toSource(TopProxy::Type type)
+{
+ switch (type) {
+ case TopProxy::Peak:
+ return TreeModel::PeakColumn;
+ case TopProxy::Leaked:
+ return TreeModel::LeakedColumn;
+ case TopProxy::Allocations:
+ return TreeModel::AllocationsColumn;;
+ case TopProxy::Temporary:
+ return TreeModel::TemporaryColumn;
+ case TopProxy::Allocated:
+ return TreeModel::AllocatedColumn;
+ }
+ Q_UNREACHABLE();
+}
+}
+
+TopProxy::TopProxy(Type type, QObject* parent)
+ : QSortFilterProxyModel(parent)
+ , m_type(type)
+{
+}
+
+TopProxy::~TopProxy() = default;
+
+bool TopProxy::filterAcceptsColumn(int source_column, const QModelIndex& source_parent) const
+{
+ return source_column == TreeModel::LocationColumn || source_column == toSource(m_type);
+}
+
+bool TopProxy::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
+{
+ return !source_parent.isValid();
+}
--- /dev/null
+/*
+ * Copyright 2016 Milian Wolff <mail@milianw.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TOPPROXY_H
+#define TOPPROXY_H
+
+#include <QSortFilterProxyModel>
+
+#include "treemodel.h"
+
+class TopProxy : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ enum Type {
+ Peak,
+ Leaked,
+ Allocations,
+ Allocated,
+ Temporary
+ };
+
+ explicit TopProxy(Type type, QObject* parent = nullptr);
+ ~TopProxy() override;
+
+ bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
+ bool filterAcceptsColumn(int source_column, const QModelIndex& source_parent) const override;
+
+private:
+ Type m_type;
+};
+
+#endif // TOPPROXY_H