summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qfile.cpp
diff options
context:
space:
mode:
authormread <qt-info@nokia.com>2010-03-24 12:25:58 (GMT)
committermread <qt-info@nokia.com>2010-03-24 12:43:09 (GMT)
commitd0645d1792e1cbdf417a923ea071975e4390fccd (patch)
tree2697d23c3eead57aad7ca5f88f3ab2e3914168b1 /src/corelib/io/qfile.cpp
parentfa2a64ee5ec1d9e65cb0c4b984c27b56fdae0120 (diff)
downloadQt-d0645d1792e1cbdf417a923ea071975e4390fccd.zip
Qt-d0645d1792e1cbdf417a923ea071975e4390fccd.tar.gz
Qt-d0645d1792e1cbdf417a923ea071975e4390fccd.tar.bz2
QIODevice::read() and QFile::atEnd() performance improvements
atEnd improvements, since atEnd is used in published example Qt read loops. The two main ideas are to push the buffer test forward, which optimises the normal buffered case, and to cache the file size till you get to the end, which otherwise has to get the file size every 16K of data. read buffer improvements: The ring buffer structure was causing significant performance overheads. In practice QIODevice has much simpler requirements on its read buffer, and a linear buffer can be used instead. This now uses a buffer optimised to QIODevice's use of it. QIODevice read function improvements. There are a number of sub-themes here, which all are aimed at getting the normal buffered path through the code done as fast as possible. This gives greatest improvements for small reads, but it is these small reads that have the biggest problems. - removing the isSequential test, by setting a pointer to the qint64 to update and using a dummy qint64 target when isSequential, then writing through the pointer. - doing the readability check on the first read only, out of the fast path - doing the maxSize<0 test after the getchar fast path - removing the buffer isEmpty test and giving a fast exit test instead - moving arithmetic out of the fast path, so "data" and "maxSize" are now dynamically updating - for RCVT builds, ARM mode is used for the read functions because the 64-bit operations are much slower with this compiler in Thumb mode There are some other changes to read() which improve clarity: - bytesToBuffer is now always set to QIODEVICE_BUFFERSIZE. This has always been the case, its just that the logic was not clear before. - moreToRead is set to false now in the case where the request was met by a direct device read. Leaving it true in this case was pointless, and setting it true in the converse case seems dangerous because the function might iterate for a very long time, although it might meet the API semantics better and would be a change in behavior because the function used to not read more when it claimed it would. Reviewed-by: Joao Reviewed-by: Aleksandar Babic
Diffstat (limited to 'src/corelib/io/qfile.cpp')
-rw-r--r--src/corelib/io/qfile.cpp46
1 files changed, 35 insertions, 11 deletions
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index aa1c7d9..50e9a8f 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -90,7 +90,8 @@ QFile::DecoderFn QFilePrivate::decoder = locale_decode;
QFilePrivate::QFilePrivate()
: fileEngine(0), lastWasWrite(false),
- writeBuffer(QFILE_WRITEBUFFER_SIZE), error(QFile::NoError)
+ writeBuffer(QFILE_WRITEBUFFER_SIZE), error(QFile::NoError),
+ cachedSize(0)
{
}
@@ -1257,8 +1258,10 @@ QFile::resize(qint64 sz)
seek(sz);
if(d->fileEngine->setSize(sz)) {
unsetError();
+ d->cachedSize = sz;
return true;
}
+ d->cachedSize = 0;
d->setError(QFile::ResizeError, d->fileEngine->errorString());
return false;
}
@@ -1420,7 +1423,8 @@ qint64 QFile::size() const
Q_D(const QFile);
if (!d->ensureFlushed())
return 0;
- return fileEngine()->size();
+ d->cachedSize = fileEngine()->size();
+ return d->cachedSize;
}
/*!
@@ -1446,16 +1450,16 @@ bool QFile::atEnd() const
{
Q_D(const QFile);
+ // If there's buffered data left, we're not at the end.
+ if (!d->buffer.isEmpty())
+ return false;
+
if (!isOpen())
return true;
if (!d->ensureFlushed())
return false;
- // If there's buffered data left, we're not at the end.
- if (!d->buffer.isEmpty())
- return false;
-
// If the file engine knows best, say what it says.
if (d->fileEngine->supportsExtension(QAbstractFileEngine::AtEndExtension)) {
// Check if the file engine supports AtEndExtension, and if it does,
@@ -1463,6 +1467,11 @@ bool QFile::atEnd() const
return d->fileEngine->atEnd();
}
+ // if it looks like we are at the end, or if size is not cached,
+ // fall through to bytesAvailable() to make sure.
+ if (pos() < d->cachedSize)
+ return false;
+
// Fall back to checking how much is available (will stat files).
return bytesAvailable() == 0;
}
@@ -1502,12 +1511,21 @@ qint64 QFile::readLineData(char *data, qint64 maxlen)
if (!d->ensureFlushed())
return -1;
- if (d->fileEngine->supportsExtension(QAbstractFileEngine::FastReadLineExtension))
- return d->fileEngine->readLine(data, maxlen);
+ qint64 read;
+ if (d->fileEngine->supportsExtension(QAbstractFileEngine::FastReadLineExtension)) {
+ read = d->fileEngine->readLine(data, maxlen);
+ } else {
+ // Fall back to QIODevice's readLine implementation if the engine
+ // cannot do it faster.
+ read = QIODevice::readLineData(data, maxlen);
+ }
+
+ if (read < maxlen) {
+ // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked
+ d->cachedSize = 0;
+ }
- // Fall back to QIODevice's readLine implementation if the engine
- // cannot do it faster.
- return QIODevice::readLineData(data, maxlen);
+ return read;
}
/*!
@@ -1528,6 +1546,12 @@ qint64 QFile::readData(char *data, qint64 len)
err = QFile::ReadError;
d->setError(err, d->fileEngine->errorString());
}
+
+ if (read < len) {
+ // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked
+ d->cachedSize = 0;
+ }
+
return read;
}