Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "absl/numeric/int128.h"
00016
00017 #include <algorithm>
00018 #include <cstdint>
00019 #include <random>
00020 #include <vector>
00021
00022 #include "benchmark/benchmark.h"
00023 #include "absl/base/config.h"
00024
00025 namespace {
00026
00027 constexpr size_t kSampleSize = 1000000;
00028
00029 std::mt19937 MakeRandomEngine() {
00030 std::random_device r;
00031 std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()});
00032 return std::mt19937(seed);
00033 }
00034
00035 std::vector<std::pair<absl::uint128, absl::uint128>>
00036 GetRandomClass128SampleUniformDivisor() {
00037 std::vector<std::pair<absl::uint128, absl::uint128>> values;
00038 std::mt19937 random = MakeRandomEngine();
00039 std::uniform_int_distribution<uint64_t> uniform_uint64;
00040 values.reserve(kSampleSize);
00041 for (size_t i = 0; i < kSampleSize; ++i) {
00042 absl::uint128 a =
00043 absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
00044 absl::uint128 b =
00045 absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
00046 values.emplace_back(std::max(a, b),
00047 std::max(absl::uint128(2), std::min(a, b)));
00048 }
00049 return values;
00050 }
00051
00052 void BM_DivideClass128UniformDivisor(benchmark::State& state) {
00053 auto values = GetRandomClass128SampleUniformDivisor();
00054 while (state.KeepRunningBatch(values.size())) {
00055 for (const auto& pair : values) {
00056 benchmark::DoNotOptimize(pair.first / pair.second);
00057 }
00058 }
00059 }
00060 BENCHMARK(BM_DivideClass128UniformDivisor);
00061
00062 std::vector<std::pair<absl::uint128, uint64_t>>
00063 GetRandomClass128SampleSmallDivisor() {
00064 std::vector<std::pair<absl::uint128, uint64_t>> values;
00065 std::mt19937 random = MakeRandomEngine();
00066 std::uniform_int_distribution<uint64_t> uniform_uint64;
00067 values.reserve(kSampleSize);
00068 for (size_t i = 0; i < kSampleSize; ++i) {
00069 absl::uint128 a =
00070 absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
00071 uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
00072 values.emplace_back(std::max(a, absl::uint128(b)), b);
00073 }
00074 return values;
00075 }
00076
00077 void BM_DivideClass128SmallDivisor(benchmark::State& state) {
00078 auto values = GetRandomClass128SampleSmallDivisor();
00079 while (state.KeepRunningBatch(values.size())) {
00080 for (const auto& pair : values) {
00081 benchmark::DoNotOptimize(pair.first / pair.second);
00082 }
00083 }
00084 }
00085 BENCHMARK(BM_DivideClass128SmallDivisor);
00086
00087 std::vector<std::pair<absl::uint128, absl::uint128>> GetRandomClass128Sample() {
00088 std::vector<std::pair<absl::uint128, absl::uint128>> values;
00089 std::mt19937 random = MakeRandomEngine();
00090 std::uniform_int_distribution<uint64_t> uniform_uint64;
00091 values.reserve(kSampleSize);
00092 for (size_t i = 0; i < kSampleSize; ++i) {
00093 values.emplace_back(
00094 absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)),
00095 absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)));
00096 }
00097 return values;
00098 }
00099
00100 void BM_MultiplyClass128(benchmark::State& state) {
00101 auto values = GetRandomClass128Sample();
00102 while (state.KeepRunningBatch(values.size())) {
00103 for (const auto& pair : values) {
00104 benchmark::DoNotOptimize(pair.first * pair.second);
00105 }
00106 }
00107 }
00108 BENCHMARK(BM_MultiplyClass128);
00109
00110 void BM_AddClass128(benchmark::State& state) {
00111 auto values = GetRandomClass128Sample();
00112 while (state.KeepRunningBatch(values.size())) {
00113 for (const auto& pair : values) {
00114 benchmark::DoNotOptimize(pair.first + pair.second);
00115 }
00116 }
00117 }
00118 BENCHMARK(BM_AddClass128);
00119
00120 #ifdef ABSL_HAVE_INTRINSIC_INT128
00121
00122
00123
00124 class UniformIntDistribution128 {
00125 public:
00126
00127 unsigned __int128 operator()(std::mt19937& generator) {
00128 return (static_cast<unsigned __int128>(dist64_(generator)) << 64) |
00129 dist64_(generator);
00130 }
00131
00132 private:
00133 std::uniform_int_distribution<uint64_t> dist64_;
00134 };
00135
00136 std::vector<std::pair<unsigned __int128, unsigned __int128>>
00137 GetRandomIntrinsic128SampleUniformDivisor() {
00138 std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
00139 std::mt19937 random = MakeRandomEngine();
00140 UniformIntDistribution128 uniform_uint128;
00141 values.reserve(kSampleSize);
00142 for (size_t i = 0; i < kSampleSize; ++i) {
00143 unsigned __int128 a = uniform_uint128(random);
00144 unsigned __int128 b = uniform_uint128(random);
00145 values.emplace_back(
00146 std::max(a, b),
00147 std::max(static_cast<unsigned __int128>(2), std::min(a, b)));
00148 }
00149 return values;
00150 }
00151
00152 void BM_DivideIntrinsic128UniformDivisor(benchmark::State& state) {
00153 auto values = GetRandomIntrinsic128SampleUniformDivisor();
00154 while (state.KeepRunningBatch(values.size())) {
00155 for (const auto& pair : values) {
00156 benchmark::DoNotOptimize(pair.first / pair.second);
00157 }
00158 }
00159 }
00160 BENCHMARK(BM_DivideIntrinsic128UniformDivisor);
00161
00162 std::vector<std::pair<unsigned __int128, uint64_t>>
00163 GetRandomIntrinsic128SampleSmallDivisor() {
00164 std::vector<std::pair<unsigned __int128, uint64_t>> values;
00165 std::mt19937 random = MakeRandomEngine();
00166 UniformIntDistribution128 uniform_uint128;
00167 std::uniform_int_distribution<uint64_t> uniform_uint64;
00168 values.reserve(kSampleSize);
00169 for (size_t i = 0; i < kSampleSize; ++i) {
00170 unsigned __int128 a = uniform_uint128(random);
00171 uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
00172 values.emplace_back(std::max(a, static_cast<unsigned __int128>(b)), b);
00173 }
00174 return values;
00175 }
00176
00177 void BM_DivideIntrinsic128SmallDivisor(benchmark::State& state) {
00178 auto values = GetRandomIntrinsic128SampleSmallDivisor();
00179 while (state.KeepRunningBatch(values.size())) {
00180 for (const auto& pair : values) {
00181 benchmark::DoNotOptimize(pair.first / pair.second);
00182 }
00183 }
00184 }
00185 BENCHMARK(BM_DivideIntrinsic128SmallDivisor);
00186
00187 std::vector<std::pair<unsigned __int128, unsigned __int128>>
00188 GetRandomIntrinsic128Sample() {
00189 std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
00190 std::mt19937 random = MakeRandomEngine();
00191 UniformIntDistribution128 uniform_uint128;
00192 values.reserve(kSampleSize);
00193 for (size_t i = 0; i < kSampleSize; ++i) {
00194 values.emplace_back(uniform_uint128(random), uniform_uint128(random));
00195 }
00196 return values;
00197 }
00198
00199 void BM_MultiplyIntrinsic128(benchmark::State& state) {
00200 auto values = GetRandomIntrinsic128Sample();
00201 while (state.KeepRunningBatch(values.size())) {
00202 for (const auto& pair : values) {
00203 benchmark::DoNotOptimize(pair.first * pair.second);
00204 }
00205 }
00206 }
00207 BENCHMARK(BM_MultiplyIntrinsic128);
00208
00209 void BM_AddIntrinsic128(benchmark::State& state) {
00210 auto values = GetRandomIntrinsic128Sample();
00211 while (state.KeepRunningBatch(values.size())) {
00212 for (const auto& pair : values) {
00213 benchmark::DoNotOptimize(pair.first + pair.second);
00214 }
00215 }
00216 }
00217 BENCHMARK(BM_AddIntrinsic128);
00218
00219 #endif // ABSL_HAVE_INTRINSIC_INT128
00220
00221 }