swift
Loading...
Searching...
No Matches
samplesperformance.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3
6
8
9#include <algorithm>
10#include <iterator>
11
12#include <QDateTime>
13#include <QElapsedTimer>
14#include <QHash>
15#include <QList>
16#include <QRegularExpression>
17#include <QRegularExpressionMatch>
18#include <QString>
19#include <QStringBuilder>
20#include <QStringList>
21#include <QTextStream>
22#include <QVector>
23#include <Qt>
24
34#include "misc/directoryutils.h"
36#include "misc/math/mathutils.h"
37#include "misc/pq/units.h"
40#include "misc/stringutils.h"
42#include "misc/test/testing.h"
43
44using namespace swift::misc;
45using namespace swift::misc::aviation;
46using namespace swift::misc::geo;
47using namespace swift::misc::math;
48using namespace swift::misc::network;
49using namespace swift::misc::physical_quantities;
50using namespace swift::misc::simulation;
51using namespace swift::misc::test;
52using namespace swift::core::db;
53
54namespace swift::sample
55{
57 {
58 QElapsedTimer timer;
59 qint64 ms {};
60 int number {};
61 CSamplesPerformance::copy10kStations(1); // init
62
63 // ATC stations, tradionally created
64 timer.start();
66 ms = timer.elapsed();
67 out << "created (copy) " << atcs1.size() << " ATC stations in " << ms << "ms" << Qt::endl;
68
69 timer.start();
71 ms = timer.elapsed();
72 out << "created (copy) " << atcs2.size() << " ATC stations in " << ms << "ms" << Qt::endl;
73
74 // ATC stations, property index created
75 timer.start();
77 ms = timer.elapsed();
78 out << "created (propertyIndex) " << atcs3.size() << " ATC stations in " << ms << "ms" << Qt::endl;
79
80 timer.start();
81 CAtcStationList atcs4 = CTesting::createAtcStations(100000, true);
82 ms = timer.elapsed();
83 out << "created (propertyIndex) " << atcs4.size() << " ATC stations in " << ms << "ms" << Qt::endl;
84
85 // Sort by
86 timer.start();
88 ms = timer.elapsed();
89 out << "Sorted by callsign " << atcs1.size() << " ATC stations in " << ms << "ms" << Qt::endl;
90
91 timer.start();
93 ms = timer.elapsed();
94 out << "Sorted by callsign " << atcs2.size() << " ATC stations in " << ms << "ms" << Qt::endl;
95
96 // Read data, this is what all our models do when displaying in a table view
97 timer.start();
98 CSamplesPerformance::accessStationsData(atcs1, false);
99 ms = timer.elapsed();
100 out << "Read (getters) " << atcs1.size() << " ATC stations in " << ms << "ms" << Qt::endl;
101
102 timer.start();
103 CSamplesPerformance::accessStationsData(atcs2, false);
104 ms = timer.elapsed();
105 out << "Read (getters) " << atcs2.size() << " ATC stations in " << ms << "ms" << Qt::endl;
106
107 timer.start();
108 CSamplesPerformance::accessStationsData(atcs1, true);
109 ms = timer.elapsed();
110 out << "Read (propertyIndex) " << atcs1.size() << " ATC stations in " << ms << "ms" << Qt::endl;
111
112 timer.start();
113 CSamplesPerformance::accessStationsData(atcs2, true);
114 ms = timer.elapsed();
115 out << "Read (propertyIndex) " << atcs2.size() << " ATC stations in " << ms << "ms" << Qt::endl;
116
117 // calculate
118 number = 10000;
119 timer.start();
120 CSamplesPerformance::calculateDistance(number);
121 ms = timer.elapsed();
122 out << "Calculated distances " << number << " in " << ms << "ms" << Qt::endl;
123
124 number = 100000;
125 timer.start();
126 CSamplesPerformance::calculateDistance(number);
127 ms = timer.elapsed();
128 out << "Calculated distances " << number << "in " << ms << "ms" << Qt::endl;
129
130 // parse
131 number = 100000;
132 timer.start();
133 CSamplesPerformance::parseWgs(number);
134 ms = timer.elapsed();
135 out << "Parse WGS coordinates " << number << " in " << ms << "ms" << Qt::endl;
136
137 // copy
138 timer.start();
139 number = 20;
140 CSamplesPerformance::copy10kStations(number);
141 ms = timer.elapsed();
142 out << "Copied 10k stations " << number << " times in " << ms << "ms" << Qt::endl;
143
144 timer.start();
145 number = 100;
146 CSamplesPerformance::copy10kStations(number);
147 ms = timer.elapsed();
148 out << "Copied 10k stations " << number << " times in " << ms << "ms" << Qt::endl;
149
150 // Regex pattern matching with lists of 10000 strings containing random hex numbers
151 auto generator = []() { return QString::number(CMathUtils::randomGenerator().generate(), 16); };
152 QStringList strList1;
153 QStringList strList2;
154 QStringList strList3;
155 QStringList strList4;
156 std::generate_n(std::back_inserter(strList1), 100000, generator);
157 std::generate_n(std::back_inserter(strList2), 100000, generator);
158 std::generate_n(std::back_inserter(strList3), 100000, generator);
159 std::generate_n(std::back_inserter(strList4), 100000, generator);
162 QString containsStr("aaa");
163 number = 0;
164 timer.start();
165 for (const auto &str : std::as_const(strList1))
166 {
167 if (newRegex.match(str).hasMatch()) number++;
168 }
169 ms = timer.elapsed();
170 out << "new regex matched " << number << " of" << strList1.size() << " strings in " << ms << "ms" << Qt::endl;
171 number = 0;
172 timer.start();
173 for (const auto &str : std::as_const(strList2))
174 {
175 if (fullRegex.match(str).hasMatch()) number++;
176 }
177 ms = timer.elapsed();
178 out << "full regex matched " << number << " of" << strList2.size() << " strings in " << ms << "ms" << Qt::endl;
179 number = 0;
180 timer.start();
181 for (const auto &str : std::as_const(strList4))
182 {
183 if (str.contains(containsStr)) number++;
184 }
185 ms = timer.elapsed();
186 out << "contains matched " << number << " of " << strList4.size() << " strings in " << ms << "ms" << Qt::endl;
187
188 out << "-----------------------------------------------" << Qt::endl;
189 return EXIT_SUCCESS;
190 }
191
192 int CSamplesPerformance::interpolatorScenario(QTextStream &out, int numberOfCallsigns, int numberOfTimes)
193 {
194 const qint64 baseTimeEpoch = QDateTime::currentMSecsSinceEpoch();
195 CAircraftSituationList situations = createSituations(baseTimeEpoch, numberOfCallsigns, numberOfTimes);
196 CAircraftSituationList situationsBefore;
197 CAircraftSituationList situationsAfter;
198
199 qint64 halfTime = baseTimeEpoch + DeltaTime * numberOfTimes / 2;
200
201 QElapsedTimer timer;
202 timer.start();
203 for (int cs = 0; cs < numberOfCallsigns; cs++)
204 {
205 CCallsign callsign("CS" + QString::number(cs));
206 situationsBefore = situations.findBefore(halfTime).findByCallsign(callsign);
207 situationsAfter = situations.findAfter(halfTime - 1).findByCallsign(callsign);
208 }
209 out << "Reads by time, callsigns: " << timer.elapsed() << "ms" << Qt::endl;
210
211 timer.start();
212 situationsBefore = situations.findBefore(halfTime);
213 situationsAfter = situations.findAfter(halfTime - 1);
214 for (int cs = 0; cs < numberOfCallsigns; cs++)
215 {
216 CCallsign callsign("CS" + QString::number(cs));
217 CAircraftSituationList csSituationsBefore = situationsBefore.findByCallsign(callsign);
218 CAircraftSituationList csSituationsAfter = situationsAfter.findByCallsign(callsign);
219 Q_UNUSED(csSituationsBefore);
220 Q_UNUSED(csSituationsAfter);
221 }
222 out << "Split by time upfront, then callsigns: " << timer.elapsed() << "ms" << Qt::endl;
223 int b = situationsBefore.size();
224 int a = situationsAfter.size();
225 Q_ASSERT(a + b == numberOfTimes * numberOfCallsigns);
226 Q_UNUSED(a);
227 Q_UNUSED(b);
228
229 timer.start();
230 const QHash<CCallsign, CAircraftSituationList> csSituations = situations.splitPerCallsign();
231 out << "Split by " << csSituations.size() << " callsigns, " << timer.elapsed() << "ms" << Qt::endl;
232
233 timer.start();
234 for (const CAircraftSituationList &csl : csSituations)
235 {
236 CAircraftSituationList csSituationsBefore = csl.findBefore(halfTime);
237 CAircraftSituationList csSituationsAfter = csl.findAfter(halfTime - 1);
238 a = csSituationsBefore.size();
239 b = csSituationsAfter.size();
240 Q_ASSERT(a + b == numberOfTimes);
241 Q_UNUSED(csSituationsBefore);
242 Q_UNUSED(csSituationsAfter);
243 }
244 out << "Split by callsign, by time: " << timer.elapsed() << "ms" << Qt::endl;
245
246 out << Qt::endl;
247 return EXIT_SUCCESS;
248 }
249
251 {
252 QElapsedTimer timer;
253 auto situations = createSituations(0, 10000, 10);
254 auto models = createModels(10000, 100);
255
256 timer.start();
257 QJsonObject json = situations.toJson();
258 out << "Convert 100,000 aircraft situations to JSON: " << timer.elapsed() << "ms" << Qt::endl;
259
260 timer.start();
261 situations.convertFromJson(json);
262 out << "Convert 100,000 aircraft situations from JSON: " << timer.elapsed() << "ms" << Qt::endl
263 << Qt::endl;
264
265 timer.start();
266 json = models.toJson();
267 out << "Convert 10,000 aircraft models to JSON (naive): " << timer.elapsed() << "ms" << Qt::endl;
268
269 timer.start();
270 models.convertFromJson(json);
271 out << "Convert 10,000 aircraft models from JSON (naive): " << timer.elapsed() << "ms" << Qt::endl
272 << Qt::endl;
273
274 timer.start();
275 json = models.toMemoizedJson();
276 out << "Convert 10,000 aircraft models to JSON (memoize): " << timer.elapsed() << "ms" << Qt::endl;
277
278 timer.start();
279 models.convertFromMemoizedJson(json);
280 out << "Convert 10,000 aircraft models from JSON (memoize): " << timer.elapsed() << "ms" << Qt::endl
281 << Qt::endl;
282
283 return EXIT_SUCCESS;
284 }
285
287 {
289 const QString modelFileName = QDir(dir).filePath("models.json");
290 const QString liveriesFileName = QDir(dir).filePath("liveries.json");
291
292 QFile modelFile(modelFileName);
293 [[maybe_unused]] const bool existsModel = modelFile.exists();
294 Q_ASSERT_X(existsModel, Q_FUNC_INFO, "Model file does not exist");
295 QFile liveryFile(liveriesFileName);
296 [[maybe_unused]] const bool existsLivery = liveryFile.exists();
297 Q_ASSERT_X(existsLivery, Q_FUNC_INFO, "Liveries file does not exist");
298
299 out << "Loaded DB JSON model file " << modelFile.fileName() << Qt::endl;
300 const QString modelData = CFileUtils::readFileToString(modelFile.fileName());
301 Q_ASSERT_X(!modelData.isEmpty(), Q_FUNC_INFO, "Model file empty");
302
303 out << "Loaded DB JSON livery file " << liveryFile.fileName() << Qt::endl;
304 const QString liveryData = CFileUtils::readFileToString(liveryFile.fileName());
305 Q_ASSERT_X(!liveryData.isEmpty(), Q_FUNC_INFO, "Livery file empty");
306
307 // DB format, all models denormalized in DB JSON format
309 QElapsedTimer timer;
310
311 CDatabaseReader::stringToDatastoreResponse(liveryData, response);
312 timer.start();
313 const CLiveryList dbLiveries = CLiveryList::fromDatabaseJson(response);
314 qint64 ms = timer.elapsed();
315 out << "Read via DB JSON format: " << dbLiveries.size() << " liveries in " << ms << "ms" << Qt::endl;
316
317 // does not result in better performance, liveries/airlines have almost a 1:1 ratio
318 // unlike models' fromDatabaseJsonCaching not many airlines will be recycled
319 timer.start();
320 const CLiveryList dbLiveries2 = CLiveryList::fromDatabaseJsonCaching(response);
321 ms = timer.elapsed();
322 out << "Read via DB JSON format (new): " << dbLiveries2.size() << " liveries in " << ms << "ms" << Qt::endl;
323
324 const CAirlineIcaoCodeList liveryAirlines = dbLiveries2.getAirlines();
325 timer.start();
326 const CLiveryList dbLiveries3 = CLiveryList::fromDatabaseJsonCaching(response, liveryAirlines);
327 ms = timer.elapsed();
328 out << "Read via DB JSON format (new, passing airlines): " << dbLiveries3.size() << " liveries in " << ms
329 << "ms" << Qt::endl;
330
331 CDatabaseReader::stringToDatastoreResponse(modelData, response);
332 timer.start();
334 ms = timer.elapsed();
335 out << "Read via DB JSON format: " << dbModels.size() << " models in " << ms << "ms" << Qt::endl;
336
337 timer.start();
339 ms = timer.elapsed();
340 out << "Read via DB JSON format (new): " << dbModels2.size() << " models in " << ms << "ms" << Qt::endl;
341
342 // swift JSON format
343 const QJsonObject swiftJsonObject = dbModels.toJson();
344 out << "Converted to swift JSON" << Qt::endl;
345
346 CAircraftModelList swiftModels;
347 timer.start();
348 swiftModels.convertFromJson(swiftJsonObject);
349 ms = timer.elapsed();
350 out << "Read via swift JSON format: " << swiftModels.size() << " models in " << ms << "ms" << Qt::endl;
351
352 Q_ASSERT_X(swiftModels.size() == dbModels.size(), Q_FUNC_INFO, "Mismatching container size");
353 return EXIT_SUCCESS;
354 }
355
357 {
358 QElapsedTimer timer;
359 static const QString chars =
360 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~_-=+!\"@#$%^&*()[]{} \t;:\\/?,.<>";
361 QStringList strings;
362 std::generate_n(std::back_inserter(strings), 100000, [] {
363 QString s;
364 std::generate_n(std::back_inserter(s), 10,
365 [] { return chars[CMathUtils::randomInteger(0, static_cast<int>(chars.size() - 1))]; });
366 return s;
367 });
368 QString bigString = strings.join("\n");
369
370 QRegularExpression upperRegex("[A-Z]");
371 upperRegex.optimize();
372
373 timer.start();
374 for (const QString &s : std::as_const(strings))
375 {
376 auto c = containsChar(s, [](QChar c) { return c.isUpper(); });
377 Q_UNUSED(c);
378 }
379 out << "Check 100,000 strings for containing uppercase letter: (utility) " << timer.elapsed() << "ms"
380 << Qt::endl;
381
382 timer.start();
383 for (const QString &s : std::as_const(strings))
384 {
385 auto c = s.contains(upperRegex);
386 Q_UNUSED(c);
387 }
388 out << "Check 100,000 strings for containing uppercase letter: (regex) " << timer.elapsed() << "ms"
389 << Qt::endl
390 << Qt::endl;
391
392 timer.start();
393 for (const QString &s : std::as_const(strings))
394 {
395 auto i = indexOfChar(s, [](QChar c) { return c.isUpper(); });
396 Q_UNUSED(i);
397 }
398 out << "Check 100,000 strings for index of first uppercase letter: (utility) " << timer.elapsed() << "ms"
399 << Qt::endl;
400
401 timer.start();
402 for (const QString &s : std::as_const(strings))
403 {
404 auto i = s.indexOf(upperRegex);
405 Q_UNUSED(i);
406 }
407 out << "Check 100,000 strings for index of first uppercase letter: (regex) " << timer.elapsed() << "ms"
408 << Qt::endl
409 << Qt::endl;
410
411 auto temp = strings;
412 timer.start();
413 for (QString &s : strings)
414 {
415 removeChars(s, [](QChar c) { return c.isUpper(); });
416 }
417 out << "Remove from 100,000 strings all uppercase letters: (utility) " << timer.elapsed() << "ms"
418 << Qt::endl;
419 strings = temp;
420
421 timer.start();
422 for (QString &s : strings)
423 {
424 s.remove(upperRegex);
425 }
426 out << "Remove from 100,000 strings all uppercase letters: (regex) " << timer.elapsed() << "ms"
427 << Qt::endl
428 << Qt::endl;
429
430 timer.start();
431 {
432 auto lines = splitLines(bigString);
433 Q_UNUSED(lines);
434 }
435 out << "Split 100,000 line string into list of lines: (QStringList) " << timer.elapsed() << "ms"
436 << Qt::endl;
437
438 timer.start();
439 {
440 auto lines = splitLinesRefs(bigString);
441 Q_UNUSED(lines);
442 }
443 out << "Split 100,000 line string into list of lines: (QList<QStringView>) " << timer.elapsed() << "ms"
444 << Qt::endl;
445
446 return EXIT_SUCCESS;
447 }
448
450 {
451 const int loop = 250000;
452 QString x;
453 const QString x1 = "11-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
454 const QString x2 = "22-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
455 const QString x3 = "33-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
456 const QString x4 = "44-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
457 const QString x5 = "55-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
458 const QString x6 = "66-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
459 const QString x7 = "77-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
460 const QString x8 = "88-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
461 const QString x9 = "99-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
462
463 QElapsedTimer time;
464 time.start();
465 for (int i = 0; i < loop; i++)
466 {
467 x += "12-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
468 }
469 out << "+= String " << time.elapsed() << "ms" << Qt::endl;
470 x.clear();
471
472 time.start();
473 for (int i = 0; i < loop; i++)
474 {
475 x += QLatin1String("12-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
476 }
477 out << "+= QLatin1String " << time.elapsed() << "ms" << Qt::endl;
478 x.clear();
479
480 time.start();
481 for (int i = 0; i < loop; i++)
482 {
483 x += QStringLiteral("12-1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
484 }
485 out << "+= QStringLiteral " << time.elapsed() << "ms" << Qt::endl;
486 x.clear();
487
488 time.start();
489 for (int i = 0; i < loop; i++)
490 {
491 x = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9;
492 }
493 out << "+ String multiple " << time.elapsed() << "ms" << Qt::endl;
494 x.clear();
495
496 time.start();
497 for (int i = 0; i < loop; i++)
498 {
499 x = x1 % x2 % x3 % x4 % x5 % x6 % x7 % x8 % x9;
500 }
501 out << "% String multiple " << time.elapsed() << "ms" << Qt::endl;
502 x.clear();
503
504 time.start();
505 for (int i = 0; i < loop; i++)
506 {
507 x = x.append(x1).append(x2).append(x3).append(x4).append(x5).append(x6).append(x7).append(x8).append(x9);
508 }
509 out << "append String multiple " << time.elapsed() << "ms" << Qt::endl;
510 x.clear();
511
512 static const QString xArgString("%1 %2 %3 %4 %5 %6 %7 %8 %9");
513 time.start();
514 for (int i = 0; i < loop; i++)
515 {
516 x = xArgString.arg(x1, x2, x3, x4, x5, x6, x7, x8, x9);
517 }
518 out << "arg String multiple " << time.elapsed() << "ms" << Qt::endl;
519 x.clear();
520
521 time.start();
522 for (int i = 0; i < loop; i++)
523 {
524 x = QStringLiteral("%1 %2 %3 %4 %5 %6 %7 %8 %9").arg(x1, x2, x3, x4, x5, x6, x7, x8, x9);
525 }
526 out << "arg QStringLiteral multiple " << time.elapsed() << "ms" << Qt::endl;
527 x.clear();
528
529 return EXIT_SUCCESS;
530 }
531
533 {
534 const int loop = 1e7;
535 QElapsedTimer time;
536 QString x;
537 time.start();
538 for (int i = 0; i < loop; i++)
539 {
540 x = fooString();
541 }
542 out << "by constQString " << time.elapsed() << "ms" << Qt::endl;
543 x.clear();
544
545 time.start();
546 for (int i = 0; i < loop; i++)
547 {
548 x = fooStringLiteral();
549 }
550 out << "by QStringLiteral " << time.elapsed() << "ms" << Qt::endl;
551 x.clear();
552
553 time.start();
554 for (int i = 0; i < loop; i++)
555 {
556 x = QString("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. "
557 "Sed cursus ante dapibus diam. Sed nisi.");
558 }
559 out << "by QString(\"...\") " << time.elapsed() << "ms" << Qt::endl;
560 x.clear();
561
562 time.start();
563 for (int i = 0; i < loop; i++)
564 {
565 x = QStringLiteral("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent "
566 "libero. Sed cursus ante dapibus diam. Sed nisi.");
567 }
568 out << "by QStringLiteral(\"...\") " << time.elapsed() << "ms" << Qt::endl;
569 x.clear();
570
571 time.start();
572 for (int i = 0; i < loop; i++)
573 {
574 QStringList foo = generateList();
575 Q_UNUSED(foo.size());
576 }
577 out << "generated list " << time.elapsed() << "ms" << Qt::endl;
578
579 time.start();
580 for (int i = 0; i < loop; i++)
581 {
582 QStringList foo = replacedList();
583 Q_UNUSED(foo.size());
584 }
585 out << "replaced list " << time.elapsed() << "ms" << Qt::endl;
586
587 return EXIT_SUCCESS;
588 }
589
591 {
592 const CCallsignSet cs10 = CSamplesPerformance::callsigns(10);
593 const CCallsignSet cs25 = CSamplesPerformance::callsigns(25);
594 const CCallsignSet cs50 = CSamplesPerformance::callsigns(50);
595
596 const QMap<CCallsign, CAircraftSituation> m10 = CSamplesPerformance::situationsMap(cs10);
597 const QMap<CCallsign, CAircraftSituation> m25 = CSamplesPerformance::situationsMap(cs25);
598 const QMap<CCallsign, CAircraftSituation> m50 = CSamplesPerformance::situationsMap(cs50);
599
600 const QHash<CCallsign, CAircraftSituation> h10 = CSamplesPerformance::situationsHash(cs10);
601 const QHash<CCallsign, CAircraftSituation> h25 = CSamplesPerformance::situationsHash(cs25);
602 const QHash<CCallsign, CAircraftSituation> h50 = CSamplesPerformance::situationsHash(cs50);
603
604 Q_ASSERT(m10.size() == 10 && h10.size() == 10);
605 Q_ASSERT(m25.size() == 25 && h25.size() == 25);
606 Q_ASSERT(m50.size() == 50 && h50.size() == 50);
607
608 // QList since we have to add callsigns multiple times, set does not allow that
609 QList<CCallsign> cs_10_100_rnd;
610 QList<CCallsign> cs_25_100_rnd;
611 QList<CCallsign> cs_50_100_rnd;
612
613 for (int i = 0; i < 20; ++i)
614 {
615 cs_10_100_rnd.append(cs10.randomElements(5).toQList());
616 cs_25_100_rnd.append(cs25.randomElements(5).toQList());
617 cs_50_100_rnd.append(cs50.randomElements(5).toQList());
618 }
619
620 Q_ASSERT(cs_10_100_rnd.size() == 100);
621 Q_ASSERT(cs_25_100_rnd.size() == 100);
622 Q_ASSERT(cs_50_100_rnd.size() == 100);
623
624 QElapsedTimer time;
625 time.start();
626 for (int i = 1; i < 10000; ++i)
627 {
628 for (const CCallsign &cs : cs_10_100_rnd)
629 {
630 CAircraftSituation s = m10[cs];
631 Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign");
632 }
633 }
634 out << "map 100 out of 10: " << time.elapsed() << "ms" << Qt::endl;
635
636 time.start();
637 for (int i = 1; i < 10000; ++i)
638 {
639 for (const CCallsign &cs : cs_10_100_rnd)
640 {
641 CAircraftSituation s = h10[cs];
642 Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign");
643 }
644 }
645 out << "hash 100 out of 10: " << time.elapsed() << "ms" << Qt::endl;
646
647 time.start();
648 for (int i = 1; i < 10000; ++i)
649 {
650 for (const CCallsign &cs : cs_25_100_rnd)
651 {
652 CAircraftSituation s = m25[cs];
653 Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign");
654 }
655 }
656 out << "map 100 out of 25: " << time.elapsed() << "ms" << Qt::endl;
657
658 time.start();
659 for (int i = 1; i < 10000; ++i)
660 {
661 for (const CCallsign &cs : cs_25_100_rnd)
662 {
663 CAircraftSituation s = h25[cs];
664 Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign");
665 }
666 }
667 out << "hash 100 out of 25: " << time.elapsed() << "ms" << Qt::endl;
668
669 time.start();
670 for (int i = 1; i < 10000; ++i)
671 {
672 for (const CCallsign &cs : cs_50_100_rnd)
673 {
674 CAircraftSituation s = m50[cs];
675 Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign");
676 }
677 }
678 out << "map 100 out of 50: " << time.elapsed() << "ms" << Qt::endl;
679
680 time.start();
681 for (int i = 1; i < 10000; ++i)
682 {
683 for (const CCallsign &cs : cs_50_100_rnd)
684 {
685 CAircraftSituation s = h50[cs];
686 Q_ASSERT_X(s.getCallsign() == cs, Q_FUNC_INFO, "Wromg callsign");
687 }
688 }
689 out << "hash 100 out of 50: " << time.elapsed() << "ms" << Qt::endl;
690
691 return EXIT_SUCCESS;
692 }
693
694 CAircraftSituationList CSamplesPerformance::createSituations(qint64 baseTimeEpoch, int numberOfCallsigns,
695 int numberOfTimes)
696 {
697 CAircraftSituationList situations;
698 for (int cs = 0; cs < numberOfCallsigns; cs++)
699 {
700 CCallsign callsign("CS" + QString::number(cs));
701 CCoordinateGeodetic coordinate(cs, cs, cs);
702 for (int t = 0; t < numberOfTimes; t++)
703 {
704 CAircraftSituation s(callsign, coordinate);
705 s.setMSecsSinceEpoch(baseTimeEpoch + DeltaTime * t);
706 situations.push_back(s);
707 }
708 }
709 return situations;
710 }
711
712 CAircraftModelList CSamplesPerformance::createModels(int numberOfModels, int numberOfMemoParts)
713 {
714 CAircraftIcaoCodeList aircraftIcaos;
715 CLiveryList liveries;
716 CDistributorList distributors;
717 for (int i = 0; i < numberOfMemoParts; ++i)
718 {
719 aircraftIcaos.push_back(CAircraftIcaoCode("A" + QString::number(i), "A" + QString::number(i), "L1P", "Lego",
720 "Foo", CWakeTurbulenceCategory::MEDIUM, false, false, false, 0));
721 liveries.push_back(CLivery(
722 "A" + QString::number(i),
723 CAirlineIcaoCode("A" + QString::number(i), "Foo", CCountry("DE", "Germany"), "Foo", false, false),
724 "Foo", "red", "blue", false));
725 distributors.push_back(CDistributor(QString::number(i), "Foo", {}, {}, CSimulatorInfo::MSFS));
726 }
727
728 CAircraftModelList models;
729 for (int i = 0; i < numberOfModels; ++i)
730 {
731 const auto &aircraftIcao = aircraftIcaos[CMathUtils::randomInteger(0, numberOfMemoParts - 1)];
732 const auto &livery = liveries[CMathUtils::randomInteger(0, numberOfMemoParts - 1)];
733 const auto &distributor = distributors[CMathUtils::randomInteger(0, numberOfMemoParts - 1)];
734 models.push_back(CAircraftModel(QString::number(i), CAircraftModel::TypeUnknown, CSimulatorInfo::MSFS,
735 QString::number(i), QString::number(i), aircraftIcao, livery));
736 models.back().setDistributor(distributor);
737 }
738 return models;
739 }
740
741 void CSamplesPerformance::calculateDistance(int n)
742 {
743 if (n < 1)
744 {
745 return;
746 }
747 CAtcStation atc = CTesting::createStation(1);
748 const QList<CCoordinateGeodetic> pos(
749 { CCoordinateGeodetic(10.0, 10.0, 10.0), CCoordinateGeodetic(20.0, 20.0, 20.0),
750 CCoordinateGeodetic(30.0, 30.0, 30.0), CCoordinateGeodetic(40.0, 40.0, 40.0),
751 CCoordinateGeodetic(50.0, 50.0, 50.0), CCoordinateGeodetic(60.0, 60.0, 60.0),
752 CCoordinateGeodetic(70.0, 70.0, 70.0) });
753 const qsizetype s = pos.size();
754 for (int i = 0; i < n; i++)
755 {
756 const qsizetype p = i % s;
758 }
759 }
760
761 void CSamplesPerformance::copy10kStations(int times)
762 {
763 CAtcStationList stations;
764 for (int i = 0; i < times; i++)
765 {
766 stations = stations10k();
767 stations.pop_back(); // make sure stations are really copied (copy-on-write)
768 }
769 }
770
771 void CSamplesPerformance::parseWgs(int times)
772 {
773 static QStringList wgsLatLng({ "12° 11′ 10″ N", "11° 22′ 33″ W", "48° 21′ 13″ N", "11° 47′ 09″ E",
774 " 8° 21′ 13″ N", "11° 47′ 09″ W", "18° 21′ 13″ S", "11° 47′ 09″ E",
775 "09° 12′ 13″ S", "11° 47′ 09″ W" });
776
777 CCoordinateGeodetic c;
778 const CAltitude a(333, CLengthUnit::m());
779 for (int i = 0; i < times; i++)
780 {
781 int idx = (i % 5) * 2;
782 c = CCoordinateGeodetic::fromWgs84(wgsLatLng.at(idx), wgsLatLng.at(idx + 1), a);
783 }
784 }
785
786 const QString &CSamplesPerformance::fooString()
787 {
788 static const QString s("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent "
789 "libero. Sed cursus ante dapibus diam. Sed nisi.");
790 return s;
791 }
792
793 QString CSamplesPerformance::fooStringLiteral()
794 {
795 return QStringLiteral("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent "
796 "libero. Sed cursus ante dapibus diam. Sed nisi.");
797 }
798
799 QStringList CSamplesPerformance::generateList() { return QStringList({ "1", "2", "3", "4" }); }
800
801 QStringList CSamplesPerformance::replacedList()
802 {
803 static const QStringList l({ "1", "2", "3", "4" });
804 QStringList lc(l);
805 lc[1] = QStringLiteral("6");
806 lc[3] = QStringLiteral("7");
807 return lc;
808 }
809
810 CCallsignSet CSamplesPerformance::callsigns(int number)
811 {
812 CCallsignSet set;
813 static const QString cs("FOO%1");
814 for (int i = 0; i < number; i++)
815 {
816 set.insert(CCallsign(cs.arg(i)));
817 }
818 return set;
819 }
820
821 QMap<CCallsign, CAircraftSituation> CSamplesPerformance::situationsMap(const CCallsignSet &callsigns)
822 {
823 QMap<CCallsign, CAircraftSituation> situations;
824 for (const CCallsign &cs : callsigns)
825 {
826 const CAircraftSituation s(cs);
827 situations.insert(cs, s);
828 }
829 return situations;
830 }
831
832 QHash<CCallsign, CAircraftSituation> CSamplesPerformance::situationsHash(const CCallsignSet &callsigns)
833 {
834 QHash<CCallsign, CAircraftSituation> situations;
835 for (const CCallsign &cs : callsigns)
836 {
837 const CAircraftSituation s(cs);
838 situations.insert(cs, s);
839 }
840 return situations;
841 }
842
843 const CAtcStationList &CSamplesPerformance::stations10k()
844 {
845 static const CAtcStationList s = CTesting::createAtcStations(10000, false);
846 return s;
847 }
848
849 void CSamplesPerformance::accessStationsData(const CAtcStationList &stations, bool byPropertyIndex)
850 {
851 for (const CAtcStation &station : stations)
852 {
853 const QString s = CSamplesPerformance::accessStationData(station, byPropertyIndex);
854 Q_UNUSED(s);
855 }
856 }
857
858 QString CSamplesPerformance::accessStationData(const CAtcStation &station, bool byPropertyIndex)
859 {
860 QString r;
861 if (byPropertyIndex)
862 {
863 r.append(station.propertyByIndex(CPropertyIndex { CAtcStation::IndexCallsign, CCallsign::IndexString })
864 .toString());
865 r.append(station.propertyByIndex(CPropertyIndex { CAtcStation::IndexController, CUser::IndexRealName })
866 .toString());
867 r.append(station
868 .propertyByIndex(
869 CPropertyIndex { CAtcStation::IndexPosition, CCoordinateGeodetic::IndexLatitudeAsString })
870 .toString());
871 r.append(station
872 .propertyByIndex(
873 CPropertyIndex { CAtcStation::IndexPosition, CCoordinateGeodetic::IndexLongitudeAsString })
874 .toString());
875 r.append(station
876 .propertyByIndex(CPropertyIndex { CAtcStation::IndexRelativeDistance,
877 CLength::IndexValueRounded2DigitsWithUnit })
878 .toString());
879 r.append(station.propertyByIndex(CPropertyIndex { CAtcStation::IndexLogoffTime })
880 .toDateTime()
881 .toString("yyyy-MM-dd hh:mm"));
882 }
883 else
884 {
885 r.append(station.getCallsignAsString());
886 r.append(station.getController().getRealName());
887 r.append(station.getPosition().latitudeAsString());
888 r.append(station.getPosition().longitudeAsString());
889 r.append(station.getRelativeDistance().toQString(true));
890 r.append(station.getLogoffTimeUtc().toString("yyyy-MM-dd hh:mm"));
891 }
892 return r;
893 }
894} // namespace swift::sample
iterator insert(const_iterator hint, const T &value)
For compatibility with std::inserter.
Definition collection.h:205
QList< T > toQList() const
Convert to a QList.
Definition collection.h:360
QJsonObject toJson() const
Cast to JSON object.
void convertFromJson(const QJsonObject &json)
Assign from JSON object.
static QString readFileToString(const QString &fileNameAndPath)
Read file into string.
Definition fileutils.cpp:83
Derived randomElements(int n) const
Copy n elements from the container at random.
Definition range.h:151
size_type size() const
Returns number of elements in the sequence.
Definition sequence.h:273
void sortBy(K1 key1, Keys... keys)
In-place sort by some particular key(s).
Definition sequence.h:603
void pop_back()
Removes an element at the end of the sequence.
Definition sequence.h:376
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition sequence.h:308
reference back()
Access the last element.
Definition sequence.h:249
static const QString & staticDbFilesDirectory()
Where static DB files are located.
CONTAINER findAfter(const QDateTime &dateTime) const
List of objects after dateTime (newer).
CONTAINER findBefore(const QDateTime &dateTime) const
List of objects before dateTime (older).
Value object encapsulating information of an aircraft's situation.
const CCallsign & getCallsign() const
Corresponding callsign.
Value object encapsulating a list of ICAO codes.
const geo::CCoordinateGeodetic & getPosition() const
Get the position of the center of the controller's area of visibility.
Definition atcstation.h:141
QString getCallsignAsString() const
Get callsign as string.
Definition atcstation.h:90
const CCallsign & getCallsign() const
Get callsign.
Definition atcstation.h:84
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
const swift::misc::network::CUser & getController() const
Get controller.
Definition atcstation.h:105
const QDateTime & getLogoffTimeUtc() const
Return the expected logoff time (UTC). This data comes from the controller through its ATIS line.
Definition atcstation.h:169
Value object for a list of ATC stations.
Value object encapsulating information of a callsign.
Definition callsign.h:30
Value object for a set of callsigns.
Definition callsignset.h:26
Value object for a list of airports.
Definition liverylist.h:29
CAirlineIcaoCodeList getAirlines() const
All aircraft codes.
static CLiveryList fromDatabaseJsonCaching(const QJsonArray &array, const CAirlineIcaoCodeList &relatedAirlines={})
Caching version from DB data.
CONTAINER findByCallsign(const CCallsign &callsign) const
Find 0..n stations by callsign.
QHash< CCallsign, CONTAINER > splitPerCallsign() const
Split into 0..n containers as per callsign.
static CCoordinateGeodetic fromWgs84(const QString &latitudeWgs84, const QString &longitudeWgs84, const aviation::CAltitude &geodeticHeight={})
Coordinate by WGS84 position data.
QString longitudeAsString() const
Longitude as string.
QString latitudeAsString() const
Latitude as string.
const physical_quantities::CLength & getRelativeDistance() const
Get the distance.
physical_quantities::CLength calculcateAndUpdateRelativeDistance(const geo::ICoordinateGeodetic &position)
Calculcate distance, set it, and return distance.
static QRandomGenerator & randomGenerator()
Thread-local random generator.
Definition mathutils.cpp:71
static int randomInteger(int low, int high)
Random number between low and high.
Definition mathutils.cpp:77
QString toQString(bool i18n=false) const
Cast as QString.
Definition mixinstring.h:74
const QString & getRealName() const
Get full name.
Definition user.h:59
static CLengthUnit m()
Meter m.
Definition units.h:140
void setDistributor(const CDistributor &distributor)
Set distributor.
Value object encapsulating a list of aircraft models.
static CAircraftModelList fromDatabaseJsonCaching(const QJsonArray &array, const aviation::CAircraftIcaoCodeList &aircraftIcaos={}, const aviation::CAircraftCategoryList &aircraftCategories={}, const aviation::CLiveryList &liveries={}, const CDistributorList &distributors={})
Newer version.
static swift::misc::aviation::CAtcStation createStation(int index, bool byPropertyIndex=false)
Single station, annotated by index.
Definition testing.cpp:43
static swift::misc::aviation::CAtcStationList createAtcStations(int number, bool byPropertyIndex=false)
Generate number of ATC stations.
Definition testing.cpp:33
static int samplesStringUtilsVsRegEx(QTextStream &out)
String manipulation (inserter).
static int samplesStringConcat(QTextStream &out)
String manipulation (concatenation).
static int samplesJsonModelAndLivery(QTextStream &out)
JSON loading (database vs. own format.
static int samplesJson(QTextStream &out)
JSON (de)serialization.
static int samplesMisc(QTextStream &out)
Copy, create, RegEx.
static int sampleQMapVsQHashByCallsign(QTextStream &out)
Callsign based hash/map comparison.
static int samplesStringLiteralVsConstQString(QTextStream &out)
const QString vs. QStringLiteral
static int interpolatorScenario(QTextStream &out, int numberOfCallsigns, int numberOfTimes)
Interpolator scenario.
Classes interacting with the swift database (aka "datastore").
Generate data for testing purposes.
Definition testdata.h:45
Free functions in swift::misc.
QString removeChars(const QString &s, F predicate)
Return a string with characters removed that match the given predicate.
Definition stringutils.h:34
int indexOfChar(const QString &s, F predicate)
Index of first character in the string matching the given predicate, or -1 if not found.
Definition stringutils.h:77
SWIFT_MISC_EXPORT QStringList splitLines(const QString &s)
Split a string into multiple lines. Blank lines are skipped.
SWIFT_MISC_EXPORT QList< QStringView > splitLinesRefs(const QString &s)
Split a string into multiple lines. Blank lines are skipped.
bool containsChar(const QString &s, F predicate)
True if any character in the string matches the given predicate.
Definition stringutils.h:64
bool isUpper(char32_t ucs4)
qint64 currentMSecsSinceEpoch()
QString toString(QStringView format) const const
QString filePath(const QString &fileName) const const
qint64 elapsed() const const
bool exists(const QString &fileName)
virtual QString fileName() const const override
QHash< Key, T >::iterator insert(Key &&key, T &&value)
qsizetype size() const const
void append(QList< T > &&value)
qsizetype size() const const
QMap< Key, T >::iterator insert(QMap< Key, T >::const_iterator pos, const Key &key, const T &value)
QMap< Key, T >::size_type size() const const
QRegularExpressionMatch match(QStringView subjectView, qsizetype offset, QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions) const const
void optimize() const const
bool hasMatch() const const
QString & append(QChar ch)
QString arg(Args &&... args) const const
void clear()
bool isEmpty() const const
QString number(double n, char format, int precision)
qsizetype size() const const
QString join(QChar separator) const const
QTextStream & endl(QTextStream &stream)
QDateTime toDateTime() const const
QString toString() const const
Response from our database (depending on JSON DB backend generates).