summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Trotsenko <alex1973tr@gmail.com>2020-09-18 19:10:35 +0300
committerAlex Trotsenko <alex1973tr@gmail.com>2020-11-10 17:56:51 +0200
commitaefd414ce2418bee5d6dacf9092f7a3949f02af8 (patch)
treee84181a5d423b98134ac878f6ac0787a7f477f53
parent0bfb39da858606a837f38f3d406f041a3f3c179c (diff)
QWinEventNotifier: unlink from event dispatcher
Instead of multiplexing all notifications into a single Qt event for the event dispatcher, we can send 'WinEventAct' event directly for each notifier which activated. This trick improves the performance (esp. on a large number of events) and allows us to remove notifiers handling from the event dispatcher completely. As an alternative to sending Qt events, use of Windows' APC queue in conjunction with waking up the Qt event loop from within the Windows thread pool has been considered. However, that would lead to signal emission asynchronous to the Qt event loop's operation, which is not acceptable. Thanks to Oswald Buddenhagen for the proposed idea. [ChangeLog][QtCore][QAbstractEventDispatcher] The {un}registerEventNotifier() member functions have been removed. QWinEventNotifier is no longer needed to be registered in the event dispatcher. Change-Id: I140892fb909eaae0eabf2e07ebabcab78c43841c Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher.cpp24
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher.h9
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp102
-rw-r--r--src/corelib/kernel/qeventdispatcher_win_p.h13
-rw-r--r--src/corelib/kernel/qwineventnotifier.cpp58
-rw-r--r--src/corelib/kernel/qwineventnotifier_p.h6
-rw-r--r--tests/benchmarks/corelib/kernel/CMakeLists.txt3
-rw-r--r--tests/benchmarks/corelib/kernel/kernel.pro6
-rw-r--r--tests/benchmarks/corelib/kernel/qwineventnotifier/CMakeLists.txt15
-rw-r--r--tests/benchmarks/corelib/kernel/qwineventnotifier/main.cpp136
-rw-r--r--tests/benchmarks/corelib/kernel/qwineventnotifier/qwineventnotifier.pro6
11 files changed, 199 insertions, 179 deletions
diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp
index b6947dc7dc..358a59d05b 100644
--- a/src/corelib/kernel/qabstracteventdispatcher.cpp
+++ b/src/corelib/kernel/qabstracteventdispatcher.cpp
@@ -460,30 +460,6 @@ bool QAbstractEventDispatcher::filterNativeEvent(const QByteArray &eventType, vo
return false;
}
-/*! \fn bool QAbstractEventDispatcher::registerEventNotifier(QWinEventNotifier *notifier)
-
- This pure virtual method exists on windows only and has to be reimplemented by a Windows specific
- event dispatcher implementation. \a notifier is the QWinEventNotifier instance to be registered.
-
- The method should return true if the registration of \a notifier was successful, otherwise false.
-
- QWinEventNotifier calls this method in it's constructor and there should never be a need to call this
- method directly.
-
- \sa QWinEventNotifier, unregisterEventNotifier()
-*/
-
-/*! \fn bool QAbstractEventDispatcher::unregisterEventNotifier(QWinEventNotifier *notifier)
-
- This pure virtual method exists on windows only and has to be reimplemented by a Windows specific
- event dispatcher implementation. \a notifier is the QWinEventNotifier instance to be unregistered.
-
- QWinEventNotifier calls this method in it's destructor and there should never be a need to call this
- method directly.
-
- \sa QWinEventNotifier, registerEventNotifier()
-*/
-
/*! \fn void QAbstractEventDispatcher::awake()
This signal is emitted after the event loop returns from a
diff --git a/src/corelib/kernel/qabstracteventdispatcher.h b/src/corelib/kernel/qabstracteventdispatcher.h
index 9a0a049ed4..717fdc8984 100644
--- a/src/corelib/kernel/qabstracteventdispatcher.h
+++ b/src/corelib/kernel/qabstracteventdispatcher.h
@@ -49,10 +49,6 @@ class QAbstractNativeEventFilter;
class QAbstractEventDispatcherPrivate;
class QSocketNotifier;
-#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
-class QWinEventNotifier;
-#endif
-
class Q_CORE_EXPORT QAbstractEventDispatcher : public QObject
{
Q_OBJECT
@@ -88,11 +84,6 @@ public:
virtual int remainingTime(int timerId) = 0;
-#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
- virtual bool registerEventNotifier(QWinEventNotifier *notifier) = 0;
- virtual void unregisterEventNotifier(QWinEventNotifier *notifier) = 0;
-#endif
-
virtual void wakeUp() = 0;
virtual void interrupt() = 0;
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index 44487d57e2..1336238795 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -47,12 +47,10 @@
#include "qset.h"
#include "qsocketnotifier.h"
#include "qvarlengtharray.h"
-#include "qwineventnotifier.h"
#include "qelapsedtimer.h"
#include "qcoreapplication_p.h"
#include <private/qthread_p.h>
-#include <private/qwineventnotifier_p.h>
QT_BEGIN_NAMESPACE
@@ -99,7 +97,7 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
: interrupt(false), internalHwnd(0),
getMessageHook(0), sendPostedEventsTimerId(0), wakeUps(0),
- activateNotifiersPosted(false), activateEventNotifiersPosted(false)
+ activateNotifiersPosted(false)
{
}
@@ -109,12 +107,6 @@ QEventDispatcherWin32Private::~QEventDispatcherWin32Private()
DestroyWindow(internalHwnd);
}
-void QEventDispatcherWin32Private::activateEventNotifier(QWinEventNotifier * wen)
-{
- QEvent event(QEvent::WinEventAct);
- QCoreApplication::sendEvent(wen, &event);
-}
-
// This function is called by a workerthread
void WINAPI QT_WIN_CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/, DWORD_PTR user, DWORD_PTR /*reserved*/, DWORD_PTR /*reserved*/)
{
@@ -455,14 +447,6 @@ void QEventDispatcherWin32Private::postActivateSocketNotifiers()
activateNotifiersPosted = PostMessage(internalHwnd, WM_QT_ACTIVATENOTIFIERS, 0, 0);
}
-void QEventDispatcherWin32Private::postActivateEventNotifiers()
-{
- Q_Q(QEventDispatcherWin32);
-
- if (!activateEventNotifiersPosted.fetchAndStoreRelease(true))
- QCoreApplication::postEvent(q, new QEvent(QEvent::WinEventAct));
-}
-
QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent)
: QEventDispatcherWin32(*new QEventDispatcherWin32Private, parent)
{
@@ -817,83 +801,6 @@ QEventDispatcherWin32::registeredTimers(QObject *object) const
return list;
}
-bool QEventDispatcherWin32::registerEventNotifier(QWinEventNotifier *notifier)
-{
- Q_ASSERT(notifier);
-#ifndef QT_NO_DEBUG
- if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
- qWarning("QEventDispatcherWin32: event notifiers cannot be enabled from another thread");
- return false;
- }
-#endif
-
- Q_D(QEventDispatcherWin32);
-
- if (d->winEventNotifierList.contains(notifier))
- return true;
-
- d->winEventNotifierList.append(notifier);
- d->winEventNotifierListModified = true;
-
- return QWinEventNotifierPrivate::get(notifier)->registerWaitObject();
-}
-
-void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier)
-{
- Q_ASSERT(notifier);
-#ifndef QT_NO_DEBUG
- if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
- qWarning("QEventDispatcherWin32: event notifiers cannot be disabled from another thread");
- return;
- }
-#endif
- doUnregisterEventNotifier(notifier);
-}
-
-void QEventDispatcherWin32::doUnregisterEventNotifier(QWinEventNotifier *notifier)
-{
- Q_D(QEventDispatcherWin32);
-
- int i = d->winEventNotifierList.indexOf(notifier);
- if (i == -1)
- return;
- d->winEventNotifierList.takeAt(i);
- d->winEventNotifierListModified = true;
- QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier);
- if (nd->waitHandle)
- nd->unregisterWaitObject();
-}
-
-void QEventDispatcherWin32::activateEventNotifiers()
-{
- Q_D(QEventDispatcherWin32);
-
- // Enable WM_QT_ACTIVATEWINEVENTS posting.
- d->activateEventNotifiersPosted.fetchAndStoreAcquire(false);
-
- // Activate signaled notifiers. Our winEventNotifierList can be modified in activation slots.
- do {
- d->winEventNotifierListModified = false;
- for (int i = 0; i < d->winEventNotifierList.count(); ++i) {
- QWinEventNotifier *notifier = d->winEventNotifierList.at(i);
- QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier);
- if (nd->signaled.loadRelaxed()) {
- nd->signaled.storeRelaxed(false);
- nd->unregisterWaitObject();
- d->activateEventNotifier(notifier);
- }
- }
- } while (d->winEventNotifierListModified);
-
- // Re-register the remaining activated notifiers.
- for (int i = 0; i < d->winEventNotifierList.count(); ++i) {
- QWinEventNotifier *notifier = d->winEventNotifierList.at(i);
- QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier);
- if (!nd->waitHandle)
- nd->registerWaitObject();
- }
-}
-
int QEventDispatcherWin32::remainingTime(int timerId)
{
#ifndef QT_NO_DEBUG
@@ -958,10 +865,6 @@ void QEventDispatcherWin32::closingDown()
doUnregisterSocketNotifier((*(d->sn_except.begin()))->obj);
Q_ASSERT(d->active_fd.isEmpty());
- // clean up any eventnotifiers
- while (!d->winEventNotifierList.isEmpty())
- doUnregisterEventNotifier(d->winEventNotifierList.first());
-
// clean up any timers
for (int i = 0; i < d->timerVec.count(); ++i)
d->unregisterTimer(d->timerVec.at(i));
@@ -1009,9 +912,6 @@ bool QEventDispatcherWin32::event(QEvent *e)
case QEvent::Timer:
d->sendTimerEvent(static_cast<const QTimerEvent*>(e)->timerId());
break;
- case QEvent::WinEventAct:
- activateEventNotifiers();
- break;
default:
break;
}
diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h
index a5c063e062..4637185563 100644
--- a/src/corelib/kernel/qeventdispatcher_win_p.h
+++ b/src/corelib/kernel/qeventdispatcher_win_p.h
@@ -60,7 +60,6 @@
QT_BEGIN_NAMESPACE
-class QWinEventNotifier;
class QEventDispatcherWin32Private;
// forward declaration
@@ -86,10 +85,6 @@ public:
bool unregisterTimers(QObject *object) override;
QList<TimerInfo> registeredTimers(QObject *object) const override;
- bool registerEventNotifier(QWinEventNotifier *notifier) override;
- void unregisterEventNotifier(QWinEventNotifier *notifier) override;
- void activateEventNotifiers();
-
int remainingTime(int timerId) override;
void wakeUp() override;
@@ -106,7 +101,6 @@ protected:
QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent = nullptr);
virtual void sendPostedEvents();
void doUnregisterSocketNotifier(QSocketNotifier *notifier);
- void doUnregisterEventNotifier(QWinEventNotifier *notifier);
private:
friend LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
@@ -156,7 +150,6 @@ class Q_CORE_EXPORT QEventDispatcherWin32Private : public QAbstractEventDispatch
public:
QEventDispatcherWin32Private();
~QEventDispatcherWin32Private();
- static QEventDispatcherWin32Private *get(QEventDispatcherWin32 *q) { return q->d_func(); }
QAtomicInt interrupt;
@@ -186,12 +179,6 @@ public:
bool closingDown = false;
- bool winEventNotifierListModified = false;
- QAtomicInt activateEventNotifiersPosted;
- QList<QWinEventNotifier *> winEventNotifierList;
- void postActivateEventNotifiers();
- void activateEventNotifier(QWinEventNotifier * wen);
-
QList<MSG> queuedUserInputEvents;
QList<MSG> queuedSocketEvents;
};
diff --git a/src/corelib/kernel/qwineventnotifier.cpp b/src/corelib/kernel/qwineventnotifier.cpp
index 5a3ad9ed5d..d3be82db58 100644
--- a/src/corelib/kernel/qwineventnotifier.cpp
+++ b/src/corelib/kernel/qwineventnotifier.cpp
@@ -39,10 +39,8 @@
#include "qwineventnotifier_p.h"
-#include "qeventdispatcher_win_p.h"
#include "qcoreapplication.h"
-
-#include <private/qthread_p.h>
+#include "qthread.h"
QT_BEGIN_NAMESPACE
@@ -120,12 +118,8 @@ QWinEventNotifier::QWinEventNotifier(HANDLE hEvent, QObject *parent)
: QObject(*new QWinEventNotifierPrivate(hEvent, false), parent)
{
Q_D(QWinEventNotifier);
- QAbstractEventDispatcher *eventDispatcher = d->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
- if (Q_UNLIKELY(!eventDispatcher)) {
- qWarning("QWinEventNotifier: Can only be used with threads started with QThread");
- return;
- }
- eventDispatcher->registerEventNotifier(this);
+
+ d->registerWaitObject();
d->enabled = true;
}
@@ -193,19 +187,20 @@ void QWinEventNotifier::setEnabled(bool enable)
return;
d->enabled = enable;
- QAbstractEventDispatcher *eventDispatcher = d->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
- if (!eventDispatcher) // perhaps application is shutting down
- return;
if (Q_UNLIKELY(thread() != QThread::currentThread())) {
qWarning("QWinEventNotifier: Event notifiers cannot be enabled or disabled from another thread");
return;
}
if (enable) {
- d->signaled.storeRelaxed(false);
- eventDispatcher->registerEventNotifier(this);
- } else {
- eventDispatcher->unregisterEventNotifier(this);
+ // It is possible that the notifier was disabled after an event was already
+ // posted. In that case we set a state that indicates that such an obsolete
+ // event shall be ignored.
+ d->winEventActPosted.testAndSetRelaxed(QWinEventNotifierPrivate::Posted,
+ QWinEventNotifierPrivate::IgnorePosted);
+ d->registerWaitObject();
+ } else if (d->waitHandle != NULL) {
+ d->unregisterWaitObject();
}
}
@@ -225,28 +220,33 @@ bool QWinEventNotifier::event(QEvent * e)
}
QObject::event(e); // will activate filters
if (e->type() == QEvent::WinEventAct) {
- emit activated(d->handleToEvent, QPrivateSignal());
+ // Emit notification, but only if the event has not been invalidated
+ // since by the notifier being disabled, even if it was re-enabled
+ // again.
+ if (d->winEventActPosted.fetchAndStoreRelaxed(QWinEventNotifierPrivate::NotPosted)
+ == QWinEventNotifierPrivate::Posted && d->enabled) {
+ d->unregisterWaitObject();
+
+ emit activated(d->handleToEvent, QPrivateSignal());
+
+ if (d->enabled && d->waitHandle == NULL)
+ d->registerWaitObject();
+ }
return true;
}
return false;
}
-static void CALLBACK wfsoCallback(void *context, BOOLEAN /*ignore*/)
+void CALLBACK QWinEventNotifierPrivate::wfsoCallback(void *context, BOOLEAN /*ignore*/)
{
QWinEventNotifierPrivate *nd = reinterpret_cast<QWinEventNotifierPrivate *>(context);
- QAbstractEventDispatcher *eventDispatcher = nd->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
- // Happens when Q(Core)Application is destroyed before QWinEventNotifier.
- // https://bugreports.qt.io/browse/QTBUG-70214
- if (!eventDispatcher) { // perhaps application is shutting down
- qWarning("QWinEventNotifier: no event dispatcher, application shutting down? Cannot deliver event.");
- return;
+ // Do not post an event, if an event is already in the message queue. Note
+ // that an event that was previously invalidated will be reactivated.
+ if (nd->winEventActPosted.fetchAndStoreRelaxed(QWinEventNotifierPrivate::Posted)
+ == QWinEventNotifierPrivate::NotPosted) {
+ QCoreApplication::postEvent(nd->q_func(), new QEvent(QEvent::WinEventAct));
}
-
- QEventDispatcherWin32Private *edp = QEventDispatcherWin32Private::get(
- static_cast<QEventDispatcherWin32 *>(eventDispatcher));
- nd->signaled.storeRelaxed(true);
- edp->postActivateEventNotifiers();
}
bool QWinEventNotifierPrivate::registerWaitObject()
diff --git a/src/corelib/kernel/qwineventnotifier_p.h b/src/corelib/kernel/qwineventnotifier_p.h
index f8f7cd8eff..da9d8ff9a0 100644
--- a/src/corelib/kernel/qwineventnotifier_p.h
+++ b/src/corelib/kernel/qwineventnotifier_p.h
@@ -68,13 +68,15 @@ public:
QWinEventNotifierPrivate(HANDLE h, bool e)
: handleToEvent(h), enabled(e) {}
- static QWinEventNotifierPrivate *get(QWinEventNotifier *q) { return q->d_func(); }
+ static void CALLBACK wfsoCallback(void *context, BOOLEAN /*ignore*/);
bool registerWaitObject();
void unregisterWaitObject();
HANDLE handleToEvent;
HANDLE waitHandle = NULL;
- QAtomicInt signaled;
+
+ enum PostingState { NotPosted = 0, Posted, IgnorePosted };
+ QAtomicInt winEventActPosted;
bool enabled;
};
diff --git a/tests/benchmarks/corelib/kernel/CMakeLists.txt b/tests/benchmarks/corelib/kernel/CMakeLists.txt
index 2b41ea30f7..556785fd62 100644
--- a/tests/benchmarks/corelib/kernel/CMakeLists.txt
+++ b/tests/benchmarks/corelib/kernel/CMakeLists.txt
@@ -9,3 +9,6 @@ if(TARGET Qt::Widgets)
add_subdirectory(qmetaobject)
add_subdirectory(qobject)
endif()
+if(win32_x_)
+ add_subdirectory(qwineventnotifier)
+endif()
diff --git a/tests/benchmarks/corelib/kernel/kernel.pro b/tests/benchmarks/corelib/kernel/kernel.pro
index 92f7174419..b7cb23aad6 100644
--- a/tests/benchmarks/corelib/kernel/kernel.pro
+++ b/tests/benchmarks/corelib/kernel/kernel.pro
@@ -6,8 +6,12 @@ SUBDIRS = \
qobject \
qvariant \
qcoreapplication \
- qtimer_vs_qmetaobject
+ qtimer_vs_qmetaobject \
+ qwineventnotifier
!qtHaveModule(widgets): SUBDIRS -= \
qmetaobject \
qobject
+
+# This test is only applicable on Windows
+!win32: SUBDIRS -= qwineventnotifier
diff --git a/tests/benchmarks/corelib/kernel/qwineventnotifier/CMakeLists.txt b/tests/benchmarks/corelib/kernel/qwineventnotifier/CMakeLists.txt
new file mode 100644
index 0000000000..a2bf2e9574
--- /dev/null
+++ b/tests/benchmarks/corelib/kernel/qwineventnotifier/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Generated from qwineventnotifier.pro.
+
+#####################################################################
+## tst_bench_qwineventnotifier Binary:
+#####################################################################
+
+qt_add_benchmark(tst_bench_qwineventnotifier
+ SOURCES
+ main.cpp
+ PUBLIC_LIBRARIES
+ Qt::Test
+)
+
+#### Keys ignored in scope 1:.:.:qwineventnotifier.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/benchmarks/corelib/kernel/qwineventnotifier/main.cpp b/tests/benchmarks/corelib/kernel/qwineventnotifier/main.cpp
new file mode 100644
index 0000000000..5ee59f8fb8
--- /dev/null
+++ b/tests/benchmarks/corelib/kernel/qwineventnotifier/main.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://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 <QtTest/QtTest>
+#include <QtCore/qglobal.h>
+#include <QtCore/qwineventnotifier.h>
+#include <QtCore/qeventloop.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qt_windows.h>
+
+class QWinEventNotifierBenchmark : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void waves_data();
+ void waves();
+};
+
+class EventsFactory : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit EventsFactory(int waves, int notifiers, int iterations)
+ : numberOfWaves(waves), numberOfNotifiers(notifiers),
+ numberOfIterations(iterations)
+ {
+ events.resize(notifiers);
+ for (int i = 0; i < notifiers; ++i) {
+ events[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
+ QVERIFY(events[i] != NULL);
+ QWinEventNotifier *notifier = new QWinEventNotifier(events[i], this);
+ Q_CHECK_PTR(notifier);
+
+ connect(notifier, &QWinEventNotifier::activated, [i, this]() {
+ ResetEvent(this->events[i]);
+ if (--this->numberOfIterations == 0)
+ this->eventLoop.quit();
+ else
+ SetEvent(this->events[(i + 1) % this->numberOfNotifiers]);
+ });
+
+ connect(this, &EventsFactory::stop, [notifier]() {
+ notifier->setEnabled(false);
+ });
+ }
+ }
+ virtual ~EventsFactory()
+ {
+ for (auto event : events)
+ CloseHandle(event);
+ }
+
+ void run()
+ {
+ Q_ASSERT(numberOfWaves != 0);
+
+ int offset = 0;
+ for (int i = 0; i < numberOfWaves; ++i) {
+ SetEvent(events[offset]);
+ offset += qMax(1, numberOfNotifiers / numberOfWaves);
+ offset %= numberOfNotifiers;
+ }
+ eventLoop.exec();
+ }
+
+signals:
+ void stop();
+
+protected:
+ QVector<HANDLE> events;
+ QEventLoop eventLoop;
+ int numberOfWaves;
+ int numberOfNotifiers;
+ int numberOfIterations;
+};
+
+void QWinEventNotifierBenchmark::waves_data()
+{
+ QTest::addColumn<int>("waves");
+ QTest::addColumn<int>("notifiers");
+ for (int waves : {1, 3, 10}) {
+ for (int notifiers : {10, 100, 1000})
+ QTest::addRow("waves: %d, notifiers: %d", waves, notifiers) << waves << notifiers;
+ }
+}
+
+void QWinEventNotifierBenchmark::waves()
+{
+ QFETCH(int, waves);
+ QFETCH(int, notifiers);
+
+ const int iterations = 100000;
+
+ EventsFactory factory(waves, notifiers, iterations);
+
+ QElapsedTimer timer;
+ timer.start();
+
+ factory.run();
+
+ qDebug("Elapsed time: %.1f s", timer.elapsed() / 1000.0);
+
+ emit factory.stop();
+}
+
+QTEST_MAIN(QWinEventNotifierBenchmark)
+
+#include "main.moc"
diff --git a/tests/benchmarks/corelib/kernel/qwineventnotifier/qwineventnotifier.pro b/tests/benchmarks/corelib/kernel/qwineventnotifier/qwineventnotifier.pro
new file mode 100644
index 0000000000..5c70ff6cc7
--- /dev/null
+++ b/tests/benchmarks/corelib/kernel/qwineventnotifier/qwineventnotifier.pro
@@ -0,0 +1,6 @@
+TEMPLATE = app
+CONFIG += benchmark
+QT = core testlib
+
+TARGET = tst_bench_qwineventnotifier
+SOURCES += main.cpp