QIODevice: implement a "zero-copy" strategy for buffered writes
It works as follows: - user calls write(const QByteArray &); - this function keeps a pointer to the chunk and calls a regular write(data, len); - write(data, len) calls a virtual writeData(); - subclass calls a new QIODevicePrivate::write(); - QIODevicePrivate::write() makes a shallow copy of the byte array. Proposed solution is fully compatible with existing subclasses. By replacing a call to d->writeBuffer.append() with d->write(), subclasses can improve their performance. Bump the TypeInformationVersion field in qtHookData, to notify the Qt Creator developers that the offset of QFilePrivate::fileName was changed and dumpers should be adapted. Change-Id: I24713386cc74a9f37e5223c617e4b1ba97f968dc Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
729d102b1c
commit
a41c61fb2d
@ -67,7 +67,7 @@ quintptr Q_CORE_EXPORT qtHookData[] = {
|
|||||||
// The required sizes and offsets are tested in tests/auto/other/toolsupport.
|
// The required sizes and offsets are tested in tests/auto/other/toolsupport.
|
||||||
// When this fails and the change was intentional, adjust the test and
|
// When this fails and the change was intentional, adjust the test and
|
||||||
// adjust this value here.
|
// adjust this value here.
|
||||||
18
|
19
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0]));
|
static_assert(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0]));
|
||||||
|
@ -158,13 +158,14 @@ static void checkWarnMessage(const QIODevice *device, const char *function, cons
|
|||||||
QIODevicePrivate::QIODevicePrivate()
|
QIODevicePrivate::QIODevicePrivate()
|
||||||
: openMode(QIODevice::NotOpen),
|
: openMode(QIODevice::NotOpen),
|
||||||
pos(0), devicePos(0),
|
pos(0), devicePos(0),
|
||||||
|
transactionPos(0),
|
||||||
readChannelCount(0),
|
readChannelCount(0),
|
||||||
writeChannelCount(0),
|
writeChannelCount(0),
|
||||||
currentReadChannel(0),
|
currentReadChannel(0),
|
||||||
currentWriteChannel(0),
|
currentWriteChannel(0),
|
||||||
readBufferChunkSize(QIODEVICE_BUFFERSIZE),
|
readBufferChunkSize(QIODEVICE_BUFFERSIZE),
|
||||||
writeBufferChunkSize(0),
|
writeBufferChunkSize(0),
|
||||||
transactionPos(0),
|
currentWriteChunk(nullptr),
|
||||||
transactionStarted(false)
|
transactionStarted(false)
|
||||||
, baseReadLineDataCalled(false)
|
, baseReadLineDataCalled(false)
|
||||||
, accessMode(Unset)
|
, accessMode(Unset)
|
||||||
@ -1750,7 +1751,34 @@ qint64 QIODevice::write(const char *data)
|
|||||||
|
|
||||||
qint64 QIODevice::write(const QByteArray &data)
|
qint64 QIODevice::write(const QByteArray &data)
|
||||||
{
|
{
|
||||||
return write(data.constData(), data.size());
|
Q_D(QIODevice);
|
||||||
|
|
||||||
|
// Keep the chunk pointer for further processing in
|
||||||
|
// QIODevicePrivate::write(). To reduce fragmentation,
|
||||||
|
// the chunk size must be sufficiently large.
|
||||||
|
if (data.size() >= QRINGBUFFER_CHUNKSIZE)
|
||||||
|
d->currentWriteChunk = &data;
|
||||||
|
|
||||||
|
const qint64 ret = write(data.constData(), data.size());
|
||||||
|
|
||||||
|
d->currentWriteChunk = nullptr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
void QIODevicePrivate::write(const char *data, qint64 size)
|
||||||
|
{
|
||||||
|
if (currentWriteChunk != nullptr
|
||||||
|
&& currentWriteChunk->constData() == data
|
||||||
|
&& currentWriteChunk->size() == size) {
|
||||||
|
// We are called from write(const QByteArray &) overload.
|
||||||
|
// So, we can make a shallow copy of chunk.
|
||||||
|
writeBuffer.append(*currentWriteChunk);
|
||||||
|
} else {
|
||||||
|
writeBuffer.append(data, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -124,13 +124,14 @@ public:
|
|||||||
QRingBufferRef writeBuffer;
|
QRingBufferRef writeBuffer;
|
||||||
qint64 pos;
|
qint64 pos;
|
||||||
qint64 devicePos;
|
qint64 devicePos;
|
||||||
|
qint64 transactionPos;
|
||||||
int readChannelCount;
|
int readChannelCount;
|
||||||
int writeChannelCount;
|
int writeChannelCount;
|
||||||
int currentReadChannel;
|
int currentReadChannel;
|
||||||
int currentWriteChannel;
|
int currentWriteChannel;
|
||||||
int readBufferChunkSize;
|
int readBufferChunkSize;
|
||||||
int writeBufferChunkSize;
|
int writeBufferChunkSize;
|
||||||
qint64 transactionPos;
|
const QByteArray *currentWriteChunk;
|
||||||
bool transactionStarted;
|
bool transactionStarted;
|
||||||
bool baseReadLineDataCalled;
|
bool baseReadLineDataCalled;
|
||||||
|
|
||||||
@ -175,6 +176,7 @@ public:
|
|||||||
virtual qint64 peek(char *data, qint64 maxSize);
|
virtual qint64 peek(char *data, qint64 maxSize);
|
||||||
virtual QByteArray peek(qint64 maxSize);
|
virtual QByteArray peek(qint64 maxSize);
|
||||||
qint64 skipByReading(qint64 maxSize);
|
qint64 skipByReading(qint64 maxSize);
|
||||||
|
void write(const char *data, qint64 size);
|
||||||
|
|
||||||
#ifdef QT_NO_QOBJECT
|
#ifdef QT_NO_QOBJECT
|
||||||
QIODevice *q_ptr;
|
QIODevice *q_ptr;
|
||||||
|
@ -1899,7 +1899,7 @@ qint64 QProcess::writeData(const char *data, qint64 len)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
d->writeBuffer.append(data, len);
|
d->write(data, len);
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
if (!d->stdinWriteTrigger->isActive())
|
if (!d->stdinWriteTrigger->isActive())
|
||||||
d->stdinWriteTrigger->start();
|
d->stdinWriteTrigger->start();
|
||||||
|
@ -2542,7 +2542,7 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
|
|||||||
// We just write to our write buffer and enable the write notifier
|
// We just write to our write buffer and enable the write notifier
|
||||||
// The write notifier then flush()es the buffer.
|
// The write notifier then flush()es the buffer.
|
||||||
|
|
||||||
d->writeBuffer.append(data, size);
|
d->write(data, size);
|
||||||
qint64 written = size;
|
qint64 written = size;
|
||||||
|
|
||||||
if (d->socketEngine && !d->writeBuffer.isEmpty())
|
if (d->socketEngine && !d->writeBuffer.isEmpty())
|
||||||
|
@ -214,7 +214,7 @@ qint64 QLocalSocket::writeData(const char *data, qint64 len)
|
|||||||
Q_D(QLocalSocket);
|
Q_D(QLocalSocket);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
d->writeBuffer.append(data, len);
|
d->write(data, len);
|
||||||
if (!d->pipeWriter) {
|
if (!d->pipeWriter) {
|
||||||
d->pipeWriter = new QWindowsPipeWriter(d->handle, this);
|
d->pipeWriter = new QWindowsPipeWriter(d->handle, this);
|
||||||
connect(d->pipeWriter, &QWindowsPipeWriter::bytesWritten,
|
connect(d->pipeWriter, &QWindowsPipeWriter::bytesWritten,
|
||||||
|
@ -1819,7 +1819,7 @@ qint64 QSslSocket::writeData(const char *data, qint64 len)
|
|||||||
if (d->mode == UnencryptedMode && !d->autoStartHandshake)
|
if (d->mode == UnencryptedMode && !d->autoStartHandshake)
|
||||||
return d->plainSocket->write(data, len);
|
return d->plainSocket->write(data, len);
|
||||||
|
|
||||||
d->writeBuffer.append(data, len);
|
d->write(data, len);
|
||||||
|
|
||||||
// make sure we flush to the plain socket's buffer
|
// make sure we flush to the plain socket's buffer
|
||||||
if (!d->flushTriggered) {
|
if (!d->flushTriggered) {
|
||||||
|
@ -126,9 +126,9 @@ void tst_toolsupport::offsets_data()
|
|||||||
#ifdef Q_PROCESSOR_X86
|
#ifdef Q_PROCESSOR_X86
|
||||||
// x86 32-bit has weird alignment rules. Refer to QtPrivate::AlignOf in
|
// x86 32-bit has weird alignment rules. Refer to QtPrivate::AlignOf in
|
||||||
// qglobal.h for more details.
|
// qglobal.h for more details.
|
||||||
data << 184 << 288;
|
data << 188 << 296;
|
||||||
#else
|
#else
|
||||||
data << 188 << 288;
|
data << 192 << 296;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user