proxygen
TDigestBenchmark.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2012-present Facebook, Inc.
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 #include <folly/stats/TDigest.h>
17 
18 #include <algorithm>
19 #include <chrono>
20 #include <random>
21 
22 #include <folly/Benchmark.h>
24 
25 using folly::TDigest;
26 
27 void merge(unsigned int iters, size_t maxSize, size_t bufSize) {
28  TDigest digest(maxSize);
29 
30  std::vector<std::vector<double>> buffers;
31 
33  std::default_random_engine generator;
34  generator.seed(std::chrono::system_clock::now().time_since_epoch().count());
35 
36  std::lognormal_distribution<double> distribution(0.0, 1.0);
37 
38  for (size_t i = 0; i < iters; ++i) {
39  std::vector<double> buffer;
40  for (size_t j = 0; j < bufSize; ++j) {
41  buffer.push_back(distribution(generator));
42  }
43  std::sort(buffer.begin(), buffer.end());
44  buffers.push_back(std::move(buffer));
45  }
46  }
47 
48  for (const auto& buffer : buffers) {
49  digest = digest.merge(folly::presorted, buffer);
50  }
51 }
52 
53 void mergeDigests(unsigned int iters, size_t maxSize, size_t nDigests) {
54  std::vector<TDigest> digests;
56  TDigest digest(maxSize);
57  std::default_random_engine generator;
58  generator.seed(std::chrono::system_clock::now().time_since_epoch().count());
59 
60  std::lognormal_distribution<double> distribution(0.0, 1.0);
61 
62  for (size_t i = 0; i < nDigests; ++i) {
63  std::vector<double> buffer;
64  for (size_t j = 0; j < maxSize; ++j) {
65  buffer.push_back(distribution(generator));
66  }
67  digests.push_back(digest.merge(buffer));
68  }
69  }
70 
71  for (size_t i = 0; i < iters; ++i) {
72  TDigest::merge(digests);
73  }
74 }
75 
76 void estimateQuantile(unsigned int iters, size_t maxSize, double quantile) {
77  TDigest digest(maxSize);
78 
79  size_t bufSize = maxSize * 10;
81  std::vector<double> values;
82 
83  std::default_random_engine generator;
84  generator.seed(std::chrono::system_clock::now().time_since_epoch().count());
85 
86  std::lognormal_distribution<double> distribution(0.0, 1.0);
87 
88  for (size_t i = 0; i < 50000; ++i) {
89  values.push_back(distribution(generator));
90  }
91 
92  for (size_t i = 0; i < 50000 / bufSize; ++i) {
93  std::vector<double> buffer;
94  for (size_t j = 0; j < bufSize; ++j) {
95  buffer.push_back(values[i * bufSize + j]);
96  }
97  digest = digest.merge(buffer);
98  }
99  }
100 
101  for (size_t i = 0; i < iters; ++i) {
102  digest.estimateQuantile(quantile);
103  }
104 }
105 
106 BENCHMARK_NAMED_PARAM(merge, 100x1, 100, 100)
107 BENCHMARK_RELATIVE_NAMED_PARAM(merge, 100x5, 100, 500)
108 BENCHMARK_RELATIVE_NAMED_PARAM(merge, 100x10, 100, 1000)
109 BENCHMARK_RELATIVE_NAMED_PARAM(merge, 1000x1, 1000, 1000)
110 BENCHMARK_RELATIVE_NAMED_PARAM(merge, 1000x5, 1000, 5000)
111 BENCHMARK_RELATIVE_NAMED_PARAM(merge, 1000x10, 1000, 10000)
113 BENCHMARK_NAMED_PARAM(mergeDigests, 100x10, 100, 10)
118 BENCHMARK_NAMED_PARAM(estimateQuantile, 100x1_p001, 100, 0.001)
126 BENCHMARK_RELATIVE_NAMED_PARAM(estimateQuantile, 1000_p001, 1000, 0.001)
132 BENCHMARK_RELATIVE_NAMED_PARAM(estimateQuantile, 1000_p999, 1000, 0.999)
133 
134 /*
135  * ./tdigest_benchmark
136  * ============================================================================
137  * folly/stats/test/TDigestBenchmark.cpp relative time/iter iters/s
138  * ============================================================================
139  * merge(100x1) 2.30us 434.11K
140  * merge(100x5) 65.52% 3.52us 284.42K
141  * merge(100x10) 48.66% 4.73us 211.26K
142  * merge(1000x1) 9.37% 24.59us 40.67K
143  * merge(1000x5) 6.22% 37.03us 27.00K
144  * merge(1000x10) 4.60% 50.03us 19.99K
145  * ----------------------------------------------------------------------------
146  * mergeDigests(100x10) 21.50us 46.52K
147  * mergeDigests(100x30) 20.03% 107.34us 9.32K
148  * mergeDigests(100x60) 8.66% 248.29us 4.03K
149  * mergeDigests(1000x60) 0.78% 2.75ms 363.17
150  * ----------------------------------------------------------------------------
151  * estimateQuantile(100x1_p001) 7.34ns 136.21M
152  * estimateQuantile(100_p01) 68.10% 10.78ns 92.76M
153  * estimateQuantile(100_p25) 11.51% 63.77ns 15.68M
154  * estimateQuantile(100_p50) 7.98% 92.03ns 10.87M
155  * estimateQuantile(100_p75) 14.99% 48.98ns 20.42M
156  * estimateQuantile(100_p99) 77.57% 9.46ns 105.65M
157  * estimateQuantile(100_p999) 130.42% 5.63ns 177.64M
158  * ----------------------------------------------------------------------------
159  * estimateQuantile(1000_p001) 16.69% 43.99ns 22.73M
160  * estimateQuantile(1000_p01) 6.08% 120.74ns 8.28M
161  * estimateQuantile(1000_p25) 1.43% 513.01ns 1.95M
162  * estimateQuantile(1000_p50) 1.06% 693.28ns 1.44M
163  * estimateQuantile(1000_p75) 1.66% 442.20ns 2.26M
164  * estimateQuantile(1000_p99) 7.12% 103.08ns 9.70M
165  * estimateQuantile(1000_p999) 22.98% 31.94ns 31.30M
166  * ============================================================================
167  */
168 
169 int main(int argc, char* argv[]) {
170  gflags::ParseCommandLineFlags(&argc, &argv, true);
172  return 0;
173 }
std::vector< uint8_t > buffer(kBufferSize+16)
void estimateQuantile(unsigned int iters, size_t maxSize, double quantile)
int main(int argc, char *argv[])
std::default_random_engine generator
#define BENCHMARK_SUSPEND
Definition: Benchmark.h:576
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::chrono::steady_clock::time_point now()
#define BENCHMARK_RELATIVE_NAMED_PARAM(name, param_name,...)
Definition: Benchmark.h:531
double estimateQuantile(double q) const
Definition: TDigest.cpp:312
void runBenchmarks()
Definition: Benchmark.cpp:456
char ** argv
void mergeDigests(unsigned int iters, size_t maxSize, size_t nDigests)
#define BENCHMARK_NAMED_PARAM(name, param_name,...)
Definition: Benchmark.h:449
BENCHMARK_DRAW_LINE()
int * count
TDigest merge(presorted_t, Range< const double * > sortedValues) const
Definition: TDigest.cpp:126
constexpr presorted_t presorted
Definition: Utility.h:311
void merge(unsigned int iters, size_t maxSize, size_t bufSize)
std::vector< int > values(1'000)