diff --git a/src/backend/common/common.cmake b/src/backend/common/common.cmake index ce7f3a27..ddeca0d6 100644 --- a/src/backend/common/common.cmake +++ b/src/backend/common/common.cmake @@ -1,6 +1,7 @@ set(HEADERS_BACKEND_COMMON src/backend/common/Hashrate.h src/backend/common/interfaces/IBackend.h + src/backend/common/interfaces/IRxListener.h src/backend/common/interfaces/IThread.h src/backend/common/interfaces/IWorker.h src/backend/common/misc/PciTopology.h diff --git a/src/backend/common/interfaces/IRxListener.h b/src/backend/common/interfaces/IRxListener.h new file mode 100644 index 00000000..b4dde9e5 --- /dev/null +++ b/src/backend/common/interfaces/IRxListener.h @@ -0,0 +1,44 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2018 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_IRXLISTENER_H +#define XMRIG_IRXLISTENER_H + + +namespace xmrig { + + +class IRxListener +{ +public: + virtual ~IRxListener() = default; + +# ifdef XMRIG_ALGO_RANDOMX + virtual void onDatasetReady() = 0; +# endif +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_IRXLISTENER_H diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 91c0e920..b2b1e8db 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -24,8 +24,8 @@ #include +#include #include -#include #include "backend/common/Hashrate.h" @@ -63,13 +63,14 @@ namespace xmrig { +static std::mutex mutex; + + class MinerPrivate { public: inline MinerPrivate(Controller *controller) : controller(controller) { - uv_rwlock_init(&rwlock); - # ifdef XMRIG_ALGO_RANDOMX Rx::init(); # endif @@ -78,8 +79,6 @@ public: inline ~MinerPrivate() { - uv_rwlock_destroy(&rwlock); - delete timer; for (IBackend *backend : backends) { @@ -118,7 +117,7 @@ public: } - inline void handleJobChange(bool reset) + inline void handleJobChange() { active = true; @@ -230,10 +229,19 @@ public: # endif +# ifdef XMRIG_ALGO_RANDOMX + bool initRX(IRxListener *listener) + { + return Rx::init(job, controller->config()->rx().threads(), controller->config()->cpu().isHugePages(), controller->config()->rx().isNUMA(), listener); + } +# endif + + Algorithm algorithm; Algorithms algorithms; bool active = false; bool enabled = true; + bool reset = true; Controller *controller; Job job; mutable std::map maxHashrate; @@ -241,7 +249,6 @@ public: String userJobId; Timer *timer = nullptr; uint64_t ticks = 0; - uv_rwlock_t rwlock; }; @@ -302,11 +309,9 @@ const std::vector &xmrig::Miner::backends() const xmrig::Job xmrig::Miner::job() const { - uv_rwlock_rdlock(&d_ptr->rwlock); - Job job = d_ptr->job; - uv_rwlock_rdunlock(&d_ptr->rwlock); + std::lock_guard lock(mutex); - return job; + return d_ptr->job; } @@ -382,12 +387,12 @@ void xmrig::Miner::setJob(const Job &job, bool donate) d_ptr->algorithm = job.algorithm(); - uv_rwlock_wrlock(&d_ptr->rwlock); + mutex.lock(); const uint8_t index = donate ? 1 : 0; - const bool reset = !(d_ptr->job.index() == 1 && index == 0 && d_ptr->userJobId == job.id()); - d_ptr->job = job; + d_ptr->reset = !(d_ptr->job.index() == 1 && index == 0 && d_ptr->userJobId == job.id()); + d_ptr->job = job; d_ptr->job.setIndex(index); if (index == 0) { @@ -395,16 +400,16 @@ void xmrig::Miner::setJob(const Job &job, bool donate) } # ifdef XMRIG_ALGO_RANDOMX - Rx::init(d_ptr->job, - d_ptr->controller->config()->rx().threads(), - d_ptr->controller->config()->cpu().isHugePages(), - d_ptr->controller->config()->rx().isNUMA() - ); + const bool ready = d_ptr->initRX(this); +# else + constexpr const bool ready = true; # endif - uv_rwlock_wrunlock(&d_ptr->rwlock); + mutex.unlock(); - d_ptr->handleJobChange(reset); + if (ready) { + d_ptr->handleJobChange(); + } } @@ -490,3 +495,15 @@ void xmrig::Miner::onRequest(IApiRequest &request) } } #endif + + +#ifdef XMRIG_ALGO_RANDOMX +void xmrig::Miner::onDatasetReady() +{ + if (!Rx::isReady(job())) { + return; + } + + d_ptr->handleJobChange(); +} +#endif diff --git a/src/core/Miner.h b/src/core/Miner.h index 6fc75cd0..21568f12 100644 --- a/src/core/Miner.h +++ b/src/core/Miner.h @@ -29,6 +29,7 @@ #include +#include "backend/common/interfaces/IRxListener.h" #include "base/api/interfaces/IApiListener.h" #include "base/kernel/interfaces/IBaseListener.h" #include "base/kernel/interfaces/ITimerListener.h" @@ -44,7 +45,7 @@ class MinerPrivate; class IBackend; -class Miner : public ITimerListener, public IBaseListener, public IApiListener +class Miner : public ITimerListener, public IBaseListener, public IApiListener, public IRxListener { public: Miner(Controller *controller); @@ -69,6 +70,10 @@ protected: void onRequest(IApiRequest &request) override; # endif +# ifdef XMRIG_ALGO_RANDOMX + void onDatasetReady() override; +# endif + private: MinerPrivate *d_ptr; }; diff --git a/src/crypto/rx/Rx.cpp b/src/crypto/rx/Rx.cpp index 8e757ddf..2b8d06e6 100644 --- a/src/crypto/rx/Rx.cpp +++ b/src/crypto/rx/Rx.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef XMRIG_FEATURE_HWLOC @@ -36,12 +37,14 @@ #endif +#include "backend/common/interfaces/IRxListener.h" #include "backend/cpu/Cpu.h" #include "base/io/log/Log.h" #include "base/kernel/Platform.h" #include "base/net/stratum/Job.h" #include "base/tools/Buffer.h" #include "base/tools/Chrono.h" +#include "base/tools/Handle.h" #include "crypto/rx/Rx.h" #include "crypto/rx/RxAlgo.h" #include "crypto/rx/RxCache.h" @@ -56,6 +59,7 @@ class RxPrivate; static const char *tag = BLUE_BG(WHITE_BOLD_S " rx ") " "; static RxPrivate *d_ptr = nullptr; +static std::mutex mutex; #ifdef XMRIG_FEATURE_HWLOC @@ -91,6 +95,11 @@ public: inline RxPrivate() : m_seed() { + m_async = new uv_async_t; + m_async->data = this; + + uv_async_init(uv_default_loop(), m_async, RxPrivate::onReady); + # ifdef XMRIG_FEATURE_HWLOC if (Cpu::info()->nodes() > 1) { for (uint32_t nodeId : HwlocCpuInfo::nodeIndexes()) { @@ -107,6 +116,8 @@ public: inline ~RxPrivate() { + Handle::close(m_async); + for (auto const &item : datasets) { delete item.second; } @@ -119,6 +130,7 @@ public: 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; } + inline void asyncSend() { m_ready++; if (m_ready == count()) { uv_async_send(m_async); } } static void allocate(uint32_t nodeId) @@ -163,12 +175,12 @@ public: static void initDataset(uint32_t nodeId, uint32_t threads) { - std::lock_guard lock(d_ptr->mutex); + std::lock_guard lock(mutex); const uint64_t ts = Chrono::steadyMSecs(); d_ptr->getOrAllocate(nodeId)->init(d_ptr->seed(), threads); - d_ptr->m_ready++; + d_ptr->asyncSend(); LOG_INFO("%s" CYAN_BOLD("#%u") GREEN(" init done") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, nodeId, Chrono::steadyMSecs() - ts); } @@ -196,7 +208,7 @@ public: } - inline void setState(const Job &job, bool hugePages, bool numa) + inline void setState(const Job &job, bool hugePages, bool numa, IRxListener *listener) { if (m_algorithm != job.algorithm()) { m_algorithm = RxAlgo::apply(job.algorithm()); @@ -205,6 +217,7 @@ public: m_ready = 0; m_numa = numa && Cpu::info()->nodes() > 1; m_hugePages = hugePages; + m_listener = listener; memcpy(m_seed, job.seedHash(), sizeof(m_seed)); } @@ -217,23 +230,73 @@ public: std::map datasets; - std::mutex mutex; private: - bool m_hugePages = true; - bool m_numa = true; + static void onReady(uv_async_t *) + { + if (d_ptr->m_listener) { + d_ptr->m_listener->onDatasetReady(); + } + } + Algorithm m_algorithm; - size_t m_ready = 0; + bool m_hugePages = true; + bool m_numa = true; + IRxListener *m_listener = nullptr; + size_t m_ready = 0; uint8_t m_seed[32]; + uv_async_t *m_async; }; } // namespace xmrig +bool xmrig::Rx::init(const Job &job, int initThreads, bool hugePages, bool numa, IRxListener *listener) +{ + if (job.algorithm().family() != Algorithm::RANDOM_X) { + return true; + } + + std::lock_guard lock(mutex); + + if (d_ptr->isReady(job)) { + return true; + } + + d_ptr->setState(job, hugePages, numa, listener); + const uint32_t threads = initThreads < 1 ? static_cast(Cpu::info()->threads()) : static_cast(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->isNUMA()) { + for (auto const &item : d_ptr->datasets) { + std::thread thread(RxPrivate::initDataset, item.first, threads); + thread.detach(); + } + } + else +# endif + { + std::thread thread(RxPrivate::initDataset, 0, threads); + thread.detach(); + } + + return false; +} + + bool xmrig::Rx::isReady(const Job &job) { - std::lock_guard lock(d_ptr->mutex); + std::lock_guard lock(mutex); return d_ptr->isReady(job); } @@ -241,7 +304,7 @@ bool xmrig::Rx::isReady(const Job &job) xmrig::RxDataset *xmrig::Rx::dataset(const Job &job, uint32_t nodeId) { - std::lock_guard lock(d_ptr->mutex); + std::lock_guard lock(mutex); if (!d_ptr->isReady(job)) { return nullptr; } @@ -253,7 +316,7 @@ xmrig::RxDataset *xmrig::Rx::dataset(const Job &job, uint32_t nodeId) std::pair xmrig::Rx::hugePages() { std::pair pages(0, 0); - std::lock_guard lock(d_ptr->mutex); + std::lock_guard lock(mutex); for (auto const &item : d_ptr->datasets) { if (!item.second) { @@ -281,43 +344,3 @@ 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; - } - - std::lock_guard lock(d_ptr->mutex); - - if (d_ptr->isReady(job)) { - return; - } - - d_ptr->setState(job, hugePages, numa); - const uint32_t threads = initThreads < 1 ? static_cast(Cpu::info()->threads()) : static_cast(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->isNUMA()) { - for (auto const &item : d_ptr->datasets) { - std::thread thread(RxPrivate::initDataset, item.first, threads); - thread.detach(); - } - } - else -# endif - { - std::thread thread(RxPrivate::initDataset, 0, threads); - thread.detach(); - } -} diff --git a/src/crypto/rx/Rx.h b/src/crypto/rx/Rx.h index 1a383055..cdff9504 100644 --- a/src/crypto/rx/Rx.h +++ b/src/crypto/rx/Rx.h @@ -37,19 +37,20 @@ namespace xmrig class Algorithm; -class RxDataset; +class IRxListener; class Job; +class RxDataset; class Rx { public: + static bool init(const Job &job, int initThreads, bool hugePages, bool numa, IRxListener *listener); static bool isReady(const Job &job); static RxDataset *dataset(const Job &job, uint32_t nodeId); static std::pair hugePages(); static void destroy(); static void init(); - static void init(const Job &job, int initThreads, bool hugePages, bool numa); };