diff --git a/README.md b/README.md index ce223261..fdbf0f59 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ CPU backend: --randomx-no-numa disable NUMA support for RandomX --randomx-mode=MODE RandomX mode: auto, fast, light --randomx-1gb-pages use 1GB hugepages for dataset (Linux only) + --randomx-wrmsr=N write value (0-15) to Intel MSR register 0x1a4 or do nothing (-1) (Linux only) API: --api-worker-id=ID custom worker-id for API diff --git a/cmake/randomx.cmake b/cmake/randomx.cmake index 290b8391..5a225c00 100644 --- a/cmake/randomx.cmake +++ b/cmake/randomx.cmake @@ -75,13 +75,12 @@ if (WITH_RANDOMX) ) list(APPEND SOURCES_CRYPTO - src/crypto/rx/RxConfig_hwloc.cpp src/crypto/rx/RxNUMAStorage.cpp ) - else() - list(APPEND SOURCES_CRYPTO - src/crypto/rx/RxConfig_basic.cpp - ) + endif() + + if (XMRIG_OS_LINUX) + list(APPEND SOURCES_CRYPTO src/crypto/rx/Rx_linux.cpp) endif() else() remove_definitions(/DXMRIG_ALGO_RANDOMX) diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h index 94b5f90a..fe1a24b5 100644 --- a/src/base/kernel/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -91,6 +91,7 @@ public: RandomXNumaKey = 1023, RandomXModeKey = 1029, RandomX1GbPagesKey = 1031, + RandomXWrmsrKey = 1032, CPUMaxThreadsKey = 1026, MemoryPoolKey = 1027, YieldKey = 1030, diff --git a/src/config.json b/src/config.json index ea2e4e15..52afb4cb 100644 --- a/src/config.json +++ b/src/config.json @@ -11,13 +11,13 @@ "restricted": true }, "autosave": true, - "version": 1, "background": false, "colors": true, "randomx": { "init": -1, "mode": "auto", "1gb-pages": false, + "wrmsr": 6, "numa": true }, "cpu": { diff --git a/src/core/config/ConfigTransform.cpp b/src/core/config/ConfigTransform.cpp index 20a885ba..bc1ce7fc 100644 --- a/src/core/config/ConfigTransform.cpp +++ b/src/core/config/ConfigTransform.cpp @@ -168,6 +168,9 @@ void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const case IConfig::RandomX1GbPagesKey: /* --randomx-1gb-pages */ return set(doc, kRandomX, "1gb-pages", true); + + case IConfig::RandomXWrmsrKey: /* --randomx-wrmsr */ + return set(doc, kRandomX, "wrmsr", static_cast(strtol(arg, nullptr, 10))); # endif # ifdef XMRIG_FEATURE_OPENCL diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h index 2a606501..9b360b23 100644 --- a/src/core/config/Config_platform.h +++ b/src/core/config/Config_platform.h @@ -100,6 +100,7 @@ static const option options[] = { { "randomx-mode", 1, nullptr, IConfig::RandomXModeKey }, { "randomx-1gb-pages", 0, nullptr, IConfig::RandomX1GbPagesKey }, { "1gb-pages", 0, nullptr, IConfig::RandomX1GbPagesKey }, + { "randomx-wrmsr", 1, nullptr, IConfig::RandomXWrmsrKey }, # 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 03526148..27edee3d 100644 --- a/src/core/config/usage.h +++ b/src/core/config/usage.h @@ -89,6 +89,7 @@ static inline const std::string &usage() u += " --randomx-no-numa disable NUMA support for RandomX\n"; u += " --randomx-mode=MODE RandomX mode: auto, fast, light\n"; u += " --randomx-1gb-pages use 1GB hugepages for dataset (Linux only)\n"; + u += " --randomx-wrmsr=N write value (0-15) to Intel MSR register 0x1a4 or do nothing (-1) (Linux only)\n"; # endif # ifdef XMRIG_FEATURE_HTTP diff --git a/src/crypto/rx/Rx.cpp b/src/crypto/rx/Rx.cpp index c311e533..1de648c2 100644 --- a/src/crypto/rx/Rx.cpp +++ b/src/crypto/rx/Rx.cpp @@ -39,8 +39,9 @@ namespace xmrig { class RxPrivate; -static const char *tag = BLUE_BG(WHITE_BOLD_S " rx ") " "; -static RxPrivate *d_ptr = nullptr; +static bool osInitialized = false; +static const char *tag = BLUE_BG(WHITE_BOLD_S " rx ") " "; +static RxPrivate *d_ptr = nullptr; class RxPrivate @@ -71,6 +72,11 @@ bool xmrig::Rx::init(const Job &job, const RxConfig &config, const CpuConfig &cp return true; } + if (!osInitialized) { + osInit(config); + osInitialized = true; + } + d_ptr->queue.enqueue(job, config.nodeset(), config.threads(cpu.limit()), cpu.isHugePages(), config.isOneGbPages(), config.mode(), cpu.priority()); return false; @@ -107,3 +113,10 @@ void xmrig::Rx::init(IRxListener *listener) { d_ptr = new RxPrivate(listener); } + + +#ifndef XMRIG_OS_LINUX +void xmrig::Rx::osInit(const RxConfig &) +{ +} +#endif diff --git a/src/crypto/rx/Rx.h b/src/crypto/rx/Rx.h index d2630445..1a289b05 100644 --- a/src/crypto/rx/Rx.h +++ b/src/crypto/rx/Rx.h @@ -56,6 +56,9 @@ public: static RxDataset *dataset(const Job &job, uint32_t nodeId); static void destroy(); static void init(IRxListener *listener); + +private: + static void osInit(const RxConfig &config); }; diff --git a/src/crypto/rx/RxConfig.cpp b/src/crypto/rx/RxConfig.cpp index 7ae7d35d..cd8601a7 100644 --- a/src/crypto/rx/RxConfig.cpp +++ b/src/crypto/rx/RxConfig.cpp @@ -25,9 +25,15 @@ #include "crypto/rx/RxConfig.h" #include "backend/cpu/Cpu.h" +#include "base/io/json/Json.h" #include "rapidjson/document.h" +#ifdef XMRIG_FEATURE_HWLOC +# include "backend/cpu/platform/HwlocCpuInfo.h" +#endif + + #include #include #include @@ -40,11 +46,100 @@ namespace xmrig { +static const char *kInit = "init"; +static const char *kMode = "mode"; +static const char *kOneGbPages = "1gb-pages"; +static const char *kWrmsr = "wrmsr"; + +#ifdef XMRIG_FEATURE_HWLOC +static const char *kNUMA = "numa"; +#endif static const std::array modeNames = { "auto", "fast", "light" }; +} -} // namespace xmrig + +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)); + m_wrmsr = readMSR(Json::getValue(value, kWrmsr)); + +# ifdef XMRIG_OS_LINUX + m_oneGbPages = Json::getBool(value, kOneGbPages, m_oneGbPages); +# endif + +# ifdef XMRIG_FEATURE_HWLOC + if (m_mode == LightMode) { + m_numa = false; + + return true; + } + + const auto &numa = Json::getValue(value, kNUMA); + if (numa.IsArray()) { + m_nodeset.reserve(numa.Size()); + + for (const auto &node : numa.GetArray()) { + if (node.IsUint()) { + m_nodeset.emplace_back(node.GetUint()); + } + } + } + else if (numa.IsBool()) { + m_numa = numa.GetBool(); + } +# endif + + return true; + } + + return false; +} + + +rapidjson::Value xmrig::RxConfig::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Value obj(kObjectType); + obj.AddMember(StringRef(kInit), m_threads, allocator); + obj.AddMember(StringRef(kMode), StringRef(modeName()), allocator); + obj.AddMember(StringRef(kOneGbPages), m_oneGbPages, allocator); + obj.AddMember(StringRef(kWrmsr), m_wrmsr < 0 ? Value(kFalseType) : Value(m_wrmsr), allocator); + +# ifdef XMRIG_FEATURE_HWLOC + if (!m_nodeset.empty()) { + Value numa(kArrayType); + + for (uint32_t i : m_nodeset) { + numa.PushBack(i, allocator); + } + + obj.AddMember(StringRef(kNUMA), numa, allocator); + } + else { + obj.AddMember(StringRef(kNUMA), m_numa, allocator); + } +# endif + + return obj; +} + + +#ifdef XMRIG_FEATURE_HWLOC +std::vector xmrig::RxConfig::nodeset() const +{ + if (!m_nodeset.empty()) { + return m_nodeset; + } + + return (m_numa && Cpu::info()->nodes() > 1) ? static_cast(Cpu::info())->nodeset() : std::vector(); +} +#endif const char *xmrig::RxConfig::modeName() const @@ -67,6 +162,20 @@ uint32_t xmrig::RxConfig::threads(uint32_t limit) const } +int xmrig::RxConfig::readMSR(const rapidjson::Value &value) const +{ + if (value.IsInt()) { + return std::min(value.GetInt(), 15); + } + + if (value.IsBool() && !value.GetBool()) { + return -1; + } + + return m_wrmsr; +} + + xmrig::RxConfig::Mode xmrig::RxConfig::readMode(const rapidjson::Value &value) const { if (value.IsUint()) { diff --git a/src/crypto/rx/RxConfig.h b/src/crypto/rx/RxConfig.h index 90beb4e8..bf5992a3 100644 --- a/src/crypto/rx/RxConfig.h +++ b/src/crypto/rx/RxConfig.h @@ -58,14 +58,17 @@ public: uint32_t threads(uint32_t limit = 100) const; inline bool isOneGbPages() const { return m_oneGbPages; } + inline int wrmsr() const { return m_wrmsr; } inline Mode mode() const { return m_mode; } private: + int readMSR(const rapidjson::Value &value) const; Mode readMode(const rapidjson::Value &value) const; bool m_numa = true; bool m_oneGbPages = false; int m_threads = -1; + int m_wrmsr = 6; Mode m_mode = AutoMode; # ifdef XMRIG_FEATURE_HWLOC diff --git a/src/crypto/rx/RxConfig_basic.cpp b/src/crypto/rx/RxConfig_basic.cpp deleted file mode 100644 index bf2a2c8f..00000000 --- a/src/crypto/rx/RxConfig_basic.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 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 . - */ - - -#include "crypto/rx/RxConfig.h" -#include "base/io/json/Json.h" -#include "rapidjson/document.h" - - -namespace xmrig { - -static const char *kInit = "init"; -static const char *kMode = "mode"; -static const char *kOneGbPages = "1gb-pages"; - -} - - -rapidjson::Value xmrig::RxConfig::toJSON(rapidjson::Document &doc) const -{ - using namespace rapidjson; - auto &allocator = doc.GetAllocator(); - - Value obj(kObjectType); - obj.AddMember(StringRef(kInit), m_threads, allocator); - obj.AddMember(StringRef(kMode), StringRef(modeName()), allocator); - obj.AddMember(StringRef(kOneGbPages), m_oneGbPages, allocator); - - return obj; -} - - -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)); - -# ifdef XMRIG_OS_LINUX - m_oneGbPages = Json::getBool(value, kOneGbPages, m_oneGbPages); -# endif - - return true; - } - - return false; -} diff --git a/src/crypto/rx/RxConfig_hwloc.cpp b/src/crypto/rx/RxConfig_hwloc.cpp deleted file mode 100644 index 91104ef4..00000000 --- a/src/crypto/rx/RxConfig_hwloc.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 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 . - */ - - -#include "backend/cpu/Cpu.h" -#include "backend/cpu/platform/HwlocCpuInfo.h" -#include "base/io/json/Json.h" -#include "crypto/rx/RxConfig.h" -#include "rapidjson/document.h" - - -namespace xmrig { - -static const char *kInit = "init"; -static const char *kMode = "mode"; -static const char *kNUMA = "numa"; -static const char *kOneGbPages = "1gb-pages"; - -} - - -rapidjson::Value xmrig::RxConfig::toJSON(rapidjson::Document &doc) const -{ - using namespace rapidjson; - auto &allocator = doc.GetAllocator(); - - Value obj(kObjectType); - - obj.AddMember(StringRef(kInit), m_threads, allocator); - obj.AddMember(StringRef(kMode), StringRef(modeName()), allocator); - obj.AddMember(StringRef(kOneGbPages), m_oneGbPages, allocator); - - if (!m_nodeset.empty()) { - Value numa(kArrayType); - - for (uint32_t i : m_nodeset) { - numa.PushBack(i, allocator); - } - - obj.AddMember(StringRef(kNUMA), numa, allocator); - } - else { - obj.AddMember(StringRef(kNUMA), m_numa, allocator); - } - - return obj; -} - - -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)); - -# ifdef XMRIG_OS_LINUX - m_oneGbPages = Json::getBool(value, kOneGbPages, m_oneGbPages); -# endif - - if (m_mode == LightMode) { - m_numa = false; - - return true; - } - - const auto &numa = Json::getValue(value, kNUMA); - if (numa.IsArray()) { - m_nodeset.reserve(numa.Size()); - - for (const auto &node : numa.GetArray()) { - if (node.IsUint()) { - m_nodeset.emplace_back(node.GetUint()); - } - } - } - else if (numa.IsBool()) { - m_numa = numa.GetBool(); - } - - return true; - } - - return false; -} - - -std::vector xmrig::RxConfig::nodeset() const -{ - if (!m_nodeset.empty()) { - return m_nodeset; - } - - return (m_numa && Cpu::info()->nodes() > 1) ? static_cast(Cpu::info())->nodeset() : std::vector(); -} diff --git a/src/crypto/rx/Rx_linux.cpp b/src/crypto/rx/Rx_linux.cpp new file mode 100644 index 00000000..a513d38a --- /dev/null +++ b/src/crypto/rx/Rx_linux.cpp @@ -0,0 +1,114 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 2000 Transmeta Corporation + * Copyright 2004-2008 H. Peter Anvin + * Copyright 2016-2019 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 . + */ + + +#include "crypto/rx/Rx.h" +#include "backend/common/Tags.h" +#include "backend/cpu/Cpu.h" +#include "base/io/log/Log.h" +#include "crypto/rx/RxConfig.h" + + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace xmrig { + + +static inline int dir_filter(const struct dirent *dirp) +{ + return isdigit(dirp->d_name[0]) ? 1 : 0; +} + + +static bool wrmsr_on_cpu(uint32_t reg, uint32_t cpu, uint64_t value) +{ + char msr_file_name[64]{}; + + sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu); + int fd = open(msr_file_name, O_WRONLY); + if (fd < 0) { + return false; + } + + const bool success = pwrite(fd, &value, sizeof value, reg) == sizeof value; + + close(fd); + + return success; +} + + +static bool wrmsr_on_all_cpus(uint32_t reg, uint64_t value) +{ + struct dirent **namelist; + int dir_entries = scandir("/dev/cpu", &namelist, dir_filter, 0); + int errors = 0; + + while (dir_entries--) { + if (!wrmsr_on_cpu(reg, strtoul(namelist[dir_entries]->d_name, nullptr, 10), value)) { + ++errors; + } + + free(namelist[dir_entries]); + } + + free(namelist); + + if (errors) { + LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "cannot set MSR 0x%04" PRIx32 " to 0x%04" PRIx64, rx_tag(), reg, value); + } + + return errors == 0; +} + + +} // namespace xmrig + + +void xmrig::Rx::osInit(const RxConfig &config) +{ + if (config.wrmsr() < 0 || Cpu::info()->vendor() != ICpuInfo::VENDOR_INTEL) { + return; + } + + if (system("/sbin/modprobe msr > /dev/null 2>&1") != 0) { + LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "msr kernel module is not available", rx_tag()); + + return; + } + + wrmsr_on_all_cpus(0x1a4, config.wrmsr()); +}