Use a memory pool to reduce block deserialization heap usage (#2025)
* Use a memory pool when deserializing blocks to reduce heap usage * Stop work watcher * Purge memory at end of main * Formatting * Forgot to add it to add purging in rpc_test * Formatting
This commit is contained in:
parent
80370ae4fd
commit
f9021b36e7
10 changed files with 87 additions and 34 deletions
|
@ -1,4 +1,6 @@
|
|||
#include "gtest/gtest.h"
|
||||
|
||||
#include <nano/lib/blocks.hpp>
|
||||
namespace nano
|
||||
{
|
||||
void cleanup_test_directories_on_exit ();
|
||||
|
@ -8,6 +10,7 @@ GTEST_API_ int main (int argc, char ** argv)
|
|||
{
|
||||
printf ("Running main() from core_test_main.cc\n");
|
||||
nano::force_nano_test_network ();
|
||||
nano::block_memory_pool_cleanup_guard block_memory_pool_cleanup_guard;
|
||||
testing::InitGoogleTest (&argc, argv);
|
||||
auto res = RUN_ALL_TESTS ();
|
||||
nano::cleanup_test_directories_on_exit ();
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/pool/singleton_pool.hpp>
|
||||
|
||||
/** Compare blocks, first by type, then content. This is an optimization over dynamic_cast, which is very slow on some platforms. */
|
||||
namespace
|
||||
|
@ -14,6 +15,60 @@ bool blocks_equal (T const & first, nano::block const & second)
|
|||
static_assert (std::is_base_of<nano::block, T>::value, "Input parameter is not a block type");
|
||||
return (first.type () == second.type ()) && (static_cast<T const &> (second)) == first;
|
||||
}
|
||||
|
||||
template <typename tag, typename block_type>
|
||||
using pool = boost::singleton_pool<tag, sizeof (block_type)>;
|
||||
|
||||
template <typename tag, typename block_type>
|
||||
struct pool_deleter
|
||||
{
|
||||
void operator() (block_type * p) const
|
||||
{
|
||||
pool<tag, block_type>::free (p);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename tag, typename block_type>
|
||||
std::shared_ptr<block_type> deserialize_block_from_pool (nano::stream & stream_a)
|
||||
{
|
||||
bool error (false);
|
||||
auto obj_raw = static_cast<block_type *> (pool<tag, block_type>::malloc ());
|
||||
new (obj_raw) block_type (error, stream_a);
|
||||
if (!error)
|
||||
{
|
||||
return std::shared_ptr<block_type> (obj_raw, pool_deleter<tag, block_type>{});
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct state_block_tag
|
||||
{
|
||||
};
|
||||
struct send_block_tag
|
||||
{
|
||||
};
|
||||
struct open_block_tag
|
||||
{
|
||||
};
|
||||
struct change_or_receive_block_tag
|
||||
{
|
||||
};
|
||||
|
||||
// For efficiency as change and receive blocks currently have the same size they share the same memory pool
|
||||
static_assert (nano::change_block::size == nano::receive_block::size, "Change and receive blocks not longer the same size, a new pool is required");
|
||||
}
|
||||
|
||||
nano::block_memory_pool_cleanup_guard::~block_memory_pool_cleanup_guard ()
|
||||
{
|
||||
purge ();
|
||||
}
|
||||
|
||||
void nano::block_memory_pool_cleanup_guard::purge ()
|
||||
{
|
||||
pool<open_block_tag, nano::open_block>::purge_memory ();
|
||||
pool<state_block_tag, nano::state_block>::purge_memory ();
|
||||
pool<send_block_tag, nano::send_block>::purge_memory ();
|
||||
pool<change_or_receive_block_tag, nano::change_block>::purge_memory ();
|
||||
}
|
||||
|
||||
std::string nano::block::to_json () const
|
||||
|
@ -1236,7 +1291,7 @@ std::shared_ptr<nano::block> nano::deserialize_block_json (boost::property_tree:
|
|||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<nano::block> nano::deserialize_block (nano::stream & stream_a, nano::block_uniquer * uniquer_a)
|
||||
std::shared_ptr<nano::block> nano::deserialize_block (nano::stream & stream_a)
|
||||
{
|
||||
nano::block_type type;
|
||||
auto error (try_read (stream_a, type));
|
||||
|
@ -1255,52 +1310,27 @@ std::shared_ptr<nano::block> nano::deserialize_block (nano::stream & stream_a, n
|
|||
{
|
||||
case nano::block_type::receive:
|
||||
{
|
||||
bool error (false);
|
||||
std::unique_ptr<nano::receive_block> obj (new nano::receive_block (error, stream_a));
|
||||
if (!error)
|
||||
{
|
||||
result = std::move (obj);
|
||||
}
|
||||
result = deserialize_block_from_pool<change_or_receive_block_tag, nano::receive_block> (stream_a);
|
||||
break;
|
||||
}
|
||||
case nano::block_type::send:
|
||||
{
|
||||
bool error (false);
|
||||
std::unique_ptr<nano::send_block> obj (new nano::send_block (error, stream_a));
|
||||
if (!error)
|
||||
{
|
||||
result = std::move (obj);
|
||||
}
|
||||
result = deserialize_block_from_pool<send_block_tag, nano::send_block> (stream_a);
|
||||
break;
|
||||
}
|
||||
case nano::block_type::open:
|
||||
{
|
||||
bool error (false);
|
||||
std::unique_ptr<nano::open_block> obj (new nano::open_block (error, stream_a));
|
||||
if (!error)
|
||||
{
|
||||
result = std::move (obj);
|
||||
}
|
||||
result = deserialize_block_from_pool<open_block_tag, nano::open_block> (stream_a);
|
||||
break;
|
||||
}
|
||||
case nano::block_type::change:
|
||||
{
|
||||
bool error (false);
|
||||
std::unique_ptr<nano::change_block> obj (new nano::change_block (error, stream_a));
|
||||
if (!error)
|
||||
{
|
||||
result = std::move (obj);
|
||||
}
|
||||
result = deserialize_block_from_pool<change_or_receive_block_tag, nano::change_block> (stream_a);
|
||||
break;
|
||||
}
|
||||
case nano::block_type::state:
|
||||
{
|
||||
bool error (false);
|
||||
std::unique_ptr<nano::state_block> obj (new nano::state_block (error, stream_a));
|
||||
if (!error)
|
||||
{
|
||||
result = std::move (obj);
|
||||
}
|
||||
result = deserialize_block_from_pool<state_block_tag, nano::state_block> (stream_a);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -356,8 +356,17 @@ private:
|
|||
|
||||
std::unique_ptr<seq_con_info_component> collect_seq_con_info (block_uniquer & block_uniquer, const std::string & name);
|
||||
|
||||
std::shared_ptr<nano::block> deserialize_block (nano::stream &, nano::block_uniquer * = nullptr);
|
||||
std::shared_ptr<nano::block> deserialize_block (nano::stream &);
|
||||
std::shared_ptr<nano::block> deserialize_block (nano::stream &, nano::block_type, nano::block_uniquer * = nullptr);
|
||||
std::shared_ptr<nano::block> deserialize_block_json (boost::property_tree::ptree const &, nano::block_uniquer * = nullptr);
|
||||
void serialize_block (nano::stream &, nano::block const &);
|
||||
|
||||
class block_memory_pool_cleanup_guard final
|
||||
{
|
||||
public:
|
||||
~block_memory_pool_cleanup_guard ();
|
||||
|
||||
private:
|
||||
static void purge ();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ void update_flags (nano::node_flags & flags_a, boost::program_options::variables
|
|||
int main (int argc, char * const * argv)
|
||||
{
|
||||
nano::set_umask ();
|
||||
|
||||
nano::block_memory_pool_cleanup_guard block_memory_pool_cleanup_guard;
|
||||
boost::program_options::options_description description ("Command line options");
|
||||
nano::add_node_options (description);
|
||||
|
||||
|
|
|
@ -372,7 +372,7 @@ int run_wallet (QApplication & application, int argc, char * const * argv, boost
|
|||
int main (int argc, char * const * argv)
|
||||
{
|
||||
nano::set_umask ();
|
||||
|
||||
nano::block_memory_pool_cleanup_guard block_memory_pool_cleanup_guard;
|
||||
try
|
||||
{
|
||||
QApplication application (argc, const_cast<char **> (argv));
|
||||
|
|
|
@ -1763,6 +1763,7 @@ void nano::wallets::stop ()
|
|||
{
|
||||
thread.join ();
|
||||
}
|
||||
watcher.stop ();
|
||||
}
|
||||
|
||||
nano::write_transaction nano::wallets::tx_begin_write ()
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
int main (int argc, char ** argv)
|
||||
{
|
||||
nano::network_constants::set_active_network (nano::nano_networks::nano_test_network);
|
||||
nano::block_memory_pool_cleanup_guard block_memory_pool_cleanup_guard;
|
||||
QApplication application (argc, argv);
|
||||
QCoreApplication::setOrganizationName ("Nano");
|
||||
QCoreApplication::setOrganizationDomain ("nano.org");
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <nano/lib/blocks.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <QApplication>
|
||||
|
@ -11,6 +13,7 @@ void force_nano_test_network ();
|
|||
int main (int argc, char ** argv)
|
||||
{
|
||||
nano::force_nano_test_network ();
|
||||
nano::block_memory_pool_cleanup_guard block_memory_pool_cleanup_guard;
|
||||
QApplication application (argc, argv);
|
||||
test_application = &application;
|
||||
testing::InitGoogleTest (&argc, argv);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <nano/lib/blocks.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
namespace nano
|
||||
{
|
||||
|
@ -8,6 +10,7 @@ void force_nano_test_network ();
|
|||
int main (int argc, char ** argv)
|
||||
{
|
||||
nano::force_nano_test_network ();
|
||||
nano::block_memory_pool_cleanup_guard block_memory_pool_cleanup_guard;
|
||||
testing::InitGoogleTest (&argc, argv);
|
||||
auto res = RUN_ALL_TESTS ();
|
||||
nano::cleanup_test_directories_on_exit ();
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <nano/lib/blocks.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
namespace nano
|
||||
{
|
||||
|
@ -8,6 +10,7 @@ void force_nano_test_network ();
|
|||
int main (int argc, char ** argv)
|
||||
{
|
||||
nano::force_nano_test_network ();
|
||||
nano::block_memory_pool_cleanup_guard block_memory_pool_cleanup_guard;
|
||||
testing::InitGoogleTest (&argc, argv);
|
||||
auto res = RUN_ALL_TESTS ();
|
||||
nano::cleanup_test_directories_on_exit ();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue