From 3bd236b556457637a14af1456f8ae48f365c566c Mon Sep 17 00:00:00 2001 From: ADAM David Alan Martin Date: Thu, 5 Sep 2024 18:35:39 -0400 Subject: [PATCH] Add fast random facility. This is a low-memory-overhead and low-cpu-overhead (per generated bit) random number generator. The repeat cycle is around 2**88. Which means around 2**120 bits are available before a cycle. Which means that about 2**102 12-bit samples are available before repeats. This should be more than sufficient for blob rollover purposes. If 100 million blobs are split per second (absurdly high), then that's about 2**27 per second. If run for 30 years, that's 2**30 seconds. If run across 128 CPUs, that's 2**7 CPUs. Thus 2**(27+30+7) total samples are required before loop. This is 2**64 which is WAAAY less than 2**88. (And this is overly conservative, as these generators should be one-per-thread... so we're really much closer to 2**57, not that it matters.) For this reason, there's no reseed code. The cycle length of mt11213b is significantly longer, however, it has a significantly larger state. One goal here is to keep the amount of state for this generator to a single cache line. As such, if the cycle length is later shown to be significantly smaller than 2**48 or so, a reseed code path may need to be added. (This is on the assumption that the above described intensive run would run for more than 1 million seconds, or about two weeks.) --- CMakeLists.txt | 1 + fastRandom.cc | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ fastRandom.h | 20 ++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 fastRandom.cc create mode 100644 fastRandom.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fa07543..b042b02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ add_library( alepha SHARED Console.cc ProgramOptions.cc string_algorithms.cc + fastRandom.cc word_wrap.cc Thread.cc delimited_list.cc diff --git a/fastRandom.cc b/fastRandom.cc new file mode 100644 index 0000000..8e01c24 --- /dev/null +++ b/fastRandom.cc @@ -0,0 +1,63 @@ +static_assert( __cplusplus > 2023'00 ); + +#include "fastRandom.h" + +#include + +#include + +namespace Alepha::Hydrogen ::detail:: fastRandom_m +{ + namespace + { + struct FastRandomState + { + boost::random::taus88 fastRandomState{ std::random_device{}() }; + std::uint32_t pool; + int remainingBits= 0; + + void + next() + { + pool= fastRandomState(); + remainingBits= 32; + } + + void + refresh() + { + if( remainingBits == 0 ) next(); + } + + std::uint32_t + getBit() + { + refresh(); + const std::uint32_t rv= pool & 1; + --remainingBits; + pool>>= 1; + return rv; + } + + std::uint32_t + get( int count ) + { + std::uint32_t rv= 0; + while( count-- ) + { + rv<<= 1; + rv|= getBit(); + } + return rv; + } + }; + + thread_local FastRandomState fastRandom; + } + + std::uint32_t + exports::fastRandomBits( const int numBits ) + { + return fastRandom.get( numBits ); + } +} diff --git a/fastRandom.h b/fastRandom.h new file mode 100644 index 0000000..3febd23 --- /dev/null +++ b/fastRandom.h @@ -0,0 +1,20 @@ +static_assert( __cplusplus > 2023'00 ); + +#pragma once + +#include + +#include + +namespace Alepha::Hydrogen ::detail:: fastRandom_m +{ + inline namespace exports + { + std::uint32_t fastRandomBits( int numBits ); + } +} + +namespace Alepha::Hydrogen::inline exports::inline fastRandom_m +{ + using namespace detail::fastRandom_m::exports; +}