File indexing completed on 2024-04-28 17:02:21

0001 /*
0002    This file is part of Massif Visualizer
0003 
0004    Copyright 2014 Milian Wolff <mail@milianw.de>
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public License as
0008    published by the Free Software Foundation; either version 2 of
0009    the License or (at your option) version 3 or any later version
0010    accepted by the membership of KDE e.V. (or its successor approved
0011    by the membership of KDE e.V.), which shall act as a proxy
0012    defined in Section 14 of version 3 of the license.
0013 
0014    This program is distributed in the hope that it will be useful,
0015    but WITHOUT ANY WARRANTY; without even the implied warranty of
0016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017    GNU General Public License for more details.
0018 
0019    You should have received a copy of the GNU General Public License
0020    along with this program.  If not, see <http://www.gnu.org/licenses/>.
0021 */
0022 
0023 #include "allocatorsmodel.h"
0024 
0025 #include "massifdata/snapshotitem.h"
0026 #include "massifdata/filedata.h"
0027 #include "massifdata/treeleafitem.h"
0028 
0029 #include <KLocalizedString>
0030 
0031 using namespace Massif;
0032 
0033 namespace {
0034 
0035 ParsedLabel labelForNode(const TreeLeafItem* node)
0036 {
0037     ParsedLabel label;
0038     if (!isBelowThreshold(node->label())) {
0039         label = parseLabel(node->label());
0040         label.address.clear();
0041     }
0042     return label;
0043 }
0044 
0045 }
0046 
0047 AllocatorsModel::AllocatorsModel(const FileData* data, QObject* parent)
0048     : QAbstractItemModel(parent)
0049 {
0050     m_data.reserve(1024);
0051 
0052     QHash<ParsedLabel, int> labelToData;
0053     foreach (const SnapshotItem* snapshot, data->snapshots()) {
0054         if (!snapshot->heapTree()) {
0055             continue;
0056         }
0057         foreach (const TreeLeafItem* node, snapshot->heapTree()->children()) {
0058             const ParsedLabel label = labelForNode(node);
0059 
0060             int idx = labelToData.value(label, -1);
0061             if (idx == -1) {
0062                 idx = m_data.size();
0063                 labelToData[label] = idx;
0064                 Data data;
0065                 data.label = label;
0066                 data.peak = node;
0067                 m_data << data;
0068             }
0069 
0070             Data& data = m_data[idx];
0071             if (data.peak->cost() < node->cost()) {
0072                 data.peak = node;
0073             }
0074         }
0075     }
0076 }
0077 
0078 AllocatorsModel::~AllocatorsModel()
0079 {
0080 
0081 }
0082 
0083 int AllocatorsModel::columnCount(const QModelIndex& parent) const
0084 {
0085     if (parent.isValid()) {
0086         return 0;
0087     }
0088     return NUM_COLUMNS;
0089 }
0090 
0091 int AllocatorsModel::rowCount(const QModelIndex& parent) const
0092 {
0093     if (parent.isValid()) {
0094         return 0;
0095     }
0096     return m_data.size();
0097 }
0098 
0099 QModelIndex AllocatorsModel::index(int row, int column, const QModelIndex& parent) const
0100 {
0101     if (parent.isValid() || row < 0 || column < 0 || row >= m_data.size() || column >= NUM_COLUMNS) {
0102         return QModelIndex();
0103     }
0104     return createIndex(row, column);
0105 }
0106 
0107 QModelIndex AllocatorsModel::parent(const QModelIndex& /*child*/) const
0108 {
0109     return QModelIndex();
0110 }
0111 
0112 QVariant AllocatorsModel::data(const QModelIndex& index, int role) const
0113 {
0114     if (role != Qt::DisplayRole && role != Qt::ToolTipRole && role != SortRole && role != ItemRole) {
0115         return QVariant();
0116     }
0117 
0118     if (!index.isValid() || index.parent().isValid() || index.row() < 0 || index.row() >= m_data.size()
0119         || index.column() < 0 || index.column() >= NUM_COLUMNS)
0120     {
0121         return QVariant();
0122     }
0123 
0124     const Data& data = m_data.value(index.row());
0125 
0126     if (role == Qt::ToolTipRole) {
0127         QString tooltip = i18n("<dt>peak cost:</dt><dd>%1</dd>", prettyCost(data.peak->cost()));
0128         tooltip += formatLabelForTooltip(data.label);
0129         return finalizeTooltip(tooltip);
0130     } else if (role == ItemRole) {
0131         return QVariant::fromValue(ModelItem(data.peak, 0));
0132     }
0133 
0134     switch (index.column()) {
0135         case Function:
0136             if (data.label.function.isEmpty()) {
0137                 return i18n("below threshold");
0138             }
0139             return shortenTemplates(data.label.function);
0140         case Location:
0141             return data.label.location;
0142         case Peak:
0143             if (role == SortRole) {
0144                 return data.peak->cost();
0145             }
0146             return prettyCost(data.peak->cost());
0147     }
0148 
0149     return QVariant();
0150 }
0151 
0152 QVariant AllocatorsModel::headerData(int section, Qt::Orientation orientation, int role) const
0153 {
0154     if (role != Qt::DisplayRole || orientation != Qt::Horizontal || section < 0 || section >= NUM_COLUMNS) {
0155         return QVariant();
0156     }
0157 
0158     switch (section) {
0159         case Function:
0160             return i18n("Function");
0161         case Location:
0162             return i18n("Location");
0163         case Peak:
0164             return i18n("Peak");
0165     }
0166 
0167     return QVariant();
0168 }
0169 
0170 QModelIndex AllocatorsModel::indexForItem(const ModelItem& item) const
0171 {
0172     if (!item.first) {
0173         return QModelIndex();
0174     }
0175 
0176     const ParsedLabel label = labelForNode(item.first);
0177 
0178     for (int i = 0; i < m_data.size(); ++i) {
0179         if (m_data[i].label == label) {
0180             return createIndex(i, Function);
0181         }
0182     }
0183 
0184     return QModelIndex();
0185 }
0186 
0187 void AllocatorsModel::settingsChanged()
0188 {
0189     if (m_data.isEmpty()) {
0190         return;
0191     }
0192     // update shorten templates
0193     dataChanged(createIndex(0, Function),
0194                 createIndex(m_data.size() - 1, Function));
0195 }