From fa9ddb01c96b1f0a9d0b73ab3c0148e59fac325f Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Thu, 23 Apr 2026 13:48:11 +0200 Subject: [PATCH 1/3] test: Use MiB operator directly in cuckoocache_tests Previously, they were using a pattern of defininig a constant megabytes symbol, and then multiplying that by 1_MiB. It is easier to use the _MiB operator directly. --- src/test/cuckoocache_tests.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp index 9d2cb8e4cc4..7566d22262d 100644 --- a/src/test/cuckoocache_tests.cpp +++ b/src/test/cuckoocache_tests.cpp @@ -50,16 +50,15 @@ BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes) }; struct HitRateTest : BasicTestingSetup { -/** This helper returns the hit rate when megabytes*load worth of entries are - * inserted into a megabytes sized cache +/** This helper returns the hit rate when bytes*load worth of entries are + * inserted into a bytes sized cache */ template -double test_cache(size_t megabytes, double load) +double test_cache(size_t bytes, double load) { SeedRandomForTest(SeedRand::ZEROS); std::vector hashes; Cache set{}; - size_t bytes{megabytes * 1_MiB}; set.setup_bytes(bytes); uint32_t n_insert = static_cast(load * (bytes / sizeof(uint256))); hashes.resize(n_insert); @@ -114,9 +113,8 @@ BOOST_FIXTURE_TEST_CASE(cuckoocache_hit_rate_ok, HitRateTest) * as a lower bound on performance. */ double HitRateThresh = 0.98; - size_t megabytes = 4; for (double load = 0.1; load < 2; load *= 2) { - double hits = test_cache>(megabytes, load); + double hits = test_cache>(4_MiB, load); BOOST_CHECK(normalize_hit_rate(hits, load) > HitRateThresh); } } @@ -126,13 +124,12 @@ struct EraseTest : BasicTestingSetup { /** This helper checks that erased elements are preferentially inserted onto and * that the hit rate of "fresher" keys is reasonable*/ template -void test_cache_erase(size_t megabytes) +void test_cache_erase(size_t bytes) { double load = 1; SeedRandomForTest(SeedRand::ZEROS); std::vector hashes; Cache set{}; - size_t bytes{megabytes * 1_MiB}; set.setup_bytes(bytes); uint32_t n_insert = static_cast(load * (bytes / sizeof(uint256))); hashes.resize(n_insert); @@ -185,19 +182,17 @@ void test_cache_erase(size_t megabytes) BOOST_FIXTURE_TEST_CASE(cuckoocache_erase_ok, EraseTest) { - size_t megabytes = 4; - test_cache_erase>(megabytes); + test_cache_erase>(4_MiB); } struct EraseParallelTest : BasicTestingSetup { template -void test_cache_erase_parallel(size_t megabytes) +void test_cache_erase_parallel(size_t bytes) { double load = 1; SeedRandomForTest(SeedRand::ZEROS); std::vector hashes; Cache set{}; - size_t bytes{megabytes * 1_MiB}; set.setup_bytes(bytes); uint32_t n_insert = static_cast(load * (bytes / sizeof(uint256))); hashes.resize(n_insert); @@ -277,8 +272,7 @@ void test_cache_erase_parallel(size_t megabytes) }; // struct EraseParallelTest BOOST_FIXTURE_TEST_CASE(cuckoocache_erase_parallel_ok, EraseParallelTest) { - size_t megabytes = 4; - test_cache_erase_parallel>(megabytes); + test_cache_erase_parallel>(4_MiB); } From fa5801762e38c0776145c9b4dfe68a554dfd4585 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 17 Apr 2026 12:55:30 +0200 Subject: [PATCH 2/3] util: Return uint64_t from _MiB and _GiB operators --- src/node/caches.cpp | 2 +- src/test/util_tests.cpp | 48 ++++++++++++++++++++--------------------- src/util/byte_units.h | 18 ++++++++-------- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/src/node/caches.cpp b/src/node/caches.cpp index 3b9e609f367..3250c51a8c2 100644 --- a/src/node/caches.cpp +++ b/src/node/caches.cpp @@ -30,7 +30,7 @@ static constexpr size_t MAX_32BIT_DBCACHE{1_GiB}; //! Larger default dbcache on 64-bit systems with enough RAM. static constexpr size_t HIGH_DEFAULT_DBCACHE{1_GiB}; //! Minimum detected RAM required for HIGH_DEFAULT_DBCACHE. -static constexpr uint64_t HIGH_DEFAULT_DBCACHE_MIN_TOTAL_RAM{uint64_t{4} * 1_GiB}; +static constexpr uint64_t HIGH_DEFAULT_DBCACHE_MIN_TOTAL_RAM{4_GiB}; namespace node { size_t GetDefaultDBCache() diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index a407d7d3fdc..5747c3b080e 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,7 @@ #include #include #include -#include +#include #include #include @@ -1827,6 +1828,9 @@ BOOST_AUTO_TEST_CASE(saturating_left_shift_test) TestSaturatingLeftShift(); } +template +concept BraceInitializesTo = requires { Int{bytes}; }; + BOOST_AUTO_TEST_CASE(mib_string_literal_test) { // Basic equivalences and simple arithmetic operations @@ -1850,16 +1854,12 @@ BOOST_AUTO_TEST_CASE(mib_string_literal_test) BOOST_CHECK_EQUAL(128_MiB, 0x8000000U); BOOST_CHECK_EQUAL(550_MiB, 550ULL * 1024 * 1024); - // Overflow handling - constexpr auto max_mib{std::numeric_limits::max() >> 20}; - if constexpr (SIZE_MAX == UINT32_MAX) { - BOOST_CHECK_EQUAL(max_mib, 4095U); - BOOST_CHECK_EQUAL(4095_MiB, size_t{4095} << 20); - BOOST_CHECK_EXCEPTION(4096_MiB, std::overflow_error, HasReason("MiB value too large for size_t byte conversion")); - } else { - BOOST_CHECK_EQUAL(4096_MiB, size_t{4096} << 20); - } - BOOST_CHECK_EXCEPTION(operator""_MiB(max_mib + 1), std::overflow_error, HasReason("MiB value too large for size_t byte conversion")); + // 4095 MiB fits in uint32_t bytes. 4096 MiB requires the uint64_t return type. + static_assert(BraceInitializesTo); + static_assert(!BraceInitializesTo); + static_assert(BraceInitializesTo); + BOOST_CHECK_EQUAL(4095_MiB, uint32_t{4095} << 20); + BOOST_CHECK_EQUAL(4096_MiB, uint64_t{4096} << 20); } BOOST_AUTO_TEST_CASE(ceil_div_test) @@ -1916,20 +1916,18 @@ BOOST_AUTO_TEST_CASE(gib_string_literal_test) BOOST_CHECK_EQUAL(3_GiB / 1_GiB, 3U); BOOST_CHECK_EQUAL(3_GiB, 3U << 30); - // Overflow handling and specific codebase values - constexpr auto max_gib{std::numeric_limits::max() >> 30}; - if constexpr (SIZE_MAX == UINT32_MAX) { - BOOST_CHECK_EQUAL(max_gib, 3U); - BOOST_CHECK_EXCEPTION(4_GiB, std::overflow_error, HasReason("GiB value too large for size_t byte conversion")); - } else { - BOOST_CHECK_GT(max_gib, 3U); - BOOST_CHECK_EQUAL(4_GiB, size_t{4} << 30); - BOOST_CHECK_EQUAL(4_GiB, 4096_MiB); - BOOST_CHECK_EQUAL(8_GiB, 8192_MiB); - BOOST_CHECK_EQUAL(16_GiB, 16384_MiB); - BOOST_CHECK_EQUAL(32_GiB, 32768_MiB); - } - BOOST_CHECK_EXCEPTION(operator""_GiB(max_gib + 1), std::overflow_error, HasReason("GiB value too large for size_t byte conversion")); + // 3 GiB fits in uint32_t bytes. 4 GiB requires the uint64_t return type. + static_assert(BraceInitializesTo); + static_assert(!BraceInitializesTo); + static_assert(BraceInitializesTo); + BOOST_CHECK_EQUAL(3_GiB, uint32_t{3} << 30); + BOOST_CHECK_EQUAL(4_GiB, uint64_t{4} << 30); + + // Specific codebase values + BOOST_CHECK_EQUAL(4_GiB, 4096_MiB); + BOOST_CHECK_EQUAL(8_GiB, 8192_MiB); + BOOST_CHECK_EQUAL(16_GiB, 16384_MiB); + BOOST_CHECK_EQUAL(32_GiB, 32768_MiB); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/util/byte_units.h b/src/util/byte_units.h index b67af5a48e4..27d13b08dd9 100644 --- a/src/util/byte_units.h +++ b/src/util/byte_units.h @@ -12,26 +12,26 @@ namespace util::detail { template -constexpr size_t ByteUnitsToBytes(unsigned long long units, const char* exception_msg) +consteval uint64_t ByteUnitsToBytes(unsigned long long units) { const auto bytes{CheckedLeftShift(units, SHIFT)}; - if (!bytes || *bytes > std::numeric_limits::max()) { - throw std::overflow_error(exception_msg); + if (!bytes || *bytes > std::numeric_limits::max()) { + throw std::overflow_error("Too large"); } return *bytes; } } // namespace util::detail -//! Overflow-safe conversion of MiB to bytes. -constexpr size_t operator""_MiB(unsigned long long mebibytes) +/// Conversion of MiB to bytes. +consteval uint64_t operator""_MiB(unsigned long long mebibytes) { - return util::detail::ByteUnitsToBytes<20>(mebibytes, "MiB value too large for size_t byte conversion"); + return util::detail::ByteUnitsToBytes<20>(mebibytes); } -//! Overflow-safe conversion of GiB to bytes. -constexpr size_t operator""_GiB(unsigned long long gibibytes) +/// Conversion of GiB to bytes. +consteval uint64_t operator""_GiB(unsigned long long gibibytes) { - return util::detail::ByteUnitsToBytes<30>(gibibytes, "GiB value too large for size_t byte conversion"); + return util::detail::ByteUnitsToBytes<30>(gibibytes); } #endif // BITCOIN_UTIL_BYTE_UNITS_H From fa43da21f1979bd8ef52d895d970f19dbb5c8c9e Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 24 Apr 2026 08:55:47 +0200 Subject: [PATCH 3/3] refactor: Run ShouldWarnOversizedDbCache calculation in u64 This follows the approach of the MiB and GiB operators. This allows to remove some `if constexpr (SIZE_MAX == UINT64_MAX)` in the tests. --- src/node/caches.h | 4 ++-- src/test/caches_tests.cpp | 26 ++++++++++++-------------- src/test/system_ram_tests.cpp | 7 +------ 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/node/caches.h b/src/node/caches.h index 483521dfcfc..f4143bed44f 100644 --- a/src/node/caches.h +++ b/src/node/caches.h @@ -29,9 +29,9 @@ struct CacheSizes { kernel::CacheSizes kernel; }; CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes = 0); -constexpr bool ShouldWarnOversizedDbCache(size_t dbcache, size_t total_ram) noexcept +constexpr bool ShouldWarnOversizedDbCache(uint64_t dbcache, uint64_t total_ram) noexcept { - const size_t cap{(total_ram < 2_GiB) ? DEFAULT_DB_CACHE : (total_ram / 100) * 75}; + const uint64_t cap{(total_ram < 2_GiB) ? DEFAULT_DB_CACHE : (total_ram / 100) * 75}; return dbcache > cap; } diff --git a/src/test/caches_tests.cpp b/src/test/caches_tests.cpp index bdca1d40f82..69c42f0bbf1 100644 --- a/src/test/caches_tests.cpp +++ b/src/test/caches_tests.cpp @@ -22,23 +22,21 @@ BOOST_AUTO_TEST_CASE(oversized_dbcache_warning) BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/1500_MiB, /*total_ram=*/2_GiB)); // Under cap BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/1600_MiB, /*total_ram=*/2_GiB)); // Over cap - if constexpr (SIZE_MAX == UINT64_MAX) { - // 4 GiB RAM - cap is 75% - BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/2500_MiB, /*total_ram=*/4_GiB)); // Under cap - BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/3500_MiB, /*total_ram=*/4_GiB)); // Over cap + // 4 GiB RAM - cap is 75% + BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/2500_MiB, /*total_ram=*/4_GiB)); // Under cap + BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/3500_MiB, /*total_ram=*/4_GiB)); // Over cap - // 8 GiB RAM - cap is 75% - BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/6000_MiB, /*total_ram=*/8_GiB)); // Under cap - BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/7000_MiB, /*total_ram=*/8_GiB)); // Over cap + // 8 GiB RAM - cap is 75% + BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/6000_MiB, /*total_ram=*/8_GiB)); // Under cap + BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/7000_MiB, /*total_ram=*/8_GiB)); // Over cap - // 16 GiB RAM - cap is 75% - BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/10'000_MiB, /*total_ram=*/16_GiB)); // Under cap - BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/15'000_MiB, /*total_ram=*/16_GiB)); // Over cap + // 16 GiB RAM - cap is 75% + BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/10_GiB, /*total_ram=*/16_GiB)); // Under cap + BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/15_GiB, /*total_ram=*/16_GiB)); // Over cap - // 32 GiB RAM - cap is 75% - BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/20'000_MiB, /*total_ram=*/32_GiB)); // Under cap - BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/30'000_MiB, /*total_ram=*/32_GiB)); // Over cap - } + // 32 GiB RAM - cap is 75% + BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/20_GiB, /*total_ram=*/32_GiB)); // Under cap + BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/30_GiB, /*total_ram=*/32_GiB)); // Over cap } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/system_ram_tests.cpp b/src/test/system_ram_tests.cpp index 8ad622642f5..4eb4e1e3e52 100644 --- a/src/test/system_ram_tests.cpp +++ b/src/test/system_ram_tests.cpp @@ -21,12 +21,7 @@ BOOST_AUTO_TEST_CASE(total_ram) } BOOST_CHECK_GE(*total, 1000_MiB); - - if constexpr (SIZE_MAX == UINT64_MAX) { - // Upper bound check only on 64-bit: 32-bit systems can reasonably have max memory, - // but extremely large values on 64-bit likely indicate detection errors - BOOST_CHECK_LT(*total, 10'000'000_MiB); // >10 TiB memory is unlikely - } + BOOST_CHECK_LT(*total, 10'000_GiB); // ~10 TiB memory is unlikely } BOOST_AUTO_TEST_SUITE_END()