mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-13 11:35:20 +01:00
optimization: refactor: Introduce Uint256ExtraSipHasher to cache SipHash constant state
Previously, only k0 and k1 were stored, causing the constant xor operations to be recomputed in every call to `SipHashUint256Extra`. This commit adds a dedicated `Uint256ExtraSipHasher` class that caches the initial state (v0-v3) and to perform the `SipHash` computation on a `uint256` (with an extra parameter), hiding the constant computation details from higher-level code and improving efficiency. This basically brings the precalculations in the `CSipHasher` constructor to the `uint256` specialized SipHash implementation. > cmake -B build -DBUILD_BENCH=ON -DCMAKE_BUILD_TYPE=Release && cmake --build build -j$(nproc) && build/src/bench/bench_bitcoin -filter='SaltedOutpointHasherBench' -min-time=10000 > C++ compiler .......................... AppleClang 16.0.0.16000026 | ns/op | op/s | err% | total | benchmark |--------------------:|--------------------:|--------:|----------:|:---------- | 57.27 | 17,462,299.19 | 0.1% | 11.02 | `SaltedOutpointHasherBench_create_set` | 11.24 | 88,997,888.48 | 0.3% | 11.04 | `SaltedOutpointHasherBench_hash` | 13.91 | 71,902,014.20 | 0.2% | 11.01 | `SaltedOutpointHasherBench_match` | 13.29 | 75,230,390.31 | 0.1% | 11.00 | `SaltedOutpointHasherBench_mismatch` compared to master: create_set - 17,462,299.19/17,065,922.04 - 2.3% faster hash - 88,997,888.48/83,576,684.83 - 6.4% faster match - 71,902,014.20/68,985,850.12 - 4.2% faster mismatch - 75,230,390.31/71,942,033.47 - 4.5% faster > C++ compiler .......................... GNU 13.3.0 | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- | 135.38 | 7,386,349.49 | 0.0% | 1,078.19 | 486.16 | 2.218 | 119.56 | 1.1% | 11.00 | `SaltedOutpointHasherBench_create_set` | 23.67 | 42,254,558.08 | 0.0% | 247.01 | 85.01 | 2.906 | 4.00 | 0.0% | 11.00 | `SaltedOutpointHasherBench_hash` | 58.95 | 16,962,220.14 | 0.1% | 446.55 | 211.74 | 2.109 | 20.86 | 1.4% | 11.01 | `SaltedOutpointHasherBench_match` | 76.98 | 12,991,047.69 | 0.1% | 548.93 | 276.50 | 1.985 | 20.25 | 2.3% | 10.72 | `SaltedOutpointHasherBench_mismatch` compared to master: create_set - 7,386,349.49/7,312,133.16 - 1% faster hash - 42,254,558.08/41,978,882.62 - 0.6% faster match - 16,962,220.14/16,549,695.42 - 2.4% faster mismatch - 12,991,047.69/12,713,595.35 - 2% faster
This commit is contained in:
parent
39e33d4928
commit
a06a674b43
6 changed files with 27 additions and 21 deletions
|
@ -132,17 +132,12 @@ uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
|
|||
return v0 ^ v1 ^ v2 ^ v3;
|
||||
}
|
||||
|
||||
uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)
|
||||
/* Specialized implementation for efficiency */
|
||||
uint64_t Uint256ExtraSipHasher::operator()(const uint256& val, uint32_t extra) const noexcept
|
||||
{
|
||||
/* Specialized implementation for efficiency */
|
||||
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
|
||||
uint64_t d = val.GetUint64(0);
|
||||
|
||||
// TODO moved in next commit
|
||||
uint64_t v0 = CSipHasher::C0 ^ k0;
|
||||
uint64_t v1 = CSipHasher::C1 ^ k1;
|
||||
uint64_t v2 = CSipHasher::C2 ^ k0;
|
||||
uint64_t v3 = CSipHasher::C3 ^ k1 ^ d;
|
||||
|
||||
v3 ^= d;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= d;
|
||||
|
|
|
@ -48,6 +48,19 @@ public:
|
|||
* .Finalize()
|
||||
*/
|
||||
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
|
||||
uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra);
|
||||
|
||||
class Uint256ExtraSipHasher {
|
||||
uint64_t v[4];
|
||||
|
||||
public:
|
||||
Uint256ExtraSipHasher(const uint64_t k0, const uint64_t k1) noexcept {
|
||||
v[0] = CSipHasher::C0 ^ k0;
|
||||
v[1] = CSipHasher::C1 ^ k1;
|
||||
v[2] = CSipHasher::C2 ^ k0;
|
||||
v[3] = CSipHasher::C3 ^ k1;
|
||||
}
|
||||
|
||||
uint64_t operator()(const uint256& val, uint32_t extra) const noexcept;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_CRYPTO_SIPHASH_H
|
||||
|
|
|
@ -119,7 +119,7 @@ FUZZ_TARGET(integer, .init = initialize_integer)
|
|||
(void)MillisToTimeval(i64);
|
||||
(void)SighashToStr(uch);
|
||||
(void)SipHashUint256(u64, u64, u256);
|
||||
(void)SipHashUint256Extra(u64, u64, u256, u32);
|
||||
(void)Uint256ExtraSipHasher(u64, u64)(u256, u32);
|
||||
(void)ToLower(ch);
|
||||
(void)ToUpper(ch);
|
||||
{
|
||||
|
|
|
@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE(siphash)
|
|||
ss << TX_WITH_WITNESS(tx);
|
||||
BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL);
|
||||
|
||||
// Check consistency between CSipHasher and SipHashUint256[Extra].
|
||||
// Check consistency between CSipHasher and SipHashUint256 and Uint256ExtraSipHasher.
|
||||
FastRandomContext ctx;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
uint64_t k0 = ctx.rand64();
|
||||
|
@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(siphash)
|
|||
CSipHasher sip288 = sip256;
|
||||
sip288.Write(nb);
|
||||
BOOST_CHECK_EQUAL(SipHashUint256(k0, k1, x), sip256.Finalize());
|
||||
BOOST_CHECK_EQUAL(SipHashUint256Extra(k0, k1, x, n), sip288.Finalize()); // TODO modified in follow-up commit
|
||||
BOOST_CHECK_EQUAL(Uint256ExtraSipHasher(k0, k1)(x, n), sip288.Finalize());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@ SaltedTxidHasher::SaltedTxidHasher() :
|
|||
k0{FastRandomContext().rand64()},
|
||||
k1{FastRandomContext().rand64()} {}
|
||||
|
||||
SaltedOutpointHasher::SaltedOutpointHasher(bool deterministic) :
|
||||
k0{deterministic ? 0x8e819f2607a18de6 : FastRandomContext().rand64()},
|
||||
k1{deterministic ? 0xf4020d2e3983b0eb : FastRandomContext().rand64()}
|
||||
SaltedOutpointHasher::SaltedOutpointHasher(bool deterministic) : hasher{
|
||||
deterministic ? 0x8e819f2607a18de6 : FastRandomContext().rand64(),
|
||||
deterministic ? 0xf4020d2e3983b0eb : FastRandomContext().rand64()}
|
||||
{}
|
||||
|
||||
SaltedSipHasher::SaltedSipHasher() :
|
||||
|
|
|
@ -30,12 +30,10 @@ public:
|
|||
|
||||
class SaltedOutpointHasher
|
||||
{
|
||||
private:
|
||||
/** Salt */
|
||||
const uint64_t k0, k1;
|
||||
const Uint256ExtraSipHasher hasher;
|
||||
|
||||
public:
|
||||
SaltedOutpointHasher(bool deterministic = false);
|
||||
explicit SaltedOutpointHasher(bool deterministic = false);
|
||||
|
||||
/**
|
||||
* Having the hash noexcept allows libstdc++'s unordered_map to recalculate
|
||||
|
@ -47,7 +45,7 @@ public:
|
|||
* @see https://gcc.gnu.org/onlinedocs/gcc-13.2.0/libstdc++/manual/manual/unordered_associative.html
|
||||
*/
|
||||
size_t operator()(const COutPoint& id) const noexcept {
|
||||
return SipHashUint256Extra(k0, k1, id.hash, id.n);
|
||||
return hasher(id.hash, id.n);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue