blob: ce48f21869d56394a02e492cd26d346eec075fd4 [file] [log] [blame]
#include <algorithm>
#include <cstdint>
#include <limits>
#include <random>
#include <type_traits>
#include <vector>
#include "benchmark/benchmark.h"
#if defined(__SIZEOF_INT128__)
namespace {
constexpr size_t kSampleSize = 1 << 20;
// Some implementations of <random> do not support __int128_t when it is
// available, so we make our own uniform_int_distribution-like type.
template <typename T>
class UniformIntDistribution128 {
public:
T operator()(std::mt19937& generator) {
return (static_cast<T>(dist64_(generator)) << 64) | dist64_(generator);
}
private:
using H = typename std::conditional<
std::is_same<T, __int128_t>::value, int64_t, uint64_t>::type;
std::uniform_int_distribution<H> dist64_;
};
// Generates uniformly pairs (a, b) of 128-bit integers such as a >= b.
template <typename T>
std::vector<std::pair<T, T>> GetRandomIntrinsic128SampleUniformDivisor() {
std::vector<std::pair<T, T>> values;
std::mt19937 random;
UniformIntDistribution128<T> uniform_128;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
T a = uniform_128(random);
T b = uniform_128(random);
values.emplace_back(std::max(static_cast<T>(2), std::max(a, b)),
std::max(static_cast<T>(2), std::min(a, b)));
}
return values;
}
template <typename T>
void BM_DivideIntrinsic128UniformDivisor(benchmark::State& state) {
auto values = GetRandomIntrinsic128SampleUniformDivisor<T>();
size_t i = 0;
for (const auto _ : state) {
benchmark::DoNotOptimize(values[i].first / values[i].second);
i = (i + 1) % kSampleSize;
}
}
BENCHMARK_TEMPLATE(BM_DivideIntrinsic128UniformDivisor, __uint128_t);
BENCHMARK_TEMPLATE(BM_DivideIntrinsic128UniformDivisor, __int128_t);
template <typename T>
void BM_RemainderIntrinsic128UniformDivisor(benchmark::State& state) {
auto values = GetRandomIntrinsic128SampleUniformDivisor<T>();
size_t i = 0;
for (const auto _ : state) {
benchmark::DoNotOptimize(values[i].first % values[i].second);
i = (i + 1) % kSampleSize;
}
}
BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128UniformDivisor, __uint128_t);
BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128UniformDivisor, __int128_t);
// Generates random pairs of (a, b) where a >= b, a is 128-bit and
// b is 64-bit.
template <typename T, typename H = typename std::conditional<
std::is_same<T, __int128_t>::value, int64_t, uint64_t>::type>
std::vector<std::pair<T, H>> GetRandomIntrinsic128SampleSmallDivisor() {
std::vector<std::pair<T, H>> values;
std::mt19937 random;
UniformIntDistribution128<T> uniform_int128;
std::uniform_int_distribution<H> uniform_int64;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
T a = uniform_int128(random);
H b = std::max(H{2}, uniform_int64(random));
values.emplace_back(std::max(a, static_cast<T>(b)), b);
}
return values;
}
template <typename T>
void BM_DivideIntrinsic128SmallDivisor(benchmark::State& state) {
auto values = GetRandomIntrinsic128SampleSmallDivisor<T>();
size_t i = 0;
for (const auto _ : state) {
benchmark::DoNotOptimize(values[i].first / values[i].second);
i = (i + 1) % kSampleSize;
}
}
BENCHMARK_TEMPLATE(BM_DivideIntrinsic128SmallDivisor, __uint128_t);
BENCHMARK_TEMPLATE(BM_DivideIntrinsic128SmallDivisor, __int128_t);
template <typename T>
void BM_RemainderIntrinsic128SmallDivisor(benchmark::State& state) {
auto values = GetRandomIntrinsic128SampleSmallDivisor<T>();
size_t i = 0;
for (const auto _ : state) {
benchmark::DoNotOptimize(values[i].first % values[i].second);
i = (i + 1) % kSampleSize;
}
}
BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128SmallDivisor, __uint128_t);
BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128SmallDivisor, __int128_t);
} // namespace
#endif
BENCHMARK_MAIN();