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>
This commit is contained in:
parent
0bfb39da85
commit
aefd414ce2
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -9,3 +9,6 @@ if(TARGET Qt::Widgets)
|
||||
add_subdirectory(qmetaobject)
|
||||
add_subdirectory(qobject)
|
||||
endif()
|
||||
if(win32_x_)
|
||||
add_subdirectory(qwineventnotifier)
|
||||
endif()
|
||||
|
@ -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
|
||||
|
@ -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"
|
136
tests/benchmarks/corelib/kernel/qwineventnotifier/main.cpp
Normal file
136
tests/benchmarks/corelib/kernel/qwineventnotifier/main.cpp
Normal file
@ -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"
|
@ -0,0 +1,6 @@
|
||||
TEMPLATE = app
|
||||
CONFIG += benchmark
|
||||
QT = core testlib
|
||||
|
||||
TARGET = tst_bench_qwineventnotifier
|
||||
SOURCES += main.cpp
|
Loading…
Reference in New Issue
Block a user