Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the Mersenne Twister engine when C++11 is available #2159

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 12 additions & 7 deletions srtcore/sync.cpp
Expand Up @@ -283,10 +283,11 @@ bool srt::sync::CGlobEvent::waitForEvent()
namespace srt
{
#if HAVE_CXX11
static std::random_device& randomDevice()
static std::mt19937& randomGen()
{
static std::random_device s_RandomDevice;
return s_RandomDevice;
static std::mt19937 s_GenMT19937(s_RandomDevice());
return s_GenMT19937;
}
#elif defined(_WIN32) && defined(__MINGW32__)
static void initRandSeed()
Expand All @@ -300,7 +301,7 @@ static pthread_once_t s_InitRandSeedOnce = PTHREAD_ONCE_INIT;
static unsigned int genRandSeed()
{
// Duration::count() does not depend on any global objects,
// therefore it is preferred over count)microseconds(..).
// therefore it is preferred over count_microseconds(..).
const int64_t seed = sync::steady_clock::now().time_since_epoch().count();
return (unsigned int) seed;
}
Expand All @@ -325,7 +326,7 @@ int srt::sync::genRandomInt(int minVal, int maxVal)
sync::ScopedLock lck(s_mtxRandomDevice);
#if HAVE_CXX11
uniform_int_distribution<> dis(minVal, maxVal);
return dis(randomDevice());
return dis(randomGen());
#else
#if defined(__MINGW32__)
// No rand_r(..) for MinGW.
Expand All @@ -342,9 +343,13 @@ int srt::sync::genRandomInt(int minVal, int maxVal)
#endif

// Map onto [minVal, maxVal].
// Note. The probablity to get maxVal as the result is minuscule.
const int res = minVal + static_cast<int>((maxVal - minVal) * rand_0_1);
return res;
// Note. There is a minuscule probablity to get maxVal+1 as the result.
// So we have to use long long to handle cases when maxVal = INT32_MAX.
// Also we must check 'res' does not exceed maxVal,
// which may happen if rand_0_1 = 1, even though the chances are low.
const long long llMaxVal = maxVal;
const int res = minVal + static_cast<int>((llMaxVal + 1 - minVal) * rand_0_1);
return min(res, maxVal);
#endif // HAVE_CXX11
}

5 changes: 4 additions & 1 deletion test/test_many_connections.cpp
Expand Up @@ -126,7 +126,10 @@ class TestConnection
};



// This test establishes multiple connections to a single SRT listener on a localhost port.
// Packets are submitted for sending to all those connections in a non-blocking mode.
// Then all connections are closed. Some sockets may potentially still have undelivered packets.
// This test tries to reproduce the issue described in #1182, and fixed by #1315.
TEST_F(TestConnection, Multiple)
{
const sockaddr_in lsa = m_sa;
Expand Down
50 changes: 32 additions & 18 deletions test/test_sync.cpp
@@ -1,4 +1,5 @@
#include "gtest/gtest.h"
#include <array>
#include <chrono>
#include <thread>
#include <future>
Expand All @@ -15,14 +16,6 @@
using namespace std;
using namespace srt::sync;

// GNUC supports C++14 starting from version 5
//#if defined(__GNUC__) && (__GNUC__ < 5)
////namespace srt
// constexpr chrono::milliseconds operator"" ms(
// unsigned long long _Val) { // return integral milliseconds
// return chrono::milliseconds(_Val);
//}
//#endif

TEST(SyncDuration, BasicChecks)
{
Expand Down Expand Up @@ -159,23 +152,44 @@ TEST(SyncDuration, OperatorMultIntEq)

TEST(SyncRandom, GenRandomInt)
{
vector<int> mn(64);
array<int, 64> mn = {};

for (int i = 0; i < 2048; ++i)
// Check generated values are in the specified range.
const size_t n = 2048;
for (size_t i = 0; i < n; ++i)
{
const int rand_val = genRandomInt(0, 63);
const int rand_val = genRandomInt(0, mn.size() - 1);
ASSERT_GE(rand_val, 0);
ASSERT_LE(rand_val, 63);
ASSERT_LT(rand_val, mn.size());
++mn[rand_val];
}

// Check the distribution is more or less uniform.
// 100% uniform if each value is generated (n / (2 * mn.size())) times.
// We expect at least half of that value for a random uniform distribution.
const int min_value = n / (2 * mn.size()) - 1;
cout << "min value: " << min_value << endl;
for (size_t i = 0; i < mn.size(); ++i)
{
EXPECT_GE(mn[i], min_value) << "i=" << i << ". Ok-ish if the count is non-zero.";
}

// Uncomment to see the distribution.
// for (size_t i = 0; i < mn.size(); ++i)
// {
// cout << i << '\t';
// for (int j=0; j<mn[i]; ++j) cout << '*';
// cout << '\n';
// }
//for (size_t i = 0; i < mn.size(); ++i)
//{
// cout << i << '\t';
// for (int j=0; j<mn[i]; ++j) cout << '*';
// cout << '\n';
//}

// Check INT32_MAX
for (size_t i = 0; i < n; ++i)
{
const int rand_val = genRandomInt(INT32_MAX - 1, INT32_MAX);

EXPECT_GE(rand_val, INT32_MAX - 1);
EXPECT_LE(rand_val, INT32_MAX);
}
}

/*****************************************************************************/
Expand Down