aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@theqtcompany.com>2016-03-03 13:38:27 +0100
committerUlf Hermann <ulf.hermann@theqtcompany.com>2016-03-11 09:19:01 +0000
commit6300f4dde0ab3279b18a0fb29f94cfe142557cba (patch)
tree4158af34ad0e812fa50f8b046f54439411ebc151 /src/plugins
parent9ca9de7cbc8b045c19899987d6666576399af33d (diff)
QmlDebug: Reuse packets instead of deleting and recreating them
This reduces memory churn as we don't have to reallocate the various QPacket, QBuffer, QByteArray objects and their private classes all the time. Also, subsequent packets often have similar sizes, which makes it beneficial to preallocate the underlying byte array to the size of the previous packet on clear(). In order not to carry the extra reserved space in the lists passed to the debug server, we squeeze the byte arrays before inserting them into the lists. That detaches and copies them, which would have been done anyway when reusing the same packet for the next message. The result is a reduction in the number of temporary memory allocations from QQmlProfilerServiceImpl::sendMessages() by about 75%. Change-Id: Ief98cd7a93a2e8e840e111dee6b346cae00e06bf Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/qmltooling/packetprotocol/qpacket.cpp27
-rw-r--r--src/plugins/qmltooling/packetprotocol/qpacket_p.h4
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp6
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp51
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h6
-rw-r--r--src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp6
6 files changed, 64 insertions, 36 deletions
diff --git a/src/plugins/qmltooling/packetprotocol/qpacket.cpp b/src/plugins/qmltooling/packetprotocol/qpacket.cpp
index c42288e920..fab0a5b189 100644
--- a/src/plugins/qmltooling/packetprotocol/qpacket.cpp
+++ b/src/plugins/qmltooling/packetprotocol/qpacket.cpp
@@ -108,11 +108,34 @@ QPacket::QPacket(int version, const QByteArray &data)
}
/*!
- Returns raw packet data.
+ Returns a reference to the raw packet data.
*/
-QByteArray QPacket::data() const
+const QByteArray &QPacket::data() const
{
return buf.data();
}
+/*!
+ Returns a copy of the raw packet data, with extra reserved space removed.
+ Mind that this triggers a deep copy. Use it if you anticipate the data to be detached soon anyway.
+ */
+QByteArray QPacket::squeezedData() const
+{
+ QByteArray ret = buf.data();
+ ret.squeeze();
+ return ret;
+}
+
+/*!
+ Clears the packet, discarding any data.
+ */
+void QPacket::clear()
+{
+ buf.reset();
+ QByteArray &buffer = buf.buffer();
+ // Keep the old size to prevent unnecessary allocations
+ buffer.reserve(buffer.capacity());
+ buffer.truncate(0);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/packetprotocol/qpacket_p.h b/src/plugins/qmltooling/packetprotocol/qpacket_p.h
index a079b244e8..b6fda2411d 100644
--- a/src/plugins/qmltooling/packetprotocol/qpacket_p.h
+++ b/src/plugins/qmltooling/packetprotocol/qpacket_p.h
@@ -61,7 +61,9 @@ class QPacket : public QDataStream
public:
QPacket(int version);
explicit QPacket(int version, const QByteArray &ba);
- QByteArray data() const;
+ const QByteArray &data() const;
+ QByteArray squeezedData() const;
+ void clear();
private:
void init(QIODevice::OpenMode mode);
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
index 872dcbe718..688ced26ec 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
@@ -67,7 +67,7 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin
// (see tst_qqmldebugtrace::trace() benchmark)
static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList<QByteArray> &messages)
{
- QByteArray data;
+ QQmlDebugPacket ds;
Q_ASSERT_X(((d->messageType | d->detailType) & (1 << 31)) == 0, Q_FUNC_INFO,
"You can use at most 31 message types and 31 detail types.");
for (uint decodedMessageType = 0; (d->messageType >> decodedMessageType) != 0;
@@ -81,7 +81,6 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList<QByteA
continue;
//### using QDataStream is relatively expensive
- QQmlDebugPacket ds;
ds << d->time << decodedMessageType << decodedDetailType;
switch (decodedMessageType) {
@@ -99,7 +98,8 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList<QByteA
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type.");
break;
}
- messages << ds.data();
+ messages.append(ds.squeezedData());
+ ds.clear();
}
}
}
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
index e91f7fbf51..b50eef5545 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
@@ -39,7 +39,6 @@
#include "qv4profileradapter.h"
#include "qqmlprofilerservice.h"
-#include "qqmldebugpacket.h"
QT_BEGIN_NAMESPACE
@@ -68,27 +67,28 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut
QVector<QV4::Profiling::MemoryAllocationProperties>)));
}
-qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages)
+qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages,
+ QQmlDebugPacket &d)
{
while (m_memoryData.length() > m_memoryPos && m_memoryData[m_memoryPos].timestamp <= until) {
- QQmlDebugPacket d;
QV4::Profiling::MemoryAllocationProperties &props = m_memoryData[m_memoryPos];
d << props.timestamp << MemoryAllocation << props.type << props.size;
++m_memoryPos;
- messages.append(d.data());
+ messages.append(d.squeezedData());
+ d.clear();
}
return m_memoryData.length() == m_memoryPos ? -1 : m_memoryData[m_memoryPos].timestamp;
}
qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &messages,
- qint64 callNext)
+ qint64 callNext, QQmlDebugPacket &d)
{
if (callNext == -1) {
m_functionCallData.clear();
m_functionCallPos = 0;
}
- qint64 memoryNext = appendMemoryEvents(until, messages);
+ qint64 memoryNext = appendMemoryEvents(until, messages, d);
if (memoryNext == -1) {
m_memoryData.clear();
@@ -101,42 +101,43 @@ qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &mes
qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
{
+ QQmlDebugPacket d;
while (true) {
while (!m_stack.isEmpty() &&
(m_functionCallPos == m_functionCallData.length() ||
m_stack.top() <= m_functionCallData[m_functionCallPos].start)) {
if (m_stack.top() > until || messages.length() > s_numMessagesPerBatch)
- return finalizeMessages(until, messages, m_stack.top());
+ return finalizeMessages(until, messages, m_stack.top(), d);
- appendMemoryEvents(m_stack.top(), messages);
- QQmlDebugPacket d;
+ appendMemoryEvents(m_stack.top(), messages, d);
d << m_stack.pop() << RangeEnd << Javascript;
- messages.append(d.data());
+ messages.append(d.squeezedData());
+ d.clear();
}
while (m_functionCallPos != m_functionCallData.length() &&
(m_stack.empty() || m_functionCallData[m_functionCallPos].start < m_stack.top())) {
const QV4::Profiling::FunctionCallProperties &props =
m_functionCallData[m_functionCallPos];
if (props.start > until || messages.length() > s_numMessagesPerBatch)
- return finalizeMessages(until, messages, props.start);
-
- appendMemoryEvents(props.start, messages);
-
- QQmlDebugPacket d_start;
- d_start << props.start << RangeStart << Javascript;
- messages.push_back(d_start.data());
- QQmlDebugPacket d_location;
- d_location << props.start << RangeLocation << Javascript << props.file << props.line
- << props.column;
- messages.push_back(d_location.data());
- QQmlDebugPacket d_data;
- d_data << props.start << RangeData << Javascript << props.name;
- messages.push_back(d_data.data());
+ return finalizeMessages(until, messages, props.start, d);
+
+ appendMemoryEvents(props.start, messages, d);
+
+ d << props.start << RangeStart << Javascript;
+ messages.push_back(d.squeezedData());
+ d.clear();
+ d << props.start << RangeLocation << Javascript << props.file << props.line
+ << props.column;
+ messages.push_back(d.squeezedData());
+ d.clear();
+ d << props.start << RangeData << Javascript << props.name;
+ messages.push_back(d.squeezedData());
+ d.clear();
m_stack.push(props.end);
++m_functionCallPos;
}
if (m_stack.empty() && m_functionCallPos == m_functionCallData.length())
- return finalizeMessages(until, messages, -1);
+ return finalizeMessages(until, messages, -1, d);
}
}
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h
index 303ccab72c..f2985af98b 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h
+++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h
@@ -53,6 +53,7 @@
#include <private/qv4profiling_p.h>
#include <private/qqmlabstractprofileradapter_p.h>
+#include "qqmldebugpacket.h"
#include <QStack>
#include <QList>
@@ -86,8 +87,9 @@ private:
int m_functionCallPos;
int m_memoryPos;
QStack<qint64> m_stack;
- qint64 appendMemoryEvents(qint64 until, QList<QByteArray> &messages);
- qint64 finalizeMessages(qint64 until, QList<QByteArray> &messages, qint64 callNext);
+ qint64 appendMemoryEvents(qint64 until, QList<QByteArray> &messages, QQmlDebugPacket &d);
+ qint64 finalizeMessages(qint64 until, QList<QByteArray> &messages, qint64 callNext,
+ QQmlDebugPacket &d);
static quint64 translateFeatures(quint64 qmlFeatures);
};
diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
index 0f44ba3dc2..9a2afd367d 100644
--- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
@@ -79,6 +79,7 @@ QQuickProfilerAdapter::~QQuickProfilerAdapter()
static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data,
QList<QByteArray> &messages)
{
+ QQmlDebugPacket ds;
Q_ASSERT_X(((data.messageType | data.detailType) & (1 << 31)) == 0, Q_FUNC_INFO,
"You can use at most 31 message types and 31 detail types.");
for (uint decodedMessageType = 0; (data.messageType >> decodedMessageType) != 0;
@@ -91,8 +92,6 @@ static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data,
if ((data.detailType & (1 << decodedDetailType)) == 0)
continue;
- //### using QDataStream is relatively expensive
- QQmlDebugPacket ds;
ds << data.time << decodedMessageType << decodedDetailType;
switch (decodedMessageType) {
@@ -145,7 +144,8 @@ static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data,
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type.");
break;
}
- messages << ds.data();
+ messages.append(ds.squeezedData());
+ ds.clear();
}
}
}