31 #define TRACE_LOADER 0
38 class CachegrindLoader:
public Loader
52 enum lineType { SelfCost, CallCost, BoringJump, CondJump };
60 void ensureFunction();
62 void setCalledObject(
const QString&);
64 void setCalledFile(
const QString&);
65 void setFunction(
const QString&);
66 void setCalledFunction(
const QString&);
68 void prepareNewPart();
82 lineType nextLineType;
83 bool hasLineInfo, hasAddrInfo;
113 SubCost jumpsFollowed, jumpsExecuted;
126 void clearCompression();
143 CachegrindLoader::CachegrindLoader()
145 QObject::tr(
"Import filter for Cachegrind/Callgrind generated profile data files") )
150 bool CachegrindLoader::canLoad(
QIODevice* file)
152 if (!file)
return false;
161 int read = file->
read(buf,2047);
167 int pos = s.
indexOf(
"events:");
168 if (pos>0 && buf[pos-1] !=
'\n') pos = -1;
180 l.setLogger(_logger);
182 return l.loadInternal(d, file, filename);
187 return new CachegrindLoader();
190 void CachegrindLoader::error(
QString msg)
192 loadError(_lineNo, msg);
195 void CachegrindLoader::warning(
QString msg)
197 loadWarning(_lineNo, msg);
203 bool CachegrindLoader::parsePosition(
FixString& line,
211 if (!line.
first(c))
return false;
216 newPos.
fromAddr = currentPos.fromAddr;
217 newPos.
toAddr = currentPos.toAddr;
222 newPos.
fromAddr = currentPos.fromAddr + diff;
228 newPos.
fromAddr = currentPos.fromAddr - diff;
246 else if ((c ==
'-') || (c ==
':')) {
267 if (!line.
first(c))
return false;
269 if (c >
'9')
return false;
273 newPos.
fromLine = currentPos.fromLine;
274 newPos.
toLine = currentPos.toLine;
279 newPos.
fromLine = currentPos.fromLine + diff;
285 if (currentPos.fromLine < diff) {
286 error(
QString(
"Negative line number %1")
287 .arg((
int)currentPos.fromLine - (
int)diff));
288 diff = currentPos.fromLine;
290 newPos.
fromLine = currentPos.fromLine - diff;
306 else if ((c ==
'-') || (c ==
':')) {
315 qDebug() <<
" Got Line " << newPos.
fromLine;
317 qDebug() <<
" Got LineRange " << newPos.
fromLine
327 void CachegrindLoader::clearCompression()
330 _objectVector.clear();
332 _functionVector.clear();
335 _objectVector.resize(100);
336 _fileVector.resize(1000);
337 _functionVector.resize(10000);
342 if (n ==
"???")
return _emptyString;
348 if ((name[0] !=
'(') || !name[1].isDigit())
return _data->object(checkUnknown(name));
353 error(
QString(
"Invalid compressed ELF object ('%1')").arg(name));
356 int index = name.
mid(1, p-1).
toInt();
361 if (_objectVector.size() <= index) {
362 int newSize = index * 2;
364 qDebug() <<
" CachegrindLoader: objectVector enlarged to "
367 _objectVector.resize(newSize);
372 if (o && (o->name() != realName)) {
373 error(
QString(
"Redefinition of compressed ELF object index %1 (was '%2') to %3")
374 .arg(index).arg(o->name()).arg(realName));
377 o = _data->object(realName);
378 _objectVector.replace(index, o);
381 if ((_objectVector.size() <= index) ||
382 ( (o=(
TraceObject*)_objectVector.at(index)) == 0)) {
383 error(
QString(
"Undefined compressed ELF object index %1").arg(index));
396 if ((name[0] !=
'(') || !name[1].isDigit())
return _data->file(checkUnknown(name));
401 error(
QString(
"Invalid compressed file ('%1')").arg(name));
409 if (_fileVector.size() <= index) {
410 int newSize = index * 2;
412 qDebug() <<
" CachegrindLoader::fileVector enlarged to "
415 _fileVector.resize(newSize);
420 if (f && (f->name() != realName)) {
421 error(
QString(
"Redefinition of compressed file index %1 (was '%2') to %3")
422 .arg(index).arg(f->name()).arg(realName));
425 f = _data->file(realName);
426 _fileVector.replace(index, f);
429 if ((_fileVector.size() <= index) ||
430 ( (f=(
TraceFile*)_fileVector.at(index)) == 0)) {
431 error(
QString(
"Undefined compressed file index %1").arg(index));
446 if ((name[0] !=
'(') || !name[1].isDigit())
447 return _data->function(checkUnknown(name), file,
object);
452 error(
QString(
"Invalid compressed function ('%1')").arg(name));
462 if (_functionVector.size() <= index) {
463 int newSize = index * 2;
465 qDebug() <<
" CachegrindLoader::functionVector enlarged to "
468 _functionVector.resize(newSize);
473 if (f && (f->name() != realName)) {
474 error(
QString(
"Redefinition of compressed function index %1 (was '%2') to %3")
475 .arg(index).arg(f->name()).arg(realName));
478 f = _data->function(realName, file,
object);
479 _functionVector.replace(index, f);
482 qDebug() <<
"compressedFunction: Inserted at Index " << index
484 <<
"\n in " << f->cls()->fullName()
485 <<
"\n in " << f->file()->fullName()
486 <<
"\n in " << f->object()->fullName();
490 if ((_functionVector.size() <= index) ||
492 error(
QString(
"Undefined compressed function index %1").arg(index));
507 void CachegrindLoader::ensureObject()
509 if (currentObject)
return;
511 currentObject = _data->object(_emptyString);
512 currentPartObject = currentObject->partObject(_part);
515 void CachegrindLoader::setObject(
const QString& name)
517 currentObject = compressedObject(name);
518 if (!currentObject) {
519 error(
QString(
"Invalid ELF object specification, setting to unknown"));
521 currentObject = _data->object(_emptyString);
524 currentPartObject = currentObject->partObject(_part);
526 currentPartFunction = 0;
529 void CachegrindLoader::setCalledObject(
const QString& name)
531 currentCalledObject = compressedObject(name);
533 if (!currentCalledObject) {
534 error(
QString(
"Invalid specification of called ELF object, setting to unknown"));
536 currentCalledObject = _data->object(_emptyString);
539 currentCalledPartObject = currentCalledObject->partObject(_part);
544 void CachegrindLoader::ensureFile()
546 if (currentFile)
return;
548 currentFile = _data->file(_emptyString);
549 currentPartFile = currentFile->partFile(_part);
552 void CachegrindLoader::setFile(
const QString& name)
554 currentFile = compressedFile(name);
557 error(
QString(
"Invalid file specification, setting to unknown"));
559 currentFile = _data->file(_emptyString);
562 currentPartFile = currentFile->partFile(_part);
567 void CachegrindLoader::setCalledFile(
const QString& name)
569 currentCalledFile = compressedFile(name);
571 if (!currentCalledFile) {
572 error(
QString(
"Invalid specification of called file, setting to unknown"));
574 currentCalledFile = _data->file(_emptyString);
577 currentCalledPartFile = currentCalledFile->partFile(_part);
581 void CachegrindLoader::ensureFunction()
583 if (currentFunction)
return;
585 error(
QString(
"Function not specified, setting to unknown"));
590 currentFunction = _data->function(_emptyString,
593 currentPartFunction = currentFunction->partFunction(_part,
598 void CachegrindLoader::setFunction(
const QString& name)
603 currentFunction = compressedFunction( name,
607 if (!currentFunction) {
608 error(
QString(
"Invalid function specification, setting to unknown"));
610 currentFunction = _data->function(_emptyString,
615 currentPartFunction = currentFunction->partFunction(_part,
619 currentFunctionSource = 0;
624 void CachegrindLoader::setCalledFunction(
const QString& name)
627 if (!currentCalledObject) {
628 currentCalledObject = currentObject;
629 currentCalledPartObject = currentPartObject;
632 if (!currentCalledFile) {
634 currentCalledFile = currentFile;
635 currentCalledPartFile = currentPartFile;
638 currentCalledFunction = compressedFunction(name,
640 currentCalledObject);
641 if (!currentCalledFunction) {
642 error(
"Invalid called function, setting to unknown");
644 currentCalledFunction = _data->function(_emptyString,
646 currentCalledObject);
649 currentCalledPartFunction =
650 currentCalledFunction->partFunction(_part,
651 currentCalledPartFile,
652 currentCalledPartObject);
656 void CachegrindLoader::clearPosition()
662 currentPartFunction = 0;
663 currentFunctionSource = 0;
665 currentFunctionFile = 0;
668 currentPartObject = 0;
672 currentPartInstr = 0;
675 currentCalledObject = 0;
676 currentCalledPartObject = 0;
677 currentCalledFile = 0;
678 currentCalledPartFile = 0;
679 currentCalledFunction = 0;
680 currentCalledPartFunction = 0;
681 currentCallCount = 0;
684 currentJumpToFile = 0;
685 currentJumpToFunction = 0;
693 void CachegrindLoader::prepareNewPart()
697 if (mapping == 0)
return;
701 _part->totals()->clear();
702 _part->totals()->addCost(_part);
703 _data->addPart(_part);
711 _part->setName(_filename);
717 int CachegrindLoader::loadInternal(
TraceData* data,
720 if (!data || !device)
return 0;
723 _filename = filename;
726 loadStart(_filename);
728 FixFile file(device, _filename);
729 if (!file.exists()) {
730 loadFinished(
"File does not exist");
734 int statusProgress = 0;
738 FixPool* pool = _data->fixPool();
749 nextLineType = SelfCost;
754 while (file.nextLine(line)) {
759 qDebug() <<
"[CachegrindLoader] " << _filename <<
":" << _lineNo
760 <<
" - '" <<
QString(line) <<
"'";
764 if (!line.
first(c))
continue;
768 if (c ==
'#')
continue;
771 if (!parsePosition(line, currentPos)) {
772 error(
QString(
"Invalid position specification '%1'").arg(line));
792 currentFunctionFile = currentFile;
807 if (currentFile != currentFunctionFile)
808 currentFile = currentFunctionFile;
812 int progress = (int)(100.0 * file.current() / file.len() +.5);
813 if (progress != statusProgress) {
814 statusProgress = progress;
821 loadProgress(statusProgress);
832 setCalledObject(line);
846 setCalledFunction(line);
854 nextLineType = CallCost;
861 if (!_data->command().isEmpty() &&
862 _data->command() != command) {
864 error(
QString(
"Redefined command, was '%1'").arg(_data->command()));
866 _data->setCommand(command);
887 parsePosition(line, targetPos);
890 error(
QString(
"Invalid line after 'jcnd'"));
893 nextLineType = CondJump;
901 parsePosition(line, targetPos);
904 error(
QString(
"Invalid line after 'jump'"));
907 nextLineType = BoringJump;
913 currentJumpToFile = compressedFile(line);
920 if (!currentJumpToFile) {
922 currentJumpToFile = currentFile;
925 currentJumpToFunction =
926 compressedFunction(line,
955 _part->setThreadID(
QString(line).toInt());
961 _part->setTimeframe(line);
976 _part->setTrigger(line);
988 mapping = _data->eventTypes()->createMapping(line);
989 _part->setEventMapping(mapping);
999 error(
QString(
"Invalid event"));
1020 _part->setPartNumber(
QString(line).toInt());
1027 _part->setProcessID(
QString(line).toInt());
1035 hasLineInfo = positions.contains(
"line");
1036 hasAddrInfo = positions.contains(
"instr");
1055 error(
QString(
"No event line found. Skipping file"));
1060 _part->totals()->set(mapping, line);
1071 nextLineType = CallCost;
1073 warning(
QString(
"Old file format using deprecated 'rcalls'"));
1082 error(
QString(
"Invalid line '%1%2'").arg(c).arg(line));
1087 error(
QString(
"No event line found. Skipping file"));
1097 if (!currentFunctionSource ||
1098 (currentFunctionSource->file() != currentFile)) {
1099 currentFunctionSource = currentFunction->sourceFile(currentFile,
1105 if (!currentInstr ||
1106 (currentInstr->addr() != currentPos.fromAddr)) {
1107 currentInstr = currentFunction->instr(currentPos.fromAddr,
1110 if (!currentInstr) {
1111 error(
QString(
"Invalid address '%1'").arg(currentPos.fromAddr.toString()));
1116 currentPartInstr = currentInstr->partInstr(_part,
1117 currentPartFunction);
1123 (currentLine->lineno() != currentPos.fromLine)) {
1125 currentLine = currentFunctionSource->line(currentPos.fromLine,
1127 currentPartLine = currentLine->partLine(_part,
1128 currentPartFunction);
1130 if (hasAddrInfo && currentInstr)
1131 currentInstr->setLine(currentLine);
1136 qDebug() << _filename <<
":" << _lineNo;
1137 qDebug() <<
" currentInstr "
1138 << (currentInstr ? qPrintable(currentInstr->toString()) :
".");
1139 qDebug() <<
" currentLine "
1140 << (currentLine ? qPrintable(currentLine->toString()) :
".")
1141 <<
"( file " << currentFile->name() <<
")";
1142 qDebug() <<
" currentFunction "
1143 << qPrintable(currentFunction->prettyName());
1144 qDebug() <<
" currentCalled "
1145 << (currentCalledFunction ? qPrintable(currentCalledFunction->prettyName()) :
".");
1150 if (nextLineType == SelfCost) {
1153 new (pool)
FixCost(_part, pool,
1154 currentFunctionSource,
1156 currentPartFunction,
1161 partInstr = currentInstr->partInstr(_part, currentPartFunction);
1166 const char* s = line.
ascii();
1168 partInstr->
addCost(mapping, line);
1172 partInstr->
addCost(mapping, line);
1177 partLine = currentLine->partLine(_part, currentPartFunction);
1178 partLine->
addCost(mapping, line);
1183 error(
QString(
"Garbage at end of cost line ('%1')").arg(line));
1186 else if (nextLineType == CallCost) {
1187 nextLineType = SelfCost;
1189 TraceCall* calling = currentFunction->calling(currentCalledFunction);
1191 calling->
partCall(_part, currentPartFunction,
1192 currentCalledPartFunction);
1197 currentFunctionSource,
1198 hasLineInfo ? currentPos.fromLine : 0,
1199 hasAddrInfo ? currentPos.fromAddr :
Addr(0),
1201 currentCallCount, line);
1202 fcc->
setMax(_data->callMax());
1208 instrCall = calling->
instrCall(currentInstr);
1209 partInstrCall = instrCall->
partInstrCall(_part, partCalling);
1215 const char* s = line.
ascii();
1217 partInstrCall->
addCost(mapping, line);
1221 partInstrCall->
addCost(mapping, line);
1224 _data->callMax()->maxCost(partInstrCall);
1231 lineCall = calling->
lineCall(currentLine);
1232 partLineCall = lineCall->
partLineCall(_part, partCalling);
1235 partLineCall->
addCost(mapping, line);
1238 _data->callMax()->maxCost(partLineCall);
1241 currentCalledFile = 0;
1242 currentCalledPartFile = 0;
1243 currentCalledObject = 0;
1244 currentCalledPartObject = 0;
1245 currentCallCount = 0;
1248 error(
QString(
"Garbage at end of call cost line ('%1')").arg(line));
1255 if (!currentJumpToFunction)
1256 currentJumpToFunction = currentFunction;
1258 targetSource = (currentJumpToFile) ?
1259 currentJumpToFunction->sourceFile(currentJumpToFile,
true) :
1260 currentFunctionSource;
1263 new (pool)
FixJump(_part, pool,
1265 hasLineInfo ? currentPos.fromLine : 0,
1266 hasAddrInfo ? currentPos.fromAddr : 0,
1267 currentPartFunction,
1268 currentFunctionSource,
1270 hasLineInfo ? targetPos.fromLine : 0,
1271 hasAddrInfo ? targetPos.fromAddr :
Addr(0),
1272 currentJumpToFunction,
1274 (nextLineType == CondJump),
1275 jumpsExecuted, jumpsFollowed);
1282 jumpToInstr = currentJumpToFunction->instr(targetPos.fromAddr,
1284 instrJump = currentInstr->instrJump(jumpToInstr,
1285 (nextLineType == CondJump));
1288 if (nextLineType == CondJump)
1297 jumpToLine = targetSource->line(targetPos.fromLine,
true);
1298 lineJump = currentLine->lineJump(jumpToLine,
1299 (nextLineType == CondJump));
1303 if (nextLineType == CondJump)
1309 qDebug() << _filename <<
":" << _lineNo
1310 <<
" - jump from 0x" << currentPos.fromAddr.toString()
1311 <<
" (line " << currentPos.fromLine
1312 <<
") to 0x" << targetPos.fromAddr.toString()
1313 <<
" (line " << targetPos.fromLine <<
")";
1315 if (nextLineType == BoringJump)
1316 qDebug() <<
" Boring Jump, count " << jumpsExecuted.pretty();
1318 qDebug() <<
" Cond. Jump, followed " << jumpsFollowed.pretty()
1319 <<
", executed " << jumpsExecuted.pretty();
1322 nextLineType = SelfCost;
1323 currentJumpToFunction = 0;
1324 currentJumpToFile = 0;
1327 error(
QString(
"Garbage at end of jump cost line ('%1')").arg(line));
1336 _part->invalidate();
1337 _part->totals()->clear();
1338 _part->totals()->addCost(_part);
Loader * createCachegrindLoader()
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
A source file containing function definitions.
void stripSpaces()
Strip leading spaces.
bool stripUInt(uint &, bool stripSpaces=true)
Cost of a call at a line from a trace file.
void addCallCount(SubCost c)
unsigned long long uint64
QByteArray fromRawData(const char *data, int size)
A call from an instruction of one function to another function.
To implement a new loader, inherit from the Loader class and and reimplement canLoad() and load()...
A call from a line of one function to another function.
virtual bool canLoad(QIODevice *file)
TracePartInstrJump * partInstrJump(TracePart *)
A index list into a EventTypeSet.
Addresses are 64bit values like costs to be able to always load profile data produced on 64bit archit...
A object containing a text segment (shared lib/executable) with defined functions.
TraceInstrCall * instrCall(TraceInstr *)
A class for fast line by line reading of a read-only ASCII file.
Cost of a call at a instruction code address from a trace file.
void stripSurroundingSpaces()
Strip leading and trailing spaces.
A class holding an unchangable cost item of an input file.
int indexOf(char ch, int from) const
TracePartInstrCall * partInstrCall(TracePart *, TracePartCall *)
A code instruction address of the program.
int toInt(bool *ok, int base) const
QString fullName() const
Returns type name + dynamic name.
TracePartCall * partCall(TracePart *, TracePartFunction *, TracePartFunction *)
A container helper class for TraceFunction for source lines where a function is implemented in...
Cost of a line from a trace file.
void setMax(ProfileCostArray *)
qint64 read(char *data, qint64 maxSize)
A simple, constant string class.
A source line of the program.
Cost of a function, from a single trace file.
Cost of a call at a function to another function, from a single trace file.
bool stripName(FixString &)
Strip name: [A-Za-z_][0-9A_Za-z_]*.
void addFollowedCount(SubCost c)
TraceLineCall * lineCall(TraceLine *)
Cost of a code instruction address from a trace file.
A Trace Part: All data read from a trace file, containing all costs that happened in a specified time...
bool stripPrefix(const char *)
void set(const char *s, int l)
A jump from an instruction to another inside of a function.
FixString stripUntil(char)
Strip string until char appears or end.
QString mid(int position, int n) const
static void add(EventType *, bool overwriteExisting=true)
A class holding a jump (mostly) inside of a function.
Cost of jump at a instruction code address from a trace file.
Cost event counter, simple wrapper around a 64bit entity.
Cost of a source file, from a single trace file.
const QChar at(int position) const
Cost of jump at a source line from a trace file.
void addCost(EventTypeMapping *, const char *)
bool stripUInt64(uint64 &, bool stripSpaces=true)
virtual int load(TraceData *, QIODevice *file, const QString &filename)
void addExecutedCount(SubCost c)
TracePartLineCall * partLineCall(TracePart *, TracePartCall *)
This class holds profiling data of multiple tracefiles generated with cachegrind on one command...
TracePartLineJump * partLineJump(TracePart *)
A call from one to another function.
void addPart(TracePart *)
A jump from one line to another inside of a function.
Cost of a object, from a single trace file.
uint toUInt(bool *ok, int base) const
A FixCallCost will be inserted into a.