Add summary tab and display all top functions there.
authorMilian Wolff <mail@milianw.de>
Wed, 24 Feb 2016 00:24:47 +0000 (01:24 +0100)
committerMilian Wolff <mail@milianw.de>
Wed, 24 Feb 2016 00:24:47 +0000 (01:24 +0100)
gui/CMakeLists.txt
gui/mainwindow.cpp
gui/mainwindow.h
gui/mainwindow.ui
gui/parser.cpp
gui/topproxy.cpp [new file with mode: 0644]
gui/topproxy.h [new file with mode: 0644]

index 8683694..18cb20b 100644 (file)
@@ -25,6 +25,7 @@ add_executable(heaptrack_gui
     parser.cpp
     flamegraph.cpp
     stacksmodel.cpp
+    topproxy.cpp
     ${UIFILES}
 )
 
index b1c043e..0ae3434 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "treemodel.h"
 #include "treeproxy.h"
+#include "topproxy.h"
 #include "parser.h"
 #include "chartmodel.h"
 #include "chartproxy.h"
@@ -42,6 +43,7 @@ using namespace std;
 
 namespace {
 const int MAINWINDOW_VERSION = 1;
+
 namespace Config {
 namespace Groups {
 const char MainWindow[] = "MainWindow";
@@ -50,6 +52,19 @@ namespace Entries {
 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)
@@ -99,7 +114,6 @@ 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) {
@@ -160,7 +174,6 @@ MainWindow::MainWindow(QWidget* parent)
     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,
@@ -186,9 +199,48 @@ MainWindow::MainWindow(QWidget* parent)
     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));
@@ -199,6 +251,7 @@ MainWindow::MainWindow(QWidget* parent)
             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();
@@ -213,7 +266,8 @@ MainWindow::MainWindow(QWidget* parent)
             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);
@@ -221,34 +275,12 @@ MainWindow::MainWindow(QWidget* parent)
             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();
 }
index d9c83ba..d3e2d31 100644 (file)
@@ -43,6 +43,8 @@ public slots:
     void openFile();
 
 private:
+    void setupStacks();
+
     QScopedPointer<Ui::MainWindow> m_ui;
     Parser* m_parser;
     KSharedConfig::Ptr m_config;
index 4e23005..0d42055 100644 (file)
@@ -6,7 +6,7 @@
    <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>
index ffd596d..c3deb12 100644 (file)
@@ -300,20 +300,20 @@ QString generateSummary(const ParserData& data)
     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;
 }
 
diff --git a/gui/topproxy.cpp b/gui/topproxy.cpp
new file mode 100644 (file)
index 0000000..0855256
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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();
+}
diff --git a/gui/topproxy.h b/gui/topproxy.h
new file mode 100644 (file)
index 0000000..083a5b1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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