aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2016-04-25 14:52:12 +0200
committerUlf Hermann <ulf.hermann@qt.io>2016-05-02 09:03:46 +0000
commit434750f1a6cd78b595933210f41e1bf3ab3bd51b (patch)
treed898623df2075f3376112e856e685472a7cbbf35 /src/plugins
parenta2e64a20777867726b51a9c9196dc1b8dd68f512 (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.cpp29
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h4
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;
};