diff options
Diffstat (limited to 'tdecachegrind/tdecachegrind/cachegrindloader.cpp')
-rw-r--r-- | tdecachegrind/tdecachegrind/cachegrindloader.cpp | 1323 |
1 files changed, 1323 insertions, 0 deletions
diff --git a/tdecachegrind/tdecachegrind/cachegrindloader.cpp b/tdecachegrind/tdecachegrind/cachegrindloader.cpp new file mode 100644 index 00000000..4fe57d34 --- /dev/null +++ b/tdecachegrind/tdecachegrind/cachegrindloader.cpp @@ -0,0 +1,1323 @@ +/* This file is part of KCachegrind. + Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de> + + KCachegrind is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation, version 2. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <errno.h> + +#include <tqfile.h> +#include <tqcstring.h> + +#include <klocale.h> +#include <kdebug.h> + +#include "loader.h" +#include "tracedata.h" +#include "utils.h" +#include "fixcost.h" + + +#define TRACE_LOADER 0 + +/* + * Loader for Callgrind Profile data (format based on Cachegrind format). + * See Callgrind documentation for the file format. + */ + +class CachegrindLoader: public Loader +{ +public: + CachegrindLoader(); + + bool canLoadTrace(TQFile* file); + bool loadTrace(TracePart*); + bool isPartOfTrace(TQString file, TraceData*); + +private: + bool loadTraceInternal(TracePart*); + + enum lineType { SelfCost, CallCost, BoringJump, CondJump }; + + bool parsePosition(FixString& s, PositionSpec& newPos); + + // position setters + void clearPosition(); + void ensureObject(); + void ensureFile(); + void ensureFunction(); + void setObject(const TQString&); + void setCalledObject(const TQString&); + void setFile(const TQString&); + void setCalledFile(const TQString&); + void setFunction(const TQString&); + void setCalledFunction(const TQString&); + + TQString _emptyString; + + // current line in file to read in + TQString _filename; + int _lineNo; + + TraceSubMapping* subMapping; + TraceData* _data; + TracePart* _part; + + // current position + lineType nextLineType; + bool hasLineInfo, hasAddrInfo; + PositionSpec currentPos; + + // current function/line + TraceObject* currentObject; + TracePartObject* currentPartObject; + TraceFile* currentFile; + TracePartFile* currentPartFile; + TraceFunction* currentFunction; + TracePartFunction* currentPartFunction; + TraceFunctionSource* currentFunctionSource; + TraceInstr* currentInstr; + TracePartInstr* currentPartInstr; + TraceLine* currentLine; + TracePartLine* currentPartLine; + + // current call + TraceObject* currentCalledObject; + TracePartObject* currentCalledPartObject; + TraceFile* currentCalledFile; + TracePartFile* currentCalledPartFile; + TraceFunction* currentCalledFunction; + TracePartFunction* currentCalledPartFunction; + SubCost currentCallCount; + + // current jump + TraceFile* currentJumpToFile; + TraceFunction* currentJumpToFunction; + PositionSpec targetPos; + SubCost jumpsFollowed, jumpsExecuted; + + /** Support for compressed string format + * This uses the following string compression model + * for objects, files, functions: + * If the name matches + * "(<Integer>) Name": this is a compression specification, + * mapping the integer number to Name and using Name. + * "(<Integer>)" : this is a compression reference. + * Assumes previous compression specification of the + * integer number to a name, uses this name. + * "Name" : Regular name + */ + void clearCompression(); + const TQString& checkUnknown(const TQString& n); + TraceObject* compressedObject(const TQString& name); + TraceFile* compressedFile(const TQString& name); + TraceFunction* compressedFunction(const TQString& name, + TraceFile*, TraceObject*); + + TQPtrVector<TraceCostItem> _objectVector, _fileVector, _functionVector; +}; + + + +/********************************************************** + * Loader + */ + + +CachegrindLoader::CachegrindLoader() + : Loader("Callgrind", + i18n( "Import filter for Cachegrind/Callgrind generated profile data files") ) +{ + _emptyString = TQString(""); +} + +bool CachegrindLoader::canLoadTrace(TQFile* file) +{ + if (!file) return false; + + if (!file->isOpen()) { + if (!file->open( IO_ReadOnly ) ) { + kdDebug() << TQFile::encodeName(_filename).data() << ": " + << strerror( errno ) << endl; + return false; + } + } + + /* + * We recognize this as cachegrind/callgrind format if in the first + * 2047 bytes we see the string "\nevents:" + */ + char buf[2048]; + int read = file->readBlock(buf,2047); + if (read < 0) + return false; + buf[read] = 0; + + TQCString s; + s.setRawData(buf, read+1); + int pos = s.find("events:"); + if (pos>0 && buf[pos-1] != '\n') pos = -1; + s.resetRawData(buf, read+1); + return (pos>=0); +} + +bool CachegrindLoader::loadTrace(TracePart* p) +{ + /* do the loading in a new object so parallel load + * operations do not interfere each other. + */ + CachegrindLoader l; + + /* emit progress signals via the singleton loader */ + connect(&l, TQT_SIGNAL(updateStatus(TQString, int)), + this, TQT_SIGNAL(updateStatus(TQString, int))); + + return l.loadTraceInternal(p); +} + +Loader* createCachegrindLoader() +{ + return new CachegrindLoader(); +} + + + +/** + * Return false if this is no position specification + */ +bool CachegrindLoader::parsePosition(FixString& line, + PositionSpec& newPos) +{ + char c; + uint diff; + + if (hasAddrInfo) { + + if (!line.first(c)) return false; + + if (c == '*') { + // nothing changed + line.stripFirst(c); + newPos.fromAddr = currentPos.fromAddr; + newPos.toAddr = currentPos.toAddr; + } + else if (c == '+') { + line.stripFirst(c); + line.stripUInt(diff, false); + newPos.fromAddr = currentPos.fromAddr + diff; + newPos.toAddr = newPos.fromAddr; + } + else if (c == '-') { + line.stripFirst(c); + line.stripUInt(diff, false); + newPos.fromAddr = currentPos.fromAddr - diff; + newPos.toAddr = newPos.fromAddr; + } + else if (c >= '0') { + uint64 v; + line.stripUInt64(v, false); + newPos.fromAddr = Addr(v); + newPos.toAddr = newPos.fromAddr; + } + else return false; + + // Range specification + if (line.first(c)) { + if (c == '+') { + line.stripFirst(c); + line.stripUInt(diff); + newPos.toAddr = newPos.fromAddr + diff; + } + else if ((c == '-') || (c == ':')) { + line.stripFirst(c); + uint64 v; + line.stripUInt64(v); + newPos.toAddr = Addr(v); + } + } + line.stripSpaces(); + +#if TRACE_LOADER + if (newPos.fromAddr == newPos.toAddr) + kdDebug() << " Got Addr " << newPos.fromAddr.toString() << endl; + else + kdDebug() << " Got AddrRange " << newPos.fromAddr.toString() + << ":" << newPos.toAddr.toString() << endl; +#endif + + } + + if (hasLineInfo) { + + if (!line.first(c)) return false; + + if (c > '9') return false; + else if (c == '*') { + // nothing changed + line.stripFirst(c); + newPos.fromLine = currentPos.fromLine; + newPos.toLine = currentPos.toLine; + } + else if (c == '+') { + line.stripFirst(c); + line.stripUInt(diff, false); + newPos.fromLine = currentPos.fromLine + diff; + newPos.toLine = newPos.fromLine; + } + else if (c == '-') { + line.stripFirst(c); + line.stripUInt(diff, false); + if (currentPos.fromLine < diff) { + kdError() << _filename << ":" << _lineNo + << " - Negative line number " + << (int)currentPos.fromLine - (int)diff << endl; + diff = currentPos.fromLine; + } + newPos.fromLine = currentPos.fromLine - diff; + newPos.toLine = newPos.fromLine; + } + else if (c >= '0') { + line.stripUInt(newPos.fromLine, false); + newPos.toLine = newPos.fromLine; + } + else return false; + + // Range specification + if (line.first(c)) { + if (c == '+') { + line.stripFirst(c); + line.stripUInt(diff); + newPos.toLine = newPos.fromLine + diff; + } + else if ((c == '-') || (c == ':')) { + line.stripFirst(c); + line.stripUInt(newPos.toLine); + } + } + line.stripSpaces(); + +#if TRACE_LOADER + if (newPos.fromLine == newPos.toLine) + kdDebug() << " Got Line " << newPos.fromLine << endl; + else + kdDebug() << " Got LineRange " << newPos.fromLine + << ":" << newPos.toLine << endl; +#endif + + } + + return true; +} + +// Support for compressed strings +void CachegrindLoader::clearCompression() +{ + // this doesn't delete previous contained objects + _objectVector.clear(); + _fileVector.clear(); + _functionVector.clear(); + + // reset to reasonable init size. We double lengths if needed. + _objectVector.resize(100); + _fileVector.resize(1000); + _functionVector.resize(10000); +} + +const TQString& CachegrindLoader::checkUnknown(const TQString& n) +{ + if (n == "???") return _emptyString; + return n; +} + +TraceObject* CachegrindLoader::compressedObject(const TQString& name) +{ + if ((name[0] != '(') || !name[1].isDigit()) return _data->object(checkUnknown(name)); + + // compressed format using _objectVector + int p = name.find(')'); + if (p<2) { + kdError() << _filename << ":" << _lineNo + << " - Invalid compressed ELF object ('" + << name << "')" << endl; + return 0; + } + unsigned index = name.mid(1, p-1).toInt(); + TraceObject* o = 0; + p++; + if ((int)name.length()>p) { + while(name.at(p).isSpace()) p++; + + if (_objectVector.size() <= index) { + int newSize = index * 2; +#if TRACE_LOADER + kdDebug() << " CachegrindLoader: objectVector enlarged to " + << newSize << endl; +#endif + _objectVector.resize(newSize); + } + + TQString realName = checkUnknown(name.mid(p)); + o = (TraceObject*) _objectVector.at(index); + if (o && (o->name() != realName)) { + kdError() << _filename << ":" << _lineNo + << " - Redefinition of compressed ELF object index " << index + << " (was '" << o->name() + << "') to '" << realName << "'" << endl; + } + + o = _data->object(realName); + _objectVector.insert(index, o); + } + else { + if ((_objectVector.size() <= index) || + ( (o=(TraceObject*)_objectVector.at(index)) == 0)) { + kdError() << _filename << ":" << _lineNo + << " - Undefined compressed ELF object index " << index << endl; + return 0; + } + } + + return o; +} + + +// Note: Callgrind sometimes gives different IDs for same file +// (when references to same source file come from different ELF objects) +TraceFile* CachegrindLoader::compressedFile(const TQString& name) +{ + if ((name[0] != '(') || !name[1].isDigit()) return _data->file(checkUnknown(name)); + + // compressed format using _fileVector + int p = name.find(')'); + if (p<2) { + kdError() << _filename << ":" << _lineNo + << " - Invalid compressed file ('" + << name << "')" << endl; + return 0; + } + unsigned int index = name.mid(1, p-1).toUInt(); + TraceFile* f = 0; + p++; + if ((int)name.length()>p) { + while(name.at(p).isSpace()) p++; + + if (_fileVector.size() <= index) { + int newSize = index * 2; +#if TRACE_LOADER + kdDebug() << " CachegrindLoader::fileVector enlarged to " + << newSize << endl; +#endif + _fileVector.resize(newSize); + } + + TQString realName = checkUnknown(name.mid(p)); + f = (TraceFile*) _fileVector.at(index); + if (f && (f->name() != realName)) { + kdError() << _filename << ":" << _lineNo + << " - Redefinition of compressed file index " << index + << " (was '" << f->name() + << "') to '" << realName << "'" << endl; + } + + f = _data->file(realName); + _fileVector.insert(index, f); + } + else { + if ((_fileVector.size() <= index) || + ( (f=(TraceFile*)_fileVector.at(index)) == 0)) { + kdError() << _filename << ":" << _lineNo + << " - Undefined compressed file index " << index << endl; + return 0; + } + } + + return f; +} + +// 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 TQString& 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.find(')'); + if (p<2) { + kdError() << _filename << ":" << _lineNo + << " - Invalid compressed function ('" + << name << "')" << endl; + return 0; + } + + + unsigned int index = name.mid(1, p-1).toUInt(); + TraceFunction* f = 0; + p++; + if ((int)name.length()>p) { + while(name.at(p).isSpace()) p++; + + if (_functionVector.size() <= index) { + int newSize = index * 2; +#if TRACE_LOADER + kdDebug() << " CachegrindLoader::functionVector enlarged to " + << newSize << endl; +#endif + _functionVector.resize(newSize); + } + + TQString realName = checkUnknown(name.mid(p)); + f = (TraceFunction*) _functionVector.at(index); + if (f && (f->name() != realName)) { + kdError() << _filename << ":" << _lineNo + << " - Redefinition of compressed function index " << index + << " (was '" << f->name() + << "') to '" << realName << "'" << endl; + } + + f = _data->function(realName, file, object); + _functionVector.insert(index, f); + +#if TRACE_LOADER + kdDebug() << "compressedFunction: Inserted at Index " << index + << "\n " << f->fullName() + << "\n in " << f->cls()->fullName() + << "\n in " << f->file()->fullName() + << "\n in " << f->object()->fullName() << endl; +#endif + } + else { + if ((_functionVector.size() <= index) || + ( (f=(TraceFunction*)_functionVector.at(index)) == 0)) { + kdError() << _filename << ":" << _lineNo + << " - Undefined compressed function index " + << index << endl; + 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; +} + + +// make sure that a valid object is set, at least dummy with empty name +void CachegrindLoader::ensureObject() +{ + if (currentObject) return; + + currentObject = _data->object(_emptyString); + currentPartObject = currentObject->partObject(_part); +} + +void CachegrindLoader::setObject(const TQString& name) +{ + currentObject = compressedObject(name); + if (!currentObject) { + kdError() << _filename << ":" << _lineNo + << " - Invalid object specification, setting to unknown" << endl; + + currentObject = _data->object(_emptyString); + } + + currentPartObject = currentObject->partObject(_part); + currentFunction = 0; + currentPartFunction = 0; +} + +void CachegrindLoader::setCalledObject(const TQString& name) +{ + currentCalledObject = compressedObject(name); + + if (!currentCalledObject) { + kdError() << _filename << ":" << _lineNo + << " - Invalid called specification, setting to unknown" << endl; + + currentCalledObject = _data->object(_emptyString); + } + + currentCalledPartObject = currentCalledObject->partObject(_part); +} + + +// make sure that a valid file is set, at least dummy with empty name +void CachegrindLoader::ensureFile() +{ + if (currentFile) return; + + currentFile = _data->file(_emptyString); + currentPartFile = currentFile->partFile(_part); +} + +void CachegrindLoader::setFile(const TQString& name) +{ + currentFile = compressedFile(name); + + if (!currentFile) { + kdWarning() << _filename << ":" << _lineNo + << " - Invalid file specification, setting to unknown" << endl; + + currentFile = _data->file(_emptyString); + } + + currentPartFile = currentFile->partFile(_part); + currentLine = 0; + currentPartLine = 0; +} + +void CachegrindLoader::setCalledFile(const TQString& name) +{ + currentCalledFile = compressedFile(name); + + if (!currentCalledFile) { + kdError() << _filename << ":" << _lineNo + << " - Invalid called file specification, setting to unknown" << endl; + + currentCalledFile = _data->file(_emptyString); + } + + currentCalledPartFile = currentCalledFile->partFile(_part); +} + +// make sure that a valid function is set, at least dummy with empty name +void CachegrindLoader::ensureFunction() +{ + if (currentFunction) return; + + kdWarning() << _filename << ":" << _lineNo + << " - Function name not set" << endl; + + ensureFile(); + ensureObject(); + + currentFunction = _data->function(_emptyString, + currentFile, + currentObject); + currentPartFunction = currentFunction->partFunction(_part, + currentPartFile, + currentPartObject); +} + +void CachegrindLoader::setFunction(const TQString& name) +{ + ensureFile(); + ensureObject(); + + currentFunction = compressedFunction( name, + currentFile, + currentObject); + + if (!currentFunction) { + kdWarning() << _filename << ":" << _lineNo + << " - Invalid function, setting to unknown" << endl; + + currentFunction = _data->function(_emptyString, + currentFile, + currentObject); + } + + currentPartFunction = currentFunction->partFunction(_part, + currentPartFile, + currentPartObject); + + currentFunctionSource = 0; + currentLine = 0; + currentPartLine = 0; +} + +void CachegrindLoader::setCalledFunction(const TQString& 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) { + kdWarning() << _filename << ":" << _lineNo + << " - Invalid called function, setting to unknown" << endl; + + currentCalledFunction = _data->function(_emptyString, + currentCalledFile, + currentCalledObject); + } + + currentCalledPartFunction = + currentCalledFunction->partFunction(_part, + currentCalledPartFile, + currentCalledPartObject); +} + + +void CachegrindLoader::clearPosition() +{ + currentPos = PositionSpec(); + + // current function/line + currentFunction = 0; + currentPartFunction = 0; + currentFunctionSource = 0; + currentFile = 0; + currentPartFile = 0; + currentObject = 0; + currentPartObject = 0; + currentLine = 0; + currentPartLine = 0; + currentInstr = 0; + currentPartInstr = 0; + + // current call + currentCalledObject = 0; + currentCalledPartObject = 0; + currentCalledFile = 0; + currentCalledPartFile = 0; + currentCalledFunction = 0; + currentCalledPartFunction = 0; + currentCallCount = 0; + + // current jump + currentJumpToFile = 0; + currentJumpToFunction = 0; + targetPos = PositionSpec(); + jumpsFollowed = 0; + jumpsExecuted = 0; + + subMapping = 0; +} + + +/** + * The main import function... + */ +bool CachegrindLoader::loadTraceInternal(TracePart* part) +{ + clearCompression(); + clearPosition(); + + _part = part; + _data = part->data(); + TQFile* pFile = part->file(); + + if (!pFile) return false; + + _filename = pFile->name(); + + FixFile file(pFile); + if (!file.exists()) { + kdError() << "File doesn't exist\n" << endl; + return false; + } + kdDebug() << "Loading " << _filename << " ..." << endl; + TQString statusMsg = i18n("Loading %1").arg(_filename); + int statusProgress = 0; + emit updateStatus(statusMsg,statusProgress); + + +#if USE_FIXCOST + // FixCost Memory Pool + FixPool* pool = _data->fixPool(); +#endif + + _lineNo = 0; + FixString line; + char c; + bool totalsSet = false; + + // current position + nextLineType = SelfCost; + // default if there's no "positions:" line + hasLineInfo = true; + hasAddrInfo = false; + + while (file.nextLine(line)) { + + _lineNo++; + +#if TRACE_LOADER + kdDebug() << "[CachegrindLoader] " << _filename << ":" << _lineNo + << " - '" << TQString(line) << "'" << endl; +#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)) { + kdError() << _filename << ":" << _lineNo + << " - Invalid position specification ('" + << TQString(line) << "')" << endl; + continue; + } + + // go through after big switch + } + else { // if (c > '9') + + line.stripFirst(c); + + /* in order of probability */ + switch(c) { + + case 'f': + + // fl=, fi=, fe= + if (line.stripPrefix("l=") || + line.stripPrefix("i=") || + line.stripPrefix("e=")) { + + setFile(line); + continue; + } + + // fn= + if (line.stripPrefix("n=")) { + + 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. + */ + emit updateStatus(statusMsg,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:")) { + TQString command = TQString(line).stripWhiteSpace(); + if (!_data->command().isEmpty() && + _data->command() != command) { + + kdWarning() << _filename << ":" << _lineNo + << " - Redefined command, was '" + << _data->command() + << "'" << endl; + } + _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) { + kdError() << _filename << ":" << _lineNo + << " - Invalid jcnd line" << endl; + } + else + nextLineType = CondJump; + continue; + } + + if (line.stripPrefix("ump=")) { + bool valid; + + valid = line.stripUInt64(jumpsExecuted) && + parsePosition(line, targetPos); + + if (!valid) { + kdError() << _filename << ":" << _lineNo + << " - Invalid jump line" << endl; + } + 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 't': + + // totals: + if (line.stripPrefix("otals:")) continue; + + // thread: + if (line.stripPrefix("hread:")) { + part->setThreadID(TQString(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:")) { + subMapping = _data->mapping()->subMapping(line); + part->setFixSubMapping(subMapping); + continue; + } + + // event:<name>[=<formula>][:<long name>] + if (line.stripPrefix("vent:")) { + line.stripSurroundingSpaces(); + + FixString e, f, l; + if (!line.stripName(e)) { + kdError() << _filename << ":" << _lineNo + << " - Invalid event" << endl; + 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; + TraceCostType::add(new TraceCostType(e,line,f)); + continue; + } + break; + + case 'p': + + // part: + if (line.stripPrefix("art:")) { + part->setPartNumber(TQString(line).toInt()); + continue; + } + + // pid: + if (line.stripPrefix("id:")) { + part->setProcessID(TQString(line).toInt()); + continue; + } + + // positions: + if (line.stripPrefix("ositions:")) { + TQString positions(line); + hasLineInfo = (positions.find("line")>=0); + hasAddrInfo = (positions.find("instr")>=0); + continue; + } + break; + + case 'v': + + // version: + if (line.stripPrefix("ersion:")) { + part->setVersion(line); + continue; + } + break; + + case 's': + + // summary: + if (line.stripPrefix("ummary:")) { + if (!subMapping) { + kdError() << "No event line found. Skipping '" << _filename << endl; + return false; + } + + part->totals()->set(subMapping, 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; + + kdDebug() << "WARNING: This trace dump was generated by an old " + "version\n of the call-tree skin. Use a new one!" << endl; + + continue; + } + break; + + default: + break; + } + + kdError() << _filename << ":" << _lineNo + << " - Invalid line '" << c << TQString(line) << "'" << endl; + continue; + } + + if (!subMapping) { + kdError() << "No event line found. Skipping '" << _filename << "'" << endl; + return false; + } + + // for a cost line, we always need a current function + ensureFunction(); + + +#if USE_FIXCOST + if (!currentFunctionSource || + (currentFunctionSource->file() != currentFile)) + currentFunctionSource = currentFunction->sourceFile(currentFile, + true); +#else + if (hasAddrInfo) { + if (!currentInstr || + (currentInstr->addr() != currentPos.fromAddr)) { + currentInstr = currentFunction->instr(currentPos.fromAddr, + true); + + if (!currentInstr) { + kdError() << _filename << ":" << _lineNo + << " - Invalid address " + << currentPos.fromAddr.toString() << endl; + + continue; + } + + currentPartInstr = currentInstr->partInstr(part, + currentPartFunction); + } + } + + if (hasLineInfo) { + if (!currentLine || + (currentLine->lineno() != currentPos.fromLine)) { + + currentLine = currentFunction->line(currentFile, + currentPos.fromLine, + true); + currentPartLine = currentLine->partLine(part, + currentPartFunction); + } + if (hasAddrInfo && currentInstr) + currentInstr->setLine(currentLine); + } +#endif + +#if TRACE_LOADER + kdDebug() << _filename << ":" << _lineNo + << endl << " currentInstr " + << (currentInstr ? currentInstr->toString().ascii() : ".") + << endl << " currentLine " + << (currentLine ? currentLine->toString().ascii() : ".") + << "( file " << currentFile->name() << ")" + << endl << " currentFunction " + << currentFunction->prettyName().ascii() + << endl << " currentCalled " + << (currentCalledFunction ? currentCalledFunction->prettyName().ascii() : ".") + << endl; +#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(subMapping, line); + line.set(s,l); + } + else + partInstr->addCost(subMapping, line); + } + + if (hasLineInfo) { + TracePartLine* partLine; + partLine = currentLine->partLine(part, currentPartFunction); + partLine->addCost(subMapping, line); + } +#endif + + if (!line.isEmpty()) { + kdError() << _filename << ":" << _lineNo + << " - Garbage at end of cost line ('" + << TQString(line) << "')" << endl; + } + } + 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()); +#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(subMapping, line); + line.set(s,l); + } + else + partInstrCall->addCost(subMapping, line); + + // update maximum of call cost + _data->callMax()->maxCost(partInstrCall); + } + + if (hasLineInfo) { + TraceLineCall* lineCall; + TracePartLineCall* partLineCall; + + lineCall = calling->lineCall(currentLine); + partLineCall = lineCall->partLineCall(part, partCalling); + + partLineCall->addCallCount(currentCallCount); + partLineCall->addCost(subMapping, line); + + // update maximum of call cost + _data->callMax()->maxCost(partLineCall); + } +#endif + currentCalledFile = 0; + currentCalledPartFile = 0; + currentCalledObject = 0; + currentCalledPartObject = 0; + currentCallCount = 0; + + if (!line.isEmpty()) { + kdError() << _filename << ":" << _lineNo + << " - Garbage at end of call cost line ('" + << TQString(line) << "')" << endl; + } + } + 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); +#endif + + if (0) { + kdDebug() << _filename << ":" << _lineNo + << " - jump from 0x" << currentPos.fromAddr.toString() + << " (line " << currentPos.fromLine + << ") to 0x" << targetPos.fromAddr.toString() + << " (line " << targetPos.fromLine << ")" << endl; + + if (nextLineType == BoringJump) + kdDebug() << " Boring Jump, count " << jumpsExecuted.pretty() << endl; + else + kdDebug() << " Cond. Jump, followed " << jumpsFollowed.pretty() + << ", executed " << jumpsExecuted.pretty() << endl; + } + + nextLineType = SelfCost; + currentJumpToFunction = 0; + currentJumpToFile = 0; + + if (!line.isEmpty()) { + kdError() << _filename << ":" << _lineNo + << " - Garbage at end of jump cost line ('" + << TQString(line) << "')" << endl; + } + + } + } + + + emit updateStatus(statusMsg,100); + + _part->invalidate(); + if (!totalsSet) { + _part->totals()->clear(); + _part->totals()->addCost(_part); + } + + pFile->close(); + + return true; +} + |