File indexing completed on 2024-04-28 05:41:35

0001 /*
0002     This file is part of KCachegrind.
0003 
0004     SPDX-FileCopyrightText: 2003-2016 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only
0007 */
0008 
0009 /*
0010  * TracePart as Nested Area
0011  */
0012 
0013 #include "partgraph.h"
0014 
0015 #include <QPixmap>
0016 
0017 #include "globalguiconfig.h"
0018 #include "listutils.h"
0019 
0020 
0021 // PartAreaWidget
0022 
0023 PartAreaWidget::PartAreaWidget(QWidget* parent)
0024     : TreeMapWidget(new BasePartItem(), parent)
0025 {
0026     _data = nullptr;
0027     _function = nullptr;
0028 
0029     _eventType = nullptr;
0030     _groupType = ProfileContext::InvalidType;
0031     _visualization = NoVisualization;
0032     _zoomFunction = false;
0033     _callLevels = 1;
0034 }
0035 
0036 void PartAreaWidget::setData(TraceData* data)
0037 {
0038     if (data == _data) return;
0039 
0040     _data = data;
0041     _function = nullptr;
0042     _hiddenParts.clear();
0043 
0044     ((BasePartItem*)base())->setData(data);
0045 }
0046 
0047 void PartAreaWidget::changeHidden(const TracePartList& list)
0048 {
0049     _hiddenParts = list;
0050     base()->refresh();
0051 }
0052 
0053 
0054 void PartAreaWidget::setEventType(EventType* ct)
0055 {
0056     _eventType = ct;
0057 
0058     // this resizes items
0059     base()->redraw();
0060 }
0061 
0062 void PartAreaWidget::setVisualization(VisualizationMode m)
0063 {
0064     _visualization = m;
0065     refreshParts();
0066 }
0067 
0068 void PartAreaWidget::setZoomFunction(bool zoomFunction)
0069 {
0070     _zoomFunction = zoomFunction;
0071     refreshParts();
0072 }
0073 
0074 void PartAreaWidget::setCallLevels(int callLevels)
0075 {
0076     _callLevels = callLevels;
0077     refreshParts();
0078 }
0079 
0080 void PartAreaWidget::refreshParts()
0081 {
0082     // rebuild only subparts to keep part selection state
0083     TreeMapItemList* l = base()->children();
0084     if (l)
0085         foreach(TreeMapItem* i, *l)
0086             i->refresh();
0087 
0088     // but resize part areas
0089     base()->redraw();
0090 }
0091 
0092 
0093 void PartAreaWidget::setFunction(TraceFunction* f)
0094 {
0095     _function = f;
0096 
0097     if (_visualization == PartAreaWidget::Inclusive)
0098         refreshParts();
0099 }
0100 
0101 void PartAreaWidget::setGroupType(ProfileContext::Type gt)
0102 {
0103     _groupType = gt;
0104 
0105     // rebuild hierarchy below parts.
0106     // thus, selected parts stay selected
0107     TreeMapItemList* l = base()->children();
0108     if (l)
0109         foreach(TreeMapItem* i, *l)
0110             i->refresh();
0111 
0112     base()->redraw();
0113 }
0114 
0115 bool PartAreaWidget::isHidden(TracePart* part) const
0116 {
0117     return _hiddenParts.contains(part);
0118 }
0119 
0120 QColor PartAreaWidget::groupColor(TraceFunction* f) const
0121 {
0122     if (!f)
0123         return palette().color( QPalette::Button );
0124 
0125     return GlobalGUIConfig::functionColor(_groupType, f);
0126 }
0127 
0128 QString PartAreaWidget::tipString(TreeMapItem* i) const
0129 {
0130     QString tip, itemTip;
0131     int count = 0;
0132 
0133     //qDebug("PartAreaWidget::tipString for '%s'", i->name().toAscii());
0134 
0135     // first, SubPartItem's
0136     while (i && count<GlobalConfig::maxSymbolCount() && i->rtti() == 3) {
0137         itemTip = GlobalConfig::shortenSymbol(i->text(0));
0138 
0139         if (!i->text(1).isEmpty())
0140             itemTip += " (" + i->text(1) + ')';
0141 
0142         if (!tip.isEmpty())
0143             itemTip += '\n';
0144 
0145         tip = itemTip + tip;
0146         i = i->parent();
0147         count++;
0148     }
0149 
0150     // skip to part
0151     while (i && i->rtti()==3) i = i->parent();
0152 
0153     if (i && i->rtti()==2) {
0154         itemTip = QObject::tr("Profile Part %1").arg(i->text(0));
0155         if (!i->text(1).isEmpty())
0156             itemTip += " (" + i->text(1) + ')';
0157 
0158         if (!tip.isEmpty())
0159             itemTip += '\n';
0160 
0161         tip = itemTip + tip;
0162     }
0163 
0164     //  qDebug("PartAreaWidget:: tip %s, itemTip %s",
0165     //         tip.toAscii(), itemTip.toAscii());
0166 
0167     return tip;
0168 }
0169 
0170 
0171 
0172 
0173 
0174 // BasePartItem
0175 
0176 BasePartItem::BasePartItem()
0177     : TreeMapItem()
0178 {
0179     _data = nullptr;
0180     setSorting(-1);
0181 }
0182 
0183 void BasePartItem::setData(TraceData* data)
0184 {
0185     if (data == _data) return;
0186 
0187     _data = data;
0188     refresh();
0189 }
0190 
0191 TreeMapItemList* BasePartItem::children()
0192 {
0193     if (!_data) return _children;
0194 
0195     if (!initialized()) {
0196         //    qDebug("Create Parts (%s)", name().toAscii());
0197 
0198         PartAreaWidget* w = (PartAreaWidget*) widget();
0199         foreach(TracePart* part, _data->parts())
0200             if (!w->isHidden(part))
0201                 addItem(new PartItem(part));
0202     }
0203 
0204     return _children;
0205 }
0206 
0207 QString BasePartItem::text(int textNo) const
0208 {
0209     if (textNo == 0) {
0210         if (!_data)
0211             return QObject::tr("(no trace)");
0212 
0213         if (_data->parts().isEmpty())
0214             return QObject::tr("(no part)");
0215     }
0216     return QString();
0217 }
0218 
0219 
0220 QColor BasePartItem::backColor() const
0221 {
0222     return widget()->palette().base().color();
0223 }
0224 
0225 double BasePartItem::value() const
0226 {
0227     if (!_data) return 0;
0228 
0229     PartAreaWidget* w = (PartAreaWidget*) widget();
0230     return (double)_data->subCost(w->eventType());
0231 }
0232 
0233 
0234 
0235 
0236 
0237 // PartItem
0238 
0239 PartItem::PartItem(TracePart* p)
0240 {
0241     _p = p;
0242     _factor=1;
0243 }
0244 
0245 QString PartItem::text(int textNo) const
0246 {
0247     if (textNo == 0)
0248         return _p->prettyName();
0249 
0250     if (textNo != 1)
0251         return QString();
0252 
0253     EventType* ct;
0254     PartAreaWidget* w = (PartAreaWidget*)widget();
0255     SubCost v;
0256 
0257     ct = w->eventType();
0258     v = _p->subCost(ct);
0259 
0260     if (GlobalConfig::showPercentage()) {
0261         ProfileCostArray* t = _p->data()->totals();
0262         double p  = 100.0 * v / t->subCost(ct);
0263         return QStringLiteral("%1 %")
0264                 .arg(p, 0, 'f', GlobalConfig::percentPrecision());
0265     }
0266     return v.pretty();
0267 }
0268 
0269 
0270 QPixmap PartItem::pixmap(int i) const
0271 {
0272     if (i != 1) return QPixmap();
0273 
0274     // Cost pixmap
0275 
0276     EventType* ct = ((PartAreaWidget*)widget())->eventType();
0277     return costPixmap( ct, _p, (double) (_p->data()->totals()->subCost(ct)), false );
0278 }
0279 
0280 
0281 double PartItem::value() const
0282 {
0283     PartAreaWidget* w = (PartAreaWidget*)widget();
0284     EventType* ct = w->eventType();
0285     if ((w->visualization() == PartAreaWidget::Inclusive) &&
0286         w->zoomFunction()) {
0287 
0288         // use value of zoomed function
0289         TraceFunction* f = w->function();
0290         if (f) {
0291             TracePartFunction* pf = (TracePartFunction*) f->findDepFromPart(_p);
0292             if (pf)
0293                 return (double) pf->inclusive()->subCost(ct);
0294             // when function is not available in part, hide part
0295             return 0.0;
0296         }
0297     }
0298     return (double) _p->subCost(ct);
0299 }
0300 
0301 double PartItem::sum() const
0302 {
0303     PartAreaWidget* w = (PartAreaWidget*)widget();
0304     if (w->visualization() == PartAreaWidget::Inclusive) {
0305         double s = value();
0306         //qDebug("PartItem::sum [part %s]: %d", _p->name().toAscii(), s);
0307         return s;
0308     }
0309     return 0.0;
0310 }
0311 
0312 TreeMapItemList* PartItem::children()
0313 {
0314     if (initialized()) return _children;
0315 
0316     ProfileCostArray* c;
0317     //    qDebug("Create Part subitems (%s)", name().toAscii());
0318 
0319     PartAreaWidget* w = (PartAreaWidget*)widget();
0320     if (w->visualization() == PartAreaWidget::Inclusive) {
0321         TraceFunction* f = w->function();
0322         if (f) {
0323             c = f->findDepFromPart(_p);
0324             if (c) addItem(new SubPartItem(c));
0325         }
0326 
0327         return _children;
0328     }
0329 
0330 
0331     switch( ((PartAreaWidget*)widget())->groupType() ) {
0332 
0333     case ProfileContext::Object:
0334     {
0335         TraceObjectMap::Iterator it;
0336         for ( it = _p->data()->objectMap().begin();
0337               it != _p->data()->objectMap().end(); ++it ) {
0338             c = (*it).findDepFromPart(_p);
0339             if (c)
0340                 addItem(new SubPartItem(c));
0341         }
0342     }
0343         break;
0344 
0345     case ProfileContext::Class:
0346     {
0347         TraceClassMap::Iterator it;
0348         for ( it = _p->data()->classMap().begin();
0349               it != _p->data()->classMap().end(); ++it ) {
0350             c = (*it).findDepFromPart(_p);
0351             if (c)
0352                 addItem(new SubPartItem(c));
0353         }
0354     }
0355         break;
0356 
0357     case ProfileContext::File:
0358     {
0359         TraceFileMap::Iterator it;
0360         for ( it = _p->data()->fileMap().begin();
0361               it != _p->data()->fileMap().end(); ++it ) {
0362             c = (*it).findDepFromPart(_p);
0363             if (c)
0364                 addItem(new SubPartItem(c));
0365         }
0366     }
0367         break;
0368 
0369     case ProfileContext::Function:
0370     {
0371         TraceFunctionMap::Iterator it;
0372         for ( it = _p->data()->functionMap().begin();
0373               it != _p->data()->functionMap().end(); ++it ) {
0374             c = (*it).findDepFromPart(_p);
0375             if (c)
0376                 addItem(new SubPartItem(c));
0377         }
0378     }
0379         break;
0380 
0381     default:
0382         break;
0383     }
0384 
0385     return _children;
0386 }
0387 
0388 
0389 QColor PartItem::backColor() const
0390 {
0391     PartAreaWidget* w = (PartAreaWidget*)widget();
0392     return w->groupColor(nullptr);
0393 }
0394 
0395 
0396 // SubPartItem
0397 
0398 SubPartItem::SubPartItem(ProfileCostArray* c)
0399 {
0400     _partCostItem = c;
0401     _factor=1;
0402 }
0403 
0404 QString SubPartItem::text(int textNo) const
0405 {
0406     if (textNo == 0) {
0407         if (!_partCostItem)
0408             return QObject::tr("(unknown)");
0409 
0410         return _partCostItem->dependent()->prettyName();
0411     }
0412 
0413     if (textNo != 1)
0414         return QString();
0415 
0416     EventType* ct;
0417     PartAreaWidget* w = (PartAreaWidget*)widget();
0418     SubCost v;
0419 
0420     ct = w->eventType();
0421     if (w->visualization() == PartAreaWidget::Inclusive)
0422         v = ((TracePartFunction*)_partCostItem)->inclusive()->subCost(ct);
0423     else
0424         v = _partCostItem->subCost(ct);
0425 
0426     if (GlobalConfig::showPercentage()) {
0427         ProfileCostArray* t = GlobalConfig::showExpanded() ?
0428                                   _partCostItem->part() : _partCostItem->part()->data()->totals();
0429         double p  = 100.0 * v / t->subCost(ct);
0430         return QStringLiteral("%1 %")
0431                 .arg(p, 0, 'f', GlobalConfig::percentPrecision());
0432     }
0433     return v.pretty();
0434 }
0435 
0436 QPixmap SubPartItem::pixmap(int i) const
0437 {
0438     if (i != 1) return QPixmap();
0439 
0440     // Cost pixmap
0441 
0442     PartAreaWidget* w = (PartAreaWidget*)widget();
0443     EventType* ct = w->eventType();
0444     ProfileCostArray* t = GlobalConfig::showExpanded() ?
0445                               _partCostItem->part() : _partCostItem->part()->data()->totals();
0446     ProfileCostArray* c;
0447     if (w->visualization() == PartAreaWidget::Inclusive)
0448         c = ((TracePartFunction*)_partCostItem)->inclusive();
0449     else
0450         c = _partCostItem;
0451 
0452     return costPixmap( ct, c, (double) (t->subCost(ct)), false );
0453 }
0454 
0455 double SubPartItem::value() const
0456 {
0457     EventType* ct;
0458     PartAreaWidget* w = (PartAreaWidget*)widget();
0459 
0460     ct = w->eventType();
0461     if (w->visualization() == PartAreaWidget::Inclusive)
0462         return (double)
0463                 ((TracePartFunction*)_partCostItem)->inclusive()->subCost(ct);
0464 
0465     return (double) _partCostItem->subCost(ct);
0466 }
0467 
0468 double SubPartItem::sum() const
0469 {
0470     PartAreaWidget* w = (PartAreaWidget*)widget();
0471     if (w->visualization() == PartAreaWidget::Inclusive) {
0472         double s = value();
0473         //qDebug("SubPartItem::sum [Cost %s]: %d", _cost->name().toAscii(), s);
0474         return s;
0475     }
0476     return 0.0;
0477 }
0478 
0479 TreeMapItemList* SubPartItem::children()
0480 {
0481     if (!initialized()) {
0482         //    qDebug("Create Part sub-subitems (%s)", name().toAscii());
0483 
0484         PartAreaWidget* w = (PartAreaWidget*)widget();
0485 
0486         if (depth()-2 > w->callLevels())
0487             return _children;
0488 
0489         if (w->visualization() == PartAreaWidget::Inclusive) {
0490             setSum(value());
0491 
0492             TracePartCallList l;
0493             l = ((TracePartFunction*)_partCostItem)->partCallings();
0494             foreach(TracePartCall* call, l) {
0495                 TraceFunction* called = call->call()->called();
0496                 ProfileCostArray* partCalled = called->findDepFromPart(call->part());
0497                 if (partCalled)
0498                     addItem(new SubPartItem(partCalled));
0499             }
0500         }
0501     }
0502 
0503     return _children;
0504 }
0505 
0506 
0507 QColor SubPartItem::backColor() const
0508 {
0509     PartAreaWidget* w = (PartAreaWidget*)widget();
0510     if (w->visualization() == PartAreaWidget::Inclusive)
0511         return w->groupColor((TraceFunction*)(_partCostItem->dependent()));
0512 
0513     return GlobalGUIConfig::groupColor(_partCostItem->dependent());
0514 }
0515 
0516 #include "moc_partgraph.cpp"