int128_benchmark.cc
Go to the documentation of this file.
1 // 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 
15 #include "absl/numeric/int128.h"
16 
17 #include <algorithm>
18 #include <cstdint>
19 #include <random>
20 #include <vector>
21 
22 #include "benchmark/benchmark.h"
23 #include "absl/base/config.h"
24 
25 namespace {
26 
27 constexpr size_t kSampleSize = 1000000;
28 
29 std::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 
35 std::vector<std::pair<absl::uint128, absl::uint128>>
36 GetRandomClass128SampleUniformDivisor() {
37  std::vector<std::pair<absl::uint128, absl::uint128>> values;
38  std::mt19937 random = MakeRandomEngine();
39  std::uniform_int_distribution<uint64_t> uniform_uint64;
40  values.reserve(kSampleSize);
41  for (size_t i = 0; i < kSampleSize; ++i) {
43  absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
45  absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
46  values.emplace_back(std::max(a, b),
47  std::max(absl::uint128(2), std::min(a, b)));
48  }
49  return values;
50 }
51 
52 void BM_DivideClass128UniformDivisor(benchmark::State& state) {
53  auto values = GetRandomClass128SampleUniformDivisor();
54  while (state.KeepRunningBatch(values.size())) {
55  for (const auto& pair : values) {
56  benchmark::DoNotOptimize(pair.first / pair.second);
57  }
58  }
59 }
60 BENCHMARK(BM_DivideClass128UniformDivisor);
61 
62 std::vector<std::pair<absl::uint128, uint64_t>>
63 GetRandomClass128SampleSmallDivisor() {
64  std::vector<std::pair<absl::uint128, uint64_t>> values;
65  std::mt19937 random = MakeRandomEngine();
66  std::uniform_int_distribution<uint64_t> uniform_uint64;
67  values.reserve(kSampleSize);
68  for (size_t i = 0; i < kSampleSize; ++i) {
69  absl::uint128 a =
70  absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
71  uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
72  values.emplace_back(std::max(a, absl::uint128(b)), b);
73  }
74  return values;
75 }
76 
77 void BM_DivideClass128SmallDivisor(benchmark::State& state) {
78  auto values = GetRandomClass128SampleSmallDivisor();
79  while (state.KeepRunningBatch(values.size())) {
80  for (const auto& pair : values) {
81  benchmark::DoNotOptimize(pair.first / pair.second);
82  }
83  }
84 }
85 BENCHMARK(BM_DivideClass128SmallDivisor);
86 
87 std::vector<std::pair<absl::uint128, absl::uint128>> GetRandomClass128Sample() {
88  std::vector<std::pair<absl::uint128, absl::uint128>> values;
89  std::mt19937 random = MakeRandomEngine();
90  std::uniform_int_distribution<uint64_t> uniform_uint64;
91  values.reserve(kSampleSize);
92  for (size_t i = 0; i < kSampleSize; ++i) {
93  values.emplace_back(
94  absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)),
95  absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)));
96  }
97  return values;
98 }
99 
100 void BM_MultiplyClass128(benchmark::State& state) {
101  auto values = GetRandomClass128Sample();
102  while (state.KeepRunningBatch(values.size())) {
103  for (const auto& pair : values) {
104  benchmark::DoNotOptimize(pair.first * pair.second);
105  }
106  }
107 }
108 BENCHMARK(BM_MultiplyClass128);
109 
110 void BM_AddClass128(benchmark::State& state) {
111  auto values = GetRandomClass128Sample();
112  while (state.KeepRunningBatch(values.size())) {
113  for (const auto& pair : values) {
114  benchmark::DoNotOptimize(pair.first + pair.second);
115  }
116  }
117 }
118 BENCHMARK(BM_AddClass128);
119 
120 #ifdef ABSL_HAVE_INTRINSIC_INT128
121 
122 // Some implementations of <random> do not support __int128 when it is
123 // available, so we make our own uniform_int_distribution-like type.
124 class UniformIntDistribution128 {
125  public:
126  // NOLINTNEXTLINE: mimicking std::uniform_int_distribution API
127  unsigned __int128 operator()(std::mt19937& generator) {
128  return (static_cast<unsigned __int128>(dist64_(generator)) << 64) |
129  dist64_(generator);
130  }
131 
132  private:
133  std::uniform_int_distribution<uint64_t> dist64_;
134 };
135 
136 std::vector<std::pair<unsigned __int128, unsigned __int128>>
137 GetRandomIntrinsic128SampleUniformDivisor() {
138  std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
139  std::mt19937 random = MakeRandomEngine();
140  UniformIntDistribution128 uniform_uint128;
141  values.reserve(kSampleSize);
142  for (size_t i = 0; i < kSampleSize; ++i) {
143  unsigned __int128 a = uniform_uint128(random);
144  unsigned __int128 b = uniform_uint128(random);
145  values.emplace_back(
146  std::max(a, b),
147  std::max(static_cast<unsigned __int128>(2), std::min(a, b)));
148  }
149  return values;
150 }
151 
152 void BM_DivideIntrinsic128UniformDivisor(benchmark::State& state) {
153  auto values = GetRandomIntrinsic128SampleUniformDivisor();
154  while (state.KeepRunningBatch(values.size())) {
155  for (const auto& pair : values) {
156  benchmark::DoNotOptimize(pair.first / pair.second);
157  }
158  }
159 }
160 BENCHMARK(BM_DivideIntrinsic128UniformDivisor);
161 
162 std::vector<std::pair<unsigned __int128, uint64_t>>
163 GetRandomIntrinsic128SampleSmallDivisor() {
164  std::vector<std::pair<unsigned __int128, uint64_t>> values;
165  std::mt19937 random = MakeRandomEngine();
166  UniformIntDistribution128 uniform_uint128;
167  std::uniform_int_distribution<uint64_t> uniform_uint64;
168  values.reserve(kSampleSize);
169  for (size_t i = 0; i < kSampleSize; ++i) {
170  unsigned __int128 a = uniform_uint128(random);
171  uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
172  values.emplace_back(std::max(a, static_cast<unsigned __int128>(b)), b);
173  }
174  return values;
175 }
176 
177 void BM_DivideIntrinsic128SmallDivisor(benchmark::State& state) {
178  auto values = GetRandomIntrinsic128SampleSmallDivisor();
179  while (state.KeepRunningBatch(values.size())) {
180  for (const auto& pair : values) {
181  benchmark::DoNotOptimize(pair.first / pair.second);
182  }
183  }
184 }
185 BENCHMARK(BM_DivideIntrinsic128SmallDivisor);
186 
187 std::vector<std::pair<unsigned __int128, unsigned __int128>>
188  GetRandomIntrinsic128Sample() {
189  std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
190  std::mt19937 random = MakeRandomEngine();
191  UniformIntDistribution128 uniform_uint128;
192  values.reserve(kSampleSize);
193  for (size_t i = 0; i < kSampleSize; ++i) {
194  values.emplace_back(uniform_uint128(random), uniform_uint128(random));
195  }
196  return values;
197 }
198 
199 void BM_MultiplyIntrinsic128(benchmark::State& state) {
200  auto values = GetRandomIntrinsic128Sample();
201  while (state.KeepRunningBatch(values.size())) {
202  for (const auto& pair : values) {
203  benchmark::DoNotOptimize(pair.first * pair.second);
204  }
205  }
206 }
207 BENCHMARK(BM_MultiplyIntrinsic128);
208 
209 void BM_AddIntrinsic128(benchmark::State& state) {
210  auto values = GetRandomIntrinsic128Sample();
211  while (state.KeepRunningBatch(values.size())) {
212  for (const auto& pair : values) {
213  benchmark::DoNotOptimize(pair.first + pair.second);
214  }
215  }
216 }
217 BENCHMARK(BM_AddIntrinsic128);
218 
219 #endif // ABSL_HAVE_INTRINSIC_INT128
220 
221 } // namespace
std::pair< std::string, std::string > pair
constexpr uint128 MakeUint128(uint64_t high, uint64_t low)
Definition: int128.h:301
uint64_t b
Definition: layout_test.cc:50


abseil_cpp
Author(s):
autogenerated on Mon Feb 28 2022 21:31:19