blob: eab1515c0ad8d08ae7af97523b4396766ea3bb97 [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001// Copyright 2017 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Austin Schuh36244a12019-09-21 17:52:38 -070015#include <algorithm>
16#include <cstdint>
Austin Schuhb4691e92020-12-31 12:37:18 -080017#include <limits>
Austin Schuh36244a12019-09-21 17:52:38 -070018#include <random>
19#include <vector>
20
21#include "benchmark/benchmark.h"
22#include "absl/base/config.h"
Austin Schuhb4691e92020-12-31 12:37:18 -080023#include "absl/numeric/int128.h"
Austin Schuh36244a12019-09-21 17:52:38 -070024
25namespace {
26
27constexpr size_t kSampleSize = 1000000;
28
29std::mt19937 MakeRandomEngine() {
30 std::random_device r;
31 std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()});
32 return std::mt19937(seed);
33}
34
Austin Schuhb4691e92020-12-31 12:37:18 -080035template <typename T,
36 typename H = typename std::conditional<
37 std::numeric_limits<T>::is_signed, int64_t, uint64_t>::type>
38std::vector<std::pair<T, T>> GetRandomClass128SampleUniformDivisor() {
39 std::vector<std::pair<T, T>> values;
Austin Schuh36244a12019-09-21 17:52:38 -070040 std::mt19937 random = MakeRandomEngine();
Austin Schuhb4691e92020-12-31 12:37:18 -080041 std::uniform_int_distribution<H> uniform_h;
Austin Schuh36244a12019-09-21 17:52:38 -070042 values.reserve(kSampleSize);
43 for (size_t i = 0; i < kSampleSize; ++i) {
Austin Schuhb4691e92020-12-31 12:37:18 -080044 T a{absl::MakeUint128(uniform_h(random), uniform_h(random))};
45 T b{absl::MakeUint128(uniform_h(random), uniform_h(random))};
46 values.emplace_back(std::max(a, b), std::max(T(2), std::min(a, b)));
Austin Schuh36244a12019-09-21 17:52:38 -070047 }
48 return values;
49}
50
Austin Schuhb4691e92020-12-31 12:37:18 -080051template <typename T>
Austin Schuh36244a12019-09-21 17:52:38 -070052void BM_DivideClass128UniformDivisor(benchmark::State& state) {
Austin Schuhb4691e92020-12-31 12:37:18 -080053 auto values = GetRandomClass128SampleUniformDivisor<T>();
Austin Schuh36244a12019-09-21 17:52:38 -070054 while (state.KeepRunningBatch(values.size())) {
55 for (const auto& pair : values) {
56 benchmark::DoNotOptimize(pair.first / pair.second);
57 }
58 }
59}
Austin Schuhb4691e92020-12-31 12:37:18 -080060BENCHMARK_TEMPLATE(BM_DivideClass128UniformDivisor, absl::uint128);
61BENCHMARK_TEMPLATE(BM_DivideClass128UniformDivisor, absl::int128);
Austin Schuh36244a12019-09-21 17:52:38 -070062
Austin Schuhb4691e92020-12-31 12:37:18 -080063template <typename T>
64void BM_RemainderClass128UniformDivisor(benchmark::State& state) {
65 auto values = GetRandomClass128SampleUniformDivisor<T>();
66 while (state.KeepRunningBatch(values.size())) {
67 for (const auto& pair : values) {
68 benchmark::DoNotOptimize(pair.first % pair.second);
69 }
70 }
71}
72BENCHMARK_TEMPLATE(BM_RemainderClass128UniformDivisor, absl::uint128);
73BENCHMARK_TEMPLATE(BM_RemainderClass128UniformDivisor, absl::int128);
74
75template <typename T,
76 typename H = typename std::conditional<
77 std::numeric_limits<T>::is_signed, int64_t, uint64_t>::type>
78std::vector<std::pair<T, H>> GetRandomClass128SampleSmallDivisor() {
79 std::vector<std::pair<T, H>> values;
Austin Schuh36244a12019-09-21 17:52:38 -070080 std::mt19937 random = MakeRandomEngine();
Austin Schuhb4691e92020-12-31 12:37:18 -080081 std::uniform_int_distribution<H> uniform_h;
Austin Schuh36244a12019-09-21 17:52:38 -070082 values.reserve(kSampleSize);
83 for (size_t i = 0; i < kSampleSize; ++i) {
Austin Schuhb4691e92020-12-31 12:37:18 -080084 T a{absl::MakeUint128(uniform_h(random), uniform_h(random))};
85 H b{std::max(H{2}, uniform_h(random))};
86 values.emplace_back(std::max(a, T(b)), b);
Austin Schuh36244a12019-09-21 17:52:38 -070087 }
88 return values;
89}
90
Austin Schuhb4691e92020-12-31 12:37:18 -080091template <typename T>
Austin Schuh36244a12019-09-21 17:52:38 -070092void BM_DivideClass128SmallDivisor(benchmark::State& state) {
Austin Schuhb4691e92020-12-31 12:37:18 -080093 auto values = GetRandomClass128SampleSmallDivisor<T>();
Austin Schuh36244a12019-09-21 17:52:38 -070094 while (state.KeepRunningBatch(values.size())) {
95 for (const auto& pair : values) {
96 benchmark::DoNotOptimize(pair.first / pair.second);
97 }
98 }
99}
Austin Schuhb4691e92020-12-31 12:37:18 -0800100BENCHMARK_TEMPLATE(BM_DivideClass128SmallDivisor, absl::uint128);
101BENCHMARK_TEMPLATE(BM_DivideClass128SmallDivisor, absl::int128);
102
103template <typename T>
104void BM_RemainderClass128SmallDivisor(benchmark::State& state) {
105 auto values = GetRandomClass128SampleSmallDivisor<T>();
106 while (state.KeepRunningBatch(values.size())) {
107 for (const auto& pair : values) {
108 benchmark::DoNotOptimize(pair.first % pair.second);
109 }
110 }
111}
112BENCHMARK_TEMPLATE(BM_RemainderClass128SmallDivisor, absl::uint128);
113BENCHMARK_TEMPLATE(BM_RemainderClass128SmallDivisor, absl::int128);
Austin Schuh36244a12019-09-21 17:52:38 -0700114
115std::vector<std::pair<absl::uint128, absl::uint128>> GetRandomClass128Sample() {
116 std::vector<std::pair<absl::uint128, absl::uint128>> values;
117 std::mt19937 random = MakeRandomEngine();
118 std::uniform_int_distribution<uint64_t> uniform_uint64;
119 values.reserve(kSampleSize);
120 for (size_t i = 0; i < kSampleSize; ++i) {
121 values.emplace_back(
122 absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)),
123 absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)));
124 }
125 return values;
126}
127
128void BM_MultiplyClass128(benchmark::State& state) {
129 auto values = GetRandomClass128Sample();
130 while (state.KeepRunningBatch(values.size())) {
131 for (const auto& pair : values) {
132 benchmark::DoNotOptimize(pair.first * pair.second);
133 }
134 }
135}
136BENCHMARK(BM_MultiplyClass128);
137
138void BM_AddClass128(benchmark::State& state) {
139 auto values = GetRandomClass128Sample();
140 while (state.KeepRunningBatch(values.size())) {
141 for (const auto& pair : values) {
142 benchmark::DoNotOptimize(pair.first + pair.second);
143 }
144 }
145}
146BENCHMARK(BM_AddClass128);
147
148#ifdef ABSL_HAVE_INTRINSIC_INT128
149
150// Some implementations of <random> do not support __int128 when it is
151// available, so we make our own uniform_int_distribution-like type.
Austin Schuhb4691e92020-12-31 12:37:18 -0800152template <typename T,
153 typename H = typename std::conditional<
154 std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
Austin Schuh36244a12019-09-21 17:52:38 -0700155class UniformIntDistribution128 {
156 public:
157 // NOLINTNEXTLINE: mimicking std::uniform_int_distribution API
Austin Schuhb4691e92020-12-31 12:37:18 -0800158 T operator()(std::mt19937& generator) {
159 return (static_cast<T>(dist64_(generator)) << 64) | dist64_(generator);
Austin Schuh36244a12019-09-21 17:52:38 -0700160 }
161
162 private:
Austin Schuhb4691e92020-12-31 12:37:18 -0800163 std::uniform_int_distribution<H> dist64_;
Austin Schuh36244a12019-09-21 17:52:38 -0700164};
165
Austin Schuhb4691e92020-12-31 12:37:18 -0800166template <typename T,
167 typename H = typename std::conditional<
168 std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
169std::vector<std::pair<T, T>> GetRandomIntrinsic128SampleUniformDivisor() {
170 std::vector<std::pair<T, T>> values;
Austin Schuh36244a12019-09-21 17:52:38 -0700171 std::mt19937 random = MakeRandomEngine();
Austin Schuhb4691e92020-12-31 12:37:18 -0800172 UniformIntDistribution128<T> uniform_128;
Austin Schuh36244a12019-09-21 17:52:38 -0700173 values.reserve(kSampleSize);
174 for (size_t i = 0; i < kSampleSize; ++i) {
Austin Schuhb4691e92020-12-31 12:37:18 -0800175 T a = uniform_128(random);
176 T b = uniform_128(random);
177 values.emplace_back(std::max(a, b),
178 std::max(static_cast<T>(2), std::min(a, b)));
Austin Schuh36244a12019-09-21 17:52:38 -0700179 }
180 return values;
181}
182
Austin Schuhb4691e92020-12-31 12:37:18 -0800183template <typename T>
Austin Schuh36244a12019-09-21 17:52:38 -0700184void BM_DivideIntrinsic128UniformDivisor(benchmark::State& state) {
Austin Schuhb4691e92020-12-31 12:37:18 -0800185 auto values = GetRandomIntrinsic128SampleUniformDivisor<T>();
Austin Schuh36244a12019-09-21 17:52:38 -0700186 while (state.KeepRunningBatch(values.size())) {
187 for (const auto& pair : values) {
188 benchmark::DoNotOptimize(pair.first / pair.second);
189 }
190 }
191}
Austin Schuhb4691e92020-12-31 12:37:18 -0800192BENCHMARK_TEMPLATE(BM_DivideIntrinsic128UniformDivisor, unsigned __int128);
193BENCHMARK_TEMPLATE(BM_DivideIntrinsic128UniformDivisor, __int128);
Austin Schuh36244a12019-09-21 17:52:38 -0700194
Austin Schuhb4691e92020-12-31 12:37:18 -0800195template <typename T>
196void BM_RemainderIntrinsic128UniformDivisor(benchmark::State& state) {
197 auto values = GetRandomIntrinsic128SampleUniformDivisor<T>();
198 while (state.KeepRunningBatch(values.size())) {
199 for (const auto& pair : values) {
200 benchmark::DoNotOptimize(pair.first % pair.second);
201 }
202 }
203}
204BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128UniformDivisor, unsigned __int128);
205BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128UniformDivisor, __int128);
206
207template <typename T,
208 typename H = typename std::conditional<
209 std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
210std::vector<std::pair<T, H>> GetRandomIntrinsic128SampleSmallDivisor() {
211 std::vector<std::pair<T, H>> values;
Austin Schuh36244a12019-09-21 17:52:38 -0700212 std::mt19937 random = MakeRandomEngine();
Austin Schuhb4691e92020-12-31 12:37:18 -0800213 UniformIntDistribution128<T> uniform_int128;
214 std::uniform_int_distribution<H> uniform_int64;
Austin Schuh36244a12019-09-21 17:52:38 -0700215 values.reserve(kSampleSize);
216 for (size_t i = 0; i < kSampleSize; ++i) {
Austin Schuhb4691e92020-12-31 12:37:18 -0800217 T a = uniform_int128(random);
218 H b = std::max(H{2}, uniform_int64(random));
219 values.emplace_back(std::max(a, static_cast<T>(b)), b);
Austin Schuh36244a12019-09-21 17:52:38 -0700220 }
221 return values;
222}
223
Austin Schuhb4691e92020-12-31 12:37:18 -0800224template <typename T>
Austin Schuh36244a12019-09-21 17:52:38 -0700225void BM_DivideIntrinsic128SmallDivisor(benchmark::State& state) {
Austin Schuhb4691e92020-12-31 12:37:18 -0800226 auto values = GetRandomIntrinsic128SampleSmallDivisor<T>();
Austin Schuh36244a12019-09-21 17:52:38 -0700227 while (state.KeepRunningBatch(values.size())) {
228 for (const auto& pair : values) {
229 benchmark::DoNotOptimize(pair.first / pair.second);
230 }
231 }
232}
Austin Schuhb4691e92020-12-31 12:37:18 -0800233BENCHMARK_TEMPLATE(BM_DivideIntrinsic128SmallDivisor, unsigned __int128);
234BENCHMARK_TEMPLATE(BM_DivideIntrinsic128SmallDivisor, __int128);
235
236template <typename T>
237void BM_RemainderIntrinsic128SmallDivisor(benchmark::State& state) {
238 auto values = GetRandomIntrinsic128SampleSmallDivisor<T>();
239 while (state.KeepRunningBatch(values.size())) {
240 for (const auto& pair : values) {
241 benchmark::DoNotOptimize(pair.first % pair.second);
242 }
243 }
244}
245BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128SmallDivisor, unsigned __int128);
246BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128SmallDivisor, __int128);
Austin Schuh36244a12019-09-21 17:52:38 -0700247
248std::vector<std::pair<unsigned __int128, unsigned __int128>>
249 GetRandomIntrinsic128Sample() {
250 std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
251 std::mt19937 random = MakeRandomEngine();
Austin Schuhb4691e92020-12-31 12:37:18 -0800252 UniformIntDistribution128<unsigned __int128> uniform_uint128;
Austin Schuh36244a12019-09-21 17:52:38 -0700253 values.reserve(kSampleSize);
254 for (size_t i = 0; i < kSampleSize; ++i) {
255 values.emplace_back(uniform_uint128(random), uniform_uint128(random));
256 }
257 return values;
258}
259
260void BM_MultiplyIntrinsic128(benchmark::State& state) {
261 auto values = GetRandomIntrinsic128Sample();
262 while (state.KeepRunningBatch(values.size())) {
263 for (const auto& pair : values) {
264 benchmark::DoNotOptimize(pair.first * pair.second);
265 }
266 }
267}
268BENCHMARK(BM_MultiplyIntrinsic128);
269
270void BM_AddIntrinsic128(benchmark::State& state) {
271 auto values = GetRandomIntrinsic128Sample();
272 while (state.KeepRunningBatch(values.size())) {
273 for (const auto& pair : values) {
274 benchmark::DoNotOptimize(pair.first + pair.second);
275 }
276 }
277}
278BENCHMARK(BM_AddIntrinsic128);
279
280#endif // ABSL_HAVE_INTRINSIC_INT128
281
282} // namespace