From 1918155b13596bf219aa4de3aedf860e8e2c7979 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Mon, 18 Mar 2024 11:31:51 -0400 Subject: [PATCH 1/4] Replace hacky version of `calculate_max_depth` with simpler one. --- .../eosio/chain/incremental_merkle.hpp | 56 ++----------------- 1 file changed, 6 insertions(+), 50 deletions(-) diff --git a/libraries/chain/include/eosio/chain/incremental_merkle.hpp b/libraries/chain/include/eosio/chain/incremental_merkle.hpp index 0a84d076f5..090e2f4b5e 100644 --- a/libraries/chain/include/eosio/chain/incremental_merkle.hpp +++ b/libraries/chain/include/eosio/chain/incremental_merkle.hpp @@ -3,52 +3,10 @@ #include #include -namespace eosio { namespace chain { +namespace eosio::chain { namespace detail { -/** - * given an unsigned integral number return the smallest - * power-of-2 which is greater than or equal to the given number - * - * @param value - an unsigned integral - * @return - the minimum power-of-2 which is >= value - */ -constexpr uint64_t next_power_of_2(uint64_t value) { - value -= 1; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - value |= value >> 32; - value += 1; - return value; -} - -/** - * Given a power-of-2 (assumed correct) return the number of leading zeros - * - * This is a classic count-leading-zeros in parallel without the necessary - * math to make it safe for anything that is not already a power-of-2 - * - * @param value - and integral power-of-2 - * @return the number of leading zeros - */ -constexpr int clz_power_2(uint64_t value) { - int lz = 64; - - if (value) lz--; - if (value & 0x00000000FFFFFFFFULL) lz -= 32; - if (value & 0x0000FFFF0000FFFFULL) lz -= 16; - if (value & 0x00FF00FF00FF00FFULL) lz -= 8; - if (value & 0x0F0F0F0F0F0F0F0FULL) lz -= 4; - if (value & 0x3333333333333333ULL) lz -= 2; - if (value & 0x5555555555555555ULL) lz -= 1; - - return lz; -} - /** * Given a number of nodes return the depth required to store them * in a fully balanced binary tree. @@ -56,12 +14,10 @@ constexpr int clz_power_2(uint64_t value) { * @param node_count - the number of nodes in the implied tree * @return the max depth of the minimal tree that stores them */ -constexpr int calcluate_max_depth(uint64_t node_count) { - if (node_count == 0) { +constexpr uint64_t calculate_max_depth(uint64_t node_count) { + if (node_count == 0) return 0; - } - auto implied_count = next_power_of_2(node_count); - return clz_power_2(implied_count) + 1; + return std::llround(std::ceil(std::log2(node_count))) + 1; } template @@ -167,7 +123,7 @@ class incremental_merkle_impl { */ const DigestType& append(const DigestType& digest) { bool partial = false; - auto max_depth = detail::calcluate_max_depth(_node_count + 1); + auto max_depth = detail::calculate_max_depth(_node_count + 1); auto current_depth = max_depth - 1; auto index = _node_count; auto top = digest; @@ -246,6 +202,6 @@ class incremental_merkle_impl { typedef incremental_merkle_impl incremental_merkle; typedef incremental_merkle_impl shared_incremental_merkle; -} } /// eosio::chain +} /// eosio::chain FC_REFLECT( eosio::chain::incremental_merkle, (_active_nodes)(_node_count) ); From cdb766b10aa33bd83ddc341a23876574d0c9d510 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Mon, 18 Mar 2024 13:48:04 -0400 Subject: [PATCH 2/4] Use Matt's non-floating point implementation of `calculate_max_depth`. --- libraries/chain/include/eosio/chain/incremental_merkle.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/incremental_merkle.hpp b/libraries/chain/include/eosio/chain/incremental_merkle.hpp index 090e2f4b5e..56708f7be0 100644 --- a/libraries/chain/include/eosio/chain/incremental_merkle.hpp +++ b/libraries/chain/include/eosio/chain/incremental_merkle.hpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace eosio::chain { @@ -17,7 +18,8 @@ namespace detail { constexpr uint64_t calculate_max_depth(uint64_t node_count) { if (node_count == 0) return 0; - return std::llround(std::ceil(std::log2(node_count))) + 1; + // following is non-floating point equivalent to `std::ceil(std::log2(node_count)) + 1) + return 8*sizeof(node_count) - std::countl_zero(std::bit_ceil(node_count)); } template From dce42d13eb7ca217e6814ec3249e54791b01f76f Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Mon, 18 Mar 2024 13:53:11 -0400 Subject: [PATCH 3/4] Update comment. --- libraries/chain/include/eosio/chain/incremental_merkle.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/incremental_merkle.hpp b/libraries/chain/include/eosio/chain/incremental_merkle.hpp index 56708f7be0..8f06c8205f 100644 --- a/libraries/chain/include/eosio/chain/incremental_merkle.hpp +++ b/libraries/chain/include/eosio/chain/incremental_merkle.hpp @@ -18,7 +18,7 @@ namespace detail { constexpr uint64_t calculate_max_depth(uint64_t node_count) { if (node_count == 0) return 0; - // following is non-floating point equivalent to `std::ceil(std::log2(node_count)) + 1) + // following is non-floating point equivalent to `std::ceil(std::log2(node_count)) + 1)` (and about 9x faster) return 8*sizeof(node_count) - std::countl_zero(std::bit_ceil(node_count)); } From c365b9c0bb1683eab0c77602fa272f605ffd0eeb Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Mon, 18 Mar 2024 16:06:01 -0400 Subject: [PATCH 4/4] Use improved version from Matt. --- libraries/chain/include/eosio/chain/incremental_merkle.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/incremental_merkle.hpp b/libraries/chain/include/eosio/chain/incremental_merkle.hpp index 8f06c8205f..68b4348e9d 100644 --- a/libraries/chain/include/eosio/chain/incremental_merkle.hpp +++ b/libraries/chain/include/eosio/chain/incremental_merkle.hpp @@ -19,7 +19,7 @@ constexpr uint64_t calculate_max_depth(uint64_t node_count) { if (node_count == 0) return 0; // following is non-floating point equivalent to `std::ceil(std::log2(node_count)) + 1)` (and about 9x faster) - return 8*sizeof(node_count) - std::countl_zero(std::bit_ceil(node_count)); + return std::bit_width(std::bit_ceil(node_count)); } template