1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
//
// 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()
{
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;
}
|