diff --git a/README.md b/README.md index 814f927b..6b7ce909 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ CPU backend: --asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer --randomx-init=N threads count to initialize RandomX dataset --randomx-no-numa disable NUMA support for RandomX + --randomx-mode=MODE RandomX mode: auto, fast, light API: --api-worker-id=ID custom worker-id for API diff --git a/src/backend/common/interfaces/IRxStorage.h b/src/backend/common/interfaces/IRxStorage.h index 49273ee3..9e0407b0 100644 --- a/src/backend/common/interfaces/IRxStorage.h +++ b/src/backend/common/interfaces/IRxStorage.h @@ -24,6 +24,9 @@ #define XMRIG_IRXSTORAGE_H +#include "crypto/rx/RxConfig.h" + + #include #include @@ -41,9 +44,9 @@ class IRxStorage public: virtual ~IRxStorage() = default; - virtual RxDataset *dataset(const Job &job, uint32_t nodeId) const = 0; - virtual std::pair hugePages() const = 0; - virtual void init(const RxSeed &seed, uint32_t threads, bool hugePages) = 0; + virtual RxDataset *dataset(const Job &job, uint32_t nodeId) const = 0; + virtual std::pair hugePages() const = 0; + virtual void init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode mode) = 0; }; diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h index 79a42a27..5044545a 100644 --- a/src/base/kernel/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -89,6 +89,7 @@ public: AssemblyKey = 1015, RandomXInitKey = 1022, RandomXNumaKey = 1023, + RandomXModeKey = 1029, CPUMaxThreadsKey = 1026, MemoryPoolKey = 1027, diff --git a/src/config.json b/src/config.json index fbc60474..fbbf8225 100644 --- a/src/config.json +++ b/src/config.json @@ -16,6 +16,7 @@ "colors": true, "randomx": { "init": -1, + "mode": "auto", "numa": true }, "cpu": { diff --git a/src/core/config/ConfigTransform.cpp b/src/core/config/ConfigTransform.cpp index d0264258..667d9117 100644 --- a/src/core/config/ConfigTransform.cpp +++ b/src/core/config/ConfigTransform.cpp @@ -160,6 +160,9 @@ void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const case IConfig::RandomXNumaKey: /* --randomx-no-numa */ return set(doc, kRandomX, "numa", false); + + case IConfig::RandomXModeKey: /* --randomx-mode */ + return set(doc, kRandomX, "mode", arg); # endif # ifdef XMRIG_FEATURE_OPENCL diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h index 80fcf87f..608ac48e 100644 --- a/src/core/config/Config_platform.h +++ b/src/core/config/Config_platform.h @@ -96,6 +96,7 @@ static const option options[] = { # ifdef XMRIG_ALGO_RANDOMX { "randomx-init", 1, nullptr, IConfig::RandomXInitKey }, { "randomx-no-numa", 0, nullptr, IConfig::RandomXNumaKey }, + { "randomx-mode", 1, nullptr, IConfig::RandomXModeKey }, # endif # ifdef XMRIG_FEATURE_OPENCL { "opencl", 0, nullptr, IConfig::OclKey }, diff --git a/src/core/config/usage.h b/src/core/config/usage.h index 48b34b81..dcae30f4 100644 --- a/src/core/config/usage.h +++ b/src/core/config/usage.h @@ -86,6 +86,7 @@ static inline const std::string &usage() # ifdef XMRIG_ALGO_RANDOMX u += " --randomx-init=N threads count to initialize RandomX dataset\n"; u += " --randomx-no-numa disable NUMA support for RandomX\n"; + u += " --randomx-mode=MODE RandomX mode: auto, fast, light\n"; # endif # ifdef XMRIG_FEATURE_HTTP diff --git a/src/crypto/rx/Rx.cpp b/src/crypto/rx/Rx.cpp index 115c0f62..b08f844e 100644 --- a/src/crypto/rx/Rx.cpp +++ b/src/crypto/rx/Rx.cpp @@ -70,7 +70,7 @@ bool xmrig::Rx::init(const Job &job, const RxConfig &config, bool hugePages) return true; } - d_ptr->queue.enqueue(job, config.nodeset(), config.threads(), hugePages); + d_ptr->queue.enqueue(job, config.nodeset(), config.threads(), hugePages, config.mode()); return false; } diff --git a/src/crypto/rx/RxBasicStorage.cpp b/src/crypto/rx/RxBasicStorage.cpp index dcabad5b..bc1ceb2d 100644 --- a/src/crypto/rx/RxBasicStorage.cpp +++ b/src/crypto/rx/RxBasicStorage.cpp @@ -69,11 +69,11 @@ public: } - inline void createDataset(bool hugePages) + inline void createDataset(bool hugePages, RxConfig::Mode mode) { const uint64_t ts = Chrono::steadyMSecs(); - m_dataset = new RxDataset(hugePages, true); + m_dataset = new RxDataset(hugePages, true, mode); printAllocStatus(ts); } @@ -150,19 +150,19 @@ xmrig::RxDataset *xmrig::RxBasicStorage::dataset(const Job &job, uint32_t) const std::pair xmrig::RxBasicStorage::hugePages() const { if (!d_ptr->dataset()) { - return { 0u, 0u }; + return { 0U, 0U }; } return d_ptr->dataset()->hugePages(); } -void xmrig::RxBasicStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages) +void xmrig::RxBasicStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode mode) { d_ptr->setSeed(seed); if (!d_ptr->dataset()) { - d_ptr->createDataset(hugePages); + d_ptr->createDataset(hugePages, mode); } d_ptr->initDataset(threads); diff --git a/src/crypto/rx/RxBasicStorage.h b/src/crypto/rx/RxBasicStorage.h index 63eba1d9..bd6575d2 100644 --- a/src/crypto/rx/RxBasicStorage.h +++ b/src/crypto/rx/RxBasicStorage.h @@ -50,7 +50,7 @@ public: protected: RxDataset *dataset(const Job &job, uint32_t nodeId) const override; std::pair hugePages() const override; - void init(const RxSeed &seed, uint32_t threads, bool hugePages) override; + void init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode mode) override; private: RxBasicStoragePrivate *d_ptr; diff --git a/src/crypto/rx/RxConfig.cpp b/src/crypto/rx/RxConfig.cpp index 07f45eac..2318bfbe 100644 --- a/src/crypto/rx/RxConfig.cpp +++ b/src/crypto/rx/RxConfig.cpp @@ -25,9 +25,54 @@ #include "crypto/rx/RxConfig.h" #include "backend/cpu/Cpu.h" +#include "rapidjson/document.h" + + +#include +#include + + +#ifdef _MSC_VER +# define strcasecmp _stricmp +#endif + + +namespace xmrig { + + +static const std::array modeNames = { "auto", "fast", "light" }; + + +} // namespace xmrig + + +const char *xmrig::RxConfig::modeName() const +{ + return modeNames[m_mode]; +} uint32_t xmrig::RxConfig::threads() const { return m_threads < 1 ? static_cast(Cpu::info()->threads()) : static_cast(m_threads); } + + +xmrig::RxConfig::Mode xmrig::RxConfig::readMode(const rapidjson::Value &value) const +{ + if (value.IsUint()) { + return static_cast(std::min(value.GetUint(), ModeMax - 1)); + } + + if (value.IsString()) { + auto mode = value.GetString(); + + for (size_t i = 0; i < modeNames.size(); i++) { + if (strcasecmp(mode, modeNames[i]) == 0) { + return static_cast(i); + } + } + } + + return LightMode; +} diff --git a/src/crypto/rx/RxConfig.h b/src/crypto/rx/RxConfig.h index 52a832a2..13ebb9d1 100644 --- a/src/crypto/rx/RxConfig.h +++ b/src/crypto/rx/RxConfig.h @@ -38,6 +38,13 @@ namespace xmrig { class RxConfig { public: + enum Mode : uint32_t { + AutoMode, + FastMode, + LightMode, + ModeMax + }; + bool read(const rapidjson::Value &value); rapidjson::Value toJSON(rapidjson::Document &doc) const; @@ -47,11 +54,17 @@ public: inline std::vector nodeset() const { return std::vector(); } # endif + const char *modeName() const; uint32_t threads() const; + inline Mode mode() const { return m_mode; } + private: + Mode readMode(const rapidjson::Value &value) const; + bool m_numa = true; int m_threads = -1; + Mode m_mode = AutoMode; # ifdef XMRIG_FEATURE_HWLOC std::vector m_nodeset; diff --git a/src/crypto/rx/RxConfig_basic.cpp b/src/crypto/rx/RxConfig_basic.cpp index 26ef7a90..1311b220 100644 --- a/src/crypto/rx/RxConfig_basic.cpp +++ b/src/crypto/rx/RxConfig_basic.cpp @@ -31,6 +31,7 @@ namespace xmrig { static const char *kInit = "init"; +static const char *kMode = "mode"; } @@ -42,6 +43,7 @@ rapidjson::Value xmrig::RxConfig::toJSON(rapidjson::Document &doc) const Value obj(kObjectType); obj.AddMember(StringRef(kInit), m_threads, allocator); + obj.AddMember(StringRef(kMode), StringRef(modeName()), allocator); return obj; } @@ -51,6 +53,7 @@ bool xmrig::RxConfig::read(const rapidjson::Value &value) { if (value.IsObject()) { m_threads = Json::getInt(value, kInit, m_threads); + m_mode = readMode(Json::getValue(value, kMode)); return true; } diff --git a/src/crypto/rx/RxConfig_hwloc.cpp b/src/crypto/rx/RxConfig_hwloc.cpp index 66f086f2..4fc57fb6 100644 --- a/src/crypto/rx/RxConfig_hwloc.cpp +++ b/src/crypto/rx/RxConfig_hwloc.cpp @@ -33,6 +33,7 @@ namespace xmrig { static const char *kInit = "init"; +static const char *kMode = "mode"; static const char *kNUMA = "numa"; } @@ -46,6 +47,7 @@ rapidjson::Value xmrig::RxConfig::toJSON(rapidjson::Document &doc) const Value obj(kObjectType); obj.AddMember(StringRef(kInit), m_threads, allocator); + obj.AddMember(StringRef(kMode), StringRef(modeName()), allocator); if (!m_nodeset.empty()) { Value numa(kArrayType); @@ -68,6 +70,13 @@ bool xmrig::RxConfig::read(const rapidjson::Value &value) { if (value.IsObject()) { m_threads = Json::getInt(value, kInit, m_threads); + m_mode = readMode(Json::getValue(value, kMode)); + + if (m_mode == LightMode) { + m_numa = false; + + return true; + } const auto &numa = Json::getValue(value, kNUMA); if (numa.IsArray()) { diff --git a/src/crypto/rx/RxDataset.cpp b/src/crypto/rx/RxDataset.cpp index 62887a01..ce41a58e 100644 --- a/src/crypto/rx/RxDataset.cpp +++ b/src/crypto/rx/RxDataset.cpp @@ -26,6 +26,8 @@ #include "crypto/rx/RxDataset.h" +#include "backend/common/Tags.h" +#include "base/io/log/Log.h" #include "crypto/common/VirtualMemory.h" #include "crypto/randomx/randomx.h" #include "crypto/rx/RxAlgo.h" @@ -33,12 +35,14 @@ #include +#include static_assert(RANDOMX_FLAG_LARGE_PAGES == 1, "RANDOMX_FLAG_LARGE_PAGES flag mismatch"); -xmrig::RxDataset::RxDataset(bool hugePages, bool cache) +xmrig::RxDataset::RxDataset(bool hugePages, bool cache, RxConfig::Mode mode) : + m_mode(mode) { allocate(hugePages); @@ -118,7 +122,7 @@ size_t xmrig::RxDataset::size(bool cache) const std::pair xmrig::RxDataset::hugePages(bool cache) const { - constexpr size_t twoMiB = 2u * 1024u * 1024u; + constexpr size_t twoMiB = 2U * 1024U * 1024U; constexpr size_t cacheSize = VirtualMemory::align(RxCache::maxSize(), twoMiB) / twoMiB; size_t total = VirtualMemory::align(maxSize(), twoMiB) / twoMiB; @@ -157,6 +161,18 @@ void xmrig::RxDataset::setRaw(const void *raw) void xmrig::RxDataset::allocate(bool hugePages) { + if (m_mode == RxConfig::LightMode) { + LOG_ERR(CLEAR "%s" RED_BOLD_S "fast RandomX mode disabled by config", rx_tag()); + + return; + } + + if (m_mode == RxConfig::AutoMode && uv_get_total_memory() < (maxSize() + RxCache::maxSize())) { + LOG_ERR(CLEAR "%s" RED_BOLD_S "not enough memory for RandomX dataset", rx_tag()); + + return; + } + if (hugePages) { m_flags = RANDOMX_FLAG_LARGE_PAGES; m_dataset = randomx_alloc_dataset(static_cast(m_flags)); diff --git a/src/crypto/rx/RxDataset.h b/src/crypto/rx/RxDataset.h index 9b4f4120..30455956 100644 --- a/src/crypto/rx/RxDataset.h +++ b/src/crypto/rx/RxDataset.h @@ -28,9 +28,10 @@ #define XMRIG_RX_DATASET_H +#include "base/tools/Object.h" #include "crypto/common/Algorithm.h" #include "crypto/randomx/configuration.h" -#include "base/tools/Object.h" +#include "crypto/rx/RxConfig.h" struct randomx_dataset; @@ -49,7 +50,7 @@ class RxDataset public: XMRIG_DISABLE_COPY_MOVE_DEFAULT(RxDataset) - RxDataset(bool hugePages, bool cache); + RxDataset(bool hugePages, bool cache, RxConfig::Mode mode); RxDataset(RxCache *cache); ~RxDataset(); @@ -69,9 +70,10 @@ public: private: void allocate(bool hugePages); - int m_flags = 0; - randomx_dataset *m_dataset = nullptr; - RxCache *m_cache = nullptr; + const RxConfig::Mode m_mode = RxConfig::FastMode; + int m_flags = 0; + randomx_dataset *m_dataset = nullptr; + RxCache *m_cache = nullptr; }; diff --git a/src/crypto/rx/RxNUMAStorage.cpp b/src/crypto/rx/RxNUMAStorage.cpp index 6d8ec167..646d3d95 100644 --- a/src/crypto/rx/RxNUMAStorage.cpp +++ b/src/crypto/rx/RxNUMAStorage.cpp @@ -198,7 +198,7 @@ private: return; } - auto dataset = new RxDataset(hugePages, false); + auto dataset = new RxDataset(hugePages, false, RxConfig::FastMode); if (!dataset->get()) { printSkipped(nodeId, "failed to allocate dataset"); @@ -339,14 +339,14 @@ xmrig::RxDataset *xmrig::RxNUMAStorage::dataset(const Job &job, uint32_t nodeId) std::pair xmrig::RxNUMAStorage::hugePages() const { if (!d_ptr->isAllocated()) { - return { 0u, 0u }; + return { 0U, 0U }; } return d_ptr->hugePages(); } -void xmrig::RxNUMAStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages) +void xmrig::RxNUMAStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode) { d_ptr->setSeed(seed); diff --git a/src/crypto/rx/RxNUMAStorage.h b/src/crypto/rx/RxNUMAStorage.h index 3afdd81d..bed0bc75 100644 --- a/src/crypto/rx/RxNUMAStorage.h +++ b/src/crypto/rx/RxNUMAStorage.h @@ -53,7 +53,7 @@ public: protected: RxDataset *dataset(const Job &job, uint32_t nodeId) const override; std::pair hugePages() const override; - void init(const RxSeed &seed, uint32_t threads, bool hugePages) override; + void init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode mode) override; private: RxNUMAStoragePrivate *d_ptr; diff --git a/src/crypto/rx/RxQueue.cpp b/src/crypto/rx/RxQueue.cpp index 6614d407..b420d0c2 100644 --- a/src/crypto/rx/RxQueue.cpp +++ b/src/crypto/rx/RxQueue.cpp @@ -90,11 +90,11 @@ std::pair xmrig::RxQueue::hugePages() { std::lock_guard lock(m_mutex); - return m_storage && m_state == STATE_IDLE ? m_storage->hugePages() : std::pair(0u, 0u); + return m_storage && m_state == STATE_IDLE ? m_storage->hugePages() : std::pair(0U, 0U); } -void xmrig::RxQueue::enqueue(const RxSeed &seed, const std::vector &nodeset, uint32_t threads, bool hugePages) +void xmrig::RxQueue::enqueue(const RxSeed &seed, const std::vector &nodeset, uint32_t threads, bool hugePages, RxConfig::Mode mode) { std::unique_lock lock(m_mutex); @@ -114,7 +114,7 @@ void xmrig::RxQueue::enqueue(const RxSeed &seed, const std::vector &no return; } - m_queue.emplace_back(seed, nodeset, threads, hugePages); + m_queue.emplace_back(seed, nodeset, threads, hugePages, mode); m_seed = seed; m_state = STATE_PENDING; @@ -156,7 +156,7 @@ void xmrig::RxQueue::backgroundInit() Buffer::toHex(item.seed.data().data(), 8).data() ); - m_storage->init(item.seed, item.threads, item.hugePages); + m_storage->init(item.seed, item.threads, item.hugePages, item.mode); lock = std::unique_lock(m_mutex); diff --git a/src/crypto/rx/RxQueue.h b/src/crypto/rx/RxQueue.h index 28407a87..2d77e2e3 100644 --- a/src/crypto/rx/RxQueue.h +++ b/src/crypto/rx/RxQueue.h @@ -29,6 +29,7 @@ #include "base/tools/Object.h" +#include "crypto/rx/RxConfig.h" #include "crypto/rx/RxSeed.h" @@ -52,14 +53,16 @@ class RxDataset; class RxQueueItem { public: - RxQueueItem(const RxSeed &seed, const std::vector &nodeset, uint32_t threads, bool hugePages) : + RxQueueItem(const RxSeed &seed, const std::vector &nodeset, uint32_t threads, bool hugePages, RxConfig::Mode mode) : hugePages(hugePages), + mode(mode), seed(seed), nodeset(nodeset), threads(threads) {} const bool hugePages; + const RxConfig::Mode mode; const RxSeed seed; const std::vector nodeset; const uint32_t threads; @@ -77,7 +80,7 @@ public: bool isReady(const Job &job); RxDataset *dataset(const Job &job, uint32_t nodeId); std::pair hugePages(); - void enqueue(const RxSeed &seed, const std::vector &nodeset, uint32_t threads, bool hugePages); + void enqueue(const RxSeed &seed, const std::vector &nodeset, uint32_t threads, bool hugePages, RxConfig::Mode mode); private: enum State {