Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qbenchmark.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtTest/qbenchmark.h>
5#include <QtTest/private/qbenchmark_p.h>
6#include <QtTest/private/qbenchmarkmetric_p.h>
7#include <QtTest/private/qbenchmarktimemeasurers_p.h>
8
9#include <QtCore/qdir.h>
10#include <QtCore/qset.h>
11#include <QtCore/qdebug.h>
12
14
15QBenchmarkGlobalData *QBenchmarkGlobalData::current;
16
17QBenchmarkGlobalData::QBenchmarkGlobalData()
18{
19 setMode(mode_);
20}
21
22QBenchmarkGlobalData::~QBenchmarkGlobalData()
23{
24 delete measurer;
25 if (QBenchmarkGlobalData::current == this)
26 QBenchmarkGlobalData::current = nullptr;
27}
28
29void QBenchmarkGlobalData::setMode(Mode mode)
30{
31 mode_ = mode;
32
33 delete measurer;
34 measurer = createMeasurer();
35}
36
37QBenchmarkMeasurerBase * QBenchmarkGlobalData::createMeasurer()
38{
39 QBenchmarkMeasurerBase *measurer = nullptr;
40 if (0) {
41#if QT_CONFIG(valgrind)
42 } else if (mode_ == CallgrindChildProcess || mode_ == CallgrindParentProcess) {
43 measurer = new QBenchmarkCallgrindMeasurer;
44#endif
45#ifdef QTESTLIB_USE_PERF_EVENTS
46 } else if (mode_ == PerfCounter) {
47 measurer = new QBenchmarkPerfEventsMeasurer;
48#endif
49#ifdef HAVE_TICK_COUNTER
50 } else if (mode_ == TickCounter) {
51 measurer = new QBenchmarkTickMeasurer;
52#endif
53 } else if (mode_ == EventCounter) {
54 measurer = new QBenchmarkEvent;
55 } else {
56 measurer = new QBenchmarkTimeMeasurer;
57 }
58 return measurer;
59}
60
61int QBenchmarkGlobalData::adjustMedianIterationCount()
62{
63 return medianIterationCount != -1
64 ? medianIterationCount : measurer->adjustMedianCount(1);
65}
66
67
68QBenchmarkTestMethodData *QBenchmarkTestMethodData::current;
69
70QBenchmarkTestMethodData::QBenchmarkTestMethodData() = default;
71
72QBenchmarkTestMethodData::~QBenchmarkTestMethodData()
73{
74 QBenchmarkTestMethodData::current = nullptr;
75}
76
77void QBenchmarkTestMethodData::beginDataRun()
78{
79 iterationCount = adjustIterationCount(1);
80}
81
82void QBenchmarkTestMethodData::endDataRun()
83{
84}
85
86int QBenchmarkTestMethodData::adjustIterationCount(int suggestion)
87{
88 // Let the -iterations option override the measurer.
89 if (QBenchmarkGlobalData::current->iterationCount != -1) {
90 iterationCount = QBenchmarkGlobalData::current->iterationCount;
91 } else {
92 iterationCount = QBenchmarkGlobalData::current->measurer->adjustIterationCount(suggestion);
93 }
94
95 return iterationCount;
96}
97
98void QBenchmarkTestMethodData::setResults(const QList<QBenchmarkMeasurerBase::Measurement> &list,
99 bool setByMacro)
100{
101 bool accepted = false;
102 QBenchmarkMeasurerBase::Measurement firstMeasurement = {};
103 if (!list.isEmpty())
104 firstMeasurement = list.constFirst();
105
106 // Always accept the result if the iteration count has been
107 // specified on the command line with -iterations.
108 if (QBenchmarkGlobalData::current->iterationCount != -1)
109 accepted = true;
110
111 else if (QBenchmarkTestMethodData::current->runOnce || !setByMacro) {
112 iterationCount = 1;
113 accepted = true;
114 }
115
116 // Test the result directly without calling the measurer if the minimum time
117 // has been specified on the command line with -minimumvalue.
118 else if (QBenchmarkGlobalData::current->walltimeMinimum != -1)
119 accepted = (firstMeasurement.value > QBenchmarkGlobalData::current->walltimeMinimum);
120 else
121 accepted = QBenchmarkGlobalData::current->measurer->isMeasurementAccepted(firstMeasurement);
122
123 // Accept the result or double the number of iterations.
124 if (accepted)
125 resultAccepted = true;
126 else
127 iterationCount *= 2;
128
129 valid = true;
130 results.reserve(list.size());
131 for (auto m : list)
132 results.emplaceBack(QBenchmarkGlobalData::current->context, m, iterationCount, setByMacro);
133}
134
135/*!
136 \class QTest::QBenchmarkIterationController
137 \internal
138
139 The QBenchmarkIterationController class is used by the QBENCHMARK macro to
140 drive the benchmarking loop. It is responsible for starting and stopping
141 the timing measurements as well as calling the result reporting functions.
142*/
143
144/*! \internal
145*/
146QTest::QBenchmarkIterationController::QBenchmarkIterationController(RunMode runMode)
147{
148 i = 0;
149 if (runMode == RunOnce)
150 QBenchmarkTestMethodData::current->runOnce = true;
151 QTest::beginBenchmarkMeasurement();
152}
153
154QTest::QBenchmarkIterationController::QBenchmarkIterationController()
155{
156 i = 0;
157 QTest::beginBenchmarkMeasurement();
158}
159
160/*! \internal
161*/
162QTest::QBenchmarkIterationController::~QBenchmarkIterationController()
163{
164 QBenchmarkTestMethodData::current->setResults(QTest::endBenchmarkMeasurement());
165}
166
167/*! \internal
168*/
169bool QTest::QBenchmarkIterationController::isDone() const noexcept
170{
171 if (QBenchmarkTestMethodData::current->runOnce)
172 return i > 0;
173 return i >= QTest::iterationCount();
174}
175
176/*! \internal
177*/
178void QTest::QBenchmarkIterationController::next() noexcept
179{
180 ++i;
181}
182
183/*! \internal
184*/
185int QTest::iterationCount() noexcept
186{
187 return QBenchmarkTestMethodData::current->iterationCount;
188}
189
190/*! \internal
191*/
192void QTest::setIterationCountHint(int count)
193{
194 QBenchmarkTestMethodData::current->adjustIterationCount(count);
195}
196
197/*! \internal
198*/
199void QTest::setIterationCount(int count)
200{
201 QBenchmarkTestMethodData::current->iterationCount = count;
202 QBenchmarkTestMethodData::current->resultAccepted = true;
203}
204
205/*! \internal
206*/
207void QTest::beginBenchmarkMeasurement()
208{
209 QBenchmarkGlobalData::current->measurer->start();
210 // the clock is ticking after the line above, don't add code here.
211}
212
213/*! \internal
214*/
215QList<QBenchmarkMeasurerBase::Measurement> QTest::endBenchmarkMeasurement()
216{
217 // the clock is ticking before the line below, don't add code here.
218 return QBenchmarkGlobalData::current->measurer->stop();
219}
220
221/*!
222 Sets the benchmark result for this test function to \a result.
223
224 Use this function if you want to report benchmark results without
225 using the QBENCHMARK macro. Use \a metric to specify how Qt Test
226 should interpret the results.
227
228 The context for the result will be the test function name and any
229 data tag from the _data function. This function can only be called
230 once in each test function, subsequent calls will replace the
231 earlier reported results.
232
233 Note that the -iterations command line argument has no effect
234 on test functions without the QBENCHMARK macro.
235
236 \since 4.7
237*/
238void QTest::setBenchmarkResult(qreal result, QTest::QBenchmarkMetric metric)
239{
240 QBenchmarkTestMethodData::current->setResult({ result, metric }, false);
241}
242
243template <typename T>
244typename T::value_type qAverage(const T &container)
245{
246 typename T::const_iterator it = container.constBegin();
247 typename T::const_iterator end = container.constEnd();
248 typename T::value_type acc = typename T::value_type();
249 int count = 0;
250 while (it != end) {
251 acc += *it;
252 ++it;
253 ++count;
254 }
255 return acc / count;
256}
257
258QT_END_NAMESPACE
T::value_type qAverage(const T &container)