• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2017, 2018 James E. King III
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 //   https://www.boost.org/LICENSE_1_0.txt)
7 //
8 // benchmark for random_generators in different forms
9 //
10 
11 #include <boost/core/ignore_unused.hpp>
12 #include <boost/timer/timer.hpp>
13 #include <boost/predef/os.h>
14 #include <boost/uuid/random_generator.hpp>
15 #include <boost/uuid/uuid.hpp>
16 #include <boost/uuid/uuid_io.hpp>
17 #include <iostream>
18 #include <limits>
19 
20 #if !defined(BOOST_NO_STRESS_TEST)
21 // must be a Valgrind, UBsan, or other stressful job
22 #define AVG_LOOPS 1
23 #define GEN_LOOPS 10
24 #define REUSE_LOOPS 100
25 #else
26 #define AVG_LOOPS 10
27 #define GEN_LOOPS 10000
28 #define REUSE_LOOPS 1000000
29 #endif
30 
31 template<class Generator>
auto_timed_generator_ctordtor(size_t count)32 void auto_timed_generator_ctordtor(size_t count)
33 {
34     boost::timer::auto_cpu_timer t;
35     for (size_t i = 0; i < count; ++i)
36     {
37         Generator gen;
38         boost::ignore_unused(gen);
39     }
40 }
41 
42 template<class Generator>
auto_timed_generator_novel(size_t count)43 void auto_timed_generator_novel(size_t count)
44 {
45     boost::timer::auto_cpu_timer t;
46     for (size_t i = 0; i < count; ++i)
47     {
48         Generator gen;
49         boost::uuids::uuid u = gen();
50         boost::ignore_unused(u);
51     }
52 }
53 
54 template<class Generator>
auto_timed_generator_reuse(size_t count)55 void auto_timed_generator_reuse(size_t count)
56 {
57     Generator gen;
58     {
59         boost::timer::auto_cpu_timer t;
60         for (size_t i = 0; i < count; ++i)
61         {
62             boost::uuids::uuid u = gen();
63             boost::ignore_unused(u);
64         }
65     }
66 }
67 
68 template<class Generator>
timed_generator(size_t count)69 boost::timer::cpu_times timed_generator(size_t count)
70 {
71     boost::timer::cpu_timer t;
72     Generator gen;
73     for (size_t i = 0; i < count; ++i)
74     {
75         boost::uuids::uuid u = gen();
76         boost::ignore_unused(u);
77     }
78     return t.elapsed();
79 }
80 
main(int,char * [])81 int main(int, char*[])
82 {
83     std::cout << "Operating system entropy provider: "
84               << boost::uuids::detail::random_provider().name() << std::endl;
85 
86 #if !defined(BOOST_NO_STRESS_TEST)
87 
88     //
89     // Determine the cutoff point where it is more wall-clock efficient to
90     // use the bulk generator over the standard one.
91     //
92 
93     std::cout << "Calculating the number of operator() calls where random_generator" << std::endl;
94     std::cout << "is more efficient than random_generator_mt19937..." << std::endl;
95     std::cout << "at ";
96     bool asterisk = false;
97     size_t minn = (std::numeric_limits<size_t>::max)();
98     size_t summ = 0;
99     size_t maxx = 0;
100     for (size_t i = 0; i < AVG_LOOPS + 1; ++i)  // the first loop is thrown away, see below
101     {
102         size_t answer = 0;
103         for (size_t count = 1; !answer; ++count)
104         {
105             boost::timer::cpu_times standard = timed_generator<boost::uuids::random_generator>(count);
106             boost::timer::cpu_times pseudo = timed_generator<boost::uuids::random_generator_mt19937>(count);
107             if (standard.wall > pseudo.wall)
108             {
109                 answer = count;
110             }
111             else if (count >= 999)
112             {
113                 std::cout << "*";
114                 asterisk = true;
115                 answer = count;
116             }
117         }
118 
119         // throw away the first answer in case it contains time related to loading
120         // or initializing the crypto library being used
121         if (i > 0)
122         {
123             if (minn > answer) minn = answer;
124             if (maxx < answer) maxx = answer;
125             summ += answer;
126             std::cout << answer << " " << std::flush;
127         }
128     }
129     if (asterisk)
130     {
131         std::cout << "* = limited to 999" << std::endl;
132     }
133     std::cout << "calls to operator()" << std::endl;
134     size_t answer = summ / AVG_LOOPS;
135     std::cout << "For this platform, random_generator_mt19937 outperforms "
136         << "random_generator after " << answer << " generations (min " << minn << " / max " << maxx << ")."
137         << std::endl;
138     std::cout << std::endl;
139 
140 #endif
141 
142     //
143     // Measure ctor/dtor of both
144     //
145     std::cout << "Construction/destruction time for random_generator "
146         << "(" << GEN_LOOPS << " iterations): " << std::endl;
147     auto_timed_generator_ctordtor<boost::uuids::random_generator>(GEN_LOOPS);
148     std::cout << std::endl;
149 
150     std::cout << "Construction/destruction time for random_generator_mt19937 "
151         << "(" << GEN_LOOPS << " iterations): " << std::endl;
152     auto_timed_generator_ctordtor<boost::uuids::random_generator_mt19937>(GEN_LOOPS);
153     std::cout << std::endl;
154 
155     //
156     // Two common use cases:
157     //
158     // Use an OS provided RNG which has no seed code but is slower to reuse
159     // Use a PRNG which is expensive to seed once but fast to reuse
160     //
161     // Measure the default selections of the library
162     //
163 
164     std::cout << "Benchmark boost::uuids::random_generator "
165               << "(reused for " << REUSE_LOOPS << " loops):" << std::endl;
166     auto_timed_generator_reuse<boost::uuids::random_generator>(REUSE_LOOPS);
167     std::cout << std::endl;
168 
169     std::cout << "Benchmark boost::uuids::random_generator_mt19937 "
170         << "(reused for " << REUSE_LOOPS << " loops):" << std::endl;
171     auto_timed_generator_reuse<boost::uuids::random_generator_mt19937>(REUSE_LOOPS);
172     std::cout << std::endl;
173 
174     std::cout << "Benchmark boost::uuids::random_generator "
175               << "(new generator each loop for " << GEN_LOOPS << " loops):" << std::endl;
176     auto_timed_generator_novel<boost::uuids::random_generator>(GEN_LOOPS);
177     std::cout << std::endl;
178 
179     std::cout << "Benchmark boost::uuids::random_generator_mt19937 "
180               << "(new generator each loop for " << GEN_LOOPS << " loops):" << std::endl;
181     auto_timed_generator_novel<boost::uuids::random_generator_mt19937>(GEN_LOOPS);
182     std::cout << std::endl;
183 
184     return 0;
185 }
186 
187 
188