aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-generic/odp_random_std.c
blob: 5ae47d596b4d7cda5d113ff4f47483ef891f9477 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright (c) 2014-2018 Linaro Limited
 */

#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>

/*
 * 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;

	*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)
{
	const uint32_t ret = len;

	if (!_ODP_UNALIGNED) {
		uint32_t r = xorshift64s32(seed);

		if (((uintptr_t)buf & 1) && len) {
			*(uint8_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;
		}
	} else {
		for (uint32_t i = 0; i < len / 4; i++) {
			*(odp_una_u32_t *)buf = xorshift64s32(seed);
			buf += 4;
		}
	}

	if (len & 3) {
		uint32_t r = xorshift64s32(seed);

		if (len & 2) {
			*(odp_una_u16_t *)buf = r & 0xffff;
			r >>= 16;
			buf += 2;
		}

		if (len & 1)
			*(uint8_t *)buf = r & 0xff;
	}

	return ret;
}

int32_t _odp_random_std_test_data(uint8_t *buf, uint32_t len, uint64_t *seed)
{
	return _random_data(buf, len, seed);
}

static __thread uint64_t this_seed;

int32_t _odp_random_std_data(uint8_t *buf, uint32_t len)
{
	return _random_data(buf, len, &this_seed);
}

int _odp_random_std_init_local(void)
{
	this_seed = time(NULL);
	this_seed ^= (uint64_t)odp_cpu_id() << 32;

	return 0;
}

int _odp_random_std_term_local(void)
{
	return 0;
}