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

0001 /*
0002    This file is part of Massif Visualizer
0003 
0004    Copyright 2010 Milian Wolff <mail@milianw.de>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Lesser General Public
0008    License as published by the Free Software Foundation; either
0009    version 2.1 of the License, or (at your option) version 3, or any
0010    later version accepted by the membership of KDE e.V. (or its
0011    successor approved by the membership of KDE e.V.), which shall
0012    act as a proxy defined in Section 6 of version 3 of the license.
0013 
0014    This library 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 GNU
0017    Lesser General Public License for more details.
0018 
0019    You should have received a copy of the GNU Lesser General Public
0020    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0021 */
0022 
0023 #include "util.h"
0024 
0025 #include "snapshotitem.h"
0026 #include "treeleafitem.h"
0027 
0028 #include <KSharedConfig>
0029 #include <KLocalizedString>
0030 #include <KConfigGroup>
0031 #include <KFormat>
0032 
0033 namespace Massif {
0034 
0035 QString prettyCost(quint64 cost)
0036 {
0037     Q_ASSERT(KSharedConfig::openConfig());
0038     KConfigGroup conf = KSharedConfig::openConfig()->group(QLatin1String("Settings"));
0039     int precision = conf.readEntry(QLatin1String("prettyCostPrecision"), 1);
0040     KFormat format(QLocale::system());
0041     return format.formatByteSize(cost, precision);
0042 }
0043 
0044 QByteArray shortenTemplates(const QByteArray& identifier)
0045 {
0046     QByteArray ret = identifier;
0047     Q_ASSERT(KSharedConfig::openConfig());
0048     KConfigGroup conf = KSharedConfig::openConfig()->group(QLatin1String("Settings"));
0049     if (conf.readEntry(QLatin1String("shortenTemplates"), false)) {
0050         // remove template arguments between <...>
0051         int depth = 0;
0052         int open = 0;
0053         for (int i = 0; i < ret.length(); ++i) {
0054             if (ret.at(i) == '<') {
0055                 if (!depth) {
0056                     open = i;
0057                 }
0058                 ++depth;
0059             } else if (ret.at(i) == '>') {
0060                 --depth;
0061                 if (!depth) {
0062                     ret.remove(open + 1, i - open - 1);
0063                     i = open + 1;
0064                     open = 0;
0065                 }
0066             }
0067         }
0068     }
0069     return ret;
0070 }
0071 
0072 ParsedLabel parseLabel(const QByteArray& label)
0073 {
0074     ParsedLabel ret;
0075     int functionStart = 0;
0076     int functionEnd = label.length();
0077     if (label.startsWith("0x")) {
0078         int colonPos = label.indexOf(": ");
0079         if (colonPos != -1) {
0080             ret.address = label.left(colonPos);
0081             functionStart = colonPos + 2;
0082         }
0083     }
0084     if (label.endsWith(')')) {
0085         int locationPos = label.lastIndexOf(" (");
0086         if (locationPos != -1) {
0087             ret.location = label.mid(locationPos + 2, label.length() - locationPos - 3);
0088             functionEnd = locationPos;
0089         }
0090     }
0091     ret.function = label.mid(functionStart, functionEnd - functionStart);
0092     return ret;
0093 }
0094 
0095 uint qHash(const ParsedLabel& label)
0096 {
0097     return qHash(label.function) + 17 * qHash(label.location) + 19 * qHash(label.address);
0098 }
0099 
0100 QByteArray prettyLabel(const QByteArray& label)
0101 {
0102     ParsedLabel parsed = parseLabel(label);
0103     const QByteArray func = shortenTemplates(parsed.function);
0104 
0105     if (!parsed.location.isEmpty()) {
0106         return func + " (" + parsed.location + ")";
0107     } else {
0108         return func;
0109     }
0110 }
0111 
0112 QByteArray functionInLabel(const QByteArray& label)
0113 {
0114     return parseLabel(label).function;
0115 }
0116 
0117 QByteArray addressInLabel(const QByteArray& label)
0118 {
0119     return parseLabel(label).address;
0120 }
0121 
0122 QByteArray locationInLabel(const QByteArray& label)
0123 {
0124     return parseLabel(label).location;
0125 }
0126 
0127 bool isBelowThreshold(const QByteArray& label)
0128 {
0129     return label.indexOf("all below massif's threshold") != -1;
0130 }
0131 
0132 QString formatLabelForTooltip(const ParsedLabel& parsed)
0133 {
0134     QString ret;
0135     if (!parsed.function.isEmpty()) {
0136         ret += i18n("<dt>function:</dt><dd>%1</dd>\n", QString::fromUtf8(parsed.function).toHtmlEscaped());
0137     }
0138     if (!parsed.location.isEmpty()) {
0139         ret += i18n("<dt>location:</dt><dd>%1</dd>\n", QString::fromUtf8(parsed.location).toHtmlEscaped());
0140     }
0141     if (!parsed.address.isEmpty()) {
0142         ret += i18n("<dt>address:</dt><dd>%1</dd>\n", QString::fromUtf8(parsed.address).toHtmlEscaped());
0143     }
0144     return ret;
0145 }
0146 
0147 QString finalizeTooltip(const QString& contents)
0148 {
0149     return QLatin1String("<html><head><style>dt{font-weight:bold;} dd {font-family:monospace;}</style></head><body><dl>\n")
0150         + contents + QLatin1String("</dl></body></html>");
0151 }
0152 
0153 QString tooltipForTreeLeaf(const TreeLeafItem* node, const SnapshotItem* snapshot, const QByteArray& label)
0154 {
0155     QString tooltip = i18n("<dt>cost:</dt><dd>%1, i.e. %2% of snapshot #%3</dd>", prettyCost(node ? node->cost() : 0),
0156                     // yeah nice how I round to two decimals, right? :D
0157                     double(int(double(node ? node->cost() : 0)/snapshot->cost()*10000))/100, snapshot->number());
0158     tooltip += formatLabelForTooltip(parseLabel(label));
0159     return finalizeTooltip(tooltip);
0160 }
0161 
0162 }