diff options
author | Jere Leppänen <jere.leppanen@nokia.com> | 2021-11-19 10:22:23 +0200 |
---|---|---|
committer | Petri Savolainen <petri.savolainen@nokia.com> | 2021-12-27 10:54:58 +0200 |
commit | 5238facbb6c250f947f731439ab779c7c969f21f (patch) | |
tree | 002d8c005f1a29c22bce08fba12028ef8dc94166 | |
parent | 98e75e98317509d7cd580145102688cd7d5a9448 (diff) |
linux-gen: random: improve ODP_RANDOM_BASIC data and random test data
Improve the quality of data generated by and the speed of
odp_random_test_data() and _odp_random_std_data() (used when OpenSSL
random is not enabled).
Signed-off-by: Jere Leppänen <jere.leppanen@nokia.com>
Reviewed-by: Tuomas Taipale <tuomas.taipale@nokia.com>
Reviewed-by: Petri Savolainen <petri.savolainen@nokia.com>
-rw-r--r-- | platform/linux-generic/odp_random_std.c | 94 |
1 files changed, 65 insertions, 29 deletions
diff --git a/platform/linux-generic/odp_random_std.c b/platform/linux-generic/odp_random_std.c index 3afd049f4..50cd773f2 100644 --- a/platform/linux-generic/odp_random_std.c +++ b/platform/linux-generic/odp_random_std.c @@ -4,52 +4,88 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include <odp_posix_extensions.h> -#include <stdint.h> -#include <stdlib.h> #include <odp/api/byteorder.h> #include <odp/api/cpu.h> #include <odp/api/debug.h> #include <odp_init_internal.h> #include <odp_random_std_internal.h> +#include <odp_cpu.h> +#include <stdint.h> #include <time.h> -/* Assume at least two rand bytes are available and RAND_MAX is power of two - 1 */ -ODP_STATIC_ASSERT(RAND_MAX >= UINT16_MAX, "RAND_MAX too small"); -ODP_STATIC_ASSERT((RAND_MAX & (RAND_MAX + 1ULL)) == 0, "RAND_MAX not power of two - 1"); +/* + * Xorshift64*, adapted from [1], and modified to return only the high 32 bits. + * + * [1] An experimental exploration of Marsaglia's xorshift generators, scrambled + * Sebastiano Vigna, July 2016. + * http://vigna.di.unimi.it/ftp/papers/xorshift.pdf + */ +static inline uint32_t xorshift64s32(uint64_t *x) +{ + /* The variable x should be initialized to a nonzero seed. [1] */ + if (!*x) + /* + * 2^64 / phi. As far away as possible from any small integer + * fractions, which the caller might be likely to use for the + * next seed after 0. + */ + *x = 11400714819323198485ull; -static int32_t _random_data(uint8_t *buf, uint32_t len, uint32_t *seed) + *x ^= *x >> 12; /* a */ + *x ^= *x << 25; /* b */ + *x ^= *x >> 27; /* c */ + return (*x * 2685821657736338717ull) >> 32; +} + +static int32_t _random_data(uint8_t *buf, uint32_t len, uint64_t *seed) { - union { - uint32_t rand_word; - uint8_t rand_byte[4]; - } u; - uint32_t i = 0, j, k; - - while (i < len) { - u.rand_word = rand_r(seed); - - /* Use two least significant bytes */ - j = ODP_LITTLE_ENDIAN ? 0 : 2; - for (k = 0; k < 2 && i < len; i++, j++, k++) - *buf++ = u.rand_byte[j]; + const uint32_t ret = len; + + if (!_ODP_UNALIGNED && ((uintptr_t)buf & 3) && len) { + uint32_t r = xorshift64s32(seed); + + if ((uintptr_t)buf & 1) { + *(uint8_t *)(uintptr_t)buf = r & 0xff; + r >>= 8; + buf += 1; + len -= 1; + } + + if (((uintptr_t)buf & 2) && len >= 2) { + *(uint16_t *)(uintptr_t)buf = r & 0xffff; + buf += 2; + len -= 2; + } + } + + for (uint32_t i = 0; i < len / 4; i++) { + *(uint32_t *)(uintptr_t)buf = xorshift64s32(seed); + buf += 4; } - return len; + if (len & 3) { + uint32_t r = xorshift64s32(seed); + + if (len & 2) { + *(uint16_t *)(uintptr_t)buf = r & 0xffff; + r >>= 16; + buf += 2; + } + + if (len & 1) + *(uint8_t *)(uintptr_t)buf = r & 0xff; + } + + return ret; } int32_t _odp_random_std_test_data(uint8_t *buf, uint32_t len, uint64_t *seed) { - uint32_t seed32 = (*seed) & 0xffffffff; - - _random_data(buf, len, &seed32); - - *seed = seed32; - return len; + return _random_data(buf, len, seed); } -static __thread uint32_t this_seed; +static __thread uint64_t this_seed; int32_t _odp_random_std_data(uint8_t *buf, uint32_t len) { @@ -59,7 +95,7 @@ int32_t _odp_random_std_data(uint8_t *buf, uint32_t len) int _odp_random_std_init_local(void) { this_seed = time(NULL); - this_seed ^= odp_cpu_id() << 16; + this_seed ^= (uint64_t)odp_cpu_id() << 32; return 0; } |