QRandomGenerator: optimize for the common use case

The most common uses of QRandomGenerator are getting 32- and 64-bit
quantities, either through the generate() and generate64() functions or
by ones that call those, like bounded() or generateDouble(). So optimize
for those with the same entry point by returning one 64-bit value from
the _fillRange() function. Further optimize by not requiring a buffer
for those two cases, which required us to replace the (begin, end)
parameters with (begin, count).

Change-Id: I3eb349b832c14610895efffd16356859eecd5397
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
bb10
Thiago Macieira 2020-09-16 16:46:18 -07:00
parent d0c4d18b01
commit 0096562299
2 changed files with 28 additions and 22 deletions

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2019 Intel Corporation.
** Copyright (C) 2020 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -1177,22 +1177,32 @@ bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
/*!
\internal
Fills the range pointed by \a buffer and \a bufferEnd with 32-bit random
values. The buffer must be correctly aligned.
Fills the range pointed by \a buffer with \a count 32-bit random values.
The buffer must be correctly aligned.
Returns the value of the first two 32-bit entries as a \c{quint64}.
*/
void QRandomGenerator::_fillRange(void *buffer, void *bufferEnd)
quint64 QRandomGenerator::_fillRange(void *buffer, qptrdiff count)
{
// Verify that the pointers are properly aligned for 32-bit
Q_ASSERT(quintptr(buffer) % sizeof(quint32) == 0);
Q_ASSERT(quintptr(bufferEnd) % sizeof(quint32) == 0);
quint32 *begin = static_cast<quint32 *>(buffer);
quint32 *end = static_cast<quint32 *>(bufferEnd);
Q_ASSERT(count >= 0);
Q_ASSERT(buffer || count <= 2);
if (type == SystemRNG || Q_UNLIKELY(uint(qt_randomdevice_control.loadAcquire()) & (UseSystemRNG|SetRandomData)))
return SystemGenerator::self().generate(begin, end);
quint64 dummy;
quint32 *begin = static_cast<quint32 *>(buffer ? buffer : &dummy);
quint32 *end = begin + count;
SystemAndGlobalGenerators::PRNGLocker lock(this);
std::generate(begin, end, [this]() { return storage.engine()(); });
if (type == SystemRNG || Q_UNLIKELY(uint(qt_randomdevice_control.loadAcquire()) & (UseSystemRNG|SetRandomData))) {
SystemGenerator::self().generate(begin, end);
} else {
SystemAndGlobalGenerators::PRNGLocker lock(this);
std::generate(begin, end, [this]() { return storage.engine()(); });
}
if (end - begin == 1)
return *begin;
return begin[0] | (quint64(begin[1]) << 32);
}
namespace {

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2017 Intel Corporation.
** Copyright (C) 2020 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -83,16 +83,12 @@ public:
quint32 generate()
{
quint32 ret;
fillRange(&ret, 1);
return ret;
return _fillRange(nullptr, 1);
}
quint64 generate64()
{
quint32 buf[2];
fillRange(buf);
return buf[0] | (quint64(buf[1]) << 32);
return _fillRange(nullptr, sizeof(quint64) / sizeof(quint32));
}
double generateDouble()
@ -142,13 +138,13 @@ public:
template <typename UInt, IfValidUInt<UInt> = true>
void fillRange(UInt *buffer, qsizetype count)
{
_fillRange(buffer, buffer + count);
_fillRange(buffer, count * sizeof(UInt) / sizeof(quint32));
}
template <typename UInt, size_t N, IfValidUInt<UInt> = true>
void fillRange(UInt (&buffer)[N])
{
_fillRange(buffer, buffer + N);
_fillRange(buffer, N * sizeof(UInt) / sizeof(quint32));
}
// API like std::seed_seq
@ -160,7 +156,7 @@ public:
void generate(quint32 *begin, quint32 *end)
{
_fillRange(begin, end);
_fillRange(begin, end - begin);
}
// API like std:: random engines
@ -181,7 +177,7 @@ protected:
QRandomGenerator(System);
private:
Q_CORE_EXPORT void _fillRange(void *buffer, void *bufferEnd);
Q_CORE_EXPORT quint64 _fillRange(void *buffer, qptrdiff count);
friend class QRandomGenerator64;
struct SystemGenerator;