commit 4da2e6bed1087fa334d8d11e41f2057c07cff459
parent 411db4829bbecfbdd9504cd8c7caeb844fcc6855
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Sat, 13 Jun 2015 14:57:37 +0200
Add threefry and aes counter based RNG (from Random123).
aes is currently activated with MSVC compiler only.
Diffstat:
5 files changed, 188 insertions(+), 13 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -39,6 +39,10 @@ option(NO_TEST "Disable the test" OFF)
################################################################################
# Check dependencies
################################################################################
+get_filename_component(_current_source_dir ${CMAKE_CURRENT_LIST_FILE} PATH)
+set(Random123_DIR ${_current_source_dir}/)
+
+find_package(Random123 REQUIRED)
find_package(RCMake 0.1 REQUIRED)
find_package(RSys 0.2 REQUIRED)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
@@ -49,9 +53,11 @@ if(MSVC)
# Currently, the C++11 random library on MSVC is bugged and consequently we
# use the Boost library instead
find_package(Boost 1.58 REQUIRED COMPONENTS random)
- include_directories(${RSys_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
+ include_directories(${RSys_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${Random123_INCLUDE_DIR})
+ # Random123 AES generator compiles on MSVC
+ add_definitions(-DWITH_R123_AES)
else()
- include_directories(${RSys_INCLUDE_DIR})
+ include_directories(${RSys_INCLUDE_DIR} ${Random123_INCLUDE_DIR})
endif()
rcmake_append_runtime_dirs(_runtime_dirs RSys)
@@ -130,6 +136,10 @@ if(NOT NO_TEST)
register_test(test_ssp_rng_mt19937_64 test_ssp_rng mt19937_64)
register_test(test_ssp_rng_ranlux48 test_ssp_rng ranlux48)
register_test(test_ssp_rng_random_device test_ssp_rng random_device)
+ register_test(test_ssp_rng_threefry test_ssp_rng threefry)
+ if(MSVC)
+ register_test(test_ssp_rng_aes test_ssp_rng aes)
+ endif()
new_test(test_ssp_ran_hemisphere ${MATH_LIB})
new_test(test_ssp_rng_proxy)
endif()
diff --git a/cmake/Random123Config.cmake b/cmake/Random123Config.cmake
@@ -0,0 +1,54 @@
+# Copyright (C) |Meso|Star> 2015 (contact@meso-star.com)
+#
+# This software is a computer program whose purpose is to generate files
+# used to build the Star-3D library.
+#
+# This software is governed by the CeCILL license under French law and
+# abiding by the rules of distribution of free software. You can use,
+# modify and/or redistribute the software under the terms of the CeCILL
+# license as circulated by CEA, CNRS and INRIA at the following URL
+# "http://www.cecill.info".
+#
+# As a counterpart to the access to the source code and rights to copy,
+# modify and redistribute granted by the license, users are provided only
+# with a limited warranty and the software's author, the holder of the
+# economic rights, and the successive licensors have only limited
+# liability.
+#
+# In this respect, the user's attention is drawn to the risks associated
+# with loading, using, modifying and/or developing or reproducing the
+# software by the user in light of its specific status of free software,
+# that may mean that it is complicated to manipulate, and that also
+# therefore means that it is reserved for developers and experienced
+# professionals having in-depth computer knowledge. Users are therefore
+# encouraged to load and test the software's suitability as regards their
+# requirements in conditions enabling the security of their systems and/or
+# data to be ensured and, more generally, to use and operate it in the
+# same conditions as regards security.
+#
+# The fact that you are presently reading this means that you have had
+# knowledge of the CeCILL license and that you accept its terms.
+
+cmake_minimum_required(VERSION 2.6)
+
+# Try to find the Random123 devel. Once done this will define:
+# - Random123_FOUND: system has Random123
+# - Random123_INCLUDE_DIR: the include directory
+# - Random123: Link this to use Random123
+
+find_path(Random123_INCLUDE_DIR Random123/threefry.h)
+find_library(Random123_LIBRARY Random123 DOC "Path to the library Random123.")
+
+# Create the imported library target
+if(CMAKE_HOST_WIN32)
+ set(_property IMPORTED_IMPLIB)
+else(CMAKE_HOST_WIN32)
+ set(_property IMPORTED_LOCATION)
+endif(CMAKE_HOST_WIN32)
+add_library(Random123 SHARED IMPORTED)
+
+# Check the package
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Random123 DEFAULT_MSG
+ Random123_INCLUDE_DIR)
+
diff --git a/src/ssp.h b/src/ssp.h
@@ -89,14 +89,22 @@ SSP_API const struct ssp_rng_type ssp_rng_kiss;
SSP_API const struct ssp_rng_type ssp_rng_mt19937_64;
/* 48-bits RANLUX builtin PRNG type of Lusher and James, 1994 */
SSP_API const struct ssp_rng_type ssp_rng_ranlux48;
-
-/* A random_device RNG is a uniformly-distributed integer random number generator
- * that produces non-deterministic random numbers. It may may be implemented in
- * terms of an implementation-defined pseudo-random number engine if a
- * non-deterministic source (e.g. a hardware device) is not available to the
- * implementation. In this case each random_device object may generate the same
- * number sequence. */
+/*
+random_device generator from Boost / C++11
+std::random_device is a uniformly-distributed integer random number generator
+that produces non-deterministic random numbers.
+std::random_device may be implemented in terms of an implementation-defined
+pseudo-random number engine if a non-deterministic source (e.g. a hardware device)
+is not available to the implementation.
+In this case each std::random_device object may generate the same number sequence.
+*/
SSP_API const struct ssp_rng_type ssp_rng_random_device;
+/* Counter Based RNG threefry of Salmon, Moraes, Dror & Shaw */
+SSP_API const struct ssp_rng_type ssp_rng_threefry;
+#ifdef WITH_R123_AES
+/* Counter Based RNG aes of Salmon, Moraes, Dror & Shaw */
+SSP_API const struct ssp_rng_type ssp_rng_aes;
+#endif
/*******************************************************************************
* Random Number Generator API
diff --git a/src/ssp_rng.c b/src/ssp_rng.c
@@ -33,7 +33,6 @@
#include <rsys/mem_allocator.h>
-#include <cstring>
#ifdef COMPILER_CL
/* The random C++11 library is bugged on MSVC 12. Use the boost version */
#include <boost/random.hpp>
@@ -47,7 +46,33 @@
#define RAN_NAMESPACE std
#endif
+#ifdef COMPILER_GCC
+ #pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconversion" /* conversion to ‘yyy’ from ‘xxx’ may alter its value */
+#elif defined(COMPILER_CL)
+// disable some warnings in Random123 includes
+#pragma warning(push)
+#pragma warning(disable:4100) /* unreferenced formal parameter */
+#pragma warning(disable:4127) /* conditional expression is constant */
+#pragma warning(disable:4512) /* assignment operator could not be generated */
+#pragma warning(disable:4521) /* multiple copy constructors specified */
+#endif
+
+#include "Random123/conventional/Engine.hpp"
+#include "Random123/threefry.h"
+#ifdef WITH_R123_AES
+#include "Random123/aes.h"
+#endif
+
+#ifdef COMPILER_GCC
+#pragma GCC diagnostic pop
+#elif defined(COMPILER_CL)
+#pragma warning(pop)
+#endif
+
#include <sstream>
+#include <cstring>
+#include <limits>
/*******************************************************************************
* KISS PRNG
@@ -364,6 +389,66 @@ const struct ssp_rng_type ssp_rng_random_device = {
};
/*******************************************************************************
+* Random123 Counter Based RNG
+******************************************************************************/
+
+typedef r123::Engine<r123::Threefry4x64> threefry_t;
+
+#ifdef WITH_R123_AES
+typedef r123::Engine<r123::AESNI4x32> aes_t;
+
+template<>
+res_T
+rng_cxx_init<aes_t>(struct mem_allocator* allocator, void* data)
+{
+ (void) allocator;
+ if (!haveAESNI()) {
+ // AES-NI instructions not available on this hardware
+ return RES_BAD_OP;
+ }
+ ASSERT(data);
+ new (data) aes_t;
+ return RES_OK;
+}
+#endif
+
+/* threefry generator */
+const struct ssp_rng_type ssp_rng_threefry = {
+ rng_cxx_init<threefry_t>,
+ rng_cxx_release<threefry_t>,
+ rng_cxx_set<threefry_t>,
+ rng_cxx_get<threefry_t>,
+ rng_cxx_uniform_uint64<threefry_t>,
+ rng_cxx_uniform_double<threefry_t>,
+ rng_cxx_canonical<threefry_t>,
+ rng_cxx_read<threefry_t>,
+ rng_cxx_write<threefry_t>,
+ rng_cxx_entropy<threefry_t>,
+ std::numeric_limits<threefry_t::result_type>::min(),
+ std::numeric_limits<threefry_t::result_type>::max(),
+ sizeof(threefry_t)
+};
+
+#ifdef WITH_R123_AES
+/* aes generator */
+const struct ssp_rng_type ssp_rng_aes = {
+ rng_cxx_init<aes_t>,
+ rng_cxx_release<aes_t>,
+ rng_cxx_set<aes_t>,
+ rng_cxx_get<aes_t>,
+ rng_cxx_uniform_uint64<aes_t>,
+ rng_cxx_uniform_double<aes_t>,
+ rng_cxx_canonical<aes_t>,
+ rng_cxx_read<aes_t>,
+ rng_cxx_write<aes_t>,
+ rng_cxx_entropy<aes_t>,
+ std::numeric_limits<aes_t::result_type>::min(),
+ std::numeric_limits<aes_t::result_type>::max(),
+ sizeof(aes_t)
+};
+#endif
+
+/*******************************************************************************
* Helper functions
******************************************************************************/
static char
diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c
@@ -49,6 +49,7 @@ test_rng(const struct ssp_rng_type* type)
double dataf[NRAND];
char buf[512];
int i, j;
+ res_T r;
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);
@@ -62,7 +63,14 @@ test_rng(const struct ssp_rng_type* type)
CHECK(ssp_rng_create(&allocator, type, NULL), RES_BAD_ARG);
CHECK(ssp_rng_create(NULL, NULL, &rng), RES_BAD_ARG);
CHECK(ssp_rng_create(&allocator, NULL, &rng), RES_BAD_ARG);
- CHECK(ssp_rng_create(NULL, type, &rng), RES_OK);
+ r = ssp_rng_create(NULL, type, &rng);
+#ifdef WITH_R123_AES
+ if (r == RES_BAD_OP && type == &ssp_rng_aes) {
+ printf("AES-NI instructions not available on this CPU and system.\n");
+ return;
+ }
+#endif
+ CHECK(r, RES_OK);
CHECK(ssp_rng_ref_get(NULL), RES_BAD_ARG);
CHECK(ssp_rng_ref_get(rng), RES_OK);
@@ -170,8 +178,12 @@ test_rng(const struct ssp_rng_type* type)
int
main(int argc, char** argv)
{
- if(argc <= 1) {
- fprintf(stderr, "Usage: %s <kiss|mt19937_64|ranlux48|random_device>\n", argv[0]);
+ if (argc <= 1) {
+#ifdef WITH_R123_AES
+ fprintf(stderr, "Usage: %s <kiss|mt19937_64|ranlux48|random_device|threefry|aes>\n", argv[0]);
+#else
+ fprintf(stderr, "Usage: %s <kiss|mt19937_64|ranlux48|random_device|threefry>\n", argv[0]);
+#endif
exit(0);
}
if(!strcmp(argv[1], "kiss")) {
@@ -182,6 +194,12 @@ main(int argc, char** argv)
test_rng(&ssp_rng_ranlux48);
} else if(!strcmp(argv[1], "random_device")) {
test_rng(&ssp_rng_random_device);
+ } else if(!strcmp(argv[1], "threefry")) {
+ test_rng(&ssp_rng_threefry);
+#ifdef WITH_R123_AES
+ } else if(!strcmp(argv[1], "aes")) {
+ test_rng(&ssp_rng_aes);
+#endif
} else {
fprintf(stderr, "Unknown RNG `%s'\n", argv[1]);
ASSERT(0);