QmlProfiler: display animation traces from Qt5

Change-Id: I7959052ec07089419e85186b0b0e58f911e273ec
Reviewed-by: Kai Koehne <kai.koehne@nokia.com>
This commit is contained in:
Christiaan Janssen
2011-12-14 16:44:33 +01:00
parent af6e06dfb2
commit 52b3138a38
8 changed files with 190 additions and 8 deletions

View File

@@ -180,6 +180,9 @@ struct QmlEventStartTimeData {
qint64 nestingDepth; qint64 nestingDepth;
QmlEventData *description; QmlEventData *description;
// animation-related data
int frameRate;
int animationCount;
}; };
struct QmlEventTypeCount { struct QmlEventTypeCount {
@@ -281,6 +284,10 @@ public:
qint64 m_qmlMeasuredTime; qint64 m_qmlMeasuredTime;
qint64 m_v8MeasuredTime; qint64 m_v8MeasuredTime;
QmlEventStartTimeData *m_lastFrameEvent;
qint64 m_maximumAnimationCount;
qint64 m_minimumAnimationCount;
// file to load // file to load
QString m_filename; QString m_filename;
}; };
@@ -302,7 +309,9 @@ QmlProfilerEventList::QmlProfilerEventList(QObject *parent) :
d->m_rootEventDesc = tr("Main Program"); d->m_rootEventDesc = tr("Main Program");
d->clearQmlRootEvent(); d->clearQmlRootEvent();
d->clearV8RootEvent(); d->clearV8RootEvent();
d->m_lastFrameEvent = 0;
d->m_maximumAnimationCount = 0;
d->m_minimumAnimationCount = 0;
} }
QmlProfilerEventList::~QmlProfilerEventList() QmlProfilerEventList::~QmlProfilerEventList()
@@ -335,6 +344,10 @@ void QmlProfilerEventList::clear()
d->m_qmlMeasuredTime = 0; d->m_qmlMeasuredTime = 0;
d->m_v8MeasuredTime = 0; d->m_v8MeasuredTime = 0;
d->m_lastFrameEvent = 0;
d->m_maximumAnimationCount = 0;
d->m_minimumAnimationCount = 0;
emit countChanged(); emit countChanged();
emit dataClear(); emit dataClear();
} }
@@ -423,6 +436,8 @@ void QmlProfilerEventList::addRangedEvent(int type, qint64 startTime, qint64 len
startTimeData.length = length; startTimeData.length = length;
startTimeData.description = newEvent; startTimeData.description = newEvent;
startTimeData.endTimeIndex = d->m_endTimeSortedList.count(); startTimeData.endTimeIndex = d->m_endTimeSortedList.count();
startTimeData.animationCount = -1;
startTimeData.frameRate = 1e9/length;
d->m_endTimeSortedList << endTimeData; d->m_endTimeSortedList << endTimeData;
d->m_startTimeSortedList << startTimeData; d->m_startTimeSortedList << startTimeData;
@@ -494,6 +509,58 @@ void QmlProfilerEventList::addV8Event(int depth, const QString &function, const
} }
} }
void QmlProfilerEventList::addFrameEvent(qint64 time, int framerate, int animationcount)
{
QString displayName, eventHashStr, details;
emit processingData();
details = tr("Animation Timer Update");
displayName = tr("<Animation Update>");
eventHashStr = displayName;
QmlEventData *newEvent;
if (d->m_eventDescriptions.contains(eventHashStr)) {
newEvent = d->m_eventDescriptions[eventHashStr];
} else {
newEvent = new QmlEventData;
newEvent->displayname = displayName;
newEvent->filename = QString();
newEvent->eventHashStr = eventHashStr;
newEvent->line = -1;
newEvent->eventType = QmlJsDebugClient::Painting;
newEvent->details = details;
d->m_eventDescriptions.insert(eventHashStr, newEvent);
}
qint64 length = 1e9/framerate;
// avoid overlap
if (d->m_lastFrameEvent && d->m_lastFrameEvent->startTime + d->m_lastFrameEvent->length >= time) {
d->m_lastFrameEvent->length = time - 1 - d->m_lastFrameEvent->startTime;
d->m_endTimeSortedList[d->m_lastFrameEvent->endTimeIndex].endTime = d->m_lastFrameEvent->startTime + d->m_lastFrameEvent->length;
}
QmlEventEndTimeData endTimeData;
endTimeData.endTime = time + length;
endTimeData.description = newEvent;
endTimeData.startTimeIndex = d->m_startTimeSortedList.count();
QmlEventStartTimeData startTimeData;
startTimeData.startTime = time;
startTimeData.length = length;
startTimeData.description = newEvent;
startTimeData.endTimeIndex = d->m_endTimeSortedList.count();
startTimeData.animationCount = animationcount;
startTimeData.frameRate = framerate;
d->m_endTimeSortedList << endTimeData;
d->m_startTimeSortedList << startTimeData;
d->m_lastFrameEvent = &d->m_startTimeSortedList.last();
emit countChanged();
}
void QmlProfilerEventList::QmlProfilerEventListPrivate::collectV8Statistics() void QmlProfilerEventList::QmlProfilerEventListPrivate::collectV8Statistics()
{ {
if (!m_v8EventList.isEmpty()) { if (!m_v8EventList.isEmpty()) {
@@ -634,6 +701,11 @@ void QmlProfilerEventList::compileStatistics(qint64 startTime, qint64 endTime)
continue; continue;
} }
if (eventDescription->eventType == QmlJsDebugClient::Painting && d->m_startTimeSortedList[index].animationCount >=0) {
// skip animation events
continue;
}
eventDescription->calls++; eventDescription->calls++;
qint64 duration = d->m_startTimeSortedList[index].length; qint64 duration = d->m_startTimeSortedList[index].length;
eventDescription->duration += duration; eventDescription->duration += duration;
@@ -831,6 +903,30 @@ void QmlProfilerEventList::sortEndTimes()
d->m_startTimeSortedList[d->m_endTimeSortedList[i].startTimeIndex].endTimeIndex = i; d->m_startTimeSortedList[d->m_endTimeSortedList[i].startTimeIndex].endTimeIndex = i;
} }
void QmlProfilerEventList::findAnimationLimits()
{
d->m_maximumAnimationCount = 0;
d->m_minimumAnimationCount = 0;
d->m_lastFrameEvent = 0;
for (int i = 0; i < d->m_startTimeSortedList.count(); i++) {
if (d->m_startTimeSortedList[i].description->eventType == QmlJsDebugClient::Painting &&
d->m_startTimeSortedList[i].animationCount >= 0) {
int animationcount = d->m_startTimeSortedList[i].animationCount;
if (d->m_lastFrameEvent) {
if (animationcount > d->m_maximumAnimationCount)
d->m_maximumAnimationCount = animationcount;
if (animationcount < d->m_minimumAnimationCount)
d->m_minimumAnimationCount = animationcount;
} else {
d->m_maximumAnimationCount = animationcount;
d->m_minimumAnimationCount = animationcount;
}
d->m_lastFrameEvent = &d->m_startTimeSortedList[i];
}
}
}
void QmlProfilerEventList::computeNestingLevels() void QmlProfilerEventList::computeNestingLevels()
{ {
// compute levels // compute levels
@@ -903,10 +999,11 @@ void QmlProfilerEventList::postProcess()
if (count() != 0) { if (count() != 0) {
sortStartTimes(); sortStartTimes();
sortEndTimes(); sortEndTimes();
findAnimationLimits();
computeLevels(); computeLevels();
linkEndsToStarts(); linkEndsToStarts();
prepareForDisplay();
compileStatistics(traceStartTime(), traceEndTime()); compileStatistics(traceStartTime(), traceEndTime());
prepareForDisplay();
} }
// data is ready even when there's no data // data is ready even when there's no data
emit dataReady(); emit dataReady();
@@ -1116,6 +1213,11 @@ bool QmlProfilerEventList::save(const QString &filename)
stream.writeAttribute("startTime", QString::number(rangedEvent.startTime)); stream.writeAttribute("startTime", QString::number(rangedEvent.startTime));
stream.writeAttribute("duration", QString::number(rangedEvent.length)); stream.writeAttribute("duration", QString::number(rangedEvent.length));
stream.writeAttribute("eventIndex", QString::number(d->m_eventDescriptions.keys().indexOf(rangedEvent.description->eventHashStr))); stream.writeAttribute("eventIndex", QString::number(d->m_eventDescriptions.keys().indexOf(rangedEvent.description->eventHashStr)));
if (rangedEvent.description->eventType == QmlJsDebugClient::Painting && rangedEvent.animationCount >= 0) {
// animation frame
stream.writeAttribute("framerate", QString::number(rangedEvent.frameRate));
stream.writeAttribute("animationcount", QString::number(rangedEvent.animationCount));
}
stream.writeEndElement(); stream.writeEndElement();
} }
stream.writeEndElement(); // eventList stream.writeEndElement(); // eventList
@@ -1254,6 +1356,10 @@ void QmlProfilerEventList::load()
rangedEvent.startTime = attributes.value("startTime").toString().toLongLong(); rangedEvent.startTime = attributes.value("startTime").toString().toLongLong();
if (attributes.hasAttribute("duration")) if (attributes.hasAttribute("duration"))
rangedEvent.length = attributes.value("duration").toString().toLongLong(); rangedEvent.length = attributes.value("duration").toString().toLongLong();
if (attributes.hasAttribute("framerate"))
rangedEvent.frameRate = attributes.value("framerate").toString().toInt();
if (attributes.hasAttribute("animationcount"))
rangedEvent.animationCount = attributes.value("animationcount").toString().toInt();
if (attributes.hasAttribute("eventIndex")) { if (attributes.hasAttribute("eventIndex")) {
int ndx = attributes.value("eventIndex").toString().toInt(); int ndx = attributes.value("eventIndex").toString().toInt();
if (!descriptionBuffer.value(ndx)) if (!descriptionBuffer.value(ndx))
@@ -1513,6 +1619,12 @@ int QmlProfilerEventList::getLine(int index) const {
} }
QString QmlProfilerEventList::getDetails(int index) const { QString QmlProfilerEventList::getDetails(int index) const {
// special: animations
if (d->m_startTimeSortedList[index].description->eventType == QmlJsDebugClient::Painting &&
d->m_startTimeSortedList[index].animationCount >= 0)
return tr("%1 animations at %2 FPS").arg(
QString::number(d->m_startTimeSortedList[index].animationCount),
QString::number(d->m_startTimeSortedList[index].frameRate));
return d->m_startTimeSortedList[index].description->details; return d->m_startTimeSortedList[index].description->details;
} }
@@ -1520,6 +1632,26 @@ int QmlProfilerEventList::getEventId(int index) const {
return d->m_startTimeSortedList[index].description->eventId; return d->m_startTimeSortedList[index].description->eventId;
} }
int QmlProfilerEventList::getFramerate(int index) const
{
return d->m_startTimeSortedList[index].frameRate;
}
int QmlProfilerEventList::getAnimationCount(int index) const
{
return d->m_startTimeSortedList[index].animationCount;
}
int QmlProfilerEventList::getMaximumAnimationCount() const
{
return d->m_maximumAnimationCount;
}
int QmlProfilerEventList::getMinimumAnimationCount() const
{
return d->m_minimumAnimationCount;
}
int QmlProfilerEventList::uniqueEventsOfType(int type) const { int QmlProfilerEventList::uniqueEventsOfType(int type) const {
if (!d->m_typeCounts.contains(type)) if (!d->m_typeCounts.contains(type))
return 0; return 0;

View File

@@ -141,6 +141,10 @@ public:
Q_INVOKABLE int getLine(int index) const; Q_INVOKABLE int getLine(int index) const;
Q_INVOKABLE QString getDetails(int index) const; Q_INVOKABLE QString getDetails(int index) const;
Q_INVOKABLE int getEventId(int index) const; Q_INVOKABLE int getEventId(int index) const;
Q_INVOKABLE int getFramerate(int index) const;
Q_INVOKABLE int getAnimationCount(int index) const;
Q_INVOKABLE int getMaximumAnimationCount() const;
Q_INVOKABLE int getMinimumAnimationCount() const;
// per-type data // per-type data
Q_INVOKABLE int uniqueEventsOfType(int type) const; Q_INVOKABLE int uniqueEventsOfType(int type) const;
@@ -172,6 +176,7 @@ public slots:
void complete(); void complete();
void addV8Event(int depth,const QString &function,const QString &filename, int lineNumber, double totalTime, double selfTime); void addV8Event(int depth,const QString &function,const QString &filename, int lineNumber, double totalTime, double selfTime);
void addFrameEvent(qint64 time, int framerate, int animationcount);
bool save(const QString &filename); bool save(const QString &filename);
void load(const QString &filename); void load(const QString &filename);
void setFilename(const QString &filename); void setFilename(const QString &filename);
@@ -183,6 +188,7 @@ public slots:
private: private:
void postProcess(); void postProcess();
void sortEndTimes(); void sortEndTimes();
void findAnimationLimits();
void sortStartTimes(); void sortStartTimes();
void computeLevels(); void computeLevels();
void computeNestingLevels(); void computeNestingLevels();

View File

@@ -151,6 +151,12 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
if (event == EndTrace) { if (event == EndTrace) {
emit this->traceFinished(time); emit this->traceFinished(time);
d->maximumTime = time; d->maximumTime = time;
d->maximumTime = qMax(time, d->maximumTime);
} else if (event == AnimationFrame) {
int frameRate, animationCount;
stream >> frameRate >> animationCount;
emit this->frame(time, frameRate, animationCount);
d->maximumTime = qMax(time, d->maximumTime);
} else if (event == StartTrace) { } else if (event == StartTrace) {
emit this->traceStarted(time); emit this->traceStarted(time);
d->maximumTime = time; d->maximumTime = time;

View File

@@ -101,6 +101,7 @@ signals:
void traceStarted( qint64 time ); void traceStarted( qint64 time );
void range(int type, qint64 startTime, qint64 length, void range(int type, qint64 startTime, qint64 length,
const QStringList &data, const QString &fileName, int line); const QStringList &data, const QString &fileName, int line);
void frame(qint64 time, int frameRate, int animationCount);
void recordingChanged(bool arg); void recordingChanged(bool arg);

View File

@@ -73,9 +73,25 @@ function drawData(canvas, ctxt, region)
xx = Math.round(xx); xx = Math.round(xx);
var ty = qmlEventList.getType(ii); var ty = qmlEventList.getType(ii);
if (xx + eventWidth > highest[ty]) { if (xx + eventWidth > highest[ty]) {
// special: animations
if (ty === 0 && qmlEventList.getAnimationCount(ii) >= 0) {
var vertScale = qmlEventList.getMaximumAnimationCount() - qmlEventList.getMinimumAnimationCount();
if (vertScale < 1)
vertScale = 1;
var fraction = (qmlEventList.getAnimationCount(ii) - qmlEventList.getMinimumAnimationCount()) / vertScale;
var eventHeight = blockHeight * (fraction * 0.85 + 0.15);
var yy = bump + ty*blockHeight + blockHeight - eventHeight;
var fpsFraction = qmlEventList.getFramerate(ii) / 60.0;
if (fpsFraction > 1.0)
fpsFraction = 1.0;
ctxt.fillStyle = "hsl("+(fpsFraction*0.27+0.028)+",0.3,0.65)";
ctxt.fillRect(xx, yy, eventWidth, eventHeight);
} else {
var hue = ( qmlEventList.getEventId(ii) * 25 ) % 360; var hue = ( qmlEventList.getEventId(ii) * 25 ) % 360;
ctxt.fillStyle = "hsl("+(hue/360.0+0.001)+",0.3,0.65)"; ctxt.fillStyle = "hsl("+(hue/360.0+0.001)+",0.3,0.65)";
ctxt.fillRect(xx, bump + ty*blockHeight, eventWidth, blockHeight); ctxt.fillRect(xx, bump + ty*blockHeight, eventWidth, blockHeight);
}
highest[ty] = xx+eventWidth; highest[ty] = xx+eventWidth;
} }
} }

View File

@@ -123,9 +123,10 @@ QColor TimelineView::colorForItem(int itemIndex)
void TimelineView::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex) void TimelineView::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
{ {
int x,y,width,rowNumber, eventType; int x, y, width, height, rowNumber, eventType;
for (int i = fromIndex; i <= toIndex; i++) { for (int i = fromIndex; i <= toIndex; i++) {
x = (m_eventList->getStartTime(i) - m_startTime) * m_spacing; x = (m_eventList->getStartTime(i) - m_startTime) * m_spacing;
eventType = m_eventList->getType(i); eventType = m_eventList->getType(i);
if (m_rowsExpanded[eventType]) if (m_rowsExpanded[eventType])
y = m_rowStarts[eventType] + DefaultRowHeight*(m_eventList->eventPosInType(i) + 1); y = m_rowStarts[eventType] + DefaultRowHeight*(m_eventList->eventPosInType(i) + 1);
@@ -141,8 +142,25 @@ void TimelineView::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
continue; continue;
m_rowLastX[rowNumber] = x+width; m_rowLastX[rowNumber] = x+width;
// special: animations
if (eventType == 0 && m_eventList->getAnimationCount(i) >= 0) {
double scale = m_eventList->getMaximumAnimationCount() - m_eventList->getMinimumAnimationCount();
if (scale < 1)
scale = 1;
double fraction = (double)(m_eventList->getAnimationCount(i) - m_eventList->getMinimumAnimationCount()) / scale;
height = DefaultRowHeight * (fraction * 0.85 + 0.15);
y += DefaultRowHeight - height;
double fpsFraction = m_eventList->getFramerate(i) / 60.0;
if (fpsFraction > 1.0)
fpsFraction = 1.0;
p->setBrush(QColor::fromHsl((fpsFraction*96)+10, 76, 166));
p->drawRect(x, y, width, height);
} else {
// normal events
p->setBrush(colorForItem(i)); p->setBrush(colorForItem(i));
p->drawRect(x,y,width,DefaultRowHeight); p->drawRect(x, y, width, DefaultRowHeight);
}
} }
} }

View File

@@ -137,6 +137,7 @@ TraceWindow::TraceWindow(QWidget *parent)
connect(this,SIGNAL(range(int,qint64,qint64,QStringList,QString,int)), m_eventList, SLOT(addRangedEvent(int,qint64,qint64,QStringList,QString,int))); connect(this,SIGNAL(range(int,qint64,qint64,QStringList,QString,int)), m_eventList, SLOT(addRangedEvent(int,qint64,qint64,QStringList,QString,int)));
connect(this, SIGNAL(traceFinished(qint64)), m_eventList, SLOT(setTraceEndTime(qint64))); connect(this, SIGNAL(traceFinished(qint64)), m_eventList, SLOT(setTraceEndTime(qint64)));
connect(this, SIGNAL(traceStarted(qint64)), m_eventList, SLOT(setTraceStartTime(qint64))); connect(this, SIGNAL(traceStarted(qint64)), m_eventList, SLOT(setTraceStartTime(qint64)));
connect(this, SIGNAL(frameEvent(qint64,int,int)), m_eventList, SLOT(addFrameEvent(qint64,int,int)));
connect(this,SIGNAL(viewUpdated()), m_eventList, SLOT(complete())); connect(this,SIGNAL(viewUpdated()), m_eventList, SLOT(complete()));
m_mainView->rootContext()->setContextProperty("qmlEventList", m_eventList); m_mainView->rootContext()->setContextProperty("qmlEventList", m_eventList);
m_overview->rootContext()->setContextProperty("qmlEventList", m_eventList); m_overview->rootContext()->setContextProperty("qmlEventList", m_eventList);
@@ -311,6 +312,7 @@ void TraceWindow::connectClientSignals()
this, SIGNAL(range(int,qint64,qint64,QStringList,QString,int))); this, SIGNAL(range(int,qint64,qint64,QStringList,QString,int)));
connect(m_plugin.data(), SIGNAL(traceFinished(qint64)), this, SIGNAL(traceFinished(qint64))); connect(m_plugin.data(), SIGNAL(traceFinished(qint64)), this, SIGNAL(traceFinished(qint64)));
connect(m_plugin.data(), SIGNAL(traceStarted(qint64)), this, SIGNAL(traceStarted(qint64))); connect(m_plugin.data(), SIGNAL(traceStarted(qint64)), this, SIGNAL(traceStarted(qint64)));
connect(m_plugin.data(), SIGNAL(frame(qint64,int,int)), this, SIGNAL(frameEvent(qint64,int,int)));
connect(m_plugin.data(), SIGNAL(enabledChanged()), this, SLOT(updateProfilerState())); connect(m_plugin.data(), SIGNAL(enabledChanged()), this, SLOT(updateProfilerState()));
connect(m_plugin.data(), SIGNAL(enabledChanged()), m_plugin.data(), SLOT(sendRecordingStatus())); connect(m_plugin.data(), SIGNAL(enabledChanged()), m_plugin.data(), SLOT(sendRecordingStatus()));
} }

View File

@@ -136,6 +136,7 @@ signals:
int lineNumber, double totalTime, double selfTime); int lineNumber, double totalTime, double selfTime);
void traceFinished(qint64); void traceFinished(qint64);
void traceStarted(qint64); void traceStarted(qint64);
void frameEvent(qint64, int, int);
void internalClearDisplay(); void internalClearDisplay();
void jumpToPrev(); void jumpToPrev();