~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the test suite 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 Digia.  For licensing terms and
 
14
** conditions see http://qt.digia.com/licensing.  For further information
 
15
** use the contact form at http://qt.digia.com/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 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL included in the
 
21
** packaging of this file.  Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 2.1 requirements
 
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
24
**
 
25
** In addition, as a special exception, Digia gives you certain additional
 
26
** rights.  These rights are described in the Digia Qt LGPL Exception
 
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
28
**
 
29
** GNU General Public License Usage
 
30
** Alternatively, this file may be used under the terms of the GNU
 
31
** General Public License version 3.0 as published by the Free Software
 
32
** Foundation and appearing in the file LICENSE.GPL included in the
 
33
** packaging of this file.  Please review the following information to
 
34
** ensure the GNU General Public License version 3.0 requirements will be
 
35
** met: http://www.gnu.org/copyleft/gpl.html.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include <QtCore/QtCore>
 
43
#include <QtTest/QtTest>
 
44
 
 
45
#include <math.h>
 
46
 
 
47
//#define USE_SEM_T
 
48
 
 
49
#if defined(Q_OS_UNIX)
 
50
#if !defined(USE_SEM_T)
 
51
#  include <pthread.h>
 
52
#  include <errno.h>
 
53
typedef pthread_mutex_t NativeMutexType;
 
54
void NativeMutexInitialize(NativeMutexType *mutex)
 
55
{
 
56
    pthread_mutex_init(mutex, NULL);
 
57
}
 
58
void NativeMutexDestroy(NativeMutexType *mutex)
 
59
{
 
60
    pthread_mutex_destroy(mutex);
 
61
}
 
62
void NativeMutexLock(NativeMutexType *mutex)
 
63
{
 
64
    pthread_mutex_lock(mutex);
 
65
}
 
66
void NativeMutexUnlock(NativeMutexType *mutex)
 
67
{
 
68
    pthread_mutex_unlock(mutex);
 
69
}
 
70
#else
 
71
#  include <semaphore.h>
 
72
typedef sem_t NativeMutexType;
 
73
void NativeMutexInitialize(NativeMutexType *mutex)
 
74
{
 
75
    sem_init(mutex, false, 1);
 
76
}
 
77
void NativeMutexDestroy(NativeMutexType *mutex)
 
78
{
 
79
    sem_destroy(mutex);
 
80
}
 
81
void NativeMutexLock(NativeMutexType *mutex)
 
82
{
 
83
    sem_wait(mutex);
 
84
}
 
85
void NativeMutexUnlock(NativeMutexType *mutex)
 
86
{
 
87
    sem_post(mutex);
 
88
}
 
89
#endif
 
90
#elif defined(Q_OS_WIN)
 
91
#  define _WIN32_WINNT 0x0400
 
92
#  include <windows.h>
 
93
typedef CRITICAL_SECTION NativeMutexType;
 
94
void NativeMutexInitialize(NativeMutexType *mutex)
 
95
{
 
96
    InitializeCriticalSection(mutex);
 
97
}
 
98
void NativeMutexDestroy(NativeMutexType *mutex)
 
99
{
 
100
    DeleteCriticalSection(mutex);
 
101
}
 
102
void NativeMutexLock(NativeMutexType *mutex)
 
103
{
 
104
    EnterCriticalSection(mutex);
 
105
}
 
106
void NativeMutexUnlock(NativeMutexType *mutex)
 
107
{
 
108
    LeaveCriticalSection(mutex);
 
109
}
 
110
#endif
 
111
 
 
112
class tst_QMutex : public QObject
 
113
{
 
114
    Q_OBJECT
 
115
 
 
116
    int threadCount;
 
117
 
 
118
public:
 
119
    // barriers for the contended tests
 
120
    static QSemaphore semaphore1, semaphore2, semaphore3, semaphore4;
 
121
 
 
122
    tst_QMutex()
 
123
    {
 
124
        // at least 2 threads, even on single cpu/core machines
 
125
        threadCount = qMax(2, QThread::idealThreadCount());
 
126
        qDebug("thread count: %d", threadCount);
 
127
    }
 
128
 
 
129
private slots:
 
130
    void noThread_data();
 
131
    void noThread();
 
132
 
 
133
    void constructionNative();
 
134
    void uncontendedNative();
 
135
    void constructionQMutex();
 
136
    void uncontendedQMutex();
 
137
    void uncontendedQMutexLocker();
 
138
 
 
139
    void contendedNative_data();
 
140
    void contendedQMutex_data() { contendedNative_data(); }
 
141
    void contendedQMutexLocker_data() { contendedNative_data(); }
 
142
 
 
143
    void contendedNative();
 
144
    void contendedQMutex();
 
145
    void contendedQMutexLocker();
 
146
};
 
147
 
 
148
QSemaphore tst_QMutex::semaphore1;
 
149
QSemaphore tst_QMutex::semaphore2;
 
150
QSemaphore tst_QMutex::semaphore3;
 
151
QSemaphore tst_QMutex::semaphore4;
 
152
 
 
153
void tst_QMutex::noThread_data()
 
154
{
 
155
    QTest::addColumn<int>("t");
 
156
 
 
157
    QTest::newRow("noLock") << 1;
 
158
    QTest::newRow("QMutex") << 3;
 
159
    QTest::newRow("QMutexLocker") << 4;
 
160
}
 
161
 
 
162
void tst_QMutex::noThread()
 
163
{
 
164
    volatile int count = 0;
 
165
    const int N = 5000000;
 
166
    QMutex mtx;
 
167
 
 
168
    QFETCH(int, t);
 
169
    switch(t) {
 
170
        case 1:
 
171
            QBENCHMARK {
 
172
                count = 0;
 
173
                for (int i = 0; i < N; i++) {
 
174
                    count++;
 
175
                }
 
176
            }
 
177
            break;
 
178
        case 3:
 
179
            QBENCHMARK {
 
180
                count = 0;
 
181
                for (int i = 0; i < N; i++) {
 
182
                    mtx.lock();
 
183
                    count++;
 
184
                    mtx.unlock();
 
185
                }
 
186
            }
 
187
            break;
 
188
        case 4:
 
189
            QBENCHMARK {
 
190
                count = 0;
 
191
                for (int i = 0; i < N; i++) {
 
192
                    QMutexLocker locker(&mtx);
 
193
                    count++;
 
194
                }
 
195
            }
 
196
            break;
 
197
    }
 
198
    QCOMPARE(int(count), N);
 
199
}
 
200
 
 
201
void tst_QMutex::constructionNative()
 
202
{
 
203
    QBENCHMARK {
 
204
        NativeMutexType mutex;
 
205
        NativeMutexInitialize(&mutex);
 
206
        NativeMutexDestroy(&mutex);
 
207
    }
 
208
}
 
209
 
 
210
void tst_QMutex::uncontendedNative()
 
211
{
 
212
    NativeMutexType mutex;
 
213
    NativeMutexInitialize(&mutex);
 
214
    QBENCHMARK {
 
215
        NativeMutexLock(&mutex);
 
216
        NativeMutexUnlock(&mutex);
 
217
    }
 
218
    NativeMutexDestroy(&mutex);
 
219
}
 
220
 
 
221
void tst_QMutex::constructionQMutex()
 
222
{
 
223
    QBENCHMARK {
 
224
        QMutex mutex;
 
225
        Q_UNUSED(mutex);
 
226
    }
 
227
}
 
228
 
 
229
void tst_QMutex::uncontendedQMutex()
 
230
{
 
231
    QMutex mutex;
 
232
    QBENCHMARK {
 
233
        mutex.lock();
 
234
        mutex.unlock();
 
235
    }
 
236
}
 
237
 
 
238
void tst_QMutex::uncontendedQMutexLocker()
 
239
{
 
240
    QMutex mutex;
 
241
    QBENCHMARK {
 
242
        QMutexLocker locker(&mutex);
 
243
    }
 
244
}
 
245
 
 
246
void tst_QMutex::contendedNative_data()
 
247
{
 
248
    QTest::addColumn<int>("iterations");
 
249
    QTest::addColumn<int>("msleepDuration");
 
250
    QTest::addColumn<bool>("use2mutexes");
 
251
 
 
252
    QTest::newRow("baseline")               <<    0 <<  -1 << false;
 
253
 
 
254
    QTest::newRow("no msleep, 1 mutex")     << 1000 <<  -1 << false;
 
255
    QTest::newRow("no msleep, 2 mutexes")   << 1000 <<  -1 << true;
 
256
    QTest::newRow("msleep(0), 1 mutex")     << 1000 <<   0 << false;
 
257
    QTest::newRow("msleep(0), 2 mutexes")   << 1000 <<   0 << true;
 
258
    QTest::newRow("msleep(1), 1 mutex")     <<   10 <<   1 << false;
 
259
    QTest::newRow("msleep(1), 2 mutexes")   <<   10 <<   1 << true;
 
260
    QTest::newRow("msleep(2), 1 mutex")     <<   10 <<   2 << false;
 
261
    QTest::newRow("msleep(2), 2 mutexes")   <<   10 <<   2 << true;
 
262
    QTest::newRow("msleep(10), 1 mutex")    <<   10 <<  10 << false;
 
263
    QTest::newRow("msleep(10), 2 mutexes")  <<   10 <<  10 << true;
 
264
}
 
265
 
 
266
class NativeMutexThread : public QThread
 
267
{
 
268
    NativeMutexType *mutex1, *mutex2;
 
269
    int iterations, msleepDuration;
 
270
    bool use2mutexes;
 
271
public:
 
272
    bool done;
 
273
    NativeMutexThread(NativeMutexType *mutex1, NativeMutexType *mutex2, int iterations, int msleepDuration, bool use2mutexes)
 
274
        : mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
 
275
    { }
 
276
    void run() {
 
277
        forever {
 
278
            tst_QMutex::semaphore1.release();
 
279
            tst_QMutex::semaphore2.acquire();
 
280
            if (done)
 
281
                break;
 
282
            for (int i = 0; i < iterations; ++i) {
 
283
                NativeMutexLock(mutex1);
 
284
                if (use2mutexes)
 
285
                    NativeMutexLock(mutex2);
 
286
                if (msleepDuration >= 0)
 
287
                    msleep(msleepDuration);
 
288
                if (use2mutexes)
 
289
                    NativeMutexUnlock(mutex2);
 
290
                NativeMutexUnlock(mutex1);
 
291
 
 
292
                QThread::yieldCurrentThread();
 
293
            }
 
294
            tst_QMutex::semaphore3.release();
 
295
            tst_QMutex::semaphore4.acquire();
 
296
        }
 
297
    }
 
298
};
 
299
 
 
300
void tst_QMutex::contendedNative()
 
301
{
 
302
    QFETCH(int, iterations);
 
303
    QFETCH(int, msleepDuration);
 
304
    QFETCH(bool, use2mutexes);
 
305
 
 
306
    NativeMutexType mutex1, mutex2;
 
307
    NativeMutexInitialize(&mutex1);
 
308
    NativeMutexInitialize(&mutex2);
 
309
 
 
310
    QVector<NativeMutexThread *> threads(threadCount);
 
311
    for (int i = 0; i < threads.count(); ++i) {
 
312
        threads[i] = new NativeMutexThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
 
313
        threads[i]->start();
 
314
    }
 
315
 
 
316
    QBENCHMARK {
 
317
        semaphore1.acquire(threadCount);
 
318
        semaphore2.release(threadCount);
 
319
        semaphore3.acquire(threadCount);
 
320
        semaphore4.release(threadCount);
 
321
    }
 
322
 
 
323
    for (int i = 0; i < threads.count(); ++i)
 
324
        threads[i]->done = true;
 
325
    semaphore1.acquire(threadCount);
 
326
    semaphore2.release(threadCount);
 
327
    for (int i = 0; i < threads.count(); ++i)
 
328
        threads[i]->wait();
 
329
    qDeleteAll(threads);
 
330
 
 
331
    NativeMutexDestroy(&mutex1);
 
332
    NativeMutexDestroy(&mutex2);
 
333
}
 
334
 
 
335
class QMutexThread : public QThread
 
336
{
 
337
    QMutex *mutex1, *mutex2;
 
338
    int iterations, msleepDuration;
 
339
    bool use2mutexes;
 
340
public:
 
341
    bool done;
 
342
    QMutexThread(QMutex *mutex1, QMutex *mutex2, int iterations, int msleepDuration, bool use2mutexes)
 
343
        : mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
 
344
    { }
 
345
    void run() {
 
346
        forever {
 
347
            tst_QMutex::semaphore1.release();
 
348
            tst_QMutex::semaphore2.acquire();
 
349
            if (done)
 
350
                break;
 
351
            for (int i = 0; i < iterations; ++i) {
 
352
                mutex1->lock();
 
353
                if (use2mutexes)
 
354
                    mutex2->lock();
 
355
                if (msleepDuration >= 0)
 
356
                    msleep(msleepDuration);
 
357
                if (use2mutexes)
 
358
                    mutex2->unlock();
 
359
                mutex1->unlock();
 
360
 
 
361
                QThread::yieldCurrentThread();
 
362
            }
 
363
            tst_QMutex::semaphore3.release();
 
364
            tst_QMutex::semaphore4.acquire();
 
365
        }
 
366
    }
 
367
};
 
368
 
 
369
void tst_QMutex::contendedQMutex()
 
370
{
 
371
    QFETCH(int, iterations);
 
372
    QFETCH(int, msleepDuration);
 
373
    QFETCH(bool, use2mutexes);
 
374
 
 
375
    QMutex mutex1, mutex2;
 
376
 
 
377
    QVector<QMutexThread *> threads(threadCount);
 
378
    for (int i = 0; i < threads.count(); ++i) {
 
379
        threads[i] = new QMutexThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
 
380
        threads[i]->start();
 
381
    }
 
382
 
 
383
    QBENCHMARK {
 
384
        semaphore1.acquire(threadCount);
 
385
        semaphore2.release(threadCount);
 
386
        semaphore3.acquire(threadCount);
 
387
        semaphore4.release(threadCount);
 
388
    }
 
389
 
 
390
    for (int i = 0; i < threads.count(); ++i)
 
391
        threads[i]->done = true;
 
392
    semaphore1.acquire(threadCount);
 
393
    semaphore2.release(threadCount);
 
394
    for (int i = 0; i < threads.count(); ++i)
 
395
        threads[i]->wait();
 
396
    qDeleteAll(threads);
 
397
}
 
398
 
 
399
class QMutexLockerThread : public QThread
 
400
{
 
401
    QMutex *mutex1, *mutex2;
 
402
    int iterations, msleepDuration;
 
403
    bool use2mutexes;
 
404
public:
 
405
    bool done;
 
406
    QMutexLockerThread(QMutex *mutex1, QMutex *mutex2, int iterations, int msleepDuration, bool use2mutexes)
 
407
        : mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
 
408
    { }
 
409
    void run() {
 
410
        forever {
 
411
            tst_QMutex::semaphore1.release();
 
412
            tst_QMutex::semaphore2.acquire();
 
413
            if (done)
 
414
                break;
 
415
            for (int i = 0; i < iterations; ++i) {
 
416
                {
 
417
                    QMutexLocker locker1(mutex1);
 
418
                    QMutexLocker locker2(use2mutexes ? mutex2 : 0);
 
419
                    if (msleepDuration >= 0)
 
420
                        msleep(msleepDuration);
 
421
                }
 
422
 
 
423
                QThread::yieldCurrentThread();
 
424
            }
 
425
            tst_QMutex::semaphore3.release();
 
426
            tst_QMutex::semaphore4.acquire();
 
427
        }
 
428
    }
 
429
};
 
430
 
 
431
void tst_QMutex::contendedQMutexLocker()
 
432
{
 
433
    QFETCH(int, iterations);
 
434
    QFETCH(int, msleepDuration);
 
435
    QFETCH(bool, use2mutexes);
 
436
 
 
437
    QMutex mutex1, mutex2;
 
438
 
 
439
    QVector<QMutexLockerThread *> threads(threadCount);
 
440
    for (int i = 0; i < threads.count(); ++i) {
 
441
        threads[i] = new QMutexLockerThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
 
442
        threads[i]->start();
 
443
    }
 
444
 
 
445
    QBENCHMARK {
 
446
        semaphore1.acquire(threadCount);
 
447
        semaphore2.release(threadCount);
 
448
        semaphore3.acquire(threadCount);
 
449
        semaphore4.release(threadCount);
 
450
    }
 
451
 
 
452
    for (int i = 0; i < threads.count(); ++i)
 
453
        threads[i]->done = true;
 
454
    semaphore1.acquire(threadCount);
 
455
    semaphore2.release(threadCount);
 
456
    for (int i = 0; i < threads.count(); ++i)
 
457
        threads[i]->wait();
 
458
    qDeleteAll(threads);
 
459
}
 
460
 
 
461
QTEST_MAIN(tst_QMutex)
 
462
#include "tst_qmutex.moc"