blob: a5502d927c085c863cb0ab84cdd189f039913e10 [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
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
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
35std::vector<std::pair<absl::uint128, absl::uint128>>
36GetRandomClass128SampleUniformDivisor() {
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) {
42 absl::uint128 a =
43 absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
44 absl::uint128 b =
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
52void 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}
60BENCHMARK(BM_DivideClass128UniformDivisor);
61
62std::vector<std::pair<absl::uint128, uint64_t>>
63GetRandomClass128SampleSmallDivisor() {
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
77void 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}
85BENCHMARK(BM_DivideClass128SmallDivisor);
86
87std::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
100void 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}
108BENCHMARK(BM_MultiplyClass128);
109
110void 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}
118BENCHMARK(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.
124class 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
136std::vector<std::pair<unsigned __int128, unsigned __int128>>
137GetRandomIntrinsic128SampleUniformDivisor() {
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
152void 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}
160BENCHMARK(BM_DivideIntrinsic128UniformDivisor);
161
162std::vector<std::pair<unsigned __int128, uint64_t>>
163GetRandomIntrinsic128SampleSmallDivisor() {
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
177void 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}
185BENCHMARK(BM_DivideIntrinsic128SmallDivisor);
186
187std::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
199void 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}
207BENCHMARK(BM_MultiplyIntrinsic128);
208
209void 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}
217BENCHMARK(BM_AddIntrinsic128);
218
219#endif // ABSL_HAVE_INTRINSIC_INT128
220
221} // namespace