diff options
Diffstat (limited to 'tests/benchmarks/corelib/io/qfile')
-rw-r--r-- | tests/benchmarks/corelib/io/qfile/CMakeLists.txt | 10 | ||||
-rw-r--r-- | tests/benchmarks/corelib/io/qfile/main.cpp | 707 | ||||
-rw-r--r-- | tests/benchmarks/corelib/io/qfile/tst_bench_qfile.cpp | 593 |
3 files changed, 597 insertions, 713 deletions
diff --git a/tests/benchmarks/corelib/io/qfile/CMakeLists.txt b/tests/benchmarks/corelib/io/qfile/CMakeLists.txt index 6ae5029a8a..0cd6b5fb16 100644 --- a/tests/benchmarks/corelib/io/qfile/CMakeLists.txt +++ b/tests/benchmarks/corelib/io/qfile/CMakeLists.txt @@ -1,4 +1,5 @@ -# Generated from qfile.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_bench_qfile Binary: @@ -6,15 +7,12 @@ qt_internal_add_benchmark(tst_bench_qfile SOURCES - main.cpp - PUBLIC_LIBRARIES + tst_bench_qfile.cpp + LIBRARIES Qt::CorePrivate Qt::Test ) -#### Keys ignored in scope 1:.:.:qfile.pro:<TRUE>: -# TEMPLATE = "app" - ## Scopes: ##################################################################### diff --git a/tests/benchmarks/corelib/io/qfile/main.cpp b/tests/benchmarks/corelib/io/qfile/main.cpp deleted file mode 100644 index 73b3ba8c48..0000000000 --- a/tests/benchmarks/corelib/io/qfile/main.cpp +++ /dev/null @@ -1,707 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QDebug> -#include <QTemporaryFile> -#include <QString> -#include <QDirIterator> - -#include <private/qfsfileengine_p.h> - -#include <qtest.h> - -#include <stdio.h> - -#ifdef Q_OS_WIN -# include <windows.h> -#endif - -#if defined(Q_OS_QNX) && defined(open) -#undef open -#endif - -#define BUFSIZE 1024*512 -#define FACTOR 1024*512 -#define TF_SIZE FACTOR*81 - -// 10 predefined (but random() seek positions -// hardcoded to be comparable over several runs -const int seekpos[] = {int(TF_SIZE*0.52), - int(TF_SIZE*0.23), - int(TF_SIZE*0.73), - int(TF_SIZE*0.77), - int(TF_SIZE*0.80), - int(TF_SIZE*0.12), - int(TF_SIZE*0.53), - int(TF_SIZE*0.21), - int(TF_SIZE*0.27), - int(TF_SIZE*0.78)}; - -const int sp_size = sizeof(seekpos)/sizeof(int); - -class tst_qfile: public QObject -{ -Q_ENUMS(BenchmarkType) -Q_OBJECT -public: - enum BenchmarkType { - QFileBenchmark = 1, -#ifdef QT_BUILD_INTERNAL - QFSFileEngineBenchmark, -#endif - Win32Benchmark, - PosixBenchmark, - QFileFromPosixBenchmark - }; -private slots: - void initTestCase(); - void cleanupTestCase(); - - void open_data(); - void open(); - void seek_data(); - void seek(); - - void readSmallFiles_QFile(); - void readSmallFiles_QFSFileEngine(); - void readSmallFiles_posix(); - void readSmallFiles_Win32(); - - void readSmallFiles_QFile_data(); - void readSmallFiles_QFSFileEngine_data(); - void readSmallFiles_posix_data(); - void readSmallFiles_Win32_data(); - - void readBigFile_QFile_data(); - void readBigFile_QFSFileEngine_data(); - void readBigFile_posix_data(); - void readBigFile_Win32_data(); - - void readBigFile_QFile(); - void readBigFile_QFSFileEngine(); - void readBigFile_posix(); - void readBigFile_Win32(); - -private: - void readBigFile_data(BenchmarkType type, QIODevice::OpenModeFlag t, QIODevice::OpenModeFlag b); - void readBigFile(); - void readSmallFiles_data(BenchmarkType type, QIODevice::OpenModeFlag t, QIODevice::OpenModeFlag b); - void readSmallFiles(); - void createFile(); - void fillFile(int factor=FACTOR); - void removeFile(); - void createSmallFiles(); - void removeSmallFiles(); - QString filename; - QString tmpDirName; -}; - -Q_DECLARE_METATYPE(tst_qfile::BenchmarkType) -Q_DECLARE_METATYPE(QIODevice::OpenMode) -Q_DECLARE_METATYPE(QIODevice::OpenModeFlag) - -void tst_qfile::createFile() -{ - removeFile(); // Cleanup in case previous test case aborted before cleaning up - - QTemporaryFile tmpFile; - tmpFile.setAutoRemove(false); - if (!tmpFile.open()) - ::exit(1); - filename = tmpFile.fileName(); - tmpFile.close(); -} - -void tst_qfile::removeFile() -{ - 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); -} - -void tst_qfile::initTestCase() -{ -} - -void tst_qfile::cleanupTestCase() -{ -} - -void tst_qfile::readBigFile_QFile() { readBigFile(); } -void tst_qfile::readBigFile_QFSFileEngine() -{ -#ifdef QT_BUILD_INTERNAL - readBigFile(); -#else - QSKIP("This test requires -developer-build."); -#endif -} -void tst_qfile::readBigFile_posix() -{ - readBigFile(); -} -void tst_qfile::readBigFile_Win32() { readBigFile(); } - -void tst_qfile::readBigFile_QFile_data() -{ - readBigFile_data(QFileBenchmark, QIODevice::NotOpen, QIODevice::NotOpen); - readBigFile_data(QFileBenchmark, QIODevice::NotOpen, QIODevice::Unbuffered); - readBigFile_data(QFileBenchmark, QIODevice::Text, QIODevice::NotOpen); - readBigFile_data(QFileBenchmark, QIODevice::Text, QIODevice::Unbuffered); - -} - -void tst_qfile::readBigFile_QFSFileEngine_data() -{ -#ifdef QT_BUILD_INTERNAL - readBigFile_data(QFSFileEngineBenchmark, QIODevice::NotOpen, QIODevice::NotOpen); - readBigFile_data(QFSFileEngineBenchmark, QIODevice::NotOpen, QIODevice::Unbuffered); - readBigFile_data(QFSFileEngineBenchmark, QIODevice::Text, QIODevice::NotOpen); - readBigFile_data(QFSFileEngineBenchmark, QIODevice::Text, QIODevice::Unbuffered); -#else - QTest::addColumn<int>("dummy"); - QTest::newRow("Test will be skipped") << -1; -#endif -} - -void tst_qfile::readBigFile_posix_data() -{ - readBigFile_data(PosixBenchmark, QIODevice::NotOpen, QIODevice::NotOpen); -} - -void tst_qfile::readBigFile_Win32_data() -{ - readBigFile_data(Win32Benchmark, QIODevice::NotOpen, QIODevice::NotOpen); -} - - -void tst_qfile::readBigFile_data(BenchmarkType type, QIODevice::OpenModeFlag t, QIODevice::OpenModeFlag b) -{ - QTest::addColumn<tst_qfile::BenchmarkType>("testType"); - QTest::addColumn<int>("blockSize"); - QTest::addColumn<QFile::OpenModeFlag>("textMode"); - QTest::addColumn<QFile::OpenModeFlag>("bufferedMode"); - - const int bs[] = {1024, 1024*2, 1024*8, 1024*16, 1024*32,1024*512}; - int bs_entries = sizeof(bs)/sizeof(const int); - - QString flagstring; - if (t & QIODevice::Text) flagstring += "textMode "; - if (b & QIODevice::Unbuffered) flagstring += "unbuffered "; - if (flagstring.isEmpty()) flagstring = "none"; - - for (int i=0; i<bs_entries; ++i) - QTest::newRow((QString("BS: %1, Flags: %2" )).arg(bs[i]).arg(flagstring).toLatin1().constData()) << type << bs[i] << t << b; -} - -void tst_qfile::readBigFile() -{ - QFETCH(tst_qfile::BenchmarkType, testType); - QFETCH(int, blockSize); - QFETCH(QFile::OpenModeFlag, textMode); - QFETCH(QFile::OpenModeFlag, bufferedMode); - -#ifndef Q_OS_WIN - if (testType == Win32Benchmark) - QSKIP("This is Windows only benchmark."); -#endif - - char *buffer = new char[BUFSIZE]; - createFile(); - fillFile(); - - switch (testType) { - case(QFileBenchmark): { - QFile file(filename); - file.open(QIODevice::ReadOnly|textMode|bufferedMode); - QBENCHMARK { - while(!file.atEnd()) - file.read(blockSize); - file.reset(); - } - file.close(); - } - break; -#ifdef QT_BUILD_INTERNAL - case(QFSFileEngineBenchmark): { - QFSFileEngine fse(filename); - fse.open(QIODevice::ReadOnly|textMode|bufferedMode); - QBENCHMARK { - //qWarning() << fse.supportsExtension(QAbstractFileEngine::AtEndExtension); - while(fse.read(buffer, blockSize)); - fse.seek(0); - } - fse.close(); - } - break; -#endif - case(PosixBenchmark): { - QByteArray data = filename.toLocal8Bit(); - const char* cfilename = data.constData(); - FILE* cfile = ::fopen(cfilename, "rb"); - QBENCHMARK { - while(!feof(cfile)) - ::fread(buffer, blockSize, 1, cfile); - ::fseek(cfile, 0, SEEK_SET); - } - ::fclose(cfile); - } - break; - case(QFileFromPosixBenchmark): { - // No gain in benchmarking this case - } - break; - case(Win32Benchmark): { -#ifdef Q_OS_WIN - HANDLE hndl; - - // ensure we don't account string conversion - wchar_t* cfilename = (wchar_t*)filename.utf16(); - - hndl = CreateFile(cfilename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); - Q_ASSERT(hndl); - wchar_t* nativeBuffer = new wchar_t[BUFSIZE]; - DWORD numberOfBytesRead; - - QBENCHMARK { - do { - ReadFile(hndl, nativeBuffer, blockSize, &numberOfBytesRead, NULL); - } while(numberOfBytesRead != 0); - SetFilePointer(hndl, 0, NULL, FILE_BEGIN); - } - delete[] nativeBuffer; - CloseHandle(hndl); -#else - QFAIL("Not running on a non-Windows platform!"); -#endif - } - break; - } - - removeFile(); - delete[] buffer; -} - -void tst_qfile::seek_data() -{ - QTest::addColumn<tst_qfile::BenchmarkType>("testType"); - QTest::newRow("QFile") << QFileBenchmark; -#ifdef QT_BUILD_INTERNAL - QTest::newRow("QFSFileEngine") << QFSFileEngineBenchmark; -#endif - QTest::newRow("Posix FILE*") << PosixBenchmark; -#ifdef Q_OS_WIN - QTest::newRow("Win32 API") << Win32Benchmark; -#endif -} - -void tst_qfile::seek() -{ - QFETCH(tst_qfile::BenchmarkType, testType); - int i = 0; - - createFile(); - fillFile(); - - switch (testType) { - case(QFileBenchmark): { - QFile file(filename); - file.open(QIODevice::ReadOnly); - QBENCHMARK { - i=(i+1)%sp_size; - file.seek(seekpos[i]); - } - file.close(); - } - break; -#ifdef QT_BUILD_INTERNAL - case(QFSFileEngineBenchmark): { - QFSFileEngine fse(filename); - fse.open(QIODevice::ReadOnly); - QBENCHMARK { - i=(i+1)%sp_size; - fse.seek(seekpos[i]); - } - fse.close(); - } - break; -#endif - case(PosixBenchmark): { - QByteArray data = filename.toLocal8Bit(); - const char* cfilename = data.constData(); - FILE* cfile = ::fopen(cfilename, "rb"); - QBENCHMARK { - i=(i+1)%sp_size; - ::fseek(cfile, seekpos[i], SEEK_SET); - } - ::fclose(cfile); - } - break; - case(QFileFromPosixBenchmark): { - // No gain in benchmarking this case - } - break; - case(Win32Benchmark): { -#ifdef Q_OS_WIN - HANDLE hndl; - - // ensure we don't account string conversion - wchar_t* cfilename = (wchar_t*)filename.utf16(); - - hndl = CreateFile(cfilename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); - Q_ASSERT(hndl); - QBENCHMARK { - i=(i+1)%sp_size; - SetFilePointer(hndl, seekpos[i], NULL, 0); - } - CloseHandle(hndl); -#else - QFAIL("Not running on a Windows plattform!"); -#endif - } - break; - } - - removeFile(); -} - -void tst_qfile::open_data() -{ - QTest::addColumn<tst_qfile::BenchmarkType>("testType"); - QTest::newRow("QFile") << QFileBenchmark; -#ifdef QT_BUILD_INTERNAL - QTest::newRow("QFSFileEngine") << QFSFileEngineBenchmark; -#endif - QTest::newRow("Posix FILE*") << PosixBenchmark; - QTest::newRow("QFile from FILE*") << QFileFromPosixBenchmark; -#ifdef Q_OS_WIN - QTest::newRow("Win32 API") << Win32Benchmark; -#endif -} - -void tst_qfile::open() -{ - QFETCH(tst_qfile::BenchmarkType, testType); - - createFile(); - - switch (testType) { - case(QFileBenchmark): { - QBENCHMARK { - QFile file( filename ); - file.open( QIODevice::ReadOnly ); - file.close(); - } - } - break; -#ifdef QT_BUILD_INTERNAL - case(QFSFileEngineBenchmark): { - QBENCHMARK { - QFSFileEngine fse(filename); - fse.open(QIODevice::ReadOnly); - fse.close(); - } - } - break; -#endif - case(PosixBenchmark): { - // ensure we don't account toLocal8Bit() - QByteArray data = filename.toLocal8Bit(); - const char* cfilename = data.constData(); - - QBENCHMARK { - FILE* cfile = ::fopen(cfilename, "rb"); - ::fclose(cfile); - } - } - break; - case(QFileFromPosixBenchmark): { - // ensure we don't account toLocal8Bit() - QByteArray data = filename.toLocal8Bit(); - const char* cfilename = data.constData(); - FILE* cfile = ::fopen(cfilename, "rb"); - - QBENCHMARK { - QFile file; - file.open(cfile, QIODevice::ReadOnly); - file.close(); - } - ::fclose(cfile); - } - break; - case(Win32Benchmark): { -#ifdef Q_OS_WIN - HANDLE hndl; - - // ensure we don't account string conversion - wchar_t* cfilename = (wchar_t*)filename.utf16(); - - QBENCHMARK { - hndl = CreateFile(cfilename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); - Q_ASSERT(hndl); - CloseHandle(hndl); - } -#else - QFAIL("Not running on a non-Windows platform!"); -#endif - } - break; - } - - removeFile(); -} - - -void tst_qfile::readSmallFiles_QFile() { readSmallFiles(); } -void tst_qfile::readSmallFiles_QFSFileEngine() -{ -#ifdef QT_BUILD_INTERNAL - readSmallFiles(); -#else - QSKIP("This test requires -developer-build."); -#endif -} -void tst_qfile::readSmallFiles_posix() -{ - readSmallFiles(); -} -void tst_qfile::readSmallFiles_Win32() -{ - readSmallFiles(); -} - -void tst_qfile::readSmallFiles_QFile_data() -{ - readSmallFiles_data(QFileBenchmark, QIODevice::NotOpen, QIODevice::NotOpen); - readSmallFiles_data(QFileBenchmark, QIODevice::NotOpen, QIODevice::Unbuffered); - readSmallFiles_data(QFileBenchmark, QIODevice::Text, QIODevice::NotOpen); - readSmallFiles_data(QFileBenchmark, QIODevice::Text, QIODevice::Unbuffered); - -} - -void tst_qfile::readSmallFiles_QFSFileEngine_data() -{ -#ifdef QT_BUILD_INTERNAL - readSmallFiles_data(QFSFileEngineBenchmark, QIODevice::NotOpen, QIODevice::NotOpen); - readSmallFiles_data(QFSFileEngineBenchmark, QIODevice::NotOpen, QIODevice::Unbuffered); - readSmallFiles_data(QFSFileEngineBenchmark, QIODevice::Text, QIODevice::NotOpen); - readSmallFiles_data(QFSFileEngineBenchmark, QIODevice::Text, QIODevice::Unbuffered); -#else - QTest::addColumn<int>("dummy"); - QTest::newRow("Test will be skipped") << -1; -#endif -} - -void tst_qfile::readSmallFiles_posix_data() -{ - readSmallFiles_data(PosixBenchmark, QIODevice::NotOpen, QIODevice::NotOpen); -} - -void tst_qfile::readSmallFiles_Win32_data() -{ - readSmallFiles_data(Win32Benchmark, QIODevice::NotOpen, QIODevice::NotOpen); -} - - -void tst_qfile::readSmallFiles_data(BenchmarkType type, QIODevice::OpenModeFlag t, QIODevice::OpenModeFlag b) -{ - QTest::addColumn<tst_qfile::BenchmarkType>("testType"); - QTest::addColumn<int>("blockSize"); - QTest::addColumn<QFile::OpenModeFlag>("textMode"); - QTest::addColumn<QFile::OpenModeFlag>("bufferedMode"); - - const int bs[] = {1024, 1024*2, 1024*8, 1024*16, 1024*32,1024*512}; - int bs_entries = sizeof(bs)/sizeof(const int); - - QString flagstring; - if (t & QIODevice::Text) flagstring += "textMode "; - if (b & QIODevice::Unbuffered) flagstring += "unbuffered "; - if (flagstring.isEmpty()) flagstring = "none"; - - for (int i=0; i<bs_entries; ++i) - QTest::newRow((QString("BS: %1, Flags: %2" )).arg(bs[i]).arg(flagstring).toLatin1().constData()) << type << bs[i] << t << b; - -} - -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); - QFETCH(int, blockSize); - QFETCH(QFile::OpenModeFlag, textMode); - QFETCH(QFile::OpenModeFlag, bufferedMode); - -#ifndef Q_OS_WIN - if (testType == Win32Benchmark) - QSKIP("This is Windows only benchmark."); -#endif - - createSmallFiles(); - - QDir dir(tmpDirName); - const QStringList files = dir.entryList(QDir::NoDotAndDotDot|QDir::NoSymLinks|QDir::Files); - char *buffer = new char[BUFSIZE]; - - switch (testType) { - case(QFileBenchmark): { - QList<QFile*> fileList; - Q_FOREACH(QString file, files) { - QFile *f = new QFile(tmpDirName + QLatin1Char('/') + file); - f->open(QIODevice::ReadOnly|textMode|bufferedMode); - fileList.append(f); - } - - QBENCHMARK { - Q_FOREACH(QFile *file, fileList) { - while (!file->atEnd()) { - file->read(buffer, blockSize); - } - } - } - - Q_FOREACH(QFile *file, fileList) { - file->close(); - delete file; - } - } - break; -#ifdef QT_BUILD_INTERNAL - case(QFSFileEngineBenchmark): { - QList<QFSFileEngine*> fileList; - Q_FOREACH(QString file, files) { - QFSFileEngine *fse = new QFSFileEngine(tmpDirName + QLatin1Char('/') + file); - fse->open(QIODevice::ReadOnly|textMode|bufferedMode); - fileList.append(fse); - } - - QBENCHMARK { - Q_FOREACH(QFSFileEngine *fse, fileList) { - while (fse->read(buffer, blockSize)); - } - } - - Q_FOREACH(QFSFileEngine *fse, fileList) { - fse->close(); - delete fse; - } - } - break; -#endif - case(PosixBenchmark): { - QList<FILE*> fileList; - Q_FOREACH(QString file, files) { - fileList.append(::fopen(QFile::encodeName(tmpDirName + QLatin1Char('/') + file).constData(), "rb")); - } - - QBENCHMARK { - Q_FOREACH(FILE* cfile, fileList) { - while(!feof(cfile)) - ::fread(buffer, blockSize, 1, cfile); - ::fseek(cfile, 0, SEEK_SET); - } - } - - Q_FOREACH(FILE* cfile, fileList) { - ::fclose(cfile); - } - } - break; - case(QFileFromPosixBenchmark): { - // No gain in benchmarking this case - } - break; - case(Win32Benchmark): { -#ifdef Q_OS_WIN - HANDLE hndl; - - // ensure we don't account string conversion - wchar_t* cfilename = (wchar_t*)filename.utf16(); - - hndl = CreateFile(cfilename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); - Q_ASSERT(hndl); - wchar_t* nativeBuffer = new wchar_t[BUFSIZE]; - DWORD numberOfBytesRead; - QBENCHMARK { - do { - ReadFile(hndl, nativeBuffer, blockSize, &numberOfBytesRead, NULL); - } while(numberOfBytesRead != 0); - } - delete nativeBuffer; - CloseHandle(hndl); -#else - QFAIL("Not running on a non-Windows platform!"); -#endif - } - break; - } - - removeSmallFiles(); - delete[] buffer; -} - -QTEST_MAIN(tst_qfile) - -#include "main.moc" diff --git a/tests/benchmarks/corelib/io/qfile/tst_bench_qfile.cpp b/tests/benchmarks/corelib/io/qfile/tst_bench_qfile.cpp new file mode 100644 index 0000000000..b805726f5f --- /dev/null +++ b/tests/benchmarks/corelib/io/qfile/tst_bench_qfile.cpp @@ -0,0 +1,593 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QDebug> +#include <QTemporaryFile> +#include <QString> +#include <QDirIterator> + +#include <private/qfsfileengine_p.h> + +#include <qtest.h> + +#include <stdio.h> + +#ifdef Q_OS_WIN +# include <qt_windows.h> +#endif + +#if defined(Q_OS_QNX) && defined(open) +#undef open +#endif + +#define BUFSIZE 1024*512 +#define FACTOR 1024*512 +#define TF_SIZE FACTOR*81 + +// 10 predefined (but random() seek positions +// hardcoded to be comparable over several runs +const int seekpos[] = {int(TF_SIZE*0.52), + int(TF_SIZE*0.23), + int(TF_SIZE*0.73), + int(TF_SIZE*0.77), + int(TF_SIZE*0.80), + int(TF_SIZE*0.12), + int(TF_SIZE*0.53), + int(TF_SIZE*0.21), + int(TF_SIZE*0.27), + int(TF_SIZE*0.78)}; + +const int sp_size = sizeof(seekpos)/sizeof(int); + +class tst_qfile: public QObject +{ +Q_ENUMS(BenchmarkType) +Q_OBJECT +public: + enum BenchmarkType { + QFileBenchmark = 1, +#ifdef QT_BUILD_INTERNAL + QFSFileEngineBenchmark, +#endif + Win32Benchmark, + PosixBenchmark, + QFileFromPosixBenchmark + }; +private slots: + void initTestCase(); + + void open_data(); + void open(); + void seek_data(); + void seek(); + + void readSmallFiles_QFile() { readSmallFiles(); } + void readSmallFiles_QFSFileEngine() { readSmallFiles(); } + void readSmallFiles_posix() { readSmallFiles(); } + void readSmallFiles_Win32() { readSmallFiles(); } + + void readSmallFiles_QFile_data(); + void readSmallFiles_QFSFileEngine_data(); + void readSmallFiles_posix_data(); + void readSmallFiles_Win32_data(); + + void readBigFile_QFile_data(); + void readBigFile_QFSFileEngine_data(); + void readBigFile_posix_data(); + void readBigFile_Win32_data(); + + void readBigFile_QFile() { readBigFile(); } + void readBigFile_QFSFileEngine() { readBigFile(); } + void readBigFile_posix() { readBigFile(); } + void readBigFile_Win32() { readBigFile(); } + +private: + void readFile_data(BenchmarkType type, QIODevice::OpenModeFlag t, QIODevice::OpenModeFlag b); + void readBigFile(); + void readSmallFiles(); + + 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) + +/* 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() +{ + 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::TestDataDir::createSmallFiles() +{ + 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, + QIODevice::OpenModeFlag b) +{ + QTest::addColumn<tst_qfile::BenchmarkType>("testType"); + QTest::addColumn<int>("blockSize"); + QTest::addColumn<QFile::OpenModeFlag>("textMode"); + QTest::addColumn<QFile::OpenModeFlag>("bufferedMode"); + + QByteArray flagstring; + if (t & QIODevice::Text) + flagstring += "textMode"; + if (b & QIODevice::Unbuffered) { + if (flagstring.size()) + flagstring += ' '; + flagstring += "unbuffered"; + } + if (flagstring.isEmpty()) + flagstring = "none"; + + const int kbs[] = {1, 2, 8, 16, 32, 512}; + for (int kb : kbs) { + const int size = 1024 * kb; + QTest::addRow("BS: %d, Flags: %s", size, flagstring.constData()) + << type << size << t << b; + } +} + +void tst_qfile::readBigFile_QFile_data() +{ + readFile_data(QFileBenchmark, QIODevice::NotOpen, QIODevice::NotOpen); + readFile_data(QFileBenchmark, QIODevice::NotOpen, QIODevice::Unbuffered); + readFile_data(QFileBenchmark, QIODevice::Text, QIODevice::NotOpen); + readFile_data(QFileBenchmark, QIODevice::Text, QIODevice::Unbuffered); + +} + +void tst_qfile::readBigFile_QFSFileEngine_data() +{ +#ifdef QT_BUILD_INTERNAL + // Support for buffering dropped at 5.10, so only test Unbuffered + readFile_data(QFSFileEngineBenchmark, QIODevice::NotOpen, QIODevice::Unbuffered); + readFile_data(QFSFileEngineBenchmark, QIODevice::Text, QIODevice::Unbuffered); +#else + QSKIP("This test requires -developer-build."); +#endif +} + +void tst_qfile::readBigFile_posix_data() +{ + readFile_data(PosixBenchmark, QIODevice::NotOpen, QIODevice::NotOpen); +} + +void tst_qfile::readBigFile_Win32_data() +{ +#ifdef Q_OS_WIN + readFile_data(Win32Benchmark, QIODevice::NotOpen, QIODevice::NotOpen); +#else + QSKIP("This is Windows only benchmark."); +#endif +} + +void tst_qfile::readBigFile() +{ + QFETCH(tst_qfile::BenchmarkType, testType); + QFETCH(int, blockSize); + QFETCH(QFile::OpenModeFlag, textMode); + QFETCH(QFile::OpenModeFlag, bufferedMode); + + char buffer[BUFSIZE]; + switch (testType) { + case QFileBenchmark: { + QFile file(tempDir.filename); + file.open(QIODevice::ReadOnly|textMode|bufferedMode); + QBENCHMARK { + while(!file.atEnd()) + file.read(blockSize); + file.reset(); + } + file.close(); + } + break; +#ifdef QT_BUILD_INTERNAL + case QFSFileEngineBenchmark: { + QFSFileEngine fse(tempDir.filename); + fse.open(QIODevice::ReadOnly | textMode | bufferedMode, std::nullopt); + QBENCHMARK { + //qWarning() << fse.supportsExtension(QAbstractFileEngine::AtEndExtension); + while (fse.read(buffer, blockSize)) {} + fse.seek(0); + } + fse.close(); + } + break; +#endif + case PosixBenchmark: { + QByteArray data = tempDir.filename.toLocal8Bit(); + const char* cfilename = data.constData(); + FILE* cfile = ::fopen(cfilename, "rb"); + QBENCHMARK { + while(!feof(cfile)) + [[maybe_unused]] auto r = ::fread(buffer, blockSize, 1, cfile); + ::fseek(cfile, 0, SEEK_SET); + } + ::fclose(cfile); + } + break; + case QFileFromPosixBenchmark: { + // No gain in benchmarking this case + } + break; + case Win32Benchmark: { +#ifdef Q_OS_WIN + HANDLE hndl; + + // ensure we don't account string conversion + 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); + wchar_t* nativeBuffer = new wchar_t[BUFSIZE]; + DWORD numberOfBytesRead; + + QBENCHMARK { + do { + ReadFile(hndl, nativeBuffer, blockSize, &numberOfBytesRead, NULL); + } while(numberOfBytesRead != 0); + SetFilePointer(hndl, 0, NULL, FILE_BEGIN); + } + delete[] nativeBuffer; + CloseHandle(hndl); +#else + QFAIL("Not running on a non-Windows platform!"); +#endif + } + break; + } +} + +void tst_qfile::seek_data() +{ + QTest::addColumn<tst_qfile::BenchmarkType>("testType"); + QTest::newRow("QFile") << QFileBenchmark; +#ifdef QT_BUILD_INTERNAL + QTest::newRow("QFSFileEngine") << QFSFileEngineBenchmark; +#endif + QTest::newRow("Posix FILE*") << PosixBenchmark; +#ifdef Q_OS_WIN + QTest::newRow("Win32 API") << Win32Benchmark; +#endif +} + +void tst_qfile::seek() +{ + QFETCH(tst_qfile::BenchmarkType, testType); + int i = 0; + + switch (testType) { + case QFileBenchmark: { + QFile file(tempDir.filename); + file.open(QIODevice::ReadOnly); + QBENCHMARK { + i=(i+1)%sp_size; + file.seek(seekpos[i]); + } + file.close(); + } + break; +#ifdef QT_BUILD_INTERNAL + case QFSFileEngineBenchmark: { + QFSFileEngine fse(tempDir.filename); + fse.open(QIODevice::ReadOnly | QIODevice::Unbuffered, std::nullopt); + QBENCHMARK { + i=(i+1)%sp_size; + fse.seek(seekpos[i]); + } + fse.close(); + } + break; +#endif + case PosixBenchmark: { + QByteArray data = tempDir.filename.toLocal8Bit(); + const char* cfilename = data.constData(); + FILE* cfile = ::fopen(cfilename, "rb"); + QBENCHMARK { + i=(i+1)%sp_size; + ::fseek(cfile, seekpos[i], SEEK_SET); + } + ::fclose(cfile); + } + break; + case QFileFromPosixBenchmark: { + // No gain in benchmarking this case + } + break; + case Win32Benchmark: { +#ifdef Q_OS_WIN + HANDLE hndl; + + // ensure we don't account string conversion + 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); + QBENCHMARK { + i=(i+1)%sp_size; + SetFilePointer(hndl, seekpos[i], NULL, 0); + } + CloseHandle(hndl); +#else + QFAIL("Not running on a Windows platform!"); +#endif + } + break; + } +} + +void tst_qfile::open_data() +{ + QTest::addColumn<tst_qfile::BenchmarkType>("testType"); + QTest::newRow("QFile") << QFileBenchmark; +#ifdef QT_BUILD_INTERNAL + QTest::newRow("QFSFileEngine") << QFSFileEngineBenchmark; +#endif + QTest::newRow("Posix FILE*") << PosixBenchmark; + QTest::newRow("QFile from FILE*") << QFileFromPosixBenchmark; +#ifdef Q_OS_WIN + QTest::newRow("Win32 API") << Win32Benchmark; +#endif +} + +void tst_qfile::open() +{ + QFETCH(tst_qfile::BenchmarkType, testType); + + switch (testType) { + case QFileBenchmark: { + QBENCHMARK { + QFile file(tempDir.filename); + file.open(QIODevice::ReadOnly); + file.close(); + } + } + break; +#ifdef QT_BUILD_INTERNAL + case QFSFileEngineBenchmark: { + QBENCHMARK { + QFSFileEngine fse(tempDir.filename); + fse.open(QIODevice::ReadOnly | QIODevice::Unbuffered, std::nullopt); + fse.close(); + } + } + break; +#endif + case PosixBenchmark: { + // ensure we don't account toLocal8Bit() + QByteArray data = tempDir.filename.toLocal8Bit(); + const char* cfilename = data.constData(); + + QBENCHMARK { + FILE* cfile = ::fopen(cfilename, "rb"); + ::fclose(cfile); + } + } + break; + case QFileFromPosixBenchmark: { + // ensure we don't account toLocal8Bit() + QByteArray data = tempDir.filename.toLocal8Bit(); + const char* cfilename = data.constData(); + FILE* cfile = ::fopen(cfilename, "rb"); + + QBENCHMARK { + QFile file; + file.open(cfile, QIODevice::ReadOnly); + file.close(); + } + ::fclose(cfile); + } + break; + case Win32Benchmark: { +#ifdef Q_OS_WIN + HANDLE hndl; + + // ensure we don't account string conversion + const wchar_t *cfilename = reinterpret_cast<const wchar_t *>(tempDir.filename.utf16()); + + QBENCHMARK { + hndl = CreateFile(cfilename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); + Q_ASSERT(hndl); + CloseHandle(hndl); + } +#else + QFAIL("Not running on a non-Windows platform!"); +#endif + } + break; + } +} + +void tst_qfile::readSmallFiles_QFile_data() +{ + readFile_data(QFileBenchmark, QIODevice::NotOpen, QIODevice::NotOpen); + readFile_data(QFileBenchmark, QIODevice::NotOpen, QIODevice::Unbuffered); + readFile_data(QFileBenchmark, QIODevice::Text, QIODevice::NotOpen); + readFile_data(QFileBenchmark, QIODevice::Text, QIODevice::Unbuffered); + +} + +void tst_qfile::readSmallFiles_QFSFileEngine_data() +{ +#ifdef QT_BUILD_INTERNAL + // Support for buffering dropped at 5.10, so only test Unbuffered + readFile_data(QFSFileEngineBenchmark, QIODevice::NotOpen, QIODevice::Unbuffered); + readFile_data(QFSFileEngineBenchmark, QIODevice::Text, QIODevice::Unbuffered); +#else + QSKIP("This test requires -developer-build."); +#endif +} + +void tst_qfile::readSmallFiles_posix_data() +{ + readFile_data(PosixBenchmark, QIODevice::NotOpen, QIODevice::NotOpen); +} + +void tst_qfile::readSmallFiles_Win32_data() +{ + +#ifdef Q_OS_WIN + readFile_data(Win32Benchmark, QIODevice::NotOpen, QIODevice::NotOpen); +#else + QSKIP("This is Windows only benchmark."); +#endif +} + +void tst_qfile::readSmallFiles() +{ + QFETCH(tst_qfile::BenchmarkType, testType); + QFETCH(int, blockSize); + QFETCH(QFile::OpenModeFlag, textMode); + QFETCH(QFile::OpenModeFlag, bufferedMode); + + QDir dir(tempDir.path()); + const QStringList files = dir.entryList(QDir::NoDotAndDotDot|QDir::NoSymLinks|QDir::Files); + char buffer[BUFSIZE]; + + switch (testType) { + case QFileBenchmark: { + QList<QFile*> fileList; + for (const QString &file : files) { + QFile *f = new QFile(tempDir.filePath(file)); + f->open(QIODevice::ReadOnly|textMode|bufferedMode); + fileList.append(f); + } + + QBENCHMARK { + for (QFile *const file : std::as_const(fileList)) { + while (!file->atEnd()) + file->read(buffer, blockSize); + } + } + + for (QFile *const file : std::as_const(fileList)) { + file->close(); + delete file; + } + } + break; +#ifdef QT_BUILD_INTERNAL + case QFSFileEngineBenchmark: { + QList<QFSFileEngine*> fileList; + for (const QString &file : files) { + QFSFileEngine *fse = new QFSFileEngine(tempDir.filePath(file)); + fse->open(QIODevice::ReadOnly | textMode | bufferedMode, std::nullopt); + fileList.append(fse); + } + + QBENCHMARK { + for (QFSFileEngine *const fse : std::as_const(fileList)) + while (fse->read(buffer, blockSize)) {} + } + + for (QFSFileEngine *const fse : std::as_const(fileList)) { + fse->close(); + delete fse; + } + } + break; +#endif + case PosixBenchmark: { + QList<FILE *> fileList; + for (const QString &file : files) + fileList.append(::fopen(QFile::encodeName(tempDir.filePath(file)).constData(), "rb")); + + QBENCHMARK { + for (FILE *const cfile : std::as_const(fileList)) { + while (!feof(cfile)) + [[maybe_unused]] auto f = ::fread(buffer, blockSize, 1, cfile); + ::fseek(cfile, 0, SEEK_SET); + } + } + + for (FILE *const cfile : std::as_const(fileList)) + ::fclose(cfile); + } + break; + case QFileFromPosixBenchmark: { + // No gain in benchmarking this case + } + break; + case Win32Benchmark: { +#ifdef Q_OS_WIN + HANDLE hndl; + + // ensure we don't account string conversion + 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); + wchar_t* nativeBuffer = new wchar_t[BUFSIZE]; + DWORD numberOfBytesRead; + QBENCHMARK { + do { + ReadFile(hndl, nativeBuffer, blockSize, &numberOfBytesRead, NULL); + } while(numberOfBytesRead != 0); + } + delete nativeBuffer; + CloseHandle(hndl); +#else + QFAIL("Not running on a non-Windows platform!"); +#endif + } + break; + } +} + +QTEST_MAIN(tst_qfile) + +#include "tst_bench_qfile.moc" |