diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2016-04-25 14:52:12 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2016-05-02 09:03:46 +0000 |
commit | 434750f1a6cd78b595933210f41e1bf3ab3bd51b (patch) | |
tree | d898623df2075f3376112e856e685472a7cbbf35 /src/plugins | |
parent | a2e64a20777867726b51a9c9196dc1b8dd68f512 (diff) |
QmlProfiler: Reduce memory usage for file names and URLs
As the various file names are actually not kept as QStrings in the
respective objects being profiled, our saving them as QStrings in each
and every profiling event is not implicitly shared and causes a huge
memory overhead. Avoid that by saving each location only once, indexed
by a disguised pointer to the object it refers to.
Normally, objects could disappear during the profiling session, and new
objects could be allocated in their place, which would mess up our
indexing system. We prevent that by referencing the objects when we
index them, thus preventing them from getting auto-destructed.
Mind that those are not JavaScript objects but rather functions,
bindings, components and the like. So, this will only cause a memory
leak if you're compiling and dropping QML components over and over.
Task-number: QTBUG-52937
Change-Id: Ia4dfb09a71a5c9a2d6ce25c3811bbe2a1036c1c1
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp | 29 | ||||
-rw-r--r-- | src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h | 4 |
2 files changed, 25 insertions, 8 deletions
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp index 0ee69a6e02..a193ddea0b 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp @@ -58,14 +58,18 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), engine->profiler, SLOT(setTimer(QElapsedTimer))); - connect(engine->profiler, SIGNAL(dataReady(QVector<QQmlProfilerData>)), - this, SLOT(receiveData(QVector<QQmlProfilerData>))); + connect(engine->profiler, + SIGNAL(dataReady(QVector<QQmlProfilerData>,QQmlProfiler::LocationHash)), + this, + SLOT(receiveData(QVector<QQmlProfilerData>,QQmlProfiler::LocationHash))); } // convert to QByteArrays that can be sent to the debug client // use of QDataStream can skew results // (see tst_qqmldebugtrace::trace() benchmark) -static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d, QList<QByteArray> &messages) +static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d, + const QQmlProfiler::LocationHash &locations, + QList<QByteArray> &messages) { QQmlDebugPacket ds; Q_ASSERT_X((d.messageType & (1 << 31)) == 0, Q_FUNC_INFO, @@ -78,15 +82,18 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d, QList<QByteA //### using QDataStream is relatively expensive ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType); + QQmlProfiler::Location l = locations.value(d.locationId); + switch (decodedMessageType) { case QQmlProfilerDefinitions::RangeStart: case QQmlProfilerDefinitions::RangeEnd: break; case QQmlProfilerDefinitions::RangeData: - ds << (d.detailString.isEmpty() ? d.detailUrl.toString() : d.detailString); + ds << (l.location.sourceFile.isEmpty() ? l.url.toString() : l.location.sourceFile); break; case QQmlProfilerDefinitions::RangeLocation: - ds << (d.detailUrl.isEmpty() ? d.detailString : d.detailUrl.toString()) << d.x << d.y; + ds << (l.url.isEmpty() ? l.location.sourceFile : l.url.toString()) + << static_cast<qint32>(l.location.line) << static_cast<qint32>(l.location.column); break; default: Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); @@ -103,21 +110,29 @@ qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messag const QQmlProfilerData &nextData = data.at(next); if (nextData.time > until || messages.length() > s_numMessagesPerBatch) return nextData.time; - qQmlProfilerDataToByteArrays(nextData, messages); + qQmlProfilerDataToByteArrays(nextData, locations, messages); ++next; } next = 0; data.clear(); + locations.clear(); return -1; } -void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data) +void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data, + const QQmlProfiler::LocationHash &new_locations) { if (data.isEmpty()) data = new_data; else data.append(new_data); + + if (locations.isEmpty()) + locations = new_locations; + else + locations.unite(new_locations); + service->dataReady(this); } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h index 2d93efba1b..7e13b6c479 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h @@ -63,10 +63,12 @@ public: qint64 sendMessages(qint64 until, QList<QByteArray> &messages) Q_DECL_OVERRIDE; public slots: - void receiveData(const QVector<QQmlProfilerData> &new_data); + void receiveData(const QVector<QQmlProfilerData> &new_data, + const QQmlProfiler::LocationHash &locations); private: QVector<QQmlProfilerData> data; + QQmlProfiler::LocationHash locations; int next; }; |