test_ssp_rng_proxy.c (29251B)
1 /* Copyright (C) 2015-2025 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "ssp.h" 17 #include "test_ssp_utils.h" 18 19 #define NRANDS 2000000 20 #define COUNT 4605307 21 22 static void 23 test_creation(void) 24 { 25 struct ssp_rng_proxy* proxy; 26 enum ssp_rng_type type; 27 28 CHK(ssp_rng_proxy_create(NULL, -1, 0, NULL) == RES_BAD_ARG); 29 CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 0, NULL) == RES_BAD_ARG); 30 CHK(ssp_rng_proxy_create(NULL, -1, 4, NULL) == RES_BAD_ARG); 31 CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, NULL) == RES_BAD_ARG); 32 CHK(ssp_rng_proxy_create(NULL, -1, 0, &proxy) == RES_BAD_ARG); 33 CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 0, &proxy) == RES_BAD_ARG); 34 CHK(ssp_rng_proxy_create(NULL, -1, 4, &proxy) == RES_BAD_ARG); 35 CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, &proxy) == RES_OK); 36 37 CHK(ssp_rng_proxy_get_type(NULL, NULL) == RES_BAD_ARG); 38 CHK(ssp_rng_proxy_get_type(proxy, NULL) == RES_BAD_ARG); 39 CHK(ssp_rng_proxy_get_type(NULL, &type) == RES_BAD_ARG); 40 CHK(ssp_rng_proxy_get_type(proxy, &type) == RES_OK); 41 42 CHK(type != SSP_RNG_KISS); 43 CHK(type == SSP_RNG_MT19937_64); 44 45 CHK(ssp_rng_proxy_ref_get(NULL) == RES_BAD_ARG); 46 CHK(ssp_rng_proxy_ref_get(proxy) == RES_OK); 47 CHK(ssp_rng_proxy_ref_put(NULL) == RES_BAD_ARG); 48 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 49 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 50 51 CHK(ssp_rng_proxy_create 52 (&mem_default_allocator, SSP_RNG_THREEFRY, 1, &proxy) == RES_OK); 53 CHK(ssp_rng_proxy_get_type(proxy, &type) == RES_OK); 54 CHK(type == SSP_RNG_THREEFRY); 55 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 56 57 CHK(ssp_rng_proxy_create(NULL, SSP_RNG_KISS, 4, &proxy) == RES_OK); 58 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 59 } 60 61 static void 62 test_creation2(void) 63 { 64 struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL; 65 struct ssp_rng_proxy* proxy; 66 67 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); 68 69 args.type = SSP_RNG_MT19937_64; 70 args.sequence_offset = 0; 71 args.sequence_size = 32; 72 args.sequence_pitch = 32; 73 args.nbuckets = 1; 74 CHK(ssp_rng_proxy_create2(NULL, &args, NULL) == RES_BAD_ARG); 75 76 args.type = SSP_RNG_TYPE_NULL; 77 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); 78 args.type = SSP_RNG_MT19937_64; 79 args.sequence_size= 0; 80 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); 81 args.sequence_size = 32; 82 args.sequence_pitch = 0; 83 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); 84 args.sequence_pitch = 31; 85 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); 86 args.sequence_pitch = 32; 87 args.nbuckets = 0; 88 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); 89 args.nbuckets = 33; 90 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); 91 args.nbuckets = 1; 92 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 93 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 94 95 args.nbuckets = 4; 96 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 97 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 98 99 args.nbuckets = 5; 100 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 101 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 102 103 args.nbuckets = 32; 104 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 105 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 106 107 args.sequence_offset = 1024; 108 args.nbuckets = 4; 109 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 110 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 111 112 args.type = SSP_RNG_KISS; 113 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 114 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 115 } 116 117 static void 118 test_rng_from_proxy(void) 119 { 120 enum ssp_rng_type type; 121 struct ssp_rng_proxy* proxy; 122 struct ssp_rng* rng[4]; 123 uint64_t r[4]; 124 size_t i, j, k; 125 126 CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, &proxy) == RES_OK); 127 128 CHK(ssp_rng_proxy_create_rng(NULL, 0, NULL) == RES_BAD_ARG); 129 CHK(ssp_rng_proxy_create_rng(proxy, 0, NULL) == RES_BAD_ARG); 130 CHK(ssp_rng_proxy_create_rng(NULL, 0, &rng[0]) == RES_BAD_ARG); 131 CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng[0]) == RES_OK); 132 CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng[1]) == RES_BAD_ARG); 133 CHK(ssp_rng_ref_put(rng[0]) == RES_OK); 134 135 CHK(ssp_rng_proxy_create_rng(proxy, 4, &rng[0]) == RES_BAD_ARG); 136 137 FOR_EACH(i, 0, 4) CHK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]) == RES_OK); 138 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 139 140 CHK(ssp_rng_get_type(rng[0], &type) == RES_OK); 141 FOR_EACH(i, 1, 4) { 142 enum ssp_rng_type type2; 143 CHK(ssp_rng_get_type(rng[i], &type2) == RES_OK); 144 CHK(type == type2); 145 } 146 147 FOR_EACH(i, 0, NRANDS) { 148 FOR_EACH(j, 0, 4) { 149 r[j] = ssp_rng_get(rng[j]); 150 FOR_EACH(k, 0, j) CHK(r[k] != r[j]); 151 } 152 } 153 154 FOR_EACH(i, 0, 4) CHK(ssp_rng_ref_put(rng[i]) == RES_OK); 155 } 156 157 static void 158 test_rng_from_proxy2(void) 159 { 160 struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL; 161 struct ssp_rng_proxy* proxy[2]; 162 struct ssp_rng* rng[4]; 163 const size_t block_sz = 99; 164 const size_t nrands = 1000; 165 uint64_t* r[4]; 166 size_t i, j; 167 168 CHK((r[0] = mem_alloc(sizeof(uint64_t)*nrands)) != NULL); 169 CHK((r[1] = mem_alloc(sizeof(uint64_t)*nrands)) != NULL); 170 CHK((r[2] = mem_alloc(sizeof(uint64_t)*nrands)) != NULL); 171 CHK((r[3] = mem_alloc(sizeof(uint64_t)*nrands)) != NULL); 172 173 args.type = SSP_RNG_MT19937_64; 174 args.sequence_size = block_sz; 175 args.sequence_pitch = block_sz; 176 args.nbuckets = 4; 177 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy[0]) == RES_OK); 178 179 CHK(ssp_rng_proxy_create_rng(proxy[0], 0, &rng[0]) == RES_OK); 180 CHK(ssp_rng_proxy_create_rng(proxy[0], 1, &rng[1]) == RES_OK); 181 CHK(ssp_rng_proxy_create_rng(proxy[0], 2, &rng[2]) == RES_OK); 182 CHK(ssp_rng_proxy_create_rng(proxy[0], 3, &rng[3]) == RES_OK); 183 184 /* Generate random numbers */ 185 FOR_EACH(i, 0, nrands) { 186 r[0][i] = ssp_rng_get(rng[0]); 187 r[1][i] = ssp_rng_get(rng[1]); 188 r[2][i] = ssp_rng_get(rng[2]); 189 r[3][i] = ssp_rng_get(rng[3]); 190 } 191 192 /* Check that each RNG generate a unique sequence of random numbers */ 193 FOR_EACH(i, 0, nrands) { 194 FOR_EACH(j, 0, nrands) { 195 CHK(r[0][i] != r[1][j]); 196 CHK(r[0][i] != r[2][j]); 197 CHK(r[0][i] != r[3][j]); 198 CHK(r[1][i] != r[2][j]); 199 CHK(r[1][i] != r[3][j]); 200 CHK(r[2][i] != r[3][j]); 201 } 202 } 203 204 CHK(ssp_rng_proxy_ref_put(proxy[0]) == RES_OK); 205 CHK(ssp_rng_ref_put(rng[0]) == RES_OK); 206 CHK(ssp_rng_ref_put(rng[1]) == RES_OK); 207 CHK(ssp_rng_ref_put(rng[2]) == RES_OK); 208 CHK(ssp_rng_ref_put(rng[3]) == RES_OK); 209 210 args.type = SSP_RNG_MT19937_64; 211 args.sequence_size = block_sz; 212 args.sequence_pitch = 2*block_sz; 213 args.nbuckets = 2; 214 215 args.sequence_offset = 0; 216 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy[0]) == RES_OK); 217 args.sequence_offset = block_sz; 218 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy[1]) == RES_OK); 219 220 CHK(ssp_rng_proxy_create_rng(proxy[0], 0, &rng[0]) == RES_OK); 221 CHK(ssp_rng_proxy_create_rng(proxy[0], 1, &rng[1]) == RES_OK); 222 CHK(ssp_rng_proxy_create_rng(proxy[1], 0, &rng[2]) == RES_OK); 223 CHK(ssp_rng_proxy_create_rng(proxy[1], 1, &rng[3]) == RES_OK); 224 225 /* Generate random numbers */ 226 FOR_EACH(i, 0, nrands) { 227 r[0][i] = ssp_rng_get(rng[0]); 228 r[1][i] = ssp_rng_get(rng[1]); 229 r[2][i] = ssp_rng_get(rng[2]); 230 r[3][i] = ssp_rng_get(rng[3]); 231 } 232 233 /* Check that each RNG generate a unique sequence of random numbers */ 234 FOR_EACH(i, 0, nrands) { 235 FOR_EACH(j, 0, nrands) { 236 CHK(r[0][i] != r[1][j]); 237 CHK(r[0][i] != r[2][j]); 238 CHK(r[0][i] != r[3][j]); 239 CHK(r[1][i] != r[2][j]); 240 CHK(r[1][i] != r[3][j]); 241 CHK(r[2][i] != r[3][j]); 242 } 243 } 244 245 CHK(ssp_rng_proxy_ref_put(proxy[0]) == RES_OK); 246 CHK(ssp_rng_proxy_ref_put(proxy[1]) == RES_OK); 247 CHK(ssp_rng_ref_put(rng[0]) == RES_OK); 248 CHK(ssp_rng_ref_put(rng[1]) == RES_OK); 249 CHK(ssp_rng_ref_put(rng[2]) == RES_OK); 250 CHK(ssp_rng_ref_put(rng[3]) == RES_OK); 251 252 mem_rm(r[0]); 253 mem_rm(r[1]); 254 mem_rm(r[2]); 255 mem_rm(r[3]); 256 } 257 258 static void 259 test_multi_proxies(void) 260 { 261 struct ssp_rng_proxy* proxy1; 262 struct ssp_rng_proxy* proxy2; 263 struct ssp_rng* rng1; 264 struct ssp_rng* rng2; 265 struct ssp_rng* rng3; 266 size_t i; 267 268 CHK(ssp_rng_proxy_create(NULL, SSP_RNG_THREEFRY, 1, &proxy1) == RES_OK); 269 CHK(ssp_rng_proxy_create(NULL, SSP_RNG_THREEFRY, 1, &proxy2) == RES_OK); 270 271 CHK(ssp_rng_proxy_create_rng(proxy1, 0, &rng1) == RES_OK); 272 CHK(ssp_rng_proxy_create_rng(proxy2, 0, &rng2) == RES_OK); 273 ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng3); 274 275 CHK(ssp_rng_proxy_ref_put(proxy1) == RES_OK); 276 CHK(ssp_rng_proxy_ref_put(proxy2) == RES_OK); 277 278 ssp_rng_discard(rng1, COUNT); 279 ssp_rng_discard(rng3, COUNT+1); 280 FOR_EACH(i, 0, COUNT) ssp_rng_get(rng2); 281 282 CHK(ssp_rng_get(rng1) == ssp_rng_get(rng2)); 283 CHK(ssp_rng_get(rng1) == ssp_rng_get(rng3)); 284 285 CHK(ssp_rng_ref_put(rng1) == RES_OK); 286 CHK(ssp_rng_ref_put(rng2) == RES_OK); 287 CHK(ssp_rng_ref_put(rng3) == RES_OK); 288 } 289 290 static void 291 test_proxy_from_rng(void) 292 { 293 struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL; 294 struct ssp_rng_proxy* proxy; 295 struct ssp_rng* rng[4]; 296 enum ssp_rng_type type; 297 uint64_t r[4]; 298 size_t i, j, k; 299 300 CHK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng[0]) == RES_OK); 301 CHK(ssp_rng_discard(rng[0], COUNT) == RES_OK); 302 303 CHK(ssp_rng_proxy_create_from_rng(NULL, NULL, 0, NULL) == RES_BAD_ARG); 304 CHK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 0, NULL) == RES_BAD_ARG); 305 CHK(ssp_rng_proxy_create_from_rng(NULL, NULL, 1, NULL) == RES_BAD_ARG); 306 CHK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 1, NULL) == RES_BAD_ARG); 307 CHK(ssp_rng_proxy_create_from_rng(NULL, NULL, 0, &proxy) == RES_BAD_ARG); 308 CHK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 0, &proxy) == RES_BAD_ARG); 309 CHK(ssp_rng_proxy_create_from_rng(NULL, NULL, 1, &proxy) == RES_BAD_ARG); 310 CHK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 1, &proxy) == RES_OK); 311 CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng[1]) == RES_OK); 312 CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng[2]) == RES_BAD_ARG); 313 CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng[2]) == RES_BAD_ARG); 314 315 CHK(ssp_rng_get(rng[0]) == ssp_rng_get(rng[1])); 316 317 CHK(ssp_rng_ref_put(rng[1]) == RES_OK); 318 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 319 320 CHK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 4, &proxy) == RES_OK); 321 CHK(ssp_rng_ref_put(rng[0]) == RES_OK); 322 FOR_EACH(i, 0, 4) CHK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]) == RES_OK); 323 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 324 325 CHK(ssp_rng_get_type(rng[0], &type) == RES_OK); 326 FOR_EACH(i, 1, 4) { 327 enum ssp_rng_type type2; 328 CHK(ssp_rng_get_type(rng[i], &type2) == RES_OK); 329 CHK(type == type2); 330 } 331 332 FOR_EACH(i, 0, NRANDS) { 333 FOR_EACH(j, 0, 4) { 334 r[j] = ssp_rng_get(rng[j]); 335 FOR_EACH(k, 0, j) CHK(r[k] != r[j]); 336 } 337 } 338 339 FOR_EACH(i, 1, 4) CHK(ssp_rng_ref_put(rng[i]) == RES_OK); 340 341 args.rng = rng[0]; 342 args.sequence_offset = 0; 343 args.sequence_size = 4000; 344 args.sequence_pitch = 4000; 345 args.nbuckets = 4; 346 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_BAD_ARG); 347 CHK(ssp_rng_ref_put(rng[0]) == RES_OK); 348 349 CHK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng[0]) == RES_OK); 350 CHK(ssp_rng_discard(rng[0], 100) == RES_OK); 351 352 args.rng = rng[0]; 353 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 354 CHK(ssp_rng_ref_put(rng[0]) == RES_OK); 355 FOR_EACH(i, 0, 4) { 356 CHK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]) == RES_OK); 357 } 358 359 FOR_EACH(i, 0, NRANDS) { 360 FOR_EACH(j, 0, 4) { 361 r[j] = ssp_rng_get(rng[j]); 362 FOR_EACH(k, 0, j) CHK(r[k] != r[j]); 363 } 364 } 365 366 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 367 FOR_EACH(i, 0, 4) CHK(ssp_rng_ref_put(rng[i]) == RES_OK); 368 } 369 370 static void 371 test_read(void) 372 { 373 struct ssp_rng_proxy* proxy; 374 struct ssp_rng* rng; 375 struct ssp_rng* rng1[4]; 376 FILE* stream; 377 uint64_t r[4]; 378 size_t i, j, k; 379 380 CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK); 381 CHK(ssp_rng_discard(rng, COUNT) == RES_OK); 382 383 /* Create a RNG state */ 384 stream = tmpfile(); 385 CHK(stream != NULL); 386 CHK(ssp_rng_write(rng, stream) == RES_OK); 387 rewind(stream); 388 389 /* Create a proxy from the RNG state */ 390 CHK(ssp_rng_proxy_create(NULL, SSP_RNG_MT19937_64, 4, &proxy) == RES_OK); 391 CHK(ssp_rng_proxy_read(NULL, NULL) == RES_BAD_ARG); 392 CHK(ssp_rng_proxy_read(proxy, NULL) == RES_BAD_ARG); 393 CHK(ssp_rng_proxy_read(NULL, stream) == RES_BAD_ARG); 394 CHK(ssp_rng_proxy_read(proxy, stream) == RES_OK); 395 396 /* Create the list of RNG managed by the proxy */ 397 FOR_EACH(i, 0, 4) CHK(ssp_rng_proxy_create_rng(proxy, i, &rng1[i]) == RES_OK); 398 399 /* Check the random number sequences */ 400 r[0] = ssp_rng_get(rng); 401 CHK(r[0] == ssp_rng_get(rng1[0])); 402 CHK(r[0] != ssp_rng_get(rng1[1])); 403 CHK(r[0] != ssp_rng_get(rng1[2])); 404 CHK(r[0] != ssp_rng_get(rng1[3])); 405 FOR_EACH(i, 0, NRANDS) { 406 FOR_EACH(j, 0, 4) { 407 r[j] = ssp_rng_get(rng1[j]); 408 FOR_EACH(k, 0, j) CHK(r[k] != r[j]); 409 } 410 } 411 412 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 413 CHK(ssp_rng_ref_put(rng) == RES_OK); 414 FOR_EACH(i, 0, 4) CHK(ssp_rng_ref_put(rng1[i]) == RES_OK); 415 416 CHK(fclose(stream) == 0); 417 } 418 419 static void 420 test_read_with_cached_states(void) 421 { 422 struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL; 423 struct ssp_rng_proxy* proxy; 424 struct ssp_rng* rng; 425 struct ssp_rng* rng0; 426 struct ssp_rng* rng1; 427 FILE* stream; 428 size_t iseq; 429 size_t i; 430 431 CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK); 432 433 /* Create a proxy with a very small sequence size of 2 RNs per bucket in 434 * order to maximize the number of cached states. Furthermore, use the 435 * Mersenne Twister RNG type since its internal state is the greatest one of 436 * the proposed builtin type and is thus the one that will fill quickly the 437 * cache stream. */ 438 args.type = SSP_RNG_MT19937_64; 439 args.sequence_size = 10; 440 args.sequence_pitch = 10; 441 args.nbuckets = 2; 442 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 443 CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK); 444 CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK); 445 446 /* Check RNG states */ 447 FOR_EACH(i, 0, args.sequence_size) { 448 if(i < args.sequence_size/2) { 449 CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); 450 } else { 451 CHK(ssp_rng_get(rng) == ssp_rng_get(rng1)); 452 } 453 } 454 455 /* Discard several RNs for the 1st RNG to cache several states for the rng1 */ 456 CHK(ssp_rng_discard(rng0, 103) == RES_OK); 457 458 /* Generate a RNG state */ 459 stream = tmpfile(); 460 CHK(stream != NULL); 461 CHK(ssp_rng_discard(rng, 100000) == RES_OK); 462 CHK(ssp_rng_write(rng, stream) == RES_OK); 463 rewind(stream); 464 465 /* Setup the proxy state and check that the RNGs managed by the proxy now use 466 * the new state properly, even though RNG states were previously cached */ 467 CHK(ssp_rng_proxy_read(proxy, stream) == RES_OK); 468 FOR_EACH(iseq, 0, 100) { 469 FOR_EACH(i, 0, args.sequence_size) { 470 if(i < args.sequence_size/2) { 471 CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); 472 } else { 473 CHK(ssp_rng_get(rng) == ssp_rng_get(rng1)); 474 } 475 } 476 } 477 478 /* Discard several RNs for the first RNG only to make under pressure the 479 * cache stream of 'rng1'. The cache memory limit is 32 MB maximum and the 480 * size of a Mersenne Twister RNG state is greater than 6 KB. Consquently, 481 * ~5500 RNG states will exceed the cache stream, i.e. 5500*2 = 11000 482 * random generations (since there is 2 RNs per bucket). Above this limit, 483 * 'rng1' will not rely anymore on the proxy RNG to manage its state. */ 484 CHK(ssp_rng_discard(rng0, 20000) == RES_OK); 485 486 /* Generate a new RNG state */ 487 rewind(stream); 488 CHK(ssp_rng_discard(rng, 100000) == RES_OK); 489 CHK(ssp_rng_write(rng, stream) == RES_OK); 490 rewind(stream); 491 492 /* Now setup a new proxy state and check that the RNGs managed by the proxy 493 * correctly use the new state */ 494 CHK(ssp_rng_proxy_read(proxy, stream) == RES_OK); 495 FOR_EACH(iseq, 0, 100) { 496 FOR_EACH(i, 0, args.sequence_size) { 497 if(i < args.sequence_size/2) { 498 CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); 499 } else { 500 CHK(ssp_rng_get(rng) == ssp_rng_get(rng1)); 501 } 502 } 503 } 504 505 /* Discard several RNs for the 1st RNG to cache several states for the rng1 */ 506 CHK(ssp_rng_discard(rng0, 100) == RES_OK); 507 508 /* Finally verify that the cache was reset on proxy read */ 509 FOR_EACH(iseq, 0, 100) { 510 FOR_EACH(i, 0, args.sequence_size) { 511 if(i < args.sequence_size/2) { 512 CHK(ssp_rng_discard(rng, 1) == RES_OK); 513 } else { 514 CHK(ssp_rng_get(rng) == ssp_rng_get(rng1)); 515 } 516 } 517 } 518 519 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 520 CHK(ssp_rng_ref_put(rng0) == RES_OK); 521 CHK(ssp_rng_ref_put(rng1) == RES_OK); 522 CHK(ssp_rng_ref_put(rng) == RES_OK); 523 524 CHK(fclose(stream) == 0); 525 } 526 527 static void 528 test_write(void) 529 { 530 struct ssp_rng_proxy* proxy; 531 struct ssp_rng* rng0; 532 struct ssp_rng* rng1; 533 FILE* stream; 534 uint64_t r; 535 536 stream = tmpfile(); 537 CHK(stream != NULL); 538 539 CHK(ssp_rng_proxy_create(NULL, SSP_RNG_RANLUX48, 1, &proxy) == RES_OK); 540 CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK); 541 542 CHK(ssp_rng_proxy_write(NULL, NULL) == RES_BAD_ARG); 543 CHK(ssp_rng_proxy_write(proxy, NULL) == RES_BAD_ARG); 544 CHK(ssp_rng_proxy_write(NULL, stream) == RES_BAD_ARG); 545 CHK(ssp_rng_proxy_write(proxy, stream) == RES_OK); 546 547 CHK(ssp_rng_create(NULL, SSP_RNG_RANLUX48, &rng1) == RES_OK); 548 r = ssp_rng_get(rng0); 549 CHK(r == ssp_rng_get(rng1)); 550 551 rewind(stream); 552 CHK(ssp_rng_read(rng1, stream) == RES_OK); 553 CHK(r == ssp_rng_get(rng1)); 554 CHK(ssp_rng_get(rng0) == ssp_rng_get(rng1)); 555 556 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 557 CHK(ssp_rng_ref_put(rng0) == RES_OK); 558 CHK(ssp_rng_ref_put(rng1) == RES_OK); 559 560 CHK(fclose(stream) == 0); 561 } 562 563 static void 564 test_cache(void) 565 { 566 struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL; 567 struct ssp_rng_proxy* proxy; 568 struct ssp_rng* rng0; 569 struct ssp_rng* rng1; 570 struct ssp_rng* rng; 571 const size_t nrands = 20000; 572 size_t i; 573 574 /* Create a proxy with a very small sequence size of 2 RNs per bucket in 575 * order to maximize the number of cached states. Furthermore, use the 576 * Mersenne Twister RNG type since its internal state is the greatest one of 577 * the proposed builtin type and is thus the one that will fill quickly the 578 * cache stream. */ 579 args.type = SSP_RNG_MT19937_64; 580 args.sequence_size = 4; 581 args.sequence_pitch = 4; 582 args.nbuckets = 2; 583 584 /* Simply test that the RNs generated by the proxy are the same than the 585 * ones generated by a regular RNG. Since each RNG invocation are 586 * interleaved, the cache pressure is very low, at most 1 RNG state is 587 * cached. */ 588 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 589 CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK); 590 CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK); 591 CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK); 592 FOR_EACH(i, 0, nrands*2) { 593 if((i / 2) % 2) { 594 CHK(ssp_rng_get(rng1) == ssp_rng_get(rng)); 595 } else { 596 CHK(ssp_rng_get(rng0) == ssp_rng_get(rng)); 597 } 598 } 599 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 600 CHK(ssp_rng_ref_put(rng0) == RES_OK); 601 CHK(ssp_rng_ref_put(rng1) == RES_OK); 602 CHK(ssp_rng_ref_put(rng) == RES_OK); 603 604 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 605 CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK); 606 CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK); 607 CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK); 608 609 /* Generate several RNs for the first RNG only to make under pressure the 610 * cache stream of 'rng1'. The cache memory limit is 32 MB maximum and the 611 * size of a Mersenne Twister RNG state is greater than 6 KB. Consquently, 612 * ~5500 RNG states will exceed the cache stream, i.e. 5500*2 = 11000 613 * random generations (since there is 2 RNs per bucket). Above this limit, 614 * 'rng1' will not rely anymore on the proxy RNG to manage its state. 615 * 616 * For both RNGs, ensure that the generated RNs are the expected ones by 617 * comparing them to the ones generated by a regular RNG */ 618 FOR_EACH(i, 0, nrands) { 619 CHK(ssp_rng_get(rng0) == ssp_rng_get(rng)); 620 if(i % 2) CHK(ssp_rng_discard(rng, 2) == RES_OK); 621 } 622 CHK(ssp_rng_ref_put(rng) == RES_OK); 623 624 /* Check the cache mechanisme of rng1 */ 625 CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK); 626 CHK(ssp_rng_discard(rng, 2) == RES_OK); 627 FOR_EACH(i, 0, nrands) { 628 CHK(ssp_rng_get(rng1) == ssp_rng_get(rng)); 629 if(i % 2) CHK(ssp_rng_discard(rng, 2) == RES_OK); 630 } 631 632 CHK(ssp_rng_ref_put(rng) == RES_OK); 633 634 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 635 CHK(ssp_rng_ref_put(rng0) == RES_OK); 636 CHK(ssp_rng_ref_put(rng1) == RES_OK); 637 } 638 639 640 static void 641 test_sequence(void) 642 { 643 struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL; 644 struct ssp_rng_proxy* proxy; 645 struct ssp_rng* rng0; 646 struct ssp_rng* rng1; 647 struct ssp_rng* rng; 648 size_t id; 649 size_t iseq; 650 size_t i; 651 652 args.type = SSP_RNG_MT19937_64; 653 args.sequence_offset = 0; 654 args.sequence_size = 16; 655 args.sequence_pitch = 16; 656 args.nbuckets = 2; 657 658 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 659 CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK); 660 CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK); 661 CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK); 662 663 CHK(ssp_rng_proxy_get_sequence_id(NULL, &id) == RES_BAD_ARG); 664 CHK(ssp_rng_proxy_get_sequence_id(proxy, NULL) == RES_BAD_ARG); 665 666 /* Check that directly after its creation, the proxy has a the sequence index 667 * of SSP_SEQUENCE_ID_NONE */ 668 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 669 CHK(id == SSP_SEQUENCE_ID_NONE); 670 671 /* Generate 4 sequences of random numbers and check the progression of the 672 * sequence index */ 673 FOR_EACH(iseq, 0, 4) { 674 FOR_EACH(i, 0, args.sequence_size) { 675 if(i < args.sequence_size/2) { 676 CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); 677 } else { 678 CHK(ssp_rng_get(rng) == ssp_rng_get(rng1)); 679 } 680 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 681 CHK(id == iseq); 682 } 683 } 684 685 /* Generate 1 more RN to go to the next sequence. Then, discard the remaining 686 * random numbers of the first RNG and check the the sequence is the same 687 * until a new RN is discarded */ 688 CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); 689 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 690 CHK(id == 4); 691 CHK(ssp_rng_discard(rng0, args.sequence_size/2 - 1) == RES_OK); 692 CHK(ssp_rng_discard(rng, args.sequence_size/2 - 1) == RES_OK); 693 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 694 CHK(id == 4); 695 CHK(ssp_rng_discard(rng0, 1) == RES_OK); 696 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 697 CHK(id == 5); 698 699 /* Check the random sequence of the second RNG */ 700 FOR_EACH(i, 0, args.sequence_size/2) { 701 CHK(ssp_rng_get(rng) == ssp_rng_get(rng1)); 702 } 703 704 /* Check the sequence of the first RNG */ 705 CHK(ssp_rng_discard(rng, 1) == RES_OK); 706 CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); 707 708 /* Discard the random numbers of the current sequence associated to the 709 * second RNG. Check the the sequence is the same until a new random number 710 * is discarded */ 711 CHK(ssp_rng_discard(rng1, args.sequence_size/2) == RES_OK); 712 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 713 CHK(id == 5); 714 CHK(ssp_rng_discard(rng1, 1) == RES_OK); 715 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 716 CHK(id == 6); 717 718 /* Synchronise the RNGs through sequence 6 */ 719 CHK(ssp_rng_discard(rng0, args.sequence_size/2-2) == RES_OK); 720 CHK(ssp_rng_discard(rng, args.sequence_size-2) == RES_OK); 721 FOR_EACH(i, 0, args.sequence_size) { 722 if(i < args.sequence_size/2) { 723 CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); 724 } else if(i == args.sequence_size/2) { 725 CHK(ssp_rng_discard(rng, 1) == RES_OK); 726 } else { 727 CHK(ssp_rng_get(rng) == ssp_rng_get(rng1)); 728 } 729 } 730 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 731 CHK(id == 6); 732 733 /* Move in sequence 7 */ 734 CHK(ssp_rng_discard(rng0, 3) == RES_OK); 735 CHK(ssp_rng_discard(rng1, 7) == RES_OK); 736 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 737 CHK(id == 7); 738 739 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 740 CHK(ssp_rng_ref_put(rng1) == RES_OK); 741 CHK(ssp_rng_ref_put(rng0) == RES_OK); 742 CHK(ssp_rng_ref_put(rng) == RES_OK); 743 } 744 745 static void 746 test_flush_sequence() 747 { 748 struct ssp_rng_proxy_create2_args args = SSP_RNG_PROXY_CREATE2_ARGS_NULL; 749 struct ssp_rng_proxy* proxy; 750 struct ssp_rng* rng0; 751 struct ssp_rng* rng1; 752 struct ssp_rng* rng; 753 size_t id; 754 size_t i; 755 756 args.type = SSP_RNG_MT19937_64; 757 args.sequence_offset = 0; 758 args.sequence_size = 10; 759 args.sequence_pitch = 10; 760 args.nbuckets = 2; 761 762 CHK(ssp_rng_proxy_create2(NULL, &args, &proxy) == RES_OK); 763 CHK(ssp_rng_proxy_create_rng(proxy, 0, &rng0) == RES_OK); 764 CHK(ssp_rng_proxy_create_rng(proxy, 1, &rng1) == RES_OK); 765 CHK(ssp_rng_create(NULL, SSP_RNG_MT19937_64, &rng) == RES_OK); 766 767 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 768 CHK(id == SSP_SEQUENCE_ID_NONE); 769 CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); 770 771 /* Flush 0 sequence, i.e. do nothing */ 772 CHK(ssp_rng_proxy_flush_sequences(NULL, 0) == RES_BAD_ARG); 773 CHK(ssp_rng_proxy_flush_sequences(proxy, 0) == RES_OK); 774 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 775 CHK(id == 0); 776 CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); 777 778 /* Discard several numbers of the rng1 to fill the cache of rng0. We will 779 * thus be able to check the cache clearing when we will flush sequences */ 780 CHK(ssp_rng_discard(rng1, 314) == RES_OK); 781 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 782 CHK(id == 62); 783 784 /* Flush the remaining random number of the current sequence */ 785 CHK(ssp_rng_proxy_flush_sequences(proxy, 1) == RES_OK); 786 787 /* We are still in the sequence 62 but without any available random numbers */ 788 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 789 CHK(id == 62); 790 791 /* Synchronize RNG with the current state of the proxy */ 792 CHK(ssp_rng_discard 793 (rng, args.sequence_size*63 /*#random number to discard */ 794 - 2/*... minus the 2 already consumed random numbers*/) == RES_OK); 795 796 /* Check RNG states */ 797 FOR_EACH(i, 0, args.sequence_size) { 798 if(i < args.sequence_size/2) { 799 CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); 800 } else { 801 CHK(ssp_rng_get(rng) == ssp_rng_get(rng1)); 802 } 803 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 804 CHK(id == 63); 805 } 806 807 /* Fill the cache of the rng1 */ 808 CHK(ssp_rng_discard(rng0, 1013) == RES_OK); 809 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 810 CHK(id == 63 + 203/*ceil(1013/(args.sequence_size*0.5))*/); 811 812 /* Discard several sequences */ 813 CHK(ssp_rng_proxy_flush_sequences(proxy, 314) == RES_OK); 814 815 /* Synchronize RNG with the current state of the proxy */ 816 CHK(ssp_rng_discard(rng, args.sequence_size*(203 + 314 - 1)) == RES_OK); 817 818 /* Check RNG states */ 819 FOR_EACH(i, 0, args.sequence_size) { 820 if(i < args.sequence_size/2) { 821 CHK(ssp_rng_get(rng) == ssp_rng_get(rng0)); 822 } else { 823 CHK(ssp_rng_get(rng) == ssp_rng_get(rng1)); 824 } 825 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 826 CHK(id == 63 + 203 + 314); 827 } 828 829 /* Generate several RNs for the first RNG only to make under pressure the 830 * cache stream of 'rng1'. The cache memory limit is 32 MB maximum and the 831 * size of a Mersenne Twister RNG state is greater than 6 KB. Consquently, 832 * ~5500 RNG states will exceed the cache stream, i.e. 5500*5 = 27500 833 * random generations (since there is 5 RNs per bucket). Above this limit, 834 * 'rng1' will not rely anymore on the proxy RNG to manage its state. */ 835 CHK(ssp_rng_discard(rng0, 30000) == RES_OK); 836 837 /* Discard enough random numbers from rng1 to consume all cached RNG states, 838 * and thus disable read cache usage */ 839 CHK(ssp_rng_discard(rng1, 30000) == RES_OK); 840 841 CHK(ssp_rng_proxy_get_sequence_id(proxy, &id) == RES_OK); 842 CHK(id == 63+203+314+(30000*2)/args.sequence_size); 843 844 /* Try to flush a sequence on a proxy whose a generator don't use cache */ 845 CHK(ssp_rng_proxy_flush_sequences(proxy, 1) == RES_OK); 846 847 CHK(ssp_rng_proxy_ref_put(proxy) == RES_OK); 848 CHK(ssp_rng_ref_put(rng1) == RES_OK); 849 CHK(ssp_rng_ref_put(rng0) == RES_OK); 850 CHK(ssp_rng_ref_put(rng) == RES_OK); 851 } 852 853 int 854 main(int argc, char** argv) 855 { 856 (void)argc, (void)argv; 857 test_creation(); 858 test_creation2(); 859 test_rng_from_proxy(); 860 test_rng_from_proxy2(); 861 test_multi_proxies(); 862 test_proxy_from_rng(); 863 test_read(); 864 test_read_with_cached_states(); 865 test_write(); 866 test_cache(); 867 test_sequence(); 868 test_flush_sequence(); 869 CHK(mem_allocated_size() == 0); 870 return 0; 871 }