commit 2a2c2572b07857b108d983feab45c27ab2470f41
parent 8b1aa179a7ed924669914eebdbb7a238500b0645
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Tue, 25 Aug 2015 14:35:46 +0200
Add the new discard() API call
And use it when building state of proxy generators
Diffstat:
5 files changed, 90 insertions(+), 2 deletions(-)
diff --git a/src/ssp.h b/src/ssp.h
@@ -68,6 +68,7 @@ struct ssp_rng_type {
res_T (*set)(void* state, const uint64_t seed);
uint64_t (*get)(void* state);
+ res_T(*discard)(void* state, uint64_t n);
uint64_t (*uniform_uint64)(void* state, const uint64_t min, const uint64_t max);
double (*uniform_double)(void* state, const double min, const double max);
double (*canonical)(void* state);
@@ -130,6 +131,12 @@ SSP_API uint64_t
ssp_rng_get
(struct ssp_rng* rng);
+/* Advances the internal state by n times.
+ Equivalent to calling ssp_rng_get() n times and discarding the result */
+SSP_API res_T
+ssp_rng_discard
+ (struct ssp_rng* rng, uint64_t n);
+
/* Uniform random integer distribution in [lower, upper) */
SSP_API uint64_t
ssp_rng_uniform_uint64
diff --git a/src/ssp_rng.c b/src/ssp_rng.c
@@ -178,12 +178,22 @@ rng_kiss_entropy(const void* data)
return 0.;
}
+static res_T
+rng_kiss_discard(void* data, uint64_t n)
+{
+ while (n-- > 0) {
+ rng_kiss_get(data);
+ }
+ return RES_OK;
+}
+
/* Exported type */
const struct ssp_rng_type ssp_rng_kiss = {
rng_kiss_init,
rng_kiss_release,
rng_kiss_set,
rng_kiss_get,
+ rng_kiss_discard,
rng_kiss_uniform_uint64,
rng_kiss_uniform_double,
rng_kiss_canonical,
@@ -329,6 +339,24 @@ rng_cxx_entropy(const void* data)
return 0;
}
+template<typename RNG>
+res_T
+rng_cxx_discard(void* data, uint64_t n)
+{
+ RNG* rng = (RNG*) data;
+ ASSERT(rng);
+ rng->discard(n);
+ return RES_OK;
+}
+
+template<>
+res_T
+rng_cxx_discard<RAN_NAMESPACE::random_device>(void* data, uint64_t n)
+{
+ (void) data; (void) n;
+ return RES_BAD_OP;
+}
+
template<>
double
rng_cxx_entropy<RAN_NAMESPACE::random_device>(const void* data)
@@ -345,6 +373,7 @@ const struct ssp_rng_type ssp_rng_mt19937_64 = {
rng_cxx_release<RAN_NAMESPACE::mt19937_64>,
rng_cxx_set<RAN_NAMESPACE::mt19937_64>,
rng_cxx_get<RAN_NAMESPACE::mt19937_64>,
+ rng_cxx_discard<RAN_NAMESPACE::mt19937_64>,
rng_cxx_uniform_uint64<RAN_NAMESPACE::mt19937_64>,
rng_cxx_uniform_double<RAN_NAMESPACE::mt19937_64>,
rng_cxx_canonical<RAN_NAMESPACE::mt19937_64>,
@@ -362,6 +391,7 @@ const struct ssp_rng_type ssp_rng_ranlux48 = {
rng_cxx_release<RAN_NAMESPACE::ranlux48>,
rng_cxx_set<RAN_NAMESPACE::ranlux48>,
rng_cxx_get<RAN_NAMESPACE::ranlux48>,
+ rng_cxx_discard<RAN_NAMESPACE::ranlux48>,
rng_cxx_uniform_uint64<RAN_NAMESPACE::ranlux48>,
rng_cxx_uniform_double<RAN_NAMESPACE::ranlux48>,
rng_cxx_canonical<RAN_NAMESPACE::ranlux48>,
@@ -379,6 +409,7 @@ const struct ssp_rng_type ssp_rng_random_device = {
rng_cxx_release<RAN_NAMESPACE::random_device>,
rng_cxx_set<RAN_NAMESPACE::random_device>,
rng_cxx_get<RAN_NAMESPACE::random_device>,
+ rng_cxx_discard<RAN_NAMESPACE::random_device>,
rng_cxx_uniform_uint64<RAN_NAMESPACE::random_device>,
rng_cxx_uniform_double<RAN_NAMESPACE::random_device>,
rng_cxx_canonical<RAN_NAMESPACE::random_device>,
@@ -419,6 +450,7 @@ const struct ssp_rng_type ssp_rng_threefry = {
rng_cxx_release<threefry_T>,
rng_cxx_set<threefry_T>,
rng_cxx_get<threefry_T>,
+ rng_cxx_discard<threefry_T>,
rng_cxx_uniform_uint64<threefry_T>,
rng_cxx_uniform_double<threefry_T>,
rng_cxx_canonical<threefry_T>,
@@ -437,6 +469,7 @@ const struct ssp_rng_type ssp_rng_aes = {
rng_cxx_release<aes_T>,
rng_cxx_set<aes_T>,
rng_cxx_get<aes_T>,
+ rng_cxx_discard<aes_T>,
rng_cxx_uniform_uint64<aes_T>,
rng_cxx_uniform_double<aes_T>,
rng_cxx_canonical<aes_T>,
@@ -622,6 +655,13 @@ ssp_rng_entropy(const struct ssp_rng* rng)
return rng->type.entropy(rng->state);
}
+res_T
+ssp_rng_discard(struct ssp_rng* rng, uint64_t n)
+{
+ if (!rng) FATAL("The Random Number Generator is NULL\n");
+ return rng->type.discard(rng->state, n);
+}
+
/*******************************************************************************
* Exported distributions
******************************************************************************/
diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c
@@ -262,11 +262,25 @@ rng_bucket_entropy(const void* data)
return 0;
}
+static res_T
+rng_bucket_discard(void* data, uint64_t n)
+{
+ struct rng_bucket* rng = (struct rng_bucket*)data;
+ ASSERT(data);
+ while (rng->count <= n) {
+ n -= rng->count;
+ rng_bucket_next_ran_pool(rng);
+ }
+ rng->count -= n;
+ return ssp_rng_discard(rng->pool, n);
+}
+
static const struct ssp_rng_type RNG_BUCKET_NULL = {
rng_bucket_init,
rng_bucket_release,
rng_bucket_set,
rng_bucket_get,
+ rng_bucket_discard,
rng_bucket_uniform_uint64,
rng_bucket_uniform_double,
rng_bucket_canonical,
@@ -295,10 +309,9 @@ rng_proxy_next_ran_pool
size_t ibucket;
/* Register a new state for *all* buckets */
FOR_EACH(ibucket, 0, sa_size(proxy->states)) {
- size_t irand;
res = rng_state_cache_write(proxy->states + ibucket, proxy->rng);
if(res != RES_OK) FATAL("RNG proxy: cannot write to state cache\n");
- FOR_EACH(irand, 0, BUCKET_SIZE) ssp_rng_get(proxy->rng); /* Discard */
+ ssp_rng_discard(proxy->rng, BUCKET_SIZE);
}
}
diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c
@@ -42,6 +42,7 @@ test_rng(const struct ssp_rng_type* type)
{
FILE* stream;
struct ssp_rng* rng;
+ struct ssp_rng* rng1, * rng2;
struct mem_allocator allocator;
struct time t0, t1;
uint64_t datai0[NRAND];
@@ -53,6 +54,7 @@ test_rng(const struct ssp_rng_type* type)
const char can_set = (type != &ssp_rng_random_device);
const char can_rw = (type != &ssp_rng_random_device);
const char can_have_entropy = (type == &ssp_rng_random_device);
+ const char can_discard = (type != &ssp_rng_random_device);
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -82,6 +84,14 @@ test_rng(const struct ssp_rng_type* type)
CHECK(ssp_rng_set(NULL, 0), RES_BAD_ARG);
CHECK(ssp_rng_set(rng, 0), can_set ? RES_OK : RES_BAD_OP);
+ ssp_rng_create(NULL, type, &rng1);
+ ssp_rng_create(NULL, type, &rng2);
+ CHECK(ssp_rng_discard(rng1, 10), can_discard ? RES_OK : RES_BAD_OP);
+ if (type != &ssp_rng_random_device) {
+ for (i = 0; i < 10; i++) ssp_rng_get(rng2);
+ CHECK(ssp_rng_get(rng1), ssp_rng_get(rng2));
+ }
+
FOR_EACH(i, 0, NRAND) {
datai0[i] = ssp_rng_get(rng);
CHECK(datai0[i] >= ssp_rng_min(rng), 1);
@@ -171,6 +181,8 @@ test_rng(const struct ssp_rng_type* type)
fclose(stream);
CHECK(ssp_rng_ref_put(rng), RES_OK);
+ ssp_rng_ref_put(rng1);
+ ssp_rng_ref_put(rng2);
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
}
diff --git a/src/test_ssp_rng_proxy.c b/src/test_ssp_rng_proxy.c
@@ -35,7 +35,9 @@ int
main(int argc, char** argv)
{
struct ssp_rng_proxy* proxy;
+ struct ssp_rng_proxy* proxy1, *proxy2;
struct ssp_rng* rng[4];
+ struct ssp_rng* rng1[4], * rng2[4];
struct mem_allocator allocator;
size_t i = 0;
(void)argc, (void)argv;
@@ -84,7 +86,21 @@ main(int argc, char** argv)
}
}
+ CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_threefry, 4, &proxy1), RES_OK);
+ CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_threefry, 4, &proxy2), RES_OK);
+ FOR_EACH(i, 0, 4) {
+ CHECK(ssp_rng_proxy_create_rng(proxy1, i, &rng1[i]), RES_OK);
+ CHECK(ssp_rng_proxy_create_rng(proxy2, i, &rng2[i]), RES_OK);
+ }
+ CHECK(ssp_rng_proxy_ref_put(proxy1), RES_OK);
+ CHECK(ssp_rng_proxy_ref_put(proxy2), RES_OK);
+ ssp_rng_discard(rng1[0], 1000307);
+ for (i = 0; i < 1000307; i++) ssp_rng_get(rng2[0]);
+ CHECK(ssp_rng_get(rng1[0]), ssp_rng_get(rng2[0]));
+
FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng[i]), RES_OK);
+ FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng1[i]), RES_OK);
+ FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng2[i]), RES_OK);
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);