diff --git a/CHANGELOG.md b/CHANGELOG.md
index 38ac7b77..e6aaeea6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,17 @@
+# v4.2.0-beta
+- [#1202](https://github.com/xmrig/xmrig/issues/1202) Fixed algorithm verification in donate strategy.
+- Added per pool option `coin` with single possible value `monero` for pools without algorithm negotiation, for upcoming Monero fork.
+- Added config option `cpu/max-threads-hint` and command line option `--cpu-max-threads-hint`.
+
+# v4.1.0-beta
+- **OpenCL backend disabled by default.**.
+- [#1183](https://github.com/xmrig/xmrig/issues/1183) Fixed compatibility with systemd.
+- [#1185](https://github.com/xmrig/xmrig/pull/1185) Added JIT compiler for RandomX on ARMv8.
+- Improved API endpoint `GET /2/backends` and added support for this endpoint to [workers.xmrig.info](http://workers.xmrig.info).
+- Added command line option `--no-cpu` to disable CPU backend.
+- Added OpenCL specific command line options: `--opencl`, `--opencl-devices`, `--opencl-platform`, `--opencl-loader` and `--opencl-no-cache`.
+- Removed command line option `--http-enabled`, HTTP API enabled automatically if any other `--http-*` option provided.
+
# v4.0.1-beta
- [#1177](https://github.com/xmrig/xmrig/issues/1177) Fixed compatibility with old AMD drivers.
- [#1180](https://github.com/xmrig/xmrig/issues/1180) Fixed possible duplicated shares after algorithm switching.
@@ -9,6 +23,10 @@
- [#268](https://github.com/xmrig/xmrig-amd/pull/268) [#270](https://github.com/xmrig/xmrig-amd/pull/270) [#271](https://github.com/xmrig/xmrig-amd/pull/271) [#273](https://github.com/xmrig/xmrig-amd/pull/273) [#274](https://github.com/xmrig/xmrig-amd/pull/274) [#1171](https://github.com/xmrig/xmrig/pull/1171) Added RandomX support for OpenCL, thanks [@SChernykh](https://github.com/SChernykh).
- Algorithm `cn/wow` removed, as no longer alive.
+# v3.1.3
+- [#1180](https://github.com/xmrig/xmrig/issues/1180) Fixed possible duplicated shares after algorithm switching.
+- Fixed wrong config file permissions after write (only gcc builds on recent Windows 10 affected).
+
# v3.1.2
- Many RandomX optimizations and fixes.
- [#1132](https://github.com/xmrig/xmrig/issues/1132) Fixed build on CentOS 7.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bc3b7156..5729a332 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -71,6 +71,7 @@ set(HEADERS_CRYPTO
src/crypto/cn/skein_port.h
src/crypto/cn/soft_aes.h
src/crypto/common/Algorithm.h
+ src/crypto/common/Coin.h
src/crypto/common/keccak.h
src/crypto/common/Nonce.h
src/crypto/common/portable/mm_malloc.h
@@ -109,6 +110,7 @@ set(SOURCES_CRYPTO
src/crypto/cn/CnCtx.cpp
src/crypto/cn/CnHash.cpp
src/crypto/common/Algorithm.cpp
+ src/crypto/common/Coin.cpp
src/crypto/common/keccak.cpp
src/crypto/common/Nonce.cpp
src/crypto/common/VirtualMemory.cpp
@@ -144,7 +146,7 @@ else()
endif()
endif()
-if (CMAKE_SYSTEM_NAME MATCHES "Linux")
+if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android")
EXECUTE_PROCESS(COMMAND uname -o COMMAND tr -d '\n' OUTPUT_VARIABLE OPERATING_SYSTEM)
if (OPERATING_SYSTEM MATCHES "Android")
set(EXTRA_LIBS ${EXTRA_LIBS} log)
diff --git a/cmake/randomx.cmake b/cmake/randomx.cmake
index be4e9de4..563a90db 100644
--- a/cmake/randomx.cmake
+++ b/cmake/randomx.cmake
@@ -70,6 +70,13 @@ if (WITH_RANDOMX)
)
# cheat because cmake and ccache hate each other
set_property(SOURCE src/crypto/randomx/jit_compiler_x86_static.S PROPERTY LANGUAGE C)
+ elseif (XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+ list(APPEND SOURCES_CRYPTO
+ src/crypto/randomx/jit_compiler_a64_static.S
+ src/crypto/randomx/jit_compiler_a64.cpp
+ )
+ # cheat because cmake and ccache hate each other
+ set_property(SOURCE src/crypto/randomx/jit_compiler_a64_static.S PROPERTY LANGUAGE C)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES Clang)
diff --git a/doc/CPU.md b/doc/CPU.md
index 4d1f0858..66745a66 100644
--- a/doc/CPU.md
+++ b/doc/CPU.md
@@ -94,3 +94,6 @@ Enable/configure or disable ASM optimizations. Possible values: `true`, `false`,
#### `argon2-impl` (since v3.1.0)
Allow override automatically detected Argon2 implementation, this option added mostly for debug purposes, default value `null` means autodetect. Other possible values: `"x86_64"`, `"SSE2"`, `"SSSE3"`, `"XOP"`, `"AVX2"`, `"AVX-512F"`. Manual selection has no safe guards, if you CPU not support required instuctions, miner will crash.
+
+#### `max-threads-hint` (since v4.2.0)
+Maximum CPU threads count (in percentage) hint for autoconfig. [CPU_MAX_USAGE.md](CPU_MAX_USAGE.md)
diff --git a/doc/CPU_MAX_USAGE.md b/doc/CPU_MAX_USAGE.md
new file mode 100644
index 00000000..fccfd456
--- /dev/null
+++ b/doc/CPU_MAX_USAGE.md
@@ -0,0 +1,26 @@
+# Maximum CPU usage
+
+Please read this document carefully, `max-threads-hint` (was known as `max-cpu-usage`) option is most confusing option in the miner with many myth and legends.
+This option is just hint for automatic configuration and can't precise define CPU usage.
+
+### Option definition
+#### Config file:
+```json
+{
+ ...
+ "cpu": {
+ "max-threads-hint": 100,
+ ...
+ },
+ ...
+}
+```
+
+#### Command line
+`--cpu-max-threads-hint 100`
+
+### Known issues and usage
+
+* This option has no effect if miner already generated CPU configuration, to prevent config generation use `"autosave":false,`.
+* Only threads count can be changed, for 1 core CPU this option has no effect, for 2 core CPU only 2 values possible 50% and 100%, for 4 cores: 25%, 50%, 75%, 100%. etc.
+* You CPU may limited by other factors, eg cache.
diff --git a/doc/topology/AMD_Opteron_6344_x2_N4_win7_2_0_4_bug.xml b/doc/topology/AMD_Opteron_6344_x2_N4_win7_2_0_4_bug.xml
new file mode 100644
index 00000000..f3a25ff5
--- /dev/null
+++ b/doc/topology/AMD_Opteron_6344_x2_N4_win7_2_0_4_bug.xml
@@ -0,0 +1,262 @@
+
+
+
+
+
diff --git a/doc/topology/AMD_Opteron_6348_x4_N8_linux_2_0_4.xml b/doc/topology/AMD_Opteron_6348_x4_N8_linux_2_0_4.xml
new file mode 100644
index 00000000..909dbcb9
--- /dev/null
+++ b/doc/topology/AMD_Opteron_6348_x4_N8_linux_2_0_4.xml
@@ -0,0 +1,399 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1 2 5 6
+ 10 22 16 22 22 10 22 16 16 22
+ 10 22 22 16 22 10
+
+
+
diff --git a/src/App.cpp b/src/App.cpp
index 21ae8099..5134adc5 100644
--- a/src/App.cpp
+++ b/src/App.cpp
@@ -24,7 +24,7 @@
*/
-#include
+#include
#include
@@ -42,18 +42,9 @@
#include "version.h"
-xmrig::App::App(Process *process) :
- m_console(nullptr),
- m_signals(nullptr)
+xmrig::App::App(Process *process)
{
m_controller = new Controller(process);
- if (m_controller->init() != 0) {
- return;
- }
-
- if (!m_controller->config()->isBackground()) {
- m_console = new Console(this);
- }
}
@@ -68,12 +59,26 @@ xmrig::App::~App()
int xmrig::App::exec()
{
if (!m_controller->isReady()) {
+ LOG_EMERG("no valid configuration found.");
+
return 2;
}
m_signals = new Signals(this);
- background();
+ int rc = 0;
+ if (background(rc)) {
+ return rc;
+ }
+
+ rc = m_controller->init();
+ if (rc != 0) {
+ return rc;
+ }
+
+ if (!m_controller->isBackground()) {
+ m_console = new Console(this);
+ }
VirtualMemory::init(m_controller->config()->cpu().isHugePages());
@@ -94,10 +99,10 @@ int xmrig::App::exec()
m_controller->start();
}
- const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ rc = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
uv_loop_close(uv_default_loop());
- return r;
+ return rc;
}
@@ -157,7 +162,11 @@ void xmrig::App::onSignal(int signum)
void xmrig::App::close()
{
m_signals->stop();
- m_console->stop();
+
+ if (m_console) {
+ m_console->stop();
+ }
+
m_controller->stop();
Log::destroy();
diff --git a/src/App.h b/src/App.h
index aa534aad..b46dcefa 100644
--- a/src/App.h
+++ b/src/App.h
@@ -29,6 +29,7 @@
#include "base/kernel/interfaces/IConsoleListener.h"
#include "base/kernel/interfaces/ISignalListener.h"
+#include "base/tools/Object.h"
namespace xmrig {
@@ -44,6 +45,8 @@ class Signals;
class App : public IConsoleListener, public ISignalListener
{
public:
+ XMRIG_DISABLE_COPY_MOVE_DEFAULT(App)
+
App(Process *process);
~App() override;
@@ -54,12 +57,12 @@ protected:
void onSignal(int signum) override;
private:
- void background();
+ bool background(int &rc);
void close();
- Console *m_console;
- Controller *m_controller;
- Signals *m_signals;
+ Console *m_console = nullptr;
+ Controller *m_controller = nullptr;
+ Signals *m_signals = nullptr;
};
diff --git a/src/App_unix.cpp b/src/App_unix.cpp
index 5149513c..ae2905db 100644
--- a/src/App_unix.cpp
+++ b/src/App_unix.cpp
@@ -23,33 +23,36 @@
*/
-#include
-#include
-#include
+#include
+#include
+#include
#include
#include "App.h"
#include "base/io/log/Log.h"
-#include "core/config/Config.h"
#include "core/Controller.h"
-void xmrig::App::background()
+bool xmrig::App::background(int &rc)
{
signal(SIGPIPE, SIG_IGN);
- if (!m_controller->config()->isBackground()) {
- return;
+ if (!m_controller->isBackground()) {
+ return false;
}
int i = fork();
if (i < 0) {
- exit(1);
+ rc = 1;
+
+ return true;
}
if (i > 0) {
- exit(0);
+ rc = 0;
+
+ return true;
}
i = setsid();
@@ -62,4 +65,6 @@ void xmrig::App::background()
if (i < 0) {
LOG_ERR("chdir() failed (errno = %d)", errno);
}
+
+ return false;
}
diff --git a/src/App_win.cpp b/src/App_win.cpp
index a41ed505..e803080c 100644
--- a/src/App_win.cpp
+++ b/src/App_win.cpp
@@ -29,13 +29,12 @@
#include "App.h"
#include "core/Controller.h"
-#include "core/config/Config.h"
-void xmrig::App::background()
+bool xmrig::App::background(int &)
{
- if (!m_controller->config()->isBackground()) {
- return;
+ if (!m_controller->isBackground()) {
+ return false;
}
HWND hcon = GetConsoleWindow();
@@ -46,4 +45,6 @@ void xmrig::App::background()
CloseHandle(h);
FreeConsole();
}
+
+ return false;
}
diff --git a/src/backend/common/Threads.h b/src/backend/common/Threads.h
index afae184c..f73b22a0 100644
--- a/src/backend/common/Threads.h
+++ b/src/backend/common/Threads.h
@@ -44,6 +44,7 @@ class Threads
public:
inline bool has(const char *profile) const { return m_profiles.count(profile) > 0; }
inline bool isDisabled(const Algorithm &algo) const { return m_disabled.count(algo) > 0; }
+ inline bool isEmpty() const { return m_profiles.empty(); }
inline bool isExist(const Algorithm &algo) const { return isDisabled(algo) || m_aliases.count(algo) > 0 || has(algo.shortName()); }
inline const T &get(const Algorithm &algo, bool strict = false) const { return get(profileName(algo, strict)); }
inline void disable(const Algorithm &algo) { m_disabled.insert(algo); }
diff --git a/src/backend/common/misc/PciTopology.h b/src/backend/common/misc/PciTopology.h
index dcfacb20..ee531f50 100644
--- a/src/backend/common/misc/PciTopology.h
+++ b/src/backend/common/misc/PciTopology.h
@@ -27,7 +27,7 @@
#define XMRIG_PCITOPOLOGY_H
-#include
+#include
#include "base/tools/String.h"
@@ -40,19 +40,30 @@ class PciTopology
{
public:
PciTopology() = default;
- PciTopology(uint32_t bus, uint32_t device, uint32_t function) : bus(bus), device(device), function(function) {}
+ PciTopology(uint32_t bus, uint32_t device, uint32_t function) : m_valid(true), m_bus(bus), m_device(device), m_function(function) {}
- uint32_t bus = 0;
- uint32_t device = 0;
- uint32_t function = 0;
+ inline bool isValid() const { return m_valid; }
+ inline uint8_t bus() const { return m_bus; }
+ inline uint8_t device() const { return m_device; }
+ inline uint8_t function() const { return m_function; }
String toString() const
{
+ if (!isValid()) {
+ return "n/a";
+ }
+
char *buf = new char[8]();
- snprintf(buf, 8, "%02x:%02x.%01x", bus, device, function);
+ snprintf(buf, 8, "%02hhx:%02hhx.%01hhx", bus(), device(), function());
return buf;
}
+
+private:
+ bool m_valid = false;
+ uint8_t m_bus = 0;
+ uint8_t m_device = 0;
+ uint8_t m_function = 0;
};
diff --git a/src/backend/cpu/Cpu.cpp b/src/backend/cpu/Cpu.cpp
index 4d9effce..5d095e68 100644
--- a/src/backend/cpu/Cpu.cpp
+++ b/src/backend/cpu/Cpu.cpp
@@ -23,7 +23,7 @@
*/
-#include
+#include
#include "backend/cpu/Cpu.h"
@@ -44,7 +44,15 @@ static xmrig::ICpuInfo *cpuInfo = nullptr;
xmrig::ICpuInfo *xmrig::Cpu::info()
{
- assert(cpuInfo != nullptr);
+ if (cpuInfo == nullptr) {
+# if defined(XMRIG_FEATURE_HWLOC)
+ cpuInfo = new HwlocCpuInfo();
+# elif defined(XMRIG_FEATURE_LIBCPUID)
+ cpuInfo = new AdvancedCpuInfo();
+# else
+ cpuInfo = new BasicCpuInfo();
+# endif
+ }
return cpuInfo;
}
@@ -62,7 +70,7 @@ rapidjson::Value xmrig::Cpu::toJSON(rapidjson::Document &doc)
cpu.AddMember("brand", StringRef(i->brand()), allocator);
cpu.AddMember("aes", i->hasAES(), allocator);
cpu.AddMember("avx2", i->hasAVX2(), allocator);
- cpu.AddMember("x64", i->isX64(), allocator);
+ cpu.AddMember("x64", ICpuInfo::isX64(), allocator);
cpu.AddMember("l2", static_cast(i->L2()), allocator);
cpu.AddMember("l3", static_cast(i->L3()), allocator);
cpu.AddMember("cores", static_cast(i->cores()), allocator);
@@ -81,20 +89,6 @@ rapidjson::Value xmrig::Cpu::toJSON(rapidjson::Document &doc)
}
-void xmrig::Cpu::init()
-{
- assert(cpuInfo == nullptr);
-
-# if defined(XMRIG_FEATURE_HWLOC)
- cpuInfo = new HwlocCpuInfo();
-# elif defined(XMRIG_FEATURE_LIBCPUID)
- cpuInfo = new AdvancedCpuInfo();
-# else
- cpuInfo = new BasicCpuInfo();
-# endif
-}
-
-
void xmrig::Cpu::release()
{
assert(cpuInfo != nullptr);
diff --git a/src/backend/cpu/Cpu.h b/src/backend/cpu/Cpu.h
index bece97d3..a8dd1f3a 100644
--- a/src/backend/cpu/Cpu.h
+++ b/src/backend/cpu/Cpu.h
@@ -37,7 +37,6 @@ class Cpu
public:
static ICpuInfo *info();
static rapidjson::Value toJSON(rapidjson::Document &doc);
- static void init();
static void release();
inline static Assembly::Id assembly(Assembly::Id hint) { return hint == Assembly::AUTO ? Cpu::info()->assembly() : hint; }
diff --git a/src/backend/cpu/CpuConfig.cpp b/src/backend/cpu/CpuConfig.cpp
index 9f4766e6..d66de779 100644
--- a/src/backend/cpu/CpuConfig.cpp
+++ b/src/backend/cpu/CpuConfig.cpp
@@ -35,6 +35,7 @@ static const char *kCn = "cn";
static const char *kEnabled = "enabled";
static const char *kHugePages = "huge-pages";
static const char *kHwAes = "hw-aes";
+static const char *kMaxThreadsHint = "max-threads-hint";
static const char *kPriority = "priority";
#ifdef XMRIG_FEATURE_ASM
@@ -73,11 +74,6 @@ extern template class Threads;
}
-xmrig::CpuConfig::CpuConfig()
-{
-}
-
-
bool xmrig::CpuConfig::isHwAES() const
{
return (m_aes == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aes) == AES_HW;
@@ -96,6 +92,10 @@ rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const
obj.AddMember(StringRef(kHwAes), m_aes == AES_AUTO ? Value(kNullType) : Value(m_aes == AES_HW), allocator);
obj.AddMember(StringRef(kPriority), priority() != -1 ? Value(priority()) : Value(kNullType), allocator);
+ if (m_threads.isEmpty()) {
+ obj.AddMember(StringRef(kMaxThreadsHint), m_limit, allocator);
+ }
+
# ifdef XMRIG_FEATURE_ASM
obj.AddMember(StringRef(kAsm), m_assembly.toJSON(), allocator);
# endif
@@ -132,8 +132,9 @@ std::vector xmrig::CpuConfig::get(const Miner *miner, cons
void xmrig::CpuConfig::read(const rapidjson::Value &value, uint32_t version)
{
if (value.IsObject()) {
- m_enabled = Json::getBool(value, kEnabled, m_enabled);
- m_hugePages = Json::getBool(value, kHugePages, m_hugePages);
+ m_enabled = Json::getBool(value, kEnabled, m_enabled);
+ m_hugePages = Json::getBool(value, kHugePages, m_hugePages);
+ m_limit = Json::getUint(value, kMaxThreadsHint, m_limit);
setAesMode(Json::getValue(value, kHwAes));
setPriority(Json::getInt(value, kPriority, -1));
@@ -169,29 +170,29 @@ void xmrig::CpuConfig::generate()
ICpuInfo *cpu = Cpu::info();
m_threads.disable(Algorithm::CN_0);
- m_threads.move(kCn, cpu->threads(Algorithm::CN_0));
+ m_threads.move(kCn, cpu->threads(Algorithm::CN_0, m_limit));
# ifdef XMRIG_ALGO_CN_GPU
- m_threads.move(kCnGPU, cpu->threads(Algorithm::CN_GPU));
+ m_threads.move(kCnGPU, cpu->threads(Algorithm::CN_GPU, m_limit));
# endif
# ifdef XMRIG_ALGO_CN_LITE
m_threads.disable(Algorithm::CN_LITE_0);
- m_threads.move(kCnLite, cpu->threads(Algorithm::CN_LITE_1));
+ m_threads.move(kCnLite, cpu->threads(Algorithm::CN_LITE_1, m_limit));
# endif
# ifdef XMRIG_ALGO_CN_HEAVY
- m_threads.move(kCnHeavy, cpu->threads(Algorithm::CN_HEAVY_0));
+ m_threads.move(kCnHeavy, cpu->threads(Algorithm::CN_HEAVY_0, m_limit));
# endif
# ifdef XMRIG_ALGO_CN_PICO
- m_threads.move(kCnPico, cpu->threads(Algorithm::CN_PICO_0));
+ m_threads.move(kCnPico, cpu->threads(Algorithm::CN_PICO_0, m_limit));
# endif
# ifdef XMRIG_ALGO_RANDOMX
- m_threads.move(kRx, cpu->threads(Algorithm::RX_0));
- m_threads.move(kRxWOW, cpu->threads(Algorithm::RX_WOW));
- m_threads.move(kDefyX, cpu->threads(Algorithm::DEFYX));
+ m_threads.move(kRx, cpu->threads(Algorithm::RX_0, m_limit));
+ m_threads.move(kRxWOW, cpu->threads(Algorithm::RX_WOW, m_limit));
+ m_threads.move(kDefyX, cpu->threads(Algorithm::DEFYX, m_limit));
# endif
generateArgon2();
@@ -201,7 +202,7 @@ void xmrig::CpuConfig::generate()
void xmrig::CpuConfig::generateArgon2()
{
# ifdef XMRIG_ALGO_ARGON2
- m_threads.move(kArgon2, Cpu::info()->threads(Algorithm::AR2_CHUKWA));
+ m_threads.move(kArgon2, Cpu::info()->threads(Algorithm::AR2_CHUKWA, m_limit));
# endif
}
diff --git a/src/backend/cpu/CpuConfig.h b/src/backend/cpu/CpuConfig.h
index 67010eea..27075425 100644
--- a/src/backend/cpu/CpuConfig.h
+++ b/src/backend/cpu/CpuConfig.h
@@ -44,7 +44,7 @@ public:
AES_SOFT
};
- CpuConfig();
+ CpuConfig() = default;
bool isHwAES() const;
rapidjson::Value toJSON(rapidjson::Document &doc) const;
@@ -74,6 +74,7 @@ private:
int m_priority = -1;
String m_argon2Impl;
Threads m_threads;
+ uint32_t m_limit = 100;
};
diff --git a/src/backend/cpu/interfaces/ICpuInfo.h b/src/backend/cpu/interfaces/ICpuInfo.h
index 9bc3b11a..20e72391 100644
--- a/src/backend/cpu/interfaces/ICpuInfo.h
+++ b/src/backend/cpu/interfaces/ICpuInfo.h
@@ -45,18 +45,18 @@ public:
inline constexpr static bool isX64() { return false; }
# endif
- virtual Assembly::Id assembly() const = 0;
- virtual bool hasAES() const = 0;
- virtual bool hasAVX2() const = 0;
- virtual const char *backend() const = 0;
- virtual const char *brand() const = 0;
- virtual CpuThreads threads(const Algorithm &algorithm) const = 0;
- virtual size_t cores() const = 0;
- virtual size_t L2() const = 0;
- virtual size_t L3() const = 0;
- virtual size_t nodes() const = 0;
- virtual size_t packages() const = 0;
- virtual size_t threads() const = 0;
+ virtual Assembly::Id assembly() const = 0;
+ virtual bool hasAES() const = 0;
+ virtual bool hasAVX2() const = 0;
+ virtual const char *backend() const = 0;
+ virtual const char *brand() const = 0;
+ virtual CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const = 0;
+ virtual size_t cores() const = 0;
+ virtual size_t L2() const = 0;
+ virtual size_t L3() const = 0;
+ virtual size_t nodes() const = 0;
+ virtual size_t packages() const = 0;
+ virtual size_t threads() const = 0;
};
diff --git a/src/backend/cpu/platform/AdvancedCpuInfo.cpp b/src/backend/cpu/platform/AdvancedCpuInfo.cpp
index 26798895..5cae55e2 100644
--- a/src/backend/cpu/platform/AdvancedCpuInfo.cpp
+++ b/src/backend/cpu/platform/AdvancedCpuInfo.cpp
@@ -23,10 +23,10 @@
*/
#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
#include "3rdparty/libcpuid/libcpuid.h"
@@ -109,7 +109,7 @@ xmrig::AdvancedCpuInfo::AdvancedCpuInfo() :
}
-xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm) const
+xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm, uint32_t limit) const
{
if (threads() == 1) {
return 1;
@@ -153,5 +153,12 @@ xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm) co
}
# endif
- return CpuThreads(std::max(std::min(count, threads()), 1), intensity);
+ if (limit > 0 && limit < 100) {
+ count = std::min(count, static_cast(round(threads() * (limit / 100.0))));
+ }
+ else {
+ count = std::min(count, threads());
+ }
+
+ return CpuThreads(std::max(count, 1), intensity);
}
diff --git a/src/backend/cpu/platform/AdvancedCpuInfo.h b/src/backend/cpu/platform/AdvancedCpuInfo.h
index 51b84c9f..e2909a91 100644
--- a/src/backend/cpu/platform/AdvancedCpuInfo.h
+++ b/src/backend/cpu/platform/AdvancedCpuInfo.h
@@ -38,7 +38,7 @@ public:
AdvancedCpuInfo();
protected:
- CpuThreads threads(const Algorithm &algorithm) const override;
+ CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override;
inline Assembly::Id assembly() const override { return m_assembly; }
inline bool hasAES() const override { return m_aes; }
diff --git a/src/backend/cpu/platform/BasicCpuInfo.cpp b/src/backend/cpu/platform/BasicCpuInfo.cpp
index 15ac8f40..db3741ee 100644
--- a/src/backend/cpu/platform/BasicCpuInfo.cpp
+++ b/src/backend/cpu/platform/BasicCpuInfo.cpp
@@ -179,7 +179,7 @@ const char *xmrig::BasicCpuInfo::backend() const
}
-xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm) const
+xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm, uint32_t limit) const
{
const size_t count = std::thread::hardware_concurrency();
diff --git a/src/backend/cpu/platform/BasicCpuInfo.h b/src/backend/cpu/platform/BasicCpuInfo.h
index 6cf25714..4c68c5f8 100644
--- a/src/backend/cpu/platform/BasicCpuInfo.h
+++ b/src/backend/cpu/platform/BasicCpuInfo.h
@@ -39,7 +39,7 @@ public:
protected:
const char *backend() const override;
- CpuThreads threads(const Algorithm &algorithm) const override;
+ CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override;
inline Assembly::Id assembly() const override { return m_assembly; }
inline bool hasAES() const override { return m_aes; }
diff --git a/src/backend/cpu/platform/BasicCpuInfo_arm.cpp b/src/backend/cpu/platform/BasicCpuInfo_arm.cpp
index b241e197..e52bdf94 100644
--- a/src/backend/cpu/platform/BasicCpuInfo_arm.cpp
+++ b/src/backend/cpu/platform/BasicCpuInfo_arm.cpp
@@ -63,7 +63,7 @@ const char *xmrig::BasicCpuInfo::backend() const
}
-xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &) const
+xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &, uint32_t) const
{
return CpuThreads(threads());
}
diff --git a/src/backend/cpu/platform/HwlocCpuInfo.cpp b/src/backend/cpu/platform/HwlocCpuInfo.cpp
index 9e503742..e87faf2d 100644
--- a/src/backend/cpu/platform/HwlocCpuInfo.cpp
+++ b/src/backend/cpu/platform/HwlocCpuInfo.cpp
@@ -29,6 +29,7 @@
#include
+#include
#include
@@ -127,9 +128,7 @@ static inline bool isCacheExclusive(hwloc_obj_t obj)
} // namespace xmrig
-xmrig::HwlocCpuInfo::HwlocCpuInfo() : BasicCpuInfo(),
- m_backend(),
- m_cache()
+xmrig::HwlocCpuInfo::HwlocCpuInfo()
{
m_threads = 0;
@@ -149,7 +148,7 @@ xmrig::HwlocCpuInfo::HwlocCpuInfo() : BasicCpuInfo(),
# endif
const std::vector packages = findByType(hwloc_get_root_obj(m_topology), HWLOC_OBJ_PACKAGE);
- if (packages.size()) {
+ if (!packages.empty()) {
const char *value = hwloc_obj_get_info_by_name(packages[0], "CPUModel");
if (value) {
strncpy(m_brand, value, 64);
@@ -202,10 +201,10 @@ xmrig::HwlocCpuInfo::~HwlocCpuInfo()
}
-xmrig::CpuThreads xmrig::HwlocCpuInfo::threads(const Algorithm &algorithm) const
+xmrig::CpuThreads xmrig::HwlocCpuInfo::threads(const Algorithm &algorithm, uint32_t limit) const
{
if (L2() == 0 && L3() == 0) {
- return BasicCpuInfo::threads(algorithm);
+ return BasicCpuInfo::threads(algorithm, limit);
}
const unsigned depth = L3() > 0 ? 3 : 2;
@@ -218,21 +217,37 @@ xmrig::CpuThreads xmrig::HwlocCpuInfo::threads(const Algorithm &algorithm) const
findCache(hwloc_get_root_obj(m_topology), depth, depth, [&caches](hwloc_obj_t found) { caches.emplace_back(found); });
- for (hwloc_obj_t cache : caches) {
- processTopLevelCache(cache, algorithm, threads);
+ if (limit > 0 && limit < 100 && !caches.empty()) {
+ const double maxTotalThreads = round(m_threads * (limit / 100.0));
+ const auto maxPerCache = std::max(static_cast(round(maxTotalThreads / caches.size())), 1);
+ int remaining = std::max(static_cast(maxTotalThreads), 1);
+
+ for (hwloc_obj_t cache : caches) {
+ processTopLevelCache(cache, algorithm, threads, std::min(maxPerCache, remaining));
+
+ remaining -= maxPerCache;
+ if (remaining <= 0) {
+ break;
+ }
+ }
+ }
+ else {
+ for (hwloc_obj_t cache : caches) {
+ processTopLevelCache(cache, algorithm, threads, 0);
+ }
}
if (threads.isEmpty()) {
LOG_WARN("hwloc auto configuration for algorithm \"%s\" failed.", algorithm.shortName());
- return BasicCpuInfo::threads(algorithm);
+ return BasicCpuInfo::threads(algorithm, limit);
}
return threads;
}
-void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorithm &algorithm, CpuThreads &threads) const
+void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorithm &algorithm, CpuThreads &threads, size_t limit) const
{
constexpr size_t oneMiB = 1024u * 1024u;
@@ -296,6 +311,10 @@ void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorith
}
# endif
+ if (limit > 0) {
+ cacheHashes = std::min(cacheHashes, limit);
+ }
+
if (cacheHashes >= PUs) {
for (hwloc_obj_t core : cores) {
const std::vector units = findByType(core, HWLOC_OBJ_PU);
diff --git a/src/backend/cpu/platform/HwlocCpuInfo.h b/src/backend/cpu/platform/HwlocCpuInfo.h
index 340864f5..ec4aea2c 100644
--- a/src/backend/cpu/platform/HwlocCpuInfo.h
+++ b/src/backend/cpu/platform/HwlocCpuInfo.h
@@ -27,10 +27,11 @@
#include "backend/cpu/platform/BasicCpuInfo.h"
+#include "base/tools/Object.h"
-typedef struct hwloc_obj *hwloc_obj_t;
-typedef struct hwloc_topology *hwloc_topology_t;
+using hwloc_obj_t = struct hwloc_obj *;
+using hwloc_topology_t = struct hwloc_topology *;
namespace xmrig {
@@ -39,6 +40,9 @@ namespace xmrig {
class HwlocCpuInfo : public BasicCpuInfo
{
public:
+ XMRIG_DISABLE_COPY_MOVE(HwlocCpuInfo)
+
+
enum Feature : uint32_t {
SET_THISTHREAD_MEMBIND = 1
};
@@ -51,7 +55,7 @@ public:
static inline const std::vector &nodeIndexes() { return m_nodeIndexes; }
protected:
- CpuThreads threads(const Algorithm &algorithm) const override;
+ CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override;
inline const char *backend() const override { return m_backend; }
inline size_t cores() const override { return m_cores; }
@@ -61,17 +65,17 @@ protected:
inline size_t packages() const override { return m_packages; }
private:
- void processTopLevelCache(hwloc_obj_t obj, const Algorithm &algorithm, CpuThreads &threads) const;
+ void processTopLevelCache(hwloc_obj_t obj, const Algorithm &algorithm, CpuThreads &threads, size_t limit) const;
static std::vector m_nodeIndexes;
static uint32_t m_features;
- char m_backend[20];
- hwloc_topology_t m_topology;
- size_t m_cache[5];
- size_t m_cores = 0;
- size_t m_nodes = 0;
- size_t m_packages = 0;
+ char m_backend[20] = { 0 };
+ hwloc_topology_t m_topology = nullptr;
+ size_t m_cache[5] = { 0 };
+ size_t m_cores = 0;
+ size_t m_nodes = 0;
+ size_t m_packages = 0;
};
diff --git a/src/backend/opencl/OclBackend.cpp b/src/backend/opencl/OclBackend.cpp
index 65c3ded9..9b226811 100644
--- a/src/backend/opencl/OclBackend.cpp
+++ b/src/backend/opencl/OclBackend.cpp
@@ -135,6 +135,10 @@ public:
return printDisabled(RED_S " (failed to load OpenCL runtime)");
}
+ if (platform.isValid()) {
+ return;
+ }
+
platform = cl.platform();
if (!platform.isValid()) {
return printDisabled(RED_S " (selected OpenCL platform NOT found)");
@@ -150,7 +154,7 @@ public:
for (const OclDevice &device : devices) {
Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("#%zu") YELLOW(" %s") " %s " WHITE_BOLD("%uMHz") " cu:" WHITE_BOLD("%u") " mem:" CYAN("%zu/%zu") " MB", "OPENCL GPU",
device.index(),
- device.hasTopology() ? device.topology().toString().data() : "n/a",
+ device.topology().toString().data(),
device.printableName().data(),
device.clock(),
device.computeUnits(),
@@ -177,7 +181,7 @@ public:
CYAN_BOLD("%3u") " |" CYAN_BOLD("%3s") " |" CYAN_BOLD("%3u") " |" CYAN("%5zu") " | %s",
i,
data.thread.index(),
- data.device.hasTopology() ? data.device.topology().toString().data() : "n/a",
+ data.device.topology().toString().data(),
data.thread.intensity(),
data.thread.worksize(),
data.thread.stridedIndex(),
@@ -285,7 +289,7 @@ void xmrig::OclBackend::printHashrate(bool details)
Hashrate::format(hashrate()->calc(i, Hashrate::MediumInterval), num + 8, sizeof num / 3),
Hashrate::format(hashrate()->calc(i, Hashrate::LargeInterval), num + 8 * 2, sizeof num / 3),
data.device.index(),
- data.device.hasTopology() ? data.device.topology().toString().data() : "n/a",
+ data.device.topology().toString().data(),
data.device.printableName().data()
);
@@ -302,12 +306,15 @@ void xmrig::OclBackend::printHashrate(bool details)
void xmrig::OclBackend::setJob(const Job &job)
{
+ const OclConfig &cl = d_ptr->controller->config()->cl();
+ if (cl.isEnabled()) {
+ d_ptr->init(cl);
+ }
+
if (!isEnabled()) {
return stop();
}
- const OclConfig &cl = d_ptr->controller->config()->cl();
-
std::vector threads = cl.get(d_ptr->controller->miner(), job.algorithm(), d_ptr->platform, d_ptr->devices, tag);
if (!d_ptr->threads.empty() && d_ptr->threads.size() == threads.size() && std::equal(d_ptr->threads.begin(), d_ptr->threads.end(), threads.begin())) {
return;
@@ -401,6 +408,8 @@ rapidjson::Value xmrig::OclBackend::toJSON(rapidjson::Document &doc) const
thread.AddMember("affinity", data.affinity, allocator);
thread.AddMember("hashrate", hashrate()->toJSON(i, doc), allocator);
+ data.device.toJSON(thread, doc);
+
i++;
threads.PushBack(thread, allocator);
}
diff --git a/src/backend/opencl/OclConfig.cpp b/src/backend/opencl/OclConfig.cpp
index cdb38ccb..7424dba7 100644
--- a/src/backend/opencl/OclConfig.cpp
+++ b/src/backend/opencl/OclConfig.cpp
@@ -30,12 +30,16 @@
#include "rapidjson/document.h"
+#include
+
+
namespace xmrig {
static const char *kAMD = "AMD";
static const char *kCache = "cache";
static const char *kCn = "cn";
static const char *kCn2 = "cn/2";
+static const char *kDevicesHint = "devices-hint";
static const char *kEnabled = "enabled";
static const char *kINTEL = "INTEL";
static const char *kLoader = "loader";
@@ -90,6 +94,22 @@ static size_t generate(const char *key, Threads &threads, const Algo
}
+static inline std::vector filterDevices(const std::vector &devices, const std::vector &hints)
+{
+ std::vector out;
+ out.reserve(std::min(devices.size(), hints.size()));
+
+ for (const auto &device : devices) {
+ auto it = std::find(hints.begin(), hints.end(), device.index());
+ if (it != hints.end()) {
+ out.emplace_back(device);
+ }
+ }
+
+ return out;
+}
+
+
}
@@ -214,17 +234,20 @@ void xmrig::OclConfig::read(const rapidjson::Value &value)
m_loader = Json::getString(value, kLoader);
setPlatform(Json::getValue(value, kPlatform));
+ setDevicesHint(Json::getString(value, kDevicesHint));
- if (isEnabled()) {
- m_threads.read(value);
+ m_threads.read(value);
- generate();
- }
+ generate();
}
- else if (value.IsBool() && value.IsFalse()) {
- m_enabled = false;
+ else if (value.IsBool()) {
+ m_enabled = value.GetBool();
+
+ generate();
}
else {
+ m_shouldSave = true;
+
generate();
}
}
@@ -232,11 +255,15 @@ void xmrig::OclConfig::read(const rapidjson::Value &value)
void xmrig::OclConfig::generate()
{
+ if (!isEnabled() || m_threads.has("*")) {
+ return;
+ }
+
if (!OclLib::init(loader())) {
return;
}
- const auto devices = platform().devices();
+ const auto devices = m_devicesHint.empty() ? platform().devices() : filterDevices(platform().devices(), m_devicesHint);
if (devices.empty()) {
return;
}
@@ -281,6 +308,21 @@ void xmrig::OclConfig::generate()
}
+void xmrig::OclConfig::setDevicesHint(const char *devicesHint)
+{
+ if (devicesHint == nullptr) {
+ return;
+ }
+
+ const auto indexes = String(devicesHint).split(',');
+ m_devicesHint.reserve(indexes.size());
+
+ for (const auto &index : indexes) {
+ m_devicesHint.push_back(strtoul(index, nullptr, 10));
+ }
+}
+
+
void xmrig::OclConfig::setPlatform(const rapidjson::Value &platform)
{
if (platform.IsString()) {
diff --git a/src/backend/opencl/OclConfig.h b/src/backend/opencl/OclConfig.h
index 22d1378e..9dd5ad1d 100644
--- a/src/backend/opencl/OclConfig.h
+++ b/src/backend/opencl/OclConfig.h
@@ -53,11 +53,13 @@ public:
private:
void generate();
+ void setDevicesHint(const char *devicesHint);
void setPlatform(const rapidjson::Value &platform);
bool m_cache = true;
- bool m_enabled = true;
+ bool m_enabled = false;
bool m_shouldSave = false;
+ std::vector m_devicesHint;
String m_loader;
String m_platformVendor;
Threads m_threads;
diff --git a/src/backend/opencl/OclThread.cpp b/src/backend/opencl/OclThread.cpp
index 02ef5f3b..8ca4574f 100644
--- a/src/backend/opencl/OclThread.cpp
+++ b/src/backend/opencl/OclThread.cpp
@@ -52,6 +52,10 @@ static const char* kDatasetHost = "dataset_host";
xmrig::OclThread::OclThread(const rapidjson::Value &value)
{
+ if (!value.IsObject()) {
+ return;
+ }
+
m_index = Json::getUint(value, kIndex);
m_worksize = std::max(std::min(Json::getUint(value, kWorksize), 128u), 1u);
m_unrollFactor = std::max(std::min(Json::getUint(value, kUnroll, m_unrollFactor), 128u), 1u);
diff --git a/src/backend/opencl/runners/tools/OclCnR.cpp b/src/backend/opencl/runners/tools/OclCnR.cpp
index ed415194..929938cc 100644
--- a/src/backend/opencl/runners/tools/OclCnR.cpp
+++ b/src/backend/opencl/runners/tools/OclCnR.cpp
@@ -237,7 +237,7 @@ private:
for (size_t i = 0; i < OclCnR::kHeightChunkSize; ++i) {
V4_Instruction code[256];
const int code_size = v4_random_math_init(code, offset + i);
- const std::string kernel = std::regex_replace(cryptonight_r_cl, std::regex("XMRIG_INCLUDE_RANDOM_MATH"), getCode(code, code_size));
+ const std::string kernel = std::regex_replace(std::string(cryptonight_r_cl), std::regex("XMRIG_INCLUDE_RANDOM_MATH"), getCode(code, code_size));
source += std::regex_replace(kernel, std::regex("KERNEL_NAME"), "cn1_" + std::to_string(offset + i));
}
diff --git a/src/backend/opencl/wrappers/OclDevice.cpp b/src/backend/opencl/wrappers/OclDevice.cpp
index f6338717..67f8166b 100644
--- a/src/backend/opencl/wrappers/OclDevice.cpp
+++ b/src/backend/opencl/wrappers/OclDevice.cpp
@@ -59,7 +59,7 @@ extern bool ocl_vega_cn_generator(const OclDevice &device, const Algorithm &algo
extern bool ocl_generic_cn_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads);
-ocl_gen_config_fun generators[] = {
+static ocl_gen_config_fun generators[] = {
# ifdef XMRIG_ALGO_RANDOMX
ocl_generic_rx_generator,
# endif
@@ -142,16 +142,14 @@ xmrig::OclDevice::OclDevice(uint32_t index, cl_device_id id, cl_platform_id plat
topology_amd topology;
if (OclLib::getDeviceInfo(id, 0x4037 /* CL_DEVICE_TOPOLOGY_AMD */, sizeof(topology), &topology, nullptr) == CL_SUCCESS && topology.raw.type == 1) {
- m_topology = true;
- m_pciTopology = PciTopology(static_cast(topology.pcie.bus), static_cast(topology.pcie.device), static_cast(topology.pcie.function));
+ m_topology = PciTopology(static_cast(topology.pcie.bus), static_cast(topology.pcie.device), static_cast(topology.pcie.function));
}
}
else if (m_vendorId == OCL_VENDOR_NVIDIA) {
cl_uint bus = 0;
if (OclLib::getDeviceInfo(id, 0x4008 /* CL_DEVICE_PCI_BUS_ID_NV */, sizeof (bus), &bus, nullptr) == CL_SUCCESS) {
- m_topology = true;
cl_uint slot = OclLib::getUint(id, 0x4009 /* CL_DEVICE_PCI_SLOT_ID_NV */);
- m_pciTopology = PciTopology(bus, (slot >> 3) & 0xff, slot & 7);
+ m_topology = PciTopology(bus, (slot >> 3) & 0xff, slot & 7);
}
}
}
@@ -205,3 +203,18 @@ void xmrig::OclDevice::generate(const Algorithm &algorithm, OclThreads &threads)
}
}
}
+
+
+#ifdef XMRIG_FEATURE_API
+void xmrig::OclDevice::toJSON(rapidjson::Value &out, rapidjson::Document &doc) const
+{
+ using namespace rapidjson;
+ auto &allocator = doc.GetAllocator();
+
+ out.AddMember("board", board().toJSON(doc), allocator);
+ out.AddMember("name", name().toJSON(doc), allocator);
+ out.AddMember("bus_id", topology().toString().toJSON(doc), allocator);
+ out.AddMember("cu", computeUnits(), allocator);
+ out.AddMember("global_mem", static_cast(globalMemSize()), allocator);
+}
+#endif
diff --git a/src/backend/opencl/wrappers/OclDevice.h b/src/backend/opencl/wrappers/OclDevice.h
index 517fa2bd..3be58ed2 100644
--- a/src/backend/opencl/wrappers/OclDevice.h
+++ b/src/backend/opencl/wrappers/OclDevice.h
@@ -69,10 +69,9 @@ public:
uint32_t clock() const;
void generate(const Algorithm &algorithm, OclThreads &threads) const;
- inline bool hasTopology() const { return m_topology; }
inline bool isValid() const { return m_id != nullptr && m_platform != nullptr; }
inline cl_device_id id() const { return m_id; }
- inline const PciTopology &topology() const { return m_pciTopology; }
+ inline const PciTopology &topology() const { return m_topology; }
inline const String &board() const { return m_board.isNull() ? m_name : m_board; }
inline const String &name() const { return m_name; }
inline const String &vendor() const { return m_vendor; }
@@ -81,8 +80,11 @@ public:
inline uint32_t computeUnits() const { return m_computeUnits; }
inline uint32_t index() const { return m_index; }
+# ifdef XMRIG_FEATURE_API
+ void toJSON(rapidjson::Value &out, rapidjson::Document &doc) const;
+# endif
+
private:
- bool m_topology = false;
cl_device_id m_id = nullptr;
cl_platform_id m_platform = nullptr;
const String m_board;
@@ -91,7 +93,7 @@ private:
const uint32_t m_computeUnits = 1;
const uint32_t m_index = 0;
OclVendor m_vendorId = OCL_VENDOR_UNKNOWN;
- PciTopology m_pciTopology;
+ PciTopology m_topology;
Type m_type = Unknown;
};
diff --git a/src/backend/opencl/wrappers/OclPlatform.cpp b/src/backend/opencl/wrappers/OclPlatform.cpp
index 987ec5e3..601ee6fa 100644
--- a/src/backend/opencl/wrappers/OclPlatform.cpp
+++ b/src/backend/opencl/wrappers/OclPlatform.cpp
@@ -73,7 +73,7 @@ rapidjson::Value xmrig::OclPlatform::toJSON(rapidjson::Document &doc) const
}
Value out(kObjectType);
- out.AddMember("index", index(), allocator);
+ out.AddMember("index", static_cast(index()), allocator);
out.AddMember("profile", profile().toJSON(doc), allocator);
out.AddMember("version", version().toJSON(doc), allocator);
out.AddMember("name", name().toJSON(doc), allocator);
diff --git a/src/base/api/Api.cpp b/src/base/api/Api.cpp
index b52e6976..22f00b77 100644
--- a/src/base/api/Api.cpp
+++ b/src/base/api/Api.cpp
@@ -117,9 +117,10 @@ void xmrig::Api::exec(IApiRequest &request)
auto &allocator = request.doc().GetAllocator();
request.accept();
- request.reply().AddMember("id", StringRef(m_id), allocator);
- request.reply().AddMember("worker_id", StringRef(m_workerId), allocator);
- request.reply().AddMember("uptime", (Chrono::currentMSecsSinceEpoch() - m_timestamp) / 1000, allocator);
+ request.reply().AddMember("id", StringRef(m_id), allocator);
+ request.reply().AddMember("worker_id", StringRef(m_workerId), allocator);
+ request.reply().AddMember("uptime", (Chrono::currentMSecsSinceEpoch() - m_timestamp) / 1000, allocator);
+ request.reply().AddMember("restricted", request.isRestricted(), allocator);
Value features(kArrayType);
# ifdef XMRIG_FEATURE_API
diff --git a/src/base/api/Api.h b/src/base/api/Api.h
index 334609c9..0c1a728d 100644
--- a/src/base/api/Api.h
+++ b/src/base/api/Api.h
@@ -27,10 +27,11 @@
#include
-#include
+#include
#include "base/kernel/interfaces/IBaseListener.h"
+#include "base/tools/Object.h"
namespace xmrig {
@@ -47,6 +48,8 @@ class String;
class Api : public IBaseListener
{
public:
+ XMRIG_DISABLE_COPY_MOVE_DEFAULT(Api)
+
Api(Base *base);
~Api() override;
diff --git a/src/base/io/Console.cpp b/src/base/io/Console.cpp
index 0e5cd269..bba73035 100644
--- a/src/base/io/Console.cpp
+++ b/src/base/io/Console.cpp
@@ -31,8 +31,11 @@
xmrig::Console::Console(IConsoleListener *listener)
: m_listener(listener)
{
- m_tty = new uv_tty_t;
+ if (!isSupported()) {
+ return;
+ }
+ m_tty = new uv_tty_t;
m_tty->data = this;
uv_tty_init(uv_default_loop(), m_tty, 0, 1);
@@ -53,6 +56,10 @@ xmrig::Console::~Console()
void xmrig::Console::stop()
{
+ if (!m_tty) {
+ return;
+ }
+
uv_tty_reset_mode();
Handle::close(m_tty);
@@ -60,6 +67,13 @@ void xmrig::Console::stop()
}
+bool xmrig::Console::isSupported() const
+{
+ const uv_handle_type type = uv_guess_handle(0);
+ return type == UV_TTY || type == UV_NAMED_PIPE;
+}
+
+
void xmrig::Console::onAllocBuffer(uv_handle_t *handle, size_t, uv_buf_t *buf)
{
auto console = static_cast(handle->data);
diff --git a/src/base/io/Console.h b/src/base/io/Console.h
index c0a36ec4..0a075348 100644
--- a/src/base/io/Console.h
+++ b/src/base/io/Console.h
@@ -26,9 +26,11 @@
#define XMRIG_CONSOLE_H
-#include
+#include "base/tools/Object.h"
+#include
+
namespace xmrig {
@@ -39,18 +41,22 @@ class IConsoleListener;
class Console
{
public:
+ XMRIG_DISABLE_COPY_MOVE_DEFAULT(Console)
+
Console(IConsoleListener *listener);
~Console();
void stop();
private:
+ bool isSupported() const;
+
static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf);
static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
- char m_buf[1];
+ char m_buf[1] = { 0 };
IConsoleListener *m_listener;
- uv_tty_t *m_tty;
+ uv_tty_t *m_tty = nullptr;
};
diff --git a/src/base/io/json/Json.cpp b/src/base/io/json/Json.cpp
index 07986c4a..03d4c65a 100644
--- a/src/base/io/json/Json.cpp
+++ b/src/base/io/json/Json.cpp
@@ -27,6 +27,9 @@
#include "rapidjson/document.h"
+#include
+
+
namespace xmrig {
static const rapidjson::Value kNullValue;
@@ -36,6 +39,8 @@ static const rapidjson::Value kNullValue;
bool xmrig::Json::getBool(const rapidjson::Value &obj, const char *key, bool defaultValue)
{
+ assert(obj.IsObject());
+
auto i = obj.FindMember(key);
if (i != obj.MemberEnd() && i->value.IsBool()) {
return i->value.GetBool();
@@ -47,6 +52,8 @@ bool xmrig::Json::getBool(const rapidjson::Value &obj, const char *key, bool def
const char *xmrig::Json::getString(const rapidjson::Value &obj, const char *key, const char *defaultValue)
{
+ assert(obj.IsObject());
+
auto i = obj.FindMember(key);
if (i != obj.MemberEnd() && i->value.IsString()) {
return i->value.GetString();
@@ -58,6 +65,8 @@ const char *xmrig::Json::getString(const rapidjson::Value &obj, const char *key,
const rapidjson::Value &xmrig::Json::getArray(const rapidjson::Value &obj, const char *key)
{
+ assert(obj.IsObject());
+
auto i = obj.FindMember(key);
if (i != obj.MemberEnd() && i->value.IsArray()) {
return i->value;
@@ -69,6 +78,8 @@ const rapidjson::Value &xmrig::Json::getArray(const rapidjson::Value &obj, const
const rapidjson::Value &xmrig::Json::getObject(const rapidjson::Value &obj, const char *key)
{
+ assert(obj.IsObject());
+
auto i = obj.FindMember(key);
if (i != obj.MemberEnd() && i->value.IsObject()) {
return i->value;
@@ -80,6 +91,8 @@ const rapidjson::Value &xmrig::Json::getObject(const rapidjson::Value &obj, cons
const rapidjson::Value &xmrig::Json::getValue(const rapidjson::Value &obj, const char *key)
{
+ assert(obj.IsObject());
+
auto i = obj.FindMember(key);
if (i != obj.MemberEnd()) {
return i->value;
@@ -91,6 +104,8 @@ const rapidjson::Value &xmrig::Json::getValue(const rapidjson::Value &obj, const
int xmrig::Json::getInt(const rapidjson::Value &obj, const char *key, int defaultValue)
{
+ assert(obj.IsObject());
+
auto i = obj.FindMember(key);
if (i != obj.MemberEnd() && i->value.IsInt()) {
return i->value.GetInt();
@@ -102,6 +117,8 @@ int xmrig::Json::getInt(const rapidjson::Value &obj, const char *key, int defaul
int64_t xmrig::Json::getInt64(const rapidjson::Value &obj, const char *key, int64_t defaultValue)
{
+ assert(obj.IsObject());
+
auto i = obj.FindMember(key);
if (i != obj.MemberEnd() && i->value.IsInt64()) {
return i->value.GetInt64();
@@ -113,6 +130,8 @@ int64_t xmrig::Json::getInt64(const rapidjson::Value &obj, const char *key, int6
uint64_t xmrig::Json::getUint64(const rapidjson::Value &obj, const char *key, uint64_t defaultValue)
{
+ assert(obj.IsObject());
+
auto i = obj.FindMember(key);
if (i != obj.MemberEnd() && i->value.IsUint64()) {
return i->value.GetUint64();
@@ -124,6 +143,8 @@ uint64_t xmrig::Json::getUint64(const rapidjson::Value &obj, const char *key, ui
unsigned xmrig::Json::getUint(const rapidjson::Value &obj, const char *key, unsigned defaultValue)
{
+ assert(obj.IsObject());
+
auto i = obj.FindMember(key);
if (i != obj.MemberEnd() && i->value.IsUint()) {
return i->value.GetUint();
diff --git a/src/base/io/log/backends/ConsoleLog.cpp b/src/base/io/log/backends/ConsoleLog.cpp
index a5b6c1a7..34a7d66b 100644
--- a/src/base/io/log/backends/ConsoleLog.cpp
+++ b/src/base/io/log/backends/ConsoleLog.cpp
@@ -24,7 +24,7 @@
*/
-#include
+#include
#include "base/tools/Handle.h"
@@ -32,9 +32,13 @@
#include "base/io/log/Log.h"
-xmrig::ConsoleLog::ConsoleLog() :
- m_stream(nullptr)
+xmrig::ConsoleLog::ConsoleLog()
{
+ if (!isSupported()) {
+ Log::colors = false;
+ return;
+ }
+
m_tty = new uv_tty_t;
if (uv_tty_init(uv_default_loop(), m_tty, 1, 0) < 0) {
@@ -66,7 +70,7 @@ xmrig::ConsoleLog::~ConsoleLog()
void xmrig::ConsoleLog::print(int, const char *line, size_t, size_t size, bool colors)
{
- if (Log::colors != colors) {
+ if (!m_tty || Log::colors != colors) {
return;
}
@@ -86,12 +90,18 @@ void xmrig::ConsoleLog::print(int, const char *line, size_t, size_t size, bool c
}
+bool xmrig::ConsoleLog::isSupported() const
+{
+ const uv_handle_type type = uv_guess_handle(1);
+ return type == UV_TTY || type == UV_NAMED_PIPE;
+}
+
+
bool xmrig::ConsoleLog::isWritable() const
{
if (!m_stream || uv_is_writable(m_stream) != 1) {
return false;
}
- const uv_handle_type type = uv_guess_handle(1);
- return type == UV_TTY || type == UV_NAMED_PIPE;
+ return isSupported();
}
diff --git a/src/base/io/log/backends/ConsoleLog.h b/src/base/io/log/backends/ConsoleLog.h
index 90e4fa14..6277cc7b 100644
--- a/src/base/io/log/backends/ConsoleLog.h
+++ b/src/base/io/log/backends/ConsoleLog.h
@@ -27,11 +27,12 @@
#define XMRIG_CONSOLELOG_H
-typedef struct uv_stream_s uv_stream_t;
-typedef struct uv_tty_s uv_tty_t;
+using uv_stream_t = struct uv_stream_s;
+using uv_tty_t = struct uv_tty_s;
#include "base/kernel/interfaces/ILogBackend.h"
+#include "base/tools/Object.h"
namespace xmrig {
@@ -40,6 +41,8 @@ namespace xmrig {
class ConsoleLog : public ILogBackend
{
public:
+ XMRIG_DISABLE_COPY_MOVE(ConsoleLog)
+
ConsoleLog();
~ConsoleLog() override;
@@ -47,10 +50,11 @@ protected:
void print(int level, const char *line, size_t offset, size_t size, bool colors) override;
private:
+ bool isSupported() const;
bool isWritable() const;
- uv_stream_t *m_stream;
- uv_tty_t *m_tty;
+ uv_stream_t *m_stream = nullptr;
+ uv_tty_t *m_tty = nullptr;
};
diff --git a/src/base/kernel/Base.cpp b/src/base/kernel/Base.cpp
index 3740655d..90c7cb57 100644
--- a/src/base/kernel/Base.cpp
+++ b/src/base/kernel/Base.cpp
@@ -23,7 +23,7 @@
*/
-#include
+#include
#include
@@ -64,15 +64,16 @@ static const char *kConfigPathV2 = "/2/config";
#endif
-class xmrig::BasePrivate
+namespace xmrig {
+
+
+class BasePrivate
{
public:
- inline BasePrivate(Process *process) :
- api(nullptr),
- config(nullptr),
- process(process),
- watcher(nullptr)
- {}
+ XMRIG_DISABLE_COPY_MOVE_DEFAULT(BasePrivate)
+
+
+ inline BasePrivate(Process *process) : config(load(process)) {}
inline ~BasePrivate()
@@ -94,13 +95,33 @@ public:
}
- inline Config *load()
+ inline void replace(Config *newConfig)
+ {
+ Config *previousConfig = config;
+ config = newConfig;
+
+ for (IBaseListener *listener : listeners) {
+ listener->onConfigChanged(config, previousConfig);
+ }
+
+ delete previousConfig;
+ }
+
+
+ Api *api = nullptr;
+ Config *config = nullptr;
+ std::vector listeners;
+ Watcher *watcher = nullptr;
+
+
+private:
+ inline Config *load(Process *process)
{
JsonChain chain;
ConfigTransform transform;
std::unique_ptr config;
- transform.load(chain, process, transform);
+ ConfigTransform::load(chain, process, transform);
if (read(chain, config)) {
return config.release();
@@ -122,29 +143,12 @@ public:
return nullptr;
}
-
-
- inline void replace(Config *newConfig)
- {
- Config *previousConfig = config;
- config = newConfig;
-
- for (IBaseListener *listener : listeners) {
- listener->onConfigChanged(config, previousConfig);
- }
-
- delete previousConfig;
- }
-
-
- Api *api;
- Config *config;
- Process *process;
- std::vector listeners;
- Watcher *watcher;
};
+} // namespace xmrig
+
+
xmrig::Base::Base(Process *process)
: d_ptr(new BasePrivate(process))
{
@@ -165,14 +169,6 @@ bool xmrig::Base::isReady() const
int xmrig::Base::init()
{
- d_ptr->config = d_ptr->load();
-
- if (!d_ptr->config) {
- LOG_EMERG("No valid configuration found. Exiting.");
-
- return 1;
- }
-
# ifdef XMRIG_FEATURE_API
d_ptr->api = new Api(this);
d_ptr->api->addListener(this);
@@ -184,7 +180,7 @@ int xmrig::Base::init()
Platform::setProcessPriority(config()->cpu().priority());
# endif
- if (config()->isBackground()) {
+ if (isBackground()) {
Log::background = true;
}
else {
@@ -240,6 +236,12 @@ xmrig::Api *xmrig::Base::api() const
}
+bool xmrig::Base::isBackground() const
+{
+ return d_ptr->config && d_ptr->config->isBackground();
+}
+
+
bool xmrig::Base::reload(const rapidjson::Value &json)
{
JsonReader reader(json);
@@ -247,7 +249,7 @@ bool xmrig::Base::reload(const rapidjson::Value &json)
return false;
}
- Config *config = new Config();
+ auto config = new Config();
if (!config->read(reader, d_ptr->config->fileName())) {
delete config;
@@ -289,7 +291,7 @@ void xmrig::Base::onFileChanged(const String &fileName)
JsonChain chain;
chain.addFile(fileName);
- Config *config = new Config();
+ auto config = new Config();
if (!config->read(chain, chain.fileName())) {
LOG_ERR("reloading failed");
diff --git a/src/base/kernel/Base.h b/src/base/kernel/Base.h
index 8eb68866..ef850edd 100644
--- a/src/base/kernel/Base.h
+++ b/src/base/kernel/Base.h
@@ -29,6 +29,7 @@
#include "base/api/interfaces/IApiListener.h"
#include "base/kernel/interfaces/IConfigListener.h"
#include "base/kernel/interfaces/IWatcherListener.h"
+#include "base/tools/Object.h"
#include "rapidjson/fwd.h"
@@ -45,6 +46,8 @@ class Process;
class Base : public IWatcherListener, public IApiListener
{
public:
+ XMRIG_DISABLE_COPY_MOVE_DEFAULT(Base)
+
Base(Process *process);
~Base() override;
@@ -54,6 +57,7 @@ public:
virtual void stop();
Api *api() const;
+ bool isBackground() const;
bool reload(const rapidjson::Value &json);
Config *config() const;
void addListener(IBaseListener *listener);
diff --git a/src/base/kernel/Entry.cpp b/src/base/kernel/Entry.cpp
index 605f8e20..1d1b7eb8 100644
--- a/src/base/kernel/Entry.cpp
+++ b/src/base/kernel/Entry.cpp
@@ -23,7 +23,7 @@
*/
-#include
+#include
#include
@@ -161,7 +161,7 @@ int xmrig::Entry::exec(const Process &process, Id id)
{
switch (id) {
case Usage:
- printf(usage);
+ printf("%s\n", usage().c_str());
return 0;
case Version:
diff --git a/src/base/kernel/Process.cpp b/src/base/kernel/Process.cpp
index 9193d378..fae0d679 100644
--- a/src/base/kernel/Process.cpp
+++ b/src/base/kernel/Process.cpp
@@ -23,8 +23,8 @@
*/
+#include
#include
-#include
#include "base/kernel/Process.h"
@@ -55,11 +55,6 @@ xmrig::Process::Process(int argc, char **argv) :
}
-xmrig::Process::~Process()
-{
-}
-
-
xmrig::String xmrig::Process::location(Location location, const char *fileName) const
{
constexpr const size_t max = 520;
diff --git a/src/base/kernel/Process.h b/src/base/kernel/Process.h
index 9b29eb57..22959044 100644
--- a/src/base/kernel/Process.h
+++ b/src/base/kernel/Process.h
@@ -47,7 +47,6 @@ public:
# endif
Process(int argc, char **argv);
- ~Process();
String location(Location location, const char *fileName = nullptr) const;
diff --git a/src/base/kernel/config/BaseTransform.cpp b/src/base/kernel/config/BaseTransform.cpp
index 189b5a15..8a193ab7 100644
--- a/src/base/kernel/config/BaseTransform.cpp
+++ b/src/base/kernel/config/BaseTransform.cpp
@@ -23,7 +23,7 @@
*/
-#include
+#include
#ifdef _MSC_VER
@@ -47,15 +47,11 @@ namespace xmrig
static const char *kAlgo = "algo";
static const char *kApi = "api";
+static const char *kCoin = "coin";
static const char *kHttp = "http";
static const char *kPools = "pools";
-}
-
-
-xmrig::BaseTransform::BaseTransform()
-{
-}
+} // namespace xmrig
void xmrig::BaseTransform::load(JsonChain &chain, Process *process, IConfigTransform &transform)
@@ -68,7 +64,7 @@ void xmrig::BaseTransform::load(JsonChain &chain, Process *process, IConfigTrans
Document doc(kObjectType);
- while (1) {
+ while (true) {
key = getopt_long(argc, argv, short_options, options, nullptr);
if (key < 0) {
break;
@@ -107,6 +103,19 @@ void xmrig::BaseTransform::finalize(rapidjson::Document &doc)
}
}
}
+
+ if (m_coin.isValid() && doc.HasMember(kPools)) {
+ auto &pools = doc[kPools];
+ for (Value &pool : pools.GetArray()) {
+ if (!pool.HasMember(kCoin)) {
+ pool.AddMember(StringRef(kCoin), m_coin.toJSON(), allocator);
+ }
+ }
+ }
+
+ if (m_http) {
+ set(doc, kHttp, "enabled", true);
+ }
}
@@ -122,6 +131,15 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch
}
break;
+ case IConfig::CoinKey: /* --coin */
+ if (!doc.HasMember(kPools)) {
+ m_coin = arg;
+ }
+ else {
+ return add(doc, kPools, kCoin, arg);
+ }
+ break;
+
case IConfig::UserpassKey: /* --userpass */
{
const char *p = strrchr(arg, ':');
@@ -169,9 +187,11 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch
return set(doc, "log-file", arg);
case IConfig::HttpAccessTokenKey: /* --http-access-token */
+ m_http = true;
return set(doc, kHttp, "access-token", arg);
case IConfig::HttpHostKey: /* --http-host */
+ m_http = true;
return set(doc, kHttp, "host", arg);
case IConfig::ApiWorkerIdKey: /* --api-worker-id */
@@ -228,8 +248,10 @@ void xmrig::BaseTransform::transformBoolean(rapidjson::Document &doc, int key, b
case IConfig::TlsKey: /* --tls */
return add(doc, kPools, "tls", enable);
+# ifdef XMRIG_FEATURE_HTTP
case IConfig::DaemonKey: /* --daemon */
return add(doc, kPools, "daemon", enable);
+# endif
# ifndef XMRIG_PROXY_PROJECT
case IConfig::NicehashKey: /* --nicehash */
@@ -240,10 +262,12 @@ void xmrig::BaseTransform::transformBoolean(rapidjson::Document &doc, int key, b
return set(doc, "colors", enable);
case IConfig::HttpRestrictedKey: /* --http-no-restricted */
+ m_http = true;
return set(doc, kHttp, "restricted", enable);
case IConfig::HttpEnabledKey: /* --http-enabled */
- return set(doc, kHttp, "enabled", enable);
+ m_http = true;
+ break;
case IConfig::DryRunKey: /* --dry-run */
return set(doc, "dry-run", enable);
@@ -273,13 +297,16 @@ void xmrig::BaseTransform::transformUint64(rapidjson::Document &doc, int key, ui
return set(doc, "donate-over-proxy", arg);
case IConfig::HttpPort: /* --http-port */
+ m_http = true;
return set(doc, kHttp, "port", arg);
case IConfig::PrintTimeKey: /* --print-time */
return set(doc, "print-time", arg);
+# ifdef XMRIG_FEATURE_HTTP
case IConfig::DaemonPollKey: /* --daemon-poll-interval */
return add(doc, kPools, "daemon-poll-interval", arg);
+# endif
case IConfig::BenchAlgoTimeKey: /* --bench-algo-time */
return set(doc, "bench-algo-time", arg);
diff --git a/src/base/kernel/config/BaseTransform.h b/src/base/kernel/config/BaseTransform.h
index 02b28c12..704f0899 100644
--- a/src/base/kernel/config/BaseTransform.h
+++ b/src/base/kernel/config/BaseTransform.h
@@ -27,6 +27,7 @@
#include "base/kernel/interfaces/IConfigTransform.h"
+#include "crypto/common/Coin.h"
#include "rapidjson/document.h"
@@ -44,8 +45,6 @@ class Process;
class BaseTransform : public IConfigTransform
{
public:
- BaseTransform();
-
static void load(JsonChain &chain, Process *process, IConfigTransform &transform);
protected:
@@ -99,11 +98,14 @@ protected:
protected:
Algorithm m_algorithm;
+ Coin m_coin;
private:
void transformBoolean(rapidjson::Document &doc, int key, bool enable);
void transformUint64(rapidjson::Document &doc, int key, uint64_t arg);
+
+ bool m_http = false;
};
diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h
index 105a2569..93a21d16 100644
--- a/src/base/kernel/interfaces/IConfig.h
+++ b/src/base/kernel/interfaces/IConfig.h
@@ -43,6 +43,7 @@ public:
enum Keys {
// common
AlgorithmKey = 'a',
+ CoinKey = 1025,
ApiWorkerIdKey = 4002,
ApiIdKey = 4005,
HttpPort = 4100,
@@ -81,6 +82,7 @@ public:
BenchAlgoTimeKey = 10002,
// xmrig cpu
+ CPUKey = 1024,
AVKey = 'v',
CPUAffinityKey = 1020,
DryRunKey = 5000,
@@ -89,6 +91,7 @@ public:
AssemblyKey = 1015,
RandomXInitKey = 1022,
RandomXNumaKey = 1023,
+ CPUMaxThreadsKey = 1026,
// xmrig amd
OclPlatformKey = 1400,
@@ -102,6 +105,7 @@ public:
OclMemChunkKey = 1408,
OclUnrollKey = 1409,
OclCompModeKey = 1410,
+ OclKey = 1411,
// xmrig-proxy
AccessLogFileKey = 'A',
diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp
index 0888128d..fe4fe36b 100644
--- a/src/base/net/stratum/Client.cpp
+++ b/src/base/net/stratum/Client.cpp
@@ -338,6 +338,9 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code)
if (algo) {
job.setAlgorithm(algo);
}
+ else if (m_pool.coin().isValid()) {
+ job.setAlgorithm(m_pool.coin().algorithm(job.blob()[0]));
+ }
job.setHeight(Json::getUint64(params, "height"));
@@ -430,7 +433,12 @@ bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm, const char *algo
{
if (!algorithm.isValid()) {
if (!isQuiet()) {
- LOG_ERR("[%s] Unknown/unsupported algorithm \"%s\" detected, reconnect", url(), algo);
+ if (algo == nullptr) {
+ LOG_ERR("[%s] unknown algorithm, make sure you set \"algo\" or \"coin\" option", url(), algo);
+ }
+ else {
+ LOG_ERR("[%s] unsupported algorithm \"%s\" detected, reconnect", url(), algo);
+ }
}
return false;
@@ -440,7 +448,7 @@ bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm, const char *algo
m_listener->onVerifyAlgorithm(this, algorithm, &ok);
if (!ok && !isQuiet()) {
- LOG_ERR("[%s] Incompatible/disabled algorithm \"%s\" detected, reconnect", url(), algorithm.shortName());
+ LOG_ERR("[%s] incompatible/disabled algorithm \"%s\" detected, reconnect", url(), algorithm.shortName());
}
return ok;
diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp
index 0c141c7d..0870dc1d 100644
--- a/src/base/net/stratum/DaemonClient.cpp
+++ b/src/base/net/stratum/DaemonClient.cpp
@@ -25,7 +25,7 @@
#include
-#include
+#include
#include "3rdparty/http-parser/http_parser.h"
@@ -225,6 +225,10 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code)
job.setDiff(Json::getUint64(params, "difficulty"));
job.setId(blocktemplate.data() + blocktemplate.size() - 32);
+ if (m_pool.coin().isValid()) {
+ job.setAlgorithm(m_pool.coin().algorithm(job.blob()[0]));
+ }
+
m_job = std::move(job);
m_blocktemplate = std::move(blocktemplate);
m_prevHash = Json::getString(params, "prev_hash");
diff --git a/src/base/net/stratum/Job.h b/src/base/net/stratum/Job.h
index eafd10e3..d695c561 100644
--- a/src/base/net/stratum/Job.h
+++ b/src/base/net/stratum/Job.h
@@ -75,6 +75,7 @@ public:
inline uint8_t fixedByte() const { return *(m_blob + 42); }
inline uint8_t index() const { return m_index; }
inline void reset() { m_size = 0; m_diff = 0; }
+ inline void setAlgorithm(const Algorithm::Id id) { m_algorithm = id; }
inline void setAlgorithm(const char *algo) { m_algorithm = algo; }
inline void setClientId(const String &id) { m_clientId = id; }
inline void setHeight(uint64_t height) { m_height = height; }
diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp
index ba31c35d..15586fe8 100644
--- a/src/base/net/stratum/Pool.cpp
+++ b/src/base/net/stratum/Pool.cpp
@@ -48,6 +48,7 @@
namespace xmrig {
static const char *kAlgo = "algo";
+static const char *kCoin = "coin";
static const char *kDaemon = "daemon";
static const char *kDaemonPollInterval = "daemon-poll-interval";
static const char *kEnabled = "enabled";
@@ -120,6 +121,7 @@ xmrig::Pool::Pool(const rapidjson::Value &object) :
m_fingerprint = Json::getString(object, kFingerprint);
m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval);
m_algorithm = Json::getString(object, kAlgo);
+ m_coin = Json::getString(object, kCoin);
m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true));
m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash));
@@ -172,7 +174,7 @@ bool xmrig::Pool::isEnabled() const
}
# endif
- if (isDaemon() && !algorithm().isValid()) {
+ if (isDaemon() && (!algorithm().isValid() && !coin().isValid())) {
return false;
}
@@ -186,6 +188,7 @@ bool xmrig::Pool::isEqual(const Pool &other) const
&& m_keepAlive == other.m_keepAlive
&& m_port == other.m_port
&& m_algorithm == other.m_algorithm
+ && m_coin == other.m_coin
&& m_fingerprint == other.m_fingerprint
&& m_host == other.m_host
&& m_password == other.m_password
@@ -268,6 +271,7 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const
Value obj(kObjectType);
obj.AddMember(StringRef(kAlgo), m_algorithm.toJSON(), allocator);
+ obj.AddMember(StringRef(kCoin), m_coin.toJSON(), allocator);
obj.AddMember(StringRef(kUrl), m_url.toJSON(), allocator);
obj.AddMember(StringRef(kUser), m_user.toJSON(), allocator);
diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h
index 36c3ed1b..15d31ccc 100644
--- a/src/base/net/stratum/Pool.h
+++ b/src/base/net/stratum/Pool.h
@@ -32,7 +32,7 @@
#include "base/tools/String.h"
-#include "crypto/common/Algorithm.h"
+#include "crypto/common/Coin.h"
#include "rapidjson/fwd.h"
@@ -74,6 +74,7 @@ public:
inline bool isTLS() const { return m_flags.test(FLAG_TLS); }
inline bool isValid() const { return !m_host.isNull() && m_port > 0; }
inline const Algorithm &algorithm() const { return m_algorithm; }
+ inline const Coin &coin() const { return m_coin; }
inline const String &fingerprint() const { return m_fingerprint; }
inline const String &host() const { return m_host; }
inline const String &password() const { return !m_password.isNull() ? m_password : kDefaultPassword; }
@@ -107,6 +108,7 @@ private:
bool parseIPv6(const char *addr);
Algorithm m_algorithm;
+ Coin m_coin;
int m_keepAlive;
std::bitset m_flags;
String m_fingerprint;
diff --git a/src/base/net/stratum/Pools.cpp b/src/base/net/stratum/Pools.cpp
index 37ddb662..18005413 100644
--- a/src/base/net/stratum/Pools.cpp
+++ b/src/base/net/stratum/Pools.cpp
@@ -138,11 +138,12 @@ void xmrig::Pools::print() const
{
size_t i = 1;
for (const Pool &pool : m_data) {
- Log::print(GREEN_BOLD(" * ") WHITE_BOLD("POOL #%-7zu") CSI "1;%dm%s" CLEAR " algo " WHITE_BOLD("%s"),
+ Log::print(GREEN_BOLD(" * ") WHITE_BOLD("POOL #%-7zu") CSI "1;%dm%s" CLEAR " %s " WHITE_BOLD("%s"),
i,
(pool.isEnabled() ? (pool.isTLS() ? 32 : 36) : 31),
pool.url().data(),
- pool.algorithm().isValid() ? pool.algorithm().shortName() : "auto"
+ pool.coin().isValid() ? "coin" : "algo",
+ pool.coin().isValid() ? pool.coin().name() : (pool.algorithm().isValid() ? pool.algorithm().shortName() : "auto")
);
i++;
diff --git a/src/config.json b/src/config.json
index 01247b5d..d3fee91b 100644
--- a/src/config.json
+++ b/src/config.json
@@ -25,6 +25,7 @@
"huge-pages": true,
"hw-aes": null,
"priority": null,
+ "max-threads-hint": 100,
"asm": true,
"argon2-impl": null,
"cn/0": false,
@@ -44,6 +45,7 @@
"pools": [
{
"algo": null,
+ "coin": null,
"url": "gulf.moneroocean.stream:10001",
"user": "YOUR_WALLET_ADDRESS",
"pass": "x",
diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp
index 4191c2d3..b586c4fc 100644
--- a/src/core/Controller.cpp
+++ b/src/core/Controller.cpp
@@ -23,7 +23,7 @@
*/
-#include
+#include
#include "backend/cpu/Cpu.h"
@@ -44,20 +44,9 @@ xmrig::Controller::~Controller()
}
-bool xmrig::Controller::isReady() const
-{
- return Base::isReady() && m_network;
-}
-
-
int xmrig::Controller::init()
{
- Cpu::init();
-
- const int rc = Base::init();
- if (rc != 0) {
- return rc;
- }
+ Base::init();
m_network = new Network(this);
return 0;
diff --git a/src/core/Controller.h b/src/core/Controller.h
index 188aa67e..b7a6fc59 100644
--- a/src/core/Controller.h
+++ b/src/core/Controller.h
@@ -27,6 +27,7 @@
#include "base/kernel/Base.h"
+#include "base/tools/Object.h"
namespace xmrig {
@@ -40,10 +41,11 @@ class Network;
class Controller : public Base
{
public:
+ XMRIG_DISABLE_COPY_MOVE_DEFAULT(Controller)
+
Controller(Process *process);
~Controller() override;
- bool isReady() const override;
int init() override;
void pre_start();
void start() override;
diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp
index d5372422..b6b89948 100644
--- a/src/core/Miner.cpp
+++ b/src/core/Miner.cpp
@@ -97,7 +97,7 @@ public:
bool isEnabled(const Algorithm &algorithm) const
{
for (IBackend *backend : backends) {
- if (backend->isEnabled(algorithm)) {
+ if (backend->isEnabled() && backend->isEnabled(algorithm)) {
return true;
}
}
diff --git a/src/core/config/ConfigTransform.cpp b/src/core/config/ConfigTransform.cpp
index ce0d324c..3bdbcac5 100644
--- a/src/core/config/ConfigTransform.cpp
+++ b/src/core/config/ConfigTransform.cpp
@@ -35,11 +35,16 @@ namespace xmrig
static const char *kAffinity = "affinity";
static const char *kAsterisk = "*";
static const char *kCpu = "cpu";
+static const char *kEnabled = "enabled";
static const char *kIntensity = "intensity";
static const char *kThreads = "threads";
#ifdef XMRIG_ALGO_RANDOMX
-static const char *kRandomX = "randomx";
+static const char *kRandomX = "randomx";
+#endif
+
+#ifdef XMRIG_FEATURE_OPENCL
+static const char *kOcl = "opencl";
#endif
@@ -80,12 +85,7 @@ static inline bool isHwAes(uint64_t av)
}
-}
-
-
-xmrig::ConfigTransform::ConfigTransform() : BaseTransform()
-{
-}
+} // namespace xmrig
void xmrig::ConfigTransform::finalize(rapidjson::Document &doc)
@@ -109,6 +109,12 @@ void xmrig::ConfigTransform::finalize(rapidjson::Document &doc)
doc[kCpu].AddMember(StringRef(kAsterisk), profile, doc.GetAllocator());
}
+
+# ifdef XMRIG_FEATURE_OPENCL
+ if (m_opencl) {
+ set(doc, kOcl, kEnabled, true);
+ }
+# endif
}
@@ -123,6 +129,7 @@ void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const
return transformUint64(doc, key, static_cast(strtol(arg, nullptr, 10)));
case IConfig::HugePagesKey: /* --no-huge-pages */
+ case IConfig::CPUKey: /* --no-cpu */
return transformBoolean(doc, key, false);
case IConfig::CPUAffinityKey: /* --cpu-affinity */
@@ -131,7 +138,10 @@ void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const
return transformUint64(doc, key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10));
}
-# ifndef XMRIG_NO_ASM
+ case IConfig::CPUMaxThreadsKey: /* --cpu-max-threads-hint */
+ return set(doc, kCpu, "max-threads-hint", static_cast(strtol(arg, nullptr, 10)));
+
+# ifdef XMRIG_FEATURE_ASM
case IConfig::AssemblyKey: /* --asm */
return set(doc, kCpu, "asm", arg);
# endif
@@ -144,6 +154,29 @@ void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const
return set(doc, kRandomX, "numa", false);
# endif
+# ifdef XMRIG_FEATURE_OPENCL
+ case IConfig::OclKey: /* --opencl */
+ m_opencl = true;
+ break;
+
+ case IConfig::OclCacheKey: /* --opencl-no-cache */
+ return set(doc, kOcl, "cache", false);
+
+ case IConfig::OclLoaderKey: /* --opencl-loader */
+ return set(doc, kOcl, "loader", arg);
+
+ case IConfig::OclDevicesKey: /* --opencl-devices */
+ m_opencl = true;
+ return set(doc, kOcl, "devices-hint", arg);
+
+ case IConfig::OclPlatformKey: /* --opencl-platform */
+ if (strlen(arg) < 3) {
+ return set(doc, kOcl, "platform", static_cast(strtol(arg, nullptr, 10)));
+ }
+
+ return set(doc, kOcl, "platform", arg);
+# endif
+
default:
break;
}
@@ -156,6 +189,9 @@ void xmrig::ConfigTransform::transformBoolean(rapidjson::Document &doc, int key,
case IConfig::HugePagesKey: /* --no-huge-pages */
return set(doc, kCpu, "huge-pages", enable);
+ case IConfig::CPUKey: /* --no-cpu */
+ return set(doc, kCpu, kEnabled, enable);
+
default:
break;
}
diff --git a/src/core/config/ConfigTransform.h b/src/core/config/ConfigTransform.h
index 440a7169..66c497ab 100644
--- a/src/core/config/ConfigTransform.h
+++ b/src/core/config/ConfigTransform.h
@@ -34,9 +34,6 @@ namespace xmrig {
class ConfigTransform : public BaseTransform
{
-public:
- ConfigTransform();
-
protected:
void finalize(rapidjson::Document &doc) override;
void transform(rapidjson::Document &doc, int key, const char *arg) override;
@@ -45,6 +42,7 @@ private:
void transformBoolean(rapidjson::Document &doc, int key, bool enable);
void transformUint64(rapidjson::Document &doc, int key, uint64_t arg);
+ bool m_opencl = false;
int64_t m_affinity = -1;
uint64_t m_intensity = 1;
uint64_t m_threads = 0;
diff --git a/src/core/config/Config_default.h b/src/core/config/Config_default.h
index 8011bf16..00c4cf12 100644
--- a/src/core/config/Config_default.h
+++ b/src/core/config/Config_default.h
@@ -57,13 +57,14 @@ R"===(
"huge-pages": true,
"hw-aes": null,
"priority": null,
+ "max-threads-hint": 100,
"asm": true,
"argon2-impl": null,
"cn/0": false,
"cn-lite/0": false
},
"opencl": {
- "enabled": true,
+ "enabled": false,
"cache": true,
"loader": null,
"platform": "AMD",
@@ -76,6 +77,7 @@ R"===(
"pools": [
{
"algo": null,
+ "coin": null,
"url": "donate.v2.xmrig.com:3333",
"user": "YOUR_WALLET_ADDRESS",
"pass": "x",
diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h
index 4447bf1b..d7083ba6 100644
--- a/src/core/config/Config_platform.h
+++ b/src/core/config/Config_platform.h
@@ -45,6 +45,8 @@ static const char short_options[] = "a:c:kBp:Px:r:R:s:t:T:o:u:O:v:l:S";
static const option options[] = {
{ "algo", 1, nullptr, IConfig::AlgorithmKey },
+ { "coin", 1, nullptr, IConfig::CoinKey },
+# ifdef XMRIG_FEATURE_HTTP
{ "api-worker-id", 1, nullptr, IConfig::ApiWorkerIdKey },
{ "api-id", 1, nullptr, IConfig::ApiIdKey },
{ "http-enabled", 0, nullptr, IConfig::HttpEnabledKey },
@@ -52,6 +54,9 @@ static const option options[] = {
{ "http-access-token", 1, nullptr, IConfig::HttpAccessTokenKey },
{ "http-port", 1, nullptr, IConfig::HttpPort },
{ "http-no-restricted", 0, nullptr, IConfig::HttpRestrictedKey },
+ { "daemon", 0, nullptr, IConfig::DaemonKey },
+ { "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey },
+# endif
{ "av", 1, nullptr, IConfig::AVKey },
{ "background", 0, nullptr, IConfig::BackgroundKey },
{ "config", 1, nullptr, IConfig::ConfigKey },
@@ -63,6 +68,8 @@ static const option options[] = {
{ "keepalive", 0, nullptr, IConfig::KeepAliveKey },
{ "log-file", 1, nullptr, IConfig::LogFileKey },
{ "nicehash", 0, nullptr, IConfig::NicehashKey },
+ { "rebench-algo", 0, nullptr, IConfig::RebenchAlgoKey },
+ { "bench-algo-time", 1, nullptr, IConfig::BenchAlgoTimeKey },
{ "no-color", 0, nullptr, IConfig::ColorKey },
{ "no-huge-pages", 0, nullptr, IConfig::HugePagesKey },
{ "pass", 1, nullptr, IConfig::PasswordKey },
@@ -76,15 +83,27 @@ static const option options[] = {
{ "user-agent", 1, nullptr, IConfig::UserAgentKey },
{ "userpass", 1, nullptr, IConfig::UserpassKey },
{ "rig-id", 1, nullptr, IConfig::RigIdKey },
+ { "no-cpu", 0, nullptr, IConfig::CPUKey },
+ { "max-cpu-usage", 1, nullptr, IConfig::CPUMaxThreadsKey },
+ { "cpu-max-threads-hint", 1, nullptr, IConfig::CPUMaxThreadsKey },
+# ifdef XMRIG_FEATURE_TLS
{ "tls", 0, nullptr, IConfig::TlsKey },
{ "tls-fingerprint", 1, nullptr, IConfig::FingerprintKey },
+# endif
+# ifdef XMRIG_FEATURE_ASM
{ "asm", 1, nullptr, IConfig::AssemblyKey },
- { "daemon", 0, nullptr, IConfig::DaemonKey },
- { "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey },
- { "rebench-algo", 0, nullptr, IConfig::RebenchAlgoKey },
- { "bench-algo-time", 1, nullptr, IConfig::BenchAlgoTimeKey },
+# endif
+# ifdef XMRIG_ALGO_RANDOMX
{ "randomx-init", 1, nullptr, IConfig::RandomXInitKey },
{ "randomx-no-numa", 0, nullptr, IConfig::RandomXNumaKey },
+# endif
+# ifdef XMRIG_FEATURE_OPENCL
+ { "opencl", 0, nullptr, IConfig::OclKey },
+ { "opencl-devices", 1, nullptr, IConfig::OclDevicesKey },
+ { "opencl-platform", 1, nullptr, IConfig::OclPlatformKey },
+ { "opencl-loader", 1, nullptr, IConfig::OclLoaderKey },
+ { "opencl-no-cache", 0, nullptr, IConfig::OclCacheKey },
+# endif
{ nullptr, 0, nullptr, 0 }
};
diff --git a/src/core/config/usage.h b/src/core/config/usage.h
index f1acd7c1..0d7cdc5e 100644
--- a/src/core/config/usage.h
+++ b/src/core/config/usage.h
@@ -29,99 +29,106 @@
#include "version.h"
+#include
+
+
namespace xmrig {
-static char const usage[] = "\
-Usage: " APP_ID " [OPTIONS]\n\
-Options:\n\
- -a, --algo=ALGO specify the algorithm to use\n\
- cn/r, cn/2, cn/1, cn/0, cn/double, cn/half, cn/fast,\n\
- cn/rwz, cn/zls, cn/xao, cn/rto"
-#ifdef XMRIG_ALGO_CN_GPU
-", cn/gpu,\n"
-#else
-",\n"
-#endif
-#ifdef XMRIG_ALGO_CN_LITE
-"\
- cn-lite/1,\n"
-#endif
-#ifdef XMRIG_ALGO_CN_HEAVY
-"\
- cn-heavy/xhv, cn-heavy/tube, cn-heavy/0,\n"
-#endif
-#ifdef XMRIG_ALGO_CN_PICO
-"\
- cn-pico,\n"
-#endif
-#ifdef XMRIG_ALGO_RANDOMX
-"\
- rx/wow, rx/loki, defyx\n"
-#endif
-"\
- -o, --url=URL URL of mining server\n\
- -O, --userpass=U:P username:password pair for mining server\n\
- -u, --user=USERNAME username for mining server\n\
- -p, --pass=PASSWORD password for mining server\n\
- --rig-id=ID rig identifier for pool-side statistics (needs pool support)\n\
- -t, --threads=N number of miner threads\n\
- -v, --av=N algorithm variation, 0 auto select\n\
- -k, --keepalive send keepalived packet for prevent timeout (needs pool support)\n\
- --nicehash enable nicehash.com support\n"
-#ifdef XMRIG_FEATURE_TLS
-"\
- --tls enable SSL/TLS support (needs pool support)\n\
- --tls-fingerprint=F pool TLS certificate fingerprint, if set enable strict certificate pinning\n"
-#endif
-#ifdef XMRIG_FEATURE_HTTP
-"\
- --daemon use daemon RPC instead of pool for solo mining\n\
- --daemon-poll-interval=N daemon poll interval in milliseconds (default: 1000)\n"
-#endif
-"\
- -r, --retries=N number of times to retry before switch to backup server (default: 5)\n\
- -R, --retry-pause=N time to pause between retries (default: 5)\n\
- --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\
- --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\
- --no-huge-pages disable huge pages support\n\
- --no-color disable colored output\n\
- --donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\
- --user-agent set custom user-agent string for pool\n\
- -B, --background run the miner in the background\n\
- -c, --config=FILE load a JSON-format configuration file\n\
- -l, --log-file=FILE log all output to a file\n"
-# ifdef HAVE_SYSLOG_H
-"\
- -S, --syslog use system log for output messages\n"
-# endif
-"\
- --asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer.\n\
- --print-time=N print hashrate report every N seconds\n"
-#ifdef XMRIG_FEATURE_HTTP
-"\
- --api-worker-id=ID custom worker-id for API\n\
- --api-id=ID custom instance ID for API\n\
- --http-enabled enable HTTP API\n\
- --http-host=HOST bind host for HTTP API (default: 127.0.0.1)\n\
- --http-port=N bind port for HTTP API\n\
- --http-access-token=T access token for HTTP API\n\
- --http-no-restricted enable full remote access to HTTP API (only if access token set)\n"
-#endif
-#ifdef XMRIG_ALGO_RANDOMX
-"\
- --randomx-init=N threads count to initialize RandomX dataset\n\
- --randomx-no-numa disable NUMA support for RandomX\n"
-#endif
-#ifdef XMRIG_FEATURE_HWLOC
-"\
- --export-topology export hwloc topology to a XML file and exit\n"
-#endif
-"\
- --dry-run test configuration and exit\n\
- -h, --help display this help and exit\n\
- -V, --version output version information and exit\n\
-";
+static inline const std::string &usage()
+{
+ static std::string u;
+
+ if (!u.empty()) {
+ return u;
+ }
+
+ u += "Usage: " APP_ID " [OPTIONS]\n\nNetwork:\n";
+ u += " -o, --url=URL URL of mining server\n";
+ u += " -a, --algo=ALGO mining algorithm https://xmrig.com/docs/algorithms\n";
+ u += " -u, --user=USERNAME username for mining server\n";
+ u += " -p, --pass=PASSWORD password for mining server\n";
+ u += " -O, --userpass=U:P username:password pair for mining server\n";
+ u += " -k, --keepalive send keepalived packet for prevent timeout (needs pool support)\n";
+ u += " --nicehash enable nicehash.com support\n";
+ u += " --rig-id=ID rig identifier for pool-side statistics (needs pool support)\n";
+
+# ifdef XMRIG_FEATURE_TLS
+ u += " --tls enable SSL/TLS support (needs pool support)\n";
+ u += " --tls-fingerprint=HEX pool TLS certificate fingerprint for strict certificate pinning\n";
+# endif
+
+# ifdef XMRIG_FEATURE_HTTP
+ u += " --daemon use daemon RPC instead of pool for solo mining\n";
+ u += " --daemon-poll-interval=N daemon poll interval in milliseconds (default: 1000)\n";
+# endif
+
+ u += " -r, --retries=N number of times to retry before switch to backup server (default: 5)\n";
+ u += " -R, --retry-pause=N time to pause between retries (default: 5)\n";
+ u += " --user-agent set custom user-agent string for pool\n";
+ u += " --donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n";
+ u += " --donate-over-proxy=N control donate over xmrig-proxy feature\n";
+
+ u += "\nCPU backend:\n";
+
+ u += " --no-cpu disable CPU mining backend\n";
+ u += " -t, --threads=N number of CPU threads\n";
+ u += " -v, --av=N algorithm variation, 0 auto select\n";
+ u += " --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n";
+ u += " --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n";
+ u += " --cpu-max-threads-hint=N maximum CPU threads count (in percentage) hint for autoconfig\n";
+ u += " --no-huge-pages disable huge pages support\n";
+ u += " --asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer\n";
+
+# 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";
+# endif
+
+# ifdef XMRIG_FEATURE_HTTP
+ u += "\nAPI:\n";
+ u += " --api-worker-id=ID custom worker-id for API\n";
+ u += " --api-id=ID custom instance ID for API\n";
+ u += " --http-host=HOST bind host for HTTP API (default: 127.0.0.1)\n";
+ u += " --http-port=N bind port for HTTP API\n";
+ u += " --http-access-token=T access token for HTTP API\n";
+ u += " --http-no-restricted enable full remote access to HTTP API (only if access token set)\n";
+# endif
+
+# ifdef XMRIG_FEATURE_OPENCL
+ u += "\nOpenCL backend:\n";
+ u += " --opencl enable OpenCL mining backend\n";
+ u += " --opencl-devices=N list of OpenCL devices to use\n";
+ u += " --opencl-platform=N OpenCL platform index or name\n";
+ u += " --opencl-loader=N path to OpenCL-ICD-Loader (OpenCL.dll or libOpenCL.so)\n";
+ u += " --opencl-no-cache disable OpenCL cache\n";
+ u += " --print-platforms print available OpenCL platforms and exit\n";
+# endif
+
+ u += "\nLogging:\n";
+
+# ifdef HAVE_SYSLOG_H
+ u += " -S, --syslog use system log for output messages\n";
+# endif
+
+ u += " -l, --log-file=FILE log all output to a file\n";
+ u += " --print-time=N print hashrate report every N seconds\n";
+ u += " --no-color disable colored output\n";
+
+ u += "\nMisc:\n";
+
+ u += " -c, --config=FILE load a JSON-format configuration file\n";
+ u += " -B, --background run the miner in the background\n";
+ u += " -V, --version output version information and exit\n";
+ u += " -h, --help display this help and exit\n";
+ u += " --dry-run test configuration and exit\n";
+
+# ifdef XMRIG_FEATURE_HWLOC
+ u += " --export-topology export hwloc topology to a XML file and exit\n";
+# endif
+
+ return u;
+}
} /* namespace xmrig */
diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp
index 9177325b..121a7d66 100644
--- a/src/crypto/common/Algorithm.cpp
+++ b/src/crypto/common/Algorithm.cpp
@@ -103,9 +103,8 @@ static AlgoName const algorithm_names[] = {
{ "cryptonight_turtle", "cn_turtle", Algorithm::CN_PICO_0 },
# endif
# ifdef XMRIG_ALGO_RANDOMX
+ { "randomx/0", "rx/0", Algorithm::RX_0 },
{ "randomx/test", "rx/test", Algorithm::RX_0 },
- { "randomx/0", "rx/0", Algorithm::RX_0 },
- { "randomx/0", "rx/0", Algorithm::RX_0 },
{ "RandomX", "rx", Algorithm::RX_0 },
{ "randomx/wow", "rx/wow", Algorithm::RX_WOW },
{ "RandomWOW", nullptr, Algorithm::RX_WOW },
diff --git a/src/crypto/common/Coin.cpp b/src/crypto/common/Coin.cpp
new file mode 100644
index 00000000..f5a32851
--- /dev/null
+++ b/src/crypto/common/Coin.cpp
@@ -0,0 +1,103 @@
+/* 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 Lee Clagett
+ * 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/common/Coin.h"
+#include "rapidjson/document.h"
+
+
+#include
+
+
+#ifdef _MSC_VER
+# define strcasecmp _stricmp
+#endif
+
+
+namespace xmrig {
+
+
+struct CoinName
+{
+ const char *name;
+ const Coin::Id id;
+};
+
+
+static CoinName const coin_names[] = {
+ { "monero", Coin::MONERO },
+ { "xmr", Coin::MONERO },
+};
+
+
+} /* namespace xmrig */
+
+
+
+xmrig::Algorithm::Id xmrig::Coin::algorithm(uint8_t blobVersion) const
+{
+ if (id() == MONERO) {
+ return (blobVersion >= 12) ? Algorithm::RX_0 : Algorithm::CN_R;
+ }
+
+ return Algorithm::INVALID;
+}
+
+
+
+const char *xmrig::Coin::name() const
+{
+ for (const auto &i : coin_names) {
+ if (i.id == m_id) {
+ return i.name;
+ }
+ }
+
+ return nullptr;
+}
+
+
+rapidjson::Value xmrig::Coin::toJSON() const
+{
+ using namespace rapidjson;
+
+ return isValid() ? Value(StringRef(name())) : Value(kNullType);
+}
+
+
+xmrig::Coin::Id xmrig::Coin::parse(const char *name)
+{
+ if (name == nullptr || strlen(name) < 3) {
+ return INVALID;
+ }
+
+ for (const auto &i : coin_names) {
+ if (strcasecmp(name, i.name) == 0) {
+ return i.id;
+ }
+ }
+
+ return INVALID;
+}
diff --git a/src/crypto/common/Coin.h b/src/crypto/common/Coin.h
new file mode 100644
index 00000000..779d60b8
--- /dev/null
+++ b/src/crypto/common/Coin.h
@@ -0,0 +1,75 @@
+/* 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 Lee Clagett
+ * 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 .
+ */
+
+#ifndef XMRIG_COIN_H
+#define XMRIG_COIN_H
+
+
+#include "crypto/common/Algorithm.h"
+#include "rapidjson/fwd.h"
+
+
+namespace xmrig {
+
+
+class Coin
+{
+public:
+ enum Id : int {
+ INVALID = -1,
+ MONERO,
+ };
+
+
+ Coin() = default;
+ inline Coin(const char *name) : m_id(parse(name)) {}
+ inline Coin(Id id) : m_id(id) {}
+
+
+ inline bool isEqual(const Coin &other) const { return m_id == other.m_id; }
+ inline bool isValid() const { return m_id != INVALID; }
+ inline Id id() const { return m_id; }
+
+ Algorithm::Id algorithm(uint8_t blobVersion) const;
+ const char *name() const;
+ rapidjson::Value toJSON() const;
+
+ inline bool operator!=(Coin::Id id) const { return m_id != id; }
+ inline bool operator!=(const Coin &other) const { return !isEqual(other); }
+ inline bool operator==(Coin::Id id) const { return m_id == id; }
+ inline bool operator==(const Coin &other) const { return isEqual(other); }
+ inline operator Coin::Id() const { return m_id; }
+
+ static Id parse(const char *name);
+
+private:
+ Id m_id = INVALID;
+};
+
+
+} /* namespace xmrig */
+
+
+#endif /* XMRIG_COIN_H */
diff --git a/src/crypto/randomx/common.hpp b/src/crypto/randomx/common.hpp
index da36f2c5..48f31bac 100644
--- a/src/crypto/randomx/common.hpp
+++ b/src/crypto/randomx/common.hpp
@@ -108,7 +108,7 @@ namespace randomx {
class JitCompilerX86;
using JitCompiler = JitCompilerX86;
#elif defined(__aarch64__)
- #define RANDOMX_HAVE_COMPILER 0
+ #define RANDOMX_HAVE_COMPILER 1
class JitCompilerA64;
using JitCompiler = JitCompilerA64;
#else
diff --git a/src/crypto/randomx/intrin_portable.h b/src/crypto/randomx/intrin_portable.h
index e4916096..346c433a 100644
--- a/src/crypto/randomx/intrin_portable.h
+++ b/src/crypto/randomx/intrin_portable.h
@@ -376,11 +376,138 @@ FORCE_INLINE rx_vec_f128 rx_cvt_packed_int_vec_f128(const void* addr) {
#define RANDOMX_DEFAULT_FENV
-void rx_reset_float_state();
+#elif defined(__aarch64__)
-void rx_set_rounding_mode(uint32_t mode);
+#include
+#include
+#include
-#else //end altivec
+typedef uint8x16_t rx_vec_i128;
+typedef float64x2_t rx_vec_f128;
+
+inline void* rx_aligned_alloc(size_t size, size_t align) {
+ void* p;
+ if (posix_memalign(&p, align, size) == 0)
+ return p;
+
+ return 0;
+};
+
+#define rx_aligned_free(a) free(a)
+
+inline void rx_prefetch_nta(void* ptr) {
+ asm volatile ("prfm pldl1strm, [%0]\n" : : "r" (ptr));
+}
+
+FORCE_INLINE rx_vec_f128 rx_load_vec_f128(const double* pd) {
+ return vld1q_f64((const float64_t*)pd);
+}
+
+FORCE_INLINE void rx_store_vec_f128(double* mem_addr, rx_vec_f128 val) {
+ vst1q_f64((float64_t*)mem_addr, val);
+}
+
+FORCE_INLINE rx_vec_f128 rx_swap_vec_f128(rx_vec_f128 a) {
+ float64x2_t temp;
+ temp = vcopyq_laneq_f64(temp, 1, a, 1);
+ a = vcopyq_laneq_f64(a, 1, a, 0);
+ return vcopyq_laneq_f64(a, 0, temp, 1);
+}
+
+FORCE_INLINE rx_vec_f128 rx_set_vec_f128(uint64_t x1, uint64_t x0) {
+ uint64x2_t temp0 = vdupq_n_u64(x0);
+ uint64x2_t temp1 = vdupq_n_u64(x1);
+ return vreinterpretq_f64_u64(vcopyq_laneq_u64(temp0, 1, temp1, 0));
+}
+
+FORCE_INLINE rx_vec_f128 rx_set1_vec_f128(uint64_t x) {
+ return vreinterpretq_f64_u64(vdupq_n_u64(x));
+}
+
+#define rx_add_vec_f128 vaddq_f64
+#define rx_sub_vec_f128 vsubq_f64
+#define rx_mul_vec_f128 vmulq_f64
+#define rx_div_vec_f128 vdivq_f64
+#define rx_sqrt_vec_f128 vsqrtq_f64
+
+FORCE_INLINE rx_vec_f128 rx_xor_vec_f128(rx_vec_f128 a, rx_vec_f128 b) {
+ return vreinterpretq_f64_u8(veorq_u8(vreinterpretq_u8_f64(a), vreinterpretq_u8_f64(b)));
+}
+
+FORCE_INLINE rx_vec_f128 rx_and_vec_f128(rx_vec_f128 a, rx_vec_f128 b) {
+ return vreinterpretq_f64_u8(vandq_u8(vreinterpretq_u8_f64(a), vreinterpretq_u8_f64(b)));
+}
+
+FORCE_INLINE rx_vec_f128 rx_or_vec_f128(rx_vec_f128 a, rx_vec_f128 b) {
+ return vreinterpretq_f64_u8(vorrq_u8(vreinterpretq_u8_f64(a), vreinterpretq_u8_f64(b)));
+}
+
+#ifdef __ARM_FEATURE_CRYPTO
+
+
+FORCE_INLINE rx_vec_i128 rx_aesenc_vec_i128(rx_vec_i128 a, rx_vec_i128 key) {
+ const uint8x16_t zero = { 0 };
+ return vaesmcq_u8(vaeseq_u8(a, zero)) ^ key;
+}
+
+FORCE_INLINE rx_vec_i128 rx_aesdec_vec_i128(rx_vec_i128 a, rx_vec_i128 key) {
+ const uint8x16_t zero = { 0 };
+ return vaesimcq_u8(vaesdq_u8(a, zero)) ^ key;
+}
+
+#define HAVE_AES
+
+#endif
+
+#define rx_xor_vec_i128 veorq_u8
+
+FORCE_INLINE int rx_vec_i128_x(rx_vec_i128 a) {
+ return vgetq_lane_s32(vreinterpretq_s32_u8(a), 0);
+}
+
+FORCE_INLINE int rx_vec_i128_y(rx_vec_i128 a) {
+ return vgetq_lane_s32(vreinterpretq_s32_u8(a), 1);
+}
+
+FORCE_INLINE int rx_vec_i128_z(rx_vec_i128 a) {
+ return vgetq_lane_s32(vreinterpretq_s32_u8(a), 2);
+}
+
+FORCE_INLINE int rx_vec_i128_w(rx_vec_i128 a) {
+ return vgetq_lane_s32(vreinterpretq_s32_u8(a), 3);
+}
+
+FORCE_INLINE rx_vec_i128 rx_set_int_vec_i128(int _I3, int _I2, int _I1, int _I0) {
+ int32_t data[4];
+ data[0] = _I0;
+ data[1] = _I1;
+ data[2] = _I2;
+ data[3] = _I3;
+ return vreinterpretq_u8_s32(vld1q_s32(data));
+};
+
+#define rx_xor_vec_i128 veorq_u8
+
+FORCE_INLINE rx_vec_i128 rx_load_vec_i128(const rx_vec_i128* mem_addr) {
+ return vld1q_u8((const uint8_t*)mem_addr);
+}
+
+FORCE_INLINE void rx_store_vec_i128(rx_vec_i128* mem_addr, rx_vec_i128 val) {
+ vst1q_u8((uint8_t*)mem_addr, val);
+}
+
+FORCE_INLINE rx_vec_f128 rx_cvt_packed_int_vec_f128(const void* addr) {
+ double lo = unsigned32ToSigned2sCompl(load32((uint8_t*)addr + 0));
+ double hi = unsigned32ToSigned2sCompl(load32((uint8_t*)addr + 4));
+ rx_vec_f128 x;
+ x = vsetq_lane_f64(lo, x, 0);
+ x = vsetq_lane_f64(hi, x, 1);
+ return x;
+}
+
+#define RANDOMX_DEFAULT_FENV
+
+#else //portable fallback
#include
#include
@@ -487,7 +614,6 @@ FORCE_INLINE rx_vec_f128 rx_set1_vec_f128(uint64_t x) {
return v;
}
-
FORCE_INLINE rx_vec_f128 rx_xor_vec_f128(rx_vec_f128 a, rx_vec_f128 b) {
rx_vec_f128 x;
x.i.u64[0] = a.i.u64[0] ^ b.i.u64[0];
@@ -578,10 +704,6 @@ FORCE_INLINE rx_vec_f128 rx_cvt_packed_int_vec_f128(const void* addr) {
#define RANDOMX_DEFAULT_FENV
-void rx_reset_float_state();
-
-void rx_set_rounding_mode(uint32_t mode);
-
#endif
#ifndef HAVE_AES
@@ -598,6 +720,14 @@ FORCE_INLINE rx_vec_i128 rx_aesdec_vec_i128(rx_vec_i128 v, rx_vec_i128 rkey) {
}
#endif
+#ifdef RANDOMX_DEFAULT_FENV
+
+void rx_reset_float_state();
+
+void rx_set_rounding_mode(uint32_t mode);
+
+#endif
+
double loadDoublePortable(const void* addr);
uint64_t mulh(uint64_t, uint64_t);
int64_t smulh(int64_t, int64_t);
diff --git a/src/crypto/randomx/jit_compiler_a64.cpp b/src/crypto/randomx/jit_compiler_a64.cpp
new file mode 100644
index 00000000..08f84f1c
--- /dev/null
+++ b/src/crypto/randomx/jit_compiler_a64.cpp
@@ -0,0 +1,1020 @@
+/*
+Copyright (c) 2018-2019, tevador
+Copyright (c) 2019, SChernykh
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+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 "crypto/randomx/jit_compiler_a64.hpp"
+#include "crypto/randomx/superscalar.hpp"
+#include "crypto/randomx/program.hpp"
+#include "crypto/randomx/reciprocal.h"
+#include "crypto/randomx/virtual_memory.hpp"
+
+namespace ARMV8A {
+
+constexpr uint32_t B = 0x14000000;
+constexpr uint32_t EOR = 0xCA000000;
+constexpr uint32_t EOR32 = 0x4A000000;
+constexpr uint32_t ADD = 0x8B000000;
+constexpr uint32_t SUB = 0xCB000000;
+constexpr uint32_t MUL = 0x9B007C00;
+constexpr uint32_t UMULH = 0x9BC07C00;
+constexpr uint32_t SMULH = 0x9B407C00;
+constexpr uint32_t MOVZ = 0xD2800000;
+constexpr uint32_t MOVN = 0x92800000;
+constexpr uint32_t MOVK = 0xF2800000;
+constexpr uint32_t ADD_IMM_LO = 0x91000000;
+constexpr uint32_t ADD_IMM_HI = 0x91400000;
+constexpr uint32_t LDR_LITERAL = 0x58000000;
+constexpr uint32_t ROR = 0x9AC02C00;
+constexpr uint32_t ROR_IMM = 0x93C00000;
+constexpr uint32_t MOV_REG = 0xAA0003E0;
+constexpr uint32_t MOV_VREG_EL = 0x6E080400;
+constexpr uint32_t FADD = 0x4E60D400;
+constexpr uint32_t FSUB = 0x4EE0D400;
+constexpr uint32_t FEOR = 0x6E201C00;
+constexpr uint32_t FMUL = 0x6E60DC00;
+constexpr uint32_t FDIV = 0x6E60FC00;
+constexpr uint32_t FSQRT = 0x6EE1F800;
+
+}
+
+namespace randomx {
+
+static const size_t CodeSize = ((uint8_t*)randomx_init_dataset_aarch64_end) - ((uint8_t*)randomx_program_aarch64);
+static const size_t MainLoopBegin = ((uint8_t*)randomx_program_aarch64_main_loop) - ((uint8_t*)randomx_program_aarch64);
+static const size_t PrologueSize = ((uint8_t*)randomx_program_aarch64_vm_instructions) - ((uint8_t*)randomx_program_aarch64);
+static const size_t ImulRcpLiteralsEnd = ((uint8_t*)randomx_program_aarch64_imul_rcp_literals_end) - ((uint8_t*)randomx_program_aarch64);
+
+static size_t CalcDatasetItemSize()
+{
+ return
+ // Prologue
+ ((uint8_t*)randomx_calc_dataset_item_aarch64_prefetch - (uint8_t*)randomx_calc_dataset_item_aarch64) +
+ // Main loop
+ RandomX_CurrentConfig.CacheAccesses * (
+ // Main loop prologue
+ ((uint8_t*)randomx_calc_dataset_item_aarch64_mix - ((uint8_t*)randomx_calc_dataset_item_aarch64_prefetch)) + 4 +
+ // Inner main loop (instructions)
+ ((RandomX_CurrentConfig.SuperscalarLatency * 3) + 2) * 16 +
+ // Main loop epilogue
+ ((uint8_t*)randomx_calc_dataset_item_aarch64_store_result - (uint8_t*)randomx_calc_dataset_item_aarch64_mix) + 4
+ ) +
+ // Epilogue
+ ((uint8_t*)randomx_calc_dataset_item_aarch64_end - (uint8_t*)randomx_calc_dataset_item_aarch64_store_result);
+}
+
+constexpr uint32_t IntRegMap[8] = { 4, 5, 6, 7, 12, 13, 14, 15 };
+
+JitCompilerA64::JitCompilerA64()
+ : code((uint8_t*) allocExecutableMemory(CodeSize + CalcDatasetItemSize()))
+ , literalPos(ImulRcpLiteralsEnd)
+ , num32bitLiterals(0)
+{
+ memset(reg_changed_offset, 0, sizeof(reg_changed_offset));
+ memcpy(code, (void*) randomx_program_aarch64, CodeSize);
+}
+
+JitCompilerA64::~JitCompilerA64()
+{
+ freePagedMemory(code, CodeSize + CalcDatasetItemSize());
+}
+
+void JitCompilerA64::generateProgram(Program& program, ProgramConfiguration& config)
+{
+ uint32_t codePos = MainLoopBegin + 4;
+
+ // and w16, w10, ScratchpadL3Mask64
+ emit32(0x121A0000 | 16 | (10 << 5) | ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 7) << 10), code, codePos);
+
+ // and w17, w18, ScratchpadL3Mask64
+ emit32(0x121A0000 | 17 | (18 << 5) | ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 7) << 10), code, codePos);
+
+ codePos = PrologueSize;
+ literalPos = ImulRcpLiteralsEnd;
+ num32bitLiterals = 0;
+
+ for (uint32_t i = 0; i < RegistersCount; ++i)
+ reg_changed_offset[i] = codePos;
+
+ for (uint32_t i = 0; i < program.getSize(); ++i)
+ {
+ Instruction& instr = program(i);
+ instr.src %= RegistersCount;
+ instr.dst %= RegistersCount;
+ (this->*engine[instr.opcode])(instr, codePos);
+ }
+
+ // Update spMix2
+ // eor w18, config.readReg2, config.readReg3
+ emit32(ARMV8A::EOR32 | 18 | (IntRegMap[config.readReg2] << 5) | (IntRegMap[config.readReg3] << 16), code, codePos);
+
+ // Jump back to the main loop
+ const uint32_t offset = (((uint8_t*)randomx_program_aarch64_vm_instructions_end) - ((uint8_t*)randomx_program_aarch64)) - codePos;
+ emit32(ARMV8A::B | (offset / 4), code, codePos);
+
+ // and w18, w18, CacheLineAlignMask
+ codePos = (((uint8_t*)randomx_program_aarch64_cacheline_align_mask1) - ((uint8_t*)randomx_program_aarch64));
+ emit32(0x121A0000 | 18 | (18 << 5) | ((RandomX_CurrentConfig.Log2_DatasetBaseSize - 7) << 10), code, codePos);
+
+ // and w10, w10, CacheLineAlignMask
+ codePos = (((uint8_t*)randomx_program_aarch64_cacheline_align_mask2) - ((uint8_t*)randomx_program_aarch64));
+ emit32(0x121A0000 | 10 | (10 << 5) | ((RandomX_CurrentConfig.Log2_DatasetBaseSize - 7) << 10), code, codePos);
+
+ // Update spMix1
+ // eor x10, config.readReg0, config.readReg1
+ codePos = ((uint8_t*)randomx_program_aarch64_update_spMix1) - ((uint8_t*)randomx_program_aarch64);
+ emit32(ARMV8A::EOR | 10 | (IntRegMap[config.readReg0] << 5) | (IntRegMap[config.readReg1] << 16), code, codePos);
+
+#ifdef __GNUC__
+ __builtin___clear_cache(reinterpret_cast(code + MainLoopBegin), reinterpret_cast(code + codePos));
+#endif
+}
+
+void JitCompilerA64::generateProgramLight(Program& program, ProgramConfiguration& config, uint32_t datasetOffset)
+{
+ uint32_t codePos = MainLoopBegin + 4;
+
+ // and w16, w10, ScratchpadL3Mask64
+ emit32(0x121A0000 | 16 | (10 << 5) | ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 7) << 10), code, codePos);
+
+ // and w17, w18, ScratchpadL3Mask64
+ emit32(0x121A0000 | 17 | (18 << 5) | ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 7) << 10), code, codePos);
+
+ codePos = PrologueSize;
+ literalPos = ImulRcpLiteralsEnd;
+ num32bitLiterals = 0;
+
+ for (uint32_t i = 0; i < RegistersCount; ++i)
+ reg_changed_offset[i] = codePos;
+
+ for (uint32_t i = 0; i < program.getSize(); ++i)
+ {
+ Instruction& instr = program(i);
+ instr.src %= RegistersCount;
+ instr.dst %= RegistersCount;
+ (this->*engine[instr.opcode])(instr, codePos);
+ }
+
+ // Update spMix2
+ // eor w18, config.readReg2, config.readReg3
+ emit32(ARMV8A::EOR32 | 18 | (IntRegMap[config.readReg2] << 5) | (IntRegMap[config.readReg3] << 16), code, codePos);
+
+ // Jump back to the main loop
+ const uint32_t offset = (((uint8_t*)randomx_program_aarch64_vm_instructions_end_light) - ((uint8_t*)randomx_program_aarch64)) - codePos;
+ emit32(ARMV8A::B | (offset / 4), code, codePos);
+
+ // and w2, w9, CacheLineAlignMask
+ codePos = (((uint8_t*)randomx_program_aarch64_light_cacheline_align_mask) - ((uint8_t*)randomx_program_aarch64));
+ emit32(0x121A0000 | 2 | (9 << 5) | ((RandomX_CurrentConfig.Log2_DatasetBaseSize - 7) << 10), code, codePos);
+
+ // Update spMix1
+ // eor x10, config.readReg0, config.readReg1
+ codePos = ((uint8_t*)randomx_program_aarch64_update_spMix1) - ((uint8_t*)randomx_program_aarch64);
+ emit32(ARMV8A::EOR | 10 | (IntRegMap[config.readReg0] << 5) | (IntRegMap[config.readReg1] << 16), code, codePos);
+
+ // Apply dataset offset
+ codePos = ((uint8_t*)randomx_program_aarch64_light_dataset_offset) - ((uint8_t*)randomx_program_aarch64);
+
+ datasetOffset /= CacheLineSize;
+ const uint32_t imm_lo = datasetOffset & ((1 << 12) - 1);
+ const uint32_t imm_hi = datasetOffset >> 12;
+
+ emit32(ARMV8A::ADD_IMM_LO | 2 | (2 << 5) | (imm_lo << 10), code, codePos);
+ emit32(ARMV8A::ADD_IMM_HI | 2 | (2 << 5) | (imm_hi << 10), code, codePos);
+
+#ifdef __GNUC__
+ __builtin___clear_cache(reinterpret_cast(code + MainLoopBegin), reinterpret_cast(code + codePos));
+#endif
+}
+
+template
+void JitCompilerA64::generateSuperscalarHash(SuperscalarProgram(&programs)[N], std::vector &reciprocalCache)
+{
+ uint32_t codePos = CodeSize;
+
+ uint8_t* p1 = (uint8_t*)randomx_calc_dataset_item_aarch64;
+ uint8_t* p2 = (uint8_t*)randomx_calc_dataset_item_aarch64_prefetch;
+ memcpy(code + codePos, p1, p2 - p1);
+ codePos += p2 - p1;
+
+ num32bitLiterals = 64;
+ constexpr uint32_t tmp_reg = 12;
+
+ for (size_t i = 0; i < RandomX_CurrentConfig.CacheAccesses; ++i)
+ {
+ // and x11, x10, CacheSize / CacheLineSize - 1
+ emit32(0x92400000 | 11 | (10 << 5) | ((RandomX_CurrentConfig.Log2_CacheSize - 1) << 10), code, codePos);
+
+ p1 = ((uint8_t*)randomx_calc_dataset_item_aarch64_prefetch) + 4;
+ p2 = (uint8_t*)randomx_calc_dataset_item_aarch64_mix;
+ memcpy(code + codePos, p1, p2 - p1);
+ codePos += p2 - p1;
+
+ SuperscalarProgram& prog = programs[i];
+ const size_t progSize = prog.getSize();
+
+ uint32_t jmp_pos = codePos;
+ codePos += 4;
+
+ // Fill in literal pool
+ for (size_t j = 0; j < progSize; ++j)
+ {
+ const Instruction& instr = prog(j);
+ if (static_cast(instr.opcode) == randomx::SuperscalarInstructionType::IMUL_RCP)
+ emit64(reciprocalCache[instr.getImm32()], code, codePos);
+ }
+
+ // Jump over literal pool
+ uint32_t literal_pos = jmp_pos;
+ emit32(ARMV8A::B | ((codePos - jmp_pos) / 4), code, literal_pos);
+
+ for (size_t j = 0; j < progSize; ++j)
+ {
+ const Instruction& instr = prog(j);
+ const uint32_t src = instr.src;
+ const uint32_t dst = instr.dst;
+
+ switch (static_cast(instr.opcode))
+ {
+ case randomx::SuperscalarInstructionType::ISUB_R:
+ emit32(ARMV8A::SUB | dst | (dst << 5) | (src << 16), code, codePos);
+ break;
+ case randomx::SuperscalarInstructionType::IXOR_R:
+ emit32(ARMV8A::EOR | dst | (dst << 5) | (src << 16), code, codePos);
+ break;
+ case randomx::SuperscalarInstructionType::IADD_RS:
+ emit32(ARMV8A::ADD | dst | (dst << 5) | (instr.getModShift() << 10) | (src << 16), code, codePos);
+ break;
+ case randomx::SuperscalarInstructionType::IMUL_R:
+ emit32(ARMV8A::MUL | dst | (dst << 5) | (src << 16), code, codePos);
+ break;
+ case randomx::SuperscalarInstructionType::IROR_C:
+ emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((instr.getImm32() & 63) << 10) | (dst << 16), code, codePos);
+ break;
+ case randomx::SuperscalarInstructionType::IADD_C7:
+ case randomx::SuperscalarInstructionType::IADD_C8:
+ case randomx::SuperscalarInstructionType::IADD_C9:
+ emitAddImmediate(dst, dst, instr.getImm32(), code, codePos);
+ break;
+ case randomx::SuperscalarInstructionType::IXOR_C7:
+ case randomx::SuperscalarInstructionType::IXOR_C8:
+ case randomx::SuperscalarInstructionType::IXOR_C9:
+ emitMovImmediate(tmp_reg, instr.getImm32(), code, codePos);
+ emit32(ARMV8A::EOR | dst | (dst << 5) | (tmp_reg << 16), code, codePos);
+ break;
+ case randomx::SuperscalarInstructionType::IMULH_R:
+ emit32(ARMV8A::UMULH | dst | (dst << 5) | (src << 16), code, codePos);
+ break;
+ case randomx::SuperscalarInstructionType::ISMULH_R:
+ emit32(ARMV8A::SMULH | dst | (dst << 5) | (src << 16), code, codePos);
+ break;
+ case randomx::SuperscalarInstructionType::IMUL_RCP:
+ {
+ int32_t offset = (literal_pos - codePos) / 4;
+ offset &= (1 << 19) - 1;
+ literal_pos += 8;
+
+ // ldr tmp_reg, reciprocal
+ emit32(ARMV8A::LDR_LITERAL | tmp_reg | (offset << 5), code, codePos);
+
+ // mul dst, dst, tmp_reg
+ emit32(ARMV8A::MUL | dst | (dst << 5) | (tmp_reg << 16), code, codePos);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ p1 = (uint8_t*)randomx_calc_dataset_item_aarch64_mix;
+ p2 = (uint8_t*)randomx_calc_dataset_item_aarch64_store_result;
+ memcpy(code + codePos, p1, p2 - p1);
+ codePos += p2 - p1;
+
+ // Update registerValue
+ emit32(ARMV8A::MOV_REG | 10 | (prog.getAddressRegister() << 16), code, codePos);
+ }
+
+ p1 = (uint8_t*)randomx_calc_dataset_item_aarch64_store_result;
+ p2 = (uint8_t*)randomx_calc_dataset_item_aarch64_end;
+ memcpy(code + codePos, p1, p2 - p1);
+ codePos += p2 - p1;
+
+#ifdef __GNUC__
+ __builtin___clear_cache(reinterpret_cast(code + CodeSize), reinterpret_cast(code + codePos));
+#endif
+}
+
+template void JitCompilerA64::generateSuperscalarHash(SuperscalarProgram(&programs)[RANDOMX_CACHE_MAX_ACCESSES], std::vector &reciprocalCache);
+
+DatasetInitFunc* JitCompilerA64::getDatasetInitFunc()
+{
+ return (DatasetInitFunc*)(code + (((uint8_t*)randomx_init_dataset_aarch64) - ((uint8_t*)randomx_program_aarch64)));
+}
+
+size_t JitCompilerA64::getCodeSize()
+{
+ return CodeSize;
+}
+
+void JitCompilerA64::emitMovImmediate(uint32_t dst, uint32_t imm, uint8_t* code, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ if (imm < (1 << 16))
+ {
+ // movz tmp_reg, imm32 (16 low bits)
+ emit32(ARMV8A::MOVZ | dst | (imm << 5), code, k);
+ }
+ else
+ {
+ if (num32bitLiterals < 64)
+ {
+ if (static_cast(imm) < 0)
+ {
+ // smov dst, vN.s[M]
+ emit32(0x4E042C00 | dst | ((num32bitLiterals / 4) << 5) | ((num32bitLiterals % 4) << 19), code, k);
+ }
+ else
+ {
+ // umov dst, vN.s[M]
+ emit32(0x0E043C00 | dst | ((num32bitLiterals / 4) << 5) | ((num32bitLiterals % 4) << 19), code, k);
+ }
+
+ ((uint32_t*)(code + ImulRcpLiteralsEnd))[num32bitLiterals] = imm;
+ ++num32bitLiterals;
+ }
+ else
+ {
+ if (static_cast(imm) < 0)
+ {
+ // movn tmp_reg, ~imm32 (16 high bits)
+ emit32(ARMV8A::MOVN | dst | (1 << 21) | ((~imm >> 16) << 5), code, k);
+ }
+ else
+ {
+ // movz tmp_reg, imm32 (16 high bits)
+ emit32(ARMV8A::MOVZ | dst | (1 << 21) | ((imm >> 16) << 5), code, k);
+ }
+
+ // movk tmp_reg, imm32 (16 low bits)
+ emit32(ARMV8A::MOVK | dst | ((imm & 0xFFFF) << 5), code, k);
+ }
+ }
+
+ codePos = k;
+}
+
+void JitCompilerA64::emitAddImmediate(uint32_t dst, uint32_t src, uint32_t imm, uint8_t* code, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ if (imm < (1 << 24))
+ {
+ const uint32_t imm_lo = imm & ((1 << 12) - 1);
+ const uint32_t imm_hi = imm >> 12;
+
+ if (imm_lo && imm_hi)
+ {
+ emit32(ARMV8A::ADD_IMM_LO | dst | (src << 5) | (imm_lo << 10), code, k);
+ emit32(ARMV8A::ADD_IMM_HI | dst | (dst << 5) | (imm_hi << 10), code, k);
+ }
+ else if (imm_lo)
+ {
+ emit32(ARMV8A::ADD_IMM_LO | dst | (src << 5) | (imm_lo << 10), code, k);
+ }
+ else
+ {
+ emit32(ARMV8A::ADD_IMM_HI | dst | (src << 5) | (imm_hi << 10), code, k);
+ }
+ }
+ else
+ {
+ constexpr uint32_t tmp_reg = 18;
+ emitMovImmediate(tmp_reg, imm, code, k);
+
+ // add dst, src, tmp_reg
+ emit32(ARMV8A::ADD | dst | (src << 5) | (tmp_reg << 16), code, k);
+ }
+
+ codePos = k;
+}
+
+template
+void JitCompilerA64::emitMemLoad(uint32_t dst, uint32_t src, Instruction& instr, uint8_t* code, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ uint32_t imm = instr.getImm32();
+
+ if (src != dst)
+ {
+ imm &= instr.getModMem() ? (RandomX_CurrentConfig.ScratchpadL1_Size - 1) : (RandomX_CurrentConfig.ScratchpadL2_Size - 1);
+ emitAddImmediate(tmp_reg, src, imm, code, k);
+
+ constexpr uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
+ const uint32_t andInstrL1 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL1 - 4) << 10);
+ const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10);
+
+ emit32(instr.getModMem() ? andInstrL1 : andInstrL2, code, k);
+
+ // ldr tmp_reg, [x2, tmp_reg]
+ emit32(0xf8606840 | tmp_reg | (tmp_reg << 16), code, k);
+ }
+ else
+ {
+ imm = (imm & ScratchpadL3Mask) >> 3;
+ emitMovImmediate(tmp_reg, imm, code, k);
+
+ // ldr tmp_reg, [x2, tmp_reg, lsl 3]
+ emit32(0xf8607840 | tmp_reg | (tmp_reg << 16), code, k);
+ }
+
+ codePos = k;
+}
+
+template
+void JitCompilerA64::emitMemLoadFP(uint32_t src, Instruction& instr, uint8_t* code, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ uint32_t imm = instr.getImm32();
+ constexpr uint32_t tmp_reg = 18;
+
+ imm &= instr.getModMem() ? (RandomX_CurrentConfig.ScratchpadL1_Size - 1) : (RandomX_CurrentConfig.ScratchpadL2_Size - 1);
+ emitAddImmediate(tmp_reg, src, imm, code, k);
+
+ constexpr uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
+ const uint32_t andInstrL1 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL1 - 4) << 10);
+ const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10);
+
+ emit32(instr.getModMem() ? andInstrL1 : andInstrL2, code, k);
+
+ // add tmp_reg, x2, tmp_reg
+ emit32(ARMV8A::ADD | tmp_reg | (2 << 5) | (tmp_reg << 16), code, k);
+
+ // ldpsw tmp_reg, tmp_reg + 1, [tmp_reg]
+ emit32(0x69400000 | tmp_reg | (tmp_reg << 5) | ((tmp_reg + 1) << 10), code, k);
+
+ // ins tmp_reg_fp.d[0], tmp_reg
+ emit32(0x4E081C00 | tmp_reg_fp | (tmp_reg << 5), code, k);
+
+ // ins tmp_reg_fp.d[1], tmp_reg + 1
+ emit32(0x4E181C00 | tmp_reg_fp | ((tmp_reg + 1) << 5), code, k);
+
+ // scvtf tmp_reg_fp.2d, tmp_reg_fp.2d
+ emit32(0x4E61D800 | tmp_reg_fp | (tmp_reg_fp << 5), code, k);
+
+ codePos = k;
+}
+
+void JitCompilerA64::h_IADD_RS(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+ const uint32_t shift = instr.getModShift();
+
+ // add dst, src << shift
+ emit32(ARMV8A::ADD | dst | (dst << 5) | (shift << 10) | (src << 16), code, k);
+
+ if (instr.dst == RegisterNeedsDisplacement)
+ emitAddImmediate(dst, dst, instr.getImm32(), code, k);
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_IADD_M(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ constexpr uint32_t tmp_reg = 18;
+ emitMemLoad(dst, src, instr, code, k);
+
+ // add dst, dst, tmp_reg
+ emit32(ARMV8A::ADD | dst | (dst << 5) | (tmp_reg << 16), code, k);
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_ISUB_R(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ if (src != dst)
+ {
+ // sub dst, dst, src
+ emit32(ARMV8A::SUB | dst | (dst << 5) | (src << 16), code, k);
+ }
+ else
+ {
+ emitAddImmediate(dst, dst, -instr.getImm32(), code, k);
+ }
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_ISUB_M(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ constexpr uint32_t tmp_reg = 18;
+ emitMemLoad(dst, src, instr, code, k);
+
+ // sub dst, dst, tmp_reg
+ emit32(ARMV8A::SUB | dst | (dst << 5) | (tmp_reg << 16), code, k);
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_IMUL_R(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ if (src == dst)
+ {
+ src = 18;
+ emitMovImmediate(src, instr.getImm32(), code, k);
+ }
+
+ // mul dst, dst, src
+ emit32(ARMV8A::MUL | dst | (dst << 5) | (src << 16), code, k);
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_IMUL_M(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ constexpr uint32_t tmp_reg = 18;
+ emitMemLoad(dst, src, instr, code, k);
+
+ // sub dst, dst, tmp_reg
+ emit32(ARMV8A::MUL | dst | (dst << 5) | (tmp_reg << 16), code, k);
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_IMULH_R(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ // umulh dst, dst, src
+ emit32(ARMV8A::UMULH | dst | (dst << 5) | (src << 16), code, k);
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_IMULH_M(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ constexpr uint32_t tmp_reg = 18;
+ emitMemLoad(dst, src, instr, code, k);
+
+ // umulh dst, dst, tmp_reg
+ emit32(ARMV8A::UMULH | dst | (dst << 5) | (tmp_reg << 16), code, k);
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_ISMULH_R(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ // smulh dst, dst, src
+ emit32(ARMV8A::SMULH | dst | (dst << 5) | (src << 16), code, k);
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_ISMULH_M(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ constexpr uint32_t tmp_reg = 18;
+ emitMemLoad(dst, src, instr, code, k);
+
+ // smulh dst, dst, tmp_reg
+ emit32(ARMV8A::SMULH | dst | (dst << 5) | (tmp_reg << 16), code, k);
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_IMUL_RCP(Instruction& instr, uint32_t& codePos)
+{
+ const uint64_t divisor = instr.getImm32();
+ if (isZeroOrPowerOf2(divisor))
+ return;
+
+ uint32_t k = codePos;
+
+ constexpr uint32_t tmp_reg = 18;
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ constexpr uint64_t N = 1ULL << 63;
+ const uint64_t q = N / divisor;
+ const uint64_t r = N % divisor;
+#ifdef __GNUC__
+ const uint64_t shift = 64 - __builtin_clzll(divisor);
+#else
+ uint64_t shift = 32;
+ for (uint64_t k = 1U << 31; (k & divisor) == 0; k >>= 1)
+ --shift;
+#endif
+
+ const uint32_t literal_id = (ImulRcpLiteralsEnd - literalPos) / sizeof(uint64_t);
+
+ literalPos -= sizeof(uint64_t);
+ *(uint64_t*)(code + literalPos) = (q << shift) + ((r << shift) / divisor);
+
+ if (literal_id < 13)
+ {
+ static constexpr uint32_t literal_regs[13] = { 30 << 16, 29 << 16, 28 << 16, 27 << 16, 26 << 16, 25 << 16, 24 << 16, 23 << 16, 22 << 16, 21 << 16, 20 << 16, 11 << 16, 0 };
+
+ // mul dst, dst, literal_reg
+ emit32(ARMV8A::MUL | dst | (dst << 5) | literal_regs[literal_id], code, k);
+ }
+ else
+ {
+ // ldr tmp_reg, reciprocal
+ const uint32_t offset = (literalPos - k) / 4;
+ emit32(ARMV8A::LDR_LITERAL | tmp_reg | (offset << 5), code, k);
+
+ // mul dst, dst, tmp_reg
+ emit32(ARMV8A::MUL | dst | (dst << 5) | (tmp_reg << 16), code, k);
+ }
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_INEG_R(Instruction& instr, uint32_t& codePos)
+{
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ // sub dst, xzr, dst
+ emit32(ARMV8A::SUB | dst | (31 << 5) | (dst << 16), code, codePos);
+
+ reg_changed_offset[instr.dst] = codePos;
+}
+
+void JitCompilerA64::h_IXOR_R(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ if (src == dst)
+ {
+ src = 18;
+ emitMovImmediate(src, instr.getImm32(), code, k);
+ }
+
+ // eor dst, dst, src
+ emit32(ARMV8A::EOR | dst | (dst << 5) | (src << 16), code, k);
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_IXOR_M(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ constexpr uint32_t tmp_reg = 18;
+ emitMemLoad(dst, src, instr, code, k);
+
+ // eor dst, dst, tmp_reg
+ emit32(ARMV8A::EOR | dst | (dst << 5) | (tmp_reg << 16), code, k);
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_IROR_R(Instruction& instr, uint32_t& codePos)
+{
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ if (src != dst)
+ {
+ // ror dst, dst, src
+ emit32(ARMV8A::ROR | dst | (dst << 5) | (src << 16), code, codePos);
+ }
+ else
+ {
+ // ror dst, dst, imm
+ emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((instr.getImm32() & 63) << 10) | (dst << 16), code, codePos);
+ }
+
+ reg_changed_offset[instr.dst] = codePos;
+}
+
+void JitCompilerA64::h_IROL_R(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ if (src != dst)
+ {
+ constexpr uint32_t tmp_reg = 18;
+
+ // sub tmp_reg, xzr, src
+ emit32(ARMV8A::SUB | tmp_reg | (31 << 5) | (src << 16), code, k);
+
+ // ror dst, dst, tmp_reg
+ emit32(ARMV8A::ROR | dst | (dst << 5) | (tmp_reg << 16), code, k);
+ }
+ else
+ {
+ // ror dst, dst, imm
+ emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((-instr.getImm32() & 63) << 10) | (dst << 16), code, k);
+ }
+
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_ISWAP_R(Instruction& instr, uint32_t& codePos)
+{
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+
+ if (src == dst)
+ return;
+
+ uint32_t k = codePos;
+
+ constexpr uint32_t tmp_reg = 18;
+ emit32(ARMV8A::MOV_REG | tmp_reg | (dst << 16), code, k);
+ emit32(ARMV8A::MOV_REG | dst | (src << 16), code, k);
+ emit32(ARMV8A::MOV_REG | src | (tmp_reg << 16), code, k);
+
+ reg_changed_offset[instr.src] = k;
+ reg_changed_offset[instr.dst] = k;
+ codePos = k;
+}
+
+void JitCompilerA64::h_FSWAP_R(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t dst = instr.dst + 16;
+
+ constexpr uint32_t tmp_reg_fp = 28;
+ constexpr uint32_t src_index1 = 1 << 14;
+ constexpr uint32_t dst_index1 = 1 << 20;
+
+ emit32(ARMV8A::MOV_VREG_EL | tmp_reg_fp | (dst << 5) | src_index1, code, k);
+ emit32(ARMV8A::MOV_VREG_EL | dst | (dst << 5) | dst_index1, code, k);
+ emit32(ARMV8A::MOV_VREG_EL | dst | (tmp_reg_fp << 5), code, k);
+
+ codePos = k;
+}
+
+void JitCompilerA64::h_FADD_R(Instruction& instr, uint32_t& codePos)
+{
+ const uint32_t src = (instr.src % 4) + 24;
+ const uint32_t dst = (instr.dst % 4) + 16;
+
+ emit32(ARMV8A::FADD | dst | (dst << 5) | (src << 16), code, codePos);
+}
+
+void JitCompilerA64::h_FADD_M(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = (instr.dst % 4) + 16;
+
+ constexpr uint32_t tmp_reg_fp = 28;
+ emitMemLoadFP(src, instr, code, k);
+
+ emit32(ARMV8A::FADD | dst | (dst << 5) | (tmp_reg_fp << 16), code, k);
+
+ codePos = k;
+}
+
+void JitCompilerA64::h_FSUB_R(Instruction& instr, uint32_t& codePos)
+{
+ const uint32_t src = (instr.src % 4) + 24;
+ const uint32_t dst = (instr.dst % 4) + 16;
+
+ emit32(ARMV8A::FSUB | dst | (dst << 5) | (src << 16), code, codePos);
+}
+
+void JitCompilerA64::h_FSUB_M(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = (instr.dst % 4) + 16;
+
+ constexpr uint32_t tmp_reg_fp = 28;
+ emitMemLoadFP(src, instr, code, k);
+
+ emit32(ARMV8A::FSUB | dst | (dst << 5) | (tmp_reg_fp << 16), code, k);
+
+ codePos = k;
+}
+
+void JitCompilerA64::h_FSCAL_R(Instruction& instr, uint32_t& codePos)
+{
+ const uint32_t dst = (instr.dst % 4) + 16;
+
+ emit32(ARMV8A::FEOR | dst | (dst << 5) | (31 << 16), code, codePos);
+}
+
+void JitCompilerA64::h_FMUL_R(Instruction& instr, uint32_t& codePos)
+{
+ const uint32_t src = (instr.src % 4) + 24;
+ const uint32_t dst = (instr.dst % 4) + 20;
+
+ emit32(ARMV8A::FMUL | dst | (dst << 5) | (src << 16), code, codePos);
+}
+
+void JitCompilerA64::h_FDIV_M(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = (instr.dst % 4) + 20;
+
+ constexpr uint32_t tmp_reg_fp = 28;
+ emitMemLoadFP(src, instr, code, k);
+
+ // and tmp_reg_fp, tmp_reg_fp, and_mask_reg
+ emit32(0x4E201C00 | tmp_reg_fp | (tmp_reg_fp << 5) | (29 << 16), code, k);
+
+ // orr tmp_reg_fp, tmp_reg_fp, or_mask_reg
+ emit32(0x4EA01C00 | tmp_reg_fp | (tmp_reg_fp << 5) | (30 << 16), code, k);
+
+ emit32(ARMV8A::FDIV | dst | (dst << 5) | (tmp_reg_fp << 16), code, k);
+
+ codePos = k;
+}
+
+void JitCompilerA64::h_FSQRT_R(Instruction& instr, uint32_t& codePos)
+{
+ const uint32_t dst = (instr.dst % 4) + 20;
+
+ emit32(ARMV8A::FSQRT | dst | (dst << 5), code, codePos);
+}
+
+void JitCompilerA64::h_CBRANCH(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t dst = IntRegMap[instr.dst];
+ const uint32_t modCond = instr.getModCond();
+ const uint32_t shift = modCond + RandomX_CurrentConfig.JumpOffset;
+ const uint32_t imm = (instr.getImm32() | (1U << shift)) & ~(1U << (shift - 1));
+
+ emitAddImmediate(dst, dst, imm, code, k);
+
+ // tst dst, mask
+ emit32((0xF2781C1F - (modCond << 16)) | (dst << 5), code, k);
+
+ int32_t offset = reg_changed_offset[instr.dst];
+ offset = ((offset - k) >> 2) & ((1 << 19) - 1);
+
+ // beq target
+ emit32(0x54000000 | (offset << 5), code, k);
+
+ for (uint32_t i = 0; i < RegistersCount; ++i)
+ reg_changed_offset[i] = k;
+
+ codePos = k;
+}
+
+void JitCompilerA64::h_CFROUND(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+
+ constexpr uint32_t tmp_reg = 18;
+ constexpr uint32_t fpcr_tmp_reg = 8;
+
+ // ror tmp_reg, src, imm
+ emit32(ARMV8A::ROR_IMM | tmp_reg | (src << 5) | ((instr.getImm32() & 63) << 10) | (src << 16), code, k);
+
+ // bfi fpcr_tmp_reg, tmp_reg, 40, 2
+ emit32(0xB3580400 | fpcr_tmp_reg | (tmp_reg << 5), code, k);
+
+ // rbit tmp_reg, fpcr_tmp_reg
+ emit32(0xDAC00000 | tmp_reg | (fpcr_tmp_reg << 5), code, k);
+
+ // msr fpcr, tmp_reg
+ emit32(0xD51B4400 | tmp_reg, code, k);
+
+ codePos = k;
+}
+
+void JitCompilerA64::h_ISTORE(Instruction& instr, uint32_t& codePos)
+{
+ uint32_t k = codePos;
+
+ const uint32_t src = IntRegMap[instr.src];
+ const uint32_t dst = IntRegMap[instr.dst];
+ constexpr uint32_t tmp_reg = 18;
+
+ uint32_t imm = instr.getImm32();
+
+ if (instr.getModCond() < StoreL3Condition)
+ imm &= instr.getModMem() ? (RandomX_CurrentConfig.ScratchpadL1_Size - 1) : (RandomX_CurrentConfig.ScratchpadL2_Size - 1);
+ else
+ imm &= RandomX_CurrentConfig.ScratchpadL3_Size - 1;
+
+ emitAddImmediate(tmp_reg, dst, imm, code, k);
+
+ constexpr uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
+ const uint32_t andInstrL1 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL1 - 4) << 10);
+ const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10);
+ const uint32_t andInstrL3 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 4) << 10);
+
+ emit32((instr.getModCond() < StoreL3Condition) ? (instr.getModMem() ? andInstrL1 : andInstrL2) : andInstrL3, code, k);
+
+ // str src, [x2, tmp_reg]
+ emit32(0xF8206840 | src | (tmp_reg << 16), code, k);
+
+ codePos = k;
+}
+
+void JitCompilerA64::h_NOP(Instruction& instr, uint32_t& codePos)
+{
+}
+
+InstructionGeneratorA64 JitCompilerA64::engine[256] = {};
+
+}
diff --git a/src/crypto/randomx/jit_compiler_a64.hpp b/src/crypto/randomx/jit_compiler_a64.hpp
index 4b0bed66..e524feb8 100644
--- a/src/crypto/randomx/jit_compiler_a64.hpp
+++ b/src/crypto/randomx/jit_compiler_a64.hpp
@@ -1,5 +1,6 @@
/*
Copyright (c) 2018-2019, tevador
+Copyright (c) 2019, SChernykh
All rights reserved.
@@ -32,42 +33,91 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include
#include
#include "crypto/randomx/common.hpp"
+#include "crypto/randomx/jit_compiler_a64_static.hpp"
namespace randomx {
class Program;
class ProgramConfiguration;
class SuperscalarProgram;
+ class Instruction;
+
+ typedef void(JitCompilerA64::*InstructionGeneratorA64)(Instruction&, uint32_t&);
class JitCompilerA64 {
public:
- JitCompilerA64() {
- throw std::runtime_error("ARM64 JIT compiler is not implemented yet.");
- }
- void generateProgram(Program&, ProgramConfiguration&) {
+ JitCompilerA64();
+ ~JitCompilerA64();
+
+ void generateProgram(Program&, ProgramConfiguration&);
+ void generateProgramLight(Program&, ProgramConfiguration&, uint32_t);
- }
- void generateProgramLight(Program&, ProgramConfiguration&, uint32_t) {
-
- }
template
- void generateSuperscalarHash(SuperscalarProgram(&programs)[N], std::vector &) {
+ void generateSuperscalarHash(SuperscalarProgram(&programs)[N], std::vector &);
- }
- void generateDatasetInitCode() {
+ void generateDatasetInitCode() {}
+ ProgramFunc* getProgramFunc() { return reinterpret_cast(code); }
+ DatasetInitFunc* getDatasetInitFunc();
+ uint8_t* getCode() { return code; }
+ size_t getCodeSize();
+
+ static InstructionGeneratorA64 engine[256];
+ uint32_t reg_changed_offset[8];
+ uint8_t* code;
+ uint32_t literalPos;
+ uint32_t num32bitLiterals;
+
+ static void emit32(uint32_t val, uint8_t* code, uint32_t& codePos)
+ {
+ *(uint32_t*)(code + codePos) = val;
+ codePos += sizeof(val);
}
- ProgramFunc* getProgramFunc() {
- return nullptr;
- }
- DatasetInitFunc* getDatasetInitFunc() {
- return nullptr;
- }
- uint8_t* getCode() {
- return nullptr;
- }
- size_t getCodeSize() {
- return 0;
+
+ static void emit64(uint64_t val, uint8_t* code, uint32_t& codePos)
+ {
+ *(uint64_t*)(code + codePos) = val;
+ codePos += sizeof(val);
}
+
+ void emitMovImmediate(uint32_t dst, uint32_t imm, uint8_t* code, uint32_t& codePos);
+ void emitAddImmediate(uint32_t dst, uint32_t src, uint32_t imm, uint8_t* code, uint32_t& codePos);
+
+ template
+ void emitMemLoad(uint32_t dst, uint32_t src, Instruction& instr, uint8_t* code, uint32_t& codePos);
+
+ template
+ void emitMemLoadFP(uint32_t src, Instruction& instr, uint8_t* code, uint32_t& codePos);
+
+ void h_IADD_RS(Instruction&, uint32_t&);
+ void h_IADD_M(Instruction&, uint32_t&);
+ void h_ISUB_R(Instruction&, uint32_t&);
+ void h_ISUB_M(Instruction&, uint32_t&);
+ void h_IMUL_R(Instruction&, uint32_t&);
+ void h_IMUL_M(Instruction&, uint32_t&);
+ void h_IMULH_R(Instruction&, uint32_t&);
+ void h_IMULH_M(Instruction&, uint32_t&);
+ void h_ISMULH_R(Instruction&, uint32_t&);
+ void h_ISMULH_M(Instruction&, uint32_t&);
+ void h_IMUL_RCP(Instruction&, uint32_t&);
+ void h_INEG_R(Instruction&, uint32_t&);
+ void h_IXOR_R(Instruction&, uint32_t&);
+ void h_IXOR_M(Instruction&, uint32_t&);
+ void h_IROR_R(Instruction&, uint32_t&);
+ void h_IROL_R(Instruction&, uint32_t&);
+ void h_ISWAP_R(Instruction&, uint32_t&);
+ void h_FSWAP_R(Instruction&, uint32_t&);
+ void h_FADD_R(Instruction&, uint32_t&);
+ void h_FADD_M(Instruction&, uint32_t&);
+ void h_FSUB_R(Instruction&, uint32_t&);
+ void h_FSUB_M(Instruction&, uint32_t&);
+ void h_FSCAL_R(Instruction&, uint32_t&);
+ void h_FMUL_R(Instruction&, uint32_t&);
+ void h_FDIV_M(Instruction&, uint32_t&);
+ void h_FSQRT_R(Instruction&, uint32_t&);
+ void h_CBRANCH(Instruction&, uint32_t&);
+ void h_CFROUND(Instruction&, uint32_t&);
+ void h_ISTORE(Instruction&, uint32_t&);
+ void h_NOP(Instruction&, uint32_t&);
};
}
diff --git a/src/crypto/randomx/jit_compiler_a64_static.S b/src/crypto/randomx/jit_compiler_a64_static.S
new file mode 100644
index 00000000..be37602b
--- /dev/null
+++ b/src/crypto/randomx/jit_compiler_a64_static.S
@@ -0,0 +1,577 @@
+# Copyright (c) 2018-2019, tevador
+# Copyright (c) 2019, SChernykh
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the copyright holder nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# 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.
+
+ .arch armv8-a
+ .text
+ .global randomx_program_aarch64
+ .global randomx_program_aarch64_main_loop
+ .global randomx_program_aarch64_vm_instructions
+ .global randomx_program_aarch64_imul_rcp_literals_end
+ .global randomx_program_aarch64_vm_instructions_end
+ .global randomx_program_aarch64_cacheline_align_mask1
+ .global randomx_program_aarch64_cacheline_align_mask2
+ .global randomx_program_aarch64_update_spMix1
+ .global randomx_program_aarch64_vm_instructions_end_light
+ .global randomx_program_aarch64_light_cacheline_align_mask
+ .global randomx_program_aarch64_light_dataset_offset
+ .global randomx_init_dataset_aarch64
+ .global randomx_init_dataset_aarch64_end
+ .global randomx_calc_dataset_item_aarch64
+ .global randomx_calc_dataset_item_aarch64_prefetch
+ .global randomx_calc_dataset_item_aarch64_mix
+ .global randomx_calc_dataset_item_aarch64_store_result
+ .global randomx_calc_dataset_item_aarch64_end
+
+# Register allocation
+
+# x0 -> pointer to reg buffer and then literal for IMUL_RCP
+# x1 -> pointer to mem buffer and then to dataset
+# x2 -> pointer to scratchpad
+# x3 -> loop counter
+# x4 -> "r0"
+# x5 -> "r1"
+# x6 -> "r2"
+# x7 -> "r3"
+# x8 -> fpcr (reversed bits)
+# x9 -> mx, ma
+# x10 -> spMix1
+# x11 -> literal for IMUL_RCP
+# x12 -> "r4"
+# x13 -> "r5"
+# x14 -> "r6"
+# x15 -> "r7"
+# x16 -> spAddr0
+# x17 -> spAddr1
+# x18 -> temporary
+# x19 -> temporary
+# x20 -> literal for IMUL_RCP
+# x21 -> literal for IMUL_RCP
+# x22 -> literal for IMUL_RCP
+# x23 -> literal for IMUL_RCP
+# x24 -> literal for IMUL_RCP
+# x25 -> literal for IMUL_RCP
+# x26 -> literal for IMUL_RCP
+# x27 -> literal for IMUL_RCP
+# x28 -> literal for IMUL_RCP
+# x29 -> literal for IMUL_RCP
+# x30 -> literal for IMUL_RCP
+
+# v0-v15 -> store 32-bit literals
+# v16 -> "f0"
+# v17 -> "f1"
+# v18 -> "f2"
+# v19 -> "f3"
+# v20 -> "e0"
+# v21 -> "e1"
+# v22 -> "e2"
+# v23 -> "e3"
+# v24 -> "a0"
+# v25 -> "a1"
+# v26 -> "a2"
+# v27 -> "a3"
+# v28 -> temporary
+# v29 -> E 'and' mask = 0x00ffffffffffffff00ffffffffffffff
+# v30 -> E 'or' mask = 0x3*00000000******3*00000000******
+# v31 -> scale mask = 0x81f000000000000081f0000000000000
+
+randomx_program_aarch64:
+ # Save callee-saved registers
+ sub sp, sp, 192
+ stp x16, x17, [sp]
+ stp x18, x19, [sp, 16]
+ stp x20, x21, [sp, 32]
+ stp x22, x23, [sp, 48]
+ stp x24, x25, [sp, 64]
+ stp x26, x27, [sp, 80]
+ stp x28, x29, [sp, 96]
+ stp x8, x30, [sp, 112]
+ stp d8, d9, [sp, 128]
+ stp d10, d11, [sp, 144]
+ stp d12, d13, [sp, 160]
+ stp d14, d15, [sp, 176]
+
+ # Zero integer registers
+ mov x4, xzr
+ mov x5, xzr
+ mov x6, xzr
+ mov x7, xzr
+ mov x12, xzr
+ mov x13, xzr
+ mov x14, xzr
+ mov x15, xzr
+
+ # Load ma, mx and dataset pointer
+ ldp x9, x1, [x1]
+
+ # Load initial spMix value
+ mov x10, x9
+
+ # Load group A registers
+ ldp q24, q25, [x0, 192]
+ ldp q26, q27, [x0, 224]
+
+ # Load E 'and' mask
+ mov x16, 0x00FFFFFFFFFFFFFF
+ ins v29.d[0], x16
+ ins v29.d[1], x16
+
+ # Load E 'or' mask (stored in reg.f[0])
+ ldr q30, [x0, 64]
+
+ # Load scale mask
+ mov x16, 0x80f0000000000000
+ ins v31.d[0], x16
+ ins v31.d[1], x16
+
+ # Read fpcr
+ mrs x8, fpcr
+ rbit x8, x8
+
+ # Save x0
+ str x0, [sp, -16]!
+
+ # Read literals
+ ldr x0, literal_x0
+ ldr x11, literal_x11
+ ldr x20, literal_x20
+ ldr x21, literal_x21
+ ldr x22, literal_x22
+ ldr x23, literal_x23
+ ldr x24, literal_x24
+ ldr x25, literal_x25
+ ldr x26, literal_x26
+ ldr x27, literal_x27
+ ldr x28, literal_x28
+ ldr x29, literal_x29
+ ldr x30, literal_x30
+
+ ldr q0, literal_v0
+ ldr q1, literal_v1
+ ldr q2, literal_v2
+ ldr q3, literal_v3
+ ldr q4, literal_v4
+ ldr q5, literal_v5
+ ldr q6, literal_v6
+ ldr q7, literal_v7
+ ldr q8, literal_v8
+ ldr q9, literal_v9
+ ldr q10, literal_v10
+ ldr q11, literal_v11
+ ldr q12, literal_v12
+ ldr q13, literal_v13
+ ldr q14, literal_v14
+ ldr q15, literal_v15
+
+randomx_program_aarch64_main_loop:
+ # spAddr0 = spMix1 & ScratchpadL3Mask64;
+ # spAddr1 = (spMix1 >> 32) & ScratchpadL3Mask64;
+ lsr x18, x10, 32
+
+ # Actual mask will be inserted by JIT compiler
+ and w16, w10, 1
+ and w17, w18, 1
+
+ # x16 = scratchpad + spAddr0
+ # x17 = scratchpad + spAddr1
+ add x16, x16, x2
+ add x17, x17, x2
+
+ # xor integer registers with scratchpad data (spAddr0)
+ ldp x18, x19, [x16]
+ eor x4, x4, x18
+ eor x5, x5, x19
+ ldp x18, x19, [x16, 16]
+ eor x6, x6, x18
+ eor x7, x7, x19
+ ldp x18, x19, [x16, 32]
+ eor x12, x12, x18
+ eor x13, x13, x19
+ ldp x18, x19, [x16, 48]
+ eor x14, x14, x18
+ eor x15, x15, x19
+
+ # Load group F registers (spAddr1)
+ ldpsw x18, x19, [x17]
+ ins v16.d[0], x18
+ ins v16.d[1], x19
+ ldpsw x18, x19, [x17, 8]
+ ins v17.d[0], x18
+ ins v17.d[1], x19
+ ldpsw x18, x19, [x17, 16]
+ ins v18.d[0], x18
+ ins v18.d[1], x19
+ ldpsw x18, x19, [x17, 24]
+ ins v19.d[0], x18
+ ins v19.d[1], x19
+ scvtf v16.2d, v16.2d
+ scvtf v17.2d, v17.2d
+ scvtf v18.2d, v18.2d
+ scvtf v19.2d, v19.2d
+
+ # Load group E registers (spAddr1)
+ ldpsw x18, x19, [x17, 32]
+ ins v20.d[0], x18
+ ins v20.d[1], x19
+ ldpsw x18, x19, [x17, 40]
+ ins v21.d[0], x18
+ ins v21.d[1], x19
+ ldpsw x18, x19, [x17, 48]
+ ins v22.d[0], x18
+ ins v22.d[1], x19
+ ldpsw x18, x19, [x17, 56]
+ ins v23.d[0], x18
+ ins v23.d[1], x19
+ scvtf v20.2d, v20.2d
+ scvtf v21.2d, v21.2d
+ scvtf v22.2d, v22.2d
+ scvtf v23.2d, v23.2d
+ and v20.16b, v20.16b, v29.16b
+ and v21.16b, v21.16b, v29.16b
+ and v22.16b, v22.16b, v29.16b
+ and v23.16b, v23.16b, v29.16b
+ orr v20.16b, v20.16b, v30.16b
+ orr v21.16b, v21.16b, v30.16b
+ orr v22.16b, v22.16b, v30.16b
+ orr v23.16b, v23.16b, v30.16b
+
+ # Execute VM instructions
+randomx_program_aarch64_vm_instructions:
+
+ # 16 KB buffer for generated instructions
+ .fill 4096,4,0
+
+literal_x0: .fill 1,8,0
+literal_x11: .fill 1,8,0
+literal_x20: .fill 1,8,0
+literal_x21: .fill 1,8,0
+literal_x22: .fill 1,8,0
+literal_x23: .fill 1,8,0
+literal_x24: .fill 1,8,0
+literal_x25: .fill 1,8,0
+literal_x26: .fill 1,8,0
+literal_x27: .fill 1,8,0
+literal_x28: .fill 1,8,0
+literal_x29: .fill 1,8,0
+literal_x30: .fill 1,8,0
+randomx_program_aarch64_imul_rcp_literals_end:
+
+literal_v0: .fill 2,8,0
+literal_v1: .fill 2,8,0
+literal_v2: .fill 2,8,0
+literal_v3: .fill 2,8,0
+literal_v4: .fill 2,8,0
+literal_v5: .fill 2,8,0
+literal_v6: .fill 2,8,0
+literal_v7: .fill 2,8,0
+literal_v8: .fill 2,8,0
+literal_v9: .fill 2,8,0
+literal_v10: .fill 2,8,0
+literal_v11: .fill 2,8,0
+literal_v12: .fill 2,8,0
+literal_v13: .fill 2,8,0
+literal_v14: .fill 2,8,0
+literal_v15: .fill 2,8,0
+
+randomx_program_aarch64_vm_instructions_end:
+
+ # mx ^= r[readReg2] ^ r[readReg3];
+ eor x9, x9, x18
+
+ # Calculate dataset pointer for dataset prefetch
+ mov w18, w9
+randomx_program_aarch64_cacheline_align_mask1:
+ # Actual mask will be inserted by JIT compiler
+ and x18, x18, 1
+ add x18, x18, x1
+
+ # Prefetch dataset data
+ prfm pldl2strm, [x18]
+
+ # mx <-> ma
+ ror x9, x9, 32
+
+ # Calculate dataset pointer for dataset read
+ mov w10, w9
+randomx_program_aarch64_cacheline_align_mask2:
+ # Actual mask will be inserted by JIT compiler
+ and x10, x10, 1
+ add x10, x10, x1
+
+randomx_program_aarch64_xor_with_dataset_line:
+ # xor integer registers with dataset data
+ ldp x18, x19, [x10]
+ eor x4, x4, x18
+ eor x5, x5, x19
+ ldp x18, x19, [x10, 16]
+ eor x6, x6, x18
+ eor x7, x7, x19
+ ldp x18, x19, [x10, 32]
+ eor x12, x12, x18
+ eor x13, x13, x19
+ ldp x18, x19, [x10, 48]
+ eor x14, x14, x18
+ eor x15, x15, x19
+
+randomx_program_aarch64_update_spMix1:
+ # JIT compiler will replace it with "eor x10, config.readReg0, config.readReg1"
+ eor x10, x0, x0
+
+ # Store integer registers to scratchpad (spAddr1)
+ stp x4, x5, [x17, 0]
+ stp x6, x7, [x17, 16]
+ stp x12, x13, [x17, 32]
+ stp x14, x15, [x17, 48]
+
+ # xor group F and group E registers
+ eor v16.16b, v16.16b, v20.16b
+ eor v17.16b, v17.16b, v21.16b
+ eor v18.16b, v18.16b, v22.16b
+ eor v19.16b, v19.16b, v23.16b
+
+ # Store FP registers to scratchpad (spAddr0)
+ stp q16, q17, [x16, 0]
+ stp q18, q19, [x16, 32]
+
+ subs x3, x3, 1
+ bne randomx_program_aarch64_main_loop
+
+ # Restore x0
+ ldr x0, [sp], 16
+
+ # Store integer registers
+ stp x4, x5, [x0, 0]
+ stp x6, x7, [x0, 16]
+ stp x12, x13, [x0, 32]
+ stp x14, x15, [x0, 48]
+
+ # Store FP registers
+ stp q16, q17, [x0, 64]
+ stp q18, q19, [x0, 96]
+ stp q20, q21, [x0, 128]
+ stp q22, q23, [x0, 160]
+
+ # Restore callee-saved registers
+ ldp x16, x17, [sp]
+ ldp x18, x19, [sp, 16]
+ ldp x20, x21, [sp, 32]
+ ldp x22, x23, [sp, 48]
+ ldp x24, x25, [sp, 64]
+ ldp x26, x27, [sp, 80]
+ ldp x28, x29, [sp, 96]
+ ldp x8, x30, [sp, 112]
+ ldp d8, d9, [sp, 128]
+ ldp d10, d11, [sp, 144]
+ ldp d12, d13, [sp, 160]
+ ldp d14, d15, [sp, 176]
+ add sp, sp, 192
+
+ ret
+
+randomx_program_aarch64_vm_instructions_end_light:
+ sub sp, sp, 96
+ stp x0, x1, [sp, 64]
+ stp x2, x30, [sp, 80]
+
+ # mx ^= r[readReg2] ^ r[readReg3];
+ eor x9, x9, x18
+
+ # mx <-> ma
+ ror x9, x9, 32
+
+ # x0 -> pointer to cache memory
+ mov x0, x1
+
+ # x1 -> pointer to output
+ mov x1, sp
+
+randomx_program_aarch64_light_cacheline_align_mask:
+ # Actual mask will be inserted by JIT compiler
+ and w2, w9, 1
+
+ # x2 -> item number
+ lsr x2, x2, 6
+
+randomx_program_aarch64_light_dataset_offset:
+ # Apply dataset offset (filled in by JIT compiler)
+ add x2, x2, 0
+ add x2, x2, 0
+
+ bl randomx_calc_dataset_item_aarch64
+
+ mov x10, sp
+ ldp x0, x1, [sp, 64]
+ ldp x2, x30, [sp, 80]
+ add sp, sp, 96
+
+ b randomx_program_aarch64_xor_with_dataset_line
+
+
+
+# Input parameters
+#
+# x0 -> pointer to cache
+# x1 -> pointer to dataset memory at startItem
+# x2 -> start item
+# x3 -> end item
+
+randomx_init_dataset_aarch64:
+ # Save x30 (return address)
+ str x30, [sp, -16]!
+
+ # Load pointer to cache memory
+ ldr x0, [x0]
+
+randomx_init_dataset_aarch64_main_loop:
+ bl randomx_calc_dataset_item_aarch64
+ add x1, x1, 64
+ add x2, x2, 1
+ cmp x2, x3
+ bne randomx_init_dataset_aarch64_main_loop
+
+ # Restore x30 (return address)
+ ldr x30, [sp], 16
+
+ ret
+
+randomx_init_dataset_aarch64_end:
+
+# Input parameters
+#
+# x0 -> pointer to cache memory
+# x1 -> pointer to output
+# x2 -> item number
+#
+# Register allocation
+#
+# x0-x7 -> output value (calculated dataset item)
+# x8 -> pointer to cache memory
+# x9 -> pointer to output
+# x10 -> registerValue
+# x11 -> mixBlock
+# x12 -> temporary
+# x13 -> temporary
+
+randomx_calc_dataset_item_aarch64:
+ sub sp, sp, 112
+ stp x0, x1, [sp]
+ stp x2, x3, [sp, 16]
+ stp x4, x5, [sp, 32]
+ stp x6, x7, [sp, 48]
+ stp x8, x9, [sp, 64]
+ stp x10, x11, [sp, 80]
+ stp x12, x13, [sp, 96]
+
+ ldr x12, superscalarMul0
+
+ mov x8, x0
+ mov x9, x1
+ mov x10, x2
+
+ # rl[0] = (itemNumber + 1) * superscalarMul0;
+ madd x0, x2, x12, x12
+
+ # rl[1] = rl[0] ^ superscalarAdd1;
+ ldr x12, superscalarAdd1
+ eor x1, x0, x12
+
+ # rl[2] = rl[0] ^ superscalarAdd2;
+ ldr x12, superscalarAdd2
+ eor x2, x0, x12
+
+ # rl[3] = rl[0] ^ superscalarAdd3;
+ ldr x12, superscalarAdd3
+ eor x3, x0, x12
+
+ # rl[4] = rl[0] ^ superscalarAdd4;
+ ldr x12, superscalarAdd4
+ eor x4, x0, x12
+
+ # rl[5] = rl[0] ^ superscalarAdd5;
+ ldr x12, superscalarAdd5
+ eor x5, x0, x12
+
+ # rl[6] = rl[0] ^ superscalarAdd6;
+ ldr x12, superscalarAdd6
+ eor x6, x0, x12
+
+ # rl[7] = rl[0] ^ superscalarAdd7;
+ ldr x12, superscalarAdd7
+ eor x7, x0, x12
+
+ b randomx_calc_dataset_item_aarch64_prefetch
+
+superscalarMul0: .quad 6364136223846793005
+superscalarAdd1: .quad 9298411001130361340
+superscalarAdd2: .quad 12065312585734608966
+superscalarAdd3: .quad 9306329213124626780
+superscalarAdd4: .quad 5281919268842080866
+superscalarAdd5: .quad 10536153434571861004
+superscalarAdd6: .quad 3398623926847679864
+superscalarAdd7: .quad 9549104520008361294
+
+# Prefetch -> SuperScalar hash -> Mix will be repeated N times
+
+randomx_calc_dataset_item_aarch64_prefetch:
+ # Actual mask will be inserted by JIT compiler
+ and x11, x10, 1
+ add x11, x8, x11, lsl 6
+ prfm pldl2strm, [x11]
+
+ # Generated SuperScalar hash program goes here
+
+randomx_calc_dataset_item_aarch64_mix:
+ ldp x12, x13, [x11]
+ eor x0, x0, x12
+ eor x1, x1, x13
+ ldp x12, x13, [x11, 16]
+ eor x2, x2, x12
+ eor x3, x3, x13
+ ldp x12, x13, [x11, 32]
+ eor x4, x4, x12
+ eor x5, x5, x13
+ ldp x12, x13, [x11, 48]
+ eor x6, x6, x12
+ eor x7, x7, x13
+
+randomx_calc_dataset_item_aarch64_store_result:
+ stp x0, x1, [x9]
+ stp x2, x3, [x9, 16]
+ stp x4, x5, [x9, 32]
+ stp x6, x7, [x9, 48]
+
+ ldp x0, x1, [sp]
+ ldp x2, x3, [sp, 16]
+ ldp x4, x5, [sp, 32]
+ ldp x6, x7, [sp, 48]
+ ldp x8, x9, [sp, 64]
+ ldp x10, x11, [sp, 80]
+ ldp x12, x13, [sp, 96]
+ add sp, sp, 112
+
+ ret
+
+randomx_calc_dataset_item_aarch64_end:
diff --git a/src/crypto/randomx/jit_compiler_a64_static.hpp b/src/crypto/randomx/jit_compiler_a64_static.hpp
new file mode 100644
index 00000000..a9b922e2
--- /dev/null
+++ b/src/crypto/randomx/jit_compiler_a64_static.hpp
@@ -0,0 +1,51 @@
+/*
+Copyright (c) 2018-2019, tevador
+Copyright (c) 2019, SChernykh
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+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.
+*/
+
+#pragma once
+
+extern "C" {
+ void randomx_program_aarch64(void* reg, void* mem, void* scratchpad, uint64_t iterations);
+ void randomx_program_aarch64_main_loop();
+ void randomx_program_aarch64_vm_instructions();
+ void randomx_program_aarch64_imul_rcp_literals_end();
+ void randomx_program_aarch64_vm_instructions_end();
+ void randomx_program_aarch64_cacheline_align_mask1();
+ void randomx_program_aarch64_cacheline_align_mask2();
+ void randomx_program_aarch64_update_spMix1();
+ void randomx_program_aarch64_vm_instructions_end_light();
+ void randomx_program_aarch64_light_cacheline_align_mask();
+ void randomx_program_aarch64_light_dataset_offset();
+ void randomx_init_dataset_aarch64();
+ void randomx_init_dataset_aarch64_end();
+ void randomx_calc_dataset_item_aarch64();
+ void randomx_calc_dataset_item_aarch64_prefetch();
+ void randomx_calc_dataset_item_aarch64_mix();
+ void randomx_calc_dataset_item_aarch64_store_result();
+ void randomx_calc_dataset_item_aarch64_end();
+}
diff --git a/src/crypto/randomx/randomx.cpp b/src/crypto/randomx/randomx.cpp
index 51680704..cab1be9f 100644
--- a/src/crypto/randomx/randomx.cpp
+++ b/src/crypto/randomx/randomx.cpp
@@ -26,6 +26,7 @@ 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 "crypto/randomx/common.hpp"
#include "crypto/randomx/randomx.h"
#include "crypto/randomx/dataset.hpp"
#include "crypto/randomx/vm_interpreted.hpp"
@@ -33,7 +34,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "crypto/randomx/vm_compiled.hpp"
#include "crypto/randomx/vm_compiled_light.hpp"
#include "crypto/randomx/blake2/blake2.h"
+
+#if defined(_M_X64) || defined(__x86_64__)
#include "crypto/randomx/jit_compiler_x86_static.hpp"
+#elif defined(XMRIG_ARM)
+#include "crypto/randomx/jit_compiler_a64_static.hpp"
+#endif
+
#include
RandomX_ConfigurationWownero::RandomX_ConfigurationWownero()
@@ -156,19 +163,10 @@ RandomX_ConfigurationBase::RandomX_ConfigurationBase()
#endif
}
+static uint32_t Log2(size_t value) { return (value > 1) ? (Log2(value / 2) + 1) : 0; }
+
void RandomX_ConfigurationBase::Apply()
{
-#if defined(_M_X64) || defined(__x86_64__)
- *(uint32_t*)(codeShhPrefetchTweaked + 3) = ArgonMemory * 16 - 1;
- const uint32_t DatasetBaseMask = DatasetBaseSize - RANDOMX_DATASET_ITEM_SIZE;
- *(uint32_t*)(codeReadDatasetTweaked + 7) = DatasetBaseMask;
- *(uint32_t*)(codeReadDatasetTweaked + 23) = DatasetBaseMask;
- *(uint32_t*)(codeReadDatasetLightSshInitTweaked + 59) = DatasetBaseMask;
-#endif
-
- CacheLineAlignMask_Calculated = (DatasetBaseSize - 1) & ~(RANDOMX_DATASET_ITEM_SIZE - 1);
- DatasetExtraItems_Calculated = DatasetExtraSize / RANDOMX_DATASET_ITEM_SIZE;
-
ScratchpadL1Mask_Calculated = (ScratchpadL1_Size / sizeof(uint64_t) - 1) * 8;
ScratchpadL1Mask16_Calculated = (ScratchpadL1_Size / sizeof(uint64_t) / 2 - 1) * 16;
ScratchpadL2Mask_Calculated = (ScratchpadL2_Size / sizeof(uint64_t) - 1) * 8;
@@ -176,22 +174,40 @@ void RandomX_ConfigurationBase::Apply()
ScratchpadL3Mask_Calculated = (((ScratchpadL3_Size / sizeof(uint64_t)) - 1) * 8);
ScratchpadL3Mask64_Calculated = ((ScratchpadL3_Size / sizeof(uint64_t)) / 8 - 1) * 64;
-#if defined(_M_X64) || defined(__x86_64__)
- *(uint32_t*)(codePrefetchScratchpadTweaked + 4) = ScratchpadL3Mask64_Calculated;
- *(uint32_t*)(codePrefetchScratchpadTweaked + 18) = ScratchpadL3Mask64_Calculated;
-#endif
+ CacheLineAlignMask_Calculated = (DatasetBaseSize - 1) & ~(RANDOMX_DATASET_ITEM_SIZE - 1);
+ DatasetExtraItems_Calculated = DatasetExtraSize / RANDOMX_DATASET_ITEM_SIZE;
ConditionMask_Calculated = (1 << JumpBits) - 1;
- constexpr int CEIL_NULL = 0;
- int k = 0;
-
#if defined(_M_X64) || defined(__x86_64__)
+ *(uint32_t*)(codeShhPrefetchTweaked + 3) = ArgonMemory * 16 - 1;
+ const uint32_t DatasetBaseMask = DatasetBaseSize - RANDOMX_DATASET_ITEM_SIZE;
+ *(uint32_t*)(codeReadDatasetTweaked + 7) = DatasetBaseMask;
+ *(uint32_t*)(codeReadDatasetTweaked + 23) = DatasetBaseMask;
+ *(uint32_t*)(codeReadDatasetLightSshInitTweaked + 59) = DatasetBaseMask;
+
+ *(uint32_t*)(codePrefetchScratchpadTweaked + 4) = ScratchpadL3Mask64_Calculated;
+ *(uint32_t*)(codePrefetchScratchpadTweaked + 18) = ScratchpadL3Mask64_Calculated;
+
#define JIT_HANDLE(x, prev) randomx::JitCompilerX86::engine[k] = &randomx::JitCompilerX86::h_##x
+
+#elif defined(XMRIG_ARM)
+
+ Log2_ScratchpadL1 = Log2(ScratchpadL1_Size);
+ Log2_ScratchpadL2 = Log2(ScratchpadL2_Size);
+ Log2_ScratchpadL3 = Log2(ScratchpadL3_Size);
+ Log2_DatasetBaseSize = Log2(DatasetBaseSize);
+ Log2_CacheSize = Log2((ArgonMemory * randomx::ArgonBlockSize) / randomx::CacheLineSize);
+
+#define JIT_HANDLE(x, prev) randomx::JitCompilerA64::engine[k] = &randomx::JitCompilerA64::h_##x
+
#else
#define JIT_HANDLE(x, prev)
#endif
+ constexpr int CEIL_NULL = 0;
+ int k = 0;
+
#define INST_HANDLE(x, prev) \
CEIL_##x = CEIL_##prev + RANDOMX_FREQ_##x; \
for (; k < CEIL_##x; ++k) { JIT_HANDLE(x, prev); }
@@ -435,12 +451,12 @@ extern "C" {
assert(inputSize == 0 || input != nullptr);
assert(output != nullptr);
alignas(16) uint64_t tempHash[8];
- rx_blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0);
+ rx_blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0);
machine->initScratchpad(&tempHash);
machine->resetRoundingMode();
for (uint32_t chain = 0; chain < RandomX_CurrentConfig.ProgramCount - 1; ++chain) {
machine->run(&tempHash);
- rx_blake2b(tempHash, sizeof(tempHash), machine->getRegisterFile(), sizeof(randomx::RegisterFile), nullptr, 0);
+ rx_blake2b(tempHash, sizeof(tempHash), machine->getRegisterFile(), sizeof(randomx::RegisterFile), nullptr, 0);
}
machine->run(&tempHash);
machine->getFinalResult(output, RANDOMX_HASH_SIZE);
diff --git a/src/crypto/randomx/randomx.h b/src/crypto/randomx/randomx.h
index 05b7bdc8..c69fb313 100644
--- a/src/crypto/randomx/randomx.h
+++ b/src/crypto/randomx/randomx.h
@@ -133,6 +133,14 @@ struct RandomX_ConfigurationBase
uint32_t ConditionMask_Calculated;
+#ifdef XMRIG_ARM
+ uint32_t Log2_ScratchpadL1;
+ uint32_t Log2_ScratchpadL2;
+ uint32_t Log2_ScratchpadL3;
+ uint32_t Log2_DatasetBaseSize;
+ uint32_t Log2_CacheSize;
+#endif
+
int CEIL_IADD_RS;
int CEIL_IADD_M;
int CEIL_ISUB_R;
diff --git a/src/crypto/randomx/virtual_machine.hpp b/src/crypto/randomx/virtual_machine.hpp
index 2dc89bb5..c85af009 100644
--- a/src/crypto/randomx/virtual_machine.hpp
+++ b/src/crypto/randomx/virtual_machine.hpp
@@ -64,7 +64,7 @@ protected:
alignas(64) randomx::RegisterFile reg;
alignas(16) randomx::ProgramConfiguration config;
randomx::MemoryRegisters mem;
- uint8_t* scratchpad;
+ uint8_t* scratchpad = nullptr;
union {
randomx_cache* cachePtr = nullptr;
randomx_dataset* datasetPtr;
diff --git a/src/crypto/randomx/vm_compiled.cpp b/src/crypto/randomx/vm_compiled.cpp
index f3b9758c..d2ee59e8 100644
--- a/src/crypto/randomx/vm_compiled.cpp
+++ b/src/crypto/randomx/vm_compiled.cpp
@@ -50,6 +50,9 @@ namespace randomx {
template
void CompiledVm::execute() {
+#ifdef XMRIG_ARM
+ memcpy(reg.f, config.eMask, sizeof(config.eMask));
+#endif
compiler.getProgramFunc()(reg, mem, scratchpad, RandomX_CurrentConfig.ProgramIterations);
}
diff --git a/src/crypto/rx/RxVm.cpp b/src/crypto/rx/RxVm.cpp
index 275f9558..6426443a 100644
--- a/src/crypto/rx/RxVm.cpp
+++ b/src/crypto/rx/RxVm.cpp
@@ -33,11 +33,9 @@
xmrig::RxVm::RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes)
{
-# ifndef XMRIG_ARM
if (!softAes) {
m_flags |= RANDOMX_FLAG_HARD_AES;
}
-# endif
if (dataset->get()) {
m_flags |= RANDOMX_FLAG_FULL_MEM;
diff --git a/src/net/Network.cpp b/src/net/Network.cpp
index 04b90715..2a472407 100644
--- a/src/net/Network.cpp
+++ b/src/net/Network.cpp
@@ -28,10 +28,10 @@
#endif
#include
-#include
+#include
+#include
#include
#include
-#include
#include "base/io/log/Log.h"
@@ -83,11 +83,7 @@ xmrig::Network::~Network()
JobResults::stop();
delete m_timer;
-
- if (m_donate) {
- delete m_donate;
- }
-
+ delete m_donate;
delete m_strategy;
}
@@ -312,8 +308,8 @@ void xmrig::Network::getResults(rapidjson::Value &reply, rapidjson::Document &do
results.AddMember("hashes_total", m_state.total, allocator);
Value best(kArrayType);
- for (size_t i = 0; i < m_state.topDiff.size(); ++i) {
- best.PushBack(m_state.topDiff[i], allocator);
+ for (uint64_t i : m_state.topDiff) {
+ best.PushBack(i, allocator);
}
results.AddMember("best", best, allocator);
diff --git a/src/net/Network.h b/src/net/Network.h
index 716ce610..7fd95e31 100644
--- a/src/net/Network.h
+++ b/src/net/Network.h
@@ -34,6 +34,7 @@
#include "base/kernel/interfaces/IBaseListener.h"
#include "base/kernel/interfaces/IStrategyListener.h"
#include "base/kernel/interfaces/ITimerListener.h"
+#include "base/tools/Object.h"
#include "interfaces/IJobResultListener.h"
#include "net/NetworkState.h"
#include "rapidjson/fwd.h"
@@ -49,6 +50,8 @@ class IStrategy;
class Network : public IJobResultListener, public IStrategyListener, public IBaseListener, public ITimerListener, public IApiListener
{
public:
+ XMRIG_DISABLE_COPY_MOVE_DEFAULT(Network)
+
Network(Controller *controller);
~Network() override;
diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp
index 3c6efd66..15100fcd 100644
--- a/src/net/strategies/DonateStrategy.cpp
+++ b/src/net/strategies/DonateStrategy.cpp
@@ -24,7 +24,7 @@
#include
-#include
+#include
#include
@@ -49,33 +49,28 @@ namespace xmrig {
static inline double randomf(double min, double max) { return (max - min) * (((static_cast(rand())) / static_cast(RAND_MAX))) + min; }
static inline uint64_t random(uint64_t base, double min, double max) { return static_cast(base * randomf(min, max)); }
+static const char *kDonateHost = "xmrig.moneroocean.stream";
+
} /* namespace xmrig */
xmrig::DonateStrategy::DonateStrategy(Controller *controller, IStrategyListener *listener) :
- m_tls(false),
- m_userId(),
m_donateTime(static_cast(controller->config()->pools().donateLevel()) * 60 * 1000),
m_idleTime((100 - static_cast(controller->config()->pools().donateLevel())) * 60 * 1000),
m_controller(controller),
- m_proxy(nullptr),
- m_strategy(nullptr),
- m_listener(listener),
- m_state(STATE_NEW),
- m_now(0),
- m_timestamp(0)
+ m_listener(listener)
{
static char donate_user[] = "44qJYxdbuqSKarYnDSXB6KLbsH4yR65vpJe3ELLDii9i4ZgKpgQXZYR4AMJxBJbfbKZGWUxZU42QyZSsP4AyZZMbJBCrWr1";
# ifndef XMRIG_FEATURE_TLS
- m_pools.push_back(Pool("xmrig.moneroocean.stream", 20001, donate_user, nullptr, 0, true, true));
+ m_pools.emplace_back(kDonateHost, 20001, donate_user, nullptr, 0, true, true);
# endif
- m_pools.push_back(Pool("xmrig.moneroocean.stream", 10001, donate_user, nullptr, 0, true));
+ m_pools.emplace_back(kDonateHost, 10001, donate_user, nullptr, 0, true);
if (m_pools.size() > 1) {
- m_strategy = new FailoverStrategy(m_pools, 1, 2, this, true);
+ m_strategy = new FailoverStrategy(m_pools, 10, 2, this, true);
}
else {
- m_strategy = new SinglePoolStrategy(m_pools.front(), 1, 2, this, true);
+ m_strategy = new SinglePoolStrategy(m_pools.front(), 10, 2, this, true);
}
m_timer = new Timer(this);
@@ -213,6 +208,18 @@ void xmrig::DonateStrategy::onLoginSuccess(IClient *client)
}
+void xmrig::DonateStrategy::onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok)
+{
+ m_listener->onVerifyAlgorithm(this, client, algorithm, ok);
+}
+
+
+void xmrig::DonateStrategy::onVerifyAlgorithm(IStrategy *, const IClient *client, const Algorithm &algorithm, bool *ok)
+{
+ m_listener->onVerifyAlgorithm(this, client, algorithm, ok);
+}
+
+
void xmrig::DonateStrategy::onTimer(const Timer *)
{
setState(isActive() ? STATE_WAIT : STATE_CONNECT);
@@ -236,7 +243,7 @@ xmrig::Client *xmrig::DonateStrategy::createProxy()
Pool pool(client->ip(), client->pool().port(), m_userId, client->pool().password(), 0, true, client->isTLS());
pool.setAlgo(client->pool().algorithm());
- Client *proxy = new Client(-1, Platform::userAgent(), this);
+ auto proxy = new Client(-1, Platform::userAgent(), this);
proxy->setPool(pool);
proxy->setQuiet(true);
diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h
index 134127bf..4c621f66 100644
--- a/src/net/strategies/DonateStrategy.h
+++ b/src/net/strategies/DonateStrategy.h
@@ -34,6 +34,7 @@
#include "base/kernel/interfaces/IStrategyListener.h"
#include "base/kernel/interfaces/ITimerListener.h"
#include "base/net/stratum/Pool.h"
+#include "base/tools/Object.h"
namespace xmrig {
@@ -47,6 +48,8 @@ class IStrategyListener;
class DonateStrategy : public IStrategy, public IStrategyListener, public ITimerListener, public IClientListener
{
public:
+ XMRIG_DISABLE_COPY_MOVE_DEFAULT(DonateStrategy)
+
DonateStrategy(Controller *controller, IStrategyListener *listener);
~DonateStrategy() override;
@@ -57,8 +60,6 @@ protected:
inline void onJobReceived(IClient *client, const Job &job, const rapidjson::Value &) override { setJob(client, job); }
inline void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); }
inline void onResultAccepted(IStrategy *, IClient *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); }
- inline void onVerifyAlgorithm(const IClient *, const Algorithm &, bool *) override {}
- inline void onVerifyAlgorithm(IStrategy *, const IClient *, const Algorithm &, bool *) override {}
inline void resume() override {}
int64_t submit(const JobResult &result) override;
@@ -74,6 +75,8 @@ protected:
void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override;
void onLogin(IStrategy *strategy, IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override;
void onLoginSuccess(IClient *client) override;
+ void onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok) override;
+ void onVerifyAlgorithm(IStrategy *strategy, const IClient *client, const Algorithm &algorithm, bool *ok) override;
void onTimer(const Timer *timer) override;
@@ -96,19 +99,19 @@ private:
void setState(State state);
Algorithm m_algorithm;
- bool m_tls;
- char m_userId[65];
+ bool m_tls = false;
+ char m_userId[65] = { 0 };
const uint64_t m_donateTime;
const uint64_t m_idleTime;
Controller *m_controller;
- IClient *m_proxy;
- IStrategy *m_strategy;
+ IClient *m_proxy = nullptr;
+ IStrategy *m_strategy = nullptr;
IStrategyListener *m_listener;
- State m_state;
+ State m_state = STATE_NEW;
std::vector m_pools;
- Timer *m_timer;
- uint64_t m_now;
- uint64_t m_timestamp;
+ Timer *m_timer = nullptr;
+ uint64_t m_now = 0;
+ uint64_t m_timestamp = 0;
};
diff --git a/src/version.h b/src/version.h
index f79b88b8..8816feaa 100644
--- a/src/version.h
+++ b/src/version.h
@@ -28,15 +28,15 @@
#define APP_ID "xmrig"
#define APP_NAME "XMRig"
#define APP_DESC "XMRig miner"
-#define APP_VERSION "4.0.1-beta-mo1"
+#define APP_VERSION "4.2.0-beta-mo1"
#define APP_DOMAIN "xmrig.com"
#define APP_SITE "www.xmrig.com"
#define APP_COPYRIGHT "Copyright (C) 2016-2019 xmrig.com"
#define APP_KIND "miner"
#define APP_VER_MAJOR 4
-#define APP_VER_MINOR 0
-#define APP_VER_PATCH 1
+#define APP_VER_MINOR 2
+#define APP_VER_PATCH 0
#ifdef _MSC_VER
# if (_MSC_VER >= 1920)