star-sp

Random number generators and distributions
git clone git://git.meso-star.fr/star-sp.git
Log | Files | Refs | README | LICENSE

commit 2fe6f86096157085c12ddd4460cf50293f95437c
parent 6a944967b1e5fa96e9728392e95d4049b8f78dae
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon,  6 Feb 2017 18:47:45 +0100

Add and test the ssp_rng_proxy_<read|write> functions

Diffstat:
Msrc/ssp.h | 10++++++++++
Msrc/ssp_rng.c | 2+-
Msrc/ssp_rng_proxy.c | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/test_ssp_rng_proxy.c | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/test_ssp_utils.h | 2+-
5 files changed, 242 insertions(+), 51 deletions(-)

diff --git a/src/ssp.h b/src/ssp.h @@ -232,6 +232,16 @@ ssp_rng_proxy_create_from_rng struct ssp_rng_proxy** proxy); SSP_API res_T +ssp_rng_proxy_read + (struct ssp_rng_proxy* proxy, + FILE* stream); + +SSP_API res_T +ssp_rng_proxy_write + (const struct ssp_rng_proxy* proxy, + FILE* stream); + +SSP_API res_T ssp_rng_proxy_ref_get (struct ssp_rng_proxy* proxy); diff --git a/src/ssp_rng.c b/src/ssp_rng.c @@ -378,7 +378,7 @@ rng_cxx_init<aes_T>(struct mem_allocator* allocator, void* data) { (void) allocator; if (!haveAESNI()) { - // AES-NI instructions not available on this hardware + /* AES-NI instructions not available on this hardware */ return RES_BAD_OP; } ASSERT(data); diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c @@ -33,6 +33,7 @@ #include <rsys/mutex.h> #include <rsys/ref_count.h> +#include <rsys/signal.h> #include <rsys/stretchy_array.h> #include <limits.h> @@ -45,6 +46,13 @@ struct rng_state_cache { long head, tail; /* Position onto the head/tail `states' stream */ }; +CLBK(rng_proxy_cb_T, ARG1(const struct ssp_rng_proxy*)); + +enum rng_proxy_sig { + RNG_PROXY_SIG_READ, + RNG_PROXY_SIGS_COUNT__ +}; + /* A proxy manages a list of N independent RNGs of the same type named buckets. * One ensure that each bucket have independent `infinite' random numbers by * partitioning a unique random sequence in N random pools, each containing @@ -69,6 +77,8 @@ struct ssp_rng_proxy { struct ssp_rng** pools; /* `type' RNGs wrapped by bucket RNGs */ struct rng_state_cache* states; /* Cache of `type' RNG states */ + signal_T signals[RNG_PROXY_SIGS_COUNT__]; + struct mutex* mutex; struct mem_allocator* allocator; ref_T ref; @@ -161,8 +171,20 @@ struct rng_bucket { struct ssp_rng_proxy* proxy; /* The RNG proxy */ size_t name; /* Unique bucket identifier in [0, #buckets) */ size_t count; /* Remaining unique random numbers in `pool' */ + rng_proxy_cb_T cb_on_proxy_read; }; +static void +rng_bucket_on_proxy_read(const struct ssp_rng_proxy* proxy, void* ctx) +{ + struct rng_bucket* rng = (struct rng_bucket*)ctx; + ASSERT(proxy && ctx && rng->proxy == proxy); + (void)proxy; + /* Reset bucket */ + rng->count = 0; + rng->pool = NULL; +} + static INLINE void rng_bucket_next_ran_pool(struct rng_bucket* rng) { @@ -221,6 +243,7 @@ rng_bucket_release(void* data) struct rng_bucket* rng = (struct rng_bucket*)data; ASSERT(data && rng->proxy); ATOMIC_SET(&rng->proxy->buckets[rng->name], 0); + CLBK_DISCONNECT(&rng->cb_on_proxy_read); SSP(rng_proxy_ref_put(rng->proxy)); } @@ -363,6 +386,7 @@ ssp_rng_proxy_create { struct mem_allocator* allocator = NULL; struct ssp_rng_proxy* proxy = NULL; + size_t i; res_T res = RES_OK; if(!type || !out_proxy || !nbuckets) { @@ -390,6 +414,10 @@ ssp_rng_proxy_create goto error; } + FOR_EACH(i, 0, RNG_PROXY_SIGS_COUNT__) { + SIG_INIT(proxy->signals + i); + } + res = rng_proxy_setup(proxy, nbuckets); if(res != RES_OK) goto error; @@ -415,6 +443,7 @@ ssp_rng_proxy_create_from_rng struct ssp_rng_proxy* proxy = NULL; struct ssp_rng_type type; FILE* stream = NULL; + size_t i; res_T res = RES_OK; if(!rng || !out_proxy || !nbuckets) { @@ -458,6 +487,10 @@ ssp_rng_proxy_create_from_rng goto error; } + FOR_EACH(i, 0, RNG_PROXY_SIGS_COUNT__) { + SIG_INIT(proxy->signals + i); + } + res = rng_proxy_setup(proxy, nbuckets); if(res != RES_OK) goto error; @@ -474,6 +507,34 @@ error: } res_T +ssp_rng_proxy_read(struct ssp_rng_proxy* proxy, FILE* stream) +{ + res_T res = RES_OK; + if(!proxy || !stream) return RES_BAD_ARG; + + mutex_lock(proxy->mutex); + res = ssp_rng_read(proxy->rng, stream); + mutex_unlock(proxy->mutex); + if(res != RES_OK) return res; + + SIG_BROADCAST(proxy->signals+RNG_PROXY_SIG_READ, rng_proxy_cb_T, ARG1(proxy)); + return RES_OK; +} + +res_T +ssp_rng_proxy_write(const struct ssp_rng_proxy* proxy, FILE* stream) +{ + res_T res = RES_OK; + + if(!proxy || !stream) return RES_BAD_ARG; + + mutex_lock(proxy->mutex); + res = ssp_rng_write(proxy->rng, stream); + mutex_unlock(proxy->mutex); + return res; +} + +res_T ssp_rng_proxy_ref_get(struct ssp_rng_proxy* proxy) { if(!proxy) return RES_BAD_ARG; @@ -497,6 +558,7 @@ ssp_rng_proxy_create_rng { struct ssp_rng* rng = NULL; struct ssp_rng_type type = RNG_BUCKET_NULL; + struct rng_bucket* bucket = NULL; res_T res = RES_OK; if(!proxy || ibucket >= sa_size(proxy->buckets) || !out_rng) { @@ -516,10 +578,17 @@ ssp_rng_proxy_create_rng res = ssp_rng_create(proxy->allocator, &type, &rng); if(res != RES_OK) goto error; - ((struct rng_bucket*)rng->state)->name = ibucket; - ((struct rng_bucket*)rng->state)->proxy = proxy; + bucket = (struct rng_bucket*)rng->state; + bucket->name = ibucket; + bucket->proxy = proxy; SSP(rng_proxy_ref_get(proxy)); + /* The bucket RNG listens the "write" signal of the proxy to reset its + * internal RNs counter on "write" invocation. */ + CLBK_INIT(&bucket->cb_on_proxy_read); + CLBK_SETUP(&bucket->cb_on_proxy_read, rng_bucket_on_proxy_read, bucket); + SIG_CONNECT_CLBK(proxy->signals+RNG_PROXY_SIG_READ, &bucket->cb_on_proxy_read); + exit: if(out_rng) *out_rng = rng; return res; diff --git a/src/test_ssp_rng_proxy.c b/src/test_ssp_rng_proxy.c @@ -31,20 +31,14 @@ #include "ssp.h" #include "test_ssp_utils.h" -int -main(int argc, char** argv) +#define NRANDS 2000000 +#define COUNT 4605307 + +static void +test_creation(void) { - struct ssp_rng_type type; struct ssp_rng_proxy* proxy; - struct ssp_rng_proxy* proxy1, *proxy2; - struct ssp_rng* rng[4]; - struct ssp_rng* rng1[4], * rng2[4]; - struct ssp_rng* rng3; - struct mem_allocator allocator; - size_t i = 0; - (void)argc, (void)argv; - - mem_init_proxy_allocator(&allocator, &mem_default_allocator); + struct ssp_rng_type type; CHECK(ssp_rng_proxy_create(NULL, NULL, 0, NULL), RES_BAD_ARG); CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 0, NULL), RES_BAD_ARG); @@ -69,7 +63,23 @@ main(int argc, char** argv) CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); - CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_mt19937_64, 4, &proxy), RES_OK); + CHECK(ssp_rng_proxy_create + (&mem_default_allocator, &ssp_rng_threefry, 1, &proxy), RES_OK); + CHECK(ssp_rng_proxy_get_type(proxy, &type), RES_OK); + CHECK(ssp_rng_type_eq(&type, &ssp_rng_threefry), 1); + CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); +} + +static void +test_rng_from_proxy(void) +{ + struct ssp_rng_type type; + struct ssp_rng_proxy* proxy; + struct ssp_rng* rng[4]; + uint64_t r[4]; + size_t i, j, k; + + CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 4, &proxy), RES_OK); CHECK(ssp_rng_proxy_create_rng(NULL, 0, NULL), RES_BAD_ARG); CHECK(ssp_rng_proxy_create_rng(proxy, 0, NULL), RES_BAD_ARG); @@ -79,9 +89,8 @@ main(int argc, char** argv) CHECK(ssp_rng_ref_put(rng[0]), RES_OK); CHECK(ssp_rng_proxy_create_rng(proxy, 4, &rng[0]), RES_BAD_ARG); - FOR_EACH(i, 0, 4) { - CHECK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]), RES_OK); - } + + FOR_EACH(i, 0, 4) CHECK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]), RES_OK); CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); CHECK(ssp_rng_get_type(rng[0], &type), RES_OK); @@ -91,35 +100,56 @@ main(int argc, char** argv) CHECK(ssp_rng_type_eq(&type, &type2), 1); } - FOR_EACH(i, 0, 2000000) { - uint64_t r[4]; - int j; + FOR_EACH(i, 0, NRANDS) { FOR_EACH(j, 0, 4) { - int k; r[j] = ssp_rng_get(rng[j]); - FOR_EACH(k, 0, j) - NCHECK(r[k], r[j]); + FOR_EACH(k, 0, j) NCHECK(r[k], r[j]); } } - CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_threefry, 1, &proxy1), RES_OK); - CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_threefry, 1, &proxy2), RES_OK); - CHECK(ssp_rng_proxy_create_rng(proxy1, 0, &rng1[0]), RES_OK); - CHECK(ssp_rng_proxy_create_rng(proxy2, 0, &rng2[0]), RES_OK); + FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng[i]), RES_OK); +} + +static void +test_multi_proxies(void) +{ + struct ssp_rng_proxy* proxy1; + struct ssp_rng_proxy* proxy2; + struct ssp_rng* rng1; + struct ssp_rng* rng2; + struct ssp_rng* rng3; + size_t i; + + CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_threefry, 1, &proxy1), RES_OK); + CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_threefry, 1, &proxy2), RES_OK); + + CHECK(ssp_rng_proxy_create_rng(proxy1, 0, &rng1), RES_OK); + CHECK(ssp_rng_proxy_create_rng(proxy2, 0, &rng2), RES_OK); ssp_rng_create(NULL, &ssp_rng_threefry, &rng3); + CHECK(ssp_rng_proxy_ref_put(proxy1), RES_OK); CHECK(ssp_rng_proxy_ref_put(proxy2), RES_OK); -#define COUNT 4605307 - ssp_rng_discard(rng1[0], COUNT); + + ssp_rng_discard(rng1, COUNT); ssp_rng_discard(rng3, COUNT+1); - FOR_EACH(i, 0, COUNT) ssp_rng_get(rng2[0]); - CHECK(ssp_rng_get(rng1[0]), ssp_rng_get(rng2[0])); - CHECK(ssp_rng_get(rng1[0]), ssp_rng_get(rng3)); + FOR_EACH(i, 0, COUNT) ssp_rng_get(rng2); - FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng[i]), RES_OK); - CHECK(ssp_rng_ref_put(rng1[0]), RES_OK); - CHECK(ssp_rng_ref_put(rng2[0]), RES_OK); + CHECK(ssp_rng_get(rng1), ssp_rng_get(rng2)); + CHECK(ssp_rng_get(rng1), ssp_rng_get(rng3)); + + CHECK(ssp_rng_ref_put(rng1), RES_OK); + CHECK(ssp_rng_ref_put(rng2), RES_OK); CHECK(ssp_rng_ref_put(rng3), RES_OK); +} + +static void +test_proxy_from_rng(void) +{ + struct ssp_rng_proxy* proxy; + struct ssp_rng* rng[4]; + struct ssp_rng_type type; + uint64_t r[4]; + size_t i, j, k; CHECK(ssp_rng_create(NULL, &ssp_rng_threefry, &rng[0]), RES_OK); CHECK(ssp_rng_discard(rng[0], COUNT), RES_OK); @@ -137,17 +167,13 @@ main(int argc, char** argv) CHECK(ssp_rng_proxy_create_rng(proxy, 1, &rng[2]), RES_BAD_ARG); CHECK(ssp_rng_get(rng[0]), ssp_rng_get(rng[1])); - CHECK(ssp_rng_get(rng[0]), ssp_rng_get(rng[1])); - CHECK(ssp_rng_get(rng[0]), ssp_rng_get(rng[1])); - CHECK(ssp_rng_get(rng[0]), ssp_rng_get(rng[1])); CHECK(ssp_rng_ref_put(rng[1]), RES_OK); CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); CHECK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 4, &proxy), RES_OK); CHECK(ssp_rng_ref_put(rng[0]), RES_OK); - FOR_EACH(i, 0, 4) - CHECK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]), RES_OK); + FOR_EACH(i, 0, 4) CHECK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]), RES_OK); CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); CHECK(ssp_rng_get_type(rng[0], &type), RES_OK); @@ -157,20 +183,106 @@ main(int argc, char** argv) CHECK(ssp_rng_type_eq(&type, &type2), 1); } - FOR_EACH(i, 0, 2000000) { - uint64_t r[4]; - int j; + FOR_EACH(i, 0, NRANDS) { FOR_EACH(j, 0, 4) { - int k; r[j] = ssp_rng_get(rng[j]); - FOR_EACH(k, 0, j) - NCHECK(r[k], r[j]); + FOR_EACH(k, 0, j) NCHECK(r[k], r[j]); } } FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng[i]), RES_OK); +} + +static void +test_read(void) +{ + struct ssp_rng_proxy* proxy; + struct ssp_rng* rng; + struct ssp_rng* rng1[4]; + FILE* stream; + uint64_t r[4]; + size_t i, j, k; + + CHECK(ssp_rng_create(NULL, &ssp_rng_mt19937_64, &rng), RES_OK); + CHECK(ssp_rng_discard(rng, COUNT), RES_OK); + + stream = tmpfile(); + NCHECK(stream, NULL); + CHECK(ssp_rng_write(rng, stream), RES_OK); + rewind(stream); + + CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 4, &proxy), RES_OK); + CHECK(ssp_rng_proxy_read(NULL, NULL), RES_BAD_ARG); + CHECK(ssp_rng_proxy_read(proxy, NULL), RES_BAD_ARG); + CHECK(ssp_rng_proxy_read(NULL, stream), RES_BAD_ARG); + CHECK(ssp_rng_proxy_read(proxy, stream), RES_OK); + + FOR_EACH(i, 0, 4) CHECK(ssp_rng_proxy_create_rng(proxy, i, &rng1[i]), RES_OK); + + r[0] = ssp_rng_get(rng); + CHECK(r[0], ssp_rng_get(rng1[0])); + NCHECK(r[0], ssp_rng_get(rng1[1])); + NCHECK(r[0], ssp_rng_get(rng1[2])); + NCHECK(r[0], ssp_rng_get(rng1[3])); + + FOR_EACH(i, 0, NRANDS) { + FOR_EACH(j, 0, 4) { + r[j] = ssp_rng_get(rng1[j]); + FOR_EACH(k, 0, j) NCHECK(r[k], r[j]); + } + } - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); + CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); + FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng1[i]), RES_OK); + fclose(stream); +} + +static void +test_write(void) +{ + struct ssp_rng_proxy* proxy; + struct ssp_rng* rng0; + struct ssp_rng* rng1; + FILE* stream; + uint64_t r; + + stream = tmpfile(); + NCHECK(stream, NULL); + + CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_ranlux48, 1, &proxy), RES_OK); + CHECK(ssp_rng_proxy_create_rng(proxy, 0, &rng0), RES_OK); + + CHECK(ssp_rng_proxy_write(NULL, NULL), RES_BAD_ARG); + CHECK(ssp_rng_proxy_write(proxy, NULL), RES_BAD_ARG); + CHECK(ssp_rng_proxy_write(NULL, stream), RES_BAD_ARG); + CHECK(ssp_rng_proxy_write(proxy, stream), RES_OK); + + CHECK(ssp_rng_create(NULL, &ssp_rng_ranlux48, &rng1), RES_OK); + r = ssp_rng_get(rng0); + CHECK(r, ssp_rng_get(rng1)); + + rewind(stream); + CHECK(ssp_rng_read(rng1, stream), RES_OK); + CHECK(r, ssp_rng_get(rng1)); + CHECK(ssp_rng_get(rng0), ssp_rng_get(rng1)); + + CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK); + CHECK(ssp_rng_ref_put(rng0), RES_OK); + CHECK(ssp_rng_ref_put(rng1), RES_OK); + + fclose(stream); +} + +int +main(int argc, char** argv) +{ + (void)argc, (void)argv; + test_creation(); + test_rng_from_proxy(); + test_multi_proxies(); + test_proxy_from_rng(); + test_read(); + test_write(); CHECK(mem_allocated_size(), 0); return 0; } diff --git a/src/test_ssp_utils.h b/src/test_ssp_utils.h @@ -32,7 +32,7 @@ #include <rsys/mem_allocator.h> #include <stdio.h> -static void +static INLINE void check_memory_allocator(struct mem_allocator* allocator) { if(MEM_ALLOCATED_SIZE(allocator)) {