[FFmpeg-devel] [PATCH] lavu/lfg: add 64 bit random number generator
Ganesh Ajjanagadde
gajjanag at gmail.com
Mon Mar 14 00:12:50 CET 2016
This is based on the relatively well known xorshift128+ of Sebastiano
Vigna (https://en.wikipedia.org/wiki/Xorshift) that performs very well on the
BigCrush suite, is very efficient, and is thus used by a number of
clients: http://xorshift.di.unimi.it/ (see Introduction).
Moreover, the implementation is in the public domain:
http://xorshift.di.unimi.it/xorshift128plus.c.
Concretely, it is nearly as fast as av_lfg_get (which only returns 32 bits),
and has a much smaller cache (128 bits). Thus, the timings should also
be more stable.
This is needed because av_lfg_get<<32 | av_lfg_get is far slower, and
likely less random as measured by BigCrush - most LFG's perform
quite poorly on the BigCrush suite:
http://www6.tw.freebsd.org/distfiles/testu01.pdf.
In particular, FFmpeg's seems to be Ran055 in the paper, see pg31.
Sample benchmark (Haswell, GCC + -march=native):
23200 decicycles in 624 calls of av_lfg_get, 1 runs, 0 skips
23040 decicycles in 624 calls of av_lfg_get, 2 runs, 0 skips
22810 decicycles in 624 calls of av_lfg_get, 4 runs, 0 skips
[...]
19884 decicycles in 624 calls of av_lfg_get, 65532 runs, 4 skips
19880 decicycles in 624 calls of av_lfg_get, 131067 runs, 5 skips
19884 decicycles in 624 calls of av_lfg_get, 262136 runs, 8 skips
19877 decicycles in 624 calls of av_lfg_get, 524276 runs, 12 skips
25380 decicycles in 624 calls of av_rand64_get, 1 runs, 0 skips
28560 decicycles in 624 calls of av_rand64_get, 2 runs, 0 skips
30112 decicycles in 624 calls of av_rand64_get, 4 runs, 0 skips
[...]
22627 decicycles in 624 calls of av_rand64_get, 65536 runs, 0 skips
22625 decicycles in 624 calls of av_rand64_get, 131072 runs, 0 skips
22625 decicycles in 624 calls of av_rand64_get, 262143 runs, 1 skips
22624 decicycles in 624 calls of av_rand64_get, 524286 runs, 2 skips
Signed-off-by: Ganesh Ajjanagadde <gajjanag at gmail.com>
---
libavutil/lfg.c | 33 ++++++++++++++++++++++++++++++++-
libavutil/lfg.h | 26 ++++++++++++++++++++++++++
2 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/libavutil/lfg.c b/libavutil/lfg.c
index 5ffd76f..e8e4adf 100644
--- a/libavutil/lfg.c
+++ b/libavutil/lfg.c
@@ -1,6 +1,11 @@
/*
* Lagged Fibonacci PRNG
* Copyright (c) 2008 Michael Niedermayer
+ * 64 bit random number generator written by
+ * Written in 2015 by Sebastiano Vigna (vigna at acm.org)
+ * under public domain:
+ * https://creativecommons.org/publicdomain/zero/1.0/
+ *
*
* This file is part of FFmpeg.
*
@@ -44,6 +49,19 @@ av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
c->index = 0;
}
+static inline uint64_t next64(uint64_t x) {
+ uint64_t z = (x += UINT64_C(0x9E3779B97F4A7C15));
+ z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9);
+ z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB);
+ return z ^ (z >> 31);
+}
+
+av_cold void av_rand64_init(AVRAND64 *rng, uint64_t seed)
+{
+ rng->state[0] = seed;
+ rng->state[1] = next64(seed);
+}
+
void av_bmg_get(AVLFG *lfg, double out[2])
{
double x1, x2, w;
@@ -66,11 +84,14 @@ void av_bmg_get(AVLFG *lfg, double out[2])
int main(void)
{
int x = 0;
+ uint64_t y = 0;
int i, j;
AVLFG state;
+ AVRAND64 state64;
av_lfg_init(&state, 0xdeadbeef);
- for (j = 0; j < 10000; j++) {
+ av_rand64_init(&state64, UINT64_C(0xdeadbeefdeadbeef));
+ for (j = 0; j < 1000000; j++) {
START_TIMER
for (i = 0; i < 624; i++) {
//av_log(NULL, AV_LOG_ERROR, "%X\n", av_lfg_get(&state));
@@ -80,6 +101,16 @@ int main(void)
}
av_log(NULL, AV_LOG_ERROR, "final value:%X\n", x);
+ for (j = 0; j < 1000000; j++) {
+ START_TIMER
+ for (i = 0; i < 624; i++) {
+ //av_log(NULL, AV_LOG_ERROR, "%X\n", av_lfg_get(&state));
+ y += av_rand64_get(&state64);
+ //y += ((uint64_t)av_lfg_get(&state) << 32) | av_lfg_get(&state);
+ }
+ STOP_TIMER("624 calls of av_rand64_get");
+ }
+
/* BMG usage example */
{
double mean = 1000;
diff --git a/libavutil/lfg.h b/libavutil/lfg.h
index ec90562..1f0f38d 100644
--- a/libavutil/lfg.h
+++ b/libavutil/lfg.h
@@ -1,6 +1,10 @@
/*
* Lagged Fibonacci PRNG
* Copyright (c) 2008 Michael Niedermayer
+ * 64 bit random number generator written by
+ * Written in 2015 by Sebastiano Vigna (vigna at acm.org)
+ * under public domain:
+ * https://creativecommons.org/publicdomain/zero/1.0/
*
* This file is part of FFmpeg.
*
@@ -21,15 +25,28 @@
#ifndef AVUTIL_LFG_H
#define AVUTIL_LFG_H
+#include <stdint.h>
typedef struct AVLFG {
unsigned int state[64];
int index;
} AVLFG;
+typedef struct AVRAND64 {
+ uint64_t state[2];
+} AVRAND64;
+
void av_lfg_init(AVLFG *c, unsigned int seed);
/**
+ * Initialize the 64 bit random number generator.
+ *
+ * @param rng AVRAND64 structure that is initialized
+ * @param seed 64 bit seed
+ */
+void av_rand64_init(AVRAND64 *rng, uint64_t seed);
+
+/**
* Get the next random unsigned 32-bit number using an ALFG.
*
* Please also consider a simple LCG like state= state*1664525+1013904223,
@@ -40,6 +57,15 @@ static inline unsigned int av_lfg_get(AVLFG *c){
return c->state[c->index++ & 63];
}
+static inline uint64_t av_rand64_get(AVRAND64 *rng){
+ uint64_t x = rng->state[0];
+ uint64_t const y = rng->state[1];
+ rng->state[0] = y;
+ x ^= x << 23; // a
+ rng->state[1] = x ^ y ^ (x >> 17) ^ (y >> 26); // b, c
+ return rng->state[1] + y;
+}
+
/**
* Get the next random unsigned 32-bit number using a MLFG.
*
--
2.7.3
More information about the ffmpeg-devel
mailing list