Warning, file /sdk/kcachegrind/libcore/tracedata.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     This file is part of KCachegrind.
0003 
0004     SPDX-FileCopyrightText: 2002-2016 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only
0007 */
0008 
0009 
0010 #include "tracedata.h"
0011 
0012 #include <errno.h>
0013 #include <stdlib.h>
0014 
0015 #include <QFile>
0016 #include <QDir>
0017 #include <QFileInfo>
0018 #include <QDebug>
0019 
0020 #include "logger.h"
0021 #include "loader.h"
0022 #include "globalconfig.h"
0023 #include "utils.h"
0024 #include "fixcost.h"
0025 
0026 
0027 #define TRACE_DEBUG      0
0028 #define TRACE_ASSERTIONS 0
0029 
0030 
0031 
0032 
0033 //---------------------------------------------------
0034 // TraceJumpCost
0035 
0036 TraceJumpCost::TraceJumpCost(ProfileContext* c)
0037     :CostItem(c)
0038 {
0039     TraceJumpCost::clear();
0040 }
0041 
0042 TraceJumpCost::~TraceJumpCost()
0043 {}
0044 
0045 SubCost TraceJumpCost::executedCount()
0046 {
0047     if (_dirty) update();
0048 
0049     return _executedCount;
0050 }
0051 
0052 SubCost TraceJumpCost::followedCount()
0053 {
0054     if (_dirty) update();
0055 
0056     return _followedCount;
0057 }
0058 
0059 QString TraceJumpCost::costString(EventTypeSet*)
0060 {
0061     if (_dirty) update();
0062 
0063     return QStringLiteral("%1/%2")
0064             .arg(_followedCount.pretty())
0065             .arg(_executedCount.pretty());
0066 }
0067 
0068 void TraceJumpCost::clear()
0069 {
0070     _followedCount = 0;
0071     _executedCount = 0;
0072 }
0073 
0074 void TraceJumpCost::addCost(TraceJumpCost* item)
0075 {
0076     if (item->_dirty) item->update();
0077 
0078     _followedCount += item->followedCount();
0079     _executedCount += item->executedCount();
0080 }
0081 
0082 
0083 
0084 //---------------------------------------------------
0085 // TraceCallCost
0086 
0087 TraceCallCost::TraceCallCost(ProfileContext* context)
0088     : ProfileCostArray(context)
0089 {
0090     _callCount = 0;
0091 }
0092 
0093 TraceCallCost::~TraceCallCost()
0094 {}
0095 
0096 
0097 QString TraceCallCost::costString(EventTypeSet* m)
0098 {
0099     return QStringLiteral("%1, Calls %2")
0100             .arg(ProfileCostArray::costString(m))
0101             .arg(_callCount.pretty());
0102 }
0103 
0104 QString TraceCallCost::prettyCallCount()
0105 {
0106     return _callCount.pretty();
0107 }
0108 
0109 void TraceCallCost::clear()
0110 {
0111     _callCount = 0;
0112     ProfileCostArray::clear();
0113 }
0114 
0115 SubCost TraceCallCost::callCount()
0116 {
0117     if (_dirty) update();
0118 
0119     return _callCount;
0120 }
0121 
0122 void TraceCallCost::addCallCount(SubCost c)
0123 {
0124     _callCount += c;
0125 
0126     invalidate();
0127 }
0128 
0129 
0130 //---------------------------------------------------
0131 // TraceInclusiveCost
0132 
0133 TraceInclusiveCost::TraceInclusiveCost(ProfileContext* context)
0134     : ProfileCostArray(context), _inclusive(context)
0135 {}
0136 
0137 TraceInclusiveCost::~TraceInclusiveCost()
0138 {}
0139 
0140 QString TraceInclusiveCost::costString(EventTypeSet* m)
0141 {
0142     return QStringLiteral("%1, Inclusive %2")
0143             .arg(ProfileCostArray::costString(m))
0144             .arg(_inclusive.costString(m));
0145 }
0146 
0147 void TraceInclusiveCost::clear()
0148 {
0149     _inclusive.clear();
0150     ProfileCostArray::clear();
0151 }
0152 
0153 ProfileCostArray* TraceInclusiveCost::inclusive()
0154 {
0155     if (_dirty) update();
0156 
0157     return &_inclusive;
0158 }
0159 
0160 void TraceInclusiveCost::addInclusive(ProfileCostArray* c)
0161 {
0162     _inclusive.addCost(c);
0163 
0164     invalidate();
0165 }
0166 
0167 
0168 //---------------------------------------------------
0169 // TraceListCost
0170 
0171 TraceListCost::TraceListCost(ProfileContext* context)
0172     : ProfileCostArray(context)
0173 {
0174     _lastDep = nullptr;
0175 }
0176 
0177 TraceListCost::~TraceListCost()
0178 {}
0179 
0180 void TraceListCost::addDep(ProfileCostArray* dep)
0181 {
0182 #if TRACE_ASSERTIONS
0183     if (_deps.contains(dep)) {
0184         qDebug("addDep: %s already in list!",
0185                qPrintable(dep->fullName()));
0186         return;
0187     }
0188 #endif
0189 
0190     _deps.append(dep);
0191     _lastDep = dep;
0192     invalidate();
0193 
0194 #if TRACE_DEBUG
0195     qDebug("%s added\n %s (now %d)",
0196            qPrintable( fullName() ), qPrintable(dep->fullName()),
0197            _deps.count());
0198 #endif
0199 }
0200 
0201 ProfileCostArray* TraceListCost::findDepFromPart(TracePart* part)
0202 {
0203     if (_lastDep && _lastDep->part() == part)
0204         return _lastDep;
0205 
0206     foreach(ProfileCostArray* dep, _deps) {
0207         if (dep->part() == part) {
0208             _lastDep = dep;
0209             return dep;
0210         }
0211     }
0212     return nullptr;
0213 }
0214 
0215 
0216 void TraceListCost::update()
0217 {
0218     if (!_dirty) return;
0219 
0220 #if TRACE_DEBUG
0221     qDebug("update %s (count %d)",
0222            qPrintable( fullName() ), _deps.count());
0223 #endif
0224 
0225     clear();
0226     foreach(ProfileCostArray* item, _deps) {
0227         if (onlyActiveParts())
0228             if (!item->part() || !item->part()->isActive()) continue;
0229 
0230         addCost(item);
0231     }
0232 
0233     _dirty = false;
0234 
0235 #if TRACE_DEBUG
0236     qDebug("   > %s", qPrintable(costString(0)));
0237 #endif
0238 }
0239 
0240 
0241 
0242 //---------------------------------------------------
0243 // TraceJumpListCost
0244 
0245 TraceJumpListCost::TraceJumpListCost(ProfileContext* context)
0246     : TraceJumpCost(context)
0247 {
0248     _lastDep = nullptr;
0249 }
0250 
0251 TraceJumpListCost::~TraceJumpListCost()
0252 {}
0253 
0254 void TraceJumpListCost::addDep(TraceJumpCost* dep)
0255 {
0256 #if TRACE_ASSERTIONS
0257     if (_deps.contains(dep)) {
0258         qDebug("addDep: %s already in list!",
0259                qPrintable(dep->fullName()));
0260         return;
0261     }
0262 #endif
0263 
0264     _deps.append(dep);
0265     _lastDep = dep;
0266     invalidate();
0267 
0268 #if TRACE_DEBUG
0269     qDebug("%s added\n %s (now %d)",
0270            qPrintable( fullName() ), qPrintable(dep->fullName()),
0271            _deps.count());
0272 #endif
0273 }
0274 
0275 TraceJumpCost* TraceJumpListCost::findDepFromPart(TracePart* part)
0276 {
0277     if (_lastDep && _lastDep->part() == part)
0278         return _lastDep;
0279 
0280     foreach(TraceJumpCost* dep, _deps) {
0281         if (dep->part() == part) {
0282             _lastDep = dep;
0283             return dep;
0284         }
0285     }
0286     return nullptr;
0287 }
0288 
0289 
0290 void TraceJumpListCost::update()
0291 {
0292     if (!_dirty) return;
0293 
0294 #if TRACE_DEBUG
0295     qDebug("update %s (count %d)",
0296            qPrintable( fullName() ), _deps.count());
0297 #endif
0298 
0299     clear();
0300     foreach(TraceJumpCost* item, _deps) {
0301         if (onlyActiveParts())
0302             if (!item->part() || !item->part()->isActive()) continue;
0303 
0304         addCost(item);
0305     }
0306 
0307     _dirty = false;
0308 
0309 #if TRACE_DEBUG
0310     qDebug("   > %s", qPrintable(costString(0)));
0311 #endif
0312 }
0313 
0314 
0315 
0316 //---------------------------------------------------
0317 // TraceCallListCost
0318 
0319 TraceCallListCost::TraceCallListCost(ProfileContext* context)
0320     : TraceCallCost(context)
0321 {
0322     _lastDep = nullptr;
0323 }
0324 
0325 TraceCallListCost::~TraceCallListCost()
0326 {}
0327 
0328 void TraceCallListCost::addDep(TraceCallCost* dep)
0329 {
0330 #if TRACE_ASSERTIONS
0331     if (_deps.contains(dep)) {
0332         qDebug("addDep: %s already in list!",
0333                qPrintable(dep->fullName()));
0334         return;
0335     }
0336 #endif
0337 
0338     _deps.append(dep);
0339     _lastDep = dep;
0340     invalidate();
0341 
0342 #if TRACE_DEBUG
0343     qDebug("%s added\n %s (now %d)",
0344            qPrintable( fullName() ), qPrintable(dep->fullName()),
0345            _deps.count());
0346 #endif
0347 }
0348 
0349 TraceCallCost* TraceCallListCost::findDepFromPart(TracePart* part)
0350 {
0351     if (_lastDep && _lastDep->part() == part)
0352         return _lastDep;
0353 
0354     foreach(TraceCallCost* dep, _deps) {
0355         if (dep->part() == part) {
0356             _lastDep = dep;
0357             return dep;
0358         }
0359     }
0360     return nullptr;
0361 }
0362 
0363 
0364 void TraceCallListCost::update()
0365 {
0366     if (!_dirty) return;
0367 
0368 #if TRACE_DEBUG
0369     qDebug("update %s (count %d)",
0370            qPrintable( fullName() ), _deps.count());
0371 #endif
0372 
0373     /* Without dependent cost items, assume fixed costs,
0374      * i.e. do not change cost */
0375     if (_deps.count()>0) {
0376         clear();
0377         foreach(TraceCallCost* item, _deps) {
0378             if (onlyActiveParts())
0379                 if (!item->part() || !item->part()->isActive()) continue;
0380 
0381             addCost(item);
0382             addCallCount(item->callCount());
0383         }
0384     }
0385 
0386     _dirty = false;
0387 
0388 #if TRACE_DEBUG
0389     qDebug("   > %s", qPrintable(costString(0)));
0390 #endif
0391 }
0392 
0393 
0394 //---------------------------------------------------
0395 // TraceInclusiveListCost
0396 
0397 TraceInclusiveListCost::TraceInclusiveListCost(ProfileContext* context)
0398     : TraceInclusiveCost(context)
0399 {
0400     _lastDep = nullptr;
0401 }
0402 
0403 TraceInclusiveListCost::~TraceInclusiveListCost()
0404 {}
0405 
0406 
0407 void TraceInclusiveListCost::addDep(TraceInclusiveCost* dep)
0408 {
0409 #if TRACE_ASSERTIONS
0410     if (_deps.contains(dep)) {
0411         qDebug("addDep: %s already in list!",
0412                qPrintable(dep->fullName()));
0413         return;
0414     }
0415 #endif
0416 
0417     _deps.append(dep);
0418     _lastDep = dep;
0419     invalidate();
0420 
0421 #if TRACE_DEBUG
0422     qDebug("%s added\n %s (now %d)",
0423            qPrintable( fullName() ), qPrintable(dep->fullName()),
0424            _deps.count());
0425 #endif
0426 }
0427 
0428 TraceInclusiveCost* TraceInclusiveListCost::findDepFromPart(TracePart* part)
0429 {
0430     if (_lastDep && _lastDep->part() == part)
0431         return _lastDep;
0432 
0433     foreach(TraceInclusiveCost* dep, _deps) {
0434         if (dep->part() == part) {
0435             _lastDep = dep;
0436             return dep;
0437         }
0438     }
0439     return nullptr;
0440 }
0441 
0442 void TraceInclusiveListCost::update()
0443 {
0444     if (!_dirty) return;
0445 
0446 #if TRACE_DEBUG
0447     qDebug("update %s (count %d)",
0448            qPrintable( fullName() ), _deps.count());
0449 #endif
0450 
0451     clear();
0452     foreach(TraceInclusiveCost* item, _deps) {
0453         if (onlyActiveParts())
0454             if (!item->part() || !item->part()->isActive()) continue;
0455 
0456         addCost(item);
0457         addInclusive(item->inclusive());
0458     }
0459 
0460     _dirty = false;
0461 
0462 #if TRACE_DEBUG
0463     qDebug("   > %s", qPrintable(costString(0)));
0464 #endif
0465 }
0466 
0467 
0468 
0469 //---------------------------------------------------
0470 // TracePartInstrJump
0471 
0472 TracePartInstrJump::TracePartInstrJump(TraceInstrJump* instrJump,
0473                                        TracePartInstrJump* next)
0474     : TraceJumpCost(ProfileContext::context(ProfileContext::PartInstrJump))
0475 {
0476     _dep = instrJump;
0477     _next = next;
0478 }
0479 
0480 TracePartInstrJump::~TracePartInstrJump()
0481 {}
0482 
0483 
0484 //---------------------------------------------------
0485 // TracePartInstrCall
0486 
0487 TracePartInstrCall::TracePartInstrCall(TraceInstrCall* instrCall)
0488     : TraceCallCost(ProfileContext::context(ProfileContext::PartInstrCall))
0489 {
0490     _dep = instrCall;
0491 }
0492 
0493 TracePartInstrCall::~TracePartInstrCall()
0494 {}
0495 
0496 
0497 
0498 //---------------------------------------------------
0499 // TracePartInstr
0500 
0501 TracePartInstr::TracePartInstr(TraceInstr* instr)
0502     : ProfileCostArray(ProfileContext::context(ProfileContext::PartInstr))
0503 {
0504     _dep = instr;
0505 }
0506 
0507 TracePartInstr::~TracePartInstr()
0508 {}
0509 
0510 
0511 
0512 //---------------------------------------------------
0513 // TracePartLineJump
0514 
0515 TracePartLineJump::TracePartLineJump(TraceLineJump* lineJump)
0516     : TraceJumpCost(ProfileContext::context(ProfileContext::PartLineJump))
0517 {
0518     _dep = lineJump;
0519 }
0520 
0521 TracePartLineJump::~TracePartLineJump()
0522 {}
0523 
0524 
0525 //---------------------------------------------------
0526 // TracePartLineCall
0527 
0528 TracePartLineCall::TracePartLineCall(TraceLineCall* lineCall)
0529     : TraceCallCost(ProfileContext::context(ProfileContext::PartLineCall))
0530 {
0531     _dep = lineCall;
0532 }
0533 
0534 TracePartLineCall::~TracePartLineCall()
0535 {}
0536 
0537 
0538 //---------------------------------------------------
0539 // TracePartLine
0540 
0541 TracePartLine::TracePartLine(TraceLine* line)
0542     : ProfileCostArray(ProfileContext::context(ProfileContext::PartLine))
0543 {
0544     _dep = line;
0545 }
0546 
0547 TracePartLine::~TracePartLine()
0548 {}
0549 
0550 
0551 
0552 
0553 //---------------------------------------------------
0554 // TracePartCall
0555 
0556 TracePartCall::TracePartCall(TraceCall* call)
0557     : TraceCallListCost(ProfileContext::context(ProfileContext::PartCall))
0558 {
0559     _dep = call;
0560 
0561     _firstFixCallCost = nullptr;
0562 }
0563 
0564 TracePartCall::~TracePartCall()
0565 {}
0566 
0567 bool TracePartCall::isRecursion()
0568 {
0569     return call()->isRecursion();
0570 }
0571 
0572 void TracePartCall::update()
0573 {
0574 #if !USE_FIXCOST
0575     TraceCallListCost::update();
0576 #else
0577 
0578     if (!_dirty) return;
0579 
0580 #if TRACE_DEBUG
0581     qDebug("update %s", qPrintable( fullName() ));
0582 #endif
0583 
0584     /* Without dependent cost items, assume fixed costs,
0585      * i.e. do not change cost */
0586     if (_firstFixCallCost) {
0587         clear();
0588         FixCallCost* item;
0589         for (item = _firstFixCallCost; item; item = item->nextCostOfPartCall())
0590             item->addTo(this);
0591     }
0592 
0593     _dirty = false;
0594 
0595 #if TRACE_DEBUG
0596     qDebug("   > %s", qPrintable(costString(0)));
0597 #endif
0598 
0599 #endif // USE_FIXCOST
0600 }
0601 
0602 
0603 //---------------------------------------------------
0604 // TracePartFunction
0605 
0606 TracePartFunction::TracePartFunction(TraceFunction* function,
0607                                      TracePartObject* partObject,
0608                                      TracePartFile *partFile)
0609     : TraceInclusiveCost(ProfileContext::context(ProfileContext::PartFunction))
0610 {
0611     _dep = function;
0612     _partObject = partObject;
0613     _partFile = partFile;
0614     _partClass = nullptr;
0615 
0616     _calledCount     = 0;
0617     _callingCount    = 0;
0618     _calledContexts  = 0;
0619     _callingContexts = 0;
0620 
0621     _firstFixCost = nullptr;
0622     _firstFixJump = nullptr;
0623 }
0624 
0625 TracePartFunction::~TracePartFunction()
0626 {}
0627 
0628 QString TracePartFunction::prettyCalledCount()
0629 {
0630     return _calledCount.pretty();
0631 }
0632 
0633 QString TracePartFunction::prettyCallingCount()
0634 {
0635     return _callingCount.pretty();
0636 }
0637 
0638 QString TracePartFunction::costString(EventTypeSet* m)
0639 {
0640     update();
0641 
0642     QString res = TraceInclusiveCost::costString(m);
0643     res += QStringLiteral(", called from %1: %2")
0644            .arg(_calledContexts).arg(prettyCalledCount());
0645     res += QStringLiteral(", calling from %1: %2")
0646            .arg(_callingContexts).arg(prettyCallingCount());
0647 
0648     return res;
0649 }
0650 
0651 
0652 void TracePartFunction::addPartInstr(TracePartInstr* ref)
0653 {
0654 #if TRACE_ASSERTIONS
0655     if (_partInstr.contains(ref)) {
0656         qDebug("TracePartFunction::addPartInstr: %s already in list!",
0657                qPrintable(ref->name()));
0658         return;
0659     }
0660 #endif
0661 
0662     _partInstr.append(ref);
0663     invalidate();
0664 
0665 #if TRACE_DEBUG
0666     qDebug("%s added\n %s (now %d)",
0667            qPrintable( fullName() ), qPrintable(ref->fullName()),
0668            _partInstr.count());
0669 #endif
0670 }
0671 
0672 
0673 void TracePartFunction::addPartLine(TracePartLine* ref)
0674 {
0675 #if TRACE_ASSERTIONS
0676     if (_partLines.contains(ref)) {
0677         qDebug("TracePartFunction::addPartLine: %s already in list!",
0678                qPrintable(ref->name()));
0679         return;
0680     }
0681 #endif
0682 
0683     _partLines.append(ref);
0684     invalidate();
0685 
0686 #if TRACE_DEBUG
0687     qDebug("%s added\n %s (now %d)",
0688            qPrintable( fullName() ), qPrintable(ref->fullName()),
0689            _partLines.count());
0690 #endif
0691 }
0692 
0693 
0694 void TracePartFunction::addPartCaller(TracePartCall* ref)
0695 {
0696 #if TRACE_ASSERTIONS
0697     if (_partCallers.contains(ref)) {
0698         qDebug("TracePartFunction::addPartCaller: %s already in list!",
0699                qPrintable(ref->name()));
0700         return;
0701     }
0702 #endif
0703 
0704     _partCallers.append(ref);
0705     invalidate();
0706 
0707 #if TRACE_DEBUG
0708     qDebug("%s added Caller\n %s (now %d)",
0709            qPrintable( fullName() ), qPrintable(ref->fullName()),
0710            _partCallers.count());
0711 #endif
0712 }
0713 
0714 
0715 void TracePartFunction::addPartCalling(TracePartCall* ref)
0716 {
0717 #if TRACE_ASSERTIONS
0718     if (_partCallings.contains(ref)) {
0719         qDebug("TracePartFunction::addPartCalling: %s already in list!",
0720                qPrintable(ref->name()));
0721         return;
0722     }
0723 #endif
0724 
0725     _partCallings.append(ref);
0726     invalidate();
0727 
0728 #if TRACE_DEBUG
0729     qDebug("%s added Calling\n %s (now %d)",
0730            qPrintable( fullName() ), qPrintable(ref->fullName()),
0731            _partCallings.count());
0732 #endif
0733 }
0734 
0735 SubCost TracePartFunction::calledCount()
0736 {
0737     if (_dirty) update();
0738 
0739     return _calledCount;
0740 }
0741 
0742 int TracePartFunction::calledContexts()
0743 {
0744     if (_dirty) update();
0745 
0746     return _calledContexts;
0747 }
0748 
0749 SubCost TracePartFunction::callingCount()
0750 {
0751     if (_dirty) update();
0752 
0753     return _callingCount;
0754 }
0755 
0756 
0757 int TracePartFunction::callingContexts()
0758 {
0759     if (_dirty) update();
0760 
0761     return _callingContexts;
0762 }
0763 
0764 
0765 void TracePartFunction::update()
0766 {
0767     if (!_dirty) return;
0768 
0769 #if TRACE_DEBUG
0770     qDebug("TracePartFunction::update %s (Callers %d, Callings %d, lines %d)",
0771            qPrintable(name()), _partCallers.count(), _partCallings.count(),
0772            _partLines.count());
0773 #endif
0774 
0775     _calledCount     = 0;
0776     _callingCount    = 0;
0777     _calledContexts  = 0;
0778     _callingContexts = 0;
0779 
0780     // To calculate context counts, we just use first real event type (FIXME?)
0781     EventType* e = data() ? data()->eventTypes()->realType(0) : nullptr;
0782 
0783     // calculate additional cost metrics
0784     foreach(TracePartCall* caller, _partCallers) {
0785         if (e && (caller->subCost(e) >0))
0786             _calledContexts++;
0787 
0788         SubCost c = caller->callCount();
0789         if (c>0) {
0790             _calledCount += c;
0791         }
0792     }
0793     foreach(TracePartCall* calling, _partCallings) {
0794         if (e && (calling->subCost(e)>0))
0795             _callingContexts++;
0796 
0797         SubCost c = calling->callCount();
0798         if (c>0) {
0799             _callingCount += c;
0800         }
0801     }
0802 
0803     // self cost
0804 #if !USE_FIXCOST
0805     if (_partLines.count()>0) {
0806         ProfileCostArray::clear();
0807 
0808         foreach(TracePartLine* line, _partLines)
0809             addCost(line);
0810     }
0811 #else
0812     if (_firstFixCost) {
0813         ProfileCostArray::clear();
0814 
0815         FixCost* item;
0816         for (item = _firstFixCost; item; item = item->nextCostOfPartFunction())
0817             item->addTo(this);
0818     }
0819 #endif
0820 
0821 
0822     /* There are two possibilities to calculate inclusive cost:
0823      * 1) sum of call costs to this function
0824      * 2) sum of call costs from this function + self cost
0825      *
0826      * 1) is wrong if a function was called spontaneous, but also by a call.
0827      * This eventually can happen with thread/process startup functions,
0828      * and signal handlers.
0829      *
0830      * 2) is wrong with "skipped PLT" and the calltree skin, because
0831      *    cost of PLT is attributed to called function (?)
0832      *
0833      * For now, do 1) if there are callers, otherwise 2).
0834      * Should this be fixed to take the maximum of 1) and 2) ?
0835      */
0836     _inclusive.clear();
0837     if (_calledCount>0) {
0838         // inclusive cost: if possible, use caller sums
0839         foreach(TracePartCall* caller, _partCallers) {
0840             // detect simple recursion (no cycle)
0841             if (caller->isRecursion()) continue;
0842 
0843             addInclusive(caller);
0844         }
0845     }
0846     else {
0847         // without caller info, use calling sum + line costs
0848         foreach(TracePartCall* calling, _partCallings) {
0849             // detect simple recursion (no cycle)
0850             if (calling->isRecursion()) continue;
0851 
0852             addInclusive(calling);
0853         }
0854         _dirty = false; // do not recurse!
0855         addInclusive(this);
0856     }
0857 
0858     _dirty = false;
0859 
0860 #if TRACE_DEBUG
0861     qDebug("   > %s", qPrintable(costString(0)));
0862 #endif
0863 }
0864 
0865 
0866 
0867 //---------------------------------------------------
0868 // TracePartClass
0869 
0870 TracePartClass::TracePartClass(TraceClass* cls)
0871     : TraceInclusiveListCost(ProfileContext::context(ProfileContext::PartClass))
0872 {
0873     _dep = cls;
0874 }
0875 
0876 TracePartClass::~TracePartClass()
0877 {}
0878 
0879 QString TracePartClass::prettyName() const
0880 {
0881     return QStringLiteral("%1 from %2")
0882             .arg( _dep->name().isEmpty() ? QStringLiteral("(global)") : _dep->name())
0883             .arg(part()->name());
0884 }
0885 
0886 //---------------------------------------------------
0887 // TracePartFile
0888 
0889 TracePartFile::TracePartFile(TraceFile* file)
0890     : TraceInclusiveListCost(ProfileContext::context(ProfileContext::PartFile))
0891 {
0892     _dep = file;
0893 }
0894 
0895 TracePartFile::~TracePartFile()
0896 {}
0897 
0898 
0899 //---------------------------------------------------
0900 // TracePartObject
0901 
0902 TracePartObject::TracePartObject(TraceObject* object)
0903     : TraceInclusiveListCost(ProfileContext::context(ProfileContext::PartObject))
0904 {
0905     _dep = object;
0906 }
0907 
0908 TracePartObject::~TracePartObject()
0909 {}
0910 
0911 
0912 
0913 
0914 //---------------------------------------------------
0915 // TraceInstrJump
0916 
0917 TraceInstrJump::TraceInstrJump(TraceInstr* instrFrom, TraceInstr* instrTo,
0918                                bool isCondJump)
0919     : TraceJumpCost(ProfileContext::context(ProfileContext::InstrJump))
0920 {
0921     _first = nullptr;
0922 
0923     _instrFrom = instrFrom;
0924     _instrTo = instrTo;
0925     _isCondJump = isCondJump;
0926 }
0927 
0928 TraceInstrJump::~TraceInstrJump()
0929 {
0930     // we are the owner of the TracePartInstrJump's generated in our factory
0931     TracePartInstrJump* item = _first, *next;
0932     while(item) {
0933         next = item->next();
0934         delete item;
0935         item = next;
0936     }
0937 }
0938 
0939 TracePartInstrJump* TraceInstrJump::partInstrJump(TracePart* part)
0940 {
0941     static TracePartInstrJump* item = nullptr;
0942 
0943     // shortcut if recently used
0944     if (item &&
0945         (item->instrJump()==this) &&
0946         (item->part() == part)) return item;
0947 
0948     for(item = _first; item; item = item->next())
0949         if (item->part() == part)
0950             return item;
0951 
0952     item = new TracePartInstrJump(this, _first);
0953     item->setPosition(part);
0954     _first = item;
0955     return item;
0956 }
0957 
0958 void TraceInstrJump::update()
0959 {
0960     if (!_dirty) return;
0961 
0962     clear();
0963     TracePartInstrJump* item;
0964     for (item = _first; item; item = item->next()) {
0965         if (!item->part() || !item->part()->isActive()) continue;
0966 
0967         addCost(item);
0968     }
0969     _dirty = false;
0970 
0971 #if TRACE_DEBUG
0972     qDebug("updated %s", qPrintable( fullName() ));
0973 #endif
0974 
0975 #if TRACE_DEBUG
0976     qDebug("   > %s", qPrintable(costString(0)));
0977 #endif
0978 }
0979 
0980 QString TraceInstrJump::name() const
0981 {
0982     return QStringLiteral("jump at 0x%1 to 0x%2")
0983             .arg(_instrFrom->addr().toString())
0984             .arg(_instrTo->addr().toString());
0985 }
0986 
0987 
0988 //---------------------------------------------------
0989 // TraceLineJump
0990 
0991 TraceLineJump::TraceLineJump(TraceLine* lineFrom, TraceLine* lineTo,
0992                              bool isCondJump)
0993     : TraceJumpListCost(ProfileContext::context(ProfileContext::LineJump))
0994 {
0995     _lineFrom = lineFrom;
0996     _lineTo   = lineTo;
0997     _isCondJump = isCondJump;
0998 }
0999 
1000 TraceLineJump::~TraceLineJump()
1001 {
1002     // we are the owner of TracePartLineJump's generated in our factory
1003     qDeleteAll(_deps);
1004 }
1005 
1006 
1007 TracePartLineJump* TraceLineJump::partLineJump(TracePart* part)
1008 {
1009     TracePartLineJump* item = (TracePartLineJump*) findDepFromPart(part);
1010     if (!item) {
1011         item = new TracePartLineJump(this);
1012         item->setPosition(part);
1013         addDep(item);
1014     }
1015     return item;
1016 }
1017 
1018 
1019 QString TraceLineJump::name() const
1020 {
1021     return QStringLiteral("jump at %1 to %2")
1022             .arg(_lineFrom->prettyName())
1023             .arg(_lineTo->prettyName());
1024 }
1025 
1026 
1027 //---------------------------------------------------
1028 // TraceInstrCall
1029 
1030 TraceInstrCall::TraceInstrCall(TraceCall* call, TraceInstr* instr)
1031     : TraceCallListCost(ProfileContext::context(ProfileContext::InstrCall))
1032 {
1033     _call  = call;
1034     _instr = instr;
1035 }
1036 
1037 TraceInstrCall::~TraceInstrCall()
1038 {
1039     // we are the owner of TracePartInstrCall's generated in our factory
1040     qDeleteAll(_deps);
1041 }
1042 
1043 
1044 TracePartInstrCall* TraceInstrCall::partInstrCall(TracePart* part,
1045                                                   TracePartCall*)
1046 {
1047     TracePartInstrCall* item = (TracePartInstrCall*) findDepFromPart(part);
1048     if (!item) {
1049         item = new TracePartInstrCall(this);
1050         item->setPosition(part);
1051         addDep(item);
1052         // instruction calls are not registered in function calls
1053         // as together with line calls calls are duplicated
1054         //partCall->addDep(item);
1055     }
1056     return item;
1057 }
1058 
1059 
1060 QString TraceInstrCall::name() const
1061 {
1062     return QStringLiteral("%1 at %2").arg(_call->name()).arg(_instr->name());
1063 }
1064 
1065 
1066 //---------------------------------------------------
1067 // TraceLineCall
1068 
1069 TraceLineCall::TraceLineCall(TraceCall* call, TraceLine* line)
1070     : TraceCallListCost(ProfileContext::context(ProfileContext::LineCall))
1071 {
1072     _call = call;
1073 
1074     _line = line;
1075 }
1076 
1077 TraceLineCall::~TraceLineCall()
1078 {
1079     // we are the owner of TracePartLineCall's generated in our factory
1080     qDeleteAll(_deps);
1081 }
1082 
1083 
1084 TracePartLineCall* TraceLineCall::partLineCall(TracePart* part,
1085                                                TracePartCall* partCall)
1086 {
1087     TracePartLineCall* item = (TracePartLineCall*) findDepFromPart(part);
1088     if (!item) {
1089         item = new TracePartLineCall(this);
1090         item->setPosition(part);
1091         addDep(item);
1092         partCall->addDep(item);
1093     }
1094     return item;
1095 }
1096 
1097 
1098 QString TraceLineCall::name() const
1099 {
1100     return QStringLiteral("%1 at %2").arg(_call->name()).arg(_line->name());
1101 }
1102 
1103 
1104 //---------------------------------------------------
1105 // TraceCall
1106 
1107 TraceCall::TraceCall(TraceFunction* caller, TraceFunction* called)
1108     : TraceCallListCost(ProfileContext::context(ProfileContext::Call))
1109 {
1110     _caller = caller;
1111     _called = called;
1112 }
1113 
1114 
1115 TraceCall::~TraceCall()
1116 {
1117     // we are the owner of all items generated in our factories
1118     qDeleteAll(_deps);
1119     qDeleteAll(_lineCalls);
1120 }
1121 
1122 TracePartCall* TraceCall::partCall(TracePart* part,
1123                                    TracePartFunction* partCaller,
1124                                    TracePartFunction* partCalling)
1125 {
1126     TracePartCall* item = (TracePartCall*) findDepFromPart(part);
1127     if (!item) {
1128         item = new TracePartCall(this);
1129         item->setPosition(part);
1130         addDep(item);
1131         partCaller->addPartCalling(item);
1132         partCalling->addPartCaller(item);
1133     }
1134     return item;
1135 }
1136 
1137 TraceInstrCall* TraceCall::instrCall(TraceInstr* i)
1138 {
1139     foreach(TraceInstrCall* icall, _instrCalls)
1140         if (icall->instr() == i)
1141             return icall;
1142 
1143     TraceInstrCall* icall = new TraceInstrCall(this, i);
1144     _instrCalls.append(icall);
1145     invalidate();
1146 
1147 #if TRACE_DEBUG
1148     qDebug("Created %s [TraceCall::instrCall]", qPrintable(icall->fullName()));
1149 #endif
1150     i->addInstrCall(icall);
1151     return icall;
1152 }
1153 
1154 
1155 TraceLineCall* TraceCall::lineCall(TraceLine* l)
1156 {
1157     foreach(TraceLineCall* lcall, _lineCalls)
1158         if (lcall->line() == l)
1159             return lcall;
1160 
1161     TraceLineCall* lcall = new TraceLineCall(this, l);
1162     _lineCalls.append(lcall);
1163     invalidate();
1164 
1165 #if TRACE_DEBUG
1166     qDebug("Created %s [TraceCall::lineCall]", qPrintable(lcall->fullName()));
1167 #endif
1168     l->addLineCall(lcall);
1169     return lcall;
1170 }
1171 
1172 
1173 void TraceCall::invalidateDynamicCost()
1174 {
1175     foreach(TraceLineCall* lc, _lineCalls)
1176         lc->invalidate();
1177 
1178     foreach(TraceInstrCall* ic, _instrCalls)
1179         ic->invalidate();
1180 
1181     invalidate();
1182 }
1183 
1184 
1185 QString TraceCall::name() const
1186 {
1187     return QStringLiteral("%1 => %2")
1188             .arg(_caller->name())
1189             .arg(_called->name());
1190 }
1191 
1192 int TraceCall::inCycle()
1193 {
1194     if (!_caller || !_called) return 0;
1195     if (!_caller->cycle()) return 0;
1196     if (_caller == _caller->cycle()) return 0;
1197     if (_caller->cycle() != _called->cycle()) return 0;
1198 
1199     return _caller->cycle()->cycleNo();
1200 }
1201 
1202 void TraceCall::update()
1203 {
1204     if (!_dirty) return;
1205 
1206     // special handling for cycles
1207     if (_caller && _caller->cycle() && _caller==_caller->cycle()) {
1208 
1209         // we have no part calls: use inclusive cost of called function
1210         clear();
1211         if (_called)
1212             addCost(_called->inclusive());
1213         _dirty = false;
1214         return;
1215     }
1216 
1217     TraceCallListCost::update();
1218 }
1219 
1220 TraceFunction* TraceCall::caller(bool /*skipCycle*/) const
1221 {
1222     return _caller;
1223 }
1224 
1225 TraceFunction* TraceCall::called(bool skipCycle) const
1226 {
1227     if (!skipCycle && _called) {
1228         // if this is a call to a cycle member from outside of the cycle,
1229         // fake it to be a call to the whole cycle
1230         if (_called->cycle() && _caller &&
1231             (_caller->cycle() != _called->cycle()))
1232             return _called->cycle();
1233     }
1234 
1235     return _called;
1236 }
1237 
1238 QString TraceCall::callerName(bool skipCycle) const
1239 {
1240     if (!_caller) return QObject::tr("(no caller)");
1241 
1242     if (!skipCycle) {
1243         // if this call goes into a cycle, add the entry function
1244         TraceFunctionCycle* c = _called->cycle();
1245         if (c && _caller && (_caller->cycle() != c)) {
1246             QString via = _called->prettyName();
1247             return QObject::tr("%1 via %2").arg(_caller->prettyName()).arg(via);
1248         }
1249     }
1250 
1251     return _caller->prettyName();
1252 }
1253 
1254 QString TraceCall::calledName(bool skipCycle) const
1255 {
1256     if (!_called) return QObject::tr("(no callee)");
1257 
1258     if (!skipCycle) {
1259         // if this call goes into a cycle, add the entry function
1260         TraceFunctionCycle* c = _called->cycle();
1261         if (c && _caller && (_caller->cycle() != c)) {
1262             // HACK to get rid of cycle postfix...
1263             _called->setCycle(nullptr);
1264             QString via = _called->prettyName();
1265             _called->setCycle(c);
1266             return QObject::tr("%1 via %2").arg(c->name()).arg(via);
1267         }
1268     }
1269     return _called->prettyName();
1270 }
1271 
1272 
1273 //---------------------------------------------------
1274 // TraceInstr
1275 
1276 TraceInstr::TraceInstr()
1277     : TraceListCost(ProfileContext::context(ProfileContext::Instr))
1278 {
1279     _addr = 0;
1280     _line = nullptr;
1281     _function = nullptr;
1282 }
1283 
1284 TraceInstr::~TraceInstr()
1285 {
1286     // we are the owner of items generated in our factories
1287     qDeleteAll(_deps);
1288     qDeleteAll(_instrJumps);
1289 }
1290 
1291 bool TraceInstr::hasCost(EventType* ct)
1292 {
1293     if (subCost(ct) >0)
1294         return true;
1295 
1296     foreach(TraceInstrCall* ic, _instrCalls)
1297         if (ic->subCost(ct) >0)
1298             return true;
1299 
1300     foreach(TraceInstrJump* ij, _instrJumps)
1301         if (ij->executedCount() >0)
1302             return true;
1303 
1304     return false;
1305 }
1306 
1307 TracePartInstr* TraceInstr::partInstr(TracePart* part,
1308                                       TracePartFunction* partFunction)
1309 {
1310     TracePartInstr* item = (TracePartInstr*) findDepFromPart(part);
1311     if (!item) {
1312         item = new TracePartInstr(this);
1313         item->setPosition(part);
1314         addDep(item);
1315         //part->addDep(item);
1316         partFunction->addPartInstr(item);
1317     }
1318     return item;
1319 }
1320 
1321 TraceInstrJump* TraceInstr::instrJump(TraceInstr* to, bool isJmpCond)
1322 {
1323     foreach(TraceInstrJump* jump, _instrJumps)
1324         if (jump->instrTo() == to)
1325             return jump;
1326 
1327     TraceInstrJump* jump = new TraceInstrJump(this, to, isJmpCond);
1328     _instrJumps.append(jump);
1329     return jump;
1330 }
1331 
1332 
1333 
1334 void TraceInstr::addInstrCall(TraceInstrCall* instrCall)
1335 {
1336 #if TRACE_ASSERTIONS
1337     if (_instrCalls.contains(instrCall)) return;
1338 
1339     if (instrCall->instr() != this) {
1340         qDebug("Can not add instruction call to another instruction!");
1341         return;
1342     }
1343 #endif
1344 
1345     _instrCalls.append(instrCall);
1346     invalidate();
1347 
1348 #if TRACE_DEBUG
1349     qDebug("%s added\n %s (now %d)",
1350            qPrintable( fullName() ),
1351            qPrintable(instrCall->fullName()), _instrCalls.count());
1352 #endif
1353 }
1354 
1355 
1356 QString TraceInstr::name() const
1357 {
1358     return QStringLiteral("0x%1").arg(_addr.toString());
1359 }
1360 
1361 QString TraceInstr::prettyName() const
1362 {
1363     return QStringLiteral("0x%1").arg(_addr.toString());
1364 }
1365 
1366 
1367 //---------------------------------------------------
1368 // TraceLine
1369 
1370 TraceLine::TraceLine()
1371     : TraceListCost(ProfileContext::context(ProfileContext::Line))
1372 {
1373     _lineno = 0;
1374     _sourceFile = nullptr;
1375 }
1376 
1377 TraceLine::~TraceLine()
1378 {
1379     // we are the owner of items generated in our factories
1380     qDeleteAll(_deps);
1381     qDeleteAll(_lineJumps);
1382 }
1383 
1384 bool TraceLine::hasCost(EventType* ct)
1385 {
1386     if (subCost(ct) >0)
1387         return true;
1388 
1389     foreach(TraceLineCall* lc, _lineCalls)
1390         if (lc->subCost(ct) >0)
1391             return true;
1392 
1393     foreach(TraceLineJump* lj, _lineJumps)
1394         if (lj->executedCount() >0)
1395             return true;
1396 
1397     return false;
1398 }
1399 
1400 TracePartLine* TraceLine::partLine(TracePart* part,
1401                                    TracePartFunction* partFunction)
1402 {
1403     TracePartLine* item = (TracePartLine*) findDepFromPart(part);
1404     if (!item) {
1405         item = new TracePartLine(this);
1406         item->setPosition(part);
1407         addDep(item);
1408 #if !USE_FIXCOST
1409         part->addDep(item);
1410 #endif
1411         partFunction->addPartLine(item);
1412     }
1413     return item;
1414 }
1415 
1416 TraceLineJump* TraceLine::lineJump(TraceLine* to, bool isJmpCond)
1417 {
1418     foreach(TraceLineJump* jump, _lineJumps)
1419         if (jump->lineTo() == to)
1420             return jump;
1421 
1422     TraceLineJump* jump = new TraceLineJump(this, to, isJmpCond);
1423     _lineJumps.append(jump);
1424     return jump;
1425 }
1426 
1427 
1428 void TraceLine::addLineCall(TraceLineCall* lineCall)
1429 {
1430 #if TRACE_ASSERTIONS
1431     if (_lineCalls.contains(lineCall)) return;
1432 
1433     if (lineCall->line() != this) {
1434         qDebug("Can not add line call to another line!");
1435         return;
1436     }
1437 #endif
1438 
1439     TraceFunction* caller = lineCall->call()->caller();
1440     TraceFunction* function = _sourceFile->function();
1441     if (caller != function) {
1442         // We regard 2 functions as the same if they have
1443         // same class, name, object
1444         if ((caller->cls() != function->cls()) ||
1445             (caller->name() != function->name()) ||
1446             (caller->object() != function->object())) {
1447 
1448             qDebug("ERROR: Adding line call, line %d\n  of %s to\n  %s ?!",
1449                    lineCall->line()->lineno(),
1450                    qPrintable(caller->info()), qPrintable(function->info()));
1451         }
1452     }
1453 
1454     _lineCalls.append(lineCall);
1455     invalidate();
1456 
1457 #if TRACE_DEBUG
1458     qDebug("%s added\n %s (now %d)",
1459            qPrintable( fullName() ),
1460            qPrintable(lineCall->fullName()), _lineCalls.count());
1461 #endif
1462 }
1463 
1464 
1465 QString TraceLine::name() const
1466 {
1467     QString fileShortName = _sourceFile->file()->shortName();
1468     if (fileShortName.isEmpty())
1469         return TraceFile::prettyEmptyName();
1470 
1471     return QStringLiteral("%1:%2")
1472             .arg(fileShortName).arg(_lineno);
1473 }
1474 
1475 QString TraceLine::prettyName() const
1476 {
1477     return QStringLiteral("%1 [%2]")
1478             .arg(name()).arg(_sourceFile->function()->prettyName());
1479 }
1480 
1481 //---------------------------------------------------
1482 // TraceCostItem
1483 
1484 TraceCostItem::TraceCostItem(ProfileContext* context)
1485     : TraceInclusiveListCost(context)
1486 {
1487 }
1488 
1489 TraceCostItem::~TraceCostItem()
1490 {}
1491 
1492 
1493 //---------------------------------------------------
1494 // TraceFunctionSource
1495 
1496 TraceFunctionSource::TraceFunctionSource(TraceFunction* function,
1497                                          TraceFile* file)
1498     : ProfileCostArray(ProfileContext::context(ProfileContext::FunctionSource))
1499 {
1500     _file = file;
1501     _function = function;
1502 
1503     // the function is dependent from our cost sum
1504     _dep = _function;
1505 
1506     _lineMap = nullptr;
1507     _lineMapFilled = false;
1508     _line0 = nullptr;
1509 }
1510 
1511 TraceFunctionSource::~TraceFunctionSource()
1512 {
1513     delete _lineMap;
1514     delete _line0;
1515 }
1516 
1517 QString TraceFunctionSource::name() const
1518 {
1519     return QStringLiteral("%1 for %2").arg(_file->name()).arg(_function->name());
1520 }
1521 
1522 uint TraceFunctionSource::firstLineno()
1523 {
1524     // lazy generate the map if not done up to now
1525     TraceLineMap* map = lineMap();
1526     // ignore line 0 here
1527     if (!map || map->count() == 0) return 0;
1528     TraceLineMap::Iterator it = map->begin();
1529     return (*it).lineno();
1530 }
1531 
1532 uint TraceFunctionSource::lastLineno()
1533 {
1534     // lazy generate the map if not done up to now
1535     TraceLineMap* map = lineMap();
1536     // ignore line 0 here
1537     if (!map || map->count() == 0) return 0;
1538     TraceLineMap::Iterator it = map->end();
1539     --it;
1540     return (*it).lineno();
1541 }
1542 
1543 /* factory */
1544 TraceLine* TraceFunctionSource::line(uint lineno, bool createNew)
1545 {
1546     if (lineno == 0) {
1547         if (!_line0) {
1548             if (!createNew) return nullptr;
1549             _line0 = new TraceLine;
1550             _line0->setSourceFile(this);
1551             _line0->setLineno(0);
1552         }
1553         return _line0;
1554     }
1555 
1556     if (!createNew) {
1557         if (!_lineMap) return nullptr;
1558         TraceLineMap::Iterator it = _lineMap->find(lineno);
1559         if (it == _lineMap->end()) return nullptr;
1560         return &(it.value());
1561     }
1562 
1563     if (!_lineMap) _lineMap = new TraceLineMap;
1564 
1565     TraceLine& l = (*_lineMap)[lineno];
1566     if (!l.isValid()) {
1567         l.setSourceFile(this);
1568         l.setLineno(lineno);
1569 
1570 #if TRACE_DEBUG
1571         qDebug("Created %s [TraceFunctionSource::line]",
1572                qPrintable(l.fullName()));
1573 #endif
1574     }
1575     return &l;
1576 }
1577 
1578 void TraceFunctionSource::update()
1579 {
1580     if (!_dirty) return;
1581 
1582     clear();
1583 
1584     // no need to create lineMap if not already created
1585     if (_lineMap) {
1586         TraceLineMap::Iterator lit;
1587         for ( lit = _lineMap->begin();
1588               lit != _lineMap->end(); ++lit )
1589             addCost( &(*lit) );
1590     }
1591 
1592     _dirty = false;
1593 }
1594 
1595 void TraceFunctionSource::invalidateDynamicCost()
1596 {
1597     // no need to create lineMap if not already created
1598     if (_lineMap) {
1599         TraceLineMap::Iterator lit;
1600         for ( lit = _lineMap->begin();
1601               lit != _lineMap->end(); ++lit )
1602             (*lit).invalidate();
1603     }
1604 
1605     invalidate();
1606 }
1607 
1608 TraceLineMap* TraceFunctionSource::lineMap()
1609 {
1610 #if USE_FIXCOST
1611 
1612     if (_lineMapFilled) return _lineMap;
1613     _lineMapFilled = true;
1614     if (!_lineMap)
1615         _lineMap = new TraceLineMap;
1616 
1617     TraceLine* l = nullptr;
1618     TracePartLine* pl = nullptr;
1619     TraceLineCall* lc = nullptr;
1620     TracePartLineCall* plc = nullptr;
1621 
1622     /* go over all part objects for this function, and
1623      * - build TraceLines (the line map) using FixCost objects
1624      * - build TraceJumpLines using FixJump objects
1625      */
1626     foreach(TraceInclusiveCost* ic, _function->deps()) {
1627         TracePartFunction* pf = (TracePartFunction*) ic;
1628 
1629         if (0) qDebug("PartFunction %s:%d",
1630                       qPrintable(pf->function()->name()),
1631                       pf->part()->partNumber());
1632 
1633         FixCost* fc = pf->firstFixCost();
1634         for(; fc; fc = fc->nextCostOfPartFunction()) {
1635             if (fc->line() == 0) continue;
1636             if (fc->functionSource() != this) continue;
1637 
1638             if (!l || l->lineno() != fc->line()) {
1639                 l = &(*_lineMap)[fc->line()];
1640                 if (!l->isValid()) {
1641                     l->setSourceFile(this);
1642                     l->setLineno(fc->line());
1643                 }
1644                 pl = nullptr;
1645             }
1646             if (!pl || pl->part() != fc->part())
1647                 pl = l->partLine(fc->part(), pf);
1648             fc->addTo(pl);
1649         }
1650 
1651         TraceLine* to = nullptr;
1652         TraceLineJump* lj;
1653         TracePartLineJump* plj;
1654         FixJump* fj = pf->firstFixJump();
1655         for(; fj; fj = fj->nextJumpOfPartFunction()) {
1656             if (fj->line() == 0) continue;
1657             if (fj->source() != this) continue;
1658             if (!fj->targetSource()) {
1659                 // be robust against buggy loaders
1660                 continue;
1661             }
1662 
1663             // do not display jumps to same or following line
1664             if ((fj->line() == fj->targetLine()) ||
1665                 (fj->line()+1 == fj->targetLine())) continue;
1666 
1667             if (!l || l->lineno() != fj->line()) {
1668                 l = &(*_lineMap)[fj->line()];
1669                 if (!l->isValid()) {
1670                     l->setSourceFile(this);
1671                     l->setLineno(fj->line());
1672                 }
1673             }
1674 
1675             to = fj->targetSource()->line(fj->targetLine(), true);
1676 
1677             lj = l->lineJump(to, fj->isCondJump());
1678             plj = lj->partLineJump(fj->part());
1679 
1680             fj->addTo(plj);
1681         }
1682 
1683         foreach(TracePartCall* pc, pf->partCallings()) {
1684 
1685             if (0) qDebug("PartCall %s:%d",
1686                           qPrintable(pc->call()->name()),
1687                           pf->part()->partNumber());
1688 
1689             FixCallCost* fcc = pc->firstFixCallCost();
1690             for(; fcc; fcc = fcc->nextCostOfPartCall()) {
1691                 if (fcc->line() == 0) continue;
1692                 if (fcc->functionSource() != this) continue;
1693 
1694                 if (!l || l->lineno() != fcc->line()) {
1695                     l = &(*_lineMap)[fcc->line()];
1696                     if (!l->isValid()) {
1697                         l->setSourceFile(this);
1698                         l->setLineno(fcc->line());
1699                     }
1700                 }
1701                 if (!lc || lc->call() != pc->call() || lc->line() != l) {
1702                     lc = pc->call()->lineCall(l);
1703                     plc = nullptr;
1704                 }
1705                 if (!plc || plc->part() != fcc->part())
1706                     plc = lc->partLineCall(fcc->part(), pc);
1707 
1708                 fcc->addTo(plc);
1709                 if (0) qDebug("Add FixCallCost %s:%d/0x%s, CallCount %s",
1710                               qPrintable(fcc->functionSource()->file()->shortName()),
1711                               fcc->line(), qPrintable(fcc->addr().toString()),
1712                               qPrintable(fcc->callCount().pretty()));
1713             }
1714         }
1715     }
1716 
1717 #endif
1718 
1719     return _lineMap;
1720 }
1721 
1722 
1723 
1724 //---------------------------------------------------
1725 // TraceAssociation
1726 
1727 TraceAssociation::TraceAssociation()
1728 {
1729     _function = nullptr;
1730     _valid = false;
1731 }
1732 
1733 TraceAssociation::~TraceAssociation()
1734 {
1735     // do not delete from TraceFunction
1736     if (_function) _function->removeAssociation(this);
1737 }
1738 
1739 bool TraceAssociation::isAssociated()
1740 {
1741     if (!_function) return false;
1742 
1743     return _function->association(rtti())==this;
1744 }
1745 
1746 bool TraceAssociation::setFunction(TraceFunction* f)
1747 {
1748     if (_function == f)
1749         return isAssociated();
1750 
1751     if (_function) {
1752         // do not delete ourself
1753         _function->removeAssociation(this);
1754     }
1755 
1756     _function = f;
1757     if (f && f->association(rtti()) == nullptr) {
1758         f->addAssociation(this);
1759         return true;
1760     }
1761     return false;
1762 }
1763 
1764 void TraceAssociation::clear(TraceData* d, int rtti)
1765 {
1766     TraceFunctionMap::Iterator it;
1767     for ( it = d->functionMap().begin();
1768           it != d->functionMap().end(); ++it )
1769         (*it).removeAssociation(rtti);
1770 }
1771 
1772 void TraceAssociation::invalidate(TraceData* d, int rtti)
1773 {
1774     TraceFunctionMap::Iterator it;
1775     for ( it = d->functionMap().begin();
1776           it != d->functionMap().end(); ++it )
1777         (*it).invalidateAssociation(rtti);
1778 }
1779 
1780 
1781 //---------------------------------------------------
1782 // TraceFunction
1783 
1784 TraceFunction::TraceFunction()
1785     : TraceCostItem(ProfileContext::context(ProfileContext::Function))
1786 {
1787     _object = nullptr;
1788     _file = nullptr;
1789     _cls = nullptr;
1790     _cycle = nullptr;
1791 
1792     _calledCount     = 0;
1793     _callingCount    = 0;
1794     _calledContexts  = 0;
1795     _callingContexts = 0;
1796 
1797     _instrMap = nullptr;
1798     _instrMapFilled = false;
1799 }
1800 
1801 
1802 TraceFunction::~TraceFunction()
1803 {
1804     qDeleteAll(_associations);
1805 
1806     // we are the owner of items generated in our factories
1807     qDeleteAll(_deps);
1808     qDeleteAll(_callings);
1809     qDeleteAll(_sourceFiles);
1810 
1811     delete _instrMap;
1812 }
1813 
1814 // no unique check is done!
1815 void TraceFunction::addAssociation(TraceAssociation* a)
1816 {
1817     if (!a) return;
1818     _associations.append(a);
1819 }
1820 
1821 void TraceFunction::removeAssociation(TraceAssociation* a)
1822 {
1823     _associations.removeAll(a);
1824 }
1825 
1826 void TraceFunction::removeAssociation(int rtti, bool reallyDelete)
1827 {
1828     if (rtti==0) {
1829         if (reallyDelete)
1830             qDeleteAll(_associations);
1831         _associations.clear();
1832         return;
1833     }
1834 
1835     foreach(TraceAssociation* a, _associations) {
1836         if (a->rtti() == rtti) {
1837             if (reallyDelete) delete a;
1838             _associations.removeAll(a);
1839             return;
1840         }
1841     }
1842 }
1843 
1844 void TraceFunction::invalidateAssociation(int rtti)
1845 {
1846     foreach(TraceAssociation* a, _associations) {
1847         if ((rtti==0) || (a->rtti() == rtti))
1848             a->invalidate();
1849     }
1850 }
1851 
1852 TraceAssociation* TraceFunction::association(int rtti)
1853 {
1854     foreach(TraceAssociation* a, _associations) {
1855         if (a->rtti() == rtti)
1856             return a;
1857     }
1858     return nullptr;
1859 }
1860 
1861 #if 0
1862 // helper for prettyName
1863 bool TraceFunction::isUniquePrefix(const QString& prefix) const
1864 {
1865     TraceFunctionMap::ConstIterator it, it2;
1866     it = it2 = _myMapIterator;
1867     if (it != data()->functionBeginIterator()) {
1868         it2--;
1869         if ((*it2).name().startsWith(prefix)) return false;
1870     }
1871     if (it != data()->functionEndIterator()) {
1872         it++;
1873         if ((*it).name().startsWith(prefix)) return false;
1874     }
1875     return true;
1876 }
1877 #endif
1878 
1879 QString TraceFunction::prettyName() const
1880 {
1881     QString res = _name;
1882 
1883     if (_name.isEmpty())
1884         return prettyEmptyName();
1885 
1886     if (GlobalConfig::hideTemplates()) {
1887 
1888         res = QString();
1889         int d = 0;
1890         for(int i=0;i<_name.length();i++) {
1891             switch(_name[i].toLatin1()) {
1892             case '<':
1893                 if (d<=0) res.append(_name[i]);
1894                 d++;
1895                 break;
1896             case '>':
1897                 d--;
1898                 // fall through
1899             default:
1900                 if (d<=0) res.append(_name[i]);
1901                 break;
1902             }
1903         }
1904     }
1905 #if 0
1906     // TODO: make it a configuration, but disabled by default.
1907     //
1908     // Stripping parameter signature of C++ symbols is fine
1909     // if the function name is unique in the whole program.
1910     // However, we only can detect if it is unique in the profile,
1911     // which makes this "beautification" potentially confusing
1912     int p = _name.indexOf('(');
1913     if (p>0) {
1914         // handle C++ "operator()" correct
1915         if ( (p+2 < _name.size()) && (_name[p+1] == ')') && (_name[p+2] == '(')) p+=2;
1916 
1917         // we have a C++ symbol with argument types:
1918         // check for unique function name (inclusive '(' !)
1919         if (isUniquePrefix(_name.left(p+1)))
1920             res = _name.left(p);
1921     }
1922 #endif
1923 
1924     // cycle members
1925     if (_cycle) {
1926         if (_cycle != this)
1927             res = QStringLiteral("%1 <cycle %2>").arg(res).arg(_cycle->cycleNo());
1928         else
1929             res = QStringLiteral("<cycle %2>").arg(_cycle->cycleNo());
1930     }
1931 
1932 
1933     return res;
1934 }
1935 
1936 QString TraceFunction::formattedName() const
1937 {
1938     // produce a "rich" name only if templates are hidden
1939     if (!GlobalConfig::hideTemplates() || _name.isEmpty()) return QString();
1940 
1941     // bold, but inside template parameters normal, function arguments italic
1942     QString rich(QStringLiteral("<b>"));
1943     int d = 0;
1944     for(int i=0;i<_name.length();i++) {
1945         switch(_name[i].toLatin1()) {
1946         case '&':
1947             rich.append("&amp;");
1948             break;
1949         case '<':
1950             d++;
1951             rich.append("&lt;");
1952             if (d==1)
1953                 rich.append("</b>");
1954             break;
1955         case '>':
1956             d--;
1957             if (d==0)
1958                 rich.append("<b>");
1959             rich.append("&gt; "); // add space to allow for line break
1960             break;
1961         case '(':
1962             rich.append("</b>(<i><b>");
1963             break;
1964         case ')':
1965             rich.append("</b></i>)<b>");
1966             break;
1967         default:
1968             rich.append(_name[i]);
1969             break;
1970         }
1971     }
1972     rich.append("</b>");
1973     return rich;
1974 }
1975 
1976 QString TraceFunction::prettyEmptyName()
1977 {
1978     return QObject::tr("(unknown)");
1979 }
1980 
1981 /*
1982  * Returns location string: ELF object and source file(s).
1983  */
1984 QString TraceFunction::location(int maxFiles) const
1985 {
1986     QString loc;
1987 
1988     // add object file with address range
1989     if (_object) {
1990         loc = _object->shortName();
1991 
1992 #if 0
1993         uint from = firstAddress();
1994         uint to = lastAddress();
1995         if (from != 0 && to != 0) {
1996             if (from == to)
1997                 loc += QString(" (0x%1)").arg(to, 0, 16);
1998             else
1999                 loc += QString(" (0x%1-0x%2)").arg(from, 0, 16).arg(to, 0, 16);
2000         }
2001 #endif
2002     }
2003 
2004     // add all source files
2005     int filesAdded = 0;
2006     foreach(TraceFunctionSource* sourceFile, _sourceFiles) {
2007         if (!sourceFile->file() ||
2008             (sourceFile->file()->name().isEmpty()) )
2009             continue;
2010 
2011         if (!loc.isEmpty())
2012             loc += (filesAdded>0) ? ", " : ": ";
2013         filesAdded++;
2014 
2015         if ((maxFiles>0) && (filesAdded>maxFiles)) {
2016             loc += QLatin1String("...");
2017             break;
2018         }
2019         loc += sourceFile->file()->shortName();
2020 
2021 #if 0
2022         from = sourceFile->firstLineno();
2023         to = sourceFile->lastLineno();
2024         if (from != 0 && to != 0) {
2025             if (from == to)
2026                 loc += QString(" (%1)").arg(to);
2027             else
2028                 loc += QString(" (%1-%2)").arg(from).arg(to);
2029         }
2030 #endif
2031     }
2032 
2033     return loc;
2034 }
2035 
2036 // pretty version is allowed to mangle the string...
2037 QString TraceFunction::prettyLocation(int maxFiles) const
2038 {
2039     QString l = location(maxFiles);
2040     if (l.isEmpty()) return QObject::tr("(unknown)");
2041 
2042     return l;
2043 }
2044 
2045 void TraceFunction::addPrettyLocation(QString& s, int maxFiles) const
2046 {
2047     QString l = location(maxFiles);
2048     if (l.isEmpty()) return;
2049 
2050     s += QStringLiteral(" (%1)").arg(l);
2051 }
2052 
2053 QString TraceFunction::prettyNameWithLocation(int maxFiles) const
2054 {
2055     QString l = location(maxFiles);
2056     if (l.isEmpty()) return prettyName();
2057 
2058     return QStringLiteral("%1 (%2)").arg(prettyName()).arg(l);
2059 }
2060 
2061 QString TraceFunction::info() const
2062 {
2063     QString l = location();
2064     if (l.isEmpty())
2065         return QStringLiteral("Function %1").arg(name());
2066 
2067     return QStringLiteral("Function %1 (location %2)")
2068             .arg(name()).arg(l);
2069 }
2070 
2071 
2072 Addr TraceFunction::firstAddress() const
2073 {
2074     // ignore address 0 here
2075     if (!_instrMap || _instrMap->count() == 0) return 0;
2076     TraceInstrMap::ConstIterator it = _instrMap->constBegin();
2077     return (*it).addr();
2078 }
2079 
2080 Addr TraceFunction::lastAddress() const
2081 {
2082     // ignore address 0 here
2083     if (!_instrMap || _instrMap->count() == 0) return 0;
2084     TraceInstrMap::ConstIterator it = _instrMap->constEnd();
2085     --it;
2086     return (*it).addr();
2087 }
2088 
2089 /* factory */
2090 TraceInstr* TraceFunction::instr(Addr addr, bool createNew)
2091 {
2092     // address 0 not allowed
2093     if (addr == Addr(0)) return nullptr;
2094 
2095     if (!createNew) {
2096         if (!_instrMap) return nullptr;
2097         TraceInstrMap::Iterator it = _instrMap->find(addr);
2098         if (it == _instrMap->end())
2099             return nullptr;
2100         return &(it.value());
2101     }
2102 
2103     if (!_instrMap) _instrMap = new TraceInstrMap;
2104 
2105     TraceInstr& i = (*_instrMap)[addr];
2106     if (!i.isValid()) {
2107         i.setAddr(addr);
2108         i.setFunction(this);
2109 
2110 #if TRACE_DEBUG
2111         qDebug("Created %s [TraceFunction::instr]",
2112                qPrintable(i.fullName()));
2113 #endif
2114     }
2115     return &i;
2116 }
2117 
2118 void TraceFunction::addCaller(TraceCall* caller)
2119 {
2120 #if TRACE_ASSERTIONS
2121     if (caller->called() != this) {
2122         qDebug("Can not add call to another line!\n");
2123         return;
2124     }
2125 
2126     if (_callers.contains(caller)) return;
2127 #endif
2128 
2129     _callers.append(caller);
2130     invalidate();
2131 
2132 #if TRACE_DEBUG
2133     qDebug("%s added Caller\n %s (now %d)",
2134            qPrintable( fullName() ), qPrintable(caller->fullName()), _callers.count());
2135 #endif
2136 }
2137 
2138 
2139 
2140 TraceCall* TraceFunction::calling(TraceFunction* called)
2141 {
2142     foreach(TraceCall* calling, _callings)
2143         if (calling->called() == called)
2144             return calling;
2145 
2146     TraceCall* calling = new TraceCall(this, called);
2147     _callings.append(calling);
2148 
2149     // we have to invalidate ourself so invalidations from item propagate up
2150     invalidate();
2151 
2152 #if TRACE_DEBUG
2153     qDebug("Created %s [TraceFunction::calling]", qPrintable(calling->fullName()));
2154 #endif
2155     called->addCaller(calling);
2156     return calling;
2157 }
2158 
2159 TraceFunctionSource* TraceFunction::sourceFile(TraceFile* file,
2160                                                bool createNew)
2161 {
2162     if (!file) file = _file;
2163 
2164     foreach(TraceFunctionSource* sourceFile, _sourceFiles)
2165         if (sourceFile->file() == file)
2166             return sourceFile;
2167 
2168     if (!createNew) return nullptr;
2169 
2170     TraceFunctionSource* sourceFile = new TraceFunctionSource(this, file);
2171     _sourceFiles.append(sourceFile);
2172 
2173     // we have to invalidate ourself so invalidations from item propagate up
2174     invalidate();
2175 
2176 #if TRACE_DEBUG
2177     qDebug("Created SourceFile %s [TraceFunction::line]",
2178            qPrintable(file->name()));
2179 #endif
2180     file->addSourceFile(sourceFile);
2181     return sourceFile;
2182 }
2183 
2184 TraceLine* TraceFunction::line(TraceFile* file, uint lineno,
2185                                bool createNew)
2186 {
2187     Q_ASSERT(file!=nullptr);
2188 
2189     TraceFunctionSource* sf = sourceFile(file, createNew);
2190     if (!sf)
2191         return nullptr;
2192     else
2193         return sf->line(lineno, createNew);
2194 }
2195 
2196 
2197 TracePartFunction* TraceFunction::partFunction(TracePart* part,
2198                                                TracePartFile* partFile,
2199                                                TracePartObject* partObject)
2200 {
2201     TracePartFunction* item = (TracePartFunction*) findDepFromPart(part);
2202     if (!item) {
2203         item = new TracePartFunction(this, partObject, partFile);
2204         item->setPosition(part);
2205         addDep(item);
2206 #if USE_FIXCOST
2207         part->addDep(item);
2208 #endif
2209 
2210         if (_cls) {
2211             TracePartClass* partClass = _cls->partClass(part);
2212             partClass->addPartFunction(item);
2213             item->setPartClass(partClass);
2214         }
2215 
2216         partFile->addPartFunction(item);
2217         if (partObject)
2218             partObject->addPartFunction(item);
2219     }
2220     else if (item->partObject()==nullptr && partObject) {
2221         item->setPartObject(partObject);
2222         partObject->addPartFunction(item);
2223     }
2224 
2225     return item;
2226 }
2227 
2228 
2229 SubCost TraceFunction::calledCount()
2230 {
2231     if (_dirty) update();
2232 
2233     return _calledCount;
2234 }
2235 
2236 int TraceFunction::calledContexts()
2237 {
2238     if (_dirty) update();
2239 
2240     return _calledContexts;
2241 }
2242 
2243 SubCost TraceFunction::callingCount()
2244 {
2245     if (_dirty) update();
2246 
2247     return _callingCount;
2248 }
2249 
2250 int TraceFunction::callingContexts()
2251 {
2252     if (_dirty) update();
2253 
2254     return _callingContexts;
2255 }
2256 
2257 QString TraceFunction::prettyCalledCount()
2258 {
2259     return _calledCount.pretty();
2260 }
2261 
2262 QString TraceFunction::prettyCallingCount()
2263 {
2264     return _callingCount.pretty();
2265 }
2266 
2267 
2268 TraceCallList TraceFunction::callers(bool skipCycle) const
2269 {
2270     if (skipCycle) return _callers;
2271 
2272     // fake the callers for cycle members
2273     if (_cycle && (_cycle != this)) {
2274         TraceCallList l;
2275 
2276         // inner-cycle-callers
2277         foreach(TraceCall* c, _callers)
2278             if (c->caller()->cycle() == _cycle)
2279                 l.append(c);
2280 
2281         // call from cycle itself
2282         foreach(TraceCall* c, _cycle->_callings)
2283             if (c->called() == this) {
2284                 l.append(c);
2285                 return l;
2286             }
2287     }
2288 
2289     return _callers;
2290 }
2291 
2292 const TraceCallList& TraceFunction::callings(bool /* skipCycle */) const
2293 {
2294     return _callings;
2295 }
2296 
2297 void TraceFunction::invalidateDynamicCost()
2298 {
2299     foreach(TraceCall* c, _callings)
2300         c->invalidateDynamicCost();
2301 
2302     foreach(TraceFunctionSource* sf, _sourceFiles)
2303         sf->invalidateDynamicCost();
2304 
2305     if (_instrMap) {
2306         TraceInstrMap::Iterator iit;
2307         for ( iit = _instrMap->begin();
2308               iit != _instrMap->end(); ++iit )
2309             (*iit).invalidate();
2310     }
2311 
2312     invalidate();
2313 }
2314 
2315 void TraceFunction::update()
2316 {
2317     if (!_dirty) return;
2318 
2319 #if TRACE_DEBUG
2320     qDebug("Update %s (Callers %d, sourceFiles %d, instrs %d)",
2321            qPrintable(_name), _callers.count(),
2322            _sourceFiles.count(), _instrMap ? _instrMap->count():0);
2323 #endif
2324 
2325     _calledCount    = 0;
2326     _callingCount    = 0;
2327     _calledContexts  = 0;
2328     _callingContexts = 0;
2329     clear();
2330 
2331     // To calculate context counts, we just use first real event type (FIXME?)
2332     EventType* e = data() ? data()->eventTypes()->realType(0) : nullptr;
2333 
2334     // context count is NOT the sum of part contexts
2335     foreach(TraceCall *caller, _callers) {
2336         if (e && (caller->subCost(e) >0))
2337             _calledContexts++;
2338         _calledCount += caller->callCount();
2339     }
2340 
2341     foreach(TraceCall* callee, _callings) {
2342         if (e && (callee->subCost(e) >0))
2343             _callingContexts++;
2344         _callingCount += callee->callCount();
2345     }
2346 
2347     if (data()->inFunctionCycleUpdate() || !_cycle) {
2348         // usual case (no cycle member)
2349         foreach(TraceInclusiveCost* item, _deps) {
2350             if (!item->part() || !item->part()->isActive()) continue;
2351 
2352             addCost(item);
2353             addInclusive(item->inclusive());
2354         }
2355     }
2356     else {
2357         // this is a cycle or cycle member
2358         foreach(TraceCall* callee, _callings) {
2359 
2360             // ignore inner-cycle member calls for inclusive cost
2361             if ((_cycle != this) &&
2362                 (callee->inCycle()>0))  continue;
2363 
2364             addInclusive(callee);
2365         }
2366 
2367         // self cost
2368         if (type() == ProfileContext::FunctionCycle) {
2369             // cycle: self cost is sum of cycle member self costs, but
2370             //        does not add to inclusive cost
2371             foreach(TraceFunction* m, ((TraceFunctionCycle*)this)->members())
2372                 addCost(m);
2373         }
2374         else {
2375             // cycle member
2376             foreach(TraceInclusiveCost* item, _deps) {
2377                 if (!item->part() || !item->part()->isActive()) continue;
2378 
2379                 addCost(item);
2380             }
2381             _dirty = false; // do not recurse
2382             addInclusive(this);
2383         }
2384     }
2385     _dirty = false;
2386 
2387 #if TRACE_DEBUG
2388     qDebug("> %s", qPrintable(costString(0)));
2389 #endif
2390 }
2391 
2392 bool TraceFunction::isCycle()
2393 {
2394     return _cycle == this;
2395 }
2396 
2397 bool TraceFunction::isCycleMember()
2398 {
2399     return _cycle && (_cycle != this);
2400 }
2401 
2402 void TraceFunction::cycleReset()
2403 {
2404     _cycle = nullptr;
2405     _cycleStackDown = nullptr;
2406     _cycleLow = 0;
2407 }
2408 
2409 // this does not mark functions calling themself !
2410 void TraceFunction::cycleDFS(int d, int& pNo, TraceFunction** pTop)
2411 {
2412     if (_cycleLow != 0) return;
2413 
2414     // initialize with prefix order
2415     pNo++;
2416     int prefixNo = pNo;
2417     _cycleLow = prefixNo;
2418 
2419     // put myself on stack
2420     _cycleStackDown = *pTop;
2421     *pTop = this;
2422 
2423     /* cycle cut heuristic:
2424      * skip calls for cycle detection if they make less than _cycleCut
2425      * percent of the cost of the function.
2426      * FIXME: Which cost type to use for this heuristic ?!
2427      */
2428     Q_ASSERT((data() != nullptr) && (data()->eventTypes()->realCount()>0));
2429     EventType* e = data()->eventTypes()->realType(0);
2430 
2431     SubCost base = 0;
2432     if (_callers.count()>0) {
2433         foreach(TraceCall* caller, _callers)
2434             if (caller->subCost(e) > base)
2435                 base = caller->subCost(e);
2436     }
2437     else base = inclusive()->subCost(e);
2438 
2439     SubCost cutLimit = SubCost(base * GlobalConfig::cycleCut());
2440 
2441     if (0) {
2442         qDebug("%s (%d) Visiting %s",
2443                qPrintable(QString().fill(' ', d)),
2444                pNo, qPrintable(prettyName()));
2445         qDebug("%s       Cum. %s, Max Caller %s, cut limit %s",
2446                qPrintable(QString().fill(' ', d)),
2447                qPrintable(inclusive()->subCost(e).pretty()),
2448                qPrintable(base.pretty()),
2449                qPrintable(cutLimit.pretty()));
2450     }
2451 
2452     foreach(TraceCall *callee, _callings) {
2453         TraceFunction* called = callee->called();
2454 
2455         // cycle cut heuristic
2456         if (callee->subCost(e) < cutLimit) {
2457             if (0) qDebug("%s       Cut call to %s (cum. %s)",
2458                           qPrintable(QString().fill(' ', d)),
2459                           qPrintable(called->prettyName()),
2460                           qPrintable(callee->subCost(e).pretty()));
2461 
2462             continue;
2463         }
2464 
2465         if (called->_cycleLow==0) {
2466             // not visited yet
2467             called->cycleDFS(d+1, pNo, pTop);
2468             if (called->_cycleLow < _cycleLow)
2469                 _cycleLow = called->_cycleLow;
2470         }
2471         else if (called->_cycleStackDown) {
2472             // backlink to same SCC (still in stack)
2473             if (called->_cycleLow < _cycleLow)
2474                 _cycleLow = called->_cycleLow;
2475 
2476             if (0) qDebug("%s (low %d) Back to %s",
2477                           qPrintable(QString().fill(' ', d)),
2478                           _cycleLow, qPrintable(called->prettyName()));
2479         }
2480     }
2481 
2482     if (prefixNo == _cycleLow) {
2483         // this is the base of a SCC.
2484 
2485         if (*pTop == this) {
2486             *pTop = _cycleStackDown;
2487             _cycleStackDown = nullptr;
2488         }
2489         else {
2490             // a SCC with >1 members
2491 
2492             TraceFunctionCycle* cycle = data()->functionCycle(this);
2493             if (0) qDebug("Found Cycle %d with base %s:",
2494                           cycle->cycleNo(), qPrintable(prettyName()));
2495             while(*pTop) {
2496                 TraceFunction* top = *pTop;
2497                 cycle->add(top);
2498 
2499                 // remove from stack
2500                 *pTop = top->_cycleStackDown;
2501                 top->_cycleStackDown = nullptr;
2502 
2503                 if (0) qDebug("  %s", qPrintable(top->prettyName()));
2504                 if (top == this) break;
2505             }
2506         }
2507     }
2508 }
2509 
2510 
2511 TraceInstrMap* TraceFunction::instrMap()
2512 {
2513 #if USE_FIXCOST
2514 
2515     if (_instrMapFilled) return _instrMap;
2516     _instrMapFilled = true;
2517     if (!_instrMap)
2518         _instrMap = new TraceInstrMap;
2519 
2520     TraceLine* l = nullptr;
2521     TraceInstr* i = nullptr;
2522     TracePartInstr* pi = nullptr;
2523     TraceInstrCall* ic = nullptr;
2524     TracePartInstrCall* pic = nullptr;
2525 
2526     foreach(TraceInclusiveCost* icost, deps()) {
2527         TracePartFunction* pf = (TracePartFunction*) icost;
2528 
2529         if (0) qDebug("PartFunction %s:%d",
2530                       qPrintable(pf->function()->name()),
2531                       pf->part()->partNumber());
2532 
2533         FixCost* fc = pf->firstFixCost();
2534         for(; fc; fc = fc->nextCostOfPartFunction()) {
2535             if (fc->addr() == 0) continue;
2536 
2537             if (!l || (l->lineno() != fc->line()) ||
2538                 (l->functionSource() != fc->functionSource()))
2539                 l = fc->functionSource()->line(fc->line(),true);
2540 
2541             if (!i || i->addr() != fc->addr()) {
2542                 i = &(*_instrMap)[fc->addr()];
2543                 if (!i->isValid()) {
2544                     i->setFunction(this);
2545                     i->setAddr(fc->addr());
2546                     i->setLine(l);
2547                 }
2548                 pi = nullptr;
2549             }
2550             if (!pi || pi->part() != fc->part())
2551                 pi = i->partInstr(fc->part(), pf);
2552             fc->addTo(pi);
2553         }
2554 
2555         TraceInstr* to = nullptr;
2556         TraceInstrJump* ij;
2557         TracePartInstrJump* pij;
2558         FixJump* fj = pf->firstFixJump();
2559         for(; fj; fj = fj->nextJumpOfPartFunction()) {
2560             if (fj->addr() == 0) continue;
2561 
2562             if (!l || (l->lineno() != fj->line()) ||
2563                 (l->functionSource() != fj->source()))
2564                 l = fj->source()->line(fj->line(),true);
2565 
2566             if (!i || i->addr() != fj->addr()) {
2567                 i = &(*_instrMap)[fj->addr()];
2568                 if (!i->isValid()) {
2569                     i->setFunction(this);
2570                     i->setAddr(fj->addr());
2571                     i->setLine(l);
2572                 }
2573             }
2574 
2575             to = fj->targetFunction()->instr(fj->targetAddr(), true);
2576 
2577             ij = i->instrJump(to, fj->isCondJump());
2578             pij = ij->partInstrJump(fj->part());
2579 
2580             fj->addTo(pij);
2581         }
2582 
2583         foreach(TracePartCall* pc, pf->partCallings()) {
2584 
2585             if (0) qDebug("PartCall %s:%d",
2586                           qPrintable(pc->call()->name()),
2587                           pf->part()->partNumber());
2588 
2589             FixCallCost* fcc = pc->firstFixCallCost();
2590             for(; fcc; fcc = fcc->nextCostOfPartCall()) {
2591                 if (fcc->addr() == 0) continue;
2592 
2593                 if (!l || (l->lineno() != fcc->line()) ||
2594                     (l->functionSource() != fcc->functionSource()))
2595                     l = fcc->functionSource()->line(fcc->line(),true);
2596 
2597                 if (!i || i->addr() != fcc->addr()) {
2598                     i = &(*_instrMap)[fcc->addr()];
2599                     if (!i->isValid()) {
2600                         i->setFunction(this);
2601                         i->setAddr(fcc->addr());
2602                         i->setLine(l);
2603                     }
2604                 }
2605                 if (!ic || ic->call() != pc->call() || ic->instr() != i) {
2606                     ic = pc->call()->instrCall(i);
2607                     pic = nullptr;
2608                 }
2609                 if (!pic || pic->part() != fcc->part())
2610                     pic = ic->partInstrCall(fcc->part(), pc);
2611 
2612                 fcc->addTo(pic);
2613                 if (0) qDebug("Add FixCallCost %s:%d/0x%s, CallCount %s",
2614                               qPrintable(fcc->functionSource()->file()->shortName()),
2615                               fcc->line(), qPrintable(fcc->addr().toString()),
2616                               qPrintable(fcc->callCount().pretty()));
2617             }
2618         }
2619     }
2620 
2621 #endif
2622 
2623     return _instrMap;
2624 }
2625 
2626 
2627 
2628 //---------------------------------------------------
2629 // TraceFunctionCycle
2630 
2631 TraceFunctionCycle::TraceFunctionCycle(TraceFunction* f, int n)
2632 {
2633     _base = f;
2634     _cycleNo = n;
2635     _cycle = this;
2636 
2637     setContext(ProfileContext::context(ProfileContext::FunctionCycle));
2638 
2639     setPosition(f->data());
2640     setName(QStringLiteral("<cycle %1>").arg(n));
2641 
2642     // reset to attributes of base function
2643     setFile(_base->file());
2644     setClass(_base->cls());
2645     setObject(_base->object());
2646 }
2647 
2648 void TraceFunctionCycle::init()
2649 {
2650     _members.clear();
2651     _callers.clear();
2652     // this deletes all TraceCall's to members
2653     _callings.clear();
2654 
2655     invalidate();
2656 }
2657 
2658 void TraceFunctionCycle::add(TraceFunction* f)
2659 {
2660     _members.append(f);
2661 }
2662 
2663 void TraceFunctionCycle::setup()
2664 {
2665     if (_members.isEmpty()) return;
2666 
2667     foreach(TraceFunction* f, _members) {
2668 
2669         // the cycle takes all outside callers from its members
2670         foreach(TraceCall* call, f->callers()) {
2671             if (_members.contains(call->caller())) continue;
2672             _callers.append(call);
2673         }
2674 
2675         // the cycle has a call to each member
2676         TraceCall* call = new TraceCall(this, f);
2677         call->invalidate();
2678         _callings.append(call);
2679 
2680         // now do some faking...
2681         f->setCycle(this);
2682     }
2683     invalidate();
2684 }
2685 
2686 
2687 //---------------------------------------------------
2688 // TraceClass
2689 
2690 TraceClass::TraceClass()
2691     : TraceCostItem(ProfileContext::context(ProfileContext::Class))
2692 {}
2693 
2694 TraceClass::~TraceClass()
2695 {
2696     // we are the owner of items generated in our factory
2697     qDeleteAll(_deps);
2698 }
2699 
2700 QString TraceClass::prettyName() const
2701 {
2702     if (_name.isEmpty())
2703         return prettyEmptyName();
2704     return _name;
2705 }
2706 
2707 QString TraceClass::prettyEmptyName()
2708 {
2709     return QObject::tr("(global)");
2710 }
2711 
2712 TracePartClass* TraceClass::partClass(TracePart* part)
2713 {
2714     TracePartClass* item = (TracePartClass*) findDepFromPart(part);
2715     if (!item) {
2716         item = new TracePartClass(this);
2717         item->setPosition(part);
2718         addDep(item);
2719     }
2720     return item;
2721 }
2722 
2723 void TraceClass::addFunction(TraceFunction* function)
2724 {
2725 #if TRACE_ASSERTIONS
2726     if (function->cls() != this) {
2727         qDebug("Can not add function to a class not enclosing this function\n");
2728         return;
2729     }
2730 
2731     if (_functions.contains(function)) return;
2732 #endif
2733 
2734     _functions.append(function);
2735 
2736     invalidate();
2737 
2738 #if TRACE_DEBUG
2739     qDebug("%s added\n %s (now %d)",
2740            qPrintable( fullName() ),
2741            qPrintable(function->fullName()), _functions.count());
2742 #endif
2743 }
2744 
2745 
2746 
2747 //---------------------------------------------------
2748 // TraceFile
2749 
2750 TraceFile::TraceFile()
2751     : TraceCostItem(ProfileContext::context(ProfileContext::File))
2752 {}
2753 
2754 TraceFile::~TraceFile()
2755 {
2756     // we are the owner of items generated in our factory
2757     qDeleteAll(_deps);
2758 }
2759 
2760 TracePartFile* TraceFile::partFile(TracePart* part)
2761 {
2762     TracePartFile* item = (TracePartFile*) findDepFromPart(part);
2763     if (!item) {
2764         item = new TracePartFile(this);
2765         item->setPosition(part);
2766         addDep(item);
2767     }
2768     return item;
2769 }
2770 
2771 void TraceFile::addFunction(TraceFunction* function)
2772 {
2773 #if TRACE_ASSERTIONS
2774     if (function->file() != this) {
2775         qDebug("Can not add function to a file not enclosing this function\n");
2776         return;
2777     }
2778 
2779     if (_functions.contains(function)) return;
2780 #endif
2781 
2782     _functions.append(function);
2783 
2784     invalidate();
2785 
2786 #if TRACE_DEBUG
2787     qDebug("%s added\n %s (now %d)",
2788            qPrintable( fullName() ),
2789            qPrintable(function->fullName()), _functions.count());
2790 #endif
2791 }
2792 
2793 
2794 void TraceFile::addSourceFile(TraceFunctionSource* sourceFile)
2795 {
2796 #if TRACE_ASSERTIONS
2797     if (sourceFile->file() != this) {
2798         qDebug("Can not add sourceFile to a file not having lines for it\n");
2799         return;
2800     }
2801 #endif
2802 
2803     _sourceFiles.append(sourceFile);
2804     // not truly needed, as we do not use the sourceFiles for cost update
2805     invalidate();
2806 
2807 #if TRACE_DEBUG
2808     qDebug("%s \n added SourceFile %s (now %d)",
2809            qPrintable( fullName() ), qPrintable(sourceFile->fullName()),
2810            _sourceFiles.count());
2811 #endif
2812 }
2813 
2814 
2815 
2816 void TraceFile::setDirectory(const QString& dir)
2817 {
2818     if (dir.endsWith('/'))
2819         _dir = dir.left(dir.length()-1);
2820     else
2821         _dir = dir;
2822 }
2823 
2824 QString TraceFile::directory()
2825 {
2826     if (!_dir.isEmpty()) return _dir;
2827 
2828     int lastIndex = 0, index;
2829     while ( (index=_name.indexOf(QLatin1Char('/'), lastIndex)) >=0)
2830         lastIndex = index+1;
2831 
2832     if (lastIndex==0) return QString();
2833 
2834     // without ending "/"
2835     return _name.left(lastIndex-1);
2836 }
2837 
2838 
2839 QString TraceFile::shortName() const
2840 {
2841     int lastIndex = 0, index;
2842     while ( (index=_name.indexOf(QLatin1Char('/'), lastIndex)) >=0)
2843         lastIndex = index+1;
2844 
2845     return _name.mid(lastIndex);
2846 }
2847 
2848 QString TraceFile::prettyName() const
2849 {
2850     QString sn = shortName();
2851 
2852     if (sn.isEmpty())
2853         return prettyEmptyName();
2854 
2855     return sn;
2856 }
2857 
2858 QString TraceFile::prettyEmptyName()
2859 {
2860     return QObject::tr("(unknown)");
2861 }
2862 
2863 QString TraceFile::prettyLongName() const
2864 {
2865     if (_name.isEmpty())
2866         return prettyEmptyName();
2867     return _name;
2868 }
2869 
2870 
2871 //---------------------------------------------------
2872 // TraceObject
2873 
2874 TraceObject::TraceObject()
2875     : TraceCostItem(ProfileContext::context(ProfileContext::Object))
2876 {}
2877 
2878 TraceObject::~TraceObject()
2879 {
2880     // we are the owner of items generated in our factory
2881     qDeleteAll(_deps);
2882 }
2883 
2884 TracePartObject* TraceObject::partObject(TracePart* part)
2885 {
2886     TracePartObject* item = (TracePartObject*) findDepFromPart(part);
2887     if (!item) {
2888         item = new TracePartObject(this);
2889         item->setPosition(part);
2890         addDep(item);
2891     }
2892     return item;
2893 }
2894 
2895 void TraceObject::addFunction(TraceFunction* function)
2896 {
2897 #if TRACE_ASSERTIONS
2898     if (function->object() != this) {
2899         qDebug("Can not add function to an object not enclosing this function\n");
2900         return;
2901     }
2902 
2903     if (_functions.contains(function)) return;
2904 #endif
2905 
2906     _functions.append(function);
2907 
2908     invalidate();
2909 
2910 #if TRACE_DEBUG
2911     qDebug("%s added\n %s (now %d)",
2912            qPrintable( fullName() ),
2913            qPrintable(function->fullName()), _functions.count());
2914 #endif
2915 }
2916 
2917 void TraceObject::setDirectory(const QString& dir)
2918 {
2919     if (dir.endsWith('/'))
2920         _dir = dir.left(dir.length()-1);
2921     else
2922         _dir = dir;
2923 }
2924 
2925 QString TraceObject::directory()
2926 {
2927     if (!_dir.isEmpty()) return _dir;
2928 
2929     int lastIndex = 0, index;
2930     while ( (index=_name.indexOf(QLatin1Char('/'), lastIndex)) >=0)
2931         lastIndex = index+1;
2932 
2933     if (lastIndex==0) return QString();
2934 
2935     // without ending "/"
2936     return _name.left(lastIndex-1);
2937 }
2938 
2939 
2940 QString TraceObject::shortName() const
2941 {
2942     int lastIndex = 0, index;
2943     while ( (index=_name.indexOf(QLatin1Char('/'), lastIndex)) >=0)
2944         lastIndex = index+1;
2945 
2946     return _name.mid(lastIndex);
2947 }
2948 
2949 QString TraceObject::prettyName() const
2950 {
2951     QString sn = shortName();
2952 
2953     if (sn.isEmpty())
2954         return prettyEmptyName();
2955 
2956     return sn;
2957 }
2958 
2959 QString TraceObject::prettyEmptyName()
2960 {
2961     return QObject::tr("(unknown)");
2962 }
2963 
2964 //---------------------------------------------------
2965 // TracePart
2966 
2967 TracePart::TracePart(TraceData* data)
2968     : TraceListCost(ProfileContext::context(ProfileContext::Part))
2969 {
2970     setPosition(data);
2971 
2972     _dep = data;
2973     _active = true;
2974     _number = 0;
2975     _tid = 0;
2976     _pid = 0;
2977 
2978     _eventTypeMapping = nullptr;
2979 }
2980 
2981 TracePart::~TracePart()
2982 {
2983     delete _eventTypeMapping;
2984 }
2985 
2986 void TracePart::setPartNumber(int n)
2987 {
2988     if (data()->maxPartNumber() <n) data()->setMaxPartNumber(n);
2989     _number = n;
2990 }
2991 
2992 void TracePart::setThreadID(int tid)
2993 {
2994     if (data()->maxThreadID() <tid) data()->setMaxThreadID(tid);
2995     _tid = tid;
2996 }
2997 
2998 void TracePart::setProcessID(int pid)
2999 {
3000     _pid = pid;
3001 }
3002 
3003 
3004 
3005 // strip path
3006 QString TracePart::shortName() const
3007 {
3008     int lastIndex = 0, index;
3009     while ( (index=_name.indexOf(QLatin1Char('/'), lastIndex)) >=0)
3010         lastIndex = index+1;
3011 
3012     return _name.mid(lastIndex);
3013 }
3014 
3015 QString TracePart::prettyName() const
3016 {
3017     if (_pid==0) return shortName();
3018     QString name = QStringLiteral("PID %1").arg(_pid);
3019     if (_number>0)
3020         name += QStringLiteral(", section %2").arg(_number);
3021     if ((data()->maxThreadID()>1) && (_tid>0))
3022         name += QStringLiteral(", thread %3").arg(_tid);
3023     return name;
3024 }
3025 
3026 bool TracePart::activate(bool active)
3027 {
3028     if (_active == active) return false;
3029     _active = active;
3030 
3031     // to be done by the client of this function
3032     //  data()->invalidateDynamicCost();
3033     // So better use the TraceData functions...
3034 
3035     return true;
3036 }
3037 
3038 bool TracePart::operator<(const TracePart& p2) const
3039 {
3040     if (processID() < p2.processID()) return true;
3041 
3042     if (processID() == p2.processID()) {
3043         if (partNumber() < p2.partNumber()) return true;
3044 
3045         if (partNumber() == p2.partNumber())
3046             return (threadID() < p2.threadID());
3047     }
3048     return false;
3049 }
3050 
3051 
3052 //---------------------------------------------------
3053 // TraceData
3054 
3055 
3056 // create vectors with reasonable default sizes, but not wasting memory
3057 TraceData::TraceData(Logger* l)
3058     : ProfileCostArray(ProfileContext::context(ProfileContext::Data))
3059 {
3060     _logger = l;
3061     init();
3062 }
3063 
3064 void TraceData::init()
3065 {
3066     _functionCycleCount = 0;
3067     _inFunctionCycleUpdate = false;
3068 
3069     _maxThreadID = 0;
3070     _maxPartNumber = 0;
3071     _fixPool = nullptr;
3072     _dynPool = nullptr;
3073 
3074     _arch = ArchUnknown;
3075 }
3076 
3077 TraceData::~TraceData()
3078 {
3079     qDeleteAll(_parts);
3080 
3081     delete _fixPool;
3082     delete _dynPool;
3083 }
3084 
3085 QString TraceData::shortTraceName() const
3086 {
3087     int lastIndex = 0, index;
3088     while ( (index=_traceName.indexOf(QLatin1Char('/'), lastIndex)) >=0)
3089         lastIndex = index+1;
3090 
3091     return _traceName.mid(lastIndex);
3092 }
3093 
3094 FixPool* TraceData::fixPool()
3095 {
3096     if (!_fixPool)
3097         _fixPool = new FixPool();
3098 
3099     return _fixPool;
3100 }
3101 
3102 DynPool* TraceData::dynPool()
3103 {
3104     if (!_dynPool)
3105         _dynPool = new DynPool();
3106 
3107     return _dynPool;
3108 }
3109 
3110 bool partLessThan(const TracePart* p1, const TracePart* p2)
3111 {
3112     return *p1 < *p2;
3113 }
3114 
3115 /**
3116  * Load a list of files.
3117  * If only one file is given, it is assumed to be a prefix, and all
3118  * existing files with that prefix are loaded.
3119  *
3120  * Returns 0 if nothing found to load
3121  */
3122 int TraceData::load(QStringList files)
3123 {
3124     if (files.isEmpty()) return 0;
3125 
3126     _traceName = files[0];
3127     if (files.count() == 1) {
3128         QFileInfo finfo(_traceName);
3129         QString prefix = finfo.fileName();
3130         QDir dir = finfo.dir();
3131         if (finfo.isDir()) {
3132             prefix = QStringLiteral("callgrind.out");
3133             _traceName += QLatin1String("/callgrind.out");
3134         }
3135 
3136         files = dir.entryList(QStringList() << prefix + '*', QDir::Files);
3137         QStringList::Iterator it = files.begin();
3138         for (; it != files.end(); ++it ) {
3139             *it = dir.path() + '/' + *it;
3140         }
3141     }
3142 
3143     if (files.isEmpty()) {
3144         _traceName += ' ' + QObject::tr("(not found)");
3145         return 0;
3146     }
3147 
3148     QStringList::const_iterator it;
3149     int partsLoaded = 0;
3150     for (it = files.constBegin(); it != files.constEnd(); ++it ) {
3151         QFile file(*it);
3152         partsLoaded += internalLoad(&file, *it);
3153     }
3154     if (partsLoaded == 0) return 0;
3155 
3156     std::sort(_parts.begin(), _parts.end(), partLessThan);
3157     invalidateDynamicCost();
3158     updateFunctionCycles();
3159 
3160     return partsLoaded;
3161 }
3162 
3163 int TraceData::load(QString file)
3164 {
3165     return load(QStringList(file));
3166 }
3167 
3168 int TraceData::load(QIODevice* file, const QString& filename)
3169 {
3170     _traceName = filename;
3171     int partsLoaded = internalLoad(file, filename);
3172     if (partsLoaded>0) {
3173         invalidateDynamicCost();
3174         updateFunctionCycles();
3175     }
3176     return partsLoaded;
3177 }
3178 
3179 int TraceData::internalLoad(QIODevice* device, const QString& filename)
3180 {
3181     if (!device->open( QIODevice::ReadOnly ) ) {
3182         _logger->loadStart(filename);
3183         _logger->loadFinished(QString::fromLocal8Bit(strerror( errno )));
3184         return 0;
3185     }
3186 
3187     Loader* l = Loader::matchingLoader(device);
3188     if (!l) {
3189         // special case empty file: ignore...
3190         if (device->size() == 0) return 0;
3191 
3192         _logger->loadStart(filename);
3193         _logger->loadFinished(QStringLiteral("Unknown file format"));
3194         return 0;
3195     }
3196     l->setLogger(_logger);
3197 
3198     int partsLoaded = l->load(this, device, filename);
3199 
3200     l->setLogger(nullptr);
3201 
3202     return partsLoaded;
3203 }
3204 
3205 bool TraceData::activateParts(const TracePartList& l)
3206 {
3207     bool changed = false;
3208 
3209     foreach(TracePart* part, _parts)
3210         if (part->activate(l.contains(part)))
3211             changed = true;
3212 
3213     if (changed) {
3214         // because active parts have changed, throw away calculated
3215         // costs...
3216         invalidateDynamicCost();
3217         updateFunctionCycles();
3218     }
3219 
3220     return changed;
3221 }
3222 
3223 
3224 bool TraceData::activateParts(TracePartList l, bool active)
3225 {
3226     bool changed = false;
3227 
3228     foreach(TracePart* part, l) {
3229         if (_parts.contains(part))
3230             if (part->activate(active))
3231                 changed = true;
3232     }
3233 
3234     if (changed) {
3235         invalidateDynamicCost();
3236         updateFunctionCycles();
3237     }
3238 
3239     return changed;
3240 }
3241 
3242 bool TraceData::activatePart(TracePart* p, bool active)
3243 {
3244     return p->activate(active);
3245 }
3246 
3247 bool TraceData::activateAll(bool active)
3248 {
3249     return activateParts(_parts, active);
3250 }
3251 
3252 void TraceData::addPart(TracePart* part)
3253 {
3254     if (_parts.contains(part)>0) return;
3255 
3256     if ((part->partNumber()==0) &&
3257         (part->processID()==0)) {
3258         _maxPartNumber++;
3259         part->setPartNumber(_maxPartNumber);
3260     }
3261     _parts.append(part);
3262 }
3263 
3264 TracePart* TraceData::partWithName(const QString& name)
3265 {
3266     foreach(TracePart* part, _parts)
3267         if (part->name() == name)
3268             return part;
3269     return nullptr;
3270 }
3271 
3272 QString TraceData::activePartRange()
3273 {
3274     QString res;
3275     int r1=-1, r2=-1, count=0;
3276     foreach(TracePart* part, _parts) {
3277         count++;
3278         if (part->isActive()) {
3279             if (r1<0) { r1 = r2 = count; }
3280             else if (r2 == count-1) { r2 = count; }
3281             else {
3282                 if (!res.isEmpty()) res += ';';
3283                 if (r1==r2) res += QString::number(r1);
3284                 else res += QStringLiteral("%1-%2").arg(r1).arg(r2);
3285                 r1 = r2 = count;
3286             }
3287         }
3288     }
3289     if (r1>=0) {
3290         if (!res.isEmpty()) res += ';';
3291         if (r1==r2) res += QString::number(r1);
3292         else res += QStringLiteral("%1-%2").arg(r1).arg(r2);
3293     }
3294 
3295     return res;
3296 }
3297 
3298 void TraceData::invalidateDynamicCost()
3299 {
3300     // invalidate all dynamic costs
3301 
3302     TraceObjectMap::Iterator oit;
3303     for ( oit = _objectMap.begin();
3304           oit != _objectMap.end(); ++oit )
3305         (*oit).invalidate();
3306 
3307     TraceClassMap::Iterator cit;
3308     for ( cit = _classMap.begin();
3309           cit != _classMap.end(); ++cit )
3310         (*cit).invalidate();
3311 
3312     TraceFileMap::Iterator fit;
3313     for ( fit = _fileMap.begin();
3314           fit != _fileMap.end(); ++fit )
3315         (*fit).invalidate();
3316 
3317     TraceFunctionMap::Iterator it;
3318     for ( it = _functionMap.begin();
3319           it != _functionMap.end(); ++it ) {
3320         (*it).invalidateDynamicCost();
3321     }
3322 
3323     invalidate();
3324 
3325 }
3326 
3327 
3328 TraceObject* TraceData::object(const QString& name)
3329 {
3330     TraceObject& o = _objectMap[name];
3331     if (!o.data()) {
3332         // was created
3333         o.setPosition(this);
3334         o.setName(name);
3335 
3336 #if TRACE_DEBUG
3337         qDebug("Created %s [TraceData::object]",
3338                qPrintable(o.fullName()));
3339 #endif
3340     }
3341     return &o;
3342 }
3343 
3344 
3345 TraceFile* TraceData::file(const QString& name)
3346 {
3347     TraceFile& f = _fileMap[name];
3348     if (!f.data()) {
3349         // was created
3350         f.setPosition(this);
3351         f.setName(name);
3352 
3353 #if TRACE_DEBUG
3354         qDebug("Created %s [TraceData::file]",
3355                qPrintable(f.fullName()));
3356 #endif
3357     }
3358     return &f;
3359 }
3360 
3361 
3362 // usually only called by function()
3363 TraceClass* TraceData::cls(const QString& fnName, QString& shortName)
3364 {
3365     int lastIndex = 0, index, pIndex;
3366 
3367     // we ignore any "::" after a '(' or a space
3368     pIndex=fnName.indexOf('(', 0);
3369 
3370 #if 0
3371     int sIndex=fnName.find(" ", 0);
3372     if (sIndex>=0)
3373         if ((pIndex == -1) || (sIndex < pIndex))
3374             pIndex = sIndex;
3375 #endif
3376 
3377     while ((index=fnName.indexOf(QLatin1String("::"), lastIndex)) >=0) {
3378         if (pIndex>=0 && pIndex<index) break;
3379         lastIndex = index+2;
3380     }
3381 
3382     QString clsName = (lastIndex < 3) ? QString() :
3383                                         fnName.left(lastIndex-2);
3384     shortName = fnName.mid(lastIndex);
3385 
3386     TraceClass& c = _classMap[clsName];
3387     if (!c.data()) {
3388         // was created
3389         c.setPosition(this);
3390         c.setName(clsName);
3391 
3392 #if TRACE_DEBUG
3393         qDebug("Created %s [TraceData::cls]",
3394                qPrintable(c.fullName()));
3395 #endif
3396     }
3397     return &c;
3398 }
3399 
3400 
3401 // name is inclusive class/namespace prefix
3402 TraceFunction* TraceData::function(const QString& name,
3403                                    TraceFile* file, TraceObject* object)
3404 {
3405     // strip class name
3406     QString shortName;
3407     TraceClass* c = cls(name, shortName);
3408 
3409     if (!file || !object || !c) {
3410         qDebug("ERROR - no file/object/class for %s ?!", qPrintable(name));
3411         return nullptr;
3412     }
3413 
3414     // Use object name and file name as part of key, to get distinct
3415     // function objects for functions with same name but defined in
3416     // different ELF objects or different files (this is possible e.g.
3417     // in C by using "static").
3418     //
3419     // Note about usage of this factory method by the Cachegrind loader:
3420     // that dump format does not explicitly specify the attribution
3421     // of functions to ELF objects and files. Rather, cost is attributed
3422     // to ELF object, source file and function. We use the first cost
3423     // seen for a function to bind an ELF object and source file to that
3424     // function. Callgrind always prints the cost of the instruction at
3425     // function entry first, so there, this strategy works.
3426     // But such an order is not enforced by the format. If the cost of
3427     // an inlined function from another source file would be printed first,
3428     // the attribution would go wrong. The format also allows cost of
3429     // the same function to be spread over the dump. With wrong
3430     // attributions, it can happen that cost of the same function is
3431     // interpreted as being from distinct functions.
3432     // For a correct solution, the format needs to be more expressive,
3433     // or the ordering of costs specified.
3434     // Previously, the file name was left out from the key.
3435     // The change was motivated by bug ID 3014067 (on SourceForge).
3436     QString key = name + file->shortName() + object->shortName();
3437 
3438     TraceFunctionMap::Iterator it;
3439     it = _functionMap.find(key);
3440     if (it == _functionMap.end()) {
3441         it = _functionMap.insert(key, TraceFunction());
3442         TraceFunction& f = it.value();
3443 
3444         f.setPosition(this);
3445         f.setName(name);
3446         f.setClass(c);
3447         f.setObject(object);
3448         f.setFile(file);
3449         //f.setMapIterator(it);
3450 
3451 #if TRACE_DEBUG
3452         qDebug("Created %s [TraceData::function]\n  for %s, %s, %s",
3453                qPrintable(f.fullName()),
3454                qPrintable(c->fullName()), qPrintable(file->fullName()),
3455                object ? qPrintable(object->fullName()) : "(unknown object)");
3456 #endif
3457 
3458         c->addFunction(&f);
3459         object->addFunction(&f);
3460         file->addFunction(&f);
3461     }
3462 
3463     return &(it.value());
3464 }
3465 
3466 TraceFunctionMap::Iterator TraceData::functionIterator(TraceFunction* f)
3467 {
3468 
3469     // IMPORTANT: build as SAME key as used in function() above !!
3470     QString key;
3471 
3472     if (f->cls()) key = f->cls()->name() + "::";
3473     key += f->name();
3474     key += f->object()->shortName();
3475 
3476     return _functionMap.find(key);
3477 }
3478 
3479 TraceFunctionMap::ConstIterator TraceData::functionBeginIterator() const
3480 {
3481     return _functionMap.begin();
3482 }
3483 
3484 TraceFunctionMap::ConstIterator TraceData::functionEndIterator() const
3485 {
3486     return _functionMap.end();
3487 }
3488 
3489 // _maxCallCount is maintained globally, and only updated at loading
3490 void TraceData::updateMaxCallCount(SubCost c)
3491 {
3492     if (_maxCallCount < c)
3493         _maxCallCount = c;
3494 }
3495 
3496 void TraceData::resetSourceDirs()
3497 {
3498     TraceFileMap::Iterator fit;
3499     for ( fit = _fileMap.begin();
3500           fit != _fileMap.end(); ++fit )
3501         (*fit).resetDirectory();
3502 }
3503 
3504 void TraceData::update()
3505 {
3506     if (!_dirty) return;
3507 
3508     clear();
3509     _totals.clear();
3510 
3511     foreach(TracePart* part, _parts) {
3512         _totals.addCost(part->totals());
3513         if (part->isActive())
3514             addCost(part->totals());
3515     }
3516 
3517     _dirty = false;
3518 }
3519 
3520 ProfileCostArray* TraceData::search(ProfileContext::Type t, QString name,
3521                                     EventType* ct, ProfileCostArray* parent)
3522 {
3523     ProfileCostArray* result = nullptr;
3524     ProfileContext::Type pt;
3525     SubCost sc, scTop = 0;
3526 
3527     pt = parent ? parent->type() : ProfileContext::InvalidType;
3528     switch(t) {
3529     case ProfileContext::Function:
3530     {
3531         TraceFunction *f;
3532         TraceFunctionMap::Iterator it;
3533         for ( it = _functionMap.begin();
3534               it != _functionMap.end(); ++it ) {
3535             f = &(*it);
3536 
3537             if (f->name() != name) continue;
3538 
3539             if ((pt == ProfileContext::Class) && (parent != f->cls())) continue;
3540             if ((pt == ProfileContext::File) && (parent != f->file())) continue;
3541             if ((pt == ProfileContext::Object) && (parent != f->object())) continue;
3542 
3543             if (ct) {
3544                 sc = f->inclusive()->subCost(ct);
3545                 if (sc <= scTop) continue;
3546                 scTop = sc;
3547             }
3548 
3549             result = f;
3550         }
3551     }
3552         break;
3553 
3554     case ProfileContext::File:
3555     {
3556         TraceFile *f;
3557         TraceFileMap::Iterator it;
3558         for ( it = _fileMap.begin();
3559               it != _fileMap.end(); ++it ) {
3560             f = &(*it);
3561             if (f->name() != name) continue;
3562             if (ct) {
3563                 sc = f->subCost(ct);
3564                 if (sc <= scTop) continue;
3565                 scTop = sc;
3566             }
3567             result = f;
3568         }
3569     }
3570         break;
3571 
3572     case ProfileContext::Class:
3573     {
3574         TraceClass *c;
3575         TraceClassMap::Iterator it;
3576         for ( it = _classMap.begin();
3577               it != _classMap.end(); ++it ) {
3578             c = &(*it);
3579             if (c->name() != name) continue;
3580             if (ct) {
3581                 sc = c->subCost(ct);
3582                 if (sc <= scTop) continue;
3583                 scTop = sc;
3584             }
3585             result = c;
3586         }
3587     }
3588         break;
3589 
3590     case ProfileContext::Object:
3591     {
3592         TraceObject *o;
3593         TraceObjectMap::Iterator it;
3594         for ( it = _objectMap.begin();
3595               it != _objectMap.end(); ++it ) {
3596             o = &(*it);
3597             if (o->name() != name) continue;
3598             if (ct) {
3599                 sc = o->subCost(ct);
3600                 if (sc <= scTop) continue;
3601                 scTop = sc;
3602             }
3603             result = o;
3604         }
3605     }
3606         break;
3607 
3608     case ProfileContext::Instr:
3609         if (pt == ProfileContext::Function) {
3610             TraceInstrMap* instrMap = ((TraceFunction*)parent)->instrMap();
3611             if (!instrMap) break;
3612 
3613             TraceInstr *instr;
3614             TraceInstrMap::Iterator it;
3615             for ( it = instrMap->begin();
3616                   it != instrMap->end(); ++it ) {
3617                 instr = &(*it);
3618                 if (instr->name() != name) continue;
3619                 result = instr;
3620             }
3621         }
3622         break;
3623 
3624     case ProfileContext::Line:
3625     {
3626         TraceFunctionSourceList sList;
3627         if (pt == ProfileContext::Function)
3628             sList = ((TraceFunction*)parent)->sourceFiles();
3629         else if (pt == ProfileContext::FunctionSource)
3630             sList.append((TraceFunctionSource*) parent);
3631         else break;
3632 
3633         TraceLineMap* lineMap;
3634         TraceLine* line;
3635         TraceLineMap::Iterator it;
3636         foreach(TraceFunctionSource* fs, sList) {
3637             lineMap = fs->lineMap();
3638             if (!lineMap) continue;
3639 
3640             for ( it = lineMap->begin();
3641                   it != lineMap->end(); ++it ) {
3642                 line = &(*it);
3643                 if (line->name() != name) continue;
3644                 result = line;
3645             }
3646         }
3647     }
3648         break;
3649 
3650     default:
3651         break;
3652     }
3653 
3654     return result;
3655 }
3656 
3657 
3658 TraceFunctionCycle* TraceData::functionCycle(TraceFunction* f)
3659 {
3660     TraceFunctionCycle* cycle;
3661     foreach(cycle, _functionCycles)
3662         if (cycle->base() == f)
3663             return cycle;
3664 
3665     _functionCycleCount++;
3666     cycle = new TraceFunctionCycle(f, _functionCycleCount);
3667 
3668     _functionCycles.append(cycle);
3669     return cycle;
3670 }
3671 
3672 
3673 void TraceData::updateFunctionCycles()
3674 {
3675     //qDebug("Updating cycles...");
3676 
3677     // init cycle info
3678     foreach(TraceFunctionCycle* cycle, _functionCycles)
3679         cycle->init();
3680 
3681     TraceFunctionMap::Iterator it;
3682     for ( it = _functionMap.begin(); it != _functionMap.end(); ++it )
3683         (*it).cycleReset();
3684 
3685     if (!GlobalConfig::showCycles()) return;
3686 
3687     _inFunctionCycleUpdate = true;
3688 
3689 
3690 #if 0
3691     int fCount = _functionMap.size(), fNo = 0, progress=0, p;
3692     QString msg = tr("Recalculating Function Cycles...");
3693     if (_topLevel) _topLevel->showStatus(msg,0);
3694 #endif
3695 
3696     // DFS and collapse strong connected components (Tarjan)
3697     int pNo = 0;
3698     TraceFunction* stackTop;
3699     for ( it = _functionMap.begin(); it != _functionMap.end(); ++it ) {
3700 
3701 #if 0
3702         if (_topLevel) {
3703             fNo++;
3704             p = 100*fNo/fCount;
3705             if (p> progress) {
3706                 progress = p;
3707                 _topLevel->showStatus(msg, p);
3708             }
3709         }
3710 #endif
3711 
3712         stackTop = nullptr;
3713         (*it).cycleDFS(1, pNo, &stackTop);
3714     }
3715 
3716     // postprocess cycles
3717     foreach(TraceFunctionCycle* cycle, _functionCycles)
3718         cycle->setup();
3719 
3720     _inFunctionCycleUpdate = false;
3721     // we have to invalidate costs because cycles are now taken into account
3722     invalidateDynamicCost();
3723 
3724 #if 0
3725     if (0) if (_topLevel) _topLevel->showStatus(QString(), 0);
3726 #endif
3727 }
3728 
3729 void TraceData::updateObjectCycles()
3730 {
3731 }
3732 
3733 
3734 void TraceData::updateClassCycles()
3735 {
3736 }
3737 
3738 
3739 void TraceData::updateFileCycles()
3740 {
3741 }
3742