Skip to content

Commit

Permalink
Add a benchmark for QReadWriteLock
Browse files Browse the repository at this point in the history
Results on current dev branch [955b2bd]:

thread count: 4
********* Start testing of tst_QReadWriteLock *********
Config: Using QtTest library 5.8.0, Qt 5.8.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 6.1.1 20160707)
PASS   : tst_QReadWriteLock::initTestCase()
PASS   : tst_QReadWriteLock::uncontended(nothing)
RESULT : tst_QReadWriteLock::uncontended():"nothing":
     1,113,292.1 CPU ticks per iteration (total: 11,132,922, iterations: 10)
PASS   : tst_QReadWriteLock::uncontended(QMutex)
RESULT : tst_QReadWriteLock::uncontended():"QMutex":
     35,490,310.7 CPU ticks per iteration (total: 354,903,108, iterations: 10)
PASS   : tst_QReadWriteLock::uncontended(QReadWriteLock, read)
RESULT : tst_QReadWriteLock::uncontended():"QReadWriteLock, read":
     40,513,695.0 CPU ticks per iteration (total: 405,136,950, iterations: 10)
PASS   : tst_QReadWriteLock::uncontended(QReadWriteLock, write)
RESULT : tst_QReadWriteLock::uncontended():"QReadWriteLock, write":
     43,179,327.2 CPU ticks per iteration (total: 431,793,272, iterations: 10)
PASS   : tst_QReadWriteLock::uncontended(std::mutex)
RESULT : tst_QReadWriteLock::uncontended():"std::mutex":
     37,733,243.0 CPU ticks per iteration (total: 377,332,430, iterations: 10)
PASS   : tst_QReadWriteLock::uncontended(std::shared_timed_mutex, read)
RESULT : tst_QReadWriteLock::uncontended():"std::shared_timed_mutex, read":
     71,517,438.7 CPU ticks per iteration (total: 715,174,388, iterations: 10)
PASS   : tst_QReadWriteLock::uncontended(std::shared_timed_mutex, write)
RESULT : tst_QReadWriteLock::uncontended():"std::shared_timed_mutex, write":
     69,967,867.5 CPU ticks per iteration (total: 699,678,676, iterations: 10)
PASS   : tst_QReadWriteLock::readOnly(nothing)
RESULT : tst_QReadWriteLock::readOnly():"nothing":
     479,393,335.3 CPU ticks per iteration (total: 4,793,933,354, iterations: 10)
PASS   : tst_QReadWriteLock::readOnly(QMutex)
RESULT : tst_QReadWriteLock::readOnly():"QMutex":
     823,493,383.2 CPU ticks per iteration (total: 8,234,933,832, iterations: 10)
PASS   : tst_QReadWriteLock::readOnly(QReadWriteLock)
RESULT : tst_QReadWriteLock::readOnly():"QReadWriteLock":
     559,816,053.6 CPU ticks per iteration (total: 5,598,160,536, iterations: 10)
PASS   : tst_QReadWriteLock::readOnly(std::mutex)
RESULT : tst_QReadWriteLock::readOnly():"std::mutex":
     961,903,416.3 CPU ticks per iteration (total: 9,619,034,164, iterations: 10)
PASS   : tst_QReadWriteLock::readOnly(std::shared_timed_mutex)
RESULT : tst_QReadWriteLock::readOnly():"std::shared_timed_mutex":
     1,786,254,363.5 CPU ticks per iteration (total: 17,862,543,636, iterations: 10)
PASS   : tst_QReadWriteLock::cleanupTestCase()
Totals: 14 passed, 0 failed, 0 skipped, 0 blacklisted, 44507ms
********* Finished testing of tst_QReadWriteLock *********

Change-Id: I42189f7a356dcb36378e9d54111b7fbe89e62402
Reviewed-by: Thiago Macieira <[email protected]>
  • Loading branch information
ogoffart committed Aug 10, 2016
1 parent 9981f52 commit 5699530
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TEMPLATE = app
TARGET = tst_bench_qreadwritelock
QT = core testlib
SOURCES += tst_qreadwritelock.cpp
CONFIG += c++14 # for std::shared_timed_mutex

183 changes: 183 additions & 0 deletions tests/benchmarks/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/****************************************************************************
**
** Copyright (C) 2016 Olivier Goffart <[email protected]>
** Contact: http://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtCore/QtCore>
#include <QtTest/QtTest>
#include <mutex>
#if QT_HAS_INCLUDE(<shared_mutex>)
#if __cplusplus > 201103L
#include <shared_mutex>
#endif
#endif

// Wrapers that take pointers instead of reference to have the same interface as Qt
template <typename T>
struct LockerWrapper : T
{
LockerWrapper(typename T::mutex_type *mtx)
: T(*mtx)
{
}
};

int threadCount;

class tst_QReadWriteLock : public QObject
{
Q_OBJECT
public:
tst_QReadWriteLock()
{
// at least 2 threads, even on single cpu/core machines
threadCount = qMax(2, QThread::idealThreadCount());
qDebug("thread count: %d", threadCount);
}

private slots:
void uncontended_data();
void uncontended();
void readOnly_data();
void readOnly();
// void readWrite();
};

struct FunctionPtrHolder
{
FunctionPtrHolder(QFunctionPointer value = nullptr)
: value(value)
{
}
QFunctionPointer value;
};
Q_DECLARE_METATYPE(FunctionPtrHolder)

struct FakeLock
{
FakeLock(volatile int *i) { *i = 0; }
};

enum { Iterations = 1000000 };

template <typename Mutex, typename Locker>
void testUncontended()
{
Mutex lock;
QBENCHMARK {
for (int i = 0; i < Iterations; ++i) {
Locker locker(&lock);
}
}
}

void tst_QReadWriteLock::uncontended_data()
{
QTest::addColumn<FunctionPtrHolder>("holder");

QTest::newRow("nothing") << FunctionPtrHolder(testUncontended<int, FakeLock>);
QTest::newRow("QMutex") << FunctionPtrHolder(testUncontended<QMutex, QMutexLocker>);
QTest::newRow("QReadWriteLock, read")
<< FunctionPtrHolder(testUncontended<QReadWriteLock, QReadLocker>);
QTest::newRow("QReadWriteLock, write")
<< FunctionPtrHolder(testUncontended<QReadWriteLock, QWriteLocker>);
QTest::newRow("std::mutex") << FunctionPtrHolder(
testUncontended<std::mutex, LockerWrapper<std::unique_lock<std::mutex>>>);
#if defined __cpp_lib_shared_timed_mutex
QTest::newRow("std::shared_timed_mutex, read") << FunctionPtrHolder(
testUncontended<std::shared_timed_mutex,
LockerWrapper<std::shared_lock<std::shared_timed_mutex>>>);
QTest::newRow("std::shared_timed_mutex, write") << FunctionPtrHolder(
testUncontended<std::shared_timed_mutex,
LockerWrapper<std::unique_lock<std::shared_timed_mutex>>>);
#endif
}

void tst_QReadWriteLock::uncontended()
{
QFETCH(FunctionPtrHolder, holder);
holder.value();
}

static QHash<QString, QString> global_hash;

template <typename Mutex, typename Locker>
void testReadOnly()
{
struct Thread : QThread
{
Mutex *lock;
void run()
{
for (int i = 0; i < Iterations; ++i) {
QString s = QString::number(i); // Do something outside the lock
Locker locker(lock);
global_hash.contains(s);
}
}
};
Mutex lock;
QVector<QThread *> threads;
for (int i = 0; i < threadCount; ++i) {
auto t = new Thread;
t->lock = &lock;
threads.append(t);
}
QBENCHMARK {
for (auto t : threads) {
t->start();
}
for (auto t : threads) {
t->wait();
}
}
qDeleteAll(threads);
}

void tst_QReadWriteLock::readOnly_data()
{
QTest::addColumn<FunctionPtrHolder>("holder");

QTest::newRow("nothing") << FunctionPtrHolder(testReadOnly<int, FakeLock>);
QTest::newRow("QMutex") << FunctionPtrHolder(testReadOnly<QMutex, QMutexLocker>);
QTest::newRow("QReadWriteLock") << FunctionPtrHolder(testReadOnly<QReadWriteLock, QReadLocker>);
QTest::newRow("std::mutex") << FunctionPtrHolder(
testReadOnly<std::mutex, LockerWrapper<std::unique_lock<std::mutex>>>);
#if defined __cpp_lib_shared_timed_mutex
QTest::newRow("std::shared_timed_mutex") << FunctionPtrHolder(
testReadOnly<std::shared_timed_mutex,
LockerWrapper<std::shared_lock<std::shared_timed_mutex>>>);
#endif
}

void tst_QReadWriteLock::readOnly()
{
QFETCH(FunctionPtrHolder, holder);
holder.value();
}

QTEST_MAIN(tst_QReadWriteLock)
#include "tst_qreadwritelock.moc"
1 change: 1 addition & 0 deletions tests/benchmarks/corelib/thread/thread.pro
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
TEMPLATE = subdirs
SUBDIRS = \
qmutex \
qreadwritelock \
qthreadstorage \
qthreadpool \
qwaitcondition \

0 comments on commit 5699530

Please sign in to comment.