File indexing completed on 2024-05-19 04:39:26

0001 /*
0002     SPDX-FileCopyrightText: 2012-2013 Milian Wolff <mail@milianw.de>
0003     SPDX-FileCopyrightText: 2020 Igor Kushnir <igorkuo@gmail.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006 */
0007 
0008 #include "bench_indexedstring.h"
0009 
0010 #include <language/util/kdevhash.h>
0011 #include <serialization/indexedstring.h>
0012 #include <tests/testhelpers.h>
0013 
0014 #include <QTest>
0015 
0016 #include <utility>
0017 #include <vector>
0018 
0019 QTEST_GUILESS_MAIN(BenchIndexedString)
0020 
0021 using namespace KDevelop;
0022 
0023 static QVector<QString> generateData()
0024 {
0025     QVector<QString> data;
0026     static const int NUM_ITEMS = 100000;
0027     data.resize(NUM_ITEMS);
0028     for (int i = 0; i < NUM_ITEMS; ++i) {
0029         data[i] = QStringLiteral("/foo/%1").arg(i);
0030     }
0031 
0032     return data;
0033 }
0034 
0035 void BenchIndexedString::bench_index()
0036 {
0037     const QVector<QString> data = generateData();
0038     QBENCHMARK {
0039         for (const QString& item : data) {
0040             IndexedString idx(item);
0041             Q_UNUSED(idx);
0042         }
0043     }
0044 }
0045 
0046 static QVector<uint> setupTest()
0047 {
0048     const QVector<QString> data = generateData();
0049     QVector<uint> indices;
0050     indices.reserve(data.size());
0051     for (const QString& item : data) {
0052         IndexedString idx(item);
0053         indices << idx.index();
0054     }
0055 
0056     return indices;
0057 }
0058 
0059 void BenchIndexedString::bench_length()
0060 {
0061     const QVector<uint> indices = setupTest();
0062     QBENCHMARK {
0063         for (uint index : indices) {
0064             IndexedString str = IndexedString::fromIndex(index);
0065             str.length();
0066         }
0067     }
0068 }
0069 
0070 void BenchIndexedString::bench_qstring()
0071 {
0072     const QVector<uint> indices = setupTest();
0073     QBENCHMARK {
0074         for (uint index : indices) {
0075             IndexedString str = IndexedString::fromIndex(index);
0076             str.str();
0077         }
0078     }
0079 }
0080 
0081 void BenchIndexedString::bench_kurl()
0082 {
0083     const QVector<uint> indices = setupTest();
0084     QBENCHMARK {
0085         for (uint index : indices) {
0086             IndexedString str = IndexedString::fromIndex(index);
0087             str.toUrl();
0088         }
0089     }
0090 }
0091 
0092 void BenchIndexedString::bench_qhashQString()
0093 {
0094     const QVector<QString> data = generateData();
0095     quint64 sum = 0;
0096     QBENCHMARK {
0097         for (const auto& string : data) {
0098             sum += qHash(string);
0099         }
0100     }
0101     QVERIFY(sum > 0);
0102 }
0103 
0104 void BenchIndexedString::bench_qhashIndexedString()
0105 {
0106     const QVector<uint> indices = setupTest();
0107     quint64 sum = 0;
0108     QBENCHMARK {
0109         for (uint index : indices) {
0110             sum += qHash(IndexedString::fromIndex(index));
0111         }
0112     }
0113     QVERIFY(sum > 0);
0114 }
0115 
0116 void BenchIndexedString::bench_hashString()
0117 {
0118     const QVector<QString> strings = generateData();
0119     QVector<QByteArray> byteArrays;
0120     byteArrays.reserve(strings.size());
0121     for (const auto& string : strings) {
0122         byteArrays << string.toUtf8();
0123     }
0124 
0125     quint64 sum = 0;
0126     QBENCHMARK {
0127         for (const auto& array : qAsConst(byteArrays)) {
0128             sum += IndexedString::hashString(array.constData(), array.length());
0129         }
0130     }
0131     QVERIFY(sum > 0);
0132 }
0133 
0134 void BenchIndexedString::bench_kdevhash()
0135 {
0136     const QVector<QString> strings = generateData();
0137     QVector<QByteArray> byteArrays;
0138     byteArrays.reserve(strings.size());
0139     for (const auto& string : strings) {
0140         byteArrays << string.toUtf8();
0141     }
0142 
0143     quint64 sum = 0;
0144     QBENCHMARK {
0145         for (const auto& array : qAsConst(byteArrays)) {
0146             sum += KDevHash() << array;
0147         }
0148     }
0149     QVERIFY(sum > 0);
0150 }
0151 
0152 void BenchIndexedString::bench_qSet()
0153 {
0154     const QVector<uint> indices = setupTest();
0155     QSet<IndexedString> set;
0156     QBENCHMARK {
0157         for (uint index : indices) {
0158             set.insert(IndexedString::fromIndex(index));
0159         }
0160     }
0161 }
0162 
0163 static std::vector<IndexedString> createIndexedStrings(std::size_t count)
0164 {
0165     std::vector<IndexedString> result;
0166     // result.reserve(count) is called after verifying that count is not too great.
0167 
0168     constexpr char first{33};
0169     constexpr char last{127};
0170     constexpr std::size_t dataSize{4};
0171 
0172     std::size_t maxCount{1};
0173     for (std::size_t i = 0; i < dataSize; ++i) {
0174         maxCount *= (last - first);
0175     }
0176     // Subtract 1 to account for the fact that count is checked at the beginning
0177     // of the innermost loop in order to support count == 0.
0178     --maxCount;
0179     QVERIFY_RETURN(count <= maxCount, result);
0180 
0181     result.reserve(count);
0182 
0183     char data[dataSize + 1] = {};
0184     QCOMPARE_RETURN(data[dataSize], 0, result);
0185     for (char a = first; a != last; ++a) {
0186         data[0] = a;
0187         for (char b = first; b != last; ++b) {
0188             data[1] = b;
0189             for (char c = first; c != last; ++c) {
0190                 data[2] = c;
0191                 for (char d = first; d != last; ++d) {
0192                     if (count-- == 0) {
0193                         return result;
0194                     }
0195                     data[3] = d;
0196                     result.emplace_back(data, dataSize);
0197                 }
0198             }
0199         }
0200     }
0201     Q_UNREACHABLE();
0202 }
0203 
0204 void BenchIndexedString::bench_create()
0205 {
0206     QBENCHMARK_ONCE {
0207         createIndexedStrings(1'000'000);
0208     }
0209 }
0210 
0211 void BenchIndexedString::bench_destroy()
0212 {
0213     auto strings = createIndexedStrings(10'000'000);
0214     QBENCHMARK_ONCE {
0215         strings = {};
0216     }
0217 }
0218 
0219 void BenchIndexedString::bench_swap()
0220 {
0221     IndexedString a("foo");
0222     IndexedString b("bar");
0223     QBENCHMARK {
0224         using std::swap;
0225         swap(a, b);
0226     }
0227 }
0228 
0229 void BenchIndexedString::bench_string_vector_data()
0230 {
0231     QTest::addColumn<int>("type");
0232     QTest::addRow("std::vector") << 0;
0233     QTest::addRow("QVector") << 1;
0234 }
0235 
0236 void BenchIndexedString::bench_string_vector()
0237 {
0238     auto bench = [](auto container) {
0239         for (int i = 0; i < 10000; ++i) {
0240             container.push_back(IndexedString(QString::number(i)));
0241         }
0242         // deliberately do a worst-case remove-from-front here
0243         // we want to see how this performs without any noexcept move operators
0244         QBENCHMARK_ONCE {
0245             while (!container.empty()) {
0246                 container.erase(container.begin());
0247             }
0248         }
0249     };
0250 
0251     QFETCH(int, type);
0252     switch (type) {
0253     case 0: {
0254         std::vector<IndexedString> container;
0255         bench(container);
0256         break;
0257     }
0258     case 1: {
0259         QVector<IndexedString> container;
0260         bench(container);
0261         break;
0262     }
0263     default:
0264         QFAIL("unhandled type");
0265         break;
0266     }
0267 }
0268 
0269 #include "moc_bench_indexedstring.cpp"