File indexing completed on 2024-04-28 05:41:31
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 * Call Map View 0011 */ 0012 0013 0014 #include "callmapview.h" 0015 0016 #include <QPixmap> 0017 #include <QAction> 0018 #include <QMenu> 0019 0020 #include "config.h" 0021 #include "globalguiconfig.h" 0022 #include "listutils.h" 0023 #include "toplevelbase.h" 0024 0025 0026 // 0027 // CallMapView 0028 // 0029 0030 0031 // defaults 0032 #define DEFAULT_SPLITMODE "Rows" 0033 #define DEFAULT_DRAWNAME true 0034 #define DEFAULT_DRAWCOST true 0035 #define DEFAULT_DRAWLOCATION false 0036 #define DEFAULT_DRAWCALLS false 0037 #define DEFAULT_FORCESTRINGS false 0038 #define DEFAULT_ROTATION true 0039 #define DEFAULT_SHADING true 0040 #define DEFAULT_STOPNAME "" 0041 #define DEFAULT_MAXDEPTH -1 0042 #define DEFAULT_MAXAREA 100 0043 0044 0045 CallMapView::CallMapView(bool showCallers, TraceItemView* parentView, 0046 QWidget* parent, const QString& name) 0047 : TreeMapWidget(new CallMapRootItem(), parent), TraceItemView(parentView) 0048 { 0049 setObjectName(name); 0050 _showCallers = showCallers; 0051 0052 setFieldType(0, tr("A thing's name", "Name" )); 0053 setFieldType(1, tr( "Cost" )); 0054 setFieldType(2, tr( "Location" )); 0055 setFieldPosition(2, TreeMapItem::TopLeft); 0056 setFieldType(3, tr( "Calls" )); 0057 setFieldPosition(3, TreeMapItem::TopRight); 0058 0059 setSplitMode(DEFAULT_SPLITMODE); 0060 setFieldVisible(0, DEFAULT_DRAWNAME); 0061 setFieldVisible(1, DEFAULT_DRAWCOST); 0062 setFieldVisible(2, DEFAULT_DRAWLOCATION); 0063 setFieldVisible(3, DEFAULT_DRAWCALLS); 0064 setFieldForced(0, DEFAULT_FORCESTRINGS); 0065 setFieldForced(1, DEFAULT_FORCESTRINGS); 0066 setFieldForced(2, DEFAULT_FORCESTRINGS); 0067 setFieldForced(3, DEFAULT_FORCESTRINGS); 0068 setAllowRotation(DEFAULT_ROTATION); 0069 setShadingEnabled(DEFAULT_SHADING); 0070 setMinimalArea(DEFAULT_MAXAREA); 0071 0072 connect(this, 0073 &TreeMapWidget::doubleClicked, 0074 this, &CallMapView::activatedSlot); 0075 connect(this, 0076 &TreeMapWidget::returnPressed, 0077 this, &CallMapView::activatedSlot); 0078 connect(this, 0079 &TreeMapWidget::currentChanged, 0080 this, &CallMapView::selectedSlot); 0081 connect(this, 0082 &TreeMapWidget::contextMenuRequested, 0083 this, &CallMapView::context); 0084 0085 this->setWhatsThis( whatsThis()); 0086 } 0087 0088 QString CallMapView::whatsThis() const 0089 { 0090 QString s = _showCallers ? 0091 tr( "<b>Caller Map</b>" 0092 "<p>This graph shows the nested hierarchy of " 0093 "all callers of the current activated function. " 0094 "Each colored rectangle represents a function; " 0095 "its size tries to be proportional to the cost spent " 0096 "therein while the active function is running " 0097 "(however, there are drawing constraints).</p>") : 0098 tr("<b>Call Map</b>" 0099 "<p>This graph shows the nested hierarchy of " 0100 "all callees of the current activated function. " 0101 "Each colored rectangle represents a function; " 0102 "its size tries to be proportional to the cost spent " 0103 "therein while the active function is running " 0104 "(however, there are drawing constraints).</p>"); 0105 0106 s += tr( "<p>Appearance options can be found in the " 0107 "context menu. To get exact size proportions, " 0108 "choose 'Hide incorrect borders'. As this mode can be " 0109 "<em>very</em> time consuming, you may want to limit " 0110 "the maximum drawn nesting level before. " 0111 "'Best' determinates the split direction for children " 0112 "from the aspect ratio of the parent. " 0113 "'Always Best' decides on remaining space for each " 0114 "sibling. " 0115 "'Ignore Proportions' takes space for function name " 0116 "drawing <em>before</em> drawing children. Note that " 0117 "size proportions can get <em>heavily</em> wrong.</p>" 0118 0119 "<p>This is a <em>TreeMap</em> widget. " 0120 "Keyboard navigation is available with the left/right arrow " 0121 "keys for traversing siblings, and up/down arrow keys " 0122 "to go a nesting level up/down. " 0123 "<em>Return</em> activates the current item.</p>"); 0124 0125 return s; 0126 } 0127 0128 void CallMapView::setData(TraceData* d) 0129 { 0130 TraceItemView::setData(d); 0131 0132 ((CallMapRootItem*)base())->setFunction(nullptr); 0133 } 0134 0135 void CallMapView::addItemListMenu(QMenu* menu, TreeMapItem* item) 0136 { 0137 QAction* a; 0138 0139 QMenu* m = menu->addMenu(tr("Go To")); 0140 int count = 0; 0141 while (count<GlobalConfig::maxSymbolCount() && item) { 0142 QString name = item->text(IDX_FUNCNAME); 0143 a = m->addAction(GlobalConfig::shortenSymbol(name)); 0144 a->setData(QVariant::fromValue( (void*)item )); 0145 item = item->parent(); 0146 count++; 0147 } 0148 connect(m, &QMenu::triggered, 0149 this, &CallMapView::mapItemTriggered ); 0150 } 0151 0152 void CallMapView::mapItemTriggered(QAction* a) 0153 { 0154 activatedSlot( (TreeMapItem*) a->data().value<void*>() ); 0155 } 0156 0157 QAction* CallMapView::addDrawingDepthAction(QMenu* m, 0158 const QString& s, int d) 0159 { 0160 QAction* a = m->addAction(s); 0161 a->setData(d); 0162 a->setCheckable(true); 0163 a->setChecked(maxDrawingDepth() == d); 0164 return a; 0165 } 0166 0167 void CallMapView::addDrawingDepthMenu(QMenu* menu, 0168 TreeMapItem* i, const QString& name) 0169 { 0170 QMenu* m = menu->addMenu(tr("Stop at Depth")); 0171 addDrawingDepthAction(m, tr("No Depth Limit"), -1); 0172 m->addSeparator(); 0173 addDrawingDepthAction(m, tr("Depth 10"), 10); 0174 addDrawingDepthAction(m, tr("Depth 15"), 15); 0175 addDrawingDepthAction(m, tr("Depth 20"), 20); 0176 if (i) { 0177 m->addSeparator(); 0178 addDrawingDepthAction(m, tr("Depth of '%1' (%2)") 0179 .arg(name).arg(i->depth()), 0180 i->depth()); 0181 } 0182 int maxDepth = maxDrawingDepth(); 0183 if (maxDepth>0) { 0184 m->addSeparator(); 0185 addDrawingDepthAction(m, tr("Decrement Depth (to %1)").arg(maxDepth-1), 0186 maxDepth-1); 0187 addDrawingDepthAction(m, tr("Increment Depth (to %1)").arg(maxDepth+1), 0188 maxDepth+1); 0189 } 0190 0191 connect(m, &QMenu::triggered, 0192 this, &CallMapView::drawingDepthTriggered ); 0193 } 0194 0195 void CallMapView::drawingDepthTriggered(QAction* a) 0196 { 0197 setMaxDrawingDepth(a->data().toInt()); 0198 } 0199 0200 QAction* CallMapView::addStopFunctionAction(QMenu* m, 0201 const QString& s, 0202 const QString& v) 0203 { 0204 QAction* a = m->addAction(s); 0205 a->setData(v); 0206 a->setCheckable(true); 0207 a->setChecked(fieldStop(IDX_FUNCNAME) == v); 0208 return a; 0209 } 0210 0211 void CallMapView::addStopFunctionMenu(QMenu* menu, TreeMapItem* item) 0212 { 0213 QMenu* m = menu->addMenu(tr("Stop at Function")); 0214 addStopFunctionAction(m, tr("No Function Limit"), QString()); 0215 0216 bool foundStopName = false; 0217 QAction* a; 0218 if (item) { 0219 m->addSeparator(); 0220 int count = 0; 0221 while (count<GlobalConfig::maxSymbolCount() && item) { 0222 QString name = GlobalConfig::shortenSymbol(item->text(IDX_FUNCNAME)); 0223 a = addStopFunctionAction(m, name, item->text(IDX_FUNCNAME)); 0224 if (a->isChecked()) foundStopName = true; 0225 item = item->parent(); 0226 count++; 0227 } 0228 } 0229 if (!foundStopName && !fieldStop(IDX_FUNCNAME).isEmpty()) { 0230 m->addSeparator(); 0231 QString name = GlobalConfig::shortenSymbol(fieldStop(IDX_FUNCNAME)); 0232 addStopFunctionAction(m, name, fieldStop(IDX_FUNCNAME)); 0233 } 0234 0235 connect(m, &QMenu::triggered, 0236 this, &CallMapView::stopFunctionTriggered ); 0237 } 0238 0239 void CallMapView::stopFunctionTriggered(QAction* a) 0240 { 0241 setFieldStop(IDX_FUNCNAME, a->data().toString()); 0242 } 0243 0244 QAction* CallMapView::addAreaLimitAction(QMenu* m, 0245 const QString& s, int v) 0246 { 0247 QAction* a = m->addAction(s); 0248 a->setData(v); 0249 a->setCheckable(true); 0250 a->setChecked(minimalArea() == v); 0251 return a; 0252 } 0253 0254 void CallMapView::addAreaLimitMenu(QMenu* menu, TreeMapItem* i, 0255 const QString& name) 0256 { 0257 QMenu* m = menu->addMenu(tr("Stop at Area")); 0258 addAreaLimitAction(m, tr("No Area Limit"), -1); 0259 m->addSeparator(); 0260 addAreaLimitAction(m, tr("100 Pixels"), 100); 0261 addAreaLimitAction(m, tr("200 Pixels"), 200); 0262 addAreaLimitAction(m, tr("500 Pixels"), 500); 0263 addAreaLimitAction(m, tr("1000 Pixels"), 1000); 0264 0265 int currentArea = 0; 0266 if (i) { 0267 currentArea = i->width() * i->height(); 0268 m->addSeparator(); 0269 addAreaLimitAction(m, tr("Area of '%1' (%2)") 0270 .arg(name).arg(currentArea), currentArea); 0271 } 0272 int mArea = minimalArea(); 0273 if (mArea>0) { 0274 m->addSeparator(); 0275 addAreaLimitAction(m, tr("Double Area Limit (to %1)") 0276 .arg(mArea*2), mArea*2); 0277 addAreaLimitAction(m, tr("Half Area Limit (to %1)") 0278 .arg(mArea/2), mArea/2); 0279 } 0280 0281 connect(m, &QMenu::triggered, 0282 this, &CallMapView::areaLimitTriggered ); 0283 } 0284 0285 void CallMapView::areaLimitTriggered(QAction* a) 0286 { 0287 setMinimalArea(a->data().toInt()); 0288 } 0289 0290 QAction* CallMapView::addBorderWidthAction(QMenu* m, const QString& s, int v) 0291 { 0292 QAction* a = m->addAction(s); 0293 a->setData(v); 0294 a->setCheckable(true); 0295 a->setChecked(borderWidth() == v); 0296 return a; 0297 } 0298 0299 void CallMapView::borderWidthTriggered(QAction* a) 0300 { 0301 setBorderWidth(a->data().toInt()); 0302 } 0303 0304 void CallMapView::context(TreeMapItem* i,const QPoint & p) 0305 { 0306 if (!i) return; 0307 0308 QMenu popup; 0309 QAction* a; 0310 0311 QString shortCurrentName; 0312 if (i) { 0313 shortCurrentName = GlobalConfig::shortenSymbol(i->text(IDX_FUNCNAME)); 0314 } 0315 0316 if (i) { 0317 addItemListMenu(&popup, i); 0318 popup.addSeparator(); 0319 } 0320 addGoMenu(&popup); 0321 popup.addSeparator(); 0322 addDrawingDepthMenu(&popup, i, shortCurrentName); 0323 addStopFunctionMenu(&popup, i); 0324 addAreaLimitMenu(&popup, i, shortCurrentName); 0325 popup.addSeparator(); 0326 0327 QMenu* vpopup = popup.addMenu(tr("Visualization")); 0328 QMenu* spopup = vpopup->addMenu(tr("Split Direction")); 0329 addSplitDirectionItems(spopup); 0330 0331 QAction* skipBorderAction = vpopup->addAction(tr("Skip Incorrect Borders")); 0332 skipBorderAction->setEnabled(!_showCallers); 0333 skipBorderAction->setCheckable(true); 0334 skipBorderAction->setChecked(skipIncorrectBorder()); 0335 0336 QMenu* bpopup = vpopup->addMenu(tr("Border Width")); 0337 a = addBorderWidthAction(bpopup, tr("Border 0"), 0); 0338 a->setEnabled(!_showCallers); 0339 addBorderWidthAction(bpopup, tr("Border 1"), 1); 0340 addBorderWidthAction(bpopup, tr("Border 2"), 2); 0341 addBorderWidthAction(bpopup, tr("Border 3"), 3); 0342 connect(bpopup, &QMenu::triggered, 0343 this, &CallMapView::borderWidthTriggered ); 0344 vpopup->addSeparator(); 0345 0346 QAction* drawNamesAction = vpopup->addAction(tr("Draw Symbol Names")); 0347 drawNamesAction->setCheckable(true); 0348 QAction* drawCostAction = vpopup->addAction(tr("Draw Cost")); 0349 drawCostAction->setCheckable(true); 0350 QAction* drawLocationAction = vpopup->addAction(tr("Draw Location")); 0351 drawLocationAction->setCheckable(true); 0352 QAction* drawCallsAction = vpopup->addAction(tr("Draw Calls")); 0353 drawCallsAction->setCheckable(true); 0354 vpopup->addSeparator(); 0355 0356 QAction* ignorePropAction = vpopup->addAction(tr("Ignore Proportions")); 0357 ignorePropAction->setCheckable(true); 0358 QAction* allowRotationAction = vpopup->addAction(tr("Allow Rotation")); 0359 allowRotationAction->setCheckable(true); 0360 if (!fieldVisible(0) && 0361 !fieldVisible(1) && 0362 !fieldVisible(2) && 0363 !fieldVisible(3)) { 0364 ignorePropAction->setEnabled(false); 0365 allowRotationAction->setEnabled(false); 0366 } 0367 else { 0368 drawNamesAction->setChecked(fieldVisible(IDX_FUNCNAME)); 0369 drawCostAction->setChecked(fieldVisible(IDX_COST)); 0370 drawLocationAction->setChecked(fieldVisible(IDX_LOCATION)); 0371 drawCallsAction->setChecked(fieldVisible(IDX_CALLCOUNT)); 0372 ignorePropAction->setChecked(fieldForced(0)); 0373 allowRotationAction->setChecked(allowRotation()); 0374 } 0375 0376 QAction* drawShadingAction = vpopup->addAction(tr("Shading")); 0377 drawShadingAction->setCheckable(true); 0378 drawShadingAction->setChecked(isShadingEnabled()); 0379 0380 a = popup.exec(mapToGlobal(p)); 0381 if (a == drawNamesAction) 0382 setFieldVisible(IDX_FUNCNAME, !fieldVisible(IDX_FUNCNAME)); 0383 else if (a == drawCostAction) 0384 setFieldVisible(IDX_COST, !fieldVisible(IDX_COST)); 0385 else if (a == drawLocationAction) 0386 setFieldVisible(IDX_LOCATION, !fieldVisible(IDX_LOCATION)); 0387 else if (a == drawCallsAction) 0388 setFieldVisible(IDX_CALLCOUNT, !fieldVisible(IDX_CALLCOUNT)); 0389 else if (a == ignorePropAction) { 0390 bool newSetting = !fieldForced(0); 0391 setFieldForced(0, newSetting); 0392 setFieldForced(1, newSetting); 0393 setFieldForced(2, newSetting); 0394 setFieldForced(3, newSetting); 0395 } 0396 else if (a == allowRotationAction) 0397 setAllowRotation(!allowRotation()); 0398 else if (a == drawShadingAction) 0399 setShadingEnabled(!isShadingEnabled()); 0400 else if (a == skipBorderAction) 0401 setSkipIncorrectBorder(!skipIncorrectBorder()); 0402 } 0403 0404 void CallMapView::activatedSlot(TreeMapItem* item) 0405 { 0406 if (!item) return; 0407 0408 if (item->rtti() == 1) { 0409 CallMapRootItem* bi = (CallMapRootItem*)item; 0410 activated(bi->function()); 0411 } 0412 else if (item->rtti() == 2) { 0413 CallMapCallingItem* ci = (CallMapCallingItem*)item; 0414 activated(ci->function()); 0415 } 0416 else if (item->rtti() == 3) { 0417 CallMapCallerItem* ci = (CallMapCallerItem*)item; 0418 activated(ci->function()); 0419 } 0420 } 0421 0422 void CallMapView::selectedSlot(TreeMapItem* item, bool kbd) 0423 { 0424 if (!item) return; 0425 if (item->text(IDX_FUNCNAME).isEmpty()) return; 0426 0427 if (kbd) { 0428 QString msg = tr("Call Map: Current is '%1'").arg(item->text(IDX_FUNCNAME)); 0429 if (_topLevel) 0430 _topLevel->showMessage(msg, 5000); 0431 } 0432 0433 TraceFunction* f = nullptr; 0434 0435 if (item->rtti() == 1) { 0436 CallMapRootItem* bi = (CallMapRootItem*)item; 0437 f = bi->function(); 0438 } 0439 else if (item->rtti() == 2) { 0440 CallMapCallingItem* ci = (CallMapCallingItem*)item; 0441 f = ci->function(); 0442 } 0443 else if (item->rtti() == 3) { 0444 CallMapCallerItem* ci = (CallMapCallerItem*)item; 0445 f = ci->function(); 0446 } 0447 if (f) { 0448 // this avoids marking 0449 _selectedItem = f; 0450 selected(f); 0451 } 0452 } 0453 0454 CostItem* CallMapView::canShow(CostItem* i) 0455 { 0456 ProfileContext::Type t = i ? i->type() : ProfileContext::InvalidType; 0457 0458 switch(t) { 0459 case ProfileContext::Function: 0460 case ProfileContext::FunctionCycle: 0461 return i; 0462 default: 0463 break; 0464 } 0465 return nullptr; 0466 } 0467 0468 void CallMapView::doUpdate(int changeType, bool) 0469 { 0470 if (changeType == eventType2Changed) return; 0471 0472 // if there is a selected item, always draw marking... 0473 if (changeType & selectedItemChanged) { 0474 TraceFunction* f = nullptr; 0475 0476 if (_selectedItem) { 0477 switch(_selectedItem->type()) { 0478 case ProfileContext::Function: 0479 case ProfileContext::FunctionCycle: 0480 f = (TraceFunction*)_selectedItem; 0481 break; 0482 default: 0483 break; 0484 } 0485 } 0486 // if this is the only change... 0487 if (changeType == selectedItemChanged) { 0488 setMarked(f ? 1:0, true); 0489 return; 0490 } 0491 setMarked(f ? 1:0, false); 0492 } 0493 0494 0495 if (changeType & activeItemChanged) { 0496 TraceFunction* f = nullptr; 0497 0498 if (_activeItem) { 0499 switch(_activeItem->type()) { 0500 case ProfileContext::Function: 0501 case ProfileContext::FunctionCycle: 0502 f = (TraceFunction*)_activeItem; 0503 break; 0504 default: 0505 break; 0506 } 0507 } 0508 ((CallMapRootItem*)base())->setFunction(f); 0509 } 0510 else if ( ((changeType & partsChanged) && GlobalConfig::showCycles()) || 0511 (changeType & dataChanged) || 0512 (changeType & configChanged)) { 0513 /* regenerates the treemap because traceitems were added/removed */ 0514 base()->refresh(); 0515 } 0516 else if ((changeType & partsChanged) || 0517 (changeType & eventTypeChanged)) { 0518 /* we need to do the draw order sorting again as the values change */ 0519 resort(); 0520 redraw(); 0521 } 0522 else 0523 redraw(); 0524 } 0525 0526 0527 0528 QColor CallMapView::groupColor(TraceFunction* f) const 0529 { 0530 if (!f) 0531 return palette().color( QPalette::Button ); 0532 0533 return GlobalGUIConfig::functionColor(_groupType, f); 0534 } 0535 0536 0537 QString CallMapView::tipString(TreeMapItem* i) const 0538 { 0539 QString tip, itemTip; 0540 int count = 0; 0541 0542 //qDebug("CallMapView::tipString for '%s'", i->text(0).toAscii()); 0543 0544 // first, SubPartItem's 0545 while (i && count<GlobalConfig::maxSymbolCount()) { 0546 itemTip = GlobalConfig::shortenSymbol(i->text(IDX_FUNCNAME)); 0547 0548 if (!i->text(IDX_COST).isEmpty()) 0549 itemTip += " (" + i->text(IDX_COST) + ')'; 0550 0551 if (!tip.isEmpty()) tip += '\n'; 0552 0553 tip += itemTip; 0554 i = i->parent(); 0555 count++; 0556 } 0557 if (count == GlobalConfig::maxSymbolCount()) tip += QLatin1String("\n..."); 0558 0559 return tip; 0560 } 0561 0562 0563 ProfileCostArray* CallMapView::totalCost() 0564 { 0565 TraceFunction* f = ((CallMapRootItem*)base())->function(); 0566 if (!f) return nullptr; 0567 0568 return GlobalConfig::showExpanded() ? f->inclusive() : f->data(); 0569 } 0570 0571 0572 0573 // CallMapItemBase 0574 0575 int CallMapItemBase::maxLines(int i) const 0576 { 0577 if ((i == IDX_FUNCNAME) || (i == IDX_LOCATION)) return 1; 0578 return 0; 0579 } 0580 0581 bool CallMapItemBase::allowBreak(int i) const 0582 { 0583 if ((i == IDX_COST) || (i == IDX_CALLCOUNT)) return false; 0584 return true; 0585 } 0586 0587 bool CallMapItemBase::allowTruncation(int i) const 0588 { 0589 if ((i == IDX_COST) || (i == IDX_CALLCOUNT)) return false; 0590 return true; 0591 } 0592 0593 DrawParams::Position CallMapItemBase::position(int i) const 0594 { 0595 if ((i == IDX_FUNCNAME) || (i == IDX_LOCATION)) return TopLeft; 0596 return TopRight; 0597 } 0598 0599 0600 0601 // CallMapRootItem 0602 0603 CallMapRootItem::CallMapRootItem() 0604 { 0605 _f = nullptr; 0606 } 0607 0608 void CallMapRootItem::setFunction(TraceFunction* f) 0609 { 0610 if (f == _f) return; 0611 0612 _f = f; 0613 refresh(); 0614 } 0615 0616 0617 QString CallMapRootItem::text(int i) const 0618 { 0619 if (i == IDX_FUNCNAME) { 0620 if (!_f) 0621 return QObject::tr("(no function)"); 0622 0623 return _f->prettyName(); 0624 } 0625 0626 if (!_f) return QString(); 0627 0628 if (i == IDX_LOCATION) 0629 return _f->prettyLocation(); 0630 if (i == IDX_CALLCOUNT) 0631 return QString("%1 x").arg(_f->calledCount().pretty()); 0632 if (i != IDX_COST) 0633 return QString(); 0634 0635 EventType* ct = ((CallMapView*)widget())->eventType(); 0636 ProfileCostArray* t = ((CallMapView*)widget())->totalCost(); 0637 0638 if (GlobalConfig::showPercentage()) { 0639 double sum, total = t->subCost(ct); 0640 if (total == 0.0) 0641 sum = 100.0; 0642 else 0643 sum = 100.0 * _f->inclusive()->subCost(ct) / total; 0644 0645 return QStringLiteral("%1 %") 0646 .arg(sum, 0, 'f', GlobalConfig::percentPrecision()); 0647 } 0648 return _f->inclusive()->prettySubCost(ct); 0649 } 0650 0651 0652 QPixmap CallMapRootItem::pixmap(int i) const 0653 { 0654 if ((i != IDX_COST) || !_f) return QPixmap(); 0655 0656 EventType* ct = ((CallMapView*)widget())->eventType(); 0657 ProfileCostArray* t = ((CallMapView*)widget())->totalCost(); 0658 0659 // colored level meter with frame 0660 return costPixmap( ct, _f->inclusive(), (double) (t->subCost(ct)), true); 0661 } 0662 0663 0664 double CallMapRootItem::value() const 0665 { 0666 if (!_f) return 0.0; 0667 0668 EventType* ct; 0669 ct = ((CallMapView*)widget())->eventType(); 0670 return (double) _f->inclusive()->subCost(ct); 0671 } 0672 0673 0674 double CallMapRootItem::sum() const 0675 { 0676 if (!_f) return 0.0; 0677 0678 CallMapView* w = (CallMapView*)widget(); 0679 0680 if (w->showCallers()) 0681 return 0.0; 0682 else 0683 return (double) _f->inclusive()->subCost(w->eventType()); 0684 } 0685 0686 0687 bool CallMapRootItem::isMarked(int) const 0688 { 0689 return ((CallMapView*)widget())->selectedItem() == _f; 0690 } 0691 0692 TreeMapItemList* CallMapRootItem::children() 0693 { 0694 if (_f && !initialized()) { 0695 CallMapView* w = (CallMapView*)widget(); 0696 0697 if (0) qDebug("Create Function %s (%s)", 0698 w->showCallers() ? "Callers":"Callees", 0699 qPrintable(text(IDX_FUNCNAME))); 0700 0701 setSorting(-1); 0702 if (w->showCallers()) { 0703 foreach(TraceCall* call, _f->callers()) { 0704 // do not show calls inside of a cycle 0705 if (call->inCycle()>0) continue; 0706 if (call->isRecursion()) continue; 0707 0708 addItem(new CallMapCallerItem(1.0, call)); 0709 } 0710 0711 setSum(0); 0712 } 0713 else { 0714 foreach(TraceCall* call, _f->callings()) { 0715 // do not show calls inside of a cycle 0716 if (call->inCycle()>0) continue; 0717 if (call->isRecursion()) continue; 0718 0719 CallMapCallingItem* i = new CallMapCallingItem(1.0, call); 0720 i->init(); 0721 addItem(i); 0722 } 0723 0724 setSum(_f->inclusive()->subCost(w->eventType())); 0725 } 0726 setSorting(-2, false); 0727 } 0728 0729 return _children; 0730 } 0731 0732 QColor CallMapRootItem::backColor() const 0733 { 0734 return ((CallMapView*)widget())->groupColor(_f); 0735 } 0736 0737 0738 0739 // CallMapCallingItems 0740 0741 CallMapCallingItem::CallMapCallingItem(double factor, TraceCall* c) 0742 { 0743 _factor = factor; 0744 _c = c; 0745 } 0746 0747 void CallMapCallingItem::init() 0748 { 0749 #if 0 0750 // create association: if not possible, i.e. an ass. already exists 0751 // for the function, we need to draw the recursive version 0752 _recursive = !setFunction(_c->called()); 0753 _valid = true; 0754 #endif 0755 } 0756 0757 QString CallMapCallingItem::text(int textNo) const 0758 { 0759 if (textNo == IDX_FUNCNAME) { 0760 if (!_c) 0761 return QObject::tr("(no call)"); 0762 0763 return _c->calledName(); 0764 } 0765 0766 if (textNo == IDX_LOCATION) 0767 return _c->called()->prettyLocation(); 0768 if (textNo == IDX_CALLCOUNT) 0769 return QString("%1 x").arg(SubCost(_factor * _c->callCount()).pretty()); 0770 if (textNo != IDX_COST) 0771 return QString(); 0772 0773 EventType* ct; 0774 ct = ((CallMapView*)widget())->eventType(); 0775 0776 SubCost val = SubCost(_factor * _c->subCost(ct)); 0777 if (GlobalConfig::showPercentage()) { 0778 // percentage relative to function cost 0779 ProfileCostArray* t = ((CallMapView*)widget())->totalCost(); 0780 double p = 100.0 * _factor * _c->subCost(ct) / t->subCost(ct); 0781 return QStringLiteral("%1 %") 0782 .arg(p, 0, 'f', GlobalConfig::percentPrecision()); 0783 } 0784 return val.pretty(); 0785 } 0786 0787 0788 QPixmap CallMapCallingItem::pixmap(int i) const 0789 { 0790 if (i != IDX_COST) return QPixmap(); 0791 0792 // Cost pixmap 0793 EventType* ct = ((CallMapView*)widget())->eventType(); 0794 ProfileCostArray* t = ((CallMapView*)widget())->totalCost(); 0795 0796 // colored level meter with frame 0797 return costPixmap( ct, _c, t->subCost(ct) / _factor, true); 0798 } 0799 0800 0801 double CallMapCallingItem::value() const 0802 { 0803 EventType* ct; 0804 ct = ((CallMapView*)widget())->eventType(); 0805 return _factor * _c->subCost(ct); 0806 } 0807 0808 double CallMapCallingItem::sum() const 0809 { 0810 return value(); 0811 } 0812 0813 bool CallMapCallingItem::isMarked(int) const 0814 { 0815 return ((CallMapView*)widget())->selectedItem() == _c->called(); 0816 } 0817 0818 0819 TreeMapItemList* CallMapCallingItem::children() 0820 { 0821 if (!initialized()) { 0822 if (0) qDebug("Create Calling subitems (%s)", 0823 qPrintable(path(0).join("/"))); 0824 0825 EventType* ct; 0826 ct = ((CallMapView*)widget())->eventType(); 0827 0828 // same as sum() 0829 SubCost s = _c->called()->inclusive()->subCost(ct); 0830 SubCost v = _c->subCost(ct); 0831 if (v>s) { 0832 qDebug("Warning: CallingItem subVal %u > Sum %u (%s)", 0833 (unsigned)v, (unsigned)s, qPrintable(_c->called()->prettyName())); 0834 v = s; 0835 } 0836 double newFactor = _factor * v / s; 0837 0838 #if 0 0839 qDebug("CallingItem: Subitems of %s => %s, factor %f * %d/%d => %f", 0840 qPrintable(_c->caller()->prettyName()), 0841 qPrintable(_c->called()->prettyName()), 0842 _factor, v, s, newFactor); 0843 #endif 0844 setSorting(-1); 0845 foreach(TraceCall* call, _c->called()->callings()) { 0846 // do not show calls inside of a cycle 0847 if (call->inCycle()>0) continue; 0848 if (call->isRecursion()) continue; 0849 0850 CallMapCallingItem* i = new CallMapCallingItem(newFactor, call); 0851 i->init(); 0852 addItem(i); 0853 } 0854 setSorting(-2, false); 0855 } 0856 0857 return _children; 0858 } 0859 0860 0861 QColor CallMapCallingItem::backColor() const 0862 { 0863 CallMapView* w = (CallMapView*)widget(); 0864 return w->groupColor(_c->called()); 0865 } 0866 0867 0868 // CallMapCallerItem 0869 0870 CallMapCallerItem::CallMapCallerItem(double factor, TraceCall* c) 0871 { 0872 _factor = factor; 0873 _c = c; 0874 } 0875 0876 QString CallMapCallerItem::text(int i) const 0877 { 0878 if (i == IDX_FUNCNAME) { 0879 if (!_c) 0880 return QObject::tr("(no call)"); 0881 0882 return _c->callerName(); 0883 } 0884 0885 if (i == IDX_LOCATION) 0886 return _c->caller()->prettyLocation(); 0887 if (i == IDX_CALLCOUNT) 0888 return QString("%1 x").arg(SubCost(_factor * _c->callCount()).pretty()); 0889 if (i != IDX_COST) 0890 return QString(); 0891 0892 EventType* ct; 0893 ct = ((CallMapView*)widget())->eventType(); 0894 0895 SubCost val = SubCost(_factor * _c->subCost(ct)); 0896 if (GlobalConfig::showPercentage()) { 0897 ProfileCostArray* t = ((CallMapView*)widget())->totalCost(); 0898 double p = 100.0 * _factor * _c->subCost(ct) / t->subCost(ct); 0899 return QStringLiteral("%1 %") 0900 .arg(p, 0, 'f', GlobalConfig::percentPrecision()); 0901 } 0902 return val.pretty(); 0903 } 0904 0905 QPixmap CallMapCallerItem::pixmap(int i) const 0906 { 0907 if (i != IDX_COST) return QPixmap(); 0908 0909 // Cost pixmap 0910 EventType* ct = ((CallMapView*)widget())->eventType(); 0911 ProfileCostArray* t = ((CallMapView*)widget())->totalCost(); 0912 0913 // colored level meter with frame 0914 return costPixmap( ct, _c, t->subCost(ct) / _factor, true ); 0915 } 0916 0917 0918 double CallMapCallerItem::value() const 0919 { 0920 EventType* ct; 0921 ct = ((CallMapView*)widget())->eventType(); 0922 return (double) _c->subCost(ct); 0923 } 0924 0925 bool CallMapCallerItem::isMarked(int) const 0926 { 0927 return ((CallMapView*)widget())->selectedItem() == _c->caller(); 0928 } 0929 0930 0931 TreeMapItemList* CallMapCallerItem::children() 0932 { 0933 if (!initialized()) { 0934 //qDebug("Create Caller subitems (%s)", name().toAscii()); 0935 0936 EventType* ct; 0937 ct = ((CallMapView*)widget())->eventType(); 0938 0939 SubCost s = _c->caller()->inclusive()->subCost(ct); 0940 SubCost v = _c->subCost(ct); 0941 double newFactor = _factor * v / s; 0942 0943 0944 #if 0 0945 qDebug("CallerItem: Subitems of %s => %s, factor %f * %d/%d => %f", 0946 qPrintable(_c->caller()->prettyName()), 0947 qPrintable(_c->called()->prettyName()), 0948 _factor, v, s, newFactor); 0949 #endif 0950 setSorting(-1); 0951 0952 foreach(TraceCall* call, _c->caller()->callers()) { 0953 // do not show calls inside of a cycle 0954 if (call->inCycle()>0) continue; 0955 if (call->isRecursion()) continue; 0956 0957 TreeMapItem* i = new CallMapCallerItem(newFactor, call); 0958 addItem(i); 0959 } 0960 setSorting(-2, false); 0961 } 0962 0963 return _children; 0964 } 0965 0966 QColor CallMapCallerItem::backColor() const 0967 { 0968 CallMapView* w = (CallMapView*)widget(); 0969 return w->groupColor(_c->caller()); 0970 } 0971 0972 void CallMapView::restoreOptions(const QString& prefix, const QString& postfix) 0973 { 0974 ConfigGroup* g = ConfigStorage::group(prefix, postfix); 0975 0976 setSplitMode(g->value(QStringLiteral("SplitMode"), QStringLiteral(DEFAULT_SPLITMODE)).toString()); 0977 0978 setFieldVisible(IDX_FUNCNAME, 0979 g->value(QStringLiteral("DrawName"), DEFAULT_DRAWNAME).toBool()); 0980 setFieldVisible(IDX_COST, 0981 g->value(QStringLiteral("DrawCost"), DEFAULT_DRAWCOST).toBool()); 0982 setFieldVisible(IDX_LOCATION, 0983 g->value(QStringLiteral("DrawLocation"), DEFAULT_DRAWLOCATION).toBool()); 0984 setFieldVisible(IDX_CALLCOUNT, 0985 g->value(QStringLiteral("DrawCalls"), DEFAULT_DRAWCALLS).toBool()); 0986 0987 bool enable = g->value(QStringLiteral("ForceStrings"), DEFAULT_FORCESTRINGS).toBool(); 0988 setFieldForced(0, enable); 0989 setFieldForced(1, enable); 0990 setFieldForced(2, enable); 0991 setFieldForced(3, enable); 0992 0993 setAllowRotation(g->value(QStringLiteral("AllowRotation"), DEFAULT_ROTATION).toBool()); 0994 setShadingEnabled(g->value(QStringLiteral("Shading"), DEFAULT_SHADING).toBool()); 0995 setFieldStop(IDX_FUNCNAME, 0996 g->value(QStringLiteral("StopName"), QLatin1String(DEFAULT_STOPNAME)).toString()); 0997 setMaxDrawingDepth(g->value(QStringLiteral("MaxDepth"), DEFAULT_MAXDEPTH).toInt()); 0998 setMinimalArea(g->value(QStringLiteral("MaxArea"), DEFAULT_MAXAREA).toInt()); 0999 1000 delete g; 1001 } 1002 1003 void CallMapView::saveOptions(const QString& prefix, const QString& postfix) 1004 { 1005 ConfigGroup* g = ConfigStorage::group(prefix + postfix); 1006 1007 g->setValue(QStringLiteral("SplitMode"), splitModeString(), QStringLiteral(DEFAULT_SPLITMODE)); 1008 g->setValue(QStringLiteral("DrawName"), 1009 fieldVisible(IDX_FUNCNAME), DEFAULT_DRAWNAME); 1010 g->setValue(QStringLiteral("DrawCost"), 1011 fieldVisible(IDX_COST), DEFAULT_DRAWCOST); 1012 g->setValue(QStringLiteral("DrawLocation"), 1013 fieldVisible(IDX_LOCATION), DEFAULT_DRAWLOCATION); 1014 g->setValue(QStringLiteral("DrawCalls"), 1015 fieldVisible(IDX_CALLCOUNT), DEFAULT_DRAWCALLS); 1016 // when option for all text (0-3) 1017 g->setValue(QStringLiteral("ForceStrings"), fieldForced(IDX_FUNCNAME), DEFAULT_FORCESTRINGS); 1018 1019 g->setValue(QStringLiteral("AllowRotation"), allowRotation(), DEFAULT_ROTATION); 1020 g->setValue(QStringLiteral("Shading"), isShadingEnabled(), DEFAULT_SHADING); 1021 1022 g->setValue(QStringLiteral("StopName"), fieldStop(IDX_FUNCNAME), QLatin1String(DEFAULT_STOPNAME)); 1023 g->setValue(QStringLiteral("MaxDepth"), maxDrawingDepth(), DEFAULT_MAXDEPTH); 1024 g->setValue(QStringLiteral("MaxArea"), minimalArea(), DEFAULT_MAXAREA); 1025 1026 delete g; 1027 } 1028 1029 #include "moc_callmapview.cpp"