diff --git a/.gitignore b/.gitignore index 7bfb5c1573..93eb2f522b 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ build /configure /libtool .dirstamp +/.vs diff --git a/include/bitcoin/system/hash/sha/algorithm.hpp b/include/bitcoin/system/hash/sha/algorithm.hpp index 46ee4de435..480d470de4 100644 --- a/include/bitcoin/system/hash/sha/algorithm.hpp +++ b/include/bitcoin/system/hash/sha/algorithm.hpp @@ -234,6 +234,8 @@ class algorithm INLINE static constexpr void input(buffer_t& buffer, const block_t& block) NOEXCEPT; INLINE static constexpr void input_left(auto& buffer, const half_t& half) NOEXCEPT; INLINE static constexpr void input_right(auto& buffer, const half_t& half) NOEXCEPT; + INLINE static constexpr void reinput_left(auto& buffer, const auto& left) NOEXCEPT; + INLINE static constexpr void reinput_right(auto& buffer, const auto& right) NOEXCEPT; INLINE static constexpr digest_t output(const state_t& state) NOEXCEPT; /// Padding. @@ -257,12 +259,6 @@ class algorithm static constexpr void pad_half(auto& buffer) NOEXCEPT; static constexpr void pad_n(auto& buffer, count_t blocks) NOEXCEPT; - /// Double hashing. - /// ----------------------------------------------------------------------- - - static constexpr void reinput_left(auto& buffer, const auto& left) NOEXCEPT; - static constexpr void reinput_right(auto& buffer, const auto& right) NOEXCEPT; - /// Iteration (message scheduling vectorized for multiple blocks). /// ----------------------------------------------------------------------- @@ -386,9 +382,12 @@ class algorithm xint128_t message) NOEXCEPT; template - static void native_rounds(xint128_t& lo, xint128_t& hi, + INLINE static void native_rounds(xint128_t& lo, xint128_t& hi, const block_t& block) NOEXCEPT; + INLINE static void native_rounds(xint128_t& lo, xint128_t& hi, + const half_t& left, const chunk_t& pad) NOEXCEPT; + template static void native_transform(state_t& state, const auto& block) NOEXCEPT; static void native_transform(state_t& state, iblocks_t& blocks) NOEXCEPT; @@ -409,8 +408,6 @@ class algorithm static digest_t native_double_hash(const half_t& half) NOEXCEPT; static digest_t native_double_hash(const half_t& left, const half_t& right) NOEXCEPT; - - public: /// Summary public values. /// ----------------------------------------------------------------------- diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_compress.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_compress.ipp index 6b9db05926..210448e29b 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_compress.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_compress.ipp @@ -243,25 +243,8 @@ template constexpr void CLASS:: compress(state_t& state, const buffer_t& buffer) NOEXCEPT { - if (std::is_constant_evaluated()) - { - compress_(state, buffer); - } - ////else if constexpr (native) - ////{ - //// // Single block shani compression optimization. - //// compress_native(state, buffer); - ////} - ////else if constexpr (vector) - ////{ - //// // Compression is not vectorized within a block, however this is - //// // feasible but may not be optimal (see round() comments). - //// compress_vector(buffer); - ////} - else - { - compress_(state, buffer); - } + // block-internal vectorization is suboptimal. + compress_(state, buffer); } } // namespace sha diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_double.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_double.ipp index 95aec5abb3..ea13a311ae 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_double.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_double.ipp @@ -28,59 +28,6 @@ namespace libbitcoin { namespace system { namespace sha { -// protected -// ---------------------------------------------------------------------------- - -TEMPLATE -INLINE constexpr void CLASS:: -reinput_left(auto& buffer, const auto& left) NOEXCEPT -{ - using words = decltype(buffer); - static_assert(array_count >= SHA::state_words); - - if (std::is_constant_evaluated()) - { - buffer.at(0) = left.at(0); - buffer.at(1) = left.at(1); - buffer.at(2) = left.at(2); - buffer.at(3) = left.at(3); - buffer.at(4) = left.at(4); - buffer.at(5) = left.at(5); - buffer.at(6) = left.at(6); - buffer.at(7) = left.at(7); - } - else - { - using word = array_element; - array_cast(buffer) = left; - } -} - -TEMPLATE -INLINE constexpr void CLASS:: -reinput_right(auto& buffer, const auto& right) NOEXCEPT -{ - using words = decltype(buffer); - static_assert(array_count >= SHA::state_words); - - if (std::is_constant_evaluated()) - { - buffer.at(8) = right.at(0); - buffer.at(9) = right.at(1); - buffer.at(10) = right.at(2); - buffer.at(11) = right.at(3); - buffer.at(12) = right.at(4); - buffer.at(13) = right.at(5); - buffer.at(14) = right.at(6); - buffer.at(15) = right.at(7); - } - else - { - using word = array_element; - array_cast(buffer) = right; - } -} - // public // ---------------------------------------------------------------------------- // These benefit from avoiding state endian transition and reusing buffer. diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_merkle.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_merkle.ipp index 338c97306c..05d8ae2a56 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_merkle.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_merkle.ipp @@ -401,18 +401,13 @@ merkle_hash_vector(digests_t& digests) NOEXCEPT auto idigests = idigests_t{ to_half(size), data }; const auto start = iblocks.size(); - // Merkle hash vector dispatch. + // Always use if available. if constexpr (use_x512) merkle_hash_vector(idigests, iblocks); - // Use if shani is not available or at least 32 blocks. - if constexpr (use_x256) - { - if constexpr (!native) - merkle_hash_vector(idigests, iblocks); - else if (start >= 32_size) - merkle_hash_vector(idigests, iblocks); - } + // Only use if shani is not available. + if constexpr (use_x256 && !native) + merkle_hash_vector(idigests, iblocks); // Only use if shani is not available. if constexpr (use_x128 && !native) diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_native.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_native.ipp index 798ecce9d3..b63156804e 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_native.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_native.ipp @@ -104,7 +104,7 @@ round_4(xint128_t& state0, xint128_t& state1, xint128_t message) NOEXCEPT TEMPLATE template -void CLASS:: +INLINE void CLASS:: native_rounds(xint128_t& lo, xint128_t& hi, const block_t& block) NOEXCEPT { const auto& wblock = array_cast(block); @@ -186,11 +186,13 @@ TEMPLATE void CLASS:: native_transform(state_t& state, iblocks_t& blocks) NOEXCEPT { + // Individual state vars are used vs. array to ensure register persistence. auto& wstate = array_cast(state); auto lo = load(wstate[0]); auto hi = load(wstate[1]); shuffle(lo, hi); + // native_rounds must be inlined here (register boundary). for (auto& block: blocks) native_rounds(lo, hi, block); @@ -208,7 +210,10 @@ native_transform(state_t& state, const auto& block) NOEXCEPT auto lo = load(wstate[0]); auto hi = load(wstate[1]); shuffle(lo, hi); + + // native_rounds must be inlined here (register boundary). native_rounds(lo, hi, array_cast(block)); + unshuffle(lo, hi); store(wstate[0], lo); store(wstate[1], hi); @@ -228,6 +233,8 @@ native_finalize(state_t& state, const words_t& pad) NOEXCEPT auto lo = load(wstate[0]); auto hi = load(wstate[1]); shuffle(lo, hi); + + // native_rounds must be inlined here (register boundary). native_rounds(lo, hi, array_cast(pad)); unshuffle(lo, hi); diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_parsing.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_parsing.ipp index 9101cce7ce..9ba22b5f38 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_parsing.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_parsing.ipp @@ -58,32 +58,32 @@ input(buffer_t& buffer, const block_t& block) NOEXCEPT } else if constexpr (bc::is_little_endian) { - if constexpr (have_lanes && !with_clang) - { - using xword_t = to_extended; - const auto& in = array_cast(block); - auto& out = array_cast(buffer); - out[0] = byteswap(in[0]); - } - else if constexpr (have_lanes && !with_clang) - { - using xword_t = to_extended; - const auto& in = array_cast(block); - auto& out = array_cast(buffer); - out[0] = byteswap(in[0]); - out[1] = byteswap(in[1]); - } - else if constexpr (have_lanes && !with_clang) - { - using xword_t = to_extended; - const auto& in = array_cast(block); - auto& out = array_cast(buffer); - out[0] = byteswap(in[0]); - out[1] = byteswap(in[1]); - out[2] = byteswap(in[2]); - out[3] = byteswap(in[3]); - } - else + ////if constexpr (have_lanes && !with_clang) + ////{ + //// using xword_t = to_extended; + //// const auto& in = array_cast(block); + //// auto& out = array_cast(buffer); + //// out[0] = byteswap(in[0]); + ////} + ////else if constexpr (have_lanes && !with_clang) + ////{ + //// using xword_t = to_extended; + //// const auto& in = array_cast(block); + //// auto& out = array_cast(buffer); + //// out[0] = byteswap(in[0]); + //// out[1] = byteswap(in[1]); + ////} + ////else if constexpr (have_lanes && !with_clang) + ////{ + //// using xword_t = to_extended; + //// const auto& in = array_cast(block); + //// auto& out = array_cast(buffer); + //// out[0] = byteswap(in[0]); + //// out[1] = byteswap(in[1]); + //// out[2] = byteswap(in[2]); + //// out[3] = byteswap(in[3]); + ////} + ////else { const auto& in = array_cast(block); buffer[0] = native_from_big_end(in[0]); @@ -131,22 +131,22 @@ input_left(auto& buffer, const half_t& half) NOEXCEPT } else if constexpr (bc::is_little_endian) { - if constexpr (have_lanes && !with_clang) - { - using xword_t = to_extended; - const auto& in = array_cast(half); - auto& out = array_cast(buffer); - out[0] = byteswap(in[0]); - } - else if constexpr (have_lanes && !with_clang) - { - using xword_t = to_extended; - const auto& in = array_cast(half); - auto& out = array_cast(buffer); - out[0] = byteswap(in[0]); - out[1] = byteswap(in[1]); - } - else + ////if constexpr (have_lanes && !with_clang) + ////{ + //// using xword_t = to_extended; + //// const auto& in = array_cast(half); + //// auto& out = array_cast(buffer); + //// out[0] = byteswap(in[0]); + ////} + ////else if constexpr (have_lanes && !with_clang) + ////{ + //// using xword_t = to_extended; + //// const auto& in = array_cast(half); + //// auto& out = array_cast(buffer); + //// out[0] = byteswap(in[0]); + //// out[1] = byteswap(in[1]); + ////} + ////else { const auto& in = array_cast(half); buffer[0] = native_from_big_end(in[0]); @@ -185,22 +185,22 @@ input_right(auto& buffer, const half_t& half) NOEXCEPT } else if constexpr (bc::is_little_endian) { - if constexpr (have_lanes && !with_clang) - { - using xword_t = to_extended; - const auto& in = array_cast(half); - auto& out = array_cast(buffer); - out[1] = byteswap(in[0]); - } - else if constexpr (have_lanes && !with_clang) - { - using xword_t = to_extended; - const auto& in = array_cast(half); - auto& out = array_cast(buffer); - out[2] = byteswap(in[0]); - out[3] = byteswap(in[1]); - } - else + ////if constexpr (have_lanes && !with_clang) + ////{ + //// using xword_t = to_extended; + //// const auto& in = array_cast(half); + //// auto& out = array_cast(buffer); + //// out[1] = byteswap(in[0]); + ////} + ////else if constexpr (have_lanes && !with_clang) + ////{ + //// using xword_t = to_extended; + //// const auto& in = array_cast(half); + //// auto& out = array_cast(buffer); + //// out[2] = byteswap(in[0]); + //// out[3] = byteswap(in[1]); + ////} + ////else { const auto& in = array_cast(half); buffer[8] = native_from_big_end(in[0]); @@ -248,26 +248,26 @@ output(const state_t& state) NOEXCEPT { if constexpr (SHA::strength != 160) { - if constexpr (have_lanes && !with_clang) - { - using xword_t = to_extended; - const auto& in = array_cast(state); - return array_cast(wstate_t - { - byteswap(in[0]) - }); - } - else if constexpr (have_lanes && !with_clang) - { - using xword_t = to_extended; - const auto& in = array_cast(state); - return array_cast(wstate_t - { - byteswap(in[0]), - byteswap(in[1]) - }); - } - else + ////if constexpr (have_lanes && !with_clang) + ////{ + //// using xword_t = to_extended; + //// const auto& in = array_cast(state); + //// return array_cast(wstate_t + //// { + //// byteswap(in[0]) + //// }); + ////} + ////else if constexpr (have_lanes && !with_clang) + ////{ + //// using xword_t = to_extended; + //// const auto& in = array_cast(state); + //// return array_cast(wstate_t + //// { + //// byteswap(in[0]), + //// byteswap(in[1]) + //// }); + ////} + ////else { return array_cast(state_t { @@ -300,6 +300,60 @@ output(const state_t& state) NOEXCEPT } } +// protected +// ---------------------------------------------------------------------------- +// These bypass endianness, used for padding and state reintroduction. + +TEMPLATE +INLINE constexpr void CLASS:: +reinput_left(auto& buffer, const auto& left) NOEXCEPT +{ + using words = decltype(buffer); + static_assert(array_count >= SHA::state_words); + + if (std::is_constant_evaluated()) + { + buffer.at(0) = left.at(0); + buffer.at(1) = left.at(1); + buffer.at(2) = left.at(2); + buffer.at(3) = left.at(3); + buffer.at(4) = left.at(4); + buffer.at(5) = left.at(5); + buffer.at(6) = left.at(6); + buffer.at(7) = left.at(7); + } + else + { + using word = array_element; + array_cast(buffer) = left; + } +} + +TEMPLATE +INLINE constexpr void CLASS:: +reinput_right(auto& buffer, const auto& right) NOEXCEPT +{ + using words = decltype(buffer); + static_assert(array_count >= SHA::state_words); + + if (std::is_constant_evaluated()) + { + buffer.at(8) = right.at(0); + buffer.at(9) = right.at(1); + buffer.at(10) = right.at(2); + buffer.at(11) = right.at(3); + buffer.at(12) = right.at(4); + buffer.at(13) = right.at(5); + buffer.at(14) = right.at(6); + buffer.at(15) = right.at(7); + } + else + { + using word = array_element; + array_cast(buffer) = right; + } +} + } // namespace sha } // namespace system } // namespace libbitcoin diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_schedule.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_schedule.ipp index b65704e27b..6d1b5343b5 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_schedule.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_schedule.ipp @@ -138,11 +138,6 @@ schedule(buffer_t& buffer) NOEXCEPT { schedule_(buffer); } - ////else if constexpr (native) - ////{ - //// // Single block (with shani) message scheduling optimization. - //// schedule_native(buffer); - ////} else if constexpr (vector) { // Single block (without shani) message scheduling optimization. diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_single.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_single.ipp index 06383ec21b..9e27cf11cb 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_single.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_single.ipp @@ -54,6 +54,7 @@ TEMPLATE constexpr typename CLASS::digest_t CLASS:: hash(const block_t& block) NOEXCEPT { + // As an array of a 1 arrays is the same as the array, this compiles away. return hash(ablocks_t{ block }); } diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_stream.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_stream.ipp index d4a821cada..a018fae98d 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_stream.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_stream.ipp @@ -40,6 +40,7 @@ TEMPLATE constexpr void CLASS:: accumulate(state_t& state, const block_t& block) NOEXCEPT { + // As an array of a 1 arrays is the same as the array, this compiles away. iterate(state, ablocks_t{ block }); } diff --git a/test/hash/performance/baseline/rmd160.cpp b/test/hash/performance/baseline/rmd160.cpp index 7a06a676fe..f8b01aa5f9 100644 --- a/test/hash/performance/baseline/rmd160.cpp +++ b/test/hash/performance/baseline/rmd160.cpp @@ -266,7 +266,7 @@ CRIPEMD160& CRIPEMD160::Write(const unsigned char* data, size_t len) return *this; } -void CRIPEMD160::Finalize(unsigned char hash[OUTPUT_SIZE]) +void CRIPEMD160::Finalize(unsigned char hash[digest_bytes]) { static const unsigned char pad[64] = {0x80}; unsigned char sizedesc[8]; diff --git a/test/hash/performance/baseline/rmd160.h b/test/hash/performance/baseline/rmd160.h index 585cb6377b..2510ccabd3 100644 --- a/test/hash/performance/baseline/rmd160.h +++ b/test/hash/performance/baseline/rmd160.h @@ -19,11 +19,11 @@ class CRIPEMD160 uint64_t bytes; public: - static const size_t OUTPUT_SIZE = 20; + static const size_t digest_bytes = 20; CRIPEMD160(); CRIPEMD160& Write(const unsigned char* data, size_t len); - void Finalize(unsigned char hash[OUTPUT_SIZE]); + void Finalize(unsigned char hash[digest_bytes]); CRIPEMD160& Reset(); }; diff --git a/test/hash/performance/baseline/sha256.cpp b/test/hash/performance/baseline/sha256.cpp index 8f44d7d9ec..cd9942419a 100644 --- a/test/hash/performance/baseline/sha256.cpp +++ b/test/hash/performance/baseline/sha256.cpp @@ -454,7 +454,7 @@ CSHA256& CSHA256::Write(const unsigned char* data, size_t len) return *this; } -void CSHA256::Finalize(unsigned char hash[OUTPUT_SIZE]) +void CSHA256::Finalize(unsigned char hash[digest_bytes]) { static const unsigned char pad[64] = {0x80}; unsigned char sizedesc[8]; diff --git a/test/hash/performance/baseline/sha256.h b/test/hash/performance/baseline/sha256.h index adde788a83..18c13e2180 100644 --- a/test/hash/performance/baseline/sha256.h +++ b/test/hash/performance/baseline/sha256.h @@ -19,11 +19,12 @@ class CSHA256 uint64_t bytes; public: - static const size_t OUTPUT_SIZE = 32; + using digest_t = system::hash_digest; + static const size_t digest_bytes = 32; CSHA256(); CSHA256& Write(const unsigned char* data, size_t len); - void Finalize(unsigned char hash[OUTPUT_SIZE]); + void Finalize(unsigned char hash[digest_bytes]); CSHA256& Reset(); }; diff --git a/test/hash/performance/performance.cpp b/test/hash/performance/performance.cpp index bc04927ced..78ee464b23 100644 --- a/test/hash/performance/performance.cpp +++ b/test/hash/performance/performance.cpp @@ -21,25 +21,23 @@ #if defined(HAVE_PERFORMANCE_TESTS) -BOOST_AUTO_TEST_SUITE(performance_tests) - using namespace performance; -using rmd160a = rmd160_parameters; -using rmd160c = rmd160_parameters; -using sha256a = sha256_parameters; -using sha256c_cached = sha256_parameters; +using rmd160a = rmd160_parameters; +using rmd160c = rmd160_parameters; +using sha256a = sha256_parameters; +using sha256c_cached = sha256_parameters; using sha256c_uncached = sha256_parameters; -using sha256a_both = sha256_parameters; -using sha256a_comp = sha256_parameters; -using sha256a_vect = sha256_parameters; -using sha256a_none = sha256_parameters; +using sha256a_both = sha256_parameters; +using sha256a_comp = sha256_parameters; +using sha256a_vect = sha256_parameters; +using sha256a_none = sha256_parameters; using namespace baseline; -using base_rmd160a = base::parameters; -using base_rmd160c = base::parameters; -using base_sha256a = base::parameters; -using base_sha256c = base::parameters; +using base_rmd160a = base::parameters; +using base_rmd160c = base::parameters; +using base_sha256a = base::parameters; +using base_sha256c = base::parameters; struct v0 { @@ -74,212 +72,287 @@ struct v4 struct mr { static constexpr size_t c = 10 * 1024; - ////static constexpr size_t s = 32; }; -////BOOST_AUTO_TEST_CASE(performance__sha256a_none__merkle) -////{ -//// auto complete = true; -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// BOOST_CHECK(complete); -////} -//// -////BOOST_AUTO_TEST_CASE(performance__sha256a_vect__merkle) -////{ -//// auto complete = true; -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// BOOST_CHECK(complete); -////} -//// -////BOOST_AUTO_TEST_CASE(performance__sha256a_comp__merkle) -////{ -//// auto complete = true; -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// BOOST_CHECK(complete); -////} - -//// -////BOOST_AUTO_TEST_CASE(performance__sha256a_both__merkle) -////{ -//// auto complete = true; -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// complete &= test_merkle(std::cout); -//// BOOST_CHECK(complete); -////} - -// !using shax (see performahce.hpp) - -////BOOST_AUTO_TEST_CASE(performance__base_sha256a) -////{ -//// auto complete = true; -//// complete &= base::test_hash(std::cout); -//// complete &= base::test_hash(std::cout); -//// complete &= base::test_hash(std::cout); -//// complete &= base::test_hash(std::cout); -//// complete &= base::test_hash(std::cout); -//// BOOST_CHECK(complete); -////} - -////BOOST_AUTO_TEST_CASE(performance__sha256a_none) -////{ -//// auto complete = true; -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// BOOST_CHECK(complete); -////} -//// -////BOOST_AUTO_TEST_CASE(performance__sha256a_vect) -////{ -//// auto complete = true; -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// BOOST_CHECK(complete); -////} -//// -////BOOST_AUTO_TEST_CASE(performance__sha256a_comp) -////{ -//// auto complete = true; -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// BOOST_CHECK(complete); -////} -//// -////BOOST_AUTO_TEST_CASE(performance__sha256a_both) -////{ -//// auto complete = true; -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// BOOST_CHECK(complete); -////} - -////BOOST_AUTO_TEST_CASE(performance__rmd160__baseline) -////{ -//// auto complete = true; -//// complete &= base::test_hash(std::cout); -//// complete &= base::test_hash(std::cout); -//// complete &= base::test_hash(std::cout); -//// complete &= base::test_hash(std::cout); -//// complete &= base::test_hash(std::cout); -//// BOOST_CHECK(complete); -////} -//// -////BOOST_AUTO_TEST_CASE(performance__rmd160__algorithm) -////{ -//// auto complete = true; -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// BOOST_CHECK(complete); -////} - -////BOOST_AUTO_TEST_CASE(performance__sha256__accumulator) -////{ -//// auto complete = true; -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// BOOST_CHECK(complete); -////} -//// -////BOOST_AUTO_TEST_CASE(performance__rmd160__accumulator) -////{ -//// auto complete = true; -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// BOOST_CHECK(complete); -////} - -////BOOST_AUTO_TEST_CASE(performance__sha256c_cached__accumulator) -////{ -//// auto complete = true; -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// BOOST_CHECK(complete); -////} -//// -////BOOST_AUTO_TEST_CASE(performance__sha256c_uncached__accumulator) -////{ -//// auto complete = true; -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// complete &= test_accumulator(std::cout); -//// BOOST_CHECK(complete); -////} +BOOST_AUTO_TEST_SUITE(performance_merkle_tests) + +BOOST_AUTO_TEST_CASE(performance__sha256a_base__merkle) +{ + auto complete = true; + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + complete &= base::test_merkle(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__sha256a_none__merkle) +{ + auto complete = true; + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__sha256a_vect__merkle) +{ + auto complete = true; + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__sha256a_comp__merkle) +{ + auto complete = true; + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__sha256a_both__merkle) +{ + auto complete = true; + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + complete &= test_merkle(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(performance_sha256_tests) + +BOOST_AUTO_TEST_CASE(performance__base_sha256a) +{ + auto complete = true; + complete &= base::test_hash(std::cout); + complete &= base::test_hash(std::cout); + + complete &= base::test_hash(std::cout); + complete &= base::test_hash(std::cout); + + complete &= base::test_hash(std::cout); + complete &= base::test_hash_double(std::cout); + + complete &= base::test_hash(std::cout); + complete &= base::test_hash_double(std::cout); + + complete &= base::test_hash_pair(std::cout); + complete &= base::test_hash_pair_double(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__sha256a_none) +{ + auto complete = true; + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_algorithm_pair(std::cout); + complete &= test_algorithm_pair_double(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__sha256a_vect) +{ + auto complete = true; + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_algorithm_pair(std::cout); + complete &= test_algorithm_pair_double(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__sha256a_comp) +{ + auto complete = true; + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_algorithm_pair(std::cout); + complete &= test_algorithm_pair_double(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__sha256a_both) +{ + auto complete = true; + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_accumulator(std::cout); + complete &= test_algorithm_double(std::cout); + + complete &= test_algorithm_pair(std::cout); + complete &= test_algorithm_pair_double(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(performance_sha256_accumulator_tests) + +BOOST_AUTO_TEST_CASE(performance__sha256__accumulator) +{ + auto complete = true; + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__sha256c_cached__accumulator) +{ + auto complete = true; + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__sha256c_uncached__accumulator) +{ + auto complete = true; + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(performance_rmd160_tests) + +BOOST_AUTO_TEST_CASE(performance__rmd160__baseline) +{ + auto complete = true; + complete &= base::test_hash(std::cout); + complete &= base::test_hash(std::cout); + complete &= base::test_hash(std::cout); + complete &= base::test_hash(std::cout); + complete &= base::test_hash(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__rmd160__algorithm) +{ + auto complete = true; + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + BOOST_CHECK(complete); +} + +BOOST_AUTO_TEST_CASE(performance__rmd160__accumulator) +{ + auto complete = true; + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + complete &= test_accumulator(std::cout); + BOOST_CHECK(complete); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/hash/performance/performance.hpp b/test/hash/performance/performance.hpp index bb3bc30fe5..149890d1fd 100644 --- a/test/hash/performance/performance.hpp +++ b/test/hash/performance/performance.hpp @@ -25,6 +25,8 @@ #include namespace performance { + +constexpr bool use_csv = false; // format timing results to ostream // ---------------------------------------------------------------------------- @@ -245,8 +247,8 @@ template = true> -bool test_accumulator(std::ostream& out, float ghz = 3.0f, - bool csv = false) noexcept +bool test_accumulator(std::ostream& out, bool csv = use_csv, + float ghz = 3.0f) noexcept { using P = Parameters; using Precision = std::chrono::nanoseconds; @@ -280,8 +282,8 @@ template = true, bool_if = true, if_base_of = true> -bool test_algorithm(std::ostream& out, float ghz = 3.0f, - bool csv = false) noexcept +bool test_algorithm(std::ostream& out, bool csv = use_csv, + float ghz = 3.0f) noexcept { using P = Parameters; using Precision = std::chrono::nanoseconds; @@ -307,13 +309,112 @@ bool test_algorithm(std::ostream& out, float ghz = 3.0f, return true; } +template = true, + bool_if = true, + if_base_of = true> +bool test_algorithm_pair(std::ostream& out, bool csv = use_csv, + float ghz = 3.0f) noexcept +{ + using P = Parameters; + using Precision = std::chrono::nanoseconds; + using Timer = timer; + using Algorithm = hash_selector< + P::strength, + P::native, + P::vector, + P::cached, + P::ripemd>; + + uint64_t time = zero; + for (size_t seed = 0; seed < Count; ++seed) + { + const auto data = get_data(seed); + time += Timer::execution([&data]() noexcept + { + Algorithm::hash(*data, *data); + }); + } + + output(out, time, ghz, csv); + return true; +} + +template = true, + bool_if = true, + if_base_of = true> +bool test_algorithm_pair_double(std::ostream& out, bool csv = use_csv, + float ghz = 3.0f) noexcept +{ + using P = Parameters; + using Precision = std::chrono::nanoseconds; + using Timer = timer; + using Algorithm = hash_selector< + P::strength, + P::native, + P::vector, + P::cached, + P::ripemd>; + + uint64_t time = zero; + for (size_t seed = 0; seed < Count; ++seed) + { + const auto data = get_data(seed); + time += Timer::execution([&data]() noexcept + { + Algorithm::double_hash(*data, *data); + }); + } + + output(out, time, ghz, csv); + return true; +} + +template = true, + bool_if = true, + if_base_of = true> +bool test_algorithm_double(std::ostream& out, bool csv = use_csv, + float ghz = 3.0f) noexcept +{ + using P = Parameters; + using Precision = std::chrono::nanoseconds; + using Timer = timer; + using Algorithm = hash_selector< + P::strength, + P::native, + P::vector, + P::cached, + P::ripemd>; + + uint64_t time = zero; + for (size_t seed = 0; seed < Count; ++seed) + { + const auto data = get_data(seed); + time += Timer::execution([&data]() noexcept + { + Algorithm::double_hash(*data); + }); + } + + output(out, time, ghz, csv); + return true; +} + template = true, if_base_of = true> -bool test_merkle(std::ostream& out, float ghz = 3.0f, - bool csv = false) noexcept +bool test_merkle(std::ostream& out, bool csv = use_csv, + float ghz = 3.0f) noexcept { using P = Parameters; using Precision = std::chrono::nanoseconds; @@ -340,7 +441,7 @@ bool test_merkle(std::ostream& out, float ghz = 3.0f, time += Timer::execution([&]() noexcept { - Algorithm::merkle_root(std::move(digests)); + Algorithm::merkle_hash(digests); }); } @@ -408,6 +509,20 @@ struct rmd160_parameters : parameters // Baseline test runner helper. // ---------------------------------------------------------------------------- +// Equivalent to: +// hash_digest accumulator::hash(data); +// short_hash accumulator::hash(data); +template +inline typename Algorithm::digest_t base_merkle( + std::vector& data) noexcept +{ + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + const auto bytes = system::pointer_cast(data.data()); + baseline::SHA256D64(bytes, bytes, to_half(data.size())); + return system::unsafe_array_cast(bytes); + BC_POP_WARNING() +} + // Equivalent to: // hash_digest accumulator::hash(data); // short_hash accumulator::hash(data); @@ -415,7 +530,7 @@ template inline auto base_accumulator(auto& data) noexcept { BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) - std_array out{}; + std_array out{}; Algorithm hasher{}; hasher.Write(data.data(), data.size()); hasher.Finalize(out.data()); @@ -423,6 +538,58 @@ inline auto base_accumulator(auto& data) noexcept BC_POP_WARNING() } +// Equivalent to: +// hash_digest accumulator::hash(left, left); +template +inline auto base_accumulator(const auto& left, + const auto& right) noexcept +{ + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + std_array out{}; + Algorithm hasher{}; + hasher.Write(left.data(), left.size()); + hasher.Write(right.data(), right.size()); + hasher.Finalize(out.data()); + return out; + BC_POP_WARNING() +} + +// Equivalent to: +// hash_digest accumulator::double_hash(left, left); +template +inline auto base_accumulator_double(const auto& left, + const auto& right) noexcept +{ + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + std_array out{}; + Algorithm hasher{}; + hasher.Write(left.data(), left.size()); + hasher.Write(right.data(), right.size()); + hasher.Finalize(out.data()); + hasher.Reset(); + hasher.Write(out.data(), out.size()); + hasher.Finalize(out.data()); + return out; + BC_POP_WARNING() +} + +// Equivalent to: +// hash_digest accumulator::double_hash(data); +template +inline auto base_accumulator_double(const auto& data) noexcept +{ + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + std_array out{}; + Algorithm hasher{}; + hasher.Write(data.data(), data.size()); + hasher.Finalize(out.data()); + hasher.Reset(); + hasher.Write(out.data(), out.size()); + hasher.Finalize(out.data()); + return out; + BC_POP_WARNING() +} + // baseline test runner. // ---------------------------------------------------------------------------- @@ -440,7 +607,8 @@ struct parameters template // bytes per iteration (1KiB) -bool test_hash(std::ostream& out, float ghz = 3.0f, bool csv = false) noexcept +bool test_hash(std::ostream& out, bool csv = use_csv, + float ghz = 3.0f) noexcept { using P = Parameters; using algorithm = typename P::algorithm; @@ -466,6 +634,139 @@ bool test_hash(std::ostream& out, float ghz = 3.0f, bool csv = false) noexcept return true; } +// Defaults to 1Mi rounds over 1KiB data (1GiB). +template // bytes per iteration +bool test_hash_pair(std::ostream& out, bool csv = use_csv, + float ghz = 3.0f) noexcept +{ + using P = Parameters; + using algorithm = typename P::algorithm; + using Precision = std::chrono::nanoseconds; + using Timer = timer; + using params = iif, + sha256_parameters, + rmd160_parameters>; + + uint64_t time = zero; + for (size_t seed = 0; seed < Count; ++seed) + { + const auto data = get_data(seed); + time += Timer::execution([&data]() noexcept + { + base_accumulator(*data, *data); + }); + } + + // Dumping output also precludes compiler removal. + // Return value, check to preclude compiler removal if output is bypassed. + output(out, time, ghz, csv); + return true; +} + +// Defaults to 1Mi rounds over 1KiB data (1GiB). +template // bytes per iteration +bool test_hash_pair_double(std::ostream& out, bool csv = use_csv, + float ghz = 3.0f) noexcept +{ + using P = Parameters; + using algorithm = typename P::algorithm; + using Precision = std::chrono::nanoseconds; + using Timer = timer; + using params = iif, + sha256_parameters, + rmd160_parameters>; + + uint64_t time = zero; + for (size_t seed = 0; seed < Count; ++seed) + { + const auto data = get_data(seed); + time += Timer::execution([&data]() noexcept + { + base_accumulator_double(*data, *data); + }); + } + + // Dumping output also precludes compiler removal. + // Return value, check to preclude compiler removal if output is bypassed. + output(out, time, ghz, csv); + return true; +} + +// Defaults to 1Mi rounds over 1KiB data (1GiB). +template // bytes per iteration +bool test_hash_double(std::ostream& out, bool csv = use_csv, + float ghz = 3.0f) noexcept +{ + using P = Parameters; + using algorithm = typename P::algorithm; + using Precision = std::chrono::nanoseconds; + using Timer = timer; + using params = iif, + sha256_parameters, + rmd160_parameters>; + + uint64_t time = zero; + for (size_t seed = 0; seed < Count; ++seed) + { + const auto data = get_data(seed); + time += Timer::execution([&data]() noexcept + { + base_accumulator_double(*data); + }); + } + + // Dumping output also precludes compiler removal. + // Return value, check to preclude compiler removal if output is bypassed. + output(out, time, ghz, csv); + return true; +} + +// Defaults to 1Mi rounds over 1KiB data (1GiB). +template // number of blocks +bool test_merkle(std::ostream& out, bool csv = use_csv, + float ghz = 3.0f) noexcept +{ + using P = Parameters; + using algorithm = typename P::algorithm; + using Precision = std::chrono::nanoseconds; + using Timer = timer; + using params = iif, + sha256_parameters, + rmd160_parameters>; + + uint64_t time = zero; + for (size_t seed = 0; seed < Count; ++seed) + { + constexpr auto size = array_count; + std::vector digests{}; + digests.reserve(Size * two); + + for (size_t blocks = 0; blocks < Size; ++blocks) + { + digests.push_back(*get_data(blocks + seed)); + digests.push_back(*get_data(blocks + add1(seed))); + } + + time += Timer::execution([&]() noexcept + { + base_merkle(digests); + }); + } + + // Dumping output also precludes compiler removal. + // Return value, check to preclude compiler removal if output is bypassed. + output(out, time, ghz, csv); + return true; +} + } // namespace base } // namespace performance