void CoverageView::refresh() { clear(); if (!_data || !_activeItem) return; ProfileContext::Type t = _activeItem->type(); TraceFunction* f = 0; if (t == ProfileContext::Function) f = (TraceFunction*) _activeItem; if (t == ProfileContext::FunctionCycle) f = (TraceFunction*) _activeItem; if (!f) return; _hc.clear(GlobalConfig::maxListCount()); SubCost realSum = f->inclusive()->subCost(_eventType); TraceFunctionList l; if (_showCallers) l = Coverage::coverage(f, Coverage::Caller, _eventType); else l = Coverage::coverage(f, Coverage::Called, _eventType); foreach(TraceFunction* f2, l) { Coverage* c = (Coverage*) f2->association(Coverage::Rtti); if (c && (c->inclusive()>0.0)) _hc.addCost(f2, SubCost(realSum * c->inclusive())); }
// for call lines InstrItem::InstrItem(InstrView* iv, QTreeWidgetItem* parent, Addr addr, TraceInstr* instr, TraceInstrCall* instrCall) : QTreeWidgetItem(parent) { _view = iv; _addr = addr; _instr = instr; _instrCall = instrCall; _instrJump = 0; _inside = true; setTextAlignment(0, Qt::AlignRight); setTextAlignment(1, Qt::AlignRight); setTextAlignment(2, Qt::AlignRight); //qDebug("InstrItem: (file %d, line %d) Linecall to %s", // fileno, lineno, _lineCall->call()->called()->prettyName().toAscii()); SubCost cc = _instrCall->callCount(); QString callStr = " "; if (cc==0) callStr += QObject::tr("Active call to '%1'") .arg(_instrCall->call()->calledName()); else callStr += QObject::tr("%n call(s) to '%2'", "", (uint64)cc) .arg(_instrCall->call()->calledName()); TraceFunction* calledF = _instrCall->call()->called(); calledF->addPrettyLocation(callStr); setText(6, callStr); updateGroup(); updateCost(); }
void SourceView::context(QListViewItem* i, const QPoint & p, int c) { QPopupMenu popup; // Menu entry: TraceLineCall* lc = i ? ((SourceItem*) i)->lineCall() : 0; TraceLineJump* lj = i ? ((SourceItem*) i)->lineJump() : 0; TraceFunction* f = lc ? lc->call()->called() : 0; TraceLine* line = lj ? lj->lineTo() : 0; if (f) { QString name = f->name(); if ((int)name.length()>Configuration::maxSymbolLength()) name = name.left(Configuration::maxSymbolLength()) + "..."; popup.insertItem(i18n("Go to '%1'").arg(name), 93); popup.insertSeparator(); } else if (line) { popup.insertItem(i18n("Go to Line %1").arg(line->name()), 93); popup.insertSeparator(); } if ((c == 1) || (c == 2)) { addCostMenu(&popup); popup.insertSeparator(); } addGoMenu(&popup); int r = popup.exec(p); if (r == 93) { if (f) activated(f); if (line) activated(line); } }
void CoverageView::context(QListViewItem* i, const QPoint & p, int c) { QPopupMenu popup; TraceFunction* f = 0; if (i) { f = _showCallers ? ((CallerCoverageItem*)i)->function() : ((CalleeCoverageItem*)i)->function(); } if (f) { QString name = f->name(); if ((int)name.length()>Configuration::maxSymbolLength()) name = name.left(Configuration::maxSymbolLength()) + "..."; popup.insertItem(i18n("Go to '%1'").arg(name), 93); popup.insertSeparator(); } if ((c == 0) || (!_showCallers && c == 1)) { addCostMenu(&popup, false); popup.insertSeparator(); } addGoMenu(&popup); int r = popup.exec(p); if (r == 93) activated(f); }
void CoverageView::context(const QPoint & p) { int c = columnAt(p.x()); QTreeWidgetItem* i = itemAt(p); QMenu popup; TraceFunction* f = 0; if (i) { f = _showCallers ? ((CallerCoverageItem*)i)->function() : ((CalleeCoverageItem*)i)->function(); } QAction* activateFunctionAction = 0; if (f) { QString menuText = tr("Go to '%1'").arg(GlobalConfig::shortenSymbol(f->prettyName())); activateFunctionAction = popup.addAction(menuText); popup.addSeparator(); } if ((c == 0) || (!_showCallers && c == 1)) { addEventTypeMenu(&popup, false); popup.addSeparator(); } addGoMenu(&popup); QAction* a = popup.exec(mapToGlobal(p + QPoint(0,header()->height()))); if (a == activateFunctionAction) TraceItemView::activated(f); }
bool Stack::contains(TraceFunction* fn) { // cycles are listed on there own if (fn->cycle() == fn) return false; if (_top->cycle() == _top) return false; if (fn == _top) return true; TraceFunction* f = _top; TraceCall* c; for (c=_calls.first();c;c=_calls.next()) { f = c->called(); if (f == fn) return true; } TraceCallList l; // try to extend at bottom (even if callCount 0) l = f->callings(); for (c=l.first();c;c=l.next()) { f = c->called(); if (f == fn) break; } if (c) { _calls.append(c); // extend at bottom after found one extendBottom(); return true; } // try to extend at top (even if callCount 0) l = _top->callers(); for (c=l.first();c;c=l.next()) { f = c->caller(); if (f == fn) break; } if (c) { _calls.prepend(c); // extend at top after found one extendTop(); return true; } return false; }
void CachegrindLoader::setFunction(const QString& name) { ensureFile(); ensureObject(); currentFunction = compressedFunction( name, currentFile, currentObject); if (!currentFunction) { error(QStringLiteral("Invalid function specification, setting to unknown")); currentFunction = _data->function(_emptyString, currentFile, currentObject); } currentPartFunction = currentFunction->partFunction(_part, currentPartFile, currentPartObject); currentFunctionSource = 0; currentLine = 0; currentPartLine = 0; }
void CachegrindLoader::setCalledFunction(const QString& name) { // if called object/file not set, use current object/file if (!currentCalledObject) { currentCalledObject = currentObject; currentCalledPartObject = currentPartObject; } if (!currentCalledFile) { // !=0 as functions needs file currentCalledFile = currentFile; currentCalledPartFile = currentPartFile; } currentCalledFunction = compressedFunction(name, currentCalledFile, currentCalledObject); if (!currentCalledFunction) { error(QStringLiteral("Invalid called function, setting to unknown")); currentCalledFunction = _data->function(_emptyString, currentCalledFile, currentCalledObject); } currentCalledPartFunction = currentCalledFunction->partFunction(_part, currentCalledPartFile, currentCalledPartObject); }
void Stack::extendBottom() { TraceCallList l; TraceCall *c, *call; SubCost most; TraceFunction* f; if (_calls.last()) f = _calls.last()->called(); else f = _top; if (!f) return; // do not follow calls from cycles if (f->cycle() == f) return; int max = 30; // try to extend to lower stack frames while (f && (max-- >0)) { l = f->callings(); call = 0; most = 0; for (c=l.first();c;c=l.next()) { // no cycle calls in stack: could be deleted without notice if (c->called()->cycle() == c->called()) continue; // no simple recursions if (c->called() == _top) continue; if (c->called()->name().isEmpty()) continue; SubCost sc = c->subCost(0); // FIXME if (sc == 0) continue; if (sc > most) { most = sc; call = c; } } if (!call) break; _calls.append(call); f = call->called(); } }
void CallView::context(const QPoint & p) { QMenu popup; // p is in local coordinates int col = columnAt(p.x()); QTreeWidgetItem* i = itemAt(p); TraceCall* c = i ? ((CallItem*) i)->call() : 0; TraceFunction *f = 0, *cycle = 0; QAction* activateFunctionAction = 0; QAction* activateCycleAction = 0; if (c) { QString name = _showCallers ? c->callerName(true) : c->calledName(true); f = _showCallers ? c->caller(true) : c->called(true); cycle = f->cycle(); QString menuText = tr("Go to '%1'").arg(GlobalConfig::shortenSymbol(name)); activateFunctionAction = popup.addAction(menuText); if (cycle) { name = GlobalConfig::shortenSymbol(cycle->prettyName()); QString menuText = tr("Go to '%1'").arg(name); activateCycleAction = popup.addAction(menuText); } popup.addSeparator(); } if ((col == 0) || (col == 1)) { addEventTypeMenu(&popup); popup.addSeparator(); } addGoMenu(&popup); QAction* a = popup.exec(mapToGlobal(p + QPoint(0,header()->height()))); if (a == activateFunctionAction) TraceItemView::activated(f); else if (a == activateCycleAction) TraceItemView::activated(cycle); }
void CallView::refresh() { clear(); setColumnWidth(1, _eventType2 ? 50:0); if (_eventType) _headerLabels[0] = _eventType->name(); if (_eventType2) _headerLabels[1] = _eventType2->name(); setHeaderLabels(_headerLabels); if (!_data || !_activeItem) return; TraceFunction* f = activeFunction(); if (!f) return; TraceCall* call; // In the call lists, we skip cycles to show the real call relations TraceCallList l = _showCallers ? f->callers(true) : f->callings(true); QList<QTreeWidgetItem*> items; for (call=l.first();call;call=l.next()) if (call->subCost(_eventType)>0) items.append(new CallItem(this, 0, call)); // when inserting, switch off sorting for performance reason setSortingEnabled(false); addTopLevelItems(items); setSortingEnabled(true); // enabling sorting switches on the indicator, but we want it off header()->setSortIndicatorShown(false); // resize to content now (section size still can be interactively changed) header()->resizeSections(QHeaderView::ResizeToContents); if (!_eventType2) setColumnWidth(1, 0); }
// for call lines SourceItem::SourceItem(SourceView* sv, QTreeWidgetItem* parent, int fileno, unsigned int lineno, TraceLine* line, TraceLineCall* lineCall) : QTreeWidgetItem(parent) { _view = sv; _lineno = lineno; _fileno = fileno; _inside = true; _line = line; _lineCall = lineCall; _lineJump = 0; setTextAlignment(0, Qt::AlignRight); setTextAlignment(1, Qt::AlignRight); setTextAlignment(2, Qt::AlignRight); //qDebug("SourceItem: (file %d, line %d) Linecall to %s", // fileno, lineno, _lineCall->call()->called()->prettyName().toAscii()); SubCost cc = _lineCall->callCount(); QString callStr = " "; if (cc==0) callStr += QObject::tr("Active call to '%1'") .arg(_lineCall->call()->calledName()); else callStr += QObject::tr("%n call(s) to '%2'", "", (uint64)cc) .arg(_lineCall->call()->calledName()); TraceFunction* calledF = _lineCall->call()->called(); calledF->addPrettyLocation(callStr); setText(4, callStr); updateGroup(); updateCost(); }
// make sure that a valid function is set, at least dummy with empty name void CachegrindLoader::ensureFunction() { if (currentFunction) return; error(QStringLiteral("Function not specified, setting to unknown")); ensureFile(); ensureObject(); currentFunction = _data->function(_emptyString, currentFile, currentObject); currentPartFunction = currentFunction->partFunction(_part, currentPartFile, currentPartObject); }
void CoverageView::refresh() { clear(); setColumnWidth(0, 50); if (!_showCallers) setColumnWidth(1, 50); if (!_data || !_activeItem) return; TraceItem::CostType t = _activeItem->type(); TraceFunction* f = 0; if (t == TraceItem::Function) f = (TraceFunction*) _activeItem; if (t == TraceItem::FunctionCycle) f = (TraceFunction*) _activeItem; if (!f) return; TraceFunction* ff; TraceFunctionList l; _hc.clear(Configuration::maxListCount()); SubCost realSum = f->inclusive()->subCost(_costType); if (_showCallers) l = Coverage::coverage(f, Coverage::Caller, _costType); else l = Coverage::coverage(f, Coverage::Called, _costType); for (ff=l.first();ff;ff=l.next()) { Coverage* c = (Coverage*) ff->assoziation(Coverage::Rtti); if (c && (c->inclusive()>0.0)) _hc.addCost(ff, SubCost(realSum * c->inclusive())); } for(int i=0;i<_hc.realCount();i++) { ff = (TraceFunction*) _hc[i]; Coverage* c = (Coverage*) ff->assoziation(Coverage::Rtti); if (_showCallers) new CallerCoverageItem(this, c, f, _costType, _groupType); else new CalleeCoverageItem(this, c, f, _costType, _groupType); } if (_hc.hasMore()) { // a placeholder for all the functions skipped ... ff = (TraceFunction*) _hc[_hc.maxSize()-1]; Coverage* c = (Coverage*) ff->assoziation(Coverage::Rtti); if (_showCallers) new CallerCoverageItem(this, _hc.count() - _hc.maxSize(), c, f, _costType, _groupType); else new CalleeCoverageItem(this, _hc.count() - _hc.maxSize(), c, f, _costType, _groupType); } }
/** * The main import function... */ int CachegrindLoader::loadInternal(TraceData* data, QIODevice* device, const QString& filename) { if (!data || !device) return 0; _data = data; _filename = filename; _lineNo = 0; loadStart(_filename); FixFile file(device, _filename); if (!file.exists()) { loadFinished(QStringLiteral("File does not exist")); return 0; } int statusProgress = 0; #if USE_FIXCOST // FixCost Memory Pool FixPool* pool = _data->fixPool(); #endif _part = 0; partsAdded = 0; prepareNewPart(); FixString line; char c; // current position nextLineType = SelfCost; // default if there is no "positions:" line hasLineInfo = true; hasAddrInfo = false; while (file.nextLine(line)) { _lineNo++; #if TRACE_LOADER qDebug() << "[CachegrindLoader] " << _filename << ":" << _lineNo << " - '" << QString(line) << "'"; #endif // if we cannot strip a character, this was an empty line if (!line.first(c)) continue; if (c <= '9') { if (c == '#') continue; // parse position(s) if (!parsePosition(line, currentPos)) { error(QStringLiteral("Invalid position specification '%1'").arg(line)); continue; } // go through after big switch } else { // if (c > '9') line.stripFirst(c); /* in order of probability */ switch(c) { case 'f': // fl= if (line.stripPrefix("l=")) { setFile(line); // this is the default for new functions currentFunctionFile = currentFile; continue; } // fi=, fe= if (line.stripPrefix("i=") || line.stripPrefix("e=")) { setFile(line); continue; } // fn= if (line.stripPrefix("n=")) { if (currentFile != currentFunctionFile) currentFile = currentFunctionFile; setFunction(line); // on a new function, update status int progress = (int)(100.0 * file.current() / file.len() +.5); if (progress != statusProgress) { statusProgress = progress; /* When this signal is connected, it most probably * should lead to GUI update. Thus, when multiple * "long operations" (like file loading) are in progress, * this can temporarly switch to another operation. */ loadProgress(statusProgress); } continue; } break; case 'c': // cob= if (line.stripPrefix("ob=")) { setCalledObject(line); continue; } // cfi= / cfl= if (line.stripPrefix("fl=") || line.stripPrefix("fi=")) { setCalledFile(line); continue; } // cfn= if (line.stripPrefix("fn=")) { setCalledFunction(line); continue; } // calls= if (line.stripPrefix("alls=")) { // ignore long lines... line.stripUInt64(currentCallCount); nextLineType = CallCost; continue; } // cmd: if (line.stripPrefix("md:")) { QString command = QString(line).trimmed(); if (!_data->command().isEmpty() && _data->command() != command) { error(QStringLiteral("Redefined command, was '%1'").arg(_data->command())); } _data->setCommand(command); continue; } // creator: if (line.stripPrefix("reator:")) { // ignore ... continue; } break; case 'j': // jcnd= if (line.stripPrefix("cnd=")) { bool valid; valid = line.stripUInt64(jumpsFollowed) && line.stripPrefix("/") && line.stripUInt64(jumpsExecuted) && parsePosition(line, targetPos); if (!valid) { error(QStringLiteral("Invalid line after 'jcnd'")); } else nextLineType = CondJump; continue; } if (line.stripPrefix("ump=")) { bool valid; valid = line.stripUInt64(jumpsExecuted) && parsePosition(line, targetPos); if (!valid) { error(QStringLiteral("Invalid line after 'jump'")); } else nextLineType = BoringJump; continue; } // jfi= if (line.stripPrefix("fi=")) { currentJumpToFile = compressedFile(line); continue; } // jfn= if (line.stripPrefix("fn=")) { if (!currentJumpToFile) { // !=0 as functions needs file currentJumpToFile = currentFile; } currentJumpToFunction = compressedFunction(line, currentJumpToFile, currentObject); continue; } break; case 'o': // ob= if (line.stripPrefix("b=")) { setObject(line); continue; } break; case '#': continue; case 'a': // "arch: arm" if (line.stripPrefix("rch: arm")) { TraceData::Arch a = _data->architecture(); if ((a != TraceData::ArchUnknown) && (a != TraceData::ArchARM)) { error(QStringLiteral("Redefined architecture!")); } _data->setArchitecture(TraceData::ArchARM); continue; } break; case 't': // totals: if (line.stripPrefix("otals:")) continue; // thread: if (line.stripPrefix("hread:")) { prepareNewPart(); _part->setThreadID(QString(line).toInt()); continue; } // timeframe (BB): if (line.stripPrefix("imeframe (BB):")) { _part->setTimeframe(line); continue; } break; case 'd': // desc: if (line.stripPrefix("esc:")) { line.stripSurroundingSpaces(); // desc: Trigger: if (line.stripPrefix("Trigger:")) { _part->setTrigger(line); } continue; } break; case 'e': // events: if (line.stripPrefix("vents:")) { prepareNewPart(); mapping = _data->eventTypes()->createMapping(line); _part->setEventMapping(mapping); continue; } // event:<name>[=<formula>][:<long name>] if (line.stripPrefix("vent:")) { line.stripSurroundingSpaces(); FixString e, f, l; if (!line.stripName(e)) { error(QStringLiteral("Invalid event")); continue; } line.stripSpaces(); if (!line.stripFirst(c)) continue; if (c=='=') f = line.stripUntil(':'); line.stripSpaces(); // add to known cost types if (line.isEmpty()) line = e; EventType::add(new EventType(e,line,f)); continue; } break; case 'p': // part: if (line.stripPrefix("art:")) { prepareNewPart(); _part->setPartNumber(QString(line).toInt()); continue; } // pid: if (line.stripPrefix("id:")) { prepareNewPart(); _part->setProcessID(QString(line).toInt()); continue; } // positions: if (line.stripPrefix("ositions:")) { prepareNewPart(); QString positions(line); hasLineInfo = positions.contains(QStringLiteral("line")); hasAddrInfo = positions.contains(QStringLiteral("instr")); continue; } break; case 'v': // version: if (line.stripPrefix("ersion:")) { // ignore for now continue; } break; case 's': // summary: if (line.stripPrefix("ummary:")) { if (!mapping) { error(QStringLiteral("No event line found. Skipping file")); delete _part; return false; } _part->totals()->set(mapping, line); continue; } case 'r': // rcalls= (deprecated) if (line.stripPrefix("calls=")) { // handle like normal calls: we need the sum of call count // recursive cost is discarded in cycle detection line.stripUInt64(currentCallCount); nextLineType = CallCost; warning(QStringLiteral("Old file format using deprecated 'rcalls'")); continue; } break; default: break; } error(QStringLiteral("Invalid line '%1%2'").arg(c).arg(line)); continue; } if (!mapping) { error(QStringLiteral("No event line found. Skipping file")); delete _part; return false; } // for a cost line, we always need a current function ensureFunction(); if (!currentFunctionSource || (currentFunctionSource->file() != currentFile)) { currentFunctionSource = currentFunction->sourceFile(currentFile, true); } #if !USE_FIXCOST if (hasAddrInfo) { if (!currentInstr || (currentInstr->addr() != currentPos.fromAddr)) { currentInstr = currentFunction->instr(currentPos.fromAddr, true); if (!currentInstr) { error(QString("Invalid address '%1'").arg(currentPos.fromAddr.toString())); continue; } currentPartInstr = currentInstr->partInstr(_part, currentPartFunction); } } if (hasLineInfo) { if (!currentLine || (currentLine->lineno() != currentPos.fromLine)) { currentLine = currentFunctionSource->line(currentPos.fromLine, true); currentPartLine = currentLine->partLine(_part, currentPartFunction); } if (hasAddrInfo && currentInstr) currentInstr->setLine(currentLine); } #endif #if TRACE_LOADER qDebug() << _filename << ":" << _lineNo; qDebug() << " currentInstr " << (currentInstr ? qPrintable(currentInstr->toString()) : "."); qDebug() << " currentLine " << (currentLine ? qPrintable(currentLine->toString()) : ".") << "( file " << currentFile->name() << ")"; qDebug() << " currentFunction " << qPrintable(currentFunction->prettyName()); qDebug() << " currentCalled " << (currentCalledFunction ? qPrintable(currentCalledFunction->prettyName()) : "."); #endif // create cost item if (nextLineType == SelfCost) { #if USE_FIXCOST new (pool) FixCost(_part, pool, currentFunctionSource, currentPos, currentPartFunction, line); #else if (hasAddrInfo) { TracePartInstr* partInstr; partInstr = currentInstr->partInstr(_part, currentPartFunction); if (hasLineInfo) { // we need to set <line> back after reading for the line int l = line.len(); const char* s = line.ascii(); partInstr->addCost(mapping, line); line.set(s,l); } else partInstr->addCost(mapping, line); } if (hasLineInfo) { TracePartLine* partLine; partLine = currentLine->partLine(_part, currentPartFunction); partLine->addCost(mapping, line); } #endif if (!line.isEmpty()) { error(QStringLiteral("Garbage at end of cost line ('%1')").arg(line)); } } else if (nextLineType == CallCost) { nextLineType = SelfCost; TraceCall* calling = currentFunction->calling(currentCalledFunction); TracePartCall* partCalling = calling->partCall(_part, currentPartFunction, currentCalledPartFunction); #if USE_FIXCOST FixCallCost* fcc; fcc = new (pool) FixCallCost(_part, pool, currentFunctionSource, hasLineInfo ? currentPos.fromLine : 0, hasAddrInfo ? currentPos.fromAddr : Addr(0), partCalling, currentCallCount, line); fcc->setMax(_data->callMax()); _data->updateMaxCallCount(fcc->callCount()); #else if (hasAddrInfo) { TraceInstrCall* instrCall; TracePartInstrCall* partInstrCall; instrCall = calling->instrCall(currentInstr); partInstrCall = instrCall->partInstrCall(_part, partCalling); partInstrCall->addCallCount(currentCallCount); if (hasLineInfo) { // we need to set <line> back after reading for the line int l = line.len(); const char* s = line.ascii(); partInstrCall->addCost(mapping, line); line.set(s,l); } else partInstrCall->addCost(mapping, line); // update maximum of call cost _data->callMax()->maxCost(partInstrCall); _data->updateMaxCallCount(partInstrCall->callCount()); } if (hasLineInfo) { TraceLineCall* lineCall; TracePartLineCall* partLineCall; lineCall = calling->lineCall(currentLine); partLineCall = lineCall->partLineCall(_part, partCalling); partLineCall->addCallCount(currentCallCount); partLineCall->addCost(mapping, line); // update maximum of call cost _data->callMax()->maxCost(partLineCall); _data->updateMaxCallCount(partLineCall->callCount()); } #endif currentCalledFile = 0; currentCalledPartFile = 0; currentCalledObject = 0; currentCalledPartObject = 0; currentCallCount = 0; if (!line.isEmpty()) { error(QStringLiteral("Garbage at end of call cost line ('%1')").arg(line)); } } else { // (nextLineType == BoringJump || nextLineType == CondJump) TraceFunctionSource* targetSource; if (!currentJumpToFunction) currentJumpToFunction = currentFunction; targetSource = (currentJumpToFile) ? currentJumpToFunction->sourceFile(currentJumpToFile, true) : currentFunctionSource; #if USE_FIXCOST new (pool) FixJump(_part, pool, /* source */ hasLineInfo ? currentPos.fromLine : 0, hasAddrInfo ? currentPos.fromAddr : 0, currentPartFunction, currentFunctionSource, /* target */ hasLineInfo ? targetPos.fromLine : 0, hasAddrInfo ? targetPos.fromAddr : Addr(0), currentJumpToFunction, targetSource, (nextLineType == CondJump), jumpsExecuted, jumpsFollowed); #else if (hasAddrInfo) { TraceInstr* jumpToInstr; TraceInstrJump* instrJump; TracePartInstrJump* partInstrJump; jumpToInstr = currentJumpToFunction->instr(targetPos.fromAddr, true); instrJump = currentInstr->instrJump(jumpToInstr, (nextLineType == CondJump)); partInstrJump = instrJump->partInstrJump(_part); partInstrJump->addExecutedCount(jumpsExecuted); if (nextLineType == CondJump) partInstrJump->addFollowedCount(jumpsFollowed); } if (hasLineInfo) { TraceLine* jumpToLine; TraceLineJump* lineJump; TracePartLineJump* partLineJump; jumpToLine = targetSource->line(targetPos.fromLine, true); lineJump = currentLine->lineJump(jumpToLine, (nextLineType == CondJump)); partLineJump = lineJump->partLineJump(_part); partLineJump->addExecutedCount(jumpsExecuted); if (nextLineType == CondJump) partLineJump->addFollowedCount(jumpsFollowed); } #endif if (0) { qDebug() << _filename << ":" << _lineNo << " - jump from 0x" << currentPos.fromAddr.toString() << " (line " << currentPos.fromLine << ") to 0x" << targetPos.fromAddr.toString() << " (line " << targetPos.fromLine << ")"; if (nextLineType == BoringJump) qDebug() << " Boring Jump, count " << jumpsExecuted.pretty(); else qDebug() << " Cond. Jump, followed " << jumpsFollowed.pretty() << ", executed " << jumpsExecuted.pretty(); } nextLineType = SelfCost; currentJumpToFunction = 0; currentJumpToFile = 0; if (!line.isEmpty()) { error(QStringLiteral("Garbage at end of jump cost line ('%1')").arg(line)); } } } loadFinished(); if (mapping) { _part->invalidate(); _part->totals()->clear(); _part->totals()->addCost(_part); data->addPart(_part); partsAdded++; } else { delete _part; } device->close(); return partsAdded; }
void SourceView::refresh() { clear(); setColumnWidth(0, 20); setColumnWidth(1, 50); setColumnWidth(2, _costType2 ? 50:0); setColumnWidth(3, 0); // arrows, defaults to invisible setSorting(0); // always reset to line number sort if (_costType) setColumnText(1, _costType->name()); if (_costType2) setColumnText(2, _costType2->name()); _arrowLevels = 0; if (!_data || !_activeItem) { setColumnText(4, i18n("(No Source)")); return; } TraceItem::CostType t = _activeItem->type(); TraceFunction* f = 0; if (t == TraceItem::Function) f = (TraceFunction*) _activeItem; if (t == TraceItem::Instr) { f = ((TraceInstr*)_activeItem)->function(); if (!_selectedItem) _selectedItem = _activeItem; } if (t == TraceItem::Line) { f = ((TraceLine*)_activeItem)->functionSource()->function(); if (!_selectedItem) _selectedItem = _activeItem; } if (!f) return; // Allow resizing of column 2 setColumnWidthMode(2, QListView::Maximum); TraceFunctionSource* mainSF = f->sourceFile(); // skip first source if there's no debug info and there are more sources // (this is for a bug in GCC 2.95.x giving unknown source for prologs) if (mainSF && (mainSF->firstLineno() == 0) && (mainSF->lastLineno() == 0) && (f->sourceFiles().count()>1) ) { // skip } else fillSourceFile(mainSF, 0); TraceFunctionSource* sf; int fileno = 1; TraceFunctionSourceList l = f->sourceFiles(); for (sf=l.first();sf;sf=l.next(), fileno++) if (sf != mainSF) fillSourceFile(sf, fileno); if (!_costType2) { setColumnWidthMode(2, QListView::Manual); setColumnWidth(2, 0); } }
void CostTypeItem::update() { TraceData* d = _costItem ? _costItem->data() : 0; double total = d ? ((double)d->subCost(_costType)) : 0.0; if (total == 0.0) { setText(1, "-"); setPixmap(1, QPixmap()); setText(2, "-"); setPixmap(2, QPixmap()); return; } TraceFunction* f = (_costItem->type()==TraceCost::Function) ? (TraceFunction*)_costItem : 0; TraceCost* selfTotalCost = f ? f->data() : d; if (f && Configuration::showExpanded()) { switch(_groupType) { case TraceCost::Object: selfTotalCost = f->object(); break; case TraceCost::Class: selfTotalCost = f->cls(); break; case TraceCost::File: selfTotalCost = f->file(); break; case TraceCost::FunctionCycle: selfTotalCost = f->cycle(); break; default: break; } } if (_costItem->type()==TraceCost::FunctionCycle) { f = (TraceFunction*)_costItem; selfTotalCost = f->data(); } double selfTotal = selfTotalCost->subCost(_costType); // for all cost items there's a self cost _pure = _costItem ? _costItem->subCost(_costType) : SubCost(0); double pure = 100.0 * _pure / selfTotal; if (Configuration::showPercentage()) { setText(2, QString("%1") .arg(pure, 0, 'f', Configuration::percentPrecision())); } else setText(2, _costItem->prettySubCost(_costType)); setPixmap(2, costPixmap(_costType, _costItem, selfTotal, false)); if (!f) { setText(1, "-"); setPixmap(1, QPixmap()); return; } _sum = f->inclusive()->subCost(_costType); double sum = 100.0 * _sum / total; if (Configuration::showPercentage()) { setText(1, QString("%1") .arg(sum, 0, 'f', Configuration::percentPrecision())); } else setText(1, _sum.pretty()); setPixmap(1, costPixmap(_costType, f->inclusive(), total, false)); }
void EventTypeItem::update() { TraceData* d = _costItem ? _costItem->data() : 0; double total = d ? ((double)d->subCost(_eventType)) : 0.0; if (total == 0.0) { setText(1, "-"); setIcon(1, QIcon()); setText(2, "-"); setIcon(2, QIcon()); return; } TraceFunction* f = (_costItem && _costItem->type()==ProfileContext::Function) ? (TraceFunction*)_costItem : 0; ProfileCostArray* selfTotalCost = f ? f->data() : d; if (f && GlobalConfig::showExpanded()) { ProfileCostArray* parent = 0; switch(_groupType) { case ProfileContext::Object: parent = f->object(); break; case ProfileContext::Class: parent = f->cls(); break; case ProfileContext::File: parent = f->file(); break; case ProfileContext::FunctionCycle: parent = f->cycle(); break; default: break; } if (parent) selfTotalCost = parent; } if (_costItem && _costItem->type()==ProfileContext::FunctionCycle) { f = (TraceFunction*)_costItem; selfTotalCost = f->data(); } double selfTotal = selfTotalCost->subCost(_eventType); // for all cost items there is a self cost _pure = _costItem ? _costItem->subCost(_eventType) : SubCost(0); double pure = 100.0 * _pure / selfTotal; if (GlobalConfig::showPercentage()) { setText(2, QString("%1") .arg(pure, 0, 'f', GlobalConfig::percentPrecision())); } else if (_costItem) setText(2, _costItem->prettySubCost(_eventType)); setIcon(2, QIcon(costPixmap(_eventType, _costItem, selfTotal, false))); if (!f) { setText(1, "-"); setIcon(1, QIcon()); return; } _sum = f->inclusive()->subCost(_eventType); double sum = 100.0 * _sum / total; if (GlobalConfig::showPercentage()) { setText(1, QString("%1") .arg(sum, 0, 'f', GlobalConfig::percentPrecision())); } else setText(1, _sum.pretty()); setIcon(1, QIcon(costPixmap(_eventType, f->inclusive(), total, false))); }
// Note: Callgrind gives different IDs even for same function // when parts of the function are from different source files. // Thus, it is no error when multiple indexes map to same function. TraceFunction* CachegrindLoader::compressedFunction(const QString& name, TraceFile* file, TraceObject* object) { if ((name[0] != '(') || !name[1].isDigit()) return _data->function(checkUnknown(name), file, object); // compressed format using _functionVector int p = name.indexOf(')'); if (p<2) { error(QStringLiteral("Invalid compressed function ('%1')").arg(name)); return 0; } int index = name.midRef(1, p-1).toUInt(); TraceFunction* f = 0; p++; while((name.length()>p) && name.at(p).isSpace()) p++; if (name.length()>p) { if (_functionVector.size() <= index) { int newSize = index * 2; #if TRACE_LOADER qDebug() << " CachegrindLoader::functionVector enlarged to " << newSize; #endif _functionVector.resize(newSize); } QString realName = checkUnknown(name.mid(p)); f = (TraceFunction*) _functionVector.at(index); if (f && (f->name() != realName)) { error(QStringLiteral("Redefinition of compressed function index %1 (was '%2') to %3") .arg(index).arg(f->name()).arg(realName)); } f = _data->function(realName, file, object); _functionVector.replace(index, f); #if TRACE_LOADER qDebug() << "compressedFunction: Inserted at Index " << index << "\n " << f->fullName() << "\n in " << f->cls()->fullName() << "\n in " << f->file()->fullName() << "\n in " << f->object()->fullName(); #endif } else { if ((_functionVector.size() <= index) || ( (f=(TraceFunction*)_functionVector.at(index)) == 0)) { error(QStringLiteral("Undefined compressed function index %1").arg(index)); return 0; } // there was a check if the used function (returned from KCachegrinds // model) has the same object and file as here given to us, but that was wrong: // that holds only if we make this assumption on the model... } return f; }