tests/auto/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
child 7 f7bc934e204c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 #include <QThread>
       
    42 #include "../qfuture/versioncheck.h"
       
    43 
       
    44 struct TestIterator
       
    45 {
       
    46     TestIterator(int i)
       
    47     :i(i) { }
       
    48 
       
    49     int operator-(const TestIterator &other)
       
    50     {
       
    51         return i - other.i;
       
    52     }
       
    53 
       
    54     TestIterator& operator++()
       
    55     {
       
    56         ++i;
       
    57         return *this;
       
    58     }
       
    59 
       
    60     bool operator!=(const TestIterator &other) const
       
    61     {
       
    62         return i != other.i;
       
    63     }
       
    64 
       
    65     int i;
       
    66 };
       
    67 
       
    68 #include <qiterator.h>
       
    69 #ifndef QT_NO_STL
       
    70 namespace std {
       
    71 template <>
       
    72 struct iterator_traits<TestIterator>
       
    73 {
       
    74     typedef random_access_iterator_tag iterator_category;
       
    75 };
       
    76 
       
    77 int distance(TestIterator &a, TestIterator &b)
       
    78 {
       
    79     return b - a;
       
    80 }
       
    81 
       
    82 }
       
    83 #endif
       
    84 
       
    85 
       
    86 #include <qtconcurrentiteratekernel.h>
       
    87 #include <QtTest/QtTest>
       
    88 
       
    89 #ifndef QT_NO_CONCURRENT_TEST
       
    90 
       
    91 using namespace QtConcurrent;
       
    92 
       
    93 class tst_iteratekernel: public QObject
       
    94 {
       
    95     Q_OBJECT
       
    96 private slots:
       
    97     // "for" iteration tests:
       
    98     void instantiate();
       
    99     void cancel();
       
   100     void stresstest();
       
   101     void noIterations();
       
   102     void throttling();
       
   103     void blockSize();
       
   104     void multipleResults();
       
   105 #if 0
       
   106     //"while" iterations tests:
       
   107     void instantiateWhile();
       
   108     void stresstestWhile();
       
   109 #endif
       
   110 };
       
   111 
       
   112 QAtomicInt iterations;
       
   113 class PrintFor : public IterateKernel<TestIterator, void>
       
   114 {
       
   115 public:
       
   116     PrintFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) {iterations = 0; }
       
   117     bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *)
       
   118     {
       
   119         iterations.fetchAndAddRelaxed(end - begin);
       
   120 #ifdef PRINT
       
   121         qDebug() << QThread::currentThread() << "iteration" << begin <<  "to" << end << "(exclusive)";
       
   122 #endif
       
   123         return false;
       
   124     }
       
   125     bool runIteration(TestIterator it, int index , void *result)
       
   126     { 
       
   127         return runIterations(it, index, index + 1, result);
       
   128     }
       
   129 
       
   130 };
       
   131 
       
   132 class SleepPrintFor : public IterateKernel<TestIterator, void>
       
   133 {
       
   134 public:
       
   135     SleepPrintFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) {iterations = 0; }
       
   136     inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *)
       
   137     {
       
   138         QTest::qSleep(200);
       
   139         iterations.fetchAndAddRelaxed(end - begin);
       
   140 #ifdef PRINT
       
   141         qDebug() << QThread::currentThread() << "iteration" << begin <<  "to" << end << "(exclusive)";
       
   142 #endif
       
   143         return false;
       
   144     }
       
   145     bool runIteration(TestIterator it, int index , void *result)
       
   146     { 
       
   147         return runIterations(it, index, index + 1, result);
       
   148     }
       
   149 };
       
   150 
       
   151 
       
   152 void tst_iteratekernel::instantiate()
       
   153 {
       
   154     startThreadEngine(new PrintFor(0, 40)).startBlocking();
       
   155     QCOMPARE((int)iterations, 40);
       
   156 }
       
   157 
       
   158 void tst_iteratekernel::cancel()
       
   159 {
       
   160     {
       
   161         QFuture<void> f = startThreadEngine(new SleepPrintFor(0, 40)).startAsynchronously();
       
   162         f.cancel();
       
   163         f.waitForFinished();
       
   164         QVERIFY(f.isCanceled());
       
   165         QVERIFY(int(iterations) <= QThread::idealThreadCount()); // the threads might run one iteration each before they are canceled.
       
   166     }
       
   167 }
       
   168 
       
   169 QAtomicInt counter;
       
   170 class CountFor : public IterateKernel<TestIterator, void>
       
   171 {
       
   172 public:
       
   173     CountFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) {iterations = 0; }
       
   174     inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *)
       
   175     {
       
   176         counter.fetchAndAddRelaxed(end - begin);
       
   177         return false;
       
   178     }
       
   179     bool runIteration(TestIterator it, int index , void *result)
       
   180     { 
       
   181         return runIterations(it, index, index + 1, result);
       
   182     }
       
   183 };
       
   184 
       
   185 void tst_iteratekernel::stresstest()
       
   186 {
       
   187     const int iterations = 1000;
       
   188     const int times = 50;
       
   189     for (int i = 0; i < times; ++i) {
       
   190         counter = 0;
       
   191         CountFor f(0, iterations);
       
   192         f.startBlocking();
       
   193         QCOMPARE((int)counter, iterations);
       
   194     }
       
   195 }
       
   196 
       
   197 void tst_iteratekernel::noIterations()
       
   198 {
       
   199     const int times = 20000;
       
   200     for (int i = 0; i < times; ++i)
       
   201         startThreadEngine(new IterateKernel<TestIterator, void>(0, 0)).startBlocking();
       
   202 }
       
   203 
       
   204 QSet<QThread *> threads;
       
   205 class ThrottleFor : public IterateKernel<TestIterator, void>
       
   206 {
       
   207 public:
       
   208     // this class throttles between iterations 100 and 200,
       
   209     // and then records how many threads that run between
       
   210     // iterations 140 and 160.
       
   211     ThrottleFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) {iterations = 0; throttling = false; }
       
   212     inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *)
       
   213     {
       
   214         if (200 >= begin && 200 < end) {
       
   215             throttling = false;
       
   216         }
       
   217 
       
   218         iterations.fetchAndAddRelaxed(end - begin);
       
   219 
       
   220         QThread *thread = QThread::currentThread();
       
   221 
       
   222         if (begin > 140 && end < 160)
       
   223             threads.insert(thread);
       
   224 
       
   225         if (100 >= begin && 100 < end) {
       
   226             throttling = true;
       
   227         }
       
   228         
       
   229         QTest::qWait(1);
       
   230 
       
   231         return false;
       
   232     }
       
   233     bool runIteration(TestIterator it, int index , void *result)
       
   234     { 
       
   235         return runIterations(it, index, index + 1, result);
       
   236     }
       
   237 
       
   238     bool shouldThrottleThread()
       
   239     {
       
   240        return (iterations > 100 && iterations < 200);
       
   241     }
       
   242     bool throttling;
       
   243 };
       
   244 
       
   245 void tst_iteratekernel::throttling()
       
   246 {
       
   247     const int totalIterations = 400;
       
   248     iterations = 0;
       
   249 
       
   250     threads.clear();
       
   251 
       
   252     ThrottleFor f(0, totalIterations);
       
   253     f.startBlocking();
       
   254 
       
   255     QCOMPARE((int)iterations, totalIterations);
       
   256 
       
   257 
       
   258     QCOMPARE(threads.count(), 1);
       
   259 }
       
   260 
       
   261 
       
   262 int peakBlockSize = 0;
       
   263 class BlockSizeRecorder : public IterateKernel<TestIterator, void>
       
   264 {
       
   265 public:
       
   266     BlockSizeRecorder(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, void>(begin, end) { }
       
   267     inline bool runIterations(TestIterator, int begin, int end, void *)
       
   268     {
       
   269         peakBlockSize = qMax(peakBlockSize, end - begin);
       
   270         return false;
       
   271     }
       
   272 };
       
   273 
       
   274 void tst_iteratekernel::blockSize()
       
   275 {
       
   276 #ifdef QT_NO_STL
       
   277     QSKIP("Missing stl iterators prevent correct block size calculation", SkipAll);
       
   278 #endif
       
   279     const int expectedMinimumBlockSize = 1024 / QThread::idealThreadCount();
       
   280     BlockSizeRecorder(0, 10000).startBlocking();
       
   281     if (peakBlockSize < expectedMinimumBlockSize)
       
   282         qDebug() << "block size" << peakBlockSize;
       
   283     QVERIFY(peakBlockSize >= expectedMinimumBlockSize);
       
   284 }
       
   285 
       
   286 class MultipleResultsFor : public IterateKernel<TestIterator, int>
       
   287 {
       
   288 public:
       
   289     MultipleResultsFor(TestIterator begin, TestIterator end) : IterateKernel<TestIterator, int>(begin, end) { }
       
   290     inline bool runIterations(TestIterator, int begin, int end, int *results)
       
   291     {
       
   292         for (int i = begin; i < end; ++i)
       
   293             results[i - begin] = i;
       
   294         return true;
       
   295     }
       
   296 };
       
   297 
       
   298 
       
   299 void tst_iteratekernel::multipleResults()
       
   300 {
       
   301 #ifdef QT_NO_STL
       
   302     QSKIP("Missing stl iterators prevent correct summation", SkipAll);
       
   303 #endif
       
   304     QFuture<int> f = startThreadEngine(new MultipleResultsFor(0, 10)).startAsynchronously();
       
   305     QCOMPARE(f.results().count() , 10);
       
   306     QCOMPARE(f.resultAt(0), 0);
       
   307     QCOMPARE(f.resultAt(5), 5);
       
   308     QCOMPARE(f.resultAt(9), 9);
       
   309     f.waitForFinished();
       
   310 }
       
   311 
       
   312 #if 0
       
   313 class PrintWhile : public IterateKernel<TestIterator, void>
       
   314 {
       
   315 public:
       
   316     PrintWhile() : IterateKernel<TestIterator, void>(0, 10, WhileIteration) { }
       
   317     bool runIteration(TestIterator it, TestIterator, void *)
       
   318     {
       
   319         return false;
       
   320     }
       
   321 };
       
   322 
       
   323 void tst_iteratekernel::instantiateWhile()
       
   324 {
       
   325     PrintWhile w;
       
   326     w.startBlocking();
       
   327 }
       
   328 
       
   329 QAtomicInt iterationCount;
       
   330 class StressWhile : public IterateKernel<TestIterator, void>
       
   331 {
       
   332 public:
       
   333     StressWhile(TestIterator iterations) : IterateKernel<TestIterator, void>(0, iterations, WhileIteration) { }
       
   334     bool runIteration(TestIterator it, TestIterator index, void *)
       
   335     {
       
   336         if (it == index) // should match.
       
   337             ::iterationCount.ref();
       
   338         return false;
       
   339     }
       
   340 };
       
   341 
       
   342 void tst_iteratekernel::stresstestWhile()
       
   343 {
       
   344     int iterations = 100000;
       
   345     StressWhile w(iterations);
       
   346     w.startBlocking();
       
   347     QCOMPARE(int(iterationCount), iterations);
       
   348 }
       
   349 #endif
       
   350 
       
   351 QTEST_MAIN(tst_iteratekernel)
       
   352 
       
   353 #include "tst_qtconcurrentiteratekernel.moc"
       
   354 
       
   355 #else
       
   356 QTEST_NOOP_MAIN
       
   357 #endif