QmlProfiler: fix crash in binding loop detection

The cause of the crash was that animation events are a special case
inside the profile data model, and some parts of the statistics
computation were not taking that circumstance into account.

Change-Id: Ibec929abb18fcdd8af4ddb5ff40b125915746725
Reviewed-by: Kai Koehne <kai.koehne@nokia.com>
This commit is contained in:
Christiaan Janssen
2012-03-26 13:10:44 +02:00
parent fc829b2303
commit 0009bf8e2b

View File

@@ -127,6 +127,8 @@ struct QmlRangeEventStartInstance {
qint64 nestingDepth; qint64 nestingDepth;
QmlRangeEventData *statsInfo; QmlRangeEventData *statsInfo;
int baseEventIndex;
// animation-related data // animation-related data
int frameRate; int frameRate;
int animationCount; int animationCount;
@@ -359,6 +361,7 @@ void QmlProfilerDataModel::addRangedEvent(int type, qint64 startTime, qint64 len
startTimeData.endTimeIndex = d->endInstanceList.count(); startTimeData.endTimeIndex = d->endInstanceList.count();
startTimeData.animationCount = -1; startTimeData.animationCount = -1;
startTimeData.frameRate = 1e9/length; startTimeData.frameRate = 1e9/length;
startTimeData.baseEventIndex = d->startInstanceList.count(); // point to itself by default
d->endInstanceList << endTimeData; d->endInstanceList << endTimeData;
d->startInstanceList << startTimeData; d->startInstanceList << startTimeData;
@@ -416,6 +419,7 @@ void QmlProfilerDataModel::addFrameEvent(qint64 time, int framerate, int animati
startTimeData.endTimeIndex = d->endInstanceList.count(); startTimeData.endTimeIndex = d->endInstanceList.count();
startTimeData.animationCount = animationcount; startTimeData.animationCount = animationcount;
startTimeData.frameRate = framerate; startTimeData.frameRate = framerate;
startTimeData.baseEventIndex = d->startInstanceList.count(); // point to itself by default
d->endInstanceList << endTimeData; d->endInstanceList << endTimeData;
d->startInstanceList << startTimeData; d->startInstanceList << startTimeData;
@@ -537,13 +541,8 @@ int QmlProfilerDataModel::findFirstIndex(qint64 startTime) const
candidate = toIndex; candidate = toIndex;
} }
int ndx = d->endInstanceList[candidate].startTimeIndex; int eventIndex = d->endInstanceList[candidate].startTimeIndex;
return d->startInstanceList[eventIndex].baseEventIndex;
// and then go to the parent
while (ndx > 0 && d->startInstanceList[ndx].level > d->startInstanceList[ndx-1].level )
ndx--;
return ndx;
} }
int QmlProfilerDataModel::findFirstIndexNoParents(qint64 startTime) const int QmlProfilerDataModel::findFirstIndexNoParents(qint64 startTime) const
@@ -969,6 +968,8 @@ void QmlProfilerDataModel::QmlProfilerDataModelPrivate::computeNestingLevels()
QList< QHash<int, qint64> > endtimesPerNestingLevel; QList< QHash<int, qint64> > endtimesPerNestingLevel;
int level = Constants::QML_MIN_LEVEL; int level = Constants::QML_MIN_LEVEL;
endtimesPerLevel[Constants::QML_MIN_LEVEL] = 0; endtimesPerLevel[Constants::QML_MIN_LEVEL] = 0;
int lastBaseEventIndex = 0;
qint64 lastBaseEventEndTime = traceStartTime;
for (int i = 0; i < QmlJsDebugClient::MaximumQmlEventType; i++) { for (int i = 0; i < QmlJsDebugClient::MaximumQmlEventType; i++) {
nestingLevels << Constants::QML_MIN_LEVEL; nestingLevels << Constants::QML_MIN_LEVEL;
@@ -986,6 +987,11 @@ void QmlProfilerDataModel::QmlProfilerDataModelPrivate::computeNestingLevels()
// but are not considered parents of other events for statistical purposes // but are not considered parents of other events for statistical purposes
startInstanceList[i].level = Constants::QML_MIN_LEVEL - 1; startInstanceList[i].level = Constants::QML_MIN_LEVEL - 1;
startInstanceList[i].nestingLevel = Constants::QML_MIN_LEVEL; startInstanceList[i].nestingLevel = Constants::QML_MIN_LEVEL;
if (lastBaseEventEndTime < startInstanceList[i].startTime) {
lastBaseEventIndex = i;
lastBaseEventEndTime = startInstanceList[i].startTime + startInstanceList[i].duration;
}
startInstanceList[i].baseEventIndex = lastBaseEventIndex;
continue; continue;
} }
@@ -1014,8 +1020,13 @@ void QmlProfilerDataModel::QmlProfilerDataModelPrivate::computeNestingLevels()
if (level == Constants::QML_MIN_LEVEL) { if (level == Constants::QML_MIN_LEVEL) {
qmlMeasuredTime += startInstanceList[i].duration; qmlMeasuredTime += startInstanceList[i].duration;
if (lastBaseEventEndTime < startInstanceList[i].startTime) {
lastBaseEventIndex = i;
lastBaseEventEndTime = startInstanceList[i].startTime + startInstanceList[i].duration;
} }
} }
startInstanceList[i].baseEventIndex = lastBaseEventIndex;
}
} }
void QmlProfilerDataModel::QmlProfilerDataModelPrivate::computeNestingDepth() void QmlProfilerDataModel::QmlProfilerDataModelPrivate::computeNestingDepth()
@@ -1208,6 +1219,10 @@ void QmlProfilerDataModel::QmlProfilerDataModelPrivate::findBindingLoops(qint64
QmlRangeEventStartInstance *inTimeEvent = &startInstanceList[i]; QmlRangeEventStartInstance *inTimeEvent = &startInstanceList[i];
inTimeEvent->bindingLoopHead = -1; inTimeEvent->bindingLoopHead = -1;
// special: skip animation events (but not old paint events)
if (inTimeEvent->statsInfo->eventType == Painting && inTimeEvent->animationCount >= 0)
continue;
// managing call stack // managing call stack
for (int j = stack.count() - 1; j >= 0; j--) { for (int j = stack.count() - 1; j >= 0; j--) {
if (stack[j]->startTime + stack[j]->duration <= inTimeEvent->startTime) { if (stack[j]->startTime + stack[j]->duration <= inTimeEvent->startTime) {