QmlProfiler: Move EventList to qmljsdebugclient library

Change-Id: Icbd24ffeb51db0f098d8fe9c62a0a889a722f760
Reviewed-on: http://codereview.qt.nokia.com/3222
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Christiaan Janssen <christiaan.janssen@nokia.com>
This commit is contained in:
Kai Koehne
2011-08-18 16:10:33 +02:00
parent 91e22b2e81
commit 749534ea76
10 changed files with 53 additions and 56 deletions

View File

@@ -27,8 +27,7 @@ SOURCES += \
codaqmlprofilerrunner.cpp \
remotelinuxqmlprofilerrunner.cpp \
qmlprofilereventview.cpp \
qmlprofilerruncontrolfactory.cpp \
qmlprofilereventlist.cpp
qmlprofilerruncontrolfactory.cpp
HEADERS += \
qmlprofilerconstants.h \
@@ -44,8 +43,7 @@ HEADERS += \
codaqmlprofilerrunner.h \
remotelinuxqmlprofilerrunner.h \
qmlprofilereventview.h \
qmlprofilerruncontrolfactory.h\
qmlprofilereventlist.h
qmlprofilerruncontrolfactory.h
RESOURCES += \
qml/qml.qrc

View File

@@ -1,849 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** 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.
**
** 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#include "qmlprofilereventlist.h"
#include <coreplugin/icore.h>
#include <QtCore/QUrl>
#include <QtCore/QHash>
#include <QtCore/QtAlgorithms>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QFile>
#include <QtCore/QXmlStreamReader>
#include <QtCore/QXmlStreamWriter>
#include <QtCore/QTimer>
#include <QtGui/QMainWindow>
#include <QtGui/QMessageBox>
#include <QDebug>
namespace QmlProfiler {
namespace Internal {
#define MIN_LEVEL 1
// description
struct QmlEventDescription {
QmlEventDescription() : displayname(0), location(0), filename(0), details(0) {}
~QmlEventDescription() {
delete displayname;
delete location;
delete filename;
delete details;
}
QString *displayname;
QString *location;
QString *filename;
QString *details;
int eventType;
int line;
};
// endtimedata
struct QmlEventEndTimeData {
qint64 endTime;
int startTimeIndex;
QmlEventData *description;
};
// starttimedata
struct QmlEventStartTimeData {
qint64 startTime;
qint64 length;
qint64 level;
int endTimeIndex;
qint64 nestingLevel;
qint64 nestingDepth;
QmlEventData *description;
};
// used by quicksort
bool compareEndTimes(const QmlEventEndTimeData &t1, const QmlEventEndTimeData &t2)
{
return t1.endTime < t2.endTime;
}
bool compareStartTimes(const QmlEventStartTimeData &t1, const QmlEventStartTimeData &t2)
{
return t1.startTime < t2.startTime;
}
bool compareStartIndexes(const QmlEventEndTimeData &t1, const QmlEventEndTimeData &t2)
{
return t1.startTimeIndex < t2.startTimeIndex;
}
class QmlProfilerEventList::QmlProfilerEventListPrivate
{
public:
QmlProfilerEventListPrivate(QmlProfilerEventList *qq) : q(qq) {}
QmlProfilerEventList *q;
// Stored data
QmlEventHash m_eventDescriptions;
QList<QmlEventEndTimeData> m_endTimeSortedList;
QList<QmlEventStartTimeData> m_startTimeSortedList;
// file to load
QString m_filename;
ParsingStatus m_parsingStatus;
};
////////////////////////////////////////////////////////////////////////////////////
QmlProfilerEventList::QmlProfilerEventList(QObject *parent) :
QObject(parent), d(new QmlProfilerEventListPrivate(this))
{
d->m_parsingStatus = DoneStatus;
setObjectName("QmlProfilerEventStatistics");
}
QmlProfilerEventList::~QmlProfilerEventList()
{
clear();
}
void QmlProfilerEventList::clear()
{
foreach (QmlEventData *binding, d->m_eventDescriptions.values())
delete binding;
d->m_eventDescriptions.clear();
d->m_endTimeSortedList.clear();
d->m_startTimeSortedList.clear();
emit countChanged();
}
QList <QmlEventData *> QmlProfilerEventList::getEventDescriptions() const
{
return d->m_eventDescriptions.values();
}
void QmlProfilerEventList::addRangedEvent(int type, qint64 startTime, qint64 length,
const QStringList &data, const QString &fileName, int line)
{
setParsingStatus(GettingDataStatus);
const QChar colon = QLatin1Char(':');
QString displayName, location, details;
if (fileName.isEmpty()) {
displayName = tr("<bytecode>");
location = QString("--:%1:%2").arg(QString::number(type), data.join(" "));
} else {
const QString filePath = QUrl(fileName).path();
displayName = filePath.mid(filePath.lastIndexOf(QChar('/')) + 1) + colon + QString::number(line);
location = fileName+colon+QString::number(line);
}
QmlEventData *newEvent;
if (d->m_eventDescriptions.contains(location)) {
newEvent = d->m_eventDescriptions[location];
} else {
// 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);
}
newEvent = new QmlEventData;
newEvent->displayname = displayName;
newEvent->filename = fileName;
newEvent->location = location;
newEvent->line = line;
newEvent->eventType = (QmlJsDebugClient::QmlEventType)type;
newEvent->details = details;
d->m_eventDescriptions.insert(location, newEvent);
}
QmlEventEndTimeData endTimeData;
endTimeData.endTime = startTime + length;
endTimeData.description = newEvent;
endTimeData.startTimeIndex = d->m_startTimeSortedList.count();
QmlEventStartTimeData startTimeData;
startTimeData.startTime = startTime;
startTimeData.length = length;
startTimeData.description = newEvent;
startTimeData.endTimeIndex = d->m_endTimeSortedList.count();
d->m_endTimeSortedList << endTimeData;
d->m_startTimeSortedList << startTimeData;
emit countChanged();
}
void QmlProfilerEventList::complete()
{
postProcess();
}
void QmlProfilerEventList::compileStatistics()
{
// clear existing statistics
foreach (QmlEventData *eventDescription, d->m_eventDescriptions.values()) {
eventDescription->calls = 0;
// maximum possible value
eventDescription->minTime = d->m_endTimeSortedList.last().endTime;
eventDescription->maxTime = 0;
eventDescription->cumulatedDuration = 0;
eventDescription->parentList.clear();
eventDescription->childrenList.clear();
}
// compute parent-child relationship and call count
QHash<int, QmlEventData*> lastParent;
foreach (QmlEventStartTimeData eventStartData, d->m_startTimeSortedList) {
QmlEventData *eventDescription = eventStartData.description;
eventDescription->calls++;
eventDescription->cumulatedDuration += eventStartData.length;
if (eventDescription->maxTime < eventStartData.length)
eventDescription->maxTime = eventStartData.length;
if (eventDescription->minTime > eventStartData.length)
eventDescription->minTime = eventStartData.length;
if (eventStartData.level > MIN_LEVEL) {
if (lastParent.contains(eventStartData.level-1)) {
QmlEventData *parentEvent = lastParent[eventStartData.level-1];
if (!eventDescription->parentList.contains(parentEvent))
eventDescription->parentList.append(parentEvent);
if (!parentEvent->childrenList.contains(eventDescription))
parentEvent->childrenList.append(eventDescription);
}
}
lastParent[eventStartData.level] = eventDescription;
}
// compute percentages
double totalTime = 0;
foreach (QmlEventData *binding, d->m_eventDescriptions.values()) {
if (binding->filename.isEmpty())
continue;
totalTime += binding->cumulatedDuration;
}
foreach (QmlEventData *binding, d->m_eventDescriptions.values()) {
if (binding->filename.isEmpty())
continue;
binding->percentOfTime = binding->cumulatedDuration * 100.0 / totalTime;
binding->timePerCall = binding->calls > 0 ? double(binding->cumulatedDuration) / binding->calls : 0;
}
// continue postprocess
postProcess();
}
void QmlProfilerEventList::sortStartTimes()
{
if (d->m_startTimeSortedList.count() < 2)
return;
// assuming startTimes is partially sorted
// identify blocks of events and sort them with quicksort
QList<QmlEventStartTimeData>::iterator itFrom = d->m_startTimeSortedList.end() - 2;
QList<QmlEventStartTimeData>::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;
// continue postprocess
postProcess();
}
void QmlProfilerEventList::sortEndTimes()
{
// assuming endTimes is partially sorted
// identify blocks of events and sort them with quicksort
if (d->m_endTimeSortedList.count() < 2)
return;
QList<QmlEventEndTimeData>::iterator itFrom = d->m_endTimeSortedList.begin();
QList<QmlEventEndTimeData>::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;
// continue postprocess
postProcess();
}
void QmlProfilerEventList::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 < QmlJsDebugClient::MaximumQmlEventType; 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;
// 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];
}
}
void QmlProfilerEventList::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 QmlProfilerEventList::postProcess()
{
switch (d->m_parsingStatus) {
case GettingDataStatus: {
setParsingStatus(SortingListsStatus);
QTimer::singleShot(50, this, SLOT(sortStartTimes()));
break;
}
case SortingEndsStatus: {
setParsingStatus(SortingListsStatus);
QTimer::singleShot(50, this, SLOT(sortEndTimes()));
break;
}
case SortingListsStatus: {
setParsingStatus(ComputingLevelsStatus);
QTimer::singleShot(50, this, SLOT(computeLevels()));
break;
}
case ComputingLevelsStatus: {
setParsingStatus(CompilingStatisticsStatus);
QTimer::singleShot(50, this, SLOT(compileStatistics()));
break;
}
case CompilingStatisticsStatus: {
linkEndsToStarts();
setParsingStatus(DoneStatus);
emit dataReady();
break;
}
default: break;
}
}
void QmlProfilerEventList::setParsingStatus(ParsingStatus ps)
{
if (d->m_parsingStatus != ps) {
d->m_parsingStatus = ps;
emit parsingStatusChanged();
}
}
ParsingStatus QmlProfilerEventList::getParsingStatus() const
{
return d->m_parsingStatus;
}
void QmlProfilerEventList::linkEndsToStarts()
{
for (int i = 0; i < d->m_startTimeSortedList.count(); i++)
d->m_endTimeSortedList[d->m_startTimeSortedList[i].endTimeIndex].startTimeIndex = i;
}
void QmlProfilerEventList::computeLevels()
{
computeNestingLevels();
computeNestingDepth();
// continue postprocess
postProcess();
}
// 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 QmlProfilerEventList::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 QmlProfilerEventList::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 QmlProfilerEventList::firstTimeMark() const
{
if (d->m_startTimeSortedList.isEmpty())
return 0;
else {
return d->m_startTimeSortedList[0].startTime;
}
}
qint64 QmlProfilerEventList::lastTimeMark() const
{
if (d->m_endTimeSortedList.isEmpty())
return 0;
else {
return d->m_endTimeSortedList.last().endTime;
}
}
int QmlProfilerEventList::count() const
{
return d->m_startTimeSortedList.count();
}
////////////////////////////////////////////////////////////////////////////////////
void QmlProfilerEventList::save(const QString &filename) const
{
if (count() == 0) {
showErrorDialog(tr("No data to save"));
return;
}
QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
showErrorDialog(tr("Could not open %1 for writing").arg(filename));
return;
}
QXmlStreamWriter stream(&file);
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement("trace");
stream.writeStartElement("eventData");
foreach (const QmlEventData *eventData, d->m_eventDescriptions.values()) {
stream.writeStartElement("event");
stream.writeAttribute("index", QString::number(d->m_eventDescriptions.keys().indexOf(eventData->location)));
stream.writeTextElement("displayname", eventData->displayname);
stream.writeTextElement("type", QString::number(eventData->eventType));
if (!eventData->filename.isEmpty()) {
stream.writeTextElement("filename", eventData->filename);
stream.writeTextElement("line", QString::number(eventData->line));
}
stream.writeTextElement("details", eventData->details);
stream.writeEndElement();
}
stream.writeEndElement(); // eventData
stream.writeStartElement("eventList");
foreach (const QmlEventStartTimeData &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->location)));
stream.writeEndElement();
}
stream.writeEndElement(); // eventList
stream.writeEndElement(); // trace
stream.writeEndDocument();
file.close();
}
void QmlProfilerEventList::setFilename(const QString &filename)
{
d->m_filename = filename;
}
void QmlProfilerEventList::load(const QString &filename)
{
setFilename(filename);
load();
}
// "be strict in your output but tolerant in your inputs"
void QmlProfilerEventList::load()
{
QString filename = d->m_filename;
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
showErrorDialog(tr("Could not open %1 for reading").arg(filename));
return;
}
setParsingStatus(GettingDataStatus);
// erase current
clear();
QHash <int, QmlEventData *> descriptionBuffer;
QmlEventData *currentEvent = 0;
bool startTimesAreSorted = true;
QXmlStreamReader stream(&file);
while (!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 == "event") {
QXmlStreamAttributes attributes = stream.attributes();
if (attributes.hasAttribute("index")) {
int ndx = attributes.value("index").toString().toInt();
if (!descriptionBuffer.value(ndx))
descriptionBuffer[ndx] = new QmlEventData;
currentEvent = descriptionBuffer[ndx];
}
break;
}
if (elementName == "range") {
QmlEventStartTimeData 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("eventIndex")) {
int ndx = attributes.value("eventIndex").toString().toInt();
if (!descriptionBuffer.value(ndx))
descriptionBuffer[ndx] = new QmlEventData();
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;
QmlEventEndTimeData endTimeEvent;
endTimeEvent.endTime = rangedEvent.startTime + rangedEvent.length;
endTimeEvent.startTimeIndex = d->m_startTimeSortedList.length()-1;
endTimeEvent.description = rangedEvent.description;
d->m_endTimeSortedList << endTimeEvent;
break;
}
// the remaining are eventdata 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 = QmlJsDebugClient::QmlEventType(readData.toInt());
break;
}
if (elementName == "filename") {
currentEvent->filename = readData;
break;
}
if (elementName == "line") {
currentEvent->line = readData.toInt();
break;
}
if (elementName == "details") {
currentEvent->details = readData;
break;
}
break;
}
case QXmlStreamReader::EndElement : {
if (elementName == "event")
currentEvent = 0;
break;
}
default: break;
}
}
file.close();
if (stream.hasError()) {
showErrorDialog(tr("Error while parsing %1").arg(filename));
clear();
return;
}
stream.clear();
// move the buffered data to the details cache
foreach (QmlEventData *desc, descriptionBuffer.values()) {
QString location = QString("%1:%2:%3").arg(QString::number(desc->eventType), desc->displayname, desc->details);
desc->location = location;
d->m_eventDescriptions[location] = 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++) {
QmlEventStartTimeData startTimeData = d->m_startTimeSortedList[i];
d->m_endTimeSortedList[startTimeData.endTimeIndex].startTimeIndex = i;
}
qSort(d->m_endTimeSortedList.begin(), d->m_endTimeSortedList.end(), compareStartIndexes);
}
emit countChanged();
setParsingStatus(SortingEndsStatus);
descriptionBuffer.clear();
postProcess();
}
void QmlProfilerEventList::showErrorDialog(const QString &st ) const
{
Core::ICore * const core = Core::ICore::instance();
QMessageBox *errorDialog = new QMessageBox(core->mainWindow());
errorDialog->setIcon(QMessageBox::Warning);
errorDialog->setWindowTitle(tr("QML Profiler"));
errorDialog->setText( st );
errorDialog->setStandardButtons(QMessageBox::Ok);
errorDialog->setDefaultButton(QMessageBox::Ok);
errorDialog->setModal(false);
errorDialog->show();
}
///////////////////////////////////////////////
qint64 QmlProfilerEventList::getStartTime(int index) const {
return d->m_startTimeSortedList[index].startTime;
}
qint64 QmlProfilerEventList::getEndTime(int index) const {
return d->m_startTimeSortedList[index].startTime + d->m_startTimeSortedList[index].length;
}
qint64 QmlProfilerEventList::getDuration(int index) const {
return d->m_startTimeSortedList[index].length;
}
int QmlProfilerEventList::getType(int index) const {
return d->m_startTimeSortedList[index].description->eventType;
}
int QmlProfilerEventList::getNestingLevel(int index) const {
return d->m_startTimeSortedList[index].nestingLevel;
}
int QmlProfilerEventList::getNestingDepth(int index) const {
return d->m_startTimeSortedList[index].nestingDepth;
}
QString QmlProfilerEventList::getFilename(int index) const {
return d->m_startTimeSortedList[index].description->filename;
}
int QmlProfilerEventList::getLine(int index) const {
return d->m_startTimeSortedList[index].description->line;
}
QString QmlProfilerEventList::getDetails(int index) const {
return d->m_startTimeSortedList[index].description->details;
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,138 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** 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.
**
** 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#ifndef QMLPROFILEREVENTLIST_H
#define QMLPROFILEREVENTLIST_H
#include <QObject>
#include <QtCore/QHash>
#include "qmljsdebugclient/qmlprofilereventtypes.h"
namespace QmlProfiler {
namespace Internal {
struct QmlEventData
{
QString displayname;
QString filename;
QString location;
QString details;
int line;
QmlJsDebugClient::QmlEventType eventType;
QList< QmlEventData *> parentList;
QList< QmlEventData *> childrenList;
qint64 cumulatedDuration;
qint64 calls;
qint64 minTime;
qint64 maxTime;
double timePerCall;
double percentOfTime;
};
typedef QHash<QString, QmlEventData *> QmlEventHash;
typedef QList<QmlEventData *> QmlEventDescriptions;
enum ParsingStatus {
GettingDataStatus = 0,
SortingListsStatus = 1,
SortingEndsStatus = 2,
ComputingLevelsStatus = 3,
CompilingStatisticsStatus = 4,
DoneStatus = 5
};
class QmlProfilerEventList : public QObject
{
Q_OBJECT
public:
explicit QmlProfilerEventList(QObject *parent = 0);
~QmlProfilerEventList();
QmlEventDescriptions getEventDescriptions() const;
int findFirstIndex(qint64 startTime) const;
int findLastIndex(qint64 endTime) const;
Q_INVOKABLE qint64 firstTimeMark() const;
Q_INVOKABLE qint64 lastTimeMark() const;
Q_INVOKABLE int count() const;
void setParsingStatus(ParsingStatus ps);
Q_INVOKABLE ParsingStatus getParsingStatus() const;
// data access
Q_INVOKABLE qint64 getStartTime(int index) const;
Q_INVOKABLE qint64 getEndTime(int index) const;
Q_INVOKABLE qint64 getDuration(int index) const;
Q_INVOKABLE int getType(int index) const;
Q_INVOKABLE int getNestingLevel(int index) const;
Q_INVOKABLE int getNestingDepth(int index) const;
Q_INVOKABLE QString getFilename(int index) const;
Q_INVOKABLE int getLine(int index) const;
Q_INVOKABLE QString getDetails(int index) const;
void showErrorDialog(const QString &st ) const;
signals:
void dataReady();
void countChanged();
void parsingStatusChanged();
public slots:
void clear();
void addRangedEvent(int type, qint64 startTime, qint64 length,
const QStringList &data, const QString &fileName, int line);
void complete();
void save(const QString &filename) const;
void load(const QString &filename);
void setFilename(const QString &filename);
void load();
private slots:
void postProcess();
void sortEndTimes();
void sortStartTimes();
void computeLevels();
void computeNestingLevels();
void computeNestingDepth();
void compileStatistics();
void linkEndsToStarts();
private:
class QmlProfilerEventListPrivate;
QmlProfilerEventListPrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILEREVENTLIST_H

View File

@@ -35,13 +35,13 @@
#include <QTreeView>
#include <qmljsdebugclient/qmlprofilereventtypes.h>
#include "qmlprofilereventlist.h"
#include <qmljsdebugclient/qmlprofilereventlist.h>
namespace QmlProfiler {
namespace Internal {
typedef QHash<QString, QmlEventData *> QmlEventHash;
typedef QList<QmlEventData *> QmlEventList;
typedef QHash<QString, QmlJsDebugClient::QmlEventData *> QmlEventHash;
typedef QList<QmlJsDebugClient::QmlEventData *> QmlEventList;
enum ItemRole {
LocationRole = Qt::UserRole+1,
@@ -77,10 +77,10 @@ public:
MaxViewTypes
};
explicit QmlProfilerEventsView(QWidget *parent, QmlProfilerEventList *model);
explicit QmlProfilerEventsView(QWidget *parent, QmlJsDebugClient::QmlProfilerEventList *model);
~QmlProfilerEventsView();
void setEventStatisticsModel( QmlProfilerEventList *model );
void setEventStatisticsModel(QmlJsDebugClient::QmlProfilerEventList *model);
void setFieldViewable(Fields field, bool show);
void setViewType(ViewTypes type);
void setShowAnonymousEvents( bool showThem );

View File

@@ -35,12 +35,12 @@
#include "qmlprofilerplugin.h"
#include "qmlprofilerconstants.h"
#include "qmlprofilerattachdialog.h"
#include "qmlprofilereventlist.h"
#include "qmlprofilereventview.h"
#include "tracewindow.h"
#include "timelineview.h"
#include <qmljsdebugclient/qmlprofilereventlist.h>
#include <qmljsdebugclient/qdeclarativedebugclient.h>
#include <analyzerbase/analyzermanager.h>
@@ -255,6 +255,7 @@ QWidget *QmlProfilerTool::createWidgets()
connect(d->m_traceWindow, SIGNAL(gotoSourceLocation(QString,int)),this, SLOT(gotoSourceLocation(QString,int)));
connect(d->m_traceWindow, SIGNAL(timeChanged(qreal)), this, SLOT(updateTimer(qreal)));
connect(d->m_traceWindow, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
connect(d->m_traceWindow->getEventList(), SIGNAL(error(QString)), this, SLOT(showErrorDialog(QString)));
d->m_eventsView = new QmlProfilerEventsView(mw, d->m_traceWindow->getEventList());
d->m_eventsView->setViewType(QmlProfilerEventsView::EventsView);
@@ -582,3 +583,16 @@ void QmlProfilerTool::showLoadDialog()
QTimer::singleShot(100, d->m_traceWindow->getEventList(), SLOT(load()));
}
}
void QmlProfilerTool::showErrorDialog(const QString &error)
{
Core::ICore *core = Core::ICore::instance();
QMessageBox *errorDialog = new QMessageBox(core->mainWindow());
errorDialog->setIcon(QMessageBox::Warning);
errorDialog->setWindowTitle(tr("QML Profiler"));
errorDialog->setText(error);
errorDialog->setStandardButtons(QMessageBox::Ok);
errorDialog->setDefaultButton(QMessageBox::Ok);
errorDialog->setModal(false);
errorDialog->show();
}

View File

@@ -90,6 +90,7 @@ private slots:
void connectionStateChanged();
void showSaveDialog();
void showLoadDialog();
void showErrorDialog(const QString &error);
private:
void connectToClient();

View File

@@ -35,7 +35,7 @@
#include <QtDeclarative/QDeclarativeItem>
#include <QtScript/QScriptValue>
#include <qmlprofilereventlist.h>
#include <qmljsdebugclient/qmlprofilereventlist.h>
namespace QmlProfiler {
namespace Internal {
@@ -81,10 +81,10 @@ public:
qreal cachedProgress() const;
QmlProfilerEventList *eventList() const { return m_eventList; }
QmlJsDebugClient::QmlProfilerEventList *eventList() const { return m_eventList; }
void setEventList(QObject *eventList)
{
m_eventList = qobject_cast<QmlProfilerEventList *>(eventList);
m_eventList = qobject_cast<QmlJsDebugClient::QmlProfilerEventList *>(eventList);
emit eventListChanged(m_eventList);
}
@@ -100,7 +100,7 @@ signals:
void endTimeChanged(qint64 arg);
void startXChanged(qreal arg);
void totalWidthChanged(qreal arg);
void eventListChanged(QmlProfilerEventList *list);
void eventListChanged(QmlJsDebugClient::QmlProfilerEventList *list);
void cachedProgressChanged();
void cacheReady();
@@ -157,7 +157,7 @@ private:
int prevMin;
int prevMax;
QmlProfilerEventList *m_eventList;
QmlJsDebugClient::QmlProfilerEventList *m_eventList;
qreal m_totalWidth;
int m_lastCachedIndex;

View File

@@ -33,9 +33,8 @@
#include "tracewindow.h"
#include "qmlprofilerplugin.h"
#include "qmlprofilereventlist.h"
#include <qmljsdebugclient/qdeclarativedebugclient.h>
#include <qmljsdebugclient/qmlprofilereventlist.h>
#include <qmljsdebugclient/qmlprofilertraceclient.h>
#include <utils/styledbar.h>

View File

@@ -34,7 +34,7 @@
#define TRACEWINDOW_H
#include <qmljsdebugclient/qmlprofilertraceclient.h>
#include "qmlprofilereventlist.h"
#include <qmljsdebugclient/qmlprofilereventlist.h>
#include <QtCore/QPointer>
#include <QtGui/QWidget>
@@ -56,7 +56,7 @@ public:
void reset(QmlJsDebugClient::QDeclarativeDebugConnection *conn);
QmlProfilerEventList *getEventList() const;
QmlJsDebugClient::QmlProfilerEventList *getEventList() const;
void setRecording(bool recording);
bool isRecording() const;
@@ -91,7 +91,7 @@ private:
QSize m_sizeHint;
QDeclarativeView *m_view;
QmlProfilerEventList *m_eventList;
QmlJsDebugClient::QmlProfilerEventList *m_eventList;
};
} // namespace Internal