mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-02 07:15:27 +08:00
qt 6.5.1 original
This commit is contained in:
22
tests/benchmarks/CMakeLists.txt
Normal file
22
tests/benchmarks/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(corelib)
|
||||
if(TARGET Qt::DBus)
|
||||
add_subdirectory(dbus)
|
||||
endif()
|
||||
if(TARGET Qt::Gui)
|
||||
add_subdirectory(gui)
|
||||
endif()
|
||||
if(TARGET Qt::Network)
|
||||
add_subdirectory(network)
|
||||
endif()
|
||||
if(TARGET Qt::Sql)
|
||||
add_subdirectory(sql)
|
||||
endif()
|
||||
if(TARGET Qt::Test)
|
||||
add_subdirectory(testlib)
|
||||
endif()
|
||||
if(TARGET Qt::Widgets)
|
||||
add_subdirectory(widgets)
|
||||
endif()
|
81
tests/benchmarks/README
Normal file
81
tests/benchmarks/README
Normal file
@ -0,0 +1,81 @@
|
||||
The most reliable way of running benchmarks is to do it in an otherwise idle
|
||||
system. On a busy system, the results will vary according to the other tasks
|
||||
demanding attention in the system.
|
||||
|
||||
We have managed to obtain quite reliable results by doing the following on
|
||||
Linux (and you need root):
|
||||
|
||||
- switching the scheduler to a Real-Time mode
|
||||
- setting the processor affinity to one single processor
|
||||
- disabling the other thread of the same core
|
||||
|
||||
This should work rather well for CPU-intensive tasks. A task that is in Real-
|
||||
Time mode will simply not be preempted by the OS. But if you make OS syscalls,
|
||||
especially I/O ones, your task will be de-scheduled. Note that this includes
|
||||
page faults, so if you can, make sure your benchmark's warmup code paths touch
|
||||
most of the data.
|
||||
|
||||
To do this you need a tool called schedtool (package schedtool), from
|
||||
http://freequaos.host.sk/schedtool/
|
||||
|
||||
From this point on, we are using CPU0 for all tasks:
|
||||
|
||||
If you have a Hyperthreaded multi-core processor (Core-i5 and Core-i7), you
|
||||
have to disable the other thread of the same core as CPU0. To discover which
|
||||
one it is:
|
||||
|
||||
$ cat /sys/devices/system/cpu/cpu0/topology/thread_siblings_list
|
||||
|
||||
This will print something like 0,4, meaning that CPUs 0 and 4 are sibling
|
||||
threads on the same core. So we'll turn CPU 4 off:
|
||||
|
||||
(as root)
|
||||
# echo 0 > /sys/devices/system/cpu/cpu4/online
|
||||
|
||||
To turn it back on, echo 1 into the same file.
|
||||
|
||||
To run a task on CPU 0 exclusively, using FIFO RT priority 10, you run the
|
||||
following:
|
||||
|
||||
(as root)
|
||||
# schedtool -F -p 10 -a 1 -e ./taskname
|
||||
|
||||
For example:
|
||||
# schedtool -F -p 10 -a 1 -e ./tst_bench_qstring -tickcounter
|
||||
|
||||
Warning: if your task livelocks or takes far too long to complete, your system
|
||||
may be unusable for a long time, especially if you don't have other cores to
|
||||
run stuff on. To prevent that, run it before schedtool and time it.
|
||||
|
||||
You can also limit the CPU time that the task is allowed to take. Run in the
|
||||
same shell as you'll run schedtool:
|
||||
|
||||
$ ulimit -s 300
|
||||
To limit to 300 seconds (5 minutes)
|
||||
|
||||
If your task runs away, it will get a SIGXCPU after consuming 5 minutes of CPU
|
||||
time (5 minutes running at 100%).
|
||||
|
||||
If your app is multithreaded, you may want to give it more CPUs, like CPU0 and
|
||||
CPU1 with -a 3 (it's a bitmask).
|
||||
|
||||
For best results, you should disable ALL other cores and threads of the same
|
||||
processor. The new Core-i7 have one processor with 4 cores,
|
||||
each core can run 2 threads; the older Mac Pros have two processors with 4
|
||||
cores each. So on those Mac Pros, you'd disable cores 1, 2 and 3, while on the
|
||||
Core-i7, you'll need to disable all other CPUs.
|
||||
|
||||
However, disabling just the sibling thread seems to produce very reliable
|
||||
results for me already, with variance often below 0.5% (even though there are
|
||||
some measurable spikes).
|
||||
|
||||
Other things to try:
|
||||
|
||||
Running the benchmark with highest priority, i.e. "sudo nice -19"
|
||||
usually produces stable results on some machines. If the benchmark also
|
||||
involves displaying something on the screen (on X11), running it with
|
||||
"-sync" is a must. Though, in that case the "real" cost is not correct,
|
||||
but it is useful to discover regressions.
|
||||
|
||||
Also; not many people know about ionice (1)
|
||||
ionice - get/set program io scheduling class and priority
|
13
tests/benchmarks/corelib/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(io)
|
||||
add_subdirectory(itemmodels)
|
||||
add_subdirectory(json)
|
||||
add_subdirectory(mimetypes)
|
||||
add_subdirectory(kernel)
|
||||
add_subdirectory(text)
|
||||
add_subdirectory(thread)
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(plugin)
|
14
tests/benchmarks/corelib/io/CMakeLists.txt
Normal file
14
tests/benchmarks/corelib/io/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(qdir)
|
||||
add_subdirectory(qdiriterator)
|
||||
add_subdirectory(qfile)
|
||||
add_subdirectory(qfileinfo)
|
||||
add_subdirectory(qiodevice)
|
||||
if(QT_FEATURE_process)
|
||||
add_subdirectory(qprocess)
|
||||
endif()
|
||||
add_subdirectory(qtemporaryfile)
|
||||
add_subdirectory(qtextstream)
|
||||
add_subdirectory(qurl)
|
13
tests/benchmarks/corelib/io/qdir/10000/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/io/qdir/10000/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qdir_10000 Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qdir_10000
|
||||
SOURCES
|
||||
tst_bench_qdir_10000.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
185
tests/benchmarks/corelib/io/qdir/10000/tst_bench_qdir_10000.cpp
Normal file
185
tests/benchmarks/corelib/io/qdir/10000/tst_bench_qdir_10000.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QDirIterator>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <qt_windows.h>
|
||||
#else
|
||||
# include <sys/stat.h>
|
||||
# include <sys/types.h>
|
||||
# include <dirent.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
class tst_QDir_10000 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
void initTestCase()
|
||||
{
|
||||
QDir testdir = QDir::tempPath();
|
||||
|
||||
const QString subfolder_name = QLatin1String("test_speed");
|
||||
QVERIFY(testdir.mkdir(subfolder_name));
|
||||
QVERIFY(testdir.cd(subfolder_name));
|
||||
|
||||
for (uint i=0; i<10000; ++i) {
|
||||
QFile file(testdir.absolutePath() + "/testfile_" + QString::number(i));
|
||||
file.open(QIODevice::WriteOnly);
|
||||
}
|
||||
}
|
||||
void cleanupTestCase()
|
||||
{
|
||||
QDir testdir(QDir::tempPath() + QLatin1String("/test_speed"));
|
||||
QVERIFY(testdir.removeRecursively());
|
||||
}
|
||||
private slots:
|
||||
void sizeSpeed()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QDir testdir(QDir::tempPath() + QLatin1String("/test_speed"));
|
||||
QFileInfoList fileInfoList = testdir.entryInfoList(QDir::Files, QDir::Unsorted);
|
||||
foreach (const QFileInfo &fileInfo, fileInfoList) {
|
||||
fileInfo.isDir();
|
||||
fileInfo.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
void sizeSpeedIterator()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QDir testdir(QDir::tempPath() + QLatin1String("/test_speed"));
|
||||
QDirIterator dit(testdir.path(), QDir::Files);
|
||||
while (dit.hasNext()) {
|
||||
const auto fi = dit.nextFileInfo();
|
||||
(void)fi.isDir();
|
||||
(void)fi.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sizeSpeedWithoutFilter()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QDir testdir(QDir::tempPath() + QLatin1String("/test_speed"));
|
||||
QFileInfoList fileInfoList = testdir.entryInfoList(QDir::NoFilter, QDir::Unsorted);
|
||||
foreach (const QFileInfo &fileInfo, fileInfoList) {
|
||||
fileInfo.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
void sizeSpeedWithoutFilterIterator()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QDir testdir(QDir::tempPath() + QLatin1String("/test_speed"));
|
||||
QDirIterator dit(testdir.path());
|
||||
while (dit.hasNext()) {
|
||||
const auto fi = dit.nextFileInfo();
|
||||
(void)fi.isDir();
|
||||
(void)fi.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sizeSpeedWithoutFileInfoList()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QDir testdir(QDir::tempPath() + QLatin1String("/test_speed"));
|
||||
testdir.setSorting(QDir::Unsorted);
|
||||
QStringList fileList = testdir.entryList(QDir::NoFilter, QDir::Unsorted);
|
||||
foreach (const QString &filename, fileList) {
|
||||
QFileInfo fileInfo(filename);
|
||||
fileInfo.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void iDontWantAnyStat()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QDir testdir(QDir::tempPath() + QLatin1String("/test_speed"));
|
||||
testdir.setSorting(QDir::Unsorted);
|
||||
testdir.setFilter(QDir::AllEntries | QDir::System | QDir::Hidden);
|
||||
QStringList fileList = testdir.entryList(QDir::NoFilter, QDir::Unsorted);
|
||||
foreach (const QString &filename, fileList) {
|
||||
Q_UNUSED(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
void iDontWantAnyStatIterator()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QDirIterator dit(QDir::tempPath() + QLatin1String("/test_speed"));
|
||||
while (dit.hasNext()) {
|
||||
dit.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sorted_byTime()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QDir testdir(QDir::tempPath() + QLatin1String("/test_speed"));
|
||||
testdir.setSorting(QDir::Time);
|
||||
testdir.setFilter(QDir::AllEntries | QDir::System | QDir::Hidden);
|
||||
QStringList fileList = testdir.entryList(QDir::NoFilter, QDir::Time);
|
||||
foreach (const QString &filename, fileList) {
|
||||
Q_UNUSED(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sorted_byName()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QDir testdir(QDir::tempPath() + QLatin1String("/test_speed"));
|
||||
testdir.setFilter(QDir::AllEntries | QDir::System | QDir::Hidden);
|
||||
[[maybe_unused]] auto r = testdir.entryInfoList(QDir::NoFilter, QDir::Name);
|
||||
}
|
||||
}
|
||||
|
||||
void sizeSpeedWithoutFilterLowLevel()
|
||||
{
|
||||
QDir testdir(QDir::tempPath() + QLatin1String("/test_speed"));
|
||||
#ifdef Q_OS_WIN
|
||||
const wchar_t *dirpath = (wchar_t*)testdir.absolutePath().utf16();
|
||||
wchar_t appendedPath[MAX_PATH];
|
||||
wcscpy(appendedPath, dirpath);
|
||||
wcscat(appendedPath, L"\\*");
|
||||
|
||||
QBENCHMARK {
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE hSearch = FindFirstFileW(appendedPath, &fd);
|
||||
QVERIFY(hSearch != INVALID_HANDLE_VALUE);
|
||||
|
||||
do {
|
||||
|
||||
} while (FindNextFile(hSearch, &fd));
|
||||
FindClose(hSearch);
|
||||
}
|
||||
#else
|
||||
QVERIFY(!chdir(qPrintable(testdir.absolutePath())));
|
||||
QBENCHMARK {
|
||||
DIR *dir = opendir(qPrintable(testdir.absolutePath()));
|
||||
QVERIFY(dir);
|
||||
|
||||
struct dirent *item = readdir(dir);
|
||||
while (item) {
|
||||
char *fileName = item->d_name;
|
||||
|
||||
struct stat fileStat;
|
||||
QVERIFY(!stat(fileName, &fileStat));
|
||||
|
||||
item = readdir(dir);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_QDir_10000)
|
||||
|
||||
#include "tst_bench_qdir_10000.moc"
|
2
tests/benchmarks/corelib/io/qdir/CMakeLists.txt
Normal file
2
tests/benchmarks/corelib/io/qdir/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
add_subdirectory(10000)
|
||||
add_subdirectory(tree)
|
11908
tests/benchmarks/corelib/io/qdir/tree/4.6.0-list.txt
Normal file
11908
tests/benchmarks/corelib/io/qdir/tree/4.6.0-list.txt
Normal file
File diff suppressed because it is too large
Load Diff
25
tests/benchmarks/corelib/io/qdir/tree/CMakeLists.txt
Normal file
25
tests/benchmarks/corelib/io/qdir/tree/CMakeLists.txt
Normal file
@ -0,0 +1,25 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qdir_tree Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qdir_tree
|
||||
SOURCES
|
||||
tst_bench_qdir_tree.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(qdir_tree_resource_files
|
||||
"4.6.0-list.txt"
|
||||
)
|
||||
|
||||
qt_internal_add_resource(tst_bench_qdir_tree "tst_bench_qdir_tree"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${qdir_tree_resource_files}
|
||||
)
|
201
tests/benchmarks/corelib/io/qdir/tree/tst_bench_qdir_tree.cpp
Normal file
201
tests/benchmarks/corelib/io/qdir/tree/tst_bench_qdir_tree.cpp
Normal file
@ -0,0 +1,201 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtTest/QTest>
|
||||
|
||||
#include <QDirIterator>
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
#include <QStack>
|
||||
|
||||
#include "../../../../../shared/filesystem.h"
|
||||
|
||||
class tst_QDir_tree
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QDir_tree()
|
||||
: prefix("test-tree/"),
|
||||
musicprefix(QLatin1String("music")),
|
||||
photoprefix(QLatin1String("photos")),
|
||||
sourceprefix(QLatin1String("source")),
|
||||
musicsize(0),
|
||||
photosize(0),
|
||||
sourcesize(0)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
QByteArray prefix;
|
||||
QString musicprefix;
|
||||
QString photoprefix;
|
||||
QString sourceprefix;
|
||||
qint64 musicsize;
|
||||
qint64 photosize;
|
||||
qint64 sourcesize;
|
||||
FileSystem fs; // Uses QTemporaryDir to tidy away file tree created.
|
||||
|
||||
private slots:
|
||||
void initTestCase()
|
||||
{
|
||||
QFile list(":/4.6.0-list.txt");
|
||||
QVERIFY(list.open(QIODevice::ReadOnly | QIODevice::Text));
|
||||
|
||||
QVERIFY(fs.createDirectory(prefix));
|
||||
|
||||
QStack<QByteArray> stack;
|
||||
QByteArray line;
|
||||
while (true) {
|
||||
char ch;
|
||||
if (!list.getChar(&ch))
|
||||
break;
|
||||
if (ch != ' ') {
|
||||
line.append(ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
int pop = 1;
|
||||
if (!line.isEmpty())
|
||||
pop = line.toInt();
|
||||
|
||||
while (pop) {
|
||||
stack.pop();
|
||||
--pop;
|
||||
}
|
||||
|
||||
line = list.readLine().trimmed();
|
||||
stack.push(line);
|
||||
|
||||
line = prefix;
|
||||
for (const QByteArray &pathElement : std::as_const(stack))
|
||||
line += pathElement;
|
||||
|
||||
if (line.endsWith('/'))
|
||||
QVERIFY(fs.createDirectory(line));
|
||||
else
|
||||
QVERIFY(fs.createFile(line));
|
||||
|
||||
line.clear();
|
||||
}
|
||||
|
||||
//Use case: music collection - 10 files in 100 directories (albums)
|
||||
QVERIFY(fs.createDirectory(musicprefix));
|
||||
for (int i=0;i<1000;i++) {
|
||||
if ((i % 10) == 0)
|
||||
QVERIFY(fs.createDirectory(QString("%1/directory%2").arg(musicprefix).arg(i/10)));
|
||||
qint64 size = fs.createFileWithContent(QString("%1/directory%2/file%3").arg(musicprefix).arg(i/10).arg(i));
|
||||
QVERIFY(size > 0);
|
||||
musicsize += size;
|
||||
}
|
||||
//Use case: photos - 1000 files in 1 directory
|
||||
QVERIFY(fs.createDirectory(photoprefix));
|
||||
for (int i=0;i<1000;i++) {
|
||||
qint64 size = fs.createFileWithContent(QString("%1/file%2").arg(photoprefix).arg(i));
|
||||
QVERIFY(size > 0);
|
||||
photosize += size;
|
||||
}
|
||||
//Use case: source - 10 files in 10 subdirectories in 10 directories (1000 total)
|
||||
QVERIFY(fs.createDirectory(sourceprefix));
|
||||
for (int i=0;i<1000;i++) {
|
||||
if ((i % 100) == 0)
|
||||
QVERIFY(fs.createDirectory(QString("%1/directory%2").arg(sourceprefix).arg(i/100)));
|
||||
if ((i % 10) == 0)
|
||||
QVERIFY(fs.createDirectory(QString("%1/directory%2/subdirectory%3").arg(sourceprefix).arg(i/100).arg(i/10)));
|
||||
qint64 size = fs.createFileWithContent(QString("%1/directory%2/subdirectory%3/file%4").arg(sourceprefix).arg(i/100).arg(i/10).arg(i));
|
||||
QVERIFY(size > 0);
|
||||
sourcesize += size;
|
||||
}
|
||||
}
|
||||
|
||||
void fileSearch_data() const
|
||||
{
|
||||
QTest::addColumn<QStringList>("nameFilters");
|
||||
QTest::addColumn<int>("filter");
|
||||
QTest::addColumn<int>("entryCount");
|
||||
|
||||
QTest::newRow("*.cpp") << QStringList("*.cpp") << int(QDir::Files) << 3791;
|
||||
QTest::newRow("executables")
|
||||
<< QStringList("*")
|
||||
<< int(QDir::Executable | QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot)
|
||||
<< 536;
|
||||
}
|
||||
|
||||
void fileSearch() const
|
||||
{
|
||||
QFETCH(QStringList, nameFilters);
|
||||
QFETCH(int, filter);
|
||||
QFETCH(int, entryCount);
|
||||
|
||||
int count = 0;
|
||||
QBENCHMARK {
|
||||
// Recursive directory iteration
|
||||
QDirIterator iterator(fs.absoluteFilePath(prefix),
|
||||
nameFilters, QDir::Filter(filter),
|
||||
QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
|
||||
|
||||
count = 0;
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
++count;
|
||||
}
|
||||
|
||||
QCOMPARE(count, entryCount);
|
||||
}
|
||||
|
||||
QCOMPARE(count, entryCount);
|
||||
}
|
||||
|
||||
void traverseDirectory() const
|
||||
{
|
||||
int count = 0;
|
||||
QBENCHMARK {
|
||||
QDirIterator iterator(
|
||||
fs.absoluteFilePath(prefix),
|
||||
QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System,
|
||||
QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
|
||||
|
||||
count = 0;
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
++count;
|
||||
}
|
||||
|
||||
QCOMPARE(count, 11906);
|
||||
}
|
||||
|
||||
QCOMPARE(count, 11906);
|
||||
}
|
||||
|
||||
void thousandFiles_data() const
|
||||
{
|
||||
QTest::addColumn<QString>("dirName");
|
||||
QTest::addColumn<qint64>("expectedSize");
|
||||
QTest::newRow("music") << musicprefix << musicsize;
|
||||
QTest::newRow("photos") << photoprefix << photosize;
|
||||
QTest::newRow("src") << sourceprefix << sourcesize;
|
||||
}
|
||||
|
||||
void thousandFiles() const
|
||||
{
|
||||
QFETCH(QString, dirName);
|
||||
QFETCH(qint64, expectedSize);
|
||||
QBENCHMARK {
|
||||
qint64 totalsize = 0;
|
||||
int count = 0;
|
||||
QDirIterator iter(fs.absoluteFilePath(dirName),
|
||||
QDir::Files, QDirIterator::Subdirectories);
|
||||
while(iter.hasNext()) {
|
||||
count++;
|
||||
totalsize += iter.nextFileInfo().size();
|
||||
}
|
||||
QCOMPARE(count, 1000);
|
||||
QCOMPARE(totalsize, expectedSize);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_QDir_tree)
|
||||
|
||||
#include "tst_bench_qdir_tree.moc"
|
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>4.6.0-list.txt</file>
|
||||
</qresource>
|
||||
</RCC>
|
22
tests/benchmarks/corelib/io/qdiriterator/CMakeLists.txt
Normal file
22
tests/benchmarks/corelib/io/qdiriterator/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qdiriterator Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qdiriterator
|
||||
SOURCES
|
||||
tst_bench_qdiriterator.cpp
|
||||
qfilesystemiterator.cpp qfilesystemiterator.h
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_extend_target(tst_bench_qdiriterator CONDITION (QT_FEATURE_cxx17_filesystem) AND (GCC AND (QMAKE_GCC_MAJOR_VERSION LESS 9))
|
||||
LINK_OPTIONS
|
||||
"-lstdc++fs"
|
||||
)
|
645
tests/benchmarks/corelib/io/qdiriterator/qfilesystemiterator.cpp
Normal file
645
tests/benchmarks/corelib/io/qdiriterator/qfilesystemiterator.cpp
Normal file
@ -0,0 +1,645 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
/*!
|
||||
\since 4.5
|
||||
\class QFileSystemIterator
|
||||
\brief The QFileSystemIterator class provides an iterator for directory entrylists.
|
||||
|
||||
You can use QFileSystemIterator to navigate entries of a directory one at a time.
|
||||
It is similar to QDir::entryList() and QDir::entryInfoList(), but because
|
||||
it lists entries one at a time instead of all at once, it scales better
|
||||
and is more suitable for large directories. It also supports listing
|
||||
directory contents recursively, and following symbolic links. Unlike
|
||||
QDir::entryList(), QFileSystemIterator does not support sorting.
|
||||
|
||||
The QFileSystemIterator constructor takes a QDir or a directory as
|
||||
argument. After construction, the iterator is located before the first
|
||||
directory entry. Here's how to iterate over all the entries sequentially:
|
||||
|
||||
\snippet doc/src/snippets/code/src.corelib.io.qdiriterator.cpp 0
|
||||
|
||||
The next() function returns the path to the next directory entry and
|
||||
advances the iterator. You can also call filePath() to get the current
|
||||
file path without advancing the iterator. The fileName() function returns
|
||||
only the name of the file, similar to how QDir::entryList() works. You can
|
||||
also call fileInfo() to get a QFileInfo for the current entry.
|
||||
|
||||
Unlike Qt's container iterators, QFileSystemIterator is uni-directional (i.e.,
|
||||
you cannot iterate directories in reverse order) and does not allow random
|
||||
access.
|
||||
|
||||
QFileSystemIterator works with all supported file engines, and is implemented
|
||||
using QAbstractFileEngineIterator.
|
||||
|
||||
\sa QDir, QDir::entryList(), QAbstractFileEngineIterator
|
||||
*/
|
||||
|
||||
/*! \enum QFileSystemIterator::IteratorFlag
|
||||
|
||||
This enum describes flags that you can combine to configure the behavior
|
||||
of QFileSystemIterator.
|
||||
|
||||
\value NoIteratorFlags The default value, representing no flags. The
|
||||
iterator will return entries for the assigned path.
|
||||
|
||||
\value Subdirectories List entries inside all subdirectories as well.
|
||||
|
||||
\value FollowSymlinks When combined with Subdirectories, this flag
|
||||
enables iterating through all subdirectories of the assigned path,
|
||||
following all symbolic links. Symbolic link loops (e.g., "link" => "." or
|
||||
"link" => "..") are automatically detected and ignored.
|
||||
*/
|
||||
|
||||
#include "qfilesystemiterator.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/qset.h>
|
||||
#include <QtCore/qstack.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <qplatformdefs.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <qt_windows.h>
|
||||
#else
|
||||
# include <sys/stat.h>
|
||||
# include <sys/types.h>
|
||||
# include <dirent.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QDirIteratorTest {
|
||||
|
||||
class QFileSystemIteratorPrivate
|
||||
{
|
||||
public:
|
||||
QFileSystemIteratorPrivate(const QString &path, const QStringList &nameFilters,
|
||||
QDir::Filters filters, QFileSystemIterator::IteratorFlags flags);
|
||||
~QFileSystemIteratorPrivate();
|
||||
|
||||
void pushSubDirectory(const QByteArray &path);
|
||||
void advance();
|
||||
bool isAcceptable() const;
|
||||
bool shouldFollowDirectory(const QFileInfo &);
|
||||
//bool matchesFilters(const QAbstractFileEngineIterator *it) const;
|
||||
inline bool atEnd() const { return m_dirPaths.isEmpty(); }
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QStack<HANDLE> m_dirStructs;
|
||||
WIN32_FIND_DATA* m_entry;
|
||||
WIN32_FIND_DATA m_fileSearchResult;
|
||||
bool m_bFirstSearchResult;
|
||||
#else
|
||||
QStack<DIR *> m_dirStructs;
|
||||
dirent *m_entry;
|
||||
#endif
|
||||
|
||||
QSet<QString> visitedLinks;
|
||||
QStack<QByteArray> m_dirPaths;
|
||||
QFileInfo fileInfo;
|
||||
QString currentFilePath;
|
||||
QFileSystemIterator::IteratorFlags iteratorFlags;
|
||||
QDir::Filters filters;
|
||||
QStringList nameFilters;
|
||||
|
||||
enum { DontShowDir, ShowDotDotDir, ShowDotDir, ShowDir }
|
||||
m_currentDirShown, m_nextDirShown;
|
||||
|
||||
QFileSystemIterator *q;
|
||||
|
||||
private:
|
||||
bool advanceHelper(); // returns true if we know we have something suitable
|
||||
};
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QFileSystemIteratorPrivate::QFileSystemIteratorPrivate(const QString &path,
|
||||
const QStringList &nameFilters, QDir::Filters filters,
|
||||
QFileSystemIterator::IteratorFlags flags)
|
||||
: iteratorFlags(flags)
|
||||
{
|
||||
if (filters == QDir::NoFilter)
|
||||
filters = QDir::AllEntries;
|
||||
this->filters = filters;
|
||||
this->nameFilters = nameFilters;
|
||||
|
||||
fileInfo.setFile(path);
|
||||
QString dir = fileInfo.isSymLink() ? fileInfo.canonicalFilePath() : path;
|
||||
pushSubDirectory(dir.toLocal8Bit());
|
||||
// skip to acceptable entry
|
||||
while (true) {
|
||||
if (atEnd())
|
||||
return;
|
||||
if (isAcceptable())
|
||||
return;
|
||||
if (advanceHelper())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QFileSystemIteratorPrivate::~QFileSystemIteratorPrivate()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
while (!m_dirStructs.isEmpty())
|
||||
::FindClose(m_dirStructs.pop());
|
||||
#else
|
||||
while (!m_dirStructs.isEmpty())
|
||||
::closedir(m_dirStructs.pop());
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static bool isDotOrDotDot(const wchar_t* name)
|
||||
{
|
||||
if (name[0] == L'.' && name[1] == 0)
|
||||
return true;
|
||||
if (name[0] == L'.' && name[1] == L'.' && name[2] == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
static bool isDotOrDotDot(const char *name)
|
||||
{
|
||||
if (name[0] == '.' && name[1] == 0)
|
||||
return true;
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void QFileSystemIteratorPrivate::pushSubDirectory(const QByteArray &path)
|
||||
{
|
||||
/*
|
||||
if (iteratorFlags & QFileSystemIterator::FollowSymlinks) {
|
||||
if (fileInfo.filePath() != path)
|
||||
fileInfo.setFile(path);
|
||||
if (fileInfo.isSymLink()) {
|
||||
visitedLinks << fileInfo.canonicalFilePath();
|
||||
} else {
|
||||
visitedLinks << fileInfo.absoluteFilePath();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
wchar_t szSearchPath[MAX_PATH];
|
||||
const int end = QString::fromLatin1(path + "\\*").toWCharArray(szSearchPath);
|
||||
Q_ASSERT(end < MAX_PATH);
|
||||
szSearchPath[end] = L'\0';
|
||||
HANDLE dir = FindFirstFile(szSearchPath, &m_fileSearchResult);
|
||||
m_bFirstSearchResult = true;
|
||||
#else
|
||||
DIR *dir = ::opendir(path.constData());
|
||||
//m_entry = ::readdir(dir);
|
||||
//while (m_entry && isDotOrDotDot(m_entry->d_name))
|
||||
// m_entry = ::readdir(m_dirStructs.top());
|
||||
#endif
|
||||
m_dirStructs.append(dir);
|
||||
m_dirPaths.append(path);
|
||||
m_entry = 0;
|
||||
if (filters & QDir::Dirs)
|
||||
m_nextDirShown = ShowDir;
|
||||
else
|
||||
m_nextDirShown = DontShowDir;
|
||||
m_currentDirShown = DontShowDir;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
bool QFileSystemIteratorPrivate::isAcceptable() const
|
||||
{
|
||||
if (!m_entry)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
|
||||
|
||||
void QFileSystemIteratorPrivate::advance()
|
||||
{
|
||||
while (true) {
|
||||
if (advanceHelper())
|
||||
return;
|
||||
if (atEnd())
|
||||
return;
|
||||
if (isAcceptable())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool QFileSystemIteratorPrivate::advanceHelper()
|
||||
{
|
||||
if (m_dirStructs.isEmpty())
|
||||
return true;
|
||||
|
||||
//printf("ADV %d %d\n", int(m_currentDirShown), int(m_nextDirShown));
|
||||
|
||||
if ((filters & QDir::Dirs)) {
|
||||
m_currentDirShown = m_nextDirShown;
|
||||
if (m_nextDirShown == ShowDir) {
|
||||
//printf("RESTING ON DIR %s %x\n", m_dirPaths.top().constData(), int(filters));
|
||||
m_nextDirShown = (filters & QDir::NoDotAndDotDot) ? DontShowDir : ShowDotDir;
|
||||
// skip start directory itself
|
||||
if (m_dirStructs.size() == 1 && m_currentDirShown == ShowDir)
|
||||
return advanceHelper();
|
||||
return true;
|
||||
}
|
||||
if (m_nextDirShown == ShowDotDir) {
|
||||
//printf("RESTING ON DOT %s %x\n", m_dirPaths.top().constData(), int(filters));
|
||||
m_nextDirShown = ShowDotDotDir;
|
||||
return true;
|
||||
}
|
||||
if (m_nextDirShown == ShowDotDotDir) {
|
||||
//printf("RESTING ON DOTDOT %s %x\n", m_dirPaths.top().constData(), int(filters));
|
||||
m_nextDirShown = DontShowDir;
|
||||
return true;
|
||||
}
|
||||
m_currentDirShown = DontShowDir;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
m_entry = &m_fileSearchResult;
|
||||
if (m_bFirstSearchResult) {
|
||||
m_bFirstSearchResult = false;
|
||||
} else {
|
||||
if (!FindNextFile(m_dirStructs.top(), m_entry))
|
||||
m_entry = 0;
|
||||
}
|
||||
|
||||
while (m_entry && isDotOrDotDot(m_entry->cFileName))
|
||||
if (!FindNextFile(m_dirStructs.top(), m_entry))
|
||||
m_entry = 0;
|
||||
|
||||
if (!m_entry) {
|
||||
m_dirPaths.pop();
|
||||
FindClose(m_dirStructs.pop());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
QByteArray ba = m_dirPaths.top();
|
||||
ba += '\\';
|
||||
ba += QString::fromWCharArray(m_entry->cFileName).toUtf8();
|
||||
pushSubDirectory(ba);
|
||||
}
|
||||
#else
|
||||
m_entry = ::readdir(m_dirStructs.top());
|
||||
while (m_entry && isDotOrDotDot(m_entry->d_name))
|
||||
m_entry = ::readdir(m_dirStructs.top());
|
||||
//return false; // further iteration possibly needed
|
||||
//printf("READ %p %s\n", m_entry, m_entry ? m_entry->d_name : "");
|
||||
|
||||
if (!m_entry) {
|
||||
m_dirPaths.pop();
|
||||
DIR *dir = m_dirStructs.pop();
|
||||
::closedir(dir);
|
||||
return false; // further iteration possibly needed
|
||||
}
|
||||
|
||||
const char *name = m_entry->d_name;
|
||||
|
||||
QByteArray ba = m_dirPaths.top();
|
||||
ba += '/';
|
||||
ba += name;
|
||||
QT_STATBUF st;
|
||||
QT_LSTAT(ba.constData(), &st);
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
pushSubDirectory(ba);
|
||||
return false; // further iteration possibly needed
|
||||
}
|
||||
#endif
|
||||
return false; // further iteration possiblye needed
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
bool QFileSystemIteratorPrivate::shouldFollowDirectory(const QFileInfo &fileInfo)
|
||||
{
|
||||
// If we're doing flat iteration, we're done.
|
||||
if (!(iteratorFlags & QFileSystemIterator::Subdirectories))
|
||||
return false;
|
||||
|
||||
// Never follow non-directory entries
|
||||
if (!fileInfo.isDir())
|
||||
return false;
|
||||
|
||||
|
||||
// Never follow . and ..
|
||||
if (fileInfo.fileName() == QLatin1String(".") || fileInfo.fileName() == QLatin1String(".."))
|
||||
return false;
|
||||
|
||||
|
||||
// Check symlinks
|
||||
if (fileInfo.isSymLink() && !(iteratorFlags & QFileSystemIterator::FollowSymlinks)) {
|
||||
// Follow symlinks only if FollowSymlinks was passed
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stop link loops
|
||||
if (visitedLinks.contains(fileInfo.canonicalFilePath()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\internal
|
||||
|
||||
This convenience function implements the iterator's filtering logics and
|
||||
applies then to the current directory entry.
|
||||
|
||||
It returns true if the current entry matches the filters (i.e., the
|
||||
current entry will be returned as part of the directory iteration);
|
||||
otherwise, false is returned.
|
||||
*/
|
||||
#if 0
|
||||
bool QFileSystemIteratorPrivate::matchesFilters(const QAbstractFileEngineIterator *it) const
|
||||
{
|
||||
const bool filterPermissions = ((filters & QDir::PermissionMask)
|
||||
&& (filters & QDir::PermissionMask) != QDir::PermissionMask);
|
||||
const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
|
||||
const bool skipFiles = !(filters & QDir::Files);
|
||||
const bool skipSymlinks = (filters & QDir::NoSymLinks);
|
||||
const bool doReadable = !filterPermissions || (filters & QDir::Readable);
|
||||
const bool doWritable = !filterPermissions || (filters & QDir::Writable);
|
||||
const bool doExecutable = !filterPermissions || (filters & QDir::Executable);
|
||||
const bool includeHidden = (filters & QDir::Hidden);
|
||||
const bool includeSystem = (filters & QDir::System);
|
||||
|
||||
#ifndef QT_NO_REGEXP
|
||||
// Prepare name filters
|
||||
QList<QRegExp> regexps;
|
||||
bool hasNameFilters = !nameFilters.isEmpty() && !(nameFilters.contains(QLatin1String("*")));
|
||||
if (hasNameFilters) {
|
||||
for (int i = 0; i < nameFilters.size(); ++i) {
|
||||
regexps << QRegExp(nameFilters.at(i),
|
||||
(filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive,
|
||||
QRegExp::Wildcard);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
QString fileName = it->currentFileName();
|
||||
if (fileName.isEmpty()) {
|
||||
// invalid entry
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo fi = it->currentFileInfo();
|
||||
QString filePath = it->currentFilePath();
|
||||
|
||||
#ifndef QT_NO_REGEXP
|
||||
// Pass all entries through name filters, except dirs if the AllDirs
|
||||
// filter is passed.
|
||||
if (hasNameFilters && !((filters & QDir::AllDirs) && fi.isDir())) {
|
||||
bool matched = false;
|
||||
for (int i = 0; i < regexps.size(); ++i) {
|
||||
if (regexps.at(i).exactMatch(fileName)) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool dotOrDotDot = (fileName == QLatin1String(".") || fileName == QLatin1String(".."));
|
||||
if ((filters & QDir::NoDotAndDotDot) && dotOrDotDot)
|
||||
return false;
|
||||
|
||||
bool isHidden = !dotOrDotDot && fi.isHidden();
|
||||
if (!includeHidden && isHidden)
|
||||
return false;
|
||||
|
||||
bool isSystem = (!fi.isFile() && !fi.isDir() && !fi.isSymLink())
|
||||
|| (!fi.exists() && fi.isSymLink());
|
||||
if (!includeSystem && isSystem)
|
||||
return false;
|
||||
|
||||
bool alwaysShow = (filters & QDir::TypeMask) == 0
|
||||
&& ((isHidden && includeHidden)
|
||||
|| (includeSystem && isSystem));
|
||||
|
||||
// Skip files and directories
|
||||
if ((filters & QDir::AllDirs) == 0 && skipDirs && fi.isDir()) {
|
||||
if (!alwaysShow)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((skipFiles && (fi.isFile() || !fi.exists()))
|
||||
|| (skipSymlinks && fi.isSymLink())) {
|
||||
if (!alwaysShow)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filterPermissions
|
||||
&& ((doReadable && !fi.isReadable())
|
||||
|| (doWritable && !fi.isWritable())
|
||||
|| (doExecutable && !fi.isExecutable()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!includeSystem && !dotOrDotDot && ((fi.exists() && !fi.isFile() && !fi.isDir() && !fi.isSymLink())
|
||||
|| (!fi.exists() && fi.isSymLink()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Constructs a QFileSystemIterator that can iterate over \a dir's entrylist, using
|
||||
\a dir's name filters and regular filters. You can pass options via \a
|
||||
flags to decide how the directory should be iterated.
|
||||
|
||||
By default, \a flags is NoIteratorFlags, which provides the same behavior
|
||||
as in QDir::entryList().
|
||||
|
||||
The sorting in \a dir is ignored.
|
||||
|
||||
\sa atEnd(), next(), IteratorFlags
|
||||
*/
|
||||
QFileSystemIterator::QFileSystemIterator(const QDir &dir, IteratorFlags flags)
|
||||
: d(new QFileSystemIteratorPrivate(dir.path(), dir.nameFilters(), dir.filter(), flags))
|
||||
{
|
||||
d->q = this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QFileSystemIterator that can iterate over \a path, with no name
|
||||
filtering and \a filters for entry filtering. You can pass options via \a
|
||||
flags to decide how the directory should be iterated.
|
||||
|
||||
By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags,
|
||||
which provides the same behavior as in QDir::entryList().
|
||||
|
||||
\sa atEnd(), next(), IteratorFlags
|
||||
*/
|
||||
QFileSystemIterator::QFileSystemIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
|
||||
: d(new QFileSystemIteratorPrivate(path, QStringList(QLatin1String("*")), filters, flags))
|
||||
{
|
||||
d->q = this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QFileSystemIterator that can iterate over \a path. You can pass
|
||||
options via \a flags to decide how the directory should be iterated.
|
||||
|
||||
By default, \a flags is NoIteratorFlags, which provides the same behavior
|
||||
as in QDir::entryList().
|
||||
|
||||
\sa atEnd(), next(), IteratorFlags
|
||||
*/
|
||||
QFileSystemIterator::QFileSystemIterator(const QString &path, IteratorFlags flags)
|
||||
: d(new QFileSystemIteratorPrivate(path, QStringList(QLatin1String("*")), QDir::NoFilter, flags))
|
||||
{
|
||||
d->q = this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QFileSystemIterator that can iterate over \a path, using \a
|
||||
nameFilters and \a filters. You can pass options via \a flags to decide
|
||||
how the directory should be iterated.
|
||||
|
||||
By default, \a flags is NoIteratorFlags, which provides the same behavior
|
||||
as QDir::entryList().
|
||||
|
||||
\sa atEnd(), next(), IteratorFlags
|
||||
*/
|
||||
QFileSystemIterator::QFileSystemIterator(const QString &path, const QStringList &nameFilters,
|
||||
QDir::Filters filters, IteratorFlags flags)
|
||||
: d(new QFileSystemIteratorPrivate(path, nameFilters, filters, flags))
|
||||
{
|
||||
d->q = this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys the QFileSystemIterator.
|
||||
*/
|
||||
QFileSystemIterator::~QFileSystemIterator()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
/*!
|
||||
Advances the iterator to the next entry, and returns the file path of this
|
||||
new entry. If atEnd() returns true, this function does nothing, and
|
||||
returns a null QString.
|
||||
|
||||
You can call fileName() or filePath() to get the current entry file name
|
||||
or path, or fileInfo() to get a QFileInfo for the current entry.
|
||||
|
||||
\sa hasNext(), fileName(), filePath(), fileInfo()
|
||||
*/
|
||||
void QFileSystemIterator::next()
|
||||
{
|
||||
d->advance();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if there is at least one more entry in the directory;
|
||||
otherwise, false is returned.
|
||||
|
||||
\sa next(), fileName(), filePath(), fileInfo()
|
||||
*/
|
||||
bool QFileSystemIterator::atEnd() const
|
||||
{
|
||||
return d->atEnd();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the file name for the current directory entry, without the path
|
||||
prepended. If the current entry is invalid (i.e., isValid() returns
|
||||
false), a null QString is returned.
|
||||
|
||||
This function is provided for the convenience when iterating single
|
||||
directories. For recursive iteration, you should call filePath() or
|
||||
fileInfo() instead.
|
||||
|
||||
\sa filePath(), fileInfo()
|
||||
*/
|
||||
QString QFileSystemIterator::fileName() const
|
||||
{
|
||||
if (d->atEnd() || !d->m_entry)
|
||||
return QString();
|
||||
if (d->m_currentDirShown == QFileSystemIteratorPrivate::ShowDir)
|
||||
return QString();
|
||||
if (d->m_currentDirShown == QFileSystemIteratorPrivate::ShowDotDir)
|
||||
return QLatin1String("@");
|
||||
if (d->m_currentDirShown == QFileSystemIteratorPrivate::ShowDotDotDir)
|
||||
return QLatin1String("@@");
|
||||
#ifdef Q_OS_WIN
|
||||
return QString::fromWCharArray(d->m_entry->cFileName);
|
||||
#else
|
||||
return QString::fromLocal8Bit(d->m_entry->d_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the full file path for the current directory entry. If the current
|
||||
entry is invalid (i.e., isValid() returns false), a null QString is
|
||||
returned.
|
||||
|
||||
\sa fileInfo(), fileName()
|
||||
*/
|
||||
QString QFileSystemIterator::filePath() const
|
||||
{
|
||||
if (d->atEnd())
|
||||
return QString();
|
||||
QByteArray ba = d->m_dirPaths.top();
|
||||
if (d->m_currentDirShown == QFileSystemIteratorPrivate::ShowDotDir)
|
||||
ba += "/.";
|
||||
else if (d->m_currentDirShown == QFileSystemIteratorPrivate::ShowDotDotDir)
|
||||
ba += "/..";
|
||||
else if (d->m_entry) {
|
||||
ba += '/';
|
||||
#ifdef Q_OS_WIN
|
||||
ba += QString::fromWCharArray(d->m_entry->cFileName).toUtf8();
|
||||
#else
|
||||
ba += d->m_entry->d_name;
|
||||
#endif
|
||||
}
|
||||
return QString::fromLocal8Bit(ba);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a QFileInfo for the current directory entry. If the current entry
|
||||
is invalid (i.e., isValid() returns false), a null QFileInfo is returned.
|
||||
|
||||
\sa filePath(), fileName()
|
||||
*/
|
||||
QFileInfo QFileSystemIterator::fileInfo() const
|
||||
{
|
||||
return QFileInfo(filePath());
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the base directory of the iterator.
|
||||
*/
|
||||
QString QFileSystemIterator::path() const
|
||||
{
|
||||
return QString::fromLocal8Bit(d->m_dirPaths.top());
|
||||
}
|
||||
|
||||
} // QDirIteratorTest::
|
||||
|
||||
QT_END_NAMESPACE
|
@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef QFILESYSTEMITERATOR_H
|
||||
#define QFILESYSTEMITERATOR_H
|
||||
|
||||
#include <QtCore/qdir.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QDirIteratorTest {
|
||||
|
||||
class QFileSystemIteratorPrivate;
|
||||
class //Q_CORE_EXPORT
|
||||
QFileSystemIterator
|
||||
{
|
||||
public:
|
||||
enum IteratorFlag {
|
||||
NoIteratorFlags = 0x0,
|
||||
FollowSymlinks = 0x1,
|
||||
Subdirectories = 0x2
|
||||
};
|
||||
Q_DECLARE_FLAGS(IteratorFlags, IteratorFlag)
|
||||
|
||||
QFileSystemIterator(const QDir &dir, IteratorFlags flags = NoIteratorFlags);
|
||||
QFileSystemIterator(const QString &path,
|
||||
IteratorFlags flags = NoIteratorFlags);
|
||||
QFileSystemIterator(const QString &path,
|
||||
QDir::Filters filter,
|
||||
IteratorFlags flags = NoIteratorFlags);
|
||||
QFileSystemIterator(const QString &path,
|
||||
const QStringList &nameFilters,
|
||||
QDir::Filters filters = QDir::NoFilter,
|
||||
IteratorFlags flags = NoIteratorFlags);
|
||||
|
||||
virtual ~QFileSystemIterator();
|
||||
|
||||
void next();
|
||||
bool atEnd() const;
|
||||
|
||||
QString fileName() const;
|
||||
QString filePath() const;
|
||||
QFileInfo fileInfo() const;
|
||||
QString path() const;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QFileSystemIterator)
|
||||
|
||||
QFileSystemIteratorPrivate *d;
|
||||
friend class QDir;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemIterator::IteratorFlags)
|
||||
|
||||
} // namespace QDirIteratorTest
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
@ -0,0 +1,237 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QDebug>
|
||||
#include <QDirIterator>
|
||||
#include <QString>
|
||||
#include <qplatformdefs.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <qt_windows.h>
|
||||
#else
|
||||
# include <sys/stat.h>
|
||||
# include <sys/types.h>
|
||||
# include <dirent.h>
|
||||
# include <errno.h>
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#include <qtest.h>
|
||||
|
||||
#include "qfilesystemiterator.h"
|
||||
|
||||
#if QT_CONFIG(cxx17_filesystem)
|
||||
#include <filesystem>
|
||||
#endif
|
||||
|
||||
class tst_QDirIterator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
void data();
|
||||
private slots:
|
||||
void posix();
|
||||
void posix_data() { data(); }
|
||||
void diriterator();
|
||||
void diriterator_data() { data(); }
|
||||
void fsiterator();
|
||||
void fsiterator_data() { data(); }
|
||||
void stdRecursiveDirectoryIterator();
|
||||
void stdRecursiveDirectoryIterator_data() { data(); }
|
||||
};
|
||||
|
||||
void tst_QDirIterator::data()
|
||||
{
|
||||
const char hereRelative[] = "tests/benchmarks/corelib/io/qdiriterator";
|
||||
QByteArray dir(QT_TESTCASE_SOURCEDIR);
|
||||
// qDebug("Source dir: %s", dir.constData());
|
||||
dir.chop(sizeof(hereRelative)); // Counts the '\0', making up for the omitted leading '/'
|
||||
// qDebug("Root dir: %s", dir.constData());
|
||||
|
||||
QTest::addColumn<QByteArray>("dirpath");
|
||||
const QByteArray ba = dir + "/src/corelib";
|
||||
|
||||
if (!QFileInfo(QString::fromLocal8Bit(ba)).isDir())
|
||||
QSKIP("Missing Qt directory");
|
||||
|
||||
QTest::newRow("corelib") << ba;
|
||||
QTest::newRow("corelib/io") << (ba + "/io");
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static int posix_helper(const wchar_t *dirpath, size_t length)
|
||||
{
|
||||
int count = 0;
|
||||
HANDLE hSearch;
|
||||
WIN32_FIND_DATA fd;
|
||||
|
||||
wchar_t appendedPath[MAX_PATH];
|
||||
Q_ASSERT(MAX_PATH > length + 3);
|
||||
wcsncpy(appendedPath, dirpath, length);
|
||||
wcscpy(appendedPath + length, L"\\*");
|
||||
hSearch = FindFirstFile(appendedPath, &fd);
|
||||
|
||||
if (hSearch == INVALID_HANDLE_VALUE) {
|
||||
qWarning("FindFirstFile failed");
|
||||
return count;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!(fd.cFileName[0] == L'.' && fd.cFileName[1] == 0) &&
|
||||
!(fd.cFileName[0] == L'.' && fd.cFileName[1] == L'.' && fd.cFileName[2] == 0))
|
||||
{
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// newLength will "point" to where we put a * earlier, so we overwrite that.
|
||||
size_t newLength = length + 1; // "+ 1" for directory separator
|
||||
Q_ASSERT(newLength + wcslen(fd.cFileName) + 1 < MAX_PATH); // "+ 1" for null-terminator
|
||||
wcscpy(appendedPath + newLength, fd.cFileName);
|
||||
newLength += wcslen(fd.cFileName);
|
||||
count += posix_helper(appendedPath, newLength);
|
||||
}
|
||||
else {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hSearch, &fd));
|
||||
FindClose(hSearch);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int posix_helper(const char *dirpath)
|
||||
{
|
||||
//qDebug() << "DIR" << dirpath;
|
||||
DIR *dir = ::opendir(dirpath);
|
||||
if (!dir)
|
||||
return 0;
|
||||
|
||||
dirent *entry = 0;
|
||||
|
||||
int count = 0;
|
||||
while ((entry = ::readdir(dir))) {
|
||||
if (qstrcmp(entry->d_name, ".") == 0)
|
||||
continue;
|
||||
if (qstrcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
++count;
|
||||
QByteArray ba = dirpath;
|
||||
ba += '/';
|
||||
ba += entry->d_name;
|
||||
QT_STATBUF st;
|
||||
QT_LSTAT(ba.constData(), &st);
|
||||
if (S_ISDIR(st.st_mode))
|
||||
count += posix_helper(ba.constData());
|
||||
}
|
||||
|
||||
::closedir(dir);
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void tst_QDirIterator::posix()
|
||||
{
|
||||
QFETCH(QByteArray, dirpath);
|
||||
|
||||
int count = 0;
|
||||
QString path(dirpath);
|
||||
QBENCHMARK {
|
||||
#ifdef Q_OS_WIN
|
||||
wchar_t wPath[MAX_PATH];
|
||||
const int end = path.toWCharArray(wPath);
|
||||
count = posix_helper(wPath, end);
|
||||
#else
|
||||
count = posix_helper(dirpath.constData());
|
||||
#endif
|
||||
}
|
||||
qDebug() << count;
|
||||
}
|
||||
|
||||
void tst_QDirIterator::diriterator()
|
||||
{
|
||||
QFETCH(QByteArray, dirpath);
|
||||
|
||||
int count = 0;
|
||||
|
||||
QBENCHMARK {
|
||||
int c = 0;
|
||||
|
||||
QDirIterator dir(dirpath,
|
||||
//QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot,
|
||||
//QDir::AllEntries | QDir::Hidden,
|
||||
QDir::Files,
|
||||
QDirIterator::Subdirectories);
|
||||
|
||||
while (dir.hasNext()) {
|
||||
const auto fi = dir.nextFileInfo();
|
||||
//printf("%s\n", qPrintable(dir.fileName()));
|
||||
0 && printf("%d %s\n",
|
||||
fi.isDir(),
|
||||
//qPrintable(fi.absoluteFilePath()),
|
||||
//qPrintable(dir.path()),
|
||||
qPrintable(fi.filePath()));
|
||||
++c;
|
||||
}
|
||||
count = c;
|
||||
}
|
||||
qDebug() << count;
|
||||
}
|
||||
|
||||
void tst_QDirIterator::fsiterator()
|
||||
{
|
||||
QFETCH(QByteArray, dirpath);
|
||||
|
||||
int count = 0;
|
||||
int dump = 0;
|
||||
|
||||
QBENCHMARK {
|
||||
int c = 0;
|
||||
|
||||
dump && printf("\n\n\n\n");
|
||||
QDirIteratorTest::QFileSystemIterator dir(dirpath,
|
||||
//QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot,
|
||||
//QDir::AllEntries | QDir::Hidden,
|
||||
//QDir::Files | QDir::NoDotAndDotDot,
|
||||
QDir::Files,
|
||||
QDirIteratorTest::QFileSystemIterator::Subdirectories);
|
||||
|
||||
for (; !dir.atEnd(); dir.next()) {
|
||||
dump && printf("%d %s\n",
|
||||
dir.fileInfo().isDir(),
|
||||
//qPrintable(dir.fileInfo().absoluteFilePath()),
|
||||
//qPrintable(dir.path()),
|
||||
qPrintable(dir.filePath())
|
||||
);
|
||||
++c;
|
||||
}
|
||||
count = c;
|
||||
}
|
||||
qDebug() << count;
|
||||
}
|
||||
|
||||
void tst_QDirIterator::stdRecursiveDirectoryIterator()
|
||||
{
|
||||
#if QT_CONFIG(cxx17_filesystem)
|
||||
QFETCH(QByteArray, dirpath);
|
||||
|
||||
int count = 0;
|
||||
|
||||
QBENCHMARK {
|
||||
int c = 0;
|
||||
for (auto obj : std::filesystem::recursive_directory_iterator(dirpath.data())) {
|
||||
if (obj.is_directory())
|
||||
continue;
|
||||
c++;
|
||||
}
|
||||
count = c;
|
||||
}
|
||||
qDebug() << count;
|
||||
#else
|
||||
QSKIP("Not supported.");
|
||||
#endif
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QDirIterator)
|
||||
|
||||
#include "tst_bench_qdiriterator.moc"
|
22
tests/benchmarks/corelib/io/qfile/CMakeLists.txt
Normal file
22
tests/benchmarks/corelib/io/qfile/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qfile Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qfile
|
||||
SOURCES
|
||||
tst_bench_qfile.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Test
|
||||
)
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_extend_target(tst_bench_qfile CONDITION WIN32
|
||||
DEFINES
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
)
|
593
tests/benchmarks/corelib/io/qfile/tst_bench_qfile.cpp
Normal file
593
tests/benchmarks/corelib/io/qfile/tst_bench_qfile.cpp
Normal file
@ -0,0 +1,593 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#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"
|
14
tests/benchmarks/corelib/io/qfileinfo/CMakeLists.txt
Normal file
14
tests/benchmarks/corelib/io/qfileinfo/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qfileinfo Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qfileinfo
|
||||
SOURCES
|
||||
tst_bench_qfileinfo.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,77 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QDebug>
|
||||
#include <qtest.h>
|
||||
#include <QTest>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include "private/qfsfileengine_p.h"
|
||||
#include "../../../../shared/filesystem.h"
|
||||
|
||||
class tst_QFileInfo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void existsTemporary();
|
||||
void existsStatic();
|
||||
#if defined(Q_OS_WIN)
|
||||
void symLinkTargetPerformanceLNK();
|
||||
void junctionTargetPerformanceMountpoint();
|
||||
#endif
|
||||
};
|
||||
|
||||
void tst_QFileInfo::existsTemporary()
|
||||
{
|
||||
QString appPath = QCoreApplication::applicationFilePath();
|
||||
QBENCHMARK { QFileInfo(appPath).exists(); }
|
||||
}
|
||||
|
||||
void tst_QFileInfo::existsStatic()
|
||||
{
|
||||
QString appPath = QCoreApplication::applicationFilePath();
|
||||
QBENCHMARK { QFileInfo::exists(appPath); }
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
void tst_QFileInfo::symLinkTargetPerformanceLNK()
|
||||
{
|
||||
QVERIFY(QFile::link("file","link.lnk"));
|
||||
QFileInfo info("link.lnk");
|
||||
info.setCaching(false);
|
||||
QVERIFY(info.isSymLink());
|
||||
QString linkTarget;
|
||||
QBENCHMARK {
|
||||
for(int i=0; i<100; i++)
|
||||
linkTarget = info.symLinkTarget();
|
||||
}
|
||||
QVERIFY(QFile::remove("link.lnk"));
|
||||
}
|
||||
|
||||
void tst_QFileInfo::junctionTargetPerformanceMountpoint()
|
||||
{
|
||||
wchar_t buffer[MAX_PATH];
|
||||
QString rootPath = QDir::toNativeSeparators(QDir::rootPath());
|
||||
QVERIFY(GetVolumeNameForVolumeMountPointW((LPCWSTR)rootPath.utf16(), buffer, MAX_PATH));
|
||||
QString rootVolume = QString::fromWCharArray(buffer);
|
||||
QString mountpoint = "mountpoint";
|
||||
rootVolume.replace("\\\\?\\","\\??\\");
|
||||
const auto result = FileSystem::createNtfsJunction(rootVolume, mountpoint);
|
||||
QVERIFY2(result.dwErr == ERROR_SUCCESS, qPrintable(result.errorMessage));
|
||||
|
||||
QFileInfo info(mountpoint);
|
||||
info.setCaching(false);
|
||||
QVERIFY(info.isJunction());
|
||||
QString junctionTarget;
|
||||
QBENCHMARK {
|
||||
for(int i=0; i<100; i++)
|
||||
junctionTarget = info.junctionTarget();
|
||||
}
|
||||
QVERIFY(QDir().rmdir(mountpoint));
|
||||
}
|
||||
#endif
|
||||
|
||||
QTEST_MAIN(tst_QFileInfo)
|
||||
|
||||
#include "tst_bench_qfileinfo.moc"
|
13
tests/benchmarks/corelib/io/qiodevice/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/io/qiodevice/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qiodevice Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qiodevice
|
||||
SOURCES
|
||||
tst_bench_qiodevice.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,98 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QDebug>
|
||||
#include <QIODevice>
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
|
||||
#include <qtest.h>
|
||||
|
||||
class tst_QIODevice : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void read_old();
|
||||
void read_old_data() { read_data(); }
|
||||
void peekAndRead();
|
||||
void peekAndRead_data() { read_data(); }
|
||||
//void read_new();
|
||||
//void read_new_data() { read_data(); }
|
||||
private:
|
||||
void read_data();
|
||||
};
|
||||
|
||||
|
||||
void tst_QIODevice::read_data()
|
||||
{
|
||||
QTest::addColumn<qint64>("size");
|
||||
QTest::newRow("10k") << qint64(10 * 1024);
|
||||
QTest::newRow("100k") << qint64(100 * 1024);
|
||||
QTest::newRow("1000k") << qint64(1000 * 1024);
|
||||
QTest::newRow("10000k") << qint64(10000 * 1024);
|
||||
QTest::newRow("100000k") << qint64(100000 * 1024);
|
||||
QTest::newRow("1000000k") << qint64(1000000 * 1024);
|
||||
}
|
||||
|
||||
void tst_QIODevice::read_old()
|
||||
{
|
||||
QFETCH(qint64, size);
|
||||
|
||||
QString name = "tmp" + QString::number(size);
|
||||
|
||||
{
|
||||
QFile file(name);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.seek(size);
|
||||
file.write("x", 1);
|
||||
file.close();
|
||||
}
|
||||
|
||||
QBENCHMARK {
|
||||
QFile file(name);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QByteArray ba;
|
||||
qint64 s = size - 1024;
|
||||
file.seek(512);
|
||||
ba = file.read(s); // crash happens during this read / assignment operation
|
||||
}
|
||||
|
||||
{
|
||||
QFile file(name);
|
||||
file.remove();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QIODevice::peekAndRead()
|
||||
{
|
||||
QFETCH(qint64, size);
|
||||
|
||||
QString name = "tmp" + QString::number(size);
|
||||
|
||||
{
|
||||
QFile file(name);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.seek(size);
|
||||
file.write("x", 1);
|
||||
file.close();
|
||||
}
|
||||
|
||||
QBENCHMARK {
|
||||
QFile file(name);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
||||
QByteArray ba(size / 1024, Qt::Uninitialized);
|
||||
while (!file.atEnd()) {
|
||||
file.peek(ba.data(), ba.size());
|
||||
file.read(ba.data(), ba.size());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
QFile file(name);
|
||||
file.remove();
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QIODevice)
|
||||
|
||||
#include "tst_bench_qiodevice.moc"
|
5
tests/benchmarks/corelib/io/qprocess/CMakeLists.txt
Normal file
5
tests/benchmarks/corelib/io/qprocess/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(testProcessLoopback)
|
||||
add_subdirectory(test)
|
14
tests/benchmarks/corelib/io/qprocess/test/CMakeLists.txt
Normal file
14
tests/benchmarks/corelib/io/qprocess/test/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qprocess Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qprocess
|
||||
SOURCES
|
||||
../tst_bench_qprocess.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## testProcessLoopback Binary:
|
||||
#####################################################################
|
||||
|
||||
add_executable(testProcessLoopback loopback.cpp)
|
@ -0,0 +1,19 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
char buffer[1024];
|
||||
for (;;) {
|
||||
size_t num = fread(buffer, 1, sizeof(buffer), stdin);
|
||||
if (num <= 0)
|
||||
break;
|
||||
fwrite(buffer, num, 1, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
70
tests/benchmarks/corelib/io/qprocess/tst_bench_qprocess.cpp
Normal file
70
tests/benchmarks/corelib/io/qprocess/tst_bench_qprocess.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QSignalSpy>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
|
||||
class tst_QProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
|
||||
void echoTest_performance();
|
||||
};
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# define EXE ".exe"
|
||||
#else
|
||||
# define EXE ""
|
||||
#endif
|
||||
|
||||
void tst_QProcess::echoTest_performance()
|
||||
{
|
||||
QProcess process;
|
||||
process.start(QFINDTESTDATA("../testProcessLoopback/testProcessLoopback" EXE));
|
||||
|
||||
QByteArray array;
|
||||
array.resize(1024 * 1024);
|
||||
for (int j = 0; j < array.size(); ++j)
|
||||
array[j] = 'a' + (j % 20);
|
||||
|
||||
QVERIFY(process.waitForStarted());
|
||||
|
||||
QElapsedTimer stopWatch;
|
||||
stopWatch.start();
|
||||
|
||||
qint64 totalBytes = 0;
|
||||
QByteArray dump;
|
||||
QSignalSpy readyReadSpy(&process, SIGNAL(readyRead()));
|
||||
QVERIFY(readyReadSpy.isValid());
|
||||
while (stopWatch.elapsed() < 2000) {
|
||||
process.write(array);
|
||||
while (process.bytesToWrite() > 0) {
|
||||
int readCount = readyReadSpy.size();
|
||||
QVERIFY(process.waitForBytesWritten(5000));
|
||||
if (readyReadSpy.size() == readCount)
|
||||
QVERIFY(process.waitForReadyRead(5000));
|
||||
}
|
||||
|
||||
while (process.bytesAvailable() < array.size())
|
||||
QVERIFY2(process.waitForReadyRead(5000), qPrintable(process.errorString()));
|
||||
dump = process.readAll();
|
||||
totalBytes += dump.size();
|
||||
}
|
||||
|
||||
qDebug() << "Elapsed time:" << stopWatch.elapsed() << "ms;"
|
||||
<< "transfer rate:" << totalBytes / (1048.576) / stopWatch.elapsed()
|
||||
<< "MB/s";
|
||||
|
||||
for (int j = 0; j < array.size(); ++j)
|
||||
QCOMPARE(char(dump.at(j)), char('a' + (j % 20)));
|
||||
|
||||
process.closeWriteChannel();
|
||||
QVERIFY(process.waitForFinished());
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QProcess)
|
||||
#include "tst_bench_qprocess.moc"
|
13
tests/benchmarks/corelib/io/qtemporaryfile/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/io/qtemporaryfile/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qtemporaryfile Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qtemporaryfile
|
||||
SOURCES
|
||||
tst_bench_qtemporaryfile.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,64 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QDebug>
|
||||
#include <QIODevice>
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
#include <QTemporaryFile>
|
||||
#include <qtest.h>
|
||||
|
||||
class tst_QTemporaryFile : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void openclose_data();
|
||||
void openclose();
|
||||
void readwrite_data() { openclose_data(); }
|
||||
void readwrite();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
void tst_QTemporaryFile::openclose_data()
|
||||
{
|
||||
QTest::addColumn<qint64>("amount");
|
||||
QTest::newRow("100") << qint64(100);
|
||||
QTest::newRow("1000") << qint64(1000);
|
||||
QTest::newRow("10000") << qint64(10000);
|
||||
}
|
||||
|
||||
void tst_QTemporaryFile::openclose()
|
||||
{
|
||||
QFETCH(qint64, amount);
|
||||
|
||||
QBENCHMARK {
|
||||
for (qint64 i = 0; i < amount; ++i) {
|
||||
QTemporaryFile file;
|
||||
file.open();
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QTemporaryFile::readwrite()
|
||||
{
|
||||
QFETCH(qint64, amount);
|
||||
|
||||
const int dataSize = 4096;
|
||||
QByteArray data;
|
||||
data.fill('a', dataSize);
|
||||
QBENCHMARK {
|
||||
for (qint64 i = 0; i < amount; ++i) {
|
||||
QTemporaryFile file;
|
||||
file.open();
|
||||
file.write(data);
|
||||
file.seek(0);
|
||||
file.read(dataSize);
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QTemporaryFile)
|
||||
|
||||
#include "tst_bench_qtemporaryfile.moc"
|
13
tests/benchmarks/corelib/io/qtextstream/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/io/qtextstream/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qtextstream Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qtextstream
|
||||
SOURCES
|
||||
tst_bench_qtextstream.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,95 @@
|
||||
// Copyright (C) 2014 David Faure <david.faure@kdab.com>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QDebug>
|
||||
#include <QIODevice>
|
||||
#include <QString>
|
||||
#include <QBuffer>
|
||||
#include <qtest.h>
|
||||
|
||||
class tst_QTextStream : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void writeSingleChar_data();
|
||||
void writeSingleChar();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
enum Output { StringOutput, DeviceOutput };
|
||||
Q_DECLARE_METATYPE(Output);
|
||||
|
||||
enum Input { CharStarInput, QStringInput, CharInput, QCharInput };
|
||||
Q_DECLARE_METATYPE(Input);
|
||||
|
||||
void tst_QTextStream::writeSingleChar_data()
|
||||
{
|
||||
QTest::addColumn<Output>("output");
|
||||
QTest::addColumn<Input>("input");
|
||||
|
||||
QTest::newRow("string_charstar") << StringOutput << CharStarInput;
|
||||
QTest::newRow("string_string") << StringOutput << QStringInput;
|
||||
QTest::newRow("string_char") << StringOutput << CharInput;
|
||||
QTest::newRow("string_qchar") << StringOutput << QCharInput;
|
||||
QTest::newRow("device_charstar") << DeviceOutput << CharStarInput;
|
||||
QTest::newRow("device_string") << DeviceOutput << QStringInput;
|
||||
QTest::newRow("device_char") << DeviceOutput << CharInput;
|
||||
QTest::newRow("device_qchar") << DeviceOutput << QCharInput;
|
||||
}
|
||||
|
||||
void tst_QTextStream::writeSingleChar()
|
||||
{
|
||||
QFETCH(Output, output);
|
||||
QFETCH(Input, input);
|
||||
|
||||
QString str;
|
||||
QBuffer buffer;
|
||||
QTextStream stream;
|
||||
if (output == StringOutput) {
|
||||
stream.setString(&str, QIODevice::WriteOnly);
|
||||
} else {
|
||||
QVERIFY(buffer.open(QIODevice::WriteOnly));
|
||||
stream.setDevice(&buffer);
|
||||
}
|
||||
// Test many different ways to write a single char into a QTextStream
|
||||
QString inputString = "h";
|
||||
const int amount = 100000;
|
||||
switch (input) {
|
||||
case CharStarInput:
|
||||
QBENCHMARK {
|
||||
for (qint64 i = 0; i < amount; ++i)
|
||||
stream << "h";
|
||||
}
|
||||
break;
|
||||
case QStringInput:
|
||||
QBENCHMARK {
|
||||
for (qint64 i = 0; i < amount; ++i)
|
||||
stream << inputString;
|
||||
}
|
||||
break;
|
||||
case CharInput:
|
||||
QBENCHMARK {
|
||||
for (qint64 i = 0; i < amount; ++i)
|
||||
stream << 'h';
|
||||
}
|
||||
break;
|
||||
case QCharInput:
|
||||
QBENCHMARK {
|
||||
for (qint64 i = 0; i < amount; ++i)
|
||||
stream << QChar('h');
|
||||
}
|
||||
break;
|
||||
}
|
||||
QString result;
|
||||
if (output == StringOutput)
|
||||
result = str;
|
||||
else
|
||||
result = QString(buffer.data());
|
||||
|
||||
QCOMPARE(result.left(10), QString("hhhhhhhhhh"));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QTextStream)
|
||||
|
||||
#include "tst_bench_qtextstream.moc"
|
21
tests/benchmarks/corelib/io/qurl/CMakeLists.txt
Normal file
21
tests/benchmarks/corelib/io/qurl/CMakeLists.txt
Normal file
@ -0,0 +1,21 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qurl Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qurl
|
||||
SOURCES
|
||||
tst_bench_qurl.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_extend_target(tst_bench_qurl CONDITION WIN32
|
||||
DEFINES
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
)
|
185
tests/benchmarks/corelib/io/qurl/tst_bench_qurl.cpp
Normal file
185
tests/benchmarks/corelib/io/qurl/tst_bench_qurl.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <qurl.h>
|
||||
#include <qtest.h>
|
||||
|
||||
class tst_QUrl : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void emptyUrl();
|
||||
void relativeUrl();
|
||||
void absoluteUrl();
|
||||
void isRelative_data();
|
||||
void isRelative();
|
||||
void toLocalFile_data();
|
||||
void toLocalFile();
|
||||
void toString_data();
|
||||
void toString();
|
||||
void resolved_data();
|
||||
void resolved();
|
||||
void equality_data();
|
||||
void equality();
|
||||
void qmlPropertyWriteUseCase();
|
||||
|
||||
private:
|
||||
void generateFirstRunData();
|
||||
};
|
||||
|
||||
void tst_QUrl::emptyUrl()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QUrl url;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUrl::relativeUrl()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QUrl url("pics/avatar.png");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUrl::absoluteUrl()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QUrl url("/tmp/avatar.png");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUrl::generateFirstRunData()
|
||||
{
|
||||
QTest::addColumn<bool>("firstRun");
|
||||
|
||||
QTest::newRow("construction + first run") << true;
|
||||
QTest::newRow("subsequent runs") << false;
|
||||
}
|
||||
|
||||
void tst_QUrl::isRelative_data()
|
||||
{
|
||||
generateFirstRunData();
|
||||
}
|
||||
|
||||
void tst_QUrl::isRelative()
|
||||
{
|
||||
QFETCH(bool, firstRun);
|
||||
if (firstRun) {
|
||||
QBENCHMARK {
|
||||
QUrl url("pics/avatar.png");
|
||||
url.isRelative();
|
||||
}
|
||||
} else {
|
||||
QUrl url("pics/avatar.png");
|
||||
QBENCHMARK {
|
||||
url.isRelative();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUrl::toLocalFile_data()
|
||||
{
|
||||
generateFirstRunData();
|
||||
}
|
||||
|
||||
void tst_QUrl::toLocalFile()
|
||||
{
|
||||
QFETCH(bool, firstRun);
|
||||
if (firstRun) {
|
||||
QBENCHMARK {
|
||||
QUrl url("/tmp/avatar.png");
|
||||
url.toLocalFile();
|
||||
}
|
||||
} else {
|
||||
QUrl url("/tmp/avatar.png");
|
||||
QBENCHMARK {
|
||||
url.toLocalFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUrl::toString_data()
|
||||
{
|
||||
generateFirstRunData();
|
||||
}
|
||||
|
||||
void tst_QUrl::toString()
|
||||
{
|
||||
QFETCH(bool, firstRun);
|
||||
if(firstRun) {
|
||||
QBENCHMARK {
|
||||
QUrl url("pics/avatar.png");
|
||||
url.toString();
|
||||
}
|
||||
} else {
|
||||
QUrl url("pics/avatar.png");
|
||||
QBENCHMARK {
|
||||
url.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUrl::resolved_data()
|
||||
{
|
||||
generateFirstRunData();
|
||||
}
|
||||
|
||||
void tst_QUrl::resolved()
|
||||
{
|
||||
QFETCH(bool, firstRun);
|
||||
QUrl expect("/home/user/pics/avatar.png"), actual;
|
||||
if (firstRun) {
|
||||
QBENCHMARK {
|
||||
QUrl baseUrl("/home/user/");
|
||||
QUrl url("pics/avatar.png");
|
||||
actual = baseUrl.resolved(url);
|
||||
}
|
||||
} else {
|
||||
QUrl baseUrl("/home/user/");
|
||||
QUrl url("pics/avatar.png");
|
||||
QBENCHMARK {
|
||||
actual = baseUrl.resolved(url);
|
||||
}
|
||||
}
|
||||
QCOMPARE(actual, expect);
|
||||
}
|
||||
|
||||
void tst_QUrl::equality_data()
|
||||
{
|
||||
generateFirstRunData();
|
||||
}
|
||||
|
||||
void tst_QUrl::equality()
|
||||
{
|
||||
QFETCH(bool, firstRun);
|
||||
if(firstRun) {
|
||||
QBENCHMARK {
|
||||
QUrl url("pics/avatar.png");
|
||||
QUrl url2("pics/avatar2.png");
|
||||
//url == url2;
|
||||
}
|
||||
} else {
|
||||
QUrl url("pics/avatar.png");
|
||||
QUrl url2("pics/avatar2.png");
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = url == url2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUrl::qmlPropertyWriteUseCase()
|
||||
{
|
||||
QUrl base("file:///home/user/qt/examples/declarative/samegame/SamegameCore/");
|
||||
QString str("pics/redStar.png");
|
||||
|
||||
QBENCHMARK {
|
||||
QUrl u = QUrl(str);
|
||||
if (!u.isEmpty() && u.isRelative())
|
||||
u = base.resolved(u);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QUrl)
|
||||
|
||||
#include "tst_bench_qurl.moc"
|
1
tests/benchmarks/corelib/itemmodels/CMakeLists.txt
Normal file
1
tests/benchmarks/corelib/itemmodels/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(qsortfilterproxymodel)
|
@ -0,0 +1,9 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qsortfilterproxymodel
|
||||
SOURCES
|
||||
tst_bench_qsortfilterproxymodel.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,98 @@
|
||||
// Copyright (C) 2021 Igor Kushnir <igorkuo@gmail.com>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringListModel>
|
||||
#include <QTest>
|
||||
|
||||
static void resizeNumberList(QStringList &numberList, int size)
|
||||
{
|
||||
if (!numberList.empty())
|
||||
QCOMPARE(numberList.constLast(), QString::number(numberList.size()));
|
||||
|
||||
if (numberList.size() < size) {
|
||||
numberList.reserve(size);
|
||||
for (int i = numberList.size() + 1; i <= size; ++i)
|
||||
numberList.push_back(QString::number(i));
|
||||
} else if (numberList.size() > size) {
|
||||
numberList.erase(numberList.begin() + size, numberList.end());
|
||||
}
|
||||
|
||||
QCOMPARE(numberList.size(), size);
|
||||
if (!numberList.empty())
|
||||
QCOMPARE(numberList.constLast(), QString::number(numberList.size()));
|
||||
}
|
||||
|
||||
class tst_QSortFilterProxyModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void clearFilter_data();
|
||||
void clearFilter();
|
||||
|
||||
private:
|
||||
QStringList m_numberList; ///< Cache the strings for efficiency.
|
||||
};
|
||||
|
||||
void tst_QSortFilterProxyModel::clearFilter_data()
|
||||
{
|
||||
QTest::addColumn<int>("itemCount");
|
||||
QTest::addColumn<QString>("pattern");
|
||||
QTest::addColumn<int>("filteredRowCount");
|
||||
|
||||
const auto matchSingleItem = [](int item) { return QStringLiteral("^%1$").arg(item); };
|
||||
|
||||
for (int thousandItemCount : { 10, 25, 50, 100, 250, 500, 1000, 2000 }) {
|
||||
const auto itemCount = thousandItemCount * 1000;
|
||||
|
||||
QTest::addRow("no match in %dK", thousandItemCount) << itemCount << "-" << 0;
|
||||
QTest::addRow("match all in %dK", thousandItemCount) << itemCount << "\\d+" << itemCount;
|
||||
|
||||
QTest::addRow("match first in %dK", thousandItemCount)
|
||||
<< itemCount << matchSingleItem(1) << 1;
|
||||
QTest::addRow("match 1000th in %dK", thousandItemCount)
|
||||
<< itemCount << matchSingleItem(1000) << 1;
|
||||
QTest::addRow("match middle in %dK", thousandItemCount)
|
||||
<< itemCount << matchSingleItem(itemCount / 2) << 1;
|
||||
QTest::addRow("match 1000th from end in %dK", thousandItemCount)
|
||||
<< itemCount << matchSingleItem(itemCount - 999) << 1;
|
||||
QTest::addRow("match last in %dK", thousandItemCount)
|
||||
<< itemCount << matchSingleItem(itemCount) << 1;
|
||||
|
||||
QTest::addRow("match each 10'000th in %dK", thousandItemCount)
|
||||
<< itemCount << "0000$" << thousandItemCount / 10;
|
||||
QTest::addRow("match each 100'000th in %dK", thousandItemCount)
|
||||
<< itemCount << "00000$" << thousandItemCount / 100;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSortFilterProxyModel::clearFilter()
|
||||
{
|
||||
QFETCH(const int, itemCount);
|
||||
resizeNumberList(m_numberList, itemCount);
|
||||
QStringListModel model(std::as_const(m_numberList));
|
||||
QCOMPARE(model.rowCount(), itemCount);
|
||||
|
||||
QSortFilterProxyModel proxy;
|
||||
proxy.setSourceModel(&model);
|
||||
QCOMPARE(model.rowCount(), itemCount);
|
||||
QCOMPARE(proxy.rowCount(), itemCount);
|
||||
|
||||
QFETCH(const QString, pattern);
|
||||
QFETCH(const int, filteredRowCount);
|
||||
proxy.setFilterRegularExpression(pattern);
|
||||
QCOMPARE(model.rowCount(), itemCount);
|
||||
QCOMPARE(proxy.rowCount(), filteredRowCount);
|
||||
|
||||
QBENCHMARK_ONCE {
|
||||
proxy.setFilterRegularExpression(QString());
|
||||
}
|
||||
QCOMPARE(model.rowCount(), itemCount);
|
||||
QCOMPARE(proxy.rowCount(), itemCount);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QSortFilterProxyModel)
|
||||
|
||||
#include "tst_bench_qsortfilterproxymodel.moc"
|
13
tests/benchmarks/corelib/json/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/json/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qtjson Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qtjson
|
||||
SOURCES
|
||||
tst_bench_qtjson.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
19
tests/benchmarks/corelib/json/numbers.json
Normal file
19
tests/benchmarks/corelib/json/numbers.json
Normal file
@ -0,0 +1,19 @@
|
||||
[
|
||||
{
|
||||
"integer": 1234567890,
|
||||
"real": -9876.543210,
|
||||
"e": 0.123456789e-12,
|
||||
"E": 1.234567890E+34,
|
||||
"": 23456789012E66,
|
||||
"zero": 0,
|
||||
"one": 1
|
||||
},
|
||||
[
|
||||
-1234567890,
|
||||
-1234567890,
|
||||
-1234567890,
|
||||
1234567890,
|
||||
1234567890,
|
||||
1234567890
|
||||
]
|
||||
]
|
66
tests/benchmarks/corelib/json/test.json
Normal file
66
tests/benchmarks/corelib/json/test.json
Normal file
File diff suppressed because one or more lines are too long
122
tests/benchmarks/corelib/json/tst_bench_qtjson.cpp
Normal file
122
tests/benchmarks/corelib/json/tst_bench_qtjson.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QVariantMap>
|
||||
#include <qjsondocument.h>
|
||||
#include <qjsonobject.h>
|
||||
|
||||
class BenchmarkQtJson: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BenchmarkQtJson(QObject *parent = nullptr);
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
void parseNumbers();
|
||||
void parseJson();
|
||||
void parseJsonToVariant();
|
||||
|
||||
void jsonObjectInsert();
|
||||
void variantMapInsert();
|
||||
};
|
||||
|
||||
BenchmarkQtJson::BenchmarkQtJson(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BenchmarkQtJson::initTestCase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BenchmarkQtJson::cleanupTestCase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BenchmarkQtJson::init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BenchmarkQtJson::cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BenchmarkQtJson::parseNumbers()
|
||||
{
|
||||
QString testFile = QFINDTESTDATA("numbers.json");
|
||||
QVERIFY2(!testFile.isEmpty(), "cannot find test file numbers.json!");
|
||||
QFile file(testFile);
|
||||
file.open(QFile::ReadOnly);
|
||||
QByteArray testJson = file.readAll();
|
||||
|
||||
QBENCHMARK {
|
||||
QJsonDocument doc = QJsonDocument::fromJson(testJson);
|
||||
QJsonObject object = doc.object();
|
||||
}
|
||||
}
|
||||
|
||||
void BenchmarkQtJson::parseJson()
|
||||
{
|
||||
QString testFile = QFINDTESTDATA("test.json");
|
||||
QVERIFY2(!testFile.isEmpty(), "cannot find test file test.json!");
|
||||
QFile file(testFile);
|
||||
file.open(QFile::ReadOnly);
|
||||
QByteArray testJson = file.readAll();
|
||||
|
||||
QBENCHMARK {
|
||||
QJsonDocument doc = QJsonDocument::fromJson(testJson);
|
||||
QJsonObject object = doc.object();
|
||||
}
|
||||
}
|
||||
|
||||
void BenchmarkQtJson::parseJsonToVariant()
|
||||
{
|
||||
QString testFile = QFINDTESTDATA("test.json");
|
||||
QVERIFY2(!testFile.isEmpty(), "cannot find test file test.json!");
|
||||
QFile file(testFile);
|
||||
file.open(QFile::ReadOnly);
|
||||
QByteArray testJson = file.readAll();
|
||||
|
||||
QBENCHMARK {
|
||||
QJsonDocument doc = QJsonDocument::fromJson(testJson);
|
||||
QVariant v = doc.toVariant();
|
||||
}
|
||||
}
|
||||
|
||||
void BenchmarkQtJson::jsonObjectInsert()
|
||||
{
|
||||
QJsonObject object;
|
||||
QString test(QStringLiteral("testString"));
|
||||
QJsonValue value(1.5);
|
||||
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 1000; i++)
|
||||
object.insert("testkey_" + QString::number(i), value);
|
||||
}
|
||||
}
|
||||
|
||||
void BenchmarkQtJson::variantMapInsert()
|
||||
{
|
||||
QVariantMap object;
|
||||
QString test(QStringLiteral("testString"));
|
||||
QVariant variantValue(1.5);
|
||||
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 1000; i++)
|
||||
object.insert("testkey_" + QString::number(i), variantValue);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(BenchmarkQtJson)
|
||||
#include "tst_bench_qtjson.moc"
|
||||
|
17
tests/benchmarks/corelib/kernel/CMakeLists.txt
Normal file
17
tests/benchmarks/corelib/kernel/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(events)
|
||||
add_subdirectory(qmetatype)
|
||||
add_subdirectory(qvariant)
|
||||
add_subdirectory(qcoreapplication)
|
||||
add_subdirectory(qtimer_vs_qmetaobject)
|
||||
add_subdirectory(qproperty)
|
||||
add_subdirectory(qmetaenum)
|
||||
if(TARGET Qt::Widgets)
|
||||
add_subdirectory(qmetaobject)
|
||||
add_subdirectory(qobject)
|
||||
endif()
|
||||
if(WIN32)
|
||||
add_subdirectory(qwineventnotifier)
|
||||
endif()
|
13
tests/benchmarks/corelib/kernel/events/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/kernel/events/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_events Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_events
|
||||
SOURCES
|
||||
tst_bench_events.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
150
tests/benchmarks/corelib/kernel/events/tst_bench_events.cpp
Normal file
150
tests/benchmarks/corelib/kernel/events/tst_bench_events.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QtCore>
|
||||
|
||||
#include <qtest.h>
|
||||
#include <qtesteventloop.h>
|
||||
|
||||
class PingPong : public QObject
|
||||
{
|
||||
public:
|
||||
void setPeer(QObject *peer);
|
||||
void resetCounter() {m_counter = 100;}
|
||||
|
||||
protected:
|
||||
bool event(QEvent *e) override;
|
||||
|
||||
private:
|
||||
QObject *m_peer;
|
||||
int m_counter;
|
||||
};
|
||||
|
||||
void PingPong::setPeer(QObject *peer)
|
||||
{
|
||||
m_peer = peer;
|
||||
m_counter = 100;
|
||||
}
|
||||
|
||||
bool PingPong::event(QEvent *)
|
||||
{
|
||||
--m_counter;
|
||||
if (m_counter > 0) {
|
||||
QEvent *e = new QEvent(QEvent::User);
|
||||
QCoreApplication::postEvent(m_peer, e);
|
||||
} else {
|
||||
QTestEventLoop::instance().exitLoop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class EventTester : public QObject
|
||||
{
|
||||
public:
|
||||
int foo(int bar);
|
||||
|
||||
protected:
|
||||
bool event(QEvent *e) override;
|
||||
};
|
||||
|
||||
bool EventTester::event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::User+1)
|
||||
return foo(e->type()) != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int EventTester::foo(int bar)
|
||||
{
|
||||
return bar + 1;
|
||||
}
|
||||
|
||||
class EventsBench : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
|
||||
void noEvent();
|
||||
void sendEvent_data();
|
||||
void sendEvent();
|
||||
void postEvent_data();
|
||||
void postEvent();
|
||||
};
|
||||
|
||||
void EventsBench::initTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
void EventsBench::cleanupTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
void EventsBench::noEvent()
|
||||
{
|
||||
EventTester tst;
|
||||
int val = 0;
|
||||
QBENCHMARK {
|
||||
val += tst.foo(1);
|
||||
}
|
||||
QVERIFY(val > 0);
|
||||
}
|
||||
|
||||
void EventsBench::sendEvent_data()
|
||||
{
|
||||
QTest::addColumn<bool>("filterEvents");
|
||||
QTest::newRow("no eventfilter") << false;
|
||||
QTest::newRow("eventfilter") << true;
|
||||
}
|
||||
|
||||
void EventsBench::sendEvent()
|
||||
{
|
||||
QFETCH(bool, filterEvents);
|
||||
EventTester tst;
|
||||
if (filterEvents)
|
||||
tst.installEventFilter(this);
|
||||
QEvent evt(QEvent::Type(QEvent::User+1));
|
||||
QBENCHMARK {
|
||||
QCoreApplication::sendEvent(&tst, &evt);
|
||||
}
|
||||
}
|
||||
|
||||
void EventsBench::postEvent_data()
|
||||
{
|
||||
QTest::addColumn<bool>("filterEvents");
|
||||
// The first time an eventloop is executed, the case runs radically slower at least
|
||||
// on some platforms, so test the "no eventfilter" case to get a comparable results
|
||||
// with the "eventfilter" case.
|
||||
QTest::newRow("first time, no eventfilter") << false;
|
||||
QTest::newRow("no eventfilter") << false;
|
||||
QTest::newRow("eventfilter") << true;
|
||||
}
|
||||
|
||||
void EventsBench::postEvent()
|
||||
{
|
||||
QFETCH(bool, filterEvents);
|
||||
PingPong ping;
|
||||
PingPong pong;
|
||||
ping.setPeer(&pong);
|
||||
pong.setPeer(&ping);
|
||||
if (filterEvents) {
|
||||
ping.installEventFilter(this);
|
||||
pong.installEventFilter(this);
|
||||
}
|
||||
|
||||
QBENCHMARK {
|
||||
// In case multiple iterations are done, event needs to be created inside the QBENCHMARK,
|
||||
// or it gets deleted once first iteration exits and can cause a crash. Similarly,
|
||||
// ping and pong need their counters reset.
|
||||
QEvent *e = new QEvent(QEvent::User);
|
||||
ping.resetCounter();
|
||||
pong.resetCounter();
|
||||
QCoreApplication::postEvent(&ping, e);
|
||||
QTestEventLoop::instance().enterLoop( 61 );
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(EventsBench)
|
||||
|
||||
#include "tst_bench_events.moc"
|
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qcoreapplication Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qcoreapplication
|
||||
SOURCES
|
||||
tst_bench_qcoreapplication.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,44 @@
|
||||
// Copyright (C) 2011 Robin Burchell <robin+qt@viroteck.net>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QtCore>
|
||||
#include <qtest.h>
|
||||
#include <qcoreapplication.h>
|
||||
|
||||
class tst_QCoreApplication : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void event_posting_benchmark_data();
|
||||
void event_posting_benchmark();
|
||||
};
|
||||
|
||||
void tst_QCoreApplication::event_posting_benchmark_data()
|
||||
{
|
||||
QTest::addColumn<int>("size");
|
||||
QTest::newRow("50 events") << 50;
|
||||
QTest::newRow("100 events") << 100;
|
||||
QTest::newRow("200 events") << 200;
|
||||
QTest::newRow("1000 events") << 1000;
|
||||
QTest::newRow("10000 events") << 10000;
|
||||
QTest::newRow("100000 events") << 100000;
|
||||
QTest::newRow("1000000 events") << 1000000;
|
||||
}
|
||||
|
||||
void tst_QCoreApplication::event_posting_benchmark()
|
||||
{
|
||||
QFETCH(int, size);
|
||||
|
||||
int type = QEvent::registerEventType();
|
||||
QCoreApplication *app = QCoreApplication::instance();
|
||||
|
||||
// benchmark posting & sending events
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < size; ++i)
|
||||
QCoreApplication::postEvent(app, new QEvent(QEvent::Type(type)));
|
||||
QCoreApplication::sendPostedEvents();
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QCoreApplication)
|
||||
|
||||
#include "tst_bench_qcoreapplication.moc"
|
10
tests/benchmarks/corelib/kernel/qmetaenum/CMakeLists.txt
Normal file
10
tests/benchmarks/corelib/kernel/qmetaenum/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qmetaenum
|
||||
SOURCES
|
||||
tst_bench_qmetaenum.cpp
|
||||
LIBRARIES
|
||||
Qt::Core
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QMetaEnum>
|
||||
#include <QTest>
|
||||
|
||||
class tst_QMetaEnum: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using QObject::QObject;
|
||||
|
||||
private Q_SLOTS:
|
||||
void valueToKeys_data();
|
||||
void valueToKeys();
|
||||
void keysToValue_data() { valueToKeys_data(); }
|
||||
void keysToValue();
|
||||
};
|
||||
|
||||
void tst_QMetaEnum::valueToKeys_data()
|
||||
{
|
||||
QTest::addColumn<int>("buttons");
|
||||
QTest::addColumn<QByteArray>("string");
|
||||
// Qt::MouseButtons has at least 24 enumerators, so it's a good performance test
|
||||
const auto me = QMetaEnum::fromType<Qt::MouseButtons>();
|
||||
int accu = 0;
|
||||
for (int i = 0; i < std::min(31, me.keyCount()); ++i) {
|
||||
accu <<= 1;
|
||||
accu |= 1;
|
||||
QTest::addRow("%d bits set", i) << accu << me.valueToKeys(accu);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaEnum::valueToKeys()
|
||||
{
|
||||
QFETCH(const int, buttons);
|
||||
const auto me = QMetaEnum::fromType<Qt::MouseButtons>();
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = me.valueToKeys(buttons);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaEnum::keysToValue()
|
||||
{
|
||||
QFETCH(const QByteArray, string);
|
||||
const auto me = QMetaEnum::fromType<Qt::MouseButtons>();
|
||||
bool ok;
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = me.keysToValue(string.data(), &ok);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QMetaEnum)
|
||||
|
||||
#include "tst_bench_qmetaenum.moc"
|
15
tests/benchmarks/corelib/kernel/qmetaobject/CMakeLists.txt
Normal file
15
tests/benchmarks/corelib/kernel/qmetaobject/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qmetaobject Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qmetaobject
|
||||
SOURCES
|
||||
tst_bench_qmetaobject.cpp
|
||||
LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::Test
|
||||
Qt::Widgets
|
||||
)
|
@ -0,0 +1,216 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QtCore>
|
||||
#include <QtWidgets/QTreeView>
|
||||
#include <qtest.h>
|
||||
|
||||
class LotsOfSignals : public QObject // for the unconnected() test
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LotsOfSignals() {}
|
||||
|
||||
signals:
|
||||
void extraSignal1();
|
||||
void extraSignal2();
|
||||
void extraSignal3();
|
||||
void extraSignal4();
|
||||
void extraSignal5();
|
||||
void extraSignal6();
|
||||
void extraSignal7();
|
||||
void extraSignal8();
|
||||
void extraSignal9();
|
||||
void extraSignal10();
|
||||
void extraSignal12();
|
||||
void extraSignal13();
|
||||
void extraSignal14();
|
||||
void extraSignal15();
|
||||
void extraSignal16();
|
||||
void extraSignal17();
|
||||
void extraSignal18();
|
||||
void extraSignal19();
|
||||
void extraSignal20();
|
||||
void extraSignal21();
|
||||
void extraSignal22();
|
||||
void extraSignal23();
|
||||
void extraSignal24();
|
||||
void extraSignal25();
|
||||
void extraSignal26();
|
||||
void extraSignal27();
|
||||
void extraSignal28();
|
||||
void extraSignal29();
|
||||
void extraSignal30();
|
||||
void extraSignal31();
|
||||
void extraSignal32();
|
||||
void extraSignal33();
|
||||
void extraSignal34();
|
||||
void extraSignal35();
|
||||
void extraSignal36();
|
||||
void extraSignal37();
|
||||
void extraSignal38();
|
||||
void extraSignal39();
|
||||
void extraSignal40();
|
||||
void extraSignal41();
|
||||
void extraSignal42();
|
||||
void extraSignal43();
|
||||
void extraSignal44();
|
||||
void extraSignal45();
|
||||
void extraSignal46();
|
||||
void extraSignal47();
|
||||
void extraSignal48();
|
||||
void extraSignal49();
|
||||
void extraSignal50();
|
||||
void extraSignal51();
|
||||
void extraSignal52();
|
||||
void extraSignal53();
|
||||
void extraSignal54();
|
||||
void extraSignal55();
|
||||
void extraSignal56();
|
||||
void extraSignal57();
|
||||
void extraSignal58();
|
||||
void extraSignal59();
|
||||
void extraSignal60();
|
||||
void extraSignal61();
|
||||
void extraSignal62();
|
||||
void extraSignal63();
|
||||
void extraSignal64();
|
||||
void extraSignal65();
|
||||
void extraSignal66();
|
||||
void extraSignal67();
|
||||
void extraSignal68();
|
||||
void extraSignal69();
|
||||
void extraSignal70();
|
||||
};
|
||||
|
||||
class tst_QMetaObject: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void indexOfProperty_data();
|
||||
void indexOfProperty();
|
||||
void indexOfMethod_data();
|
||||
void indexOfMethod();
|
||||
void indexOfSignal_data();
|
||||
void indexOfSignal();
|
||||
void indexOfSlot_data();
|
||||
void indexOfSlot();
|
||||
|
||||
void unconnected_data();
|
||||
void unconnected();
|
||||
};
|
||||
|
||||
void tst_QMetaObject::indexOfProperty_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("name");
|
||||
const QMetaObject *mo = &QTreeView::staticMetaObject;
|
||||
for (int i = 0; i < mo->propertyCount(); ++i) {
|
||||
QMetaProperty prop = mo->property(i);
|
||||
QTest::newRow(prop.name()) << QByteArray(prop.name());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaObject::indexOfProperty()
|
||||
{
|
||||
QFETCH(QByteArray, name);
|
||||
const char *p = name.constData();
|
||||
const QMetaObject *mo = &QTreeView::staticMetaObject;
|
||||
QBENCHMARK {
|
||||
(void)mo->indexOfProperty(p);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaObject::indexOfMethod_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("method");
|
||||
const QMetaObject *mo = &QTreeView::staticMetaObject;
|
||||
for (int i = 0; i < mo->methodCount(); ++i) {
|
||||
QMetaMethod method = mo->method(i);
|
||||
QByteArray sig = method.methodSignature();
|
||||
QTest::newRow(sig) << sig;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaObject::indexOfMethod()
|
||||
{
|
||||
QFETCH(QByteArray, method);
|
||||
const char *p = method.constData();
|
||||
const QMetaObject *mo = &QTreeView::staticMetaObject;
|
||||
QBENCHMARK {
|
||||
(void)mo->indexOfMethod(p);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaObject::indexOfSignal_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("signal");
|
||||
const QMetaObject *mo = &QTreeView::staticMetaObject;
|
||||
for (int i = 0; i < mo->methodCount(); ++i) {
|
||||
QMetaMethod method = mo->method(i);
|
||||
if (method.methodType() != QMetaMethod::Signal)
|
||||
continue;
|
||||
QByteArray sig = method.methodSignature();
|
||||
QTest::newRow(sig) << sig;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaObject::indexOfSignal()
|
||||
{
|
||||
QFETCH(QByteArray, signal);
|
||||
const char *p = signal.constData();
|
||||
const QMetaObject *mo = &QTreeView::staticMetaObject;
|
||||
QBENCHMARK {
|
||||
(void)mo->indexOfSignal(p);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaObject::indexOfSlot_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("slot");
|
||||
const QMetaObject *mo = &QTreeView::staticMetaObject;
|
||||
for (int i = 0; i < mo->methodCount(); ++i) {
|
||||
QMetaMethod method = mo->method(i);
|
||||
if (method.methodType() != QMetaMethod::Slot)
|
||||
continue;
|
||||
QByteArray sig = method.methodSignature();
|
||||
QTest::newRow(sig) << sig;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaObject::indexOfSlot()
|
||||
{
|
||||
QFETCH(QByteArray, slot);
|
||||
const char *p = slot.constData();
|
||||
const QMetaObject *mo = &QTreeView::staticMetaObject;
|
||||
QBENCHMARK {
|
||||
(void)mo->indexOfSlot(p);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaObject::unconnected_data()
|
||||
{
|
||||
QTest::addColumn<int>("signal_index");
|
||||
QTest::newRow("signal--9") << 9;
|
||||
QTest::newRow("signal--32") << 32;
|
||||
QTest::newRow("signal--33") << 33;
|
||||
QTest::newRow("signal--64") << 64;
|
||||
QTest::newRow("signal--65") << 65;
|
||||
QTest::newRow("signal--70") << 70;
|
||||
}
|
||||
|
||||
void tst_QMetaObject::unconnected()
|
||||
{
|
||||
LotsOfSignals *obj = new LotsOfSignals;
|
||||
QFETCH(int, signal_index);
|
||||
// 74: 70 signals in LotsOfSignals, 2 signals, 1 slot + 1 invokable in QObject
|
||||
QCOMPARE(obj->metaObject()->methodCount(), 74);
|
||||
void *v;
|
||||
QBENCHMARK {
|
||||
// Add two because QObject has one slot and one invokable
|
||||
QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, signal_index + 2, &v);
|
||||
}
|
||||
delete obj;
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QMetaObject)
|
||||
|
||||
#include "tst_bench_qmetaobject.moc"
|
13
tests/benchmarks/corelib/kernel/qmetatype/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/kernel/qmetatype/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qmetatype Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qmetatype
|
||||
SOURCES
|
||||
tst_bench_qmetatype.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,299 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <qtest.h>
|
||||
#include <QtCore/qmetatype.h>
|
||||
|
||||
class tst_QMetaType : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QMetaType();
|
||||
virtual ~tst_QMetaType();
|
||||
|
||||
private slots:
|
||||
void typeBuiltin_data();
|
||||
void typeBuiltin();
|
||||
void typeBuiltin_QByteArray_data();
|
||||
void typeBuiltin_QByteArray();
|
||||
void typeBuiltinNotNormalized_data();
|
||||
void typeBuiltinNotNormalized();
|
||||
void typeCustom();
|
||||
void typeCustomNotNormalized();
|
||||
void typeNotRegistered();
|
||||
void typeNotRegisteredNotNormalized();
|
||||
|
||||
void typeNameBuiltin_data();
|
||||
void typeNameBuiltin();
|
||||
void typeNameCustom();
|
||||
void typeNameNotRegistered();
|
||||
|
||||
void isRegisteredBuiltin_data();
|
||||
void isRegisteredBuiltin();
|
||||
void isRegisteredCustom();
|
||||
void isRegisteredNotRegistered();
|
||||
|
||||
void constructInPlace_data();
|
||||
void constructInPlace();
|
||||
void constructInPlaceCopy_data();
|
||||
void constructInPlaceCopy();
|
||||
void constructInPlaceCopyStaticLess_data();
|
||||
void constructInPlaceCopyStaticLess();
|
||||
};
|
||||
|
||||
tst_QMetaType::tst_QMetaType()
|
||||
{
|
||||
}
|
||||
|
||||
tst_QMetaType::~tst_QMetaType()
|
||||
{
|
||||
}
|
||||
|
||||
struct BigClass
|
||||
{
|
||||
double n,i,e,r,o,b;
|
||||
};
|
||||
Q_DECLARE_METATYPE(BigClass);
|
||||
|
||||
void tst_QMetaType::typeBuiltin_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("typeName");
|
||||
for (int i = 0; i < QMetaType::User; ++i) {
|
||||
if (QMetaType metaType(i); metaType.isValid())
|
||||
QTest::newRow(metaType.name()) << QByteArray(metaType.name());
|
||||
}
|
||||
}
|
||||
|
||||
// QMetaType::type(const char *)
|
||||
void tst_QMetaType::typeBuiltin()
|
||||
{
|
||||
QFETCH(QByteArray, typeName);
|
||||
const char *nm = typeName.constData();
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 100000; ++i)
|
||||
QMetaType::fromName(nm);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::typeBuiltin_QByteArray_data()
|
||||
{
|
||||
typeBuiltin_data();
|
||||
}
|
||||
|
||||
// QMetaType::type(QByteArray)
|
||||
void tst_QMetaType::typeBuiltin_QByteArray()
|
||||
{
|
||||
QFETCH(QByteArray, typeName);
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 100000; ++i)
|
||||
QMetaType::fromName(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::typeBuiltinNotNormalized_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("typeName");
|
||||
for (int i = 0; i < QMetaType::User; ++i) {
|
||||
if (QMetaType metaType(i); metaType.isValid())
|
||||
QTest::newRow(metaType.name()) << QByteArray(metaType.name()).append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::typeBuiltinNotNormalized()
|
||||
{
|
||||
QFETCH(QByteArray, typeName);
|
||||
const char *nm = typeName.constData();
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
QMetaType::fromName(nm);
|
||||
}
|
||||
}
|
||||
|
||||
struct Foo { int i; };
|
||||
|
||||
void tst_QMetaType::typeCustom()
|
||||
{
|
||||
qRegisterMetaType<Foo>("Foo");
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
QMetaType::fromName("Foo");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::typeCustomNotNormalized()
|
||||
{
|
||||
qRegisterMetaType<Foo>("Foo");
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
QMetaType::fromName("Foo ");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::typeNotRegistered()
|
||||
{
|
||||
Q_ASSERT(!QMetaType::fromName("Bar").isValid());
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
QMetaType::fromName("Bar");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::typeNotRegisteredNotNormalized()
|
||||
{
|
||||
Q_ASSERT(!QMetaType::fromName("Bar").isValid());
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
QMetaType::fromName("Bar ");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::typeNameBuiltin_data()
|
||||
{
|
||||
QTest::addColumn<int>("type");
|
||||
for (int i = 0; i < QMetaType::User; ++i) {
|
||||
if (QMetaType metaType(i); metaType.isValid())
|
||||
QTest::newRow(metaType.name()) << i;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::typeNameBuiltin()
|
||||
{
|
||||
QFETCH(int, type);
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 500000; ++i)
|
||||
QMetaType(type).name();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::typeNameCustom()
|
||||
{
|
||||
int type = qRegisterMetaType<Foo>("Foo");
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 100000; ++i)
|
||||
QMetaType(type).name();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::typeNameNotRegistered()
|
||||
{
|
||||
// We don't care much about this case, but test it anyway.
|
||||
Q_ASSERT(QMetaType(-1).name() == nullptr);
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 500000; ++i)
|
||||
QMetaType(-1).name();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::isRegisteredBuiltin_data()
|
||||
{
|
||||
typeNameBuiltin_data();
|
||||
}
|
||||
|
||||
void tst_QMetaType::isRegisteredBuiltin()
|
||||
{
|
||||
QFETCH(int, type);
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 500000; ++i)
|
||||
QMetaType::isRegistered(type);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::isRegisteredCustom()
|
||||
{
|
||||
int type = qRegisterMetaType<Foo>("Foo");
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 100000; ++i)
|
||||
QMetaType::isRegistered(type);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::isRegisteredNotRegistered()
|
||||
{
|
||||
Q_ASSERT(QMetaType(-1).name() == nullptr);
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 100000; ++i)
|
||||
QMetaType::isRegistered(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructInPlace_data()
|
||||
{
|
||||
QTest::addColumn<int>("typeId");
|
||||
for (int i = QMetaType::FirstCoreType; i <= QMetaType::LastCoreType; ++i) {
|
||||
auto name = QMetaType(i).name();
|
||||
if (name && i != QMetaType::Void)
|
||||
QTest::newRow(name) << i;
|
||||
}
|
||||
|
||||
QTest::newRow("custom") << qMetaTypeId<BigClass>();
|
||||
// GUI types are tested in tst_QGuiMetaType.
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructInPlace()
|
||||
{
|
||||
QFETCH(int, typeId);
|
||||
const QMetaType metaType(typeId);
|
||||
size_t size = metaType.sizeOf();
|
||||
void *storage = qMallocAligned(size, 2 * sizeof(qlonglong));
|
||||
QCOMPARE(metaType.construct(storage, /*copy=*/0), storage);
|
||||
metaType.destruct(storage);
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 100000; ++i) {
|
||||
metaType.construct(storage, /*copy=*/0);
|
||||
metaType.destruct(storage);
|
||||
}
|
||||
}
|
||||
qFreeAligned(storage);
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructInPlaceCopy_data()
|
||||
{
|
||||
constructInPlace_data();
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructInPlaceCopy()
|
||||
{
|
||||
QFETCH(int, typeId);
|
||||
const QMetaType metaType(typeId);
|
||||
size_t size = metaType.sizeOf();
|
||||
void *storage = qMallocAligned(size, 2 * sizeof(qlonglong));
|
||||
void *other = metaType.create();
|
||||
QCOMPARE(metaType.construct(storage, other), storage);
|
||||
metaType.destruct(storage);
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 100000; ++i) {
|
||||
metaType.construct(storage, other);
|
||||
metaType.destruct(storage);
|
||||
}
|
||||
}
|
||||
metaType.destroy(other);
|
||||
qFreeAligned(storage);
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructInPlaceCopyStaticLess_data()
|
||||
{
|
||||
constructInPlaceCopy_data();
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructInPlaceCopyStaticLess()
|
||||
{
|
||||
QFETCH(int, typeId);
|
||||
const QMetaType metaType(typeId);
|
||||
size_t size = metaType.sizeOf();
|
||||
void *storage = qMallocAligned(size, 2 * sizeof(qlonglong));
|
||||
void *other = metaType.create();
|
||||
QCOMPARE(metaType.construct(storage, other), storage);
|
||||
metaType.destruct(storage);
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 100000; ++i) {
|
||||
metaType.construct(storage, other);
|
||||
metaType.destruct(storage);
|
||||
}
|
||||
}
|
||||
metaType.destroy(other);
|
||||
qFreeAligned(storage);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QMetaType)
|
||||
#include "tst_bench_qmetatype.moc"
|
16
tests/benchmarks/corelib/kernel/qobject/CMakeLists.txt
Normal file
16
tests/benchmarks/corelib/kernel/qobject/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qobject Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qobject
|
||||
SOURCES
|
||||
tst_bench_qobject.cpp
|
||||
object.cpp object.h
|
||||
LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::Test
|
||||
Qt::Widgets
|
||||
)
|
30
tests/benchmarks/corelib/kernel/qobject/object.cpp
Normal file
30
tests/benchmarks/corelib/kernel/qobject/object.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include "object.h"
|
||||
|
||||
void Object::emitSignal0()
|
||||
{ emit signal0(); }
|
||||
void Object::emitSignal1()
|
||||
{ emit signal1(); }
|
||||
|
||||
|
||||
void Object::slot0()
|
||||
{ }
|
||||
void Object::slot1()
|
||||
{ }
|
||||
void Object::slot2()
|
||||
{ }
|
||||
void Object::slot3()
|
||||
{ }
|
||||
void Object::slot4()
|
||||
{ }
|
||||
void Object::slot5()
|
||||
{ }
|
||||
void Object::slot6()
|
||||
{ }
|
||||
void Object::slot7()
|
||||
{ }
|
||||
void Object::slot8()
|
||||
{ }
|
||||
void Object::slot9()
|
||||
{ }
|
38
tests/benchmarks/corelib/kernel/qobject/object.h
Normal file
38
tests/benchmarks/corelib/kernel/qobject/object.h
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#ifndef OBJECT_H
|
||||
#define OBJECT_H
|
||||
|
||||
#include <qobject.h>
|
||||
|
||||
class Object : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
void emitSignal0();
|
||||
void emitSignal1();
|
||||
signals:
|
||||
void signal0();
|
||||
void signal1();
|
||||
void signal2();
|
||||
void signal3();
|
||||
void signal4();
|
||||
void signal5();
|
||||
void signal6();
|
||||
void signal7();
|
||||
void signal8();
|
||||
void signal9();
|
||||
public slots:
|
||||
void slot0();
|
||||
void slot1();
|
||||
void slot2();
|
||||
void slot3();
|
||||
void slot4();
|
||||
void slot5();
|
||||
void slot6();
|
||||
void slot7();
|
||||
void slot8();
|
||||
void slot9();
|
||||
};
|
||||
|
||||
#endif // OBJECT_H
|
285
tests/benchmarks/corelib/kernel/qobject/tst_bench_qobject.cpp
Normal file
285
tests/benchmarks/corelib/kernel/qobject/tst_bench_qobject.cpp
Normal file
@ -0,0 +1,285 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QtCore>
|
||||
#include <QtWidgets/QTreeView>
|
||||
#include <qtest.h>
|
||||
#include "object.h"
|
||||
#include <qcoreapplication.h>
|
||||
#include <qdatetime.h>
|
||||
|
||||
enum {
|
||||
CreationDeletionBenckmarkConstant = 34567,
|
||||
SignalsAndSlotsBenchmarkConstant = 456789
|
||||
};
|
||||
|
||||
class tst_QObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void signal_slot_benchmark();
|
||||
void signal_slot_benchmark_data();
|
||||
void signal_many_receivers();
|
||||
void signal_many_receivers_data();
|
||||
void qproperty_benchmark_data();
|
||||
void qproperty_benchmark();
|
||||
void dynamic_property_benchmark();
|
||||
void connect_disconnect_benchmark_data();
|
||||
void connect_disconnect_benchmark();
|
||||
void receiver_destroyed_benchmark();
|
||||
|
||||
void stdAllocator();
|
||||
};
|
||||
|
||||
class QObjectUsingStandardAllocator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QObjectUsingStandardAllocator()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
inline void allocator()
|
||||
{
|
||||
// We need to allocate certain amount of objects otherwise the new implementation
|
||||
// may re-use the previous allocation, hiding the somehow high cost of allocation. It
|
||||
// also helps us to reduce the noise ratio, which is high for memory allocation.
|
||||
//
|
||||
// The check depends on memory allocation performance, which is quite non-deterministic.
|
||||
// When a new memory is requested, the new operator, depending on implementation, is trying
|
||||
// to re-use existing, already allocated for the process memory. If there is not enough, it
|
||||
// asks OS to give more. Of course the first case is faster then the second. In the same
|
||||
// time, from an application perspective the first is also more likely.
|
||||
//
|
||||
// As a result, depending on which use-case one wants to test, it may be recommended to run this
|
||||
// test in separation from others, to "force" expensive code path in the memory allocation.
|
||||
//
|
||||
// The time based results are heavily affected by background noise. One really needs to
|
||||
// prepare OS (no other tasks, CPU and RAM reservations) to run this test, or use
|
||||
// instruction counting which seems to be less fragile.
|
||||
|
||||
const int count = 256 * 1024;
|
||||
|
||||
QScopedPointer<T> objects[count];
|
||||
QBENCHMARK_ONCE {
|
||||
for (int i = 0; i < count; ++i)
|
||||
objects[i].reset(new T);
|
||||
for (int i = 0; i < count; ++i)
|
||||
objects[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QObject::stdAllocator()
|
||||
{
|
||||
allocator<QObjectUsingStandardAllocator>();
|
||||
}
|
||||
|
||||
struct Functor {
|
||||
void operator()(){}
|
||||
};
|
||||
|
||||
void tst_QObject::signal_slot_benchmark_data()
|
||||
{
|
||||
QTest::addColumn<int>("type");
|
||||
QTest::newRow("simple function") << 0;
|
||||
QTest::newRow("single signal/slot") << 1;
|
||||
QTest::newRow("multi signal/slot") << 2;
|
||||
QTest::newRow("unconnected signal") << 3;
|
||||
QTest::newRow("single signal/ptr") << 4;
|
||||
QTest::newRow("functor") << 5;
|
||||
}
|
||||
|
||||
void tst_QObject::signal_slot_benchmark()
|
||||
{
|
||||
QFETCH(int, type);
|
||||
|
||||
Object singleObject;
|
||||
Object multiObject;
|
||||
Functor functor;
|
||||
singleObject.setObjectName("single");
|
||||
multiObject.setObjectName("multi");
|
||||
|
||||
if (type == 5) {
|
||||
QObject::connect(&singleObject, &Object::signal0, functor);
|
||||
} else if (type == 4) {
|
||||
QObject::connect(&singleObject, &Object::signal0, &singleObject, &Object::slot0);
|
||||
} else {
|
||||
singleObject.connect(&singleObject, SIGNAL(signal0()), SLOT(slot0()));
|
||||
}
|
||||
|
||||
multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(slot0()));
|
||||
// multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal1()));
|
||||
multiObject.connect(&multiObject, SIGNAL(signal1()), SLOT(slot1()));
|
||||
// multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal2()));
|
||||
multiObject.connect(&multiObject, SIGNAL(signal2()), SLOT(slot2()));
|
||||
// multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal3()));
|
||||
multiObject.connect(&multiObject, SIGNAL(signal3()), SLOT(slot3()));
|
||||
// multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal4()));
|
||||
multiObject.connect(&multiObject, SIGNAL(signal4()), SLOT(slot4()));
|
||||
// multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal5()));
|
||||
multiObject.connect(&multiObject, SIGNAL(signal5()), SLOT(slot5()));
|
||||
// multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal6()));
|
||||
multiObject.connect(&multiObject, SIGNAL(signal6()), SLOT(slot6()));
|
||||
// multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal7()));
|
||||
multiObject.connect(&multiObject, SIGNAL(signal7()), SLOT(slot7()));
|
||||
// multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal8()));
|
||||
multiObject.connect(&multiObject, SIGNAL(signal8()), SLOT(slot8()));
|
||||
// multiObject.connect(&multiObject, SIGNAL(signal0()), SLOT(signal9()));
|
||||
multiObject.connect(&multiObject, SIGNAL(signal9()), SLOT(slot9()));
|
||||
|
||||
if (type == 0) {
|
||||
QBENCHMARK {
|
||||
singleObject.slot0();
|
||||
}
|
||||
} else if (type == 1) {
|
||||
QBENCHMARK {
|
||||
singleObject.emitSignal0();
|
||||
}
|
||||
} else if (type == 2) {
|
||||
QBENCHMARK {
|
||||
multiObject.emitSignal0();
|
||||
}
|
||||
} else if (type == 3) {
|
||||
QBENCHMARK {
|
||||
singleObject.emitSignal1();
|
||||
}
|
||||
} else if (type == 4 || type == 5) {
|
||||
QBENCHMARK {
|
||||
singleObject.emitSignal0();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QObject::signal_many_receivers_data()
|
||||
{
|
||||
QTest::addColumn<int>("receiverCount");
|
||||
QTest::newRow("100 receivers") << 100;
|
||||
QTest::newRow("1 000 receivers") << 1000;
|
||||
QTest::newRow("10 000 receivers") << 10000;
|
||||
}
|
||||
|
||||
void tst_QObject::signal_many_receivers()
|
||||
{
|
||||
QFETCH(int, receiverCount);
|
||||
Object sender;
|
||||
std::vector<Object> receivers(receiverCount);
|
||||
|
||||
for (Object &receiver : receivers)
|
||||
QObject::connect(&sender, &Object::signal0, &receiver, &Object::slot0);
|
||||
|
||||
QBENCHMARK {
|
||||
sender.emitSignal0();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QObject::qproperty_benchmark_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("name");
|
||||
const QMetaObject *mo = &QTreeView::staticMetaObject;
|
||||
for (int i = 0; i < mo->propertyCount(); ++i) {
|
||||
QMetaProperty prop = mo->property(i);
|
||||
if (prop.isWritable())
|
||||
QTest::newRow(prop.name()) << QByteArray(prop.name());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QObject::qproperty_benchmark()
|
||||
{
|
||||
QFETCH(QByteArray, name);
|
||||
const char *p = name.constData();
|
||||
QTreeView obj;
|
||||
QVariant v = obj.property(p);
|
||||
QBENCHMARK {
|
||||
obj.setProperty(p, v);
|
||||
(void)obj.property(p);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QObject::dynamic_property_benchmark()
|
||||
{
|
||||
QTreeView obj;
|
||||
QBENCHMARK {
|
||||
obj.setProperty("myProperty", 123);
|
||||
(void)obj.property("myProperty");
|
||||
obj.setProperty("myOtherProperty", 123);
|
||||
(void)obj.property("myOtherProperty");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QObject::connect_disconnect_benchmark_data()
|
||||
{
|
||||
QTest::addColumn<int>("type");
|
||||
QTest::newRow("normalized signature") << 0;
|
||||
QTest::newRow("unormalized signature") << 1;
|
||||
QTest::newRow("function pointer") << 2;
|
||||
QTest::newRow("normalized signature/handle") << 3;
|
||||
QTest::newRow("unormalized signature/handle") << 4;
|
||||
QTest::newRow("function pointer/handle") << 5;
|
||||
QTest::newRow("functor/handle") << 6;}
|
||||
|
||||
void tst_QObject::connect_disconnect_benchmark()
|
||||
{
|
||||
QFETCH(int, type);
|
||||
switch (type) {
|
||||
case 0: {
|
||||
QTreeView obj;
|
||||
QBENCHMARK {
|
||||
QObject::connect (&obj, SIGNAL(viewportEntered()), &obj, SLOT(expandAll()));
|
||||
QObject::disconnect(&obj, SIGNAL(viewportEntered()), &obj, SLOT(expandAll()));
|
||||
}
|
||||
} break;
|
||||
case 1: {
|
||||
QTreeView obj;
|
||||
QBENCHMARK {
|
||||
QObject::connect (&obj, SIGNAL(viewportEntered( )), &obj, SLOT(expandAll( ))); // sic: non-normalised
|
||||
QObject::disconnect(&obj, SIGNAL(viewportEntered( )), &obj, SLOT(expandAll( ))); // sic: non-normalised
|
||||
}
|
||||
} break;
|
||||
case 2: {
|
||||
QTreeView obj;
|
||||
QBENCHMARK {
|
||||
QObject::connect (&obj, &QAbstractItemView::viewportEntered, &obj, &QTreeView::expandAll);
|
||||
QObject::disconnect(&obj, &QAbstractItemView::viewportEntered, &obj, &QTreeView::expandAll);
|
||||
}
|
||||
} break;
|
||||
case 3: {
|
||||
QTreeView obj;
|
||||
QBENCHMARK {
|
||||
QObject::disconnect(QObject::connect(&obj, SIGNAL(viewportEntered()), &obj, SLOT(expandAll())));
|
||||
}
|
||||
} break;
|
||||
case 4: {
|
||||
QTreeView obj;
|
||||
QBENCHMARK {
|
||||
QObject::disconnect(QObject::connect(&obj, SIGNAL(viewportEntered( )), &obj, SLOT(expandAll( )))); // sic: non-normalised
|
||||
}
|
||||
} break;
|
||||
case 5: {
|
||||
QTreeView obj;
|
||||
QBENCHMARK {
|
||||
QObject::disconnect(QObject::connect(&obj, &QAbstractItemView::viewportEntered, &obj, &QTreeView::expandAll));
|
||||
}
|
||||
} break;
|
||||
case 6: {
|
||||
QTreeView obj;
|
||||
Functor functor;
|
||||
QBENCHMARK {
|
||||
QObject::disconnect(QObject::connect(&obj, &QAbstractItemView::viewportEntered, functor));
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QObject::receiver_destroyed_benchmark()
|
||||
{
|
||||
Object sender;
|
||||
QBENCHMARK {
|
||||
Object receiver;
|
||||
QObject::connect(&sender, &Object::signal0, &receiver, &Object::slot0);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QObject)
|
||||
|
||||
#include "tst_bench_qobject.moc"
|
11
tests/benchmarks/corelib/kernel/qproperty/CMakeLists.txt
Normal file
11
tests/benchmarks/corelib/kernel/qproperty/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qproperty
|
||||
SOURCES
|
||||
tst_bench_qproperty.cpp
|
||||
propertytester.h
|
||||
LIBRARIES
|
||||
Qt::Core
|
||||
Qt::Test
|
||||
)
|
58
tests/benchmarks/corelib/kernel/qproperty/propertytester.h
Normal file
58
tests/benchmarks/corelib/kernel/qproperty/propertytester.h
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef PROPERTYTESTER_H
|
||||
#define PROPERTYTESTER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QProperty>
|
||||
|
||||
class PropertyTester : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
signals:
|
||||
void xOldChanged();
|
||||
void yOldChanged();
|
||||
void xNotifiedChanged();
|
||||
void yNotifiedChanged();
|
||||
|
||||
public:
|
||||
PropertyTester() = default;
|
||||
Q_PROPERTY(int xOld READ xOld WRITE setXOld NOTIFY xOldChanged)
|
||||
Q_PROPERTY(int yOld READ yOld WRITE setYOld NOTIFY yOldChanged)
|
||||
Q_PROPERTY(int x MEMBER x BINDABLE xBindable)
|
||||
Q_PROPERTY(int y MEMBER y BINDABLE yBindable)
|
||||
Q_PROPERTY(int xNotified MEMBER xNotified NOTIFY xNotifiedChanged BINDABLE xNotifiedBindable)
|
||||
Q_PROPERTY(int yNotified MEMBER yNotified NOTIFY yNotifiedChanged BINDABLE yNotifiedBindable)
|
||||
void setXOld(int i) {
|
||||
if (m_xOld != i) {
|
||||
m_xOld = i;
|
||||
emit xOldChanged();
|
||||
}
|
||||
}
|
||||
void setYOld(int i) {
|
||||
if (m_yOld != i) {
|
||||
m_yOld = i;
|
||||
emit yOldChanged();
|
||||
}
|
||||
}
|
||||
int xOld() { return m_xOld; }
|
||||
int yOld() { return m_yOld; }
|
||||
QProperty<int> x;
|
||||
QProperty<int> y;
|
||||
|
||||
QBindable<int> xBindable() { return QBindable<int>(&x); }
|
||||
QBindable<int> yBindable() { return QBindable<int>(&y); }
|
||||
|
||||
Q_OBJECT_BINDABLE_PROPERTY(PropertyTester, int, xNotified, &PropertyTester::xNotifiedChanged)
|
||||
Q_OBJECT_BINDABLE_PROPERTY(PropertyTester, int, yNotified, &PropertyTester::yNotifiedChanged)
|
||||
|
||||
QBindable<int> xNotifiedBindable() { return QBindable<int>(&xNotified); }
|
||||
QBindable<int> yNotifiedBindable() { return QBindable<int>(&yNotified); }
|
||||
|
||||
private:
|
||||
int m_xOld = 0;
|
||||
int m_yOld = 0;
|
||||
};
|
||||
|
||||
#endif // PROPERTYTESTER_H
|
@ -0,0 +1,207 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QScopedPointer>
|
||||
#include <QProperty>
|
||||
|
||||
#include <qtest.h>
|
||||
|
||||
#include "propertytester.h"
|
||||
|
||||
class tst_QProperty : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void cppOldBinding();
|
||||
void cppOldBindingReadOnce();
|
||||
void cppOldBindingDirect();
|
||||
void cppOldBindingDirectReadOnce();
|
||||
|
||||
void cppNewBinding();
|
||||
void cppNewBindingReadOnce();
|
||||
void cppNewBindingDirect();
|
||||
void cppNewBindingDirectReadOnce();
|
||||
|
||||
void cppNotifying();
|
||||
void cppNotifyingReadOnce();
|
||||
void cppNotifyingDirect();
|
||||
void cppNotifyingDirectReadOnce();
|
||||
};
|
||||
|
||||
void tst_QProperty::cppOldBinding()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
auto connection = connect(tester.data(), &PropertyTester::xOldChanged,
|
||||
tester.data(), [&]() { tester->setYOld(tester->xOld()); });
|
||||
|
||||
QCOMPARE(tester->property("yOld").toInt(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->setProperty("xOld", ++i);
|
||||
if (tester->property("yOld").toInt() != i)
|
||||
QFAIL("boo");
|
||||
}
|
||||
|
||||
QObject::disconnect(connection);
|
||||
}
|
||||
|
||||
void tst_QProperty::cppOldBindingDirect()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
auto connection = connect(tester.data(), &PropertyTester::xOldChanged,
|
||||
tester.data(), [&]() { tester->setYOld(tester->xOld()); });
|
||||
|
||||
QCOMPARE(tester->yOld(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->setXOld(++i);
|
||||
if (tester->yOld() != i)
|
||||
QFAIL("boo");
|
||||
}
|
||||
|
||||
QObject::disconnect(connection);
|
||||
}
|
||||
|
||||
void tst_QProperty::cppOldBindingReadOnce()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
auto connection = connect(tester.data(), &PropertyTester::xOldChanged,
|
||||
tester.data(), [&]() { tester->setYOld(tester->xOld()); });
|
||||
|
||||
QCOMPARE(tester->property("yOld").toInt(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->setProperty("xOld", ++i);
|
||||
}
|
||||
|
||||
QCOMPARE(tester->property("yOld").toInt(), i);
|
||||
QObject::disconnect(connection);
|
||||
}
|
||||
|
||||
void tst_QProperty::cppOldBindingDirectReadOnce()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
auto connection = connect(tester.data(), &PropertyTester::xOldChanged,
|
||||
tester.data(), [&]() { tester->setYOld(tester->xOld()); });
|
||||
|
||||
QCOMPARE(tester->yOld(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->setXOld(++i);
|
||||
}
|
||||
|
||||
QCOMPARE(tester->yOld(), i);
|
||||
QObject::disconnect(connection);
|
||||
}
|
||||
|
||||
void tst_QProperty::cppNewBinding()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
tester->y.setBinding([&](){return tester->x.value();});
|
||||
|
||||
QCOMPARE(tester->property("y").toInt(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->setProperty("x", ++i);
|
||||
if (tester->property("y").toInt() != i)
|
||||
QFAIL("boo");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QProperty::cppNewBindingDirect()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
tester->y.setBinding([&](){return tester->x.value();});
|
||||
QCOMPARE(tester->y.value(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->x = ++i;
|
||||
if (tester->y.value() != i)
|
||||
QFAIL("boo");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QProperty::cppNewBindingReadOnce()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
tester->y.setBinding([&](){return tester->x.value();});
|
||||
|
||||
QCOMPARE(tester->property("y").toInt(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->setProperty("x", ++i);
|
||||
}
|
||||
|
||||
QCOMPARE(tester->property("y").toInt(), i);
|
||||
}
|
||||
|
||||
void tst_QProperty::cppNewBindingDirectReadOnce()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
tester->y.setBinding([&](){return tester->x.value();});
|
||||
QCOMPARE(tester->y.value(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->x = ++i;
|
||||
}
|
||||
|
||||
QCOMPARE(tester->y.value(), i);
|
||||
}
|
||||
|
||||
void tst_QProperty::cppNotifying()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
tester->yNotified.setBinding([&](){return tester->xNotified.value();});
|
||||
|
||||
QCOMPARE(tester->property("yNotified").toInt(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->setProperty("xNotified", ++i);
|
||||
if (tester->property("yNotified").toInt() != i)
|
||||
QFAIL("boo");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QProperty::cppNotifyingDirect()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
tester->yNotified.setBinding([&](){return tester->xNotified.value();});
|
||||
QCOMPARE(tester->yNotified.value(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->xNotified.setValue(++i);
|
||||
if (tester->yNotified.value() != i)
|
||||
QFAIL("boo");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QProperty::cppNotifyingReadOnce()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
tester->yNotified.setBinding([&](){return tester->xNotified.value();});
|
||||
|
||||
QCOMPARE(tester->property("yNotified").toInt(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->setProperty("xNotified", ++i);
|
||||
}
|
||||
|
||||
QCOMPARE(tester->property("yNotified").toInt(), i);
|
||||
}
|
||||
|
||||
void tst_QProperty::cppNotifyingDirectReadOnce()
|
||||
{
|
||||
QScopedPointer<PropertyTester> tester {new PropertyTester};
|
||||
tester->yNotified.setBinding([&](){return tester->xNotified.value();});
|
||||
QCOMPARE(tester->yNotified.value(), 0);
|
||||
int i = 0;
|
||||
QBENCHMARK {
|
||||
tester->xNotified.setValue(++i);
|
||||
}
|
||||
|
||||
QCOMPARE(tester->yNotified.value(), i);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QProperty)
|
||||
|
||||
#include "tst_bench_qproperty.moc"
|
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## qtimer_vs_qmetaobject Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(qtimer_vs_qmetaobject
|
||||
SOURCES
|
||||
tst_qtimer_vs_qmetaobject.cpp
|
||||
INCLUDE_DIRECTORIES
|
||||
.
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,115 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtCore>
|
||||
#include <QTest>
|
||||
#include <QThread>
|
||||
#include <QSignalSpy>
|
||||
|
||||
#define INVOKE_COUNT 10000
|
||||
|
||||
class qtimer_vs_qmetaobject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void bench();
|
||||
void bench_data();
|
||||
void benchBackgroundThread();
|
||||
void benchBackgroundThread_data() { bench_data(); }
|
||||
};
|
||||
|
||||
class InvokeCounter : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
InvokeCounter() : count(0) { };
|
||||
public slots:
|
||||
void invokeSlot() {
|
||||
count++;
|
||||
if (count == INVOKE_COUNT)
|
||||
emit allInvoked();
|
||||
}
|
||||
signals:
|
||||
void allInvoked();
|
||||
protected:
|
||||
int count;
|
||||
};
|
||||
|
||||
void qtimer_vs_qmetaobject::bench()
|
||||
{
|
||||
QFETCH(int, type);
|
||||
|
||||
std::function<void(InvokeCounter*)> invoke;
|
||||
if (type == 0) {
|
||||
invoke = [](InvokeCounter* invokeCounter) {
|
||||
QTimer::singleShot(0, invokeCounter, SLOT(invokeSlot()));
|
||||
};
|
||||
} else if (type == 1) {
|
||||
invoke = [](InvokeCounter* invokeCounter) {
|
||||
QTimer::singleShot(0, invokeCounter, &InvokeCounter::invokeSlot);
|
||||
};
|
||||
} else if (type == 2) {
|
||||
invoke = [](InvokeCounter* invokeCounter) {
|
||||
QTimer::singleShot(0, invokeCounter, [invokeCounter]() {
|
||||
invokeCounter->invokeSlot();
|
||||
});
|
||||
};
|
||||
} else if (type == 3) {
|
||||
invoke = [](InvokeCounter* invokeCounter) {
|
||||
QTimer::singleShot(0, [invokeCounter]() {
|
||||
invokeCounter->invokeSlot();
|
||||
});
|
||||
};
|
||||
} else if (type == 4) {
|
||||
invoke = [](InvokeCounter* invokeCounter) {
|
||||
QMetaObject::invokeMethod(invokeCounter, "invokeSlot", Qt::QueuedConnection);
|
||||
};
|
||||
} else if (type == 5) {
|
||||
invoke = [](InvokeCounter* invokeCounter) {
|
||||
QMetaObject::invokeMethod(invokeCounter, &InvokeCounter::invokeSlot, Qt::QueuedConnection);
|
||||
};
|
||||
} else if (type == 6) {
|
||||
invoke = [](InvokeCounter* invokeCounter) {
|
||||
QMetaObject::invokeMethod(invokeCounter, [invokeCounter]() {
|
||||
invokeCounter->invokeSlot();
|
||||
}, Qt::QueuedConnection);
|
||||
};
|
||||
} else {
|
||||
QFAIL("unhandled data tag");
|
||||
}
|
||||
|
||||
QBENCHMARK {
|
||||
InvokeCounter invokeCounter;
|
||||
QSignalSpy spy(&invokeCounter, &InvokeCounter::allInvoked);
|
||||
for(int i = 0; i < INVOKE_COUNT; ++i) {
|
||||
invoke(&invokeCounter);
|
||||
}
|
||||
QVERIFY(spy.wait(10000));
|
||||
}
|
||||
}
|
||||
|
||||
void qtimer_vs_qmetaobject::bench_data()
|
||||
{
|
||||
QTest::addColumn<int>("type");
|
||||
QTest::addRow("singleShot_slot") << 0;
|
||||
QTest::addRow("singleShot_pmf") << 1;
|
||||
QTest::addRow("singleShot_functor") << 2;
|
||||
QTest::addRow("singleShot_functor_noctx") << 3;
|
||||
QTest::addRow("invokeMethod_string") << 4;
|
||||
QTest::addRow("invokeMethod_pmf") << 5;
|
||||
QTest::addRow("invokeMethod_functor") << 6;
|
||||
}
|
||||
|
||||
void qtimer_vs_qmetaobject::benchBackgroundThread()
|
||||
{
|
||||
#if !QT_CONFIG(cxx11_future)
|
||||
QSKIP("This test requires QThread::create");
|
||||
#else
|
||||
QScopedPointer<QThread> thread(QThread::create([this]() { bench(); }));
|
||||
thread->start();
|
||||
QVERIFY(thread->wait());
|
||||
#endif
|
||||
}
|
||||
|
||||
QTEST_MAIN(qtimer_vs_qmetaobject)
|
||||
|
||||
#include "tst_qtimer_vs_qmetaobject.moc"
|
21
tests/benchmarks/corelib/kernel/qvariant/CMakeLists.txt
Normal file
21
tests/benchmarks/corelib/kernel/qvariant/CMakeLists.txt
Normal file
@ -0,0 +1,21 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qvariant Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qvariant
|
||||
SOURCES
|
||||
tst_bench_qvariant.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_extend_target(tst_bench_qvariant CONDITION TARGET Qt::Gui
|
||||
LIBRARIES
|
||||
Qt::Gui
|
||||
)
|
356
tests/benchmarks/corelib/kernel/qvariant/tst_bench_qvariant.cpp
Normal file
356
tests/benchmarks/corelib/kernel/qvariant/tst_bench_qvariant.cpp
Normal file
@ -0,0 +1,356 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtCore>
|
||||
#ifdef QT_GUI_LIB
|
||||
# include <QtGui/QPixmap>
|
||||
#endif
|
||||
#include <qtest.h>
|
||||
|
||||
#define ITERATION_COUNT 1e5
|
||||
|
||||
class tst_QVariant : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ABenchmarkEnum {
|
||||
FirstEnumValue,
|
||||
SecondEnumValue,
|
||||
ThirdEnumValue
|
||||
};
|
||||
Q_ENUM(ABenchmarkEnum)
|
||||
|
||||
private slots:
|
||||
void testBound();
|
||||
|
||||
void doubleVariantCreation();
|
||||
void floatVariantCreation();
|
||||
void rectVariantCreation();
|
||||
void stringVariantCreation();
|
||||
#ifdef QT_GUI_LIB
|
||||
void pixmapVariantCreation();
|
||||
#endif
|
||||
void stringListVariantCreation();
|
||||
void bigClassVariantCreation();
|
||||
void smallClassVariantCreation();
|
||||
void enumVariantCreation();
|
||||
|
||||
void doubleVariantSetValue();
|
||||
void floatVariantSetValue();
|
||||
void rectVariantSetValue();
|
||||
void stringVariantSetValue();
|
||||
void stringListVariantSetValue();
|
||||
void bigClassVariantSetValue();
|
||||
void smallClassVariantSetValue();
|
||||
void enumVariantSetValue();
|
||||
|
||||
void doubleVariantAssignment();
|
||||
void floatVariantAssignment();
|
||||
void rectVariantAssignment();
|
||||
void stringVariantAssignment();
|
||||
void stringListVariantAssignment();
|
||||
|
||||
void doubleVariantValue();
|
||||
void floatVariantValue();
|
||||
void rectVariantValue();
|
||||
void stringVariantValue();
|
||||
|
||||
void createCoreType_data();
|
||||
void createCoreType();
|
||||
void createCoreTypeCopy_data();
|
||||
void createCoreTypeCopy();
|
||||
};
|
||||
|
||||
struct BigClass
|
||||
{
|
||||
double n,i,e,r,o,b;
|
||||
};
|
||||
static_assert(sizeof(BigClass) > sizeof(QVariant::Private::MaxInternalSize));
|
||||
QT_BEGIN_NAMESPACE
|
||||
Q_DECLARE_TYPEINFO(BigClass, Q_RELOCATABLE_TYPE);
|
||||
QT_END_NAMESPACE
|
||||
Q_DECLARE_METATYPE(BigClass);
|
||||
|
||||
struct SmallClass
|
||||
{
|
||||
char s;
|
||||
};
|
||||
static_assert(sizeof(SmallClass) <= sizeof(QVariant::Private::MaxInternalSize));
|
||||
QT_BEGIN_NAMESPACE
|
||||
Q_DECLARE_TYPEINFO(SmallClass, Q_RELOCATABLE_TYPE);
|
||||
QT_END_NAMESPACE
|
||||
Q_DECLARE_METATYPE(SmallClass);
|
||||
|
||||
void tst_QVariant::testBound()
|
||||
{
|
||||
qreal d = qreal(.5);
|
||||
QBENCHMARK {
|
||||
for(int i = 0; i < ITERATION_COUNT; ++i) {
|
||||
d = qBound<qreal>(0, d, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void variantCreation(T val)
|
||||
{
|
||||
QBENCHMARK {
|
||||
for(int i = 0; i < ITERATION_COUNT; ++i) {
|
||||
QVariant v(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void variantCreation<BigClass>(BigClass val)
|
||||
{
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < ITERATION_COUNT; ++i) {
|
||||
QVariant::fromValue(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void variantCreation<SmallClass>(SmallClass val)
|
||||
{
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < ITERATION_COUNT; ++i) {
|
||||
QVariant::fromValue(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void variantCreation<tst_QVariant::ABenchmarkEnum>(tst_QVariant::ABenchmarkEnum val)
|
||||
{
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < ITERATION_COUNT; ++i) {
|
||||
QVariant::fromValue(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void tst_QVariant::doubleVariantCreation()
|
||||
{
|
||||
variantCreation<double>(0.0);
|
||||
}
|
||||
|
||||
void tst_QVariant::floatVariantCreation()
|
||||
{
|
||||
variantCreation<float>(0.0f);
|
||||
}
|
||||
|
||||
void tst_QVariant::rectVariantCreation()
|
||||
{
|
||||
variantCreation<QRect>(QRect(1, 2, 3, 4));
|
||||
}
|
||||
|
||||
void tst_QVariant::stringVariantCreation()
|
||||
{
|
||||
variantCreation<QString>(QString());
|
||||
}
|
||||
|
||||
#ifdef QT_GUI_LIB
|
||||
void tst_QVariant::pixmapVariantCreation()
|
||||
{
|
||||
variantCreation<QPixmap>(QPixmap());
|
||||
}
|
||||
#endif
|
||||
|
||||
void tst_QVariant::stringListVariantCreation()
|
||||
{
|
||||
variantCreation<QStringList>(QStringList());
|
||||
}
|
||||
|
||||
void tst_QVariant::bigClassVariantCreation()
|
||||
{
|
||||
variantCreation<BigClass>(BigClass());
|
||||
}
|
||||
|
||||
void tst_QVariant::smallClassVariantCreation()
|
||||
{
|
||||
variantCreation<SmallClass>(SmallClass());
|
||||
}
|
||||
|
||||
void tst_QVariant::enumVariantCreation()
|
||||
{
|
||||
variantCreation<ABenchmarkEnum>(FirstEnumValue);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static void variantSetValue(T d)
|
||||
{
|
||||
QVariant v;
|
||||
QBENCHMARK {
|
||||
for(int i = 0; i < ITERATION_COUNT; ++i) {
|
||||
v.setValue(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QVariant::doubleVariantSetValue()
|
||||
{
|
||||
variantSetValue<double>(0.0);
|
||||
}
|
||||
|
||||
void tst_QVariant::floatVariantSetValue()
|
||||
{
|
||||
variantSetValue<float>(0.0f);
|
||||
}
|
||||
|
||||
void tst_QVariant::rectVariantSetValue()
|
||||
{
|
||||
variantSetValue<QRect>(QRect());
|
||||
}
|
||||
|
||||
void tst_QVariant::stringVariantSetValue()
|
||||
{
|
||||
variantSetValue<QString>(QString());
|
||||
}
|
||||
|
||||
void tst_QVariant::stringListVariantSetValue()
|
||||
{
|
||||
variantSetValue<QStringList>(QStringList());
|
||||
}
|
||||
|
||||
void tst_QVariant::bigClassVariantSetValue()
|
||||
{
|
||||
variantSetValue<BigClass>(BigClass());
|
||||
}
|
||||
|
||||
void tst_QVariant::smallClassVariantSetValue()
|
||||
{
|
||||
variantSetValue<SmallClass>(SmallClass());
|
||||
}
|
||||
|
||||
void tst_QVariant::enumVariantSetValue()
|
||||
{
|
||||
variantSetValue<ABenchmarkEnum>(FirstEnumValue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void variantAssignment(T d)
|
||||
{
|
||||
QVariant v;
|
||||
QBENCHMARK {
|
||||
for(int i = 0; i < ITERATION_COUNT; ++i) {
|
||||
v = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QVariant::doubleVariantAssignment()
|
||||
{
|
||||
variantAssignment<double>(0.0);
|
||||
}
|
||||
|
||||
void tst_QVariant::floatVariantAssignment()
|
||||
{
|
||||
variantAssignment<float>(0.0f);
|
||||
}
|
||||
|
||||
void tst_QVariant::rectVariantAssignment()
|
||||
{
|
||||
variantAssignment<QRect>(QRect());
|
||||
}
|
||||
|
||||
void tst_QVariant::stringVariantAssignment()
|
||||
{
|
||||
variantAssignment<QString>(QString());
|
||||
}
|
||||
|
||||
void tst_QVariant::stringListVariantAssignment()
|
||||
{
|
||||
variantAssignment<QStringList>(QStringList());
|
||||
}
|
||||
|
||||
void tst_QVariant::doubleVariantValue()
|
||||
{
|
||||
QVariant v(0.0);
|
||||
QBENCHMARK {
|
||||
for(int i = 0; i < ITERATION_COUNT; ++i) {
|
||||
v.toDouble();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QVariant::floatVariantValue()
|
||||
{
|
||||
QVariant v(0.0f);
|
||||
QBENCHMARK {
|
||||
for(int i = 0; i < ITERATION_COUNT; ++i) {
|
||||
v.toFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QVariant::rectVariantValue()
|
||||
{
|
||||
QVariant v(QRect(1,2,3,4));
|
||||
QBENCHMARK {
|
||||
for(int i = 0; i < ITERATION_COUNT; ++i) {
|
||||
v.toRect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QVariant::stringVariantValue()
|
||||
{
|
||||
QVariant v = QString();
|
||||
QBENCHMARK {
|
||||
for(int i = 0; i < ITERATION_COUNT; ++i) {
|
||||
v.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QVariant::createCoreType_data()
|
||||
{
|
||||
QTest::addColumn<int>("typeId");
|
||||
for (int i = QMetaType::FirstCoreType; i <= QMetaType::LastCoreType; ++i) {
|
||||
if (QMetaType metaType(i); metaType.isValid()) // QMetaType(27) does not exist
|
||||
QTest::newRow(metaType.name()) << i;
|
||||
}
|
||||
}
|
||||
|
||||
// Tests how fast a Qt core type can be default-constructed by a
|
||||
// QVariant. The purpose of this benchmark is to measure the overhead
|
||||
// of creating (and destroying) a QVariant compared to creating the
|
||||
// type directly.
|
||||
void tst_QVariant::createCoreType()
|
||||
{
|
||||
QFETCH(int, typeId);
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < ITERATION_COUNT; ++i)
|
||||
QVariant(QMetaType(typeId));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QVariant::createCoreTypeCopy_data()
|
||||
{
|
||||
createCoreType_data();
|
||||
}
|
||||
|
||||
// Tests how fast a Qt core type can be copy-constructed by a
|
||||
// QVariant. The purpose of this benchmark is to measure the overhead
|
||||
// of creating (and destroying) a QVariant compared to creating the
|
||||
// type directly.
|
||||
void tst_QVariant::createCoreTypeCopy()
|
||||
{
|
||||
QFETCH(int, typeId);
|
||||
QMetaType metaType(typeId);
|
||||
QVariant other(metaType);
|
||||
const void *copy = other.constData();
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < ITERATION_COUNT; ++i)
|
||||
QVariant(metaType, copy);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QVariant)
|
||||
|
||||
#include "tst_bench_qvariant.moc"
|
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qwineventnotifier Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qwineventnotifier
|
||||
SOURCES
|
||||
tst_bench_qwineventnotifier.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,111 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qwineventnotifier.h>
|
||||
#include <QtCore/qeventloop.h>
|
||||
#include <QtCore/qvector.h>
|
||||
#include <QtCore/qelapsedtimer.h>
|
||||
#include <QtCore/qt_windows.h>
|
||||
|
||||
class tst_QWinEventNotifier : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void waves_data();
|
||||
void waves();
|
||||
};
|
||||
|
||||
class EventsFactory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EventsFactory(int waves, int notifiers, int iterations)
|
||||
: numberOfWaves(waves), numberOfNotifiers(notifiers),
|
||||
numberOfIterations(iterations)
|
||||
{
|
||||
events.resize(notifiers);
|
||||
for (int i = 0; i < notifiers; ++i) {
|
||||
events[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
QVERIFY(events[i] != NULL);
|
||||
QWinEventNotifier *notifier = new QWinEventNotifier(events[i], this);
|
||||
Q_CHECK_PTR(notifier);
|
||||
|
||||
connect(notifier, &QWinEventNotifier::activated, [i, this]() {
|
||||
ResetEvent(this->events[i]);
|
||||
if (--this->numberOfIterations == 0)
|
||||
this->eventLoop.quit();
|
||||
else
|
||||
SetEvent(this->events[(i + 1) % this->numberOfNotifiers]);
|
||||
});
|
||||
|
||||
connect(this, &EventsFactory::stop, [notifier]() {
|
||||
notifier->setEnabled(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
virtual ~EventsFactory()
|
||||
{
|
||||
for (auto event : events)
|
||||
CloseHandle(event);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
Q_ASSERT(numberOfWaves != 0);
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < numberOfWaves; ++i) {
|
||||
SetEvent(events[offset]);
|
||||
offset += qMax(1, numberOfNotifiers / numberOfWaves);
|
||||
offset %= numberOfNotifiers;
|
||||
}
|
||||
eventLoop.exec();
|
||||
}
|
||||
|
||||
signals:
|
||||
void stop();
|
||||
|
||||
protected:
|
||||
QVector<HANDLE> events;
|
||||
QEventLoop eventLoop;
|
||||
int numberOfWaves;
|
||||
int numberOfNotifiers;
|
||||
int numberOfIterations;
|
||||
};
|
||||
|
||||
void tst_QWinEventNotifier::waves_data()
|
||||
{
|
||||
QTest::addColumn<int>("waves");
|
||||
QTest::addColumn<int>("notifiers");
|
||||
for (int waves : {1, 3, 10}) {
|
||||
for (int notifiers : {10, 100, 1000})
|
||||
QTest::addRow("waves: %d, notifiers: %d", waves, notifiers) << waves << notifiers;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QWinEventNotifier::waves()
|
||||
{
|
||||
QFETCH(int, waves);
|
||||
QFETCH(int, notifiers);
|
||||
|
||||
const int iterations = 100000;
|
||||
|
||||
EventsFactory factory(waves, notifiers, iterations);
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
factory.run();
|
||||
|
||||
qDebug("Elapsed time: %.1f s", timer.elapsed() / 1000.0);
|
||||
|
||||
emit factory.stop();
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QWinEventNotifier)
|
||||
|
||||
#include "tst_bench_qwineventnotifier.moc"
|
4
tests/benchmarks/corelib/mimetypes/CMakeLists.txt
Normal file
4
tests/benchmarks/corelib/mimetypes/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(qmimedatabase)
|
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qmimedatabase Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qmimedatabase
|
||||
SOURCES
|
||||
tst_bench_qmimedatabase.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
BIN
tests/benchmarks/corelib/mimetypes/qmimedatabase/files/N.tar.gz
Normal file
BIN
tests/benchmarks/corelib/mimetypes/qmimedatabase/files/N.tar.gz
Normal file
Binary file not shown.
1
tests/benchmarks/corelib/mimetypes/qmimedatabase/files/X
Normal file
1
tests/benchmarks/corelib/mimetypes/qmimedatabase/files/X
Normal file
@ -0,0 +1 @@
|
||||
#include <math.h>
|
@ -0,0 +1 @@
|
||||
void x();
|
@ -0,0 +1,4 @@
|
||||
foo
|
||||
bar
|
||||
-
|
||||
_
|
1
tests/benchmarks/corelib/mimetypes/qmimedatabase/files/y
Normal file
1
tests/benchmarks/corelib/mimetypes/qmimedatabase/files/y
Normal file
@ -0,0 +1 @@
|
||||
diff --git a/plugins/patchreview/kdevpatchreview.json b/plugins/patchreview/kdevpatchreview.json
|
BIN
tests/benchmarks/corelib/mimetypes/qmimedatabase/files/z
Normal file
BIN
tests/benchmarks/corelib/mimetypes/qmimedatabase/files/z
Normal file
Binary file not shown.
@ -0,0 +1,139 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// Copyright (C) 2021 Igor Kushnir <igorkuo@gmail.com>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QMimeDatabase>
|
||||
|
||||
namespace {
|
||||
struct MatchModeInfo
|
||||
{
|
||||
QMimeDatabase::MatchMode mode;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
constexpr MatchModeInfo matchModes[] = { { QMimeDatabase::MatchDefault, "Default" },
|
||||
{ QMimeDatabase::MatchExtension, "Extension" },
|
||||
{ QMimeDatabase::MatchContent, "Content" } };
|
||||
|
||||
void addFileRows(const char *tag, const QString &fileName, const QStringList &expectedMimeNames)
|
||||
{
|
||||
QCOMPARE(static_cast<std::size_t>(expectedMimeNames.size()), std::size(matchModes));
|
||||
for (int i = 0; i < expectedMimeNames.size(); ++i) {
|
||||
QTest::addRow(qPrintable(tag + QStringLiteral(" - %s")), matchModes[i].name)
|
||||
<< fileName << matchModes[i].mode << expectedMimeNames[i];
|
||||
}
|
||||
}
|
||||
|
||||
void addExistentFileRows(const char *tag, const QString &fileName,
|
||||
const QStringList &expectedMimeNames)
|
||||
{
|
||||
const QString filePath = QFINDTESTDATA("files/" + fileName);
|
||||
QVERIFY2(!filePath.isEmpty(),
|
||||
qPrintable(QStringLiteral("Cannot find test file %1 in files/").arg(fileName)));
|
||||
addFileRows(tag, filePath, expectedMimeNames);
|
||||
}
|
||||
}
|
||||
|
||||
class tst_QMimeDatabase: public QObject
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void inheritsPerformance();
|
||||
void benchMimeTypeForName();
|
||||
void benchMimeTypeForFile_data();
|
||||
void benchMimeTypeForFile();
|
||||
};
|
||||
|
||||
void tst_QMimeDatabase::inheritsPerformance()
|
||||
{
|
||||
// Check performance of inherits().
|
||||
// This benchmark (which started in 2009 in kmimetypetest.cpp) uses 40 mimetypes.
|
||||
QStringList mimeTypes;
|
||||
mimeTypes << QLatin1String("image/jpeg") << QLatin1String("image/png") << QLatin1String("image/tiff") << QLatin1String("text/plain") << QLatin1String("text/html");
|
||||
mimeTypes += mimeTypes;
|
||||
mimeTypes += mimeTypes;
|
||||
mimeTypes += mimeTypes;
|
||||
QCOMPARE(mimeTypes.size(), 40);
|
||||
QMimeDatabase db;
|
||||
QMimeType mime = db.mimeTypeForName(QString::fromLatin1("text/x-chdr"));
|
||||
QVERIFY(mime.isValid());
|
||||
QBENCHMARK {
|
||||
QString match;
|
||||
foreach (const QString &mt, mimeTypes) {
|
||||
if (mime.inherits(mt)) {
|
||||
match = mt;
|
||||
// of course there would normally be a "break" here, but we're testing worse-case
|
||||
// performance here
|
||||
}
|
||||
}
|
||||
QCOMPARE(match, QString::fromLatin1("text/plain"));
|
||||
}
|
||||
// Numbers from 2011, in release mode:
|
||||
// KDE 4.7 numbers: 0.21 msec / 494,000 ticks / 568,345 instr. loads per iteration
|
||||
// QMimeBinaryProvider (with Qt 5): 0.16 msec / NA / 416,049 instr. reads per iteration
|
||||
// QMimeXmlProvider (with Qt 5): 0.062 msec / NA / 172,889 instr. reads per iteration
|
||||
// (but the startup time is way higher)
|
||||
// And memory usage is flat at 200K with QMimeBinaryProvider, while it peaks at 6 MB when
|
||||
// parsing XML, and then keeps being around 4.5 MB for all the in-memory hashes.
|
||||
}
|
||||
|
||||
void tst_QMimeDatabase::benchMimeTypeForName()
|
||||
{
|
||||
QMimeDatabase db;
|
||||
|
||||
QBENCHMARK {
|
||||
const auto s = db.mimeTypeForName(QStringLiteral("text/plain"));
|
||||
QVERIFY(s.isValid());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMimeDatabase::benchMimeTypeForFile_data()
|
||||
{
|
||||
QTest::addColumn<QString>("fileName");
|
||||
QTest::addColumn<QMimeDatabase::MatchMode>("mode");
|
||||
QTest::addColumn<QString>("expectedMimeName");
|
||||
|
||||
addFileRows("archive", "a.tar.gz",
|
||||
{ "application/x-compressed-tar",
|
||||
"application/x-compressed-tar",
|
||||
"application/octet-stream" });
|
||||
addFileRows("OpenDocument Text", "b.odt",
|
||||
{ "application/vnd.oasis.opendocument.text",
|
||||
"application/vnd.oasis.opendocument.text",
|
||||
"application/octet-stream" });
|
||||
|
||||
addExistentFileRows(
|
||||
"existent archive with extension", "N.tar.gz",
|
||||
{ "application/x-compressed-tar", "application/x-compressed-tar", "application/gzip" });
|
||||
addExistentFileRows("existent C with extension", "t.c",
|
||||
{ "text/x-csrc", "text/x-csrc", "text/plain" });
|
||||
addExistentFileRows("existent text file with extension", "u.txt",
|
||||
{ "text/plain", "text/plain", "text/plain" });
|
||||
addExistentFileRows("existent C w/o extension", "X",
|
||||
{ "text/x-csrc", "application/octet-stream", "text/x-csrc" });
|
||||
addExistentFileRows("existent patch w/o extension", "y",
|
||||
{ "text/x-patch", "application/octet-stream", "text/x-patch" });
|
||||
addExistentFileRows("existent archive w/o extension", "z",
|
||||
{ "application/gzip", "application/octet-stream", "application/gzip" });
|
||||
}
|
||||
|
||||
void tst_QMimeDatabase::benchMimeTypeForFile()
|
||||
{
|
||||
QFETCH(const QString, fileName);
|
||||
QFETCH(const QMimeDatabase::MatchMode, mode);
|
||||
QFETCH(const QString, expectedMimeName);
|
||||
|
||||
QMimeDatabase db;
|
||||
|
||||
QBENCHMARK {
|
||||
const auto mimeType = db.mimeTypeForFile(fileName, mode);
|
||||
QCOMPARE(mimeType.name(), expectedMimeName);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QMimeDatabase)
|
||||
|
||||
#include "tst_bench_qmimedatabase.moc"
|
4
tests/benchmarks/corelib/plugin/CMakeLists.txt
Normal file
4
tests/benchmarks/corelib/plugin/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(quuid)
|
13
tests/benchmarks/corelib/plugin/quuid/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/plugin/quuid/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_quuid Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_quuid
|
||||
SOURCES
|
||||
tst_bench_quuid.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
172
tests/benchmarks/corelib/plugin/quuid/tst_bench_quuid.cpp
Normal file
172
tests/benchmarks/corelib/plugin/quuid/tst_bench_quuid.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QTest>
|
||||
|
||||
class tst_QUuid : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void createUuid();
|
||||
void fromChar();
|
||||
void toString();
|
||||
void fromString();
|
||||
void toByteArray();
|
||||
void fromByteArray();
|
||||
void toRfc4122();
|
||||
void fromRfc4122();
|
||||
void createUuidV3();
|
||||
void createUuidV5();
|
||||
void toDataStream();
|
||||
void fromDataStream();
|
||||
void isNull();
|
||||
void operatorLess();
|
||||
void operatorMore();
|
||||
};
|
||||
|
||||
void tst_QUuid::createUuid()
|
||||
{
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = QUuid::createUuid();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::fromChar()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QUuid uuid("{67C8770B-44F1-410A-AB9A-F9B5446F13EE}");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::toString()
|
||||
{
|
||||
QUuid uuid = QUuid::createUuid();
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = uuid.toString();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::fromString()
|
||||
{
|
||||
QString string = "{67C8770B-44F1-410A-AB9A-F9B5446F13EE}";
|
||||
QBENCHMARK {
|
||||
QUuid uuid(string);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::toByteArray()
|
||||
{
|
||||
QUuid uuid = QUuid::createUuid();
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = uuid.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::fromByteArray()
|
||||
{
|
||||
QByteArray string = "{67C8770B-44F1-410A-AB9A-F9B5446F13EE}";
|
||||
QBENCHMARK {
|
||||
QUuid uuid(string);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::toRfc4122()
|
||||
{
|
||||
QUuid uuid = QUuid::createUuid();
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = uuid.toRfc4122();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::fromRfc4122()
|
||||
{
|
||||
QByteArray string = QByteArray::fromHex("67C8770B44F1410AAB9AF9B5446F13EE");
|
||||
QBENCHMARK {
|
||||
QUuid uuid = QUuid::fromRfc4122(string);
|
||||
Q_UNUSED(uuid)
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::createUuidV3()
|
||||
{
|
||||
QUuid ns = QUuid::createUuid();
|
||||
QByteArray name = QByteArray("Test");
|
||||
QBENCHMARK {
|
||||
QUuid uuid = QUuid::createUuidV3(ns, name);
|
||||
Q_UNUSED(uuid)
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::createUuidV5()
|
||||
{
|
||||
QUuid ns = QUuid::createUuid();
|
||||
QByteArray name = QByteArray("Test");
|
||||
QBENCHMARK {
|
||||
QUuid uuid = QUuid::createUuidV5(ns, name);
|
||||
Q_UNUSED(uuid)
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::toDataStream()
|
||||
{
|
||||
QUuid uuid = QUuid::createUuid();
|
||||
QByteArray ar;
|
||||
{
|
||||
QDataStream out(&ar,QIODevice::WriteOnly);
|
||||
QBENCHMARK {
|
||||
out << uuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::fromDataStream()
|
||||
{
|
||||
QUuid uuid1, uuid2;
|
||||
uuid1 = QUuid::createUuid();
|
||||
QByteArray ar;
|
||||
{
|
||||
QDataStream out(&ar,QIODevice::WriteOnly);
|
||||
out << uuid1;
|
||||
}
|
||||
{
|
||||
QDataStream in(&ar,QIODevice::ReadOnly);
|
||||
QBENCHMARK {
|
||||
in >> uuid2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::isNull()
|
||||
{
|
||||
QUuid uuid = QUuid();
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = uuid.isNull();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::operatorLess()
|
||||
{
|
||||
QUuid uuid1, uuid2;
|
||||
uuid1 = QUuid::createUuid();
|
||||
uuid2 = QUuid::createUuid();
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = uuid1 < uuid2;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QUuid::operatorMore()
|
||||
{
|
||||
QUuid uuid1, uuid2;
|
||||
uuid1 = QUuid::createUuid();
|
||||
uuid2 = QUuid::createUuid();
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = uuid1 > uuid2;
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QUuid)
|
||||
|
||||
#include "tst_bench_quuid.moc"
|
12
tests/benchmarks/corelib/text/CMakeLists.txt
Normal file
12
tests/benchmarks/corelib/text/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(qbytearray)
|
||||
add_subdirectory(qchar)
|
||||
add_subdirectory(qlocale)
|
||||
add_subdirectory(qstringbuilder)
|
||||
add_subdirectory(qstringlist)
|
||||
add_subdirectory(qstringtokenizer)
|
||||
add_subdirectory(qregularexpression)
|
||||
add_subdirectory(qstring)
|
||||
add_subdirectory(qutf8stringview)
|
13
tests/benchmarks/corelib/text/qbytearray/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/text/qbytearray/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qbytearray Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qbytearray
|
||||
SOURCES
|
||||
tst_bench_qbytearray.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,358 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// Copyright (C) 2016 Intel Corporation.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QDebug>
|
||||
#include <QIODevice>
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
|
||||
#include <qtest.h>
|
||||
#include <limits>
|
||||
|
||||
class tst_QByteArray : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QByteArray sourcecode;
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void append();
|
||||
void append_data();
|
||||
|
||||
void toLongLong_data();
|
||||
void toLongLong();
|
||||
void toULongLong_data();
|
||||
void toULongLong();
|
||||
|
||||
void latin1Uppercasing_qt54();
|
||||
void latin1Uppercasing_xlate();
|
||||
void latin1Uppercasing_xlate_checked();
|
||||
void latin1Uppercasing_category();
|
||||
void latin1Uppercasing_bitcheck();
|
||||
|
||||
void toPercentEncoding_data();
|
||||
void toPercentEncoding();
|
||||
};
|
||||
|
||||
void tst_QByteArray::initTestCase()
|
||||
{
|
||||
QFile self(QFINDTESTDATA("tst_bench_qbytearray.cpp"));
|
||||
QVERIFY(self.open(QIODevice::ReadOnly));
|
||||
sourcecode = self.readAll();
|
||||
}
|
||||
|
||||
void tst_QByteArray::append_data()
|
||||
{
|
||||
QTest::addColumn<int>("size");
|
||||
QTest::newRow("1") << int(1);
|
||||
QTest::newRow("10") << int(10);
|
||||
QTest::newRow("100") << int(100);
|
||||
QTest::newRow("1000") << int(1000);
|
||||
QTest::newRow("10000") << int(10000);
|
||||
QTest::newRow("100000") << int(100000);
|
||||
QTest::newRow("1000000") << int(1000000);
|
||||
QTest::newRow("10000000") << int(10000000);
|
||||
QTest::newRow("100000000") << int(100000000);
|
||||
}
|
||||
|
||||
void tst_QByteArray::append()
|
||||
{
|
||||
QFETCH(int, size);
|
||||
|
||||
QByteArray ba;
|
||||
QBENCHMARK {
|
||||
QByteArray ba2(size, 'x');
|
||||
ba.append(ba2);
|
||||
ba.clear();
|
||||
}
|
||||
}
|
||||
|
||||
static QByteArray decNext(QByteArray big)
|
||||
{
|
||||
// Increments a decimal digit-string (ignoring sign, so decrements if
|
||||
// negative); only intended for taking a boundary value just out of range,
|
||||
// so big is never a string of only 9s (that'd be one less than a power of
|
||||
// ten, which cannot be a power of two, as odd, or one less than one, as the
|
||||
// power of ten isn't a power of two).
|
||||
int i = big.size() - 1;
|
||||
while (big.at(i) == '9')
|
||||
big[i--] = '0';
|
||||
big[i] += 1;
|
||||
return big;
|
||||
}
|
||||
|
||||
void tst_QByteArray::toLongLong_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("text");
|
||||
QTest::addColumn<bool>("good");
|
||||
QTest::addColumn<qlonglong>("number");
|
||||
#define ROW(n) QTest::newRow(#n) << QByteArray(#n) << true << n ## LL
|
||||
ROW(0);
|
||||
ROW(1);
|
||||
ROW(-1);
|
||||
ROW(17);
|
||||
ROW(-17);
|
||||
ROW(1234567890);
|
||||
ROW(-1234567890);
|
||||
#undef ROW
|
||||
using LL = std::numeric_limits<qlonglong>;
|
||||
QTest::newRow("min") << QByteArray::number(LL::min()) << true << LL::min();
|
||||
QTest::newRow("min-1") << decNext(QByteArray::number(LL::min())) << false << 0LL;
|
||||
QTest::newRow("max") << QByteArray::number(LL::max()) << true << LL::max();
|
||||
QTest::newRow("max+1") << decNext(QByteArray::number(LL::max())) << false << 0LL;
|
||||
}
|
||||
|
||||
void tst_QByteArray::toLongLong()
|
||||
{
|
||||
QFETCH(QByteArray, text);
|
||||
QFETCH(bool, good);
|
||||
QFETCH(qlonglong, number);
|
||||
|
||||
qlonglong actual = 0;
|
||||
bool ok;
|
||||
QBENCHMARK {
|
||||
actual = text.toLongLong(&ok);
|
||||
}
|
||||
QCOMPARE(actual, number);
|
||||
QCOMPARE(ok, good);
|
||||
}
|
||||
|
||||
void tst_QByteArray::toULongLong_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("text");
|
||||
QTest::addColumn<bool>("good");
|
||||
QTest::addColumn<qulonglong>("number");
|
||||
#define ROW(n) \
|
||||
QTest::newRow(#n) << QByteArray(#n) << true << n ## ULL; \
|
||||
QTest::newRow("-" #n) << QByteArray("-" #n) << false << 0ULL
|
||||
ROW(0);
|
||||
ROW(1);
|
||||
ROW(17);
|
||||
ROW(1234567890);
|
||||
#undef ROW
|
||||
using ULL = std::numeric_limits<qulonglong>;
|
||||
QTest::newRow("max") << QByteArray::number(ULL::max()) << true << ULL::max();
|
||||
QTest::newRow("max+1") << decNext(QByteArray::number(ULL::max())) << false << 0ULL;
|
||||
}
|
||||
|
||||
void tst_QByteArray::toULongLong()
|
||||
{
|
||||
QFETCH(QByteArray, text);
|
||||
QFETCH(bool, good);
|
||||
QFETCH(qulonglong, number);
|
||||
|
||||
qulonglong actual = 0;
|
||||
bool ok;
|
||||
QBENCHMARK {
|
||||
actual = text.toULongLong(&ok);
|
||||
}
|
||||
QCOMPARE(actual, number);
|
||||
QCOMPARE(ok, good);
|
||||
}
|
||||
|
||||
void tst_QByteArray::latin1Uppercasing_qt54()
|
||||
{
|
||||
QByteArray s = sourcecode;
|
||||
s.detach();
|
||||
|
||||
// the following was copied from qbytearray.cpp (except for the QBENCHMARK macro):
|
||||
uchar *p_orig = reinterpret_cast<uchar *>(s.data());
|
||||
uchar *e = reinterpret_cast<uchar *>(s.end());
|
||||
|
||||
QBENCHMARK {
|
||||
uchar *p = p_orig;
|
||||
if (p) {
|
||||
while (p != e) {
|
||||
*p = QChar::toLower((ushort)*p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
#!/usr/bin/perl -l
|
||||
use feature "unicode_strings"
|
||||
for (0..255) {
|
||||
$up = uc(chr($_));
|
||||
$up = chr($_) if ord($up) > 0x100 || length $up > 1;
|
||||
printf "0x%02x,", ord($up);
|
||||
print "" if ($_ & 0xf) == 0xf;
|
||||
}
|
||||
*/
|
||||
static const uchar uppercased[256] = {
|
||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
|
||||
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
|
||||
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
|
||||
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
|
||||
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
|
||||
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
|
||||
0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
|
||||
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x7b,0x7c,0x7d,0x7e,0x7f,
|
||||
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
|
||||
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
|
||||
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
|
||||
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
|
||||
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
|
||||
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
|
||||
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
|
||||
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xf7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xff
|
||||
};
|
||||
void tst_QByteArray::latin1Uppercasing_xlate()
|
||||
{
|
||||
QByteArray output = sourcecode;
|
||||
output.detach();
|
||||
char *dst_orig = output.data();
|
||||
const char *src_orig = sourcecode.constBegin();
|
||||
const char *end = sourcecode.constEnd();
|
||||
QBENCHMARK {
|
||||
char *dst = dst_orig;
|
||||
for (const char *src = src_orig; src != end; ++src, ++dst)
|
||||
*dst = uppercased[uchar(*src)];
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QByteArray::latin1Uppercasing_xlate_checked()
|
||||
{
|
||||
QByteArray output = sourcecode;
|
||||
output.detach();
|
||||
char *dst_orig = output.data();
|
||||
const char *src_orig = sourcecode.constBegin();
|
||||
const char *end = sourcecode.constEnd();
|
||||
QBENCHMARK {
|
||||
char *dst = dst_orig;
|
||||
for (const char *src = src_orig; src != end; ++src, ++dst) {
|
||||
uchar ch = uchar(*src);
|
||||
uchar converted = uppercased[ch];
|
||||
if (ch != converted)
|
||||
*dst = converted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#!/bin/perl -l
|
||||
use feature "unicode_strings";
|
||||
sub categorize($) {
|
||||
# 'ß' and 'ÿ' are lowercase, but we cannot uppercase them
|
||||
return 0 if $_[0] == 0xDF || $_[0] == 0xFF;
|
||||
$ch = chr($_[0]);
|
||||
return 2 if uc($ch) ne $ch;
|
||||
return 1 if lc($ch) ne $ch;
|
||||
return 0;
|
||||
}
|
||||
for (0..255) {
|
||||
printf "%d,", categorize($_);
|
||||
print "" if ($_ & 0xf) == 0xf;
|
||||
}
|
||||
*/
|
||||
static const char categories[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
|
||||
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0
|
||||
};
|
||||
|
||||
void tst_QByteArray::latin1Uppercasing_category()
|
||||
{
|
||||
QByteArray output = sourcecode;
|
||||
output.detach();
|
||||
char *dst_orig = output.data();
|
||||
const char *src_orig = sourcecode.constBegin();
|
||||
const char *end = sourcecode.constEnd();
|
||||
QBENCHMARK {
|
||||
char *dst = dst_orig;
|
||||
for (const char *src = src_orig; src != end; ++src, ++dst)
|
||||
*dst = categories[uchar(*src)] == 1 ? *src & ~0x20 : *src;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#!/bin/perl -l
|
||||
use feature "unicode_strings";
|
||||
sub categorize($) {
|
||||
# 'ß' and 'ÿ' are lowercase, but we cannot uppercase them
|
||||
return 0 if $_[0] == 0xDF || $_[0] == 0xFF;
|
||||
$ch = chr($_[0]);
|
||||
return 2 if uc($ch) ne $ch;
|
||||
return 1 if lc($ch) ne $ch;
|
||||
return 0;
|
||||
}
|
||||
for $row (0..7) {
|
||||
$val = 0;
|
||||
for $col (0..31) {
|
||||
$val |= (1<<$col)
|
||||
if categorize($row * 31 + $col) == 2;
|
||||
}
|
||||
printf "0x%08x,", $val;
|
||||
}
|
||||
*/
|
||||
|
||||
static const quint32 shouldUppercase[8] = {
|
||||
0x00000000,0x00000000,0x00000000,0x3ffffff0,0x00000000,0x04000000,0x00000000,0xbfffff80
|
||||
};
|
||||
|
||||
static bool bittest(const quint32 *data, uchar bit)
|
||||
{
|
||||
static const unsigned bitsperelem = sizeof(*data) * CHAR_BIT;
|
||||
return data[bit / bitsperelem] & (1 << (bit & (bitsperelem - 1)));
|
||||
}
|
||||
|
||||
void tst_QByteArray::latin1Uppercasing_bitcheck()
|
||||
{
|
||||
QByteArray output = sourcecode;
|
||||
output.detach();
|
||||
char *dst_orig = output.data();
|
||||
const char *src_orig = sourcecode.constBegin();
|
||||
const char *end = sourcecode.constEnd();
|
||||
QBENCHMARK {
|
||||
char *dst = dst_orig;
|
||||
for (const char *src = src_orig; src != end; ++src, ++dst)
|
||||
*dst = bittest(shouldUppercase, *src) ? uchar(*src) & ~0x20 : uchar(*src);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QByteArray::toPercentEncoding_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("plaintext");
|
||||
QTest::addColumn<QByteArray>("expected");
|
||||
|
||||
QTest::newRow("empty") << QByteArray("") << QByteArray("");
|
||||
QTest::newRow("plain")
|
||||
<< QByteArray("the quick brown fox jumped over the lazy dogs")
|
||||
<< QByteArray("the%20quick%20brown%20fox%20jumped%20over%20the%20lazy%20dogs");
|
||||
QTest::newRow("specials")
|
||||
<< QByteArray(
|
||||
"\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15"
|
||||
"\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,/:;<=>?@[\\]^`{|}\x7f")
|
||||
<< QByteArray(
|
||||
"%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18"
|
||||
"%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2F%3A%3B%3C"
|
||||
"%3D%3E%3F%40%5B%5C%5D%5E%60%7B%7C%7D%7F");
|
||||
}
|
||||
|
||||
void tst_QByteArray::toPercentEncoding()
|
||||
{
|
||||
QFETCH(QByteArray, plaintext);
|
||||
QByteArray encoded;
|
||||
QBENCHMARK {
|
||||
encoded = plaintext.toPercentEncoding();
|
||||
}
|
||||
QTEST(encoded, "expected");
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QByteArray)
|
||||
|
||||
#include "tst_bench_qbytearray.moc"
|
13
tests/benchmarks/corelib/text/qchar/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/text/qchar/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qchar Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qchar
|
||||
SOURCES
|
||||
tst_bench_qchar.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
111
tests/benchmarks/corelib/text/qchar/tst_bench_qchar.cpp
Normal file
111
tests/benchmarks/corelib/text/qchar/tst_bench_qchar.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QTest>
|
||||
#include <QChar>
|
||||
|
||||
class tst_QChar: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void isUpper_data();
|
||||
void isUpper();
|
||||
void isLower_data();
|
||||
void isLower();
|
||||
void isLetter_data();
|
||||
void isLetter();
|
||||
void isDigit_data();
|
||||
void isDigit();
|
||||
void isLetterOrNumber_data();
|
||||
void isLetterOrNumber();
|
||||
void isSpace_data();
|
||||
void isSpace();
|
||||
};
|
||||
|
||||
void tst_QChar::isUpper_data()
|
||||
{
|
||||
QTest::addColumn<QChar>("c");
|
||||
|
||||
QTest::newRow("k") << QChar('k');
|
||||
QTest::newRow("K") << QChar('K');
|
||||
QTest::newRow("5") << QChar('5');
|
||||
QTest::newRow("\\0") << QChar();
|
||||
QTest::newRow("space") << QChar(' ');
|
||||
QTest::newRow("\\u3C20") << QChar(0x3C20);
|
||||
}
|
||||
|
||||
void tst_QChar::isUpper()
|
||||
{
|
||||
QFETCH(QChar, c);
|
||||
QBENCHMARK {
|
||||
c.isUpper();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QChar::isLower_data()
|
||||
{
|
||||
isUpper_data();
|
||||
}
|
||||
|
||||
void tst_QChar::isLower()
|
||||
{
|
||||
QFETCH(QChar, c);
|
||||
QBENCHMARK {
|
||||
c.isLower();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QChar::isLetter_data()
|
||||
{
|
||||
isUpper_data();
|
||||
}
|
||||
|
||||
void tst_QChar::isLetter()
|
||||
{
|
||||
QFETCH(QChar, c);
|
||||
QBENCHMARK {
|
||||
c.isLetter();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QChar::isDigit_data()
|
||||
{
|
||||
isUpper_data();
|
||||
}
|
||||
|
||||
void tst_QChar::isDigit()
|
||||
{
|
||||
QFETCH(QChar, c);
|
||||
QBENCHMARK {
|
||||
c.isDigit();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QChar::isLetterOrNumber_data()
|
||||
{
|
||||
isUpper_data();
|
||||
}
|
||||
|
||||
void tst_QChar::isLetterOrNumber()
|
||||
{
|
||||
QFETCH(QChar, c);
|
||||
QBENCHMARK {
|
||||
c.isLetterOrNumber();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QChar::isSpace_data()
|
||||
{
|
||||
isUpper_data();
|
||||
}
|
||||
|
||||
void tst_QChar::isSpace()
|
||||
{
|
||||
QFETCH(QChar, c);
|
||||
QBENCHMARK {
|
||||
c.isSpace();
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QChar)
|
||||
|
||||
#include "tst_bench_qchar.moc"
|
13
tests/benchmarks/corelib/text/qlocale/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/text/qlocale/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qlocale Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qlocale
|
||||
SOURCES
|
||||
tst_bench_qlocale.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
602
tests/benchmarks/corelib/text/qlocale/tst_bench_qlocale.cpp
Normal file
602
tests/benchmarks/corelib/text/qlocale/tst_bench_qlocale.cpp
Normal file
@ -0,0 +1,602 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QLocale>
|
||||
#include <QTest>
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
class tst_QLocale : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void fromString_data();
|
||||
void fromString();
|
||||
void fromTags_data();
|
||||
void fromTags();
|
||||
void fromLangScript_data();
|
||||
void fromLangScript();
|
||||
void fromLangLand_data();
|
||||
void fromLangLand();
|
||||
void fromScriptLand_data();
|
||||
void fromScriptLand();
|
||||
void fromLang_data();
|
||||
void fromLang();
|
||||
void fromScript_data();
|
||||
void fromScript();
|
||||
void fromLand_data();
|
||||
void fromLand();
|
||||
void toUpper_QLocale_1();
|
||||
void toUpper_QLocale_2();
|
||||
void toUpper_QString();
|
||||
void number_QString();
|
||||
void toLongLong_data();
|
||||
void toLongLong();
|
||||
void toULongLong_data();
|
||||
void toULongLong();
|
||||
void toDouble_data();
|
||||
void toDouble();
|
||||
};
|
||||
|
||||
static QString data()
|
||||
{
|
||||
return QStringLiteral("/qt-5/qtbase/tests/benchmarks/corelib/tools/qlocale");
|
||||
}
|
||||
|
||||
// Make individual cycles O(a few) msecs, rather than tiny fractions thereof:
|
||||
#define LOOP(s) for (int i = 0; i < 5000; ++i) { s; }
|
||||
|
||||
void tst_QLocale::fromString_data()
|
||||
{
|
||||
QTest::addColumn<QString>("name");
|
||||
|
||||
QTest::newRow("C") << QStringLiteral("C");
|
||||
#define ROW(name) QTest::newRow(name) << QStringLiteral(name)
|
||||
ROW("en-Latn-DE");
|
||||
ROW("sd-Deva-IN");
|
||||
ROW("az-Cyrl-AZ");
|
||||
ROW("az-Latn-AZ");
|
||||
ROW("bs-Cyrl-BA");
|
||||
ROW("bs-Latn-BA");
|
||||
ROW("ff-Latn-LR");
|
||||
ROW("ff-Latn-MR");
|
||||
ROW("pa-Arab-PK");
|
||||
ROW("pa-Guru-IN");
|
||||
ROW("shi-Latn-MA");
|
||||
ROW("shi-Tfng-MA");
|
||||
ROW("sr-Cyrl-BA");
|
||||
ROW("sr-Cyrl-RS");
|
||||
ROW("sr-Latn-BA");
|
||||
ROW("sr-Latn-ME");
|
||||
ROW("uz-Arab-AF");
|
||||
ROW("uz-Cyrl-UZ");
|
||||
ROW("uz-Latn-UZ");
|
||||
ROW("vai-Latn-LR");
|
||||
ROW("vai-Vaii-LR");
|
||||
ROW("yue-Hans-CN");
|
||||
ROW("yue-Hant-HK");
|
||||
ROW("zh-Hans-CN");
|
||||
ROW("zh-Hans-HK");
|
||||
ROW("zh-Hans-SG");
|
||||
ROW("zh-Hant-HK");
|
||||
ROW("zh-Hant-TW");
|
||||
#undef ROW
|
||||
}
|
||||
|
||||
void tst_QLocale::fromString()
|
||||
{
|
||||
QFETCH(const QString, name);
|
||||
QBENCHMARK { LOOP(QLocale loc(name)) }
|
||||
}
|
||||
|
||||
void tst_QLocale::fromTags_data()
|
||||
{
|
||||
QTest::addColumn<QLocale::Language>("language");
|
||||
QTest::addColumn<QLocale::Script>("script");
|
||||
QTest::addColumn<QLocale::Territory>("territory");
|
||||
|
||||
#define ROW(name, lang, text, land) \
|
||||
QTest::newRow(name) << QLocale::lang << QLocale::text << QLocale::land
|
||||
ROW("C", C, AnyScript, AnyTerritory);
|
||||
ROW("en-Latn-DE", English, LatinScript, Germany);
|
||||
ROW("sd-Deva-IN", Sindhi, DevanagariScript, India);
|
||||
ROW("az-Cyrl-AZ", Azerbaijani, CyrillicScript, Azerbaijan);
|
||||
ROW("az-Latn-AZ", Azerbaijani, LatinScript, Azerbaijan);
|
||||
ROW("bs-Cyrl-BA", Bosnian, CyrillicScript, BosniaAndHerzegowina);
|
||||
ROW("bs-Latn-BA", Bosnian, LatinScript, BosniaAndHerzegowina);
|
||||
ROW("ff-Latn-LR", Fulah, LatinScript, Liberia);
|
||||
ROW("ff-Latn-MR", Fulah, LatinScript, Mauritania);
|
||||
ROW("pa-Arab-PK", Punjabi, ArabicScript, Pakistan);
|
||||
ROW("pa-Guru-IN", Punjabi, GurmukhiScript, India);
|
||||
ROW("shi-Latn-MA", Tachelhit, LatinScript, Morocco);
|
||||
ROW("shi-Tfng-MA", Tachelhit, TifinaghScript, Morocco);
|
||||
ROW("sr-Cyrl-BA", Serbian, CyrillicScript, BosniaAndHerzegowina);
|
||||
ROW("sr-Cyrl-RS", Serbian, CyrillicScript, Serbia);
|
||||
ROW("sr-Latn-BA", Serbian, LatinScript, BosniaAndHerzegowina);
|
||||
ROW("sr-Latn-ME", Serbian, LatinScript, Montenegro);
|
||||
ROW("uz-Arab-AF", Uzbek, ArabicScript, Afghanistan);
|
||||
ROW("uz-Cyrl-UZ", Uzbek, CyrillicScript, Uzbekistan);
|
||||
ROW("uz-Latn-UZ", Uzbek, LatinScript, Uzbekistan);
|
||||
ROW("vai-Latn-LR", Vai, LatinScript, Liberia);
|
||||
ROW("vai-Vaii-LR", Vai, VaiScript, Liberia);
|
||||
ROW("yue-Hans-CN", Cantonese, SimplifiedHanScript, China);
|
||||
ROW("yue-Hant-HK", Cantonese, TraditionalHanScript, HongKong);
|
||||
ROW("zh-Hans-CN", Chinese, SimplifiedHanScript, China);
|
||||
ROW("zh-Hans-HK", Chinese, SimplifiedHanScript, HongKong);
|
||||
ROW("zh-Hans-SG", Chinese, SimplifiedHanScript, Singapore);
|
||||
ROW("zh-Hant-HK", Chinese, TraditionalHanScript, HongKong);
|
||||
ROW("zh-Hant-TW", Chinese, TraditionalHanScript, Taiwan);
|
||||
#undef ROW
|
||||
}
|
||||
|
||||
void tst_QLocale::fromTags()
|
||||
{
|
||||
QFETCH(const QLocale::Language, language);
|
||||
QFETCH(const QLocale::Script, script);
|
||||
QFETCH(const QLocale::Territory, territory);
|
||||
QBENCHMARK { LOOP(QLocale loc(language, script, territory)) }
|
||||
}
|
||||
|
||||
void tst_QLocale::fromLangScript_data()
|
||||
{
|
||||
QTest::addColumn<QLocale::Language>("language");
|
||||
QTest::addColumn<QLocale::Script>("script");
|
||||
|
||||
#define ROW(name, lang, text) \
|
||||
QTest::newRow(name) << QLocale::lang << QLocale::text
|
||||
ROW("C", C, AnyScript);
|
||||
ROW("en-Latn", English, LatinScript);
|
||||
ROW("sd-Deva", Sindhi, DevanagariScript);
|
||||
ROW("az-Cyrl", Azerbaijani, CyrillicScript);
|
||||
ROW("az-Latn", Azerbaijani, LatinScript);
|
||||
ROW("bs-Cyrl", Bosnian, CyrillicScript);
|
||||
ROW("bs-Latn", Bosnian, LatinScript);
|
||||
ROW("ff-Latn", Fulah, LatinScript);
|
||||
ROW("pa-Arab", Punjabi, ArabicScript);
|
||||
ROW("pa-Guru", Punjabi, GurmukhiScript);
|
||||
ROW("shi-Latn", Tachelhit, LatinScript);
|
||||
ROW("shi-Tfng", Tachelhit, TifinaghScript);
|
||||
ROW("sr-Cyrl", Serbian, CyrillicScript);
|
||||
ROW("sr-Latn", Serbian, LatinScript);
|
||||
ROW("uz-Arab", Uzbek, ArabicScript);
|
||||
ROW("uz-Cyrl", Uzbek, CyrillicScript);
|
||||
ROW("uz-Latn", Uzbek, LatinScript);
|
||||
ROW("vai-Latn", Vai, LatinScript);
|
||||
ROW("vai-Vaii", Vai, VaiScript);
|
||||
ROW("yue-Hans", Cantonese, SimplifiedHanScript);
|
||||
ROW("yue-Hant", Cantonese, TraditionalHanScript);
|
||||
ROW("zh-Hans", Chinese, SimplifiedHanScript);
|
||||
ROW("zh-Hant", Chinese, TraditionalHanScript);
|
||||
#undef ROW
|
||||
}
|
||||
|
||||
void tst_QLocale::fromLangScript()
|
||||
{
|
||||
QFETCH(const QLocale::Language, language);
|
||||
QFETCH(const QLocale::Script, script);
|
||||
QBENCHMARK { LOOP(QLocale loc(language, script, QLocale::AnyTerritory)) }
|
||||
}
|
||||
|
||||
void tst_QLocale::fromLangLand_data()
|
||||
{
|
||||
QTest::addColumn<QLocale::Language>("language");
|
||||
QTest::addColumn<QLocale::Territory>("territory");
|
||||
|
||||
#define ROW(name, lang, land) \
|
||||
QTest::newRow(name) << QLocale::lang << QLocale::land
|
||||
ROW("C", C, AnyTerritory);
|
||||
ROW("en-DE", English, Germany);
|
||||
ROW("sd-IN", Sindhi, India);
|
||||
ROW("az-AZ", Azerbaijani, Azerbaijan);
|
||||
ROW("bs-BA", Bosnian, BosniaAndHerzegowina);
|
||||
ROW("ff-LR", Fulah, Liberia);
|
||||
ROW("ff-MR", Fulah, Mauritania);
|
||||
ROW("pa-PK", Punjabi, Pakistan);
|
||||
ROW("pa-IN", Punjabi, India);
|
||||
ROW("shi-MA", Tachelhit, Morocco);
|
||||
ROW("sr-BA", Serbian, BosniaAndHerzegowina);
|
||||
ROW("sr-RS", Serbian, Serbia);
|
||||
ROW("sr-ME", Serbian, Montenegro);
|
||||
ROW("uz-AF", Uzbek, Afghanistan);
|
||||
ROW("uz-UZ", Uzbek, Uzbekistan);
|
||||
ROW("vai-LR", Vai, Liberia);
|
||||
ROW("yue-CN", Cantonese, China);
|
||||
ROW("yue-HK", Cantonese, HongKong);
|
||||
ROW("zh-CN", Chinese, China);
|
||||
ROW("zh-HK", Chinese, HongKong);
|
||||
ROW("zh-SG", Chinese, Singapore);
|
||||
ROW("zh-TW", Chinese, Taiwan);
|
||||
#undef ROW
|
||||
}
|
||||
|
||||
void tst_QLocale::fromLangLand()
|
||||
{
|
||||
QFETCH(const QLocale::Language, language);
|
||||
QFETCH(const QLocale::Territory, territory);
|
||||
QBENCHMARK { LOOP(QLocale loc(language, territory)) }
|
||||
}
|
||||
|
||||
void tst_QLocale::fromScriptLand_data()
|
||||
{
|
||||
QTest::addColumn<QLocale::Script>("script");
|
||||
QTest::addColumn<QLocale::Territory>("territory");
|
||||
|
||||
#define ROW(name, text, land) \
|
||||
QTest::newRow(name) << QLocale::text << QLocale::land
|
||||
ROW("Any", AnyScript, AnyTerritory);
|
||||
ROW("Latn-DE", LatinScript, Germany);
|
||||
ROW("Deva-IN", DevanagariScript, India);
|
||||
ROW("Cyrl-AZ", CyrillicScript, Azerbaijan);
|
||||
ROW("Latn-AZ", LatinScript, Azerbaijan);
|
||||
ROW("Cyrl-BA", CyrillicScript, BosniaAndHerzegowina);
|
||||
ROW("Latn-BA", LatinScript, BosniaAndHerzegowina);
|
||||
ROW("Latn-LR", LatinScript, Liberia);
|
||||
ROW("Latn-MR", LatinScript, Mauritania);
|
||||
ROW("Arab-PK", ArabicScript, Pakistan);
|
||||
ROW("Guru-IN", GurmukhiScript, India);
|
||||
ROW("Latn-MA", LatinScript, Morocco);
|
||||
ROW("Tfng-MA", TifinaghScript, Morocco);
|
||||
ROW("Cyrl-BA", CyrillicScript, BosniaAndHerzegowina);
|
||||
ROW("Cyrl-RS", CyrillicScript, Serbia);
|
||||
ROW("Latn-BA", LatinScript, BosniaAndHerzegowina);
|
||||
ROW("Latn-ME", LatinScript, Montenegro);
|
||||
ROW("Arab-AF", ArabicScript, Afghanistan);
|
||||
ROW("Cyrl-UZ", CyrillicScript, Uzbekistan);
|
||||
ROW("Latn-UZ", LatinScript, Uzbekistan);
|
||||
ROW("Latn-LR", LatinScript, Liberia);
|
||||
ROW("Vaii-LR", VaiScript, Liberia);
|
||||
ROW("Hans-CN", SimplifiedHanScript, China);
|
||||
ROW("Hant-HK", TraditionalHanScript, HongKong);
|
||||
ROW("Hans-CN", SimplifiedHanScript, China);
|
||||
ROW("Hans-HK", SimplifiedHanScript, HongKong);
|
||||
ROW("Hans-SG", SimplifiedHanScript, Singapore);
|
||||
ROW("Hant-HK", TraditionalHanScript, HongKong);
|
||||
ROW("Hant-TW", TraditionalHanScript, Taiwan);
|
||||
#undef ROW
|
||||
}
|
||||
|
||||
void tst_QLocale::fromScriptLand()
|
||||
{
|
||||
QFETCH(const QLocale::Script, script);
|
||||
QFETCH(const QLocale::Territory, territory);
|
||||
QBENCHMARK { LOOP(QLocale loc(QLocale::AnyLanguage, script, territory)) }
|
||||
}
|
||||
|
||||
void tst_QLocale::fromLang_data()
|
||||
{
|
||||
QTest::addColumn<QLocale::Language>("language");
|
||||
|
||||
#define ROW(name, lang) \
|
||||
QTest::newRow(name) << QLocale::lang
|
||||
ROW("C", C);
|
||||
ROW("en", English);
|
||||
ROW("sd", Sindhi);
|
||||
ROW("az", Azerbaijani);
|
||||
ROW("bs", Bosnian);
|
||||
ROW("ff", Fulah);
|
||||
ROW("pa", Punjabi);
|
||||
ROW("shi", Tachelhit);
|
||||
ROW("sr", Serbian);
|
||||
ROW("uz", Uzbek);
|
||||
ROW("vai", Vai);
|
||||
ROW("yue", Cantonese);
|
||||
ROW("zh", Chinese);
|
||||
#undef ROW
|
||||
}
|
||||
|
||||
void tst_QLocale::fromLang()
|
||||
{
|
||||
QFETCH(const QLocale::Language, language);
|
||||
QBENCHMARK { LOOP(QLocale loc(language)) }
|
||||
}
|
||||
|
||||
void tst_QLocale::fromScript_data()
|
||||
{
|
||||
QTest::addColumn<QLocale::Script>("script");
|
||||
|
||||
#define ROW(name, text) \
|
||||
QTest::newRow(name) << QLocale::text
|
||||
ROW("Any", AnyScript);
|
||||
ROW("Latn", LatinScript);
|
||||
ROW("Deva", DevanagariScript);
|
||||
ROW("Cyrl", CyrillicScript);
|
||||
ROW("Arab", ArabicScript);
|
||||
ROW("Guru", GurmukhiScript);
|
||||
ROW("Tfng", TifinaghScript);
|
||||
ROW("Vaii", VaiScript);
|
||||
ROW("Hans", SimplifiedHanScript);
|
||||
ROW("Hant", TraditionalHanScript);
|
||||
#undef ROW
|
||||
}
|
||||
|
||||
void tst_QLocale::fromScript()
|
||||
{
|
||||
QFETCH(const QLocale::Script, script);
|
||||
QBENCHMARK { LOOP(QLocale loc(QLocale::AnyLanguage, script, QLocale::AnyTerritory)) }
|
||||
}
|
||||
|
||||
void tst_QLocale::fromLand_data()
|
||||
{
|
||||
QTest::addColumn<QLocale::Territory>("territory");
|
||||
|
||||
#define ROW(name, land) \
|
||||
QTest::newRow(name) << QLocale::land
|
||||
ROW("Any", AnyTerritory);
|
||||
ROW("DE", Germany);
|
||||
ROW("IN", India);
|
||||
ROW("AZ", Azerbaijan);
|
||||
ROW("BA", BosniaAndHerzegowina);
|
||||
ROW("LR", Liberia);
|
||||
ROW("MR", Mauritania);
|
||||
ROW("PK", Pakistan);
|
||||
ROW("MA", Morocco);
|
||||
ROW("RS", Serbia);
|
||||
ROW("ME", Montenegro);
|
||||
ROW("AF", Afghanistan);
|
||||
ROW("UZ", Uzbekistan);
|
||||
ROW("CN", China);
|
||||
ROW("HK", HongKong);
|
||||
ROW("SG", Singapore);
|
||||
ROW("TW", Taiwan);
|
||||
#undef ROW
|
||||
}
|
||||
|
||||
void tst_QLocale::fromLand()
|
||||
{
|
||||
QFETCH(const QLocale::Territory, territory);
|
||||
QBENCHMARK { LOOP(QLocale loc(QLocale::AnyLanguage, territory)) }
|
||||
}
|
||||
|
||||
void tst_QLocale::toUpper_QLocale_1()
|
||||
{
|
||||
QString s = data();
|
||||
QBENCHMARK { LOOP(QString t(QLocale().toUpper(s))) }
|
||||
}
|
||||
|
||||
void tst_QLocale::toUpper_QLocale_2()
|
||||
{
|
||||
QString s = data();
|
||||
QLocale l;
|
||||
QBENCHMARK { LOOP(QString t(l.toUpper(s))) }
|
||||
}
|
||||
|
||||
void tst_QLocale::toUpper_QString()
|
||||
{
|
||||
QString s = data();
|
||||
QBENCHMARK { LOOP(QString t(s.toUpper())) }
|
||||
}
|
||||
|
||||
void tst_QLocale::number_QString()
|
||||
{
|
||||
QString s;
|
||||
QBENCHMARK {
|
||||
s = QString::number(12345678);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
void toWholeCommon_data()
|
||||
{
|
||||
QTest::addColumn<QString>("text");
|
||||
QTest::addColumn<QString>("locale");
|
||||
QTest::addColumn<bool>("good");
|
||||
QTest::addColumn<Integer>("expected");
|
||||
|
||||
QTest::newRow("C: empty") << u""_s << u"C"_s << false << Integer(0ull);
|
||||
QTest::newRow("C: 0") << u"0"_s << u"C"_s << true << Integer(0ull);
|
||||
QTest::newRow("C: 1234") << u"1234"_s << u"C"_s << true << Integer(1234ull);
|
||||
// C locale omits grouping, but doesn't reject it.
|
||||
QTest::newRow("C: 1,234") << u"1,234"_s << u"C"_s << true << Integer(1234ull);
|
||||
QTest::newRow("C: 123456789")
|
||||
<< u"123456789"_s << u"C"_s << true << Integer(123456789ull);
|
||||
QTest::newRow("C: 123,456,789")
|
||||
<< u"123,456,789"_s << u"C"_s << true << Integer(123456789ull);
|
||||
|
||||
QTest::newRow("en: empty") << u""_s << u"en"_s << false << Integer(0ull);
|
||||
QTest::newRow("en: 0") << u"0"_s << u"en"_s << true << Integer(0ull);
|
||||
QTest::newRow("en: 1234") << u"1234"_s << u"en"_s << true << Integer(1234ull);
|
||||
QTest::newRow("en: 1,234") << u"1,234"_s << u"en"_s << true << Integer(1234ull);
|
||||
QTest::newRow("en: 123,456,789")
|
||||
<< u"123,456,789"_s << u"en"_s << true << Integer(123456789ull);
|
||||
QTest::newRow("en: 123456789")
|
||||
<< u"123456789"_s << u"en"_s << true << Integer(123456789ull);
|
||||
|
||||
QTest::newRow("de: empty") << u""_s << u"de"_s << false << Integer(0ull);
|
||||
QTest::newRow("de: 0") << u"0"_s << u"de"_s << true << Integer(0ull);
|
||||
QTest::newRow("de: 1234") << u"1234"_s << u"de"_s << true << Integer(1234ull);
|
||||
QTest::newRow("de: 1.234") << u"1.234"_s << u"de"_s << true << Integer(1234ull);
|
||||
QTest::newRow("de: 123.456.789")
|
||||
<< u"123.456.789"_s << u"de"_s << true << Integer(123456789ull);
|
||||
QTest::newRow("de: 123456789")
|
||||
<< u"123456789"_s << u"de"_s << true << Integer(123456789ull);
|
||||
|
||||
// Locales with non-single-character signs:
|
||||
QTest::newRow("ar_EG: +403") // Arabic, Egypt
|
||||
<< u"\u061c+\u0664\u0660\u0663"_s << u"ar_EG"_s << true << Integer(403ull);
|
||||
QTest::newRow("ar_EG: !403") // Only first character of the sign
|
||||
<< u"\u061c\u0664\u0660\u0663"_s << u"ar_EG"_s << false << Integer(0ull);
|
||||
QTest::newRow("fa_IR: +403") // Farsi, Iran
|
||||
<< u"\u200e+\u06f4\u06f0\u06f3"_s << u"fa_IR"_s << true << Integer(403ull);
|
||||
QTest::newRow("fa_IR: !403") // Only first character of sign
|
||||
<< u"\u200e\u06f4\u06f0\u06f3"_s << u"fa_IR"_s << false << Integer(0ull);
|
||||
}
|
||||
|
||||
void tst_QLocale::toLongLong_data()
|
||||
{
|
||||
toWholeCommon_data<qlonglong>();
|
||||
|
||||
QTest::newRow("C: -1234") << u"-1234"_s << u"C"_s << true << -1234ll;
|
||||
QTest::newRow("C: -123456789") << u"-123456789"_s << u"C"_s << true << -123456789ll;
|
||||
QTest::newRow("C: qlonglong-max")
|
||||
<< u"9223372036854775807"_s << u"C"_s << true
|
||||
<< std::numeric_limits<qlonglong>::max();
|
||||
QTest::newRow("C: qlonglong-min")
|
||||
<< u"-9223372036854775808"_s << u"C"_s << true
|
||||
<< std::numeric_limits<qlonglong>::min();
|
||||
|
||||
// Locales with multi-character signs:
|
||||
QTest::newRow("ar_EG: -403") // Arabic, Egypt
|
||||
<< u"\u061c-\u0664\u0660\u0663"_s << u"ar_EG"_s << true << -403ll;
|
||||
QTest::newRow("fa_IR: -403") // Farsi, Iran
|
||||
<< u"\u200e\u2212\u06f4\u06f0\u06f3"_s << u"fa_IR"_s << true << -403ll;
|
||||
}
|
||||
|
||||
void tst_QLocale::toLongLong()
|
||||
{
|
||||
QFETCH(QString, text);
|
||||
QFETCH(QString, locale);
|
||||
QFETCH(bool, good);
|
||||
QFETCH(qlonglong, expected);
|
||||
|
||||
const QLocale loc(locale);
|
||||
qlonglong actual = expected;
|
||||
bool ok = false;
|
||||
QBENCHMARK {
|
||||
actual = loc.toLongLong(text, &ok);
|
||||
}
|
||||
QEXPECT_FAIL("ar_EG: +403", "Code wrongly assumes single character, QTBUG-107801", Abort);
|
||||
QEXPECT_FAIL("ar_EG: -403", "Code wrongly assumes single character, QTBUG-107801", Abort);
|
||||
QEXPECT_FAIL("fa_IR: +403", "Code wrongly assumes single character, QTBUG-107801", Abort);
|
||||
QEXPECT_FAIL("fa_IR: -403", "Code wrongly assumes single character, QTBUG-107801", Abort);
|
||||
QCOMPARE(ok, good);
|
||||
QCOMPARE(actual, expected);
|
||||
}
|
||||
|
||||
void tst_QLocale::toULongLong_data()
|
||||
{
|
||||
toWholeCommon_data<qulonglong>();
|
||||
|
||||
QTest::newRow("C: qlonglong-max + 1")
|
||||
<< u"9223372036854775808"_s << u"C"_s << true
|
||||
<< (qulonglong(std::numeric_limits<qlonglong>::max()) + 1);
|
||||
QTest::newRow("C: qulonglong-max")
|
||||
<< u"18446744073709551615"_s << u"C"_s << true
|
||||
<< std::numeric_limits<qulonglong>::max();
|
||||
}
|
||||
|
||||
void tst_QLocale::toULongLong()
|
||||
{
|
||||
QFETCH(QString, text);
|
||||
QFETCH(QString, locale);
|
||||
QFETCH(bool, good);
|
||||
QFETCH(qulonglong, expected);
|
||||
|
||||
const QLocale loc(locale);
|
||||
qulonglong actual = expected;
|
||||
bool ok = false;
|
||||
QBENCHMARK {
|
||||
actual = loc.toULongLong(text, &ok);
|
||||
}
|
||||
QEXPECT_FAIL("ar_EG: +403", "Code wrongly assumes single character, QTBUG-107801", Abort);
|
||||
QEXPECT_FAIL("fa_IR: +403", "Code wrongly assumes single character, QTBUG-107801", Abort);
|
||||
QCOMPARE(ok, good);
|
||||
QCOMPARE(actual, expected);
|
||||
}
|
||||
|
||||
|
||||
void tst_QLocale::toDouble_data()
|
||||
{
|
||||
QTest::addColumn<QString>("text");
|
||||
QTest::addColumn<QString>("locale");
|
||||
QTest::addColumn<bool>("good");
|
||||
QTest::addColumn<double>("expected");
|
||||
|
||||
QTest::newRow("C: empty") << u""_s << u"C"_s << false << 0.0;
|
||||
QTest::newRow("C: 0") << u"0"_s << u"C"_s << true << 0.0;
|
||||
QTest::newRow("C: 0.12340") << u"0.12340"_s << u"C"_s << true << 0.12340;
|
||||
QTest::newRow("C: -0.12340") << u"-0.12340"_s << u"C"_s << true << -0.12340;
|
||||
QTest::newRow("C: −0.12340") << u"\u2212" "0.12340"_s << u"C"_s << true << -0.12340;
|
||||
QTest::newRow("C: 1.0e-4") << u"1.0e-4"_s << u"C"_s << true << 1.0e-4;
|
||||
QTest::newRow("C: 1.0e−4") << u"1.0e\u2212" "4"_s << u"C"_s << true << 1.0e-4;
|
||||
QTest::newRow("C: 1.0e+4") << u"1.0e+4"_s << u"C"_s << true << 1.0e+4;
|
||||
QTest::newRow("C: 10.e+3") << u"10.e+3"_s << u"C"_s << true << 1.0e+4;
|
||||
QTest::newRow("C: 10e+3.") << u"10e+3."_s << u"C"_s << false << 0.0; // exp...dot
|
||||
QTest::newRow("C: 1e4") << u"1e4"_s << u"C"_s << true << 1.0e+4;
|
||||
|
||||
// NaN and infinity:
|
||||
QTest::newRow("C: nan") << u"nan"_s << u"C"_s << true << qQNaN();
|
||||
QTest::newRow("C: NaN") << u"NaN"_s << u"C"_s << true << qQNaN();
|
||||
QTest::newRow("C: -nan") << u"-nan"_s << u"C"_s << false << 0.0;
|
||||
QTest::newRow("C: +nan") << u"+nan"_s << u"C"_s << false << 0.0;
|
||||
QTest::newRow("C: inf") << u"inf"_s << u"C"_s << true << qInf();
|
||||
QTest::newRow("C: Inf") << u"Inf"_s << u"C"_s << true << qInf();
|
||||
QTest::newRow("C: +inf") << u"+inf"_s << u"C"_s << true << qInf();
|
||||
QTest::newRow("C: -inf") << u"-inf"_s << u"C"_s << true << -qInf();
|
||||
|
||||
// Wantonly long-form representations, with trailing and leading zeros:
|
||||
QTest::newRow("C: 1e-64 long-form")
|
||||
<< (u"0."_s + QString(63, u'0') + u'1' + QString(962, u'0')) << u"C"_s << true << 1e-64;
|
||||
QTest::newRow("C: 1e+64 long-form")
|
||||
<< (QString(961, u'0') + u'1' + QString(64, u'0') + u".0"_s) << u"C"_s << true << 1e+64;
|
||||
QTest::newRow("C: long-form 1 via e+64")
|
||||
<< (u"0."_s + QString(63, u'0') + u'1' + QString(962, u'0') + u"e+64"_s)
|
||||
<< u"C"_s << true << 1.0;
|
||||
QTest::newRow("C: long-form 1 via e-64")
|
||||
<< (QString(961, u'0') + u'1' + QString(64, u'0') + u".0e-64"_s)
|
||||
<< u"C"_s << true << 1.0;
|
||||
QTest::newRow("C: 12345678.9") << u"12345678.9"_s << u"C"_s << true << 12345678.9;
|
||||
|
||||
// With and without grouping, en vs de for flipped separators:
|
||||
QTest::newRow("en: 12345678.9") << u"12345678.9"_s << u"en"_s << true << 12345678.9;
|
||||
QTest::newRow("en: 12,345,678.9") << u"12,345,678.9"_s << u"en"_s << true << 12'345'678.9;
|
||||
QTest::newRow("de: 12345678,9") << u"12345678,9"_s << u"de"_s << true << 12345678.9;
|
||||
QTest::newRow("de: 12.345.678,9") << u"12.345.678,9"_s << u"de"_s << true << 12'345'678.9;
|
||||
|
||||
// NaN and infinity are locale-independent (for now - QTBUG-95460)
|
||||
QTest::newRow("cy: nan") << u"nan"_s << u"cy"_s << true << qQNaN();
|
||||
QTest::newRow("cy: NaN") << u"NaN"_s << u"cy"_s << true << qQNaN();
|
||||
QTest::newRow("cy: -nan") << u"-nan"_s << u"cy"_s << false << 0.0;
|
||||
QTest::newRow("cy: +nan") << u"+nan"_s << u"cy"_s << false << 0.0;
|
||||
QTest::newRow("cy: inf") << u"inf"_s << u"cy"_s << true << qInf();
|
||||
QTest::newRow("cy: Inf") << u"Inf"_s << u"cy"_s << true << qInf();
|
||||
QTest::newRow("cy: +inf") << u"+inf"_s << u"cy"_s << true << qInf();
|
||||
QTest::newRow("cy: -inf") << u"-inf"_s << u"cy"_s << true << -qInf();
|
||||
// Samples ready for QTBUG-95460:
|
||||
QTest::newRow("en: ∞") << u"\u221e"_s << u"en"_s << true << qInf();
|
||||
QTest::newRow("ga: Nuimh") << u"Nuimh"_s << u"ga"_s << true << qQNaN();
|
||||
|
||||
// Locales with multi-character exponents:
|
||||
QTest::newRow("sv_SE: 4e-3") // Swedish, Sweden
|
||||
<< u"4\u00d7" "10^\u2212" "03"_s << u"sv_SE"_s << true << 4e-3;
|
||||
QTest::newRow("sv_SE: 4x-3") // Only first character of exponent
|
||||
<< u"4\u00d7\u2212" "03"_s << u"sv_SE"_s << false << 0.0;
|
||||
QTest::newRow("se_NO: 4e-3") // Northern Sami, Norway
|
||||
<< u"4\u00b7" "10^\u2212" "03"_s << u"se_NO"_s << true << 4e-3;
|
||||
QTest::newRow("se_NO: 4x-3") // Only first character of exponent
|
||||
<< u"4\u00b7\u2212" "03"_s << u"se_NO"_s << false << 0.0;
|
||||
QTest::newRow("ar_EG: 4e-3") // Arabic, Egypt
|
||||
<< u"\u0664\u0627\u0633\u061c-\u0660\u0663"_s << u"ar_EG"_s << true << 4e-3;
|
||||
QTest::newRow("ar_EG: 4x-3") // Only first character of exponent
|
||||
<< u"\u0664\u0627\u061c-\u0660\u0663"_s << u"ar_EG"_s << false << 0.0;
|
||||
QTest::newRow("ar_EG: 4e!3") // Only first character of sign
|
||||
<< u"\u0664\u0627\u0633\u061c\u0660\u0663"_s << u"ar_EG"_s << false << 0.0;
|
||||
QTest::newRow("ar_EG: 4x!3") // Only first character of sign and exponent
|
||||
<< u"\u0664\u0627\u061c\u0660\u0663"_s << u"ar_EG"_s << false << 0.0;
|
||||
}
|
||||
|
||||
void tst_QLocale::toDouble()
|
||||
{
|
||||
QFETCH(QString, text);
|
||||
QFETCH(QString, locale);
|
||||
QFETCH(bool, good);
|
||||
QFETCH(double, expected);
|
||||
|
||||
const QLocale loc(locale);
|
||||
double actual = expected;
|
||||
bool ok = false;
|
||||
QBENCHMARK {
|
||||
actual = loc.toDouble(text, &ok);
|
||||
}
|
||||
QEXPECT_FAIL("sv_SE: 4e-3", "Code wrongly assumes single character, QTBUG-107801", Abort);
|
||||
QEXPECT_FAIL("se_NO: 4e-3", "Code wrongly assumes single character, QTBUG-107801", Abort);
|
||||
QEXPECT_FAIL("ar_EG: 4e-3", "Code wrongly assumes single character, QTBUG-107801", Abort);
|
||||
QEXPECT_FAIL("en: ∞", "Localized infinity support missing: QTBUG-95460", Abort);
|
||||
QEXPECT_FAIL("ga: Nuimh", "Localized NaN support missing: QTBUG-95460", Abort);
|
||||
QCOMPARE(ok, good);
|
||||
QCOMPARE(actual, expected);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QLocale)
|
||||
|
||||
#include "tst_bench_qlocale.moc"
|
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qregularexpression Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qregularexpression
|
||||
SOURCES
|
||||
tst_bench_qregularexpression.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,275 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QTest>
|
||||
|
||||
/*!
|
||||
\internal
|
||||
The main idea of the benchmark is to compare performance of QRE classes
|
||||
before and after any changes in the implementation.
|
||||
It does not try to compare performance between different patterns or
|
||||
matching options.
|
||||
*/
|
||||
|
||||
static const QString textToMatch { "The quick brown fox jumped over the lazy dogs" };
|
||||
static const QString nonEmptyPattern { "(?<article>\\w+) (?<noun>\\w+)" };
|
||||
static const QRegularExpression::PatternOptions nonEmptyPatternOptions {
|
||||
QRegularExpression::CaseInsensitiveOption | QRegularExpression::DotMatchesEverythingOption
|
||||
};
|
||||
|
||||
class tst_QRegularExpressionBenchmark : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void createDefault();
|
||||
void createAndMoveDefault();
|
||||
|
||||
void createCustom();
|
||||
void createAndMoveCustom();
|
||||
|
||||
void matchDefault();
|
||||
void matchDefaultOptimized();
|
||||
|
||||
void matchCustom();
|
||||
void matchCustomOptimized();
|
||||
|
||||
void globalMatchDefault();
|
||||
void globalMatchDefaultOptimized();
|
||||
|
||||
void globalMatchCustom();
|
||||
void globalMatchCustomOptimized();
|
||||
|
||||
void queryMatchResults();
|
||||
void queryMatchResultsByGroupIndex();
|
||||
void queryMatchResultsByGroupName();
|
||||
void iterateThroughGlobalMatchResults();
|
||||
};
|
||||
|
||||
void tst_QRegularExpressionBenchmark::createDefault()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QRegularExpression re;
|
||||
Q_UNUSED(re);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QRegularExpressionBenchmark::createAndMoveDefault()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QRegularExpression re;
|
||||
// We can compare to results of previous test to roughly
|
||||
// estimate the cost for the move() call.
|
||||
QRegularExpression re2(std::move(re));
|
||||
Q_UNUSED(re2);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QRegularExpressionBenchmark::createCustom()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QRegularExpression re(nonEmptyPattern, nonEmptyPatternOptions);
|
||||
Q_UNUSED(re);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QRegularExpressionBenchmark::createAndMoveCustom()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QRegularExpression re(nonEmptyPattern, nonEmptyPatternOptions);
|
||||
// We can compare to results of previous test to roughly
|
||||
// estimate the cost for the move() call.
|
||||
QRegularExpression re2(std::move(re));
|
||||
Q_UNUSED(re2);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal This benchmark measures the performance of the match() together
|
||||
with pattern compilation for a default-constructed object.
|
||||
We need to create the object every time, so that the compiled pattern
|
||||
does not get cached.
|
||||
*/
|
||||
void tst_QRegularExpressionBenchmark::matchDefault()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QRegularExpression re;
|
||||
auto matchResult = re.match(textToMatch);
|
||||
Q_UNUSED(matchResult);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal This benchmark measures the performance of the match() without
|
||||
pattern compilation for a default-constructed object.
|
||||
The pattern is precompiled before the actual benchmark starts.
|
||||
|
||||
\note In case we make the default constructor non-allocating, the results
|
||||
of the benchmark will be very close to the unoptimized one, as it will have
|
||||
to compile the pattern inside the call to match().
|
||||
*/
|
||||
void tst_QRegularExpressionBenchmark::matchDefaultOptimized()
|
||||
{
|
||||
QRegularExpression re;
|
||||
re.optimize();
|
||||
QBENCHMARK {
|
||||
auto matchResult = re.match(textToMatch);
|
||||
Q_UNUSED(matchResult);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal This benchmark measures the performance of the match() together
|
||||
with pattern compilation for an object with custom pattern and pattern
|
||||
options.
|
||||
We need to create the object every time, so that the compiled pattern
|
||||
does not get cached.
|
||||
*/
|
||||
void tst_QRegularExpressionBenchmark::matchCustom()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QRegularExpression re(nonEmptyPattern, nonEmptyPatternOptions);
|
||||
auto matchResult = re.match(textToMatch);
|
||||
Q_UNUSED(matchResult);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal This benchmark measures the performance of the match() without
|
||||
pattern compilation for an object with custom pattern and pattern
|
||||
options.
|
||||
The pattern is precompiled before the actual benchmark starts.
|
||||
*/
|
||||
void tst_QRegularExpressionBenchmark::matchCustomOptimized()
|
||||
{
|
||||
QRegularExpression re(nonEmptyPattern, nonEmptyPatternOptions);
|
||||
re.optimize();
|
||||
QBENCHMARK {
|
||||
auto matchResult = re.match(textToMatch);
|
||||
Q_UNUSED(matchResult);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal This benchmark measures the performance of the globalMatch()
|
||||
together with the pattern compilation for a default-constructed object.
|
||||
We need to create the object every time, so that the compiled pattern
|
||||
does not get cached.
|
||||
*/
|
||||
void tst_QRegularExpressionBenchmark::globalMatchDefault()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QRegularExpression re;
|
||||
auto matchResultIterator = re.globalMatch(textToMatch);
|
||||
Q_UNUSED(matchResultIterator);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal This benchmark measures the performance of the globalMatch()
|
||||
without the pattern compilation for a default-constructed object.
|
||||
The pattern is precompiled before the actual benchmark starts.
|
||||
|
||||
\note In case we make the default constructor non-allocating, the results
|
||||
of the benchmark will be very close to the unoptimized one, as it will have
|
||||
to compile the pattern inside the call to globalMatch().
|
||||
*/
|
||||
void tst_QRegularExpressionBenchmark::globalMatchDefaultOptimized()
|
||||
{
|
||||
QRegularExpression re;
|
||||
re.optimize();
|
||||
QBENCHMARK {
|
||||
auto matchResultIterator = re.globalMatch(textToMatch);
|
||||
Q_UNUSED(matchResultIterator);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal This benchmark measures the performance of the globalMatch()
|
||||
together with the pattern compilation for an object with custom pattern
|
||||
and pattern options.
|
||||
We need to create the object every time, so that the compiled pattern
|
||||
does not get cached.
|
||||
*/
|
||||
void tst_QRegularExpressionBenchmark::globalMatchCustom()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QRegularExpression re(nonEmptyPattern, nonEmptyPatternOptions);
|
||||
auto matchResultIterator = re.globalMatch(textToMatch);
|
||||
Q_UNUSED(matchResultIterator);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal This benchmark measures the performance of the globalMatch()
|
||||
without the pattern compilation for an object with custom pattern and
|
||||
pattern options.
|
||||
The pattern is precompiled before the actual benchmark starts.
|
||||
*/
|
||||
void tst_QRegularExpressionBenchmark::globalMatchCustomOptimized()
|
||||
{
|
||||
QRegularExpression re(nonEmptyPattern, nonEmptyPatternOptions);
|
||||
re.optimize();
|
||||
QBENCHMARK {
|
||||
auto matchResultIterator = re.globalMatch(textToMatch);
|
||||
Q_UNUSED(matchResultIterator);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QRegularExpressionBenchmark::queryMatchResults()
|
||||
{
|
||||
QRegularExpression re(nonEmptyPattern, nonEmptyPatternOptions);
|
||||
auto matchResult = re.match(textToMatch);
|
||||
QBENCHMARK {
|
||||
auto texts = matchResult.capturedTexts();
|
||||
Q_UNUSED(texts);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QRegularExpressionBenchmark::queryMatchResultsByGroupIndex()
|
||||
{
|
||||
QRegularExpression re(nonEmptyPattern, nonEmptyPatternOptions);
|
||||
auto matchResult = re.match(textToMatch);
|
||||
const int capturedCount = matchResult.lastCapturedIndex();
|
||||
QBENCHMARK {
|
||||
for (int i = 0, imax = capturedCount; i < imax; ++i) {
|
||||
auto result = matchResult.capturedView(i);
|
||||
Q_UNUSED(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QRegularExpressionBenchmark::queryMatchResultsByGroupName()
|
||||
{
|
||||
QRegularExpression re(nonEmptyPattern, nonEmptyPatternOptions);
|
||||
auto matchResult = re.match(textToMatch);
|
||||
const auto groups = matchResult.regularExpression().namedCaptureGroups();
|
||||
QBENCHMARK {
|
||||
for (const QString &groupName : groups) {
|
||||
// introduce this checks to get rid of tons of warnings.
|
||||
// The result for empty string is always the same.
|
||||
if (!groupName.isEmpty()) {
|
||||
auto result = matchResult.capturedView(groupName);
|
||||
Q_UNUSED(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QRegularExpressionBenchmark::iterateThroughGlobalMatchResults()
|
||||
{
|
||||
QRegularExpression re(nonEmptyPattern, nonEmptyPatternOptions);
|
||||
auto matchResultIterator = re.globalMatch(textToMatch);
|
||||
QBENCHMARK {
|
||||
if (matchResultIterator.isValid()) {
|
||||
while (matchResultIterator.hasNext()) {
|
||||
matchResultIterator.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QRegularExpressionBenchmark)
|
||||
|
||||
#include "tst_bench_qregularexpression.moc"
|
13
tests/benchmarks/corelib/text/qstring/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/text/qstring/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qstring Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qstring
|
||||
SOURCES
|
||||
tst_bench_qstring.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
455
tests/benchmarks/corelib/text/qstring/tst_bench_qstring.cpp
Normal file
455
tests/benchmarks/corelib/text/qstring/tst_bench_qstring.cpp
Normal file
@ -0,0 +1,455 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QStringList>
|
||||
#include <QFile>
|
||||
#include <QTest>
|
||||
#include <limits>
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
class tst_QString: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
tst_QString();
|
||||
private slots:
|
||||
void section_regexp_data() { section_data_impl(); }
|
||||
void section_regularexpression_data() { section_data_impl(); }
|
||||
void section_regularexpression() { section_impl<QRegularExpression>(); }
|
||||
void section_string_data() { section_data_impl(false); }
|
||||
void section_string() { section_impl<QString>(); }
|
||||
|
||||
void toUpper_data();
|
||||
void toUpper();
|
||||
void toLower_data();
|
||||
void toLower();
|
||||
void toCaseFolded_data();
|
||||
void toCaseFolded();
|
||||
|
||||
// Serializing:
|
||||
void number_qlonglong_data();
|
||||
void number_qlonglong() { number_impl<qlonglong>(); }
|
||||
void number_qulonglong_data();
|
||||
void number_qulonglong() { number_impl<qulonglong>(); }
|
||||
|
||||
void number_double_data();
|
||||
void number_double();
|
||||
|
||||
// Parsing:
|
||||
void toLongLong_data();
|
||||
void toLongLong();
|
||||
void toULongLong_data();
|
||||
void toULongLong();
|
||||
void toDouble_data();
|
||||
void toDouble();
|
||||
|
||||
private:
|
||||
void section_data_impl(bool includeRegExOnly = true);
|
||||
template <typename RX> void section_impl();
|
||||
template <typename Integer> void number_impl();
|
||||
};
|
||||
|
||||
tst_QString::tst_QString()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QString::section_data_impl(bool includeRegExOnly)
|
||||
{
|
||||
QTest::addColumn<QString>("s");
|
||||
QTest::addColumn<QString>("sep");
|
||||
QTest::addColumn<bool>("isRegExp");
|
||||
|
||||
QTest::newRow("IPv4") << QStringLiteral("192.168.0.1") << QStringLiteral(".") << false;
|
||||
QTest::newRow("IPv6") << QStringLiteral("2001:0db8:85a3:0000:0000:8a2e:0370:7334") << QStringLiteral(":") << false;
|
||||
if (includeRegExOnly) {
|
||||
QTest::newRow("IPv6-reversed-roles") << QStringLiteral("2001:0db8:85a3:0000:0000:8a2e:0370:7334") << QStringLiteral("\\d+") << true;
|
||||
QTest::newRow("IPv6-complex") << QStringLiteral("2001:0db8:85a3:0000:0000:8a2e:0370:7334") << QStringLiteral("(\\d+):\\1") << true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename RX>
|
||||
inline QString escape(const QString &s)
|
||||
{ return RX::escape(s); }
|
||||
|
||||
template <>
|
||||
inline QString escape<QString>(const QString &s)
|
||||
{ return s; }
|
||||
|
||||
template <typename RX>
|
||||
inline void optimize(RX &) {}
|
||||
|
||||
template <>
|
||||
inline void optimize(QRegularExpression &rx)
|
||||
{ rx.optimize(); }
|
||||
|
||||
template <typename RX>
|
||||
void tst_QString::section_impl()
|
||||
{
|
||||
QFETCH(QString, s);
|
||||
QFETCH(QString, sep);
|
||||
QFETCH(bool, isRegExp);
|
||||
|
||||
RX rx(isRegExp ? sep : escape<RX>(sep));
|
||||
optimize(rx);
|
||||
for (int i = 0; i < 20; ++i)
|
||||
(void) s.count(rx); // make (s, rx) hot
|
||||
|
||||
QBENCHMARK {
|
||||
const QString result = s.section(rx, 0, 16);
|
||||
Q_UNUSED(result);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QString::toUpper_data()
|
||||
{
|
||||
QTest::addColumn<QString>("s");
|
||||
|
||||
QString lowerLatin1(300, QChar('a'));
|
||||
QString upperLatin1(300, QChar('A'));
|
||||
|
||||
QString lowerDeseret;
|
||||
{
|
||||
QString pattern;
|
||||
pattern += QChar(QChar::highSurrogate(0x10428));
|
||||
pattern += QChar(QChar::lowSurrogate(0x10428));
|
||||
for (int i = 0; i < 300 / pattern.size(); ++i)
|
||||
lowerDeseret += pattern;
|
||||
}
|
||||
QString upperDeseret;
|
||||
{
|
||||
QString pattern;
|
||||
pattern += QChar(QChar::highSurrogate(0x10400));
|
||||
pattern += QChar(QChar::lowSurrogate(0x10400));
|
||||
for (int i = 0; i < 300 / pattern.size(); ++i)
|
||||
upperDeseret += pattern;
|
||||
}
|
||||
|
||||
QString lowerLigature(600, QChar(0xFB03));
|
||||
|
||||
QTest::newRow("600<a>") << (lowerLatin1 + lowerLatin1);
|
||||
QTest::newRow("600<A>") << (upperLatin1 + upperLatin1);
|
||||
|
||||
QTest::newRow("300<a>+300<A>") << (lowerLatin1 + upperLatin1);
|
||||
QTest::newRow("300<A>+300<a>") << (upperLatin1 + lowerLatin1);
|
||||
|
||||
QTest::newRow("300<10428>") << (lowerDeseret + lowerDeseret);
|
||||
QTest::newRow("300<10400>") << (upperDeseret + upperDeseret);
|
||||
|
||||
QTest::newRow("150<10428>+150<10400>") << (lowerDeseret + upperDeseret);
|
||||
QTest::newRow("150<10400>+150<10428>") << (upperDeseret + lowerDeseret);
|
||||
|
||||
QTest::newRow("300a+150<10400>") << (lowerLatin1 + upperDeseret);
|
||||
QTest::newRow("300a+150<10428>") << (lowerLatin1 + lowerDeseret);
|
||||
QTest::newRow("300A+150<10400>") << (upperLatin1 + upperDeseret);
|
||||
QTest::newRow("300A+150<10428>") << (upperLatin1 + lowerDeseret);
|
||||
|
||||
QTest::newRow("600<FB03> (ligature)") << lowerLigature;
|
||||
}
|
||||
|
||||
void tst_QString::toUpper()
|
||||
{
|
||||
QFETCH(QString, s);
|
||||
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = s.toUpper();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QString::toLower_data()
|
||||
{
|
||||
toUpper_data();
|
||||
}
|
||||
|
||||
void tst_QString::toLower()
|
||||
{
|
||||
QFETCH(QString, s);
|
||||
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = s.toLower();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QString::toCaseFolded_data()
|
||||
{
|
||||
toUpper_data();
|
||||
}
|
||||
|
||||
void tst_QString::toCaseFolded()
|
||||
{
|
||||
QFETCH(QString, s);
|
||||
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = s.toCaseFolded();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
void tst_QString::number_impl()
|
||||
{
|
||||
QFETCH(Integer, number);
|
||||
QFETCH(int, base);
|
||||
QFETCH(QString, expected);
|
||||
|
||||
QString actual;
|
||||
QBENCHMARK {
|
||||
actual = QString::number(number, base);
|
||||
}
|
||||
QCOMPARE(actual, expected);
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
void number_integer_common()
|
||||
{
|
||||
QTest::addColumn<Integer>("number");
|
||||
QTest::addColumn<int>("base");
|
||||
QTest::addColumn<QString>("expected");
|
||||
|
||||
QTest::newRow("0") << Integer(0ull) << 10 << QStringLiteral("0");
|
||||
QTest::newRow("1234") << Integer(1234ull) << 10 << QStringLiteral("1234");
|
||||
QTest::newRow("123456789") << Integer(123456789ull) << 10 << QStringLiteral("123456789");
|
||||
QTest::newRow("bad1dea, base 16") << Integer(0xBAD1DEAull) << 16 << QStringLiteral("bad1dea");
|
||||
QTest::newRow("242, base 8") << Integer(0242ull) << 8 << QStringLiteral("242");
|
||||
QTest::newRow("101101, base 2") << Integer(0b101101ull) << 2 << QStringLiteral("101101");
|
||||
QTest::newRow("ad, base 30") << Integer(313ull) << 30 << QStringLiteral("ad");
|
||||
}
|
||||
|
||||
void tst_QString::number_qlonglong_data()
|
||||
{
|
||||
number_integer_common<qlonglong>();
|
||||
|
||||
QTest::newRow("-1234") << -1234ll << 10 << QStringLiteral("-1234");
|
||||
QTest::newRow("-123456789") << -123456789ll << 10 << QStringLiteral("-123456789");
|
||||
QTest::newRow("-bad1dea, base 16") << -0xBAD1DEAll << 16 << QStringLiteral("-bad1dea");
|
||||
QTest::newRow("-242, base 8") << -0242ll << 8 << QStringLiteral("-242");
|
||||
QTest::newRow("-101101, base 2") << -0b101101ll << 2 << QStringLiteral("-101101");
|
||||
QTest::newRow("-ad, base 30") << -313ll << 30 << QStringLiteral("-ad");
|
||||
|
||||
QTest::newRow("qlonglong-max")
|
||||
<< std::numeric_limits<qlonglong>::max() << 10 << QStringLiteral("9223372036854775807");
|
||||
QTest::newRow("qlonglong-min")
|
||||
<< std::numeric_limits<qlonglong>::min() << 10
|
||||
<< QStringLiteral("-9223372036854775808");
|
||||
QTest::newRow("qlonglong-max, base 2")
|
||||
<< std::numeric_limits<qlonglong>::max() << 2 << QString(63, u'1');
|
||||
QTest::newRow("qlonglong-min, base 2") << std::numeric_limits<qlonglong>::min() << 2
|
||||
<< (QStringLiteral("-1") + QString(63, u'0'));
|
||||
QTest::newRow("qlonglong-max, base 16")
|
||||
<< std::numeric_limits<qlonglong>::max() << 16 << (QChar(u'7') + QString(15, u'f'));
|
||||
QTest::newRow("qlonglong-min, base 16") << std::numeric_limits<qlonglong>::min() << 16
|
||||
<< (QStringLiteral("-8") + QString(15, u'0'));
|
||||
}
|
||||
|
||||
void tst_QString::number_qulonglong_data()
|
||||
{
|
||||
number_integer_common<qulonglong>();
|
||||
|
||||
QTest::newRow("qlonglong-max + 1")
|
||||
<< (qulonglong(std::numeric_limits<qlonglong>::max()) + 1) << 10
|
||||
<< QStringLiteral("9223372036854775808");
|
||||
QTest::newRow("qulonglong-max")
|
||||
<< std::numeric_limits<qulonglong>::max() << 10
|
||||
<< QStringLiteral("18446744073709551615");
|
||||
QTest::newRow("qulonglong-max, base 2")
|
||||
<< std::numeric_limits<qulonglong>::max() << 2 << QString(64, u'1');
|
||||
QTest::newRow("qulonglong-max, base 16")
|
||||
<< std::numeric_limits<qulonglong>::max() << 16 << QString(16, u'f');
|
||||
}
|
||||
|
||||
void tst_QString::number_double_data()
|
||||
{
|
||||
QTest::addColumn<double>("number");
|
||||
QTest::addColumn<char>("format");
|
||||
QTest::addColumn<int>("precision");
|
||||
QTest::addColumn<QString>("expected");
|
||||
|
||||
struct
|
||||
{
|
||||
double d;
|
||||
char f;
|
||||
int p;
|
||||
QString expected;
|
||||
} data[] = {
|
||||
{ 0.0, 'f', 0, QStringLiteral("0") },
|
||||
{ 0.0001, 'f', 0, QStringLiteral("0") },
|
||||
{ 0.1234, 'f', 5, QStringLiteral("0.12340") },
|
||||
{ -0.1234, 'f', 5, QStringLiteral("-0.12340") },
|
||||
{ 0.5 + qSqrt(1.25), 'f', 15, QStringLiteral("1.618033988749895") },
|
||||
{ std::numeric_limits<double>::epsilon(), 'g', 10, QStringLiteral("2.220446049e-16") },
|
||||
{ 0.0001, 'E', 1, QStringLiteral("1.0E-04") },
|
||||
{ 1e8, 'E', 1, QStringLiteral("1.0E+08") },
|
||||
{ -1e8, 'E', 1, QStringLiteral("-1.0E+08") },
|
||||
};
|
||||
|
||||
for (auto &datum : data) {
|
||||
QTest::addRow("%s, format '%c', precision %d", qPrintable(datum.expected), datum.f,
|
||||
datum.p)
|
||||
<< datum.d << datum.f << datum.p << datum.expected;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QString::number_double()
|
||||
{
|
||||
QFETCH(double, number);
|
||||
QFETCH(char, format);
|
||||
QFETCH(int, precision);
|
||||
QFETCH(QString, expected);
|
||||
|
||||
QString actual;
|
||||
QBENCHMARK {
|
||||
actual = QString::number(number, format, precision);
|
||||
}
|
||||
QCOMPARE(actual, expected);
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
void toWholeCommon_data()
|
||||
{
|
||||
QTest::addColumn<QString>("text");
|
||||
QTest::addColumn<int>("base");
|
||||
QTest::addColumn<bool>("good");
|
||||
QTest::addColumn<Integer>("expected");
|
||||
|
||||
QTest::newRow("empty") << u""_s << 10 << false << Integer(0ull);
|
||||
QTest::newRow("0") << u"0"_s << 10 << true << Integer(0ull);
|
||||
QTest::newRow("1234") << u"1234"_s << 10 << true << Integer(1234ull);
|
||||
QTest::newRow("1,234") << u"1,234"_s << 10 << false << Integer(0ull);
|
||||
QTest::newRow("123456789")
|
||||
<< u"123456789"_s << 10 << true << Integer(123456789ull);
|
||||
QTest::newRow("bad1dea, base 16")
|
||||
<< u"bad1dea"_s << 16 << true << Integer(0xBAD1DEAull);
|
||||
QTest::newRow("bad1dea, base 10") << u"bad1dea"_s << 10 << false << Integer(0ull);
|
||||
QTest::newRow("42, base 13") << u"42"_s << 13 << true << Integer(6ull * 9ull);
|
||||
QTest::newRow("242, base 8") << u"242"_s << 8 << true << Integer(0242ull);
|
||||
QTest::newRow("495, base 8") << u"495"_s << 8 << false << Integer(0ull);
|
||||
QTest::newRow("101101, base 2")
|
||||
<< u"101101"_s << 2 << true << Integer(0b101101ull);
|
||||
QTest::newRow("ad, base 30") << u"ad"_s << 30 << true << Integer(313ull);
|
||||
}
|
||||
|
||||
void tst_QString::toLongLong_data()
|
||||
{
|
||||
toWholeCommon_data<qlonglong>();
|
||||
|
||||
QTest::newRow("-1234") << u"-1234"_s << 10 << true << -1234ll;
|
||||
QTest::newRow("-123456789") << u"-123456789"_s << 10 << true << -123456789ll;
|
||||
QTest::newRow("-bad1dea, base 16") << u"-bad1dea"_s << 16 << true << -0xBAD1DEAll;
|
||||
QTest::newRow("-242, base 8") << u"-242"_s << 8 << true << -0242ll;
|
||||
QTest::newRow("-101101, base 2") << u"-101101"_s << 2 << true << -0b101101ll;
|
||||
QTest::newRow("-ad, base 30") << u"-ad"_s << 30 << true << -313ll;
|
||||
|
||||
QTest::newRow("qlonglong-max")
|
||||
<< u"9223372036854775807"_s << 10 << true
|
||||
<< std::numeric_limits<qlonglong>::max();
|
||||
QTest::newRow("qlonglong-min")
|
||||
<< u"-9223372036854775808"_s << 10 << true
|
||||
<< std::numeric_limits<qlonglong>::min();
|
||||
QTest::newRow("qlonglong-max, base 2")
|
||||
<< QString(63, u'1') << 2 << true << std::numeric_limits<qlonglong>::max();
|
||||
QTest::newRow("qlonglong-min, base 2")
|
||||
<< (u"-1"_s + QString(63, u'0')) << 2 << true
|
||||
<< std::numeric_limits<qlonglong>::min();
|
||||
QTest::newRow("qlonglong-max, base 16")
|
||||
<< (QChar(u'7') + QString(15, u'f')) << 16 << true
|
||||
<< std::numeric_limits<qlonglong>::max();
|
||||
QTest::newRow("qlonglong-min, base 16")
|
||||
<< (u"-8"_s + QString(15, u'0')) << 16 << true
|
||||
<< std::numeric_limits<qlonglong>::min();
|
||||
}
|
||||
|
||||
void tst_QString::toLongLong()
|
||||
{
|
||||
QFETCH(QString, text);
|
||||
QFETCH(int, base);
|
||||
QFETCH(bool, good);
|
||||
QFETCH(qlonglong, expected);
|
||||
|
||||
qlonglong actual = expected;
|
||||
bool ok = false;
|
||||
QBENCHMARK {
|
||||
actual = text.toLongLong(&ok, base);
|
||||
}
|
||||
QCOMPARE(ok, good);
|
||||
QCOMPARE(actual, expected);
|
||||
}
|
||||
|
||||
void tst_QString::toULongLong_data()
|
||||
{
|
||||
toWholeCommon_data<qulonglong>();
|
||||
|
||||
QTest::newRow("qlonglong-max + 1")
|
||||
<< u"9223372036854775808"_s << 10 << true
|
||||
<< (qulonglong(std::numeric_limits<qlonglong>::max()) + 1);
|
||||
QTest::newRow("qulonglong-max")
|
||||
<< u"18446744073709551615"_s << 10 << true
|
||||
<< std::numeric_limits<qulonglong>::max();
|
||||
QTest::newRow("qulonglong-max, base 2")
|
||||
<< QString(64, u'1') << 2 << true << std::numeric_limits<qulonglong>::max();
|
||||
QTest::newRow("qulonglong-max, base 16")
|
||||
<< QString(16, u'f') << 16 << true << std::numeric_limits<qulonglong>::max();
|
||||
}
|
||||
|
||||
void tst_QString::toULongLong()
|
||||
{
|
||||
QFETCH(QString, text);
|
||||
QFETCH(int, base);
|
||||
QFETCH(bool, good);
|
||||
QFETCH(qulonglong, expected);
|
||||
|
||||
qulonglong actual = expected;
|
||||
bool ok = false;
|
||||
QBENCHMARK {
|
||||
actual = text.toULongLong(&ok, base);
|
||||
}
|
||||
QCOMPARE(ok, good);
|
||||
QCOMPARE(actual, expected);
|
||||
}
|
||||
|
||||
void tst_QString::toDouble_data()
|
||||
{
|
||||
QTest::addColumn<QString>("text");
|
||||
QTest::addColumn<bool>("good");
|
||||
QTest::addColumn<double>("expected");
|
||||
|
||||
QTest::newRow("empty") << u""_s << false << 0.0;
|
||||
QTest::newRow("0") << u"0"_s << true << 0.0;
|
||||
QTest::newRow("0.12340") << u"0.12340"_s << true << 0.12340;
|
||||
QTest::newRow("-0.12340") << u"-0.12340"_s << true << -0.12340;
|
||||
QTest::newRow("epsilon")
|
||||
<< u"2.220446049e-16"_s << true << std::numeric_limits<double>::epsilon();
|
||||
QTest::newRow("1.0e-4") << u"1.0e-4"_s << true << 1.0e-4;
|
||||
QTest::newRow("1.0e+4") << u"1.0e+4"_s << true << 1.0e+4;
|
||||
QTest::newRow("10.e+3") << u"10.e+3"_s << true << 1.0e+4;
|
||||
QTest::newRow("10e+3.") << u"10e+3."_s << false << 0.0;
|
||||
QTest::newRow("1e4") << u"1e4"_s << true << 1.0e+4;
|
||||
QTest::newRow("1.0e-8") << u"1.0e-8"_s << true << 1.0e-8;
|
||||
QTest::newRow("1.0e+8") << u"1.0e+8"_s << true << 1.0e+8;
|
||||
|
||||
// NaN and infinity:
|
||||
QTest::newRow("nan") << u"nan"_s << true << qQNaN();
|
||||
QTest::newRow("NaN") << u"NaN"_s << true << qQNaN();
|
||||
QTest::newRow("-nan") << u"-nan"_s << false << 0.0;
|
||||
QTest::newRow("+nan") << u"+nan"_s << false << 0.0;
|
||||
QTest::newRow("inf") << u"inf"_s << true << qInf();
|
||||
QTest::newRow("Inf") << u"Inf"_s << true << qInf();
|
||||
QTest::newRow("+inf") << u"+inf"_s << true << qInf();
|
||||
QTest::newRow("-inf") << u"-inf"_s << true << -qInf();
|
||||
}
|
||||
|
||||
void tst_QString::toDouble()
|
||||
{
|
||||
QFETCH(QString, text);
|
||||
QFETCH(bool, good);
|
||||
QFETCH(double, expected);
|
||||
|
||||
double actual = expected;
|
||||
bool ok = false;
|
||||
QBENCHMARK {
|
||||
actual = text.toDouble(&ok);
|
||||
}
|
||||
QCOMPARE(ok, good);
|
||||
QCOMPARE(actual, expected);
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_QString)
|
||||
|
||||
#include "tst_bench_qstring.moc"
|
15
tests/benchmarks/corelib/text/qstringbuilder/CMakeLists.txt
Normal file
15
tests/benchmarks/corelib/text/qstringbuilder/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qstringbuilder Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qstringbuilder
|
||||
SOURCES
|
||||
tst_bench_qstringbuilder.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
COMPILE_OPTIONS
|
||||
-g
|
||||
)
|
@ -0,0 +1,390 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
// Select one of the scenarios below
|
||||
#define SCENARIO 1
|
||||
|
||||
#if SCENARIO == 1
|
||||
// this is the "no harm done" version. Only operator% is active,
|
||||
// with NO_CAST * defined
|
||||
#undef QT_USE_FAST_OPERATOR_PLUS
|
||||
#undef QT_USE_FAST_CONCATENATION
|
||||
#define QT_NO_CAST_FROM_ASCII
|
||||
#define QT_NO_CAST_TO_ASCII
|
||||
#endif
|
||||
|
||||
|
||||
#if SCENARIO == 2
|
||||
// this is the "full" version. Operator+ is replaced by a QStringBuilder
|
||||
// based version
|
||||
// with NO_CAST * defined
|
||||
#define QT_USE_FAST_OPERATOR_PLUS
|
||||
#define QT_USE_FAST_CONCATENATION
|
||||
#define QT_NO_CAST_FROM_ASCII
|
||||
#define QT_NO_CAST_TO_ASCII
|
||||
#endif
|
||||
|
||||
#if SCENARIO == 3
|
||||
// this is the "no harm done" version. Only operator% is active,
|
||||
// with NO_CAST * _not_ defined
|
||||
#undef QT_USE_FAST_OPERATOR_PLUS
|
||||
#undef QT_USE_FAST_CONCATENATION
|
||||
#undef QT_NO_CAST_FROM_ASCII
|
||||
#undef QT_NO_CAST_TO_ASCII
|
||||
#endif
|
||||
|
||||
#if SCENARIO == 4
|
||||
// this is the "full" version. Operator+ is replaced by a QStringBuilder
|
||||
// based version
|
||||
// with NO_CAST * _not_ defined
|
||||
#define QT_USE_FAST_OPERATOR_PLUS
|
||||
#define QT_USE_FAST_CONCATENATION
|
||||
#undef QT_NO_CAST_FROM_ASCII
|
||||
#undef QT_NO_CAST_TO_ASCII
|
||||
#endif
|
||||
|
||||
|
||||
#include <qbytearray.h>
|
||||
#include <qdebug.h>
|
||||
#include <qstring.h>
|
||||
#include <qstringbuilder.h>
|
||||
|
||||
#include <qtest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
// Select one of the scenarios below
|
||||
#if SCENARIO == 1
|
||||
#define P %
|
||||
#elif SCENARIO == 2
|
||||
#define P +
|
||||
#elif SCENARIO == 3
|
||||
#define P %
|
||||
#elif SCENARIO == 4
|
||||
#define P +
|
||||
#endif
|
||||
|
||||
#define COMPARE(a, b) QCOMPARE(a, b)
|
||||
//#define COMPARE(a, b)
|
||||
|
||||
#define SEP(s) qDebug() << "\n\n-------- " s " ---------";
|
||||
|
||||
#define LITERAL "some string literal"
|
||||
|
||||
class tst_QStringBuilder : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QStringBuilder()
|
||||
: l1literal(LITERAL),
|
||||
l1string(LITERAL),
|
||||
ba(LITERAL),
|
||||
string(l1string),
|
||||
stdstring(LITERAL),
|
||||
achar('c'),
|
||||
r2(QLatin1String(LITERAL LITERAL)),
|
||||
r3(QLatin1String(LITERAL LITERAL LITERAL)),
|
||||
r4(QLatin1String(LITERAL LITERAL LITERAL LITERAL)),
|
||||
r5(QLatin1String(LITERAL LITERAL LITERAL LITERAL LITERAL))
|
||||
{}
|
||||
|
||||
|
||||
public:
|
||||
enum { N = 10000 };
|
||||
|
||||
int run_traditional()
|
||||
{
|
||||
int s = 0;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
#if 0
|
||||
s += QString(l1string + l1string).size();
|
||||
s += QString(l1string + l1string + l1string).size();
|
||||
s += QString(l1string + l1string + l1string + l1string).size();
|
||||
s += QString(l1string + l1string + l1string + l1string + l1string).size();
|
||||
#endif
|
||||
s += QString(achar + l1string + achar).size();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int run_builder()
|
||||
{
|
||||
int s = 0;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
#if 0
|
||||
s += QString(l1literal P l1literal).size();
|
||||
s += QString(l1literal P l1literal P l1literal).size();
|
||||
s += QString(l1literal P l1literal P l1literal P l1literal).size();
|
||||
s += QString(l1literal P l1literal P l1literal P l1literal P l1literal).size();
|
||||
#endif
|
||||
s += QString(achar % l1literal % achar).size();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private slots:
|
||||
|
||||
void separator_0() {
|
||||
qDebug() << "\nIn each block the QStringBuilder based result appear first "
|
||||
"(with a 'b_' prefix), QStringBased second ('q_' prefix), std::string "
|
||||
"last ('s_' prefix)\n";
|
||||
}
|
||||
|
||||
void separator_1() { SEP("literal + literal (builder first)"); }
|
||||
|
||||
void b_2_l1literal() {
|
||||
QBENCHMARK { r = l1literal P l1literal; }
|
||||
COMPARE(r, r2);
|
||||
}
|
||||
#ifndef QT_NO_CAST_FROM_ASCII
|
||||
void b_l1literal_LITERAL() {
|
||||
QBENCHMARK { r = l1literal P LITERAL; }
|
||||
COMPARE(r, r2);
|
||||
}
|
||||
#endif
|
||||
void q_2_l1string() {
|
||||
QBENCHMARK { r = l1string + l1string; }
|
||||
COMPARE(r, r2);
|
||||
}
|
||||
|
||||
|
||||
void separator_2() { SEP("2 strings"); }
|
||||
|
||||
void b_2_string() {
|
||||
QBENCHMARK { r = string P string; }
|
||||
COMPARE(r, r2);
|
||||
}
|
||||
void q_2_string() {
|
||||
QBENCHMARK { r = string + string; }
|
||||
COMPARE(r, r2);
|
||||
}
|
||||
void s_2_string() {
|
||||
QBENCHMARK { stdr = stdstring + stdstring; }
|
||||
COMPARE(stdr, stdstring + stdstring);
|
||||
}
|
||||
|
||||
|
||||
void separator_2b() { SEP("3 strings"); }
|
||||
|
||||
void b_3_string() {
|
||||
QBENCHMARK { r = string P string P string; }
|
||||
COMPARE(r, r3);
|
||||
}
|
||||
void q_3_string() {
|
||||
QBENCHMARK { r = string + string + string; }
|
||||
COMPARE(r, r3);
|
||||
}
|
||||
void s_3_string() {
|
||||
QBENCHMARK { stdr = stdstring + stdstring + stdstring; }
|
||||
COMPARE(stdr, stdstring + stdstring + stdstring);
|
||||
}
|
||||
|
||||
void separator_2e() { SEP("4 strings"); }
|
||||
|
||||
void b_4_string() {
|
||||
QBENCHMARK { r = string P string P string P string; }
|
||||
COMPARE(r, r4);
|
||||
}
|
||||
void q_4_string() {
|
||||
QBENCHMARK { r = string + string + string + string; }
|
||||
COMPARE(r, r4);
|
||||
}
|
||||
void s_4_string() {
|
||||
QBENCHMARK { stdr = stdstring + stdstring + stdstring + stdstring; }
|
||||
COMPARE(stdr, stdstring + stdstring + stdstring + stdstring);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void separator_2a() { SEP("string + literal (builder first)"); }
|
||||
|
||||
void b_string_l1literal() {
|
||||
QBENCHMARK { r = string % l1literal; }
|
||||
COMPARE(r, r2);
|
||||
}
|
||||
#ifndef QT_NO_CAST_FROM_ASCII
|
||||
void b_string_LITERAL() {
|
||||
QBENCHMARK { r = string P LITERAL; }
|
||||
COMPARE(r, r2);
|
||||
}
|
||||
void b_LITERAL_string() {
|
||||
QBENCHMARK { r = LITERAL P string; }
|
||||
COMPARE(r, r2);
|
||||
}
|
||||
#endif
|
||||
void b_string_l1string() {
|
||||
QBENCHMARK { r = string P l1string; }
|
||||
COMPARE(r, r2);
|
||||
}
|
||||
void q_string_l1literal() {
|
||||
QBENCHMARK { r = string + l1string; }
|
||||
COMPARE(r, r2);
|
||||
}
|
||||
void q_string_l1string() {
|
||||
QBENCHMARK { r = string + l1string; }
|
||||
COMPARE(r, r2);
|
||||
}
|
||||
void s_LITERAL_string() {
|
||||
QBENCHMARK { stdr = LITERAL + stdstring; }
|
||||
COMPARE(stdr, stdstring + stdstring);
|
||||
}
|
||||
|
||||
|
||||
void separator_3() { SEP("3 literals"); }
|
||||
|
||||
void b_3_l1literal() {
|
||||
QBENCHMARK { r = l1literal P l1literal P l1literal; }
|
||||
COMPARE(r, r3);
|
||||
}
|
||||
void q_3_l1string() {
|
||||
QBENCHMARK { r = l1string + l1string + l1string; }
|
||||
COMPARE(r, r3);
|
||||
}
|
||||
void s_3_l1string() {
|
||||
QBENCHMARK { stdr = stdstring + LITERAL + LITERAL; }
|
||||
COMPARE(stdr, stdstring + stdstring + stdstring);
|
||||
}
|
||||
|
||||
|
||||
void separator_4() { SEP("4 literals"); }
|
||||
|
||||
void b_4_l1literal() {
|
||||
QBENCHMARK { r = l1literal P l1literal P l1literal P l1literal; }
|
||||
COMPARE(r, r4);
|
||||
}
|
||||
void q_4_l1string() {
|
||||
QBENCHMARK { r = l1string + l1string + l1string + l1string; }
|
||||
COMPARE(r, r4);
|
||||
}
|
||||
|
||||
|
||||
void separator_5() { SEP("5 literals"); }
|
||||
|
||||
void b_5_l1literal() {
|
||||
QBENCHMARK { r = l1literal P l1literal P l1literal P l1literal P l1literal; }
|
||||
COMPARE(r, r5);
|
||||
}
|
||||
|
||||
void q_5_l1string() {
|
||||
QBENCHMARK { r = l1string + l1string + l1string + l1string + l1string; }
|
||||
COMPARE(r, r5);
|
||||
}
|
||||
|
||||
|
||||
void separator_6() { SEP("4 chars"); }
|
||||
|
||||
void b_string_4_char() {
|
||||
QBENCHMARK { r = string + achar + achar + achar + achar; }
|
||||
COMPARE(r, QString(string P achar P achar P achar P achar));
|
||||
}
|
||||
|
||||
void q_string_4_char() {
|
||||
QBENCHMARK { r = string + achar + achar + achar + achar; }
|
||||
COMPARE(r, QString(string P achar P achar P achar P achar));
|
||||
}
|
||||
|
||||
void s_string_4_char() {
|
||||
QBENCHMARK { stdr = stdstring + 'c' + 'c' + 'c' + 'c'; }
|
||||
COMPARE(stdr, stdstring + 'c' + 'c' + 'c' + 'c');
|
||||
}
|
||||
|
||||
|
||||
void separator_7() { SEP("char + string + char"); }
|
||||
|
||||
void b_char_string_char() {
|
||||
QBENCHMARK { r = achar + string + achar; }
|
||||
COMPARE(r, QString(achar P string P achar));
|
||||
}
|
||||
|
||||
void q_char_string_char() {
|
||||
QBENCHMARK { r = achar + string + achar; }
|
||||
COMPARE(r, QString(achar P string P achar));
|
||||
}
|
||||
|
||||
void s_char_string_char() {
|
||||
QBENCHMARK { stdr = 'c' + stdstring + 'c'; }
|
||||
COMPARE(stdr, 'c' + stdstring + 'c');
|
||||
}
|
||||
|
||||
|
||||
void separator_8() { SEP("string.arg"); }
|
||||
|
||||
void b_string_arg() {
|
||||
const QString pattern = l1string + QString::fromLatin1("%1") + l1string;
|
||||
QBENCHMARK { r = l1literal P string P l1literal; }
|
||||
COMPARE(r, r3);
|
||||
}
|
||||
|
||||
void q_string_arg() {
|
||||
const QString pattern = l1string + QLatin1String("%1") + l1string;
|
||||
QBENCHMARK { r = pattern.arg(string); }
|
||||
COMPARE(r, r3);
|
||||
}
|
||||
|
||||
void q_bytearray_arg() {
|
||||
QByteArray result;
|
||||
QBENCHMARK { result = ba + ba + ba; }
|
||||
}
|
||||
|
||||
|
||||
void separator_9() { SEP("QString::reserve()"); }
|
||||
|
||||
void b_reserve() {
|
||||
QBENCHMARK {
|
||||
r.clear();
|
||||
r = string P string P string P string;
|
||||
}
|
||||
COMPARE(r, r4);
|
||||
}
|
||||
void b_reserve_lit() {
|
||||
QBENCHMARK {
|
||||
r.clear();
|
||||
r = string P l1literal P string P string;
|
||||
}
|
||||
COMPARE(r, r4);
|
||||
}
|
||||
void s_reserve() {
|
||||
QBENCHMARK {
|
||||
r.clear();
|
||||
r.reserve(string.size() + string.size() + string.size() + string.size());
|
||||
r += string;
|
||||
r += string;
|
||||
r += string;
|
||||
r += string;
|
||||
}
|
||||
COMPARE(r, r4);
|
||||
}
|
||||
void s_reserve_lit() {
|
||||
QBENCHMARK {
|
||||
r.clear();
|
||||
//r.reserve(string.size() + qstrlen(l1string.latin1())
|
||||
// + string.size() + string.size());
|
||||
r.reserve(1024);
|
||||
r += string;
|
||||
r += l1string;
|
||||
r += string;
|
||||
r += string;
|
||||
}
|
||||
COMPARE(r, r4);
|
||||
}
|
||||
|
||||
private:
|
||||
const QLatin1String l1literal;
|
||||
const QLatin1String l1string;
|
||||
const QByteArray ba;
|
||||
const QString string;
|
||||
const std::string stdstring;
|
||||
const QLatin1Char achar;
|
||||
const QString r2, r3, r4, r5;
|
||||
|
||||
// short cuts for results
|
||||
QString r;
|
||||
std::string stdr;
|
||||
};
|
||||
|
||||
#undef P
|
||||
|
||||
QTEST_MAIN(tst_QStringBuilder)
|
||||
|
||||
#include "tst_bench_qstringbuilder.moc"
|
13
tests/benchmarks/corelib/text/qstringlist/CMakeLists.txt
Normal file
13
tests/benchmarks/corelib/text/qstringlist/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qstringlist Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qstringlist
|
||||
SOURCES
|
||||
tst_bench_qstringlist.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,215 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QStringList>
|
||||
#include <QTest>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class tst_QStringList: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void join() const;
|
||||
void join_data() const;
|
||||
|
||||
void removeDuplicates() const;
|
||||
void removeDuplicates_data() const;
|
||||
|
||||
void split_qlist_qbytearray() const;
|
||||
void split_qlist_qbytearray_data() const { return split_data(); }
|
||||
|
||||
void split_data() const;
|
||||
void split_qlist_qstring() const;
|
||||
void split_qlist_qstring_data() const { return split_data(); }
|
||||
|
||||
void split_stdvector_stdstring() const;
|
||||
void split_stdvector_stdstring_data() const { return split_data(); }
|
||||
|
||||
void split_stdvector_stdwstring() const;
|
||||
void split_stdvector_stdwstring_data() const { return split_data(); }
|
||||
|
||||
void split_stdlist_stdstring() const;
|
||||
void split_stdlist_stdstring_data() const { return split_data(); }
|
||||
|
||||
private:
|
||||
static QStringList populateList(const int count, const QString &unit);
|
||||
static QString populateString(const int count, const QString &unit);
|
||||
};
|
||||
|
||||
QStringList tst_QStringList::populateList(const int count, const QString &unit)
|
||||
{
|
||||
QStringList retval;
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
retval.append(unit);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
QString tst_QStringList::populateString(const int count, const QString &unit)
|
||||
{
|
||||
QString retval;
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
retval.append(unit);
|
||||
retval.append(QLatin1Char(':'));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void tst_QStringList::join() const
|
||||
{
|
||||
QFETCH(QStringList, input);
|
||||
QFETCH(QString, separator);
|
||||
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = input.join(separator);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QStringList::join_data() const
|
||||
{
|
||||
QTest::addColumn<QStringList>("input");
|
||||
QTest::addColumn<QString>("separator");
|
||||
|
||||
QTest::newRow("")
|
||||
<< populateList(100, QLatin1String("unit"))
|
||||
<< QString();
|
||||
|
||||
QTest::newRow("")
|
||||
<< populateList(1000, QLatin1String("unit"))
|
||||
<< QString();
|
||||
|
||||
QTest::newRow("")
|
||||
<< populateList(10000, QLatin1String("unit"))
|
||||
<< QString();
|
||||
|
||||
QTest::newRow("")
|
||||
<< populateList(100000, QLatin1String("unit"))
|
||||
<< QString();
|
||||
}
|
||||
|
||||
void tst_QStringList::removeDuplicates() const
|
||||
{
|
||||
QFETCH(const QStringList, input);
|
||||
|
||||
QBENCHMARK {
|
||||
auto copy = input;
|
||||
copy.removeDuplicates();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QStringList::removeDuplicates_data() const
|
||||
{
|
||||
QTest::addColumn<QStringList>("input");
|
||||
|
||||
const QStringList s = {"one", "two", "three"};
|
||||
|
||||
QTest::addRow("empty") << QStringList();
|
||||
QTest::addRow("short-dup-0.00") << s;
|
||||
QTest::addRow("short-dup-0.50") << (s + s);
|
||||
QTest::addRow("short-dup-0.66") << (s + s + s);
|
||||
QTest::addRow("short-dup-0.75") << (s + s + s + s);
|
||||
|
||||
const QStringList l = []() {
|
||||
QStringList result;
|
||||
const int n = 1000;
|
||||
result.reserve(n);
|
||||
for (int i = 0; i < n; ++i)
|
||||
result.push_back(QString::number(i));
|
||||
return result;
|
||||
}();
|
||||
QTest::addRow("long-dup-0.00") << l;
|
||||
QTest::addRow("long-dup-0.50") << (l + l);
|
||||
QTest::addRow("long-dup-0.66") << (l + l + l);
|
||||
QTest::addRow("long-dup-0.75") << (l + l + l + l);
|
||||
}
|
||||
|
||||
void tst_QStringList::split_data() const
|
||||
{
|
||||
QTest::addColumn<QString>("input");
|
||||
QString unit = QLatin1String("unit") + QString(100, QLatin1Char('s'));
|
||||
//QTest::newRow("") << populateString(10, unit);
|
||||
QTest::newRow("") << populateString(100, unit);
|
||||
//QTest::newRow("") << populateString(100, unit);
|
||||
//QTest::newRow("") << populateString(1000, unit);
|
||||
//QTest::newRow("") << populateString(10000, unit);
|
||||
}
|
||||
|
||||
void tst_QStringList::split_qlist_qbytearray() const
|
||||
{
|
||||
QFETCH(QString, input);
|
||||
const char splitChar = ':';
|
||||
QByteArray ba = input.toLatin1();
|
||||
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = ba.split(splitChar);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QStringList::split_qlist_qstring() const
|
||||
{
|
||||
QFETCH(QString, input);
|
||||
const QChar splitChar = ':';
|
||||
|
||||
QBENCHMARK {
|
||||
[[maybe_unused]] auto r = input.split(splitChar);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QStringList::split_stdvector_stdstring() const
|
||||
{
|
||||
QFETCH(QString, input);
|
||||
const char split_char = ':';
|
||||
std::string stdinput = input.toStdString();
|
||||
|
||||
QBENCHMARK {
|
||||
std::istringstream split(stdinput);
|
||||
std::vector<std::string> token;
|
||||
for (std::string each;
|
||||
std::getline(split, each, split_char);
|
||||
token.push_back(each))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QStringList::split_stdvector_stdwstring() const
|
||||
{
|
||||
QFETCH(QString, input);
|
||||
const wchar_t split_char = ':';
|
||||
std::wstring stdinput = input.toStdWString();
|
||||
|
||||
QBENCHMARK {
|
||||
std::wistringstream split(stdinput);
|
||||
std::vector<std::wstring> token;
|
||||
for (std::wstring each;
|
||||
std::getline(split, each, split_char);
|
||||
token.push_back(each))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QStringList::split_stdlist_stdstring() const
|
||||
{
|
||||
QFETCH(QString, input);
|
||||
const char split_char = ':';
|
||||
std::string stdinput = input.toStdString();
|
||||
|
||||
QBENCHMARK {
|
||||
std::istringstream split(stdinput);
|
||||
std::list<std::string> token;
|
||||
for (std::string each;
|
||||
std::getline(split, each, split_char);
|
||||
token.push_back(each))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QStringList)
|
||||
|
||||
#include "tst_bench_qstringlist.moc"
|
@ -0,0 +1,20 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qstringtokenizer Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qstringtokenizer
|
||||
SOURCES
|
||||
tst_bench_qstringtokenizer.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
||||
|
||||
qt_add_resources(tst_bench_qstringtokenizer "qstringtokenizer_bench_data"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
"./data/lorem.txt"
|
||||
)
|
@ -0,0 +1,40 @@
|
||||
Lorem ipsum dolor sit amet. Ad adipisci quos qui repellat tempore ut dolor vero eos odit soluta ut facere repellendus aut eius voluptatibus. Eos maiores nihil quo deleniti sequi ut iure dolores aut enim molestiae. Non dicta maxime aut quia temporibus ad temporibus repellat? Qui minus nemo eum reiciendis harum ut incidunt praesentium id voluptatum dolorem et enim voluptas eos iste quasi sunt mollitia. Cum fugiat totam 33 quisquam aut autem nobis et illum laborum? Et ipsam libero et harum quas id dolores officia eos nulla asperiores cum similique necessitatibus in dolores reiciendis. Ex consequatur voluptate non alias sunt est voluptatem inventore. Ab odit pariatur non possimus molestiae et dolorum reiciendis et esse nihil qui numquam fugit aut asperiores rerum sed dolorum delectus. Eos temporibus recusandae sed illum quasi in inventore dolorum. Et impedit odio aut accusamus possimus eos quia voluptatem vel fugiat corrupti cum error harum ducimus illum vel soluta porro. Et natus voluptas aut voluptas veniam non ipsa libero est necessitatibus sint ut omnis tempora id distinctio amet sit velit sunt.
|
||||
|
||||
Aut nostrum vero in natus officiis sed explicabo iusto ad odit ipsam qui modi veritatis. A eligendi fugiat sunt eaque qui veniam molestiae! Et minima facere aut galisum quisquam sed repudiandae nulla! Sed perspiciatis galisum eum consectetur tempora sed perspiciatis pariatur ea veritatis iste ea dolore laborum non numquam velit. Et consectetur voluptas id quia sint est animi impedit sed adipisci consequuntur ut fugiat reiciendis. Sit beatae porro qui assumenda ipsum sit galisum mollitia est nulla suscipit ut omnis voluptates qui aperiam impedit eum quae consequuntur. Non facere delectus ut voluptatum voluptatibus nihil vero et fugiat fugiat qui perferendis doloribus ab quia nihil rem iusto distinctio. Ex explicabo debitis non necessitatibus facilis aut debitis laudantium sit rerum explicabo est consequatur internos aut asperiores aliquid est tenetur voluptatibus. Sit quis quas non placeat exercitationem est aperiam tenetur sed sunt accusamus eum delectus quis est animi galisum. Sed molestiae nisi ea voluptatem quasi id voluptatem sunt sit vitae dolor eos nihil galisum eos deleniti rerum! Sed laudantium fuga et ipsam galisum sed temporibus delectus et optio aliquid ut reprehenderit voluptatem?
|
||||
|
||||
Ut molestiae delectus sed distinctio vero ut assumenda rerum 33 dignissimos illo. Ut pariatur unde qui cumque quis quo tenetur odio cum vitae quisquam aut consequuntur velit aut vitae rerum. Qui dignissimos voluptate sit nihil iusto sed eius laudantium et enim voluptatibus non adipisci vero aut corporis natus eum dolorum rerum. Non molestias rerum hic maiores dolor qui veniam optio est itaque blanditiis et quis distinctio qui maxime accusamus. Eos voluptate facilis et fugiat rerum et quos molestiae non tempore nemo. Est dolores porro aut molestias impedit et sunt facilis ad quam dignissimos aut dolores maiores sit perspiciatis cupiditate et molestias deserunt. Qui facilis optio aut facere voluptatum sed asperiores cumque sit dolores maxime qui voluptate sint qui accusantium quasi eos quae fugit! Aut eveniet voluptas vel galisum galisum ea velit doloremque At delectus similique sed corporis soluta ea quia pariatur. Qui earum cupiditate et voluptates magni ut corporis nemo vel totam laboriosam sit quis nulla quo maxime sint. Et nulla blanditiis id fugit enim et nihil commodi a minus consequuntur sed dolores tempore qui possimus libero ea rerum beatae. Qui inventore velit et odit eius et tenetur amet est necessitatibus sequi.
|
||||
|
||||
Est soluta distinctio rem galisum dolore quo reprehenderit non nisi similique? Aut nisi soluta vel galisum modi in quisquam aliquam sit corrupti eligendi a aliquam ducimus? In molestiae culpa et placeat dignissimos ut laudantium accusamus eum error facilis aut obcaecati consequatur est sunt placeat ex esse facilis. Sit magnam consequatur labore praesentium eum galisum ratione eum unde totam est quaerat architecto et voluptatem dolorem. Qui nesciunt ratione eum perspiciatis doloremque et quia voluptatem ea nesciunt atque et ratione aperiam in assumenda voluptate sit ipsam facilis. Est vero aliquid ut voluptatem fuga vel deserunt nihil ut excepturi asperiores id voluptates praesentium eum pariatur laudantium vel nobis sequi? At eligendi explicabo aut minus consequatur a fuga sequi et dolorum galisum ad debitis culpa non similique libero. Et modi architecto At soluta itaque ut inventore facere At omnis asperiores ab distinctio vero qui harum iure.
|
||||
|
||||
Non quos asperiores aut facilis impedit aut reiciendis possimus et dolorem possimus et facere laudantium. Eos recusandae blanditiis sunt obcaecati ut reprehenderit doloremque qui quidem debitis. Et veritatis sequi sit ducimus pariatur et sint galisum qui dolor dolorem. Et beatae possimus qui ducimus sint sit adipisci quisquam. Ad nostrum expedita sed quia fugit est consequatur quia et maiores dolorum eum quod praesentium. Aut similique beatae delectus architecto et commodi minima qui laudantium ducimus. Qui deleniti Quis ea mollitia vero sit tempore dolores. Et corrupti omnis hic aperiam ducimus et laboriosam eius aut voluptatum sint ut molestiae voluptas et vitae eaque sed harum animi! Quo assumenda eveniet id temporibus sapiente quo vitae accusamus non libero vero ea velit libero sed neque voluptas sed quas nemo. Et voluptas corrupti in sequi cum repudiandae illum est animi omnis non sint laudantium aut earum Quis. Non quia veniam ut voluptatem quam qui quisquam distinctio qui eveniet explicabo sit vitae praesentium est aliquid porro eum quod quam. Est nihil debitis non rerum dolores et error minus. Ut harum perferendis et quam molestiae cum rerum consequatur. Qui nemo quod cum quas accusamus sed quasi sunt.
|
||||
|
||||
Non nihil vitae At sapiente aliquam qui quas consectetur eum magnam perferendis ut consequatur quam et iste repellendus. Et quam eligendi ut voluptatem dolorum ut consectetur deserunt et nemo sed autem porro non harum consequatur aut doloremque molestias. Sit minima possimus aut debitis expedita eum consequatur nihil eos voluptas eius. Vel dolor laudantium sed quibusdam provident est sequi omnis quo incidunt assumenda ut modi assumenda qui consequatur doloribus aut cumque aliquid. Ad quia consequatur eos distinctio accusamus ut atque dolor non consectetur rerum qui voluptates quas qui odit velit. Est earum minus non pariatur quo internos rerum et doloremque aperiam et doloribus laudantium aut voluptas molestiae. Ea iste voluptatibus eum voluptatum dolores sit voluptatem dolore et quis nisi. Est maxime animi est magnam distinctio aut quis illo est voluptas itaque ex rerum harum rem dolorum atque?
|
||||
|
||||
Et reprehenderit dicta sed dolorum assumenda est exercitationem provident id quas accusantium aut nobis libero. Aut consequatur minima sit veniam explicabo hic voluptas eveniet et vitae eaque. Vel adipisci dolores qui quas molestias vel dolor quasi ea odit quod ea officiis molestiae id fuga quis! Et laboriosam deleniti eum nulla aliquid ut enim fugiat et accusamus quaerat. Quo nostrum possimus qui animi temporibus et ipsam doloremque non totam voluptas! Eos nisi odit aut voluptatum itaque et nulla blanditiis est esse magni ut doloribus Quis. In culpa illum ad provident dolores aut nihil inventore aut consequatur vitae. In fugiat beatae qui quod corrupti quo itaque animi sit suscipit autem. Non nobis nisi et quia magnam qui modi ipsa et velit facere. Aut quia consequatur 33 magnam Quis aut molestiae earum. Ea autem obcaecati et voluptatum nulla qui distinctio iste in voluptatem expedita aut quasi omnis. Et distinctio fugit est voluptate maiores et consequatur neque et repellendus deleniti qui incidunt laudantium et autem quam et blanditiis eveniet. Cum iste consequatur vel voluptates reprehenderit et necessitatibus natus. Sed aliquam delectus id illum assumenda 33 dolor distinctio qui galisum minus.
|
||||
|
||||
Ut aperiam voluptas ad dolor omnis qui dolorem iure sed obcaecati dicta. Et temporibus consequuntur ut veniam alias qui quos quam ea distinctio iusto. Et totam voluptatem et officia omnis sit ipsam omnis. Et expedita itaque ea repellendus sunt ut ipsam ipsam et libero amet et ipsam numquam. Cum officiis enim eum odio veritatis nemo nemo ut quia corporis a modi pariatur. Id modi quae ex magni itaque aut quibusdam ipsam est dolorem facere. Et praesentium enim ea autem nostrum id necessitatibus quod aut rerum consequatur. Aut velit eaque eum omnis quia qui galisum corrupti est nesciunt dolores.
|
||||
|
||||
Qui molestiae cumque aut dolores rerum ut soluta recusandae ex autem repellat eum sunt magni. Ab tempore voluptas ex molestiae quam aut assumenda illo id nostrum neque est nisi veniam. Sit error iure ut nihil deleniti in harum iste hic explicabo labore aut ratione minima aut sapiente eaque sit maiores explicabo. Ea praesentium nostrum non dolor quia ut dolorem nesciunt. Sed iusto eaque nam quia itaque vel maxime fugit et perferendis dolor vel porro natus sit illo voluptas. Eum quasi aliquam ut iure galisum sit inventore repudiandae aut corporis illum. Ex consequuntur illo id odit reiciendis eum dolore unde sit ipsum tempore in sunt distinctio aut labore omnis. Qui distinctio eveniet et impedit velit sed quibusdam suscipit non quibusdam magnam sed similique quia? Est tenetur mollitia id eligendi libero 33 debitis sapiente. Est fuga quod aut corrupti aut mollitia eius. Sed recusandae quod eum cupiditate rerum sit dolor quod et quidem tempora in Quis natus qui velit maxime. Aut vero autem aut quae cupiditate aut inventore quam optio atque ut magni enim eos molestiae architecto. Qui expedita repudiandae ad modi fugiat sed molestiae quas. Et repellendus velit in voluptas harum ut reiciendis sunt a autem inventore id placeat odio est repellendus laborum.
|
||||
|
||||
Cum numquam explicabo sed assumenda earum et distinctio impedit? Et sint vitae vel eligendi deleniti eum atque est nostrum. Qui laborum adipisci cum dolores assumenda est debitis ipsum quo nemo mollitia qui consequatur pariatur non recusandae esse. Et delectus rerum ut atque illum est incidunt molestiae ut sapiente harum. Qui quia architecto et placeat molestiae et optio fugit et rerum quisquam. Non sapiente distinctio cum fugit possimus 33 cupiditate autem in minus eius aut quis dolorum cum tempora eius in totam pariatur. Ut eveniet dolorem id voluptas reprehenderit eum saepe voluptatibus id dolorem beatae est facilis maxime ut animi quasi. Aut natus itaque ad consequatur sunt ut dolores voluptates.
|
||||
|
||||
Qui rerum labore 33 dolorem quasi ea quia commodi hic quae deleniti in voluptatem laudantium sit dolor animi ea voluptatibus voluptas. Est maiores voluptatem est voluptatem recusandae et voluptatem deleniti sit error autem et error vitae aut debitis aliquid. Quo quam eligendi vel accusantium nemo ut atque alias et galisum voluptatum et ducimus voluptatibus a consequatur voluptate id quis repudiandae? Aut molestiae suscipit est necessitatibus reiciendis ut repellendus obcaecati est officiis omnis sit perspiciatis vero sit ullam voluptas et consequuntur velit. Vel ipsa enim eum quae veritatis qui consequatur quaerat quo suscipit galisum ut rerum tenetur aut recusandae dicta a porro voluptas. Ut minima internos in dolor accusantium vel unde odio cum aperiam dolorum ut perspiciatis nulla ad omnis voluptas sed dolores beatae. Impedit internos sed sapiente cupiditate ut cupiditate qui corrupti accusantium? Eum voluptas unde non exercitationem Quis non laborum illum.
|
||||
|
||||
Aut iusto quam ab officiis labore est voluptatem maxime. Et quaerat nostrum sit omnis velit non alias corporis rem nemo nihil. Hic quisquam repellendus id vitae voluptas eum quidem nihil in rerum fuga 33 tempora ducimus. Est laborum reprehenderit cum ipsa unde ad dolores praesentium est autem assumenda rem galisum itaque et cumque explicabo in rerum vero. Et Quis blanditiis vel impedit eligendi nam numquam sint. Non repudiandae libero aut neque explicabo hic suscipit reiciendis. Eum dolorem maiores id placeat culpa et error distinctio et cumque minus aut itaque quaerat sit velit quia eos laborum culpa. Non rerum obcaecati cum soluta deserunt non sunt modi sit dolores quia cum dicta nulla vel rerum adipisci. Sit incidunt nihil sed omnis beatae sit nemo labore. Sit impedit animi At fugit ducimus et enim rerum sed nisi quibusdam et soluta fugit eum rerum unde sed impedit incidunt? Ut nesciunt consequatur rem porro galisum et mollitia impedit aut quibusdam molestias ea error animi sed repellendus nihil.
|
||||
|
||||
Perferendis magnam id sapiente quos aut placeat optio At quia fugit sit quisquam vitae vel voluptas sunt ea molestias galisum. Non sequi necessitatibus eum voluptate accusamus qui nesciunt cumque a excepturi vero ea tempora voluptate et enim molestias ad nostrum Quis. Ea molestiae autem et voluptas libero rem fugit rerum ut animi suscipit et quisquam voluptatem non dolores doloremque eum unde alias? Et excepturi temporibus vel minima sint et asperiores tempora vel suscipit amet et galisum porro. Est dicta consequatur aut molestiae fuga ut animi dolores aut nesciunt officiis nam dolor ullam. Non laudantium placeat a dolorem accusamus ea temporibus pariatur vel aspernatur maxime id galisum consectetur est necessitatibus animi. Et voluptas facilis aut minima provident ex libero commodi et aspernatur voluptatem a odit aliquam! Vel tenetur iste qui beatae ducimus eos ipsa illum quo tenetur nemo. Placeat ipsum hic placeat cupiditate sed molestias praesentium eum inventore reprehenderit ea dolor recusandae est obcaecati temporibus et quaerat enim. Eos vitae odit a facilis laborum est voluptatem nisi qui deserunt optio id earum quam a vitae sint ea consectetur omnis. Est sunt alias ea distinctio blanditiis et beatae ipsam ut praesentium totam non eaque corporis non neque cupiditate aut aperiam commodi.
|
||||
|
||||
Ut nemo quia ea molestiae magnam et repellendus dicta 33 aperiam ullam. Vel ducimus velit est aliquid necessitatibus et sunt quia id dolore error in quisquam sed dolorem iure sed enim facere. Totam enim eos veniam voluptatem est enim dolorem vel praesentium debitis et quam recusandae aut atque exercitationem et cupiditate natus. Eos dolorum ratione ad architecto perferendis et neque dolores et quod assumenda qui voluptates consequuntur. A minus iste et quia sint et accusamus molestiae. Qui rerum natus ut consequuntur quod ut perspiciatis autem ut dicta voluptatem aut consequuntur amet? Quo possimus quae et commodi sunt et aspernatur ipsa? Sit commodi quia nam minus possimus id sint laboriosam.
|
||||
|
||||
In numquam atque non rerum nesciunt aut consequatur dolore ex ducimus neque quo voluptas excepturi ex similique exercitationem. Sed unde rerum ut vitae consequatur voluptates assumenda quo nihil corporis eos autem aperiam vel mollitia suscipit At quasi repudiandae. Et amet eius vel molestias autem ab veritatis consequatur ea saepe minus ut molestias necessitatibus est quia facere ut reprehenderit tempore. Est ullam itaque et explicabo omnis et quos beatae cum dolore deleniti. Sed temporibus recusandae et molestias delectus id temporibus sapiente id tenetur consequatur nam sint dolore eos consectetur saepe! Et libero animi quo libero sint id enim blanditiis aut fugiat quas et numquam impedit aut odio molestias. Vel optio temporibus ea accusantium quaerat ut itaque magnam ea inventore omnis. Et omnis nemo eos distinctio dolore rem aliquam sint At obcaecati doloribus qui internos sed perspiciatis ducimus et sunt dignissimos. Ut quidem ratione qui doloremque delectus in numquam reiciendis ut numquam nobis sed mollitia modi. Aut nesciunt quis et laudantium dolorum beatae repudiandae et tempora officia. Est unde amet cum dolor a rerum iusto et dolorem ipsum aut voluptatibus quia quo sunt consequatur aut molestiae aliquam?
|
||||
|
||||
Aut iste dolor eum doloremque consequuntur et voluptas galisum. In similique soluta aut ullam dolore eum itaque maiores. Id porro quibusdam eos debitis galisum ea fugiat provident est molestiae enim et veniam dicta est sequi consequatur. Qui mollitia impedit qui error illo aut optio aperiam ut voluptatum quaerat in nihil alias vel aliquid aperiam. Ea nisi quas ut quaerat voluptatum eos porro molestiae hic voluptas odit. Qui esse adipisci est velit ipsum rem alias velit eum dignissimos autem aut possimus ipsam. Et dolore facere nam voluptas enim hic mollitia fugit sit porro ducimus est necessitatibus dolorem? Eum quae nihil sit nulla possimus ut assumenda internos.
|
||||
|
||||
Aut autem facere et quis placeat et laborum excepturi aut necessitatibus galisum sit nemo quibusdam et rerum deleniti sit veritatis ipsum. Qui sequi necessitatibus sit quidem quia nam saepe velit quo mollitia impedit quo maxime dolorum in culpa eveniet et voluptas eveniet. Est autem soluta sed asperiores dolorum et sint corporis nam voluptas internos? Id velit fuga sed rerum nihil ut labore ratione et reiciendis dolorem non impedit sint eos fuga dignissimos ad nemo nihil. Non dolorem asperiores qui illum internos vel magnam quo dolores nostrum hic velit Quis qui sunt voluptatem quo quia quia. Et culpa rerum ut quisquam minus sit quibusdam dolor aut quia optio eum delectus iusto qui dicta sunt est molestias velit. Ut suscipit neque sit illum rerum aut quos adipisci et recusandae magni nam voluptatem sint eum galisum delectus. Est quia numquam hic omnis voluptatem rem sint galisum est adipisci ducimus non architecto asperiores.
|
||||
|
||||
Nam nesciunt repellendus et temporibus sunt ut adipisci id animi nisi. Ut cupiditate temporibus cum animi laudantium aut quisquam rerum sed nesciunt consequuntur aut internos corporis et voluptatem animi. Aut voluptatum error quo velit rerum quo voluptas sunt sit deleniti autem qui nesciunt labore est ducimus sequi. Eum molestiae blanditiis sit quia perferendis et vitae distinctio rem nostrum velit sit voluptate voluptatem. A nemo voluptatem et velit optio qui vero assumenda. In placeat delectus et commodi fugit non deserunt reprehenderit sed deserunt commodi a dolor quod et voluptatem ipsum. A consectetur quae est assumenda assumenda sit omnis ducimus et amet accusantium rem dolorem rerum id esse sunt et optio accusamus! Ut autem alias a officiis quidem vel eligendi autem non temporibus quae et molestiae assumenda! Ex iusto maxime qui autem eius sit nemo aliquam ab alias rerum quo omnis eius ut soluta iusto. Et libero doloribus non odit ipsum cum voluptatum obcaecati sit asperiores nulla ut quos labore. Et laudantium quis aut fuga laborum in dolor magnam.
|
||||
|
||||
Vel rerum nisi cum quidem suscipit hic blanditiis dolore ea consectetur ipsa aut fugiat accusantium aut modi ipsa. Qui laudantium nobis qui aliquid asperiores qui dolores rerum qui numquam maxime. Est sunt officia et incidunt corrupti qui quisquam repudiandae non voluptatum nisi eum voluptatem tempora est doloribus quisquam sit nemo tenetur! Ad dignissimos dicta aut necessitatibus quia ut eligendi recusandae. Est obcaecati sunt qui dolor rerum sit obcaecati internos non dolorem repudiandae est quibusdam consequatur qui ipsa enim? Et voluptates aliquam aut eligendi unde non nihil accusamus. Qui molestiae quisquam non autem quia et consectetur laudantium vel temporibus amet cum laboriosam excepturi ut sunt galisum? Aut quibusdam sed dolorem maxime qui deleniti maiores aut corporis voluptatem qui alias cumque est magni neque? In ullam fuga et minus laboriosam et cumque omnis cum dignissimos accusamus. In inventore accusamus et mollitia iure eum consequatur nesciunt? Est quidem similique et eaque autem rem illum aperiam ea eligendi saepe et laudantium molestias eum totam totam et error praesentium. Non rerum voluptatibus et expedita natus sed consequatur doloremque qui fugiat atque aut nesciunt molestiae ea voluptatem molestias. Ea suscipit dolores aut neque autem rem adipisci officiis qui cumque iusto sit odit omnis. Cum sequi dolore aut quos saepe cum voluptas esse At autem ratione a iure modi et numquam commodi est odio suscipit.
|
||||
|
||||
Quo nisi minima vel magnam animi et quis ipsa et molestiae ipsum At inventore ipsam vel optio nisi et eveniet quos. Et alias numquam a quae iure qui perspiciatis repellendus et velit consequatur et fugiat sunt eos minus ratione At iste rerum. Eum quia ratione ut suscipit enim quo voluptatem enim quasi fugiat ut nesciunt perspiciatis est consequatur perferendis error officiis. Hic iste ducimus et tempora iure qui error blanditiis est aliquid accusantium ut dignissimos doloribus ea quia magnam non fugit quod. At illo aspernatur sed aliquid omnis sed quaerat voluptatem eum sunt dignissimos et ullam sunt rem dolorem expedita. Et laborum sint aut nisi voluptas ut molestias laborum. Quo illum expedita quo unde obcaecati sit itaque ratione ea labore labore vel ratione voluptatem et delectus autem cum ipsa repellat? Vel velit dolorum ea distinctio distinctio nam illo dolorem vel nobis velit. Ea obcaecati assumenda et explicabo sapiente ea maiores assumenda qui reiciendis temporibus sed voluptatem odit. Eos optio itaque non quos deleniti ad galisum galisum qui omnis fugit libero dolores. Ad autem voluptates eos totam facilis et atque minima et blanditiis exercitationem id consectetur doloribus. Et rerum reiciendis non omnis voluptatem ad totam internos sit modi consequatur ut quia voluptatem ut eaque dolor. Nam fugit deleniti et ullam consequatur et esse vero id debitis tempore. Rem assumenda harum et iusto blanditiis At repellendus ipsum ea autem sapiente.
|
||||
|
@ -0,0 +1,120 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtTest/QTest>
|
||||
|
||||
#include <QStringTokenizer>
|
||||
|
||||
class tst_QStringTokenizer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
void tokenize_data() const;
|
||||
template <typename T, typename U>
|
||||
void tokenize() const;
|
||||
private slots:
|
||||
void tokenize_qlatin1string_qlatin1string_data() const { tokenize_data(); }
|
||||
void tokenize_qlatin1string_qlatin1string() const { tokenize<QLatin1String, QLatin1String>(); }
|
||||
void tokenize_qstring_qstring_data() const { tokenize_data(); }
|
||||
void tokenize_qstring_qstring() const { tokenize<QString, QString>(); }
|
||||
void tokenize_qlatin1string_qstring_data() const { tokenize_data(); }
|
||||
void tokenize_qlatin1string_qstring() const { tokenize<QLatin1String, QString>(); }
|
||||
void tokenize_qstring_qlatin1string_data() const { tokenize_data(); }
|
||||
void tokenize_qstring_qlatin1string() const { tokenize<QString, QLatin1String>(); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T fromByteArray(QByteArrayView v);
|
||||
|
||||
template<>
|
||||
QString fromByteArray<QString>(QByteArrayView v)
|
||||
{
|
||||
return QString::fromLatin1(v);
|
||||
}
|
||||
|
||||
template<>
|
||||
QLatin1String fromByteArray<QLatin1String>(QByteArrayView v)
|
||||
{
|
||||
return QLatin1String(v.data(), v.size());
|
||||
}
|
||||
|
||||
void tst_QStringTokenizer::tokenize_data() const
|
||||
{
|
||||
QTest::addColumn<QByteArray>("input");
|
||||
QTest::addColumn<QByteArray>("separator");
|
||||
QTest::addColumn<bool>("caseSensitive");
|
||||
QTest::addColumn<int>("expectedCount");
|
||||
|
||||
QByteArray shortSentence = "A seriously short sentence.";
|
||||
QTest::addRow("short-sentence-spaces") << shortSentence << QByteArray(" ") << true << 4;
|
||||
QTest::addRow("short-sentence-spaces-case-insensitive")
|
||||
<< shortSentence << QByteArray(" ") << false << 4;
|
||||
|
||||
QTest::addRow("short-sentence-se") << shortSentence << QByteArray("se") << true << 3;
|
||||
QTest::addRow("short-sentence-se-case-insensitive")
|
||||
<< shortSentence << QByteArray("Se") << false << 3;
|
||||
|
||||
QFile file(":/data/lorem.txt");
|
||||
if (!file.open(QFile::ReadOnly))
|
||||
qFatal("Can't open lorem.txt");
|
||||
|
||||
const QByteArray content = file.readAll();
|
||||
QTest::addRow("lorem-ipsum-spaces") << content << QByteArray(" ") << true << 3250;
|
||||
QTest::addRow("lorem-ipsum-spaces-case-insensitive")
|
||||
<< content << QByteArray(" ") << false << 3250;
|
||||
|
||||
QTest::addRow("lorem-ipsum-l") << content << QByteArray("l") << true << 771;
|
||||
QTest::addRow("lorem-ipsum-l-case-insensitive")
|
||||
<< content << QByteArray("l") << false << 772;
|
||||
|
||||
QTest::addRow("lorem-ipsum-lo") << content << QByteArray("lo") << true << 130;
|
||||
QTest::addRow("lorem-ipsum-lo-case-insensitive")
|
||||
<< content << QByteArray("lo") << false << 131;
|
||||
|
||||
QTest::addRow("lorem-ipsum-lor") << content << QByteArray("lor") << true << 122;
|
||||
QTest::addRow("lorem-ipsum-lor-case-insensitive")
|
||||
<< content << QByteArray("lor") << false << 123;
|
||||
|
||||
QTest::addRow("lorem-ipsum-lore") << content << QByteArray("lore") << true << 73;
|
||||
QTest::addRow("lorem-ipsum-lore-case-insensitive")
|
||||
<< content << QByteArray("lore") << false << 74;
|
||||
|
||||
QTest::addRow("lorem-ipsum-lorem") << content << QByteArray("lorem") << true << 34;
|
||||
QTest::addRow("lorem-ipsum-lorem-case-insensitive")
|
||||
<< content << QByteArray("lorem") << false << 35;
|
||||
|
||||
QTest::addRow("lorem-ipsum-lorem i") << content << QByteArray("lorem i") << true << 5;
|
||||
QTest::addRow("lorem-ipsum-lorem i-case-insensitive")
|
||||
<< content << QByteArray("lorem i") << false << 6;
|
||||
|
||||
QTest::addRow("lorem-ipsum-et explicabo s") << content << QByteArray("et explicabo s") << true << 3;
|
||||
QTest::addRow("lorem-ipsum-et explicabo s-case-insensitive")
|
||||
<< content << QByteArray("et explicabo s") << false << 3;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
void tst_QStringTokenizer::tokenize() const
|
||||
{
|
||||
QFETCH(QByteArray, input);
|
||||
QFETCH(QByteArray, separator);
|
||||
QFETCH(bool, caseSensitive);
|
||||
QFETCH(int, expectedCount);
|
||||
|
||||
T haystack = fromByteArray<T>(input);
|
||||
U needle = fromByteArray<U>(separator);
|
||||
|
||||
const Qt::CaseSensitivity sensitivity = caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||
QBENCHMARK {
|
||||
QStringTokenizer tok(haystack, needle, sensitivity);
|
||||
qsizetype count = 0;
|
||||
for (auto res : tok) {
|
||||
count++;
|
||||
Q_UNUSED(res);
|
||||
}
|
||||
QCOMPARE(count, expectedCount);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QStringTokenizer)
|
||||
|
||||
#include "tst_bench_qstringtokenizer.moc"
|
14
tests/benchmarks/corelib/text/qutf8stringview/CMakeLists.txt
Normal file
14
tests/benchmarks/corelib/text/qutf8stringview/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qutf8stringview Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qutf8stringview
|
||||
SOURCES
|
||||
tst_bench_qutf8stringview.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
Qt::CorePrivate
|
||||
)
|
@ -0,0 +1,263 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <qbytearray.h>
|
||||
#include <qdebug.h>
|
||||
#include <qstring.h>
|
||||
#include <qtest.h>
|
||||
#include <qutf8stringview.h>
|
||||
|
||||
class tst_QUtf8StringView : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void equalStringsLatin1_data() { equalStrings_data(); }
|
||||
void equalStringsLatin1();
|
||||
void equalStringsUtf16_data() { equalStrings_data(); }
|
||||
void equalStringsUtf16();
|
||||
void equalStringsUtf8_data() { equalStrings_data(); }
|
||||
void equalStringsUtf8();
|
||||
|
||||
void compareStringsCaseSensitiveLatin1_data() { compareStringsCaseSensitive_data(); }
|
||||
void compareStringsCaseSensitiveLatin1() { compareStringsLatin1(true); }
|
||||
void compareStringsCaseSensitiveUtf16_data() { compareStringsCaseSensitive_data(); }
|
||||
void compareStringsCaseSensitiveUtf16() { compareStringsUtf16(true); }
|
||||
void compareStringsCaseSensitiveUtf8_data() { compareStringsCaseSensitive_data(); }
|
||||
void compareStringsCaseSensitiveUtf8() { compareStringsUtf8(true); }
|
||||
|
||||
void compareStringsCaseInsensitiveLatin1_data() { compareStringsCaseInsensitive_data(); }
|
||||
void compareStringsCaseInsensitiveLatin1() { compareStringsLatin1(false); }
|
||||
void compareStringsCaseInsensitiveUtf16_data() { compareStringsCaseInsensitive_data(); }
|
||||
void compareStringsCaseInsensitiveUtf16() { compareStringsUtf16(false); }
|
||||
void compareStringsCaseInsensitiveUtf8_data() { compareStringsCaseInsensitive_data(); }
|
||||
void compareStringsCaseInsensitiveUtf8() { compareStringsUtf8(false); }
|
||||
|
||||
void compareStringsWithErrors_data();
|
||||
void compareStringsWithErrors();
|
||||
|
||||
private:
|
||||
void equalStrings_data();
|
||||
void compareStringsCaseSensitive_data();
|
||||
void compareStringsCaseInsensitive_data();
|
||||
void compareStringsLatin1(bool caseSensitive);
|
||||
void compareStringsUtf16(bool caseSensitive);
|
||||
void compareStringsUtf8(bool caseSensitive);
|
||||
};
|
||||
|
||||
void tst_QUtf8StringView::equalStrings_data()
|
||||
{
|
||||
QTest::addColumn<QString>("lhs");
|
||||
QTest::addColumn<QString>("rhs");
|
||||
QTest::addColumn<bool>("isEqual");
|
||||
|
||||
QTest::newRow("EqualStrings") << "Test"
|
||||
<< "Test" << true;
|
||||
QTest::newRow("EqualStringsLong")
|
||||
<< "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
<< "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" << true;
|
||||
QTest::newRow("DifferentCase") << "test"
|
||||
<< "Test" << false;
|
||||
QTest::newRow("DifferentCaseLong")
|
||||
<< "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
<< "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" << false;
|
||||
QTest::newRow("ReverseStrings") << "Test"
|
||||
<< "tseT" << false;
|
||||
QTest::newRow("Latin1RangeCharacter") << u8"B\u00d8" << u8"B\u00d8" << true;
|
||||
QTest::newRow("Latin1RangeCharacterDifferentCase") << u8"B\u00d8" << u8"B\u00f8" << false;
|
||||
}
|
||||
|
||||
void tst_QUtf8StringView::equalStringsLatin1()
|
||||
{
|
||||
QFETCH(QString, lhs);
|
||||
QFETCH(QString, rhs);
|
||||
QFETCH(bool, isEqual);
|
||||
QByteArray left = lhs.toUtf8();
|
||||
QByteArray right = rhs.toLatin1();
|
||||
QBasicUtf8StringView<false> lhv(left);
|
||||
QLatin1StringView rhv(right);
|
||||
bool result;
|
||||
|
||||
QBENCHMARK {
|
||||
result = QtPrivate::equalStrings(lhv, rhv);
|
||||
};
|
||||
QCOMPARE(result, isEqual);
|
||||
}
|
||||
|
||||
void tst_QUtf8StringView::equalStringsUtf16()
|
||||
{
|
||||
QFETCH(QString, lhs);
|
||||
QFETCH(QString, rhs);
|
||||
QFETCH(bool, isEqual);
|
||||
|
||||
QByteArray left = lhs.toUtf8();
|
||||
QBasicUtf8StringView<false> lhv(left);
|
||||
QStringView rhv(rhs);
|
||||
bool result;
|
||||
|
||||
QBENCHMARK {
|
||||
result = QtPrivate::equalStrings(lhv, rhv);
|
||||
};
|
||||
QCOMPARE(result, isEqual);
|
||||
}
|
||||
|
||||
void tst_QUtf8StringView::equalStringsUtf8()
|
||||
{
|
||||
QFETCH(QString, lhs);
|
||||
QFETCH(QString, rhs);
|
||||
QFETCH(bool, isEqual);
|
||||
|
||||
QByteArray left = lhs.toUtf8();
|
||||
QByteArray right = rhs.toUtf8();
|
||||
QBasicUtf8StringView<false> lhv(left);
|
||||
QBasicUtf8StringView<false> rhv(right);
|
||||
bool result;
|
||||
|
||||
QBENCHMARK {
|
||||
result = QtPrivate::equalStrings(lhv, rhv);
|
||||
};
|
||||
QCOMPARE(result, isEqual);
|
||||
}
|
||||
|
||||
void tst_QUtf8StringView::compareStringsCaseSensitive_data()
|
||||
{
|
||||
QTest::addColumn<QString>("lhs");
|
||||
QTest::addColumn<QString>("rhs");
|
||||
QTest::addColumn<int>("compareValue");
|
||||
|
||||
QTest::newRow("EqualStrings") << "Test"
|
||||
<< "Test" << 0;
|
||||
QTest::newRow("EqualStringsLong") << "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ"
|
||||
<< "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ" << 0;
|
||||
QTest::newRow("DifferentCase") << "test"
|
||||
<< "Test" << 32;
|
||||
QTest::newRow("DifferentCaseLong")
|
||||
<< "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ"
|
||||
<< "abcdefghijklmnopqrstuvxyzabcdefghijklmnopqrstuvxyz" << -32;
|
||||
QTest::newRow("ReverseStrings") << "Test"
|
||||
<< "tseT" << -32;
|
||||
QTest::newRow("Different Strings") << "Testing and testing"
|
||||
<< "Testing and resting" << 2;
|
||||
QTest::newRow("Latin1RangeCharacter") << u8"B\u00d8" << u8"B\u00d8" << 0;
|
||||
QTest::newRow("Latin1RangeCharacterDifferentCase") << u8"B\u00d8" << u8"B\u00f8" << -32;
|
||||
}
|
||||
|
||||
void tst_QUtf8StringView::compareStringsCaseInsensitive_data()
|
||||
{
|
||||
QTest::addColumn<QString>("lhs");
|
||||
QTest::addColumn<QString>("rhs");
|
||||
QTest::addColumn<int>("compareValue");
|
||||
|
||||
QTest::newRow("EqualStrings") << "Test"
|
||||
<< "Test" << 0;
|
||||
QTest::newRow("EqualStringsLong") << "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ"
|
||||
<< "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ" << 0;
|
||||
QTest::newRow("DifferentCase") << "test"
|
||||
<< "Test" << 0;
|
||||
QTest::newRow("DifferentCaseLong") << "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ"
|
||||
<< "abcdefghijklmnopqrstuvxyzabcdefghijklmnopqrstuvxyz" << 0;
|
||||
QTest::newRow("ReverseStrings") << "Test"
|
||||
<< "tseT" << -14;
|
||||
QTest::newRow("Different Strings") << "Testing and testing"
|
||||
<< "Testing and resting" << 2;
|
||||
QTest::newRow("Latin1RangeCharacter") << u8"B\u00d8" << u8"B\u00d8" << 0;
|
||||
QTest::newRow("Latin1RangeCharacterDifferentCase") << u8"B\u00d8" << u8"B\u00f8" << 0;
|
||||
}
|
||||
|
||||
void tst_QUtf8StringView::compareStringsLatin1(bool caseSensitive)
|
||||
{
|
||||
QFETCH(QString, lhs);
|
||||
QFETCH(QString, rhs);
|
||||
QFETCH(int, compareValue);
|
||||
QByteArray left = lhs.toUtf8();
|
||||
QByteArray right = rhs.toLatin1();
|
||||
QBasicUtf8StringView<false> lhv(left);
|
||||
QLatin1StringView rhv(right);
|
||||
Qt::CaseSensitivity cs = caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||
int result;
|
||||
|
||||
QBENCHMARK {
|
||||
result = lhv.compare(rhv, cs);
|
||||
};
|
||||
QCOMPARE(result, compareValue);
|
||||
}
|
||||
|
||||
void tst_QUtf8StringView::compareStringsUtf16(bool caseSensitive)
|
||||
{
|
||||
QFETCH(QString, lhs);
|
||||
QFETCH(QString, rhs);
|
||||
QFETCH(int, compareValue);
|
||||
|
||||
QByteArray left = lhs.toUtf8();
|
||||
QBasicUtf8StringView<false> lhv(left);
|
||||
QStringView rhv(rhs);
|
||||
Qt::CaseSensitivity cs = caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||
int result;
|
||||
|
||||
QBENCHMARK {
|
||||
result = lhv.compare(rhv, cs);
|
||||
};
|
||||
QCOMPARE(result, compareValue);
|
||||
}
|
||||
|
||||
void tst_QUtf8StringView::compareStringsUtf8(bool caseSensitive)
|
||||
{
|
||||
QFETCH(QString, lhs);
|
||||
QFETCH(QString, rhs);
|
||||
QFETCH(int, compareValue);
|
||||
|
||||
QByteArray left = lhs.toUtf8();
|
||||
QByteArray right = rhs.toUtf8();
|
||||
QBasicUtf8StringView<false> lhv(left);
|
||||
QBasicUtf8StringView<false> rhv(right);
|
||||
Qt::CaseSensitivity cs = caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||
int result;
|
||||
|
||||
QBENCHMARK {
|
||||
result = lhv.compare(rhv, cs);
|
||||
};
|
||||
QCOMPARE(result, compareValue);
|
||||
}
|
||||
|
||||
void tst_QUtf8StringView::compareStringsWithErrors_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("lhs");
|
||||
QTest::addColumn<QByteArray>("rhs");
|
||||
QTest::addColumn<int>("compare");
|
||||
QTest::addColumn<bool>("caseSensitive");
|
||||
|
||||
QTest::newRow("Compare errors 0xfe vs 0xff case-insensitive")
|
||||
<< QByteArray("\xfe") << QByteArray("\xff") << 0 << false;
|
||||
QTest::newRow("Compare errors 0xff vs 0xff case-insensitive")
|
||||
<< QByteArray("\xff") << QByteArray("\xff") << 0 << false;
|
||||
QTest::newRow("Compare 'a' with error 0xff case-insensitive")
|
||||
<< QByteArray("a") << QByteArray("\xff") << -65436 << false;
|
||||
QTest::newRow("Compare errors 0xfe vs 0xff case-sensitive")
|
||||
<< QByteArray("\xfe") << QByteArray("\xff") << -1 << true;
|
||||
QTest::newRow("Compare errors 0xff vs 0xff case-sensitive")
|
||||
<< QByteArray("\xff") << QByteArray("\xff") << 0 << true;
|
||||
QTest::newRow("Compare 'a' with error 0xff case-sensitive")
|
||||
<< QByteArray("a") << QByteArray("\xff") << -158 << true;
|
||||
}
|
||||
|
||||
void tst_QUtf8StringView::compareStringsWithErrors()
|
||||
{
|
||||
QFETCH(QByteArray, lhs);
|
||||
QFETCH(QByteArray, rhs);
|
||||
QFETCH(int, compare);
|
||||
QFETCH(bool, caseSensitive);
|
||||
QBasicUtf8StringView<false> lhv(lhs);
|
||||
QBasicUtf8StringView<false> rhv(rhs);
|
||||
Qt::CaseSensitivity cs = caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||
int result;
|
||||
|
||||
QBENCHMARK {
|
||||
result = lhv.compare(rhv, cs);
|
||||
};
|
||||
QCOMPARE(result, compare);
|
||||
QCOMPARE(-result, rhv.compare(lhv, cs));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QUtf8StringView)
|
||||
|
||||
#include "tst_bench_qutf8stringview.moc"
|
9
tests/benchmarks/corelib/thread/CMakeLists.txt
Normal file
9
tests/benchmarks/corelib/thread/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(qfuture)
|
||||
add_subdirectory(qmutex)
|
||||
add_subdirectory(qreadwritelock)
|
||||
add_subdirectory(qthreadstorage)
|
||||
add_subdirectory(qthreadpool)
|
||||
add_subdirectory(qwaitcondition)
|
14
tests/benchmarks/corelib/thread/qfuture/CMakeLists.txt
Normal file
14
tests/benchmarks/corelib/thread/qfuture/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qfuture Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qfuture
|
||||
EXCEPTIONS
|
||||
SOURCES
|
||||
tst_bench_qfuture.cpp
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
297
tests/benchmarks/corelib/thread/qfuture/tst_bench_qfuture.cpp
Normal file
297
tests/benchmarks/corelib/thread/qfuture/tst_bench_qfuture.cpp
Normal file
@ -0,0 +1,297 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include <qexception.h>
|
||||
#include <qfuture.h>
|
||||
#include <qpromise.h>
|
||||
#include <qsemaphore.h>
|
||||
|
||||
class tst_QFuture : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void makeReadyfuture();
|
||||
#ifndef QT_NO_EXCEPTIONS
|
||||
void makeExceptionalFuture();
|
||||
#endif
|
||||
void result();
|
||||
void results();
|
||||
void takeResult();
|
||||
void reportResult();
|
||||
void reportResults();
|
||||
void reportResultsManualProgress();
|
||||
#ifndef QT_NO_EXCEPTIONS
|
||||
void reportException();
|
||||
#endif
|
||||
void then();
|
||||
void thenVoid();
|
||||
void onCanceled();
|
||||
void onCanceledVoid();
|
||||
#ifndef QT_NO_EXCEPTIONS
|
||||
void onFailed();
|
||||
void onFailedVoid();
|
||||
void thenOnFailed();
|
||||
void thenOnFailedVoid();
|
||||
#endif
|
||||
void reportProgress();
|
||||
void progressMinimum();
|
||||
void progressMaximum();
|
||||
void progressValue();
|
||||
void progressText();
|
||||
};
|
||||
|
||||
void tst_QFuture::makeReadyfuture()
|
||||
{
|
||||
QBENCHMARK {
|
||||
auto future = QtFuture::makeReadyFuture(42);
|
||||
Q_UNUSED(future);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef QT_NO_EXCEPTIONS
|
||||
void tst_QFuture::makeExceptionalFuture()
|
||||
{
|
||||
QException e;
|
||||
QBENCHMARK {
|
||||
auto future = QtFuture::makeExceptionalFuture(e);
|
||||
Q_UNUSED(future);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void tst_QFuture::result()
|
||||
{
|
||||
auto future = QtFuture::makeReadyFuture(42);
|
||||
|
||||
QBENCHMARK {
|
||||
auto value = future.result();
|
||||
Q_UNUSED(value);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::results()
|
||||
{
|
||||
QFutureInterface<int> fi;
|
||||
fi.reportStarted();
|
||||
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
fi.reportResult(i);
|
||||
|
||||
fi.reportFinished();
|
||||
|
||||
auto future = fi.future();
|
||||
QBENCHMARK {
|
||||
auto values = future.results();
|
||||
Q_UNUSED(values);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::takeResult()
|
||||
{
|
||||
QBENCHMARK {
|
||||
auto future = QtFuture::makeReadyFuture(42);
|
||||
auto value = future.takeResult();
|
||||
Q_UNUSED(value);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::reportResult()
|
||||
{
|
||||
QFutureInterface<int> fi;
|
||||
QBENCHMARK {
|
||||
fi.reportResult(42);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::reportResults()
|
||||
{
|
||||
QFutureInterface<int> fi;
|
||||
QList<int> values(1000);
|
||||
std::iota(values.begin(), values.end(), 0);
|
||||
QBENCHMARK {
|
||||
fi.reportResults(values);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::reportResultsManualProgress()
|
||||
{
|
||||
QFutureInterface<int> fi;
|
||||
const int resultCount = 1000;
|
||||
fi.setProgressRange(0, resultCount);
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < resultCount; ++i)
|
||||
fi.reportResult(i);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef QT_NO_EXCEPTIONS
|
||||
void tst_QFuture::reportException()
|
||||
{
|
||||
QException e;
|
||||
QBENCHMARK {
|
||||
QFutureInterface<int> fi;
|
||||
fi.reportException(e);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void tst_QFuture::then()
|
||||
{
|
||||
auto f = QtFuture::makeReadyFuture(42);
|
||||
QBENCHMARK {
|
||||
auto future = f.then([](int value) { return value; });
|
||||
Q_UNUSED(future);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::thenVoid()
|
||||
{
|
||||
auto f = QtFuture::makeReadyFuture();
|
||||
QBENCHMARK {
|
||||
auto future = f.then([] {});
|
||||
Q_UNUSED(future);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::onCanceled()
|
||||
{
|
||||
QFutureInterface<int> fi;
|
||||
fi.reportStarted();
|
||||
fi.reportCanceled();
|
||||
fi.reportFinished();
|
||||
|
||||
QBENCHMARK {
|
||||
auto future = fi.future().onCanceled([] { return 0; });
|
||||
Q_UNUSED(future);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::onCanceledVoid()
|
||||
{
|
||||
QFutureInterface<void> fi;
|
||||
fi.reportStarted();
|
||||
fi.reportCanceled();
|
||||
fi.reportFinished();
|
||||
|
||||
QBENCHMARK {
|
||||
auto future = fi.future().onCanceled([] {});
|
||||
Q_UNUSED(future);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef QT_NO_EXCEPTIONS
|
||||
void tst_QFuture::onFailed()
|
||||
{
|
||||
QException e;
|
||||
auto f = QtFuture::makeExceptionalFuture<int>(e);
|
||||
QBENCHMARK {
|
||||
auto future = f.onFailed([] { return 0; });
|
||||
Q_UNUSED(future);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::onFailedVoid()
|
||||
{
|
||||
QException e;
|
||||
auto f = QtFuture::makeExceptionalFuture(e);
|
||||
QBENCHMARK {
|
||||
auto future = f.onFailed([] {});
|
||||
Q_UNUSED(future);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::thenOnFailed()
|
||||
{
|
||||
auto f = QtFuture::makeReadyFuture(42);
|
||||
QBENCHMARK {
|
||||
auto future =
|
||||
f.then([](int) { throw std::runtime_error("error"); }).onFailed([] { return 0; });
|
||||
Q_UNUSED(future);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::thenOnFailedVoid()
|
||||
{
|
||||
auto f = QtFuture::makeReadyFuture();
|
||||
QBENCHMARK {
|
||||
auto future = f.then([] { throw std::runtime_error("error"); }).onFailed([] {});
|
||||
Q_UNUSED(future);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void tst_QFuture::reportProgress()
|
||||
{
|
||||
QFutureInterface<void> fi;
|
||||
fi.reportStarted();
|
||||
fi.reportFinished();
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
fi.setProgressValue(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::progressMinimum()
|
||||
{
|
||||
QFutureInterface<void> fi;
|
||||
fi.setProgressRange(0, 100);
|
||||
fi.reportStarted();
|
||||
fi.reportFinished();
|
||||
auto future = fi.future();
|
||||
|
||||
QBENCHMARK {
|
||||
auto value = future.progressMinimum();
|
||||
Q_UNUSED(value);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::progressMaximum()
|
||||
{
|
||||
QFutureInterface<void> fi;
|
||||
fi.setProgressRange(0, 100);
|
||||
fi.reportStarted();
|
||||
fi.reportFinished();
|
||||
auto future = fi.future();
|
||||
|
||||
QBENCHMARK {
|
||||
auto value = future.progressMaximum();
|
||||
Q_UNUSED(value);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::progressValue()
|
||||
{
|
||||
QFutureInterface<void> fi;
|
||||
fi.setProgressValue(50);
|
||||
fi.reportStarted();
|
||||
fi.reportFinished();
|
||||
auto future = fi.future();
|
||||
|
||||
QBENCHMARK {
|
||||
auto value = future.progressValue();
|
||||
Q_UNUSED(value);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QFuture::progressText()
|
||||
{
|
||||
QFutureInterface<void> fi;
|
||||
fi.setProgressValueAndText(50, "text");
|
||||
fi.reportStarted();
|
||||
fi.reportFinished();
|
||||
auto future = fi.future();
|
||||
|
||||
QBENCHMARK {
|
||||
auto text = future.progressText();
|
||||
Q_UNUSED(text);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QFuture)
|
||||
|
||||
#include "tst_bench_qfuture.moc"
|
14
tests/benchmarks/corelib/thread/qmutex/CMakeLists.txt
Normal file
14
tests/benchmarks/corelib/thread/qmutex/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qmutex Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qmutex
|
||||
SOURCES
|
||||
tst_bench_qmutex.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Test
|
||||
)
|
428
tests/benchmarks/corelib/thread/qmutex/tst_bench_qmutex.cpp
Normal file
428
tests/benchmarks/corelib/thread/qmutex/tst_bench_qmutex.cpp
Normal file
@ -0,0 +1,428 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtCore/QtCore>
|
||||
#include <QTest>
|
||||
#include <QtCore/private/qvolatile_p.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
//#define USE_SEM_T
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
#if !defined(USE_SEM_T)
|
||||
# include <pthread.h>
|
||||
# include <errno.h>
|
||||
typedef pthread_mutex_t NativeMutexType;
|
||||
void NativeMutexInitialize(NativeMutexType *mutex)
|
||||
{
|
||||
pthread_mutex_init(mutex, NULL);
|
||||
}
|
||||
void NativeMutexDestroy(NativeMutexType *mutex)
|
||||
{
|
||||
pthread_mutex_destroy(mutex);
|
||||
}
|
||||
void NativeMutexLock(NativeMutexType *mutex)
|
||||
{
|
||||
pthread_mutex_lock(mutex);
|
||||
}
|
||||
void NativeMutexUnlock(NativeMutexType *mutex)
|
||||
{
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
#else
|
||||
# include <semaphore.h>
|
||||
typedef sem_t NativeMutexType;
|
||||
void NativeMutexInitialize(NativeMutexType *mutex)
|
||||
{
|
||||
sem_init(mutex, false, 1);
|
||||
}
|
||||
void NativeMutexDestroy(NativeMutexType *mutex)
|
||||
{
|
||||
sem_destroy(mutex);
|
||||
}
|
||||
void NativeMutexLock(NativeMutexType *mutex)
|
||||
{
|
||||
sem_wait(mutex);
|
||||
}
|
||||
void NativeMutexUnlock(NativeMutexType *mutex)
|
||||
{
|
||||
sem_post(mutex);
|
||||
}
|
||||
#endif
|
||||
#elif defined(Q_OS_WIN)
|
||||
# include <qt_windows.h>
|
||||
typedef CRITICAL_SECTION NativeMutexType;
|
||||
void NativeMutexInitialize(NativeMutexType *mutex)
|
||||
{
|
||||
InitializeCriticalSection(mutex);
|
||||
}
|
||||
void NativeMutexDestroy(NativeMutexType *mutex)
|
||||
{
|
||||
DeleteCriticalSection(mutex);
|
||||
}
|
||||
void NativeMutexLock(NativeMutexType *mutex)
|
||||
{
|
||||
EnterCriticalSection(mutex);
|
||||
}
|
||||
void NativeMutexUnlock(NativeMutexType *mutex)
|
||||
{
|
||||
LeaveCriticalSection(mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
class tst_QMutex : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
int threadCount;
|
||||
|
||||
public:
|
||||
// barriers for the contended tests
|
||||
static QSemaphore semaphore1, semaphore2, semaphore3, semaphore4;
|
||||
|
||||
tst_QMutex()
|
||||
{
|
||||
// at least 2 threads, even on single cpu/core machines
|
||||
threadCount = qMax(2, QThread::idealThreadCount());
|
||||
qDebug("thread count: %d", threadCount);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void noThread_data();
|
||||
void noThread();
|
||||
|
||||
void constructionNative();
|
||||
void uncontendedNative();
|
||||
void constructionQMutex();
|
||||
void uncontendedQMutex();
|
||||
void uncontendedQMutexLocker();
|
||||
|
||||
void contendedNative_data();
|
||||
void contendedQMutex_data() { contendedNative_data(); }
|
||||
void contendedQMutexLocker_data() { contendedNative_data(); }
|
||||
|
||||
void contendedNative();
|
||||
void contendedQMutex();
|
||||
void contendedQMutexLocker();
|
||||
};
|
||||
|
||||
QSemaphore tst_QMutex::semaphore1;
|
||||
QSemaphore tst_QMutex::semaphore2;
|
||||
QSemaphore tst_QMutex::semaphore3;
|
||||
QSemaphore tst_QMutex::semaphore4;
|
||||
|
||||
void tst_QMutex::noThread_data()
|
||||
{
|
||||
QTest::addColumn<int>("t");
|
||||
|
||||
QTest::newRow("noLock") << 1;
|
||||
QTest::newRow("QMutex") << 3;
|
||||
QTest::newRow("QMutexLocker") << 4;
|
||||
}
|
||||
|
||||
void tst_QMutex::noThread()
|
||||
{
|
||||
volatile int count = 0;
|
||||
const int N = 5000000;
|
||||
QMutex mtx;
|
||||
|
||||
QFETCH(int, t);
|
||||
switch(t) {
|
||||
case 1:
|
||||
QBENCHMARK {
|
||||
count = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
QtPrivate::volatilePreIncrement(count);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
QBENCHMARK {
|
||||
count = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
mtx.lock();
|
||||
QtPrivate::volatilePreIncrement(count);
|
||||
mtx.unlock();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
QBENCHMARK {
|
||||
count = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
QMutexLocker locker(&mtx);
|
||||
QtPrivate::volatilePreIncrement(count);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
QCOMPARE(int(count), N);
|
||||
}
|
||||
|
||||
void tst_QMutex::constructionNative()
|
||||
{
|
||||
QBENCHMARK {
|
||||
NativeMutexType mutex;
|
||||
NativeMutexInitialize(&mutex);
|
||||
NativeMutexDestroy(&mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMutex::uncontendedNative()
|
||||
{
|
||||
NativeMutexType mutex;
|
||||
NativeMutexInitialize(&mutex);
|
||||
QBENCHMARK {
|
||||
NativeMutexLock(&mutex);
|
||||
NativeMutexUnlock(&mutex);
|
||||
}
|
||||
NativeMutexDestroy(&mutex);
|
||||
}
|
||||
|
||||
void tst_QMutex::constructionQMutex()
|
||||
{
|
||||
QBENCHMARK {
|
||||
QMutex mutex;
|
||||
Q_UNUSED(mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMutex::uncontendedQMutex()
|
||||
{
|
||||
QMutex mutex;
|
||||
QBENCHMARK {
|
||||
mutex.lock();
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMutex::uncontendedQMutexLocker()
|
||||
{
|
||||
QMutex mutex;
|
||||
QBENCHMARK {
|
||||
QMutexLocker locker(&mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMutex::contendedNative_data()
|
||||
{
|
||||
QTest::addColumn<int>("iterations");
|
||||
QTest::addColumn<int>("msleepDuration");
|
||||
QTest::addColumn<bool>("use2mutexes");
|
||||
|
||||
QTest::newRow("baseline") << 0 << -1 << false;
|
||||
|
||||
QTest::newRow("no msleep, 1 mutex") << 1000 << -1 << false;
|
||||
QTest::newRow("no msleep, 2 mutexes") << 1000 << -1 << true;
|
||||
QTest::newRow("msleep(0), 1 mutex") << 1000 << 0 << false;
|
||||
QTest::newRow("msleep(0), 2 mutexes") << 1000 << 0 << true;
|
||||
QTest::newRow("msleep(1), 1 mutex") << 10 << 1 << false;
|
||||
QTest::newRow("msleep(1), 2 mutexes") << 10 << 1 << true;
|
||||
QTest::newRow("msleep(2), 1 mutex") << 10 << 2 << false;
|
||||
QTest::newRow("msleep(2), 2 mutexes") << 10 << 2 << true;
|
||||
QTest::newRow("msleep(10), 1 mutex") << 10 << 10 << false;
|
||||
QTest::newRow("msleep(10), 2 mutexes") << 10 << 10 << true;
|
||||
}
|
||||
|
||||
class NativeMutexThread : public QThread
|
||||
{
|
||||
NativeMutexType *mutex1, *mutex2;
|
||||
int iterations, msleepDuration;
|
||||
bool use2mutexes;
|
||||
public:
|
||||
bool done;
|
||||
NativeMutexThread(NativeMutexType *mutex1, NativeMutexType *mutex2, int iterations, int msleepDuration, bool use2mutexes)
|
||||
: mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
|
||||
{ }
|
||||
void run() override
|
||||
{
|
||||
forever {
|
||||
tst_QMutex::semaphore1.release();
|
||||
tst_QMutex::semaphore2.acquire();
|
||||
if (done)
|
||||
break;
|
||||
for (int i = 0; i < iterations; ++i) {
|
||||
NativeMutexLock(mutex1);
|
||||
if (use2mutexes)
|
||||
NativeMutexLock(mutex2);
|
||||
if (msleepDuration >= 0)
|
||||
msleep(msleepDuration);
|
||||
if (use2mutexes)
|
||||
NativeMutexUnlock(mutex2);
|
||||
NativeMutexUnlock(mutex1);
|
||||
|
||||
QThread::yieldCurrentThread();
|
||||
}
|
||||
tst_QMutex::semaphore3.release();
|
||||
tst_QMutex::semaphore4.acquire();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void tst_QMutex::contendedNative()
|
||||
{
|
||||
QFETCH(int, iterations);
|
||||
QFETCH(int, msleepDuration);
|
||||
QFETCH(bool, use2mutexes);
|
||||
|
||||
NativeMutexType mutex1, mutex2;
|
||||
NativeMutexInitialize(&mutex1);
|
||||
NativeMutexInitialize(&mutex2);
|
||||
|
||||
QList<NativeMutexThread *> threads(threadCount);
|
||||
for (int i = 0; i < threads.size(); ++i) {
|
||||
threads[i] = new NativeMutexThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
|
||||
threads[i]->start();
|
||||
}
|
||||
|
||||
QBENCHMARK {
|
||||
semaphore1.acquire(threadCount);
|
||||
semaphore2.release(threadCount);
|
||||
semaphore3.acquire(threadCount);
|
||||
semaphore4.release(threadCount);
|
||||
}
|
||||
|
||||
for (int i = 0; i < threads.size(); ++i)
|
||||
threads[i]->done = true;
|
||||
semaphore1.acquire(threadCount);
|
||||
semaphore2.release(threadCount);
|
||||
for (int i = 0; i < threads.size(); ++i)
|
||||
threads[i]->wait();
|
||||
qDeleteAll(threads);
|
||||
|
||||
NativeMutexDestroy(&mutex1);
|
||||
NativeMutexDestroy(&mutex2);
|
||||
}
|
||||
|
||||
class QMutexThread : public QThread
|
||||
{
|
||||
QMutex *mutex1, *mutex2;
|
||||
int iterations, msleepDuration;
|
||||
bool use2mutexes;
|
||||
public:
|
||||
bool done;
|
||||
QMutexThread(QMutex *mutex1, QMutex *mutex2, int iterations, int msleepDuration, bool use2mutexes)
|
||||
: mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
|
||||
{ }
|
||||
void run() override
|
||||
{
|
||||
forever {
|
||||
tst_QMutex::semaphore1.release();
|
||||
tst_QMutex::semaphore2.acquire();
|
||||
if (done)
|
||||
break;
|
||||
for (int i = 0; i < iterations; ++i) {
|
||||
mutex1->lock();
|
||||
if (use2mutexes)
|
||||
mutex2->lock();
|
||||
if (msleepDuration >= 0)
|
||||
msleep(msleepDuration);
|
||||
if (use2mutexes)
|
||||
mutex2->unlock();
|
||||
mutex1->unlock();
|
||||
|
||||
QThread::yieldCurrentThread();
|
||||
}
|
||||
tst_QMutex::semaphore3.release();
|
||||
tst_QMutex::semaphore4.acquire();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void tst_QMutex::contendedQMutex()
|
||||
{
|
||||
QFETCH(int, iterations);
|
||||
QFETCH(int, msleepDuration);
|
||||
QFETCH(bool, use2mutexes);
|
||||
|
||||
QMutex mutex1, mutex2;
|
||||
|
||||
QList<QMutexThread *> threads(threadCount);
|
||||
for (int i = 0; i < threads.size(); ++i) {
|
||||
threads[i] = new QMutexThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
|
||||
threads[i]->start();
|
||||
}
|
||||
|
||||
QBENCHMARK {
|
||||
semaphore1.acquire(threadCount);
|
||||
semaphore2.release(threadCount);
|
||||
semaphore3.acquire(threadCount);
|
||||
semaphore4.release(threadCount);
|
||||
}
|
||||
|
||||
for (int i = 0; i < threads.size(); ++i)
|
||||
threads[i]->done = true;
|
||||
semaphore1.acquire(threadCount);
|
||||
semaphore2.release(threadCount);
|
||||
for (int i = 0; i < threads.size(); ++i)
|
||||
threads[i]->wait();
|
||||
qDeleteAll(threads);
|
||||
}
|
||||
|
||||
class QMutexLockerThread : public QThread
|
||||
{
|
||||
QMutex *mutex1, *mutex2;
|
||||
int iterations, msleepDuration;
|
||||
bool use2mutexes;
|
||||
public:
|
||||
bool done;
|
||||
QMutexLockerThread(QMutex *mutex1, QMutex *mutex2, int iterations, int msleepDuration, bool use2mutexes)
|
||||
: mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
|
||||
{ }
|
||||
void run() override
|
||||
{
|
||||
forever {
|
||||
tst_QMutex::semaphore1.release();
|
||||
tst_QMutex::semaphore2.acquire();
|
||||
if (done)
|
||||
break;
|
||||
for (int i = 0; i < iterations; ++i) {
|
||||
{
|
||||
QMutexLocker locker1(mutex1);
|
||||
QMutexLocker locker2(use2mutexes ? mutex2 : 0);
|
||||
if (msleepDuration >= 0)
|
||||
msleep(msleepDuration);
|
||||
}
|
||||
|
||||
QThread::yieldCurrentThread();
|
||||
}
|
||||
tst_QMutex::semaphore3.release();
|
||||
tst_QMutex::semaphore4.acquire();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void tst_QMutex::contendedQMutexLocker()
|
||||
{
|
||||
QFETCH(int, iterations);
|
||||
QFETCH(int, msleepDuration);
|
||||
QFETCH(bool, use2mutexes);
|
||||
|
||||
QMutex mutex1, mutex2;
|
||||
|
||||
QList<QMutexLockerThread *> threads(threadCount);
|
||||
for (int i = 0; i < threads.size(); ++i) {
|
||||
threads[i] = new QMutexLockerThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
|
||||
threads[i]->start();
|
||||
}
|
||||
|
||||
QBENCHMARK {
|
||||
semaphore1.acquire(threadCount);
|
||||
semaphore2.release(threadCount);
|
||||
semaphore3.acquire(threadCount);
|
||||
semaphore4.release(threadCount);
|
||||
}
|
||||
|
||||
for (int i = 0; i < threads.size(); ++i)
|
||||
threads[i]->done = true;
|
||||
semaphore1.acquire(threadCount);
|
||||
semaphore2.release(threadCount);
|
||||
for (int i = 0; i < threads.size(); ++i)
|
||||
threads[i]->wait();
|
||||
qDeleteAll(threads);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QMutex)
|
||||
|
||||
#include "tst_bench_qmutex.moc"
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user