From 72c9d943906839d4af6dfe52b53522b9b1e4f4e2 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sun, 6 Oct 2019 14:40:42 +0700 Subject: [PATCH 1/9] Use hwloc for set thread affinity. --- src/base/base.cmake | 9 +++++- src/base/kernel/Platform.cpp | 16 ++++++---- src/base/kernel/Platform.h | 10 ++++-- src/base/kernel/Platform_hwloc.cpp | 49 +++++++++++++++++++++++++++++ src/base/kernel/Platform_mac.cpp | 16 +++++----- src/base/kernel/Platform_unix.cpp | 16 +++++----- src/base/kernel/Platform_win.cpp | 20 ++++++------ src/crypto/common/VirtualMemory.cpp | 7 +++-- src/crypto/common/VirtualMemory.h | 13 +++++--- 9 files changed, 118 insertions(+), 38 deletions(-) create mode 100644 src/base/kernel/Platform_hwloc.cpp diff --git a/src/base/base.cmake b/src/base/base.cmake index bc022c70..8e43b6e0 100644 --- a/src/base/base.cmake +++ b/src/base/base.cmake @@ -98,7 +98,14 @@ elseif (APPLE) else() set(SOURCES_OS src/base/io/json/Json_unix.cpp - src/base/kernel//Platform_unix.cpp + src/base/kernel/Platform_unix.cpp + ) +endif() + + +if (WITH_HWLOC) + list(APPEND SOURCES_OS + src/base/kernel/Platform_hwloc.cpp ) endif() diff --git a/src/base/kernel/Platform.cpp b/src/base/kernel/Platform.cpp index a74f1978..67c72923 100644 --- a/src/base/kernel/Platform.cpp +++ b/src/base/kernel/Platform.cpp @@ -23,7 +23,10 @@ */ -#include +#include "base/kernel/Platform.h" + + +#include #include @@ -33,13 +36,14 @@ #endif -#include "Platform.h" +namespace xmrig { + +String Platform::m_userAgent; + +} // namespace xmrig -xmrig::String Platform::m_userAgent; - - -void Platform::init(const char *userAgent) +void xmrig::Platform::init(const char *userAgent) { # ifdef XMRIG_FEATURE_TLS SSL_library_init(); diff --git a/src/base/kernel/Platform.h b/src/base/kernel/Platform.h index f3c2c719..3f026f8b 100644 --- a/src/base/kernel/Platform.h +++ b/src/base/kernel/Platform.h @@ -26,12 +26,15 @@ #define XMRIG_PLATFORM_H -#include +#include #include "base/tools/String.h" +namespace xmrig { + + class Platform { public: @@ -56,8 +59,11 @@ public: private: static char *createUserAgent(); - static xmrig::String m_userAgent; + static String m_userAgent; }; +} // namespace xmrig + + #endif /* XMRIG_PLATFORM_H */ diff --git a/src/base/kernel/Platform_hwloc.cpp b/src/base/kernel/Platform_hwloc.cpp new file mode 100644 index 00000000..f4b46ba1 --- /dev/null +++ b/src/base/kernel/Platform_hwloc.cpp @@ -0,0 +1,49 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "base/kernel/Platform.h" +#include "backend/cpu/platform/HwlocCpuInfo.h" +#include "backend/cpu/Cpu.h" + + +#include + + +bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id) +{ + auto cpu = static_cast(Cpu::info()); + hwloc_obj_t pu = hwloc_get_pu_obj_by_os_index(cpu->topology(), static_cast(cpu_id)); + + if (pu == nullptr) { + return false; + } + + if (hwloc_set_cpubind(cpu->topology(), pu->cpuset, HWLOC_CPUBIND_THREAD | HWLOC_CPUBIND_STRICT) >= 0) { + return true; + } + + return hwloc_set_cpubind(cpu->topology(), pu->cpuset, HWLOC_CPUBIND_THREAD) >= 0; +} diff --git a/src/base/kernel/Platform_mac.cpp b/src/base/kernel/Platform_mac.cpp index 4e4aa0ad..146dd52d 100644 --- a/src/base/kernel/Platform_mac.cpp +++ b/src/base/kernel/Platform_mac.cpp @@ -30,7 +30,7 @@ #include -#include "Platform.h" +#include "base/kernel/Platform.h" #include "version.h" #ifdef XMRIG_NVIDIA_PROJECT @@ -38,7 +38,7 @@ #endif -char *Platform::createUserAgent() +char *xmrig::Platform::createUserAgent() { constexpr const size_t max = 256; @@ -60,7 +60,8 @@ char *Platform::createUserAgent() } -bool Platform::setThreadAffinity(uint64_t cpu_id) +#ifndef XMRIG_FEATURE_HWLOC +bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id) { thread_port_t mach_thread; thread_affinity_policy_data_t policy = { static_cast(cpu_id) }; @@ -68,25 +69,26 @@ bool Platform::setThreadAffinity(uint64_t cpu_id) return thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1) == KERN_SUCCESS; } +#endif -uint32_t Platform::setTimerResolution(uint32_t resolution) +uint32_t xmrig::Platform::setTimerResolution(uint32_t resolution) { return resolution; } -void Platform::restoreTimerResolution() +void xmrig::Platform::restoreTimerResolution() { } -void Platform::setProcessPriority(int priority) +void xmrig::Platform::setProcessPriority(int priority) { } -void Platform::setThreadPriority(int priority) +void xmrig::Platform::setThreadPriority(int priority) { if (priority == -1) { return; diff --git a/src/base/kernel/Platform_unix.cpp b/src/base/kernel/Platform_unix.cpp index 3066630a..bbba39f9 100644 --- a/src/base/kernel/Platform_unix.cpp +++ b/src/base/kernel/Platform_unix.cpp @@ -39,7 +39,7 @@ #include -#include "Platform.h" +#include "base/kernel/Platform.h" #include "version.h" #ifdef XMRIG_NVIDIA_PROJECT @@ -52,7 +52,7 @@ typedef cpuset_t cpu_set_t; #endif -char *Platform::createUserAgent() +char *xmrig::Platform::createUserAgent() { constexpr const size_t max = 256; @@ -84,7 +84,8 @@ char *Platform::createUserAgent() } -bool Platform::setThreadAffinity(uint64_t cpu_id) +#ifndef XMRIG_FEATURE_HWLOC +bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id) { cpu_set_t mn; CPU_ZERO(&mn); @@ -96,25 +97,26 @@ bool Platform::setThreadAffinity(uint64_t cpu_id) return sched_setaffinity(gettid(), sizeof(cpu_set_t), &mn) == 0; # endif } +#endif -uint32_t Platform::setTimerResolution(uint32_t resolution) +uint32_t xmrig::Platform::setTimerResolution(uint32_t resolution) { return resolution; } -void Platform::restoreTimerResolution() +void xmrig::Platform::restoreTimerResolution() { } -void Platform::setProcessPriority(int priority) +void xmrig::Platform::setProcessPriority(int priority) { } -void Platform::setThreadPriority(int priority) +void xmrig::Platform::setThreadPriority(int priority) { if (priority == -1) { return; diff --git a/src/base/kernel/Platform_win.cpp b/src/base/kernel/Platform_win.cpp index f2363cd0..064c8352 100644 --- a/src/base/kernel/Platform_win.cpp +++ b/src/base/kernel/Platform_win.cpp @@ -29,8 +29,8 @@ #include +#include "base/kernel/Platform.h" #include "base/io/log/Log.h" -#include "Platform.h" #include "version.h" @@ -51,10 +51,10 @@ static inline OSVERSIONINFOEX winOsVersion() HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); if (ntdll ) { - RtlGetVersionFunction pRtlGetVersion = reinterpret_cast(GetProcAddress(ntdll, "RtlGetVersion")); + auto pRtlGetVersion = reinterpret_cast(GetProcAddress(ntdll, "RtlGetVersion")); if (pRtlGetVersion) { - pRtlGetVersion((LPOSVERSIONINFO) &result); + pRtlGetVersion(reinterpret_cast(&result)); } } @@ -62,7 +62,7 @@ static inline OSVERSIONINFOEX winOsVersion() } -char *Platform::createUserAgent() +char *xmrig::Platform::createUserAgent() { const auto osver = winOsVersion(); constexpr const size_t max = 256; @@ -91,7 +91,8 @@ char *Platform::createUserAgent() } -bool Platform::setThreadAffinity(uint64_t cpu_id) +#ifndef XMRIG_FEATURE_HWLOC +bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id) { if (cpu_id >= 64) { LOG_ERR("Unable to set affinity. Windows supports only affinity up to 63."); @@ -99,9 +100,10 @@ bool Platform::setThreadAffinity(uint64_t cpu_id) return SetThreadAffinityMask(GetCurrentThread(), 1ULL << cpu_id) != 0; } +#endif -uint32_t Platform::setTimerResolution(uint32_t resolution) +uint32_t xmrig::Platform::setTimerResolution(uint32_t resolution) { # ifdef XMRIG_AMD_PROJECT TIMECAPS tc; @@ -119,7 +121,7 @@ uint32_t Platform::setTimerResolution(uint32_t resolution) } -void Platform::restoreTimerResolution() +void xmrig::Platform::restoreTimerResolution() { # ifdef XMRIG_AMD_PROJECT if (timerResolution) { @@ -129,7 +131,7 @@ void Platform::restoreTimerResolution() } -void Platform::setProcessPriority(int priority) +void xmrig::Platform::setProcessPriority(int priority) { if (priority == -1) { return; @@ -166,7 +168,7 @@ void Platform::setProcessPriority(int priority) } -void Platform::setThreadPriority(int priority) +void xmrig::Platform::setThreadPriority(int priority) { if (priority == -1) { return; diff --git a/src/crypto/common/VirtualMemory.cpp b/src/crypto/common/VirtualMemory.cpp index 56cf3f5f..242f32a2 100644 --- a/src/crypto/common/VirtualMemory.cpp +++ b/src/crypto/common/VirtualMemory.cpp @@ -46,8 +46,11 @@ uint32_t xmrig::VirtualMemory::bindToNUMANode(int64_t affinity) return 0; } - auto cpu = static_cast(Cpu::info()); - hwloc_obj_t pu = hwloc_get_pu_obj_by_os_index(cpu->topology(), static_cast(affinity)); + auto cpu = static_cast(Cpu::info()); + hwloc_obj_t pu = hwloc_get_pu_obj_by_os_index(cpu->topology(), static_cast(affinity)); + + char *buffer; + hwloc_bitmap_asprintf(&buffer, pu->cpuset); if (pu == nullptr || !cpu->membind(pu->nodeset)) { LOG_WARN("CPU #%02" PRId64 " warning: \"can't bind memory\"", affinity); diff --git a/src/crypto/common/VirtualMemory.h b/src/crypto/common/VirtualMemory.h index ac2f75dd..88ca0683 100644 --- a/src/crypto/common/VirtualMemory.h +++ b/src/crypto/common/VirtualMemory.h @@ -28,8 +28,11 @@ #define XMRIG_VIRTUALMEMORY_H -#include -#include +#include "base/tools/Object.h" + + +#include +#include #include @@ -39,7 +42,9 @@ namespace xmrig { class VirtualMemory { public: - inline VirtualMemory() {} + XMRIG_DISABLE_COPY_MOVE(VirtualMemory) + + VirtualMemory() = default; VirtualMemory(size_t size, bool hugePages = true, size_t align = 64); ~VirtualMemory(); @@ -49,7 +54,7 @@ public: inline std::pair hugePages() const { - return std::pair(isHugePages() ? (align(size()) / 2097152) : 0, align(size()) / 2097152); + return { isHugePages() ? (align(size()) / 2097152) : 0, align(size()) / 2097152 }; } static uint32_t bindToNUMANode(int64_t affinity); From c13c83b90236b31cf62c1e5a1aad5a090ad76ba2 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sun, 6 Oct 2019 17:49:15 +0700 Subject: [PATCH 2/9] VirtualMemory class refactoring. --- src/App.cpp | 2 +- src/crypto/common/VirtualMemory.h | 25 ++++++++++---------- src/crypto/common/VirtualMemory_unix.cpp | 19 +++++++-------- src/crypto/common/VirtualMemory_win.cpp | 30 ++++++++++++++---------- 4 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/App.cpp b/src/App.cpp index 5f59e1b5..10b10a0d 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -80,7 +80,7 @@ int xmrig::App::exec() m_console = new Console(this); } - VirtualMemory::init(m_controller->config()->cpu().isHugePages()); + VirtualMemory::init(); Summary::print(m_controller); diff --git a/src/crypto/common/VirtualMemory.h b/src/crypto/common/VirtualMemory.h index 88ca0683..e8c9dbad 100644 --- a/src/crypto/common/VirtualMemory.h +++ b/src/crypto/common/VirtualMemory.h @@ -31,6 +31,7 @@ #include "base/tools/Object.h" +#include #include #include #include @@ -42,13 +43,12 @@ namespace xmrig { class VirtualMemory { public: - XMRIG_DISABLE_COPY_MOVE(VirtualMemory) + XMRIG_DISABLE_COPY_MOVE_DEFAULT(VirtualMemory) - VirtualMemory() = default; VirtualMemory(size_t size, bool hugePages = true, size_t align = 64); ~VirtualMemory(); - inline bool isHugePages() const { return m_flags & HUGEPAGES; } + inline bool isHugePages() const { return m_flags.test(FLAG_HUGEPAGES); } inline size_t size() const { return m_size; } inline uint8_t *scratchpad() const { return m_scratchpad; } @@ -57,30 +57,29 @@ public: return { isHugePages() ? (align(size()) / 2097152) : 0, align(size()) / 2097152 }; } + static bool isHugepagesAvailable(); static uint32_t bindToNUMANode(int64_t affinity); static void *allocateExecutableMemory(size_t size); static void *allocateLargePagesMemory(size_t size); static void flushInstructionCache(void *p, size_t size); static void freeLargePagesMemory(void *p, size_t size); - static void init(bool hugePages); + static void init(); static void protectExecutableMemory(void *p, size_t size); static void unprotectExecutableMemory(void *p, size_t size); - static inline bool isHugepagesAvailable() { return (m_globalFlags & HUGEPAGES_AVAILABLE) != 0; } static inline constexpr size_t align(size_t pos, size_t align = 2097152) { return ((pos - 1) / align + 1) * align; } private: enum Flags { - HUGEPAGES_AVAILABLE = 1, - HUGEPAGES = 2, - LOCK = 4 + FLAG_HUGEPAGES, + FLAG_LOCK, + FLAG_EXTERNAL, + FLAG_MAX }; - static int m_globalFlags; - - int m_flags = 0; - size_t m_size = 0; - uint8_t *m_scratchpad = nullptr; + std::bitset m_flags; + size_t m_size = 0; + uint8_t *m_scratchpad = nullptr; }; diff --git a/src/crypto/common/VirtualMemory_unix.cpp b/src/crypto/common/VirtualMemory_unix.cpp index 310a043a..14059f03 100644 --- a/src/crypto/common/VirtualMemory_unix.cpp +++ b/src/crypto/common/VirtualMemory_unix.cpp @@ -38,21 +38,18 @@ #endif -int xmrig::VirtualMemory::m_globalFlags = 0; - - xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) : m_size(VirtualMemory::align(size)) { if (hugePages) { m_scratchpad = static_cast(allocateLargePagesMemory(m_size)); if (m_scratchpad) { - m_flags |= HUGEPAGES; + m_flags.set(FLAG_HUGEPAGES, true); madvise(m_scratchpad, size, MADV_RANDOM | MADV_WILLNEED); if (mlock(m_scratchpad, m_size) == 0) { - m_flags |= LOCK; + m_flags.set(FLAG_LOCK, true); } return; @@ -70,7 +67,7 @@ xmrig::VirtualMemory::~VirtualMemory() } if (isHugePages()) { - if (m_flags & LOCK) { + if (m_flags.test(FLAG_LOCK)) { munlock(m_scratchpad, m_size); } @@ -82,6 +79,11 @@ xmrig::VirtualMemory::~VirtualMemory() } +bool xmrig::VirtualMemory::isHugepagesAvailable() +{ + return true; +} + void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size) { @@ -123,11 +125,8 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t size) } -void xmrig::VirtualMemory::init(bool hugePages) +void xmrig::VirtualMemory::init() { - if (hugePages) { - m_globalFlags = HUGEPAGES | HUGEPAGES_AVAILABLE; - } } diff --git a/src/crypto/common/VirtualMemory_win.cpp b/src/crypto/common/VirtualMemory_win.cpp index 7bdb6365..9dbf9041 100644 --- a/src/crypto/common/VirtualMemory_win.cpp +++ b/src/crypto/common/VirtualMemory_win.cpp @@ -36,6 +36,12 @@ #include "crypto/common/VirtualMemory.h" +namespace xmrig { + + +static bool hugepagesAvailable = false; + + /***************************************************************** SetLockPagesPrivilege: a function to obtain or release the privilege of locking physical pages. @@ -83,7 +89,7 @@ static BOOL SetLockPagesPrivilege() { static LSA_UNICODE_STRING StringToLsaUnicodeString(LPCTSTR string) { LSA_UNICODE_STRING lsaString; - DWORD dwLen = (DWORD) wcslen(string); + const auto dwLen = (DWORD) wcslen(string); lsaString.Buffer = (LPWSTR) string; lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR)); lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR)); @@ -141,7 +147,7 @@ static BOOL TrySetLockPagesPrivilege() { } -int xmrig::VirtualMemory::m_globalFlags = 0; +} // namespace xmrig xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) : @@ -150,7 +156,7 @@ xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) : if (hugePages) { m_scratchpad = static_cast(allocateLargePagesMemory(m_size)); if (m_scratchpad) { - m_flags |= HUGEPAGES; + m_flags.set(FLAG_HUGEPAGES, true); return; } @@ -175,6 +181,12 @@ xmrig::VirtualMemory::~VirtualMemory() } +bool xmrig::VirtualMemory::isHugepagesAvailable() +{ + return hugepagesAvailable; +} + + void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size) { return VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); @@ -206,17 +218,9 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t) } -void xmrig::VirtualMemory::init(bool hugePages) +void xmrig::VirtualMemory::init() { - if (!hugePages) { - return; - } - - m_globalFlags = HUGEPAGES; - - if (TrySetLockPagesPrivilege()) { - m_globalFlags |= HUGEPAGES_AVAILABLE; - } + hugepagesAvailable = TrySetLockPagesPrivilege(); } From 68d77b02d7d42e5b865bb447541c4c06790b9d3f Mon Sep 17 00:00:00 2001 From: XMRig Date: Mon, 7 Oct 2019 12:36:40 +0700 Subject: [PATCH 3/9] Added initial memory pool support. --- CMakeLists.txt | 9 ++ cmake/randomx.cmake | 2 +- src/App.cpp | 3 - src/backend/common/Worker.cpp | 3 +- src/backend/common/Worker.h | 4 +- src/backend/common/interfaces/IMemoryPool.h | 52 +++++++++++ src/backend/cpu/CpuWorker.cpp | 2 +- src/core/Controller.cpp | 15 +++- src/core/config/Config.h | 5 +- src/crypto/common/MemoryPool.cpp | 95 ++++++++++++++++++++ src/crypto/common/MemoryPool.h | 66 ++++++++++++++ src/crypto/common/VirtualMemory.cpp | 98 ++++++++++++++++----- src/crypto/common/VirtualMemory.h | 15 +++- src/crypto/common/VirtualMemory_hwloc.cpp | 56 ++++++++++++ src/crypto/common/VirtualMemory_unix.cpp | 82 ++++++++--------- src/crypto/common/VirtualMemory_win.cpp | 62 ++++++------- src/net/JobResults.cpp | 2 +- 17 files changed, 444 insertions(+), 127 deletions(-) create mode 100644 src/backend/common/interfaces/IMemoryPool.h create mode 100644 src/crypto/common/MemoryPool.cpp create mode 100644 src/crypto/common/MemoryPool.h create mode 100644 src/crypto/common/VirtualMemory_hwloc.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 377a0bf6..5bb2570e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,7 @@ set(HEADERS ) set(HEADERS_CRYPTO + src/backend/common/interfaces/IMemoryPool.h src/crypto/cn/asm/CryptonightR_template.h src/crypto/cn/c_blake256.h src/crypto/cn/c_groestl.h @@ -73,6 +74,7 @@ set(HEADERS_CRYPTO src/crypto/common/Algorithm.h src/crypto/common/Coin.h src/crypto/common/keccak.h + src/crypto/common/MemoryPool.h src/crypto/common/Nonce.h src/crypto/common/portable/mm_malloc.h src/crypto/common/VirtualMemory.h @@ -111,10 +113,17 @@ set(SOURCES_CRYPTO src/crypto/common/Algorithm.cpp src/crypto/common/Coin.cpp src/crypto/common/keccak.cpp + src/crypto/common/MemoryPool.cpp src/crypto/common/Nonce.cpp src/crypto/common/VirtualMemory.cpp ) +if (WITH_HWLOC) + list(APPEND SOURCES_CRYPTO + src/crypto/common/VirtualMemory_hwloc.cpp + ) +endif() + if (WIN32) set(SOURCES_OS "${SOURCES_OS}" diff --git a/cmake/randomx.cmake b/cmake/randomx.cmake index d05ceb89..290b8391 100644 --- a/cmake/randomx.cmake +++ b/cmake/randomx.cmake @@ -70,7 +70,7 @@ if (WITH_RANDOMX) endif() if (WITH_HWLOC) - list(APPEND SOURCES_CRYPTO + list(APPEND HEADERS_CRYPTO src/crypto/rx/RxNUMAStorage.h ) diff --git a/src/App.cpp b/src/App.cpp index 10b10a0d..7db2ace2 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -36,7 +36,6 @@ #include "core/config/Config.h" #include "core/Controller.h" #include "core/Miner.h" -#include "crypto/common/VirtualMemory.h" #include "net/Network.h" #include "Summary.h" #include "version.h" @@ -80,8 +79,6 @@ int xmrig::App::exec() m_console = new Console(this); } - VirtualMemory::init(); - Summary::print(m_controller); if (m_controller->config()->isDryRun()) { diff --git a/src/backend/common/Worker.cpp b/src/backend/common/Worker.cpp index 91ef0c7a..d6e01560 100644 --- a/src/backend/common/Worker.cpp +++ b/src/backend/common/Worker.cpp @@ -34,8 +34,7 @@ xmrig::Worker::Worker(size_t id, int64_t affinity, int priority) : m_affinity(affinity), m_id(id), m_hashCount(0), - m_timestamp(0), - m_count(0) + m_timestamp(0) { m_node = VirtualMemory::bindToNUMANode(affinity); diff --git a/src/backend/common/Worker.h b/src/backend/common/Worker.h index f55ec8aa..2cdae3fc 100644 --- a/src/backend/common/Worker.h +++ b/src/backend/common/Worker.h @@ -54,8 +54,8 @@ protected: const size_t m_id; std::atomic m_hashCount; std::atomic m_timestamp; - uint32_t m_node = 0; - uint64_t m_count; + uint32_t m_node = 0; + uint64_t m_count = 0; }; diff --git a/src/backend/common/interfaces/IMemoryPool.h b/src/backend/common/interfaces/IMemoryPool.h new file mode 100644 index 00000000..869bad32 --- /dev/null +++ b/src/backend/common/interfaces/IMemoryPool.h @@ -0,0 +1,52 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2018-2019 tevador + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_IMEMORYPOOL_H +#define XMRIG_IMEMORYPOOL_H + + +#include + + +namespace xmrig { + + +class IMemoryPool +{ +public: + virtual ~IMemoryPool() = default; + + virtual bool isHugePages(uint32_t node) const = 0; + virtual uint8_t *get(size_t size, uint32_t node) = 0; + virtual void release(uint32_t node) = 0; +}; + + +} /* namespace xmrig */ + + + +#endif /* XMRIG_IMEMORYPOOL_H */ diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp index 22651c35..d993e6e6 100644 --- a/src/backend/cpu/CpuWorker.cpp +++ b/src/backend/cpu/CpuWorker.cpp @@ -62,7 +62,7 @@ xmrig::CpuWorker::CpuWorker(size_t id, const CpuLaunchData &data) : m_miner(data.miner), m_ctx() { - m_memory = new VirtualMemory(m_algorithm.l3() * N, data.hugePages); + m_memory = new VirtualMemory(m_algorithm.l3() * N, data.hugePages, true); } diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index 80381e32..75a3e51b 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -23,15 +23,17 @@ */ -#include - - -#include "backend/cpu/Cpu.h" #include "core/Controller.h" +#include "backend/cpu/Cpu.h" +#include "core/config/Config.h" #include "core/Miner.h" +#include "crypto/common/VirtualMemory.h" #include "net/Network.h" +#include + + xmrig::Controller::Controller(Process *process) : Base(process) { @@ -41,6 +43,8 @@ xmrig::Controller::Controller(Process *process) : xmrig::Controller::~Controller() { delete m_network; + + VirtualMemory::destroy(); } @@ -48,7 +52,10 @@ int xmrig::Controller::init() { Base::init(); + VirtualMemory::init(config()->cpu().isHugePages(), -1); + m_network = new Network(this); + return 0; } diff --git a/src/core/config/Config.h b/src/core/config/Config.h index 7c7bc533..22deb2c2 100644 --- a/src/core/config/Config.h +++ b/src/core/config/Config.h @@ -26,11 +26,12 @@ #define XMRIG_CONFIG_H -#include +#include #include "backend/cpu/CpuConfig.h" #include "base/kernel/config/BaseConfig.h" +#include "base/tools/Object.h" #include "rapidjson/fwd.h" @@ -46,6 +47,8 @@ class OclConfig; class Config : public BaseConfig { public: + XMRIG_DISABLE_COPY_MOVE(Config); + Config(); ~Config() override; diff --git a/src/crypto/common/MemoryPool.cpp b/src/crypto/common/MemoryPool.cpp new file mode 100644 index 00000000..475655b1 --- /dev/null +++ b/src/crypto/common/MemoryPool.cpp @@ -0,0 +1,95 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2018-2019 tevador + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "crypto/common/MemoryPool.h" +#include "crypto/common/VirtualMemory.h" + + +#include + + +namespace xmrig { + + +constexpr size_t pageSize = 2 * 1024 * 1024; + + +} // namespace xmrig + + +xmrig::MemoryPool::MemoryPool(size_t size, bool hugePages, uint32_t node) : + m_size(size) +{ + if (!size) { + return; + } + + m_memory = new VirtualMemory(size * pageSize, hugePages, false, node); +} + + +xmrig::MemoryPool::~MemoryPool() +{ + delete m_memory; +} + + +bool xmrig::MemoryPool::isHugePages(uint32_t) const +{ + return m_memory && m_memory->isHugePages(); +} + + +uint8_t *xmrig::MemoryPool::get(size_t size, uint32_t) +{ + assert(!(size % pageSize)); + + if (!m_memory || (m_memory->size() - m_offset) < size) { + return nullptr; + } + + uint8_t *out = m_memory->scratchpad() + m_offset; + + m_offset += size; + ++m_refs; + + return out; +} + + +void xmrig::MemoryPool::release(uint32_t) +{ + assert(m_refs > 0); + + if (m_refs > 0) { + --m_refs; + } + + if (m_refs == 0) { + m_offset = 0; + } +} diff --git a/src/crypto/common/MemoryPool.h b/src/crypto/common/MemoryPool.h new file mode 100644 index 00000000..b5bd1020 --- /dev/null +++ b/src/crypto/common/MemoryPool.h @@ -0,0 +1,66 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2018-2019 tevador + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_MEMORYPOOL_H +#define XMRIG_MEMORYPOOL_H + + +#include "backend/common/interfaces/IMemoryPool.h" +#include "base/tools/Object.h" + + +namespace xmrig { + + +class VirtualMemory; + + +class MemoryPool : public IMemoryPool +{ +public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(MemoryPool) + + MemoryPool(size_t size, bool hugePages, uint32_t node = 0); + ~MemoryPool() override; + +protected: + bool isHugePages(uint32_t node) const override; + uint8_t *get(size_t size, uint32_t node) override; + void release(uint32_t node) override; + +private: + size_t m_size = 0; + size_t m_refs = 0; + size_t m_offset = 0; + VirtualMemory *m_memory = nullptr; +}; + + +} /* namespace xmrig */ + + + +#endif /* XMRIG_MEMORYPOOL_H */ diff --git a/src/crypto/common/VirtualMemory.cpp b/src/crypto/common/VirtualMemory.cpp index 242f32a2..332c07fd 100644 --- a/src/crypto/common/VirtualMemory.cpp +++ b/src/crypto/common/VirtualMemory.cpp @@ -25,41 +25,91 @@ */ -#ifdef XMRIG_FEATURE_HWLOC -# include -# include "backend/cpu/platform/HwlocCpuInfo.h" -#endif - - #include "crypto/common/VirtualMemory.h" #include "backend/cpu/Cpu.h" #include "base/io/log/Log.h" +#include "crypto/common/MemoryPool.h" +#include "crypto/common/portable/mm_malloc.h" #include +#include -uint32_t xmrig::VirtualMemory::bindToNUMANode(int64_t affinity) +namespace xmrig { + +static IMemoryPool *pool = nullptr; +static std::mutex mutex; + +} // namespace xmrig + + +xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, bool usePool, uint32_t node, size_t alignSize) : + m_size(align(size)), + m_node(node) { -# ifdef XMRIG_FEATURE_HWLOC - if (affinity < 0 || Cpu::info()->nodes() < 2) { - return 0; + if (usePool) { + std::lock_guard lock(mutex); + if (hugePages && !pool->isHugePages(node) && allocateLargePagesMemory()) { + return; + } + + m_scratchpad = pool->get(m_size, node); + if (m_scratchpad) { + m_flags.set(FLAG_HUGEPAGES, pool->isHugePages(node)); + m_flags.set(FLAG_EXTERNAL, true); + + return; + } } - auto cpu = static_cast(Cpu::info()); - hwloc_obj_t pu = hwloc_get_pu_obj_by_os_index(cpu->topology(), static_cast(affinity)); - - char *buffer; - hwloc_bitmap_asprintf(&buffer, pu->cpuset); - - if (pu == nullptr || !cpu->membind(pu->nodeset)) { - LOG_WARN("CPU #%02" PRId64 " warning: \"can't bind memory\"", affinity); - - return 0; + if (hugePages && allocateLargePagesMemory()) { + return; } - return hwloc_bitmap_first(pu->nodeset); -# else - return 0; -# endif + m_scratchpad = static_cast(_mm_malloc(m_size, alignSize)); +} + + +xmrig::VirtualMemory::~VirtualMemory() +{ + if (!m_scratchpad) { + return; + } + + if (m_flags.test(FLAG_EXTERNAL)) { + std::lock_guard lock(mutex); + pool->release(m_node); + } + + if (isHugePages()) { + freeLargePagesMemory(); + } + else { + _mm_free(m_scratchpad); + } +} + + +#ifndef XMRIG_FEATURE_HWLOC +uint32_t xmrig::VirtualMemory::bindToNUMANode(int64_t) +{ + return 0; +} +#endif + + +void xmrig::VirtualMemory::destroy() +{ + delete pool; +} + + +void xmrig::VirtualMemory::init(bool hugePages, int poolSize) +{ + if (!pool) { + osInit(); + } + + pool = new MemoryPool(poolSize < 0 ? Cpu::info()->threads() : poolSize, hugePages); } diff --git a/src/crypto/common/VirtualMemory.h b/src/crypto/common/VirtualMemory.h index e8c9dbad..668ae907 100644 --- a/src/crypto/common/VirtualMemory.h +++ b/src/crypto/common/VirtualMemory.h @@ -45,7 +45,7 @@ class VirtualMemory public: XMRIG_DISABLE_COPY_MOVE_DEFAULT(VirtualMemory) - VirtualMemory(size_t size, bool hugePages = true, size_t align = 64); + VirtualMemory(size_t size, bool hugePages, bool usePool, uint32_t node = 0, size_t alignSize = 64); ~VirtualMemory(); inline bool isHugePages() const { return m_flags.test(FLAG_HUGEPAGES); } @@ -61,9 +61,10 @@ public: static uint32_t bindToNUMANode(int64_t affinity); static void *allocateExecutableMemory(size_t size); static void *allocateLargePagesMemory(size_t size); + static void destroy(); static void flushInstructionCache(void *p, size_t size); static void freeLargePagesMemory(void *p, size_t size); - static void init(); + static void init(bool hugePages, int poolSize); static void protectExecutableMemory(void *p, size_t size); static void unprotectExecutableMemory(void *p, size_t size); @@ -77,9 +78,15 @@ private: FLAG_MAX }; + static void osInit(); + + bool allocateLargePagesMemory(); + void freeLargePagesMemory(); + + const size_t m_size; + const uint32_t m_node; std::bitset m_flags; - size_t m_size = 0; - uint8_t *m_scratchpad = nullptr; + uint8_t *m_scratchpad = nullptr; }; diff --git a/src/crypto/common/VirtualMemory_hwloc.cpp b/src/crypto/common/VirtualMemory_hwloc.cpp new file mode 100644 index 00000000..6ccc0c23 --- /dev/null +++ b/src/crypto/common/VirtualMemory_hwloc.cpp @@ -0,0 +1,56 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2018-2019 tevador + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "crypto/common/VirtualMemory.h" +#include "backend/cpu/Cpu.h" +#include "backend/cpu/platform/HwlocCpuInfo.h" +#include "base/io/log/Log.h" + + +#include + + +uint32_t xmrig::VirtualMemory::bindToNUMANode(int64_t affinity) +{ + if (affinity < 0 || Cpu::info()->nodes() < 2) { + return 0; + } + + auto cpu = static_cast(Cpu::info()); + hwloc_obj_t pu = hwloc_get_pu_obj_by_os_index(cpu->topology(), static_cast(affinity)); + + char *buffer; + hwloc_bitmap_asprintf(&buffer, pu->cpuset); + + if (pu == nullptr || !cpu->membind(pu->nodeset)) { + LOG_WARN("CPU #%02" PRId64 " warning: \"can't bind memory\"", affinity); + + return 0; + } + + return hwloc_bitmap_first(pu->nodeset); +} diff --git a/src/crypto/common/VirtualMemory_unix.cpp b/src/crypto/common/VirtualMemory_unix.cpp index 14059f03..8a66c34d 100644 --- a/src/crypto/common/VirtualMemory_unix.cpp +++ b/src/crypto/common/VirtualMemory_unix.cpp @@ -25,7 +25,7 @@ */ -#include +#include #include @@ -38,47 +38,6 @@ #endif -xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) : - m_size(VirtualMemory::align(size)) -{ - if (hugePages) { - m_scratchpad = static_cast(allocateLargePagesMemory(m_size)); - if (m_scratchpad) { - m_flags.set(FLAG_HUGEPAGES, true); - - madvise(m_scratchpad, size, MADV_RANDOM | MADV_WILLNEED); - - if (mlock(m_scratchpad, m_size) == 0) { - m_flags.set(FLAG_LOCK, true); - } - - return; - } - } - - m_scratchpad = static_cast(_mm_malloc(m_size, align)); -} - - -xmrig::VirtualMemory::~VirtualMemory() -{ - if (!m_scratchpad) { - return; - } - - if (isHugePages()) { - if (m_flags.test(FLAG_LOCK)) { - munlock(m_scratchpad, m_size); - } - - freeLargePagesMemory(m_scratchpad, m_size); - } - else { - _mm_free(m_scratchpad); - } -} - - bool xmrig::VirtualMemory::isHugepagesAvailable() { return true; @@ -125,11 +84,6 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t size) } -void xmrig::VirtualMemory::init() -{ -} - - void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size) { mprotect(p, size, PROT_READ | PROT_EXEC); @@ -140,3 +94,37 @@ void xmrig::VirtualMemory::unprotectExecutableMemory(void *p, size_t size) { mprotect(p, size, PROT_WRITE | PROT_EXEC); } + + +void xmrig::VirtualMemory::osInit() +{ +} + + +bool xmrig::VirtualMemory::allocateLargePagesMemory() +{ + m_scratchpad = static_cast(allocateLargePagesMemory(m_size)); + if (m_scratchpad) { + m_flags.set(FLAG_HUGEPAGES, true); + + madvise(m_scratchpad, size, MADV_RANDOM | MADV_WILLNEED); + + if (mlock(m_scratchpad, m_size) == 0) { + m_flags.set(FLAG_LOCK, true); + } + + return true; + } + + return false; +} + + +void xmrig::VirtualMemory::freeLargePagesMemory() +{ + if (m_flags.test(FLAG_LOCK)) { + munlock(m_scratchpad, m_size); + } + + freeLargePagesMemory(m_scratchpad, m_size); +} diff --git a/src/crypto/common/VirtualMemory_win.cpp b/src/crypto/common/VirtualMemory_win.cpp index 9dbf9041..875a1e8e 100644 --- a/src/crypto/common/VirtualMemory_win.cpp +++ b/src/crypto/common/VirtualMemory_win.cpp @@ -150,37 +150,6 @@ static BOOL TrySetLockPagesPrivilege() { } // namespace xmrig -xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) : - m_size(VirtualMemory::align(size)) -{ - if (hugePages) { - m_scratchpad = static_cast(allocateLargePagesMemory(m_size)); - if (m_scratchpad) { - m_flags.set(FLAG_HUGEPAGES, true); - - return; - } - } - - m_scratchpad = static_cast(_mm_malloc(m_size, align)); -} - - -xmrig::VirtualMemory::~VirtualMemory() -{ - if (!m_scratchpad) { - return; - } - - if (isHugePages()) { - freeLargePagesMemory(m_scratchpad, m_size); - } - else { - _mm_free(m_scratchpad); - } -} - - bool xmrig::VirtualMemory::isHugepagesAvailable() { return hugepagesAvailable; @@ -218,12 +187,6 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t) } -void xmrig::VirtualMemory::init() -{ - hugepagesAvailable = TrySetLockPagesPrivilege(); -} - - void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size) { DWORD oldProtect; @@ -236,3 +199,28 @@ void xmrig::VirtualMemory::unprotectExecutableMemory(void *p, size_t size) DWORD oldProtect; VirtualProtect(p, size, PAGE_EXECUTE_READWRITE, &oldProtect); } + + +void xmrig::VirtualMemory::osInit() +{ + hugepagesAvailable = TrySetLockPagesPrivilege(); +} + + +bool xmrig::VirtualMemory::allocateLargePagesMemory() +{ + m_scratchpad = static_cast(allocateLargePagesMemory(m_size)); + if (m_scratchpad) { + m_flags.set(FLAG_HUGEPAGES, true); + + return true; + } + + return false; +} + + +void xmrig::VirtualMemory::freeLargePagesMemory() +{ + freeLargePagesMemory(m_scratchpad, m_size); +} diff --git a/src/net/JobResults.cpp b/src/net/JobResults.cpp index c6bd68bb..e8b4adce 100644 --- a/src/net/JobResults.cpp +++ b/src/net/JobResults.cpp @@ -105,7 +105,7 @@ static inline void checkHash(const JobBundle &bundle, std::vector &re static void getResults(JobBundle &bundle, std::vector &results, uint32_t &errors, bool hwAES) { const auto &algorithm = bundle.job.algorithm(); - auto memory = new VirtualMemory(algorithm.l3(), false); + auto memory = new VirtualMemory(algorithm.l3(), false, false); uint8_t hash[32]{ 0 }; if (algorithm.family() == Algorithm::RANDOM_X) { From 0e0a26f6448a7afc66220becd79390ca6cf3f335 Mon Sep 17 00:00:00 2001 From: XMRig Date: Mon, 7 Oct 2019 13:37:12 +0700 Subject: [PATCH 4/9] Fixed Linux build. --- src/backend/common/interfaces/IMemoryPool.h | 1 + src/backend/cpu/CpuWorker.cpp | 2 +- src/crypto/common/VirtualMemory_unix.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/common/interfaces/IMemoryPool.h b/src/backend/common/interfaces/IMemoryPool.h index 869bad32..44ff2495 100644 --- a/src/backend/common/interfaces/IMemoryPool.h +++ b/src/backend/common/interfaces/IMemoryPool.h @@ -28,6 +28,7 @@ #define XMRIG_IMEMORYPOOL_H +#include #include diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp index d993e6e6..d6e917fb 100644 --- a/src/backend/cpu/CpuWorker.cpp +++ b/src/backend/cpu/CpuWorker.cpp @@ -62,7 +62,7 @@ xmrig::CpuWorker::CpuWorker(size_t id, const CpuLaunchData &data) : m_miner(data.miner), m_ctx() { - m_memory = new VirtualMemory(m_algorithm.l3() * N, data.hugePages, true); + m_memory = new VirtualMemory(m_algorithm.l3() * N, data.hugePages, true, m_node); } diff --git a/src/crypto/common/VirtualMemory_unix.cpp b/src/crypto/common/VirtualMemory_unix.cpp index 8a66c34d..bb0f9658 100644 --- a/src/crypto/common/VirtualMemory_unix.cpp +++ b/src/crypto/common/VirtualMemory_unix.cpp @@ -107,7 +107,7 @@ bool xmrig::VirtualMemory::allocateLargePagesMemory() if (m_scratchpad) { m_flags.set(FLAG_HUGEPAGES, true); - madvise(m_scratchpad, size, MADV_RANDOM | MADV_WILLNEED); + madvise(m_scratchpad, m_size, MADV_RANDOM | MADV_WILLNEED); if (mlock(m_scratchpad, m_size) == 0) { m_flags.set(FLAG_LOCK, true); From 2dc4ceae290a4e8ced8a90f028922437be0dda2c Mon Sep 17 00:00:00 2001 From: XMRig Date: Mon, 7 Oct 2019 20:39:04 +0700 Subject: [PATCH 5/9] Added class NUMAMemoryPool. --- CMakeLists.txt | 7 +- src/crypto/common/NUMAMemoryPool.cpp | 106 +++++++++++++++++++++++++++ src/crypto/common/NUMAMemoryPool.h | 72 ++++++++++++++++++ src/crypto/common/VirtualMemory.cpp | 14 +++- src/crypto/rx/RxVm.cpp | 6 +- 5 files changed, 199 insertions(+), 6 deletions(-) create mode 100644 src/crypto/common/NUMAMemoryPool.cpp create mode 100644 src/crypto/common/NUMAMemoryPool.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bb2570e..90abfd42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,8 +119,13 @@ set(SOURCES_CRYPTO ) if (WITH_HWLOC) + list(APPEND HEADERS_CRYPTO + src/crypto/common/NUMAMemoryPool.h + ) + list(APPEND SOURCES_CRYPTO - src/crypto/common/VirtualMemory_hwloc.cpp + src/crypto/common/NUMAMemoryPool.cpp + src/crypto/common/VirtualMemory_hwloc.cpp ) endif() diff --git a/src/crypto/common/NUMAMemoryPool.cpp b/src/crypto/common/NUMAMemoryPool.cpp new file mode 100644 index 00000000..8c48b4ca --- /dev/null +++ b/src/crypto/common/NUMAMemoryPool.cpp @@ -0,0 +1,106 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2018-2019 tevador + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "crypto/common/NUMAMemoryPool.h" +#include "crypto/common/VirtualMemory.h" +#include "backend/cpu/Cpu.h" +#include "crypto/common/MemoryPool.h" + + +#include + + +namespace xmrig { + + +constexpr size_t pageSize = 2 * 1024 * 1024; + + +} // namespace xmrig + + +xmrig::NUMAMemoryPool::NUMAMemoryPool(size_t size, bool hugePages) : + m_hugePages(hugePages), + m_nodeSize(std::max(size / Cpu::info()->nodes(), 1)), + m_size(size) +{ +} + + +xmrig::NUMAMemoryPool::~NUMAMemoryPool() +{ + for (auto kv : m_map) { + delete kv.second; + } +} + + +bool xmrig::NUMAMemoryPool::isHugePages(uint32_t node) const +{ + if (!m_size) { + return false; + } + + return getOrCreate(node)->isHugePages(node); +} + + +uint8_t *xmrig::NUMAMemoryPool::get(size_t size, uint32_t node) +{ + if (!m_size) { + return nullptr; + } + + return getOrCreate(node)->get(size, node); +} + + +void xmrig::NUMAMemoryPool::release(uint32_t node) +{ + const auto pool = get(node); + if (pool) { + pool->release(node); + } +} + + +xmrig::IMemoryPool *xmrig::NUMAMemoryPool::get(uint32_t node) const +{ + return m_map.count(node) ? m_map.at(node) : nullptr; +} + + +xmrig::IMemoryPool *xmrig::NUMAMemoryPool::getOrCreate(uint32_t node) const +{ + auto pool = get(node); + if (!pool) { + pool = new MemoryPool(m_nodeSize, m_hugePages, node); + m_map.insert({ node, pool }); + } + + return pool; +} diff --git a/src/crypto/common/NUMAMemoryPool.h b/src/crypto/common/NUMAMemoryPool.h new file mode 100644 index 00000000..4e030494 --- /dev/null +++ b/src/crypto/common/NUMAMemoryPool.h @@ -0,0 +1,72 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2018-2019 tevador + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_NUMAMEMORYPOOL_H +#define XMRIG_NUMAMEMORYPOOL_H + + +#include "backend/common/interfaces/IMemoryPool.h" +#include "base/tools/Object.h" + + +#include + + +namespace xmrig { + + +class IMemoryPool; + + +class NUMAMemoryPool : public IMemoryPool +{ +public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(NUMAMemoryPool) + + NUMAMemoryPool(size_t size, bool hugePages); + ~NUMAMemoryPool() override; + +protected: + bool isHugePages(uint32_t node) const override; + uint8_t *get(size_t size, uint32_t node) override; + void release(uint32_t node) override; + +private: + IMemoryPool *get(uint32_t node) const; + IMemoryPool *getOrCreate(uint32_t node) const; + + bool m_hugePages = true; + size_t m_nodeSize = 0; + size_t m_size = 0; + mutable std::map m_map; +}; + + +} /* namespace xmrig */ + + + +#endif /* XMRIG_NUMAMEMORYPOOL_H */ diff --git a/src/crypto/common/VirtualMemory.cpp b/src/crypto/common/VirtualMemory.cpp index 332c07fd..95030846 100644 --- a/src/crypto/common/VirtualMemory.cpp +++ b/src/crypto/common/VirtualMemory.cpp @@ -32,6 +32,11 @@ #include "crypto/common/portable/mm_malloc.h" +#ifdef XMRIG_FEATURE_HWLOC +# include "crypto/common/NUMAMemoryPool.h" +#endif + + #include #include @@ -111,5 +116,12 @@ void xmrig::VirtualMemory::init(bool hugePages, int poolSize) osInit(); } - pool = new MemoryPool(poolSize < 0 ? Cpu::info()->threads() : poolSize, hugePages); +# ifdef XMRIG_FEATURE_HWLOC + if (Cpu::info()->nodes() > 1) { + pool = new NUMAMemoryPool(align(poolSize < 0 ? Cpu::info()->threads() : poolSize, Cpu::info()->nodes()), hugePages); + } else +# endif + { + pool = new MemoryPool(poolSize < 0 ? Cpu::info()->threads() : poolSize, hugePages); + } } diff --git a/src/crypto/rx/RxVm.cpp b/src/crypto/rx/RxVm.cpp index 526b5ce6..e8d615e8 100644 --- a/src/crypto/rx/RxVm.cpp +++ b/src/crypto/rx/RxVm.cpp @@ -43,11 +43,9 @@ xmrig::RxVm::RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes) if (!dataset->cache() || dataset->cache()->isJIT()) { m_flags |= RANDOMX_FLAG_JIT; - m_vm = randomx_create_vm(static_cast(m_flags), nullptr, dataset->get(), scratchpad); - } - else { - m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache()->get(), dataset->get(), scratchpad); } + + m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache() ? dataset->cache()->get() : nullptr, dataset->get(), scratchpad); } From c4170fbb86a0790ab9588830c0b0eaf265570f4c Mon Sep 17 00:00:00 2001 From: XMRig Date: Mon, 7 Oct 2019 21:11:58 +0700 Subject: [PATCH 6/9] Removed unnecessary error message. --- src/base/net/stratum/Client.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index b9189247..287ce4a5 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -908,8 +908,14 @@ void xmrig::Client::onConnect(uv_connect_t *req, int status) LOG_ERR("[%s] connect error: \"%s\"", client->url(), uv_strerror(status)); } + if (client->state() == ReconnectingState) { + return; + } + if (client->state() != ConnectingState) { - LOG_ERR("[%s] connect error: \"invalid state: %d\"", client->url(), client->state()); + if (!client->isQuiet()) { + LOG_ERR("[%s] connect error: \"invalid state: %d\"", client->url(), client->state()); + } return; } From 9dce868fb90bc69e24447a631a6ec5028d4ce8c0 Mon Sep 17 00:00:00 2001 From: XMRig Date: Mon, 7 Oct 2019 23:38:01 +0700 Subject: [PATCH 7/9] Added "memory-pool" option. --- src/backend/cpu/CpuConfig.cpp | 26 +++++++++++++++++++++++--- src/backend/cpu/CpuConfig.h | 5 ++++- src/core/Controller.cpp | 2 +- src/crypto/common/VirtualMemory.cpp | 6 +++--- src/crypto/common/VirtualMemory.h | 2 +- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/backend/cpu/CpuConfig.cpp b/src/backend/cpu/CpuConfig.cpp index 8a8a76c6..adda40dc 100644 --- a/src/backend/cpu/CpuConfig.cpp +++ b/src/backend/cpu/CpuConfig.cpp @@ -36,6 +36,7 @@ static const char *kEnabled = "enabled"; static const char *kHugePages = "huge-pages"; static const char *kHwAes = "hw-aes"; static const char *kMaxThreadsHint = "max-threads-hint"; +static const char *kMemoryPool = "memory-pool"; static const char *kPriority = "priority"; #ifdef XMRIG_FEATURE_ASM @@ -90,6 +91,7 @@ rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const obj.AddMember(StringRef(kHugePages), m_hugePages, allocator); obj.AddMember(StringRef(kHwAes), m_aes == AES_AUTO ? Value(kNullType) : Value(m_aes == AES_HW), allocator); obj.AddMember(StringRef(kPriority), priority() != -1 ? Value(priority()) : Value(kNullType), allocator); + obj.AddMember(StringRef(kMemoryPool), m_memoryPool < 1 ? Value(m_memoryPool < 0) : Value(m_memoryPool), allocator); if (m_threads.isEmpty()) { obj.AddMember(StringRef(kMaxThreadsHint), m_limit, allocator); @@ -109,6 +111,12 @@ rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const } +size_t xmrig::CpuConfig::memPoolSize() const +{ + return m_memoryPool < 0 ? Cpu::info()->threads() : m_memoryPool; +} + + std::vector xmrig::CpuConfig::get(const Miner *miner, const Algorithm &algorithm) const { std::vector out; @@ -137,6 +145,7 @@ void xmrig::CpuConfig::read(const rapidjson::Value &value, uint32_t version) setAesMode(Json::getValue(value, kHwAes)); setPriority(Json::getInt(value, kPriority, -1)); + setMemoryPool(Json::getValue(value, kMemoryPool)); # ifdef XMRIG_FEATURE_ASM m_assembly = Json::getValue(value, kAsm); @@ -205,12 +214,23 @@ void xmrig::CpuConfig::generateArgon2() } -void xmrig::CpuConfig::setAesMode(const rapidjson::Value &aesMode) +void xmrig::CpuConfig::setAesMode(const rapidjson::Value &value) { - if (aesMode.IsBool()) { - m_aes = aesMode.GetBool() ? AES_HW : AES_SOFT; + if (value.IsBool()) { + m_aes = value.GetBool() ? AES_HW : AES_SOFT; } else { m_aes = AES_AUTO; } } + + +void xmrig::CpuConfig::setMemoryPool(const rapidjson::Value &value) +{ + if (value.IsBool()) { + m_memoryPool = value.GetBool() ? -1 : 0; + } + else if (value.IsInt()) { + m_memoryPool = value.GetInt(); + } +} diff --git a/src/backend/cpu/CpuConfig.h b/src/backend/cpu/CpuConfig.h index 27075425..60d0a1c5 100644 --- a/src/backend/cpu/CpuConfig.h +++ b/src/backend/cpu/CpuConfig.h @@ -48,6 +48,7 @@ public: bool isHwAES() const; rapidjson::Value toJSON(rapidjson::Document &doc) const; + size_t memPoolSize() const; std::vector get(const Miner *miner, const Algorithm &algorithm) const; void read(const rapidjson::Value &value, uint32_t version); @@ -62,7 +63,8 @@ public: private: void generate(); void generateArgon2(); - void setAesMode(const rapidjson::Value &aesMode); + void setAesMode(const rapidjson::Value &value); + void setMemoryPool(const rapidjson::Value &value); inline void setPriority(int priority) { m_priority = (priority >= -1 && priority <= 5) ? priority : -1; } @@ -71,6 +73,7 @@ private: bool m_enabled = true; bool m_hugePages = true; bool m_shouldSave = false; + int m_memoryPool = 0; int m_priority = -1; String m_argon2Impl; Threads m_threads; diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index 75a3e51b..21570ea8 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -52,7 +52,7 @@ int xmrig::Controller::init() { Base::init(); - VirtualMemory::init(config()->cpu().isHugePages(), -1); + VirtualMemory::init(config()->cpu().memPoolSize(), config()->cpu().isHugePages()); m_network = new Network(this); diff --git a/src/crypto/common/VirtualMemory.cpp b/src/crypto/common/VirtualMemory.cpp index 95030846..08364a89 100644 --- a/src/crypto/common/VirtualMemory.cpp +++ b/src/crypto/common/VirtualMemory.cpp @@ -110,7 +110,7 @@ void xmrig::VirtualMemory::destroy() } -void xmrig::VirtualMemory::init(bool hugePages, int poolSize) +void xmrig::VirtualMemory::init(size_t poolSize, bool hugePages) { if (!pool) { osInit(); @@ -118,10 +118,10 @@ void xmrig::VirtualMemory::init(bool hugePages, int poolSize) # ifdef XMRIG_FEATURE_HWLOC if (Cpu::info()->nodes() > 1) { - pool = new NUMAMemoryPool(align(poolSize < 0 ? Cpu::info()->threads() : poolSize, Cpu::info()->nodes()), hugePages); + pool = new NUMAMemoryPool(align(poolSize, Cpu::info()->nodes()), hugePages); } else # endif { - pool = new MemoryPool(poolSize < 0 ? Cpu::info()->threads() : poolSize, hugePages); + pool = new MemoryPool(poolSize, hugePages); } } diff --git a/src/crypto/common/VirtualMemory.h b/src/crypto/common/VirtualMemory.h index 668ae907..3c983951 100644 --- a/src/crypto/common/VirtualMemory.h +++ b/src/crypto/common/VirtualMemory.h @@ -64,7 +64,7 @@ public: static void destroy(); static void flushInstructionCache(void *p, size_t size); static void freeLargePagesMemory(void *p, size_t size); - static void init(bool hugePages, int poolSize); + static void init(size_t poolSize, bool hugePages); static void protectExecutableMemory(void *p, size_t size); static void unprotectExecutableMemory(void *p, size_t size); From d3b137c81706517959b21ef95751a1314cca9c72 Mon Sep 17 00:00:00 2001 From: XMRig Date: Tue, 8 Oct 2019 08:50:33 +0700 Subject: [PATCH 8/9] Fixed crash. --- src/crypto/common/VirtualMemory.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/crypto/common/VirtualMemory.cpp b/src/crypto/common/VirtualMemory.cpp index 08364a89..66d29061 100644 --- a/src/crypto/common/VirtualMemory.cpp +++ b/src/crypto/common/VirtualMemory.cpp @@ -86,8 +86,7 @@ xmrig::VirtualMemory::~VirtualMemory() std::lock_guard lock(mutex); pool->release(m_node); } - - if (isHugePages()) { + else if (isHugePages()) { freeLargePagesMemory(); } else { From 58c81be1f129077db4a1004a99bb219b2f61e42a Mon Sep 17 00:00:00 2001 From: XMRig Date: Tue, 8 Oct 2019 09:41:36 +0700 Subject: [PATCH 9/9] Updated default config and docs. --- doc/CPU.md | 3 +++ src/config.json | 1 + src/core/config/Config_default.h | 1 + 3 files changed, 5 insertions(+) diff --git a/doc/CPU.md b/doc/CPU.md index 66745a66..c830590f 100644 --- a/doc/CPU.md +++ b/doc/CPU.md @@ -97,3 +97,6 @@ Allow override automatically detected Argon2 implementation, this option added m #### `max-threads-hint` (since v4.2.0) Maximum CPU threads count (in percentage) hint for autoconfig. [CPU_MAX_USAGE.md](CPU_MAX_USAGE.md) + +#### `memory-pool` (since v4.3.0) +Use continuous, persistent memory block for mining threads, useful for preserve huge pages allocation while algorithm swithing. Default value `false` (feature disabled) or `true` or specific count of 2 MB huge pages. diff --git a/src/config.json b/src/config.json index ec8ac419..65a2a2dc 100644 --- a/src/config.json +++ b/src/config.json @@ -23,6 +23,7 @@ "huge-pages": true, "hw-aes": null, "priority": null, + "memory-pool": false, "max-threads-hint": 100, "asm": true, "argon2-impl": null, diff --git a/src/core/config/Config_default.h b/src/core/config/Config_default.h index 00c4cf12..e0e3f272 100644 --- a/src/core/config/Config_default.h +++ b/src/core/config/Config_default.h @@ -57,6 +57,7 @@ R"===( "huge-pages": true, "hw-aes": null, "priority": null, + "memory-pool": false, "max-threads-hint": 100, "asm": true, "argon2-impl": null,