Commit 45339bec authored by Christoph Conrads's avatar Christoph Conrads

Add SWC benchmark comparing effect of integer type

parent a2deb3e6
......@@ -4,3 +4,5 @@ ranlux-over-seed-lfsr
ranlux-over-seed-counter.png
ranlux-over-seed-lcg.png
ranlux-over-seed-lfsr.png
*.bin
......@@ -7,22 +7,16 @@
CXX := g++
CXXFLAGS := -O3 -march=native -DNDEBUG
.PHONY: run
SOURCES := \
benchmark.cpp rlxt-vs-std.cpp print-random.cpp swc24-vs-native-ints.cpp
EXECUTABLES := $(patsubst %.cpp,%.bin,$(SOURCES))
all: benchmark rlxt-vs-std print-random
.PHONY: run
all: $(EXECUTABLES)
benchmark: benchmark.cpp random-number-engine.hpp
$(CXX) -Wextra -Wall -std=c++11 -pedantic \
$(CXXFLAGS) \
$< -o $@
rlxt-vs-std: rlxt-vs-std.cpp random-number-engine.hpp
$(CXX) -Wextra -Wall -std=c++11 -pedantic \
$(CXXFLAGS) \
$< -o $@
print-random: print-random.cpp random-number-engine.hpp
%.bin: %.cpp
$(CXX) -Wextra -Wall -std=c++11 -pedantic \
$(CXXFLAGS) \
$< -o $@
// Copyright 2019 Christoph Conrads
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef RANLUX_TOOLS_BENCHMARK_HPP
#define RANLUX_TOOLS_BENCHMARK_HPP
#include <cstdio>
#include <cstdint>
#include <ctime>
#include <limits>
#include <random>
#include "random-number-engine.hpp"
#include <string>
namespace ranlux_tools
{
// do not use `clock()` because it does not work on raspberry pi
inline timespec get_cpu_time()
{
timespec tm = { 0, 0 };
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tm);
return tm;
}
inline std::uintmax_t get_time_nsec(const timespec& tm)
{
return tm.tv_nsec + std::uintmax_t{1000*1000*1000} * tm.tv_sec;
}
struct dummy_engine
{
using result_type = std::uint32_t;
static constexpr result_type max()
{ return std::numeric_limits<result_type>::max(); }
static constexpr result_type min()
{ return std::numeric_limits<result_type>::min(); }
result_type operator() ();
result_type state_ = 0;
};
dummy_engine::result_type dummy_engine::operator() () { return state_++; }
std::string get_name(const dummy_engine&) { return "dummy-prng"; }
std::string get_name(const std::mt19937&) { return "std::mt19937"; }
std::string get_name(const std::mt19937_64&) { return "std::mt19937_64"; }
std::string get_name(const std::ranlux24&) { return "std::ranlux24"; }
std::string get_name(const std::ranlux48&) { return "std::ranlux48"; }
std::string get_name(const xoshiro128plus&) { return "xoshiro128+"; }
template<typename T, std::size_t W, std::size_t S, std::size_t R>
std::string get_name(const add_with_carry_engine<T, W, S, R>&)
{
constexpr auto FORMAT = "AWC(2^%-2zu, %2zu, %1zu)";
char buffer[80] = { 0 };
snprintf(buffer, sizeof(buffer), FORMAT, W, R, S);
return buffer;
}
template<typename T, std::size_t W, std::size_t P, std::size_t Q>
std::string get_name(const subtract_with_borrow_engine<T, W, P, Q>&)
{
constexpr auto FORMAT = "SWB(2^%-2zu, %2zu, %1zu)";
char buffer[80] = { 0 };
snprintf(buffer, sizeof(buffer), FORMAT, W, P, Q);
return buffer;
}
template<typename T, std::size_t W, std::size_t S, std::size_t R>
std::string get_name(const std::subtract_with_carry_engine<T, W, S, R>&)
{
constexpr auto FORMAT = "SWC(2^%-2zu, %1zu, %2zu)";
char buffer[80] = { 0 };
snprintf(buffer, sizeof(buffer), FORMAT, W, S, R);
return buffer;
}
template<typename Generator, std::size_t P, std::size_t Q>
std::string get_name(const std::discard_block_engine<Generator, P, Q>& gen)
{
auto name = get_name(gen.base());
constexpr auto FORMAT = "[%4zu,%2zu]";
char buffer[80] = { 0 };
snprintf(buffer, sizeof(buffer), FORMAT, P, Q);
return name + buffer;
}
template<typename Generator>
typename Generator::result_type draw(Generator& gen) __attribute__((noinline));
template<typename Generator>
typename Generator::result_type draw(Generator& gen)
{
return gen();
}
template<typename Generator>
void run(std::uintmax_t num_draws)
{
static_assert(Generator::min() == 0, "");
auto w =
Generator::max() == std::numeric_limits<std::uint64_t>::max() ? 8u :
Generator::max() == (1ull<<48) - 1u ? 6u :
Generator::max() == std::numeric_limits<std::uint32_t>::max() ? 4u :
Generator::max() == (1u<<24) - 1u ? 3u :
Generator::max() == std::numeric_limits<std::uint16_t>::max() ? 2u :
Generator::max() == std::numeric_limits<std::uint8_t>::max() ? 1u : 0u
;
auto gen = Generator();
auto t_0 = get_cpu_time();
for(auto i = std::uintmax_t{0}; i < num_draws; ++i)
draw(gen);
auto t_1 = get_cpu_time();
auto t_nsec = get_time_nsec(t_1) - get_time_nsec(t_0);
auto t_msec = t_nsec / (1000u*1000u);
auto bytes_per_msec = w * num_draws * 1000u / double(t_msec);
auto name = get_name(gen);
auto dummy = std::uint16_t(gen());
std::printf(
"%-25s | %10ju | %20.2e | %hu\n",
name.c_str(), t_msec, bytes_per_msec, dummy
);
}
}
#endif
// Copyright 2019 Christoph Conrads
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "benchmark.hpp"
#include <cassert>
#include <cstdio>
#include <cstdint>
#include <ctime>
#include <limits>
#include <random>
#include <string>
#include <type_traits>
namespace rlxt = ranlux_tools;
using swc8 =
std::subtract_with_carry_engine<std::uint8_t, 8, 10, 24>;
using swc16 =
std::subtract_with_carry_engine<std::uint16_t, 16, 10, 24>;
using swc24 = std::ranlux24_base;
using swc32 =
std::subtract_with_carry_engine<std::uint32_t, 32, 10, 24>;
using swc64 =
std::subtract_with_carry_engine<std::uint64_t, 64, 10, 24>;
int main()
{
constexpr auto num_draws = std::uintmax_t{1000} * 1000u * 1000u;
std::printf(
"%-25s | %10s | %20s | %s\n",
"generator", "time(sec)", "throughput(byte/sec)", "dummy"
);
rlxt::run<rlxt::dummy_engine>(num_draws);
rlxt::run<swc8>(num_draws);
rlxt::run<swc16>(num_draws);
rlxt::run<swc24>(num_draws);
rlxt::run<swc32>(num_draws);
rlxt::run<swc64>(num_draws);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment