2011-04-27 10:05:43 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2020-04-16 22:09:34 +00:00
|
|
|
** Copyright (C) 2019 The Qt Company Ltd.
|
|
|
|
** Copyright (C) 2020 Intel Corporation.
|
2016-01-15 07:08:27 +00:00
|
|
|
** Contact: https://www.qt.io/licensing/
|
2011-04-27 10:05:43 +00:00
|
|
|
**
|
|
|
|
** This file is part of the QtTest module of the Qt Toolkit.
|
|
|
|
**
|
2016-01-15 07:08:27 +00:00
|
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
2012-09-19 12:28:29 +00:00
|
|
|
** 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
|
2015-01-28 08:44:43 +00:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
2016-01-15 07:08:27 +00:00
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2012-09-19 12:28:29 +00:00
|
|
|
**
|
2011-04-27 10:05:43 +00:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-09-19 12:28:29 +00:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
2016-01-15 07:08:27 +00:00
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
** ensure the GNU Lesser General Public License version 3 requirements
|
|
|
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
2012-09-19 12:28:29 +00:00
|
|
|
**
|
2016-01-15 07:08:27 +00:00
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 2.0 or (at your option) the GNU General
|
|
|
|
** Public license version 3 or any later version approved by the KDE Free
|
|
|
|
** Qt Foundation. The licenses are as published by the Free Software
|
|
|
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
|
|
|
** 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-2.0.html and
|
|
|
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
2011-04-27 10:05:43 +00:00
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifndef QTEST_H
|
|
|
|
#define QTEST_H
|
|
|
|
|
2018-02-13 11:25:10 +00:00
|
|
|
#include <QtTest/qttestglobal.h>
|
2011-04-27 10:05:43 +00:00
|
|
|
#include <QtTest/qtestcase.h>
|
|
|
|
#include <QtTest/qtestdata.h>
|
|
|
|
#include <QtTest/qbenchmark.h>
|
|
|
|
|
2019-08-02 05:59:09 +00:00
|
|
|
#include <QtCore/qbitarray.h>
|
2011-04-27 10:05:43 +00:00
|
|
|
#include <QtCore/qbytearray.h>
|
2020-04-16 22:09:34 +00:00
|
|
|
#include <QtCore/qcborarray.h>
|
|
|
|
#include <QtCore/qcborcommon.h>
|
|
|
|
#include <QtCore/qcbormap.h>
|
|
|
|
#include <QtCore/qcborvalue.h>
|
2011-04-27 10:05:43 +00:00
|
|
|
#include <QtCore/qstring.h>
|
|
|
|
#include <QtCore/qstringlist.h>
|
2018-09-16 17:27:38 +00:00
|
|
|
#include <QtCore/qcborcommon.h>
|
2011-04-27 10:05:43 +00:00
|
|
|
#include <QtCore/qdatetime.h>
|
2019-07-04 21:13:07 +00:00
|
|
|
#if QT_CONFIG(itemmodel)
|
2018-12-26 13:05:06 +00:00
|
|
|
#include <QtCore/qabstractitemmodel.h>
|
2019-07-04 21:13:07 +00:00
|
|
|
#endif
|
2011-04-27 10:05:43 +00:00
|
|
|
#include <QtCore/qobject.h>
|
|
|
|
#include <QtCore/qvariant.h>
|
|
|
|
#include <QtCore/qurl.h>
|
2017-04-10 16:43:51 +00:00
|
|
|
#include <QtCore/quuid.h>
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2020-08-27 15:29:14 +00:00
|
|
|
#if defined(TESTCASE_LOWDPI)
|
|
|
|
#include <QtCore/qcoreapplication.h>
|
|
|
|
#endif
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
#include <QtCore/qpoint.h>
|
|
|
|
#include <QtCore/qsize.h>
|
|
|
|
#include <QtCore/qrect.h>
|
|
|
|
|
2020-07-10 09:41:33 +00:00
|
|
|
#include <initializer_list>
|
2017-12-07 08:46:30 +00:00
|
|
|
#include <memory>
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
|
|
|
namespace QTest
|
|
|
|
{
|
|
|
|
|
2017-04-21 10:13:21 +00:00
|
|
|
template <> inline char *toString(const QStringView &str)
|
|
|
|
{
|
|
|
|
return QTest::toPrettyUnicode(str);
|
|
|
|
}
|
|
|
|
|
2014-01-21 00:03:30 +00:00
|
|
|
template<> inline char *toString(const QString &str)
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2017-04-21 10:13:21 +00:00
|
|
|
return toString(QStringView(str));
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
2014-01-21 00:03:30 +00:00
|
|
|
template<> inline char *toString(const QLatin1String &str)
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2014-01-21 00:03:30 +00:00
|
|
|
return toString(QString(str));
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QByteArray &ba)
|
|
|
|
{
|
2014-01-21 00:03:30 +00:00
|
|
|
return QTest::toPrettyCString(ba.constData(), ba.length());
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
2019-08-02 05:59:09 +00:00
|
|
|
template<> inline char *toString(const QBitArray &ba)
|
|
|
|
{
|
|
|
|
qsizetype size = ba.size();
|
QTest::toString(QBitArray): fix Mismatched free() / delete / delete []
==8015== Mismatched free() / delete / delete []
==8015== at 0x483958B: operator delete[](void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==8015== by 0x48752D6: QTestResult::compare(bool, char const*, char*, char*, char const*, char const*, char const*, int) (qtestresult.cpp:356)
==8015== Address 0x602eb30 is 0 bytes inside a block of size 12 alloc'd
==8015== at 0x483777F: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==8015== by 0x44AAE2: char* QTest::toString<QBitArray>(QBitArray const&) (qtest.h:98)
==8015== by 0x44D212: bool QTest::qCompare<QBitArray>(QBitArray const&, QBitArray const&, char const*, char const*, char const*, int) (qtestcase.h:352)
Change-Id: Ia2aa807ffa8a4c798425fffd15dabfebfd63fdbd
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
2019-11-26 15:27:14 +00:00
|
|
|
char *str = new char[size + 1];
|
2019-08-02 05:59:09 +00:00
|
|
|
for (qsizetype i = 0; i < size; ++i)
|
2020-10-29 16:01:17 +00:00
|
|
|
str[i] = "01"[ba.testBit(i)];
|
2019-08-02 05:59:09 +00:00
|
|
|
str[size] = '\0';
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2018-09-19 11:31:18 +00:00
|
|
|
#if QT_CONFIG(datestring)
|
2011-04-27 10:05:43 +00:00
|
|
|
template<> inline char *toString(const QTime &time)
|
|
|
|
{
|
|
|
|
return time.isValid()
|
2019-07-26 19:18:40 +00:00
|
|
|
? qstrdup(qPrintable(time.toString(u"hh:mm:ss.zzz")))
|
2011-04-27 10:05:43 +00:00
|
|
|
: qstrdup("Invalid QTime");
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QDate &date)
|
|
|
|
{
|
|
|
|
return date.isValid()
|
2019-07-26 19:18:40 +00:00
|
|
|
? qstrdup(qPrintable(date.toString(u"yyyy/MM/dd")))
|
2011-04-27 10:05:43 +00:00
|
|
|
: qstrdup("Invalid QDate");
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QDateTime &dateTime)
|
|
|
|
{
|
|
|
|
return dateTime.isValid()
|
2019-07-26 19:18:40 +00:00
|
|
|
? qstrdup(qPrintable(dateTime.toString(u"yyyy/MM/dd hh:mm:ss.zzz[t]")))
|
2011-04-27 10:05:43 +00:00
|
|
|
: qstrdup("Invalid QDateTime");
|
|
|
|
}
|
2018-09-19 11:31:18 +00:00
|
|
|
#endif // datestring
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2018-09-16 17:27:38 +00:00
|
|
|
template<> inline char *toString(const QCborError &c)
|
|
|
|
{
|
|
|
|
// use the Q_ENUM formatting
|
|
|
|
return toString(c.c);
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
template<> inline char *toString(const QChar &c)
|
|
|
|
{
|
2016-07-01 14:18:41 +00:00
|
|
|
const ushort uc = c.unicode();
|
|
|
|
if (uc < 128) {
|
|
|
|
char msg[32] = {'\0'};
|
|
|
|
qsnprintf(msg, sizeof(msg), "QChar: '%c' (0x%x)", char(uc), unsigned(uc));
|
|
|
|
return qstrdup(msg);
|
|
|
|
}
|
2013-03-06 10:17:46 +00:00
|
|
|
return qstrdup(qPrintable(QString::fromLatin1("QChar: '%1' (0x%2)").arg(c).arg(QString::number(static_cast<int>(c.unicode()), 16))));
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
2019-07-04 21:13:07 +00:00
|
|
|
#if QT_CONFIG(itemmodel)
|
2018-12-26 13:05:06 +00:00
|
|
|
template<> inline char *toString(const QModelIndex &idx)
|
|
|
|
{
|
|
|
|
char msg[128];
|
|
|
|
qsnprintf(msg, sizeof(msg), "QModelIndex(%d,%d,%p,%p)", idx.row(), idx.column(), idx.internalPointer(), idx.model());
|
|
|
|
return qstrdup(msg);
|
|
|
|
}
|
2019-07-04 21:13:07 +00:00
|
|
|
#endif
|
2018-12-26 13:05:06 +00:00
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
template<> inline char *toString(const QPoint &p)
|
|
|
|
{
|
2016-07-01 14:18:41 +00:00
|
|
|
char msg[128] = {'\0'};
|
|
|
|
qsnprintf(msg, sizeof(msg), "QPoint(%d,%d)", p.x(), p.y());
|
|
|
|
return qstrdup(msg);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QSize &s)
|
|
|
|
{
|
2016-07-01 14:18:41 +00:00
|
|
|
char msg[128] = {'\0'};
|
|
|
|
qsnprintf(msg, sizeof(msg), "QSize(%dx%d)", s.width(), s.height());
|
|
|
|
return qstrdup(msg);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QRect &s)
|
|
|
|
{
|
2016-07-01 14:18:41 +00:00
|
|
|
char msg[256] = {'\0'};
|
|
|
|
qsnprintf(msg, sizeof(msg), "QRect(%d,%d %dx%d) (bottomright %d,%d)",
|
|
|
|
s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
|
|
|
|
return qstrdup(msg);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QPointF &p)
|
|
|
|
{
|
2016-07-01 14:18:41 +00:00
|
|
|
char msg[64] = {'\0'};
|
|
|
|
qsnprintf(msg, sizeof(msg), "QPointF(%g,%g)", p.x(), p.y());
|
|
|
|
return qstrdup(msg);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QSizeF &s)
|
|
|
|
{
|
2016-07-01 14:18:41 +00:00
|
|
|
char msg[64] = {'\0'};
|
|
|
|
qsnprintf(msg, sizeof(msg), "QSizeF(%gx%g)", s.width(), s.height());
|
|
|
|
return qstrdup(msg);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QRectF &s)
|
|
|
|
{
|
2016-07-01 14:18:41 +00:00
|
|
|
char msg[256] = {'\0'};
|
|
|
|
qsnprintf(msg, sizeof(msg), "QRectF(%g,%g %gx%g) (bottomright %g,%g)",
|
|
|
|
s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
|
|
|
|
return qstrdup(msg);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QUrl &uri)
|
|
|
|
{
|
2012-09-18 21:07:46 +00:00
|
|
|
if (!uri.isValid())
|
2016-07-06 08:32:54 +00:00
|
|
|
return qstrdup(qPrintable(QLatin1String("Invalid URL: ") + uri.errorString()));
|
2012-03-30 20:48:42 +00:00
|
|
|
return qstrdup(uri.toEncoded().constData());
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
2017-04-10 16:43:51 +00:00
|
|
|
template <> inline char *toString(const QUuid &uuid)
|
|
|
|
{
|
|
|
|
return qstrdup(uuid.toByteArray().constData());
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
template<> inline char *toString(const QVariant &v)
|
|
|
|
{
|
|
|
|
QByteArray vstring("QVariant(");
|
|
|
|
if (v.isValid()) {
|
|
|
|
QByteArray type(v.typeName());
|
|
|
|
if (type.isEmpty()) {
|
|
|
|
type = QByteArray::number(v.userType());
|
|
|
|
}
|
|
|
|
vstring.append(type);
|
|
|
|
if (!v.isNull()) {
|
|
|
|
vstring.append(',');
|
2020-07-27 15:00:22 +00:00
|
|
|
if (v.canConvert<QString>()) {
|
2016-05-24 13:53:04 +00:00
|
|
|
vstring.append(v.toString().toLocal8Bit());
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
vstring.append("<value not representable as string>");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vstring.append(')');
|
|
|
|
|
|
|
|
return qstrdup(vstring.constData());
|
|
|
|
}
|
|
|
|
|
2020-04-16 22:09:34 +00:00
|
|
|
namespace Internal {
|
|
|
|
struct QCborValueFormatter
|
|
|
|
{
|
|
|
|
enum { BufferLen = 256 };
|
|
|
|
static char *formatSimpleType(QCborSimpleType st)
|
|
|
|
{
|
|
|
|
char *buf = new char[BufferLen];
|
|
|
|
qsnprintf(buf, BufferLen, "QCborValue(QCborSimpleType(%d))", int(st));
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *formatTag(QCborTag tag, const QCborValue &taggedValue)
|
|
|
|
{
|
|
|
|
QScopedArrayPointer<char> hold(format(taggedValue));
|
|
|
|
char *buf = new char[BufferLen];
|
|
|
|
qsnprintf(buf, BufferLen, "QCborValue(QCborTag(%llu), %s)", tag, hold.get());
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *innerFormat(QCborValue::Type t, const char *str)
|
|
|
|
{
|
|
|
|
static const QMetaEnum typeEnum = []() {
|
|
|
|
int idx = QCborValue::staticMetaObject.indexOfEnumerator("Type");
|
|
|
|
return QCborValue::staticMetaObject.enumerator(idx);
|
|
|
|
}();
|
|
|
|
|
|
|
|
char *buf = new char[BufferLen];
|
|
|
|
const char *typeName = typeEnum.valueToKey(t);
|
|
|
|
if (typeName)
|
|
|
|
qsnprintf(buf, BufferLen, "QCborValue(%s, %s)", typeName, str);
|
|
|
|
else
|
|
|
|
qsnprintf(buf, BufferLen, "QCborValue(<unknown type 0x%02x>)", t);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> static char *format(QCborValue::Type type, const T &t)
|
|
|
|
{
|
|
|
|
QScopedArrayPointer<char> hold(QTest::toString(t));
|
|
|
|
return innerFormat(type, hold.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *format(const QCborValue &v)
|
|
|
|
{
|
|
|
|
switch (v.type()) {
|
|
|
|
case QCborValue::Integer:
|
|
|
|
return format(v.type(), v.toInteger());
|
|
|
|
case QCborValue::ByteArray:
|
|
|
|
return format(v.type(), v.toByteArray());
|
|
|
|
case QCborValue::String:
|
|
|
|
return format(v.type(), v.toString());
|
|
|
|
case QCborValue::Array:
|
|
|
|
return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toArray())).get());
|
|
|
|
case QCborValue::Map:
|
|
|
|
return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toMap())).get());
|
|
|
|
case QCborValue::Tag:
|
|
|
|
return formatTag(v.tag(), v.taggedValue());
|
|
|
|
case QCborValue::SimpleType:
|
|
|
|
break;
|
|
|
|
case QCborValue::True:
|
|
|
|
return qstrdup("QCborValue(true)");
|
|
|
|
case QCborValue::False:
|
|
|
|
return qstrdup("QCborValue(false)");
|
|
|
|
case QCborValue::Null:
|
|
|
|
return qstrdup("QCborValue(nullptr)");
|
|
|
|
case QCborValue::Undefined:
|
|
|
|
return qstrdup("QCborValue()");
|
|
|
|
case QCborValue::Double:
|
|
|
|
return format(v.type(), v.toDouble());
|
|
|
|
case QCborValue::DateTime:
|
|
|
|
case QCborValue::Url:
|
|
|
|
case QCborValue::RegularExpression:
|
|
|
|
return format(v.type(), v.taggedValue().toString());
|
|
|
|
case QCborValue::Uuid:
|
|
|
|
return format(v.type(), v.toUuid());
|
|
|
|
case QCborValue::Invalid:
|
|
|
|
return qstrdup("QCborValue(<invalid>)");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v.isSimpleType())
|
|
|
|
return formatSimpleType(v.toSimpleType());
|
|
|
|
return innerFormat(v.type(), "");
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *format(const QCborArray &a)
|
|
|
|
{
|
|
|
|
QByteArray out(1, '[');
|
|
|
|
const char *comma = "";
|
|
|
|
for (const QCborValueRef v : a) {
|
|
|
|
QScopedArrayPointer<char> s(format(v));
|
|
|
|
out += comma;
|
|
|
|
out += s.get();
|
|
|
|
comma = ", ";
|
|
|
|
}
|
|
|
|
out += ']';
|
|
|
|
return qstrdup(out.constData());
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *format(const QCborMap &m)
|
|
|
|
{
|
|
|
|
QByteArray out(1, '{');
|
|
|
|
const char *comma = "";
|
|
|
|
for (auto pair : m) {
|
|
|
|
QScopedArrayPointer<char> key(format(pair.first));
|
|
|
|
QScopedArrayPointer<char> value(format(pair.second));
|
|
|
|
out += comma;
|
|
|
|
out += key.get();
|
|
|
|
out += ": ";
|
|
|
|
out += value.get();
|
|
|
|
comma = ", ";
|
|
|
|
}
|
|
|
|
out += '}';
|
|
|
|
return qstrdup(out.constData());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QCborValue &v)
|
|
|
|
{
|
|
|
|
return Internal::QCborValueFormatter::format(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QCborValueRef &v)
|
|
|
|
{
|
|
|
|
return toString(QCborValue(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QCborArray &a)
|
|
|
|
{
|
|
|
|
return Internal::QCborValueFormatter::format(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> inline char *toString(const QCborMap &m)
|
|
|
|
{
|
|
|
|
return Internal::QCborValueFormatter::format(m);
|
|
|
|
}
|
|
|
|
|
2017-07-20 13:14:08 +00:00
|
|
|
template <typename T1, typename T2>
|
|
|
|
inline char *toString(const std::pair<T1, T2> &pair)
|
|
|
|
{
|
|
|
|
const QScopedArrayPointer<char> first(toString(pair.first));
|
|
|
|
const QScopedArrayPointer<char> second(toString(pair.second));
|
|
|
|
return toString(QString::asprintf("std::pair(%s,%s)", first.data(), second.data()));
|
|
|
|
}
|
|
|
|
|
2017-12-07 08:46:30 +00:00
|
|
|
template <typename Tuple, int... I>
|
|
|
|
inline char *toString(const Tuple & tuple, QtPrivate::IndexesList<I...>) {
|
|
|
|
using UP = std::unique_ptr<char[]>;
|
|
|
|
// Generate a table of N + 1 elements where N is the number of
|
|
|
|
// elements in the tuple.
|
|
|
|
// The last element is needed to support the empty tuple use case.
|
|
|
|
const UP data[] = {
|
|
|
|
UP(toString(std::get<I>(tuple)))..., UP{}
|
|
|
|
};
|
|
|
|
return formatString("std::tuple(", ")", sizeof...(I), data[I].get()...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class... Types>
|
|
|
|
inline char *toString(const std::tuple<Types...> &tuple)
|
|
|
|
{
|
|
|
|
static const std::size_t params_count = sizeof...(Types);
|
|
|
|
return toString(tuple, typename QtPrivate::Indexes<params_count>::Value());
|
|
|
|
}
|
|
|
|
|
2016-02-22 19:29:32 +00:00
|
|
|
inline char *toString(std::nullptr_t)
|
|
|
|
{
|
|
|
|
return toString(QLatin1String("nullptr"));
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
template<>
|
|
|
|
inline bool qCompare(QString const &t1, QLatin1String const &t2, const char *actual,
|
|
|
|
const char *expected, const char *file, int line)
|
|
|
|
{
|
2012-09-20 14:36:51 +00:00
|
|
|
return qCompare(t1, QString(t2), actual, expected, file, line);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
template<>
|
|
|
|
inline bool qCompare(QLatin1String const &t1, QString const &t2, const char *actual,
|
|
|
|
const char *expected, const char *file, int line)
|
|
|
|
{
|
2012-09-20 14:36:51 +00:00
|
|
|
return qCompare(QString(t1), t2, actual, expected, file, line);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
2020-07-10 09:41:33 +00:00
|
|
|
// Compare sequences of equal size
|
|
|
|
template <typename ActualIterator, typename ExpectedIterator>
|
2021-01-04 12:40:24 +00:00
|
|
|
bool _q_compareSequence(ActualIterator actualIt, ActualIterator actualEnd,
|
|
|
|
ExpectedIterator expectedBegin, ExpectedIterator expectedEnd,
|
|
|
|
const char *actual, const char *expected,
|
|
|
|
const char *file, int line)
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
|
|
|
char msg[1024];
|
|
|
|
msg[0] = '\0';
|
2020-07-10 09:41:33 +00:00
|
|
|
|
|
|
|
const qsizetype actualSize = actualEnd - actualIt;
|
|
|
|
const qsizetype expectedSize = expectedEnd - expectedBegin;
|
|
|
|
bool isOk = actualSize == expectedSize;
|
|
|
|
|
|
|
|
if (!isOk) {
|
2013-01-19 10:52:03 +00:00
|
|
|
qsnprintf(msg, sizeof(msg), "Compared lists have different sizes.\n"
|
2020-07-10 09:41:33 +00:00
|
|
|
" Actual (%s) size: %zd\n"
|
|
|
|
" Expected (%s) size: %zd", actual, actualSize,
|
|
|
|
expected, expectedSize);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
2014-02-28 20:44:22 +00:00
|
|
|
|
2020-07-10 09:41:33 +00:00
|
|
|
for (auto expectedIt = expectedBegin; isOk && expectedIt < expectedEnd; ++actualIt, ++expectedIt) {
|
|
|
|
if (!(*actualIt == *expectedIt)) {
|
|
|
|
const qsizetype i = qsizetype(expectedIt - expectedBegin);
|
2021-01-04 12:40:24 +00:00
|
|
|
char *val1 = toString(*actualIt);
|
|
|
|
char *val2 = toString(*expectedIt);
|
2020-07-10 09:41:33 +00:00
|
|
|
|
|
|
|
qsnprintf(msg, sizeof(msg), "Compared lists differ at index %zd.\n"
|
2014-01-21 00:03:30 +00:00
|
|
|
" Actual (%s): %s\n"
|
2014-02-28 20:44:22 +00:00
|
|
|
" Expected (%s): %s", i, actual, val1 ? val1 : "<null>",
|
|
|
|
expected, val2 ? val2 : "<null>");
|
2011-04-27 10:05:43 +00:00
|
|
|
isOk = false;
|
2014-02-28 20:44:22 +00:00
|
|
|
|
|
|
|
delete [] val1;
|
|
|
|
delete [] val2;
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
}
|
2017-09-18 09:49:52 +00:00
|
|
|
return compare_helper(isOk, msg, nullptr, nullptr, actual, expected, file, line);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
2021-01-04 12:40:24 +00:00
|
|
|
namespace Internal {
|
|
|
|
|
2020-07-23 09:41:06 +00:00
|
|
|
#if defined(TESTCASE_LOWDPI)
|
|
|
|
void disableHighDpi()
|
|
|
|
{
|
2020-08-31 12:01:12 +00:00
|
|
|
qputenv("QT_ENABLE_HIGHDPI_SCALING", "0");
|
2020-07-23 09:41:06 +00:00
|
|
|
}
|
|
|
|
Q_CONSTRUCTOR_FUNCTION(disableHighDpi);
|
|
|
|
#endif
|
|
|
|
|
2020-07-10 09:41:33 +00:00
|
|
|
} // namespace Internal
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
inline bool qCompare(QList<T> const &t1, QList<T> const &t2, const char *actual, const char *expected,
|
|
|
|
const char *file, int line)
|
|
|
|
{
|
2021-01-04 12:40:24 +00:00
|
|
|
return _q_compareSequence(t1.cbegin(), t1.cend(), t2.cbegin(), t2.cend(),
|
2020-07-10 09:41:33 +00:00
|
|
|
actual, expected, file, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, int N>
|
|
|
|
bool qCompare(QList<T> const &t1, std::initializer_list<T> t2,
|
|
|
|
const char *actual, const char *expected,
|
|
|
|
const char *file, int line)
|
|
|
|
{
|
2021-01-04 12:40:24 +00:00
|
|
|
return _q_compareSequence(t1.cbegin(), t1.cend(), t2.cbegin(), t2.cend(),
|
2020-07-10 09:41:33 +00:00
|
|
|
actual, expected, file, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compare QList against array
|
|
|
|
template <typename T, int N>
|
|
|
|
bool qCompare(QList<T> const &t1, const T (& t2)[N],
|
|
|
|
const char *actual, const char *expected,
|
|
|
|
const char *file, int line)
|
|
|
|
{
|
2021-01-04 12:40:24 +00:00
|
|
|
return _q_compareSequence(t1.cbegin(), t1.cend(), t2, t2 + N,
|
2020-07-10 09:41:33 +00:00
|
|
|
actual, expected, file, line);
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
template <typename T>
|
|
|
|
inline bool qCompare(QFlags<T> const &t1, T const &t2, const char *actual, const char *expected,
|
|
|
|
const char *file, int line)
|
|
|
|
{
|
|
|
|
return qCompare(int(t1), int(t2), actual, expected, file, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
inline bool qCompare(QFlags<T> const &t1, int const &t2, const char *actual, const char *expected,
|
|
|
|
const char *file, int line)
|
|
|
|
{
|
|
|
|
return qCompare(int(t1), t2, actual, expected, file, line);
|
|
|
|
}
|
|
|
|
|
2012-10-26 06:41:27 +00:00
|
|
|
template<>
|
|
|
|
inline bool qCompare(qint64 const &t1, qint32 const &t2, const char *actual,
|
|
|
|
const char *expected, const char *file, int line)
|
|
|
|
{
|
|
|
|
return qCompare(t1, static_cast<qint64>(t2), actual, expected, file, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
inline bool qCompare(qint64 const &t1, quint32 const &t2, const char *actual,
|
|
|
|
const char *expected, const char *file, int line)
|
|
|
|
{
|
|
|
|
return qCompare(t1, static_cast<qint64>(t2), actual, expected, file, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
inline bool qCompare(quint64 const &t1, quint32 const &t2, const char *actual,
|
|
|
|
const char *expected, const char *file, int line)
|
|
|
|
{
|
|
|
|
return qCompare(t1, static_cast<quint64>(t2), actual, expected, file, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
inline bool qCompare(qint32 const &t1, qint64 const &t2, const char *actual,
|
|
|
|
const char *expected, const char *file, int line)
|
|
|
|
{
|
|
|
|
return qCompare(static_cast<qint64>(t1), t2, actual, expected, file, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
inline bool qCompare(quint32 const &t1, qint64 const &t2, const char *actual,
|
|
|
|
const char *expected, const char *file, int line)
|
|
|
|
{
|
|
|
|
return qCompare(static_cast<qint64>(t1), t2, actual, expected, file, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
inline bool qCompare(quint32 const &t1, quint64 const &t2, const char *actual,
|
|
|
|
const char *expected, const char *file, int line)
|
|
|
|
{
|
|
|
|
return qCompare(static_cast<quint64>(t1), t2, actual, expected, file, line);
|
|
|
|
}
|
2019-07-30 08:16:53 +00:00
|
|
|
namespace Internal {
|
2012-10-26 06:41:27 +00:00
|
|
|
|
2019-07-30 08:16:53 +00:00
|
|
|
template <typename T>
|
|
|
|
class HasInitMain // SFINAE test for the presence of initMain()
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
using YesType = char[1];
|
|
|
|
using NoType = char[2];
|
|
|
|
|
|
|
|
template <typename C> static YesType& test( decltype(&C::initMain) ) ;
|
|
|
|
template <typename C> static NoType& test(...);
|
|
|
|
|
|
|
|
public:
|
|
|
|
enum { value = sizeof(test<T>(nullptr)) == sizeof(YesType) };
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
typename std::enable_if<HasInitMain<T>::value, void>::type callInitMain()
|
|
|
|
{
|
|
|
|
T::initMain();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
typename std::enable_if<!HasInitMain<T>::value, void>::type callInitMain()
|
|
|
|
{
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
2019-07-30 08:16:53 +00:00
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
|
|
|
} // namespace QTest
|
2011-04-27 10:05:43 +00:00
|
|
|
QT_END_NAMESPACE
|
|
|
|
|
2015-04-28 11:40:26 +00:00
|
|
|
#ifdef QT_TESTCASE_BUILDDIR
|
|
|
|
# define QTEST_SET_MAIN_SOURCE_PATH QTest::setMainSourcePath(__FILE__, QT_TESTCASE_BUILDDIR);
|
|
|
|
#else
|
|
|
|
# define QTEST_SET_MAIN_SOURCE_PATH QTest::setMainSourcePath(__FILE__);
|
|
|
|
#endif
|
|
|
|
|
2018-08-06 15:07:07 +00:00
|
|
|
// Hooks for coverage-testing of QTestLib itself:
|
|
|
|
#if QT_CONFIG(testlib_selfcover) && defined(__COVERAGESCANNER__)
|
|
|
|
struct QtCoverageScanner
|
|
|
|
{
|
|
|
|
QtCoverageScanner(const char *name)
|
|
|
|
{
|
|
|
|
__coveragescanner_clear();
|
|
|
|
__coveragescanner_testname(name);
|
|
|
|
}
|
|
|
|
~QtCoverageScanner()
|
|
|
|
{
|
|
|
|
__coveragescanner_save();
|
|
|
|
__coveragescanner_testname("");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#define TESTLIB_SELFCOVERAGE_START(name) QtCoverageScanner _qtCoverageScanner(name);
|
|
|
|
#else
|
|
|
|
#define TESTLIB_SELFCOVERAGE_START(name)
|
|
|
|
#endif
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
#define QTEST_APPLESS_MAIN(TestObject) \
|
|
|
|
int main(int argc, char *argv[]) \
|
|
|
|
{ \
|
2018-08-06 15:07:07 +00:00
|
|
|
TESTLIB_SELFCOVERAGE_START(TestObject) \
|
2011-04-27 10:05:43 +00:00
|
|
|
TestObject tc; \
|
2015-04-28 11:40:26 +00:00
|
|
|
QTEST_SET_MAIN_SOURCE_PATH \
|
2011-04-27 10:05:43 +00:00
|
|
|
return QTest::qExec(&tc, argc, argv); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#include <QtTest/qtestsystem.h>
|
2018-08-08 12:08:15 +00:00
|
|
|
|
2016-08-25 07:06:54 +00:00
|
|
|
#if defined(QT_NETWORK_LIB)
|
|
|
|
# include <QtTest/qtest_network.h>
|
|
|
|
#endif
|
|
|
|
|
2011-08-25 14:34:40 +00:00
|
|
|
#if defined(QT_WIDGETS_LIB)
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2014-12-17 14:39:30 +00:00
|
|
|
#include <QtTest/qtest_widgets.h>
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
#ifdef QT_KEYPAD_NAVIGATION
|
|
|
|
# define QTEST_DISABLE_KEYPAD_NAVIGATION QApplication::setNavigationMode(Qt::NavigationModeNone);
|
|
|
|
#else
|
|
|
|
# define QTEST_DISABLE_KEYPAD_NAVIGATION
|
|
|
|
#endif
|
|
|
|
|
Optimize QTimer::singleShot(0, ...) when taking PMF or Functor callable
QTimer::singleShot is optimized for zero timeouts when using the API
taking a string method name. This optimization was not used for the API
taking a PMF or functor. This patch adds it, making the various API
calls behave similarly from a performance point of view.
The approach taken here requires a QObject context object. If none is
available, e.g. a nullptr was passed explicitly, or the
QTimer::singleShot(O, Functor) API was used, the optimization could
not easily be applied. This is not only bad from a performance POV,
but also poses as a potential source for heisenbugs: Using the
different API versions of QTimer::singleShot would use different code
paths internally, which then would not ensure the expected slot call
order. This problem actually existed already when mixing the
string-based slot syntax with PMF/functors in the QTimer::singleShot
API.
This patch overcomes this hurdle and fixes all of the above: When we
encounter a 0ms single shot timer, and no QObject context object is
available, we fall back to the main thread, or create a temporary
QObject for any other thread. The updated and extended benchmark
shows that this is still a significant performance improvement
over using a timer:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.48 msecs per iteration (total: 748, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
7.20 msecs per iteration (total: 720, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
6.79 msecs per iteration (total: 679, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
6.92 msecs per iteration (total: 693, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.34 msecs per iteration (total: 735, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.90 msecs per iteration (total: 690, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
7.46 msecs per iteration (total: 747, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
6.70 msecs per iteration (total: 671, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
13.75 msecs per iteration (total: 1,376, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
7.05 msecs per iteration (total: 706, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.70 msecs per iteration (total: 670, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
6.58 msecs per iteration (total: 658, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 20977ms
********* Finished testing of qtimer_vs_qmetaobject *********
Without the change to qtimer.cpp, the results are:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
112.84 msecs per iteration (total: 11,285, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
115.62 msecs per iteration (total: 11,563, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
110.81 msecs per iteration (total: 11,082, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.04 msecs per iteration (total: 704, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 746, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
118.42 msecs per iteration (total: 11,842, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
119.35 msecs per iteration (total: 11,936, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
130.96 msecs per iteration (total: 13,096, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
8.08 msecs per iteration (total: 808, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.79 msecs per iteration (total: 680, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
7.49 msecs per iteration (total: 749, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 153995ms
********* Finished testing of qtimer_vs_qmetaobject *********
Additionally, this patch adds a unit test to verify that the slot call
order for 0ms single shot timers is followed while mixing the various
API versions. It fails without this patch but passes now.
Finally, another test is added to verify that using QTimer::singleShot
before a QCoreApplication was constructed is still working properly.
Change-Id: I0d6211554b6198cb3e527be9ec3adc572b1b54ee
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2018-01-11 16:46:24 +00:00
|
|
|
#define QTEST_MAIN_IMPL(TestObject) \
|
2018-08-06 15:07:07 +00:00
|
|
|
TESTLIB_SELFCOVERAGE_START(#TestObject) \
|
2019-07-30 08:16:53 +00:00
|
|
|
QT_PREPEND_NAMESPACE(QTest::Internal::callInitMain)<TestObject>(); \
|
2011-04-27 10:05:43 +00:00
|
|
|
QApplication app(argc, argv); \
|
2012-01-11 10:49:35 +00:00
|
|
|
app.setAttribute(Qt::AA_Use96Dpi, true); \
|
2011-04-27 10:05:43 +00:00
|
|
|
QTEST_DISABLE_KEYPAD_NAVIGATION \
|
|
|
|
TestObject tc; \
|
2015-04-28 11:40:26 +00:00
|
|
|
QTEST_SET_MAIN_SOURCE_PATH \
|
Optimize QTimer::singleShot(0, ...) when taking PMF or Functor callable
QTimer::singleShot is optimized for zero timeouts when using the API
taking a string method name. This optimization was not used for the API
taking a PMF or functor. This patch adds it, making the various API
calls behave similarly from a performance point of view.
The approach taken here requires a QObject context object. If none is
available, e.g. a nullptr was passed explicitly, or the
QTimer::singleShot(O, Functor) API was used, the optimization could
not easily be applied. This is not only bad from a performance POV,
but also poses as a potential source for heisenbugs: Using the
different API versions of QTimer::singleShot would use different code
paths internally, which then would not ensure the expected slot call
order. This problem actually existed already when mixing the
string-based slot syntax with PMF/functors in the QTimer::singleShot
API.
This patch overcomes this hurdle and fixes all of the above: When we
encounter a 0ms single shot timer, and no QObject context object is
available, we fall back to the main thread, or create a temporary
QObject for any other thread. The updated and extended benchmark
shows that this is still a significant performance improvement
over using a timer:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.48 msecs per iteration (total: 748, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
7.20 msecs per iteration (total: 720, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
6.79 msecs per iteration (total: 679, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
6.92 msecs per iteration (total: 693, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.34 msecs per iteration (total: 735, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.90 msecs per iteration (total: 690, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
7.46 msecs per iteration (total: 747, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
6.70 msecs per iteration (total: 671, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
13.75 msecs per iteration (total: 1,376, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
7.05 msecs per iteration (total: 706, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.70 msecs per iteration (total: 670, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
6.58 msecs per iteration (total: 658, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 20977ms
********* Finished testing of qtimer_vs_qmetaobject *********
Without the change to qtimer.cpp, the results are:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
112.84 msecs per iteration (total: 11,285, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
115.62 msecs per iteration (total: 11,563, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
110.81 msecs per iteration (total: 11,082, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.04 msecs per iteration (total: 704, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 746, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
118.42 msecs per iteration (total: 11,842, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
119.35 msecs per iteration (total: 11,936, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
130.96 msecs per iteration (total: 13,096, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
8.08 msecs per iteration (total: 808, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.79 msecs per iteration (total: 680, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
7.49 msecs per iteration (total: 749, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 153995ms
********* Finished testing of qtimer_vs_qmetaobject *********
Additionally, this patch adds a unit test to verify that the slot call
order for 0ms single shot timers is followed while mixing the various
API versions. It fails without this patch but passes now.
Finally, another test is added to verify that using QTimer::singleShot
before a QCoreApplication was constructed is still working properly.
Change-Id: I0d6211554b6198cb3e527be9ec3adc572b1b54ee
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2018-01-11 16:46:24 +00:00
|
|
|
return QTest::qExec(&tc, argc, argv);
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2011-08-25 14:34:40 +00:00
|
|
|
#elif defined(QT_GUI_LIB)
|
|
|
|
|
|
|
|
#include <QtTest/qtest_gui.h>
|
|
|
|
|
Optimize QTimer::singleShot(0, ...) when taking PMF or Functor callable
QTimer::singleShot is optimized for zero timeouts when using the API
taking a string method name. This optimization was not used for the API
taking a PMF or functor. This patch adds it, making the various API
calls behave similarly from a performance point of view.
The approach taken here requires a QObject context object. If none is
available, e.g. a nullptr was passed explicitly, or the
QTimer::singleShot(O, Functor) API was used, the optimization could
not easily be applied. This is not only bad from a performance POV,
but also poses as a potential source for heisenbugs: Using the
different API versions of QTimer::singleShot would use different code
paths internally, which then would not ensure the expected slot call
order. This problem actually existed already when mixing the
string-based slot syntax with PMF/functors in the QTimer::singleShot
API.
This patch overcomes this hurdle and fixes all of the above: When we
encounter a 0ms single shot timer, and no QObject context object is
available, we fall back to the main thread, or create a temporary
QObject for any other thread. The updated and extended benchmark
shows that this is still a significant performance improvement
over using a timer:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.48 msecs per iteration (total: 748, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
7.20 msecs per iteration (total: 720, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
6.79 msecs per iteration (total: 679, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
6.92 msecs per iteration (total: 693, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.34 msecs per iteration (total: 735, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.90 msecs per iteration (total: 690, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
7.46 msecs per iteration (total: 747, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
6.70 msecs per iteration (total: 671, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
13.75 msecs per iteration (total: 1,376, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
7.05 msecs per iteration (total: 706, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.70 msecs per iteration (total: 670, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
6.58 msecs per iteration (total: 658, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 20977ms
********* Finished testing of qtimer_vs_qmetaobject *********
Without the change to qtimer.cpp, the results are:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
112.84 msecs per iteration (total: 11,285, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
115.62 msecs per iteration (total: 11,563, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
110.81 msecs per iteration (total: 11,082, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.04 msecs per iteration (total: 704, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 746, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
118.42 msecs per iteration (total: 11,842, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
119.35 msecs per iteration (total: 11,936, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
130.96 msecs per iteration (total: 13,096, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
8.08 msecs per iteration (total: 808, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.79 msecs per iteration (total: 680, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
7.49 msecs per iteration (total: 749, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 153995ms
********* Finished testing of qtimer_vs_qmetaobject *********
Additionally, this patch adds a unit test to verify that the slot call
order for 0ms single shot timers is followed while mixing the various
API versions. It fails without this patch but passes now.
Finally, another test is added to verify that using QTimer::singleShot
before a QCoreApplication was constructed is still working properly.
Change-Id: I0d6211554b6198cb3e527be9ec3adc572b1b54ee
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2018-01-11 16:46:24 +00:00
|
|
|
#define QTEST_MAIN_IMPL(TestObject) \
|
2018-08-06 15:07:07 +00:00
|
|
|
TESTLIB_SELFCOVERAGE_START(#TestObject) \
|
2019-07-30 08:16:53 +00:00
|
|
|
QT_PREPEND_NAMESPACE(QTest::Internal::callInitMain)<TestObject>(); \
|
2011-08-25 14:34:40 +00:00
|
|
|
QGuiApplication app(argc, argv); \
|
2012-01-11 10:49:35 +00:00
|
|
|
app.setAttribute(Qt::AA_Use96Dpi, true); \
|
2011-08-25 14:34:40 +00:00
|
|
|
TestObject tc; \
|
2015-04-28 11:40:26 +00:00
|
|
|
QTEST_SET_MAIN_SOURCE_PATH \
|
Optimize QTimer::singleShot(0, ...) when taking PMF or Functor callable
QTimer::singleShot is optimized for zero timeouts when using the API
taking a string method name. This optimization was not used for the API
taking a PMF or functor. This patch adds it, making the various API
calls behave similarly from a performance point of view.
The approach taken here requires a QObject context object. If none is
available, e.g. a nullptr was passed explicitly, or the
QTimer::singleShot(O, Functor) API was used, the optimization could
not easily be applied. This is not only bad from a performance POV,
but also poses as a potential source for heisenbugs: Using the
different API versions of QTimer::singleShot would use different code
paths internally, which then would not ensure the expected slot call
order. This problem actually existed already when mixing the
string-based slot syntax with PMF/functors in the QTimer::singleShot
API.
This patch overcomes this hurdle and fixes all of the above: When we
encounter a 0ms single shot timer, and no QObject context object is
available, we fall back to the main thread, or create a temporary
QObject for any other thread. The updated and extended benchmark
shows that this is still a significant performance improvement
over using a timer:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.48 msecs per iteration (total: 748, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
7.20 msecs per iteration (total: 720, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
6.79 msecs per iteration (total: 679, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
6.92 msecs per iteration (total: 693, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.34 msecs per iteration (total: 735, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.90 msecs per iteration (total: 690, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
7.46 msecs per iteration (total: 747, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
6.70 msecs per iteration (total: 671, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
13.75 msecs per iteration (total: 1,376, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
7.05 msecs per iteration (total: 706, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.70 msecs per iteration (total: 670, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
6.58 msecs per iteration (total: 658, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 20977ms
********* Finished testing of qtimer_vs_qmetaobject *********
Without the change to qtimer.cpp, the results are:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
112.84 msecs per iteration (total: 11,285, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
115.62 msecs per iteration (total: 11,563, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
110.81 msecs per iteration (total: 11,082, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.04 msecs per iteration (total: 704, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 746, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
118.42 msecs per iteration (total: 11,842, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
119.35 msecs per iteration (total: 11,936, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
130.96 msecs per iteration (total: 13,096, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
8.08 msecs per iteration (total: 808, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.79 msecs per iteration (total: 680, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
7.49 msecs per iteration (total: 749, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 153995ms
********* Finished testing of qtimer_vs_qmetaobject *********
Additionally, this patch adds a unit test to verify that the slot call
order for 0ms single shot timers is followed while mixing the various
API versions. It fails without this patch but passes now.
Finally, another test is added to verify that using QTimer::singleShot
before a QCoreApplication was constructed is still working properly.
Change-Id: I0d6211554b6198cb3e527be9ec3adc572b1b54ee
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2018-01-11 16:46:24 +00:00
|
|
|
return QTest::qExec(&tc, argc, argv);
|
2011-08-25 14:34:40 +00:00
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
#else
|
|
|
|
|
Optimize QTimer::singleShot(0, ...) when taking PMF or Functor callable
QTimer::singleShot is optimized for zero timeouts when using the API
taking a string method name. This optimization was not used for the API
taking a PMF or functor. This patch adds it, making the various API
calls behave similarly from a performance point of view.
The approach taken here requires a QObject context object. If none is
available, e.g. a nullptr was passed explicitly, or the
QTimer::singleShot(O, Functor) API was used, the optimization could
not easily be applied. This is not only bad from a performance POV,
but also poses as a potential source for heisenbugs: Using the
different API versions of QTimer::singleShot would use different code
paths internally, which then would not ensure the expected slot call
order. This problem actually existed already when mixing the
string-based slot syntax with PMF/functors in the QTimer::singleShot
API.
This patch overcomes this hurdle and fixes all of the above: When we
encounter a 0ms single shot timer, and no QObject context object is
available, we fall back to the main thread, or create a temporary
QObject for any other thread. The updated and extended benchmark
shows that this is still a significant performance improvement
over using a timer:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.48 msecs per iteration (total: 748, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
7.20 msecs per iteration (total: 720, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
6.79 msecs per iteration (total: 679, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
6.92 msecs per iteration (total: 693, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.34 msecs per iteration (total: 735, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.90 msecs per iteration (total: 690, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
7.46 msecs per iteration (total: 747, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
6.70 msecs per iteration (total: 671, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
13.75 msecs per iteration (total: 1,376, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
7.05 msecs per iteration (total: 706, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.70 msecs per iteration (total: 670, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
6.58 msecs per iteration (total: 658, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 20977ms
********* Finished testing of qtimer_vs_qmetaobject *********
Without the change to qtimer.cpp, the results are:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
112.84 msecs per iteration (total: 11,285, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
115.62 msecs per iteration (total: 11,563, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
110.81 msecs per iteration (total: 11,082, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.04 msecs per iteration (total: 704, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 746, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
118.42 msecs per iteration (total: 11,842, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
119.35 msecs per iteration (total: 11,936, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
130.96 msecs per iteration (total: 13,096, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
8.08 msecs per iteration (total: 808, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.79 msecs per iteration (total: 680, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
7.49 msecs per iteration (total: 749, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 153995ms
********* Finished testing of qtimer_vs_qmetaobject *********
Additionally, this patch adds a unit test to verify that the slot call
order for 0ms single shot timers is followed while mixing the various
API versions. It fails without this patch but passes now.
Finally, another test is added to verify that using QTimer::singleShot
before a QCoreApplication was constructed is still working properly.
Change-Id: I0d6211554b6198cb3e527be9ec3adc572b1b54ee
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2018-01-11 16:46:24 +00:00
|
|
|
#define QTEST_MAIN_IMPL(TestObject) \
|
2018-08-06 15:07:07 +00:00
|
|
|
TESTLIB_SELFCOVERAGE_START(#TestObject) \
|
2019-07-30 08:16:53 +00:00
|
|
|
QT_PREPEND_NAMESPACE(QTest::Internal::callInitMain)<TestObject>(); \
|
2011-04-27 10:05:43 +00:00
|
|
|
QCoreApplication app(argc, argv); \
|
2012-01-11 10:49:35 +00:00
|
|
|
app.setAttribute(Qt::AA_Use96Dpi, true); \
|
2011-04-27 10:05:43 +00:00
|
|
|
TestObject tc; \
|
2015-04-28 11:40:26 +00:00
|
|
|
QTEST_SET_MAIN_SOURCE_PATH \
|
Optimize QTimer::singleShot(0, ...) when taking PMF or Functor callable
QTimer::singleShot is optimized for zero timeouts when using the API
taking a string method name. This optimization was not used for the API
taking a PMF or functor. This patch adds it, making the various API
calls behave similarly from a performance point of view.
The approach taken here requires a QObject context object. If none is
available, e.g. a nullptr was passed explicitly, or the
QTimer::singleShot(O, Functor) API was used, the optimization could
not easily be applied. This is not only bad from a performance POV,
but also poses as a potential source for heisenbugs: Using the
different API versions of QTimer::singleShot would use different code
paths internally, which then would not ensure the expected slot call
order. This problem actually existed already when mixing the
string-based slot syntax with PMF/functors in the QTimer::singleShot
API.
This patch overcomes this hurdle and fixes all of the above: When we
encounter a 0ms single shot timer, and no QObject context object is
available, we fall back to the main thread, or create a temporary
QObject for any other thread. The updated and extended benchmark
shows that this is still a significant performance improvement
over using a timer:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.48 msecs per iteration (total: 748, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
7.20 msecs per iteration (total: 720, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
6.79 msecs per iteration (total: 679, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
6.92 msecs per iteration (total: 693, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.34 msecs per iteration (total: 735, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.90 msecs per iteration (total: 690, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
7.46 msecs per iteration (total: 747, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
6.70 msecs per iteration (total: 671, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
13.75 msecs per iteration (total: 1,376, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
7.05 msecs per iteration (total: 706, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.70 msecs per iteration (total: 670, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
6.58 msecs per iteration (total: 658, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 20977ms
********* Finished testing of qtimer_vs_qmetaobject *********
Without the change to qtimer.cpp, the results are:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
112.84 msecs per iteration (total: 11,285, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
115.62 msecs per iteration (total: 11,563, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
110.81 msecs per iteration (total: 11,082, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.04 msecs per iteration (total: 704, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 746, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
118.42 msecs per iteration (total: 11,842, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
119.35 msecs per iteration (total: 11,936, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
130.96 msecs per iteration (total: 13,096, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
8.08 msecs per iteration (total: 808, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.79 msecs per iteration (total: 680, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
7.49 msecs per iteration (total: 749, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 153995ms
********* Finished testing of qtimer_vs_qmetaobject *********
Additionally, this patch adds a unit test to verify that the slot call
order for 0ms single shot timers is followed while mixing the various
API versions. It fails without this patch but passes now.
Finally, another test is added to verify that using QTimer::singleShot
before a QCoreApplication was constructed is still working properly.
Change-Id: I0d6211554b6198cb3e527be9ec3adc572b1b54ee
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2018-01-11 16:46:24 +00:00
|
|
|
return QTest::qExec(&tc, argc, argv);
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
#endif // QT_GUI_LIB
|
|
|
|
|
Optimize QTimer::singleShot(0, ...) when taking PMF or Functor callable
QTimer::singleShot is optimized for zero timeouts when using the API
taking a string method name. This optimization was not used for the API
taking a PMF or functor. This patch adds it, making the various API
calls behave similarly from a performance point of view.
The approach taken here requires a QObject context object. If none is
available, e.g. a nullptr was passed explicitly, or the
QTimer::singleShot(O, Functor) API was used, the optimization could
not easily be applied. This is not only bad from a performance POV,
but also poses as a potential source for heisenbugs: Using the
different API versions of QTimer::singleShot would use different code
paths internally, which then would not ensure the expected slot call
order. This problem actually existed already when mixing the
string-based slot syntax with PMF/functors in the QTimer::singleShot
API.
This patch overcomes this hurdle and fixes all of the above: When we
encounter a 0ms single shot timer, and no QObject context object is
available, we fall back to the main thread, or create a temporary
QObject for any other thread. The updated and extended benchmark
shows that this is still a significant performance improvement
over using a timer:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.48 msecs per iteration (total: 748, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
7.20 msecs per iteration (total: 720, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
6.79 msecs per iteration (total: 679, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
6.92 msecs per iteration (total: 693, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.34 msecs per iteration (total: 735, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.90 msecs per iteration (total: 690, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
7.46 msecs per iteration (total: 747, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
6.70 msecs per iteration (total: 671, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
13.75 msecs per iteration (total: 1,376, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
7.05 msecs per iteration (total: 706, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.70 msecs per iteration (total: 670, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
6.58 msecs per iteration (total: 658, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 20977ms
********* Finished testing of qtimer_vs_qmetaobject *********
Without the change to qtimer.cpp, the results are:
********* Start testing of qtimer_vs_qmetaobject *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20181127)
PASS : qtimer_vs_qmetaobject::initTestCase()
PASS : qtimer_vs_qmetaobject::bench(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_slot":
7.45 msecs per iteration (total: 745, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_pmf":
112.84 msecs per iteration (total: 11,285, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor":
115.62 msecs per iteration (total: 11,563, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::bench():"singleShot_functor_noctx":
110.81 msecs per iteration (total: 11,082, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_string":
7.04 msecs per iteration (total: 704, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_pmf":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::bench(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::bench():"invokeMethod_functor":
6.62 msecs per iteration (total: 662, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_slot)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_slot":
7.45 msecs per iteration (total: 746, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_pmf":
118.42 msecs per iteration (total: 11,842, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor":
119.35 msecs per iteration (total: 11,936, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(singleShot_functor_noctx)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"singleShot_functor_noctx":
130.96 msecs per iteration (total: 13,096, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_string)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_string":
8.08 msecs per iteration (total: 808, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_pmf)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_pmf":
6.79 msecs per iteration (total: 680, iterations: 100)
PASS : qtimer_vs_qmetaobject::benchBackgroundThread(invokeMethod_functor)
RESULT : qtimer_vs_qmetaobject::benchBackgroundThread():"invokeMethod_functor":
7.49 msecs per iteration (total: 749, iterations: 100)
PASS : qtimer_vs_qmetaobject::cleanupTestCase()
Totals: 16 passed, 0 failed, 0 skipped, 0 blacklisted, 153995ms
********* Finished testing of qtimer_vs_qmetaobject *********
Additionally, this patch adds a unit test to verify that the slot call
order for 0ms single shot timers is followed while mixing the various
API versions. It fails without this patch but passes now.
Finally, another test is added to verify that using QTimer::singleShot
before a QCoreApplication was constructed is still working properly.
Change-Id: I0d6211554b6198cb3e527be9ec3adc572b1b54ee
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2018-01-11 16:46:24 +00:00
|
|
|
#define QTEST_MAIN(TestObject) \
|
|
|
|
int main(int argc, char *argv[]) \
|
|
|
|
{ \
|
|
|
|
QTEST_MAIN_IMPL(TestObject) \
|
|
|
|
}
|
|
|
|
|
2010-11-13 23:06:07 +00:00
|
|
|
#define QTEST_GUILESS_MAIN(TestObject) \
|
|
|
|
int main(int argc, char *argv[]) \
|
|
|
|
{ \
|
2018-08-06 15:07:07 +00:00
|
|
|
TESTLIB_SELFCOVERAGE_START(#TestObject) \
|
2019-07-30 08:16:53 +00:00
|
|
|
QT_PREPEND_NAMESPACE(QTest::Internal::callInitMain)<TestObject>(); \
|
2010-11-13 23:06:07 +00:00
|
|
|
QCoreApplication app(argc, argv); \
|
2012-01-11 10:49:35 +00:00
|
|
|
app.setAttribute(Qt::AA_Use96Dpi, true); \
|
2010-11-13 23:06:07 +00:00
|
|
|
TestObject tc; \
|
2015-04-28 11:40:26 +00:00
|
|
|
QTEST_SET_MAIN_SOURCE_PATH \
|
2010-11-13 23:06:07 +00:00
|
|
|
return QTest::qExec(&tc, argc, argv); \
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
#endif
|