#include <atomic>
#include <unistd.h>
#include <sys/time.h>
+#include <random>
+#include <array>
+
+#if __GNUC_PREREQ(4, 8)
+#include <ext/random>
+#define USE_SIMD_PRNG
+#endif
namespace folly {
+ kPrime3 * static_cast<uint32_t>(tv.tv_usec);
}
+
+folly::ThreadLocalPtr<ThreadLocalPRNG::LocalInstancePRNG>
+ThreadLocalPRNG::localInstance;
+
+class ThreadLocalPRNG::LocalInstancePRNG {
+#ifdef USE_SIMD_PRNG
+ typedef __gnu_cxx::sfmt19937 RNG;
+#else
+ typedef std::mt19937 RNG;
+#endif
+
+ static RNG makeRng() {
+ std::array<int, RNG::state_size> seed_data;
+ std::random_device r;
+ std::generate_n(seed_data.data(), seed_data.size(), std::ref(r));
+ std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
+ return RNG(seq);
+ }
+
+ public:
+ LocalInstancePRNG() : rng(std::move(makeRng())) {}
+
+ RNG rng;
+};
+
+ThreadLocalPRNG::LocalInstancePRNG* ThreadLocalPRNG::initLocal() {
+ auto ret = new LocalInstancePRNG;
+ localInstance.reset(ret);
+ return ret;
+}
+
+uint32_t ThreadLocalPRNG::getImpl(LocalInstancePRNG* local) {
+ return local->rng();
+}
+
}
#define FOLLY_BASE_RANDOM_H_
#include <stdint.h>
+#include "folly/ThreadLocal.h"
namespace folly {
*/
uint32_t randomNumberSeed();
+class Random;
+
+/**
+ * A PRNG with one instance per thread. This PRNG uses a mersenne twister random
+ * number generator and is seeded from /dev/urandom. It should not be used for
+ * anything which requires security, only for statistical randomness.
+ *
+ * An instance of this class represents the current threads PRNG. This means
+ * copying an instance of this class across threads will result in corruption
+ *
+ * Most users will use the Random class which implicitly creates this class.
+ * However, if you are worried about performance, you can memoize the TLS
+ * lookups that get the per thread state by manually using this class:
+ *
+ * ThreadLocalPRNG rng = Random::threadLocalPRNG()
+ * for (...) {
+ * Random::rand32(rng);
+ * }
+ */
+class ThreadLocalPRNG {
+ public:
+ typedef uint32_t result_type;
+
+ uint32_t operator()() {
+ // Using a static method allows the compiler to avoid allocating stack space
+ // for this class.
+ return getImpl(local_);
+ }
+
+ static constexpr result_type min() {
+ return std::numeric_limits<result_type>::min();
+ }
+ static constexpr result_type max() {
+ return std::numeric_limits<result_type>::max();
+ }
+ friend class Random;
+
+ ThreadLocalPRNG() {
+ local_ = localInstance.get();
+ if (!local_) {
+ local_ = initLocal();
+ }
+ }
+
+ private:
+ class LocalInstancePRNG;
+ static LocalInstancePRNG* initLocal();
+ static folly::ThreadLocalPtr<ThreadLocalPRNG::LocalInstancePRNG>
+ localInstance;
+
+ static result_type getImpl(LocalInstancePRNG* local);
+ LocalInstancePRNG* local_;
+};
+
+
+
+class Random {
+
+ private:
+ template<class RNG>
+ using ValidRNG = typename std::enable_if<
+ std::is_unsigned<typename std::result_of<RNG&()>::type>::value,
+ RNG>::type;
+
+ public:
+
+ /**
+ * Returns a random uint32_t
+ */
+ template<class RNG = ThreadLocalPRNG>
+ static uint32_t rand32(ValidRNG<RNG> rrng = RNG()) {
+ uint32_t r = rrng.operator()();
+ return r;
+ }
+
+ /**
+ * Returns a random uint32_t in [0, max). If max == 0, returns 0.
+ */
+ template<class RNG = ThreadLocalPRNG>
+ static uint32_t rand32(uint32_t max, ValidRNG<RNG> rng = RNG()) {
+ if (max == 0) {
+ return 0;
+ }
+
+ return std::uniform_int_distribution<uint32_t>(0, max - 1)(rng);
+ }
+
+ /**
+ * Returns a random uint64_t
+ */
+ template<class RNG = ThreadLocalPRNG>
+ static uint64_t rand64(ValidRNG<RNG> rng = RNG()) {
+ return ((uint64_t) rng() << 32) | rng();
+ }
+
+ /**
+ * Returns a random uint64_t in [0, max). If max == 0, returns 0.
+ */
+ template<class RNG = ThreadLocalPRNG>
+ static uint64_t rand64(uint64_t max, ValidRNG<RNG> rng = RNG()) {
+ if (max == 0) {
+ return 0;
+ }
+
+ return std::uniform_int_distribution<uint64_t>(0, max - 1)(rng);
+ }
+
+ /**
+ * Returns true 1/n of the time. If n == 0, always returns false
+ */
+ template<class RNG = ThreadLocalPRNG>
+ static bool oneIn(uint32_t n, ValidRNG<RNG> rng = RNG()) {
+ if (n == 0) {
+ return false;
+ }
+
+ return rand32(n, rng) == 0;
+ }
+
+ /**
+ * Returns a double in [0, 1)
+ */
+ template<class RNG = ThreadLocalPRNG>
+ static double randDouble01(ValidRNG<RNG> rng = RNG()) {
+ return std::generate_canonical<double, std::numeric_limits<double>::digits>
+ (rng);
+ }
+
+};
+
}
#endif
*/
#include "folly/Random.h"
+#include "folly/Range.h"
+#include "folly/Benchmark.h"
+#include "folly/Foreach.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <thread>
#include <vector>
+#include <random>
using namespace folly;
EXPECT_LT(seeds[i], seeds[i+1]);
}
}
+
+BENCHMARK(minstdrand, n) {
+ BenchmarkSuspender braces;
+ std::random_device rd;
+ std::minstd_rand rng(rd());
+
+ braces.dismiss();
+
+ FOR_EACH_RANGE (i, 0, n) {
+ doNotOptimizeAway(rng());
+ }
+}
+
+BENCHMARK(mt19937, n) {
+ BenchmarkSuspender braces;
+ std::random_device rd;
+ std::mt19937 rng(rd());
+
+ braces.dismiss();
+
+ FOR_EACH_RANGE (i, 0, n) {
+ doNotOptimizeAway(rng());
+ }
+}
+
+BENCHMARK(threadprng, n) {
+ BenchmarkSuspender braces;
+ ThreadLocalPRNG tprng;
+ tprng();
+
+ braces.dismiss();
+
+ FOR_EACH_RANGE (i, 0, n) {
+ doNotOptimizeAway(tprng());
+ }
+}
+
+BENCHMARK(RandomDouble) { doNotOptimizeAway(Random::randDouble01()); }
+BENCHMARK(Random32) { doNotOptimizeAway(Random::rand32()); }
+BENCHMARK(Random32Num) { doNotOptimizeAway(Random::rand32(100)); }
+BENCHMARK(Random64) { doNotOptimizeAway(Random::rand64()); }
+BENCHMARK(Random64Num) { doNotOptimizeAway(Random::rand64(100ul << 32)); }
+BENCHMARK(Random64OneIn) { doNotOptimizeAway(Random::oneIn(100)); }
+
+int main(int argc, char** argv) {
+ google::ParseCommandLineFlags(&argc, &argv, true);
+
+ runBenchmarks();
+
+ return 0;
+}