QmlProfiler: Use a temporary file to store the master event list

As we only ever iterate the master event list in a linear fashion, we
can use a temporary file to store it. This should allow for larger
traces to be handled without running out of memory.

Change-Id: I0d2aea6f998458fe5f426f6fef0f6937e915ae68
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Ulf Hermann
2016-04-29 18:38:54 +02:00
parent 914e1e1fe1
commit 0f513bc91e
4 changed files with 31 additions and 32 deletions

View File

@@ -34,6 +34,7 @@
#include <QUrl> #include <QUrl>
#include <QDebug> #include <QDebug>
#include <QStack> #include <QStack>
#include <QTemporaryFile>
#include <algorithm> #include <algorithm>
namespace QmlProfiler { namespace QmlProfiler {
@@ -46,7 +47,6 @@ public:
int resolveStackTop(); int resolveStackTop();
QVector<QmlEventType> eventTypes; QVector<QmlEventType> eventTypes;
QVector<QmlEvent> eventList;
QHash<QmlEventType, int> eventTypeIds; QHash<QmlEventType, int> eventTypeIds;
QStack<QmlTypedEvent> rangesInProgress; QStack<QmlTypedEvent> rangesInProgress;
@@ -54,6 +54,9 @@ public:
QmlProfilerModelManager *modelManager; QmlProfilerModelManager *modelManager;
int modelId; int modelId;
Internal::QmlProfilerDetailsRewriter *detailsRewriter; Internal::QmlProfilerDetailsRewriter *detailsRewriter;
QTemporaryFile file;
QDataStream eventStream;
}; };
QString getDisplayName(const QmlEventType &event) QString getDisplayName(const QmlEventType &event)
@@ -117,6 +120,8 @@ QmlProfilerDataModel::QmlProfilerDataModel(Utils::FileInProjectFinder *fileFinde
this, &QmlProfilerDataModel::detailsChanged); this, &QmlProfilerDataModel::detailsChanged);
connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged, connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged,
this, &QmlProfilerDataModel::allTypesLoaded); this, &QmlProfilerDataModel::allTypesLoaded);
d->file.open();
d->eventStream.setDevice(&d->file);
} }
QmlProfilerDataModel::~QmlProfilerDataModel() QmlProfilerDataModel::~QmlProfilerDataModel()
@@ -138,25 +143,22 @@ void QmlProfilerDataModel::setData(qint64 traceStart, qint64 traceEnd,
{ {
Q_D(QmlProfilerDataModel); Q_D(QmlProfilerDataModel);
d->modelManager->traceTime()->setTime(traceStart, traceEnd); d->modelManager->traceTime()->setTime(traceStart, traceEnd);
d->eventList = events;
d->eventTypes = types; d->eventTypes = types;
for (int id = 0; id < types.count(); ++id) for (int id = 0; id < types.count(); ++id)
d->eventTypeIds[types[id]] = id; d->eventTypeIds[types[id]] = id;
foreach (const QmlEvent &event, d->eventList) foreach (const QmlEvent &event, events) {
d->modelManager->dispatch(event, d->eventTypes[event.typeIndex()]); d->modelManager->dispatch(event, d->eventTypes[event.typeIndex()]);
d->eventStream << event;
} }
int QmlProfilerDataModel::count() const
{
Q_D(const QmlProfilerDataModel);
return d->eventList.count();
} }
void QmlProfilerDataModel::clear() void QmlProfilerDataModel::clear()
{ {
Q_D(QmlProfilerDataModel); Q_D(QmlProfilerDataModel);
d->eventList.clear(); d->file.remove();
d->file.open();
d->eventStream.setDevice(&d->file);
d->eventTypes.clear(); d->eventTypes.clear();
d->eventTypeIds.clear(); d->eventTypeIds.clear();
d->rangesInProgress.clear(); d->rangesInProgress.clear();
@@ -166,7 +168,7 @@ void QmlProfilerDataModel::clear()
bool QmlProfilerDataModel::isEmpty() const bool QmlProfilerDataModel::isEmpty() const
{ {
Q_D(const QmlProfilerDataModel); Q_D(const QmlProfilerDataModel);
return d->eventList.isEmpty(); return d->file.pos() == 0;
} }
inline static uint qHash(const QmlEventType &type) inline static uint qHash(const QmlEventType &type)
@@ -234,8 +236,8 @@ int QmlProfilerDataModel::QmlProfilerDataModelPrivate::resolveStackTop()
typeIndex = resolveType(typedEvent.type); typeIndex = resolveType(typedEvent.type);
typedEvent.event.setTypeIndex(typeIndex); typedEvent.event.setTypeIndex(typeIndex);
eventList.append(typedEvent.event); eventStream << typedEvent.event;
modelManager->dispatch(eventList.last(), eventTypes[typeIndex]); modelManager->dispatch(typedEvent.event, eventTypes[typeIndex]);
return typeIndex; return typeIndex;
} }
@@ -256,9 +258,9 @@ void QmlProfilerDataModel::addEvent(const QmlEvent &event, const QmlEventType &t
case RangeEnd: { case RangeEnd: {
int typeIndex = d->resolveStackTop(); int typeIndex = d->resolveStackTop();
QTC_ASSERT(typeIndex != -1, break); QTC_ASSERT(typeIndex != -1, break);
d->eventList.append(event); QmlEvent appended = event;
QmlEvent &appended = d->eventList.last();
appended.setTypeIndex(typeIndex); appended.setTypeIndex(typeIndex);
d->eventStream << appended;
d->modelManager->dispatch(appended, d->eventTypes[typeIndex]); d->modelManager->dispatch(appended, d->eventTypes[typeIndex]);
d->rangesInProgress.pop(); d->rangesInProgress.pop();
break; break;
@@ -270,10 +272,10 @@ void QmlProfilerDataModel::addEvent(const QmlEvent &event, const QmlEventType &t
d->rangesInProgress.top().type.location = type.location; d->rangesInProgress.top().type.location = type.location;
break; break;
default: { default: {
d->eventList.append(event); QmlEvent appended = event;
QmlEvent &appended = d->eventList.last();
int typeIndex = d->resolveType(type); int typeIndex = d->resolveType(type);
appended.setTypeIndex(typeIndex); appended.setTypeIndex(typeIndex);
d->eventStream << appended;
d->modelManager->dispatch(appended, d->eventTypes[typeIndex]); d->modelManager->dispatch(appended, d->eventTypes[typeIndex]);
break; break;
} }
@@ -285,7 +287,15 @@ void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd,
{ {
Q_D(const QmlProfilerDataModel); Q_D(const QmlProfilerDataModel);
QStack<QmlEvent> stack; QStack<QmlEvent> stack;
foreach (const QmlEvent &event, d->eventList) { QmlEvent event;
QFile file(d->file.fileName());
file.open(QIODevice::ReadOnly);
QDataStream stream(&file);
while (!stream.atEnd()) {
stream >> event;
if (stream.status() == QDataStream::ReadPastEnd)
break;
const QmlEventType &type = d->eventTypes[event.typeIndex()]; const QmlEventType &type = d->eventTypes[event.typeIndex()];
if (rangeStart != -1 && rangeEnd != -1) { if (rangeStart != -1 && rangeEnd != -1) {
if (event.timestamp() < rangeStart) { if (event.timestamp() < rangeStart) {
@@ -324,18 +334,10 @@ void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd,
} }
} }
qint64 QmlProfilerDataModel::lastTimeMark() const
{
Q_D(const QmlProfilerDataModel);
if (d->eventList.isEmpty())
return 0;
return d->eventList.last().timestamp();
}
void QmlProfilerDataModel::finalize() void QmlProfilerDataModel::finalize()
{ {
Q_D(QmlProfilerDataModel); Q_D(QmlProfilerDataModel);
d->file.flush();
d->detailsRewriter->reloadDocuments(); d->detailsRewriter->reloadDocuments();
} }

View File

@@ -49,14 +49,12 @@ public:
void setData(qint64 traceStart, qint64 traceEnd, const QVector<QmlEventType> &types, void setData(qint64 traceStart, qint64 traceEnd, const QVector<QmlEventType> &types,
const QVector<QmlEvent> &events); const QVector<QmlEvent> &events);
int count() const;
void clear(); void clear();
bool isEmpty() const; bool isEmpty() const;
void addEvent(const QmlEvent &event, const QmlEventType &type); void addEvent(const QmlEvent &event, const QmlEventType &type);
void replayEvents(qint64 startTime, qint64 endTime, void replayEvents(qint64 startTime, qint64 endTime,
QmlProfilerModelManager::EventLoader loader) const; QmlProfilerModelManager::EventLoader loader) const;
void finalize(); void finalize();
qint64 lastTimeMark() const;
signals: signals:
void allTypesLoaded(); void allTypesLoaded();

View File

@@ -343,7 +343,7 @@ void QmlProfilerModelManager::load(const QString &filename)
reader->eventTypes(), reader->events()); reader->eventTypes(), reader->events());
d->notesModel->setNotes(reader->notes()); d->notesModel->setNotes(reader->notes());
setRecordedFeatures(reader->loadedFeatures()); setRecordedFeatures(reader->loadedFeatures());
d->traceTime->increaseEndTime(d->model->lastTimeMark()); d->traceTime->increaseEndTime(reader->events().last().timestamp());
delete reader; delete reader;
acquiringDone(); acquiringDone();
}, Qt::QueuedConnection); }, Qt::QueuedConnection);

View File

@@ -522,8 +522,7 @@ void QmlProfilerFileWriter::setFuture(QFutureInterface<void> *future)
void QmlProfilerFileWriter::save(QIODevice *device) void QmlProfilerFileWriter::save(QIODevice *device)
{ {
if (m_future) { if (m_future) {
m_future->setProgressRange( m_future->setProgressRange(0, qMax(m_model->eventTypes().size() + m_notes.size(), 1));
0, qMax(m_model->eventTypes().size() + m_model->count() + m_notes.size(), 1));
m_future->setProgressValue(0); m_future->setProgressValue(0);
m_newProgressValue = 0; m_newProgressValue = 0;
} }