xref: /dpdk/lib/eal/common/rte_random.c (revision 29c39cd3d54d8330ee578dd3ea27cfda1c562079)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2019 Ericsson AB
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #ifdef __RDSEED__
699a2dd95SBruce Richardson #include <x86intrin.h>
799a2dd95SBruce Richardson #endif
899a2dd95SBruce Richardson #include <unistd.h>
999a2dd95SBruce Richardson 
103d4e27fdSDavid Marchand #include <rte_bitops.h>
1199a2dd95SBruce Richardson #include <rte_branch_prediction.h>
1299a2dd95SBruce Richardson #include <rte_cycles.h>
1399a2dd95SBruce Richardson #include <rte_lcore.h>
14*29c39cd3SMattias Rönnblom #include <rte_lcore_var.h>
1599a2dd95SBruce Richardson #include <rte_random.h>
1699a2dd95SBruce Richardson 
17c6552d9aSTyler Retzlaff struct __rte_cache_aligned rte_rand_state {
1899a2dd95SBruce Richardson 	uint64_t z1;
1999a2dd95SBruce Richardson 	uint64_t z2;
2099a2dd95SBruce Richardson 	uint64_t z3;
2199a2dd95SBruce Richardson 	uint64_t z4;
2299a2dd95SBruce Richardson 	uint64_t z5;
23c6552d9aSTyler Retzlaff };
2499a2dd95SBruce Richardson 
25*29c39cd3SMattias Rönnblom RTE_LCORE_VAR_HANDLE(struct rte_rand_state, rand_state);
26*29c39cd3SMattias Rönnblom 
27*29c39cd3SMattias Rönnblom /* instance to be shared by all unregistered non-EAL threads */
28*29c39cd3SMattias Rönnblom static struct rte_rand_state unregistered_rand_state;
2999a2dd95SBruce Richardson 
3099a2dd95SBruce Richardson static uint32_t
3199a2dd95SBruce Richardson __rte_rand_lcg32(uint32_t *seed)
3299a2dd95SBruce Richardson {
3399a2dd95SBruce Richardson 	*seed = 1103515245U * *seed + 12345U;
3499a2dd95SBruce Richardson 
3599a2dd95SBruce Richardson 	return *seed;
3699a2dd95SBruce Richardson }
3799a2dd95SBruce Richardson 
3899a2dd95SBruce Richardson static uint64_t
3999a2dd95SBruce Richardson __rte_rand_lcg64(uint32_t *seed)
4099a2dd95SBruce Richardson {
4199a2dd95SBruce Richardson 	uint64_t low;
4299a2dd95SBruce Richardson 	uint64_t high;
4399a2dd95SBruce Richardson 
4499a2dd95SBruce Richardson 	/* A 64-bit LCG would have been much cleaner, but good
4599a2dd95SBruce Richardson 	 * multiplier/increments for such seem hard to come by.
4699a2dd95SBruce Richardson 	 */
4799a2dd95SBruce Richardson 
4899a2dd95SBruce Richardson 	low = __rte_rand_lcg32(seed);
4999a2dd95SBruce Richardson 	high = __rte_rand_lcg32(seed);
5099a2dd95SBruce Richardson 
5199a2dd95SBruce Richardson 	return low | (high << 32);
5299a2dd95SBruce Richardson }
5399a2dd95SBruce Richardson 
5499a2dd95SBruce Richardson static uint64_t
5599a2dd95SBruce Richardson __rte_rand_lfsr258_gen_seed(uint32_t *seed, uint64_t min_value)
5699a2dd95SBruce Richardson {
5799a2dd95SBruce Richardson 	uint64_t res;
5899a2dd95SBruce Richardson 
5999a2dd95SBruce Richardson 	res = __rte_rand_lcg64(seed);
6099a2dd95SBruce Richardson 
6199a2dd95SBruce Richardson 	if (res < min_value)
6299a2dd95SBruce Richardson 		res += min_value;
6399a2dd95SBruce Richardson 
6499a2dd95SBruce Richardson 	return res;
6599a2dd95SBruce Richardson }
6699a2dd95SBruce Richardson 
6799a2dd95SBruce Richardson static void
6899a2dd95SBruce Richardson __rte_srand_lfsr258(uint64_t seed, struct rte_rand_state *state)
6999a2dd95SBruce Richardson {
7099a2dd95SBruce Richardson 	uint32_t lcg_seed;
7199a2dd95SBruce Richardson 
7299a2dd95SBruce Richardson 	lcg_seed = (uint32_t)(seed ^ (seed >> 32));
7399a2dd95SBruce Richardson 
7499a2dd95SBruce Richardson 	state->z1 = __rte_rand_lfsr258_gen_seed(&lcg_seed, 2UL);
7599a2dd95SBruce Richardson 	state->z2 = __rte_rand_lfsr258_gen_seed(&lcg_seed, 512UL);
7699a2dd95SBruce Richardson 	state->z3 = __rte_rand_lfsr258_gen_seed(&lcg_seed, 4096UL);
7799a2dd95SBruce Richardson 	state->z4 = __rte_rand_lfsr258_gen_seed(&lcg_seed, 131072UL);
7899a2dd95SBruce Richardson 	state->z5 = __rte_rand_lfsr258_gen_seed(&lcg_seed, 8388608UL);
7999a2dd95SBruce Richardson }
8099a2dd95SBruce Richardson 
8199a2dd95SBruce Richardson void
8299a2dd95SBruce Richardson rte_srand(uint64_t seed)
8399a2dd95SBruce Richardson {
8499a2dd95SBruce Richardson 	unsigned int lcore_id;
8599a2dd95SBruce Richardson 
8699a2dd95SBruce Richardson 	/* add lcore_id to seed to avoid having the same sequence */
87*29c39cd3SMattias Rönnblom 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
88*29c39cd3SMattias Rönnblom 		struct rte_rand_state *lcore_state =
89*29c39cd3SMattias Rönnblom 			RTE_LCORE_VAR_LCORE(lcore_id, rand_state);
90*29c39cd3SMattias Rönnblom 
91*29c39cd3SMattias Rönnblom 		__rte_srand_lfsr258(seed + lcore_id, lcore_state);
92*29c39cd3SMattias Rönnblom 	}
93*29c39cd3SMattias Rönnblom 
94*29c39cd3SMattias Rönnblom 	__rte_srand_lfsr258(seed + lcore_id, &unregistered_rand_state);
9599a2dd95SBruce Richardson }
9699a2dd95SBruce Richardson 
9799a2dd95SBruce Richardson static __rte_always_inline uint64_t
9899a2dd95SBruce Richardson __rte_rand_lfsr258_comp(uint64_t z, uint64_t a, uint64_t b, uint64_t c,
9999a2dd95SBruce Richardson 			uint64_t d)
10099a2dd95SBruce Richardson {
10199a2dd95SBruce Richardson 	return ((z & c) << d) ^ (((z << a) ^ z) >> b);
10299a2dd95SBruce Richardson }
10399a2dd95SBruce Richardson 
10499a2dd95SBruce Richardson /* Based on L’Ecuyer, P.: Tables of maximally equidistributed combined
10599a2dd95SBruce Richardson  * LFSR generators.
10699a2dd95SBruce Richardson  */
10799a2dd95SBruce Richardson 
10899a2dd95SBruce Richardson static __rte_always_inline uint64_t
10999a2dd95SBruce Richardson __rte_rand_lfsr258(struct rte_rand_state *state)
11099a2dd95SBruce Richardson {
11199a2dd95SBruce Richardson 	state->z1 = __rte_rand_lfsr258_comp(state->z1, 1UL, 53UL,
11299a2dd95SBruce Richardson 					    18446744073709551614UL, 10UL);
11399a2dd95SBruce Richardson 	state->z2 = __rte_rand_lfsr258_comp(state->z2, 24UL, 50UL,
11499a2dd95SBruce Richardson 					    18446744073709551104UL, 5UL);
11599a2dd95SBruce Richardson 	state->z3 = __rte_rand_lfsr258_comp(state->z3, 3UL, 23UL,
11699a2dd95SBruce Richardson 					    18446744073709547520UL, 29UL);
11799a2dd95SBruce Richardson 	state->z4 = __rte_rand_lfsr258_comp(state->z4, 5UL, 24UL,
11899a2dd95SBruce Richardson 					    18446744073709420544UL, 23UL);
11999a2dd95SBruce Richardson 	state->z5 = __rte_rand_lfsr258_comp(state->z5, 3UL, 33UL,
12099a2dd95SBruce Richardson 					    18446744073701163008UL, 8UL);
12199a2dd95SBruce Richardson 
12299a2dd95SBruce Richardson 	return state->z1 ^ state->z2 ^ state->z3 ^ state->z4 ^ state->z5;
12399a2dd95SBruce Richardson }
12499a2dd95SBruce Richardson 
12599a2dd95SBruce Richardson static __rte_always_inline
12699a2dd95SBruce Richardson struct rte_rand_state *__rte_rand_get_state(void)
12799a2dd95SBruce Richardson {
1287ea0ac41SMattias Rönnblom 	unsigned int idx;
12999a2dd95SBruce Richardson 
1307ea0ac41SMattias Rönnblom 	idx = rte_lcore_id();
13199a2dd95SBruce Richardson 
1327ea0ac41SMattias Rönnblom 	if (unlikely(idx == LCORE_ID_ANY))
133*29c39cd3SMattias Rönnblom 		return &unregistered_rand_state;
13499a2dd95SBruce Richardson 
135*29c39cd3SMattias Rönnblom 	return RTE_LCORE_VAR(rand_state);
13699a2dd95SBruce Richardson }
13799a2dd95SBruce Richardson 
13899a2dd95SBruce Richardson uint64_t
13999a2dd95SBruce Richardson rte_rand(void)
14099a2dd95SBruce Richardson {
14199a2dd95SBruce Richardson 	struct rte_rand_state *state;
14299a2dd95SBruce Richardson 
14399a2dd95SBruce Richardson 	state = __rte_rand_get_state();
14499a2dd95SBruce Richardson 
14599a2dd95SBruce Richardson 	return __rte_rand_lfsr258(state);
14699a2dd95SBruce Richardson }
14799a2dd95SBruce Richardson 
14899a2dd95SBruce Richardson uint64_t
14999a2dd95SBruce Richardson rte_rand_max(uint64_t upper_bound)
15099a2dd95SBruce Richardson {
15199a2dd95SBruce Richardson 	struct rte_rand_state *state;
15299a2dd95SBruce Richardson 	uint8_t ones;
15399a2dd95SBruce Richardson 	uint8_t leading_zeros;
15499a2dd95SBruce Richardson 	uint64_t mask = ~((uint64_t)0);
15599a2dd95SBruce Richardson 	uint64_t res;
15699a2dd95SBruce Richardson 
15799a2dd95SBruce Richardson 	if (unlikely(upper_bound < 2))
15899a2dd95SBruce Richardson 		return 0;
15999a2dd95SBruce Richardson 
16099a2dd95SBruce Richardson 	state = __rte_rand_get_state();
16199a2dd95SBruce Richardson 
1623d4e27fdSDavid Marchand 	ones = rte_popcount64(upper_bound);
16399a2dd95SBruce Richardson 
16499a2dd95SBruce Richardson 	/* Handle power-of-2 upper_bound as a special case, since it
16599a2dd95SBruce Richardson 	 * has no bias issues.
16699a2dd95SBruce Richardson 	 */
16799a2dd95SBruce Richardson 	if (unlikely(ones == 1))
16899a2dd95SBruce Richardson 		return __rte_rand_lfsr258(state) & (upper_bound - 1);
16999a2dd95SBruce Richardson 
17099a2dd95SBruce Richardson 	/* The approach to avoiding bias is to create a mask that
17199a2dd95SBruce Richardson 	 * stretches beyond the request value range, and up to the
17299a2dd95SBruce Richardson 	 * next power-of-2. In case the masked generated random value
17399a2dd95SBruce Richardson 	 * is equal to or greater than the upper bound, just discard
17499a2dd95SBruce Richardson 	 * the value and generate a new one.
17599a2dd95SBruce Richardson 	 */
17699a2dd95SBruce Richardson 
1773d4e27fdSDavid Marchand 	leading_zeros = rte_clz64(upper_bound);
17899a2dd95SBruce Richardson 	mask >>= leading_zeros;
17999a2dd95SBruce Richardson 
18099a2dd95SBruce Richardson 	do {
18199a2dd95SBruce Richardson 		res = __rte_rand_lfsr258(state) & mask;
18299a2dd95SBruce Richardson 	} while (unlikely(res >= upper_bound));
18399a2dd95SBruce Richardson 
18499a2dd95SBruce Richardson 	return res;
18599a2dd95SBruce Richardson }
18699a2dd95SBruce Richardson 
1870cd10724SStephen Hemminger double
1880cd10724SStephen Hemminger rte_drand(void)
1890cd10724SStephen Hemminger {
1900cd10724SStephen Hemminger 	static const uint64_t denom = (uint64_t)1 << 53;
1910cd10724SStephen Hemminger 	uint64_t rand64 = rte_rand();
1920cd10724SStephen Hemminger 
1930cd10724SStephen Hemminger 	/*
1940cd10724SStephen Hemminger 	 * The double mantissa only has 53 bits, so we uniformly mask off the
1950cd10724SStephen Hemminger 	 * high 11 bits and then floating-point divide by 2^53 to achieve a
1960cd10724SStephen Hemminger 	 * result in [0, 1).
1970cd10724SStephen Hemminger 	 *
1980cd10724SStephen Hemminger 	 * We are not allowed to emit 1.0, so denom must be one greater than
1990cd10724SStephen Hemminger 	 * the possible range of the preceding step.
2000cd10724SStephen Hemminger 	 */
2010cd10724SStephen Hemminger 
2020cd10724SStephen Hemminger 	rand64 &= denom - 1;
2030cd10724SStephen Hemminger 	return (double)rand64 / denom;
2040cd10724SStephen Hemminger }
2050cd10724SStephen Hemminger 
20699a2dd95SBruce Richardson static uint64_t
20799a2dd95SBruce Richardson __rte_random_initial_seed(void)
20899a2dd95SBruce Richardson {
20999a2dd95SBruce Richardson #ifdef RTE_LIBEAL_USE_GETENTROPY
21099a2dd95SBruce Richardson 	int ge_rc;
21199a2dd95SBruce Richardson 	uint64_t ge_seed;
21299a2dd95SBruce Richardson 
21399a2dd95SBruce Richardson 	ge_rc = getentropy(&ge_seed, sizeof(ge_seed));
21499a2dd95SBruce Richardson 
21599a2dd95SBruce Richardson 	if (ge_rc == 0)
21699a2dd95SBruce Richardson 		return ge_seed;
21799a2dd95SBruce Richardson #endif
21899a2dd95SBruce Richardson #ifdef __RDSEED__
21999a2dd95SBruce Richardson 	unsigned int rdseed_low;
22099a2dd95SBruce Richardson 	unsigned int rdseed_high;
22199a2dd95SBruce Richardson 
22299a2dd95SBruce Richardson 	/* first fallback: rdseed instruction, if available */
22399a2dd95SBruce Richardson 	if (_rdseed32_step(&rdseed_low) == 1 &&
22499a2dd95SBruce Richardson 	    _rdseed32_step(&rdseed_high) == 1)
22599a2dd95SBruce Richardson 		return (uint64_t)rdseed_low | ((uint64_t)rdseed_high << 32);
22699a2dd95SBruce Richardson #endif
22799a2dd95SBruce Richardson 	/* second fallback: seed using rdtsc */
22899a2dd95SBruce Richardson 	return rte_get_tsc_cycles();
22999a2dd95SBruce Richardson }
23099a2dd95SBruce Richardson 
23199a2dd95SBruce Richardson RTE_INIT(rte_rand_init)
23299a2dd95SBruce Richardson {
23399a2dd95SBruce Richardson 	uint64_t seed;
23499a2dd95SBruce Richardson 
235*29c39cd3SMattias Rönnblom 	RTE_LCORE_VAR_ALLOC(rand_state);
236*29c39cd3SMattias Rönnblom 
23799a2dd95SBruce Richardson 	seed = __rte_random_initial_seed();
23899a2dd95SBruce Richardson 
23999a2dd95SBruce Richardson 	rte_srand(seed);
24099a2dd95SBruce Richardson }
241