QFile benchmark: only set up and tear down the data directory once

None of the tests modify the data, so there's no risk that one test
will cause another to fail via that. We can thus avoid the repeated
cost of that set-up and teardown, which was done repeatedly for each
test function since benchmarks get run repeatedly if they're quick.

Use QTemporaryDir to manage the test data, so that it's tidied away
automagically, instead of trying to tidy up at the end of each test
(which was, of course, skipped if the test failed).

As drive-bys, fix a typo in a QFAIL()'s message, change some C casts
that silently bulldozed const away to reinterpret_cast<>s with the
const qualifier and turn some heap buffers into stack buffers to save
the need to delete [] them at the end of their tests (also skipped on
failure).

Inspired by a kindred change by Andreas Buhr and a suggestion on its
review by Friedemann Kleint.

Pick-to: 6.2 6.1 5.15
Change-Id: I6067eb35babfbac02990ef39817b0d5122f563cd
Reviewed-by: Andreas Buhr <andreas.buhr@qt.io>
This commit is contained in:
Edward Welbourne 2021-07-12 13:54:46 +02:00
parent a1229a5aa1
commit e1b3a46302

View File

@ -110,54 +110,73 @@ private:
void readFile_data(BenchmarkType type, QIODevice::OpenModeFlag t, QIODevice::OpenModeFlag b);
void readBigFile();
void readSmallFiles();
void createFile();
void fillFile(int factor=FACTOR);
void removeFile();
void createSmallFiles();
void removeSmallFiles();
QString filename;
QString tmpDirName;
class TestDataDir : public QTemporaryDir
{
void createFile();
void createSmallFiles();
public:
TestDataDir() : QTemporaryDir(), fail(errorString().toLocal8Bit())
{
if (fail.isEmpty() && !QTemporaryDir::isValid())
fail = "Failed to create temporary directory for data";
if (isValid())
createSmallFiles();
if (isValid())
createFile();
if (isValid())
QTest::qSleep(2000); // let IO settle
}
bool isValid() { return QTemporaryDir::isValid() && fail.isEmpty(); }
QByteArray fail;
QString filename;
} tempDir;
};
Q_DECLARE_METATYPE(tst_qfile::BenchmarkType)
Q_DECLARE_METATYPE(QIODevice::OpenMode)
Q_DECLARE_METATYPE(QIODevice::OpenModeFlag)
void tst_qfile::createFile()
/* None of the tests modify the test data in tempDir, so it's OK to only create
* and tear down the directory once.
*/
void tst_qfile::TestDataDir::createFile()
{
removeFile(); // Cleanup in case previous test case aborted before cleaning up
QTemporaryFile tmpFile;
tmpFile.setAutoRemove(false);
if (!tmpFile.open())
::exit(1);
QFile tmpFile(filePath("testFile"));
if (!tmpFile.open(QIODevice::WriteOnly)) {
fail = "Unable to prepare files for test";
return;
}
#if 0 // Varied data, rather than filling with '\0' bytes:
for (int row = 0; row < FACTOR; ++row) {
tmpFile.write(QByteArray().fill('0' + row % ('0' - 'z'), 80));
tmpFile.write("\n");
}
#else
tmpFile.seek(FACTOR * 80);
tmpFile.putChar('\n');
#endif
filename = tmpFile.fileName();
tmpFile.close();
}
void tst_qfile::removeFile()
void tst_qfile::TestDataDir::createSmallFiles()
{
if (!filename.isEmpty())
QFile::remove(filename);
}
void tst_qfile::fillFile(int factor)
{
QFile tmpFile(filename);
tmpFile.open(QIODevice::WriteOnly);
//for (int row=0; row<factor; ++row) {
// tmpFile.write(QByteArray().fill('0'+row%('0'-'z'), 80));
// tmpFile.write("\n");
//}
tmpFile.seek(factor*80);
tmpFile.putChar('\n');
tmpFile.close();
// let IO settle
QTest::qSleep(2000);
for (int i = 0; i < 1000; ++i) {
QFile f(filePath(QString::number(i)));
if (!f.open(QIODevice::WriteOnly)) {
fail = "Unable to prepare small files for test";
return;
}
f.seek(511);
f.putChar('\n');
f.close();
}
}
void tst_qfile::initTestCase()
{
QVERIFY2(tempDir.isValid(), tempDir.fail.constData());
}
void tst_qfile::readFile_data(BenchmarkType type, QIODevice::OpenModeFlag t,
@ -228,13 +247,10 @@ void tst_qfile::readBigFile()
QFETCH(QFile::OpenModeFlag, textMode);
QFETCH(QFile::OpenModeFlag, bufferedMode);
char *buffer = new char[BUFSIZE];
createFile();
fillFile();
char buffer[BUFSIZE];
switch (testType) {
case(QFileBenchmark): {
QFile file(filename);
QFile file(tempDir.filename);
file.open(QIODevice::ReadOnly|textMode|bufferedMode);
QBENCHMARK {
while(!file.atEnd())
@ -246,7 +262,7 @@ void tst_qfile::readBigFile()
break;
#ifdef QT_BUILD_INTERNAL
case(QFSFileEngineBenchmark): {
QFSFileEngine fse(filename);
QFSFileEngine fse(tempDir.filename);
fse.open(QIODevice::ReadOnly|textMode|bufferedMode);
QBENCHMARK {
//qWarning() << fse.supportsExtension(QAbstractFileEngine::AtEndExtension);
@ -258,7 +274,7 @@ void tst_qfile::readBigFile()
break;
#endif
case(PosixBenchmark): {
QByteArray data = filename.toLocal8Bit();
QByteArray data = tempDir.filename.toLocal8Bit();
const char* cfilename = data.constData();
FILE* cfile = ::fopen(cfilename, "rb");
QBENCHMARK {
@ -278,7 +294,7 @@ void tst_qfile::readBigFile()
HANDLE hndl;
// ensure we don't account string conversion
wchar_t* cfilename = (wchar_t*)filename.utf16();
const wchar_t *cfilename = reinterpret_cast<const wchar_t *>(tempDir.filename.utf16());
hndl = CreateFile(cfilename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
Q_ASSERT(hndl);
@ -299,9 +315,6 @@ void tst_qfile::readBigFile()
}
break;
}
removeFile();
delete[] buffer;
}
void tst_qfile::seek_data()
@ -322,12 +335,9 @@ void tst_qfile::seek()
QFETCH(tst_qfile::BenchmarkType, testType);
int i = 0;
createFile();
fillFile();
switch (testType) {
case(QFileBenchmark): {
QFile file(filename);
QFile file(tempDir.filename);
file.open(QIODevice::ReadOnly);
QBENCHMARK {
i=(i+1)%sp_size;
@ -338,7 +348,7 @@ void tst_qfile::seek()
break;
#ifdef QT_BUILD_INTERNAL
case(QFSFileEngineBenchmark): {
QFSFileEngine fse(filename);
QFSFileEngine fse(tempDir.filename);
fse.open(QIODevice::ReadOnly | QIODevice::Unbuffered);
QBENCHMARK {
i=(i+1)%sp_size;
@ -349,7 +359,7 @@ void tst_qfile::seek()
break;
#endif
case(PosixBenchmark): {
QByteArray data = filename.toLocal8Bit();
QByteArray data = tempDir.filename.toLocal8Bit();
const char* cfilename = data.constData();
FILE* cfile = ::fopen(cfilename, "rb");
QBENCHMARK {
@ -368,7 +378,7 @@ void tst_qfile::seek()
HANDLE hndl;
// ensure we don't account string conversion
wchar_t* cfilename = (wchar_t*)filename.utf16();
const wchar_t *cfilename = reinterpret_cast<const wchar_t *>(tempDir.filename.utf16());
hndl = CreateFile(cfilename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
Q_ASSERT(hndl);
@ -378,13 +388,11 @@ void tst_qfile::seek()
}
CloseHandle(hndl);
#else
QFAIL("Not running on a Windows plattform!");
QFAIL("Not running on a Windows platform!");
#endif
}
break;
}
removeFile();
}
void tst_qfile::open_data()
@ -405,13 +413,11 @@ void tst_qfile::open()
{
QFETCH(tst_qfile::BenchmarkType, testType);
createFile();
switch (testType) {
case(QFileBenchmark): {
QBENCHMARK {
QFile file( filename );
file.open( QIODevice::ReadOnly );
QFile file(tempDir.filename);
file.open(QIODevice::ReadOnly);
file.close();
}
}
@ -419,7 +425,7 @@ void tst_qfile::open()
#ifdef QT_BUILD_INTERNAL
case(QFSFileEngineBenchmark): {
QBENCHMARK {
QFSFileEngine fse(filename);
QFSFileEngine fse(tempDir.filename);
fse.open(QIODevice::ReadOnly | QIODevice::Unbuffered);
fse.close();
}
@ -428,7 +434,7 @@ void tst_qfile::open()
#endif
case(PosixBenchmark): {
// ensure we don't account toLocal8Bit()
QByteArray data = filename.toLocal8Bit();
QByteArray data = tempDir.filename.toLocal8Bit();
const char* cfilename = data.constData();
QBENCHMARK {
@ -439,7 +445,7 @@ void tst_qfile::open()
break;
case(QFileFromPosixBenchmark): {
// ensure we don't account toLocal8Bit()
QByteArray data = filename.toLocal8Bit();
QByteArray data = tempDir.filename.toLocal8Bit();
const char* cfilename = data.constData();
FILE* cfile = ::fopen(cfilename, "rb");
@ -456,7 +462,7 @@ void tst_qfile::open()
HANDLE hndl;
// ensure we don't account string conversion
wchar_t* cfilename = (wchar_t*)filename.utf16();
const wchar_t *cfilename = reinterpret_cast<const wchar_t *>(tempDir.filename.utf16());
QBENCHMARK {
hndl = CreateFile(cfilename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
@ -469,8 +475,6 @@ void tst_qfile::open()
}
break;
}
removeFile();
}
void tst_qfile::readSmallFiles_QFile_data()
@ -508,31 +512,6 @@ void tst_qfile::readSmallFiles_Win32_data()
#endif
}
void tst_qfile::createSmallFiles()
{
QDir dir = QDir::temp();
dir.mkdir("tst");
dir.cd("tst");
tmpDirName = dir.absolutePath();
for (int i = 0; i < 1000; ++i) {
QFile f(tmpDirName + QLatin1Char('/') + QString::number(i));
f.open(QIODevice::WriteOnly);
f.seek(511);
f.putChar('\n');
f.close();
}
}
void tst_qfile::removeSmallFiles()
{
QDirIterator it(tmpDirName, QDirIterator::FollowSymlinks);
while (it.hasNext())
QFile::remove(it.next());
QDir::temp().rmdir("tst");
}
void tst_qfile::readSmallFiles()
{
QFETCH(tst_qfile::BenchmarkType, testType);
@ -540,17 +519,15 @@ void tst_qfile::readSmallFiles()
QFETCH(QFile::OpenModeFlag, textMode);
QFETCH(QFile::OpenModeFlag, bufferedMode);
createSmallFiles();
QDir dir(tmpDirName);
QDir dir(tempDir.path());
const QStringList files = dir.entryList(QDir::NoDotAndDotDot|QDir::NoSymLinks|QDir::Files);
char *buffer = new char[BUFSIZE];
char buffer[BUFSIZE];
switch (testType) {
case(QFileBenchmark): {
QList<QFile*> fileList;
Q_FOREACH(QString file, files) {
QFile *f = new QFile(tmpDirName + QLatin1Char('/') + file);
QFile *f = new QFile(tempDir.filePath(file));
f->open(QIODevice::ReadOnly|textMode|bufferedMode);
fileList.append(f);
}
@ -573,7 +550,7 @@ void tst_qfile::readSmallFiles()
case(QFSFileEngineBenchmark): {
QList<QFSFileEngine*> fileList;
Q_FOREACH(QString file, files) {
QFSFileEngine *fse = new QFSFileEngine(tmpDirName + QLatin1Char('/') + file);
QFSFileEngine *fse = new QFSFileEngine(tempDir.filePath(file));
fse->open(QIODevice::ReadOnly|textMode|bufferedMode);
fileList.append(fse);
}
@ -594,7 +571,7 @@ void tst_qfile::readSmallFiles()
case(PosixBenchmark): {
QList<FILE*> fileList;
Q_FOREACH(QString file, files) {
fileList.append(::fopen(QFile::encodeName(tmpDirName + QLatin1Char('/') + file).constData(), "rb"));
fileList.append(::fopen(QFile::encodeName(tempDir.filePath(file)).constData(), "rb"));
}
QBENCHMARK {
@ -619,7 +596,7 @@ void tst_qfile::readSmallFiles()
HANDLE hndl;
// ensure we don't account string conversion
wchar_t* cfilename = (wchar_t*)filename.utf16();
const wchar_t *cfilename = reinterpret_cast<const wchar_t *>(tempDir.filename.utf16());
hndl = CreateFile(cfilename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
Q_ASSERT(hndl);
@ -638,9 +615,6 @@ void tst_qfile::readSmallFiles()
}
break;
}
removeSmallFiles();
delete[] buffer;
}
QTEST_MAIN(tst_qfile)