mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-01 22:48:25 +00:00
REORG: tools: promote the debug PRNG to more general use as a statistical one
We frequently need to access a simple and fast PRNG for statistical purposes. The debug_prng() function did exactly this using a xorshift generator but its use was limited to debug only. Let's move this to tools.h and tools.c to make it accessible everywhere. Since it needs to be fast, its state is thread-local. An initialization function starts a different initial value for each thread for better distribution.
This commit is contained in:
parent
b1adf03df9
commit
06e69b556c
@ -1055,4 +1055,20 @@ static inline int32_t ha_random()
|
||||
return ha_random32() >> 1;
|
||||
}
|
||||
|
||||
extern THREAD_LOCAL unsigned int statistical_prng_state;
|
||||
|
||||
/* Xorshift RNGs from http://www.jstatsoft.org/v08/i14/paper.
|
||||
* This has a (2^32)-1 period, only zero is never returned.
|
||||
*/
|
||||
static inline unsigned int statistical_prng()
|
||||
{
|
||||
unsigned int x = statistical_prng_state;
|
||||
|
||||
x ^= x << 13;
|
||||
x ^= x >> 17;
|
||||
x ^= x << 5;
|
||||
return statistical_prng_state = x;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _HAPROXY_TOOLS_H */
|
||||
|
14
src/debug.c
14
src/debug.c
@ -42,16 +42,6 @@
|
||||
volatile unsigned long threads_to_dump = 0;
|
||||
unsigned int debug_commands_issued = 0;
|
||||
|
||||
/* Xorshift RNGs from http://www.jstatsoft.org/v08/i14/paper */
|
||||
static THREAD_LOCAL unsigned int y = 2463534242U;
|
||||
static unsigned int debug_prng()
|
||||
{
|
||||
y ^= y << 13;
|
||||
y ^= y >> 17;
|
||||
y ^= y << 5;
|
||||
return y;
|
||||
}
|
||||
|
||||
/* dumps a backtrace of the current thread that is appended to buffer <buf>.
|
||||
* Lines are prefixed with the string <prefix> which may be empty (used for
|
||||
* indenting). It is recommended to use this at a function's tail so that
|
||||
@ -748,7 +738,7 @@ static struct task *debug_task_handler(struct task *t, void *ctx, unsigned short
|
||||
t->expire = tick_add(now_ms, inter);
|
||||
|
||||
/* half of the calls will wake up another entry */
|
||||
rnd = debug_prng();
|
||||
rnd = statistical_prng();
|
||||
if (rnd & 1) {
|
||||
rnd >>= 1;
|
||||
rnd %= tctx[0];
|
||||
@ -770,7 +760,7 @@ static struct task *debug_tasklet_handler(struct task *t, void *ctx, unsigned sh
|
||||
|
||||
/* wake up two random entries */
|
||||
for (i = 0; i < 2; i++) {
|
||||
rnd = debug_prng() % tctx[0];
|
||||
rnd = statistical_prng() % tctx[0];
|
||||
rnd = tctx[rnd + 2];
|
||||
|
||||
if (rnd & 1)
|
||||
|
16
src/tools.c
16
src/tools.c
@ -78,6 +78,12 @@ THREAD_LOCAL int itoa_idx = 0; /* index of next itoa_str to use */
|
||||
THREAD_LOCAL char quoted_str[NB_QSTR][QSTR_SIZE + 1];
|
||||
THREAD_LOCAL int quoted_idx = 0;
|
||||
|
||||
/* thread-local PRNG state. It's modified to start from a different sequence
|
||||
* on all threads upon startup. It must not be used or anything beyond getting
|
||||
* statistical values as it's 100% predictable.
|
||||
*/
|
||||
THREAD_LOCAL unsigned int statistical_prng_state = 2463534242U;
|
||||
|
||||
/*
|
||||
* unsigned long long ASCII representation
|
||||
*
|
||||
@ -5363,6 +5369,16 @@ size_t sanitize_for_printing(char *line, size_t pos, size_t width)
|
||||
return pos - shift;
|
||||
}
|
||||
|
||||
static int init_tools_per_thread()
|
||||
{
|
||||
/* Let's make each thread start from a different position */
|
||||
statistical_prng_state += tid * MAX_THREADS;
|
||||
if (!statistical_prng_state)
|
||||
statistical_prng_state++;
|
||||
return 1;
|
||||
}
|
||||
REGISTER_PER_THREAD_INIT(init_tools_per_thread);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
|
Loading…
Reference in New Issue
Block a user