aboutsummaryrefslogtreecommitdiffstats
path: root/tools/qmlprofiler/profiledata.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/qmlprofiler/profiledata.cpp')
-rw-r--r--tools/qmlprofiler/profiledata.cpp1902
1 files changed, 0 insertions, 1902 deletions
diff --git a/tools/qmlprofiler/profiledata.cpp b/tools/qmlprofiler/profiledata.cpp
deleted file mode 100644
index 6082f4aa94..0000000000
--- a/tools/qmlprofiler/profiledata.cpp
+++ /dev/null
@@ -1,1902 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "profiledata.h"
-#include "constants.h"
-
-#include <QtCore/QStringList>
-#include <QtCore/QRegExp>
-#include <QtCore/QUrl>
-#include <QtCore/QFile>
-#include <QtCore/QXmlStreamReader>
-
-using namespace Constants;
-
-QmlEvent::QmlEvent()
-{
- eventType = QQmlProfilerService::MaximumRangeType;
- eventId = -1;
- duration = 0;
- calls = 0;
- minTime = 0;
- maxTime = 0;
- timePerCall = 0;
- percentOfTime = 0;
- medianTime = 0;
- isBindingLoop = false;
-}
-
-QmlEvent::~QmlEvent()
-{
- qDeleteAll(parentHash.values());
- parentHash.clear();
- qDeleteAll(childrenHash.values());
- childrenHash.clear();
-}
-
-QmlEvent &QmlEvent::operator=(const QmlEvent &ref)
-{
- if (this == &ref)
- return *this;
-
- displayname = ref.displayname;
- location = ref.location;
- eventHashStr = ref.eventHashStr;
- details = ref.details;
- eventType = ref.eventType;
- duration = ref.duration;
- calls = ref.calls;
- minTime = ref.minTime;
- maxTime = ref.maxTime;
- timePerCall = ref.timePerCall;
- percentOfTime = ref.percentOfTime;
- medianTime = ref.medianTime;
- eventId = ref.eventId;
- isBindingLoop = ref.isBindingLoop;
-
- qDeleteAll(parentHash.values());
- parentHash.clear();
- foreach (const QString &key, ref.parentHash.keys()) {
- parentHash.insert(key,
- new QmlEventSub(ref.parentHash.value(key)));
- }
-
- qDeleteAll(childrenHash.values());
- childrenHash.clear();
- foreach (const QString &key, ref.childrenHash.keys()) {
- childrenHash.insert(key,
- new QmlEventSub(ref.childrenHash.value(key)));
- }
-
- return *this;
-}
-
-V8Event::V8Event()
-{
- line = -1;
- eventId = -1;
- totalTime = 0;
- selfTime = 0;
- totalPercent = 0;
- selfPercent = 0;
-}
-
-V8Event::~V8Event()
-{
- qDeleteAll(parentHash.values());
- parentHash.clear();
- qDeleteAll(childrenHash.values());
- childrenHash.clear();
-}
-
-V8Event &V8Event::operator=(const V8Event &ref)
-{
- if (this == &ref)
- return *this;
-
- displayName = ref.displayName;
- filename = ref.filename;
- functionName = ref.functionName;
- line = ref.line;
- totalTime = ref.totalTime;
- totalPercent = ref.totalPercent;
- selfTime = ref.selfTime;
- selfPercent = ref.selfPercent;
- eventId = ref.eventId;
-
- qDeleteAll(parentHash.values());
- parentHash.clear();
- foreach (const QString &key, ref.parentHash.keys()) {
- parentHash.insert(key, new V8EventSub(ref.parentHash.value(key)));
- }
-
- qDeleteAll(childrenHash.values());
- childrenHash.clear();
- foreach (const QString &key, ref.childrenHash.keys()) {
- childrenHash.insert(key, new V8EventSub(ref.childrenHash.value(key)));
- }
- return *this;
-}
-
-// endtimedata
-struct QmlEventEndTime {
- qint64 endTime;
- int startTimeIndex;
- QmlEvent *description;
-};
-
-// starttimedata
-struct QmlEventStartTime{
- qint64 startTime;
- qint64 length;
- qint64 level;
- int endTimeIndex;
- qint64 nestingLevel;
- qint64 nestingDepth;
- QmlEvent *description;
-
- // animation-related data
- int frameRate;
- int animationCount;
-
- int bindingLoopHead;
-};
-
-struct QmlEventTypeCount {
- QList <int> eventIds;
- int nestingCount;
-};
-
-// used by quicksort
-bool compareEndTimes(const QmlEventEndTime &t1,
- const QmlEventEndTime &t2)
-{
- return t1.endTime < t2.endTime;
-}
-
-bool compareStartTimes(const QmlEventStartTime &t1,
- const QmlEventStartTime &t2)
-{
- return t1.startTime < t2.startTime;
-}
-
-bool compareStartIndexes(const QmlEventEndTime &t1,
- const QmlEventEndTime &t2)
-{
- return t1.startTimeIndex < t2.startTimeIndex;
-}
-
-QString qmlEventType(QQmlProfilerService::RangeType typeEnum)
-{
- switch (typeEnum) {
- case QQmlProfilerService::Painting:
- return QLatin1String(TYPE_PAINTING_STR);
- break;
- case QQmlProfilerService::Compiling:
- return QLatin1String(TYPE_COMPILING_STR);
- break;
- case QQmlProfilerService::Creating:
- return QLatin1String(TYPE_CREATING_STR);
- break;
- case QQmlProfilerService::Binding:
- return QLatin1String(TYPE_BINDING_STR);
- break;
- case QQmlProfilerService::HandlingSignal:
- return QLatin1String(TYPE_HANDLINGSIGNAL_STR);
- break;
- default:
- return QString::number((int)typeEnum);
- }
-}
-
-QQmlProfilerService::RangeType qmlEventType(const QString &typeString)
-{
- if (typeString == QLatin1String(TYPE_PAINTING_STR)) {
- return QQmlProfilerService::Painting;
- } else if (typeString == QLatin1String(TYPE_COMPILING_STR)) {
- return QQmlProfilerService::Compiling;
- } else if (typeString == QLatin1String(TYPE_CREATING_STR)) {
- return QQmlProfilerService::Creating;
- } else if (typeString == QLatin1String(TYPE_BINDING_STR)) {
- return QQmlProfilerService::Binding;
- } else if (typeString == QLatin1String(TYPE_HANDLINGSIGNAL_STR)) {
- return QQmlProfilerService::HandlingSignal;
- } else {
- bool isNumber = false;
- int type = typeString.toUInt(&isNumber);
- if (isNumber) {
- return (QQmlProfilerService::RangeType)type;
- } else {
- return QQmlProfilerService::MaximumRangeType;
- }
- }
-}
-
-QString getHashStringForQmlEvent(
- EventLocation location,
- QQmlProfilerService::RangeType eventType)
-{
- return QString("%1:%2:%3:%4").arg(location.filename,
- QString::number(location.line),
- QString::number(location.column),
- QString::number(eventType));
-}
-
-class ProfileDataPrivate
-{
-public:
-
- // convenience functions
- void clearQmlRootEvent();
- void clearV8RootEvent();
-
- // Stored data
- QmlEventHash m_eventDescriptions;
- QList<QmlEventEndTime> m_endTimeSortedList;
- QList<QmlEventStartTime> m_startTimeSortedList;
-
- void collectV8Statistics();
- V8Events m_v8EventList;
- QHash<int, V8Event *> m_v8parents;
-
- QmlEvent m_qmlRootEvent;
- V8Event m_v8RootEvent;
- QString m_rootEventName;
- QString m_rootEventDesc;
-
- QHash<int, QmlEventTypeCount *> m_typeCounts;
-
- qint64 m_traceEndTime;
- qint64 m_traceStartTime;
- qint64 m_qmlMeasuredTime;
- qint64 m_v8MeasuredTime;
-
- QmlEventStartTime *m_lastFrameEvent;
- qint64 m_maximumAnimationCount;
- qint64 m_minimumAnimationCount;
-
- // file to load
- QString m_filename;
-};
-
-ProfileData::ProfileData(QObject *parent) :
- QObject(parent),
- d(new ProfileDataPrivate)
-{
- setObjectName("ProfileData");
-
- d->m_traceEndTime = 0;
- d->m_traceStartTime = -1;
- d->m_qmlMeasuredTime = 0;
- d->m_v8MeasuredTime = 0;
- d->m_rootEventName = tr("<program>");
- d->m_rootEventDesc = tr("Main Program");
- d->clearQmlRootEvent();
- d->clearV8RootEvent();
- d->m_lastFrameEvent = 0;
- d->m_maximumAnimationCount = 0;
- d->m_minimumAnimationCount = 0;
-}
-
-ProfileData::~ProfileData()
-{
- clear();
-}
-
-void ProfileData::clear()
-{
- qDeleteAll(d->m_eventDescriptions.values());
- d->m_eventDescriptions.clear();
-
- qDeleteAll(d->m_v8EventList);
- d->m_v8EventList.clear();
-
- d->m_endTimeSortedList.clear();
- d->m_startTimeSortedList.clear();
-
- d->m_v8parents.clear();
-
- d->clearQmlRootEvent();
- d->clearV8RootEvent();
-
- foreach (QmlEventTypeCount *typeCount, d->m_typeCounts.values())
- delete typeCount;
- d->m_typeCounts.clear();
-
- d->m_traceEndTime = 0;
- d->m_traceStartTime = -1;
- d->m_qmlMeasuredTime = 0;
- d->m_v8MeasuredTime = 0;
-
- d->m_lastFrameEvent = 0;
- d->m_maximumAnimationCount = 0;
- d->m_minimumAnimationCount = 0;
-
- emit countChanged();
- emit dataClear();
-}
-
-QmlEvents ProfileData::getQmlEvents() const
-{
- return d->m_eventDescriptions.values();
-}
-
-QmlEvent *ProfileData::qmlEvent(int eventId) const
-{
- foreach (QmlEvent *event, d->m_eventDescriptions.values()) {
- if (event->eventId == eventId)
- return event;
- }
- return 0;
-}
-
-V8Event *ProfileData::v8Event(int eventId) const
-{
- foreach (V8Event *event, d->m_v8EventList) {
- if (event->eventId == eventId)
- return event;
- }
- return 0;
-}
-
-const V8Events& ProfileData::getV8Events() const
-{
- return d->m_v8EventList;
-}
-
-void ProfileData::addQmlEvent(
- QQmlProfilerService::RangeType type, qint64 startTime, qint64 length,
- const QStringList &data, const EventLocation &location)
-{
- const QChar colon = QLatin1Char(':');
- QString displayName, eventHashStr, details;
- EventLocation eventLocation = location;
-
- emit processingData();
-
- // generate details string
- if (data.isEmpty())
- details = tr("Source code not available");
- else {
- details = data.join(" ").replace('\n'," ").simplified();
- QRegExp rewrite("\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)");
- bool match = rewrite.exactMatch(details);
- if (match) {
- details = rewrite.cap(1) + ": " + rewrite.cap(3);
- }
- if (details.startsWith(QString("file://")))
- details = details.mid(details.lastIndexOf(QChar('/')) + 1);
- }
-
- // backwards compatibility: "compiling" events don't have a proper location in older
- // version of the protocol, but the filename is passed in the details string
- if (type == QQmlProfilerService::Compiling && eventLocation.filename.isEmpty()) {
- eventLocation.filename = details;
- eventLocation.line = 1;
- eventLocation.column = 1;
- }
-
- // generate hash
- if (eventLocation.filename.isEmpty()) {
- displayName = tr("<bytecode>");
- eventHashStr = getHashStringForQmlEvent(eventLocation, type);
- } else {
- const QString filePath = QUrl(eventLocation.filename).path();
- displayName = filePath.mid(filePath.lastIndexOf(QChar('/')) + 1) + colon + QString::number(eventLocation.line);
- eventHashStr = getHashStringForQmlEvent(eventLocation, type);
- }
-
- QmlEvent *newEvent;
- if (d->m_eventDescriptions.contains(eventHashStr)) {
- newEvent = d->m_eventDescriptions[eventHashStr];
- } else {
- newEvent = new QmlEvent;
- newEvent->displayname = displayName;
- newEvent->location = eventLocation;
- newEvent->eventHashStr = eventHashStr;
- newEvent->eventType = type;
- newEvent->details = details;
- d->m_eventDescriptions.insert(eventHashStr, newEvent);
- }
-
- QmlEventEndTime endTimeData;
- endTimeData.endTime = startTime + length;
- endTimeData.description = newEvent;
- endTimeData.startTimeIndex = d->m_startTimeSortedList.count();
-
- QmlEventStartTime startTimeData;
- startTimeData.startTime = startTime;
- startTimeData.length = length;
- startTimeData.description = newEvent;
- startTimeData.endTimeIndex = d->m_endTimeSortedList.count();
- startTimeData.animationCount = -1;
- startTimeData.frameRate = 1e9/length;
-
- d->m_endTimeSortedList << endTimeData;
- d->m_startTimeSortedList << startTimeData;
-
- emit countChanged();
-}
-
-void ProfileData::addV8Event(int depth, const QString &function,
- const QString &filename, int lineNumber,
- double totalTime, double selfTime)
-{
- QString displayName = filename.mid(
- filename.lastIndexOf(QLatin1Char('/')) + 1) + QLatin1Char(':') +
- QString::number(lineNumber);
- V8Event *eventData = 0;
-
- // time is given in milliseconds, but internally we store it in microseconds
- totalTime *= 1e6;
- selfTime *= 1e6;
-
- // cumulate information
- foreach (V8Event *v8event, d->m_v8EventList) {
- if (v8event->displayName == displayName &&
- v8event->functionName == function) {
- eventData = v8event;
- break;
- }
- }
-
- if (!eventData) {
- eventData = new V8Event;
- eventData->displayName = displayName;
- eventData->filename = filename;
- eventData->functionName = function;
- eventData->line = lineNumber;
- eventData->totalTime = totalTime;
- eventData->selfTime = selfTime;
- d->m_v8EventList << eventData;
- } else {
- eventData->totalTime += totalTime;
- eventData->selfTime += selfTime;
- }
- d->m_v8parents[depth] = eventData;
-
- V8Event *parentEvent = 0;
- if (depth == 0) {
- parentEvent = &d->m_v8RootEvent;
- d->m_v8MeasuredTime += totalTime;
- }
- if (depth > 0 && d->m_v8parents.contains(depth-1)) {
- parentEvent = d->m_v8parents.value(depth-1);
- }
-
- if (parentEvent != 0) {
- if (!eventData->parentHash.contains(parentEvent->displayName)) {
- V8EventSub *newParentSub = new V8EventSub(parentEvent);
- newParentSub->totalTime = totalTime;
-
- eventData->parentHash.insert(parentEvent->displayName, newParentSub );
- } else {
- V8EventSub *newParentSub =
- eventData->parentHash.value(parentEvent->displayName);
- newParentSub->totalTime += totalTime;
- }
-
- if (!parentEvent->childrenHash.contains(eventData->displayName)) {
- V8EventSub *newChildSub = new V8EventSub(eventData);
- newChildSub->totalTime = totalTime;
-
- parentEvent->childrenHash.insert(eventData->displayName, newChildSub);
- } else {
- V8EventSub *newChildSub =
- parentEvent->childrenHash.value(eventData->displayName);
- newChildSub->totalTime += totalTime;
- }
- }
-}
-
-void ProfileData::addFrameEvent(qint64 time, int framerate, int animationcount)
-{
- QString displayName, eventHashStr, details;
-
- emit processingData();
-
- details = tr("Animation Timer Update");
- displayName = tr("<Animation Update>");
- eventHashStr = displayName;
-
- QmlEvent *newEvent;
- if (d->m_eventDescriptions.contains(eventHashStr)) {
- newEvent = d->m_eventDescriptions[eventHashStr];
- } else {
- newEvent = new QmlEvent;
- newEvent->displayname = displayName;
- newEvent->eventHashStr = eventHashStr;
- newEvent->eventType = QQmlProfilerService::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;
- }
-
- QmlEventEndTime endTimeData;
- endTimeData.endTime = time + length;
- endTimeData.description = newEvent;
- endTimeData.startTimeIndex = d->m_startTimeSortedList.count();
-
- QmlEventStartTime 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 ProfileDataPrivate::collectV8Statistics()
-{
- if (!m_v8EventList.isEmpty()) {
- double totalTimes = m_v8MeasuredTime;
- double selfTimes = 0;
- foreach (V8Event *v8event, m_v8EventList) {
- selfTimes += v8event->selfTime;
- }
-
- // prevent divisions by 0
- if (totalTimes == 0)
- totalTimes = 1;
- if (selfTimes == 0)
- selfTimes = 1;
-
- // insert root event in eventlist
- // the +1 ns is to get it on top of the sorted list
- m_v8RootEvent.totalTime = m_v8MeasuredTime + 1;
- m_v8RootEvent.selfTime = 0;
-
- int rootEventIndex = -1;
- for (int ndx = 0; ndx < m_v8EventList.count(); ndx++)
- {
- if (m_v8EventList.at(ndx)->displayName == m_rootEventName) {
- m_v8RootEvent = *m_v8EventList.at(ndx);
- rootEventIndex = ndx;
- break;
- }
- }
- if (rootEventIndex == -1) {
- rootEventIndex = m_v8EventList.count();
- V8Event *newRootEvent = new V8Event;
- *newRootEvent = m_v8RootEvent;
- m_v8EventList << newRootEvent;
- }
-
- foreach (V8Event *v8event, m_v8EventList) {
- v8event->totalPercent = v8event->totalTime * 100.0 / totalTimes;
- v8event->selfPercent = v8event->selfTime * 100.0 / selfTimes;
- }
-
- int index = 0;
- foreach (V8Event *v8event, m_v8EventList) {
- v8event->eventId = index++;
- }
- m_v8RootEvent.eventId = m_v8EventList[rootEventIndex]->eventId;
- }
-}
-
-void ProfileData::setTraceEndTime( qint64 time )
-{
- d->m_traceEndTime = time;
-}
-
-void ProfileData::setTraceStartTime( qint64 time )
-{
- d->m_traceStartTime = time;
-}
-
-void ProfileData::complete()
-{
- emit postProcessing();
- d->collectV8Statistics();
- postProcess();
-}
-
-void ProfileDataPrivate::clearQmlRootEvent()
-{
- m_qmlRootEvent.displayname = m_rootEventName;
- m_qmlRootEvent.location = EventLocation();
- m_qmlRootEvent.eventHashStr = m_rootEventName;
- m_qmlRootEvent.details = m_rootEventDesc;
- m_qmlRootEvent.eventType = QQmlProfilerService::Binding;
- m_qmlRootEvent.duration = 0;
- m_qmlRootEvent.calls = 0;
- m_qmlRootEvent.minTime = 0;
- m_qmlRootEvent.maxTime = 0;
- m_qmlRootEvent.timePerCall = 0;
- m_qmlRootEvent.percentOfTime = 0;
- m_qmlRootEvent.medianTime = 0;
- m_qmlRootEvent.eventId = -1;
-
- qDeleteAll(m_qmlRootEvent.parentHash.values());
- qDeleteAll(m_qmlRootEvent.childrenHash.values());
- m_qmlRootEvent.parentHash.clear();
- m_qmlRootEvent.childrenHash.clear();
-}
-
-void ProfileDataPrivate::clearV8RootEvent()
-{
- m_v8RootEvent.displayName = m_rootEventName;
- m_v8RootEvent.functionName = m_rootEventDesc;
- m_v8RootEvent.line = -1;
- m_v8RootEvent.totalTime = 0;
- m_v8RootEvent.totalPercent = 0;
- m_v8RootEvent.selfTime = 0;
- m_v8RootEvent.selfPercent = 0;
- m_v8RootEvent.eventId = -1;
-
- qDeleteAll(m_v8RootEvent.parentHash.values());
- qDeleteAll(m_v8RootEvent.childrenHash.values());
- m_v8RootEvent.parentHash.clear();
- m_v8RootEvent.childrenHash.clear();
-}
-
-void ProfileData::compileStatistics(qint64 startTime, qint64 endTime)
-{
- int index;
- int fromIndex = findFirstIndex(startTime);
- int toIndex = findLastIndex(endTime);
- double totalTime = 0;
-
- // clear existing statistics
- foreach (QmlEvent *eventDescription,
- d->m_eventDescriptions.values()) {
- eventDescription->calls = 0;
- // maximum possible value
- eventDescription->minTime = d->m_endTimeSortedList.last().endTime;
- eventDescription->maxTime = 0;
- eventDescription->medianTime = 0;
- eventDescription->duration = 0;
- qDeleteAll(eventDescription->parentHash);
- qDeleteAll(eventDescription->childrenHash);
- eventDescription->parentHash.clear();
- eventDescription->childrenHash.clear();
- }
-
- // create root event for statistics
- d->clearQmlRootEvent();
-
- // compute parent-child relationship and call count
- QHash<int, QmlEvent*> lastParent;
- for (index = fromIndex; index <= toIndex; index++) {
- QmlEvent *eventDescription =
- d->m_startTimeSortedList[index].description;
-
- if (d->m_startTimeSortedList[index].startTime > endTime ||
- d->m_startTimeSortedList[index].startTime +
- d->m_startTimeSortedList[index].length < startTime) {
- continue;
- }
-
- if (eventDescription->eventType == QQmlProfilerService::Painting) {
- // skip animation/paint events
- continue;
- }
-
- eventDescription->calls++;
- qint64 duration = d->m_startTimeSortedList[index].length;
- eventDescription->duration += duration;
- if (eventDescription->maxTime < duration)
- eventDescription->maxTime = duration;
- if (eventDescription->minTime > duration)
- eventDescription->minTime = duration;
-
- int level = d->m_startTimeSortedList[index].level;
-
- QmlEvent *parentEvent = &d->m_qmlRootEvent;
- if (level > MIN_LEVEL && lastParent.contains(level-1)) {
- parentEvent = lastParent[level-1];
- }
-
- if (!eventDescription->parentHash.contains(parentEvent->eventHashStr)) {
- QmlEventSub *newParentEvent =
- new QmlEventSub(parentEvent);
- newParentEvent->calls = 1;
- newParentEvent->duration = duration;
-
- eventDescription->parentHash.insert(parentEvent->eventHashStr,
- newParentEvent);
- } else {
- QmlEventSub *newParentEvent =
- eventDescription->parentHash.value(parentEvent->eventHashStr);
- newParentEvent->duration += duration;
- newParentEvent->calls++;
- }
-
- if (!parentEvent->childrenHash.contains(eventDescription->eventHashStr)) {
- QmlEventSub *newChildEvent =
- new QmlEventSub(eventDescription);
- newChildEvent->calls = 1;
- newChildEvent->duration = duration;
-
- parentEvent->childrenHash.insert(eventDescription->eventHashStr,
- newChildEvent);
- } else {
- QmlEventSub *newChildEvent =
- parentEvent->childrenHash.value(eventDescription->eventHashStr);
- newChildEvent->duration += duration;
- newChildEvent->calls++;
- }
-
- lastParent[level] = eventDescription;
-
- if (level == MIN_LEVEL) {
- totalTime += duration;
- }
- }
-
- // fake rootEvent statistics
- // the +1 nanosecond is to force it to be on top of the sorted list
- d->m_qmlRootEvent.duration = totalTime+1;
- d->m_qmlRootEvent.minTime = totalTime+1;
- d->m_qmlRootEvent.maxTime = totalTime+1;
- d->m_qmlRootEvent.medianTime = totalTime+1;
- if (totalTime > 0)
- d->m_qmlRootEvent.calls = 1;
-
- // insert into list
- QmlEvent *listedRootEvent =
- d->m_eventDescriptions.value(d->m_rootEventName);
- if (!listedRootEvent) {
- listedRootEvent = new QmlEvent;
- d->m_eventDescriptions.insert(d->m_rootEventName, listedRootEvent);
- }
- *listedRootEvent = d->m_qmlRootEvent;
-
- // compute percentages
- foreach (QmlEvent *binding, d->m_eventDescriptions.values()) {
- binding->percentOfTime = binding->duration * 100.0 / totalTime;
- binding->timePerCall = binding->calls > 0 ?
- double(binding->duration) / binding->calls : 0;
- }
-
- // compute median time
- QHash < QmlEvent* , QList<qint64> > durationLists;
- for (index = fromIndex; index <= toIndex; index++) {
- QmlEvent *desc = d->m_startTimeSortedList[index].description;
- qint64 len = d->m_startTimeSortedList[index].length;
- durationLists[desc].append(len);
- }
- QMutableHashIterator < QmlEvent* , QList<qint64> > iter(durationLists);
- while (iter.hasNext()) {
- iter.next();
- if (!iter.value().isEmpty()) {
- qSort(iter.value());
- iter.key()->medianTime = iter.value().at(iter.value().count()/2);
- }
- }
-}
-
-void ProfileData::prepareForDisplay()
-{
- // generate numeric ids
- int ndx = 0;
- foreach (QmlEvent *binding, d->m_eventDescriptions.values()) {
- binding->eventId = ndx++;
- }
-
- // collect type counts
- foreach (const QmlEventStartTime &eventStartData,
- d->m_startTimeSortedList) {
- int typeNumber = eventStartData.description->eventType;
- if (!d->m_typeCounts.contains(typeNumber)) {
- d->m_typeCounts[typeNumber] = new QmlEventTypeCount;
- d->m_typeCounts[typeNumber]->nestingCount = 0;
- }
- if (eventStartData.nestingLevel >
- d->m_typeCounts[typeNumber]->nestingCount) {
- d->m_typeCounts[typeNumber]->nestingCount = eventStartData.nestingLevel;
- }
- if (!d->m_typeCounts[typeNumber]->eventIds.contains(
- eventStartData.description->eventId))
- d->m_typeCounts[typeNumber]->eventIds << eventStartData.description->eventId;
- }
-}
-
-void ProfileData::sortStartTimes()
-{
- if (d->m_startTimeSortedList.count() < 2)
- return;
-
- // assuming startTimes is partially sorted
- // identify blocks of events and sort them with quicksort
- QList<QmlEventStartTime>::iterator itFrom =
- d->m_startTimeSortedList.end() - 2;
- QList<QmlEventStartTime>::iterator itTo =
- d->m_startTimeSortedList.end() - 1;
-
- while (itFrom != d->m_startTimeSortedList.begin() &&
- itTo != d->m_startTimeSortedList.begin()) {
- // find block to sort
- while ( itFrom != d->m_startTimeSortedList.begin()
- && itTo->startTime > itFrom->startTime ) {
- itTo--;
- itFrom = itTo - 1;
- }
-
- // if we're at the end of the list
- if (itFrom == d->m_startTimeSortedList.begin())
- break;
-
- // find block length
- while ( itFrom != d->m_startTimeSortedList.begin()
- && itTo->startTime <= itFrom->startTime )
- itFrom--;
-
- if (itTo->startTime <= itFrom->startTime)
- qSort(itFrom, itTo + 1, compareStartTimes);
- else
- qSort(itFrom + 1, itTo + 1, compareStartTimes);
-
- // move to next block
- itTo = itFrom;
- itFrom = itTo - 1;
- }
-
- // link back the endTimes
- for (int i = 0; i < d->m_startTimeSortedList.length(); i++)
- d->m_endTimeSortedList[d->m_startTimeSortedList[i].endTimeIndex].startTimeIndex = i;
-}
-
-void ProfileData::sortEndTimes()
-{
- // assuming endTimes is partially sorted
- // identify blocks of events and sort them with quicksort
-
- if (d->m_endTimeSortedList.count() < 2)
- return;
-
- QList<QmlEventEndTime>::iterator itFrom =
- d->m_endTimeSortedList.begin();
- QList<QmlEventEndTime>::iterator itTo =
- d->m_endTimeSortedList.begin() + 1;
-
- while (itTo != d->m_endTimeSortedList.end() &&
- itFrom != d->m_endTimeSortedList.end()) {
- // find block to sort
- while ( itTo != d->m_endTimeSortedList.end()
- && d->m_startTimeSortedList[itTo->startTimeIndex].startTime >
- d->m_startTimeSortedList[itFrom->startTimeIndex].startTime +
- d->m_startTimeSortedList[itFrom->startTimeIndex].length ) {
- itFrom++;
- itTo = itFrom+1;
- }
-
- // if we're at the end of the list
- if (itTo == d->m_endTimeSortedList.end())
- break;
-
- // find block length
- while ( itTo != d->m_endTimeSortedList.end()
- && d->m_startTimeSortedList[itTo->startTimeIndex].startTime <=
- d->m_startTimeSortedList[itFrom->startTimeIndex].startTime +
- d->m_startTimeSortedList[itFrom->startTimeIndex].length )
- itTo++;
-
- // sort block
- qSort(itFrom, itTo, compareEndTimes);
-
- // move to next block
- itFrom = itTo;
- itTo = itFrom+1;
-
- }
-
- // link back the startTimes
- for (int i = 0; i < d->m_endTimeSortedList.length(); i++)
- d->m_startTimeSortedList[d->m_endTimeSortedList[i].startTimeIndex].endTimeIndex = i;
-}
-
-void ProfileData::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 ==
- QQmlProfilerService::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 ProfileData::computeNestingLevels()
-{
- // compute levels
- QHash <int, qint64> endtimesPerLevel;
- QList <int> nestingLevels;
- QList < QHash <int, qint64> > endtimesPerNestingLevel;
- int level = MIN_LEVEL;
- endtimesPerLevel[MIN_LEVEL] = 0;
-
- for (int i = 0; i < QQmlProfilerService::MaximumRangeType; i++) {
- nestingLevels << MIN_LEVEL;
- QHash <int, qint64> dummyHash;
- dummyHash[MIN_LEVEL] = 0;
- endtimesPerNestingLevel << dummyHash;
- }
-
- for (int i=0; i<d->m_startTimeSortedList.count(); i++) {
- qint64 st = d->m_startTimeSortedList[i].startTime;
- int type = d->m_startTimeSortedList[i].description->eventType;
-
- if (type == QQmlProfilerService::Painting) {
- // animation/paint events have level 1 by definition,
- // but are not considered parents of other events for
- // statistical purposes
- d->m_startTimeSortedList[i].level = MIN_LEVEL;
- d->m_startTimeSortedList[i].nestingLevel = MIN_LEVEL;
- continue;
- }
-
- // general level
- if (endtimesPerLevel[level] > st) {
- level++;
- } else {
- while (level > MIN_LEVEL && endtimesPerLevel[level-1] <= st)
- level--;
- }
- endtimesPerLevel[level] = st + d->m_startTimeSortedList[i].length;
-
- // per type
- if (endtimesPerNestingLevel[type][nestingLevels[type]] > st) {
- nestingLevels[type]++;
- } else {
- while (nestingLevels[type] > MIN_LEVEL &&
- endtimesPerNestingLevel[type][nestingLevels[type]-1] <= st)
- nestingLevels[type]--;
- }
- endtimesPerNestingLevel[type][nestingLevels[type]] = st +
- d->m_startTimeSortedList[i].length;
-
- d->m_startTimeSortedList[i].level = level;
- d->m_startTimeSortedList[i].nestingLevel = nestingLevels[type];
-
- if (level == MIN_LEVEL) {
- d->m_qmlMeasuredTime += d->m_startTimeSortedList[i].length;
- }
- }
-}
-
-void ProfileData::computeNestingDepth()
-{
- QHash <int, int> nestingDepth;
- for (int i = 0; i < d->m_endTimeSortedList.count(); i++) {
- int type = d->m_endTimeSortedList[i].description->eventType;
- int nestingInType = d->m_startTimeSortedList[d->m_endTimeSortedList[i].startTimeIndex].nestingLevel;
- if (!nestingDepth.contains(type))
- nestingDepth[type] = nestingInType;
- else {
- int nd = nestingDepth[type];
- nestingDepth[type] = nd > nestingInType ? nd : nestingInType;
- }
-
- d->m_startTimeSortedList[d->m_endTimeSortedList[i].startTimeIndex].nestingDepth
- = nestingDepth[type];
- if (nestingInType == MIN_LEVEL)
- nestingDepth[type] = MIN_LEVEL;
- }
-}
-
-void ProfileData::postProcess()
-{
- if (count() != 0) {
- sortStartTimes();
- sortEndTimes();
- findAnimationLimits();
- computeLevels();
- linkEndsToStarts();
- reloadDetails();
- compileStatistics(traceStartTime(), traceEndTime());
- prepareForDisplay();
- }
- // data is ready even when there's no data
- emit dataReady();
-}
-
-void ProfileData::linkEndsToStarts()
-{
- for (int i = 0; i < d->m_startTimeSortedList.count(); i++)
- d->m_endTimeSortedList[d->m_startTimeSortedList[i].endTimeIndex].startTimeIndex = i;
-}
-
-void ProfileData::computeLevels()
-{
- computeNestingLevels();
- computeNestingDepth();
-}
-
-void ProfileData::reloadDetails()
-{
- // request binding/signal details from the AST
- foreach (QmlEvent *event, d->m_eventDescriptions.values()) {
- if (event->eventType != QQmlProfilerService::Binding &&
- event->eventType != QQmlProfilerService::HandlingSignal)
- continue;
-
- // This skips anonymous bindings in Qt4.8 (we don't have valid location data for them)
- if (event->location.filename.isEmpty())
- continue;
-
- // Skip non-anonymous bindings from Qt4.8 (we already have correct details for them)
- if (event->location.column == -1)
- continue;
-
- emit requestDetailsForLocation(event->eventType, event->location);
- }
- emit reloadDocumentsForDetails();
-}
-
-void ProfileData::findBindingLoops(qint64 startTime, qint64 endTime)
-{
- // first clear existing data
- foreach (QmlEvent *event, d->m_eventDescriptions.values()) {
- event->isBindingLoop = false;
- foreach (QmlEventSub *parentEvent, event->parentHash.values())
- parentEvent->inLoopPath = false;
- foreach (QmlEventSub *childEvent, event->childrenHash.values())
- childEvent->inLoopPath = false;
- }
-
- QList <QmlEvent *> stackRefs;
- QList <QmlEventStartTime *> stack;
- int fromIndex = findFirstIndex(startTime);
- int toIndex = findLastIndex(endTime);
-
- for (int i = 0; i < d->m_startTimeSortedList.count(); i++) {
- QmlEvent *currentEvent = d->m_startTimeSortedList[i].description;
- QmlEventStartTime *inTimeEvent = &d->m_startTimeSortedList[i];
- inTimeEvent->bindingLoopHead = -1;
-
- // managing call stack
- for (int j = stack.count() - 1; j >= 0; j--) {
- if (stack[j]->startTime + stack[j]->length <= inTimeEvent->startTime) {
- stack.removeAt(j);
- stackRefs.removeAt(j);
- }
- }
-
- bool loopDetected = stackRefs.contains(currentEvent);
- stack << inTimeEvent;
- stackRefs << currentEvent;
-
- if (loopDetected) {
- if (i >= fromIndex && i <= toIndex) {
- // for the statistics
- currentEvent->isBindingLoop = true;
- for (int j = stackRefs.indexOf(currentEvent); j < stackRefs.count()-1; j++) {
- QmlEventSub *nextEventSub = stackRefs[j]->childrenHash.value(stackRefs[j+1]->eventHashStr);
- nextEventSub->inLoopPath = true;
- QmlEventSub *prevEventSub = stackRefs[j+1]->parentHash.value(stackRefs[j]->eventHashStr);
- prevEventSub->inLoopPath = true;
- }
- }
-
- // use crossed references to find index in starttimesortedlist
- QmlEventStartTime *head = stack[stackRefs.indexOf(currentEvent)];
- inTimeEvent->bindingLoopHead = d->m_endTimeSortedList[head->endTimeIndex].startTimeIndex;
- d->m_startTimeSortedList[inTimeEvent->bindingLoopHead].bindingLoopHead = i;
- }
- }
-}
-
-void ProfileData::rewriteDetailsString(
- QQmlProfilerService::RangeType eventType,
- const EventLocation &location, const QString &newString)
-{
- QString eventHashStr = getHashStringForQmlEvent(location,
- eventType);
- Q_ASSERT(d->m_eventDescriptions.contains(eventHashStr));
- d->m_eventDescriptions.value(eventHashStr)->details = newString;
- emit detailsChanged(d->m_eventDescriptions.value(eventHashStr)->eventId,
- newString);
-}
-
-void ProfileData::finishedRewritingDetails()
-{
- emit reloadDetailLabels();
-}
-
-// get list of events between A and B:
-// find fist event with endtime after A -> aa
-// find last event with starttime before B -> bb
-// list is from parent of aa with level=0 to bb, in the "sorted by starttime" list
-int ProfileData::findFirstIndex(qint64 startTime) const
-{
- int candidate = -1;
- // in the "endtime" list, find the first event that ends after startTime
- if (d->m_endTimeSortedList.isEmpty())
- return 0; // -1
- if (d->m_endTimeSortedList.length() == 1 ||
- d->m_endTimeSortedList.first().endTime >= startTime)
- candidate = 0;
- else
- if (d->m_endTimeSortedList.last().endTime <= startTime)
- return 0; // -1
-
- if (candidate == -1)
- {
- int fromIndex = 0;
- int toIndex = d->m_endTimeSortedList.count()-1;
- while (toIndex - fromIndex > 1) {
- int midIndex = (fromIndex + toIndex)/2;
- if (d->m_endTimeSortedList[midIndex].endTime < startTime)
- fromIndex = midIndex;
- else
- toIndex = midIndex;
- }
-
- candidate = toIndex;
- }
-
- int ndx = d->m_endTimeSortedList[candidate].startTimeIndex;
-
- // and then go to the parent
- while (d->m_startTimeSortedList[ndx].level != MIN_LEVEL && ndx > 0)
- ndx--;
-
- return ndx;
-}
-
-int ProfileData::findFirstIndexNoParents(qint64 startTime) const
-{
- int candidate = -1;
- // in the "endtime" list, find the first event that ends after startTime
- if (d->m_endTimeSortedList.isEmpty())
- return 0; // -1
- if (d->m_endTimeSortedList.length() == 1 ||
- d->m_endTimeSortedList.first().endTime >= startTime)
- candidate = 0;
- else
- if (d->m_endTimeSortedList.last().endTime <= startTime)
- return 0; // -1
-
- if (candidate == -1) {
- int fromIndex = 0;
- int toIndex = d->m_endTimeSortedList.count()-1;
- while (toIndex - fromIndex > 1) {
- int midIndex = (fromIndex + toIndex)/2;
- if (d->m_endTimeSortedList[midIndex].endTime < startTime)
- fromIndex = midIndex;
- else
- toIndex = midIndex;
- }
-
- candidate = toIndex;
- }
-
- int ndx = d->m_endTimeSortedList[candidate].startTimeIndex;
-
- return ndx;
-}
-
-int ProfileData::findLastIndex(qint64 endTime) const
-{
- // in the "starttime" list, find the last event that starts before endtime
- if (d->m_startTimeSortedList.isEmpty())
- return 0; // -1
- if (d->m_startTimeSortedList.first().startTime >= endTime)
- return 0; // -1
- if (d->m_startTimeSortedList.length() == 1)
- return 0;
- if (d->m_startTimeSortedList.last().startTime <= endTime)
- return d->m_startTimeSortedList.count()-1;
-
- int fromIndex = 0;
- int toIndex = d->m_startTimeSortedList.count()-1;
- while (toIndex - fromIndex > 1) {
- int midIndex = (fromIndex + toIndex)/2;
- if (d->m_startTimeSortedList[midIndex].startTime < endTime)
- fromIndex = midIndex;
- else
- toIndex = midIndex;
- }
-
- return fromIndex;
-}
-
-qint64 ProfileData::firstTimeMark() const
-{
- if (d->m_startTimeSortedList.isEmpty())
- return 0;
- else {
- return d->m_startTimeSortedList[0].startTime;
- }
-}
-
-qint64 ProfileData::lastTimeMark() const
-{
- if (d->m_endTimeSortedList.isEmpty())
- return 0;
- else {
- return d->m_endTimeSortedList.last().endTime;
- }
-}
-
-qint64 ProfileData::traceStartTime() const
-{
- return d->m_traceStartTime != -1? d->m_traceStartTime : firstTimeMark();
-}
-
-qint64 ProfileData::traceEndTime() const
-{
- return d->m_traceEndTime ? d->m_traceEndTime : lastTimeMark();
-}
-
-qint64 ProfileData::traceDuration() const
-{
- return traceEndTime() - traceStartTime();
-}
-
-qint64 ProfileData::qmlMeasuredTime() const
-{
- return d->m_qmlMeasuredTime;
-}
-qint64 ProfileData::v8MeasuredTime() const
-{
- return d->m_v8MeasuredTime;
-}
-
-int ProfileData::count() const
-{
- return d->m_startTimeSortedList.count();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-
-bool ProfileData::save(const QString &filename)
-{
- if (count() == 0) {
- emit error(tr("No data to save"));
- return false;
- }
-
- QFile file(filename);
- if (!file.open(QIODevice::WriteOnly)) {
- emit error(tr("Could not open %1 for writing").arg(filename));
- return false;
- }
-
- QXmlStreamWriter stream(&file);
- stream.setAutoFormatting(true);
- stream.writeStartDocument();
-
- stream.writeStartElement("trace");
- stream.writeAttribute("version", PROFILER_FILE_VERSION);
-
- stream.writeAttribute("traceStart", QString::number(traceStartTime()));
- stream.writeAttribute("traceEnd", QString::number(traceEndTime()));
-
- stream.writeStartElement("eventData");
- stream.writeAttribute("totalTime", QString::number(d->m_qmlMeasuredTime));
-
- foreach (const QmlEvent *eventData, d->m_eventDescriptions.values()) {
- stream.writeStartElement("event");
- stream.writeAttribute("index",
- QString::number(
- d->m_eventDescriptions.keys().indexOf(
- eventData->eventHashStr)));
- stream.writeTextElement("displayname", eventData->displayname);
- stream.writeTextElement("type", qmlEventType(eventData->eventType));
- if (!eventData->location.filename.isEmpty()) {
- stream.writeTextElement("filename", eventData->location.filename);
- stream.writeTextElement("line",
- QString::number(eventData->location.line));
- stream.writeTextElement("column",
- QString::number(eventData->location.column));
- }
- stream.writeTextElement("details", eventData->details);
- stream.writeEndElement();
- }
- stream.writeEndElement(); // eventData
-
- stream.writeStartElement("eventList");
- foreach (const QmlEventStartTime &rangedEvent,
- d->m_startTimeSortedList) {
- stream.writeStartElement("range");
- stream.writeAttribute("startTime", QString::number(rangedEvent.startTime));
- stream.writeAttribute("duration", QString::number(rangedEvent.length));
- stream.writeAttribute("eventIndex",
- QString::number(d->m_eventDescriptions.keys().indexOf(
- rangedEvent.description->eventHashStr)));
- if (rangedEvent.description->eventType ==
- QQmlProfilerService::Painting && rangedEvent.animationCount >= 0) {
- // animation frame
- stream.writeAttribute("framerate",
- QString::number(rangedEvent.frameRate));
- stream.writeAttribute("animationcount",
- QString::number(rangedEvent.animationCount));
- }
- stream.writeEndElement();
- }
- stream.writeEndElement(); // eventList
-
- stream.writeStartElement("v8profile"); // v8 profiler output
- stream.writeAttribute("totalTime", QString::number(d->m_v8MeasuredTime));
- foreach (V8Event *v8event, d->m_v8EventList) {
- stream.writeStartElement("event");
- stream.writeAttribute("index",
- QString::number(d->m_v8EventList.indexOf(v8event)));
- stream.writeTextElement("displayname", v8event->displayName);
- stream.writeTextElement("functionname", v8event->functionName);
- if (!v8event->filename.isEmpty()) {
- stream.writeTextElement("filename", v8event->filename);
- stream.writeTextElement("line", QString::number(v8event->line));
- }
- stream.writeTextElement("totalTime",
- QString::number(v8event->totalTime));
- stream.writeTextElement("selfTime", QString::number(v8event->selfTime));
- if (!v8event->childrenHash.isEmpty()) {
- stream.writeStartElement("childrenEvents");
- QStringList childrenIndexes;
- QStringList childrenTimes;
- QStringList parentTimes;
- foreach (V8EventSub *v8child, v8event->childrenHash.values()) {
- childrenIndexes << QString::number(v8child->reference->eventId);
- childrenTimes << QString::number(v8child->totalTime);
- parentTimes << QString::number(
- d->m_v8EventList[v8child->reference->eventId]->
- parentHash[v8event->displayName]->totalTime);
- }
-
- stream.writeAttribute("list", childrenIndexes.join(QString(", ")));
- stream.writeAttribute("childrenTimes",
- childrenTimes.join(QString(", ")));
- stream.writeAttribute("parentTimes",
- parentTimes.join(QString(", ")));
- stream.writeEndElement();
- }
- stream.writeEndElement();
- }
- stream.writeEndElement(); // v8 profiler output
-
- stream.writeEndElement(); // trace
- stream.writeEndDocument();
-
- file.close();
- return true;
-}
-
-void ProfileData::setFilename(const QString &filename)
-{
- d->m_filename = filename;
-}
-
-void ProfileData::load(const QString &filename)
-{
- setFilename(filename);
- load();
-}
-
-// "be strict in your output but tolerant in your inputs"
-void ProfileData::load()
-{
- QString filename = d->m_filename;
-
- QFile file(filename);
-
- if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- emit error(tr("Could not open %1 for reading").arg(filename));
- return;
- }
-
- emit processingData();
-
- // erase current
- clear();
-
- bool readingQmlEvents = false;
- bool readingV8Events = false;
- QHash <int, QmlEvent *> descriptionBuffer;
- QmlEvent *currentEvent = 0;
- QHash <int, V8Event *> v8eventBuffer;
- QHash <int, QString> childrenIndexes;
- QHash <int, QString> childrenTimes;
- QHash <int, QString> parentTimes;
- V8Event *v8event = 0;
- bool startTimesAreSorted = true;
- bool validVersion = true;
-
- // time computation
- d->m_v8MeasuredTime = 0;
- d->m_qmlMeasuredTime = 0;
- double cumulatedV8Time = 0;
-
- QXmlStreamReader stream(&file);
-
- while (validVersion && !stream.atEnd() && !stream.hasError()) {
- QXmlStreamReader::TokenType token = stream.readNext();
- QString elementName = stream.name().toString();
- switch (token) {
- case QXmlStreamReader::StartDocument : continue;
- case QXmlStreamReader::StartElement : {
- if (elementName == "trace") {
- QXmlStreamAttributes attributes = stream.attributes();
- if (attributes.hasAttribute("version"))
- validVersion =
- attributes.value("version").toString() ==
- PROFILER_FILE_VERSION;
- else
- validVersion = false;
- if (attributes.hasAttribute("traceStart"))
- setTraceStartTime(attributes.value("traceStart").
- toString().toLongLong());
- if (attributes.hasAttribute("traceEnd"))
- setTraceEndTime(attributes.value("traceEnd").
- toString().toLongLong());
- }
- if (elementName == "eventData" && !readingV8Events) {
- readingQmlEvents = true;
- QXmlStreamAttributes attributes = stream.attributes();
- if (attributes.hasAttribute("totalTime"))
- d->m_qmlMeasuredTime = attributes.value("totalTime").
- toString().toDouble();
- break;
- }
- if (elementName == "v8profile" && !readingQmlEvents) {
- readingV8Events = true;
- QXmlStreamAttributes attributes = stream.attributes();
- if (attributes.hasAttribute("totalTime"))
- d->m_v8MeasuredTime = attributes.value("totalTime").
- toString().toDouble();
- break;
- }
-
- if (elementName == "trace") {
- QXmlStreamAttributes attributes = stream.attributes();
- if (attributes.hasAttribute("traceStart"))
- setTraceStartTime(attributes.value("traceStart").
- toString().toLongLong());
- if (attributes.hasAttribute("traceEnd"))
- setTraceEndTime(attributes.value("traceEnd").
- toString().toLongLong());
- }
-
- if (elementName == "range") {
- QmlEventStartTime rangedEvent;
- QXmlStreamAttributes attributes = stream.attributes();
- if (attributes.hasAttribute("startTime"))
- rangedEvent.startTime = attributes.value("startTime").
- toString().toLongLong();
- if (attributes.hasAttribute("duration"))
- 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();
- else
- rangedEvent.animationCount = -1;
- if (attributes.hasAttribute("eventIndex")) {
- int ndx = attributes.value("eventIndex").toString().toInt();
- if (!descriptionBuffer.value(ndx))
- descriptionBuffer[ndx] = new QmlEvent;
- rangedEvent.description = descriptionBuffer.value(ndx);
- }
- rangedEvent.endTimeIndex = d->m_endTimeSortedList.length();
-
- if (!d->m_startTimeSortedList.isEmpty()
- && rangedEvent.startTime <
- d->m_startTimeSortedList.last().startTime)
- startTimesAreSorted = false;
- d->m_startTimeSortedList << rangedEvent;
-
- QmlEventEndTime endTimeEvent;
- endTimeEvent.endTime = rangedEvent.startTime + rangedEvent.length;
- endTimeEvent.startTimeIndex = d->m_startTimeSortedList.length()-1;
- endTimeEvent.description = rangedEvent.description;
- d->m_endTimeSortedList << endTimeEvent;
- break;
- }
-
- if (readingQmlEvents) {
- if (elementName == "event") {
- QXmlStreamAttributes attributes = stream.attributes();
- if (attributes.hasAttribute("index")) {
- int ndx = attributes.value("index").toString().toInt();
- if (!descriptionBuffer.value(ndx))
- descriptionBuffer[ndx] = new QmlEvent;
- currentEvent = descriptionBuffer[ndx];
- } else {
- currentEvent = 0;
- }
- break;
- }
-
- // the remaining are eventdata or v8eventdata elements
- if (!currentEvent)
- break;
-
- stream.readNext();
- if (stream.tokenType() != QXmlStreamReader::Characters)
- break;
- QString readData = stream.text().toString();
-
- if (elementName == "displayname") {
- currentEvent->displayname = readData;
- break;
- }
- if (elementName == "type") {
- currentEvent->eventType = qmlEventType(readData);
- break;
- }
- if (elementName == "filename") {
- currentEvent->location.filename = readData;
- break;
- }
- if (elementName == "line") {
- currentEvent->location.line = readData.toInt();
- break;
- }
- if (elementName == "column") {
- currentEvent->location.column = readData.toInt();
- }
- if (elementName == "details") {
- currentEvent->details = readData;
- break;
- }
- }
-
- if (readingV8Events) {
- if (elementName == "event") {
- QXmlStreamAttributes attributes = stream.attributes();
- if (attributes.hasAttribute("index")) {
- int ndx = attributes.value("index").toString().toInt();
- if (!v8eventBuffer.value(ndx))
- v8eventBuffer[ndx] = new V8Event;
- v8event = v8eventBuffer[ndx];
- } else {
- v8event = 0;
- }
- break;
- }
-
- // the remaining are eventdata or v8eventdata elements
- if (!v8event)
- break;
-
- if (elementName == "childrenEvents") {
- QXmlStreamAttributes attributes = stream.attributes();
- int eventIndex = v8eventBuffer.key(v8event);
- if (attributes.hasAttribute("list")) {
- // store for later parsing (we haven't read all the events yet)
- childrenIndexes[eventIndex] =
- attributes.value("list").toString();
- }
- if (attributes.hasAttribute("childrenTimes")) {
- childrenTimes[eventIndex] =
- attributes.value("childrenTimes").toString();
- }
- if (attributes.hasAttribute("parentTimes")) {
- parentTimes[eventIndex] =
- attributes.value("parentTimes").toString();
- }
- }
-
- stream.readNext();
- if (stream.tokenType() != QXmlStreamReader::Characters)
- break;
- QString readData = stream.text().toString();
-
- if (elementName == "displayname") {
- v8event->displayName = readData;
- break;
- }
-
- if (elementName == "functionname") {
- v8event->functionName = readData;
- break;
- }
-
- if (elementName == "filename") {
- v8event->filename = readData;
- break;
- }
-
- if (elementName == "line") {
- v8event->line = readData.toInt();
- break;
- }
-
- if (elementName == "totalTime") {
- v8event->totalTime = readData.toDouble();
- cumulatedV8Time += v8event->totalTime;
- break;
- }
-
- if (elementName == "selfTime") {
- v8event->selfTime = readData.toDouble();
- break;
- }
- }
-
- break;
- }
- case QXmlStreamReader::EndElement : {
- if (elementName == "event") {
- currentEvent = 0;
- break;
- }
- if (elementName == "eventData") {
- readingQmlEvents = false;
- break;
- }
- if (elementName == "v8profile") {
- readingV8Events = false;
- }
- }
- default: break;
- }
- }
-
- file.close();
-
- if (stream.hasError()) {
- emit error(tr("Error while parsing %1").arg(filename));
- clear();
- return;
- }
-
- stream.clear();
-
- if (!validVersion) {
- clear();
- emit countChanged();
- emit dataReady();
- emit error(tr("Invalid version of QML Trace file."));
- return;
- }
-
- // backwards compatibility
- if (d->m_v8MeasuredTime == 0)
- d->m_v8MeasuredTime = cumulatedV8Time;
-
- // move the buffered data to the details cache
- foreach (QmlEvent *desc, descriptionBuffer.values()) {
- desc->eventHashStr = getHashStringForQmlEvent(
- desc->location, desc->eventType);;
- d->m_eventDescriptions[desc->eventHashStr] = desc;
- }
-
- // sort startTimeSortedList
- if (!startTimesAreSorted) {
- qSort(d->m_startTimeSortedList.begin(),
- d->m_startTimeSortedList.end(), compareStartTimes);
- for (int i = 0; i< d->m_startTimeSortedList.length(); i++) {
- QmlEventStartTime startTimeData = d->m_startTimeSortedList[i];
- d->m_endTimeSortedList[startTimeData.endTimeIndex].startTimeIndex = i;
- }
- qSort(d->m_endTimeSortedList.begin(),
- d->m_endTimeSortedList.end(), compareStartIndexes);
- }
-
- // find v8events' children and parents
- foreach (int parentIndex, childrenIndexes.keys()) {
- QStringList childrenStrings =
- childrenIndexes.value(parentIndex).split(",");
- QStringList childrenTimesStrings =
- childrenTimes.value(parentIndex).split(", ");
- QStringList parentTimesStrings =
- parentTimes.value(parentIndex).split(", ");
- for (int ndx = 0; ndx < childrenStrings.count(); ndx++) {
- int childIndex = childrenStrings[ndx].toInt();
- if (v8eventBuffer.value(childIndex)) {
- V8EventSub *newChild = new V8EventSub(v8eventBuffer[childIndex]);
- V8EventSub *newParent = new V8EventSub(v8eventBuffer[parentIndex]);
- if (childrenTimesStrings.count() > ndx)
- newChild->totalTime = childrenTimesStrings[ndx].toDouble();
- if (parentTimesStrings.count() > ndx)
- newParent->totalTime = parentTimesStrings[ndx].toDouble();
- v8eventBuffer[parentIndex]->childrenHash.insert(
- newChild->reference->displayName, newChild);
- v8eventBuffer[childIndex]->parentHash.insert(
- newParent->reference->displayName, newParent);
- }
- }
- }
- // store v8 events
- d->m_v8EventList = v8eventBuffer.values();
-
- emit countChanged();
-
- descriptionBuffer.clear();
-
- emit postProcessing();
- d->collectV8Statistics();
- postProcess();
-}
-
-///////////////////////////////////////////////
-qint64 ProfileData::getStartTime(int index) const
-{
- return d->m_startTimeSortedList[index].startTime;
-}
-
-qint64 ProfileData::getEndTime(int index) const
-{
- return d->m_startTimeSortedList[index].startTime +
- d->m_startTimeSortedList[index].length;
-}
-
-qint64 ProfileData::getDuration(int index) const
-{
- return d->m_startTimeSortedList[index].length;
-}
-
-int ProfileData::getType(int index) const
-{
- return d->m_startTimeSortedList[index].description->eventType;
-}
-
-int ProfileData::getNestingLevel(int index) const
-{
- return d->m_startTimeSortedList[index].nestingLevel;
-}
-
-int ProfileData::getNestingDepth(int index) const
-{
- return d->m_startTimeSortedList[index].nestingDepth;
-}
-
-QString ProfileData::getFilename(int index) const
-{
- return d->m_startTimeSortedList[index].description->location.filename;
-}
-
-int ProfileData::getLine(int index) const
-{
- return d->m_startTimeSortedList[index].description->location.line;
-}
-
-int ProfileData::getColumn(int index) const
-{
- return d->m_startTimeSortedList[index].description->location.column;
-}
-
-QString ProfileData::getDetails(int index) const
-{
- // special: animations
- if (d->m_startTimeSortedList[index].description->eventType ==
- QQmlProfilerService::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;
-}
-
-int ProfileData::getEventId(int index) const {
- return d->m_startTimeSortedList[index].description->eventId;
-}
-
-int ProfileData::getFramerate(int index) const
-{
- return d->m_startTimeSortedList[index].frameRate;
-}
-
-int ProfileData::getAnimationCount(int index) const
-{
- return d->m_startTimeSortedList[index].animationCount;
-}
-
-int ProfileData::getMaximumAnimationCount() const
-{
- return d->m_maximumAnimationCount;
-}
-
-int ProfileData::getMinimumAnimationCount() const
-{
- return d->m_minimumAnimationCount;
-}
-
-int ProfileData::uniqueEventsOfType(int type) const
-{
- if (!d->m_typeCounts.contains(type))
- return 0;
- return d->m_typeCounts[type]->eventIds.count();
-}
-
-int ProfileData::maxNestingForType(int type) const
-{
- if (!d->m_typeCounts.contains(type))
- return 0;
- return d->m_typeCounts[type]->nestingCount;
-}
-
-QString ProfileData::eventTextForType(int type, int index) const
-{
- if (!d->m_typeCounts.contains(type))
- return QString();
- return d->m_eventDescriptions.values().at(
- d->m_typeCounts[type]->eventIds[index])->details;
-}
-
-QString ProfileData::eventDisplayNameForType(int type, int index) const
-{
- if (!d->m_typeCounts.contains(type))
- return QString();
- return d->m_eventDescriptions.values().at(
- d->m_typeCounts[type]->eventIds[index])->displayname;
-}
-
-int ProfileData::eventIdForType(int type, int index) const
-{
- if (!d->m_typeCounts.contains(type))
- return -1;
- return d->m_typeCounts[type]->eventIds[index];
-}
-
-int ProfileData::eventPosInType(int index) const
-{
- int eventType = d->m_startTimeSortedList[index].description->eventType;
- return d->m_typeCounts[eventType]->eventIds.indexOf(
- d->m_startTimeSortedList[index].description->eventId);
-}