forked from qt-creator/qt-creator
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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user