Warning, file /kdevelop/kdevelop/kdevplatform/language/duchain/tests/bench_hashes.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2012 Milian Wolff <mail@milianw.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "bench_hashes.h"
0008 
0009 #include <serialization/indexedstring.h>
0010 
0011 #include <tests/testcore.h>
0012 #include <tests/autotestshell.h>
0013 #include <QDateTime>
0014 #include <QVector>
0015 #include <QTest>
0016 
0017 #include <unordered_map>
0018 
0019 // similar to e.g. modificationrevision.cpp
0020 struct DataT
0021 {
0022     QDateTime a;
0023     QDateTime b;
0024 };
0025 
0026 using DataPair = QPair<KDevelop::IndexedString, DataT>;
0027 using InputData = QVector<DataPair>;
0028 
0029 struct IndexedStringHash
0030 {
0031     inline uint operator()(const KDevelop::IndexedString& str) const
0032     {
0033         return str.hash();
0034     }
0035 };
0036 
0037 using StlHash = std::unordered_map<KDevelop::IndexedString, DataT, IndexedStringHash>;
0038 
0039 inline void insertData(StlHash& hash, const InputData& data)
0040 {
0041     for (const DataPair& pair : data) {
0042         hash.insert(std::make_pair(pair.first, pair.second));
0043     }
0044 }
0045 
0046 using QStringHash = QHash<KDevelop::IndexedString, DataT>;
0047 inline void insertData(QStringHash& hash, const InputData& data)
0048 {
0049     for (const DataPair& pair : data) {
0050         hash.insert(pair.first, pair.second);
0051     }
0052 }
0053 
0054 QTEST_GUILESS_MAIN(BenchHashes)
0055 
0056 using namespace KDevelop;
0057 
0058 Q_DECLARE_METATYPE(InputData)
0059 
0060 void BenchHashes::initTestCase()
0061 {
0062     AutoTestShell::init();
0063     TestCore::initialize(Core::NoUi);
0064 
0065     qRegisterMetaType<InputData>();
0066 }
0067 
0068 void BenchHashes::cleanupTestCase()
0069 {
0070     TestCore::shutdown();
0071 }
0072 
0073 void BenchHashes::feedData()
0074 {
0075     QTest::addColumn<bool>("useStl");
0076     QTest::addColumn<InputData>("data");
0077 
0078     InputData data;
0079     const QVector<int> sizes{100, 1000, 10000, 100000};
0080     for (int size : sizes) {
0081         for (int i = data.size(); i < size; ++i) {
0082             data << qMakePair(IndexedString(QString::number(i)), DataT());
0083         }
0084 
0085         QCOMPARE(data.size(), size);
0086         QTest::newRow(qPrintable(QStringLiteral("unordered_map-%1").arg(size)))
0087             << true << data;
0088         QTest::newRow(qPrintable(QStringLiteral("qhash-%1").arg(size)))
0089             << false << data;
0090     }
0091 }
0092 
0093 void BenchHashes::insert()
0094 {
0095     QFETCH(bool, useStl);
0096     QFETCH(InputData, data);
0097 
0098     if (useStl) {
0099         QBENCHMARK {
0100             StlHash hash;
0101             insertData(hash, data);
0102         }
0103     } else {
0104         QBENCHMARK {
0105             QStringHash hash;
0106             insertData(hash, data);
0107         }
0108     }
0109 }
0110 
0111 void BenchHashes::insert_data()
0112 {
0113     feedData();
0114 }
0115 
0116 void BenchHashes::find()
0117 {
0118     QFETCH(bool, useStl);
0119     QFETCH(const InputData, data);
0120 
0121     if (useStl) {
0122         StlHash hash;
0123         insertData(hash, data);
0124         QBENCHMARK {
0125             for (const DataPair& pair : data) {
0126                 ( void ) hash.find(pair.first);
0127             }
0128         }
0129     } else {
0130         QStringHash hash;
0131         insertData(hash, data);
0132         QBENCHMARK {
0133             for (const DataPair& pair : data) {
0134                 ( void ) hash.find(pair.first);
0135             }
0136         }
0137     }
0138 }
0139 
0140 void BenchHashes::find_data()
0141 {
0142     feedData();
0143 }
0144 
0145 void BenchHashes::constFind()
0146 {
0147     QFETCH(bool, useStl);
0148     QFETCH(const InputData, data);
0149 
0150     if (useStl) {
0151         StlHash hash;
0152         insertData(hash, data);
0153         const StlHash& constHash = hash;
0154         QBENCHMARK {
0155             for (const DataPair& pair : data) {
0156                 ( void ) constHash.find(pair.first);
0157             }
0158         }
0159     } else {
0160         QStringHash hash;
0161         insertData(hash, data);
0162         QBENCHMARK {
0163             for (const DataPair& pair : data) {
0164                 ( void ) hash.constFind(pair.first);
0165             }
0166         }
0167     }
0168 }
0169 
0170 void BenchHashes::constFind_data()
0171 {
0172     feedData();
0173 }
0174 
0175 void BenchHashes::remove()
0176 {
0177     QFETCH(bool, useStl);
0178     QFETCH(const InputData, data);
0179 
0180     if (useStl) {
0181         StlHash hash;
0182         insertData(hash, data);
0183         QBENCHMARK {
0184             for (const DataPair& pair : data) {
0185                 hash.erase(pair.first);
0186             }
0187         }
0188     } else {
0189         QStringHash hash;
0190         insertData(hash, data);
0191         QBENCHMARK {
0192             for (const DataPair& pair : data) {
0193                 hash.remove(pair.first);
0194             }
0195         }
0196     }
0197 }
0198 
0199 void BenchHashes::remove_data()
0200 {
0201     feedData();
0202 }
0203 
0204 struct TypeRepoTestData
0205 {
0206     size_t size = 0;
0207     void* ptr = nullptr;
0208 };
0209 
0210 /**
0211  * somewhat artificial benchmark to test speed impact if we'd ever change
0212  * the underlying data type of the TypeSystem / TypeRegister.
0213  */
0214 void BenchHashes::typeRepo()
0215 {
0216     QFETCH(int, type);
0217     if (type == 1 || type == 2) {
0218         QVector<TypeRepoTestData*> v;
0219         for (int i = 0; i < 100; ++i) {
0220             v.append(new TypeRepoTestData);
0221         }
0222 
0223         if (type == 1) {
0224             QBENCHMARK {
0225                 for (int i = 0; i < 100; ++i) {
0226                     v.at(i)->size++;
0227                 }
0228             }
0229         } else if (type == 2) {
0230             TypeRepoTestData** a = v.data();
0231             QBENCHMARK {
0232                 for (int i = 0; i < 100; ++i) {
0233                     a[i]->size++;
0234                 }
0235             }
0236         }
0237         qDeleteAll(v);
0238     } else if (type == 3) {
0239         QHash<int, TypeRepoTestData*> v;
0240         for (int i = 0; i < 100; ++i) {
0241             v[i] = new TypeRepoTestData;
0242         }
0243 
0244         QBENCHMARK {
0245             for (int i = 0; i < 100; ++i) {
0246                 v.value(i)->size++;
0247             }
0248         }
0249         qDeleteAll(v);
0250     } else if (type == 4) {
0251         QMap<int, TypeRepoTestData*> v;
0252         for (int i = 0; i < 100; ++i) {
0253             v[i] = new TypeRepoTestData;
0254         }
0255 
0256         QBENCHMARK {
0257             for (int i = 0; i < 100; ++i) {
0258                 v.value(i)->size++;
0259             }
0260         }
0261         qDeleteAll(v);
0262     } else if (type == 5) {
0263         std::unordered_map<int, TypeRepoTestData*> v;
0264         for (int i = 0; i < 100; ++i) {
0265             v[i] = new TypeRepoTestData;
0266         }
0267 
0268         QBENCHMARK {
0269             for (int i = 0; i < 100; ++i) {
0270                 v.at(i)->size++;
0271             }
0272         }
0273         for (const auto& [key, value] : v) {
0274             delete value;
0275         }
0276     } else if (type == 6) {
0277         // for the idea, look at c++'s lexer.cpp
0278         const int vectors = 5;
0279         using Pair = QPair<int, TypeRepoTestData*>;
0280         using InnerVector = QVarLengthArray<Pair, vectors>;
0281         QVarLengthArray <InnerVector, 10> v;
0282         v.resize(vectors);
0283         for (int i = 0; i < 100; ++i) {
0284             v[i % vectors] << qMakePair(i, new TypeRepoTestData);
0285         }
0286 
0287         QBENCHMARK {
0288             for (int i = 0; i < 100; ++i) {
0289                 for (const Pair& p : qAsConst(v.at(i % vectors))) {
0290                     if (p.first == i) {
0291                         p.second->size++;
0292                         break;
0293                     }
0294                 }
0295             }
0296         }
0297         for (const auto& inner : v) {
0298             for (const auto& [key, value] : inner) {
0299                 delete value;
0300             }
0301         }
0302     } else if (type == 0) {
0303         QBENCHMARK {}
0304     }
0305 }
0306 
0307 void BenchHashes::typeRepo_data()
0308 {
0309     QTest::addColumn<int>("type");
0310 
0311     QTest::newRow("noop") << 0;
0312     QTest::newRow("vector") << 1;
0313     QTest::newRow("vector-raw") << 2;
0314     QTest::newRow("qhash") << 3;
0315     QTest::newRow("qmap") << 4;
0316     QTest::newRow("unordered_map") << 5;
0317     QTest::newRow("nested-vector") << 6;
0318 }
0319 
0320 #include "moc_bench_hashes.cpp"