From 398ca4fb452a6fdab8eefb8dc471b0f9f703fb16 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Tue, 12 Jun 2018 00:42:10 +0200 Subject: [PATCH] Ref T280, sample to test if QHash or QMap for key callsign is faster * QHash seems to be faster and is const * see also https://woboq.com/blog/qmap_qhash_benchmark.html --- samples/blackmisc/main.cpp | 6 +- samples/blackmisc/samplesperformance.cpp | 150 ++++++++++++++++++++++- samples/blackmisc/samplesperformance.h | 20 ++- 3 files changed, 172 insertions(+), 4 deletions(-) diff --git a/samples/blackmisc/main.cpp b/samples/blackmisc/main.cpp index d4b454ee1..949a6a639 100644 --- a/samples/blackmisc/main.cpp +++ b/samples/blackmisc/main.cpp @@ -45,7 +45,8 @@ int main(int argc, char *argv[]) qtout << endl; qtout << "1 .. JSON" << endl; qtout << "2 .. Change object" << endl; - qtout << "3 .. Containers" << endl; + qtout << "3a .. Containers" << endl; + qtout << "3b .. Callsign QMap vs QHash" << endl; qtout << "4 .. Metadata" << endl; qtout << "6a .. Performance create / copy / ..." << endl; qtout << "6b .. 40/20 Interpolator scenario" << endl; @@ -61,7 +62,8 @@ int main(int argc, char *argv[]) if (s.startsWith("1")) { CSamplesJson::samples(); } else if (s.startsWith("2")) { CSamplesChangeObject::samples(); } - else if (s.startsWith("3")) { CSamplesContainer::samples(); } + else if (s.startsWith("3a")) { CSamplesContainer::samples(); } + else if (s.startsWith("3b")) { CSamplesPerformance::sampleQMapVsQHashByCallsign(qtout); } else if (s.startsWith("4")) { CSamplesMetadata::samples(); } else if (s.startsWith("6a")) { CSamplesPerformance::samplesMisc(qtout); } else if (s.startsWith("6b")) { CSamplesPerformance::interpolatorScenario(qtout, 40, 20); } diff --git a/samples/blackmisc/samplesperformance.cpp b/samples/blackmisc/samplesperformance.cpp index 8ddba2e96..78de84dcd 100644 --- a/samples/blackmisc/samplesperformance.cpp +++ b/samples/blackmisc/samplesperformance.cpp @@ -529,6 +529,110 @@ namespace BlackSample return EXIT_SUCCESS; } + int CSamplesPerformance::sampleQMapVsQHashByCallsign(QTextStream &out) + { + const CCallsignSet cs10 = CSamplesPerformance::callsigns(10); + const CCallsignSet cs25 = CSamplesPerformance::callsigns(25); + const CCallsignSet cs50 = CSamplesPerformance::callsigns(50); + + const QMap m10 = CSamplesPerformance::situationsMap(cs10); + const QMap m25 = CSamplesPerformance::situationsMap(cs25); + const QMap m50 = CSamplesPerformance::situationsMap(cs50); + + const QHash h10 = CSamplesPerformance::situationsHash(cs10); + const QHash h25 = CSamplesPerformance::situationsHash(cs25); + const QHash h50 = CSamplesPerformance::situationsHash(cs50); + + Q_ASSERT(m10.size() == 10 && h10.size() == 10); + Q_ASSERT(m25.size() == 25 && h25.size() == 25); + Q_ASSERT(m50.size() == 50 && h50.size() == 50); + + // QList since we have to add callsigns multiple times, set does not allow that + QList cs_10_100_rnd; + QList cs_25_100_rnd; + QList cs_50_100_rnd; + + for (int i = 0; i < 20; ++i) + { + cs_10_100_rnd.append(cs10.randomElements(5).toQList()); + cs_25_100_rnd.append(cs25.randomElements(5).toQList()); + cs_50_100_rnd.append(cs50.randomElements(5).toQList()); + } + + Q_ASSERT(cs_10_100_rnd.size() == 100); + Q_ASSERT(cs_25_100_rnd.size() == 100); + Q_ASSERT(cs_50_100_rnd.size() == 100); + + QTime time; + time.start(); + for (int i = 1; i < 10000; ++i) + { + for (const CCallsign &cs : cs_10_100_rnd) + { + CAircraftSituation s = m10[cs]; + Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign"); + } + } + out << "map 100 out of 10: " << time.elapsed() << "ms" << endl; + + time.start(); + for (int i = 1; i < 10000; ++i) + { + for (const CCallsign &cs : cs_10_100_rnd) + { + CAircraftSituation s = h10[cs]; + Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign"); + } + } + out << "hash 100 out of 10: " << time.elapsed() << "ms" << endl; + + time.start(); + for (int i = 1; i < 10000; ++i) + { + for (const CCallsign &cs : cs_25_100_rnd) + { + CAircraftSituation s = m25[cs]; + Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign"); + } + } + out << "map 100 out of 25: " << time.elapsed() << "ms" << endl; + + time.start(); + for (int i = 1; i < 10000; ++i) + { + for (const CCallsign &cs : cs_25_100_rnd) + { + CAircraftSituation s = h25[cs]; + Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign"); + } + } + out << "hash 100 out of 25: " << time.elapsed() << "ms" << endl; + + time.start(); + for (int i = 1; i < 10000; ++i) + { + for (const CCallsign &cs : cs_50_100_rnd) + { + CAircraftSituation s = m50[cs]; + Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign"); + } + } + out << "map 100 out of 50: " << time.elapsed() << "ms" << endl; + + time.start(); + for (int i = 1; i < 10000; ++i) + { + for (const CCallsign &cs : cs_50_100_rnd) + { + CAircraftSituation s = h50[cs]; + Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign"); + } + } + out << "hash 100 out of 50: " << time.elapsed() << "ms" << endl; + + return EXIT_SUCCESS; + } + CAircraftSituationList CSamplesPerformance::createSituations(qint64 baseTimeEpoch, int numberOfCallsigns, int numberOfTimes) { CAircraftSituationList situations; @@ -572,7 +676,7 @@ namespace BlackSample void CSamplesPerformance::calculateDistance(int n) { - if (n < 1) return; + if (n < 1) { return; } CAtcStation atc = CTesting::createStation(1); const QList pos( { @@ -648,6 +752,50 @@ namespace BlackSample return lc; } + CCallsignSet CSamplesPerformance::callsigns(int number) + { + CCallsignSet set; + static const QString cs("FOO%1"); + for (int i = 0; i < number; i++) + { + set.insert(CCallsign(cs.arg(i))); + } + return set; + } + + const CAircraftSituationList CSamplesPerformance::situations(const CCallsignSet &callsigns) + { + CAircraftSituationList situations; + for (const CCallsign &cs : callsigns) + { + const CAircraftSituation s(cs); + situations.push_back(s); + } + return situations; + } + + const QMap CSamplesPerformance::situationsMap(const CCallsignSet &callsigns) + { + QMap situations; + for (const CCallsign &cs : callsigns) + { + const CAircraftSituation s(cs); + situations.insert(cs, s); + } + return situations; + } + + const QHash CSamplesPerformance::situationsHash(const CCallsignSet &callsigns) + { + QHash situations; + for (const CCallsign &cs : callsigns) + { + const CAircraftSituation s(cs); + situations.insert(cs, s); + } + return situations; + } + const CAtcStationList &CSamplesPerformance::stations10k() { static const CAtcStationList s = CTesting::createAtcStations(10000, false); diff --git a/samples/blackmisc/samplesperformance.h b/samples/blackmisc/samplesperformance.h index edb9852bd..066901dfd 100644 --- a/samples/blackmisc/samplesperformance.h +++ b/samples/blackmisc/samplesperformance.h @@ -13,10 +13,13 @@ #ifndef BLACKSAMPLE_SAMPLESPERFORMANCE_H #define BLACKSAMPLE_SAMPLESPERFORMANCE_H -#include "blackmisc/aviation/aircraftsituationlist.h" #include "blackmisc/simulation/aircraftmodellist.h" +#include "blackmisc/aviation/aircraftsituationlist.h" +#include "blackmisc/aviation/callsignset.h" #include #include +#include +#include class QTextStream; @@ -47,6 +50,9 @@ namespace BlackSample //! const QString vs. QStringLiteral static int samplesStringLiteralVsConstQString(QTextStream &out); + //! Callsign based hash/map comparison + static int sampleQMapVsQHashByCallsign(QTextStream &out); + private: static const qint64 DeltaTime = 10; @@ -85,6 +91,18 @@ namespace BlackSample //! String list generated static QStringList replacedList(); + + //! Get n callsigns + static BlackMisc::Aviation::CCallsignSet callsigns(int number); + + //! Situations + static const BlackMisc::Aviation::CAircraftSituationList situations(const BlackMisc::Aviation::CCallsignSet &callsigns); + + //! Situations map + static const QMap situationsMap(const BlackMisc::Aviation::CCallsignSet &callsigns); + + //! Situations hash + static const QHash situationsHash(const BlackMisc::Aviation::CCallsignSet &callsigns); }; } // namespace