test_bench_random.cpp 5.6 KB

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