Added initial memory pool support.

This commit is contained in:
XMRig 2019-10-07 12:36:40 +07:00
parent c13c83b902
commit 68d77b02d7
17 changed files with 444 additions and 127 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,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}"

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

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

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,52 @@
/* 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 <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

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

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().isHugePages(), -1);
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

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

@ -25,41 +25,91 @@
*/
#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"
#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);
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;
}
}
return hwloc_bitmap_first(pu->nodeset);
# else
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);
}
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);
}

View file

@ -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,8 +78,14 @@ private:
FLAG_MAX
};
static void osInit();
bool allocateLargePagesMemory();
void freeLargePagesMemory();
const size_t m_size;
const uint32_t m_node;
std::bitset<FLAG_MAX> m_flags;
size_t m_size = 0;
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,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<uint8_t*>(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<uint8_t*>(_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<uint8_t*>(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);
}

View file

@ -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<uint8_t*>(allocateLargePagesMemory(m_size));
if (m_scratchpad) {
m_flags.set(FLAG_HUGEPAGES, true);
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);
}
}
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<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

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