1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <thrift/lib/cpp/test/loadgen/RNG.h>
18 
19 #include <boost/random/lognormal_distribution.hpp>
20 #include <boost/random/uniform_int.hpp>
21 #include <boost/random/uniform_real.hpp>
22 #include <boost/random/variate_generator.hpp>
23 
24 #include <folly/ThreadLocal.h>
25 
26 namespace apache {
27 namespace thrift {
28 namespace loadgen {
29 
30 const bool RNG::has_fixed_range;
31 
32 namespace {
33 
34 // We use seedRNG just to choose seeds for new thread-local RNGs
35 boost::mt19937 seedRNG;
36 
37 struct RNGImpl {
RNGImplapache::thrift::loadgen::__anon23f435e90111::RNGImpl38   RNGImpl() : rng(), rngWrapper(&rng) {
39     // Pick a value from seedRNG to seed this new rng
40     rng.seed(seedRNG());
41   }
42 
43   /// The actual RNG
44   boost::mt19937 rng;
45 
46   /**
47    * An RNG wrapper object.
48    *
49    * We store a thread local RNG rather than always creating RNG objects onthe
50    * fly so that RNG::getRNG() can return a reference rather than a new object.
51    * Many of the boost random APIs require a reference, so this allows callers
52    * to pass the result of RNG::getRNG() directly to boost, rather than having
53    * to create a local RNG object on their stack.
54    */
55   RNG rngWrapper;
56 };
57 
58 folly::ThreadLocal<RNGImpl> threadLocalRNG;
59 
60 } // unnamed namespace
61 
getRNG()62 RNG& RNG::getRNG() {
63   return threadLocalRNG.get()->rngWrapper;
64 }
65 
setGlobalSeed(result_type s)66 void RNG::setGlobalSeed(result_type s) {
67   seedRNG.seed(s);
68 }
69 
getU32()70 uint32_t RNG::getU32() {
71   boost::uniform_int<uint32_t> distribution;
72   return distribution(getRNG());
73 }
74 
getU32(uint32_t max)75 uint32_t RNG::getU32(uint32_t max) {
76   boost::uniform_int<uint32_t> distribution(0, max);
77   return distribution(getRNG());
78 }
79 
getU32(uint32_t min,uint32_t max)80 uint32_t RNG::getU32(uint32_t min, uint32_t max) {
81   boost::uniform_int<uint32_t> distribution(min, max);
82   return distribution(getRNG());
83 }
84 
getReal()85 double RNG::getReal() {
86   boost::uniform_real<double> distribution;
87   return distribution(getRNG());
88 }
89 
getReal(double min,double max)90 double RNG::getReal(double min, double max) {
91   boost::uniform_real<double> distribution(min, max);
92   return distribution(getRNG());
93 }
94 
getLogNormal(double mean,double sigma)95 double RNG::getLogNormal(double mean, double sigma) {
96   // If the sigma is negative, default to half of the mean.
97   // This produces fairly nicely shaped distributions
98   if (sigma < 0) {
99     sigma = mean / 2;
100   }
101   boost::lognormal_distribution<double> dist(mean, sigma);
102   boost::variate_generator<RNG, boost::lognormal_distribution<double>> gen(
103       getRNG(), dist);
104   return gen();
105 }
106 
107 } // namespace loadgen
108 } // namespace thrift
109 } // namespace apache
110