Switch to faster unordered_map/set

This commit is contained in:
SChernykh 2021-10-22 18:18:38 +02:00
parent 04d18cdf1d
commit 148b9dd294
16 changed files with 70 additions and 42 deletions

3
.gitmodules vendored
View file

@ -19,3 +19,6 @@
[submodule "external/src/libzmq"] [submodule "external/src/libzmq"]
path = external/src/libzmq path = external/src/libzmq
url = https://github.com/SChernykh/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

View file

@ -82,6 +82,7 @@ include_directories(external/src/libzmq/include)
include_directories(external/src/llhttp) include_directories(external/src/llhttp)
include_directories(external/src/RandomX/src) include_directories(external/src/RandomX/src)
include_directories(external/src/rapidjson/include) include_directories(external/src/rapidjson/include)
include_directories(external/src/robin-hood-hashing/src/include)
if (WIN32) if (WIN32)
set(LIBS ${LIBS} ws2_32 iphlpapi userenv psapi) set(LIBS ${LIBS} ws2_32 iphlpapi userenv psapi)

View file

@ -7,3 +7,4 @@
../external/src/llhttp/ ../external/src/llhttp/
../external/src/RandomX/src/ ../external/src/RandomX/src/
../external/src/rapidjson/include ../external/src/rapidjson/include
../external/src/robin-hood-hashing/src/include

View file

@ -1,5 +1,5 @@
#!/bin/bash #!/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 grep -v 'external' errors_full.txt | grep -v 'unmatchedSuppression' > errors_filtered.txt
if [ -s errors_filtered.txt ]; then if [ -s errors_filtered.txt ]; then
cat errors_filtered.txt cat errors_filtered.txt

1
external/src/robin-hood-hashing vendored Submodule

@ -0,0 +1 @@
Subproject commit 668936f62ec025db47a3888d5a03fb3e63b25da9

View file

@ -279,6 +279,11 @@ enum class NetworkType {
Stagenet, 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 } // namespace p2pool
#include "util.h" #include "util.h"

View file

@ -20,7 +20,6 @@
#include "keccak.h" #include "keccak.h"
#include "uv_util.h" #include "uv_util.h"
#include <random> #include <random>
#include <unordered_map>
extern "C" { extern "C" {
#include "crypto-ops.h" #include "crypto-ops.h"
@ -237,8 +236,8 @@ public:
private: private:
uv_mutex_t m; uv_mutex_t m;
std::unordered_map<std::array<uint8_t, HASH_SIZE * 2>, hash> derivations; unordered_map<std::array<uint8_t, HASH_SIZE * 2>, hash> derivations;
std::unordered_map<std::array<uint8_t, HASH_SIZE * 2 + sizeof(size_t)>, hash> public_keys; unordered_map<std::array<uint8_t, HASH_SIZE * 2 + sizeof(size_t)>, hash> public_keys;
}; };
static Cache* cache = nullptr; static Cache* cache = nullptr;

View file

@ -120,7 +120,7 @@ FORCEINLINE static void remove_allocation(void* p)
__debugbreak(); __debugbreak();
} }
FORCEINLINE static void* allocate_noexcept(size_t n) noexcept void* malloc_hook(size_t n) noexcept
{ {
void* p = malloc(n); void* p = malloc(n);
if (p) { if (p) {
@ -131,20 +131,20 @@ FORCEINLINE static void* allocate_noexcept(size_t n) noexcept
FORCEINLINE static void* allocate(size_t n) FORCEINLINE static void* allocate(size_t n)
{ {
void* p = allocate_noexcept(n); void* p = malloc_hook(n);
if (!p) { if (!p) {
throw std::bad_alloc(); throw std::bad_alloc();
} }
return p; return p;
} }
FORCEINLINE static void deallocate(void* p) void free_hook(void* p) noexcept
{ {
remove_allocation(p); remove_allocation(p);
free(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); remove_allocation(ptr);
@ -155,7 +155,7 @@ static void* uv_realloc_hook(void* ptr, size_t size)
return p; 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); void* p = calloc(count, size);
if (p) { if (p) {
@ -170,7 +170,7 @@ void memory_tracking_start()
{ {
using namespace p2pool; 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); uv_mutex_init_checked(&allocation_lock);
track_memory = true; 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) { 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::malloc_hook(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::malloc_hook(n); }
NOINLINE void operator delete(void* p) noexcept { p2pool::deallocate(p); } NOINLINE void operator delete(void* p) noexcept { p2pool::free_hook(p); }
NOINLINE void operator delete[](void* p) noexcept { p2pool::deallocate(p); } NOINLINE void operator delete[](void* p) noexcept { p2pool::free_hook(p); }
NOINLINE void operator delete(void* p, size_t) noexcept { p2pool::deallocate(p); } NOINLINE void operator delete(void* p, size_t) noexcept { p2pool::free_hook(p); }
NOINLINE void operator delete[](void* p, size_t) noexcept { p2pool::deallocate(p); } NOINLINE void operator delete[](void* p, size_t) noexcept { p2pool::free_hook(p); }
#else #else
void memory_tracking_start() {} void memory_tracking_start() {}
void memory_tracking_stop() {} 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 #endif

View file

@ -18,7 +18,6 @@
#pragma once #pragma once
#include "uv_util.h" #include "uv_util.h"
#include <unordered_map>
namespace p2pool { namespace p2pool {
@ -35,7 +34,7 @@ public:
public: public:
mutable uv_rwlock_t m_lock; mutable uv_rwlock_t m_lock;
std::unordered_map<hash, TxMempoolData> m_transactions; unordered_map<hash, TxMempoolData> m_transactions;
}; };
} // namespace p2pool } // namespace p2pool

View file

@ -19,7 +19,6 @@
#include "tcp_server.h" #include "tcp_server.h"
#include <random> #include <random>
#include <unordered_map>
namespace p2pool { namespace p2pool {
@ -132,7 +131,7 @@ private:
std::string m_initialPeerList; std::string m_initialPeerList;
uv_rwlock_t m_cachedBlocksLock; uv_rwlock_t m_cachedBlocksLock;
std::unordered_map<hash, PoolBlock*> m_cachedBlocks; unordered_map<hash, PoolBlock*> m_cachedBlocks;
private: private:
static void on_timer(uv_timer_t* timer) { reinterpret_cast<P2PServer*>(timer->data)->on_timer(); } static void on_timer(uv_timer_t* timer) { reinterpret_cast<P2PServer*>(timer->data)->on_timer(); }

View file

@ -19,7 +19,6 @@
#include "uv_util.h" #include "uv_util.h"
#include <map> #include <map>
#include <unordered_map>
namespace p2pool { namespace p2pool {
@ -104,7 +103,7 @@ private:
mutable uv_rwlock_t m_mainchainLock; mutable uv_rwlock_t m_mainchainLock;
std::map<uint64_t, ChainMain> m_mainchainByHeight; std::map<uint64_t, ChainMain> m_mainchainByHeight;
std::unordered_map<hash, ChainMain> m_mainchainByHash; unordered_map<hash, ChainMain> m_mainchainByHash;
enum { TIMESTAMP_WINDOW = 60 }; enum { TIMESTAMP_WINDOW = 60 };
bool get_timestamps(uint64_t (&timestamps)[TIMESTAMP_WINDOW]) const; bool get_timestamps(uint64_t (&timestamps)[TIMESTAMP_WINDOW]) const;

View file

@ -127,7 +127,7 @@ void p2pool_api::dump_to_file_async_internal(const Category& category, const cha
void p2pool_api::dump_to_file() void p2pool_api::dump_to_file()
{ {
std::unordered_map<std::string, std::vector<char>> data; unordered_map<std::string, std::vector<char>> data;
{ {
MutexLock lock(m_dumpDataLock); MutexLock lock(m_dumpDataLock);
data = std::move(m_dumpData); data = std::move(m_dumpData);

View file

@ -18,7 +18,6 @@
#pragma once #pragma once
#include "uv_util.h" #include "uv_util.h"
#include <unordered_map>
namespace p2pool { namespace p2pool {
@ -84,7 +83,7 @@ private:
std::string m_localPath; std::string m_localPath;
uv_mutex_t m_dumpDataLock; uv_mutex_t m_dumpDataLock;
std::unordered_map<std::string, std::vector<char>> m_dumpData; unordered_map<std::string, std::vector<char>> m_dumpData;
uv_async_t m_dumpToFileAsync; uv_async_t m_dumpToFileAsync;
}; };

View file

@ -19,8 +19,6 @@
#include "uv_util.h" #include "uv_util.h"
#include <map> #include <map>
#include <unordered_map>
#include <unordered_set>
namespace p2pool { namespace p2pool {
@ -98,9 +96,9 @@ private:
mutable uv_mutex_t m_sidechainLock; mutable uv_mutex_t m_sidechainLock;
PoolBlock* m_chainTip; PoolBlock* m_chainTip;
std::map<uint64_t, std::vector<PoolBlock*>> m_blocksByHeight; std::map<uint64_t, std::vector<PoolBlock*>> m_blocksByHeight;
std::unordered_map<hash, PoolBlock*> m_blocksById; unordered_map<hash, PoolBlock*> m_blocksById;
std::unordered_set<hash> m_seenBlocks; unordered_set<hash> m_seenBlocks;
std::unordered_map<hash, time_t> m_seenWallets; unordered_map<hash, time_t> m_seenWallets;
std::vector<DifficultyData> m_difficultyData; std::vector<DifficultyData> m_difficultyData;

View file

@ -17,6 +17,21 @@
#pragma once #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 { namespace p2pool {
extern const char* VERSION; extern const char* VERSION;
@ -122,20 +137,22 @@ extern thread_local bool is_main_thread;
bool resolve_host(std::string& host, bool& is_v6); bool resolve_host(std::string& host, bool& is_v6);
template <typename Key, typename T>
using unordered_map = robin_hood::detail::Table<false, 80, Key, T, robin_hood::hash<Key>, std::equal_to<Key>>;
template <typename Key>
using unordered_set = robin_hood::detail::Table<false, 80, Key, void, robin_hood::hash<Key>, std::equal_to<Key>>;
} // namespace p2pool } // namespace p2pool
namespace std { namespace robin_hood {
template<> template<>
struct hash<p2pool::hash> struct hash<p2pool::hash>
{ {
FORCEINLINE size_t operator()(const p2pool::hash& value) const noexcept FORCEINLINE size_t operator()(const p2pool::hash& value) const noexcept
{ {
uint64_t result = 0xcbf29ce484222325ull; return hash_bytes(value.h, p2pool::HASH_SIZE);
for (size_t i = 0; i < p2pool::HASH_SIZE; ++i) {
result = (result ^ value.h[i]) * 0x100000001b3ull;
}
return static_cast<size_t>(result);
} }
}; };
@ -144,12 +161,8 @@ struct hash<std::array<uint8_t, N>>
{ {
FORCEINLINE size_t operator()(const std::array<uint8_t, N>& value) const noexcept FORCEINLINE size_t operator()(const std::array<uint8_t, N>& value) const noexcept
{ {
uint64_t result = 0xcbf29ce484222325ull; return hash_bytes(value.data(), N);
for (size_t i = 0; i < N; ++i) {
result = (result ^ value[i]) * 0x100000001b3ull;
}
return static_cast<size_t>(result);
} }
}; };
} // namespace std } // namespace robin_hood

View file

@ -84,6 +84,7 @@ set(SOURCES
../src/json_rpc_request.cpp ../src/json_rpc_request.cpp
../src/keccak.cpp ../src/keccak.cpp
../src/log.cpp ../src/log.cpp
../src/memory_leak_debug.cpp
../src/mempool.cpp ../src/mempool.cpp
../src/p2p_server.cpp ../src/p2p_server.cpp
../src/p2pool.cpp ../src/p2pool.cpp
@ -107,6 +108,7 @@ include_directories(../external/src/libzmq/include)
include_directories(../external/src/llhttp) include_directories(../external/src/llhttp)
include_directories(../external/src/RandomX/src) include_directories(../external/src/RandomX/src)
include_directories(../external/src/rapidjson/include) include_directories(../external/src/rapidjson/include)
include_directories(../external/src/robin-hood-hashing/src/include)
include_directories(src) include_directories(src)
include_directories(googletest/googletest/include) include_directories(googletest/googletest/include)