1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtTest module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "QtTest/qbenchmark.h"
43 #include "QtTest/private/qbenchmark_p.h"
44 #include "QtTest/private/qbenchmarkmetric_p.h"
45
46 #ifdef QT_GUI_LIB
47 #include <QtGui/qapplication.h>
48 #endif
49
50 #include <QtCore/qprocess.h>
51 #include <QtCore/qdir.h>
52 #include <QtCore/qset.h>
53 #include <QtCore/qdebug.h>
54
55 QT_BEGIN_NAMESPACE
56
57 QBenchmarkGlobalData *QBenchmarkGlobalData::current;
58
QBenchmarkGlobalData()59 QBenchmarkGlobalData::QBenchmarkGlobalData()
60 : measurer(0)
61 , walltimeMinimum(-1)
62 , iterationCount(-1)
63 , medianIterationCount(-1)
64 , createChart(false)
65 , verboseOutput(false)
66 , mode_(WallTime)
67 {
68 setMode(mode_);
69 }
70
~QBenchmarkGlobalData()71 QBenchmarkGlobalData::~QBenchmarkGlobalData()
72 {
73 delete measurer;
74 QBenchmarkGlobalData::current = 0;
75 }
76
setMode(Mode mode)77 void QBenchmarkGlobalData::setMode(Mode mode)
78 {
79 mode_ = mode;
80
81 if (measurer)
82 delete measurer;
83 measurer = createMeasurer();
84 }
85
createMeasurer()86 QBenchmarkMeasurerBase * QBenchmarkGlobalData::createMeasurer()
87 {
88 QBenchmarkMeasurerBase *measurer = 0;
89 if (0) {
90 #ifdef QTESTLIB_USE_VALGRIND
91 } else if (mode_ == CallgrindChildProcess || mode_ == CallgrindParentProcess) {
92 measurer = new QBenchmarkCallgrindMeasurer;
93 #endif
94 #ifdef HAVE_TICK_COUNTER
95 } else if (mode_ == TickCounter) {
96 measurer = new QBenchmarkTickMeasurer;
97 #endif
98 } else if (mode_ == EventCounter) {
99 measurer = new QBenchmarkEvent;
100 } else {
101 measurer = new QBenchmarkTimeMeasurer;
102 }
103 measurer->init();
104 return measurer;
105 }
106
adjustMedianIterationCount()107 int QBenchmarkGlobalData::adjustMedianIterationCount()
108 {
109 if (medianIterationCount != -1) {
110 return medianIterationCount;
111 } else {
112 return measurer->adjustMedianCount(1);
113 }
114 }
115
116
117 QBenchmarkTestMethodData *QBenchmarkTestMethodData::current;
118
QBenchmarkTestMethodData()119 QBenchmarkTestMethodData::QBenchmarkTestMethodData()
120 :resultAccepted(false), runOnce(false), iterationCount(-1)
121 {
122
123 }
124
~QBenchmarkTestMethodData()125 QBenchmarkTestMethodData::~QBenchmarkTestMethodData()
126 {
127 QBenchmarkTestMethodData::current = 0;
128 }
129
beginDataRun()130 void QBenchmarkTestMethodData::beginDataRun()
131 {
132 iterationCount = adjustIterationCount(1);
133 }
134
endDataRun()135 void QBenchmarkTestMethodData::endDataRun()
136 {
137
138 }
139
adjustIterationCount(int suggestion)140 int QBenchmarkTestMethodData::adjustIterationCount(int suggestion)
141 {
142 // Let the -iterations option override the measurer.
143 if (QBenchmarkGlobalData::current->iterationCount != -1) {
144 iterationCount = QBenchmarkGlobalData::current->iterationCount;
145 } else {
146 iterationCount = QBenchmarkGlobalData::current->measurer->adjustIterationCount(suggestion);
147 }
148
149 return iterationCount;
150 }
151
setResult(qreal value,QTest::QBenchmarkMetric metric,bool setByMacro)152 void QBenchmarkTestMethodData::setResult(
153 qreal value, QTest::QBenchmarkMetric metric, bool setByMacro)
154 {
155 bool accepted = false;
156
157 // Always accept the result if the iteration count has been
158 // specified on the command line with -iterations.
159 if (QBenchmarkGlobalData::current->iterationCount != -1)
160 accepted = true;
161
162 else if (QBenchmarkTestMethodData::current->runOnce || !setByMacro) {
163 iterationCount = 1;
164 accepted = true;
165 }
166
167 // Test the result directly without calling the measurer if the minimum time
168 // has been specified on the command line with -minimumvalue.
169 else if (QBenchmarkGlobalData::current->walltimeMinimum != -1)
170 accepted = (value > QBenchmarkGlobalData::current->walltimeMinimum);
171 else
172 accepted = QBenchmarkGlobalData::current->measurer->isMeasurementAccepted(value);
173
174 // Accept the result or double the number of iterations.
175 if (accepted)
176 resultAccepted = true;
177 else
178 iterationCount *= 2;
179
180 this->result = QBenchmarkResult(
181 QBenchmarkGlobalData::current->context, value, iterationCount, metric, setByMacro);
182 }
183
184 /*!
185 \class QTest::QBenchmarkIterationController
186 \internal
187
188 The QBenchmarkIterationController class is used by the QBENCHMARK macro to
189 drive the benchmarking loop. It is repsonsible for starting and stopping
190 the timing measurements as well as calling the result reporting functions.
191 */
192
193 /*! \internal
194 */
QBenchmarkIterationController(RunMode runMode)195 QTest::QBenchmarkIterationController::QBenchmarkIterationController(RunMode runMode)
196 {
197 i = 0;
198 if (runMode == RunOnce)
199 QBenchmarkTestMethodData::current->runOnce = true;
200 QTest::beginBenchmarkMeasurement();
201 }
202
QBenchmarkIterationController()203 QTest::QBenchmarkIterationController::QBenchmarkIterationController()
204 {
205 i = 0;
206 QTest::beginBenchmarkMeasurement();
207 }
208
209 /*! \internal
210 */
~QBenchmarkIterationController()211 QTest::QBenchmarkIterationController::~QBenchmarkIterationController()
212 {
213 const qreal result = QTest::endBenchmarkMeasurement();
214 QBenchmarkTestMethodData::current->setResult(result, QBenchmarkGlobalData::current->measurer->metricType());
215 }
216
217 /*! \internal
218 */
isDone()219 bool QTest::QBenchmarkIterationController::isDone()
220 {
221 if (QBenchmarkTestMethodData::current->runOnce)
222 return i > 0;
223 return i >= QTest::iterationCount();
224 }
225
226 /*! \internal
227 */
next()228 void QTest::QBenchmarkIterationController::next()
229 {
230 ++i;
231 }
232
233 /*! \internal
234 */
iterationCount()235 int QTest::iterationCount()
236 {
237 return QBenchmarkTestMethodData::current->iterationCount;
238 }
239
240 /*! \internal
241 */
setIterationCountHint(int count)242 void QTest::setIterationCountHint(int count)
243 {
244 QBenchmarkTestMethodData::current->adjustIterationCount(count);
245 }
246
247 /*! \internal
248 */
setIterationCount(int count)249 void QTest::setIterationCount(int count)
250 {
251 QBenchmarkTestMethodData::current->iterationCount = count;
252 QBenchmarkTestMethodData::current->resultAccepted = true;
253 }
254
255 /*! \internal
256 */
beginBenchmarkMeasurement()257 void QTest::beginBenchmarkMeasurement()
258 {
259 QBenchmarkGlobalData::current->measurer->start();
260 // the clock is ticking after the line above, don't add code here.
261 }
262
263 /*! \internal
264 */
endBenchmarkMeasurement()265 quint64 QTest::endBenchmarkMeasurement()
266 {
267 // the clock is ticking before the line below, don't add code here.
268 return QBenchmarkGlobalData::current->measurer->stop();
269 }
270
271 /*!
272 Sets the benchmark result for this test function to \a result.
273
274 Use this function if you want to report benchmark results without
275 using the QBENCHMARK macro. Use \a metric to specify how QTestLib
276 should interpret the results.
277
278 The context for the result will be the test function name and any
279 data tag from the _data function. This function can only be called
280 once in each test function, subsequent calls will replace the
281 earlier reported results.
282
283 Note that the -iterations command line argument has no effect
284 on test functions without the QBENCHMARK macro.
285
286 \since 4.7
287 */
setBenchmarkResult(qreal result,QTest::QBenchmarkMetric metric)288 void QTest::setBenchmarkResult(qreal result, QTest::QBenchmarkMetric metric)
289 {
290 QBenchmarkTestMethodData::current->setResult(result, metric, false);
291 }
292
293 template <typename T>
qAverage(const T & container)294 Q_TYPENAME T::value_type qAverage(const T &container)
295 {
296 Q_TYPENAME T::const_iterator it = container.constBegin();
297 Q_TYPENAME T::const_iterator end = container.constEnd();
298 Q_TYPENAME T::value_type acc = Q_TYPENAME T::value_type();
299 int count = 0;
300 while (it != end) {
301 acc += *it;
302 ++it;
303 ++count;
304 }
305 return acc / count;
306 }
307
308 QT_END_NAMESPACE
309