Merge branch 'feature-hugepages-pool' into evo

This commit is contained in:
XMRig 2019-10-08 09:47:01 +07:00
commit 119e7ea7bf
33 changed files with 811 additions and 185 deletions

View file

@ -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,22 @@ 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 HEADERS_CRYPTO
src/crypto/common/NUMAMemoryPool.h
)
list(APPEND SOURCES_CRYPTO
src/crypto/common/NUMAMemoryPool.cpp
src/crypto/common/VirtualMemory_hwloc.cpp
)
endif()
if (WIN32)
set(SOURCES_OS
"${SOURCES_OS}"

View file

@ -70,7 +70,7 @@ if (WITH_RANDOMX)
endif()
if (WITH_HWLOC)
list(APPEND SOURCES_CRYPTO
list(APPEND HEADERS_CRYPTO
src/crypto/rx/RxNUMAStorage.h
)

View file

@ -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.

View file

@ -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(m_controller->config()->cpu().isHugePages());
Summary::print(m_controller);
if (m_controller->config()->isDryRun()) {

View file

@ -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);

View file

@ -55,7 +55,7 @@ protected:
std::atomic<uint64_t> m_hashCount;
std::atomic<uint64_t> m_timestamp;
uint32_t m_node = 0;
uint64_t m_count;
uint64_t m_count = 0;
};

View file

@ -0,0 +1,53 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_IMEMORYPOOL_H
#define XMRIG_IMEMORYPOOL_H
#include <cstddef>
#include <cstdint>
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 */

View file

@ -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::CpuLaunchData> xmrig::CpuConfig::get(const Miner *miner, const Algorithm &algorithm) const
{
std::vector<CpuLaunchData> 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();
}
}

View file

@ -48,6 +48,7 @@ public:
bool isHwAES() const;
rapidjson::Value toJSON(rapidjson::Document &doc) const;
size_t memPoolSize() const;
std::vector<CpuLaunchData> 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<CpuThreads> m_threads;

View file

@ -62,7 +62,7 @@ xmrig::CpuWorker<N>::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, m_node);
}

View file

@ -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()

View file

@ -23,7 +23,10 @@
*/
#include <string.h>
#include "base/kernel/Platform.h"
#include <cstring>
#include <uv.h>
@ -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();

View file

@ -26,12 +26,15 @@
#define XMRIG_PLATFORM_H
#include <stdint.h>
#include <cstdint>
#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 */

View file

@ -0,0 +1,49 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "base/kernel/Platform.h"
#include "backend/cpu/platform/HwlocCpuInfo.h"
#include "backend/cpu/Cpu.h"
#include <hwloc.h>
bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id)
{
auto cpu = static_cast<HwlocCpuInfo *>(Cpu::info());
hwloc_obj_t pu = hwloc_get_pu_obj_by_os_index(cpu->topology(), static_cast<unsigned>(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;
}

View file

@ -30,7 +30,7 @@
#include <uv.h>
#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<integer_t>(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;

View file

@ -39,7 +39,7 @@
#include <uv.h>
#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;

View file

@ -29,8 +29,8 @@
#include <uv.h>
#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<RtlGetVersionFunction>(GetProcAddress(ntdll, "RtlGetVersion"));
auto pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(GetProcAddress(ntdll, "RtlGetVersion"));
if (pRtlGetVersion) {
pRtlGetVersion((LPOSVERSIONINFO) &result);
pRtlGetVersion(reinterpret_cast<LPOSVERSIONINFO>(&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;

View file

@ -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) {
if (!client->isQuiet()) {
LOG_ERR("[%s] connect error: \"invalid state: %d\"", client->url(), client->state());
}
return;
}

View file

@ -23,6 +23,7 @@
"huge-pages": true,
"hw-aes": null,
"priority": null,
"memory-pool": false,
"max-threads-hint": 100,
"asm": true,
"argon2-impl": null,

View file

@ -23,15 +23,17 @@
*/
#include <cassert>
#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 <cassert>
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().memPoolSize(), config()->cpu().isHugePages());
m_network = new Network(this);
return 0;
}

View file

@ -26,11 +26,12 @@
#define XMRIG_CONFIG_H
#include <stdint.h>
#include <cstdint>
#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;

View file

@ -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,

View file

@ -0,0 +1,95 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "crypto/common/MemoryPool.h"
#include "crypto/common/VirtualMemory.h"
#include <cassert>
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;
}
}

View file

@ -0,0 +1,66 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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 */

View file

@ -0,0 +1,106 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "crypto/common/NUMAMemoryPool.h"
#include "crypto/common/VirtualMemory.h"
#include "backend/cpu/Cpu.h"
#include "crypto/common/MemoryPool.h"
#include <algorithm>
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_t>(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;
}

View file

@ -0,0 +1,72 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_NUMAMEMORYPOOL_H
#define XMRIG_NUMAMEMORYPOOL_H
#include "backend/common/interfaces/IMemoryPool.h"
#include "base/tools/Object.h"
#include <map>
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<uint32_t, IMemoryPool *> m_map;
};
} /* namespace xmrig */
#endif /* XMRIG_NUMAMEMORYPOOL_H */

View file

@ -25,38 +25,102 @@
*/
#ifdef XMRIG_FEATURE_HWLOC
# include <hwloc.h>
# 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"
#ifdef XMRIG_FEATURE_HWLOC
# include "crypto/common/NUMAMemoryPool.h"
#endif
#include <cinttypes>
#include <mutex>
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<std::mutex> lock(mutex);
if (hugePages && !pool->isHugePages(node) && allocateLargePagesMemory()) {
return;
}
auto cpu = static_cast<HwlocCpuInfo *>(Cpu::info());
hwloc_obj_t pu = hwloc_get_pu_obj_by_os_index(cpu->topology(), static_cast<unsigned>(affinity));
m_scratchpad = pool->get(m_size, node);
if (m_scratchpad) {
m_flags.set(FLAG_HUGEPAGES, pool->isHugePages(node));
m_flags.set(FLAG_EXTERNAL, true);
if (pu == nullptr || !cpu->membind(pu->nodeset)) {
LOG_WARN("CPU #%02" PRId64 " warning: \"can't bind memory\"", affinity);
return 0;
return;
}
}
return hwloc_bitmap_first(pu->nodeset);
# else
return 0;
# endif
if (hugePages && allocateLargePagesMemory()) {
return;
}
m_scratchpad = static_cast<uint8_t*>(_mm_malloc(m_size, alignSize));
}
xmrig::VirtualMemory::~VirtualMemory()
{
if (!m_scratchpad) {
return;
}
if (m_flags.test(FLAG_EXTERNAL)) {
std::lock_guard<std::mutex> lock(mutex);
pool->release(m_node);
}
else 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(size_t poolSize, bool hugePages)
{
if (!pool) {
osInit();
}
# ifdef XMRIG_FEATURE_HWLOC
if (Cpu::info()->nodes() > 1) {
pool = new NUMAMemoryPool(align(poolSize, Cpu::info()->nodes()), hugePages);
} else
# endif
{
pool = new MemoryPool(poolSize, hugePages);
}
}

View file

@ -28,8 +28,12 @@
#define XMRIG_VIRTUALMEMORY_H
#include <stddef.h>
#include <stdint.h>
#include "base/tools/Object.h"
#include <bitset>
#include <cstddef>
#include <cstdint>
#include <utility>
@ -39,42 +43,49 @@ namespace xmrig {
class VirtualMemory
{
public:
inline VirtualMemory() {}
VirtualMemory(size_t size, bool hugePages = true, size_t align = 64);
XMRIG_DISABLE_COPY_MOVE_DEFAULT(VirtualMemory)
VirtualMemory(size_t size, bool hugePages, bool usePool, uint32_t node = 0, size_t alignSize = 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; }
inline std::pair<size_t, size_t> hugePages() const
{
return std::pair<size_t, size_t>(isHugePages() ? (align(size()) / 2097152) : 0, align(size()) / 2097152);
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 destroy();
static void flushInstructionCache(void *p, size_t size);
static void freeLargePagesMemory(void *p, size_t size);
static void init(bool hugePages);
static void init(size_t poolSize, bool hugePages);
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;
static void osInit();
int m_flags = 0;
size_t m_size = 0;
bool allocateLargePagesMemory();
void freeLargePagesMemory();
const size_t m_size;
const uint32_t m_node;
std::bitset<FLAG_MAX> m_flags;
uint8_t *m_scratchpad = nullptr;
};

View file

@ -0,0 +1,56 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "crypto/common/VirtualMemory.h"
#include "backend/cpu/Cpu.h"
#include "backend/cpu/platform/HwlocCpuInfo.h"
#include "base/io/log/Log.h"
#include <hwloc.h>
uint32_t xmrig::VirtualMemory::bindToNUMANode(int64_t affinity)
{
if (affinity < 0 || Cpu::info()->nodes() < 2) {
return 0;
}
auto cpu = static_cast<HwlocCpuInfo *>(Cpu::info());
hwloc_obj_t pu = hwloc_get_pu_obj_by_os_index(cpu->topology(), static_cast<unsigned>(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);
}

View file

@ -25,7 +25,7 @@
*/
#include <stdlib.h>
#include <cstdlib>
#include <sys/mman.h>
@ -38,51 +38,12 @@
#endif
int xmrig::VirtualMemory::m_globalFlags = 0;
xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) :
m_size(VirtualMemory::align(size))
bool xmrig::VirtualMemory::isHugepagesAvailable()
{
if (hugePages) {
m_scratchpad = static_cast<uint8_t*>(allocateLargePagesMemory(m_size));
if (m_scratchpad) {
m_flags |= HUGEPAGES;
madvise(m_scratchpad, size, MADV_RANDOM | MADV_WILLNEED);
if (mlock(m_scratchpad, m_size) == 0) {
m_flags |= LOCK;
}
return;
}
}
m_scratchpad = static_cast<uint8_t*>(_mm_malloc(m_size, align));
return true;
}
xmrig::VirtualMemory::~VirtualMemory()
{
if (!m_scratchpad) {
return;
}
if (isHugePages()) {
if (m_flags & LOCK) {
munlock(m_scratchpad, m_size);
}
freeLargePagesMemory(m_scratchpad, m_size);
}
else {
_mm_free(m_scratchpad);
}
}
void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size)
{
# if defined(__APPLE__)
@ -123,14 +84,6 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t size)
}
void xmrig::VirtualMemory::init(bool hugePages)
{
if (hugePages) {
m_globalFlags = HUGEPAGES | HUGEPAGES_AVAILABLE;
}
}
void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size)
{
mprotect(p, size, PROT_READ | PROT_EXEC);
@ -141,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<uint8_t*>(allocateLargePagesMemory(m_size));
if (m_scratchpad) {
m_flags.set(FLAG_HUGEPAGES, true);
madvise(m_scratchpad, m_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);
}

View file

@ -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,37 +147,12 @@ static BOOL TrySetLockPagesPrivilege() {
}
int xmrig::VirtualMemory::m_globalFlags = 0;
} // namespace xmrig
xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) :
m_size(VirtualMemory::align(size))
bool xmrig::VirtualMemory::isHugepagesAvailable()
{
if (hugePages) {
m_scratchpad = static_cast<uint8_t*>(allocateLargePagesMemory(m_size));
if (m_scratchpad) {
m_flags |= HUGEPAGES;
return;
}
}
m_scratchpad = static_cast<uint8_t*>(_mm_malloc(m_size, align));
}
xmrig::VirtualMemory::~VirtualMemory()
{
if (!m_scratchpad) {
return;
}
if (isHugePages()) {
freeLargePagesMemory(m_scratchpad, m_size);
}
else {
_mm_free(m_scratchpad);
}
return hugepagesAvailable;
}
@ -206,20 +187,6 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t)
}
void xmrig::VirtualMemory::init(bool hugePages)
{
if (!hugePages) {
return;
}
m_globalFlags = HUGEPAGES;
if (TrySetLockPagesPrivilege()) {
m_globalFlags |= HUGEPAGES_AVAILABLE;
}
}
void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size)
{
DWORD oldProtect;
@ -232,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<uint8_t*>(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);
}

View file

@ -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<randomx_flags>(m_flags), nullptr, dataset->get(), scratchpad);
}
else {
m_vm = randomx_create_vm(static_cast<randomx_flags>(m_flags), dataset->cache()->get(), dataset->get(), scratchpad);
}
m_vm = randomx_create_vm(static_cast<randomx_flags>(m_flags), dataset->cache() ? dataset->cache()->get() : nullptr, dataset->get(), scratchpad);
}

View file

@ -105,7 +105,7 @@ static inline void checkHash(const JobBundle &bundle, std::vector<JobResult> &re
static void getResults(JobBundle &bundle, std::vector<JobResult> &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) {