Changeset View
Changeset View
Standalone View
Standalone View
src/test/validation_flush_tests.cpp
Show First 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | auto print_view_mem_usage = [](CCoinsViewCache &_view) { | ||||
BOOST_TEST_MESSAGE( | BOOST_TEST_MESSAGE( | ||||
"CCoinsViewCache memory usage: " << _view.DynamicMemoryUsage()); | "CCoinsViewCache memory usage: " << _view.DynamicMemoryUsage()); | ||||
}; | }; | ||||
constexpr size_t MAX_COINS_CACHE_BYTES = 1024; | constexpr size_t MAX_COINS_CACHE_BYTES = 1024; | ||||
// Without any coins in the cache, we shouldn't need to flush. | // Without any coins in the cache, we shouldn't need to flush. | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
chainstate.GetCoinsCacheSizeState(tx_pool, MAX_COINS_CACHE_BYTES, | chainstate.GetCoinsCacheSizeState(&tx_pool, MAX_COINS_CACHE_BYTES, | ||||
/*max_mempool_size_bytes*/ 0), | /*max_mempool_size_bytes*/ 0), | ||||
CoinsCacheSizeState::OK); | CoinsCacheSizeState::OK); | ||||
// If the initial memory allocations of cacheCoins don't match these common | // If the initial memory allocations of cacheCoins don't match these common | ||||
// cases, we can't really continue to make assertions about memory usage. | // cases, we can't really continue to make assertions about memory usage. | ||||
// End the test early. | // End the test early. | ||||
if (view.DynamicMemoryUsage() != 32 && view.DynamicMemoryUsage() != 16) { | if (view.DynamicMemoryUsage() != 32 && view.DynamicMemoryUsage() != 16) { | ||||
// Add a bunch of coins to see that we at least flip over to CRITICAL. | // Add a bunch of coins to see that we at least flip over to CRITICAL. | ||||
for (int i{0}; i < 1000; ++i) { | for (int i{0}; i < 1000; ++i) { | ||||
COutPoint res = add_coin(view); | COutPoint res = add_coin(view); | ||||
BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), | BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), | ||||
COIN_SIZE); | COIN_SIZE); | ||||
} | } | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
chainstate.GetCoinsCacheSizeState(tx_pool, MAX_COINS_CACHE_BYTES, | chainstate.GetCoinsCacheSizeState(&tx_pool, MAX_COINS_CACHE_BYTES, | ||||
/*max_mempool_size_bytes*/ 0), | /*max_mempool_size_bytes*/ 0), | ||||
CoinsCacheSizeState::CRITICAL); | CoinsCacheSizeState::CRITICAL); | ||||
BOOST_TEST_MESSAGE( | BOOST_TEST_MESSAGE( | ||||
"Exiting cache flush tests early due to unsupported arch"); | "Exiting cache flush tests early due to unsupported arch"); | ||||
return; | return; | ||||
} | } | ||||
print_view_mem_usage(view); | print_view_mem_usage(view); | ||||
BOOST_CHECK_EQUAL(view.DynamicMemoryUsage(), is_64_bit ? 32U : 16U); | BOOST_CHECK_EQUAL(view.DynamicMemoryUsage(), is_64_bit ? 32U : 16U); | ||||
// We should be able to add COINS_UNTIL_CRITICAL coins to the cache before | // We should be able to add COINS_UNTIL_CRITICAL coins to the cache before | ||||
// going CRITICAL. This is contingent not only on the dynamic memory usage | // going CRITICAL. This is contingent not only on the dynamic memory usage | ||||
// of the Coins that we're adding (COIN_SIZE bytes per), but also on how | // of the Coins that we're adding (COIN_SIZE bytes per), but also on how | ||||
// much memory the cacheCoins (unordered_map) preallocates. | // much memory the cacheCoins (unordered_map) preallocates. | ||||
constexpr int COINS_UNTIL_CRITICAL{3}; | constexpr int COINS_UNTIL_CRITICAL{3}; | ||||
for (int i{0}; i < COINS_UNTIL_CRITICAL; ++i) { | for (int i{0}; i < COINS_UNTIL_CRITICAL; ++i) { | ||||
COutPoint res = add_coin(view); | COutPoint res = add_coin(view); | ||||
print_view_mem_usage(view); | print_view_mem_usage(view); | ||||
BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE); | BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE); | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
chainstate.GetCoinsCacheSizeState(tx_pool, MAX_COINS_CACHE_BYTES, | chainstate.GetCoinsCacheSizeState(&tx_pool, MAX_COINS_CACHE_BYTES, | ||||
/*max_mempool_size_bytes*/ 0), | /*max_mempool_size_bytes*/ 0), | ||||
CoinsCacheSizeState::OK); | CoinsCacheSizeState::OK); | ||||
} | } | ||||
// Adding some additional coins will push us over the edge to CRITICAL. | // Adding some additional coins will push us over the edge to CRITICAL. | ||||
for (int i{0}; i < 4; ++i) { | for (int i{0}; i < 4; ++i) { | ||||
add_coin(view); | add_coin(view); | ||||
print_view_mem_usage(view); | print_view_mem_usage(view); | ||||
if (chainstate.GetCoinsCacheSizeState(tx_pool, MAX_COINS_CACHE_BYTES, | if (chainstate.GetCoinsCacheSizeState(&tx_pool, MAX_COINS_CACHE_BYTES, | ||||
/*max_mempool_size_bytes*/ 0) == | /*max_mempool_size_bytes*/ 0) == | ||||
CoinsCacheSizeState::CRITICAL) { | CoinsCacheSizeState::CRITICAL) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
chainstate.GetCoinsCacheSizeState(tx_pool, MAX_COINS_CACHE_BYTES, | chainstate.GetCoinsCacheSizeState(&tx_pool, MAX_COINS_CACHE_BYTES, | ||||
/*max_mempool_size_bytes*/ 0), | /*max_mempool_size_bytes*/ 0), | ||||
CoinsCacheSizeState::CRITICAL); | CoinsCacheSizeState::CRITICAL); | ||||
// Passing non-zero max mempool usage should allow us more headroom. | // Passing non-zero max mempool usage should allow us more headroom. | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
chainstate.GetCoinsCacheSizeState(tx_pool, MAX_COINS_CACHE_BYTES, | chainstate.GetCoinsCacheSizeState(&tx_pool, MAX_COINS_CACHE_BYTES, | ||||
/*max_mempool_size_bytes*/ 1 << 10), | /*max_mempool_size_bytes*/ 1 << 10), | ||||
CoinsCacheSizeState::OK); | CoinsCacheSizeState::OK); | ||||
for (int i{0}; i < 3; ++i) { | for (int i{0}; i < 3; ++i) { | ||||
add_coin(view); | add_coin(view); | ||||
print_view_mem_usage(view); | print_view_mem_usage(view); | ||||
BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState( | BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState( | ||||
tx_pool, MAX_COINS_CACHE_BYTES, | &tx_pool, MAX_COINS_CACHE_BYTES, | ||||
/*max_mempool_size_bytes*/ 1 << 10), | /*max_mempool_size_bytes*/ 1 << 10), | ||||
CoinsCacheSizeState::OK); | CoinsCacheSizeState::OK); | ||||
} | } | ||||
// Adding another coin with the additional mempool room will put us >90% | // Adding another coin with the additional mempool room will put us >90% | ||||
// but not yet critical. | // but not yet critical. | ||||
add_coin(view); | add_coin(view); | ||||
print_view_mem_usage(view); | print_view_mem_usage(view); | ||||
// Only perform these checks on 64 bit hosts; I haven't done the math | // Only perform these checks on 64 bit hosts; I haven't done the math | ||||
// for 32. | // for 32. | ||||
if (is_64_bit) { | if (is_64_bit) { | ||||
float usage_percentage = (float)view.DynamicMemoryUsage() / | float usage_percentage = (float)view.DynamicMemoryUsage() / | ||||
(MAX_COINS_CACHE_BYTES + (1 << 10)); | (MAX_COINS_CACHE_BYTES + (1 << 10)); | ||||
BOOST_TEST_MESSAGE("CoinsTip usage percentage: " << usage_percentage); | BOOST_TEST_MESSAGE("CoinsTip usage percentage: " << usage_percentage); | ||||
BOOST_CHECK(usage_percentage >= 0.9); | BOOST_CHECK(usage_percentage >= 0.9); | ||||
BOOST_CHECK(usage_percentage < 1); | BOOST_CHECK(usage_percentage < 1); | ||||
BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState( | BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState( | ||||
tx_pool, MAX_COINS_CACHE_BYTES, 1 << 10), | &tx_pool, MAX_COINS_CACHE_BYTES, 1 << 10), | ||||
CoinsCacheSizeState::LARGE); | CoinsCacheSizeState::LARGE); | ||||
} | } | ||||
// Using the default max_* values permits way more coins to be added. | // Using the default max_* values permits way more coins to be added. | ||||
for (int i{0}; i < 1000; ++i) { | for (int i{0}; i < 1000; ++i) { | ||||
add_coin(view); | add_coin(view); | ||||
BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState(tx_pool), | BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState(&tx_pool), | ||||
CoinsCacheSizeState::OK); | CoinsCacheSizeState::OK); | ||||
} | } | ||||
// Flushing the view doesn't take us back to OK because cacheCoins has | // Flushing the view doesn't take us back to OK because cacheCoins has | ||||
// preallocated memory that doesn't get reclaimed even after flush. | // preallocated memory that doesn't get reclaimed even after flush. | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
chainstate.GetCoinsCacheSizeState(tx_pool, MAX_COINS_CACHE_BYTES, 0), | chainstate.GetCoinsCacheSizeState(&tx_pool, MAX_COINS_CACHE_BYTES, 0), | ||||
CoinsCacheSizeState::CRITICAL); | CoinsCacheSizeState::CRITICAL); | ||||
view.SetBestBlock(BlockHash(InsecureRand256())); | view.SetBestBlock(BlockHash(InsecureRand256())); | ||||
BOOST_CHECK(view.Flush()); | BOOST_CHECK(view.Flush()); | ||||
print_view_mem_usage(view); | print_view_mem_usage(view); | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
chainstate.GetCoinsCacheSizeState(tx_pool, MAX_COINS_CACHE_BYTES, 0), | chainstate.GetCoinsCacheSizeState(&tx_pool, MAX_COINS_CACHE_BYTES, 0), | ||||
CoinsCacheSizeState::CRITICAL); | CoinsCacheSizeState::CRITICAL); | ||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |