Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a pool allocator for shared_ptrs with blocks, elections and votes #2047

Merged
merged 3 commits into from Jun 1, 2019

Conversation

2 participants
@wezrule
Copy link
Collaborator

commented May 30, 2019

After profiling heap usage with a high amount of real-time transactions I found a couple places that could benefit from using a memory pool. In #2025 one had been added for block deserialization, however because the block objects were put in a std::shared_ptr after a heap allocation is still done for the control block. After profiling CPU usage it was found there wasn't much improvement (although less heap memory is now allocated). So I'm now using std::allocate_shared which is similar to std::make_shared except you can pass a custom allocator where the memory for both the object and control block can be taken from a pool instead of from the default new. This made the purging of memory at the end a bit more difficult because underneath it uses a boost::singleton_pool which is based on the size of the allocations, which is hidden behind details for how the std::shared_ptr is implemented. Luckily most platforms are quite similar in how they implement std::shared_ptr, Mac/Clang uses 8 more bytes which is checked for. It's not the end of the world if the pools are not purged at the end of main, it will only affect memory analysers.

During node bootstrapping there can be a large number of blocks existing in the block processor (300MB worth on my run). This will never be reclaimed when using a memory pool until the node is stopped. Calling release_memory can be a solution but this only works when an ordered_malloc is used, but I found this to be quite slow. Instead deserialize_block () uses a pool allocator by default, except when bootstrapping and --fast_bootstrap is not used, in which case it will just allocate as normal. So anyone using --fast_bootstrap can benefit from using a memory pool during bootstrapping but the maximum pool size reached will never be deallocated (perhaps this isn't a problem for normal users either?).

A helper guard class has been created which wraps all the necessary memory pool clean up functions.

@wezrule wezrule added the performance label May 30, 2019

@wezrule wezrule added this to the V19.0 milestone May 30, 2019

@wezrule wezrule requested a review from cryptocode May 30, 2019

@wezrule wezrule self-assigned this May 30, 2019

@zhyatt zhyatt added this to RC 4 (TBD) in V19 May 31, 2019

@wezrule wezrule merged commit de64020 into nanocurrency:master Jun 1, 2019

2 checks passed

continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

@wezrule wezrule deleted the wezrule:memory_pool_election_and_votes branch Jun 1, 2019

argakiig added a commit that referenced this pull request Jun 11, 2019

Use a pool allocator for shared_ptrs with blocks, elections and votes (
…#2047)

* Use a pool allocator for shared_ptrs with blocks, elections and votes

* Add config option as to whether to use memory pools
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.