diff --git a/tests/benchmarks/corelib/text/CMakeLists.txt b/tests/benchmarks/corelib/text/CMakeLists.txt index 8319d1bf3b1..f5fc9eff2c0 100644 --- a/tests/benchmarks/corelib/text/CMakeLists.txt +++ b/tests/benchmarks/corelib/text/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(qchar) add_subdirectory(qlocale) add_subdirectory(qstringbuilder) add_subdirectory(qstringlist) +add_subdirectory(qregularexpression) if(GCC) add_subdirectory(qstring) endif() diff --git a/tests/benchmarks/corelib/text/qregularexpression/.gitignore b/tests/benchmarks/corelib/text/qregularexpression/.gitignore new file mode 100644 index 00000000000..174df76c6af --- /dev/null +++ b/tests/benchmarks/corelib/text/qregularexpression/.gitignore @@ -0,0 +1 @@ +tst_bench_qregularexpression diff --git a/tests/benchmarks/corelib/text/qregularexpression/CMakeLists.txt b/tests/benchmarks/corelib/text/qregularexpression/CMakeLists.txt new file mode 100644 index 00000000000..1e1f40a2e43 --- /dev/null +++ b/tests/benchmarks/corelib/text/qregularexpression/CMakeLists.txt @@ -0,0 +1,12 @@ +# Generated from qregularexpression.pro. + +##################################################################### +## tst_bench_qregularexpression Binary: +##################################################################### + +qt_internal_add_benchmark(tst_bench_qregularexpression + SOURCES + tst_bench_qregularexpression.cpp + PUBLIC_LIBRARIES + Qt::Test +) diff --git a/tests/benchmarks/corelib/text/qregularexpression/qregularexpression.pro b/tests/benchmarks/corelib/text/qregularexpression/qregularexpression.pro new file mode 100644 index 00000000000..2a482cac379 --- /dev/null +++ b/tests/benchmarks/corelib/text/qregularexpression/qregularexpression.pro @@ -0,0 +1,5 @@ +CONFIG += benchmark +QT = core testlib + +TARGET = tst_bench_qregularexpression +SOURCES += tst_bench_qregularexpression.cpp diff --git a/tests/benchmarks/corelib/text/qregularexpression/tst_bench_qregularexpression.cpp b/tests/benchmarks/corelib/text/qregularexpression/tst_bench_qregularexpression.cpp new file mode 100644 index 00000000000..6c9c2ddaf5e --- /dev/null +++ b/tests/benchmarks/corelib/text/qregularexpression/tst_bench_qregularexpression.cpp @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +/*! + \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 { "(?
\\w+) (?\\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" diff --git a/tests/benchmarks/corelib/text/text.pro b/tests/benchmarks/corelib/text/text.pro index a2397b37fe9..839c1d0f2fb 100644 --- a/tests/benchmarks/corelib/text/text.pro +++ b/tests/benchmarks/corelib/text/text.pro @@ -4,6 +4,7 @@ SUBDIRS = \ qchar \ qlocale \ qstringbuilder \ - qstringlist + qstringlist \ + qregularexpression *g++*: SUBDIRS += qstring