Merge remote-tracking branch 'base/master' into refactor
[profile/ivi/qtbase.git] / src / testlib / qbenchmark.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtTest module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
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/qguiapplication.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
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
71 QBenchmarkGlobalData::~QBenchmarkGlobalData()
72 {
73     delete measurer;
74     QBenchmarkGlobalData::current = 0;
75 }
76
77 void QBenchmarkGlobalData::setMode(Mode mode)
78 {
79     mode_ = mode;
80
81     if (measurer)
82         delete measurer;
83     measurer = createMeasurer();
84 }
85
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
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
119 QBenchmarkTestMethodData::QBenchmarkTestMethodData()
120 :resultAccepted(false), runOnce(false), iterationCount(-1)
121 {
122    
123 }
124
125 QBenchmarkTestMethodData::~QBenchmarkTestMethodData()
126 {
127     QBenchmarkTestMethodData::current = 0;
128 }
129
130 void QBenchmarkTestMethodData::beginDataRun()
131 {
132     iterationCount = adjustIterationCount(1);
133 }
134
135 void QBenchmarkTestMethodData::endDataRun()
136 {
137
138 }
139
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
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 */
195 QTest::QBenchmarkIterationController::QBenchmarkIterationController(RunMode runMode)
196 {
197     i = 0;
198     if (runMode == RunOnce)
199         QBenchmarkTestMethodData::current->runOnce = true;    
200     QTest::beginBenchmarkMeasurement();
201 }
202
203 QTest::QBenchmarkIterationController::QBenchmarkIterationController()
204 {
205     i = 0;
206     QTest::beginBenchmarkMeasurement();
207 }
208
209 /*! \internal
210 */
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 */
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 */
228 void QTest::QBenchmarkIterationController::next()
229 {
230     ++i;
231 }
232
233 /*! \internal
234 */
235 int QTest::iterationCount()
236 {
237     return QBenchmarkTestMethodData::current->iterationCount;
238 }
239
240 /*! \internal
241 */
242 void QTest::setIterationCountHint(int count)
243 {
244     QBenchmarkTestMethodData::current->adjustIterationCount(count);
245 }
246
247 /*! \internal
248 */
249 void QTest::setIterationCount(int count)
250 {
251     QBenchmarkTestMethodData::current->iterationCount = count;
252     QBenchmarkTestMethodData::current->resultAccepted = true;
253 }
254
255 /*! \internal
256 */
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 */
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 */
288 void QTest::setBenchmarkResult(qreal result, QTest::QBenchmarkMetric metric)
289 {
290     QBenchmarkTestMethodData::current->setResult(result, metric, false);
291 }
292
293 template <typename T>
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