Merge branch 'evo' into beta

This commit is contained in:
XMRig 2019-08-03 22:25:26 +07:00
commit 14441ab5f9
24 changed files with 322 additions and 292 deletions

View file

@ -1,3 +1,10 @@
# v2.99.4-beta
- [#1062](https://github.com/xmrig/xmrig/issues/1062) Fixed 32 bit support. **32 bit is slow and deprecated**.
- [#1088](https://github.com/xmrig/xmrig/pull/1088) Fixed macOS compilation.
- [#1095](https://github.com/xmrig/xmrig/pull/1095) Fixed compatibility with hwloc 1.10.x.
- Optimized RandomX initialization and switching, fixed rare crash when re-initialize dataset.
- Fixed ARM build with hwloc.
# v2.99.3-beta
- [#1082](https://github.com/xmrig/xmrig/issues/1082) Fixed hwloc auto configuration on AMD FX CPUs.
- Added command line option `--export-topology` for export hwloc topology to a XML file.

View file

@ -34,7 +34,11 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
endif()
if (WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -Wl,--large-address-aware")
endif()
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
endif()

View file

@ -26,7 +26,7 @@
#define XMRIG_THREAD_H
#include <uv.h>
#include <thread>
#include "backend/common/interfaces/IWorker.h"
@ -43,21 +43,21 @@ class Thread
{
public:
inline Thread(IBackend *backend, size_t index, const T &config) : m_index(index), m_config(config), m_backend(backend) {}
inline ~Thread() { uv_thread_join(&m_thread); delete m_worker; }
inline ~Thread() { m_thread.join(); delete m_worker; }
inline const T &config() const { return m_config; }
inline IBackend *backend() const { return m_backend; }
inline IWorker *worker() const { return m_worker; }
inline size_t index() const { return m_index; }
inline void setWorker(IWorker *worker) { m_worker = worker; }
inline void start(void (*callback) (void *)) { uv_thread_create(&m_thread, callback, this); }
inline void start(void (*callback) (void *)) { m_thread = std::thread(callback, this); }
private:
const size_t m_index = 0;
const T m_config;
IBackend *m_backend;
IWorker *m_worker = nullptr;
uv_thread_t m_thread;
std::thread m_thread;
};

View file

@ -49,7 +49,8 @@ namespace xmrig {
extern template class Threads<CpuThread>;
static const String kType = "cpu";
static const char *tag = CYAN_BG_BOLD(" cpu ");
static const String kType = "cpu";
struct LaunchStatus
@ -94,7 +95,8 @@ public:
inline void start()
{
LOG_INFO(GREEN_BOLD("CPU") " use profile " BLUE_BG(WHITE_BOLD_S " %s ") WHITE_BOLD_S " (" CYAN_BOLD("%zu") WHITE_BOLD(" threads)") " scratchpad " CYAN_BOLD("%zu KB"),
LOG_INFO("%s use profile " BLUE_BG(WHITE_BOLD_S " %s ") WHITE_BOLD_S " (" CYAN_BOLD("%zu") WHITE_BOLD(" threads)") " scratchpad " CYAN_BOLD("%zu KB"),
tag,
profileName.data(),
threads.size(),
algo.memory() / 1024
@ -170,12 +172,8 @@ const xmrig::String &xmrig::CpuBackend::type() const
}
void xmrig::CpuBackend::prepare(const Job &nextJob)
void xmrig::CpuBackend::prepare(const Job &)
{
if (nextJob.algorithm().family() == Algorithm::RANDOM_X && nextJob.algorithm() != d_ptr->algo) {
d_ptr->workers.stop();
d_ptr->threads.clear();
}
}
@ -207,9 +205,7 @@ void xmrig::CpuBackend::printHashrate(bool details)
void xmrig::CpuBackend::setJob(const Job &job)
{
if (!isEnabled()) {
d_ptr->workers.stop();
d_ptr->threads.clear();
return;
return stop();
}
const CpuConfig &cpu = d_ptr->controller->config()->cpu();
@ -249,7 +245,8 @@ void xmrig::CpuBackend::start(IWorker *worker)
const double percent = d_ptr->status.hugePages == 0 ? 0.0 : static_cast<double>(d_ptr->status.hugePages) / d_ptr->status.pages * 100.0;
const size_t memory = d_ptr->status.ways * d_ptr->status.memory / 1024;
LOG_INFO(GREEN_BOLD("CPU READY") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") BLACK_BOLD(" (%" PRIu64 " ms)"),
LOG_INFO("%s" GREEN_BOLD(" READY") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") BLACK_BOLD(" (%" PRIu64 " ms)"),
tag,
d_ptr->status.threads, d_ptr->status.ways,
(d_ptr->status.hugePages == d_ptr->status.pages ? GREEN_BOLD_S : (d_ptr->status.hugePages == 0 ? RED_BOLD_S : YELLOW_BOLD_S)),
d_ptr->status.hugePages, d_ptr->status.pages, percent, memory,
@ -265,7 +262,12 @@ void xmrig::CpuBackend::start(IWorker *worker)
void xmrig::CpuBackend::stop()
{
const uint64_t ts = Chrono::steadyMSecs();
d_ptr->workers.stop();
d_ptr->threads.clear();
LOG_INFO("%s" YELLOW(" stopped") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, Chrono::steadyMSecs() - ts);
}

View file

@ -82,7 +82,9 @@ xmrig::CpuWorker<N>::~CpuWorker()
template<size_t N>
void xmrig::CpuWorker<N>::allocateRandomX_VM()
{
while (!Rx::isReady(m_job.currentJob(), m_node)) {
RxDataset *dataset = Rx::dataset(m_job.currentJob(), m_node);
while (dataset == nullptr) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
if (Nonce::sequence(Nonce::CPU) == 0) {
@ -90,13 +92,6 @@ void xmrig::CpuWorker<N>::allocateRandomX_VM()
}
}
RxDataset *dataset = Rx::dataset(m_node);
assert(dataset != nullptr);
if (!dataset) {
return;
}
if (!m_vm) {
m_vm = new RxVm(dataset, m_memory->scratchpad(), !m_hwAES);
}

View file

@ -39,7 +39,6 @@ if (WITH_HWLOC)
endif()
set(SOURCES_CPUID
src/backend/cpu/platform/BasicCpuInfo.cpp
src/backend/cpu/platform/BasicCpuInfo.h
src/backend/cpu/platform/HwlocCpuInfo.cpp
src/backend/cpu/platform/HwlocCpuInfo.h
@ -66,7 +65,10 @@ else()
set(SOURCES_CPUID
src/backend/cpu/platform/BasicCpuInfo.h
)
endif()
if (NOT WITH_LIBCPUID)
if (XMRIG_ARM)
set(SOURCES_CPUID ${SOURCES_CPUID} src/backend/cpu/platform/BasicCpuInfo_arm.cpp)
else()

View file

@ -36,10 +36,10 @@
xmrig::BasicCpuInfo::BasicCpuInfo() :
m_aes(false),
m_brand(),
m_avx2(false),
m_threads(std::thread::hardware_concurrency())
m_threads(std::thread::hardware_concurrency()),
m_aes(false),
m_avx2(false)
{
# ifdef XMRIG_ARMv8
memcpy(m_brand, "ARMv8", 5);

View file

@ -32,6 +32,12 @@
#include <hwloc.h>
#if HWLOC_API_VERSION < 0x00010b00
# define HWLOC_OBJ_PACKAGE HWLOC_OBJ_SOCKET
# define HWLOC_OBJ_NUMANODE HWLOC_OBJ_NODE
#endif
#include "backend/cpu/platform/HwlocCpuInfo.h"
#include "base/io/log/Log.h"
@ -152,7 +158,21 @@ xmrig::HwlocCpuInfo::HwlocCpuInfo() : BasicCpuInfo(),
# endif
hwloc_obj_t root = hwloc_get_root_obj(m_topology);
snprintf(m_backend, sizeof m_backend, "hwloc/%s", hwloc_obj_get_info_by_name(root, "hwlocVersion"));
# if HWLOC_API_VERSION >= 0x00010b00
const char *version = hwloc_obj_get_info_by_name(root, "hwlocVersion");
if (version) {
snprintf(m_backend, sizeof m_backend, "hwloc/%s", version);
}
else
# endif
{
snprintf(m_backend, sizeof m_backend, "hwloc/%d.%d.%d",
(HWLOC_API_VERSION>>16)&0x000000ff,
(HWLOC_API_VERSION>>8 )&0x000000ff,
(HWLOC_API_VERSION )&0x000000ff
);
}
findCache(root, 2, 3, [this](hwloc_obj_t found) { this->m_cache[found->attr->cache.depth] += found->attr->cache.size; });

View file

@ -31,6 +31,7 @@
#include <algorithm>
#include <mutex>
#include <string.h>
#include <string>
#include <time.h>
@ -69,14 +70,11 @@ public:
inline LogPrivate() :
m_buf()
{
uv_mutex_init(&m_mutex);
}
inline ~LogPrivate()
{
uv_mutex_destroy(&m_mutex);
for (ILogBackend *backend : m_backends) {
delete backend;
}
@ -91,13 +89,14 @@ public:
size_t size = 0;
size_t offset = 0;
lock();
std::lock_guard<std::mutex> lock(m_mutex);
timestamp(level, size, offset);
color(level, size);
const int rc = vsnprintf(m_buf + size, sizeof (m_buf) - offset - 32, fmt, args);
if (rc < 0) {
return unlock();
return;
}
size += std::min(static_cast<size_t>(rc), sizeof (m_buf) - offset - 32);
@ -119,16 +118,10 @@ public:
fputs(txt.c_str(), stdout);
fflush(stdout);
}
unlock();
}
private:
inline void lock() { uv_mutex_lock(&m_mutex); }
inline void unlock() { uv_mutex_unlock(&m_mutex); }
inline void timestamp(Log::Level level, size_t &size, size_t &offset)
{
if (level == Log::NONE) {
@ -192,8 +185,8 @@ private:
char m_buf[4096];
std::mutex m_mutex;
std::vector<ILogBackend*> m_backends;
uv_mutex_t m_mutex;
};

View file

@ -85,6 +85,8 @@ private:
#define BLUE_BG_BOLD_S CSI "44;1m"
#define MAGENTA_BG_S CSI "45m"
#define MAGENTA_BG_BOLD_S CSI "45;1m"
#define CYAN_BG_S CSI "46m"
#define CYAN_BG_BOLD_S CSI "46;1m"
//color wrappings
#define BLACK(x) BLACK_S x CLEAR
@ -108,6 +110,8 @@ private:
#define BLUE_BG_BOLD(x) BLUE_BG_BOLD_S x CLEAR
#define MAGENTA_BG(x) MAGENTA_BG_S x CLEAR
#define MAGENTA_BG_BOLD(x) MAGENTA_BG_BOLD_S x CLEAR
#define CYAN_BG(x) CYAN_BG_S x CLEAR
#define CYAN_BG_BOLD(x) CYAN_BG_BOLD_S x CLEAR
#define LOG_EMERG(x, ...) xmrig::Log::print(xmrig::Log::EMERG, x, ##__VA_ARGS__)

View file

@ -160,3 +160,20 @@ void xmrig::Job::setDiff(uint64_t diff)
m_rawTarget[16] = '\0';
# endif
}
void xmrig::Job::copy(const Job &other)
{
m_algorithm = other.m_algorithm;
m_nicehash = other.m_nicehash;
m_size = other.m_size;
m_clientId = other.m_clientId;
m_id = other.m_id;
m_diff = other.m_diff;
m_height = other.m_height;
m_target = other.m_target;
m_index = other.m_index;
memcpy(m_blob, other.m_blob, sizeof (m_blob));
memcpy(m_seedHash, other.m_seedHash, sizeof(m_seedHash));
}

View file

@ -90,10 +90,13 @@ public:
inline bool operator==(const Job &other) const { return isEqual(other); }
inline bool operator!=(const Job &other) const { return !isEqual(other); }
inline Job &operator=(const Job &other) { copy(other); return *this; }
private:
void copy(const Job &other);
Algorithm m_algorithm;
bool m_nicehash = false;
bool m_nicehash = false;
size_t m_size = 0;
String m_clientId;
String m_id;

View file

@ -43,17 +43,20 @@ public:
~Buffer();
inline char *data() { return m_data; }
inline const char *data() const { return m_data; }
inline size_t size() const { return m_size; }
inline void from(const Buffer &other) { from(other.data(), other.size()); }
inline bool isEqual(const Buffer &other) const { return m_size == other.m_size && (m_size == 0 || memcmp(m_data, other.m_data, m_size) == 0); }
inline char *data() { return m_data; }
inline const char *data() const { return m_data; }
inline size_t size() const { return m_size; }
inline void from(const Buffer &other) { from(other.data(), other.size()); }
void from(const char *data, size_t size);
inline Buffer &operator=(const Buffer &other) { from(other); return *this; }
inline Buffer &operator=(Buffer &&other) { move(std::move(other)); return *this; }
inline bool operator!=(const Buffer &other) const { return !isEqual(other); }
inline bool operator==(const Buffer &other) const { return isEqual(other); }
inline Buffer &operator=(Buffer &&other) { move(std::move(other)); return *this; }
inline Buffer &operator=(const Buffer &other) { from(other); return *this; }
static Buffer allocUnsafe(size_t size);

View file

@ -59,6 +59,10 @@ public:
inline MinerPrivate(Controller *controller) : controller(controller)
{
uv_rwlock_init(&rwlock);
# ifdef XMRIG_ALGO_RANDOMX
Rx::init();
# endif
}
@ -71,6 +75,10 @@ public:
for (IBackend *backend : backends) {
delete backend;
}
# ifdef XMRIG_ALGO_RANDOMX
Rx::destroy();
# endif
}
@ -353,12 +361,18 @@ void xmrig::Miner::setEnabled(bool enabled)
void xmrig::Miner::setJob(const Job &job, bool donate)
{
d_ptr->algorithm = job.algorithm();
for (IBackend *backend : d_ptr->backends) {
backend->prepare(job);
}
# ifdef XMRIG_ALGO_RANDOMX
if (d_ptr->algorithm.family() == Algorithm::RANDOM_X && job.algorithm().family() == Algorithm::RANDOM_X && !Rx::isReady(job)) {
stop();
}
# endif
d_ptr->algorithm = job.algorithm();
uv_rwlock_wrlock(&d_ptr->rwlock);
const uint8_t index = donate ? 1 : 0;
@ -372,7 +386,7 @@ void xmrig::Miner::setJob(const Job &job, bool donate)
}
# ifdef XMRIG_ALGO_RANDOMX
Rx::init(job,
Rx::init(d_ptr->job,
d_ptr->controller->config()->rx().threads(),
d_ptr->controller->config()->cpu().isHugePages(),
d_ptr->controller->config()->rx().isNUMA()

View file

@ -36,7 +36,10 @@ static const char *kAffinity = "affinity";
static const char *kAsterisk = "*";
static const char *kCpu = "cpu";
static const char *kIntensity = "intensity";
static const char *kRandomX = "randomx";
#ifdef XMRIG_ALGO_RANDOMX
static const char *kRandomX = "randomx";
#endif
static inline uint64_t intensity(uint64_t av)

View file

@ -28,6 +28,10 @@
#ifdef XMRIG_FEATURE_HWLOC
# include <hwloc.h>
# include "backend/cpu/platform/HwlocCpuInfo.h"
#
# if HWLOC_API_VERSION < 0x00010b00
# define HWLOC_OBJ_NUMANODE HWLOC_OBJ_NODE
# endif
#endif

View file

@ -68,9 +68,9 @@ DECL(randomx_program_prologue):
#else
#include "asm/program_prologue_linux.inc"
#endif
movapd xmm13, xmmword ptr mantissaMask[rip]
movapd xmm14, xmmword ptr exp240[rip]
movapd xmm15, xmmword ptr scaleMask[rip]
movapd xmm13, xmmword ptr [mantissaMask+rip]
movapd xmm14, xmmword ptr [exp240+rip]
movapd xmm15, xmmword ptr [scaleMask+rip]
jmp DECL(randomx_program_loop_begin)
.balign 64
@ -177,26 +177,26 @@ DECL(randomx_sshash_end):
DECL(randomx_sshash_init):
lea r8, [rbx+1]
#include "asm/program_sshash_prefetch.inc"
imul r8, qword ptr r0_mul[rip]
mov r9, qword ptr r1_add[rip]
imul r8, qword ptr [r0_mul+rip]
mov r9, qword ptr [r1_add+rip]
xor r9, r8
mov r10, qword ptr r2_add[rip]
mov r10, qword ptr [r2_add+rip]
xor r10, r8
mov r11, qword ptr r3_add[rip]
mov r11, qword ptr [r3_add+rip]
xor r11, r8
mov r12, qword ptr r4_add[rip]
mov r12, qword ptr [r4_add+rip]
xor r12, r8
mov r13, qword ptr r5_add[rip]
mov r13, qword ptr [r5_add+rip]
xor r13, r8
mov r14, qword ptr r6_add[rip]
mov r14, qword ptr [r6_add+rip]
xor r14, r8
mov r15, qword ptr r7_add[rip]
mov r15, qword ptr [r7_add+rip]
xor r15, r8
jmp DECL(randomx_program_end)
.balign 64
#include "asm/program_sshash_constants.inc"
.balign 64
DECL(randomx_program_end):
nop

View file

@ -26,80 +26,33 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "virtual_memory.hpp"
#include <stdexcept>
#if defined(_WIN32) || defined(__CYGWIN__)
#include <windows.h>
#else
#ifdef __APPLE__
#include <mach/vm_statistics.h>
#endif
#include <sys/types.h>
#include <sys/mman.h>
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
std::string getErrorMessage(const char* function) {
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
std::string message(messageBuffer, size);
LocalFree(messageBuffer);
return std::string(function) + std::string(": ") + message;
}
#endif
#include "crypto/common/VirtualMemory.h"
#include "virtual_memory.hpp"
void* allocExecutableMemory(std::size_t bytes) {
void* mem;
#if defined(_WIN32) || defined(__CYGWIN__)
mem = VirtualAlloc(nullptr, bytes, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (mem == nullptr)
throw std::runtime_error(getErrorMessage("allocExecutableMemory - VirtualAlloc"));
#else
mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (mem == MAP_FAILED)
throw std::runtime_error("allocExecutableMemory - mmap failed");
#endif
return mem;
void *mem = xmrig::VirtualMemory::allocateExecutableMemory(bytes);
if (mem == nullptr) {
throw std::runtime_error("Failed to allocate executable memory");
}
return mem;
}
constexpr std::size_t align(std::size_t pos, std::size_t align) {
return ((pos - 1) / align + 1) * align;
}
void* allocLargePagesMemory(std::size_t bytes) {
void* mem;
#if defined(_WIN32) || defined(__CYGWIN__)
auto pageMinimum = GetLargePageMinimum();
if (pageMinimum > 0)
mem = VirtualAlloc(NULL, align(bytes, pageMinimum), MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE);
else
throw std::runtime_error("allocLargePagesMemory - Large pages are not supported");
if (mem == nullptr)
throw std::runtime_error(getErrorMessage("allocLargePagesMemory - VirtualAlloc"));
#else
#ifdef __APPLE__
mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
#elif defined(__FreeBSD__)
mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER, -1, 0);
#else
mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, -1, 0);
#endif
if (mem == MAP_FAILED)
throw std::runtime_error("allocLargePagesMemory - mmap failed");
#endif
return mem;
void *mem = xmrig::VirtualMemory::allocateLargePagesMemory(bytes);
if (mem == nullptr) {
throw std::runtime_error("Failed to allocate large pages memory");
}
return mem;
}
void freePagedMemory(void* ptr, std::size_t bytes) {
#if defined(_WIN32) || defined(__CYGWIN__)
VirtualFree(ptr, 0, MEM_RELEASE);
#else
munmap(ptr, bytes);
#endif
xmrig::VirtualMemory::freeLargePagesMemory(ptr, bytes);
}

View file

@ -26,8 +26,8 @@
#include <map>
#include <mutex>
#include <thread>
#include <uv.h>
#ifdef XMRIG_FEATURE_HWLOC
@ -43,6 +43,7 @@
#include "base/tools/Buffer.h"
#include "base/tools/Chrono.h"
#include "crypto/rx/Rx.h"
#include "crypto/rx/RxAlgo.h"
#include "crypto/rx/RxCache.h"
#include "crypto/rx/RxDataset.h"
@ -50,15 +51,57 @@
namespace xmrig {
static const char *tag = BLUE_BG(WHITE_BOLD_S " rx ") " ";
class RxPrivate;
static const char *tag = BLUE_BG(WHITE_BOLD_S " rx ") " ";
static RxPrivate *d_ptr = nullptr;
#ifdef XMRIG_FEATURE_HWLOC
static void bindToNUMANode(uint32_t nodeId)
{
hwloc_topology_t topology;
hwloc_topology_init(&topology);
hwloc_topology_load(topology);
hwloc_obj_t node = hwloc_get_numanode_obj_by_os_index(topology, nodeId);
if (node) {
if (HwlocCpuInfo::has(HwlocCpuInfo::SET_THISTHREAD_MEMBIND)) {
# if HWLOC_API_VERSION >= 0x20000
hwloc_set_membind(topology, node->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_THREAD | HWLOC_MEMBIND_BYNODESET);
# else
hwloc_set_membind_nodeset(topology, node->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_THREAD);
# endif
}
Platform::setThreadAffinity(static_cast<uint64_t>(hwloc_bitmap_first(node->cpuset)));
}
hwloc_topology_destroy(topology);
}
#else
inline static void bindToNUMANode(uint32_t) {}
#endif
class RxPrivate
{
public:
inline RxPrivate()
inline RxPrivate() :
m_seed()
{
uv_mutex_init(&mutex);
# ifdef XMRIG_FEATURE_HWLOC
if (Cpu::info()->nodes() > 1) {
for (uint32_t nodeId : HwlocCpuInfo::nodeIndexes()) {
datasets.insert({ nodeId, nullptr });
}
}
else
# endif
{
datasets.insert({ 0, nullptr });
}
}
@ -69,41 +112,22 @@ public:
}
datasets.clear();
uv_mutex_destroy(&mutex);
}
inline void lock() { uv_mutex_lock(&mutex); }
inline void unlock() { uv_mutex_unlock(&mutex); }
inline bool isNUMA() const { return m_numa; }
inline const Algorithm &algorithm() const { return m_algorithm; }
inline const uint8_t *seed() const { return m_seed; }
inline size_t count() const { return isNUMA() ? datasets.size() : 1; }
static void allocate(RxPrivate *self, uint32_t nodeId)
static void allocate(uint32_t nodeId)
{
const uint64_t ts = Chrono::steadyMSecs();
# ifdef XMRIG_FEATURE_HWLOC
if (self->numa) {
hwloc_topology_t topology;
hwloc_topology_init(&topology);
hwloc_topology_load(topology);
hwloc_obj_t node = hwloc_get_numanode_obj_by_os_index(topology, nodeId);
if (node) {
if (HwlocCpuInfo::has(HwlocCpuInfo::SET_THISTHREAD_MEMBIND)) {
# if HWLOC_API_VERSION >= 0x20000
hwloc_set_membind(topology, node->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_THREAD | HWLOC_MEMBIND_BYNODESET);
# else
hwloc_set_membind_nodeset(topology, node->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_THREAD);
# endif
}
Platform::setThreadAffinity(static_cast<uint64_t>(hwloc_bitmap_first(node->cpuset)));
}
hwloc_topology_destroy(topology);
if (d_ptr->isNUMA()) {
bindToNUMANode(nodeId);
}
# endif
LOG_INFO("%s" CYAN_BOLD("#%u") MAGENTA_BOLD(" allocate") CYAN_BOLD(" %zu MB") BLACK_BOLD(" (%zu+%zu) for RandomX dataset & cache"),
tag,
@ -113,8 +137,8 @@ public:
RxCache::size() / 1024 / 1024
);
RxDataset *dataset = new RxDataset(self->hugePages);
self->datasets[nodeId] = dataset;
RxDataset *dataset = new RxDataset(d_ptr->m_hugePages);
d_ptr->datasets[nodeId] = dataset;
if (dataset->get() != nullptr) {
const auto hugePages = dataset->hugePages();
@ -137,43 +161,99 @@ public:
}
bool hugePages = true;
bool numa = true;
static void initDataset(uint32_t nodeId, uint32_t threads)
{
std::lock_guard<std::mutex> lock(d_ptr->mutex);
const uint64_t ts = Chrono::steadyMSecs();
d_ptr->getOrAllocate(nodeId)->init(d_ptr->seed(), threads);
d_ptr->m_ready++;
LOG_INFO("%s" CYAN_BOLD("#%u") GREEN(" init done") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, nodeId, Chrono::steadyMSecs() - ts);
}
inline RxDataset *getOrAllocate(uint32_t nodeId)
{
RxDataset *dataset = datasets.at(nodeId);
if (dataset == nullptr) {
# ifdef XMRIG_FEATURE_HWLOC
if (d_ptr->isNUMA()) {
std::thread thread(allocate, nodeId);
thread.join();
} else
# endif
{
allocate(nodeId);
}
dataset = datasets.at(nodeId);
}
return dataset;
}
inline void setState(const Job &job, bool hugePages, bool numa)
{
if (m_algorithm != job.algorithm()) {
m_algorithm = RxAlgo::apply(job.algorithm());
}
m_ready = 0;
m_numa = numa && Cpu::info()->nodes() > 1;
m_hugePages = hugePages;
memcpy(m_seed, job.seedHash(), sizeof(m_seed));
}
inline bool isReady(const Job &job)
{
return m_ready == count() && m_algorithm == job.algorithm() && memcmp(m_seed, job.seedHash(), sizeof(m_seed)) == 0;
}
std::map<uint32_t, RxDataset *> datasets;
uv_mutex_t mutex;
std::mutex mutex;
private:
bool m_hugePages = true;
bool m_numa = true;
Algorithm m_algorithm;
size_t m_ready = 0;
uint8_t m_seed[32];
};
static RxPrivate *d_ptr = new RxPrivate();
} // namespace xmrig
bool xmrig::Rx::isReady(const Job &job, uint32_t nodeId)
bool xmrig::Rx::isReady(const Job &job)
{
d_ptr->lock();
const bool rc = isReady(job.seedHash(), job.algorithm(), d_ptr->numa ? nodeId : 0);
d_ptr->unlock();
std::lock_guard<std::mutex> lock(d_ptr->mutex);
return rc;
return d_ptr->isReady(job);
}
xmrig::RxDataset *xmrig::Rx::dataset(uint32_t nodeId)
xmrig::RxDataset *xmrig::Rx::dataset(const Job &job, uint32_t nodeId)
{
d_ptr->lock();
RxDataset *dataset = d_ptr->datasets[d_ptr->numa ? nodeId : 0];
d_ptr->unlock();
std::lock_guard<std::mutex> lock(d_ptr->mutex);
if (!d_ptr->isReady(job)) {
return nullptr;
}
return dataset;
return d_ptr->datasets.at(d_ptr->isNUMA() ? nodeId : 0);
}
std::pair<size_t, size_t> xmrig::Rx::hugePages()
{
std::pair<size_t, size_t> pages(0, 0);
d_ptr->lock();
std::lock_guard<std::mutex> lock(d_ptr->mutex);
for (auto const &item : d_ptr->datasets) {
if (!item.second) {
@ -185,116 +265,59 @@ std::pair<size_t, size_t> xmrig::Rx::hugePages()
pages.second += p.second;
}
d_ptr->unlock();
return pages;
}
void xmrig::Rx::destroy()
{
delete d_ptr;
d_ptr = nullptr;
}
void xmrig::Rx::init()
{
d_ptr = new RxPrivate();
}
void xmrig::Rx::init(const Job &job, int initThreads, bool hugePages, bool numa)
{
if (job.algorithm().family() != Algorithm::RANDOM_X) {
return;
}
d_ptr->lock();
size_t ready = 0;
for (auto const &item : d_ptr->datasets) {
if (isReady(job.seedHash(), job.algorithm(), item.first)) {
ready++;
}
}
if (!d_ptr->datasets.empty() && ready == d_ptr->datasets.size()) {
d_ptr->unlock();
std::lock_guard<std::mutex> lock(d_ptr->mutex);
if (d_ptr->isReady(job)) {
return;
}
d_ptr->hugePages = hugePages;
d_ptr->numa = numa && Cpu::info()->nodes() > 1;
const uint32_t threads = initThreads < 1 ? static_cast<uint32_t>(Cpu::info()->threads())
: static_cast<uint32_t>(initThreads);
d_ptr->setState(job, hugePages, numa);
const uint32_t threads = initThreads < 1 ? static_cast<uint32_t>(Cpu::info()->threads()) : static_cast<uint32_t>(initThreads);
const String buf = Buffer::toHex(job.seedHash(), 8);
LOG_INFO("%s" MAGENTA_BOLD("init dataset%s") " algo " WHITE_BOLD("%s (") CYAN_BOLD("%u") WHITE_BOLD(" threads)") BLACK_BOLD(" seed %s..."),
tag,
d_ptr->count() > 1 ? "s" : "",
job.algorithm().shortName(),
threads,
buf.data()
);
# ifdef XMRIG_FEATURE_HWLOC
if (d_ptr->numa) {
for (uint32_t nodeId : HwlocCpuInfo::nodeIndexes()) {
std::thread thread(initDataset, nodeId, job.seedHash(), job.algorithm(), threads);
if (d_ptr->isNUMA()) {
for (auto const &item : d_ptr->datasets) {
std::thread thread(RxPrivate::initDataset, item.first, threads);
thread.detach();
}
}
else
# endif
{
std::thread thread(initDataset, 0, job.seedHash(), job.algorithm(), threads);
std::thread thread(RxPrivate::initDataset, 0, threads);
thread.detach();
}
d_ptr->unlock();
}
void xmrig::Rx::stop()
{
delete d_ptr;
d_ptr = nullptr;
}
bool xmrig::Rx::isReady(const uint8_t *seed, const Algorithm &algorithm, uint32_t nodeId)
{
return !d_ptr->datasets.empty() && d_ptr->datasets[nodeId] != nullptr && d_ptr->datasets[nodeId]->isReady(seed, algorithm);
}
void xmrig::Rx::initDataset(uint32_t nodeId, const uint8_t *seed, const Algorithm &algorithm, uint32_t threads)
{
d_ptr->lock();
RxDataset *dataset = d_ptr->datasets[nodeId];
if (!dataset) {
# ifdef XMRIG_FEATURE_HWLOC
if (d_ptr->numa) {
std::thread thread(RxPrivate::allocate, d_ptr, nodeId);
thread.join();
} else
# endif
{
RxPrivate::allocate(d_ptr, nodeId);
}
dataset = d_ptr->datasets[nodeId];
}
if (!dataset->isReady(seed, algorithm)) {
const uint64_t ts = Chrono::steadyMSecs();
if (dataset->get() != nullptr) {
LOG_INFO("%s" CYAN_BOLD("#%u") MAGENTA_BOLD(" init dataset") " algo " WHITE_BOLD("%s (") CYAN_BOLD("%u") WHITE_BOLD(" threads)") BLACK_BOLD(" seed %s..."),
tag,
nodeId,
algorithm.shortName(),
threads,
Buffer::toHex(seed, 8).data()
);
}
else {
LOG_INFO("%s" CYAN_BOLD("#%u") MAGENTA_BOLD(" init cache") " algo " WHITE_BOLD("%s") BLACK_BOLD(" seed %s..."),
tag,
nodeId,
algorithm.shortName(),
Buffer::toHex(seed, 8).data()
);
}
dataset->init(seed, algorithm, threads);
LOG_INFO("%s" CYAN_BOLD("#%u") GREEN(" init done") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, nodeId, Chrono::steadyMSecs() - ts);
}
d_ptr->unlock();
}

View file

@ -44,15 +44,12 @@ class Job;
class Rx
{
public:
static bool isReady(const Job &job, uint32_t nodeId);
static RxDataset *dataset(uint32_t nodeId);
static bool isReady(const Job &job);
static RxDataset *dataset(const Job &job, uint32_t nodeId);
static std::pair<size_t, size_t> hugePages();
static void destroy();
static void init();
static void init(const Job &job, int initThreads, bool hugePages, bool numa);
static void stop();
private:
static bool isReady(const uint8_t *seed, const Algorithm &algorithm, uint32_t nodeId);
static void initDataset(uint32_t nodeId, const uint8_t *seed, const Algorithm &algorithm, uint32_t threads);
};

View file

@ -53,11 +53,12 @@ public:
inline randomx_cache *get() const { return m_cache; }
bool init(const void *seed);
bool isReady(const void *seed) const;
static inline constexpr size_t size() { return RANDOMX_CACHE_MAX_SIZE; }
private:
bool isReady(const void *seed) const;
int m_flags = 0;
randomx_cache *m_cache = nullptr;
uint8_t m_seed[32];

View file

@ -64,16 +64,8 @@ xmrig::RxDataset::~RxDataset()
}
bool xmrig::RxDataset::init(const void *seed, const Algorithm &algorithm, uint32_t numThreads)
bool xmrig::RxDataset::init(const void *seed, uint32_t numThreads)
{
if (isReady(seed, algorithm)) {
return false;
}
if (m_algorithm != algorithm) {
m_algorithm = RxAlgo::apply(algorithm);
}
cache()->init(seed);
if (!get()) {
@ -104,12 +96,6 @@ bool xmrig::RxDataset::init(const void *seed, const Algorithm &algorithm, uint32
}
bool xmrig::RxDataset::isReady(const void *seed, const Algorithm &algorithm) const
{
return algorithm == m_algorithm && cache()->isReady(seed);
}
std::pair<size_t, size_t> xmrig::RxDataset::hugePages() const
{
constexpr size_t twoMiB = 2u * 1024u * 1024u;

View file

@ -52,8 +52,7 @@ public:
inline randomx_dataset *get() const { return m_dataset; }
inline RxCache *cache() const { return m_cache; }
bool init(const void *seed, const Algorithm &algorithm, uint32_t numThreads);
bool isReady(const void *seed, const Algorithm &algorithm) const;
bool init(const void *seed, uint32_t numThreads);
std::pair<size_t, size_t> hugePages() const;
static inline constexpr size_t size() { return RANDOMX_DATASET_MAX_SIZE; }

View file

@ -28,7 +28,7 @@
#define APP_ID "xmrig"
#define APP_NAME "XMRig"
#define APP_DESC "XMRig CPU miner"
#define APP_VERSION "2.99.3-beta"
#define APP_VERSION "2.99.4-evo"
#define APP_DOMAIN "xmrig.com"
#define APP_SITE "www.xmrig.com"
#define APP_COPYRIGHT "Copyright (C) 2016-2019 xmrig.com"
@ -36,7 +36,7 @@
#define APP_VER_MAJOR 2
#define APP_VER_MINOR 99
#define APP_VER_PATCH 3
#define APP_VER_PATCH 4
#ifdef _MSC_VER
# if (_MSC_VER >= 1920)