1 // Copyright 2016-2021 Francesco Biscani (bluescarni@gmail.com)
2 //
3 // This file is part of the mp++ library.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla
6 // Public License v. 2.0. If a copy of the MPL was not distributed
7 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <algorithm>
10 #include <cstdint>
11 #include <random>
12 #include <utility>
13 #include <vector>
14 
15 #if defined(MPPP_BENCHMARK_BOOST)
16 
17 #include <boost/multiprecision/cpp_int.hpp>
18 #include <boost/multiprecision/gmp.hpp>
19 
20 #endif
21 
22 #if defined(MPPP_BENCHMARK_FLINT)
23 
24 #include <flint/flint.h>
25 #include <flint/fmpzxx.h>
26 
27 #endif
28 
29 #include <fmt/core.h>
30 #include <fmt/ostream.h>
31 
32 #include <mp++/config.hpp>
33 #include <mp++/integer.hpp>
34 
35 #if defined(MPPP_BENCHMARK_BOOST)
36 
37 #include <mp++/detail/gmp.hpp>
38 
39 #endif
40 
41 #include "utils.hpp"
42 
43 namespace
44 {
45 
46 #if defined(MPPP_BENCHMARK_BOOST)
47 
48 using cpp_int = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>, boost::multiprecision::et_on>;
49 using mpz_int = boost::multiprecision::number<boost::multiprecision::gmp_int, boost::multiprecision::et_off>;
50 
51 #endif
52 
53 std::mt19937 rng;
54 
55 constexpr auto size = 30000000ul;
56 
57 template <typename T>
get_init_vectors()58 std::tuple<std::vector<T>, std::vector<T>, std::vector<T>> get_init_vectors()
59 {
60     rng.seed(0);
61     std::uniform_int_distribution<unsigned> dist(1u, 7u);
62     std::vector<T> v1(size), v2(size), v3(size);
63     std::generate(v1.begin(), v1.end(), [&dist]() { return T(dist(rng) * dist(rng)); });
64     std::generate(v2.begin(), v2.end(), [&dist]() { return T(dist(rng)); });
65     return std::make_tuple(std::move(v1), std::move(v2), std::move(v3));
66 }
67 
68 const auto benchmark_name = mppp_benchmark_name();
69 
70 } // namespace
71 
main()72 int main()
73 {
74     fmt::print("Benchmark name: {}\n", benchmark_name);
75 
76     // Warm up.
77     mppp_benchmark::warmup();
78 
79     // Prepare the benchmark result data.
80     mppp_benchmark::data_t bdata;
81 
82     {
83         auto p = get_init_vectors<mppp::integer<1>>();
84         constexpr auto name = "mppp::integer<1>";
85 
86         mppp::integer<1> ret(0);
87 
88         mppp_benchmark::simple_timer st;
89 
90         for (auto i = 0ul; i < size; ++i) {
91             tdiv_q(std::get<2>(p)[i], std::get<0>(p)[i], std::get<1>(p)[i]);
92             ret += std::get<2>(p)[i];
93         }
94 
95         const auto runtime = st.elapsed();
96         bdata.emplace_back(name, runtime);
97         fmt::print(mppp_benchmark::res_print_format, name, runtime, ret);
98     }
99 
100     {
101         auto p = get_init_vectors<std::uint_least64_t>();
102         constexpr auto name = "std::uint64_t";
103 
104         std::uint_least64_t ret = 0;
105 
106         mppp_benchmark::simple_timer st;
107 
108         for (auto i = 0ul; i < size; ++i) {
109             std::get<2>(p)[i] = std::get<0>(p)[i] / std::get<1>(p)[i];
110             ret += std::get<2>(p)[i];
111         }
112 
113         const auto runtime = st.elapsed();
114         bdata.emplace_back(name, runtime);
115         fmt::print(mppp_benchmark::res_print_format, name, runtime, ret);
116     }
117 
118 #if defined(MPPP_HAVE_GCC_INT128)
119     {
120         auto p = get_init_vectors<__uint128_t>();
121         constexpr auto name = "__uint128_t";
122 
123         __uint128_t ret = 0;
124 
125         mppp_benchmark::simple_timer st;
126 
127         for (auto i = 0ul; i < size; ++i) {
128             std::get<2>(p)[i] = std::get<0>(p)[i] / std::get<1>(p)[i];
129             ret += std::get<2>(p)[i];
130         }
131 
132         const auto runtime = st.elapsed();
133         bdata.emplace_back(name, runtime);
134         fmt::print(mppp_benchmark::res_print_format, name, runtime, ret);
135     }
136 #endif
137 
138 #if defined(MPPP_BENCHMARK_BOOST)
139     {
140         auto p = get_init_vectors<cpp_int>();
141         constexpr auto name = "boost::cpp_int";
142 
143         cpp_int ret(0);
144 
145         mppp_benchmark::simple_timer st;
146 
147         for (auto i = 0ul; i < size; ++i) {
148             std::get<2>(p)[i] = std::get<0>(p)[i] / std::get<1>(p)[i];
149             ret += std::get<2>(p)[i];
150         }
151 
152         const auto runtime = st.elapsed();
153         bdata.emplace_back(name, runtime);
154         fmt::print(mppp_benchmark::res_print_format, name, runtime, ret);
155     }
156 
157     {
158         auto p = get_init_vectors<mpz_int>();
159         constexpr auto name = "boost::gmp_int";
160 
161         mpz_int ret(0);
162 
163         mppp_benchmark::simple_timer st;
164 
165         for (auto i = 0ul; i < size; ++i) {
166             mpz_tdiv_q(std::get<2>(p)[i].backend().data(), std::get<0>(p)[i].backend().data(),
167                        std::get<1>(p)[i].backend().data());
168             mpz_add(ret.backend().data(), ret.backend().data(), std::get<2>(p)[i].backend().data());
169         }
170 
171         const auto runtime = st.elapsed();
172         bdata.emplace_back(name, runtime);
173         fmt::print(mppp_benchmark::res_print_format, name, runtime, ret);
174     }
175 #endif
176 
177 #if defined(MPPP_BENCHMARK_FLINT)
178     {
179         auto p = get_init_vectors<flint::fmpzxx>();
180         constexpr auto name = "flint::fmpzxx";
181 
182         flint::fmpzxx ret(0);
183 
184         mppp_benchmark::simple_timer st;
185 
186         for (auto i = 0ul; i < size; ++i) {
187             ::fmpz_tdiv_q(std::get<2>(p)[i]._data().inner, std::get<0>(p)[i]._data().inner,
188                           std::get<1>(p)[i]._data().inner);
189             ::fmpz_add(ret._data().inner, ret._data().inner, std::get<2>(p)[i]._data().inner);
190         }
191 
192         const auto runtime = st.elapsed();
193         bdata.emplace_back(name, runtime);
194         fmt::print(mppp_benchmark::res_print_format, name, runtime, ret);
195     }
196 #endif
197 
198     // Write out the .py and .rst files.
199     mppp_benchmark::write_out(bdata, benchmark_name);
200 }
201