QmlProfiler: New event list with caching, load, save

Change-Id: I640a16649156a49f2d7e7006d6b2ea38fe218620
Reviewed-on: http://codereview.qt.nokia.com/3043
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Kai Koehne <kai.koehne@nokia.com>
This commit is contained in:
Christiaan Janssen
2011-07-26 13:56:14 +02:00
parent 8fbaa0d10a
commit d2911d70f3
17 changed files with 1417 additions and 489 deletions

View File

@@ -35,14 +35,20 @@
#include <QtCore/QUrl>
#include <QtCore/QHash>
#include <QtGui/QStandardItem>
#include <QtGui/QHeaderView>
#include <QtGui/QStandardItemModel>
#include <QtGui/QContextMenuEvent>
#include <QDebug>
using namespace QmlJsDebugClient;
namespace QmlProfiler {
namespace Internal {
////////////////////////////////////////////////////////////////////////////////////
class EventsViewItem : public QStandardItem
{
public:
@@ -66,22 +72,6 @@ public:
};
////////////////////////////////////////////////////////////////////////////////////
class QmlProfilerEventStatistics::QmlProfilerEventStatisticsPrivate
{
public:
QmlProfilerEventStatisticsPrivate(QmlProfilerEventStatistics *qq) : q(qq) {}
void postProcess();
QmlProfilerEventStatistics *q;
QmlEventHash m_rootHash;
QHash<int, QmlEventList> m_pendingEvents;
int m_lastLevel;
};
////////////////////////////////////////////////////////////////////////////////////
class QmlProfilerEventsView::QmlProfilerEventsViewPrivate
@@ -89,7 +79,7 @@ class QmlProfilerEventsView::QmlProfilerEventsViewPrivate
public:
QmlProfilerEventsViewPrivate(QmlProfilerEventsView *qq) : q(qq) {}
void buildModelFromList(const QmlEventList &list, QStandardItem *parentItem, const QmlEventList &visitedFunctionsList = QmlEventList() );
void buildModelFromList(const QmlEventDescriptions &list, QStandardItem *parentItem, const QmlEventDescriptions &visitedFunctionsList = QmlEventDescriptions() );
int getFieldCount();
QString displayTime(double time) const;
QString nameForType(int typeNumber) const;
@@ -97,7 +87,7 @@ public:
QmlProfilerEventsView *q;
QmlProfilerEventStatistics *m_eventStatistics;
QmlProfilerEventList *m_eventStatistics;
QStandardItemModel *m_model;
QList<bool> m_fieldShown;
bool m_showAnonymous;
@@ -107,151 +97,7 @@ public:
////////////////////////////////////////////////////////////////////////////////////
QmlProfilerEventStatistics::QmlProfilerEventStatistics(QObject *parent) :
QObject(parent), d(new QmlProfilerEventStatisticsPrivate(this))
{
setObjectName("QmlProfilerEventStatistics");
d->m_lastLevel = -1;
}
QmlProfilerEventStatistics::~QmlProfilerEventStatistics()
{
clear();
}
void QmlProfilerEventStatistics::clear()
{
foreach (int levelNumber, d->m_pendingEvents.keys())
d->m_pendingEvents[levelNumber].clear();
d->m_lastLevel = -1;
foreach (QmlEventData *binding, d->m_rootHash.values())
delete binding;
d->m_rootHash.clear();
}
QList <QmlEventData *> QmlProfilerEventStatistics::getEventList() const
{
return d->m_rootHash.values();
}
int QmlProfilerEventStatistics::eventCount() const
{
return d->m_rootHash.size();
}
void QmlProfilerEventStatistics::addRangedEvent(int type, int nestingLevel, int nestingInType, qint64 startTime, qint64 length,
const QStringList &data, const QString &fileName, int line)
{
Q_UNUSED(startTime);
Q_UNUSED(nestingInType);
const QChar colon = QLatin1Char(':');
QString displayName, location, details;
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);
}
if (fileName.isEmpty()) {
displayName = tr("<bytecode>");
location = QString("--:%1:%2").arg(QString::number(type), details);
} else {
const QString filePath = QUrl(fileName).path();
displayName = filePath.mid(filePath.lastIndexOf(QChar('/')) + 1) + colon + QString::number(line);
location = fileName+colon+QString::number(line);
}
// New Data: if it's not in the hash, put it there
// if it's in the hash, get the reference from the hash
QmlEventData *newBinding;
QmlEventHash::iterator it = d->m_rootHash.find(location);
if (it != d->m_rootHash.end()) {
newBinding = it.value();
newBinding->duration += length;
newBinding->calls++;
if (newBinding->maxTime < length)
newBinding->maxTime = length;
if (newBinding->minTime > length)
newBinding->minTime = length;
} else {
newBinding = new QmlEventData;
newBinding->calls = 1;
newBinding->duration = length;
newBinding->displayname = new QString(displayName);
newBinding->filename = new QString(fileName);
newBinding->location = new QString(location);
newBinding->line = line;
newBinding->minTime = length;
newBinding->maxTime = length;
newBinding->level = nestingLevel;
newBinding->eventType = (QmlEventType)type;
newBinding->details = new QString(details);
newBinding->parentList = new QmlEventList();
newBinding->childrenList = new QmlEventList();
d->m_rootHash.insert(location, newBinding);
}
if (nestingLevel < d->m_lastLevel) {
// I'm the parent of the former
if (d->m_pendingEvents.contains(nestingLevel+1)) {
foreach (QmlEventData *child, d->m_pendingEvents[nestingLevel + 1]) {
if (!newBinding->childrenList->contains(child))
newBinding->childrenList->append(child);
if (!child->parentList->contains(newBinding))
child->parentList->append(newBinding);
}
d->m_pendingEvents[nestingLevel + 1].clear();
}
}
if (nestingLevel > 1 && !d->m_pendingEvents[nestingLevel].contains(newBinding)) {
// I'm not root... there will come a parent later
d->m_pendingEvents[nestingLevel].append(newBinding);
}
d->m_lastLevel = nestingLevel;
}
void QmlProfilerEventStatistics::complete()
{
d->postProcess();
emit dataReady();
}
void QmlProfilerEventStatistics::QmlProfilerEventStatisticsPrivate::postProcess()
{
double totalTime = 0;
foreach (QmlEventData *binding, m_rootHash.values()) {
if (binding->filename->isEmpty())
continue;
totalTime += binding->duration;
}
foreach (QmlEventData *binding, m_rootHash.values()) {
if (binding->filename->isEmpty())
continue;
binding->percentOfTime = binding->duration * 100.0 / totalTime;
binding->timePerCall = binding->calls > 0 ? double(binding->duration) / binding->calls : 0;
}
}
////////////////////////////////////////////////////////////////////////////////////
QmlProfilerEventsView::QmlProfilerEventsView(QWidget *parent, QmlProfilerEventStatistics *model) :
QmlProfilerEventsView::QmlProfilerEventsView(QWidget *parent, QmlProfilerEventList *model) :
QTreeView(parent), d(new QmlProfilerEventsViewPrivate(this))
{
setObjectName("QmlProfilerEventsView");
@@ -281,7 +127,7 @@ QmlProfilerEventsView::~QmlProfilerEventsView()
delete d->m_model;
}
void QmlProfilerEventsView::setEventStatisticsModel( QmlProfilerEventStatistics *model )
void QmlProfilerEventsView::setEventStatisticsModel( QmlProfilerEventList *model )
{
if (d->m_eventStatistics)
disconnect(d->m_eventStatistics,SIGNAL(dataReady()),this,SLOT(buildModel()));
@@ -414,7 +260,7 @@ void QmlProfilerEventsView::buildModel()
{
if (d->m_eventStatistics) {
clear();
d->buildModelFromList( d->m_eventStatistics->getEventList(), d->m_model->invisibleRootItem() );
d->buildModelFromList( d->m_eventStatistics->getEventDescriptions(), d->m_model->invisibleRootItem() );
bool hasBranches = d->m_fieldShown[Parents] || d->m_fieldShown[Children];
setRootIsDecorated(hasBranches);
@@ -434,18 +280,18 @@ void QmlProfilerEventsView::buildModel()
}
}
void QmlProfilerEventsView::QmlProfilerEventsViewPrivate::buildModelFromList( const QmlEventList &list, QStandardItem *parentItem, const QmlEventList &visitedFunctionsList )
void QmlProfilerEventsView::QmlProfilerEventsViewPrivate::buildModelFromList( const QmlEventDescriptions &list, QStandardItem *parentItem, const QmlEventDescriptions &visitedFunctionsList )
{
foreach (QmlEventData *binding, list) {
if (visitedFunctionsList.contains(binding))
continue;
if ((!m_showAnonymous) && binding->filename->isEmpty())
if ((!m_showAnonymous) && binding->filename.isEmpty())
continue;
QList<QStandardItem *> newRow;
if (m_fieldShown[Name]) {
newRow << new EventsViewItem(*binding->displayname);
newRow << new EventsViewItem(binding->displayname);
}
if (m_fieldShown[Type]) {
@@ -459,8 +305,8 @@ void QmlProfilerEventsView::QmlProfilerEventsViewPrivate::buildModelFromList( co
}
if (m_fieldShown[TotalDuration]) {
newRow << new EventsViewItem(displayTime(binding->duration));
newRow.last()->setData(QVariant(binding->duration));
newRow << new EventsViewItem(displayTime(binding->cumulatedDuration));
newRow.last()->setData(QVariant(binding->cumulatedDuration));
}
if (m_fieldShown[CallCount]) {
@@ -484,8 +330,8 @@ void QmlProfilerEventsView::QmlProfilerEventsViewPrivate::buildModelFromList( co
}
if (m_fieldShown[Details]) {
newRow << new EventsViewItem(*binding->details);
newRow.last()->setData(QVariant(*binding->details));
newRow << new EventsViewItem(binding->details);
newRow.last()->setData(QVariant(binding->details));
}
if (!newRow.isEmpty()) {
@@ -494,25 +340,25 @@ void QmlProfilerEventsView::QmlProfilerEventsViewPrivate::buildModelFromList( co
item->setEditable(false);
// metadata
newRow.at(0)->setData(QVariant(*binding->location),LocationRole);
newRow.at(0)->setData(QVariant(*binding->filename),FilenameRole);
newRow.at(0)->setData(QVariant(binding->location),LocationRole);
newRow.at(0)->setData(QVariant(binding->filename),FilenameRole);
newRow.at(0)->setData(QVariant(binding->line),LineRole);
// append
parentItem->appendRow(newRow);
if (m_fieldShown[Parents] && !binding->parentList->isEmpty()) {
QmlEventList newParentList(visitedFunctionsList);
if (m_fieldShown[Parents] && !binding->parentList.isEmpty()) {
QmlEventDescriptions newParentList(visitedFunctionsList);
newParentList.append(binding);
buildModelFromList(*binding->parentList, newRow.at(0), newParentList);
buildModelFromList(binding->parentList, newRow.at(0), newParentList);
}
if (m_fieldShown[Children] && !binding->childrenList->isEmpty()) {
QmlEventList newChildrenList(visitedFunctionsList);
if (m_fieldShown[Children] && !binding->childrenList.isEmpty()) {
QmlEventDescriptions newChildrenList(visitedFunctionsList);
newChildrenList.append(binding);
buildModelFromList(*binding->childrenList, newRow.at(0), newChildrenList);
buildModelFromList(binding->childrenList, newRow.at(0), newChildrenList);
}
}
}
@@ -556,5 +402,10 @@ void QmlProfilerEventsView::jumpToItem(const QModelIndex &index)
emit gotoSourceLocation(fileName, line);
}
void QmlProfilerEventsView::contextMenuEvent(QContextMenuEvent *ev)
{
emit contextMenuRequested(ev->globalPos());
}
} // namespace Internal
} // namespace QmlProfiler