benchmark.cpp 4.54 KB
Newer Older
Christoph Conrads's avatar
Christoph Conrads committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// 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 <cassert>
#include "random-number-engine.hpp"
#include <cstdio>
#include <cstdint>
#include <ctime>
#include <limits>
#include <random>
#include <string>
#include <type_traits>


Christoph Conrads's avatar
Christoph Conrads committed
18
namespace rlxt = ranlux_tools;
Christoph Conrads's avatar
Christoph Conrads committed
19 20 21



22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
// do not use `clock()` because it does not work on raspberry pi
timespec get_cpu_time()
{
	timespec tm = { 0, 0 };
	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tm);

	return tm;
}


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(); }


48
	result_type operator() ();
49 50 51 52 53 54 55 56 57


	result_type state_ = 0;
};

dummy_engine::result_type dummy_engine::operator() () { return state_++; }


std::string get_name(const dummy_engine&) { return "dummy-prng"; }
Christoph Conrads's avatar
Christoph Conrads committed
58 59 60
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"; }
61
std::string get_name(const std::ranlux48&) { return "std::ranlux48"; }
Christoph Conrads's avatar
Christoph Conrads committed
62 63

std::string get_name(const ranlux_tools::xoshiro128plus&)
Christoph Conrads's avatar
Christoph Conrads committed
64 65 66 67 68 69 70
{
	return "xoshiro128+";
}



template<typename T, std::size_t W, std::size_t S, std::size_t R>
Christoph Conrads's avatar
Christoph Conrads committed
71
std::string get_name(const ranlux_tools::add_with_carry_engine<T, W, S, R>&
Christoph Conrads's avatar
Christoph Conrads committed
72 73
)
{
Christoph Conrads's avatar
Christoph Conrads committed
74
	constexpr auto FORMAT = "AWC(2^%-2zu, %2zu, %1zu)";
Christoph Conrads's avatar
Christoph Conrads committed
75 76
	char buffer[80] = { 0 };

77
	snprintf(buffer, sizeof(buffer), FORMAT, W, R, S);
Christoph Conrads's avatar
Christoph Conrads committed
78 79 80 81 82

	return buffer;
}


83
template<typename T, std::size_t W, std::size_t P, std::size_t Q>
Christoph Conrads's avatar
Christoph Conrads committed
84
std::string get_name(
Christoph Conrads's avatar
Christoph Conrads committed
85
	const ranlux_tools::subtract_with_borrow_engine<T, W, P, Q>&
Christoph Conrads's avatar
Christoph Conrads committed
86 87
)
{
Christoph Conrads's avatar
Christoph Conrads committed
88
	constexpr auto FORMAT = "SWB(2^%-2zu, %2zu, %1zu)";
Christoph Conrads's avatar
Christoph Conrads committed
89 90
	char buffer[80] = { 0 };

Christoph Conrads's avatar
Christoph Conrads committed
91
	snprintf(buffer, sizeof(buffer), FORMAT, W, P, Q);
Christoph Conrads's avatar
Christoph Conrads committed
92 93 94 95 96 97 98 99 100 101

	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());

Christoph Conrads's avatar
Christoph Conrads committed
102
	constexpr auto FORMAT = "[%4zu,%2zu]";
Christoph Conrads's avatar
Christoph Conrads committed
103 104 105 106 107 108 109 110
	char buffer[80] = { 0 };

	snprintf(buffer, sizeof(buffer), FORMAT, P, Q);

	return name + buffer;
}


111 112 113 114 115 116 117 118 119 120
template<typename Generator>
typename Generator::result_type draw(Generator& gen) __attribute__((noinline));

template<typename Generator>
typename Generator::result_type draw(Generator& gen)
{
	return gen();
}


Christoph Conrads's avatar
Christoph Conrads committed
121 122 123 124 125 126 127
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 :
128
		Generator::max() == (1ull<<48) - 1u                           ? 6u :
Christoph Conrads's avatar
Christoph Conrads committed
129 130
		Generator::max() == std::numeric_limits<std::uint32_t>::max() ? 4u :
		Generator::max() == (1u<<24) - 1u                             ? 3u :
131 132
		Generator::max() == std::numeric_limits<std::uint16_t>::max() ? 2u :
		Generator::max() == std::numeric_limits<std::uint8_t>::max() ?  1u : 0u
Christoph Conrads's avatar
Christoph Conrads committed
133 134 135
	;

	auto gen = Generator();
136
	auto t_0 = get_cpu_time();
Christoph Conrads's avatar
Christoph Conrads committed
137 138

	for(auto i = std::uintmax_t{0}; i < num_draws; ++i)
139
		draw(gen);
Christoph Conrads's avatar
Christoph Conrads committed
140

141 142 143 144
	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);
Christoph Conrads's avatar
Christoph Conrads committed
145 146 147 148
	auto name = get_name(gen);
	auto dummy = std::uint16_t(gen());

	std::printf(
149
		"%-25s | %10ju | %20.2e | %hu\n",
Christoph Conrads's avatar
Christoph Conrads committed
150 151 152 153 154 155 156 157 158 159
		name.c_str(), t_msec, bytes_per_msec, dummy
	);
}


int main()
{
	constexpr auto num_draws = std::uintmax_t{1000} * 1000u * 1000u;

	std::printf(
160
		"%-25s | %10s | %20s | %s\n",
Christoph Conrads's avatar
Christoph Conrads committed
161 162 163
		"generator", "time(sec)", "throughput(byte/sec)", "dummy"
	);

Christoph Conrads's avatar
Christoph Conrads committed
164 165 166
	run<rlxt::ranlux8_base>(num_draws);
	run<rlxt::ranlux16_base>(num_draws);
	run<rlxt::ranlux32_base>(num_draws);
167
#if RANLUX_TOOLS_HAS_INT128
Christoph Conrads's avatar
Christoph Conrads committed
168
	run<rlxt::ranlux64_base>(num_draws);
169
#endif
Christoph Conrads's avatar
Christoph Conrads committed
170 171 172
	run<rlxt::fast_ranlux8>(num_draws);
	run<rlxt::fast_ranlux16>(num_draws);
	run<rlxt::fast_ranlux32>(num_draws);
173
#if RANLUX_TOOLS_HAS_INT128
Christoph Conrads's avatar
Christoph Conrads committed
174
	run<rlxt::fast_ranlux64>(num_draws);
175
#endif
Christoph Conrads's avatar
Christoph Conrads committed
176 177 178
	run<rlxt::ranlux8>(num_draws);
	run<rlxt::ranlux16>(num_draws);
	run<rlxt::ranlux32>(num_draws);
179
#if RANLUX_TOOLS_HAS_INT128
Christoph Conrads's avatar
Christoph Conrads committed
180
	run<rlxt::ranlux64>(num_draws);
181
#endif
Christoph Conrads's avatar
Christoph Conrads committed
182
	run<std::ranlux24>(num_draws);
183
	run<std::ranlux48>(num_draws);
Christoph Conrads's avatar
Christoph Conrads committed
184
	run<std::mt19937>(num_draws);
Christoph Conrads's avatar
Christoph Conrads committed
185 186
	run<std::mt19937_64>(num_draws);
	run<rlxt::xoshiro128plus>(num_draws);
Christoph Conrads's avatar
Christoph Conrads committed
187
}