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 <atomic> 10 #include <cstddef> 11 #include <random> 12 #include <thread> 13 #include <tuple> 14 #include <type_traits> 15 #include <vector> 16 17 #include <mp++/config.hpp> 18 #include <mp++/integer.hpp> 19 20 #include "catch.hpp" 21 #include "test_utils.hpp" 22 23 static const int ntries = 1000; 24 25 // NOLINTNEXTLINE(google-build-using-namespace) 26 using namespace mppp; 27 // NOLINTNEXTLINE(google-build-using-namespace) 28 using namespace mppp_test; 29 30 using sizes = std::tuple<std::integral_constant<std::size_t, 1>, std::integral_constant<std::size_t, 2>, 31 std::integral_constant<std::size_t, 3>, std::integral_constant<std::size_t, 6>, 32 std::integral_constant<std::size_t, 10>>; 33 34 struct cache_tester { 35 template <typename S> operator ()cache_tester36 inline void operator()(const S &) const 37 { 38 using integer = integer<S::value>; 39 std::atomic<bool> flag{true}; 40 // Run a variety of tests with operands with x number of limbs. 41 auto random_xy = [&flag](unsigned x) { 42 auto checker = [&flag]() { 43 #if defined(MPPP_HAVE_THREAD_LOCAL) 44 const auto &mpzc = detail::get_thread_local_mpz_cache(); 45 for (auto s : mpzc.sizes) { 46 if (s) { 47 flag.store(false); 48 } 49 } 50 #endif 51 }; 52 // NOLINTNEXTLINE(cert-err58-cpp, cert-msc32-c, cert-msc51-cpp) 53 std::mt19937 rng; 54 rng.seed(x); 55 std::uniform_int_distribution<int> sdist(0, 1); 56 detail::mpz_raii tmp; 57 std::vector<integer> v_int; 58 for (int i = 0; i < ntries; ++i) { 59 random_integer(tmp, x, rng); 60 v_int.emplace_back(&tmp.m_mpz); 61 if (sdist(rng)) { 62 v_int.back().neg(); 63 } 64 if (sdist(rng)) { 65 // Promote sometimes, if possible. 66 v_int.back().promote(); 67 } 68 } 69 v_int.resize(0); 70 free_integer_caches(); 71 free_integer_caches(); 72 free_integer_caches(); 73 checker(); 74 for (int i = 0; i < ntries; ++i) { 75 random_integer(tmp, x, rng); 76 v_int.emplace_back(&tmp.m_mpz); 77 if (sdist(rng)) { 78 v_int.back().neg(); 79 } 80 if (sdist(rng)) { 81 // Promote sometimes, if possible. 82 v_int.back().promote(); 83 } 84 } 85 v_int.resize(0); 86 free_integer_caches(); 87 free_integer_caches(); 88 free_integer_caches(); 89 checker(); 90 for (int i = 0; i < ntries; ++i) { 91 random_integer(tmp, x, rng); 92 v_int.emplace_back(&tmp.m_mpz); 93 if (sdist(rng)) { 94 v_int.back().neg(); 95 } 96 if (sdist(rng)) { 97 // Promote sometimes, if possible. 98 v_int.back().promote(); 99 } 100 } 101 free_integer_caches(); 102 free_integer_caches(); 103 free_integer_caches(); 104 }; 105 106 std::thread t0(random_xy, 0); 107 std::thread t1(random_xy, 1); 108 std::thread t2(random_xy, 2); 109 std::thread t3(random_xy, 3); 110 std::thread t4(random_xy, 4); 111 t0.join(); 112 t1.join(); 113 t2.join(); 114 t3.join(); 115 t4.join(); 116 } 117 }; 118 119 TEST_CASE("caches") 120 { 121 tuple_for_each(sizes{}, cache_tester{}); 122 } 123