Skip to content

Commit

Permalink
[core] Added srt::sync::genRandomInt(..)
Browse files Browse the repository at this point in the history
for a uniform way to get a random integer from the range.
If C++11 is enabled, uniform_int_distribution
and random_device are used.
  • Loading branch information
maxsharabayko committed May 18, 2021
1 parent 189b171 commit 393a6c7
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 32 deletions.
17 changes: 1 addition & 16 deletions srtcore/api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,22 +194,7 @@ m_bGCStatus(false),
m_ClosedSockets()
{
// Socket ID MUST start from a random value
// Note. Don't use CTimer here, because s_UDTUnited is a static instance of CUDTUnited
// with dynamic initialization (calling this constructor), while CTimer has
// a static member s_ullCPUFrequency with dynamic initialization.
// The order of initialization is not guaranteed.
timeval t;

gettimeofday(&t, 0);
srand((unsigned int)t.tv_usec);

const double rand1_0 = double(rand())/RAND_MAX;

// Motivation: in case when rand() returns the value equal to RAND_MAX,
// rand1_0 == 1, so the below formula will be
// 1 + (MAX_SOCKET_VAL-1) * 1 = 1 + MAX_SOCKET_VAL - 1 = MAX_SOCKET_VAL
// which is the highest allowed value for the socket.
m_SocketIDGenerator = 1 + int((MAX_SOCKET_VAL-1) * rand1_0);
m_SocketIDGenerator = genRandomInt(1, MAX_SOCKET_VAL);
m_SocketIDGenerator_init = m_SocketIDGenerator;

// XXX An unlikely exception thrown from the below calls
Expand Down
8 changes: 1 addition & 7 deletions srtcore/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,12 +562,6 @@ int CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const

if (!packet.isControl())
{
if (dcounter == 0)
{
timeval tv;
gettimeofday(&tv, 0);
srand(tv.tv_usec & 0xFFFF);
}
++dcounter;

if (flwcounter)
Expand All @@ -581,7 +575,7 @@ int CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const
if (dcounter > 8)
{
// Make a random number in the range between 8 and 24
int rnd = rand() % 16 + SRT_TEST_FAKE_LOSS;
const int rnd = srt::sync::getRandomInt(8, 24);

if (dcounter > rnd)
{
Expand Down
8 changes: 3 additions & 5 deletions srtcore/congctl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,11 +525,9 @@ class FileCC : public SrtCongestionControlBase

m_iLastDecSeq = m_parent->sndSeqNo();

// remove global synchronization using randomization
srand(m_iLastDecSeq);
m_iDecRandom = (int)ceil(m_iAvgNAKNum * (double(rand()) / RAND_MAX));
if (m_iDecRandom < 1)
m_iDecRandom = 1;
// remove global synchronization using randomization.
m_iDecRandom = genRandomInt(1, m_iAvgNAKNum);
SRT_ASSERT(m_iDecRandom >= 1);
HLOGC(cclog.Debug, log << "FileCC: LOSS:NEW lseqno=" << lossbegin
<< ", lastsentseqno=" << m_iLastDecSeq
<< ", seqdiff=" << CSeqNo::seqoff(m_iLastDecSeq, lossbegin)
Expand Down
4 changes: 1 addition & 3 deletions srtcore/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,9 +401,7 @@ class CUDT
static int32_t generateISN()
{
using namespace srt::sync;
// Random Initial Sequence Number (normal mode)
srand((unsigned) count_microseconds(steady_clock::now().time_since_epoch()));
return (int32_t)(CSeqNo::m_iMaxSeqNo * (double(rand()) / RAND_MAX));
return genRandomInt(0, CSeqNo::m_iMaxSeqNo);
}

// For SRT_tsbpdLoop
Expand Down
81 changes: 81 additions & 0 deletions srtcore/sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,18 @@
#include "logging.h"
#include "common.h"

// HAVE_CXX11 is defined in utilities.h, included with common.h.
// The following conditional inclusion must go after common.h.
#if HAVE_CXX11
#include <random>
#endif

namespace srt_logging
{
extern Logger inlog;
}
using namespace srt_logging;
using namespace std;

namespace srt
{
Expand Down Expand Up @@ -267,3 +274,77 @@ bool srt::sync::CGlobEvent::waitForEvent()
return g_Sync.lock_wait_for(milliseconds_from(10));
}

////////////////////////////////////////////////////////////////////////////////
//
// Random
//
////////////////////////////////////////////////////////////////////////////////

namespace srt
{
#if HAVE_CXX11
static std::random_device& randomDevice()
{
static std::random_device s_RandomDevice;
return s_RandomDevice;
}
#elif defined(_WIN32) && defined(__MINGW32__)
static void initRandSeed()
{
const int64_t seed = sync::steady_clock::now().time_since_epoch().count();
srand((unsigned int) seed);
}
static pthread_once_t s_InitRandSeedOnce = PTHREAD_ONCE_INIT;
#else

static unsigned int genRandSeed()
{
// Duration::count() does not depend on any global objects,
// therefore it is preferred over count)microseconds(..).
const int64_t seed = sync::steady_clock::now().time_since_epoch().count();
return (unsigned int) seed;
}

static unsigned int* getRandSeed()
{
static unsigned int s_uRandSeed = genRandSeed();
return &s_uRandSeed;
}

#endif
}

int srt::sync::genRandomInt(int minVal, int maxVal)
{
// This Meyers singleton initialization is thread-safe since C++11, but is not thread-safe in C++03.
// A mutex to protect simulteneout access to the random device.
// Thread-local storage could be used here instead to store the seed / random device.
// However the generator is not used often (Initial Socket ID, Initial sequence number, FileCC),
// so sharing a single seed among threads should not impact the performance.
static sync::Mutex s_mtxRandomDevice;
sync::ScopedLock lck(s_mtxRandomDevice);
#if HAVE_CXX11
uniform_int_distribution<> dis(minVal, maxVal);
return dis(randomDevice());
#else
#if defined(__MINGW32__)
// No rand_r(..) for MinGW.
pthread_once(&s_InitRandSeedOnce, initRandSeed);
// rand() returns a pseudo-random integer in the range 0 to RAND_MAX inclusive
// (i.e., the mathematical range [0, RAND_MAX]).
// Therefore, rand_0_1 belongs to [0.0, 1.0].
const double rand_0_1 = double(rand()) / RAND_MAX;
#else // not __MINGW32__
// rand_r(..) returns a pseudo-random integer in the range 0 to RAND_MAX inclusive
// (i.e., the mathematical range [0, RAND_MAX]).
// Therefore, rand_0_1 belongs to [0.0, 1.0].
const double rand_0_1 = double(rand_r(getRandSeed())) / RAND_MAX;
#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;
#endif // HAVE_CXX11
}

12 changes: 12 additions & 0 deletions srtcore/sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,18 @@ void SetThreadLocalError(const CUDTException& e);
/// @returns CUDTException pointer
CUDTException& GetThreadLocalError();

////////////////////////////////////////////////////////////////////////////////
//
// Random distribution functions.
//
////////////////////////////////////////////////////////////////////////////////

/// Generate a uniform-distributed random integer from [minVal; maxVal].
/// If HAVE_CXX11, uses std::uniform_distribution(std::random_device).
/// @param[in] minVal minimum allowed value of the resulting random number.
/// @param[in] maxVal maximum allowed value of the resulting random number.
int genRandomInt(int minVal, int maxVal);

} // namespace sync
} // namespace srt

Expand Down
1 change: 0 additions & 1 deletion srtcore/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ written by
#define ATR_UNUSED
#define ATR_DEPRECATED
#endif

#if defined(__cplusplus) && __cplusplus > 199711L
#define HAVE_CXX11 1

Expand Down
21 changes: 21 additions & 0 deletions test/test_sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,27 @@ TEST(SyncDuration, OperatorMultIntEq)
EXPECT_EQ(count_milliseconds(a), 7000);
}

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

for (int i = 0; i < 2048; ++i)
{
const int rand_val = genRandomInt(0, 63);
ASSERT_GE(rand_val, 0);
ASSERT_LE(rand_val, 63);
++mn[rand_val];
}

// 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';
// }
}

/*****************************************************************************/
/*
* TimePoint tests
Expand Down

0 comments on commit 393a6c7

Please sign in to comment.