The implementation of rte_rand() returns only 62 bits of pseudo-randomness, because the underlying calls to lrand48() "return non-negative long integers uniformly distributed between 0 and 2^31."
We have written a potential fix, but before we spend more time testing and refining it, I wanted to check with you guys. We switched to using the reentrant versions of [ls]rand48, and maintain per-lcore state. We need ~2.06 calls to lrand48_r(), per call to rte_rand(). Do you agree with the approach we've taken in this patch? Thanks, Robert --- lib/librte_eal/common/include/rte_random.h | 33 +++++++++++++++++++++++++-- lib/librte_eal/linuxapp/eal/eal_thread.c | 7 ++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/lib/librte_eal/common/include/rte_random.h b/lib/librte_eal/common/include/rte_random.h index 24ae836..b9248cd 100644 --- a/lib/librte_eal/common/include/rte_random.h +++ b/lib/librte_eal/common/include/rte_random.h @@ -46,6 +46,17 @@ extern "C" { #include <stdint.h> #include <stdlib.h> +#include <rte_per_lcore.h> +#include <rte_branch_prediction.h> + +struct rte_rand_data { + struct drand48_data _dr48; + uint32_t _hi_bits; + uint8_t _bits_left; +}; + +RTE_DECLARE_PER_LCORE(struct rte_rand_data, _rand_data); + /** * Seed the pseudo-random generator. @@ -60,7 +71,7 @@ extern "C" { static inline void rte_srand(uint64_t seedval) { - srand48((long unsigned int)seedval); + srand48_r((long unsigned int)seedval, &RTE_PER_LCORE(_rand_data)._dr48); } /** @@ -76,10 +87,26 @@ rte_srand(uint64_t seedval) static inline uint64_t rte_rand(void) { + struct rte_rand_data *rd = &RTE_PER_LCORE(_rand_data); uint64_t val; - val = lrand48(); + uint32_t hi_bits; + long int result; + + if (unlikely(rd->_bits_left < 2)) { + lrand48_r(&rd->_dr48, &result); + rd->_hi_bits |= (uint32_t)result << (1 - rd->_bits_left); + rd->_bits_left += 31; + } + + hi_bits = rd->_hi_bits; + lrand48_r(&rd->_dr48, &result); + val = (uint32_t)result | (hi_bits & 0x8000000); val <<= 32; - val += lrand48(); + hi_bits <<= 1; + lrand48_r(&rd->_dr48, &result); + val |= (uint32_t)result | (hi_bits & 0x8000000); + rd->_hi_bits = hi_bits << 1; + rd->_bits_left -= 2; return val; } diff --git a/lib/librte_eal/linuxapp/eal/eal_thread.c b/lib/librte_eal/linuxapp/eal/eal_thread.c index 5635c7d..08e7f72 100644 --- a/lib/librte_eal/linuxapp/eal/eal_thread.c +++ b/lib/librte_eal/linuxapp/eal/eal_thread.c @@ -52,6 +52,8 @@ #include <rte_eal.h> #include <rte_per_lcore.h> #include <rte_lcore.h> +#include <rte_cycles.h> +#include <rte_random.h> #include "eal_private.h" #include "eal_thread.h" @@ -59,6 +61,8 @@ RTE_DEFINE_PER_LCORE(unsigned, _lcore_id) = LCORE_ID_ANY; RTE_DEFINE_PER_LCORE(unsigned, _socket_id) = (unsigned)SOCKET_ID_ANY; RTE_DEFINE_PER_LCORE(rte_cpuset_t, _cpuset); +RTE_DEFINE_PER_LCORE(struct rte_rand_data, _rand_data); + /* * Send a message to a slave lcore identified by slave_id to call a @@ -147,6 +151,9 @@ eal_thread_loop(__attribute__((unused)) void *arg) /* set the lcore ID in per-lcore memory area */ RTE_PER_LCORE(_lcore_id) = lcore_id; + /* seed per-lcore PRNG */ + rte_srand(rte_rdtsc()); + /* set CPU affinity */ if (eal_thread_set_affinity() < 0) rte_panic("cannot set affinity\n"); -- 1.7.1