123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- //
- // Copyright (c) 2017, 2018 James E. King III
- //
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE_1_0.txt or copy at
- // https://www.boost.org/LICENSE_1_0.txt)
- //
- // benchmark for random_generators in different forms
- //
- #include <boost/core/ignore_unused.hpp>
- #include <boost/timer/timer.hpp>
- #include <boost/predef/os.h>
- #include <boost/uuid/random_generator.hpp>
- #include <boost/uuid/uuid.hpp>
- #include <boost/uuid/uuid_io.hpp>
- #include <iostream>
- #include <limits>
- #if !defined(BOOST_NO_STRESS_TEST)
- // must be a Valgrind, UBsan, or other stressful job
- #define AVG_LOOPS 1
- #define GEN_LOOPS 10
- #define REUSE_LOOPS 100
- #else
- #define AVG_LOOPS 10
- #define GEN_LOOPS 10000
- #define REUSE_LOOPS 1000000
- #endif
- template<class Generator>
- void auto_timed_generator_ctordtor(size_t count)
- {
- boost::timer::auto_cpu_timer t;
- for (size_t i = 0; i < count; ++i)
- {
- Generator gen;
- boost::ignore_unused(gen);
- }
- }
- template<class Generator>
- void auto_timed_generator_novel(size_t count)
- {
- boost::timer::auto_cpu_timer t;
- for (size_t i = 0; i < count; ++i)
- {
- Generator gen;
- boost::uuids::uuid u = gen();
- boost::ignore_unused(u);
- }
- }
- template<class Generator>
- void auto_timed_generator_reuse(size_t count)
- {
- Generator gen;
- {
- boost::timer::auto_cpu_timer t;
- for (size_t i = 0; i < count; ++i)
- {
- boost::uuids::uuid u = gen();
- boost::ignore_unused(u);
- }
- }
- }
- template<class Generator>
- boost::timer::cpu_times timed_generator(size_t count)
- {
- boost::timer::cpu_timer t;
- Generator gen;
- for (size_t i = 0; i < count; ++i)
- {
- boost::uuids::uuid u = gen();
- boost::ignore_unused(u);
- }
- return t.elapsed();
- }
- int main(int, char*[])
- {
- std::cout << "Operating system entropy provider: "
- << boost::uuids::detail::random_provider().name() << std::endl;
- #if !defined(BOOST_NO_STRESS_TEST)
- //
- // Determine the cutoff point where it is more wall-clock efficient to
- // use the bulk generator over the standard one.
- //
- std::cout << "Calculating the number of operator() calls where random_generator" << std::endl;
- std::cout << "is more efficient than random_generator_mt19937..." << std::endl;
- std::cout << "at ";
- bool asterisk = false;
- size_t minn = (std::numeric_limits<size_t>::max)();
- size_t summ = 0;
- size_t maxx = 0;
- for (size_t i = 0; i < AVG_LOOPS + 1; ++i) // the first loop is thrown away, see below
- {
- size_t answer = 0;
- for (size_t count = 1; !answer; ++count)
- {
- boost::timer::cpu_times standard = timed_generator<boost::uuids::random_generator>(count);
- boost::timer::cpu_times pseudo = timed_generator<boost::uuids::random_generator_mt19937>(count);
- if (standard.wall > pseudo.wall)
- {
- answer = count;
- }
- else if (count >= 999)
- {
- std::cout << "*";
- asterisk = true;
- answer = count;
- }
- }
- // throw away the first answer in case it contains time related to loading
- // or initializing the crypto library being used
- if (i > 0)
- {
- if (minn > answer) minn = answer;
- if (maxx < answer) maxx = answer;
- summ += answer;
- std::cout << answer << " " << std::flush;
- }
- }
- if (asterisk)
- {
- std::cout << "* = limited to 999" << std::endl;
- }
- std::cout << "calls to operator()" << std::endl;
- size_t answer = summ / AVG_LOOPS;
- std::cout << "For this platform, random_generator_mt19937 outperforms "
- << "random_generator after " << answer << " generations (min " << minn << " / max " << maxx << ")."
- << std::endl;
- std::cout << std::endl;
- #endif
- //
- // Measure ctor/dtor of both
- //
- std::cout << "Construction/destruction time for random_generator "
- << "(" << GEN_LOOPS << " iterations): " << std::endl;
- auto_timed_generator_ctordtor<boost::uuids::random_generator>(GEN_LOOPS);
- std::cout << std::endl;
- std::cout << "Construction/destruction time for random_generator_mt19937 "
- << "(" << GEN_LOOPS << " iterations): " << std::endl;
- auto_timed_generator_ctordtor<boost::uuids::random_generator_mt19937>(GEN_LOOPS);
- std::cout << std::endl;
- //
- // Two common use cases:
- //
- // Use an OS provided RNG which has no seed code but is slower to reuse
- // Use a PRNG which is expensive to seed once but fast to reuse
- //
- // Measure the default selections of the library
- //
- std::cout << "Benchmark boost::uuids::random_generator "
- << "(reused for " << REUSE_LOOPS << " loops):" << std::endl;
- auto_timed_generator_reuse<boost::uuids::random_generator>(REUSE_LOOPS);
- std::cout << std::endl;
- std::cout << "Benchmark boost::uuids::random_generator_mt19937 "
- << "(reused for " << REUSE_LOOPS << " loops):" << std::endl;
- auto_timed_generator_reuse<boost::uuids::random_generator_mt19937>(REUSE_LOOPS);
- std::cout << std::endl;
- std::cout << "Benchmark boost::uuids::random_generator "
- << "(new generator each loop for " << GEN_LOOPS << " loops):" << std::endl;
- auto_timed_generator_novel<boost::uuids::random_generator>(GEN_LOOPS);
- std::cout << std::endl;
- std::cout << "Benchmark boost::uuids::random_generator_mt19937 "
- << "(new generator each loop for " << GEN_LOOPS << " loops):" << std::endl;
- auto_timed_generator_novel<boost::uuids::random_generator_mt19937>(GEN_LOOPS);
- std::cout << std::endl;
- return 0;
- }
|