From 148b9dd29482e466188b7fec4099ddbf622ebe05 Mon Sep 17 00:00:00 2001 From: SChernykh Date: Fri, 22 Oct 2021 18:18:38 +0200 Subject: [PATCH] Switch to faster unordered_map/set --- .gitmodules | 3 +++ CMakeLists.txt | 1 + cppcheck/includes.txt | 1 + cppcheck/run.sh | 2 +- external/src/robin-hood-hashing | 1 + src/common.h | 5 +++++ src/crypto.cpp | 5 ++--- src/memory_leak_debug.cpp | 33 ++++++++++++++++++----------- src/mempool.h | 3 +-- src/p2p_server.h | 3 +-- src/p2pool.h | 3 +-- src/p2pool_api.cpp | 2 +- src/p2pool_api.h | 3 +-- src/side_chain.h | 8 +++---- src/util.h | 37 ++++++++++++++++++++++----------- tests/CMakeLists.txt | 2 ++ 16 files changed, 70 insertions(+), 42 deletions(-) create mode 160000 external/src/robin-hood-hashing diff --git a/.gitmodules b/.gitmodules index 61b548e..fbd4f02 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "external/src/libzmq"] path = external/src/libzmq url = https://github.com/SChernykh/libzmq +[submodule "external/src/robin-hood-hashing"] + path = external/src/robin-hood-hashing + url = https://github.com/SChernykh/robin-hood-hashing diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d59c4e..ec0b17b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,7 @@ include_directories(external/src/libzmq/include) include_directories(external/src/llhttp) include_directories(external/src/RandomX/src) include_directories(external/src/rapidjson/include) +include_directories(external/src/robin-hood-hashing/src/include) if (WIN32) set(LIBS ${LIBS} ws2_32 iphlpapi userenv psapi) diff --git a/cppcheck/includes.txt b/cppcheck/includes.txt index 49bc56c..a004882 100644 --- a/cppcheck/includes.txt +++ b/cppcheck/includes.txt @@ -7,3 +7,4 @@ ../external/src/llhttp/ ../external/src/RandomX/src/ ../external/src/rapidjson/include +../external/src/robin-hood-hashing/src/include diff --git a/cppcheck/run.sh b/cppcheck/run.sh index f8bc7db..243d262 100755 --- a/cppcheck/run.sh +++ b/cppcheck/run.sh @@ -1,5 +1,5 @@ #!/bin/bash -cppcheck ../src -DZMQ_STATIC --platform=unix64 --std=c++14 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" -I ../src/ -I ../external/src/ -I ../external/src/cryptonote/ -I ../external/src/libuv/ -I ../external/src/cppzmq/ -I ../external/src/libzmq/ -I ../external/src/llhttp/ -I ../external/src/RandomX/src/ -I ../external/src/rapidjson/include --suppressions-list=suppressions.txt --output-file=errors_full.txt +cppcheck ../src -DZMQ_STATIC --platform=unix64 --std=c++14 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" -I ../src/ -I ../external/src/ -I ../external/src/cryptonote/ -I ../external/src/libuv/ -I ../external/src/cppzmq/ -I ../external/src/libzmq/ -I ../external/src/llhttp/ -I ../external/src/RandomX/src/ -I ../external/src/rapidjson/include -I ../external/src/robin-hood-hashing/src/include --suppressions-list=suppressions.txt --output-file=errors_full.txt grep -v 'external' errors_full.txt | grep -v 'unmatchedSuppression' > errors_filtered.txt if [ -s errors_filtered.txt ]; then cat errors_filtered.txt diff --git a/external/src/robin-hood-hashing b/external/src/robin-hood-hashing new file mode 160000 index 0000000..668936f --- /dev/null +++ b/external/src/robin-hood-hashing @@ -0,0 +1 @@ +Subproject commit 668936f62ec025db47a3888d5a03fb3e63b25da9 diff --git a/src/common.h b/src/common.h index 20234ca..f9f2aef 100644 --- a/src/common.h +++ b/src/common.h @@ -279,6 +279,11 @@ enum class NetworkType { Stagenet, }; +void* malloc_hook(size_t n) noexcept; +void* realloc_hook(void* ptr, size_t size) noexcept; +void* calloc_hook(size_t count, size_t size) noexcept; +void free_hook(void* p) noexcept; + } // namespace p2pool #include "util.h" diff --git a/src/crypto.cpp b/src/crypto.cpp index 4b2806d..9ce0542 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -20,7 +20,6 @@ #include "keccak.h" #include "uv_util.h" #include -#include extern "C" { #include "crypto-ops.h" @@ -237,8 +236,8 @@ public: private: uv_mutex_t m; - std::unordered_map, hash> derivations; - std::unordered_map, hash> public_keys; + unordered_map, hash> derivations; + unordered_map, hash> public_keys; }; static Cache* cache = nullptr; diff --git a/src/memory_leak_debug.cpp b/src/memory_leak_debug.cpp index 2f352c7..cac47fc 100644 --- a/src/memory_leak_debug.cpp +++ b/src/memory_leak_debug.cpp @@ -120,7 +120,7 @@ FORCEINLINE static void remove_allocation(void* p) __debugbreak(); } -FORCEINLINE static void* allocate_noexcept(size_t n) noexcept +void* malloc_hook(size_t n) noexcept { void* p = malloc(n); if (p) { @@ -131,20 +131,20 @@ FORCEINLINE static void* allocate_noexcept(size_t n) noexcept FORCEINLINE static void* allocate(size_t n) { - void* p = allocate_noexcept(n); + void* p = malloc_hook(n); if (!p) { throw std::bad_alloc(); } return p; } -FORCEINLINE static void deallocate(void* p) +void free_hook(void* p) noexcept { remove_allocation(p); free(p); } -static void* uv_realloc_hook(void* ptr, size_t size) +void* realloc_hook(void* ptr, size_t size) noexcept { remove_allocation(ptr); @@ -155,7 +155,7 @@ static void* uv_realloc_hook(void* ptr, size_t size) return p; } -static void* uv_calloc_hook(size_t count, size_t size) +void* calloc_hook(size_t count, size_t size) noexcept { void* p = calloc(count, size); if (p) { @@ -170,7 +170,7 @@ void memory_tracking_start() { using namespace p2pool; - uv_replace_allocator(allocate_noexcept, uv_realloc_hook, uv_calloc_hook, deallocate); + uv_replace_allocator(malloc_hook, realloc_hook, calloc_hook, free_hook); uv_mutex_init_checked(&allocation_lock); track_memory = true; } @@ -228,14 +228,23 @@ void memory_tracking_stop() NOINLINE void* operator new(size_t n) { return p2pool::allocate(n); } NOINLINE void* operator new[](size_t n) { return p2pool::allocate(n); } -NOINLINE void* operator new(size_t n, const std::nothrow_t&) noexcept { return p2pool::allocate_noexcept(n); } -NOINLINE void* operator new[](size_t n, const std::nothrow_t&) noexcept { return p2pool::allocate_noexcept(n); } -NOINLINE void operator delete(void* p) noexcept { p2pool::deallocate(p); } -NOINLINE void operator delete[](void* p) noexcept { p2pool::deallocate(p); } -NOINLINE void operator delete(void* p, size_t) noexcept { p2pool::deallocate(p); } -NOINLINE void operator delete[](void* p, size_t) noexcept { p2pool::deallocate(p); } +NOINLINE void* operator new(size_t n, const std::nothrow_t&) noexcept { return p2pool::malloc_hook(n); } +NOINLINE void* operator new[](size_t n, const std::nothrow_t&) noexcept { return p2pool::malloc_hook(n); } +NOINLINE void operator delete(void* p) noexcept { p2pool::free_hook(p); } +NOINLINE void operator delete[](void* p) noexcept { p2pool::free_hook(p); } +NOINLINE void operator delete(void* p, size_t) noexcept { p2pool::free_hook(p); } +NOINLINE void operator delete[](void* p, size_t) noexcept { p2pool::free_hook(p); } #else void memory_tracking_start() {} void memory_tracking_stop() {} + +namespace p2pool { + +void* malloc_hook(size_t n) noexcept { return malloc(n); } +void* realloc_hook(void* ptr, size_t size) noexcept { return realloc(ptr, size); } +void* calloc_hook(size_t count, size_t size) noexcept { return calloc(count, size); } +void free_hook(void* p) noexcept { free(p); } + +} #endif diff --git a/src/mempool.h b/src/mempool.h index c751f7a..a73d963 100644 --- a/src/mempool.h +++ b/src/mempool.h @@ -18,7 +18,6 @@ #pragma once #include "uv_util.h" -#include namespace p2pool { @@ -35,7 +34,7 @@ public: public: mutable uv_rwlock_t m_lock; - std::unordered_map m_transactions; + unordered_map m_transactions; }; } // namespace p2pool diff --git a/src/p2p_server.h b/src/p2p_server.h index a598c27..1bb4e31 100644 --- a/src/p2p_server.h +++ b/src/p2p_server.h @@ -19,7 +19,6 @@ #include "tcp_server.h" #include -#include namespace p2pool { @@ -132,7 +131,7 @@ private: std::string m_initialPeerList; uv_rwlock_t m_cachedBlocksLock; - std::unordered_map m_cachedBlocks; + unordered_map m_cachedBlocks; private: static void on_timer(uv_timer_t* timer) { reinterpret_cast(timer->data)->on_timer(); } diff --git a/src/p2pool.h b/src/p2pool.h index 2e921b4..a7b1cd7 100644 --- a/src/p2pool.h +++ b/src/p2pool.h @@ -19,7 +19,6 @@ #include "uv_util.h" #include -#include namespace p2pool { @@ -104,7 +103,7 @@ private: mutable uv_rwlock_t m_mainchainLock; std::map m_mainchainByHeight; - std::unordered_map m_mainchainByHash; + unordered_map m_mainchainByHash; enum { TIMESTAMP_WINDOW = 60 }; bool get_timestamps(uint64_t (×tamps)[TIMESTAMP_WINDOW]) const; diff --git a/src/p2pool_api.cpp b/src/p2pool_api.cpp index 329417a..48ec42a 100644 --- a/src/p2pool_api.cpp +++ b/src/p2pool_api.cpp @@ -127,7 +127,7 @@ void p2pool_api::dump_to_file_async_internal(const Category& category, const cha void p2pool_api::dump_to_file() { - std::unordered_map> data; + unordered_map> data; { MutexLock lock(m_dumpDataLock); data = std::move(m_dumpData); diff --git a/src/p2pool_api.h b/src/p2pool_api.h index 203215e..50c1aba 100644 --- a/src/p2pool_api.h +++ b/src/p2pool_api.h @@ -18,7 +18,6 @@ #pragma once #include "uv_util.h" -#include namespace p2pool { @@ -84,7 +83,7 @@ private: std::string m_localPath; uv_mutex_t m_dumpDataLock; - std::unordered_map> m_dumpData; + unordered_map> m_dumpData; uv_async_t m_dumpToFileAsync; }; diff --git a/src/side_chain.h b/src/side_chain.h index 09900ab..077df53 100644 --- a/src/side_chain.h +++ b/src/side_chain.h @@ -19,8 +19,6 @@ #include "uv_util.h" #include -#include -#include namespace p2pool { @@ -98,9 +96,9 @@ private: mutable uv_mutex_t m_sidechainLock; PoolBlock* m_chainTip; std::map> m_blocksByHeight; - std::unordered_map m_blocksById; - std::unordered_set m_seenBlocks; - std::unordered_map m_seenWallets; + unordered_map m_blocksById; + unordered_set m_seenBlocks; + unordered_map m_seenWallets; std::vector m_difficultyData; diff --git a/src/util.h b/src/util.h index 4a43655..d4524d8 100644 --- a/src/util.h +++ b/src/util.h @@ -17,6 +17,21 @@ #pragma once +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 5027) +#endif + +#define ROBIN_HOOD_MALLOC(size) p2pool::malloc_hook(size) +#define ROBIN_HOOD_CALLOC(count, size) p2pool::calloc_hook((count), (size)) +#define ROBIN_HOOD_FREE(ptr) p2pool::free_hook(ptr) + +#include "robin_hood.h" + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + namespace p2pool { extern const char* VERSION; @@ -122,20 +137,22 @@ extern thread_local bool is_main_thread; bool resolve_host(std::string& host, bool& is_v6); +template +using unordered_map = robin_hood::detail::Table, std::equal_to>; + +template +using unordered_set = robin_hood::detail::Table, std::equal_to>; + } // namespace p2pool -namespace std { +namespace robin_hood { template<> struct hash { FORCEINLINE size_t operator()(const p2pool::hash& value) const noexcept { - uint64_t result = 0xcbf29ce484222325ull; - for (size_t i = 0; i < p2pool::HASH_SIZE; ++i) { - result = (result ^ value.h[i]) * 0x100000001b3ull; - } - return static_cast(result); + return hash_bytes(value.h, p2pool::HASH_SIZE); } }; @@ -144,12 +161,8 @@ struct hash> { FORCEINLINE size_t operator()(const std::array& value) const noexcept { - uint64_t result = 0xcbf29ce484222325ull; - for (size_t i = 0; i < N; ++i) { - result = (result ^ value[i]) * 0x100000001b3ull; - } - return static_cast(result); + return hash_bytes(value.data(), N); } }; -} // namespace std +} // namespace robin_hood diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2eb2981..b2a1915 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -84,6 +84,7 @@ set(SOURCES ../src/json_rpc_request.cpp ../src/keccak.cpp ../src/log.cpp + ../src/memory_leak_debug.cpp ../src/mempool.cpp ../src/p2p_server.cpp ../src/p2pool.cpp @@ -107,6 +108,7 @@ include_directories(../external/src/libzmq/include) include_directories(../external/src/llhttp) include_directories(../external/src/RandomX/src) include_directories(../external/src/rapidjson/include) +include_directories(../external/src/robin-hood-hashing/src/include) include_directories(src) include_directories(googletest/googletest/include)