aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJere Leppänen <jere.leppanen@nokia.com>2021-11-19 10:22:23 +0200
committerPetri Savolainen <petri.savolainen@nokia.com>2021-12-27 10:54:58 +0200
commit5238facbb6c250f947f731439ab779c7c969f21f (patch)
tree002d8c005f1a29c22bce08fba12028ef8dc94166
parent98e75e98317509d7cd580145102688cd7d5a9448 (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.c94
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;
}