Merge branch 'dev'

This commit is contained in:
XMRig 2019-12-01 15:30:06 +07:00
commit 84ebf9d372
No known key found for this signature in database
GPG key ID: 446A53638BE94409
58 changed files with 623 additions and 157 deletions

View file

@ -63,6 +63,7 @@ CPU backend:
--asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer --asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer
--randomx-init=N threads count to initialize RandomX dataset --randomx-init=N threads count to initialize RandomX dataset
--randomx-no-numa disable NUMA support for RandomX --randomx-no-numa disable NUMA support for RandomX
--randomx-mode=MODE RandomX mode: auto, fast, light
API: API:
--api-worker-id=ID custom worker-id for API --api-worker-id=ID custom worker-id for API

View file

@ -1,5 +1,5 @@
# CMake options # CMake options
This document contains list of useful cmake options. **Recent version of this document: https://xmrig.com/docs/miner/cmake-options**
## Algorithms ## Algorithms

View file

@ -33,6 +33,7 @@
#include "base/io/Console.h" #include "base/io/Console.h"
#include "base/io/log/Log.h" #include "base/io/log/Log.h"
#include "base/kernel/Signals.h" #include "base/kernel/Signals.h"
#include "base/kernel/Platform.h"
#include "core/config/Config.h" #include "core/config/Config.h"
#include "core/Controller.h" #include "core/Controller.h"
#include "core/Miner.h" #include "core/Miner.h"
@ -89,6 +90,8 @@ int xmrig::App::exec()
m_controller->start(); m_controller->start();
Platform::setThreadPriority(5);
rc = uv_run(uv_default_loop(), UV_RUN_DEFAULT); rc = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
uv_loop_close(uv_default_loop()); uv_loop_close(uv_default_loop());

View file

@ -102,6 +102,23 @@ static void print_cpu(Config *)
} }
static void print_memory()
{
constexpr size_t oneGiB = 1024U * 1024U * 1024U;
const auto freeMem = static_cast<double>(uv_get_free_memory());
const auto totalMem = static_cast<double>(uv_get_total_memory());
const double percent = freeMem > 0 ? ((totalMem - freeMem) / totalMem * 100.0) : 100.0;
Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%.1f/%.1f GB") BLACK_BOLD(" (%.0f%%)"),
"MEMORY",
(totalMem - freeMem) / oneGiB,
totalMem / oneGiB,
percent
);
}
static void print_threads(Config *config) static void print_threads(Config *config)
{ {
Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s%d%%"), Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s%d%%"),
@ -144,6 +161,7 @@ void xmrig::Summary::print(Controller *controller)
controller->config()->printVersions(); controller->config()->printVersions();
print_memory(controller->config()); print_memory(controller->config());
print_cpu(controller->config()); print_cpu(controller->config());
print_memory();
print_threads(controller->config()); print_threads(controller->config());
controller->config()->pools().print(); controller->config()->pools().print();

View file

@ -109,6 +109,11 @@ void xmrig::Workers<T>::start(const std::vector<T> &data)
for (Thread<T> *worker : m_workers) { for (Thread<T> *worker : m_workers) {
worker->start(Workers<T>::onReady); worker->start(Workers<T>::onReady);
// This sleep is important for optimal caching!
// Threads must allocate scratchpads in order so that adjacent cores will use adjacent scratchpads
// Sub-optimal caching can result in up to 0.5% hashrate penalty
std::this_thread::sleep_for(std::chrono::milliseconds(20));
} }
} }
@ -163,7 +168,7 @@ void xmrig::Workers<T>::onReady(void *arg)
assert(worker != nullptr); assert(worker != nullptr);
if (!worker || !worker->selfTest()) { if (!worker || !worker->selfTest()) {
LOG_ERR("%s " RED("thread ") RED_BOLD("#%zu") RED(" self-test failed"), T::tag(), worker->id()); LOG_ERR("%s " RED("thread ") RED_BOLD("#%zu") RED(" self-test failed"), T::tag(), worker ? worker->id() : 0);
handle->backend()->start(worker, false); handle->backend()->start(worker, false);
delete worker; delete worker;

View file

@ -24,6 +24,9 @@
#define XMRIG_IRXSTORAGE_H #define XMRIG_IRXSTORAGE_H
#include "crypto/rx/RxConfig.h"
#include <cstdint> #include <cstdint>
#include <utility> #include <utility>
@ -43,7 +46,7 @@ public:
virtual RxDataset *dataset(const Job &job, uint32_t nodeId) const = 0; virtual RxDataset *dataset(const Job &job, uint32_t nodeId) const = 0;
virtual std::pair<uint32_t, uint32_t> hugePages() const = 0; virtual std::pair<uint32_t, uint32_t> hugePages() const = 0;
virtual void init(const RxSeed &seed, uint32_t threads, bool hugePages) = 0; virtual void init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode mode) = 0;
}; };

View file

@ -185,8 +185,20 @@ void xmrig::CpuWorker<N>::start()
consumeJob(); consumeJob();
} }
uint64_t storeStatsMask = 7;
# ifdef XMRIG_ALGO_RANDOMX
bool first = true;
uint64_t tempHash[8] = {};
// RandomX is faster, we don't need to store stats so often
if (m_job.currentJob().algorithm().family() == Algorithm::RANDOM_X) {
storeStatsMask = 63;
}
# endif
while (!Nonce::isOutdated(Nonce::CPU, m_job.sequence())) { while (!Nonce::isOutdated(Nonce::CPU, m_job.sequence())) {
if ((m_count & 0x7) == 0) { if ((m_count & storeStatsMask) == 0) {
storeStats(); storeStats();
} }
@ -196,26 +208,34 @@ void xmrig::CpuWorker<N>::start()
break; break;
} }
uint32_t current_job_nonces[N];
for (size_t i = 0; i < N; ++i) {
current_job_nonces[i] = *m_job.nonce(i);
}
# ifdef XMRIG_ALGO_RANDOMX # ifdef XMRIG_ALGO_RANDOMX
if (job.algorithm().family() == Algorithm::RANDOM_X) { if (job.algorithm().family() == Algorithm::RANDOM_X) {
randomx_calculate_hash(m_vm->get(), m_job.blob(), job.size(), m_hash); if (first) {
first = false;
randomx_calculate_hash_first(m_vm->get(), tempHash, m_job.blob(), job.size());
}
m_job.nextRound(kReserveCount, 1);
randomx_calculate_hash_next(m_vm->get(), tempHash, m_job.blob(), job.size(), m_hash);
} }
else else
# endif # endif
{ {
fn(job.algorithm())(m_job.blob(), job.size(), m_hash, m_ctx, job.height()); fn(job.algorithm())(m_job.blob(), job.size(), m_hash, m_ctx, job.height());
m_job.nextRound(kReserveCount, 1);
} }
for (size_t i = 0; i < N; ++i) { for (size_t i = 0; i < N; ++i) {
if (*reinterpret_cast<uint64_t*>(m_hash + (i * 32) + 24) < job.target()) { if (*reinterpret_cast<uint64_t*>(m_hash + (i * 32) + 24) < job.target()) {
JobResults::submit(job, *m_job.nonce(i), m_hash + (i * 32)); JobResults::submit(job, current_job_nonces[i], m_hash + (i * 32));
} }
} }
m_job.nextRound(kReserveCount, 1);
m_count += N; m_count += N;
std::this_thread::yield();
} }
consumeJob(); consumeJob();

View file

@ -64,7 +64,7 @@ namespace xmrig {
extern template class Threads<CudaThreads>; extern template class Threads<CudaThreads>;
constexpr const size_t oneMiB = 1024u * 1024u; constexpr const size_t oneMiB = 1024U * 1024U;
static const char *kLabel = "CUDA"; static const char *kLabel = "CUDA";
static const char *tag = GREEN_BG_BOLD(WHITE_BOLD_S " nv "); static const char *tag = GREEN_BG_BOLD(WHITE_BOLD_S " nv ");
static const String kType = "cuda"; static const String kType = "cuda";
@ -249,7 +249,7 @@ public:
std::string fans; std::string fans;
if (!health.fanSpeed.empty()) { if (!health.fanSpeed.empty()) {
for (uint32_t i = 0; i < health.fanSpeed.size(); ++i) { for (size_t i = 0; i < health.fanSpeed.size(); ++i) {
fans += " fan" + std::to_string(i) + ":" CYAN_BOLD_S + std::to_string(health.fanSpeed[i]) + "%" CLEAR; fans += " fan" + std::to_string(i) + ":" CYAN_BOLD_S + std::to_string(health.fanSpeed[i]) + "%" CLEAR;
} }
} }

View file

@ -58,7 +58,7 @@ namespace xmrig {
extern template class Threads<OclThreads>; extern template class Threads<OclThreads>;
constexpr const size_t oneMiB = 1024u * 1024u; constexpr const size_t oneMiB = 1024U * 1024U;
static const char *tag = MAGENTA_BG_BOLD(WHITE_BOLD_S " ocl "); static const char *tag = MAGENTA_BG_BOLD(WHITE_BOLD_S " ocl ");
static const String kType = "opencl"; static const String kType = "opencl";
static std::mutex mutex; static std::mutex mutex;

View file

@ -49,12 +49,48 @@
#endif #endif
#include <thread>
namespace xmrig {
static rapidjson::Value getResources(rapidjson::Document &doc)
{
using namespace rapidjson;
auto &allocator = doc.GetAllocator();
size_t rss = 0;
uv_resident_set_memory(&rss);
Value out(kObjectType);
Value memory(kObjectType);
Value load_average(kArrayType);
memory.AddMember("free", uv_get_free_memory(), allocator);
memory.AddMember("total", uv_get_total_memory(), allocator);
memory.AddMember("resident_set_memory", static_cast<uint64_t>(rss), allocator);
double loadavg[3] = { 0.0 };
uv_loadavg(loadavg);
load_average.PushBack(loadavg[0], allocator);
load_average.PushBack(loadavg[1], allocator);
load_average.PushBack(loadavg[2], allocator);
out.AddMember("memory", memory, allocator);
out.AddMember("load_average", load_average, allocator);
out.AddMember("hardware_concurrency", std::thread::hardware_concurrency(), allocator);
return out;
}
} // namespace xmrig
xmrig::Api::Api(Base *base) : xmrig::Api::Api(Base *base) :
m_base(base), m_base(base),
m_id(), m_timestamp(Chrono::currentMSecsSinceEpoch())
m_workerId(),
m_timestamp(Chrono::currentMSecsSinceEpoch()),
m_httpd(nullptr)
{ {
base->addListener(this); base->addListener(this);
@ -117,10 +153,13 @@ void xmrig::Api::exec(IApiRequest &request)
auto &allocator = request.doc().GetAllocator(); auto &allocator = request.doc().GetAllocator();
request.accept(); request.accept();
request.reply().AddMember("id", StringRef(m_id), allocator);
request.reply().AddMember("worker_id", StringRef(m_workerId), allocator); auto &reply = request.reply();
request.reply().AddMember("uptime", (Chrono::currentMSecsSinceEpoch() - m_timestamp) / 1000, allocator); reply.AddMember("id", StringRef(m_id), allocator);
request.reply().AddMember("restricted", request.isRestricted(), allocator); reply.AddMember("worker_id", StringRef(m_workerId), allocator);
reply.AddMember("uptime", (Chrono::currentMSecsSinceEpoch() - m_timestamp) / 1000, allocator);
reply.AddMember("restricted", request.isRestricted(), allocator);
reply.AddMember("resources", getResources(request.doc()), allocator);
Value features(kArrayType); Value features(kArrayType);
# ifdef XMRIG_FEATURE_API # ifdef XMRIG_FEATURE_API
@ -144,7 +183,7 @@ void xmrig::Api::exec(IApiRequest &request)
# ifdef XMRIG_FEATURE_OPENCL # ifdef XMRIG_FEATURE_OPENCL
features.PushBack("opencl", allocator); features.PushBack("opencl", allocator);
# endif # endif
request.reply().AddMember("features", features, allocator); reply.AddMember("features", features, allocator);
} }
for (IApiListener *listener : m_listeners) { for (IApiListener *listener : m_listeners) {
@ -179,13 +218,13 @@ void xmrig::Api::genId(const String &id)
if (!interfaces[i].is_internal && interfaces[i].address.address4.sin_family == AF_INET) { if (!interfaces[i].is_internal && interfaces[i].address.address4.sin_family == AF_INET) {
uint8_t hash[200]; uint8_t hash[200];
const size_t addrSize = sizeof(interfaces[i].phys_addr); const size_t addrSize = sizeof(interfaces[i].phys_addr);
const size_t inSize = strlen(APP_KIND) + addrSize + sizeof(uint16_t); const size_t inSize = (sizeof(APP_KIND) - 1) + addrSize + sizeof(uint16_t);
const uint16_t port = static_cast<uint16_t>(m_base->config()->http().port()); const auto port = static_cast<uint16_t>(m_base->config()->http().port());
uint8_t *input = new uint8_t[inSize](); auto*input = new uint8_t[inSize]();
memcpy(input, &port, sizeof(uint16_t)); memcpy(input, &port, sizeof(uint16_t));
memcpy(input + sizeof(uint16_t), interfaces[i].phys_addr, addrSize); memcpy(input + sizeof(uint16_t), interfaces[i].phys_addr, addrSize);
memcpy(input + sizeof(uint16_t) + addrSize, APP_KIND, strlen(APP_KIND)); memcpy(input + sizeof(uint16_t) + addrSize, APP_KIND, (sizeof(APP_KIND) - 1));
keccak(input, inSize, hash); keccak(input, inSize, hash);
Buffer::toHex(hash, 8, m_id); Buffer::toHex(hash, 8, m_id);

View file

@ -70,10 +70,10 @@ private:
void genWorkerId(const String &id); void genWorkerId(const String &id);
Base *m_base; Base *m_base;
char m_id[32]; char m_id[32]{};
char m_workerId[128]; char m_workerId[128]{};
const uint64_t m_timestamp; const uint64_t m_timestamp;
Httpd *m_httpd; Httpd *m_httpd = nullptr;
std::vector<IApiListener *> m_listeners; std::vector<IApiListener *> m_listeners;
}; };

View file

@ -23,9 +23,9 @@
*/ */
#include "base/api/Httpd.h"
#include "3rdparty/http-parser/http_parser.h" #include "3rdparty/http-parser/http_parser.h"
#include "base/api/Api.h" #include "base/api/Api.h"
#include "base/api/Httpd.h"
#include "base/io/log/Log.h" #include "base/io/log/Log.h"
#include "base/net/http/HttpApiResponse.h" #include "base/net/http/HttpApiResponse.h"
#include "base/net/http/HttpData.h" #include "base/net/http/HttpData.h"
@ -58,9 +58,7 @@ xmrig::Httpd::Httpd(Base *base) :
} }
xmrig::Httpd::~Httpd() xmrig::Httpd::~Httpd() = default;
{
}
bool xmrig::Httpd::start() bool xmrig::Httpd::start()

View file

@ -26,11 +26,12 @@
#define XMRIG_HTTPD_H #define XMRIG_HTTPD_H
#include <stdint.h> #include <cstdint>
#include "base/kernel/interfaces/IBaseListener.h" #include "base/kernel/interfaces/IBaseListener.h"
#include "base/kernel/interfaces/IHttpListener.h" #include "base/kernel/interfaces/IHttpListener.h"
#include "base/tools/Object.h"
namespace xmrig { namespace xmrig {
@ -44,6 +45,8 @@ class TcpServer;
class Httpd : public IBaseListener, public IHttpListener class Httpd : public IBaseListener, public IHttpListener
{ {
public: public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(Httpd)
Httpd(Base *base); Httpd(Base *base);
~Httpd() override; ~Httpd() override;

View file

@ -33,6 +33,4 @@ xmrig::ApiRequest::ApiRequest(Source source, bool restricted) :
} }
xmrig::ApiRequest::~ApiRequest() xmrig::ApiRequest::~ApiRequest() = default;
{
}

View file

@ -29,6 +29,7 @@
#include "base/api/interfaces/IApiRequest.h" #include "base/api/interfaces/IApiRequest.h"
#include "base/tools/String.h" #include "base/tools/String.h"
#include "base/tools/Object.h"
namespace xmrig { namespace xmrig {
@ -37,6 +38,8 @@ namespace xmrig {
class ApiRequest : public IApiRequest class ApiRequest : public IApiRequest
{ {
public: public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(ApiRequest)
ApiRequest(Source source, bool restricted); ApiRequest(Source source, bool restricted);
~ApiRequest() override; ~ApiRequest() override;
@ -63,8 +66,8 @@ protected:
String m_rpcMethod; String m_rpcMethod;
private: private:
bool m_restricted; const bool m_restricted;
Source m_source; const Source m_source;
}; };

View file

@ -63,11 +63,6 @@
#include "version.h" #include "version.h"
xmrig::BaseConfig::BaseConfig()
{
}
void xmrig::BaseConfig::printVersions() void xmrig::BaseConfig::printVersions()
{ {
char buf[256] = { 0 }; char buf[256] = { 0 };

View file

@ -31,9 +31,6 @@
#include "base/net/stratum/Pools.h" #include "base/net/stratum/Pools.h"
struct option;
namespace xmrig { namespace xmrig {
@ -43,7 +40,7 @@ class IJsonReader;
class BaseConfig : public IConfig class BaseConfig : public IConfig
{ {
public: public:
BaseConfig(); BaseConfig() = default;
inline bool isAutoSave() const { return m_autoSave; } inline bool isAutoSave() const { return m_autoSave; }
inline bool isBackground() const { return m_background; } inline bool isBackground() const { return m_background; }

View file

@ -89,6 +89,7 @@ public:
AssemblyKey = 1015, AssemblyKey = 1015,
RandomXInitKey = 1022, RandomXInitKey = 1022,
RandomXNumaKey = 1023, RandomXNumaKey = 1023,
RandomXModeKey = 1029,
CPUMaxThreadsKey = 1026, CPUMaxThreadsKey = 1026,
MemoryPoolKey = 1027, MemoryPoolKey = 1027,
@ -125,6 +126,7 @@ public:
TlsProtocolsKey = 1114, TlsProtocolsKey = 1114,
AlgoExtKey = 1115, AlgoExtKey = 1115,
ProxyPasswordKey = 1116, ProxyPasswordKey = 1116,
LoginFileKey = 'L',
// xmrig nvidia // xmrig nvidia
CudaMaxThreadsKey = 1200, CudaMaxThreadsKey = 1200,

View file

@ -26,7 +26,7 @@
#define XMRIG_ISTRATEGY_H #define XMRIG_ISTRATEGY_H
#include <stdint.h> #include <cstdint>
namespace xmrig { namespace xmrig {

View file

@ -23,9 +23,9 @@
*/ */
#include "base/net/http/Http.h"
#include "3rdparty/rapidjson/document.h" #include "3rdparty/rapidjson/document.h"
#include "base/io/json/Json.h" #include "base/io/json/Json.h"
#include "base/net/http/Http.h"
namespace xmrig { namespace xmrig {
@ -41,10 +41,7 @@ static const char *kToken = "access-token";
xmrig::Http::Http() : xmrig::Http::Http() :
m_enabled(false), m_host(kLocalhost)
m_restricted(true),
m_host(kLocalhost),
m_port(0)
{ {
} }

View file

@ -38,7 +38,7 @@ class Http
public: public:
Http(); Http();
inline bool isAuthRequired() const { return m_restricted == false || !m_token.isNull(); } inline bool isAuthRequired() const { return !m_restricted || !m_token.isNull(); }
inline bool isEnabled() const { return m_enabled; } inline bool isEnabled() const { return m_enabled; }
inline bool isRestricted() const { return m_restricted; } inline bool isRestricted() const { return m_restricted; }
inline const String &host() const { return m_host; } inline const String &host() const { return m_host; }
@ -58,11 +58,11 @@ public:
void setPort(int port); void setPort(int port);
private: private:
bool m_enabled; bool m_enabled = false;
bool m_restricted; bool m_restricted = true;
String m_host; String m_host;
String m_token; String m_token;
uint16_t m_port; uint16_t m_port = 0;
}; };

View file

@ -66,7 +66,7 @@ public:
inline static void onWrite(uv_write_t *req, int) { delete reinterpret_cast<ClientWriteBaton *>(req->data); } inline static void onWrite(uv_write_t *req, int) { delete reinterpret_cast<ClientWriteBaton *>(req->data); }
uv_buf_t bufs[2]; uv_buf_t bufs[2]{};
private: private:
std::string m_body; std::string m_body;

View file

@ -24,27 +24,30 @@
*/ */
#include "base/net/http/HttpContext.h"
#include "3rdparty/http-parser/http_parser.h"
#include "base/kernel/interfaces/IHttpListener.h"
#include "base/tools/Chrono.h"
#include <algorithm> #include <algorithm>
#include <uv.h> #include <uv.h>
#include "3rdparty/http-parser/http_parser.h"
#include "base/kernel/interfaces/IHttpListener.h"
#include "base/net/http/HttpContext.h"
namespace xmrig { namespace xmrig {
static http_parser_settings http_settings; static http_parser_settings http_settings;
static std::map<uint64_t, HttpContext *> storage; static std::map<uint64_t, HttpContext *> storage;
static uint64_t SEQUENCE = 0; static uint64_t SEQUENCE = 0;
} // namespace xmrig } // namespace xmrig
xmrig::HttpContext::HttpContext(int parser_type, IHttpListener *listener) : xmrig::HttpContext::HttpContext(int parser_type, IHttpListener *listener) :
HttpData(SEQUENCE++), HttpData(SEQUENCE++),
m_wasHeaderValue(false), m_timestamp(Chrono::steadyMSecs()),
m_listener(listener) m_listener(listener)
{ {
storage[id()] = this; storage[id()] = this;
@ -96,6 +99,12 @@ std::string xmrig::HttpContext::ip() const
} }
uint64_t xmrig::HttpContext::elapsed() const
{
return Chrono::steadyMSecs() - m_timestamp;
}
void xmrig::HttpContext::close(int status) void xmrig::HttpContext::close(int status)
{ {
if (status < 0 && m_listener) { if (status < 0 && m_listener) {

View file

@ -59,6 +59,7 @@ public:
size_t parse(const char *data, size_t size); size_t parse(const char *data, size_t size);
std::string ip() const; std::string ip() const;
uint64_t elapsed() const;
void close(int status = 0); void close(int status = 0);
static HttpContext *get(uint64_t id); static HttpContext *get(uint64_t id);
@ -74,7 +75,8 @@ private:
void setHeader(); void setHeader();
bool m_wasHeaderValue; bool m_wasHeaderValue = false;
const uint64_t m_timestamp;
http_parser *m_parser; http_parser *m_parser;
IHttpListener *m_listener; IHttpListener *m_listener;
std::string m_lastHeaderField; std::string m_lastHeaderField;

View file

@ -38,12 +38,12 @@ namespace xmrig {
class HttpData class HttpData
{ {
public: public:
inline HttpData(uint64_t id) : method(0), status(0), m_id(id) {} inline HttpData(uint64_t id) : m_id(id) {}
inline uint64_t id() const { return m_id; } inline uint64_t id() const { return m_id; }
int method; int method = 0;
int status; int status = 0;
std::map<const std::string, const std::string> headers; std::map<const std::string, const std::string> headers;
std::string body; std::string body;
std::string url; std::string url;

View file

@ -24,20 +24,23 @@
*/ */
#include <sstream> #include "base/net/http/HttpResponse.h"
#include <string.h>
#include <uv.h>
#include "3rdparty/http-parser/http_parser.h" #include "3rdparty/http-parser/http_parser.h"
#include "base/io/log/Log.h" #include "base/io/log/Log.h"
#include "base/net/http/HttpContext.h" #include "base/net/http/HttpContext.h"
#include "base/net/http/HttpResponse.h"
#include "base/tools/Baton.h" #include "base/tools/Baton.h"
#include "base/tools/Object.h"
#include <cinttypes>
#include <cstring>
#include <sstream>
#include <uv.h>
namespace xmrig { namespace xmrig {
static const char *kCRLF = "\r\n"; static const char *kCRLF = "\r\n";
static const char *kUserAgent = "user-agent"; static const char *kUserAgent = "user-agent";
@ -45,6 +48,8 @@ static const char *kUserAgent = "user-agent";
class WriteBaton : public Baton<uv_write_t> class WriteBaton : public Baton<uv_write_t>
{ {
public: public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(WriteBaton)
inline WriteBaton(const std::stringstream &ss, const char *data, size_t size, HttpContext *ctx) : inline WriteBaton(const std::stringstream &ss, const char *data, size_t size, HttpContext *ctx) :
m_ctx(ctx), m_ctx(ctx),
m_header(ss.str()) m_header(ss.str())
@ -79,7 +84,7 @@ public:
inline static void onWrite(uv_write_t *req, int) { delete reinterpret_cast<WriteBaton *>(req->data); } inline static void onWrite(uv_write_t *req, int) { delete reinterpret_cast<WriteBaton *>(req->data); }
uv_buf_t bufs[2]; uv_buf_t bufs[2]{};
private: private:
HttpContext *m_ctx; HttpContext *m_ctx;
@ -98,7 +103,7 @@ xmrig::HttpResponse::HttpResponse(uint64_t id, int statusCode) :
bool xmrig::HttpResponse::isAlive() const bool xmrig::HttpResponse::isAlive() const
{ {
HttpContext *ctx = HttpContext::get(m_id); auto ctx = HttpContext::get(m_id);
return ctx && uv_is_writable(ctx->stream()); return ctx && uv_is_writable(ctx->stream());
} }
@ -129,8 +134,8 @@ void xmrig::HttpResponse::end(const char *data, size_t size)
ss << kCRLF; ss << kCRLF;
HttpContext *ctx = HttpContext::get(m_id); auto ctx = HttpContext::get(m_id);
WriteBaton *baton = new WriteBaton(ss, data, size, ctx); auto baton = new WriteBaton(ss, data, size, ctx);
# ifndef APP_DEBUG # ifndef APP_DEBUG
if (statusCode() >= 400) if (statusCode() >= 400)
@ -138,13 +143,14 @@ void xmrig::HttpResponse::end(const char *data, size_t size)
{ {
const bool err = statusCode() >= 400; const bool err = statusCode() >= 400;
Log::print(err ? Log::ERR : Log::INFO, CYAN("%s ") CLEAR MAGENTA_BOLD("%s") WHITE_BOLD(" %s ") CSI "1;%dm%d " CLEAR WHITE_BOLD("%zu ") BLACK_BOLD("\"%s\""), Log::print(err ? Log::ERR : Log::INFO, CYAN("%s ") CLEAR MAGENTA_BOLD("%s") WHITE_BOLD(" %s ") CSI "1;%dm%d " CLEAR WHITE_BOLD("%zu ") CYAN_BOLD("%" PRIu64 "ms ") BLACK_BOLD("\"%s\""),
ctx->ip().c_str(), ctx->ip().c_str(),
http_method_str(static_cast<http_method>(ctx->method)), http_method_str(static_cast<http_method>(ctx->method)),
ctx->url.c_str(), ctx->url.c_str(),
err ? 31 : 32, err ? 31 : 32,
statusCode(), statusCode(),
baton->size(), baton->size(),
ctx->elapsed(),
ctx->headers.count(kUserAgent) ? ctx->headers.at(kUserAgent).c_str() : nullptr ctx->headers.count(kUserAgent) ? ctx->headers.at(kUserAgent).c_str() : nullptr
); );
} }

View file

@ -49,7 +49,7 @@ xmrig::HttpServer::~HttpServer()
void xmrig::HttpServer::onConnection(uv_stream_t *stream, uint16_t) void xmrig::HttpServer::onConnection(uv_stream_t *stream, uint16_t)
{ {
HttpContext *ctx = new HttpContext(HTTP_REQUEST, m_listener); auto ctx = new HttpContext(HTTP_REQUEST, m_listener);
uv_accept(stream, ctx->stream()); uv_accept(stream, ctx->stream());
uv_read_start(ctx->stream(), uv_read_start(ctx->stream(),
@ -65,11 +65,11 @@ void xmrig::HttpServer::onConnection(uv_stream_t *stream, uint16_t)
}, },
[](uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf) [](uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf)
{ {
HttpContext *ctx = static_cast<HttpContext*>(tcp->data); auto ctx = static_cast<HttpContext*>(tcp->data);
if (nread >= 0) { if (nread >= 0) {
const size_t size = static_cast<size_t>(nread); const auto size = static_cast<size_t>(nread);
const size_t parsed = ctx->parse(buf->base, size); const auto parsed = ctx->parse(buf->base, size);
if (parsed < size) { if (parsed < size) {
ctx->close(); ctx->close();

View file

@ -28,11 +28,12 @@
#define XMRIG_HTTPSERVER_H #define XMRIG_HTTPSERVER_H
typedef struct http_parser http_parser; using http_parser = struct http_parser;
typedef struct http_parser_settings http_parser_settings; using http_parser_settings = struct http_parser_settings;
#include "base/kernel/interfaces/ITcpServerListener.h" #include "base/kernel/interfaces/ITcpServerListener.h"
#include "base/tools/Object.h"
namespace xmrig { namespace xmrig {
@ -44,6 +45,8 @@ class IHttpListener;
class HttpServer : public ITcpServerListener class HttpServer : public ITcpServerListener
{ {
public: public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(HttpServer)
HttpServer(IHttpListener *listener); HttpServer(IHttpListener *listener);
~HttpServer() override; ~HttpServer() override;

View file

@ -54,7 +54,7 @@ protected:
inline const char *mode() const override { return m_client->mode(); } inline const char *mode() const override { return m_client->mode(); }
inline const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); } inline const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); }
inline const char *tlsVersion() const override { return m_client->tlsVersion(); } inline const char *tlsVersion() const override { return m_client->tlsVersion(); }
inline const Job &job() const override { return m_client->job(); } inline const Job &job() const override { return m_job; }
inline const Pool &pool() const override { return m_client->pool(); } inline const Pool &pool() const override { return m_client->pool(); }
inline const String &ip() const override { return m_client->ip(); } inline const String &ip() const override { return m_client->ip(); }
inline int id() const override { return m_client->id(); } inline int id() const override { return m_client->id(); }

View file

@ -60,17 +60,17 @@ void xmrig::Arguments::add(const char *arg)
const size_t size = strlen(arg); const size_t size = strlen(arg);
if (size > 4 && arg[0] == '-' && arg[1] == '-') { if (size > 4 && arg[0] == '-' && arg[1] == '-') {
const char *p = strstr(arg, "="); const char *p = strchr(arg, '=');
if (p) { if (p) {
const size_t keySize = static_cast<size_t>(p - arg); const auto keySize = static_cast<size_t>(p - arg);
m_data.push_back(String(arg, keySize)); m_data.emplace_back(arg, keySize);
m_data.push_back(arg + keySize + 1); m_data.emplace_back(arg + keySize + 1);
return; return;
} }
} }
m_data.push_back(arg); m_data.emplace_back(arg);
} }

View file

@ -31,10 +31,12 @@ static inline uint8_t hf_hex2bin(uint8_t c, bool &err)
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
return c - '0'; return c - '0';
} }
else if (c >= 'a' && c <= 'f') {
if (c >= 'a' && c <= 'f') {
return c - 'a' + 0xA; return c - 'a' + 0xA;
} }
else if (c >= 'A' && c <= 'F') {
if (c >= 'A' && c <= 'F') {
return c - 'A' + 0xA; return c - 'A' + 0xA;
} }
@ -77,7 +79,9 @@ xmrig::Buffer::Buffer(const char *data, size_t size)
xmrig::Buffer::Buffer(size_t size) : xmrig::Buffer::Buffer(size_t size) :
m_size(size) m_size(size)
{ {
if (size > 0) {
m_data = new char[size](); m_data = new char[size]();
}
} }
@ -105,6 +109,10 @@ void xmrig::Buffer::from(const char *data, size_t size)
xmrig::Buffer xmrig::Buffer::allocUnsafe(size_t size) xmrig::Buffer xmrig::Buffer::allocUnsafe(size_t size)
{ {
if (size == 0) {
return {};
}
Buffer buf; Buffer buf;
buf.m_size = size; buf.m_size = size;
buf.m_data = new char[size]; buf.m_data = new char[size];
@ -169,6 +177,13 @@ xmrig::String xmrig::Buffer::toHex() const
void xmrig::Buffer::copy(const char *data, size_t size) void xmrig::Buffer::copy(const char *data, size_t size)
{ {
if (size == 0) {
m_data = nullptr;
m_size = 0;
return;
}
m_data = new char[size]; m_data = new char[size];
m_size = size; m_size = size;

View file

@ -16,6 +16,7 @@
"colors": true, "colors": true,
"randomx": { "randomx": {
"init": -1, "init": -1,
"mode": "auto",
"numa": true "numa": true
}, },
"cpu": { "cpu": {

View file

@ -160,6 +160,9 @@ void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const
case IConfig::RandomXNumaKey: /* --randomx-no-numa */ case IConfig::RandomXNumaKey: /* --randomx-no-numa */
return set(doc, kRandomX, "numa", false); return set(doc, kRandomX, "numa", false);
case IConfig::RandomXModeKey: /* --randomx-mode */
return set(doc, kRandomX, "mode", arg);
# endif # endif
# ifdef XMRIG_FEATURE_OPENCL # ifdef XMRIG_FEATURE_OPENCL

View file

@ -96,6 +96,7 @@ static const option options[] = {
# ifdef XMRIG_ALGO_RANDOMX # ifdef XMRIG_ALGO_RANDOMX
{ "randomx-init", 1, nullptr, IConfig::RandomXInitKey }, { "randomx-init", 1, nullptr, IConfig::RandomXInitKey },
{ "randomx-no-numa", 0, nullptr, IConfig::RandomXNumaKey }, { "randomx-no-numa", 0, nullptr, IConfig::RandomXNumaKey },
{ "randomx-mode", 1, nullptr, IConfig::RandomXModeKey },
# endif # endif
# ifdef XMRIG_FEATURE_OPENCL # ifdef XMRIG_FEATURE_OPENCL
{ "opencl", 0, nullptr, IConfig::OclKey }, { "opencl", 0, nullptr, IConfig::OclKey },

View file

@ -86,6 +86,7 @@ static inline const std::string &usage()
# ifdef XMRIG_ALGO_RANDOMX # ifdef XMRIG_ALGO_RANDOMX
u += " --randomx-init=N threads count to initialize RandomX dataset\n"; u += " --randomx-init=N threads count to initialize RandomX dataset\n";
u += " --randomx-no-numa disable NUMA support for RandomX\n"; u += " --randomx-no-numa disable NUMA support for RandomX\n";
u += " --randomx-mode=MODE RandomX mode: auto, fast, light\n";
# endif # endif
# ifdef XMRIG_FEATURE_HTTP # ifdef XMRIG_FEATURE_HTTP

View file

@ -212,3 +212,84 @@ void fillAes4Rx4(void *state, size_t outputSize, void *buffer) {
template void fillAes4Rx4<true>(void *state, size_t outputSize, void *buffer); template void fillAes4Rx4<true>(void *state, size_t outputSize, void *buffer);
template void fillAes4Rx4<false>(void *state, size_t outputSize, void *buffer); template void fillAes4Rx4<false>(void *state, size_t outputSize, void *buffer);
template<bool softAes>
void hashAndFillAes1Rx4(void *scratchpad, size_t scratchpadSize, void *hash, void* fill_state) {
uint8_t* scratchpadPtr = (uint8_t*)scratchpad;
const uint8_t* scratchpadEnd = scratchpadPtr + scratchpadSize;
// initial state
rx_vec_i128 hash_state0 = rx_set_int_vec_i128(AES_HASH_1R_STATE0);
rx_vec_i128 hash_state1 = rx_set_int_vec_i128(AES_HASH_1R_STATE1);
rx_vec_i128 hash_state2 = rx_set_int_vec_i128(AES_HASH_1R_STATE2);
rx_vec_i128 hash_state3 = rx_set_int_vec_i128(AES_HASH_1R_STATE3);
const rx_vec_i128 key0 = rx_set_int_vec_i128(AES_GEN_1R_KEY0);
const rx_vec_i128 key1 = rx_set_int_vec_i128(AES_GEN_1R_KEY1);
const rx_vec_i128 key2 = rx_set_int_vec_i128(AES_GEN_1R_KEY2);
const rx_vec_i128 key3 = rx_set_int_vec_i128(AES_GEN_1R_KEY3);
rx_vec_i128 fill_state0 = rx_load_vec_i128((rx_vec_i128*)fill_state + 0);
rx_vec_i128 fill_state1 = rx_load_vec_i128((rx_vec_i128*)fill_state + 1);
rx_vec_i128 fill_state2 = rx_load_vec_i128((rx_vec_i128*)fill_state + 2);
rx_vec_i128 fill_state3 = rx_load_vec_i128((rx_vec_i128*)fill_state + 3);
constexpr int PREFETCH_DISTANCE = 4096;
const char* prefetchPtr = ((const char*)scratchpad) + PREFETCH_DISTANCE;
scratchpadEnd -= PREFETCH_DISTANCE;
for (int i = 0; i < 2; ++i) {
//process 64 bytes at a time in 4 lanes
while (scratchpadPtr < scratchpadEnd) {
hash_state0 = aesenc<softAes>(hash_state0, rx_load_vec_i128((rx_vec_i128*)scratchpadPtr + 0));
hash_state1 = aesdec<softAes>(hash_state1, rx_load_vec_i128((rx_vec_i128*)scratchpadPtr + 1));
hash_state2 = aesenc<softAes>(hash_state2, rx_load_vec_i128((rx_vec_i128*)scratchpadPtr + 2));
hash_state3 = aesdec<softAes>(hash_state3, rx_load_vec_i128((rx_vec_i128*)scratchpadPtr + 3));
fill_state0 = aesdec<softAes>(fill_state0, key0);
fill_state1 = aesenc<softAes>(fill_state1, key1);
fill_state2 = aesdec<softAes>(fill_state2, key2);
fill_state3 = aesenc<softAes>(fill_state3, key3);
rx_store_vec_i128((rx_vec_i128*)scratchpadPtr + 0, fill_state0);
rx_store_vec_i128((rx_vec_i128*)scratchpadPtr + 1, fill_state1);
rx_store_vec_i128((rx_vec_i128*)scratchpadPtr + 2, fill_state2);
rx_store_vec_i128((rx_vec_i128*)scratchpadPtr + 3, fill_state3);
rx_prefetch_t0(prefetchPtr);
scratchpadPtr += 64;
prefetchPtr += 64;
}
prefetchPtr = (const char*) scratchpad;
scratchpadEnd += PREFETCH_DISTANCE;
}
rx_store_vec_i128((rx_vec_i128*)fill_state + 0, fill_state0);
rx_store_vec_i128((rx_vec_i128*)fill_state + 1, fill_state1);
rx_store_vec_i128((rx_vec_i128*)fill_state + 2, fill_state2);
rx_store_vec_i128((rx_vec_i128*)fill_state + 3, fill_state3);
//two extra rounds to achieve full diffusion
rx_vec_i128 xkey0 = rx_set_int_vec_i128(AES_HASH_1R_XKEY0);
rx_vec_i128 xkey1 = rx_set_int_vec_i128(AES_HASH_1R_XKEY1);
hash_state0 = aesenc<softAes>(hash_state0, xkey0);
hash_state1 = aesdec<softAes>(hash_state1, xkey0);
hash_state2 = aesenc<softAes>(hash_state2, xkey0);
hash_state3 = aesdec<softAes>(hash_state3, xkey0);
hash_state0 = aesenc<softAes>(hash_state0, xkey1);
hash_state1 = aesdec<softAes>(hash_state1, xkey1);
hash_state2 = aesenc<softAes>(hash_state2, xkey1);
hash_state3 = aesdec<softAes>(hash_state3, xkey1);
//output hash
rx_store_vec_i128((rx_vec_i128*)hash + 0, hash_state0);
rx_store_vec_i128((rx_vec_i128*)hash + 1, hash_state1);
rx_store_vec_i128((rx_vec_i128*)hash + 2, hash_state2);
rx_store_vec_i128((rx_vec_i128*)hash + 3, hash_state3);
}
template void hashAndFillAes1Rx4<false>(void *scratchpad, size_t scratchpadSize, void *hash, void* fill_state);
template void hashAndFillAes1Rx4<true>(void *scratchpad, size_t scratchpadSize, void *hash, void* fill_state);

View file

@ -38,3 +38,6 @@ void fillAes1Rx4(void *state, size_t outputSize, void *buffer);
template<bool softAes> template<bool softAes>
void fillAes4Rx4(void *state, size_t outputSize, void *buffer); void fillAes4Rx4(void *state, size_t outputSize, void *buffer);
template<bool softAes>
void hashAndFillAes1Rx4(void *scratchpad, size_t scratchpadSize, void *hash, void* fill_state);

View file

@ -102,6 +102,7 @@ typedef __m128d rx_vec_f128;
#define rx_aligned_alloc(a, b) _mm_malloc(a,b) #define rx_aligned_alloc(a, b) _mm_malloc(a,b)
#define rx_aligned_free(a) _mm_free(a) #define rx_aligned_free(a) _mm_free(a)
#define rx_prefetch_nta(x) _mm_prefetch((const char *)(x), _MM_HINT_NTA) #define rx_prefetch_nta(x) _mm_prefetch((const char *)(x), _MM_HINT_NTA)
#define rx_prefetch_t0(x) _mm_prefetch((const char *)(x), _MM_HINT_T0)
#define rx_load_vec_f128 _mm_load_pd #define rx_load_vec_f128 _mm_load_pd
#define rx_store_vec_f128 _mm_store_pd #define rx_store_vec_f128 _mm_store_pd
@ -201,6 +202,7 @@ typedef union{
#define rx_aligned_alloc(a, b) malloc(a) #define rx_aligned_alloc(a, b) malloc(a)
#define rx_aligned_free(a) free(a) #define rx_aligned_free(a) free(a)
#define rx_prefetch_nta(x) #define rx_prefetch_nta(x)
#define rx_prefetch_t0(x)
/* Splat 64-bit long long to 2 64-bit long longs */ /* Splat 64-bit long long to 2 64-bit long longs */
FORCE_INLINE __m128i vec_splat2sd (int64_t scalar) FORCE_INLINE __m128i vec_splat2sd (int64_t scalar)
@ -399,6 +401,10 @@ inline void rx_prefetch_nta(void* ptr) {
asm volatile ("prfm pldl1strm, [%0]\n" : : "r" (ptr)); asm volatile ("prfm pldl1strm, [%0]\n" : : "r" (ptr));
} }
inline void rx_prefetch_t0(const void* ptr) {
asm volatile ("prfm pldl1strm, [%0]\n" : : "r" (ptr));
}
FORCE_INLINE rx_vec_f128 rx_load_vec_f128(const double* pd) { FORCE_INLINE rx_vec_f128 rx_load_vec_f128(const double* pd) {
return vld1q_f64((const float64_t*)pd); return vld1q_f64((const float64_t*)pd);
} }
@ -532,6 +538,7 @@ typedef union {
#define rx_aligned_alloc(a, b) malloc(a) #define rx_aligned_alloc(a, b) malloc(a)
#define rx_aligned_free(a) free(a) #define rx_aligned_free(a) free(a)
#define rx_prefetch_nta(x) #define rx_prefetch_nta(x)
#define rx_prefetch_t0(x)
FORCE_INLINE rx_vec_f128 rx_load_vec_f128(const double* pd) { FORCE_INLINE rx_vec_f128 rx_load_vec_f128(const double* pd) {
rx_vec_f128 x; rx_vec_f128 x;

View file

@ -29,6 +29,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdexcept> #include <stdexcept>
#include <cstring> #include <cstring>
#include <climits> #include <climits>
#include <atomic>
#include "crypto/randomx/jit_compiler_x86.hpp" #include "crypto/randomx/jit_compiler_x86.hpp"
#include "crypto/randomx/jit_compiler_x86_static.hpp" #include "crypto/randomx/jit_compiler_x86_static.hpp"
#include "crypto/randomx/superscalar.hpp" #include "crypto/randomx/superscalar.hpp"
@ -36,6 +37,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "crypto/randomx/reciprocal.h" #include "crypto/randomx/reciprocal.h"
#include "crypto/randomx/virtual_memory.hpp" #include "crypto/randomx/virtual_memory.hpp"
#ifdef _MSC_VER
# include <intrin.h>
#else
# include <cpuid.h>
#endif
namespace randomx { namespace randomx {
/* /*
@ -108,7 +115,7 @@ namespace randomx {
const int32_t codeSshPrefetchSize = codeShhEnd - codeShhPrefetch; const int32_t codeSshPrefetchSize = codeShhEnd - codeShhPrefetch;
const int32_t codeSshInitSize = codeProgramEnd - codeShhInit; const int32_t codeSshInitSize = codeProgramEnd - codeShhInit;
const int32_t epilogueOffset = CodeSize - epilogueSize; const int32_t epilogueOffset = (CodeSize - epilogueSize) & ~63;
constexpr int32_t superScalarHashOffset = 32768; constexpr int32_t superScalarHashOffset = 32768;
static const uint8_t REX_ADD_RR[] = { 0x4d, 0x03 }; static const uint8_t REX_ADD_RR[] = { 0x4d, 0x03 };
@ -183,6 +190,7 @@ namespace randomx {
static const uint8_t REX_ADD_I[] = { 0x49, 0x81 }; static const uint8_t REX_ADD_I[] = { 0x49, 0x81 };
static const uint8_t REX_TEST[] = { 0x49, 0xF7 }; static const uint8_t REX_TEST[] = { 0x49, 0xF7 };
static const uint8_t JZ[] = { 0x0f, 0x84 }; static const uint8_t JZ[] = { 0x0f, 0x84 };
static const uint8_t JZ_SHORT = 0x74;
static const uint8_t RET = 0xc3; static const uint8_t RET = 0xc3;
static const uint8_t LEA_32[] = { 0x41, 0x8d }; static const uint8_t LEA_32[] = { 0x41, 0x8d };
static const uint8_t MOVNTI[] = { 0x4c, 0x0f, 0xc3 }; static const uint8_t MOVNTI[] = { 0x4c, 0x0f, 0xc3 };
@ -197,20 +205,100 @@ namespace randomx {
static const uint8_t NOP7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t NOP7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t NOP8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t NOP8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
// static const uint8_t* NOPX[] = { NOP1, NOP2, NOP3, NOP4, NOP5, NOP6, NOP7, NOP8 }; static const uint8_t* NOPX[] = { NOP1, NOP2, NOP3, NOP4, NOP5, NOP6, NOP7, NOP8 };
static const uint8_t JMP_ALIGN_PREFIX[14][16] = {
{},
{0x2E},
{0x2E, 0x2E},
{0x2E, 0x2E, 0x2E},
{0x2E, 0x2E, 0x2E, 0x2E},
{0x2E, 0x2E, 0x2E, 0x2E, 0x2E},
{0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E},
{0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E},
{0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E},
{0x90, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E},
{0x66, 0x90, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E},
{0x66, 0x66, 0x90, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E},
{0x0F, 0x1F, 0x40, 0x00, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E},
{0x0F, 0x1F, 0x44, 0x00, 0x00, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E},
};
bool JitCompilerX86::BranchesWithin32B = false;
size_t JitCompilerX86::getCodeSize() { size_t JitCompilerX86::getCodeSize() {
return codePos < prologueSize ? 0 : codePos - prologueSize; return codePos < prologueSize ? 0 : codePos - prologueSize;
} }
static inline void cpuid(uint32_t level, int32_t output[4])
{
memset(output, 0, sizeof(int32_t) * 4);
# ifdef _MSC_VER
__cpuid(output, static_cast<int>(level));
# else
__cpuid_count(level, 0, output[0], output[1], output[2], output[3]);
# endif
}
// CPU-specific tweaks
void JitCompilerX86::applyTweaks() {
int32_t info[4];
cpuid(0, info);
int32_t manufacturer[4];
manufacturer[0] = info[1];
manufacturer[1] = info[3];
manufacturer[2] = info[2];
manufacturer[3] = 0;
if (strcmp((const char*)manufacturer, "GenuineIntel") == 0) {
struct
{
unsigned int stepping : 4;
unsigned int model : 4;
unsigned int family : 4;
unsigned int processor_type : 2;
unsigned int reserved1 : 2;
unsigned int ext_model : 4;
unsigned int ext_family : 8;
unsigned int reserved2 : 4;
} processor_info;
cpuid(1, info);
memcpy(&processor_info, info, sizeof(processor_info));
// Intel JCC erratum mitigation
if (processor_info.family == 6) {
const uint32_t model = processor_info.model | (processor_info.ext_model << 4);
const uint32_t stepping = processor_info.stepping;
// Affected CPU models and stepping numbers are taken from https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf
BranchesWithin32B =
((model == 0x4E) && (stepping == 0x3)) ||
((model == 0x55) && (stepping == 0x4)) ||
((model == 0x5E) && (stepping == 0x3)) ||
((model == 0x8E) && (stepping >= 0x9) && (stepping <= 0xC)) ||
((model == 0x9E) && (stepping >= 0x9) && (stepping <= 0xD)) ||
((model == 0xA6) && (stepping == 0x0)) ||
((model == 0xAE) && (stepping == 0xA));
}
}
}
static std::atomic<size_t> codeOffset;
JitCompilerX86::JitCompilerX86() { JitCompilerX86::JitCompilerX86() {
code = (uint8_t*)allocExecutableMemory(CodeSize); applyTweaks();
allocatedCode = (uint8_t*)allocExecutableMemory(CodeSize * 2);
// Shift code base address to improve caching - all threads will use different L2/L3 cache sets
code = allocatedCode + (codeOffset.fetch_add(59 * 64) % CodeSize);
memcpy(code, codePrologue, prologueSize); memcpy(code, codePrologue, prologueSize);
memcpy(code + epilogueOffset, codeEpilogue, epilogueSize); memcpy(code + epilogueOffset, codeEpilogue, epilogueSize);
} }
JitCompilerX86::~JitCompilerX86() { JitCompilerX86::~JitCompilerX86() {
freePagedMemory(code, CodeSize); freePagedMemory(allocatedCode, CodeSize);
} }
void JitCompilerX86::generateProgram(Program& prog, ProgramConfiguration& pcfg) { void JitCompilerX86::generateProgram(Program& prog, ProgramConfiguration& pcfg) {
@ -307,6 +395,22 @@ namespace randomx {
emit(RandomX_CurrentConfig.codePrefetchScratchpadTweaked, prefetchScratchpadSize, code, codePos); emit(RandomX_CurrentConfig.codePrefetchScratchpadTweaked, prefetchScratchpadSize, code, codePos);
memcpy(code + codePos, codeLoopStore, loopStoreSize); memcpy(code + codePos, codeLoopStore, loopStoreSize);
codePos += loopStoreSize; codePos += loopStoreSize;
if (BranchesWithin32B) {
const uint32_t branch_begin = static_cast<uint32_t>(codePos);
const uint32_t branch_end = static_cast<uint32_t>(branch_begin + 9);
// If the jump crosses or touches 32-byte boundary, align it
if ((branch_begin ^ branch_end) >= 32) {
uint32_t alignment_size = 32 - (branch_begin & 31);
if (alignment_size > 8) {
emit(NOPX[alignment_size - 9], alignment_size - 8, code, codePos);
alignment_size = 8;
}
emit(NOPX[alignment_size - 1], alignment_size, code, codePos);
}
}
emit(SUB_EBX, code, codePos); emit(SUB_EBX, code, codePos);
emit(JNZ, code, codePos); emit(JNZ, code, codePos);
emit32(prologueSize - codePos - 4, code, codePos); emit32(prologueSize - codePos - 4, code, codePos);
@ -408,12 +512,13 @@ namespace randomx {
} }
} }
void JitCompilerX86::genAddressReg(const Instruction& instr, uint8_t* code, int& codePos, bool rax) { template<bool rax>
emit(LEA_32, code, codePos); FORCE_INLINE void JitCompilerX86::genAddressReg(const Instruction& instr, uint8_t* code, int& codePos) {
emitByte(0x80 + instr.src + (rax ? 0 : 8), code, codePos); const uint32_t src = *((uint32_t*)&instr) & 0xFF0000;
if (instr.src == RegisterNeedsSib) {
emitByte(0x24, code, codePos); *(uint32_t*)(code + codePos) = (rax ? 0x24808d41 : 0x24888d41) + src;
} codePos += (src == (RegisterNeedsSib << 16)) ? 4 : 3;
emit32(instr.getImm32(), code, codePos); emit32(instr.getImm32(), code, codePos);
if (rax) if (rax)
emitByte(AND_EAX_I, code, codePos); emitByte(AND_EAX_I, code, codePos);
@ -422,12 +527,14 @@ namespace randomx {
emit32(instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask, code, codePos); emit32(instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask, code, codePos);
} }
void JitCompilerX86::genAddressRegDst(const Instruction& instr, uint8_t* code, int& codePos) { template void JitCompilerX86::genAddressReg<false>(const Instruction& instr, uint8_t* code, int& codePos);
emit(LEA_32, code, codePos); template void JitCompilerX86::genAddressReg<true>(const Instruction& instr, uint8_t* code, int& codePos);
emitByte(0x80 + instr.dst, code, codePos);
if (instr.dst == RegisterNeedsSib) { FORCE_INLINE void JitCompilerX86::genAddressRegDst(const Instruction& instr, uint8_t* code, int& codePos) {
emitByte(0x24, code, codePos); const uint32_t dst = static_cast<uint32_t>(instr.dst) << 16;
} *(uint32_t*)(code + codePos) = 0x24808d41 + dst;
codePos += (dst == (RegisterNeedsSib << 16)) ? 4 : 3;
emit32(instr.getImm32(), code, codePos); emit32(instr.getImm32(), code, codePos);
emitByte(AND_EAX_I, code, codePos); emitByte(AND_EAX_I, code, codePos);
if (instr.getModCond() < StoreL3Condition) { if (instr.getModCond() < StoreL3Condition) {
@ -438,7 +545,7 @@ namespace randomx {
} }
} }
void JitCompilerX86::genAddressImm(const Instruction& instr, uint8_t* code, int& codePos) { FORCE_INLINE void JitCompilerX86::genAddressImm(const Instruction& instr, uint8_t* code, int& codePos) {
emit32(instr.getImm32() & ScratchpadL3Mask, code, codePos); emit32(instr.getImm32() & ScratchpadL3Mask, code, codePos);
} }
@ -483,7 +590,7 @@ namespace randomx {
int pos = codePos; int pos = codePos;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr, p, pos); genAddressReg<true>(instr, p, pos);
emit32(template_IADD_M[instr.dst], p, pos); emit32(template_IADD_M[instr.dst], p, pos);
} }
else { else {
@ -523,7 +630,7 @@ namespace randomx {
int pos = codePos; int pos = codePos;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr, p, pos); genAddressReg<true>(instr, p, pos);
emit(REX_SUB_RM, p, pos); emit(REX_SUB_RM, p, pos);
emitByte(0x04 + 8 * instr.dst, p, pos); emitByte(0x04 + 8 * instr.dst, p, pos);
emitByte(0x06, p, pos); emitByte(0x06, p, pos);
@ -561,7 +668,7 @@ namespace randomx {
int pos = codePos; int pos = codePos;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr, p, pos); genAddressReg<true>(instr, p, pos);
emit(REX_IMUL_RM, p, pos); emit(REX_IMUL_RM, p, pos);
emitByte(0x04 + 8 * instr.dst, p, pos); emitByte(0x04 + 8 * instr.dst, p, pos);
emitByte(0x06, p, pos); emitByte(0x06, p, pos);
@ -596,7 +703,7 @@ namespace randomx {
int pos = codePos; int pos = codePos;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr, p, pos, false); genAddressReg<false>(instr, p, pos);
emit(REX_MOV_RR64, p, pos); emit(REX_MOV_RR64, p, pos);
emitByte(0xc0 + instr.dst, p, pos); emitByte(0xc0 + instr.dst, p, pos);
emit(REX_MUL_MEM, p, pos); emit(REX_MUL_MEM, p, pos);
@ -635,7 +742,7 @@ namespace randomx {
int pos = codePos; int pos = codePos;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr, p, pos, false); genAddressReg<false>(instr, p, pos);
emit(REX_MOV_RR64, p, pos); emit(REX_MOV_RR64, p, pos);
emitByte(0xc0 + instr.dst, p, pos); emitByte(0xc0 + instr.dst, p, pos);
emit(REX_IMUL_MEM, p, pos); emit(REX_IMUL_MEM, p, pos);
@ -704,7 +811,7 @@ namespace randomx {
int pos = codePos; int pos = codePos;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr, p, pos); genAddressReg<true>(instr, p, pos);
emit(REX_XOR_RM, p, pos); emit(REX_XOR_RM, p, pos);
emitByte(0x04 + 8 * instr.dst, p, pos); emitByte(0x04 + 8 * instr.dst, p, pos);
emitByte(0x06, p, pos); emitByte(0x06, p, pos);
@ -801,7 +908,7 @@ namespace randomx {
int pos = codePos; int pos = codePos;
const uint32_t dst = instr.dst % RegisterCountFlt; const uint32_t dst = instr.dst % RegisterCountFlt;
genAddressReg(instr, p, pos); genAddressReg<true>(instr, p, pos);
emit(REX_CVTDQ2PD_XMM12, p, pos); emit(REX_CVTDQ2PD_XMM12, p, pos);
emit(REX_ADDPD, p, pos); emit(REX_ADDPD, p, pos);
emitByte(0xc4 + 8 * dst, p, pos); emitByte(0xc4 + 8 * dst, p, pos);
@ -826,7 +933,7 @@ namespace randomx {
int pos = codePos; int pos = codePos;
const uint32_t dst = instr.dst % RegisterCountFlt; const uint32_t dst = instr.dst % RegisterCountFlt;
genAddressReg(instr, p, pos); genAddressReg<true>(instr, p, pos);
emit(REX_CVTDQ2PD_XMM12, p, pos); emit(REX_CVTDQ2PD_XMM12, p, pos);
emit(REX_SUBPD, p, pos); emit(REX_SUBPD, p, pos);
emitByte(0xc4 + 8 * dst, p, pos); emitByte(0xc4 + 8 * dst, p, pos);
@ -862,7 +969,7 @@ namespace randomx {
int pos = codePos; int pos = codePos;
const uint32_t dst = instr.dst % RegisterCountFlt; const uint32_t dst = instr.dst % RegisterCountFlt;
genAddressReg(instr, p, pos); genAddressReg<true>(instr, p, pos);
emit(REX_CVTDQ2PD_XMM12, p, pos); emit(REX_CVTDQ2PD_XMM12, p, pos);
emit(REX_ANDPS_XMM12, p, pos); emit(REX_ANDPS_XMM12, p, pos);
emit(REX_DIVPD, p, pos); emit(REX_DIVPD, p, pos);
@ -902,19 +1009,39 @@ namespace randomx {
uint8_t* const p = code; uint8_t* const p = code;
int pos = codePos; int pos = codePos;
int reg = instr.dst; const int reg = instr.dst;
int32_t jmp_offset = registerUsage[reg] - (pos + 16);
if (BranchesWithin32B) {
const uint32_t branch_begin = static_cast<uint32_t>(pos + 7);
const uint32_t branch_end = static_cast<uint32_t>(branch_begin + ((jmp_offset >= -128) ? 9 : 13));
// If the jump crosses or touches 32-byte boundary, align it
if ((branch_begin ^ branch_end) >= 32) {
const uint32_t alignment_size = 32 - (branch_begin & 31);
jmp_offset -= alignment_size;
emit(JMP_ALIGN_PREFIX[alignment_size], alignment_size, p, pos);
}
}
emit(REX_ADD_I, p, pos); emit(REX_ADD_I, p, pos);
emitByte(0xc0 + reg, p, pos); emitByte(0xc0 + reg, p, pos);
int shift = instr.getModCond() + RandomX_CurrentConfig.JumpOffset; const int shift = instr.getModCond() + RandomX_CurrentConfig.JumpOffset;
uint32_t imm = instr.getImm32() | (1UL << shift); const uint32_t imm = (instr.getImm32() | (1UL << shift)) & ~(1UL << (shift - 1));
if (RandomX_CurrentConfig.JumpOffset > 0 || shift > 0)
imm &= ~(1UL << (shift - 1));
emit32(imm, p, pos); emit32(imm, p, pos);
emit(REX_TEST, p, pos); emit(REX_TEST, p, pos);
emitByte(0xc0 + reg, p, pos); emitByte(0xc0 + reg, p, pos);
emit32(RandomX_CurrentConfig.ConditionMask_Calculated << shift, p, pos); emit32(RandomX_CurrentConfig.ConditionMask_Calculated << shift, p, pos);
if (jmp_offset >= -128) {
emitByte(JZ_SHORT, p, pos);
emitByte(jmp_offset, p, pos);
}
else {
emit(JZ, p, pos); emit(JZ, p, pos);
emit32(registerUsage[reg] - (pos + 4), p, pos); emit32(jmp_offset - 4, p, pos);
}
//mark all registers as used //mark all registers as used
uint64_t* r = (uint64_t*) registerUsage; uint64_t* r = (uint64_t*) registerUsage;
uint64_t k = pos; uint64_t k = pos;

View file

@ -67,12 +67,17 @@ namespace randomx {
static InstructionGeneratorX86 engine[256]; static InstructionGeneratorX86 engine[256];
int registerUsage[RegistersCount]; int registerUsage[RegistersCount];
uint8_t* allocatedCode;
uint8_t* code; uint8_t* code;
int32_t codePos; int32_t codePos;
static bool BranchesWithin32B;
static void applyTweaks();
void generateProgramPrologue(Program&, ProgramConfiguration&); void generateProgramPrologue(Program&, ProgramConfiguration&);
void generateProgramEpilogue(Program&, ProgramConfiguration&); void generateProgramEpilogue(Program&, ProgramConfiguration&);
static void genAddressReg(const Instruction&, uint8_t* code, int& codePos, bool rax = true); template<bool rax>
static void genAddressReg(const Instruction&, uint8_t* code, int& codePos);
static void genAddressRegDst(const Instruction&, uint8_t* code, int& codePos); static void genAddressRegDst(const Instruction&, uint8_t* code, int& codePos);
static void genAddressImm(const Instruction&, uint8_t* code, int& codePos); static void genAddressImm(const Instruction&, uint8_t* code, int& codePos);
static void genSIB(int scale, int index, int base, uint8_t* code, int& codePos); static void genSIB(int scale, int index, int base, uint8_t* code, int& codePos);

View file

@ -473,4 +473,22 @@ extern "C" {
machine->getFinalResult(output, RANDOMX_HASH_SIZE); machine->getFinalResult(output, RANDOMX_HASH_SIZE);
} }
void randomx_calculate_hash_first(randomx_vm* machine, uint64_t (&tempHash)[8], const void* input, size_t inputSize) {
rx_blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0);
machine->initScratchpad(tempHash);
}
void randomx_calculate_hash_next(randomx_vm* machine, uint64_t (&tempHash)[8], const void* nextInput, size_t nextInputSize, void* output) {
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);
}
machine->run(&tempHash);
// Finish current hash and fill the scratchpad for the next hash at the same time
rx_blake2b(tempHash, sizeof(tempHash), nextInput, nextInputSize, nullptr, 0);
machine->hashAndFill(output, RANDOMX_HASH_SIZE, tempHash);
}
} }

View file

@ -338,6 +338,9 @@ RANDOMX_EXPORT void randomx_destroy_vm(randomx_vm *machine);
*/ */
RANDOMX_EXPORT void randomx_calculate_hash(randomx_vm *machine, const void *input, size_t inputSize, void *output); RANDOMX_EXPORT void randomx_calculate_hash(randomx_vm *machine, const void *input, size_t inputSize, void *output);
RANDOMX_EXPORT void randomx_calculate_hash_first(randomx_vm* machine, uint64_t (&tempHash)[8], const void* input, size_t inputSize);
RANDOMX_EXPORT void randomx_calculate_hash_next(randomx_vm* machine, uint64_t (&tempHash)[8], const void* nextInput, size_t nextInputSize, void* output);
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif

View file

@ -114,6 +114,12 @@ namespace randomx {
rx_blake2b(out, outSize, &reg, sizeof(RegisterFile), nullptr, 0); rx_blake2b(out, outSize, &reg, sizeof(RegisterFile), nullptr, 0);
} }
template<bool softAes>
void VmBase<softAes>::hashAndFill(void* out, size_t outSize, uint64_t (&fill_state)[8]) {
hashAndFillAes1Rx4<softAes>(scratchpad, ScratchpadSize, &reg.a, fill_state);
rx_blake2b(out, outSize, &reg, sizeof(RegisterFile), nullptr, 0);
}
template<bool softAes> template<bool softAes>
void VmBase<softAes>::initScratchpad(void* seed) { void VmBase<softAes>::initScratchpad(void* seed) {
fillAes1Rx4<softAes>(seed, ScratchpadSize, scratchpad); fillAes1Rx4<softAes>(seed, ScratchpadSize, scratchpad);

View file

@ -39,6 +39,7 @@ public:
virtual ~randomx_vm() = 0; virtual ~randomx_vm() = 0;
virtual void setScratchpad(uint8_t *scratchpad) = 0; virtual void setScratchpad(uint8_t *scratchpad) = 0;
virtual void getFinalResult(void* out, size_t outSize) = 0; virtual void getFinalResult(void* out, size_t outSize) = 0;
virtual void hashAndFill(void* out, size_t outSize, uint64_t (&fill_state)[8]) = 0;
virtual void setDataset(randomx_dataset* dataset) { } virtual void setDataset(randomx_dataset* dataset) { }
virtual void setCache(randomx_cache* cache) { } virtual void setCache(randomx_cache* cache) { }
virtual void initScratchpad(void* seed) = 0; virtual void initScratchpad(void* seed) = 0;
@ -82,6 +83,7 @@ namespace randomx {
void setScratchpad(uint8_t *scratchpad) override; void setScratchpad(uint8_t *scratchpad) override;
void initScratchpad(void* seed) override; void initScratchpad(void* seed) override;
void getFinalResult(void* out, size_t outSize) override; void getFinalResult(void* out, size_t outSize) override;
void hashAndFill(void* out, size_t outSize, uint64_t (&fill_state)[8]) override;
protected: protected:
void generateProgram(void* seed); void generateProgram(void* seed);

View file

@ -70,7 +70,7 @@ bool xmrig::Rx::init(const Job &job, const RxConfig &config, bool hugePages)
return true; return true;
} }
d_ptr->queue.enqueue(job, config.nodeset(), config.threads(), hugePages); d_ptr->queue.enqueue(job, config.nodeset(), config.threads(), hugePages, config.mode());
return false; return false;
} }

View file

@ -69,11 +69,11 @@ public:
} }
inline void createDataset(bool hugePages) inline void createDataset(bool hugePages, RxConfig::Mode mode)
{ {
const uint64_t ts = Chrono::steadyMSecs(); const uint64_t ts = Chrono::steadyMSecs();
m_dataset = new RxDataset(hugePages, true); m_dataset = new RxDataset(hugePages, true, mode);
printAllocStatus(ts); printAllocStatus(ts);
} }
@ -150,19 +150,19 @@ xmrig::RxDataset *xmrig::RxBasicStorage::dataset(const Job &job, uint32_t) const
std::pair<uint32_t, uint32_t> xmrig::RxBasicStorage::hugePages() const std::pair<uint32_t, uint32_t> xmrig::RxBasicStorage::hugePages() const
{ {
if (!d_ptr->dataset()) { if (!d_ptr->dataset()) {
return { 0u, 0u }; return { 0U, 0U };
} }
return d_ptr->dataset()->hugePages(); return d_ptr->dataset()->hugePages();
} }
void xmrig::RxBasicStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages) void xmrig::RxBasicStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode mode)
{ {
d_ptr->setSeed(seed); d_ptr->setSeed(seed);
if (!d_ptr->dataset()) { if (!d_ptr->dataset()) {
d_ptr->createDataset(hugePages); d_ptr->createDataset(hugePages, mode);
} }
d_ptr->initDataset(threads); d_ptr->initDataset(threads);

View file

@ -50,7 +50,7 @@ public:
protected: protected:
RxDataset *dataset(const Job &job, uint32_t nodeId) const override; RxDataset *dataset(const Job &job, uint32_t nodeId) const override;
std::pair<uint32_t, uint32_t> hugePages() const override; std::pair<uint32_t, uint32_t> hugePages() const override;
void init(const RxSeed &seed, uint32_t threads, bool hugePages) override; void init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode mode) override;
private: private:
RxBasicStoragePrivate *d_ptr; RxBasicStoragePrivate *d_ptr;

View file

@ -25,9 +25,54 @@
#include "crypto/rx/RxConfig.h" #include "crypto/rx/RxConfig.h"
#include "backend/cpu/Cpu.h" #include "backend/cpu/Cpu.h"
#include "rapidjson/document.h"
#include <array>
#include <algorithm>
#ifdef _MSC_VER
# define strcasecmp _stricmp
#endif
namespace xmrig {
static const std::array<const char *, RxConfig::ModeMax> modeNames = { "auto", "fast", "light" };
} // namespace xmrig
const char *xmrig::RxConfig::modeName() const
{
return modeNames[m_mode];
}
uint32_t xmrig::RxConfig::threads() const uint32_t xmrig::RxConfig::threads() const
{ {
return m_threads < 1 ? static_cast<uint32_t>(Cpu::info()->threads()) : static_cast<uint32_t>(m_threads); return m_threads < 1 ? static_cast<uint32_t>(Cpu::info()->threads()) : static_cast<uint32_t>(m_threads);
} }
xmrig::RxConfig::Mode xmrig::RxConfig::readMode(const rapidjson::Value &value) const
{
if (value.IsUint()) {
return static_cast<Mode>(std::min(value.GetUint(), ModeMax - 1));
}
if (value.IsString()) {
auto mode = value.GetString();
for (size_t i = 0; i < modeNames.size(); i++) {
if (strcasecmp(mode, modeNames[i]) == 0) {
return static_cast<Mode>(i);
}
}
}
return AutoMode;
}

View file

@ -38,6 +38,13 @@ namespace xmrig {
class RxConfig class RxConfig
{ {
public: public:
enum Mode : uint32_t {
AutoMode,
FastMode,
LightMode,
ModeMax
};
bool read(const rapidjson::Value &value); bool read(const rapidjson::Value &value);
rapidjson::Value toJSON(rapidjson::Document &doc) const; rapidjson::Value toJSON(rapidjson::Document &doc) const;
@ -47,11 +54,17 @@ public:
inline std::vector<uint32_t> nodeset() const { return std::vector<uint32_t>(); } inline std::vector<uint32_t> nodeset() const { return std::vector<uint32_t>(); }
# endif # endif
const char *modeName() const;
uint32_t threads() const; uint32_t threads() const;
inline Mode mode() const { return m_mode; }
private: private:
Mode readMode(const rapidjson::Value &value) const;
bool m_numa = true; bool m_numa = true;
int m_threads = -1; int m_threads = -1;
Mode m_mode = AutoMode;
# ifdef XMRIG_FEATURE_HWLOC # ifdef XMRIG_FEATURE_HWLOC
std::vector<uint32_t> m_nodeset; std::vector<uint32_t> m_nodeset;

View file

@ -31,6 +31,7 @@
namespace xmrig { namespace xmrig {
static const char *kInit = "init"; static const char *kInit = "init";
static const char *kMode = "mode";
} }
@ -42,6 +43,7 @@ rapidjson::Value xmrig::RxConfig::toJSON(rapidjson::Document &doc) const
Value obj(kObjectType); Value obj(kObjectType);
obj.AddMember(StringRef(kInit), m_threads, allocator); obj.AddMember(StringRef(kInit), m_threads, allocator);
obj.AddMember(StringRef(kMode), StringRef(modeName()), allocator);
return obj; return obj;
} }
@ -51,6 +53,7 @@ bool xmrig::RxConfig::read(const rapidjson::Value &value)
{ {
if (value.IsObject()) { if (value.IsObject()) {
m_threads = Json::getInt(value, kInit, m_threads); m_threads = Json::getInt(value, kInit, m_threads);
m_mode = readMode(Json::getValue(value, kMode));
return true; return true;
} }

View file

@ -33,6 +33,7 @@
namespace xmrig { namespace xmrig {
static const char *kInit = "init"; static const char *kInit = "init";
static const char *kMode = "mode";
static const char *kNUMA = "numa"; static const char *kNUMA = "numa";
} }
@ -46,6 +47,7 @@ rapidjson::Value xmrig::RxConfig::toJSON(rapidjson::Document &doc) const
Value obj(kObjectType); Value obj(kObjectType);
obj.AddMember(StringRef(kInit), m_threads, allocator); obj.AddMember(StringRef(kInit), m_threads, allocator);
obj.AddMember(StringRef(kMode), StringRef(modeName()), allocator);
if (!m_nodeset.empty()) { if (!m_nodeset.empty()) {
Value numa(kArrayType); Value numa(kArrayType);
@ -68,6 +70,13 @@ bool xmrig::RxConfig::read(const rapidjson::Value &value)
{ {
if (value.IsObject()) { if (value.IsObject()) {
m_threads = Json::getInt(value, kInit, m_threads); m_threads = Json::getInt(value, kInit, m_threads);
m_mode = readMode(Json::getValue(value, kMode));
if (m_mode == LightMode) {
m_numa = false;
return true;
}
const auto &numa = Json::getValue(value, kNUMA); const auto &numa = Json::getValue(value, kNUMA);
if (numa.IsArray()) { if (numa.IsArray()) {

View file

@ -26,6 +26,8 @@
#include "crypto/rx/RxDataset.h" #include "crypto/rx/RxDataset.h"
#include "backend/common/Tags.h"
#include "base/io/log/Log.h"
#include "crypto/common/VirtualMemory.h" #include "crypto/common/VirtualMemory.h"
#include "crypto/randomx/randomx.h" #include "crypto/randomx/randomx.h"
#include "crypto/rx/RxAlgo.h" #include "crypto/rx/RxAlgo.h"
@ -33,12 +35,14 @@
#include <thread> #include <thread>
#include <uv.h>
static_assert(RANDOMX_FLAG_LARGE_PAGES == 1, "RANDOMX_FLAG_LARGE_PAGES flag mismatch"); static_assert(RANDOMX_FLAG_LARGE_PAGES == 1, "RANDOMX_FLAG_LARGE_PAGES flag mismatch");
xmrig::RxDataset::RxDataset(bool hugePages, bool cache) xmrig::RxDataset::RxDataset(bool hugePages, bool cache, RxConfig::Mode mode) :
m_mode(mode)
{ {
allocate(hugePages); allocate(hugePages);
@ -118,7 +122,7 @@ size_t xmrig::RxDataset::size(bool cache) const
std::pair<uint32_t, uint32_t> xmrig::RxDataset::hugePages(bool cache) const std::pair<uint32_t, uint32_t> xmrig::RxDataset::hugePages(bool cache) const
{ {
constexpr size_t twoMiB = 2u * 1024u * 1024u; constexpr size_t twoMiB = 2U * 1024U * 1024U;
constexpr size_t cacheSize = VirtualMemory::align(RxCache::maxSize(), twoMiB) / twoMiB; constexpr size_t cacheSize = VirtualMemory::align(RxCache::maxSize(), twoMiB) / twoMiB;
size_t total = VirtualMemory::align(maxSize(), twoMiB) / twoMiB; size_t total = VirtualMemory::align(maxSize(), twoMiB) / twoMiB;
@ -157,6 +161,18 @@ void xmrig::RxDataset::setRaw(const void *raw)
void xmrig::RxDataset::allocate(bool hugePages) void xmrig::RxDataset::allocate(bool hugePages)
{ {
if (m_mode == RxConfig::LightMode) {
LOG_ERR(CLEAR "%s" RED_BOLD_S "fast RandomX mode disabled by config", rx_tag());
return;
}
if (m_mode == RxConfig::AutoMode && uv_get_total_memory() < (maxSize() + RxCache::maxSize())) {
LOG_ERR(CLEAR "%s" RED_BOLD_S "not enough memory for RandomX dataset", rx_tag());
return;
}
if (hugePages) { if (hugePages) {
m_flags = RANDOMX_FLAG_LARGE_PAGES; m_flags = RANDOMX_FLAG_LARGE_PAGES;
m_dataset = randomx_alloc_dataset(static_cast<randomx_flags>(m_flags)); m_dataset = randomx_alloc_dataset(static_cast<randomx_flags>(m_flags));

View file

@ -28,9 +28,10 @@
#define XMRIG_RX_DATASET_H #define XMRIG_RX_DATASET_H
#include "base/tools/Object.h"
#include "crypto/common/Algorithm.h" #include "crypto/common/Algorithm.h"
#include "crypto/randomx/configuration.h" #include "crypto/randomx/configuration.h"
#include "base/tools/Object.h" #include "crypto/rx/RxConfig.h"
struct randomx_dataset; struct randomx_dataset;
@ -49,7 +50,7 @@ class RxDataset
public: public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(RxDataset) XMRIG_DISABLE_COPY_MOVE_DEFAULT(RxDataset)
RxDataset(bool hugePages, bool cache); RxDataset(bool hugePages, bool cache, RxConfig::Mode mode);
RxDataset(RxCache *cache); RxDataset(RxCache *cache);
~RxDataset(); ~RxDataset();
@ -69,6 +70,7 @@ public:
private: private:
void allocate(bool hugePages); void allocate(bool hugePages);
const RxConfig::Mode m_mode = RxConfig::FastMode;
int m_flags = 0; int m_flags = 0;
randomx_dataset *m_dataset = nullptr; randomx_dataset *m_dataset = nullptr;
RxCache *m_cache = nullptr; RxCache *m_cache = nullptr;

View file

@ -198,7 +198,7 @@ private:
return; return;
} }
auto dataset = new RxDataset(hugePages, false); auto dataset = new RxDataset(hugePages, false, RxConfig::FastMode);
if (!dataset->get()) { if (!dataset->get()) {
printSkipped(nodeId, "failed to allocate dataset"); printSkipped(nodeId, "failed to allocate dataset");
@ -339,14 +339,14 @@ xmrig::RxDataset *xmrig::RxNUMAStorage::dataset(const Job &job, uint32_t nodeId)
std::pair<uint32_t, uint32_t> xmrig::RxNUMAStorage::hugePages() const std::pair<uint32_t, uint32_t> xmrig::RxNUMAStorage::hugePages() const
{ {
if (!d_ptr->isAllocated()) { if (!d_ptr->isAllocated()) {
return { 0u, 0u }; return { 0U, 0U };
} }
return d_ptr->hugePages(); return d_ptr->hugePages();
} }
void xmrig::RxNUMAStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages) void xmrig::RxNUMAStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode)
{ {
d_ptr->setSeed(seed); d_ptr->setSeed(seed);

View file

@ -53,7 +53,7 @@ public:
protected: protected:
RxDataset *dataset(const Job &job, uint32_t nodeId) const override; RxDataset *dataset(const Job &job, uint32_t nodeId) const override;
std::pair<uint32_t, uint32_t> hugePages() const override; std::pair<uint32_t, uint32_t> hugePages() const override;
void init(const RxSeed &seed, uint32_t threads, bool hugePages) override; void init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode mode) override;
private: private:
RxNUMAStoragePrivate *d_ptr; RxNUMAStoragePrivate *d_ptr;

View file

@ -90,11 +90,11 @@ std::pair<uint32_t, uint32_t> xmrig::RxQueue::hugePages()
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
return m_storage && m_state == STATE_IDLE ? m_storage->hugePages() : std::pair<uint32_t, uint32_t>(0u, 0u); return m_storage && m_state == STATE_IDLE ? m_storage->hugePages() : std::pair<uint32_t, uint32_t>(0U, 0U);
} }
void xmrig::RxQueue::enqueue(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages) void xmrig::RxQueue::enqueue(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages, RxConfig::Mode mode)
{ {
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::mutex> lock(m_mutex);
@ -114,7 +114,7 @@ void xmrig::RxQueue::enqueue(const RxSeed &seed, const std::vector<uint32_t> &no
return; return;
} }
m_queue.emplace_back(seed, nodeset, threads, hugePages); m_queue.emplace_back(seed, nodeset, threads, hugePages, mode);
m_seed = seed; m_seed = seed;
m_state = STATE_PENDING; m_state = STATE_PENDING;
@ -156,7 +156,7 @@ void xmrig::RxQueue::backgroundInit()
Buffer::toHex(item.seed.data().data(), 8).data() Buffer::toHex(item.seed.data().data(), 8).data()
); );
m_storage->init(item.seed, item.threads, item.hugePages); m_storage->init(item.seed, item.threads, item.hugePages, item.mode);
lock = std::unique_lock<std::mutex>(m_mutex); lock = std::unique_lock<std::mutex>(m_mutex);

View file

@ -29,6 +29,7 @@
#include "base/tools/Object.h" #include "base/tools/Object.h"
#include "crypto/rx/RxConfig.h"
#include "crypto/rx/RxSeed.h" #include "crypto/rx/RxSeed.h"
@ -52,14 +53,16 @@ class RxDataset;
class RxQueueItem class RxQueueItem
{ {
public: public:
RxQueueItem(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages) : RxQueueItem(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages, RxConfig::Mode mode) :
hugePages(hugePages), hugePages(hugePages),
mode(mode),
seed(seed), seed(seed),
nodeset(nodeset), nodeset(nodeset),
threads(threads) threads(threads)
{} {}
const bool hugePages; const bool hugePages;
const RxConfig::Mode mode;
const RxSeed seed; const RxSeed seed;
const std::vector<uint32_t> nodeset; const std::vector<uint32_t> nodeset;
const uint32_t threads; const uint32_t threads;
@ -77,7 +80,7 @@ public:
bool isReady(const Job &job); bool isReady(const Job &job);
RxDataset *dataset(const Job &job, uint32_t nodeId); RxDataset *dataset(const Job &job, uint32_t nodeId);
std::pair<uint32_t, uint32_t> hugePages(); std::pair<uint32_t, uint32_t> hugePages();
void enqueue(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages); void enqueue(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages, RxConfig::Mode mode);
private: private:
enum State { enum State {

View file

@ -28,15 +28,15 @@
#define APP_ID "xmrig" #define APP_ID "xmrig"
#define APP_NAME "XMRig" #define APP_NAME "XMRig"
#define APP_DESC "XMRig miner" #define APP_DESC "XMRig miner"
#define APP_VERSION "5.0.1" #define APP_VERSION "5.1.0"
#define APP_DOMAIN "xmrig.com" #define APP_DOMAIN "xmrig.com"
#define APP_SITE "www.xmrig.com" #define APP_SITE "www.xmrig.com"
#define APP_COPYRIGHT "Copyright (C) 2016-2019 xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2019 xmrig.com"
#define APP_KIND "miner" #define APP_KIND "miner"
#define APP_VER_MAJOR 5 #define APP_VER_MAJOR 5
#define APP_VER_MINOR 0 #define APP_VER_MINOR 1
#define APP_VER_PATCH 1 #define APP_VER_PATCH 0
#ifdef _MSC_VER #ifdef _MSC_VER
# if (_MSC_VER >= 1920) # if (_MSC_VER >= 1920)