From d7f42d54ad68b735db03210c1940a8a133aa93b5 Mon Sep 17 00:00:00 2001 From: XMRig Date: Mon, 10 Jun 2019 20:46:29 +0700 Subject: [PATCH 01/65] Added initial support for per pool algo option (mining code is broken). --- src/Summary.cpp | 6 +- src/base/kernel/config/BaseConfig.cpp | 23 +- src/base/kernel/config/BaseConfig.h | 14 +- src/base/kernel/interfaces/IConfig.h | 1 - src/base/net/stratum/Client.cpp | 33 +-- src/base/net/stratum/Job.cpp | 38 ---- src/base/net/stratum/Job.h | 10 +- src/base/net/stratum/Pool.cpp | 203 +---------------- src/base/net/stratum/Pool.h | 10 +- src/base/net/stratum/Pools.cpp | 21 +- src/base/net/stratum/Pools.h | 7 +- src/core/config/Config.cpp | 56 +++-- src/crypto/common/Algorithm.cpp | 304 +++++++------------------- src/crypto/common/Algorithm.h | 84 ++++--- src/net/Network.cpp | 3 +- src/net/strategies/DonateStrategy.cpp | 6 +- src/workers/MultiWorker.cpp | 3 +- src/workers/Workers.cpp | 2 +- 18 files changed, 187 insertions(+), 637 deletions(-) diff --git a/src/Summary.cpp b/src/Summary.cpp index 2b28f98d..d780d64f 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -90,10 +90,9 @@ static void print_threads(xmrig::Config *config) snprintf(buf, sizeof buf, ", affinity=0x%" PRIX64, config->affinity()); } - xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%d") WHITE_BOLD(", %s, av=%d, %sdonate=%d%%") WHITE_BOLD("%s"), + xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%d") WHITE_BOLD(", av=%d, %sdonate=%d%%") WHITE_BOLD("%s"), "THREADS", config->threadsCount(), - config->algorithm().shortName(), config->algoVariant(), config->pools().donateLevel() == 0 ? RED_BOLD_S : "", config->pools().donateLevel(), @@ -101,10 +100,9 @@ static void print_threads(xmrig::Config *config) ); } else { - xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%d") WHITE_BOLD(", %s, %sdonate=%d%%"), + xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%d") WHITE_BOLD(", %sdonate=%d%%"), "THREADS", config->threadsCount(), - config->algorithm().shortName(), config->pools().donateLevel() == 0 ? RED_BOLD_S : "", config->pools().donateLevel() ); diff --git a/src/base/kernel/config/BaseConfig.cpp b/src/base/kernel/config/BaseConfig.cpp index af2418aa..489849a3 100644 --- a/src/base/kernel/config/BaseConfig.cpp +++ b/src/base/kernel/config/BaseConfig.cpp @@ -60,14 +60,7 @@ #include "version.h" -xmrig::BaseConfig::BaseConfig() : - m_algorithm(CRYPTONIGHT, VARIANT_AUTO), - m_autoSave(true), - m_background(false), - m_dryRun(false), - m_syslog(false), - m_upgrade(false), - m_watch(true) +xmrig::BaseConfig::BaseConfig() { } @@ -160,19 +153,7 @@ bool xmrig::BaseConfig::read(const IJsonReader &reader, const char *fileName) m_http.load(chain.getObject("http")); # endif - m_algorithm.parseAlgorithm(reader.getString("algo", "cn")); - - m_pools.load(reader.getArray("pools")); - m_pools.setDonateLevel(reader.getInt("donate-level", kDefaultDonateLevel)); - m_pools.setProxyDonate(reader.getInt("donate-over-proxy", Pools::PROXY_DONATE_AUTO)); - m_pools.setRetries(reader.getInt("retries")); - m_pools.setRetryPause(reader.getInt("retry-pause")); - - if (!m_algorithm.isValid()) { - return false; - } - - m_pools.adjust(m_algorithm); + m_pools.load(reader); return m_pools.active() > 0; } diff --git a/src/base/kernel/config/BaseConfig.h b/src/base/kernel/config/BaseConfig.h index f0c52536..48d7c2cf 100644 --- a/src/base/kernel/config/BaseConfig.h +++ b/src/base/kernel/config/BaseConfig.h @@ -59,7 +59,6 @@ public: inline uint32_t printTime() const { return m_printTime; } inline bool isWatch() const override { return m_watch && !m_fileName.isNull(); } - inline const Algorithm &algorithm() const override { return m_algorithm; } inline const String &fileName() const override { return m_fileName; } inline void setFileName(const char *fileName) override { m_fileName = fileName; } @@ -69,13 +68,12 @@ public: void printVersions(); protected: - Algorithm m_algorithm; - bool m_autoSave; - bool m_background; - bool m_dryRun; - bool m_syslog; - bool m_upgrade; - bool m_watch; + bool m_autoSave = true; + bool m_background = false; + bool m_dryRun = false; + bool m_syslog = false; + bool m_upgrade = false; + bool m_watch = true; Http m_http; Pools m_pools; String m_apiId; diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h index 3d0407e6..c8189ba5 100644 --- a/src/base/kernel/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -144,7 +144,6 @@ public: virtual bool isWatch() const = 0; virtual bool read(const IJsonReader &reader, const char *fileName) = 0; virtual bool save() = 0; - virtual const Algorithm &algorithm() const = 0; virtual const String &fileName() const = 0; virtual void getJSON(rapidjson::Document &doc) const = 0; virtual void setFileName(const char *fileName) = 0; diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 1d448ddf..05e53c78 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -333,17 +333,6 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) job.setAlgorithm(params["algo"].GetString()); } - if (params.HasMember("variant")) { - const rapidjson::Value &variant = params["variant"]; - - if (variant.IsInt()) { - job.setVariant(variant.GetInt()); - } - else if (variant.IsString()){ - job.setVariant(variant.GetString()); - } - } - if (params.HasMember("height")) { const rapidjson::Value &variant = params["height"]; @@ -438,7 +427,7 @@ bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm) const } # endif - if (m_pool.isCompatible(algorithm)) { + if (m_pool.algorithm() == algorithm) { // FIXME return true; } @@ -590,18 +579,18 @@ void xmrig::Client::login() params.AddMember("rigid", m_pool.rigId().toJSON(), allocator); } -# ifdef XMRIG_PROXY_PROJECT - if (m_pool.algorithm().variant() != xmrig::VARIANT_AUTO) -# endif - { - Value algo(kArrayType); +//# ifdef XMRIG_PROXY_PROJECT FIXME +// if (m_pool.algorithm().variant() != xmrig::VARIANT_AUTO) +//# endif +// { +// Value algo(kArrayType); - for (const auto &a : m_pool.algorithms()) { - algo.PushBack(StringRef(a.shortName()), allocator); - } +// for (const auto &a : m_pool.algorithms()) { +// algo.PushBack(StringRef(a.shortName()), allocator); +// } - params.AddMember("algo", algo, allocator); - } +// params.AddMember("algo", algo, allocator); +// } m_listener->onLogin(this, doc, params); diff --git a/src/base/net/stratum/Job.cpp b/src/base/net/stratum/Job.cpp index 1f1cd413..293d0f46 100644 --- a/src/base/net/stratum/Job.cpp +++ b/src/base/net/stratum/Job.cpp @@ -34,10 +34,8 @@ xmrig::Job::Job() : - m_autoVariant(false), m_nicehash(false), m_poolId(-2), - m_threadId(-1), m_size(0), m_diff(0), m_height(0), @@ -49,10 +47,8 @@ xmrig::Job::Job() : xmrig::Job::Job(int poolId, bool nicehash, const Algorithm &algorithm, const String &clientId) : m_algorithm(algorithm), - m_autoVariant(algorithm.variant() == VARIANT_AUTO), m_nicehash(nicehash), m_poolId(poolId), - m_threadId(-1), m_size(0), m_clientId(clientId), m_diff(0), @@ -98,10 +94,6 @@ bool xmrig::Job::setBlob(const char *blob) m_nicehash = true; } - if (m_autoVariant) { - m_algorithm.setVariant(variant()); - } - # ifdef XMRIG_PROXY_PROJECT memset(m_rawBlob, 0, sizeof(m_rawBlob)); memcpy(m_rawBlob, blob, m_size * 2); @@ -153,16 +145,6 @@ bool xmrig::Job::setTarget(const char *target) } -void xmrig::Job::setAlgorithm(const char *algo) -{ - m_algorithm.parseAlgorithm(algo); - - if (m_algorithm.variant() == xmrig::VARIANT_AUTO) { - m_algorithm.setVariant(variant()); - } -} - - void xmrig::Job::setDiff(uint64_t diff) { m_diff = diff; @@ -173,23 +155,3 @@ void xmrig::Job::setDiff(uint64_t diff) m_rawTarget[16] = '\0'; # endif } - - -xmrig::Variant xmrig::Job::variant() const -{ - switch (m_algorithm.algo()) { - case CRYPTONIGHT: - return (m_blob[0] >= 10) ? VARIANT_4 : ((m_blob[0] >= 8) ? VARIANT_2 : VARIANT_1); - - case CRYPTONIGHT_LITE: - return VARIANT_1; - - case CRYPTONIGHT_HEAVY: - return VARIANT_0; - - default: - break; - } - - return m_algorithm.variant(); -} diff --git a/src/base/net/stratum/Job.h b/src/base/net/stratum/Job.h index 5052040a..518a337e 100644 --- a/src/base/net/stratum/Job.h +++ b/src/base/net/stratum/Job.h @@ -53,7 +53,6 @@ public: bool isEqual(const Job &other) const; bool setBlob(const char *blob); bool setTarget(const char *target); - void setAlgorithm(const char *algo); void setDiff(uint64_t diff); inline bool isNicehash() const { return m_nicehash; } @@ -65,7 +64,6 @@ public: inline const uint32_t *nonce() const { return reinterpret_cast(m_blob + 39); } inline const uint8_t *blob() const { return m_blob; } inline int poolId() const { return m_poolId; } - inline int threadId() const { return m_threadId; } inline size_t size() const { return m_size; } inline uint32_t *nonce() { return reinterpret_cast(m_blob + 39); } inline uint64_t diff() const { return m_diff; } @@ -73,12 +71,10 @@ public: inline uint64_t target() const { return m_target; } inline uint8_t fixedByte() const { return *(m_blob + 42); } inline void reset() { m_size = 0; m_diff = 0; } + 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; } inline void setPoolId(int poolId) { m_poolId = poolId; } - inline void setThreadId(int threadId) { m_threadId = threadId; } - inline void setVariant(const char *variant) { m_algorithm.parseVariant(variant); } - inline void setVariant(int variant) { m_algorithm.parseVariant(variant); } # ifdef XMRIG_PROXY_PROJECT inline char *rawBlob() { return m_rawBlob; } @@ -93,13 +89,9 @@ public: inline bool operator!=(const Job &other) const { return !isEqual(other); } private: - Variant variant() const; - Algorithm m_algorithm; - bool m_autoVariant; bool m_nicehash; int m_poolId; - int m_threadId; size_t m_size; String m_clientId; String m_id; diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index f441ba63..bb3fab72 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -47,6 +47,7 @@ namespace xmrig { +static const char *kAlgo = "algo"; static const char *kDaemon = "daemon"; static const char *kDaemonPollInterval = "daemon-poll-interval"; static const char *kEnabled = "enabled"; @@ -58,7 +59,6 @@ static const char *kRigId = "rig-id"; static const char *kTls = "tls"; static const char *kUrl = "url"; static const char *kUser = "user"; -static const char *kVariant = "variant"; const String Pool::kDefaultPassword = "x"; const String Pool::kDefaultUser = "x"; @@ -119,6 +119,7 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : m_rigId = Json::getString(object, kRigId); m_fingerprint = Json::getString(object, kFingerprint); m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval); + m_algorithm = Json::getString(object, kAlgo); m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true)); m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash)); @@ -132,15 +133,6 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : else if (keepalive.IsBool()) { setKeepAlive(keepalive.GetBool()); } - - const rapidjson::Value &variant = Json::getValue(object, kVariant); - if (variant.IsString()) { - algorithm().parseVariant(variant.GetString()); - } - else if (variant.IsInt()) { - algorithm().parseVariant(variant.GetInt()); - } - } @@ -166,28 +158,6 @@ xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char } -bool xmrig::Pool::isCompatible(const Algorithm &algorithm) const -{ - if (m_algorithms.empty()) { - return true; - } - - for (const auto &a : m_algorithms) { - if (algorithm == a) { - return true; - } - } - -# ifdef XMRIG_PROXY_PROJECT - if (m_algorithm.algo() == xmrig::CRYPTONIGHT && algorithm.algo() == xmrig::CRYPTONIGHT) { - return m_algorithm.variant() == xmrig::VARIANT_RWZ || m_algorithm.variant() == xmrig::VARIANT_ZLS; - } -# endif - - return false; -} - - bool xmrig::Pool::isEnabled() const { # ifndef XMRIG_FEATURE_TLS @@ -289,6 +259,7 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const Value obj(kObjectType); + obj.AddMember(StringRef(kAlgo), StringRef(m_algorithm.shortName()), allocator); obj.AddMember(StringRef(kUrl), m_url.toJSON(), allocator); obj.AddMember(StringRef(kUser), m_user.toJSON(), allocator); obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator); @@ -305,22 +276,6 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const obj.AddMember(StringRef(kKeepalive), m_keepAlive, allocator); } - switch (m_algorithm.variant()) { - case VARIANT_AUTO: - case VARIANT_0: - case VARIANT_1: - obj.AddMember(StringRef(kVariant), m_algorithm.variant(), allocator); - break; - - case VARIANT_2: - obj.AddMember(StringRef(kVariant), 2, allocator); - break; - - default: - obj.AddMember(StringRef(kVariant), StringRef(m_algorithm.variantName()), allocator); - break; - } - obj.AddMember(StringRef(kEnabled), m_flags.test(FLAG_ENABLED), allocator); obj.AddMember(StringRef(kTls), isTLS(), allocator); obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator); @@ -331,29 +286,6 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const } -void xmrig::Pool::adjust(const Algorithm &algorithm) -{ - if (!isValid()) { - return; - } - - if (!m_algorithm.isValid()) { - m_algorithm.setAlgo(algorithm.algo()); - adjustVariant(algorithm.variant()); - } - - rebuild(); -} - - -void xmrig::Pool::setAlgo(const xmrig::Algorithm &algorithm) -{ - m_algorithm = algorithm; - - rebuild(); -} - - #ifdef APP_DEBUG void xmrig::Pool::print() const { @@ -391,132 +323,3 @@ bool xmrig::Pool::parseIPv6(const char *addr) return true; } - - -void xmrig::Pool::addVariant(xmrig::Variant variant) -{ - const xmrig::Algorithm algorithm(m_algorithm.algo(), variant); - if (!algorithm.isValid() || m_algorithm == algorithm) { - return; - } - - m_algorithms.push_back(algorithm); -} - - -void xmrig::Pool::adjustVariant(const xmrig::Variant variantHint) -{ -# ifndef XMRIG_PROXY_PROJECT - using namespace xmrig; - - if (m_host.contains(".nicehash.com")) { - m_flags.set(FLAG_NICEHASH, true); - m_keepAlive = false; - bool valid = true; - - switch (m_port) { - case 3355: - case 33355: - valid = m_algorithm.algo() == CRYPTONIGHT && m_host.contains("cryptonight."); - m_algorithm.setVariant(VARIANT_0); - break; - - case 3363: - case 33363: - valid = m_algorithm.algo() == CRYPTONIGHT && m_host.contains("cryptonightv7."); - m_algorithm.setVariant(VARIANT_1); - break; - - case 3364: - valid = m_algorithm.algo() == CRYPTONIGHT_HEAVY && m_host.contains("cryptonightheavy."); - m_algorithm.setVariant(VARIANT_0); - break; - - case 3367: - case 33367: - valid = m_algorithm.algo() == CRYPTONIGHT && m_host.contains("cryptonightv8."); - m_algorithm.setVariant(VARIANT_2); - break; - - default: - break; - } - - if (!valid) { - m_algorithm.setAlgo(INVALID_ALGO); - } - - m_flags.set(FLAG_TLS, m_port > 33000); - return; - } - - if (m_host.contains(".minergate.com")) { - m_keepAlive = false; - bool valid = true; - m_algorithm.setVariant(VARIANT_1); - - if (m_host.contains("xmr.pool.")) { - valid = m_algorithm.algo() == CRYPTONIGHT; - m_algorithm.setVariant(m_port == 45700 ? VARIANT_AUTO : VARIANT_0); - } - else if (m_host.contains("aeon.pool.") && m_port == 45690) { - valid = m_algorithm.algo() == CRYPTONIGHT_LITE; - m_algorithm.setVariant(VARIANT_1); - } - - if (!valid) { - m_algorithm.setAlgo(INVALID_ALGO); - } - - return; - } - - if (variantHint != VARIANT_AUTO) { - m_algorithm.setVariant(variantHint); - return; - } - - if (m_algorithm.variant() != VARIANT_AUTO) { - return; - } - - if (m_algorithm.algo() == CRYPTONIGHT_HEAVY) { - m_algorithm.setVariant(VARIANT_0); - } - else if (m_algorithm.algo() == CRYPTONIGHT_LITE) { - m_algorithm.setVariant(VARIANT_1); - } -# endif -} - - -void xmrig::Pool::rebuild() -{ - m_algorithms.clear(); - - if (!m_algorithm.isValid()) { - return; - } - - m_algorithms.push_back(m_algorithm); - -# ifndef XMRIG_PROXY_PROJECT - addVariant(VARIANT_4); - addVariant(VARIANT_WOW); - addVariant(VARIANT_2); - addVariant(VARIANT_1); - addVariant(VARIANT_0); - addVariant(VARIANT_HALF); - addVariant(VARIANT_XTL); - addVariant(VARIANT_TUBE); - addVariant(VARIANT_MSR); - addVariant(VARIANT_XHV); - addVariant(VARIANT_XAO); - addVariant(VARIANT_RTO); - addVariant(VARIANT_GPU); - addVariant(VARIANT_RWZ); - addVariant(VARIANT_ZLS); - addVariant(VARIANT_DOUBLE); - addVariant(VARIANT_AUTO); -# endif -} diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h index 5348271a..36c3ed1b 100644 --- a/src/base/net/stratum/Pool.h +++ b/src/base/net/stratum/Pool.h @@ -69,13 +69,11 @@ public: bool tls = false ); - inline Algorithm &algorithm() { return m_algorithm; } inline bool isDaemon() const { return m_flags.test(FLAG_DAEMON); } inline bool isNicehash() const { return m_flags.test(FLAG_NICEHASH); } 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 Algorithms &algorithms() const { return m_algorithms; } 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; } @@ -85,6 +83,7 @@ public: inline int keepAlive() const { return m_keepAlive; } inline uint16_t port() const { return m_port; } inline uint64_t pollInterval() const { return m_pollInterval; } + inline void setAlgo(const Algorithm &algorithm) { m_algorithm = algorithm; } inline void setPassword(const String &password) { m_password = password; } inline void setRigId(const String &rigId) { m_rigId = rigId; } inline void setUser(const String &user) { m_user = user; } @@ -92,13 +91,10 @@ public: inline bool operator!=(const Pool &other) const { return !isEqual(other); } inline bool operator==(const Pool &other) const { return isEqual(other); } - bool isCompatible(const Algorithm &algorithm) const; bool isEnabled() const; bool isEqual(const Pool &other) const; bool parse(const char *url); rapidjson::Value toJSON(rapidjson::Document &doc) const; - void adjust(const Algorithm &algorithm); - void setAlgo(const Algorithm &algorithm); # ifdef APP_DEBUG void print() const; @@ -109,12 +105,8 @@ private: inline void setKeepAlive(int keepAlive) { m_keepAlive = keepAlive >= 0 ? keepAlive : 0; } bool parseIPv6(const char *addr); - void addVariant(Variant variant); - void adjustVariant(const Variant variantHint); - void rebuild(); Algorithm m_algorithm; - Algorithms m_algorithms; 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 638ba5ea..985e5d4e 100644 --- a/src/base/net/stratum/Pools.cpp +++ b/src/base/net/stratum/Pools.cpp @@ -24,6 +24,7 @@ #include "base/io/log/Log.h" +#include "base/kernel/interfaces/IJsonReader.h" #include "base/net/stratum/Pools.h" #include "base/net/stratum/strategies/FailoverStrategy.h" #include "base/net/stratum/strategies/SinglePoolStrategy.h" @@ -103,18 +104,11 @@ size_t xmrig::Pools::active() const } -void xmrig::Pools::adjust(const Algorithm &algorithm) -{ - for (Pool &pool : m_data) { - pool.adjust(algorithm); - } -} - - -void xmrig::Pools::load(const rapidjson::Value &pools) +void xmrig::Pools::load(const IJsonReader &reader) { m_data.clear(); + const rapidjson::Value &pools = reader.getArray("pools"); if (!pools.IsArray()) { return; } @@ -129,6 +123,11 @@ void xmrig::Pools::load(const rapidjson::Value &pools) m_data.push_back(std::move(pool)); } } + + setDonateLevel(reader.getInt("donate-level", kDefaultDonateLevel)); + setProxyDonate(reader.getInt("donate-over-proxy", PROXY_DONATE_AUTO)); + setRetries(reader.getInt("retries")); + setRetryPause(reader.getInt("retry-pause")); } @@ -136,11 +135,11 @@ 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 " variant " WHITE_BOLD("%s"), + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("POOL #%-7zu") CSI "1;%dm%s" CLEAR " algo " WHITE_BOLD("%s"), i, (pool.isEnabled() ? (pool.isTLS() ? 32 : 36) : 31), pool.url().data(), - pool.algorithm().variantName() + pool.algorithm().shortName() ); i++; diff --git a/src/base/net/stratum/Pools.h b/src/base/net/stratum/Pools.h index 6a63f166..70e17225 100644 --- a/src/base/net/stratum/Pools.h +++ b/src/base/net/stratum/Pools.h @@ -35,6 +35,7 @@ namespace xmrig { +class IJsonReader; class IStrategy; class IStrategyListener; @@ -63,15 +64,15 @@ public: IStrategy *createStrategy(IStrategyListener *listener) const; rapidjson::Value toJSON(rapidjson::Document &doc) const; size_t active() const; - void adjust(const Algorithm &algorithm); - void load(const rapidjson::Value &pools); + void load(const IJsonReader &reader); void print() const; + +private: void setDonateLevel(int level); void setProxyDonate(int value); void setRetries(int retries); void setRetryPause(int retryPause); -private: int m_donateLevel; int m_retries; int m_retryPause; diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index c1430e4d..fbb12ffa 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -87,8 +87,6 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const auto &allocator = doc.GetAllocator(); - doc.AddMember("algo", StringRef(algorithm().name()), allocator); - Value api(kObjectType); api.AddMember("id", m_apiId.toJSON(), allocator); api.AddMember("worker-id", m_apiWorkerId.toJSON(), allocator); @@ -146,37 +144,37 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const bool xmrig::Config::finalize() { - if (!m_threads.cpu.empty()) { - m_threads.mode = Advanced; - const bool softAES = (m_aesMode == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aesMode) == AES_SOFT; +// if (!m_threads.cpu.empty()) { // FIXME +// m_threads.mode = Advanced; +// const bool softAES = (m_aesMode == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aesMode) == AES_SOFT; - for (size_t i = 0; i < m_threads.cpu.size(); ++i) { - m_threads.list.push_back(CpuThread::createFromData(i, m_algorithm.algo(), m_threads.cpu[i], m_priority, softAES)); - } +// for (size_t i = 0; i < m_threads.cpu.size(); ++i) { +//// m_threads.list.push_back(CpuThread::createFromData(i, m_algorithm.algo(), m_threads.cpu[i], m_priority, softAES)); +// } - return true; - } +// return true; +// } - const AlgoVariant av = getAlgoVariant(); - m_threads.mode = m_threads.count ? Simple : Automatic; +// const AlgoVariant av = getAlgoVariant(); +// m_threads.mode = m_threads.count ? Simple : Automatic; - const size_t size = CpuThread::multiway(av) * cn_select_memory(m_algorithm.algo()) / 1024; +//// const size_t size = CpuThread::multiway(av) * cn_select_memory(m_algorithm.algo()) / 1024; - if (!m_threads.count) { - m_threads.count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); - } - else if (m_safe) { - const size_t count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); - if (m_threads.count > count) { - m_threads.count = count; - } - } +// if (!m_threads.count) { +// m_threads.count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); +// } +// else if (m_safe) { +// const size_t count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); +// if (m_threads.count > count) { +// m_threads.count = count; +// } +// } - for (size_t i = 0; i < m_threads.count; ++i) { - m_threads.list.push_back(CpuThread::createFromAV(i, m_algorithm.algo(), av, m_threads.mask, m_priority, m_assembly)); - } +// for (size_t i = 0; i < m_threads.count; ++i) { +// m_threads.list.push_back(CpuThread::createFromAV(i, m_algorithm.algo(), av, m_threads.mask, m_priority, m_assembly)); +// } - m_shouldSave = m_threads.mode == Automatic; +// m_shouldSave = m_threads.mode == Automatic; return true; } @@ -245,9 +243,9 @@ void xmrig::Config::setThreads(const rapidjson::Value &threads) xmrig::AlgoVariant xmrig::Config::getAlgoVariant() const { # ifdef XMRIG_ALGO_CN_LITE - if (m_algorithm.algo() == xmrig::CRYPTONIGHT_LITE) { - return getAlgoVariantLite(); - } +// if (m_algorithm.algo() == xmrig::CRYPTONIGHT_LITE) { // FIXME +// return getAlgoVariantLite(); +// } # endif if (m_algoVariant <= AV_AUTO || m_algoVariant >= AV_MAX) { diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index 29ca9ecf..f85b0a6f 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -44,254 +44,96 @@ #endif -struct AlgoData +namespace xmrig { + + +struct AlgoName { const char *name; const char *shortName; - xmrig::Algo algo; - xmrig::Variant variant; + const Algorithm::Id id; }; -static AlgoData const algorithms[] = { - { "cryptonight", "cn", xmrig::CRYPTONIGHT, xmrig::VARIANT_AUTO }, - { "cryptonight/0", "cn/0", xmrig::CRYPTONIGHT, xmrig::VARIANT_0 }, - { "cryptonight/1", "cn/1", xmrig::CRYPTONIGHT, xmrig::VARIANT_1 }, - { "cryptonight/xtl", "cn/xtl", xmrig::CRYPTONIGHT, xmrig::VARIANT_XTL }, - { "cryptonight/msr", "cn/msr", xmrig::CRYPTONIGHT, xmrig::VARIANT_MSR }, - { "cryptonight/xao", "cn/xao", xmrig::CRYPTONIGHT, xmrig::VARIANT_XAO }, - { "cryptonight/rto", "cn/rto", xmrig::CRYPTONIGHT, xmrig::VARIANT_RTO }, - { "cryptonight/2", "cn/2", xmrig::CRYPTONIGHT, xmrig::VARIANT_2 }, - { "cryptonight/half", "cn/half", xmrig::CRYPTONIGHT, xmrig::VARIANT_HALF }, - { "cryptonight/xtlv9", "cn/xtlv9", xmrig::CRYPTONIGHT, xmrig::VARIANT_HALF }, - { "cryptonight/wow", "cn/wow", xmrig::CRYPTONIGHT, xmrig::VARIANT_WOW }, - { "cryptonight/r", "cn/r", xmrig::CRYPTONIGHT, xmrig::VARIANT_4 }, - { "cryptonight/rwz", "cn/rwz", xmrig::CRYPTONIGHT, xmrig::VARIANT_RWZ }, - { "cryptonight/zls", "cn/zls", xmrig::CRYPTONIGHT, xmrig::VARIANT_ZLS }, - { "cryptonight/double", "cn/double", xmrig::CRYPTONIGHT, xmrig::VARIANT_DOUBLE }, - -# ifdef XMRIG_ALGO_CN_LITE - { "cryptonight-lite", "cn-lite", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_AUTO }, - { "cryptonight-light", "cn-light", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_AUTO }, - { "cryptonight-lite/0", "cn-lite/0", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_0 }, - { "cryptonight-lite/1", "cn-lite/1", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_1 }, -# endif - -# ifdef XMRIG_ALGO_CN_HEAVY - { "cryptonight-heavy", "cn-heavy", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_AUTO }, - { "cryptonight-heavy/0", "cn-heavy/0", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_0 }, - { "cryptonight-heavy/xhv", "cn-heavy/xhv", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_XHV }, - { "cryptonight-heavy/tube", "cn-heavy/tube", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_TUBE }, -# endif - -# ifdef XMRIG_ALGO_CN_PICO - { "cryptonight-pico/trtl", "cn-pico/trtl", xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, - { "cryptonight-pico", "cn-pico", xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, - { "cryptonight-turtle", "cn-trtl", xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, - { "cryptonight-ultralite", "cn-ultralite", xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, - { "cryptonight_turtle", "cn_turtle", xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, -# endif - +static AlgoName const algorithm_names[] = { + { "cryptonight/0", "cn/0", Algorithm::CN_0 }, + { "cryptonight", "cn", Algorithm::CN_0 }, + { "cryptonight/1", "cn/1", Algorithm::CN_1 }, + { "cryptonight-monerov7", nullptr, Algorithm::CN_1 }, + { "cryptonight_v7", nullptr, Algorithm::CN_1 }, + { "cryptonight/2", "cn/2", Algorithm::CN_2 }, + { "cryptonight-monerov8", nullptr, Algorithm::CN_2 }, + { "cryptonight_v8", nullptr, Algorithm::CN_2 }, + { "cryptonight/r", "cn/r", Algorithm::CN_R }, + { "cryptonight_r", nullptr, Algorithm::CN_R }, + { "cryptonight/wow", "cn/wow", Algorithm::CN_WOW }, + { "cryptonight/fast", "cn/fast", Algorithm::CN_FAST }, + { "cryptonight/msr", "cn/msr", Algorithm::CN_FAST }, + { "cryptonight/half", "cn/half", Algorithm::CN_HALF }, + { "cryptonight/xao", "cn/xao", Algorithm::CN_XAO }, + { "cryptonight_alloy", nullptr, Algorithm::CN_XAO }, + { "cryptonight/rto", "cn/rto", Algorithm::CN_RTO }, + { "cryptonight/rwz", "cn/rwz", Algorithm::CN_RWZ }, + { "cryptonight/zls", "cn/zls", Algorithm::CN_ZLS }, + { "cryptonight/double", "cn/double", Algorithm::CN_ZLS }, # ifdef XMRIG_ALGO_CN_GPU - { "cryptonight/gpu", "cn/gpu", xmrig::CRYPTONIGHT, xmrig::VARIANT_GPU }, + { "cryptonight/gpu", "cn/gpu", Algorithm::CN_GPU }, + { "cryptonight_gpu", nullptr, Algorithm::CN_GPU }, +# endif +# ifdef XMRIG_ALGO_CN_LITE + { "cryptonight-lite/0", "cn-lite/0", Algorithm::CN_LITE_0 }, + { "cryptonight-lite/1", "cn-lite/1", Algorithm::CN_LITE_1 }, + { "cryptonight-lite", "cn-lite", Algorithm::CN_LITE_1 }, + { "cryptonight-light", "cn-light", Algorithm::CN_LITE_1 }, + { "cryptonight_lite", nullptr, Algorithm::CN_LITE_1 }, + { "cryptonight-aeonv7", nullptr, Algorithm::CN_LITE_1 }, + { "cryptonight_lite_v7", nullptr, Algorithm::CN_LITE_1 }, +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + { "cryptonight-heavy/0", "cn-heavy/0", Algorithm::CN_HEAVY_0 }, + { "cryptonight-heavy", "cn-heavy", Algorithm::CN_HEAVY_0 }, + { "cryptonight_heavy", nullptr, Algorithm::CN_HEAVY_0 }, + { "cryptonight-heavy/xhv", "cn-heavy/xhv", Algorithm::CN_HEAVY_XHV }, + { "cryptonight_haven", nullptr, Algorithm::CN_HEAVY_XHV }, + { "cryptonight-heavy/tube", "cn-heavy/tube", Algorithm::CN_HEAVY_TUBE }, + { "cryptonight-bittube2", nullptr, Algorithm::CN_HEAVY_TUBE }, +# endif +# ifdef XMRIG_ALGO_CN_PICO + { "cryptonight-pico", "cn-pico", Algorithm::CN_PICO }, + { "cryptonight-pico/trtl", "cn-pico/trtl", Algorithm::CN_PICO }, + { "cryptonight-turtle", "cn-trtl", Algorithm::CN_PICO }, + { "cryptonight-ultralite", "cn-ultralite", Algorithm::CN_PICO }, + { "cryptonight_turtle", "cn_turtle", Algorithm::CN_PICO }, # endif }; -#ifdef XMRIG_PROXY_PROJECT -static AlgoData const xmrStakAlgorithms[] = { - { "cryptonight-monerov7", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_1 }, - { "cryptonight_v7", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_1 }, - { "cryptonight-monerov8", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_2 }, - { "cryptonight_v8", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_2 }, - { "cryptonight_v7_stellite", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_XTL }, - { "cryptonight_lite", nullptr, xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_0 }, - { "cryptonight-aeonv7", nullptr, xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_1 }, - { "cryptonight_lite_v7", nullptr, xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_1 }, - { "cryptonight_heavy", nullptr, xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_0 }, - { "cryptonight_haven", nullptr, xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_XHV }, - { "cryptonight_masari", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_MSR }, - { "cryptonight_masari", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_MSR }, - { "cryptonight-bittube2", nullptr, xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_TUBE }, // bittube-miner - { "cryptonight_alloy", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_XAO }, // xmr-stak-alloy - { "cryptonight_turtle", nullptr, xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, - { "cryptonight_gpu", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_GPU }, - { "cryptonight_r", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_4 }, -}; -#endif - - -static const char *variants[] = { - "0", - "1", - "tube", - "xtl", - "msr", - "xhv", - "xao", - "rto", - "2", - "half", - "trtl", - "gpu", - "wow", - "r", - "rwz", - "zls", - "double" -}; - - -static_assert(xmrig::VARIANT_MAX == ARRAY_SIZE(variants), "variants size mismatch"); - - -bool xmrig::Algorithm::isValid() const -{ - if (m_algo == INVALID_ALGO) { - return false; - } - - for (size_t i = 0; i < ARRAY_SIZE(algorithms); i++) { - if (algorithms[i].algo == m_algo && algorithms[i].variant == m_variant) { - return true; - } - } - - return false; -} - - -const char *xmrig::Algorithm::variantName() const -{ - if (m_variant == VARIANT_AUTO) { - return "auto"; - } - - return variants[m_variant]; -} - - -void xmrig::Algorithm::parseAlgorithm(const char *algo) -{ - m_algo = INVALID_ALGO; - m_variant = VARIANT_AUTO; - -// assert(algo != nullptr); - if (algo == nullptr || strlen(algo) < 1) { - return; - } - - if (*algo == '!') { - m_flags |= Forced; - - return parseAlgorithm(algo + 1); - } - - for (size_t i = 0; i < ARRAY_SIZE(algorithms); i++) { - if ((strcasecmp(algo, algorithms[i].name) == 0) || (strcasecmp(algo, algorithms[i].shortName) == 0)) { - m_algo = algorithms[i].algo; - m_variant = algorithms[i].variant; - break; - } - } - - if (m_algo == INVALID_ALGO) { - assert(false); - } -} - - -void xmrig::Algorithm::parseVariant(const char *variant) -{ - m_variant = VARIANT_AUTO; - - if (variant == nullptr || strlen(variant) < 1) { - return; - } - - if (*variant == '!') { - m_flags |= Forced; - - return parseVariant(variant + 1); - } - - for (size_t i = 0; i < ARRAY_SIZE(variants); i++) { - if (strcasecmp(variant, variants[i]) == 0) { - m_variant = static_cast(i); - return; - } - } - - if (strcasecmp(variant, "xtlv9") == 0) { - m_variant = VARIANT_HALF; - } -} - - -void xmrig::Algorithm::parseVariant(int variant) -{ - assert(variant >= -1 && variant <= 2); - - switch (variant) { - case -1: - case 0: - case 1: - m_variant = static_cast(variant); - break; - - case 2: - m_variant = VARIANT_2; - break; - - default: - break; - } -} - - -void xmrig::Algorithm::setAlgo(Algo algo) -{ - m_algo = algo; - - if (m_algo == CRYPTONIGHT_PICO && m_variant == VARIANT_AUTO) { - m_variant = xmrig::VARIANT_TRTL; - } -} - - -#ifdef XMRIG_PROXY_PROJECT -void xmrig::Algorithm::parseXmrStakAlgorithm(const char *algo) -{ - m_algo = INVALID_ALGO; - m_variant = VARIANT_AUTO; - - assert(algo != nullptr); - if (algo == nullptr) { - return; - } - - for (size_t i = 0; i < ARRAY_SIZE(xmrStakAlgorithms); i++) { - if (strcasecmp(algo, xmrStakAlgorithms[i].name) == 0) { - m_algo = xmrStakAlgorithms[i].algo; - m_variant = xmrStakAlgorithms[i].variant; - break; - } - } - - if (m_algo == INVALID_ALGO) { - assert(false); - } -} -#endif +} /* namespace xmrig */ const char *xmrig::Algorithm::name(bool shortName) const { - for (size_t i = 0; i < ARRAY_SIZE(algorithms); i++) { - if (algorithms[i].algo == m_algo && algorithms[i].variant == m_variant) { - return shortName ? algorithms[i].shortName : algorithms[i].name; + for (size_t i = 0; i < ARRAY_SIZE(algorithm_names); i++) { + if (algorithm_names[i].id == m_id) { + return shortName ? algorithm_names[i].shortName : algorithm_names[i].name; } } return "invalid"; } + + +xmrig::Algorithm::Id xmrig::Algorithm::parse(const char *name) +{ + if (name == nullptr || strlen(name) < 1) { + return INVALID; + } + + for (size_t i = 0; i < ARRAY_SIZE(algorithm_names); i++) { + if ((strcasecmp(name, algorithm_names[i].name) == 0) || (algorithm_names[i].shortName != nullptr && strcasecmp(name, algorithm_names[i].shortName) == 0)) { + return algorithm_names[i].id; + } + } + + return INVALID; +} diff --git a/src/crypto/common/Algorithm.h b/src/crypto/common/Algorithm.h index 664552aa..c70e0caa 100644 --- a/src/crypto/common/Algorithm.h +++ b/src/crypto/common/Algorithm.h @@ -30,68 +30,63 @@ #include -#include "common/xmrig.h" - - namespace xmrig { class Algorithm { public: - enum Flags { - None = 0, - Forced = 1 + enum Id : int { + INVALID = -1, + CN_0, // "cn/0" Original CryptoNight + CN_1, // "cn/1" CryptoNight variant 1 also known as Monero7 and CryptoNightV7 + CN_2, // "cn/2" CryptoNight variant 2 + CN_R, // "cn/r" CryptoNightR (Monero's variant 4) + CN_WOW, // "cn/wow" CryptoNightR (Wownero) + CN_FAST, // "cn/fast" CryptoNight variant 1 with half iterations + CN_HALF, // "cn/half" CryptoNight variant 2 with half iterations (Masari/Stellite) + CN_XAO, // "cn/xao" Modified CryptoNight variant 0 (Alloy only) + CN_RTO, // "cn/rto" Modified CryptoNight variant 1 (Arto only) + CN_RWZ, // "cn/rwz" CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation (Graft) + CN_ZLS, // "cn/zls" CryptoNight variant 2 with 3/4 iterations (Zelerius) + CN_DOUBLE, // "cn/double" CryptoNight variant 2 with double iterations (X-CASH) +# ifdef XMRIG_ALGO_CN_GPU + CN_GPU, // "cn/gpu" CryptoNight-GPU (Ryo) +# endif +# ifdef XMRIG_ALGO_CN_LITE + CN_LITE_0, // "cn-lite/0" CryptoNight-Lite (1 MB) variant 0 + CN_LITE_1, // "cn-lite/1" CryptoNight-Lite (1 MB) variant 1 +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + CN_HEAVY_0, // "cn-heavy/0" CryptoNight-Heavy (4 MB) + CN_HEAVY_TUBE, // "cn-heavy/tube" Modified CryptoNight-Heavy (TUBE only) + CN_HEAVY_XHV, // "cn-heavy/xhv" Modified CryptoNight-Heavy (Haven Protocol only) +# endif +# ifdef XMRIG_ALGO_CN_PICO + CN_PICO, // "cn-pico" CryptoNight Turtle (TRTL) +# endif + MAX }; - inline Algorithm() : - m_algo(INVALID_ALGO), - m_flags(0), - m_variant(VARIANT_AUTO) - {} + inline Algorithm() {} + inline Algorithm(const char *algo) : m_id(parse(algo)) {} + inline Algorithm(Id id) : m_id(id) {} - inline Algorithm(Algo algo, Variant variant) : - m_flags(0), - m_variant(variant) - { - setAlgo(algo); - } - - inline Algorithm(const char *algo) : - m_flags(0) - { - parseAlgorithm(algo); - } - - inline Algo algo() const { return m_algo; } - inline bool isEqual(const Algorithm &other) const { return m_algo == other.m_algo && m_variant == other.m_variant; } - inline bool isForced() const { return m_flags & Forced; } + inline bool isEqual(const Algorithm &other) const { return m_id == other.m_id; } inline const char *name() const { return name(false); } inline const char *shortName() const { return name(true); } - inline int flags() const { return m_flags; } - inline Variant variant() const { return m_variant; } - inline void setVariant(Variant variant) { m_variant = variant; } + inline Id id() const { return m_id; } + inline bool isValid() const { return m_id != INVALID; } inline bool operator!=(const Algorithm &other) const { return !isEqual(other); } inline bool operator==(const Algorithm &other) const { return isEqual(other); } - bool isValid() const; - const char *variantName() const; - void parseAlgorithm(const char *algo); - void parseVariant(const char *variant); - void parseVariant(int variant); - void setAlgo(Algo algo); - -# ifdef XMRIG_PROXY_PROJECT - void parseXmrStakAlgorithm(const char *algo); -# endif + static Id parse(const char *name); private: const char *name(bool shortName) const; - Algo m_algo; - int m_flags; - Variant m_variant; + Id m_id = INVALID; }; @@ -100,4 +95,5 @@ typedef std::vector Algorithms; } /* namespace xmrig */ -#endif /* __ALGORITHM_H__ */ + +#endif /* XMRIG_ALGORITHM_H */ diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 1ab42236..16669f52 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -231,8 +231,7 @@ void xmrig::Network::getConnection(rapidjson::Value &reply, rapidjson::Document using namespace rapidjson; auto &allocator = doc.GetAllocator(); - const Algorithm &algo = m_strategy->client()->job().algorithm(); - reply.AddMember("algo", StringRef((algo.isValid() ? algo : m_controller->config()->algorithm()).shortName()), allocator); + reply.AddMember("algo", StringRef(m_strategy->client()->job().algorithm().shortName()), allocator); Value connection(kObjectType); connection.AddMember("pool", StringRef(m_state.pool), allocator); diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index fb958a4c..3d913087 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -79,9 +79,9 @@ xmrig::DonateStrategy::DonateStrategy(Controller *controller, IStrategyListener # endif m_pools.push_back(Pool(kDonateHost, 3333, m_userId, nullptr, 0, true)); - for (Pool &pool : m_pools) { - pool.adjust(Algorithm(controller->config()->algorithm().algo(), VARIANT_AUTO)); - } +// for (Pool &pool : m_pools) { +// pool.adjust(Algorithm()); // FIXME +// } if (m_pools.size() > 1) { m_strategy = new FailoverStrategy(m_pools, 1, 2, this, true); diff --git a/src/workers/MultiWorker.cpp b/src/workers/MultiWorker.cpp index e4a5fb0c..30c43000 100644 --- a/src/workers/MultiWorker.cpp +++ b/src/workers/MultiWorker.cpp @@ -126,7 +126,8 @@ void MultiWorker::start() storeStats(); } - m_thread->fn(m_state.job.algorithm().variant())(m_state.blob, m_state.job.size(), m_hash, m_ctx, m_state.job.height()); + // FIXME +// m_thread->fn(m_state.job.algorithm().variant())(m_state.blob, m_state.job.size(), m_hash, m_ctx, m_state.job.height()); for (size_t i = 0; i < N; ++i) { if (*reinterpret_cast(m_hash + (i * 32) + 24) < m_state.job.target()) { diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index b95d8b85..62cbd1cf 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -176,7 +176,7 @@ void Workers::start(xmrig::Controller *controller) m_controller = controller; const std::vector &threads = controller->config()->threads(); - m_status.algo = controller->config()->algorithm().algo(); +// m_status.algo = controller->config()->algorithm().algo(); // FIXME m_status.threads = threads.size(); for (const xmrig::IThread *thread : threads) { From 1f0e3e501cece285744e700d0da95ede52a37fc5 Mon Sep 17 00:00:00 2001 From: XMRig Date: Thu, 13 Jun 2019 22:08:52 +0700 Subject: [PATCH 02/65] Implemented new style algorithm definitions (except ARM), removed Algo and Variant enums. --- CMakeLists.txt | 6 +- cmake/asm.cmake | 5 +- src/Mem.cpp | 13 +- src/Mem.h | 4 +- src/Mem_win.cpp | 1 - src/Summary.cpp | 4 +- src/common/cpu/BasicCpuInfo.cpp | 2 +- src/common/xmrig.h | 33 -- src/core/config/Config.cpp | 57 +- src/core/config/Config.h | 2 +- src/crypto/cn/CnAlgo.h | 207 +++++++ src/crypto/cn/CnHash.cpp | 269 +++++++++ src/crypto/cn/CnHash.h | 63 ++ src/crypto/cn/CryptoNight.h | 4 +- src/crypto/cn/CryptoNight_constants.h | 251 -------- src/crypto/cn/CryptoNight_monero.h | 36 +- src/crypto/cn/CryptoNight_test.h | 15 - src/crypto/cn/CryptoNight_x86.h | 784 ++++++++++++++----------- src/crypto/cn/gpu/cn_gpu_avx.cpp | 6 +- src/crypto/cn/gpu/cn_gpu_ssse3.cpp | 6 +- src/crypto/cn/r/variant4_random_math.h | 19 +- src/crypto/common/Algorithm.cpp | 81 ++- src/crypto/common/Algorithm.h | 15 +- src/interfaces/IThread.h | 4 +- src/workers/CpuThread.cpp | 544 +---------------- src/workers/CpuThread.h | 20 +- src/workers/MultiWorker.cpp | 88 +-- src/workers/MultiWorker.h | 17 +- src/workers/Workers.cpp | 21 +- src/workers/Workers.h | 5 +- 30 files changed, 1223 insertions(+), 1359 deletions(-) create mode 100644 src/crypto/cn/CnAlgo.h create mode 100644 src/crypto/cn/CnHash.cpp create mode 100644 src/crypto/cn/CnHash.h delete mode 100644 src/crypto/cn/CryptoNight_constants.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 30625d28..9c70a673 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,8 @@ set(HEADERS_CRYPTO src/crypto/cn/c_groestl.h src/crypto/cn/c_jh.h src/crypto/cn/c_skein.h - src/crypto/cn/CryptoNight_constants.h + src/crypto/cn/CnAlgo.h + src/crypto/cn/CnHash.h src/crypto/cn/CryptoNight_monero.h src/crypto/cn/CryptoNight_test.h src/crypto/cn/CryptoNight.h @@ -102,10 +103,11 @@ set(SOURCES ) set(SOURCES_CRYPTO - src/crypto/cn/c_groestl.c src/crypto/cn/c_blake256.c + src/crypto/cn/c_groestl.c src/crypto/cn/c_jh.c src/crypto/cn/c_skein.c + src/crypto/cn/CnHash.cpp src/crypto/common/Algorithm.cpp ) diff --git a/cmake/asm.cmake b/cmake/asm.cmake index 25cccead..d3010e51 100644 --- a/cmake/asm.cmake +++ b/cmake/asm.cmake @@ -38,8 +38,11 @@ if (WITH_ASM AND NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8) add_library(${XMRIG_ASM_LIBRARY} STATIC ${XMRIG_ASM_FILES}) set(XMRIG_ASM_SOURCES src/crypto/cn/Asm.h src/crypto/cn/Asm.cpp src/crypto/cn/r/CryptonightR_gen.cpp) set_property(TARGET ${XMRIG_ASM_LIBRARY} PROPERTY LINKER_LANGUAGE C) + + add_definitions(/DXMRIG_FEATURE_ASM) else() set(XMRIG_ASM_SOURCES "") set(XMRIG_ASM_LIBRARY "") - add_definitions(/DXMRIG_NO_ASM) + + remove_definitions(/DXMRIG_FEATURE_ASM) endif() diff --git a/src/Mem.cpp b/src/Mem.cpp index b9e0fbf9..574c5ff2 100644 --- a/src/Mem.cpp +++ b/src/Mem.cpp @@ -27,7 +27,6 @@ #include -#include "crypto/cn/CryptoNight_constants.h" #include "crypto/cn/CryptoNight.h" #include "crypto/common/portable/mm_malloc.h" #include "crypto/common/VirtualMemory.h" @@ -38,12 +37,14 @@ bool Mem::m_enabled = true; int Mem::m_flags = 0; -MemInfo Mem::create(cryptonight_ctx **ctx, xmrig::Algo algorithm, size_t count) +MemInfo Mem::create(cryptonight_ctx **ctx, const xmrig::Algorithm &algorithm, size_t count) { using namespace xmrig; + constexpr CnAlgo props; + MemInfo info; - info.size = cn_select_memory(algorithm) * count; + info.size = props.memory(algorithm.id()) * count; constexpr const size_t align_size = 2 * 1024 * 1024; info.size = ((info.size + align_size - 1) / align_size) * align_size; @@ -53,10 +54,10 @@ MemInfo Mem::create(cryptonight_ctx **ctx, xmrig::Algo algorithm, size_t count) for (size_t i = 0; i < count; ++i) { cryptonight_ctx *c = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 4096)); - c->memory = info.memory + (i * cn_select_memory(algorithm)); + c->memory = info.memory + (i * props.memory(algorithm.id())); - c->generated_code = reinterpret_cast(xmrig::VirtualMemory::allocateExecutableMemory(0x4000)); - c->generated_code_data.variant = xmrig::VARIANT_MAX; + c->generated_code = reinterpret_cast(VirtualMemory::allocateExecutableMemory(0x4000)); + c->generated_code_data.algo = Algorithm::INVALID; c->generated_code_data.height = std::numeric_limits::max(); ctx[i] = c; diff --git a/src/Mem.h b/src/Mem.h index bfb36b00..f43e005d 100644 --- a/src/Mem.h +++ b/src/Mem.h @@ -31,7 +31,7 @@ #include -#include "common/xmrig.h" +#include "crypto/cn/CnAlgo.h" struct cryptonight_ctx; @@ -56,7 +56,7 @@ public: Lock = 4 }; - static MemInfo create(cryptonight_ctx **ctx, xmrig::Algo algorithm, size_t count); + static MemInfo create(cryptonight_ctx **ctx, const xmrig::Algorithm &algorithm, size_t count); static void init(bool enabled); static void release(cryptonight_ctx **ctx, size_t count, MemInfo &info); diff --git a/src/Mem_win.cpp b/src/Mem_win.cpp index 76cbf434..34460e9d 100644 --- a/src/Mem_win.cpp +++ b/src/Mem_win.cpp @@ -34,7 +34,6 @@ #include "common/xmrig.h" #include "crypto/common/portable/mm_malloc.h" #include "crypto/common/VirtualMemory.h" -#include "crypto/cn/CryptoNight_constants.h" #include "crypto/cn/CryptoNight.h" #include "Mem.h" diff --git a/src/Summary.cpp b/src/Summary.cpp index d780d64f..2ba0fd57 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -39,7 +39,7 @@ #include "version.h" -#ifndef XMRIG_NO_ASM +#ifdef XMRIG_FEATURE_ASM static const char *coloredAsmNames[] = { RED_BOLD("none"), "auto", @@ -108,7 +108,7 @@ static void print_threads(xmrig::Config *config) ); } -# ifndef XMRIG_NO_ASM +# ifdef XMRIG_FEATURE_ASM if (config->assembly() == xmrig::ASM_AUTO) { const xmrig::Assembly assembly = xmrig::Cpu::info()->assembly(); diff --git a/src/common/cpu/BasicCpuInfo.cpp b/src/common/cpu/BasicCpuInfo.cpp index d7778bdd..c5b8ed0a 100644 --- a/src/common/cpu/BasicCpuInfo.cpp +++ b/src/common/cpu/BasicCpuInfo.cpp @@ -129,7 +129,7 @@ xmrig::BasicCpuInfo::BasicCpuInfo() : { cpu_brand_string(m_brand); -# ifndef XMRIG_NO_ASM +# ifdef XMRIG_FEATURE_ASM if (hasAES()) { char vendor[13] = { 0 }; int32_t data[4] = { 0 }; diff --git a/src/common/xmrig.h b/src/common/xmrig.h index e8ca8857..5dd41845 100644 --- a/src/common/xmrig.h +++ b/src/common/xmrig.h @@ -30,16 +30,6 @@ namespace xmrig { -enum Algo { - INVALID_ALGO = -1, - CRYPTONIGHT, /* CryptoNight (2 MB) */ - CRYPTONIGHT_LITE, /* CryptoNight (1 MB) */ - CRYPTONIGHT_HEAVY, /* CryptoNight (4 MB) */ - CRYPTONIGHT_PICO, /* CryptoNight (256 KB) */ - ALGO_MAX -}; - - //--av=1 For CPUs with hardware AES. //--av=2 Lower power mode (double hash) of 1. //--av=3 Software AES implementation. @@ -60,29 +50,6 @@ enum AlgoVariant { }; -enum Variant { - VARIANT_AUTO = -1, // Autodetect - VARIANT_0 = 0, // Original CryptoNight or CryptoNight-Heavy - VARIANT_1 = 1, // CryptoNight variant 1 also known as Monero7 and CryptoNightV7 - VARIANT_TUBE = 2, // Modified CryptoNight-Heavy (TUBE only) - VARIANT_XTL = 3, // Modified CryptoNight variant 1 (Stellite only) - VARIANT_MSR = 4, // Modified CryptoNight variant 1 (Masari only) - VARIANT_XHV = 5, // Modified CryptoNight-Heavy (Haven Protocol only) - VARIANT_XAO = 6, // Modified CryptoNight variant 0 (Alloy only) - VARIANT_RTO = 7, // Modified CryptoNight variant 1 (Arto only) - VARIANT_2 = 8, // CryptoNight variant 2 - VARIANT_HALF = 9, // CryptoNight variant 2 with half iterations (Masari/Stellite) - VARIANT_TRTL = 10, // CryptoNight Turtle (TRTL) - VARIANT_GPU = 11, // CryptoNight-GPU (Ryo) - VARIANT_WOW = 12, // CryptoNightR (Wownero) - VARIANT_4 = 13, // CryptoNightR (Monero's variant 4) - VARIANT_RWZ = 14, // CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation (Graft) - VARIANT_ZLS = 15, // CryptoNight variant 2 with 3/4 iterations (Zelerius) - VARIANT_DOUBLE = 16, // CryptoNight variant 2 with double iterations (X-CASH) - VARIANT_MAX -}; - - enum AlgoVerify { VERIFY_HW_AES = 1, VERIFY_SOFT_AES = 2 diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index fbb12ffa..d82c3225 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -33,7 +33,6 @@ #include "common/cpu/Cpu.h" #include "core/config/Config.h" #include "crypto/cn/Asm.h" -#include "crypto/cn/CryptoNight_constants.h" #include "rapidjson/document.h" #include "rapidjson/filewritestream.h" #include "rapidjson/prettywriter.h" @@ -71,7 +70,7 @@ bool xmrig::Config::read(const IJsonReader &reader, const char *fileName) setPriority(reader.getInt("cpu-priority", -1)); setThreads(reader.getValue("threads")); -# ifndef XMRIG_NO_ASM +# ifdef XMRIG_FEATURE_ASM setAssembly(reader.getValue("asm")); # endif @@ -93,7 +92,7 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const doc.AddMember("api", api, allocator); doc.AddMember("http", m_http.toJSON(doc), allocator); -# ifndef XMRIG_NO_ASM +# ifdef XMRIG_FEATURE_ASM doc.AddMember("asm", Asm::toJSON(m_assembly), allocator); # endif @@ -144,37 +143,39 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const bool xmrig::Config::finalize() { -// if (!m_threads.cpu.empty()) { // FIXME -// m_threads.mode = Advanced; -// const bool softAES = (m_aesMode == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aesMode) == AES_SOFT; + Algorithm algorithm(Algorithm::CN_0); // FIXME algo -// for (size_t i = 0; i < m_threads.cpu.size(); ++i) { -//// m_threads.list.push_back(CpuThread::createFromData(i, m_algorithm.algo(), m_threads.cpu[i], m_priority, softAES)); -// } + if (!m_threads.cpu.empty()) { + m_threads.mode = Advanced; + const bool softAES = (m_aesMode == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aesMode) == AES_SOFT; -// return true; -// } + for (size_t i = 0; i < m_threads.cpu.size(); ++i) { + m_threads.list.push_back(CpuThread::createFromData(i, algorithm, m_threads.cpu[i], m_priority, softAES)); + } -// const AlgoVariant av = getAlgoVariant(); -// m_threads.mode = m_threads.count ? Simple : Automatic; + return true; + } -//// const size_t size = CpuThread::multiway(av) * cn_select_memory(m_algorithm.algo()) / 1024; + const AlgoVariant av = getAlgoVariant(); + m_threads.mode = m_threads.count ? Simple : Automatic; -// if (!m_threads.count) { -// m_threads.count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); -// } -// else if (m_safe) { -// const size_t count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); -// if (m_threads.count > count) { -// m_threads.count = count; -// } -// } + const size_t size = CpuThread::multiway(av) * CnAlgo<>::memory(algorithm) / 1024; -// for (size_t i = 0; i < m_threads.count; ++i) { -// m_threads.list.push_back(CpuThread::createFromAV(i, m_algorithm.algo(), av, m_threads.mask, m_priority, m_assembly)); -// } + if (!m_threads.count) { + m_threads.count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); + } + else if (m_safe) { + const size_t count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); + if (m_threads.count > count) { + m_threads.count = count; + } + } -// m_shouldSave = m_threads.mode == Automatic; + for (size_t i = 0; i < m_threads.count; ++i) { + m_threads.list.push_back(CpuThread::createFromAV(i, algorithm, av, m_threads.mask, m_priority, m_assembly)); + } + + m_shouldSave = m_threads.mode == Automatic; return true; } @@ -276,7 +277,7 @@ xmrig::AlgoVariant xmrig::Config::getAlgoVariantLite() const #endif -#ifndef XMRIG_NO_ASM +#ifdef XMRIG_FEATURE_ASM void xmrig::Config::setAssembly(const rapidjson::Value &assembly) { m_assembly = Asm::parse(assembly); diff --git a/src/core/config/Config.h b/src/core/config/Config.h index 4bcb8bba..637f80df 100644 --- a/src/core/config/Config.h +++ b/src/core/config/Config.h @@ -94,7 +94,7 @@ private: AlgoVariant getAlgoVariantLite() const; # endif -# ifndef XMRIG_NO_ASM +# ifdef XMRIG_FEATURE_ASM void setAssembly(const rapidjson::Value &assembly); # endif diff --git a/src/crypto/cn/CnAlgo.h b/src/crypto/cn/CnAlgo.h new file mode 100644 index 00000000..74ade22b --- /dev/null +++ b/src/crypto/cn/CnAlgo.h @@ -0,0 +1,207 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 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_CN_ALGO_H +#define XMRIG_CN_ALGO_H + + +#include +#include + + +#include "crypto/common/Algorithm.h" + + +namespace xmrig +{ + + +template +class CnAlgo +{ +public: + constexpr inline CnAlgo() + { + static_assert(ALGO != Algorithm::INVALID && m_memory[ALGO] > 0, "invalid CRYPTONIGHT algorithm"); + static_assert(sizeof(m_memory) / sizeof(m_memory)[0] == Algorithm::MAX, "memory table size mismatch"); + static_assert(sizeof(m_iterations) / sizeof(m_iterations)[0] == Algorithm::MAX, "iterations table size mismatch"); + static_assert(sizeof(m_base) / sizeof(m_base)[0] == Algorithm::MAX, "iterations table size mismatch"); + } + + constexpr inline Algorithm::Id base() const { return m_base[ALGO]; } + constexpr inline bool isHeavy() const { return memory() == CN_MEMORY * 2; } + constexpr inline bool isR() const { return ALGO == Algorithm::CN_R || ALGO == Algorithm::CN_WOW; } + constexpr inline size_t memory() const { return m_memory[ALGO]; } + constexpr inline uint32_t iterations() const { return m_iterations[ALGO]; } + constexpr inline uint32_t mask() const { return ((memory() - 1) / 16) * 16; } + + inline static size_t memory(Algorithm::Id algo) + { + switch (Algorithm::family(algo)) { + case Algorithm::CN: + return CN_MEMORY; + + case Algorithm::CN_LITE: + return CN_MEMORY / 2; + + case Algorithm::CN_HEAVY: + return CN_MEMORY * 2; + + case Algorithm::CN_PICO: + return CN_MEMORY / 8; + + default: + break; + } + + return 0; + } + + inline static uint32_t mask(Algorithm::Id algo) + { +# ifdef XMRIG_ALGO_CN_GPU + if (algo == Algorithm::CN_GPU) { + return 0x1FFFC0; + } +# endif + +# ifdef XMRIG_ALGO_CN_PICO + if (algo == Algorithm::CN_PICO_0) { + return 0x1FFF0; + } +# endif + + return ((memory(algo) - 1) / 16) * 16; + } + +private: + constexpr const static size_t CN_MEMORY = 0x200000; + constexpr const static uint32_t CN_ITER = 0x80000; + + constexpr const static size_t m_memory[] = { + CN_MEMORY, // CN_0 + CN_MEMORY, // CN_1 + CN_MEMORY, // CN_2 + CN_MEMORY, // CN_R + CN_MEMORY, // CN_WOW + CN_MEMORY, // CN_FAST + CN_MEMORY, // CN_HALF + CN_MEMORY, // CN_XAO + CN_MEMORY, // CN_RTO + CN_MEMORY, // CN_RWZ + CN_MEMORY, // CN_ZLS + CN_MEMORY, // CN_DOUBLE +# ifdef XMRIG_ALGO_CN_GPU + CN_MEMORY, // CN_GPU +# endif +# ifdef XMRIG_ALGO_CN_LITE + CN_MEMORY / 2, // CN_LITE_0 + CN_MEMORY / 2, // CN_LITE_1 +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + CN_MEMORY * 2, // CN_HEAVY_0 + CN_MEMORY * 2, // CN_HEAVY_TUBE + CN_MEMORY * 2, // CN_HEAVY_XHV +# endif +# ifdef XMRIG_ALGO_CN_PICO + CN_MEMORY / 8, // CN_PICO_0 +# endif + }; + + constexpr const static uint32_t m_iterations[] = { + CN_ITER, // CN_0 + CN_ITER, // CN_1 + CN_ITER, // CN_2 + CN_ITER, // CN_R + CN_ITER, // CN_WOW + CN_ITER / 2, // CN_FAST + CN_ITER / 2, // CN_HALF + CN_ITER * 2, // CN_XAO + CN_ITER, // CN_RTO + 0x60000, // CN_RWZ + 0x60000, // CN_ZLS + CN_ITER * 2, // CN_DOUBLE +# ifdef XMRIG_ALGO_CN_GPU + 0xC000, // CN_GPU +# endif +# ifdef XMRIG_ALGO_CN_LITE + CN_ITER / 2, // CN_LITE_0 + CN_ITER / 2, // CN_LITE_1 +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + CN_ITER / 2, // CN_HEAVY_0 + CN_ITER / 2, // CN_HEAVY_TUBE + CN_ITER / 2, // CN_HEAVY_XHV +# endif +# ifdef XMRIG_ALGO_CN_PICO + CN_ITER / 8, // CN_PICO_0 +# endif + }; + + constexpr const static Algorithm::Id m_base[] = { + Algorithm::CN_0, // CN_0 + Algorithm::CN_1, // CN_1 + Algorithm::CN_2, // CN_2 + Algorithm::CN_2, // CN_R + Algorithm::CN_2, // CN_WOW + Algorithm::CN_1, // CN_FAST + Algorithm::CN_2, // CN_HALF + Algorithm::CN_0, // CN_XAO + Algorithm::CN_1, // CN_RTO + Algorithm::CN_2, // CN_RWZ + Algorithm::CN_2, // CN_ZLS + Algorithm::CN_2, // CN_DOUBLE +# ifdef XMRIG_ALGO_CN_GPU + Algorithm::CN_GPU, // CN_GPU +# endif +# ifdef XMRIG_ALGO_CN_LITE + Algorithm::CN_0, // CN_LITE_0 + Algorithm::CN_1, // CN_LITE_1 +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + Algorithm::CN_0, // CN_HEAVY_0 + Algorithm::CN_1, // CN_HEAVY_TUBE + Algorithm::CN_0, // CN_HEAVY_XHV +# endif +# ifdef XMRIG_ALGO_CN_PICO + Algorithm::CN_2, // CN_PICO_0 +# endif + }; +}; + + +#ifdef XMRIG_ALGO_CN_GPU +template<> constexpr inline uint32_t CnAlgo::mask() const { return 0x1FFFC0; } +#endif + +#ifdef XMRIG_ALGO_CN_PICO +template<> constexpr inline uint32_t CnAlgo::mask() const { return 0x1FFF0; } +#endif + + +} /* namespace xmrig */ + + +#endif /* XMRIG_CN_ALGO_H */ diff --git a/src/crypto/cn/CnHash.cpp b/src/crypto/cn/CnHash.cpp new file mode 100644 index 00000000..61d2ea69 --- /dev/null +++ b/src/crypto/cn/CnHash.cpp @@ -0,0 +1,269 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 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 + + +#include "common/cpu/Cpu.h" +#include "crypto/cn/CnHash.h" +#include "crypto/common/VirtualMemory.h" + + +#if defined(XMRIG_ARM) +# include "crypto/cn/CryptoNight_arm.h" +#else +# include "crypto/cn/CryptoNight_x86.h" +#endif + + +#define ADD_FN(algo) \ + m_map[algo][AV_SINGLE][ASM_NONE] = cryptonight_single_hash; \ + m_map[algo][AV_SINGLE_SOFT][ASM_NONE] = cryptonight_single_hash; \ + m_map[algo][AV_DOUBLE][ASM_NONE] = cryptonight_double_hash; \ + m_map[algo][AV_DOUBLE_SOFT][ASM_NONE] = cryptonight_double_hash; \ + m_map[algo][AV_TRIPLE][ASM_NONE] = cryptonight_triple_hash; \ + m_map[algo][AV_TRIPLE_SOFT][ASM_NONE] = cryptonight_triple_hash; \ + m_map[algo][AV_QUAD][ASM_NONE] = cryptonight_quad_hash; \ + m_map[algo][AV_QUAD_SOFT][ASM_NONE] = cryptonight_quad_hash; \ + m_map[algo][AV_PENTA][ASM_NONE] = cryptonight_penta_hash; \ + m_map[algo][AV_PENTA_SOFT][ASM_NONE] = cryptonight_penta_hash; + + +#ifdef XMRIG_FEATURE_ASM +# define ADD_FN_ASM(algo) \ + m_map[algo][AV_SINGLE][ASM_INTEL] = cryptonight_single_hash_asm; \ + m_map[algo][AV_SINGLE][ASM_RYZEN] = cryptonight_single_hash_asm; \ + m_map[algo][AV_SINGLE][ASM_BULLDOZER] = cryptonight_single_hash_asm; \ + m_map[algo][AV_DOUBLE][ASM_INTEL] = cryptonight_double_hash_asm; \ + m_map[algo][AV_DOUBLE][ASM_RYZEN] = cryptonight_double_hash_asm; \ + m_map[algo][AV_DOUBLE][ASM_BULLDOZER] = cryptonight_double_hash_asm; + + +extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx **ctx); +extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx **ctx); +extern "C" void cnv2_mainloop_bulldozer_asm(cryptonight_ctx **ctx); +extern "C" void cnv2_double_mainloop_sandybridge_asm(cryptonight_ctx **ctx); + + +namespace xmrig { + + +cn_mainloop_fun cn_half_mainloop_ivybridge_asm = nullptr; +cn_mainloop_fun cn_half_mainloop_ryzen_asm = nullptr; +cn_mainloop_fun cn_half_mainloop_bulldozer_asm = nullptr; +cn_mainloop_fun cn_half_double_mainloop_sandybridge_asm = nullptr; + +cn_mainloop_fun cn_trtl_mainloop_ivybridge_asm = nullptr; +cn_mainloop_fun cn_trtl_mainloop_ryzen_asm = nullptr; +cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm = nullptr; +cn_mainloop_fun cn_trtl_double_mainloop_sandybridge_asm = nullptr; + +cn_mainloop_fun cn_zls_mainloop_ivybridge_asm = nullptr; +cn_mainloop_fun cn_zls_mainloop_ryzen_asm = nullptr; +cn_mainloop_fun cn_zls_mainloop_bulldozer_asm = nullptr; +cn_mainloop_fun cn_zls_double_mainloop_sandybridge_asm = nullptr; + +cn_mainloop_fun cn_double_mainloop_ivybridge_asm = nullptr; +cn_mainloop_fun cn_double_mainloop_ryzen_asm = nullptr; +cn_mainloop_fun cn_double_mainloop_bulldozer_asm = nullptr; +cn_mainloop_fun cn_double_double_mainloop_sandybridge_asm = nullptr; + + +template +static void patchCode(T dst, U src, const uint32_t iterations, const uint32_t mask = CnAlgo().mask()) +{ + const uint8_t* p = reinterpret_cast(src); + + // Workaround for Visual Studio placing trampoline in debug builds. +# if defined(_MSC_VER) + if (p[0] == 0xE9) { + p += *(int32_t*)(p + 1) + 5; + } +# endif + + size_t size = 0; + while (*(uint32_t*)(p + size) != 0xDEADC0DE) { + ++size; + } + + size += sizeof(uint32_t); + + memcpy((void*) dst, (const void*) src, size); + + uint8_t* patched_data = reinterpret_cast(dst); + for (size_t i = 0; i + sizeof(uint32_t) <= size; ++i) { + switch (*(uint32_t*)(patched_data + i)) { + case CnAlgo().iterations(): + *(uint32_t*)(patched_data + i) = iterations; + break; + + case CnAlgo().mask(): + *(uint32_t*)(patched_data + i) = mask; + break; + } + } +} + + +static void patchAsmVariants() +{ + const int allocation_size = 65536; + uint8_t *base = static_cast(VirtualMemory::allocateExecutableMemory(allocation_size)); + + cn_half_mainloop_ivybridge_asm = reinterpret_cast (base + 0x0000); + cn_half_mainloop_ryzen_asm = reinterpret_cast (base + 0x1000); + cn_half_mainloop_bulldozer_asm = reinterpret_cast (base + 0x2000); + cn_half_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0x3000); + +# ifdef XMRIG_ALGO_CN_PICO + cn_trtl_mainloop_ivybridge_asm = reinterpret_cast (base + 0x4000); + cn_trtl_mainloop_ryzen_asm = reinterpret_cast (base + 0x5000); + cn_trtl_mainloop_bulldozer_asm = reinterpret_cast (base + 0x6000); + cn_trtl_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0x7000); +# endif + + cn_zls_mainloop_ivybridge_asm = reinterpret_cast (base + 0x8000); + cn_zls_mainloop_ryzen_asm = reinterpret_cast (base + 0x9000); + cn_zls_mainloop_bulldozer_asm = reinterpret_cast (base + 0xA000); + cn_zls_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0xB000); + + cn_double_mainloop_ivybridge_asm = reinterpret_cast (base + 0xC000); + cn_double_mainloop_ryzen_asm = reinterpret_cast (base + 0xD000); + cn_double_mainloop_bulldozer_asm = reinterpret_cast (base + 0xE000); + cn_double_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0xF000); + + { + constexpr uint32_t ITER = CnAlgo().iterations(); + + patchCode(cn_half_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, ITER); + patchCode(cn_half_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, ITER); + patchCode(cn_half_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, ITER); + patchCode(cn_half_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, ITER); + } + +# ifdef XMRIG_ALGO_CN_PICO + { + constexpr uint32_t ITER = CnAlgo().iterations(); + constexpr uint32_t MASK = CnAlgo().mask(); + + patchCode(cn_trtl_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, ITER, MASK); + patchCode(cn_trtl_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, ITER, MASK); + patchCode(cn_trtl_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, ITER, MASK); + patchCode(cn_trtl_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, ITER, MASK); + } +# endif + + { + constexpr uint32_t ITER = CnAlgo().iterations(); + + patchCode(cn_zls_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, ITER); + patchCode(cn_zls_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, ITER); + patchCode(cn_zls_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, ITER); + patchCode(cn_zls_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, ITER); + } + + { + constexpr uint32_t ITER = CnAlgo().iterations(); + + patchCode(cn_double_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, ITER); + patchCode(cn_double_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, ITER); + patchCode(cn_double_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, ITER); + patchCode(cn_double_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, ITER); + } + + VirtualMemory::protectExecutableMemory(base, allocation_size); + VirtualMemory::flushInstructionCache(base, allocation_size); +} +} // namespace xmrig +#else +# define ADD_FN_ASM(algo) +#endif + + +xmrig::CnHash::CnHash() +{ + ADD_FN(Algorithm::CN_0); + ADD_FN(Algorithm::CN_1); + ADD_FN(Algorithm::CN_2); + ADD_FN(Algorithm::CN_R); + ADD_FN(Algorithm::CN_WOW); + ADD_FN(Algorithm::CN_FAST); + ADD_FN(Algorithm::CN_HALF); + ADD_FN(Algorithm::CN_XAO); + ADD_FN(Algorithm::CN_RTO); + ADD_FN(Algorithm::CN_RWZ); + ADD_FN(Algorithm::CN_ZLS); + ADD_FN(Algorithm::CN_DOUBLE); + + ADD_FN_ASM(Algorithm::CN_2); + ADD_FN_ASM(Algorithm::CN_HALF); + ADD_FN_ASM(Algorithm::CN_R); + ADD_FN_ASM(Algorithm::CN_WOW); + ADD_FN_ASM(Algorithm::CN_RWZ); + ADD_FN_ASM(Algorithm::CN_ZLS); + ADD_FN_ASM(Algorithm::CN_DOUBLE); + +# ifdef XMRIG_ALGO_CN_GPU + m_map[Algorithm::CN_GPU][AV_SINGLE][ASM_NONE] = cryptonight_single_hash_gpu; + m_map[Algorithm::CN_GPU][AV_SINGLE_SOFT][ASM_NONE] = cryptonight_single_hash_gpu; +# endif + +# ifdef XMRIG_ALGO_CN_LITE + ADD_FN(Algorithm::CN_LITE_0); + ADD_FN(Algorithm::CN_LITE_1); +# endif + +# ifdef XMRIG_ALGO_CN_HEAVY + ADD_FN(Algorithm::CN_HEAVY_0); + ADD_FN(Algorithm::CN_HEAVY_TUBE); + ADD_FN(Algorithm::CN_HEAVY_XHV); +# endif + +# ifdef XMRIG_ALGO_CN_PICO + ADD_FN(Algorithm::CN_PICO_0); + ADD_FN_ASM(Algorithm::CN_PICO_0); +# endif + +# ifdef XMRIG_FEATURE_ASM + patchAsmVariants(); +# endif +} + + +xmrig::cn_hash_fun xmrig::CnHash::fn(const Algorithm &algorithm, AlgoVariant av, Assembly assembly) const +{ + if (!algorithm.isValid()) { + return nullptr; + } + +# ifdef XMRIG_FEATURE_ASM + cn_hash_fun fun = m_map[algorithm][av][assembly == ASM_AUTO ? Cpu::info()->assembly() : assembly]; + if (fun) { + return fun; + } +# endif + + return m_map[algorithm][av][ASM_NONE]; +} diff --git a/src/crypto/cn/CnHash.h b/src/crypto/cn/CnHash.h new file mode 100644 index 00000000..5fbf5c8a --- /dev/null +++ b/src/crypto/cn/CnHash.h @@ -0,0 +1,63 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 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_CN_HASH_H +#define XMRIG_CN_HASH_H + + +#include +#include + + +#include "common/xmrig.h" +#include "crypto/cn/CnAlgo.h" + + +struct cryptonight_ctx; + + +namespace xmrig +{ + +typedef void (*cn_hash_fun)(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx **ctx, uint64_t height); +typedef void (*cn_mainloop_fun)(cryptonight_ctx **ctx); + + +class CnHash +{ +public: + CnHash(); + + cn_hash_fun fn(const Algorithm &algorithm, AlgoVariant av, Assembly assembly) const; + +private: + cn_hash_fun m_map[Algorithm::MAX][AV_MAX][ASM_MAX] = {}; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_CN_HASH_H */ diff --git a/src/crypto/cn/CryptoNight.h b/src/crypto/cn/CryptoNight.h index f50966ed..434c34f8 100644 --- a/src/crypto/cn/CryptoNight.h +++ b/src/crypto/cn/CryptoNight.h @@ -42,10 +42,10 @@ typedef void(*cn_mainloop_fun_ms_abi)(cryptonight_ctx**) ABI_ATTRIBUTE; struct cryptonight_r_data { - int variant; + int algo; uint64_t height; - bool match(const int v, const uint64_t h) const { return (v == variant) && (h == height); } + bool match(const int a, const uint64_t h) const { return (a == algo) && (h == height); } }; diff --git a/src/crypto/cn/CryptoNight_constants.h b/src/crypto/cn/CryptoNight_constants.h deleted file mode 100644 index 1bc06a3b..00000000 --- a/src/crypto/cn/CryptoNight_constants.h +++ /dev/null @@ -1,251 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2019 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_CRYPTONIGHT_CONSTANTS_H -#define XMRIG_CRYPTONIGHT_CONSTANTS_H - - -#include -#include - - -#include "common/xmrig.h" - - -namespace xmrig -{ - -constexpr const size_t CRYPTONIGHT_MEMORY = 2 * 1024 * 1024; -constexpr const uint32_t CRYPTONIGHT_MASK = 0x1FFFF0; -constexpr const uint32_t CRYPTONIGHT_ITER = 0x80000; -constexpr const uint32_t CRYPTONIGHT_HALF_ITER = 0x40000; -constexpr const uint32_t CRYPTONIGHT_XAO_ITER = 0x100000; -constexpr const uint32_t CRYPTONIGHT_DOUBLE_ITER = 0x100000; -constexpr const uint32_t CRYPTONIGHT_WALTZ_ITER = 0x60000; -constexpr const uint32_t CRYPTONIGHT_ZLS_ITER = 0x60000; - -constexpr const uint32_t CRYPTONIGHT_GPU_ITER = 0xC000; -constexpr const uint32_t CRYPTONIGHT_GPU_MASK = 0x1FFFC0; - -constexpr const size_t CRYPTONIGHT_LITE_MEMORY = 1 * 1024 * 1024; -constexpr const uint32_t CRYPTONIGHT_LITE_MASK = 0xFFFF0; -constexpr const uint32_t CRYPTONIGHT_LITE_ITER = 0x40000; - -constexpr const size_t CRYPTONIGHT_HEAVY_MEMORY = 4 * 1024 * 1024; -constexpr const uint32_t CRYPTONIGHT_HEAVY_MASK = 0x3FFFF0; -constexpr const uint32_t CRYPTONIGHT_HEAVY_ITER = 0x40000; - -constexpr const size_t CRYPTONIGHT_PICO_MEMORY = 256 * 1024; -constexpr const uint32_t CRYPTONIGHT_PICO_MASK = 0x1FFF0; -constexpr const uint32_t CRYPTONIGHT_PICO_ITER = 0x40000; -constexpr const uint32_t CRYPTONIGHT_TRTL_ITER = 0x10000; - - -template inline constexpr size_t cn_select_memory() { return 0; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_MEMORY; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_LITE_MEMORY; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_HEAVY_MEMORY; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_PICO_MEMORY; } - - -inline size_t cn_select_memory(Algo algorithm) -{ - switch(algorithm) - { - case CRYPTONIGHT: - return CRYPTONIGHT_MEMORY; - - case CRYPTONIGHT_LITE: - return CRYPTONIGHT_LITE_MEMORY; - - case CRYPTONIGHT_HEAVY: - return CRYPTONIGHT_HEAVY_MEMORY; - - case CRYPTONIGHT_PICO: - return CRYPTONIGHT_PICO_MEMORY; - - default: - break; - } - - return 0; -} - - -template inline constexpr uint32_t cn_select_mask() { return 0; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_MASK; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_LITE_MASK; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_HEAVY_MASK; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_PICO_MASK; } - - -inline uint32_t cn_select_mask(Algo algorithm) -{ - switch(algorithm) - { - case CRYPTONIGHT: - return CRYPTONIGHT_MASK; - - case CRYPTONIGHT_LITE: - return CRYPTONIGHT_LITE_MASK; - - case CRYPTONIGHT_HEAVY: - return CRYPTONIGHT_HEAVY_MASK; - - case CRYPTONIGHT_PICO: - return CRYPTONIGHT_PICO_MASK; - - default: - break; - } - - return 0; -} - - -template inline constexpr uint32_t cn_select_iter() { return 0; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HALF_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HALF_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_XAO_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_GPU_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_WALTZ_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ZLS_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_DOUBLE_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_TRTL_ITER; } - - -inline uint32_t cn_select_iter(Algo algorithm, Variant variant) -{ - switch (variant) { - case VARIANT_MSR: - case VARIANT_HALF: - return CRYPTONIGHT_HALF_ITER; - - case VARIANT_GPU: - return CRYPTONIGHT_GPU_ITER; - - case VARIANT_RTO: - case VARIANT_DOUBLE: - return CRYPTONIGHT_XAO_ITER; - - case VARIANT_TRTL: - return CRYPTONIGHT_TRTL_ITER; - - case VARIANT_RWZ: - case VARIANT_ZLS: - return CRYPTONIGHT_WALTZ_ITER; - - default: - break; - } - - switch(algorithm) - { - case CRYPTONIGHT: - return CRYPTONIGHT_ITER; - - case CRYPTONIGHT_LITE: - return CRYPTONIGHT_LITE_ITER; - - case CRYPTONIGHT_HEAVY: - return CRYPTONIGHT_HEAVY_ITER; - - case CRYPTONIGHT_PICO: - return CRYPTONIGHT_TRTL_ITER; - - default: - break; - } - - return 0; -} - - -template inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_GPU; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } - - -inline Variant cn_base_variant(Variant variant) -{ - switch (variant) { - case VARIANT_0: - case VARIANT_XHV: - case VARIANT_XAO: - return VARIANT_0; - - case VARIANT_1: - case VARIANT_TUBE: - case VARIANT_XTL: - case VARIANT_MSR: - case VARIANT_RTO: - return VARIANT_1; - - case VARIANT_GPU: - return VARIANT_GPU; - - default: - break; - } - - return VARIANT_2; -} - - -template inline constexpr bool cn_is_cryptonight_r() { return false; } -template<> inline constexpr bool cn_is_cryptonight_r() { return true; } -template<> inline constexpr bool cn_is_cryptonight_r() { return true; } - -} /* namespace xmrig */ - - -#endif /* XMRIG_CRYPTONIGHT_CONSTANTS_H */ diff --git a/src/crypto/cn/CryptoNight_monero.h b/src/crypto/cn/CryptoNight_monero.h index 94a18c45..259cb3b6 100644 --- a/src/crypto/cn/CryptoNight_monero.h +++ b/src/crypto/cn/CryptoNight_monero.h @@ -33,21 +33,21 @@ #ifndef XMRIG_ARM # define VARIANT1_INIT(part) \ uint64_t tweak1_2_##part = 0; \ - if (BASE == xmrig::VARIANT_1) { \ + if (BASE == Algorithm::CN_1) { \ tweak1_2_##part = (*reinterpret_cast(input + 35 + part * size) ^ \ *(reinterpret_cast(ctx[part]->state) + 24)); \ } #else # define VARIANT1_INIT(part) \ uint64_t tweak1_2_##part = 0; \ - if (BASE == xmrig::VARIANT_1) { \ + if (BASE == Algorithm::CN_1) { \ memcpy(&tweak1_2_##part, input + 35 + part * size, sizeof tweak1_2_##part); \ tweak1_2_##part ^= *(reinterpret_cast(ctx[part]->state) + 24); \ } #endif #define VARIANT1_1(p) \ - if (BASE == xmrig::VARIANT_1) { \ + if (BASE == Algorithm::CN_1) { \ const uint8_t tmp = reinterpret_cast(p)[11]; \ static const uint32_t table = 0x75310; \ const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \ @@ -55,20 +55,20 @@ } #define VARIANT1_2(p, part) \ - if (BASE == xmrig::VARIANT_1) { \ + if (BASE == Algorithm::CN_1) { \ (p) ^= tweak1_2_##part; \ } #ifndef XMRIG_ARM # define VARIANT2_INIT(part) \ - __m128i division_result_xmm_##part = _mm_cvtsi64_si128(h##part[12]); \ - __m128i sqrt_result_xmm_##part = _mm_cvtsi64_si128(h##part[13]); + __m128i division_result_xmm_##part = _mm_cvtsi64_si128(static_cast(h##part[12])); \ + __m128i sqrt_result_xmm_##part = _mm_cvtsi64_si128(static_cast(h##part[13])); #ifdef _MSC_VER -# define VARIANT2_SET_ROUNDING_MODE() if (BASE == xmrig::VARIANT_2) { _control87(RC_DOWN, MCW_RC); } +# define VARIANT2_SET_ROUNDING_MODE() if (BASE == Algorithm::CN_2) { _control87(RC_DOWN, MCW_RC); } #else -# define VARIANT2_SET_ROUNDING_MODE() if (BASE == xmrig::VARIANT_2) { fesetround(FE_DOWNWARD); } +# define VARIANT2_SET_ROUNDING_MODE() if (BASE == Algorithm::CN_2) { fesetround(FE_DOWNWARD); } #endif # define VARIANT2_INTEGER_MATH(part, cl, cx) \ @@ -91,7 +91,7 @@ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10)), _mm_add_epi64(chunk3, _b1)); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20)), _mm_add_epi64(chunk1, _b)); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30)), _mm_add_epi64(chunk2, _a)); \ - if (VARIANT == xmrig::VARIANT_4) { \ + if (ALGO == Algorithm::CN_R) { \ _c = _mm_xor_si128(_mm_xor_si128(_c, chunk3), _mm_xor_si128(chunk1, chunk2)); \ } \ } while (0) @@ -141,7 +141,7 @@ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b1))); \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b))); \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30)), vaddq_u64(chunk2, vreinterpretq_u64_u8(_a))); \ - if (VARIANT == xmrig::VARIANT_4) { \ + if (ALGO == Algorithm::CN_4) { \ _c = veorq_u64(veorq_u64(_c, chunk3), veorq_u64(chunk1, chunk2)); \ } \ } while (0) @@ -184,17 +184,17 @@ #define VARIANT4_RANDOM_MATH_INIT(part) \ uint32_t r##part[9]; \ struct V4_Instruction code##part[256]; \ - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { \ - r##part[0] = (uint32_t)(h##part[12]); \ - r##part[1] = (uint32_t)(h##part[12] >> 32); \ - r##part[2] = (uint32_t)(h##part[13]); \ - r##part[3] = (uint32_t)(h##part[13] >> 32); \ + if (props.isR()) { \ + r##part[0] = static_cast(h##part[12]); \ + r##part[1] = static_cast(h##part[12] >> 32); \ + r##part[2] = static_cast(h##part[13]); \ + r##part[3] = static_cast(h##part[13] >> 32); \ } \ - v4_random_math_init(code##part, height); + v4_random_math_init(code##part, height); #define VARIANT4_RANDOM_MATH(part, al, ah, cl, bx0, bx1) \ - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { \ - cl ^= (r##part[0] + r##part[1]) | ((uint64_t)(r##part[2] + r##part[3]) << 32); \ + if (props.isR()) { \ + cl ^= (r##part[0] + r##part[1]) | (static_cast(r##part[2] + r##part[3]) << 32); \ r##part[4] = static_cast(al); \ r##part[5] = static_cast(ah); \ r##part[6] = static_cast(_mm_cvtsi128_si32(bx0)); \ diff --git a/src/crypto/cn/CryptoNight_test.h b/src/crypto/cn/CryptoNight_test.h index 2429fc17..77cbbb8e 100644 --- a/src/crypto/cn/CryptoNight_test.h +++ b/src/crypto/cn/CryptoNight_test.h @@ -156,21 +156,6 @@ const static uint8_t test_output_v2[160] = { }; -// "cn/xtl" Stellite (XTL) -const static uint8_t test_output_xtl[160] = { - 0x8F, 0xE5, 0xF0, 0x5F, 0x02, 0x2A, 0x61, 0x7D, 0xE5, 0x3F, 0x79, 0x36, 0x4B, 0x25, 0xCB, 0xC3, - 0xC0, 0x8E, 0x0E, 0x1F, 0xE3, 0xBE, 0x48, 0x57, 0x07, 0x03, 0xFE, 0xE1, 0xEC, 0x0E, 0xB0, 0xB1, - 0x21, 0x26, 0xFF, 0x98, 0xE6, 0x86, 0x08, 0x5B, 0xC9, 0x96, 0x44, 0xA3, 0xB8, 0x4E, 0x28, 0x90, - 0x76, 0xED, 0xAD, 0xB9, 0xAA, 0xAC, 0x01, 0x94, 0x1D, 0xBE, 0x3E, 0xEA, 0xAD, 0xEE, 0xB2, 0xCF, - 0xB0, 0x43, 0x4B, 0x88, 0xFC, 0xB2, 0xF3, 0x82, 0x9D, 0xD7, 0xDF, 0x51, 0x97, 0x2C, 0x5A, 0xE3, - 0xC7, 0x16, 0x0B, 0xC8, 0x7C, 0xB7, 0x2F, 0x1C, 0x55, 0x33, 0xCA, 0xE1, 0xEE, 0x08, 0xA4, 0x86, - 0x60, 0xED, 0x6E, 0x9D, 0x2D, 0x05, 0x0D, 0x7D, 0x02, 0x49, 0x23, 0x39, 0x7C, 0xC3, 0x6D, 0x3D, - 0x05, 0x51, 0x28, 0xF1, 0x9B, 0x3C, 0xDF, 0xC4, 0xEA, 0x8A, 0xA6, 0x6A, 0x3C, 0x8B, 0xE2, 0xAF, - 0x47, 0x00, 0xFC, 0x36, 0xED, 0x50, 0xBB, 0xD2, 0x2E, 0x63, 0x4B, 0x93, 0x11, 0x0C, 0xA7, 0xBA, - 0x32, 0x6E, 0x47, 0x4D, 0xCE, 0xCC, 0x82, 0x54, 0x1D, 0x06, 0xF8, 0x06, 0x86, 0xBD, 0x22, 0x48 -}; - - // "cn/half" const static uint8_t test_output_half[160] = { 0x5D, 0x4F, 0xBC, 0x35, 0x60, 0x97, 0xEA, 0x64, 0x40, 0xB0, 0x88, 0x8E, 0xDE, 0xB6, 0x35, 0xDD, diff --git a/src/crypto/cn/CryptoNight_x86.h b/src/crypto/cn/CryptoNight_x86.h index 8d6792d2..994ee116 100644 --- a/src/crypto/cn/CryptoNight_x86.h +++ b/src/crypto/cn/CryptoNight_x86.h @@ -37,9 +37,9 @@ #include "common/cpu/Cpu.h" #include "common/crypto/keccak.h" -#include "crypto/cn/CryptoNight.h" -#include "crypto/cn/CryptoNight_constants.h" +#include "crypto/cn/CnAlgo.h" #include "crypto/cn/CryptoNight_monero.h" +#include "crypto/cn/CryptoNight.h" #include "crypto/cn/soft_aes.h" @@ -303,9 +303,14 @@ inline void mix_and_propagate(__m128i& x0, __m128i& x1, __m128i& x2, __m128i& x3 } -template +namespace xmrig { + + +template static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) { + constexpr CnAlgo props; + __m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7; __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9; @@ -320,7 +325,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) xin6 = _mm_load_si128(input + 10); xin7 = _mm_load_si128(input + 11); - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (props.isHeavy()) { for (size_t i = 0; i < 16; i++) { aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); @@ -337,7 +342,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } } - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); @@ -361,37 +366,17 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } -#ifdef XMRIG_ALGO_CN_GPU -template -void cn_explode_scratchpad_gpu(const uint8_t *input, uint8_t *output) -{ - constexpr size_t hash_size = 200; // 25x8 bytes - alignas(16) uint64_t hash[25]; - - for (uint64_t i = 0; i < MEM / 512; i++) - { - memcpy(hash, input, hash_size); - hash[0] ^= i; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 160); - output += 160; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 176); - output += 176; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 176); - output += 176; - } -} -#endif - - -template +template static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) { + constexpr CnAlgo props; + +# ifdef XMRIG_ALGO_CN_GPU + constexpr bool IS_HEAVY = props.isHeavy() || ALGO == Algorithm::CN_GPU; +# else + constexpr bool IS_HEAVY = props.isHeavy(); +# endif + __m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7; __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9; @@ -406,8 +391,7 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) xout6 = _mm_load_si128(output + 10); xout7 = _mm_load_si128(output + 11); - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) - { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0); xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1); xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2); @@ -428,13 +412,13 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (IS_HEAVY) { mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7); } } - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { + if (IS_HEAVY) { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0); xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1); xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2); @@ -485,6 +469,9 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) } +} /* namespace xmrig */ + + static inline __m128i aes_round_tweak_div(const __m128i &in, const __m128i &key) { alignas(16) uint32_t k[4]; @@ -527,12 +514,21 @@ static inline __m128i int_sqrt_v2(const uint64_t n0) } -template -static inline void cryptonight_monero_tweak(uint64_t* mem_out, const uint8_t* l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i& cx) +void wow_soft_aes_compile_code(const V4_Instruction *code, int code_size, void *machine_code, xmrig::Assembly ASM); +void v4_soft_aes_compile_code(const V4_Instruction *code, int code_size, void *machine_code, xmrig::Assembly ASM); + + +namespace xmrig { + + +template +static inline void cryptonight_monero_tweak(uint64_t *mem_out, const uint8_t *l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i& cx) { - if (BASE == xmrig::VARIANT_2) { - VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); - _mm_store_si128((__m128i *)mem_out, _mm_xor_si128(bx0, cx)); + constexpr CnAlgo props; + + if (props.base() == Algorithm::CN_2) { + VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); + _mm_store_si128(reinterpret_cast<__m128i *>(mem_out), _mm_xor_si128(bx0, cx)); } else { __m128i tmp = _mm_xor_si128(bx0, cx); mem_out[0] = _mm_cvtsi128_si64(tmp); @@ -542,107 +538,105 @@ static inline void cryptonight_monero_tweak(uint64_t* mem_out, const uint8_t* l, uint8_t x = static_cast(vh >> 24); static const uint16_t table = 0x7531; - const uint8_t index = (((x >> (VARIANT == xmrig::VARIANT_XTL ? 4 : 3)) & 6) | (x & 1)) << 1; + const uint8_t index = (((x >> (3)) & 6) | (x & 1)) << 1; vh ^= ((table >> index) & 0x3) << 28; mem_out[1] = vh; } } -void wow_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); -void v4_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); -template +template inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - static_assert(MASK > 0 && ITERATIONS > 0 && MEM > 0, "unsupported algorithm/variant"); +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; +# endif - if (BASE == xmrig::VARIANT_1 && size < 43) { + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 32); return; } - xmrig::keccak(input, size, ctx[0]->state); + keccak(input, size, ctx[0]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[0]->state), reinterpret_cast<__m128i *>(ctx[0]->memory)); - cn_explode_scratchpad((__m128i*) ctx[0]->state, (__m128i*) ctx[0]->memory); + uint64_t *h0 = reinterpret_cast(ctx[0]->state); + uint8_t *l0 = ctx[0]->memory; - uint64_t* h0 = reinterpret_cast(ctx[0]->state); - -#ifndef XMRIG_NO_ASM - if (SOFT_AES && xmrig::cn_is_cryptonight_r()) - { - if (!ctx[0]->generated_code_data.match(VARIANT, height)) { +# ifdef XMRIG_FEATURE_ASM + if (SOFT_AES && props.isR()) { + if (!ctx[0]->generated_code_data.match(ALGO, height)) { V4_Instruction code[256]; - const int code_size = v4_random_math_init(code, height); + const int code_size = v4_random_math_init(code, height); - if (VARIANT == xmrig::VARIANT_WOW) - wow_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), xmrig::ASM_NONE); - else if (VARIANT == xmrig::VARIANT_4) - v4_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), xmrig::ASM_NONE); + if (ALGO == Algorithm::CN_WOW) { + wow_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM_NONE); + } + else if (ALGO == Algorithm::CN_R) { + v4_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM_NONE); + } - ctx[0]->generated_code_data.variant = VARIANT; - ctx[0]->generated_code_data.height = height; + ctx[0]->generated_code_data = { ALGO, height }; } - ctx[0]->saes_table = (const uint32_t*)saes_table; + ctx[0]->saes_table = reinterpret_cast(saes_table); ctx[0]->generated_code(ctx); } else { -#endif - - const uint8_t* l0 = ctx[0]->memory; +# endif VARIANT1_INIT(0); VARIANT2_INIT(0); VARIANT2_SET_ROUNDING_MODE(); VARIANT4_RANDOM_MATH_INIT(0); - uint64_t al0 = h0[0] ^ h0[4]; - uint64_t ah0 = h0[1] ^ h0[5]; - __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); - __m128i bx1 = _mm_set_epi64x(h0[9] ^ h0[11], h0[8] ^ h0[10]); - + uint64_t al0 = h0[0] ^ h0[4]; + uint64_t ah0 = h0[1] ^ h0[5]; uint64_t idx0 = al0; + __m128i bx0 = _mm_set_epi64x(static_cast(h0[3] ^ h0[7]), static_cast(h0[2] ^ h0[6])); + __m128i bx1 = _mm_set_epi64x(static_cast(h0[9] ^ h0[11]), static_cast(h0[8] ^ h0[10])); - for (size_t i = 0; i < ITERATIONS; i++) { + for (size_t i = 0; i < props.iterations(); i++) { __m128i cx; - if (VARIANT == xmrig::VARIANT_TUBE || !SOFT_AES) { - cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); + if (IS_CN_HEAVY_TUBE || !SOFT_AES) { + cx = _mm_load_si128(reinterpret_cast(&l0[idx0 & MASK])); } - const __m128i ax0 = _mm_set_epi64x(ah0, al0); - if (VARIANT == xmrig::VARIANT_TUBE) { + const __m128i ax0 = _mm_set_epi64x(static_cast(ah0), static_cast(al0)); + if (IS_CN_HEAVY_TUBE) { cx = aes_round_tweak_div(cx, ax0); } else if (SOFT_AES) { - cx = soft_aesenc((uint32_t*)&l0[idx0 & MASK], ax0, (const uint32_t*)saes_table); + cx = soft_aesenc(&l0[idx0 & MASK], ax0, reinterpret_cast(saes_table)); } else { cx = _mm_aesenc_si128(cx, ax0); } - if (BASE == xmrig::VARIANT_1 || BASE == xmrig::VARIANT_2) { - cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx0, bx1, cx); + if (BASE == Algorithm::CN_1 || BASE == Algorithm::CN_2) { + cryptonight_monero_tweak(reinterpret_cast(&l0[idx0 & MASK]), l0, idx0 & MASK, ax0, bx0, bx1, cx); } else { - _mm_store_si128((__m128i *)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); + _mm_store_si128(reinterpret_cast<__m128i *>(&l0[idx0 & MASK]), _mm_xor_si128(bx0, cx)); } - idx0 = _mm_cvtsi128_si64(cx); + idx0 = static_cast(_mm_cvtsi128_si64(cx)); uint64_t hi, lo, cl, ch; - cl = ((uint64_t*) &l0[idx0 & MASK])[0]; - ch = ((uint64_t*) &l0[idx0 & MASK])[1]; + cl = (reinterpret_cast(&l0[idx0 & MASK]))[0]; + ch = (reinterpret_cast(&l0[idx0 & MASK]))[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx0, bx1); - if (VARIANT == xmrig::VARIANT_4) { - al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); - ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); + if (ALGO == Algorithm::CN_R) { + al0 ^= r0[2] | (static_cast(r0[3]) << 32); + ah0 ^= r0[0] | (static_cast(r0[1]) << 32); } } else { VARIANT2_INTEGER_MATH(0, cl, cx); @@ -651,63 +645,67 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx0, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx0, bx1, cx, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } al0 += hi; ah0 += lo; - ((uint64_t*)&l0[idx0 & MASK])[0] = al0; + reinterpret_cast(&l0[idx0 & MASK])[0] = al0; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { - ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (BASE == xmrig::VARIANT_1) { - ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { + reinterpret_cast(&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; + } else if (BASE == Algorithm::CN_1) { + reinterpret_cast(&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { - ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; + reinterpret_cast(&l0[idx0 & MASK])[1] = ah0; } al0 ^= cl; ah0 ^= ch; idx0 = al0; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { int64_t n = ((int64_t*)&l0[idx0 & MASK])[0]; int32_t d = ((int32_t*)&l0[idx0 & MASK])[2]; int64_t q = n / (d | 0x5); ((int64_t*)&l0[idx0 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { d = ~d; } idx0 = d ^ q; } +# endif - if (BASE == xmrig::VARIANT_2) { + if (BASE == Algorithm::CN_2) { bx1 = bx0; } bx0 = cx; } -#ifndef XMRIG_NO_ASM +# ifdef XMRIG_FEATURE_ASM } -#endif - - cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); +# endif - xmrig::keccakf(h0, 24); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i *>(ctx[0]->state)); + keccakf(h0, 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); } +} /* namespace xmrig */ + + #ifdef XMRIG_ALGO_CN_GPU template void cn_gpu_inner_avx(const uint8_t *spad, uint8_t *lpad); @@ -717,17 +715,41 @@ template void cn_gpu_inner_ssse3(const uint8_t *spad, uint8_t *lpad); -template -inline void cryptonight_single_hash_gpu(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) +namespace xmrig { + + +template +void cn_explode_scratchpad_gpu(const uint8_t *input, uint8_t *output) { - constexpr size_t MASK = xmrig::CRYPTONIGHT_GPU_MASK; - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr size_t hash_size = 200; // 25x8 bytes + alignas(16) uint64_t hash[25]; - static_assert(MASK > 0 && ITERATIONS > 0 && MEM > 0, "unsupported algorithm/variant"); + for (uint64_t i = 0; i < MEM / 512; i++) { + memcpy(hash, input, hash_size); + hash[0] ^= i; - xmrig::keccak(input, size, ctx[0]->state); - cn_explode_scratchpad_gpu(ctx[0]->state, ctx[0]->memory); + xmrig::keccakf(hash, 24); + memcpy(output, hash, 160); + output += 160; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + } +} + + +template +inline void cryptonight_single_hash_gpu(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t) +{ + constexpr CnAlgo props; + + keccak(input, size, ctx[0]->state); + cn_explode_scratchpad_gpu(ctx[0]->state, ctx[0]->memory); # ifdef _MSC_VER _control87(RC_NEAR, MCW_RC); @@ -736,20 +758,22 @@ inline void cryptonight_single_hash_gpu(const uint8_t *__restrict__ input, size_ # endif if (xmrig::Cpu::info()->hasAVX2()) { - cn_gpu_inner_avx(ctx[0]->state, ctx[0]->memory); + cn_gpu_inner_avx(ctx[0]->state, ctx[0]->memory); } else { - cn_gpu_inner_ssse3(ctx[0]->state, ctx[0]->memory); + cn_gpu_inner_ssse3(ctx[0]->state, ctx[0]->memory); } - cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); - - xmrig::keccakf((uint64_t*) ctx[0]->state, 24); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i *>(ctx[0]->state)); + keccakf(reinterpret_cast(ctx[0]->state), 24); memcpy(output, ctx[0]->state, 32); } + + +} /* namespace xmrig */ #endif -#ifndef XMRIG_NO_ASM +#ifdef XMRIG_FEATURE_ASM extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx **ctx); extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx **ctx); extern "C" void cnv2_mainloop_bulldozer_asm(cryptonight_ctx **ctx); @@ -757,212 +781,243 @@ extern "C" void cnv2_double_mainloop_sandybridge_asm(cryptonight_ctx **ctx); extern "C" void cnv2_rwz_mainloop_asm(cryptonight_ctx **ctx); extern "C" void cnv2_rwz_double_mainloop_asm(cryptonight_ctx **ctx); -extern xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ivybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ryzen_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_bulldozer_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_half_double_mainloop_sandybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ivybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ryzen_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_double_mainloop_sandybridge_asm; +namespace xmrig { -extern xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ivybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ryzen_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_bulldozer_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_zls_double_mainloop_sandybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ivybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ryzen_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_bulldozer_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_double_double_mainloop_sandybridge_asm; +extern cn_mainloop_fun cn_half_mainloop_ivybridge_asm; +extern cn_mainloop_fun cn_half_mainloop_ryzen_asm; +extern cn_mainloop_fun cn_half_mainloop_bulldozer_asm; +extern cn_mainloop_fun cn_half_double_mainloop_sandybridge_asm; + +extern cn_mainloop_fun cn_trtl_mainloop_ivybridge_asm; +extern cn_mainloop_fun cn_trtl_mainloop_ryzen_asm; +extern cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm; +extern cn_mainloop_fun cn_trtl_double_mainloop_sandybridge_asm; + +extern cn_mainloop_fun cn_zls_mainloop_ivybridge_asm; +extern cn_mainloop_fun cn_zls_mainloop_ryzen_asm; +extern cn_mainloop_fun cn_zls_mainloop_bulldozer_asm; +extern cn_mainloop_fun cn_zls_double_mainloop_sandybridge_asm; + +extern cn_mainloop_fun cn_double_mainloop_ivybridge_asm; +extern cn_mainloop_fun cn_double_mainloop_ryzen_asm; +extern cn_mainloop_fun cn_double_mainloop_bulldozer_asm; +extern cn_mainloop_fun cn_double_double_mainloop_sandybridge_asm; + + +} // namespace xmrig + void wow_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); void v4_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); void wow_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); void v4_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); -template + +template void cn_r_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) { v4_compile_code(code, code_size, machine_code, ASM); } -template + +template void cn_r_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) { v4_compile_code_double(code, code_size, machine_code, ASM); } + template<> -void cn_r_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +void cn_r_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) { wow_compile_code(code, code_size, machine_code, ASM); } + template<> -void cn_r_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +void cn_r_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) { wow_compile_code_double(code, code_size, machine_code, ASM); } -template + +namespace xmrig { + + +template inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr CnAlgo props; - if (xmrig::cn_is_cryptonight_r() && !ctx[0]->generated_code_data.match(VARIANT, height)) { + if (props.isR() && !ctx[0]->generated_code_data.match(ALGO, height)) { V4_Instruction code[256]; - const int code_size = v4_random_math_init(code, height); - cn_r_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM); - ctx[0]->generated_code_data.variant = VARIANT; - ctx[0]->generated_code_data.height = height; + const int code_size = v4_random_math_init(code, height); + cn_r_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM); + + ctx[0]->generated_code_data = { ALGO, height }; } - xmrig::keccak(input, size, ctx[0]->state); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); + keccak(input, size, ctx[0]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); - if (VARIANT == xmrig::VARIANT_2) { - if (ASM == xmrig::ASM_INTEL) { + if (ALGO == Algorithm::CN_2) { + if (ASM == ASM_INTEL) { cnv2_mainloop_ivybridge_asm(ctx); } - else if (ASM == xmrig::ASM_RYZEN) { + else if (ASM == ASM_RYZEN) { cnv2_mainloop_ryzen_asm(ctx); } else { cnv2_mainloop_bulldozer_asm(ctx); } } - else if (VARIANT == xmrig::VARIANT_HALF) { - if (ASM == xmrig::ASM_INTEL) { + else if (ALGO == Algorithm::CN_HALF) { + if (ASM == ASM_INTEL) { cn_half_mainloop_ivybridge_asm(ctx); } - else if (ASM == xmrig::ASM_RYZEN) { + else if (ASM == ASM_RYZEN) { cn_half_mainloop_ryzen_asm(ctx); } else { cn_half_mainloop_bulldozer_asm(ctx); } } - else if (VARIANT == xmrig::VARIANT_TRTL) { - if (ASM == xmrig::ASM_INTEL) { +# ifdef XMRIG_ALGO_CN_PICO + else if (ALGO == Algorithm::CN_PICO_0) { + if (ASM == ASM_INTEL) { cn_trtl_mainloop_ivybridge_asm(ctx); } - else if (ASM == xmrig::ASM_RYZEN) { + else if (ASM == ASM_RYZEN) { cn_trtl_mainloop_ryzen_asm(ctx); } else { cn_trtl_mainloop_bulldozer_asm(ctx); } } - else if (VARIANT == xmrig::VARIANT_RWZ) { +# endif + else if (ALGO == Algorithm::CN_RWZ) { cnv2_rwz_mainloop_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_ZLS) { - if (ASM == xmrig::ASM_INTEL) { + else if (ALGO == Algorithm::CN_ZLS) { + if (ASM == ASM_INTEL) { cn_zls_mainloop_ivybridge_asm(ctx); } - else if (ASM == xmrig::ASM_RYZEN) { + else if (ASM == ASM_RYZEN) { cn_zls_mainloop_ryzen_asm(ctx); } else { cn_zls_mainloop_bulldozer_asm(ctx); } } - else if (VARIANT == xmrig::VARIANT_DOUBLE) { - if (ASM == xmrig::ASM_INTEL) { + else if (ALGO == Algorithm::CN_DOUBLE) { + if (ASM == ASM_INTEL) { cn_double_mainloop_ivybridge_asm(ctx); } - else if (ASM == xmrig::ASM_RYZEN) { + else if (ASM == ASM_RYZEN) { cn_double_mainloop_ryzen_asm(ctx); } else { cn_double_mainloop_bulldozer_asm(ctx); } } - else if (xmrig::cn_is_cryptonight_r()) { + else if (props.isR()) { ctx[0]->generated_code(ctx); } - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); - xmrig::keccakf(reinterpret_cast(ctx[0]->state), 24); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); + keccakf(reinterpret_cast(ctx[0]->state), 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); } -template +template inline void cryptonight_double_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr CnAlgo props; - if (xmrig::cn_is_cryptonight_r() && !ctx[0]->generated_code_data.match(VARIANT, height)) { + if (props.isR() && !ctx[0]->generated_code_data.match(ALGO, height)) { V4_Instruction code[256]; - const int code_size = v4_random_math_init(code, height); - cn_r_compile_code_double(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM); - ctx[0]->generated_code_data.variant = VARIANT; - ctx[0]->generated_code_data.height = height; + const int code_size = v4_random_math_init(code, height); + cn_r_compile_code_double(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM); + + ctx[0]->generated_code_data = { ALGO, height }; } - xmrig::keccak(input, size, ctx[0]->state); - xmrig::keccak(input + size, size, ctx[1]->state); + keccak(input, size, ctx[0]->state); + keccak(input + size, size, ctx[1]->state); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[1]->state), reinterpret_cast<__m128i*>(ctx[1]->memory)); + cn_explode_scratchpad(reinterpret_cast(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); + cn_explode_scratchpad(reinterpret_cast(ctx[1]->state), reinterpret_cast<__m128i*>(ctx[1]->memory)); - if (VARIANT == xmrig::VARIANT_2) { + if (ALGO == Algorithm::CN_2) { cnv2_double_mainloop_sandybridge_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_HALF) { + else if (ALGO == Algorithm::CN_HALF) { cn_half_double_mainloop_sandybridge_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_TRTL) { +# ifdef XMRIG_ALGO_CN_PICO + else if (ALGO == Algorithm::CN_PICO_0) { cn_trtl_double_mainloop_sandybridge_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_RWZ) { +# endif + else if (ALGO == Algorithm::CN_RWZ) { cnv2_rwz_double_mainloop_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_ZLS) { + else if (ALGO == Algorithm::CN_ZLS) { cn_zls_double_mainloop_sandybridge_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_DOUBLE) { + else if (ALGO == Algorithm::CN_DOUBLE) { cn_double_double_mainloop_sandybridge_asm(ctx); } - else if (xmrig::cn_is_cryptonight_r()) { + else if (props.isR()) { ctx[0]->generated_code(ctx); } - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[1]->memory), reinterpret_cast<__m128i*>(ctx[1]->state)); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); + cn_implode_scratchpad(reinterpret_cast(ctx[1]->memory), reinterpret_cast<__m128i*>(ctx[1]->state)); - xmrig::keccakf(reinterpret_cast(ctx[0]->state), 24); - xmrig::keccakf(reinterpret_cast(ctx[1]->state), 24); + keccakf(reinterpret_cast(ctx[0]->state), 24); + keccakf(reinterpret_cast(ctx[1]->state), 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); extra_hashes[ctx[1]->state[0] & 3](ctx[1]->state, 200, output + 32); } + + +} /* namespace xmrig */ #endif -template +namespace xmrig { + + +template inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 64); return; } - xmrig::keccak(input, size, ctx[0]->state); - xmrig::keccak(input + size, size, ctx[1]->state); + keccak(input, size, ctx[0]->state); + keccak(input + size, size, ctx[1]->state); - const uint8_t* l0 = ctx[0]->memory; - const uint8_t* l1 = ctx[1]->memory; - uint64_t* h0 = reinterpret_cast(ctx[0]->state); - uint64_t* h1 = reinterpret_cast(ctx[1]->state); + uint8_t *l0 = ctx[0]->memory; + uint8_t *l1 = ctx[1]->memory; + uint64_t *h0 = reinterpret_cast(ctx[0]->state); + uint64_t *h1 = reinterpret_cast(ctx[1]->state); VARIANT1_INIT(0); VARIANT1_INIT(1); @@ -972,8 +1027,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si VARIANT4_RANDOM_MATH_INIT(0); VARIANT4_RANDOM_MATH_INIT(1); - cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0); - cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1); + cn_explode_scratchpad(reinterpret_cast(h0), reinterpret_cast<__m128i *>(l0)); + cn_explode_scratchpad(reinterpret_cast(h1), reinterpret_cast<__m128i *>(l1)); uint64_t al0 = h0[0] ^ h0[4]; uint64_t al1 = h1[0] ^ h1[4]; @@ -988,31 +1043,31 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si uint64_t idx0 = al0; uint64_t idx1 = al1; - for (size_t i = 0; i < ITERATIONS; i++) { + for (size_t i = 0; i < props.iterations(); i++) { __m128i cx0, cx1; - if (VARIANT == xmrig::VARIANT_TUBE || !SOFT_AES) { - cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); - cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]); + if (IS_CN_HEAVY_TUBE || !SOFT_AES) { + cx0 = _mm_load_si128(reinterpret_cast(&l0[idx0 & MASK])); + cx1 = _mm_load_si128(reinterpret_cast(&l1[idx1 & MASK])); } const __m128i ax0 = _mm_set_epi64x(ah0, al0); const __m128i ax1 = _mm_set_epi64x(ah1, al1); - if (VARIANT == xmrig::VARIANT_TUBE) { + if (IS_CN_HEAVY_TUBE) { cx0 = aes_round_tweak_div(cx0, ax0); cx1 = aes_round_tweak_div(cx1, ax1); } else if (SOFT_AES) { - cx0 = soft_aesenc((uint32_t*)&l0[idx0 & MASK], ax0, (const uint32_t*)saes_table); - cx1 = soft_aesenc((uint32_t*)&l1[idx1 & MASK], ax1, (const uint32_t*)saes_table); + cx0 = soft_aesenc(&l0[idx0 & MASK], ax0, reinterpret_cast(saes_table)); + cx1 = soft_aesenc(&l1[idx1 & MASK], ax1, reinterpret_cast(saes_table)); } else { cx0 = _mm_aesenc_si128(cx0, ax0); cx1 = _mm_aesenc_si128(cx1, ax1); } - if (BASE == xmrig::VARIANT_1 || (BASE == xmrig::VARIANT_2)) { - cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx00, bx01, cx0); - cryptonight_monero_tweak((uint64_t*)&l1[idx1 & MASK], l1, idx1 & MASK, ax1, bx10, bx11, cx1); + if (BASE == Algorithm::CN_1 || BASE == Algorithm::CN_2) { + cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx00, bx01, cx0); + cryptonight_monero_tweak((uint64_t*)&l1[idx1 & MASK], l1, idx1 & MASK, ax1, bx10, bx11, cx1); } else { _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx00, cx0)); _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx10, cx1)); @@ -1025,10 +1080,10 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx00, bx01); - if (VARIANT == xmrig::VARIANT_4) { + if (ALGO == Algorithm::CN_R) { al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); } @@ -1039,11 +1094,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx0, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx00, bx01, cx0, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } @@ -1052,9 +1107,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l0[idx0 & MASK])[0] = al0; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { ((uint64_t*) &l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (BASE == xmrig::VARIANT_1) { + } else if (BASE == Algorithm::CN_1) { ((uint64_t*) &l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { ((uint64_t*) &l0[idx0 & MASK])[1] = ah0; @@ -1064,27 +1119,29 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ah0 ^= ch; idx0 = al0; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { int64_t n = ((int64_t*)&l0[idx0 & MASK])[0]; int32_t d = ((int32_t*)&l0[idx0 & MASK])[2]; int64_t q = n / (d | 0x5); ((int64_t*)&l0[idx0 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { d = ~d; } idx0 = d ^ q; } +# endif cl = ((uint64_t*) &l1[idx1 & MASK])[0]; ch = ((uint64_t*) &l1[idx1 & MASK])[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(1, al1, ah1, cl, bx10, bx11); - if (VARIANT == xmrig::VARIANT_4) { + if (ALGO == Algorithm::CN_R) { al1 ^= r1[2] | ((uint64_t)(r1[3]) << 32); ah1 ^= r1[0] | ((uint64_t)(r1[1]) << 32); } @@ -1095,11 +1152,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx1, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l1, idx1 & MASK, ax1, bx10, bx11, cx1, 0); } else { - VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } @@ -1108,9 +1165,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l1[idx1 & MASK])[0] = al1; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1 ^ al1; - } else if (BASE == xmrig::VARIANT_1) { + } else if (BASE == Algorithm::CN_1) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1; } else { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1; @@ -1120,21 +1177,23 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ah1 ^= ch; idx1 = al1; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { int64_t n = ((int64_t*)&l1[idx1 & MASK])[0]; int32_t d = ((int32_t*)&l1[idx1 & MASK])[2]; int64_t q = n / (d | 0x5); ((int64_t*)&l1[idx1 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { d = ~d; } idx1 = d ^ q; } +# endif - if (BASE == xmrig::VARIANT_2) { + if (BASE == Algorithm::CN_2) { bx01 = bx00; bx11 = bx10; } @@ -1143,11 +1202,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si bx10 = cx1; } - cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0); - cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1); + cn_implode_scratchpad(reinterpret_cast(l0), reinterpret_cast<__m128i *>(h0)); + cn_implode_scratchpad(reinterpret_cast(l1), reinterpret_cast<__m128i *>(h1)); - xmrig::keccakf(h0, 24); - xmrig::keccakf(h1, 24); + keccakf(h0, 24); + keccakf(h1, 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); extra_hashes[ctx[1]->state[0] & 3](ctx[1]->state, 200, output + 32); @@ -1159,20 +1218,20 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si c = _mm_load_si128(ptr); -#define CN_STEP2(a, b0, b1, c, l, ptr, idx) \ - if (VARIANT == xmrig::VARIANT_TUBE) { \ - c = aes_round_tweak_div(c, a); \ - } \ - else if (SOFT_AES) { \ - c = soft_aesenc(&c, a, (const uint32_t*)saes_table); \ - } else { \ - c = _mm_aesenc_si128(c, a); \ - } \ - \ - if (BASE == xmrig::VARIANT_1 || BASE == xmrig::VARIANT_2) { \ - cryptonight_monero_tweak((uint64_t*)ptr, l, idx & MASK, a, b0, b1, c); \ - } else { \ - _mm_store_si128(ptr, _mm_xor_si128(b0, c)); \ +#define CN_STEP2(a, b0, b1, c, l, ptr, idx) \ + if (IS_CN_HEAVY_TUBE) { \ + c = aes_round_tweak_div(c, a); \ + } \ + else if (SOFT_AES) { \ + c = soft_aesenc(&c, a, (const uint32_t*)saes_table); \ + } else { \ + c = _mm_aesenc_si128(c, a); \ + } \ + \ + if (BASE == Algorithm::CN_1 || BASE == Algorithm::CN_2) { \ + cryptonight_monero_tweak((uint64_t*)ptr, l, idx & MASK, a, b0, b1, c); \ + } else { \ + _mm_store_si128(ptr, _mm_xor_si128(b0, c)); \ } @@ -1183,62 +1242,60 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si uint64_t ch##part = ((uint64_t*)ptr)[1]; -#define CN_STEP4(part, a, b0, b1, c, l, mc, ptr, idx) \ - uint64_t al##part, ah##part; \ - if (BASE == xmrig::VARIANT_2) { \ - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { \ - al##part = _mm_cvtsi128_si64(a); \ - ah##part = _mm_cvtsi128_si64(_mm_srli_si128(a, 8)); \ - VARIANT4_RANDOM_MATH(part, al##part, ah##part, cl##part, b0, b1); \ - if (VARIANT == xmrig::VARIANT_4) { \ - al##part ^= r##part[2] | ((uint64_t)(r##part[3]) << 32); \ - ah##part ^= r##part[0] | ((uint64_t)(r##part[1]) << 32); \ - } \ - } else { \ - VARIANT2_INTEGER_MATH(part, cl##part, c); \ - } \ - } \ - lo = __umul128(idx, cl##part, &hi); \ - if (BASE == xmrig::VARIANT_2) { \ - if (VARIANT == xmrig::VARIANT_4) { \ - VARIANT2_SHUFFLE(l, idx & MASK, a, b0, b1, c, 0); \ - } else { \ - VARIANT2_SHUFFLE2(l, idx & MASK, a, b0, b1, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); \ - } \ - } \ - if (VARIANT == xmrig::VARIANT_4) { \ - a = _mm_set_epi64x(ah##part, al##part); \ - } \ - a = _mm_add_epi64(a, _mm_set_epi64x(lo, hi)); \ - \ - if (BASE == xmrig::VARIANT_1) { \ - _mm_store_si128(ptr, _mm_xor_si128(a, mc)); \ - \ - if (VARIANT == xmrig::VARIANT_TUBE || \ - VARIANT == xmrig::VARIANT_RTO) { \ - ((uint64_t*)ptr)[1] ^= ((uint64_t*)ptr)[0]; \ - } \ - } else { \ - _mm_store_si128(ptr, a); \ - } \ - \ - a = _mm_xor_si128(a, _mm_set_epi64x(ch##part, cl##part)); \ - idx = _mm_cvtsi128_si64(a); \ - \ - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { \ - int64_t n = ((int64_t*)&l[idx & MASK])[0]; \ - int32_t d = ((int32_t*)&l[idx & MASK])[2]; \ - int64_t q = n / (d | 0x5); \ - ((int64_t*)&l[idx & MASK])[0] = n ^ q; \ - if (VARIANT == xmrig::VARIANT_XHV) { \ - d = ~d; \ - } \ - \ - idx = d ^ q; \ - } \ - if (BASE == xmrig::VARIANT_2) { \ - b1 = b0; \ - } \ +#define CN_STEP4(part, a, b0, b1, c, l, mc, ptr, idx) \ + uint64_t al##part, ah##part; \ + if (BASE == Algorithm::CN_2) { \ + if (props.isR()) { \ + al##part = _mm_cvtsi128_si64(a); \ + ah##part = _mm_cvtsi128_si64(_mm_srli_si128(a, 8)); \ + VARIANT4_RANDOM_MATH(part, al##part, ah##part, cl##part, b0, b1); \ + if (ALGO == Algorithm::CN_R) { \ + al##part ^= r##part[2] | ((uint64_t)(r##part[3]) << 32); \ + ah##part ^= r##part[0] | ((uint64_t)(r##part[1]) << 32); \ + } \ + } else { \ + VARIANT2_INTEGER_MATH(part, cl##part, c); \ + } \ + } \ + lo = __umul128(idx, cl##part, &hi); \ + if (BASE == Algorithm::CN_2) { \ + if (ALGO == Algorithm::CN_R) { \ + VARIANT2_SHUFFLE(l, idx & MASK, a, b0, b1, c, 0); \ + } else { \ + VARIANT2_SHUFFLE2(l, idx & MASK, a, b0, b1, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); \ + } \ + } \ + if (ALGO == Algorithm::CN_R) { \ + a = _mm_set_epi64x(ah##part, al##part); \ + } \ + a = _mm_add_epi64(a, _mm_set_epi64x(lo, hi)); \ + \ + if (BASE == Algorithm::CN_1) { \ + _mm_store_si128(ptr, _mm_xor_si128(a, mc)); \ + \ + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { \ + ((uint64_t*)ptr)[1] ^= ((uint64_t*)ptr)[0]; \ + } \ + } else { \ + _mm_store_si128(ptr, a); \ + } \ + \ + a = _mm_xor_si128(a, _mm_set_epi64x(ch##part, cl##part)); \ + idx = _mm_cvtsi128_si64(a); \ + if (props.isHeavy()) { \ + int64_t n = ((int64_t*)&l[idx & MASK])[0]; \ + int32_t d = ((int32_t*)&l[idx & MASK])[2]; \ + int64_t q = n / (d | 0x5); \ + ((int64_t*)&l[idx & MASK])[0] = n ^ q; \ + if (IS_CN_HEAVY_XHV) { \ + d = ~d; \ + } \ + \ + idx = d ^ q; \ + } \ + if (BASE == Algorithm::CN_2) { \ + b1 = b0; \ + } \ b0 = c; @@ -1246,11 +1303,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si __m128i mc##n; \ __m128i division_result_xmm_##n; \ __m128i sqrt_result_xmm_##n; \ - if (BASE == xmrig::VARIANT_1) { \ + if (BASE == Algorithm::CN_1) { \ mc##n = _mm_set_epi64x(*reinterpret_cast(input + n * size + 35) ^ \ *(reinterpret_cast((ctx)->state) + 24), 0); \ } \ - if (BASE == xmrig::VARIANT_2) { \ + if (BASE == Algorithm::CN_2) { \ division_result_xmm_##n = _mm_cvtsi64_si128(h##n[12]); \ sqrt_result_xmm_##n = _mm_cvtsi64_si128(h##n[13]); \ } \ @@ -1261,22 +1318,29 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si VARIANT4_RANDOM_MATH_INIT(n); -template +template inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; + constexpr bool IS_CN_HEAVY_XHV = ALGO == Algorithm::CN_HEAVY_XHV; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; + constexpr bool IS_CN_HEAVY_XHV = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 32 * 3); return; } for (size_t i = 0; i < 3; i++) { - xmrig::keccak(input + size * i, size, ctx[i]->state); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); + keccak(input + size * i, size, ctx[i]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); } uint8_t* l0 = ctx[0]->memory; @@ -1296,7 +1360,7 @@ inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t si idx1 = _mm_cvtsi128_si64(ax1); idx2 = _mm_cvtsi128_si64(ax2); - for (size_t i = 0; i < ITERATIONS; i++) { + for (size_t i = 0; i < props.iterations(); i++) { uint64_t hi, lo; __m128i *ptr0, *ptr1, *ptr2; @@ -1318,29 +1382,36 @@ inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t si } for (size_t i = 0; i < 3; i++) { - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); - xmrig::keccakf(reinterpret_cast(ctx[i]->state), 24); + cn_implode_scratchpad(reinterpret_cast(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); + keccakf(reinterpret_cast(ctx[i]->state), 24); extra_hashes[ctx[i]->state[0] & 3](ctx[i]->state, 200, output + 32 * i); } } -template +template inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; + constexpr bool IS_CN_HEAVY_XHV = ALGO == Algorithm::CN_HEAVY_XHV; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; + constexpr bool IS_CN_HEAVY_XHV = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 32 * 4); return; } for (size_t i = 0; i < 4; i++) { - xmrig::keccak(input + size * i, size, ctx[i]->state); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); + keccak(input + size * i, size, ctx[i]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); } uint8_t* l0 = ctx[0]->memory; @@ -1364,8 +1435,7 @@ inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size idx2 = _mm_cvtsi128_si64(ax2); idx3 = _mm_cvtsi128_si64(ax3); - for (size_t i = 0; i < ITERATIONS; i++) - { + for (size_t i = 0; i < props.iterations(); i++) { uint64_t hi, lo; __m128i *ptr0, *ptr1, *ptr2, *ptr3; @@ -1391,29 +1461,36 @@ inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size } for (size_t i = 0; i < 4; i++) { - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); - xmrig::keccakf(reinterpret_cast(ctx[i]->state), 24); + cn_implode_scratchpad(reinterpret_cast(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); + keccakf(reinterpret_cast(ctx[i]->state), 24); extra_hashes[ctx[i]->state[0] & 3](ctx[i]->state, 200, output + 32 * i); } } -template +template inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; + constexpr bool IS_CN_HEAVY_XHV = ALGO == Algorithm::CN_HEAVY_XHV; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; + constexpr bool IS_CN_HEAVY_XHV = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 32 * 5); return; } for (size_t i = 0; i < 5; i++) { - xmrig::keccak(input + size * i, size, ctx[i]->state); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); + keccak(input + size * i, size, ctx[i]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); } uint8_t* l0 = ctx[0]->memory; @@ -1441,8 +1518,7 @@ inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t siz idx3 = _mm_cvtsi128_si64(ax3); idx4 = _mm_cvtsi128_si64(ax4); - for (size_t i = 0; i < ITERATIONS; i++) - { + for (size_t i = 0; i < props.iterations(); i++) { uint64_t hi, lo; __m128i *ptr0, *ptr1, *ptr2, *ptr3, *ptr4; @@ -1472,10 +1548,14 @@ inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t siz } for (size_t i = 0; i < 5; i++) { - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); - xmrig::keccakf(reinterpret_cast(ctx[i]->state), 24); + cn_implode_scratchpad(reinterpret_cast(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); + keccakf(reinterpret_cast(ctx[i]->state), 24); extra_hashes[ctx[i]->state[0] & 3](ctx[i]->state, 200, output + 32 * i); } } + +} /* namespace xmrig */ + + #endif /* XMRIG_CRYPTONIGHT_X86_H */ diff --git a/src/crypto/cn/gpu/cn_gpu_avx.cpp b/src/crypto/cn/gpu/cn_gpu_avx.cpp index 382be570..38da9714 100644 --- a/src/crypto/cn/gpu/cn_gpu_avx.cpp +++ b/src/crypto/cn/gpu/cn_gpu_avx.cpp @@ -22,7 +22,9 @@ * along with this program. If not, see . */ -#include "crypto/cn/CryptoNight_constants.h" + +#include "crypto/cn/CnAlgo.h" + #ifdef __GNUC__ # include @@ -206,4 +208,4 @@ void cn_gpu_inner_avx(const uint8_t* spad, uint8_t* lpad) } } -template void cn_gpu_inner_avx(const uint8_t* spad, uint8_t* lpad); +template void cn_gpu_inner_avx().iterations(), xmrig::CnAlgo().mask()>(const uint8_t* spad, uint8_t* lpad); diff --git a/src/crypto/cn/gpu/cn_gpu_ssse3.cpp b/src/crypto/cn/gpu/cn_gpu_ssse3.cpp index 42a11a1d..7cca096e 100644 --- a/src/crypto/cn/gpu/cn_gpu_ssse3.cpp +++ b/src/crypto/cn/gpu/cn_gpu_ssse3.cpp @@ -22,7 +22,9 @@ * along with this program. If not, see . */ -#include "crypto/cn/CryptoNight_constants.h" + +#include "crypto/cn/CnAlgo.h" + #ifdef __GNUC__ # include @@ -207,4 +209,4 @@ void cn_gpu_inner_ssse3(const uint8_t* spad, uint8_t* lpad) } } -template void cn_gpu_inner_ssse3(const uint8_t* spad, uint8_t* lpad); +template void cn_gpu_inner_ssse3().iterations(), xmrig::CnAlgo().mask()>(const uint8_t* spad, uint8_t* lpad); diff --git a/src/crypto/cn/r/variant4_random_math.h b/src/crypto/cn/r/variant4_random_math.h index c384df7a..48f0f6ce 100644 --- a/src/crypto/cn/r/variant4_random_math.h +++ b/src/crypto/cn/r/variant4_random_math.h @@ -1,6 +1,13 @@ #ifndef VARIANT4_RANDOM_MATH_H #define VARIANT4_RANDOM_MATH_H + +#include + + +#include "crypto/common/Algorithm.h" + + extern "C" { #include "crypto/cn/c_blake256.h" @@ -182,7 +189,7 @@ static FORCEINLINE void check_data(size_t* data_index, const size_t bytes_needed // Generates as many random math operations as possible with given latency and ALU restrictions // "code" array must have space for NUM_INSTRUCTIONS_MAX+1 instructions -template +template static int v4_random_math_init(struct V4_Instruction* code, const uint64_t height) { // MUL is 3 cycles, 3-way addition and rotations are 2 cycles, SUB/XOR are 1 cycle @@ -204,8 +211,7 @@ static int v4_random_math_init(struct V4_Instruction* code, const uint64_t heigh memset(data, 0, sizeof(data)); uint64_t tmp = SWAP64LE(height); memcpy(data, &tmp, sizeof(uint64_t)); - if (VARIANT == xmrig::VARIANT_4) - { + if (ALGO == xmrig::Algorithm::CN_R) { data[20] = -38; } @@ -249,7 +255,7 @@ static int v4_random_math_init(struct V4_Instruction* code, const uint64_t heigh code_size = 0; int total_iterations = 0; - r8_used = (VARIANT == xmrig::VARIANT_WOW); + r8_used = (ALGO == xmrig::Algorithm::CN_WOW); // Generate random code to achieve minimal required latency for our abstract CPU // Try to get this latency for all 4 registers @@ -291,10 +297,9 @@ static int v4_random_math_init(struct V4_Instruction* code, const uint64_t heigh int b = src_index; // Don't do ADD/SUB/XOR with the same register - if (((opcode == ADD) || (opcode == SUB) || (opcode == XOR)) && (a == b)) - { + if (((opcode == ADD) || (opcode == SUB) || (opcode == XOR)) && (a == b)) { // a is always < 4, so we don't need to check bounds here - b = (VARIANT == xmrig::VARIANT_WOW) ? (a + 4) : 8; + b = (ALGO == xmrig::Algorithm::CN_WOW) ? (a + 4) : 8; src_index = b; } diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index f85b0a6f..78272f79 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -56,12 +56,12 @@ struct AlgoName static AlgoName const algorithm_names[] = { - { "cryptonight/0", "cn/0", Algorithm::CN_0 }, - { "cryptonight", "cn", Algorithm::CN_0 }, - { "cryptonight/1", "cn/1", Algorithm::CN_1 }, - { "cryptonight-monerov7", nullptr, Algorithm::CN_1 }, - { "cryptonight_v7", nullptr, Algorithm::CN_1 }, - { "cryptonight/2", "cn/2", Algorithm::CN_2 }, + { "cryptonight/0", "cn/0", Algorithm::CN_0 }, + { "cryptonight", "cn", Algorithm::CN_0 }, + { "cryptonight/1", "cn/1", Algorithm::CN_1 }, + { "cryptonight-monerov7", nullptr, Algorithm::CN_1 }, + { "cryptonight_v7", nullptr, Algorithm::CN_1 }, + { "cryptonight/2", "cn/2", Algorithm::CN_2 }, { "cryptonight-monerov8", nullptr, Algorithm::CN_2 }, { "cryptonight_v8", nullptr, Algorithm::CN_2 }, { "cryptonight/r", "cn/r", Algorithm::CN_R }, @@ -75,7 +75,7 @@ static AlgoName const algorithm_names[] = { { "cryptonight/rto", "cn/rto", Algorithm::CN_RTO }, { "cryptonight/rwz", "cn/rwz", Algorithm::CN_RWZ }, { "cryptonight/zls", "cn/zls", Algorithm::CN_ZLS }, - { "cryptonight/double", "cn/double", Algorithm::CN_ZLS }, + { "cryptonight/double", "cn/double", Algorithm::CN_DOUBLE }, # ifdef XMRIG_ALGO_CN_GPU { "cryptonight/gpu", "cn/gpu", Algorithm::CN_GPU }, { "cryptonight_gpu", nullptr, Algorithm::CN_GPU }, @@ -99,11 +99,11 @@ static AlgoName const algorithm_names[] = { { "cryptonight-bittube2", nullptr, Algorithm::CN_HEAVY_TUBE }, # endif # ifdef XMRIG_ALGO_CN_PICO - { "cryptonight-pico", "cn-pico", Algorithm::CN_PICO }, - { "cryptonight-pico/trtl", "cn-pico/trtl", Algorithm::CN_PICO }, - { "cryptonight-turtle", "cn-trtl", Algorithm::CN_PICO }, - { "cryptonight-ultralite", "cn-ultralite", Algorithm::CN_PICO }, - { "cryptonight_turtle", "cn_turtle", Algorithm::CN_PICO }, + { "cryptonight-pico", "cn-pico", Algorithm::CN_PICO_0 }, + { "cryptonight-pico/trtl", "cn-pico/trtl", Algorithm::CN_PICO_0 }, + { "cryptonight-turtle", "cn-trtl", Algorithm::CN_PICO_0 }, + { "cryptonight-ultralite", "cn-ultralite", Algorithm::CN_PICO_0 }, + { "cryptonight_turtle", "cn_turtle", Algorithm::CN_PICO_0 }, # endif }; @@ -111,15 +111,48 @@ static AlgoName const algorithm_names[] = { } /* namespace xmrig */ -const char *xmrig::Algorithm::name(bool shortName) const +xmrig::Algorithm::Family xmrig::Algorithm::family(Id id) { - for (size_t i = 0; i < ARRAY_SIZE(algorithm_names); i++) { - if (algorithm_names[i].id == m_id) { - return shortName ? algorithm_names[i].shortName : algorithm_names[i].name; - } + switch (id) { + case CN_0: + case CN_1: + case CN_2: + case CN_R: + case CN_WOW: + case CN_FAST: + case CN_HALF: + case CN_XAO: + case CN_RTO: + case CN_RWZ: + case CN_DOUBLE: +# ifdef XMRIG_ALGO_CN_GPU + case CN_GPU: +# endif + return CN; + +# ifdef XMRIG_ALGO_CN_LITE + case CN_LITE_0: + case CN_LITE_1: + return CN_LITE; +# endif + +# ifdef XMRIG_ALGO_CN_HEAVY + case CN_HEAVY_0: + case CN_HEAVY_TUBE: + case CN_HEAVY_XHV: + return CN_HEAVY; +# endif + +# ifdef XMRIG_ALGO_CN_PICO + case Algorithm::CN_PICO_0: + return CN_PICO; +# endif + + default: + break; } - return "invalid"; + return UNKNOWN; } @@ -137,3 +170,15 @@ xmrig::Algorithm::Id xmrig::Algorithm::parse(const char *name) return INVALID; } + + +const char *xmrig::Algorithm::name(bool shortName) const +{ + for (size_t i = 0; i < ARRAY_SIZE(algorithm_names); i++) { + if (algorithm_names[i].id == m_id) { + return shortName ? algorithm_names[i].shortName : algorithm_names[i].name; + } + } + + return "invalid"; +} diff --git a/src/crypto/common/Algorithm.h b/src/crypto/common/Algorithm.h index c70e0caa..c9388dee 100644 --- a/src/crypto/common/Algorithm.h +++ b/src/crypto/common/Algorithm.h @@ -63,24 +63,35 @@ public: CN_HEAVY_XHV, // "cn-heavy/xhv" Modified CryptoNight-Heavy (Haven Protocol only) # endif # ifdef XMRIG_ALGO_CN_PICO - CN_PICO, // "cn-pico" CryptoNight Turtle (TRTL) + CN_PICO_0, // "cn-pico" CryptoNight Turtle (TRTL) # endif MAX }; + enum Family : int { + UNKNOWN, + CN, + CN_LITE, + CN_HEAVY, + CN_PICO + }; + inline Algorithm() {} inline Algorithm(const char *algo) : m_id(parse(algo)) {} inline Algorithm(Id id) : m_id(id) {} inline bool isEqual(const Algorithm &other) const { return m_id == other.m_id; } + inline bool isValid() const { return m_id != INVALID; } inline const char *name() const { return name(false); } inline const char *shortName() const { return name(true); } + inline Family family() const { return family(m_id); } inline Id id() const { return m_id; } - inline bool isValid() const { return m_id != INVALID; } inline bool operator!=(const Algorithm &other) const { return !isEqual(other); } inline bool operator==(const Algorithm &other) const { return isEqual(other); } + inline operator Algorithm::Id() const { return m_id; } + static Family family(Id id); static Id parse(const char *name); private: diff --git a/src/interfaces/IThread.h b/src/interfaces/IThread.h index e74b5bca..3c0a7287 100644 --- a/src/interfaces/IThread.h +++ b/src/interfaces/IThread.h @@ -27,7 +27,7 @@ #include -#include "common/xmrig.h" +#include "crypto/common/Algorithm.h" #include "rapidjson/fwd.h" @@ -53,7 +53,7 @@ public: virtual ~IThread() = default; - virtual Algo algorithm() const = 0; + virtual Algorithm algorithm() const = 0; virtual int priority() const = 0; virtual int64_t affinity() const = 0; virtual Multiway multiway() const = 0; diff --git a/src/workers/CpuThread.cpp b/src/workers/CpuThread.cpp index 5c98a5b3..e26b8a0a 100644 --- a/src/workers/CpuThread.cpp +++ b/src/workers/CpuThread.cpp @@ -28,20 +28,20 @@ #include "base/io/log/Log.h" #include "common/cpu/Cpu.h" #include "crypto/cn/Asm.h" +#include "crypto/cn/CnHash.h" #include "crypto/common/VirtualMemory.h" #include "Mem.h" #include "rapidjson/document.h" #include "workers/CpuThread.h" -#if defined(XMRIG_ARM) -# include "crypto/cn/CryptoNight_arm.h" -#else -# include "crypto/cn/CryptoNight_x86.h" -#endif -xmrig::CpuThread::CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly) : + +static const xmrig::CnHash cnHash; + + +xmrig::CpuThread::CpuThread(size_t index, Algorithm algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly) : m_algorithm(algorithm), m_av(av), m_assembly(assembly), @@ -55,119 +55,12 @@ xmrig::CpuThread::CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiw } -#ifndef XMRIG_NO_ASM -template -static void patchCode(T dst, U src, const uint32_t iterations, const uint32_t mask) +xmrig::cn_hash_fun xmrig::CpuThread::fn(const Algorithm &algorithm) const { - const uint8_t* p = reinterpret_cast(src); - - // Workaround for Visual Studio placing trampoline in debug builds. -# if defined(_MSC_VER) - if (p[0] == 0xE9) { - p += *(int32_t*)(p + 1) + 5; - } -# endif - - size_t size = 0; - while (*(uint32_t*)(p + size) != 0xDEADC0DE) { - ++size; - } - size += sizeof(uint32_t); - - memcpy((void*) dst, (const void*) src, size); - - uint8_t* patched_data = reinterpret_cast(dst); - for (size_t i = 0; i + sizeof(uint32_t) <= size; ++i) { - switch (*(uint32_t*)(patched_data + i)) { - case xmrig::CRYPTONIGHT_ITER: - *(uint32_t*)(patched_data + i) = iterations; - break; - - case xmrig::CRYPTONIGHT_MASK: - *(uint32_t*)(patched_data + i) = mask; - break; - } - } + return cnHash.fn(algorithm, m_av, m_assembly); } -extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx **ctx); -extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx **ctx); -extern "C" void cnv2_mainloop_bulldozer_asm(cryptonight_ctx **ctx); -extern "C" void cnv2_double_mainloop_sandybridge_asm(cryptonight_ctx **ctx); - - -xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ivybridge_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ryzen_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_bulldozer_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_half_double_mainloop_sandybridge_asm = nullptr; - -xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ivybridge_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ryzen_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_trtl_double_mainloop_sandybridge_asm = nullptr; - -xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ivybridge_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ryzen_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_bulldozer_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_zls_double_mainloop_sandybridge_asm = nullptr; - -xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ivybridge_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ryzen_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_bulldozer_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_double_double_mainloop_sandybridge_asm = nullptr; - - -void xmrig::CpuThread::patchAsmVariants() -{ - const int allocation_size = 65536; - uint8_t *base = static_cast(VirtualMemory::allocateExecutableMemory(allocation_size)); - - cn_half_mainloop_ivybridge_asm = reinterpret_cast (base + 0x0000); - cn_half_mainloop_ryzen_asm = reinterpret_cast (base + 0x1000); - cn_half_mainloop_bulldozer_asm = reinterpret_cast (base + 0x2000); - cn_half_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0x3000); - - cn_trtl_mainloop_ivybridge_asm = reinterpret_cast (base + 0x4000); - cn_trtl_mainloop_ryzen_asm = reinterpret_cast (base + 0x5000); - cn_trtl_mainloop_bulldozer_asm = reinterpret_cast (base + 0x6000); - cn_trtl_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0x7000); - - cn_zls_mainloop_ivybridge_asm = reinterpret_cast (base + 0x8000); - cn_zls_mainloop_ryzen_asm = reinterpret_cast (base + 0x9000); - cn_zls_mainloop_bulldozer_asm = reinterpret_cast (base + 0xA000); - cn_zls_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0xB000); - - cn_double_mainloop_ivybridge_asm = reinterpret_cast (base + 0xC000); - cn_double_mainloop_ryzen_asm = reinterpret_cast (base + 0xD000); - cn_double_mainloop_bulldozer_asm = reinterpret_cast (base + 0xE000); - cn_double_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0xF000); - - patchCode(cn_half_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_half_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_half_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_half_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - - patchCode(cn_trtl_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); - patchCode(cn_trtl_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); - patchCode(cn_trtl_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); - patchCode(cn_trtl_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); - - patchCode(cn_zls_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_zls_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_zls_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_zls_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); - - patchCode(cn_double_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_double_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_double_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_double_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); - - VirtualMemory::protectExecutableMemory(base, allocation_size); - VirtualMemory::flushInstructionCache(base, allocation_size); -} -#endif - bool xmrig::CpuThread::isSoftAES(AlgoVariant av) { @@ -175,418 +68,7 @@ bool xmrig::CpuThread::isSoftAES(AlgoVariant av) } -#ifndef XMRIG_NO_ASM -template -static inline void add_asm_func(xmrig::CpuThread::cn_hash_fun(&asm_func_map)[xmrig::ALGO_MAX][xmrig::AV_MAX][xmrig::VARIANT_MAX][xmrig::ASM_MAX]) -{ - asm_func_map[algo][xmrig::AV_SINGLE][variant][xmrig::ASM_INTEL] = cryptonight_single_hash_asm; - asm_func_map[algo][xmrig::AV_SINGLE][variant][xmrig::ASM_RYZEN] = cryptonight_single_hash_asm; - asm_func_map[algo][xmrig::AV_SINGLE][variant][xmrig::ASM_BULLDOZER] = cryptonight_single_hash_asm; - - asm_func_map[algo][xmrig::AV_DOUBLE][variant][xmrig::ASM_INTEL] = cryptonight_double_hash_asm; - asm_func_map[algo][xmrig::AV_DOUBLE][variant][xmrig::ASM_RYZEN] = cryptonight_double_hash_asm; - asm_func_map[algo][xmrig::AV_DOUBLE][variant][xmrig::ASM_BULLDOZER] = cryptonight_double_hash_asm; -} -#endif - -xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant av, Variant variant, Assembly assembly) -{ - assert(variant >= VARIANT_0 && variant < VARIANT_MAX); - -# ifndef XMRIG_NO_ASM - if (assembly == ASM_AUTO) { - assembly = Cpu::info()->assembly(); - } - - static cn_hash_fun asm_func_map[ALGO_MAX][AV_MAX][VARIANT_MAX][ASM_MAX] = {}; - static bool asm_func_map_initialized = false; - - if (!asm_func_map_initialized) { - add_asm_func(asm_func_map); - add_asm_func(asm_func_map); - add_asm_func(asm_func_map); - add_asm_func(asm_func_map); - -# ifdef XMRIG_ALGO_CN_PICO - add_asm_func(asm_func_map); -# endif - - add_asm_func(asm_func_map); - add_asm_func(asm_func_map); - add_asm_func(asm_func_map); - - asm_func_map_initialized = true; - } - - cn_hash_fun fun = asm_func_map[algorithm][av][variant][assembly]; - if (fun) { - return fun; - } -# endif - - constexpr const size_t count = VARIANT_MAX * 10 * ALGO_MAX; - - static const cn_hash_fun func_table[] = { - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - -# ifdef XMRIG_ALGO_CN_GPU - cryptonight_single_hash_gpu, - nullptr, - cryptonight_single_hash_gpu, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, -# else - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU -# endif - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - -# ifdef XMRIG_ALGO_CN_LITE - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE -# else - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE -# endif - -# ifdef XMRIG_ALGO_CN_HEAVY - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE -# else - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE -# endif - -# ifdef XMRIG_ALGO_CN_PICO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE -# else - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE -# endif - }; - - static_assert(count == sizeof(func_table) / sizeof(func_table[0]), "func_table size mismatch"); - - const size_t index = VARIANT_MAX * 10 * algorithm + 10 * variant + av - 1; - -# ifndef NDEBUG - cn_hash_fun func = func_table[index]; - - assert(index < sizeof(func_table) / sizeof(func_table[0])); - assert(func != nullptr); - - return func; -# else - return func_table[index]; -# endif -} - - -xmrig::CpuThread *xmrig::CpuThread::createFromAV(size_t index, Algo algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly) +xmrig::CpuThread *xmrig::CpuThread::createFromAV(size_t index, const Algorithm &algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly) { assert(av > AV_AUTO && av < AV_MAX); @@ -613,7 +95,7 @@ xmrig::CpuThread *xmrig::CpuThread::createFromAV(size_t index, Algo algorithm, A } -xmrig::CpuThread *xmrig::CpuThread::createFromData(size_t index, Algo algorithm, const CpuThread::Data &data, int priority, bool softAES) +xmrig::CpuThread *xmrig::CpuThread::createFromData(size_t index, const Algorithm &algorithm, const CpuThread::Data &data, int priority, bool softAES) { int av = AV_AUTO; const Multiway multiway = data.multiway; @@ -653,7 +135,7 @@ xmrig::CpuThread::Data xmrig::CpuThread::parse(const rapidjson::Value &object) data.affinity = affinity.GetInt64(); } -# ifndef XMRIG_NO_ASM +# ifdef XMRIG_FEATURE_ASM data.assembly = Asm::parse(object["asm"]); # endif @@ -698,7 +180,7 @@ void xmrig::CpuThread::print() const LOG_DEBUG(GREEN_BOLD("CPU thread: ") " index " WHITE_BOLD("%zu") ", multiway " WHITE_BOLD("%d") ", av " WHITE_BOLD("%d") ",", index(), static_cast(multiway()), static_cast(m_av)); -# ifndef XMRIG_NO_ASM +# ifdef XMRIG_FEATURE_ASM LOG_DEBUG(" assembly: %s, affine_to_cpu: %" PRId64, Asm::toString(m_assembly), affinity()); # else LOG_DEBUG(" affine_to_cpu: %" PRId64, affinity()); @@ -737,7 +219,7 @@ rapidjson::Value xmrig::CpuThread::toConfig(rapidjson::Document &doc) const obj.AddMember("low_power_mode", multiway(), allocator); obj.AddMember("affine_to_cpu", affinity() == -1L ? Value(kFalseType) : Value(affinity()), allocator); -# ifndef XMRIG_NO_ASM +# ifdef XMRIG_FEATURE_ASM obj.AddMember("asm", Asm::toJSON(m_assembly), allocator); # endif diff --git a/src/workers/CpuThread.h b/src/workers/CpuThread.h index 2af421be..08aa89cb 100644 --- a/src/workers/CpuThread.h +++ b/src/workers/CpuThread.h @@ -27,6 +27,7 @@ #include "common/xmrig.h" +#include "crypto/cn/CnHash.h" #include "interfaces/IThread.h" @@ -58,27 +59,20 @@ public: }; - CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly); + CpuThread(size_t index, Algorithm algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly); - typedef void (*cn_hash_fun)(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx **ctx, uint64_t height); - typedef void (*cn_mainloop_fun)(cryptonight_ctx **ctx); - -# ifndef XMRIG_NO_ASM - static void patchAsmVariants(); -# endif + cn_hash_fun fn(const Algorithm &algorithm) const; static bool isSoftAES(AlgoVariant av); - static cn_hash_fun fn(Algo algorithm, AlgoVariant av, Variant variant, Assembly assembly); - static CpuThread *createFromAV(size_t index, Algo algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly); - static CpuThread *createFromData(size_t index, Algo algorithm, const CpuThread::Data &data, int priority, bool softAES); + static CpuThread *createFromAV(size_t index, const Algorithm &algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly); + static CpuThread *createFromData(size_t index, const Algorithm &algorithm, const CpuThread::Data &data, int priority, bool softAES); static Data parse(const rapidjson::Value &object); static Multiway multiway(AlgoVariant av); inline bool isPrefetch() const { return m_prefetch; } inline bool isSoftAES() const { return m_softAES; } - inline cn_hash_fun fn(Variant variant) const { return fn(m_algorithm, m_av, variant, m_assembly); } - inline Algo algorithm() const override { return m_algorithm; } + inline Algorithm algorithm() const override { return m_algorithm; } inline int priority() const override { return m_priority; } inline int64_t affinity() const override { return m_affinity; } inline Multiway multiway() const override { return m_multiway; } @@ -97,7 +91,7 @@ protected: rapidjson::Value toConfig(rapidjson::Document &doc) const override; private: - const Algo m_algorithm; + const Algorithm m_algorithm; const AlgoVariant m_av; const Assembly m_assembly; const bool m_prefetch; diff --git a/src/workers/MultiWorker.cpp b/src/workers/MultiWorker.cpp index 30c43000..f209ca76 100644 --- a/src/workers/MultiWorker.cpp +++ b/src/workers/MultiWorker.cpp @@ -34,7 +34,7 @@ template -MultiWorker::MultiWorker(ThreadHandle *handle) +xmrig::MultiWorker::MultiWorker(ThreadHandle *handle) : Worker(handle) { m_memory = Mem::create(m_ctx, m_thread->algorithm(), N); @@ -42,61 +42,58 @@ MultiWorker::MultiWorker(ThreadHandle *handle) template -MultiWorker::~MultiWorker() +xmrig::MultiWorker::~MultiWorker() { Mem::release(m_ctx, N, m_memory); } template -bool MultiWorker::selfTest() +bool xmrig::MultiWorker::selfTest() { - using namespace xmrig; - - if (m_thread->algorithm() == CRYPTONIGHT) { - const bool rc = verify(VARIANT_0, test_output_v0) && - verify(VARIANT_1, test_output_v1) && - verify(VARIANT_2, test_output_v2) && - verify(VARIANT_XTL, test_output_xtl) && - verify(VARIANT_MSR, test_output_msr) && - verify(VARIANT_XAO, test_output_xao) && - verify(VARIANT_RTO, test_output_rto) && - verify(VARIANT_HALF, test_output_half) && - verify2(VARIANT_WOW, test_output_wow) && - verify2(VARIANT_4, test_output_r) && - verify(VARIANT_RWZ, test_output_rwz) && - verify(VARIANT_ZLS, test_output_zls) && - verify(VARIANT_DOUBLE, test_output_double); + if (m_thread->algorithm().family() == Algorithm::CN) { + const bool rc = verify(Algorithm::CN_0, test_output_v0) && + verify(Algorithm::CN_1, test_output_v1) && + verify(Algorithm::CN_2, test_output_v2) && + verify(Algorithm::CN_FAST, test_output_msr) && + verify(Algorithm::CN_XAO, test_output_xao) && + verify(Algorithm::CN_RTO, test_output_rto) && + verify(Algorithm::CN_HALF, test_output_half) && + verify2(Algorithm::CN_WOW, test_output_wow) && + verify2(Algorithm::CN_R, test_output_r) && + verify(Algorithm::CN_RWZ, test_output_rwz) && + verify(Algorithm::CN_ZLS, test_output_zls) && + verify(Algorithm::CN_DOUBLE, test_output_double); # ifdef XMRIG_ALGO_CN_GPU if (!rc || N > 1) { return rc; } - return verify(VARIANT_GPU, test_output_gpu); + return verify(Algorithm::CN_GPU, test_output_gpu); # else return rc; # endif } # ifdef XMRIG_ALGO_CN_LITE - if (m_thread->algorithm() == CRYPTONIGHT_LITE) { - return verify(VARIANT_0, test_output_v0_lite) && - verify(VARIANT_1, test_output_v1_lite); + if (m_thread->algorithm().family() == Algorithm::CN_LITE) { + return verify(Algorithm::CN_LITE_0, test_output_v0_lite) && + verify(Algorithm::CN_LITE_1, test_output_v1_lite); } # endif # ifdef XMRIG_ALGO_CN_HEAVY - if (m_thread->algorithm() == CRYPTONIGHT_HEAVY) { - return verify(VARIANT_0, test_output_v0_heavy) && - verify(VARIANT_XHV, test_output_xhv_heavy) && - verify(VARIANT_TUBE, test_output_tube_heavy); + if (m_thread->algorithm().family() == Algorithm::CN_HEAVY) { + return verify(Algorithm::CN_HEAVY_0, test_output_v0_heavy) && + verify(Algorithm::CN_HEAVY_XHV, test_output_xhv_heavy) && + verify(Algorithm::CN_HEAVY_TUBE, test_output_tube_heavy); } # endif # ifdef XMRIG_ALGO_CN_PICO - if (m_thread->algorithm() == CRYPTONIGHT_PICO) { - return verify(VARIANT_TRTL, test_output_pico_trtl); + if (m_thread->algorithm().family() == Algorithm::CN_PICO) { + return verify(Algorithm::CN_PICO_0, test_output_pico_trtl); } # endif @@ -105,7 +102,7 @@ bool MultiWorker::selfTest() template -void MultiWorker::start() +void xmrig::MultiWorker::start() { while (Workers::sequence() > 0) { if (Workers::isPaused()) { @@ -126,12 +123,11 @@ void MultiWorker::start() storeStats(); } - // FIXME -// m_thread->fn(m_state.job.algorithm().variant())(m_state.blob, m_state.job.size(), m_hash, m_ctx, m_state.job.height()); + m_thread->fn(m_state.job.algorithm())(m_state.blob, m_state.job.size(), m_hash, m_ctx, m_state.job.height()); for (size_t i = 0; i < N; ++i) { if (*reinterpret_cast(m_hash + (i * 32) + 24) < m_state.job.target()) { - Workers::submit(xmrig::JobResult(m_state.job.poolId(), m_state.job.id(), m_state.job.clientId(), *nonce(i), m_hash + (i * 32), m_state.job.diff(), m_state.job.algorithm())); + Workers::submit(JobResult(m_state.job.poolId(), m_state.job.id(), m_state.job.clientId(), *nonce(i), m_hash + (i * 32), m_state.job.diff(), m_state.job.algorithm())); } *nonce(i) += 1; @@ -148,7 +144,7 @@ void MultiWorker::start() template -bool MultiWorker::resume(const xmrig::Job &job) +bool xmrig::MultiWorker::resume(const xmrig::Job &job) { if (m_state.job.poolId() == -1 && job.poolId() >= 0 && job.id() == m_pausedState.job.id()) { m_state = m_pausedState; @@ -160,10 +156,9 @@ bool MultiWorker::resume(const xmrig::Job &job) template -bool MultiWorker::verify(xmrig::Variant variant, const uint8_t *referenceValue) +bool xmrig::MultiWorker::verify(const Algorithm &algorithm, const uint8_t *referenceValue) { - - xmrig::CpuThread::cn_hash_fun func = m_thread->fn(variant); + cn_hash_fun func = m_thread->fn(algorithm); if (!func) { return false; } @@ -174,9 +169,9 @@ bool MultiWorker::verify(xmrig::Variant variant, const uint8_t *referenceValu template -bool MultiWorker::verify2(xmrig::Variant variant, const uint8_t *referenceValue) +bool xmrig::MultiWorker::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) { - xmrig::CpuThread::cn_hash_fun func = m_thread->fn(variant); + cn_hash_fun func = m_thread->fn(algorithm); if (!func) { return false; } @@ -201,9 +196,9 @@ bool MultiWorker::verify2(xmrig::Variant variant, const uint8_t *referenceVal template<> -bool MultiWorker<1>::verify2(xmrig::Variant variant, const uint8_t *referenceValue) +bool xmrig::MultiWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) { - xmrig::CpuThread::cn_hash_fun func = m_thread->fn(variant); + cn_hash_fun func = m_thread->fn(algorithm); if (!func) { return false; } @@ -221,9 +216,9 @@ bool MultiWorker<1>::verify2(xmrig::Variant variant, const uint8_t *referenceVal template -void MultiWorker::consumeJob() +void xmrig::MultiWorker::consumeJob() { - xmrig::Job job = Workers::job(); + Job job = Workers::job(); m_sequence = Workers::sequence(); if (m_state.job == job) { return; @@ -258,7 +253,7 @@ void MultiWorker::consumeJob() template -void MultiWorker::save(const xmrig::Job &job) +void xmrig::MultiWorker::save(const Job &job) { if (job.poolId() == -1 && m_state.job.poolId() >= 0) { m_pausedState = m_state; @@ -266,8 +261,13 @@ void MultiWorker::save(const xmrig::Job &job) } +namespace xmrig { + template class MultiWorker<1>; template class MultiWorker<2>; template class MultiWorker<3>; template class MultiWorker<4>; template class MultiWorker<5>; + +} + diff --git a/src/workers/MultiWorker.h b/src/workers/MultiWorker.h index 99d37e44..82898e1e 100644 --- a/src/workers/MultiWorker.h +++ b/src/workers/MultiWorker.h @@ -33,7 +33,7 @@ #include "workers/Worker.h" -class Handle; +namespace xmrig { template @@ -48,11 +48,11 @@ protected: void start() override; private: - bool resume(const xmrig::Job &job); - bool verify(xmrig::Variant variant, const uint8_t *referenceValue); - bool verify2(xmrig::Variant variant, const uint8_t *referenceValue); + bool resume(const Job &job); + bool verify(const Algorithm &algorithm, const uint8_t *referenceValue); + bool verify2(const Algorithm &algorithm, const uint8_t *referenceValue); void consumeJob(); - void save(const xmrig::Job &job); + void save(const Job &job); inline uint32_t *nonce(size_t index) { @@ -61,8 +61,8 @@ private: struct State { - alignas(16) uint8_t blob[xmrig::Job::kMaxBlobSize * N]; - xmrig::Job job; + alignas(16) uint8_t blob[Job::kMaxBlobSize * N]; + Job job; }; @@ -73,4 +73,7 @@ private: }; +} // namespace xmrig + + #endif /* XMRIG_MULTIWORKER_H */ diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index 62cbd1cf..1955677b 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -32,7 +32,6 @@ #include "base/tools/Handle.h" #include "core/config/Config.h" #include "core/Controller.h" -#include "crypto/cn/CryptoNight_constants.h" #include "interfaces/IJobResultListener.h" #include "interfaces/IThread.h" #include "Mem.h" @@ -169,14 +168,10 @@ void Workers::start(xmrig::Controller *controller) LOG_NOTICE("--------------------------------------------------------------------------"); # endif -# ifndef XMRIG_NO_ASM - xmrig::CpuThread::patchAsmVariants(); -# endif - m_controller = controller; const std::vector &threads = controller->config()->threads(); -// m_status.algo = controller->config()->algorithm().algo(); // FIXME + m_status.algo = xmrig::Algorithm::CN_0; // FIXME algo m_status.threads = threads.size(); for (const xmrig::IThread *thread : threads) { @@ -240,7 +235,7 @@ void Workers::threadsSummary(rapidjson::Document &doc) { uv_mutex_lock(&m_mutex); const uint64_t pages[2] = { m_status.hugePages, m_status.pages }; - const uint64_t memory = m_status.ways * xmrig::cn_select_memory(m_status.algo); + const uint64_t memory = m_status.ways * xmrig::CnAlgo<>::memory(m_status.algo); uv_mutex_unlock(&m_mutex); auto &allocator = doc.GetAllocator(); @@ -263,23 +258,23 @@ void Workers::onReady(void *arg) switch (handle->config()->multiway()) { case 1: - worker = new MultiWorker<1>(handle); + worker = new xmrig::MultiWorker<1>(handle); break; case 2: - worker = new MultiWorker<2>(handle); + worker = new xmrig::MultiWorker<2>(handle); break; case 3: - worker = new MultiWorker<3>(handle); + worker = new xmrig::MultiWorker<3>(handle); break; case 4: - worker = new MultiWorker<4>(handle); + worker = new xmrig::MultiWorker<4>(handle); break; case 5: - worker = new MultiWorker<5>(handle); + worker = new xmrig::MultiWorker<5>(handle); break; default: @@ -344,7 +339,7 @@ void Workers::start(IWorker *worker) if (m_status.started == m_status.threads) { const double percent = (double) m_status.hugePages / m_status.pages * 100.0; - const size_t memory = m_status.ways * xmrig::cn_select_memory(m_status.algo) / 1024; + const size_t memory = m_status.ways * xmrig::CnAlgo<>::memory(m_status.algo) / 1024; LOG_INFO(GREEN_BOLD("READY (CPU)") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") "", m_status.threads, m_status.ways, diff --git a/src/workers/Workers.h b/src/workers/Workers.h index 5b084fc2..24480517 100644 --- a/src/workers/Workers.h +++ b/src/workers/Workers.h @@ -86,8 +86,7 @@ private: pages(0), started(0), threads(0), - ways(0), - algo(xmrig::CRYPTONIGHT) + ways(0) {} size_t hugePages; @@ -95,7 +94,7 @@ private: size_t started; size_t threads; size_t ways; - xmrig::Algo algo; + xmrig::Algorithm algo; }; static bool m_active; From 088587fa7280abd8636f4e476aaba44dafa6ff53 Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 14 Jun 2019 05:21:17 +0700 Subject: [PATCH 03/65] Fixed build on Linux. --- src/workers/MultiWorker.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/workers/MultiWorker.cpp b/src/workers/MultiWorker.cpp index f209ca76..ffa34dda 100644 --- a/src/workers/MultiWorker.cpp +++ b/src/workers/MultiWorker.cpp @@ -195,8 +195,10 @@ bool xmrig::MultiWorker::verify2(const Algorithm &algorithm, const uint8_t *r } +namespace xmrig { + template<> -bool xmrig::MultiWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) +bool MultiWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) { cn_hash_fun func = m_thread->fn(algorithm); if (!func) { @@ -214,6 +216,8 @@ bool xmrig::MultiWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *r return true; } +} // namespace xmrig + template void xmrig::MultiWorker::consumeJob() @@ -269,5 +273,5 @@ template class MultiWorker<3>; template class MultiWorker<4>; template class MultiWorker<5>; -} +} // namespace xmrig From b73c204e73bb35a6883b1810c364d3b8d9377ef8 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 15 Jun 2019 00:28:16 +0700 Subject: [PATCH 04/65] Fixed ARM mining code. --- src/crypto/cn/CryptoNight_arm.h | 315 ++++++++++++++++------------- src/crypto/cn/CryptoNight_monero.h | 2 +- src/crypto/cn/gpu/cn_gpu_arm.cpp | 4 +- 3 files changed, 182 insertions(+), 139 deletions(-) diff --git a/src/crypto/cn/CryptoNight_arm.h b/src/crypto/cn/CryptoNight_arm.h index d9be454b..6d56b548 100644 --- a/src/crypto/cn/CryptoNight_arm.h +++ b/src/crypto/cn/CryptoNight_arm.h @@ -29,11 +29,11 @@ #include "common/crypto/keccak.h" -#include "crypto/common/portable/mm_malloc.h" -#include "crypto/cn/CryptoNight_constants.h" +#include "crypto/cn/CnAlgo.h" #include "crypto/cn/CryptoNight_monero.h" #include "crypto/cn/CryptoNight.h" #include "crypto/cn/soft_aes.h" +#include "crypto/common/portable/mm_malloc.h" extern "C" @@ -226,9 +226,14 @@ inline void mix_and_propagate(__m128i& x0, __m128i& x1, __m128i& x2, __m128i& x3 } -template +namespace xmrig { + + +template static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) { + constexpr CnAlgo props; + __m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7; __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9; @@ -243,7 +248,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) xin6 = _mm_load_si128(input + 10); xin7 = _mm_load_si128(input + 11); - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (props.isHeavy()) { for (size_t i = 0; i < 16; i++) { aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); @@ -260,7 +265,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } } - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); @@ -284,37 +289,17 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } -#ifdef XMRIG_ALGO_CN_GPU -template -void cn_explode_scratchpad_gpu(const uint8_t *input, uint8_t *output) -{ - constexpr size_t hash_size = 200; // 25x8 bytes - alignas(16) uint64_t hash[25]; - - for (uint64_t i = 0; i < MEM / 512; i++) - { - memcpy(hash, input, hash_size); - hash[0] ^= i; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 160); - output += 160; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 176); - output += 176; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 176); - output += 176; - } -} -#endif - - -template +template static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) { + constexpr CnAlgo props; + +# ifdef XMRIG_ALGO_CN_GPU + constexpr bool IS_HEAVY = props.isHeavy() || ALGO == Algorithm::CN_GPU; +# else + constexpr bool IS_HEAVY = props.isHeavy(); +# endif + __m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7; __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9; @@ -329,8 +314,7 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) xout6 = _mm_load_si128(output + 10); xout7 = _mm_load_si128(output + 11); - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) - { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0); xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1); xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2); @@ -351,13 +335,13 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (IS_HEAVY) { mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7); } } - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { + if (IS_HEAVY) { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0); xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1); xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2); @@ -408,6 +392,9 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) } +} /* namespace xmrig */ + + static inline __m128i aes_round_tweak_div(const __m128i &in, const __m128i &key) { alignas(16) uint32_t k[4]; @@ -430,13 +417,18 @@ static inline __m128i aes_round_tweak_div(const __m128i &in, const __m128i &key) } -template +namespace xmrig { + + +template static inline void cryptonight_monero_tweak(const uint8_t* l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i& cx) { + constexpr CnAlgo props; + uint64_t* mem_out = (uint64_t*)&l[idx]; - if (BASE == xmrig::VARIANT_2) { - VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + if (props.base() == Algorithm::CN_2) { + VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); _mm_store_si128((__m128i *)mem_out, _mm_xor_si128(bx0, cx)); } else { __m128i tmp = _mm_xor_si128(bx0, cx); @@ -446,7 +438,7 @@ static inline void cryptonight_monero_tweak(const uint8_t* l, uint64_t idx, __m1 uint8_t x = vh >> 24; static const uint16_t table = 0x7531; - const uint8_t index = (((x >> (VARIANT == xmrig::VARIANT_XTL ? 4 : 3)) & 6) | (x & 1)) << 1; + const uint8_t index = (((x >> (3)) & 6) | (x & 1)) << 1; vh ^= ((table >> index) & 0x3) << 28; mem_out[1] = vh; @@ -454,24 +446,28 @@ static inline void cryptonight_monero_tweak(const uint8_t* l, uint64_t idx, __m1 } -template +template inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 32); return; } - xmrig::keccak(input, size, ctx[0]->state); + keccak(input, size, ctx[0]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[0]->state), reinterpret_cast<__m128i *>(ctx[0]->memory)); - cn_explode_scratchpad((__m128i*) ctx[0]->state, (__m128i*) ctx[0]->memory); - - const uint8_t* l0 = ctx[0]->memory; + uint8_t* l0 = ctx[0]->memory; uint64_t* h0 = reinterpret_cast(ctx[0]->state); VARIANT1_INIT(0); @@ -480,19 +476,19 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si uint64_t al0 = h0[0] ^ h0[4]; uint64_t ah0 = h0[1] ^ h0[5]; - __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); - __m128i bx1 = _mm_set_epi64x(h0[9] ^ h0[11], h0[8] ^ h0[10]); + __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); + __m128i bx1 = _mm_set_epi64x(h0[9] ^ h0[11], h0[8] ^ h0[10]); uint64_t idx0 = al0; - for (size_t i = 0; i < ITERATIONS; i++) { + for (size_t i = 0; i < props.iterations(); i++) { __m128i cx; - if (VARIANT == xmrig::VARIANT_TUBE || !SOFT_AES) { - cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); + if (IS_CN_HEAVY_TUBE || !SOFT_AES) { + cx = _mm_load_si128(reinterpret_cast(&l0[idx0 & MASK])); } const __m128i ax0 = _mm_set_epi64x(ah0, al0); - if (VARIANT == xmrig::VARIANT_TUBE) { + if (IS_CN_HEAVY_TUBE) { cx = aes_round_tweak_div(cx, ax0); } else if (SOFT_AES) { @@ -502,8 +498,8 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si cx = _mm_aesenc_si128(cx, ax0); } - if (BASE == xmrig::VARIANT_1 || BASE == xmrig::VARIANT_2) { - cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx0, bx1, cx); + if (BASE == Algorithm::CN_1 || BASE == Algorithm::CN_2) { + cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx0, bx1, cx); } else { _mm_store_si128((__m128i *)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); } @@ -514,10 +510,10 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx0, bx1); - if (VARIANT == xmrig::VARIANT_4) { + if (ALGO == Algorithm::CN_R) { al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); } @@ -528,11 +524,11 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx0, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx0, bx1, cx, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } @@ -541,9 +537,9 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l0[idx0 & MASK])[0] = al0; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (BASE == xmrig::VARIANT_1) { + } else if (BASE == Algorithm::CN_1) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; @@ -553,7 +549,8 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si ah0 ^= ch; idx0 = al0; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { const int64x2_t x = vld1q_s64(reinterpret_cast(&l0[idx0 & MASK])); const int64_t n = vgetq_lane_s64(x, 0); const int32_t d = vgetq_lane_s32(x, 2); @@ -561,77 +558,113 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si ((int64_t*)&l0[idx0 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { idx0 = (~d) ^ q; } else { idx0 = d ^ q; } } +# endif - if (BASE == xmrig::VARIANT_2) { + if (BASE == Algorithm::CN_2) { bx1 = bx0; } bx0 = cx; } - cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); - - xmrig::keccakf(h0, 24); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i *>(ctx[0]->state)); + keccakf(h0, 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); } +} /* namespace xmrig */ + + #ifdef XMRIG_ALGO_CN_GPU template void cn_gpu_inner_arm(const uint8_t *spad, uint8_t *lpad); -template +namespace xmrig { + + +template +void cn_explode_scratchpad_gpu(const uint8_t *input, uint8_t *output) +{ + constexpr size_t hash_size = 200; // 25x8 bytes + alignas(16) uint64_t hash[25]; + + for (uint64_t i = 0; i < MEM / 512; i++) { + memcpy(hash, input, hash_size); + hash[0] ^= i; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 160); + output += 160; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + } +} + + +template inline void cryptonight_single_hash_gpu(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::CRYPTONIGHT_GPU_MASK; - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr CnAlgo props; - static_assert(MASK > 0 && ITERATIONS > 0 && MEM > 0, "unsupported algorithm/variant"); - - xmrig::keccak(input, size, ctx[0]->state); - cn_explode_scratchpad_gpu(ctx[0]->state, ctx[0]->memory); + keccak(input, size, ctx[0]->state); + cn_explode_scratchpad_gpu(ctx[0]->state, ctx[0]->memory); fesetround(FE_TONEAREST); - cn_gpu_inner_arm(ctx[0]->state, ctx[0]->memory); + cn_gpu_inner_arm(ctx[0]->state, ctx[0]->memory); - cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); - - xmrig::keccakf((uint64_t*) ctx[0]->state, 24); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i *>(ctx[0]->state)); + keccakf(reinterpret_cast(ctx[0]->state), 24); memcpy(output, ctx[0]->state, 32); } + +} /* namespace xmrig */ #endif -template +namespace xmrig { + + +template inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 64); return; } - xmrig::keccak(input, size, ctx[0]->state); - xmrig::keccak(input + size, size, ctx[1]->state); + keccak(input, size, ctx[0]->state); + keccak(input + size, size, ctx[1]->state); - const uint8_t* l0 = ctx[0]->memory; - const uint8_t* l1 = ctx[1]->memory; - uint64_t* h0 = reinterpret_cast(ctx[0]->state); - uint64_t* h1 = reinterpret_cast(ctx[1]->state); + uint8_t *l0 = ctx[0]->memory; + uint8_t *l1 = ctx[1]->memory; + uint64_t *h0 = reinterpret_cast(ctx[0]->state); + uint64_t *h1 = reinterpret_cast(ctx[1]->state); VARIANT1_INIT(0); VARIANT1_INIT(1); @@ -640,8 +673,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si VARIANT4_RANDOM_MATH_INIT(0); VARIANT4_RANDOM_MATH_INIT(1); - cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0); - cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1); + cn_explode_scratchpad(reinterpret_cast(h0), reinterpret_cast<__m128i *>(l0)); + cn_explode_scratchpad(reinterpret_cast(h1), reinterpret_cast<__m128i *>(l1)); uint64_t al0 = h0[0] ^ h0[4]; uint64_t al1 = h1[0] ^ h1[4]; @@ -656,16 +689,16 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si uint64_t idx0 = al0; uint64_t idx1 = al1; - for (size_t i = 0; i < ITERATIONS; i++) { + for (size_t i = 0; i < props.iterations(); i++) { __m128i cx0, cx1; - if (VARIANT == xmrig::VARIANT_TUBE || !SOFT_AES) { + if (IS_CN_HEAVY_TUBE || !SOFT_AES) { cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]); } const __m128i ax0 = _mm_set_epi64x(ah0, al0); const __m128i ax1 = _mm_set_epi64x(ah1, al1); - if (VARIANT == xmrig::VARIANT_TUBE) { + if (IS_CN_HEAVY_TUBE) { cx0 = aes_round_tweak_div(cx0, ax0); cx1 = aes_round_tweak_div(cx1, ax1); } @@ -678,9 +711,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cx1 = _mm_aesenc_si128(cx1, ax1); } - if (BASE == xmrig::VARIANT_1 || (BASE == xmrig::VARIANT_2)) { - cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx00, bx01, cx0); - cryptonight_monero_tweak(l1, idx1 & MASK, ax1, bx10, bx11, cx1); + if (BASE == Algorithm::CN_1 || BASE == Algorithm::CN_2) { + cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx00, bx01, cx0); + cryptonight_monero_tweak(l1, idx1 & MASK, ax1, bx10, bx11, cx1); } else { _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx00, cx0)); _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx10, cx1)); @@ -693,10 +726,10 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx00, bx01); - if (VARIANT == xmrig::VARIANT_4) { + if (ALGO == Algorithm::CN_R) { al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); } @@ -707,11 +740,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx0, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx00, bx01, cx0, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } @@ -720,9 +753,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l0[idx0 & MASK])[0] = al0; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (BASE == xmrig::VARIANT_1) { + } else if (BASE == Algorithm::CN_1) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; @@ -732,7 +765,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ah0 ^= ch; idx0 = al0; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { const int64x2_t x = vld1q_s64(reinterpret_cast(&l0[idx0 & MASK])); const int64_t n = vgetq_lane_s64(x, 0); const int32_t d = vgetq_lane_s32(x, 2); @@ -740,21 +774,22 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((int64_t*)&l0[idx0 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { idx0 = (~d) ^ q; } else { idx0 = d ^ q; } } +# endif cl = ((uint64_t*) &l1[idx1 & MASK])[0]; ch = ((uint64_t*) &l1[idx1 & MASK])[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(1, al1, ah1, cl, bx10, bx11); - if (VARIANT == xmrig::VARIANT_4) { + if (ALGO == Algorithm::CN_R) { al1 ^= r1[2] | ((uint64_t)(r1[3]) << 32); ah1 ^= r1[0] | ((uint64_t)(r1[1]) << 32); } @@ -765,11 +800,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx1, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l1, idx1 & MASK, ax1, bx10, bx11, cx1, 0); } else { - VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } @@ -778,9 +813,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l1[idx1 & MASK])[0] = al1; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1 ^ al1; - } else if (BASE == xmrig::VARIANT_1) { + } else if (BASE == Algorithm::CN_1) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1; } else { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1; @@ -790,7 +825,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ah1 ^= ch; idx1 = al1; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { const int64x2_t x = vld1q_s64(reinterpret_cast(&l1[idx1 & MASK])); const int64_t n = vgetq_lane_s64(x, 0); const int32_t d = vgetq_lane_s32(x, 2); @@ -798,47 +834,54 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((int64_t*)&l1[idx1 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { idx1 = (~d) ^ q; } else { idx1 = d ^ q; } } - if (BASE == xmrig::VARIANT_2) { +# endif + + if (BASE == Algorithm::CN_2) { bx01 = bx00; bx11 = bx10; } + bx00 = cx0; bx10 = cx1; } - cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0); - cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1); + cn_implode_scratchpad(reinterpret_cast(l0), reinterpret_cast<__m128i *>(h0)); + cn_implode_scratchpad(reinterpret_cast(l1), reinterpret_cast<__m128i *>(h1)); - xmrig::keccakf(h0, 24); - xmrig::keccakf(h1, 24); + keccakf(h0, 24); + keccakf(h1, 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); extra_hashes[ctx[1]->state[0] & 3](ctx[1]->state, 200, output + 32); } -template +template inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) { } -template +template inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) { } -template +template inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) { } -#endif /* __CRYPTONIGHT_ARM_H__ */ + +} /* namespace xmrig */ + + +#endif /* XMRIG_CRYPTONIGHT_ARM_H */ diff --git a/src/crypto/cn/CryptoNight_monero.h b/src/crypto/cn/CryptoNight_monero.h index 259cb3b6..13948dcd 100644 --- a/src/crypto/cn/CryptoNight_monero.h +++ b/src/crypto/cn/CryptoNight_monero.h @@ -141,7 +141,7 @@ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b1))); \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b))); \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30)), vaddq_u64(chunk2, vreinterpretq_u64_u8(_a))); \ - if (ALGO == Algorithm::CN_4) { \ + if (ALGO == Algorithm::CN_R) { \ _c = veorq_u64(veorq_u64(_c, chunk3), veorq_u64(chunk1, chunk2)); \ } \ } while (0) diff --git a/src/crypto/cn/gpu/cn_gpu_arm.cpp b/src/crypto/cn/gpu/cn_gpu_arm.cpp index a1df0cc7..520d3fc8 100644 --- a/src/crypto/cn/gpu/cn_gpu_arm.cpp +++ b/src/crypto/cn/gpu/cn_gpu_arm.cpp @@ -26,7 +26,7 @@ #include -#include "crypto/cn/CryptoNight_constants.h" +#include "crypto/cn/CnAlgo.h" inline void vandq_f32(float32x4_t &v, uint32_t v2) @@ -237,4 +237,4 @@ void cn_gpu_inner_arm(const uint8_t *spad, uint8_t *lpad) } } -template void cn_gpu_inner_arm(const uint8_t* spad, uint8_t* lpad); +template void cn_gpu_inner_arm().iterations(), xmrig::CnAlgo().mask()>(const uint8_t* spad, uint8_t* lpad); From 69903246812919f12ad1fa6f5fdae888da74c62b Mon Sep 17 00:00:00 2001 From: XMRig Date: Sun, 16 Jun 2019 03:50:22 +0700 Subject: [PATCH 05/65] Allow null algorithm for pools. --- src/base/net/stratum/Client.cpp | 36 ++++++++++++++++----------------- src/base/net/stratum/Pool.cpp | 36 +++++++++++++++++++++------------ src/base/net/stratum/Pools.cpp | 2 +- src/crypto/common/Algorithm.cpp | 9 +++++++++ src/crypto/common/Algorithm.h | 5 +++++ 5 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 05e53c78..4234407c 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -421,28 +421,28 @@ bool xmrig::Client::send(BIO *bio) bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm) const { -# ifdef XMRIG_PROXY_PROJECT - if (m_pool.algorithm().variant() == VARIANT_AUTO || m_id == -1) { - return true; - } -# endif +//# ifdef XMRIG_PROXY_PROJECT +// if (m_pool.algorithm().variant() == VARIANT_AUTO || m_id == -1) { +// return true; +// } +//# endif - if (m_pool.algorithm() == algorithm) { // FIXME - return true; - } +// if (m_pool.algorithm() == algorithm) { // FIXME +// return true; +// } - if (isQuiet()) { - return false; - } +// if (isQuiet()) { +// return false; +// } - if (algorithm.isValid()) { - LOG_ERR("Incompatible algorithm \"%s\" detected, reconnect", algorithm.name()); - } - else { - LOG_ERR("Unknown/unsupported algorithm detected, reconnect"); - } +// if (algorithm.isValid()) { +// LOG_ERR("Incompatible algorithm \"%s\" detected, reconnect", algorithm.name()); +// } +// else { +// LOG_ERR("Unknown/unsupported algorithm detected, reconnect"); +// } - return false; + return true; } diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index bb3fab72..b11e1159 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -172,7 +172,11 @@ bool xmrig::Pool::isEnabled() const } # endif - return m_flags.test(FLAG_ENABLED) && isValid() && algorithm().isValid(); + if (isDaemon() && !algorithm().isValid()) { + return false; + } + + return m_flags.test(FLAG_ENABLED) && isValid(); } @@ -259,28 +263,34 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const Value obj(kObjectType); - obj.AddMember(StringRef(kAlgo), StringRef(m_algorithm.shortName()), allocator); + obj.AddMember(StringRef(kAlgo), m_algorithm.toJSON(), allocator); obj.AddMember(StringRef(kUrl), m_url.toJSON(), allocator); obj.AddMember(StringRef(kUser), m_user.toJSON(), allocator); - obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator); - obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator); -# ifndef XMRIG_PROXY_PROJECT - obj.AddMember(StringRef(kNicehash), isNicehash(), allocator); -# endif + if (!isDaemon()) { + obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator); + obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator); - if (m_keepAlive == 0 || m_keepAlive == kKeepAliveTimeout) { - obj.AddMember(StringRef(kKeepalive), m_keepAlive > 0, allocator); - } - else { - obj.AddMember(StringRef(kKeepalive), m_keepAlive, allocator); +# ifndef XMRIG_PROXY_PROJECT + obj.AddMember(StringRef(kNicehash), isNicehash(), allocator); +# endif + + if (m_keepAlive == 0 || m_keepAlive == kKeepAliveTimeout) { + obj.AddMember(StringRef(kKeepalive), m_keepAlive > 0, allocator); + } + else { + obj.AddMember(StringRef(kKeepalive), m_keepAlive, allocator); + } } obj.AddMember(StringRef(kEnabled), m_flags.test(FLAG_ENABLED), allocator); obj.AddMember(StringRef(kTls), isTLS(), allocator); obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator); obj.AddMember(StringRef(kDaemon), m_flags.test(FLAG_DAEMON), allocator); - obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator); + + if (isDaemon()) { + obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator); + } return obj; } diff --git a/src/base/net/stratum/Pools.cpp b/src/base/net/stratum/Pools.cpp index 985e5d4e..4641ecd4 100644 --- a/src/base/net/stratum/Pools.cpp +++ b/src/base/net/stratum/Pools.cpp @@ -139,7 +139,7 @@ void xmrig::Pools::print() const i, (pool.isEnabled() ? (pool.isTLS() ? 32 : 36) : 31), pool.url().data(), - pool.algorithm().shortName() + pool.algorithm().isValid() ? pool.algorithm().shortName() : "auto" ); i++; diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index 78272f79..b2f93896 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -31,6 +31,7 @@ #include "crypto/common/Algorithm.h" +#include "rapidjson/document.h" #ifdef _MSC_VER @@ -111,6 +112,14 @@ static AlgoName const algorithm_names[] = { } /* namespace xmrig */ +rapidjson::Value xmrig::Algorithm::toJSON() const +{ + using namespace rapidjson; + + return isValid() ? Value(StringRef(shortName())) : Value(kNullType); +} + + xmrig::Algorithm::Family xmrig::Algorithm::family(Id id) { switch (id) { diff --git a/src/crypto/common/Algorithm.h b/src/crypto/common/Algorithm.h index c9388dee..690814e7 100644 --- a/src/crypto/common/Algorithm.h +++ b/src/crypto/common/Algorithm.h @@ -30,6 +30,9 @@ #include +#include "rapidjson/fwd.h" + + namespace xmrig { @@ -91,6 +94,8 @@ public: inline bool operator==(const Algorithm &other) const { return isEqual(other); } inline operator Algorithm::Id() const { return m_id; } + rapidjson::Value toJSON() const; + static Family family(Id id); static Id parse(const char *name); From b38e432647e41accf7a8f5f10a261592d9a10217 Mon Sep 17 00:00:00 2001 From: XMRig Date: Mon, 17 Jun 2019 04:06:38 +0700 Subject: [PATCH 06/65] Moved keccak files. --- CMakeLists.txt | 4 ++-- src/api/Api.cpp | 2 +- src/crypto/cn/CryptoNight_arm.h | 2 +- src/crypto/cn/CryptoNight_x86.h | 5 ++++- src/{common/crypto => crypto/common}/keccak.cpp | 2 +- src/{common/crypto => crypto/common}/keccak.h | 0 src/net/strategies/DonateStrategy.cpp | 2 +- 7 files changed, 10 insertions(+), 7 deletions(-) rename src/{common/crypto => crypto/common}/keccak.cpp (99%) rename src/{common/crypto => crypto/common}/keccak.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c70a673..2dfd52e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,6 @@ set(HEADERS src/api/interfaces/IApiListener.h src/App.h src/common/cpu/Cpu.h - src/common/crypto/keccak.h src/common/interfaces/ICpuInfo.h src/common/Platform.h src/common/xmrig.h @@ -69,6 +68,7 @@ set(HEADERS_CRYPTO src/crypto/cn/skein_port.h src/crypto/cn/soft_aes.h src/crypto/common/Algorithm.h + src/crypto/common/keccak.h src/crypto/common/portable/mm_malloc.h src/crypto/common/VirtualMemory.h ) @@ -83,7 +83,6 @@ set(SOURCES "${SOURCES_BASE}" "${SOURCES_BASE_HTTP}" src/App.cpp - src/common/crypto/keccak.cpp src/common/Platform.cpp src/core/config/Config.cpp src/core/config/ConfigTransform.cpp @@ -109,6 +108,7 @@ set(SOURCES_CRYPTO src/crypto/cn/c_skein.c src/crypto/cn/CnHash.cpp src/crypto/common/Algorithm.cpp + src/crypto/common/keccak.cpp ) if (WIN32) diff --git a/src/api/Api.cpp b/src/api/Api.cpp index a11325f3..caebcba7 100644 --- a/src/api/Api.cpp +++ b/src/api/Api.cpp @@ -39,9 +39,9 @@ #include "base/kernel/Base.h" #include "base/tools/Buffer.h" #include "base/tools/Chrono.h" -#include "common/crypto/keccak.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "crypto/common/keccak.h" #include "version.h" diff --git a/src/crypto/cn/CryptoNight_arm.h b/src/crypto/cn/CryptoNight_arm.h index 6d56b548..02266634 100644 --- a/src/crypto/cn/CryptoNight_arm.h +++ b/src/crypto/cn/CryptoNight_arm.h @@ -28,11 +28,11 @@ #define XMRIG_CRYPTONIGHT_ARM_H -#include "common/crypto/keccak.h" #include "crypto/cn/CnAlgo.h" #include "crypto/cn/CryptoNight_monero.h" #include "crypto/cn/CryptoNight.h" #include "crypto/cn/soft_aes.h" +#include "crypto/common/keccak.h" #include "crypto/common/portable/mm_malloc.h" diff --git a/src/crypto/cn/CryptoNight_x86.h b/src/crypto/cn/CryptoNight_x86.h index 994ee116..fc21c7b0 100644 --- a/src/crypto/cn/CryptoNight_x86.h +++ b/src/crypto/cn/CryptoNight_x86.h @@ -36,11 +36,11 @@ #include "common/cpu/Cpu.h" -#include "common/crypto/keccak.h" #include "crypto/cn/CnAlgo.h" #include "crypto/cn/CryptoNight_monero.h" #include "crypto/cn/CryptoNight.h" #include "crypto/cn/soft_aes.h" +#include "crypto/common/keccak.h" extern "C" @@ -785,6 +785,9 @@ extern "C" void cnv2_rwz_double_mainloop_asm(cryptonight_ctx **ctx); namespace xmrig { +typedef void (*cn_mainloop_fun)(cryptonight_ctx **ctx); + + extern cn_mainloop_fun cn_half_mainloop_ivybridge_asm; extern cn_mainloop_fun cn_half_mainloop_ryzen_asm; extern cn_mainloop_fun cn_half_mainloop_bulldozer_asm; diff --git a/src/common/crypto/keccak.cpp b/src/crypto/common/keccak.cpp similarity index 99% rename from src/common/crypto/keccak.cpp rename to src/crypto/common/keccak.cpp index 0219ce36..132ae0a8 100644 --- a/src/common/crypto/keccak.cpp +++ b/src/crypto/common/keccak.cpp @@ -27,7 +27,7 @@ #include -#include "common/crypto/keccak.h" +#include "crypto/common/keccak.h" #define HASH_DATA_AREA 136 diff --git a/src/common/crypto/keccak.h b/src/crypto/common/keccak.h similarity index 100% rename from src/common/crypto/keccak.h rename to src/crypto/common/keccak.h diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index 3d913087..9669db9a 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -32,11 +32,11 @@ #include "base/net/stratum/strategies/SinglePoolStrategy.h" #include "base/tools/Buffer.h" #include "base/tools/Timer.h" -#include "common/crypto/keccak.h" #include "common/Platform.h" #include "common/xmrig.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "crypto/common/keccak.h" #include "net/Network.h" #include "net/strategies/DonateStrategy.h" #include "rapidjson/document.h" From 0aaf2d38d451919163c111818d6178f01e269c22 Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 26 Jun 2019 11:07:50 +0700 Subject: [PATCH 07/65] v2.16.1-evo --- src/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/version.h b/src/version.h index b08fcdf9..7e849c7e 100644 --- a/src/version.h +++ b/src/version.h @@ -28,7 +28,7 @@ #define APP_ID "xmrig" #define APP_NAME "XMRig" #define APP_DESC "XMRig CPU miner" -#define APP_VERSION "2.16.0-beta" +#define APP_VERSION "2.16.1-evo" #define APP_DOMAIN "xmrig.com" #define APP_SITE "www.xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2019 xmrig.com" @@ -36,7 +36,7 @@ #define APP_VER_MAJOR 2 #define APP_VER_MINOR 16 -#define APP_VER_PATCH 0 +#define APP_VER_PATCH 1 #ifdef _MSC_VER # if (_MSC_VER >= 1920) From 66d62de681bde910eb7e36f3a3a58c49016f1430 Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 28 Jun 2019 13:08:08 +0700 Subject: [PATCH 08/65] Merge Assembly enum and Asm class. --- cmake/asm.cmake | 6 +- src/Summary.cpp | 6 +- src/common/cpu/BasicCpuInfo.h | 2 +- src/common/interfaces/ICpuInfo.h | 6 +- src/common/xmrig.h | 10 --- src/core/config/Config.cpp | 7 +- src/core/cpu/AdvancedCpuInfo.cpp | 5 +- src/core/cpu/AdvancedCpuInfo.h | 2 +- src/crypto/cn/Asm.h | 50 ------------ src/crypto/cn/CnHash.cpp | 42 +++++----- src/crypto/cn/CnHash.h | 5 +- src/crypto/cn/CryptoNight_x86.h | 28 +++---- src/crypto/cn/r/CryptonightR_gen.cpp | 5 +- src/crypto/common/Algorithm.cpp | 1 - src/crypto/common/Algorithm.h | 2 +- .../{cn/Asm.cpp => common/Assembly.cpp} | 35 ++++---- src/crypto/common/Assembly.h | 79 +++++++++++++++++++ src/workers/CpuThread.cpp | 10 +-- src/workers/CpuThread.h | 2 +- 19 files changed, 164 insertions(+), 139 deletions(-) delete mode 100644 src/crypto/cn/Asm.h rename src/crypto/{cn/Asm.cpp => common/Assembly.cpp} (72%) create mode 100644 src/crypto/common/Assembly.h diff --git a/cmake/asm.cmake b/cmake/asm.cmake index d3010e51..e445defd 100644 --- a/cmake/asm.cmake +++ b/cmake/asm.cmake @@ -36,7 +36,11 @@ if (WITH_ASM AND NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8) endif() add_library(${XMRIG_ASM_LIBRARY} STATIC ${XMRIG_ASM_FILES}) - set(XMRIG_ASM_SOURCES src/crypto/cn/Asm.h src/crypto/cn/Asm.cpp src/crypto/cn/r/CryptonightR_gen.cpp) + set(XMRIG_ASM_SOURCES + src/crypto/common/Assembly.h + src/crypto/common/Assembly.cpp + src/crypto/cn/r/CryptonightR_gen.cpp + ) set_property(TARGET ${XMRIG_ASM_LIBRARY} PROPERTY LINKER_LANGUAGE C) add_definitions(/DXMRIG_FEATURE_ASM) diff --git a/src/Summary.cpp b/src/Summary.cpp index 2ba0fd57..13973c0f 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -33,7 +33,7 @@ #include "common/cpu/Cpu.h" #include "core/config/Config.h" #include "core/Controller.h" -#include "crypto/cn/Asm.h" +#include "crypto/common/Assembly.h" #include "Mem.h" #include "Summary.h" #include "version.h" @@ -49,7 +49,7 @@ static const char *coloredAsmNames[] = { }; -inline static const char *asmName(xmrig::Assembly assembly) +inline static const char *asmName(xmrig::Assembly::Id assembly) { return coloredAsmNames[assembly]; } @@ -109,7 +109,7 @@ static void print_threads(xmrig::Config *config) } # ifdef XMRIG_FEATURE_ASM - if (config->assembly() == xmrig::ASM_AUTO) { + if (config->assembly() == xmrig::Assembly::AUTO) { const xmrig::Assembly assembly = xmrig::Cpu::info()->assembly(); xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13sauto:%s"), "ASSEMBLY", asmName(assembly)); diff --git a/src/common/cpu/BasicCpuInfo.h b/src/common/cpu/BasicCpuInfo.h index 95857ed2..f6daee54 100644 --- a/src/common/cpu/BasicCpuInfo.h +++ b/src/common/cpu/BasicCpuInfo.h @@ -40,7 +40,7 @@ public: protected: size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const override; - inline Assembly assembly() const override { return m_assembly; } + inline Assembly::Id assembly() const override { return m_assembly; } inline bool hasAES() const override { return m_aes; } inline bool hasAVX2() const override { return m_avx2; } inline bool isSupported() const override { return true; } diff --git a/src/common/interfaces/ICpuInfo.h b/src/common/interfaces/ICpuInfo.h index dd4034b3..907f3f63 100644 --- a/src/common/interfaces/ICpuInfo.h +++ b/src/common/interfaces/ICpuInfo.h @@ -30,7 +30,7 @@ #include -#include "common/xmrig.h" +#include "crypto/common/Assembly.h" namespace xmrig { @@ -39,7 +39,7 @@ namespace xmrig { class ICpuInfo { public: - virtual ~ICpuInfo() {} + virtual ~ICpuInfo() = default; virtual bool hasAES() const = 0; virtual bool hasAVX2() const = 0; @@ -53,7 +53,7 @@ public: virtual int32_t sockets() const = 0; virtual int32_t threads() const = 0; virtual size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const = 0; - virtual xmrig::Assembly assembly() const = 0; + virtual Assembly::Id assembly() const = 0; }; diff --git a/src/common/xmrig.h b/src/common/xmrig.h index 5dd41845..169c4c1f 100644 --- a/src/common/xmrig.h +++ b/src/common/xmrig.h @@ -72,16 +72,6 @@ enum OclVendor { }; -enum Assembly { - ASM_NONE, - ASM_AUTO, - ASM_INTEL, - ASM_RYZEN, - ASM_BULLDOZER, - ASM_MAX -}; - - } /* namespace xmrig */ diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 69ac065f..93bd47ff 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -32,7 +32,7 @@ #include "base/kernel/interfaces/IJsonReader.h" #include "common/cpu/Cpu.h" #include "core/config/Config.h" -#include "crypto/cn/Asm.h" +#include "crypto/common/Assembly.h" #include "rapidjson/document.h" #include "rapidjson/filewritestream.h" #include "rapidjson/prettywriter.h" @@ -45,7 +45,6 @@ static char affinity_tmp[20] = { 0 }; xmrig::Config::Config() : m_aesMode(AES_AUTO), m_algoVariant(AV_AUTO), - m_assembly(ASM_AUTO), m_hugePages(true), m_safe(false), m_shouldSave(false), @@ -99,7 +98,7 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const doc.AddMember("http", m_http.toJSON(doc), allocator); # ifdef XMRIG_FEATURE_ASM - doc.AddMember("asm", Asm::toJSON(m_assembly), allocator); + doc.AddMember("asm", m_assembly.toJSON(), allocator); # endif doc.AddMember("autosave", isAutoSave(), allocator); @@ -285,6 +284,6 @@ xmrig::AlgoVariant xmrig::Config::getAlgoVariantLite() const #ifdef XMRIG_FEATURE_ASM void xmrig::Config::setAssembly(const rapidjson::Value &assembly) { - m_assembly = Asm::parse(assembly); + m_assembly = assembly; } #endif diff --git a/src/core/cpu/AdvancedCpuInfo.cpp b/src/core/cpu/AdvancedCpuInfo.cpp index df6a385e..922e8311 100644 --- a/src/core/cpu/AdvancedCpuInfo.cpp +++ b/src/core/cpu/AdvancedCpuInfo.cpp @@ -31,7 +31,6 @@ xmrig::AdvancedCpuInfo::AdvancedCpuInfo() : - m_assembly(ASM_NONE), m_aes(false), m_avx2(false), m_L2_exclusive(false), @@ -78,10 +77,10 @@ xmrig::AdvancedCpuInfo::AdvancedCpuInfo() : m_aes = true; if (data.vendor == VENDOR_AMD) { - m_assembly = (data.ext_family >= 23) ? ASM_RYZEN : ASM_BULLDOZER; + m_assembly = (data.ext_family >= 23) ? Assembly::RYZEN : Assembly::BULLDOZER; } else if (data.vendor == VENDOR_INTEL) { - m_assembly = ASM_INTEL; + m_assembly = Assembly::INTEL; } } diff --git a/src/core/cpu/AdvancedCpuInfo.h b/src/core/cpu/AdvancedCpuInfo.h index 0765da33..90152640 100644 --- a/src/core/cpu/AdvancedCpuInfo.h +++ b/src/core/cpu/AdvancedCpuInfo.h @@ -40,7 +40,7 @@ public: protected: size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const override; - inline Assembly assembly() const override { return m_assembly; } + inline Assembly::Id assembly() const override { return m_assembly; } inline bool hasAES() const override { return m_aes; } inline bool hasAVX2() const override { return m_avx2; } inline bool isSupported() const override { return true; } diff --git a/src/crypto/cn/Asm.h b/src/crypto/cn/Asm.h deleted file mode 100644 index 3b755fd6..00000000 --- a/src/crypto/cn/Asm.h +++ /dev/null @@ -1,50 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef XMRIG_ASM_H -#define XMRIG_ASM_H - - -#include "common/xmrig.h" -#include "rapidjson/fwd.h" - - -namespace xmrig { - - -class Asm -{ -public: - static Assembly parse(const char *assembly, Assembly defaultValue = ASM_AUTO); - static Assembly parse(const rapidjson::Value &value, Assembly defaultValue = ASM_AUTO); - static const char *toString(Assembly assembly); - static rapidjson::Value toJSON(Assembly assembly); - - inline static Assembly parse(bool enable) { return enable ? ASM_AUTO : ASM_NONE; } -}; - - -} /* namespace xmrig */ - - -#endif /* XMRIG_ASM_H */ diff --git a/src/crypto/cn/CnHash.cpp b/src/crypto/cn/CnHash.cpp index 61d2ea69..d17a8e2d 100644 --- a/src/crypto/cn/CnHash.cpp +++ b/src/crypto/cn/CnHash.cpp @@ -39,26 +39,26 @@ #define ADD_FN(algo) \ - m_map[algo][AV_SINGLE][ASM_NONE] = cryptonight_single_hash; \ - m_map[algo][AV_SINGLE_SOFT][ASM_NONE] = cryptonight_single_hash; \ - m_map[algo][AV_DOUBLE][ASM_NONE] = cryptonight_double_hash; \ - m_map[algo][AV_DOUBLE_SOFT][ASM_NONE] = cryptonight_double_hash; \ - m_map[algo][AV_TRIPLE][ASM_NONE] = cryptonight_triple_hash; \ - m_map[algo][AV_TRIPLE_SOFT][ASM_NONE] = cryptonight_triple_hash; \ - m_map[algo][AV_QUAD][ASM_NONE] = cryptonight_quad_hash; \ - m_map[algo][AV_QUAD_SOFT][ASM_NONE] = cryptonight_quad_hash; \ - m_map[algo][AV_PENTA][ASM_NONE] = cryptonight_penta_hash; \ - m_map[algo][AV_PENTA_SOFT][ASM_NONE] = cryptonight_penta_hash; + m_map[algo][AV_SINGLE][Assembly::NONE] = cryptonight_single_hash; \ + m_map[algo][AV_SINGLE_SOFT][Assembly::NONE] = cryptonight_single_hash; \ + m_map[algo][AV_DOUBLE][Assembly::NONE] = cryptonight_double_hash; \ + m_map[algo][AV_DOUBLE_SOFT][Assembly::NONE] = cryptonight_double_hash; \ + m_map[algo][AV_TRIPLE][Assembly::NONE] = cryptonight_triple_hash; \ + m_map[algo][AV_TRIPLE_SOFT][Assembly::NONE] = cryptonight_triple_hash; \ + m_map[algo][AV_QUAD][Assembly::NONE] = cryptonight_quad_hash; \ + m_map[algo][AV_QUAD_SOFT][Assembly::NONE] = cryptonight_quad_hash; \ + m_map[algo][AV_PENTA][Assembly::NONE] = cryptonight_penta_hash; \ + m_map[algo][AV_PENTA_SOFT][Assembly::NONE] = cryptonight_penta_hash; #ifdef XMRIG_FEATURE_ASM # define ADD_FN_ASM(algo) \ - m_map[algo][AV_SINGLE][ASM_INTEL] = cryptonight_single_hash_asm; \ - m_map[algo][AV_SINGLE][ASM_RYZEN] = cryptonight_single_hash_asm; \ - m_map[algo][AV_SINGLE][ASM_BULLDOZER] = cryptonight_single_hash_asm; \ - m_map[algo][AV_DOUBLE][ASM_INTEL] = cryptonight_double_hash_asm; \ - m_map[algo][AV_DOUBLE][ASM_RYZEN] = cryptonight_double_hash_asm; \ - m_map[algo][AV_DOUBLE][ASM_BULLDOZER] = cryptonight_double_hash_asm; + m_map[algo][AV_SINGLE][Assembly::INTEL] = cryptonight_single_hash_asm; \ + m_map[algo][AV_SINGLE][Assembly::RYZEN] = cryptonight_single_hash_asm; \ + m_map[algo][AV_SINGLE][Assembly::BULLDOZER] = cryptonight_single_hash_asm; \ + m_map[algo][AV_DOUBLE][Assembly::INTEL] = cryptonight_double_hash_asm; \ + m_map[algo][AV_DOUBLE][Assembly::RYZEN] = cryptonight_double_hash_asm; \ + m_map[algo][AV_DOUBLE][Assembly::BULLDOZER] = cryptonight_double_hash_asm; extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx **ctx); @@ -226,8 +226,8 @@ xmrig::CnHash::CnHash() ADD_FN_ASM(Algorithm::CN_DOUBLE); # ifdef XMRIG_ALGO_CN_GPU - m_map[Algorithm::CN_GPU][AV_SINGLE][ASM_NONE] = cryptonight_single_hash_gpu; - m_map[Algorithm::CN_GPU][AV_SINGLE_SOFT][ASM_NONE] = cryptonight_single_hash_gpu; + m_map[Algorithm::CN_GPU][AV_SINGLE][Assembly::NONE] = cryptonight_single_hash_gpu; + m_map[Algorithm::CN_GPU][AV_SINGLE_SOFT][Assembly::NONE] = cryptonight_single_hash_gpu; # endif # ifdef XMRIG_ALGO_CN_LITE @@ -252,18 +252,18 @@ xmrig::CnHash::CnHash() } -xmrig::cn_hash_fun xmrig::CnHash::fn(const Algorithm &algorithm, AlgoVariant av, Assembly assembly) const +xmrig::cn_hash_fun xmrig::CnHash::fn(const Algorithm &algorithm, AlgoVariant av, Assembly::Id assembly) const { if (!algorithm.isValid()) { return nullptr; } # ifdef XMRIG_FEATURE_ASM - cn_hash_fun fun = m_map[algorithm][av][assembly == ASM_AUTO ? Cpu::info()->assembly() : assembly]; + cn_hash_fun fun = m_map[algorithm][av][assembly == Assembly::AUTO ? Cpu::info()->assembly() : assembly]; if (fun) { return fun; } # endif - return m_map[algorithm][av][ASM_NONE]; + return m_map[algorithm][av][Assembly::NONE]; } diff --git a/src/crypto/cn/CnHash.h b/src/crypto/cn/CnHash.h index 5fbf5c8a..b57bff4c 100644 --- a/src/crypto/cn/CnHash.h +++ b/src/crypto/cn/CnHash.h @@ -33,6 +33,7 @@ #include "common/xmrig.h" #include "crypto/cn/CnAlgo.h" +#include "crypto/common/Assembly.h" struct cryptonight_ctx; @@ -50,10 +51,10 @@ class CnHash public: CnHash(); - cn_hash_fun fn(const Algorithm &algorithm, AlgoVariant av, Assembly assembly) const; + cn_hash_fun fn(const Algorithm &algorithm, AlgoVariant av, Assembly::Id assembly) const; private: - cn_hash_fun m_map[Algorithm::MAX][AV_MAX][ASM_MAX] = {}; + cn_hash_fun m_map[Algorithm::MAX][AV_MAX][Assembly::MAX] = {}; }; diff --git a/src/crypto/cn/CryptoNight_x86.h b/src/crypto/cn/CryptoNight_x86.h index fc21c7b0..b24dea57 100644 --- a/src/crypto/cn/CryptoNight_x86.h +++ b/src/crypto/cn/CryptoNight_x86.h @@ -577,10 +577,10 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si const int code_size = v4_random_math_init(code, height); if (ALGO == Algorithm::CN_WOW) { - wow_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM_NONE); + wow_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), Assembly::NONE); } else if (ALGO == Algorithm::CN_R) { - v4_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM_NONE); + v4_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), Assembly::NONE); } ctx[0]->generated_code_data = { ALGO, height }; @@ -849,7 +849,7 @@ void cn_r_compile_code_double(const V4_Instruction* co namespace xmrig { -template +template inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { constexpr CnAlgo props; @@ -866,10 +866,10 @@ inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_ cn_explode_scratchpad(reinterpret_cast(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); if (ALGO == Algorithm::CN_2) { - if (ASM == ASM_INTEL) { + if (ASM == Assembly::INTEL) { cnv2_mainloop_ivybridge_asm(ctx); } - else if (ASM == ASM_RYZEN) { + else if (ASM == Assembly::RYZEN) { cnv2_mainloop_ryzen_asm(ctx); } else { @@ -877,10 +877,10 @@ inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_ } } else if (ALGO == Algorithm::CN_HALF) { - if (ASM == ASM_INTEL) { + if (ASM == Assembly::INTEL) { cn_half_mainloop_ivybridge_asm(ctx); } - else if (ASM == ASM_RYZEN) { + else if (ASM == Assembly::RYZEN) { cn_half_mainloop_ryzen_asm(ctx); } else { @@ -889,10 +889,10 @@ inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_ } # ifdef XMRIG_ALGO_CN_PICO else if (ALGO == Algorithm::CN_PICO_0) { - if (ASM == ASM_INTEL) { + if (ASM == Assembly::INTEL) { cn_trtl_mainloop_ivybridge_asm(ctx); } - else if (ASM == ASM_RYZEN) { + else if (ASM == Assembly::RYZEN) { cn_trtl_mainloop_ryzen_asm(ctx); } else { @@ -904,10 +904,10 @@ inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_ cnv2_rwz_mainloop_asm(ctx); } else if (ALGO == Algorithm::CN_ZLS) { - if (ASM == ASM_INTEL) { + if (ASM == Assembly::INTEL) { cn_zls_mainloop_ivybridge_asm(ctx); } - else if (ASM == ASM_RYZEN) { + else if (ASM == Assembly::RYZEN) { cn_zls_mainloop_ryzen_asm(ctx); } else { @@ -915,10 +915,10 @@ inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_ } } else if (ALGO == Algorithm::CN_DOUBLE) { - if (ASM == ASM_INTEL) { + if (ASM == Assembly::INTEL) { cn_double_mainloop_ivybridge_asm(ctx); } - else if (ASM == ASM_RYZEN) { + else if (ASM == Assembly::RYZEN) { cn_double_mainloop_ryzen_asm(ctx); } else { @@ -935,7 +935,7 @@ inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_ } -template +template inline void cryptonight_double_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { constexpr CnAlgo props; diff --git a/src/crypto/cn/r/CryptonightR_gen.cpp b/src/crypto/cn/r/CryptonightR_gen.cpp index 8491a33b..3037327a 100644 --- a/src/crypto/cn/r/CryptonightR_gen.cpp +++ b/src/crypto/cn/r/CryptonightR_gen.cpp @@ -29,6 +29,7 @@ typedef void(*void_func)(); #include "crypto/cn/asm/CryptonightR_template.h" +#include "crypto/common/Assembly.h" #include "crypto/common/VirtualMemory.h" #include "Mem.h" @@ -42,7 +43,7 @@ static inline void add_code(uint8_t* &p, void (*p1)(), void (*p2)()) } } -static inline void add_random_math(uint8_t* &p, const V4_Instruction* code, int code_size, const void_func* instructions, const void_func* instructions_mov, bool is_64_bit, xmrig::Assembly ASM) +static inline void add_random_math(uint8_t* &p, const V4_Instruction* code, int code_size, const void_func* instructions, const void_func* instructions_mov, bool is_64_bit, xmrig::Assembly::Id ASM) { uint32_t prev_rot_src = (uint32_t)(-1); @@ -76,7 +77,7 @@ static inline void add_random_math(uint8_t* &p, const V4_Instruction* code, int void_func begin = instructions[c]; - if ((ASM = xmrig::ASM_BULLDOZER) && (inst.opcode == MUL) && !is_64_bit) { + if ((ASM = xmrig::Assembly::BULLDOZER) && (inst.opcode == MUL) && !is_64_bit) { // AMD Bulldozer has latency 4 for 32-bit IMUL and 6 for 64-bit IMUL // Always use 32-bit IMUL for AMD Bulldozer in 32-bit mode - skip prefix 0x48 and change 0x49 to 0x41 uint8_t* prefix = reinterpret_cast(begin); diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index e70b0659..66b3ddda 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -35,7 +35,6 @@ #ifdef _MSC_VER -# define strncasecmp _strnicmp # define strcasecmp _stricmp #endif diff --git a/src/crypto/common/Algorithm.h b/src/crypto/common/Algorithm.h index ccaf7de5..92c6f405 100644 --- a/src/crypto/common/Algorithm.h +++ b/src/crypto/common/Algorithm.h @@ -69,7 +69,7 @@ public: CN_PICO_0, // "cn-pico" CryptoNight Turtle (TRTL) # endif # ifdef XMRIG_ALGO_RANDOMX - RX_WOW, // "rx/wow" RandomWOW + RX_WOW, // "rx/wow" RandomWOW (Wownero) # endif MAX }; diff --git a/src/crypto/cn/Asm.cpp b/src/crypto/common/Assembly.cpp similarity index 72% rename from src/crypto/cn/Asm.cpp rename to src/crypto/common/Assembly.cpp index 331c133d..44bf0a94 100644 --- a/src/crypto/cn/Asm.cpp +++ b/src/crypto/common/Assembly.cpp @@ -6,7 +6,8 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018 SChernykh - * Copyright 2016-2018 XMRig , + * 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 @@ -28,15 +29,17 @@ #ifdef _MSC_VER -# define strncasecmp _strnicmp # define strcasecmp _stricmp #endif -#include "crypto/cn/Asm.h" +#include "crypto/common/Assembly.h" #include "rapidjson/document.h" +namespace xmrig { + + static const char *asmNames[] = { "none", "auto", @@ -46,11 +49,13 @@ static const char *asmNames[] = { }; -xmrig::Assembly xmrig::Asm::parse(const char *assembly, Assembly defaultValue) +} /* namespace xmrig */ + + +xmrig::Assembly::Id xmrig::Assembly::parse(const char *assembly, Id defaultValue) { constexpr size_t const size = sizeof(asmNames) / sizeof((asmNames)[0]); - assert(assembly != nullptr); - assert(ASM_MAX == size); + static_assert(size == MAX, "asmNames size mismatch"); if (assembly == nullptr) { return defaultValue; @@ -58,7 +63,7 @@ xmrig::Assembly xmrig::Asm::parse(const char *assembly, Assembly defaultValue) for (size_t i = 0; i < size; i++) { if (strcasecmp(assembly, asmNames[i]) == 0) { - return static_cast(i); + return static_cast(i); } } @@ -66,10 +71,10 @@ xmrig::Assembly xmrig::Asm::parse(const char *assembly, Assembly defaultValue) } -xmrig::Assembly xmrig::Asm::parse(const rapidjson::Value &value, Assembly defaultValue) +xmrig::Assembly::Id xmrig::Assembly::parse(const rapidjson::Value &value, Id defaultValue) { if (value.IsBool()) { - return parse(value.GetBool()); + return value.GetBool() ? AUTO : NONE; } if (value.IsString()) { @@ -80,23 +85,23 @@ xmrig::Assembly xmrig::Asm::parse(const rapidjson::Value &value, Assembly defaul } -const char *xmrig::Asm::toString(Assembly assembly) +const char *xmrig::Assembly::toString() const { - return asmNames[assembly]; + return asmNames[m_id]; } -rapidjson::Value xmrig::Asm::toJSON(Assembly assembly) +rapidjson::Value xmrig::Assembly::toJSON() const { using namespace rapidjson; - if (assembly == ASM_NONE) { + if (m_id == NONE) { return Value(false); } - if (assembly == ASM_AUTO) { + if (m_id == AUTO) { return Value(true); } - return Value(StringRef(toString(assembly))); + return Value(StringRef(toString())); } diff --git a/src/crypto/common/Assembly.h b/src/crypto/common/Assembly.h new file mode 100644 index 00000000..e4964d07 --- /dev/null +++ b/src/crypto/common/Assembly.h @@ -0,0 +1,79 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_ASSEMBLY_H +#define XMRIG_ASSEMBLY_H + + +#include "common/xmrig.h" +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +class Assembly +{ +public: + enum Id : int { + NONE, + AUTO, + INTEL, + RYZEN, + BULLDOZER, + MAX + }; + + + inline Assembly() {} + inline Assembly(Id id) : m_id(id) {} + inline Assembly(const char *assembly) : m_id(parse(assembly)) {} + inline Assembly(const rapidjson::Value &value) : m_id(parse(value)) {} + + static Id parse(const char *assembly, Id defaultValue = AUTO); + static Id parse(const rapidjson::Value &value, Id defaultValue = AUTO); + + const char *toString() const; + rapidjson::Value toJSON() const; + +// inline static Assembly parse(bool enable) { return enable ? ASM_AUTO : ASM_NONE; } + + inline bool isEqual(const Assembly &other) const { return m_id == other.m_id; } + + + inline bool operator!=(const Assembly &other) const { return !isEqual(other); } + inline bool operator!=(const Assembly::Id &id) const { return m_id != id; } + inline bool operator==(const Assembly &other) const { return isEqual(other); } + inline bool operator==(const Assembly::Id &id) const { return m_id == id; } + inline operator Assembly::Id() const { return m_id; } + +private: + Id m_id = AUTO; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_ASSEMBLY_H */ diff --git a/src/workers/CpuThread.cpp b/src/workers/CpuThread.cpp index e26b8a0a..9f20a35a 100644 --- a/src/workers/CpuThread.cpp +++ b/src/workers/CpuThread.cpp @@ -27,8 +27,8 @@ #include "base/io/log/Log.h" #include "common/cpu/Cpu.h" -#include "crypto/cn/Asm.h" #include "crypto/cn/CnHash.h" +#include "crypto/common/Assembly.h" #include "crypto/common/VirtualMemory.h" #include "Mem.h" #include "rapidjson/document.h" @@ -36,8 +36,6 @@ - - static const xmrig::CnHash cnHash; @@ -136,7 +134,7 @@ xmrig::CpuThread::Data xmrig::CpuThread::parse(const rapidjson::Value &object) } # ifdef XMRIG_FEATURE_ASM - data.assembly = Asm::parse(object["asm"]); + data.assembly = object["asm"]; # endif return data; @@ -181,7 +179,7 @@ void xmrig::CpuThread::print() const index(), static_cast(multiway()), static_cast(m_av)); # ifdef XMRIG_FEATURE_ASM - LOG_DEBUG(" assembly: %s, affine_to_cpu: %" PRId64, Asm::toString(m_assembly), affinity()); + LOG_DEBUG(" assembly: %s, affine_to_cpu: %" PRId64, m_assembly.toString(), affinity()); # else LOG_DEBUG(" affine_to_cpu: %" PRId64, affinity()); # endif @@ -220,7 +218,7 @@ rapidjson::Value xmrig::CpuThread::toConfig(rapidjson::Document &doc) const obj.AddMember("affine_to_cpu", affinity() == -1L ? Value(kFalseType) : Value(affinity()), allocator); # ifdef XMRIG_FEATURE_ASM - obj.AddMember("asm", Asm::toJSON(m_assembly), allocator); + obj.AddMember("asm", m_assembly.toJSON(), allocator); # endif return obj; diff --git a/src/workers/CpuThread.h b/src/workers/CpuThread.h index 08aa89cb..a43a0c09 100644 --- a/src/workers/CpuThread.h +++ b/src/workers/CpuThread.h @@ -42,7 +42,7 @@ class CpuThread : public IThread public: struct Data { - inline Data() : assembly(ASM_AUTO), valid(false), affinity(-1L), multiway(SingleWay) {} + inline Data() : valid(false), affinity(-1L), multiway(SingleWay) {} inline void setMultiway(int value) { From dd875c7c3797dbb44ffb85641fe3838d93e57236 Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 28 Jun 2019 22:28:40 +0700 Subject: [PATCH 09/65] Added class CpuConfig. --- CMakeLists.txt | 3 + src/App.cpp | 2 +- src/Summary.cpp | 10 +-- src/backend/cpu/CpuConfig.cpp | 110 ++++++++++++++++++++++++++++++++ src/backend/cpu/CpuConfig.h | 72 +++++++++++++++++++++ src/backend/cpu/cpu.cmake | 7 +++ src/base/kernel/Base.cpp | 2 +- src/core/config/Config.cpp | 115 ++++++++-------------------------- src/core/config/Config.h | 40 ++---------- src/crypto/common/Assembly.h | 5 +- 10 files changed, 233 insertions(+), 133 deletions(-) create mode 100644 src/backend/cpu/CpuConfig.cpp create mode 100644 src/backend/cpu/CpuConfig.h create mode 100644 src/backend/cpu/cpu.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index a402174a..832c95d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,11 +18,13 @@ option(WITH_EMBEDDED_CONFIG "Enable internal embedded JSON config" OFF) include (CheckIncludeFile) include (cmake/cpu.cmake) include (src/base/base.cmake) +include (src/backend/cpu/cpu.cmake) set(HEADERS "${HEADERS_BASE}" "${HEADERS_BASE_HTTP}" + "${HEADERS_CPU}" src/api/interfaces/IApiListener.h src/App.h src/common/cpu/Cpu.h @@ -83,6 +85,7 @@ endif() set(SOURCES "${SOURCES_BASE}" "${SOURCES_BASE_HTTP}" + "${SOURCES_CPU}" src/App.cpp src/common/Platform.cpp src/core/config/Config.cpp diff --git a/src/App.cpp b/src/App.cpp index 66662eb1..082bbeef 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -77,7 +77,7 @@ int xmrig::App::exec() background(); - Mem::init(m_controller->config()->isHugePages()); + Mem::init(m_controller->config()->cpu().isHugePages()); Summary::print(m_controller); diff --git a/src/Summary.cpp b/src/Summary.cpp index 13973c0f..a51f8f59 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -86,9 +86,9 @@ static void print_threads(xmrig::Config *config) { if (config->threadsMode() != xmrig::Config::Advanced) { char buf[32] = { 0 }; - if (config->affinity() != -1L) { - snprintf(buf, sizeof buf, ", affinity=0x%" PRIX64, config->affinity()); - } +// if (config->affinity() != -1L) { +// snprintf(buf, sizeof buf, ", affinity=0x%" PRIX64, config->affinity()); +// } xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%d") WHITE_BOLD(", av=%d, %sdonate=%d%%") WHITE_BOLD("%s"), "THREADS", @@ -109,13 +109,13 @@ static void print_threads(xmrig::Config *config) } # ifdef XMRIG_FEATURE_ASM - if (config->assembly() == xmrig::Assembly::AUTO) { + if (config->cpu().assembly() == xmrig::Assembly::AUTO) { const xmrig::Assembly assembly = xmrig::Cpu::info()->assembly(); xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13sauto:%s"), "ASSEMBLY", asmName(assembly)); } else { - xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s%s"), "ASSEMBLY", asmName(config->assembly())); + xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s%s"), "ASSEMBLY", asmName(config->cpu().assembly())); } # endif } diff --git a/src/backend/cpu/CpuConfig.cpp b/src/backend/cpu/CpuConfig.cpp new file mode 100644 index 00000000..b3d780f4 --- /dev/null +++ b/src/backend/cpu/CpuConfig.cpp @@ -0,0 +1,110 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/cpu/CpuConfig.h" +#include "base/io/json/Json.h" +#include "common/cpu/Cpu.h" +#include "rapidjson/document.h" + + +namespace xmrig { + + +static const char *kEnabled = "enabled"; +static const char *kHugePages = "huge-pages"; +static const char *kHwAes = "hw-aes"; +static const char *kPriority = "priority"; + + +#ifdef XMRIG_FEATURE_ASM +static const char *kAsm = "asm"; +#endif + +} + + +xmrig::CpuConfig::CpuConfig() +{ +} + + +bool xmrig::CpuConfig::isHwAES() const +{ + return (m_aes == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aes) == AES_HW; +} + + +rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + + auto &allocator = doc.GetAllocator(); + + Value obj(kObjectType); + + obj.AddMember(StringRef(kEnabled), m_enabled, allocator); + obj.AddMember(StringRef(kHugePages), m_hugePages, allocator); + 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); + +# ifdef XMRIG_FEATURE_ASM + obj.AddMember(StringRef(kAsm), m_assembly.toJSON(), allocator); +# endif + + return obj; +} + + +void xmrig::CpuConfig::read(const rapidjson::Value &value) +{ + if (value.IsObject()) { + m_enabled = Json::getBool(value, kEnabled, m_enabled); + m_hugePages = Json::getBool(value, kHugePages, m_hugePages); + + setAesMode(Json::getValue(value, kHwAes)); + setPriority(Json::getInt(value, kPriority, -1)); + +# ifdef XMRIG_FEATURE_ASM + m_assembly = Json::getValue(value, kAsm); +# endif + } +} + + +void xmrig::CpuConfig::setAesMode(const rapidjson::Value &aesMode) +{ + if (aesMode.IsBool()) { + m_aes = aesMode.GetBool() ? AES_HW : AES_SOFT; + } + else { + m_aes = AES_AUTO; + } +} + + +void xmrig::CpuConfig::setPriority(int priority) +{ + m_priority = (priority >= -1 && priority <= 5) ? priority : -1; +} diff --git a/src/backend/cpu/CpuConfig.h b/src/backend/cpu/CpuConfig.h new file mode 100644 index 00000000..04dd9175 --- /dev/null +++ b/src/backend/cpu/CpuConfig.h @@ -0,0 +1,72 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CPUCONFIG_H +#define XMRIG_CPUCONFIG_H + + +#include "crypto/common/Assembly.h" + + +namespace xmrig { + + +class CpuConfig +{ +public: + enum AesMode { + AES_AUTO, + AES_HW, + AES_SOFT + }; + + CpuConfig(); + + bool isHwAES() const; + rapidjson::Value toJSON(rapidjson::Document &doc) const; + void read(const rapidjson::Value &value); + + inline bool isEnabled() const { return m_enabled; } + inline bool isHugePages() const { return m_hugePages; } + inline bool isShouldSave() const { return m_shouldSave; } + inline const Assembly &assembly() const { return m_assembly; } + inline int priority() const { return m_priority; } + +private: + void setAesMode(const rapidjson::Value &aesMode); + void setPriority(int priority); + + AesMode m_aes = AES_AUTO; + Assembly m_assembly; + bool m_enabled = true; + bool m_hugePages = true; + bool m_shouldSave = false; + int m_priority = -1; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_CPUCONFIG_H */ diff --git a/src/backend/cpu/cpu.cmake b/src/backend/cpu/cpu.cmake new file mode 100644 index 00000000..88159893 --- /dev/null +++ b/src/backend/cpu/cpu.cmake @@ -0,0 +1,7 @@ +set(HEADERS_CPU + src/backend/cpu/CpuConfig.h + ) + +set(SOURCES_CPU + src/backend/cpu/CpuConfig.cpp + ) diff --git a/src/base/kernel/Base.cpp b/src/base/kernel/Base.cpp index 1083efe9..031daed7 100644 --- a/src/base/kernel/Base.cpp +++ b/src/base/kernel/Base.cpp @@ -172,7 +172,7 @@ int xmrig::Base::init() Platform::init(config()->userAgent()); # ifndef XMRIG_PROXY_PROJECT - Platform::setProcessPriority(config()->priority()); + Platform::setProcessPriority(config()->cpu().priority()); # endif if (!config()->isBackground()) { diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 93bd47ff..5b445c0f 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -39,46 +39,24 @@ #include "workers/CpuThread.h" -static char affinity_tmp[20] = { 0 }; - - xmrig::Config::Config() : - m_aesMode(AES_AUTO), m_algoVariant(AV_AUTO), - m_hugePages(true), - m_safe(false), - m_shouldSave(false), - m_maxCpuUsage(100), - m_priority(-1) + m_shouldSave(false) { } -bool xmrig::Config::isHwAES() const -{ - return (m_aesMode == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aesMode) == AES_HW; -} - - bool xmrig::Config::read(const IJsonReader &reader, const char *fileName) { if (!BaseConfig::read(reader, fileName)) { return false; } - m_hugePages = reader.getBool("huge-pages", true); - m_safe = reader.getBool("safe"); + m_cpu.read(reader.getValue("cpu")); - setAesMode(reader.getValue("hw-aes")); setAlgoVariant(reader.getInt("av")); - setMaxCpuUsage(reader.getInt("max-cpu-usage", 100)); - setPriority(reader.getInt("cpu-priority", -1)); setThreads(reader.getValue("threads")); -# ifdef XMRIG_FEATURE_ASM - setAssembly(reader.getValue("asm")); -# endif - return finalize(); } @@ -96,36 +74,29 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const api.AddMember("worker-id", m_apiWorkerId.toJSON(), allocator); doc.AddMember("api", api, allocator); doc.AddMember("http", m_http.toJSON(doc), allocator); - -# ifdef XMRIG_FEATURE_ASM - doc.AddMember("asm", m_assembly.toJSON(), allocator); -# endif - doc.AddMember("autosave", isAutoSave(), allocator); doc.AddMember("av", algoVariant(), allocator); doc.AddMember("background", isBackground(), allocator); doc.AddMember("colors", Log::colors, allocator); - if (affinity() != -1L) { - snprintf(affinity_tmp, sizeof(affinity_tmp) - 1, "0x%" PRIX64, affinity()); - doc.AddMember("cpu-affinity", StringRef(affinity_tmp), allocator); - } - else { - doc.AddMember("cpu-affinity", kNullType, allocator); - } +// if (affinity() != -1L) { +// snprintf(affinity_tmp, sizeof(affinity_tmp) - 1, "0x%" PRIX64, affinity()); +// doc.AddMember("cpu-affinity", StringRef(affinity_tmp), allocator); +// } +// else { +// doc.AddMember("cpu-affinity", kNullType, allocator); +// } + + + doc.AddMember("cpu", m_cpu.toJSON(doc), allocator); - doc.AddMember("cpu-priority", priority() != -1 ? Value(priority()) : Value(kNullType), allocator); doc.AddMember("donate-level", m_pools.donateLevel(), allocator); doc.AddMember("donate-over-proxy", m_pools.proxyDonate(), allocator); - doc.AddMember("huge-pages", isHugePages(), allocator); - doc.AddMember("hw-aes", m_aesMode == AES_AUTO ? Value(kNullType) : Value(m_aesMode == AES_HW), allocator); doc.AddMember("log-file", m_logFile.toJSON(), allocator); - doc.AddMember("max-cpu-usage", m_maxCpuUsage, allocator); doc.AddMember("pools", m_pools.toJSON(doc), allocator); doc.AddMember("print-time", printTime(), allocator); doc.AddMember("retries", m_pools.retries(), allocator); doc.AddMember("retry-pause", m_pools.retryPause(), allocator); - doc.AddMember("safe", m_safe, allocator); if (threadsMode() != Simple) { Value threads(kArrayType); @@ -154,7 +125,7 @@ bool xmrig::Config::finalize() m_threads.mode = Advanced; for (size_t i = 0; i < m_threads.cpu.size(); ++i) { - m_threads.list.push_back(CpuThread::createFromData(i, algorithm, m_threads.cpu[i], m_priority, !isHwAES())); + m_threads.list.push_back(CpuThread::createFromData(i, algorithm, m_threads.cpu[i], m_cpu.priority(), !m_cpu.isHwAES())); } return true; @@ -166,17 +137,17 @@ bool xmrig::Config::finalize() const size_t size = CpuThread::multiway(av) * CnAlgo<>::memory(algorithm) / 1024; // FIXME MEMORY if (!m_threads.count) { - m_threads.count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); - } - else if (m_safe) { - const size_t count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); - if (m_threads.count > count) { - m_threads.count = count; - } + m_threads.count = Cpu::info()->optimalThreadsCount(size, 100); } +// else if (m_safe) { +// const size_t count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); +// if (m_threads.count > count) { +// m_threads.count = count; +// } +// } for (size_t i = 0; i < m_threads.count; ++i) { - m_threads.list.push_back(CpuThread::createFromAV(i, algorithm, av, m_threads.mask, m_priority, m_assembly)); + m_threads.list.push_back(CpuThread::createFromAV(i, algorithm, av, m_threads.mask, m_cpu.priority(), m_cpu.assembly())); } m_shouldSave = m_threads.mode == Automatic; @@ -185,14 +156,6 @@ bool xmrig::Config::finalize() } -void xmrig::Config::setAesMode(const rapidjson::Value &aesMode) -{ - if (aesMode.IsBool()) { - m_aesMode = aesMode.GetBool() ? AES_HW : AES_SOFT; - } -} - - void xmrig::Config::setAlgoVariant(int av) { if (av >= AV_AUTO && av < AV_MAX) { @@ -201,22 +164,6 @@ void xmrig::Config::setAlgoVariant(int av) } -void xmrig::Config::setMaxCpuUsage(int max) -{ - if (max > 0 && max <= 100) { - m_maxCpuUsage = max; - } -} - - -void xmrig::Config::setPriority(int priority) -{ - if (priority >= 0 && priority <= 5) { - m_priority = priority; - } -} - - void xmrig::Config::setThreads(const rapidjson::Value &threads) { if (threads.IsArray()) { @@ -257,9 +204,9 @@ xmrig::AlgoVariant xmrig::Config::getAlgoVariant() const return Cpu::info()->hasAES() ? AV_SINGLE : AV_SINGLE_SOFT; } - if (m_safe && !Cpu::info()->hasAES() && m_algoVariant <= AV_DOUBLE) { - return static_cast(m_algoVariant + 2); - } +// if (m_safe && !Cpu::info()->hasAES() && m_algoVariant <= AV_DOUBLE) { +// return static_cast(m_algoVariant + 2); +// } return m_algoVariant; } @@ -272,18 +219,10 @@ xmrig::AlgoVariant xmrig::Config::getAlgoVariantLite() const return Cpu::info()->hasAES() ? AV_DOUBLE : AV_DOUBLE_SOFT; } - if (m_safe && !Cpu::info()->hasAES() && m_algoVariant <= AV_DOUBLE) { - return static_cast(m_algoVariant + 2); - } +// if (m_safe && !Cpu::info()->hasAES() && m_algoVariant <= AV_DOUBLE) { +// return static_cast(m_algoVariant + 2); +// } return m_algoVariant; } #endif - - -#ifdef XMRIG_FEATURE_ASM -void xmrig::Config::setAssembly(const rapidjson::Value &assembly) -{ - m_assembly = assembly; -} -#endif diff --git a/src/core/config/Config.h b/src/core/config/Config.h index 0ff13fe7..76720889 100644 --- a/src/core/config/Config.h +++ b/src/core/config/Config.h @@ -5,7 +5,8 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , + * 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 @@ -29,6 +30,7 @@ #include +#include "backend/cpu/CpuConfig.h" #include "base/kernel/config/BaseConfig.h" #include "common/xmrig.h" #include "rapidjson/fwd.h" @@ -38,23 +40,9 @@ namespace xmrig { -class ConfigLoader; class IThread; -class IConfigListener; -class Process; -/** - * @brief The Config class - * - * Options with dynamic reload: - * colors - * debug - * verbose - * custom-diff (only for new connections) - * api/worker-id - * pools/ - */ class Config : public BaseConfig { public: @@ -67,26 +55,19 @@ public: Config(); - bool isHwAES() const; bool read(const IJsonReader &reader, const char *fileName) override; void getJSON(rapidjson::Document &doc) const override; inline AlgoVariant algoVariant() const { return m_algoVariant; } - inline Assembly assembly() const { return m_assembly; } - inline bool isHugePages() const { return m_hugePages; } inline bool isShouldSave() const { return (m_shouldSave || m_upgrade) && isAutoSave(); } + inline const CpuConfig &cpu() const { return m_cpu; } inline const std::vector &threads() const { return m_threads.list; } - inline int priority() const { return m_priority; } inline int threadsCount() const { return static_cast(m_threads.list.size()); } - inline int64_t affinity() const { return m_threads.mask; } inline ThreadsMode threadsMode() const { return m_threads.mode; } private: bool finalize(); - void setAesMode(const rapidjson::Value &aesMode); void setAlgoVariant(int av); - void setMaxCpuUsage(int max); - void setPriority(int priority); void setThreads(const rapidjson::Value &threads); AlgoVariant getAlgoVariant() const; @@ -94,11 +75,6 @@ private: AlgoVariant getAlgoVariantLite() const; # endif -# ifdef XMRIG_FEATURE_ASM - void setAssembly(const rapidjson::Value &assembly); -# endif - - struct Threads { inline Threads() : mask(-1L), count(0), mode(Automatic) {} @@ -111,18 +87,14 @@ private: }; - AesMode m_aesMode; AlgoVariant m_algoVariant; - Assembly m_assembly; - bool m_hugePages; - bool m_safe; bool m_shouldSave; - int m_maxCpuUsage; - int m_priority; + CpuConfig m_cpu; Threads m_threads; }; } /* namespace xmrig */ + #endif /* XMRIG_CONFIG_H */ diff --git a/src/crypto/common/Assembly.h b/src/crypto/common/Assembly.h index e4964d07..0b3f29b3 100644 --- a/src/crypto/common/Assembly.h +++ b/src/crypto/common/Assembly.h @@ -57,10 +57,7 @@ public: const char *toString() const; rapidjson::Value toJSON() const; -// inline static Assembly parse(bool enable) { return enable ? ASM_AUTO : ASM_NONE; } - - inline bool isEqual(const Assembly &other) const { return m_id == other.m_id; } - + inline bool isEqual(const Assembly &other) const { return m_id == other.m_id; } inline bool operator!=(const Assembly &other) const { return !isEqual(other); } inline bool operator!=(const Assembly::Id &id) const { return m_id != id; } From 62edb2fc0ace1b078e821e13229f18ec94ec3c42 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 29 Jun 2019 09:51:23 +0700 Subject: [PATCH 10/65] Move CPU information classes to new location. --- CMakeLists.txt | 19 ------- src/App.cpp | 4 +- src/Summary.cpp | 4 +- src/api/v1/ApiRouter.cpp | 2 +- src/{core => backend}/cpu/Cpu.cpp | 17 ++++-- src/{common => backend}/cpu/Cpu.h | 5 +- src/backend/cpu/CpuConfig.cpp | 2 +- src/backend/cpu/cpu.cmake | 22 +++++++ .../cpu}/interfaces/ICpuInfo.h | 7 ++- .../cpu/platform}/AdvancedCpuInfo.cpp | 2 +- .../cpu/platform}/AdvancedCpuInfo.h | 8 +-- .../cpu/platform}/BasicCpuInfo.cpp | 9 +-- .../cpu/platform}/BasicCpuInfo.h | 8 +-- .../cpu/platform}/BasicCpuInfo_arm.cpp | 0 src/common/cpu/Cpu.cpp | 57 ------------------- src/core/Controller.cpp | 2 +- src/core/config/Config.cpp | 2 +- src/crypto/cn/CnHash.cpp | 2 +- src/crypto/cn/CryptoNight_x86.h | 2 +- src/workers/CpuThread.cpp | 1 - src/workers/Worker.cpp | 2 +- 21 files changed, 62 insertions(+), 115 deletions(-) rename src/{core => backend}/cpu/Cpu.cpp (73%) rename src/{common => backend}/cpu/Cpu.h (88%) rename src/{common => backend/cpu}/interfaces/ICpuInfo.h (91%) rename src/{core/cpu => backend/cpu/platform}/AdvancedCpuInfo.cpp (98%) rename src/{core/cpu => backend/cpu/platform}/AdvancedCpuInfo.h (91%) rename src/{common/cpu => backend/cpu/platform}/BasicCpuInfo.cpp (94%) rename src/{common/cpu => backend/cpu/platform}/BasicCpuInfo.h (89%) rename src/{common/cpu => backend/cpu/platform}/BasicCpuInfo_arm.cpp (100%) delete mode 100644 src/common/cpu/Cpu.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 832c95d7..7320b63d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,8 +27,6 @@ set(HEADERS "${HEADERS_CPU}" src/api/interfaces/IApiListener.h src/App.h - src/common/cpu/Cpu.h - src/common/interfaces/ICpuInfo.h src/common/Platform.h src/common/xmrig.h src/core/config/Config_default.h @@ -178,23 +176,6 @@ endif() include(cmake/flags.cmake) -if (WITH_LIBCPUID) - add_subdirectory(src/3rdparty/libcpuid) - - include_directories(src/3rdparty/libcpuid) - set(CPUID_LIB cpuid) - set(SOURCES_CPUID src/core/cpu/AdvancedCpuInfo.h src/core/cpu/AdvancedCpuInfo.cpp src/core/cpu/Cpu.cpp) -else() - add_definitions(/DXMRIG_NO_LIBCPUID) - set(SOURCES_CPUID src/common/cpu/BasicCpuInfo.h src/common/cpu/Cpu.cpp) - - if (XMRIG_ARM) - set(SOURCES_CPUID ${SOURCES_CPUID} src/common/cpu/BasicCpuInfo_arm.cpp) - else() - set(SOURCES_CPUID ${SOURCES_CPUID} src/common/cpu/BasicCpuInfo.cpp) - endif() -endif() - include(cmake/OpenSSL.cmake) include(cmake/asm.cmake) include(cmake/cn-gpu.cmake) diff --git a/src/App.cpp b/src/App.cpp index 082bbeef..6e42ac30 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -6,7 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018 Lee Clagett - * Copyright 2018 SChernykh + * Copyright 2018-2019 SChernykh * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -30,10 +30,10 @@ #include "api/Api.h" #include "App.h" +#include "backend/cpu/Cpu.h" #include "base/io/Console.h" #include "base/io/log/Log.h" #include "base/kernel/Signals.h" -#include "common/cpu/Cpu.h" #include "common/Platform.h" #include "core/config/Config.h" #include "core/Controller.h" diff --git a/src/Summary.cpp b/src/Summary.cpp index a51f8f59..59e540d4 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -28,9 +28,9 @@ #include +#include "backend/cpu/Cpu.h" #include "base/io/log/Log.h" #include "base/net/stratum/Pool.h" -#include "common/cpu/Cpu.h" #include "core/config/Config.h" #include "core/Controller.h" #include "crypto/common/Assembly.h" @@ -76,7 +76,7 @@ static void print_cpu(xmrig::Config *) Cpu::info()->hasAES() ? GREEN_BOLD_S : RED_BOLD_S "-", Cpu::info()->hasAVX2() ? GREEN_BOLD_S : RED_BOLD_S "-" ); -# ifndef XMRIG_NO_LIBCPUID +# ifdef XMRIG_FEATURE_LIBCPUID Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s%.1f MB/%.1f MB"), "CPU L2/L3", Cpu::info()->L2() / 1024.0, Cpu::info()->L3() / 1024.0); # endif } diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp index d066b0b1..0f754e17 100644 --- a/src/api/v1/ApiRouter.cpp +++ b/src/api/v1/ApiRouter.cpp @@ -29,8 +29,8 @@ #include "api/interfaces/IApiRequest.h" #include "api/v1/ApiRouter.h" +#include "backend/cpu/Cpu.h" #include "base/kernel/Base.h" -#include "common/cpu/Cpu.h" #include "common/Platform.h" #include "core/config/Config.h" #include "interfaces/IThread.h" diff --git a/src/core/cpu/Cpu.cpp b/src/backend/cpu/Cpu.cpp similarity index 73% rename from src/core/cpu/Cpu.cpp rename to src/backend/cpu/Cpu.cpp index 773255d2..fdcad5a8 100644 --- a/src/core/cpu/Cpu.cpp +++ b/src/backend/cpu/Cpu.cpp @@ -4,8 +4,9 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,11 +26,13 @@ #include -#include "common/cpu/Cpu.h" +#include "backend/cpu/Cpu.h" -#ifndef XMRIG_NO_LIBCPUID -# include "core/cpu/AdvancedCpuInfo.h" +#ifdef XMRIG_FEATURE_LIBCPUID +# include "backend/cpu/platform/AdvancedCpuInfo.h" +#else +# include "backend/cpu/platform/BasicCpuInfo.h" #endif @@ -48,7 +51,11 @@ void xmrig::Cpu::init() { assert(cpuInfo == nullptr); +# ifdef XMRIG_FEATURE_LIBCPUID cpuInfo = new AdvancedCpuInfo(); +# else + cpuInfo = new BasicCpuInfo(); +# endif } diff --git a/src/common/cpu/Cpu.h b/src/backend/cpu/Cpu.h similarity index 88% rename from src/common/cpu/Cpu.h rename to src/backend/cpu/Cpu.h index 1d5a9fb1..9c8afced 100644 --- a/src/common/cpu/Cpu.h +++ b/src/backend/cpu/Cpu.h @@ -5,7 +5,8 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , + * 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 @@ -25,7 +26,7 @@ #define XMRIG_CPU_H -#include "common/interfaces/ICpuInfo.h" +#include "backend/cpu/interfaces/ICpuInfo.h" namespace xmrig { diff --git a/src/backend/cpu/CpuConfig.cpp b/src/backend/cpu/CpuConfig.cpp index b3d780f4..5284d607 100644 --- a/src/backend/cpu/CpuConfig.cpp +++ b/src/backend/cpu/CpuConfig.cpp @@ -23,9 +23,9 @@ */ +#include "backend/cpu/Cpu.h" #include "backend/cpu/CpuConfig.h" #include "base/io/json/Json.h" -#include "common/cpu/Cpu.h" #include "rapidjson/document.h" diff --git a/src/backend/cpu/cpu.cmake b/src/backend/cpu/cpu.cmake index 88159893..03ca7075 100644 --- a/src/backend/cpu/cpu.cmake +++ b/src/backend/cpu/cpu.cmake @@ -1,7 +1,29 @@ set(HEADERS_CPU + src/backend/cpu/Cpu.h src/backend/cpu/CpuConfig.h + src/backend/cpu/interfaces/ICpuInfo.h ) set(SOURCES_CPU + src/backend/cpu/Cpu.cpp src/backend/cpu/CpuConfig.cpp ) + + +if (WITH_LIBCPUID) + add_subdirectory(src/3rdparty/libcpuid) + include_directories(src/3rdparty/libcpuid) + add_definitions(/DXMRIG_FEATURE_LIBCPUID) + + set(CPUID_LIB cpuid) + set(SOURCES_CPUID src/backend/cpu/platform/AdvancedCpuInfo.h src/backend/cpu/platform/AdvancedCpuInfo.cpp src/backend/cpu/Cpu.cpp) +else() + remove_definitions(/DXMRIG_FEATURE_LIBCPUID) + set(SOURCES_CPUID src/backend/cpu/platform/BasicCpuInfo.h src/backend/cpu/Cpu.cpp) + + if (XMRIG_ARM) + set(SOURCES_CPUID ${SOURCES_CPUID} src/backend/cpu/platform/BasicCpuInfo_arm.cpp) + else() + set(SOURCES_CPUID ${SOURCES_CPUID} src/backend/cpu/platform/BasicCpuInfo.cpp) + endif() +endif() diff --git a/src/common/interfaces/ICpuInfo.h b/src/backend/cpu/interfaces/ICpuInfo.h similarity index 91% rename from src/common/interfaces/ICpuInfo.h rename to src/backend/cpu/interfaces/ICpuInfo.h index 907f3f63..9618f489 100644 --- a/src/common/interfaces/ICpuInfo.h +++ b/src/backend/cpu/interfaces/ICpuInfo.h @@ -41,10 +41,15 @@ class ICpuInfo public: virtual ~ICpuInfo() = default; +# if defined(__x86_64__) || defined(_M_AMD64) || defined (__arm64__) || defined (__aarch64__) + inline constexpr bool isX64() const { return true; } +# else + inline constexpr bool isX64() const { return false; } +# endif + virtual bool hasAES() const = 0; virtual bool hasAVX2() const = 0; virtual bool isSupported() const = 0; - virtual bool isX64() const = 0; virtual const char *brand() const = 0; virtual int32_t cores() const = 0; virtual int32_t L2() const = 0; diff --git a/src/core/cpu/AdvancedCpuInfo.cpp b/src/backend/cpu/platform/AdvancedCpuInfo.cpp similarity index 98% rename from src/core/cpu/AdvancedCpuInfo.cpp rename to src/backend/cpu/platform/AdvancedCpuInfo.cpp index 922e8311..fc7f734d 100644 --- a/src/core/cpu/AdvancedCpuInfo.cpp +++ b/src/backend/cpu/platform/AdvancedCpuInfo.cpp @@ -27,7 +27,7 @@ #include -#include "core/cpu/AdvancedCpuInfo.h" +#include "backend/cpu/platform/AdvancedCpuInfo.h" xmrig::AdvancedCpuInfo::AdvancedCpuInfo() : diff --git a/src/core/cpu/AdvancedCpuInfo.h b/src/backend/cpu/platform/AdvancedCpuInfo.h similarity index 91% rename from src/core/cpu/AdvancedCpuInfo.h rename to src/backend/cpu/platform/AdvancedCpuInfo.h index 90152640..83c3d8e5 100644 --- a/src/core/cpu/AdvancedCpuInfo.h +++ b/src/backend/cpu/platform/AdvancedCpuInfo.h @@ -26,7 +26,7 @@ #define XMRIG_ADVANCEDCPUINFO_H -#include "common/interfaces/ICpuInfo.h" +#include "backend/cpu/interfaces/ICpuInfo.h" namespace xmrig { @@ -52,12 +52,6 @@ protected: inline int32_t sockets() const override { return m_sockets; } inline int32_t threads() const override { return m_threads; } -# if defined(__x86_64__) || defined(_M_AMD64) - inline bool isX64() const override { return true; } -# else - inline bool isX64() const override { return false; } -# endif - private: Assembly m_assembly; bool m_aes; diff --git a/src/common/cpu/BasicCpuInfo.cpp b/src/backend/cpu/platform/BasicCpuInfo.cpp similarity index 94% rename from src/common/cpu/BasicCpuInfo.cpp rename to src/backend/cpu/platform/BasicCpuInfo.cpp index c5b8ed0a..04ff589b 100644 --- a/src/common/cpu/BasicCpuInfo.cpp +++ b/src/backend/cpu/platform/BasicCpuInfo.cpp @@ -45,7 +45,8 @@ #endif -#include "common/cpu/BasicCpuInfo.h" +#include "backend/cpu/platform/BasicCpuInfo.h" +#include "crypto/common/Assembly.h" #define VENDOR_ID (0) @@ -121,7 +122,7 @@ static inline bool has_ossave() xmrig::BasicCpuInfo::BasicCpuInfo() : - m_assembly(ASM_NONE), + m_assembly(Assembly::NONE), m_aes(has_aes_ni()), m_avx2(has_avx2() && has_ossave()), m_brand(), @@ -141,10 +142,10 @@ xmrig::BasicCpuInfo::BasicCpuInfo() : memcpy(vendor + 8, &data[2], 4); if (memcmp(vendor, "GenuineIntel", 12) == 0) { - m_assembly = ASM_INTEL; + m_assembly = Assembly::INTEL; } else if (memcmp(vendor, "AuthenticAMD", 12) == 0) { - m_assembly = ASM_RYZEN; + m_assembly = Assembly::RYZEN; } } # endif diff --git a/src/common/cpu/BasicCpuInfo.h b/src/backend/cpu/platform/BasicCpuInfo.h similarity index 89% rename from src/common/cpu/BasicCpuInfo.h rename to src/backend/cpu/platform/BasicCpuInfo.h index f6daee54..4d4a5163 100644 --- a/src/common/cpu/BasicCpuInfo.h +++ b/src/backend/cpu/platform/BasicCpuInfo.h @@ -26,7 +26,7 @@ #define XMRIG_BASICCPUINFO_H -#include "common/interfaces/ICpuInfo.h" +#include "backend/cpu/interfaces/ICpuInfo.h" namespace xmrig { @@ -52,12 +52,6 @@ protected: inline int32_t sockets() const override { return 1; } inline int32_t threads() const override { return m_threads; } -# if defined(__x86_64__) || defined(_M_AMD64) || defined (__arm64__) || defined (__aarch64__) - inline bool isX64() const override { return true; } -# else - inline bool isX64() const override { return false; } -# endif - private: Assembly m_assembly; bool m_aes; diff --git a/src/common/cpu/BasicCpuInfo_arm.cpp b/src/backend/cpu/platform/BasicCpuInfo_arm.cpp similarity index 100% rename from src/common/cpu/BasicCpuInfo_arm.cpp rename to src/backend/cpu/platform/BasicCpuInfo_arm.cpp diff --git a/src/common/cpu/Cpu.cpp b/src/common/cpu/Cpu.cpp deleted file mode 100644 index b1bb28ac..00000000 --- a/src/common/cpu/Cpu.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2016-2017 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 - - -#include "common/cpu/BasicCpuInfo.h" -#include "common/cpu/Cpu.h" - - -static xmrig::ICpuInfo *cpuInfo = nullptr; - - -xmrig::ICpuInfo *xmrig::Cpu::info() -{ - assert(cpuInfo != nullptr); - - return cpuInfo; -} - - -void xmrig::Cpu::init() -{ - assert(cpuInfo == nullptr); - - cpuInfo = new BasicCpuInfo(); -} - - -void xmrig::Cpu::release() -{ - assert(cpuInfo != nullptr); - - delete cpuInfo; - cpuInfo = nullptr; -} diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index 493b3e11..8e2e03a1 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -26,7 +26,7 @@ #include -#include "common/cpu/Cpu.h" +#include "backend/cpu/Cpu.h" #include "common/Platform.h" #include "core/Controller.h" #include "net/Network.h" diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 5b445c0f..33f4cc44 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -28,9 +28,9 @@ #include +#include "backend/cpu/Cpu.h" #include "base/io/log/Log.h" #include "base/kernel/interfaces/IJsonReader.h" -#include "common/cpu/Cpu.h" #include "core/config/Config.h" #include "crypto/common/Assembly.h" #include "rapidjson/document.h" diff --git a/src/crypto/cn/CnHash.cpp b/src/crypto/cn/CnHash.cpp index d17a8e2d..6582db10 100644 --- a/src/crypto/cn/CnHash.cpp +++ b/src/crypto/cn/CnHash.cpp @@ -26,7 +26,7 @@ #include -#include "common/cpu/Cpu.h" +#include "backend/cpu/Cpu.h" #include "crypto/cn/CnHash.h" #include "crypto/common/VirtualMemory.h" diff --git a/src/crypto/cn/CryptoNight_x86.h b/src/crypto/cn/CryptoNight_x86.h index b24dea57..ae51cd18 100644 --- a/src/crypto/cn/CryptoNight_x86.h +++ b/src/crypto/cn/CryptoNight_x86.h @@ -35,7 +35,7 @@ #endif -#include "common/cpu/Cpu.h" +#include "backend/cpu/Cpu.h" #include "crypto/cn/CnAlgo.h" #include "crypto/cn/CryptoNight_monero.h" #include "crypto/cn/CryptoNight.h" diff --git a/src/workers/CpuThread.cpp b/src/workers/CpuThread.cpp index 9f20a35a..7011da12 100644 --- a/src/workers/CpuThread.cpp +++ b/src/workers/CpuThread.cpp @@ -26,7 +26,6 @@ #include "base/io/log/Log.h" -#include "common/cpu/Cpu.h" #include "crypto/cn/CnHash.h" #include "crypto/common/Assembly.h" #include "crypto/common/VirtualMemory.h" diff --git a/src/workers/Worker.cpp b/src/workers/Worker.cpp index 234e7bfd..c6ea6d9a 100644 --- a/src/workers/Worker.cpp +++ b/src/workers/Worker.cpp @@ -24,7 +24,7 @@ #include -#include "common/cpu/Cpu.h" +#include "backend/cpu/Cpu.h" #include "common/Platform.h" #include "workers/CpuThread.h" #include "workers/ThreadHandle.h" From e10671fa5121c1af75a51ecf333db179f652a545 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 29 Jun 2019 10:25:06 +0700 Subject: [PATCH 11/65] Fixed ARM build. --- src/backend/cpu/interfaces/ICpuInfo.h | 4 ++-- src/backend/cpu/platform/BasicCpuInfo_arm.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/cpu/interfaces/ICpuInfo.h b/src/backend/cpu/interfaces/ICpuInfo.h index 9618f489..abff7a6c 100644 --- a/src/backend/cpu/interfaces/ICpuInfo.h +++ b/src/backend/cpu/interfaces/ICpuInfo.h @@ -42,9 +42,9 @@ public: virtual ~ICpuInfo() = default; # if defined(__x86_64__) || defined(_M_AMD64) || defined (__arm64__) || defined (__aarch64__) - inline constexpr bool isX64() const { return true; } + inline constexpr static bool isX64() { return true; } # else - inline constexpr bool isX64() const { return false; } + inline constexpr static bool isX64() { return false; } # endif virtual bool hasAES() const = 0; diff --git a/src/backend/cpu/platform/BasicCpuInfo_arm.cpp b/src/backend/cpu/platform/BasicCpuInfo_arm.cpp index dea8de73..49e300e4 100644 --- a/src/backend/cpu/platform/BasicCpuInfo_arm.cpp +++ b/src/backend/cpu/platform/BasicCpuInfo_arm.cpp @@ -32,7 +32,7 @@ #endif -#include "common/cpu/BasicCpuInfo.h" +#include "backend/cpu/platform/BasicCpuInfo.h" xmrig::BasicCpuInfo::BasicCpuInfo() : From 83fdbbf29cba31b1b238567f7040fe6db2c133c9 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 29 Jun 2019 10:57:05 +0700 Subject: [PATCH 12/65] Added "features" and "algorithms" fields to API summary response. --- src/api/Api.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/api/Api.cpp b/src/api/Api.cpp index caebcba7..a1aeb4c2 100644 --- a/src/api/Api.cpp +++ b/src/api/Api.cpp @@ -41,6 +41,7 @@ #include "base/tools/Chrono.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "crypto/common/Algorithm.h" #include "crypto/common/keccak.h" #include "version.h" @@ -126,6 +127,32 @@ void xmrig::Api::exec(IApiRequest &request) request.reply().AddMember("id", StringRef(m_id), allocator); request.reply().AddMember("worker_id", StringRef(m_workerId), allocator); request.reply().AddMember("uptime", (Chrono::steadyMSecs() - m_timestamp) / 1000, allocator); + + Value features(kArrayType); +# ifdef XMRIG_FEATURE_API + features.PushBack("api", allocator); +# endif +# ifdef XMRIG_FEATURE_ASM + features.PushBack("asm", allocator); +# endif +# ifdef XMRIG_FEATURE_HTTP + features.PushBack("http", allocator); +# endif +# ifdef XMRIG_FEATURE_LIBCPUID + features.PushBack("cpuid", allocator); +# endif +# ifdef XMRIG_FEATURE_TLS + features.PushBack("tls", allocator); +# endif + request.reply().AddMember("features", features, allocator); + + Value algorithms(kArrayType); + + for (int i = 0; i < Algorithm::MAX; ++i) { + algorithms.PushBack(StringRef(Algorithm(static_cast(i)).shortName()), allocator); + } + + request.reply().AddMember("algorithms", algorithms, allocator); } for (IApiListener *listener : m_listeners) { From 6eb9d0963b637bdddab1b8e18bed9f73b8c21a20 Mon Sep 17 00:00:00 2001 From: SChernykh Date: Mon, 1 Jul 2019 20:11:51 +0200 Subject: [PATCH 13/65] Integrated RandomX, added RandomXL (Loki) --- CMakeLists.txt | 44 +- cmake/FindRandomX.cmake | 25 - src/base/net/stratum/Pool.cpp | 1 + src/common/xmrig.h | 1 + src/crypto/common/Algorithm.cpp | 2 + src/crypto/randomx/aes_hash.cpp | 214 +++++ src/crypto/randomx/aes_hash.hpp | 40 + src/crypto/randomx/allocator.cpp | 60 ++ src/crypto/randomx/allocator.hpp | 46 + src/crypto/randomx/argon2.h | 229 +++++ src/crypto/randomx/argon2_core.c | 516 ++++++++++ src/crypto/randomx/argon2_core.h | 254 +++++ src/crypto/randomx/argon2_ref.c | 214 +++++ .../randomx/asm/program_epilogue_linux.inc | 10 + .../randomx/asm/program_epilogue_store.inc | 19 + .../randomx/asm/program_epilogue_win64.inc | 24 + src/crypto/randomx/asm/program_loop_load.inc | 32 + src/crypto/randomx/asm/program_loop_store.inc | 19 + .../randomx/asm/program_prologue_linux.inc | 34 + .../randomx/asm/program_prologue_win64.inc | 47 + .../randomx/asm/program_read_dataset.inc | 17 + .../asm/program_read_dataset_sshash_fin.inc | 10 + .../asm/program_read_dataset_sshash_init.inc | 17 + .../randomx/asm/program_sshash_constants.inc | 24 + .../randomx/asm/program_sshash_load.inc | 8 + .../randomx/asm/program_sshash_prefetch.inc | 4 + .../randomx/asm/program_xmm_constants.inc | 6 + src/crypto/randomx/asm/randomx_reciprocal.inc | 7 + src/crypto/randomx/blake2/blake2-impl.h | 76 ++ src/crypto/randomx/blake2/blake2.h | 107 +++ src/crypto/randomx/blake2/blake2b.c | 409 ++++++++ src/crypto/randomx/blake2/blamka-round-ref.h | 73 ++ src/crypto/randomx/blake2/endian.h | 107 +++ src/crypto/randomx/blake2_generator.cpp | 62 ++ src/crypto/randomx/blake2_generator.hpp | 46 + src/crypto/randomx/bytecode_machine.cpp | 482 ++++++++++ src/crypto/randomx/bytecode_machine.hpp | 288 ++++++ src/crypto/randomx/common.hpp | 173 ++++ src/crypto/randomx/configuration.h | 47 + src/crypto/randomx/dataset.cpp | 189 ++++ src/crypto/randomx/dataset.hpp | 80 ++ src/crypto/randomx/instruction.hpp | 102 ++ src/crypto/randomx/instructions_portable.cpp | 193 ++++ src/crypto/randomx/intrin_portable.h | 605 ++++++++++++ src/crypto/randomx/jit_compiler.hpp | 37 + src/crypto/randomx/jit_compiler_a64.hpp | 73 ++ src/crypto/randomx/jit_compiler_fallback.hpp | 73 ++ src/crypto/randomx/jit_compiler_x86.cpp | 774 +++++++++++++++ src/crypto/randomx/jit_compiler_x86.hpp | 141 +++ src/crypto/randomx/jit_compiler_x86_static.S | 208 ++++ .../randomx/jit_compiler_x86_static.asm | 199 ++++ .../randomx/jit_compiler_x86_static.hpp | 48 + src/crypto/randomx/program.hpp | 60 ++ src/crypto/randomx/randomx.cpp | 476 ++++++++++ src/crypto/randomx/randomx.h | 332 +++++++ src/crypto/randomx/reciprocal.c | 80 ++ src/crypto/randomx/reciprocal.h | 48 + src/crypto/randomx/soft_aes.cpp | 364 +++++++ src/crypto/randomx/soft_aes.h | 46 + src/crypto/randomx/superscalar.cpp | 891 ++++++++++++++++++ src/crypto/randomx/superscalar.hpp | 60 ++ src/crypto/randomx/superscalar_program.hpp | 73 ++ src/crypto/randomx/virtual_machine.cpp | 137 +++ src/crypto/randomx/virtual_machine.hpp | 83 ++ src/crypto/randomx/virtual_memory.cpp | 105 +++ src/crypto/randomx/virtual_memory.hpp | 35 + src/crypto/randomx/vm_compiled.cpp | 60 ++ src/crypto/randomx/vm_compiled.hpp | 72 ++ src/crypto/randomx/vm_compiled_light.cpp | 54 ++ src/crypto/randomx/vm_compiled_light.hpp | 64 ++ src/crypto/randomx/vm_interpreted.cpp | 125 +++ src/crypto/randomx/vm_interpreted.hpp | 75 ++ src/crypto/randomx/vm_interpreted_light.cpp | 55 ++ src/crypto/randomx/vm_interpreted_light.hpp | 61 ++ src/workers/CpuThread.cpp | 8 + src/workers/MultiWorker.cpp | 4 +- src/workers/Workers.cpp | 19 +- src/workers/Workers.h | 3 +- 78 files changed, 9870 insertions(+), 36 deletions(-) delete mode 100644 cmake/FindRandomX.cmake create mode 100644 src/crypto/randomx/aes_hash.cpp create mode 100644 src/crypto/randomx/aes_hash.hpp create mode 100644 src/crypto/randomx/allocator.cpp create mode 100644 src/crypto/randomx/allocator.hpp create mode 100644 src/crypto/randomx/argon2.h create mode 100644 src/crypto/randomx/argon2_core.c create mode 100644 src/crypto/randomx/argon2_core.h create mode 100644 src/crypto/randomx/argon2_ref.c create mode 100644 src/crypto/randomx/asm/program_epilogue_linux.inc create mode 100644 src/crypto/randomx/asm/program_epilogue_store.inc create mode 100644 src/crypto/randomx/asm/program_epilogue_win64.inc create mode 100644 src/crypto/randomx/asm/program_loop_load.inc create mode 100644 src/crypto/randomx/asm/program_loop_store.inc create mode 100644 src/crypto/randomx/asm/program_prologue_linux.inc create mode 100644 src/crypto/randomx/asm/program_prologue_win64.inc create mode 100644 src/crypto/randomx/asm/program_read_dataset.inc create mode 100644 src/crypto/randomx/asm/program_read_dataset_sshash_fin.inc create mode 100644 src/crypto/randomx/asm/program_read_dataset_sshash_init.inc create mode 100644 src/crypto/randomx/asm/program_sshash_constants.inc create mode 100644 src/crypto/randomx/asm/program_sshash_load.inc create mode 100644 src/crypto/randomx/asm/program_sshash_prefetch.inc create mode 100644 src/crypto/randomx/asm/program_xmm_constants.inc create mode 100644 src/crypto/randomx/asm/randomx_reciprocal.inc create mode 100644 src/crypto/randomx/blake2/blake2-impl.h create mode 100644 src/crypto/randomx/blake2/blake2.h create mode 100644 src/crypto/randomx/blake2/blake2b.c create mode 100644 src/crypto/randomx/blake2/blamka-round-ref.h create mode 100644 src/crypto/randomx/blake2/endian.h create mode 100644 src/crypto/randomx/blake2_generator.cpp create mode 100644 src/crypto/randomx/blake2_generator.hpp create mode 100644 src/crypto/randomx/bytecode_machine.cpp create mode 100644 src/crypto/randomx/bytecode_machine.hpp create mode 100644 src/crypto/randomx/common.hpp create mode 100644 src/crypto/randomx/configuration.h create mode 100644 src/crypto/randomx/dataset.cpp create mode 100644 src/crypto/randomx/dataset.hpp create mode 100644 src/crypto/randomx/instruction.hpp create mode 100644 src/crypto/randomx/instructions_portable.cpp create mode 100644 src/crypto/randomx/intrin_portable.h create mode 100644 src/crypto/randomx/jit_compiler.hpp create mode 100644 src/crypto/randomx/jit_compiler_a64.hpp create mode 100644 src/crypto/randomx/jit_compiler_fallback.hpp create mode 100644 src/crypto/randomx/jit_compiler_x86.cpp create mode 100644 src/crypto/randomx/jit_compiler_x86.hpp create mode 100644 src/crypto/randomx/jit_compiler_x86_static.S create mode 100644 src/crypto/randomx/jit_compiler_x86_static.asm create mode 100644 src/crypto/randomx/jit_compiler_x86_static.hpp create mode 100644 src/crypto/randomx/program.hpp create mode 100644 src/crypto/randomx/randomx.cpp create mode 100644 src/crypto/randomx/randomx.h create mode 100644 src/crypto/randomx/reciprocal.c create mode 100644 src/crypto/randomx/reciprocal.h create mode 100644 src/crypto/randomx/soft_aes.cpp create mode 100644 src/crypto/randomx/soft_aes.h create mode 100644 src/crypto/randomx/superscalar.cpp create mode 100644 src/crypto/randomx/superscalar.hpp create mode 100644 src/crypto/randomx/superscalar_program.hpp create mode 100644 src/crypto/randomx/virtual_machine.cpp create mode 100644 src/crypto/randomx/virtual_machine.hpp create mode 100644 src/crypto/randomx/virtual_memory.cpp create mode 100644 src/crypto/randomx/virtual_memory.hpp create mode 100644 src/crypto/randomx/vm_compiled.cpp create mode 100644 src/crypto/randomx/vm_compiled.hpp create mode 100644 src/crypto/randomx/vm_compiled_light.cpp create mode 100644 src/crypto/randomx/vm_compiled_light.hpp create mode 100644 src/crypto/randomx/vm_interpreted.cpp create mode 100644 src/crypto/randomx/vm_interpreted.hpp create mode 100644 src/crypto/randomx/vm_interpreted_light.cpp create mode 100644 src/crypto/randomx/vm_interpreted_light.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 697f3da5..57af7068 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,13 +161,45 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") find_package(UV REQUIRED) if (WITH_RANDOMX) - find_package(RandomX REQUIRED) - include_directories(${RANDOMX_INCLUDE_DIR}) - + include_directories(src/crypto/randomx) add_definitions(/DXMRIG_ALGO_RANDOMX) + set(SOURCES_CRYPTO + "${SOURCES_CRYPTO}" + src/crypto/randomx/aes_hash.cpp + src/crypto/randomx/argon2_ref.c + src/crypto/randomx/bytecode_machine.cpp + src/crypto/randomx/dataset.cpp + src/crypto/randomx/soft_aes.cpp + src/crypto/randomx/virtual_memory.cpp + src/crypto/randomx/vm_interpreted.cpp + src/crypto/randomx/allocator.cpp + src/crypto/randomx/randomx.cpp + src/crypto/randomx/superscalar.cpp + src/crypto/randomx/vm_compiled.cpp + src/crypto/randomx/vm_interpreted_light.cpp + src/crypto/randomx/argon2_core.c + src/crypto/randomx/blake2_generator.cpp + src/crypto/randomx/instructions_portable.cpp + src/crypto/randomx/reciprocal.c + src/crypto/randomx/virtual_machine.cpp + src/crypto/randomx/vm_compiled_light.cpp + src/crypto/randomx/blake2/blake2b.c + ) + if (CMAKE_C_COMPILER_ID MATCHES MSVC) + enable_language(ASM_MASM) + list(APPEND SOURCES_CRYPTO + src/crypto/randomx/jit_compiler_x86_static.asm + src/crypto/randomx/jit_compiler_x86.cpp + ) + elseif (ARCH_ID STREQUAL "x86_64" OR ARCH_ID STREQUAL "x86-64" OR ARCH_ID STREQUAL "amd64") + list(APPEND SOURCES_CRYPTO + src/crypto/randomx/jit_compiler_x86_static.S + src/crypto/randomx/jit_compiler_x86.cpp + ) + # cheat because cmake and ccache hate each other + set_property(SOURCE src/crypto/randomx/jit_compiler_x86_static.S PROPERTY LANGUAGE C) + endif() else() - set(RANDOMX_LIBRARIES "") - remove_definitions(/DXMRIG_ALGO_RANDOMX) endif() @@ -241,4 +273,4 @@ if (WITH_DEBUG_LOG) endif() add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTP_SOURCES} ${TLS_SOURCES} ${XMRIG_ASM_SOURCES} ${CN_GPU_SOURCES}) -target_link_libraries(${CMAKE_PROJECT_NAME} ${XMRIG_ASM_LIBRARY} ${OPENSSL_LIBRARIES} ${UV_LIBRARIES} ${RANDOMX_LIBRARIES} ${EXTRA_LIBS} ${CPUID_LIB}) +target_link_libraries(${CMAKE_PROJECT_NAME} ${XMRIG_ASM_LIBRARY} ${OPENSSL_LIBRARIES} ${UV_LIBRARIES} ${EXTRA_LIBS} ${CPUID_LIB}) diff --git a/cmake/FindRandomX.cmake b/cmake/FindRandomX.cmake deleted file mode 100644 index 5696d563..00000000 --- a/cmake/FindRandomX.cmake +++ /dev/null @@ -1,25 +0,0 @@ -find_path( - RANDOMX_INCLUDE_DIR - NAMES randomx.h - PATHS "${XMRIG_DEPS}" ENV "XMRIG_DEPS" - PATH_SUFFIXES "include" - NO_DEFAULT_PATH -) - -find_path(RANDOMX_INCLUDE_DIR NAMES randomx.h) - -find_library( - RANDOMX_LIBRARY - NAMES librandomx.a randomx librandomx - PATHS "${XMRIG_DEPS}" ENV "XMRIG_DEPS" - PATH_SUFFIXES "lib" - NO_DEFAULT_PATH -) - -find_library(RANDOMX_LIBRARY NAMES librandomx.a randomx librandomx) - -set(RANDOMX_LIBRARIES ${RANDOMX_LIBRARY}) -set(RANDOMX_INCLUDE_DIRS ${RANDOMX_INCLUDE_DIR}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(RANDOMX DEFAULT_MSG RANDOMX_LIBRARY RANDOMX_INCLUDE_DIR) diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index d3b4b4a3..7ad4c73a 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -518,6 +518,7 @@ void xmrig::Pool::rebuild() addVariant(VARIANT_ZLS); addVariant(VARIANT_DOUBLE); addVariant(VARIANT_RX_WOW); + addVariant(VARIANT_RX_LOKI); addVariant(VARIANT_AUTO); # endif } diff --git a/src/common/xmrig.h b/src/common/xmrig.h index e8aa505a..cbfe330e 100644 --- a/src/common/xmrig.h +++ b/src/common/xmrig.h @@ -81,6 +81,7 @@ enum Variant { VARIANT_ZLS = 15, // CryptoNight variant 2 with 3/4 iterations (Zelerius) VARIANT_DOUBLE = 16, // CryptoNight variant 2 with double iterations (X-CASH) VARIANT_RX_WOW = 17, // RandomX (Wownero) + VARIANT_RX_LOKI = 18, // RandomX (Loki) VARIANT_MAX }; diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index c706ae0c..42f45b9d 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -72,6 +72,7 @@ static AlgoData const algorithms[] = { # ifdef XMRIG_ALGO_RANDOMX { "randomx/wow", "rx/wow", xmrig::RANDOM_X, xmrig::VARIANT_RX_WOW }, + { "randomx/loki", "rx/loki", xmrig::RANDOM_X, xmrig::VARIANT_RX_LOKI }, { "randomx", "rx", xmrig::RANDOM_X, xmrig::VARIANT_RX_WOW }, # endif @@ -145,6 +146,7 @@ static const char *variants[] = { "zls", "double", "rx/wow", + "rx/loki", }; diff --git a/src/crypto/randomx/aes_hash.cpp b/src/crypto/randomx/aes_hash.cpp new file mode 100644 index 00000000..5d6cb743 --- /dev/null +++ b/src/crypto/randomx/aes_hash.cpp @@ -0,0 +1,214 @@ +/* +Copyright (c) 2018-2019, tevador + +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 "soft_aes.h" +#include "randomx.h" + +#define AES_HASH_1R_STATE0 0xd7983aad, 0xcc82db47, 0x9fa856de, 0x92b52c0d +#define AES_HASH_1R_STATE1 0xace78057, 0xf59e125a, 0x15c7b798, 0x338d996e +#define AES_HASH_1R_STATE2 0xe8a07ce4, 0x5079506b, 0xae62c7d0, 0x6a770017 +#define AES_HASH_1R_STATE3 0x7e994948, 0x79a10005, 0x07ad828d, 0x630a240c + +#define AES_HASH_1R_XKEY0 0x06890201, 0x90dc56bf, 0x8b24949f, 0xf6fa8389 +#define AES_HASH_1R_XKEY1 0xed18f99b, 0xee1043c6, 0x51f4e03c, 0x61b263d1 + +/* + Calculate a 512-bit hash of 'input' using 4 lanes of AES. + The input is treated as a set of round keys for the encryption + of the initial state. + + 'inputSize' must be a multiple of 64. + + For a 2 MiB input, this has the same security as 32768-round + AES encryption. + + Hashing throughput: >20 GiB/s per CPU core with hardware AES +*/ +template +void hashAes1Rx4(const void *input, size_t inputSize, void *hash) { + const uint8_t* inptr = (uint8_t*)input; + const uint8_t* inputEnd = inptr + inputSize; + + rx_vec_i128 state0, state1, state2, state3; + rx_vec_i128 in0, in1, in2, in3; + + //intial state + state0 = rx_set_int_vec_i128(AES_HASH_1R_STATE0); + state1 = rx_set_int_vec_i128(AES_HASH_1R_STATE1); + state2 = rx_set_int_vec_i128(AES_HASH_1R_STATE2); + state3 = rx_set_int_vec_i128(AES_HASH_1R_STATE3); + + //process 64 bytes at a time in 4 lanes + while (inptr < inputEnd) { + in0 = rx_load_vec_i128((rx_vec_i128*)inptr + 0); + in1 = rx_load_vec_i128((rx_vec_i128*)inptr + 1); + in2 = rx_load_vec_i128((rx_vec_i128*)inptr + 2); + in3 = rx_load_vec_i128((rx_vec_i128*)inptr + 3); + + state0 = aesenc(state0, in0); + state1 = aesdec(state1, in1); + state2 = aesenc(state2, in2); + state3 = aesdec(state3, in3); + + inptr += 64; + } + + //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); + + state0 = aesenc(state0, xkey0); + state1 = aesdec(state1, xkey0); + state2 = aesenc(state2, xkey0); + state3 = aesdec(state3, xkey0); + + state0 = aesenc(state0, xkey1); + state1 = aesdec(state1, xkey1); + state2 = aesenc(state2, xkey1); + state3 = aesdec(state3, xkey1); + + //output hash + rx_store_vec_i128((rx_vec_i128*)hash + 0, state0); + rx_store_vec_i128((rx_vec_i128*)hash + 1, state1); + rx_store_vec_i128((rx_vec_i128*)hash + 2, state2); + rx_store_vec_i128((rx_vec_i128*)hash + 3, state3); +} + +template void hashAes1Rx4(const void *input, size_t inputSize, void *hash); +template void hashAes1Rx4(const void *input, size_t inputSize, void *hash); + +#define AES_GEN_1R_KEY0 0xb4f44917, 0xdbb5552b, 0x62716609, 0x6daca553 +#define AES_GEN_1R_KEY1 0x0da1dc4e, 0x1725d378, 0x846a710d, 0x6d7caf07 +#define AES_GEN_1R_KEY2 0x3e20e345, 0xf4c0794f, 0x9f947ec6, 0x3f1262f1 +#define AES_GEN_1R_KEY3 0x49169154, 0x16314c88, 0xb1ba317c, 0x6aef8135 + +/* + Fill 'buffer' with pseudorandom data based on 512-bit 'state'. + The state is encrypted using a single AES round per 16 bytes of output + in 4 lanes. + + 'outputSize' must be a multiple of 64. + + The modified state is written back to 'state' to allow multiple + calls to this function. +*/ +template +void fillAes1Rx4(void *state, size_t outputSize, void *buffer) { + const uint8_t* outptr = (uint8_t*)buffer; + const uint8_t* outputEnd = outptr + outputSize; + + rx_vec_i128 state0, state1, state2, state3; + rx_vec_i128 key0, key1, key2, key3; + + key0 = rx_set_int_vec_i128(AES_GEN_1R_KEY0); + key1 = rx_set_int_vec_i128(AES_GEN_1R_KEY1); + key2 = rx_set_int_vec_i128(AES_GEN_1R_KEY2); + key3 = rx_set_int_vec_i128(AES_GEN_1R_KEY3); + + state0 = rx_load_vec_i128((rx_vec_i128*)state + 0); + state1 = rx_load_vec_i128((rx_vec_i128*)state + 1); + state2 = rx_load_vec_i128((rx_vec_i128*)state + 2); + state3 = rx_load_vec_i128((rx_vec_i128*)state + 3); + + while (outptr < outputEnd) { + state0 = aesdec(state0, key0); + state1 = aesenc(state1, key1); + state2 = aesdec(state2, key2); + state3 = aesenc(state3, key3); + + rx_store_vec_i128((rx_vec_i128*)outptr + 0, state0); + rx_store_vec_i128((rx_vec_i128*)outptr + 1, state1); + rx_store_vec_i128((rx_vec_i128*)outptr + 2, state2); + rx_store_vec_i128((rx_vec_i128*)outptr + 3, state3); + + outptr += 64; + } + + rx_store_vec_i128((rx_vec_i128*)state + 0, state0); + rx_store_vec_i128((rx_vec_i128*)state + 1, state1); + rx_store_vec_i128((rx_vec_i128*)state + 2, state2); + rx_store_vec_i128((rx_vec_i128*)state + 3, state3); +} + +template void fillAes1Rx4(void *state, size_t outputSize, void *buffer); +template void fillAes1Rx4(void *state, size_t outputSize, void *buffer); + +template +void fillAes4Rx4(void *state, size_t outputSize, void *buffer) { + const uint8_t* outptr = (uint8_t*)buffer; + const uint8_t* outputEnd = outptr + outputSize; + + rx_vec_i128 state0, state1, state2, state3; + rx_vec_i128 key0, key1, key2, key3, key4, key5, key6, key7; + + key0 = RandomX_CurrentConfig.fillAes4Rx4_Key[0]; + key1 = RandomX_CurrentConfig.fillAes4Rx4_Key[1]; + key2 = RandomX_CurrentConfig.fillAes4Rx4_Key[2]; + key3 = RandomX_CurrentConfig.fillAes4Rx4_Key[3]; + key4 = RandomX_CurrentConfig.fillAes4Rx4_Key[4]; + key5 = RandomX_CurrentConfig.fillAes4Rx4_Key[5]; + key6 = RandomX_CurrentConfig.fillAes4Rx4_Key[6]; + key7 = RandomX_CurrentConfig.fillAes4Rx4_Key[7]; + + state0 = rx_load_vec_i128((rx_vec_i128*)state + 0); + state1 = rx_load_vec_i128((rx_vec_i128*)state + 1); + state2 = rx_load_vec_i128((rx_vec_i128*)state + 2); + state3 = rx_load_vec_i128((rx_vec_i128*)state + 3); + + while (outptr < outputEnd) { + state0 = aesdec(state0, key0); + state1 = aesenc(state1, key0); + state2 = aesdec(state2, key4); + state3 = aesenc(state3, key4); + + state0 = aesdec(state0, key1); + state1 = aesenc(state1, key1); + state2 = aesdec(state2, key5); + state3 = aesenc(state3, key5); + + state0 = aesdec(state0, key2); + state1 = aesenc(state1, key2); + state2 = aesdec(state2, key6); + state3 = aesenc(state3, key6); + + state0 = aesdec(state0, key3); + state1 = aesenc(state1, key3); + state2 = aesdec(state2, key7); + state3 = aesenc(state3, key7); + + rx_store_vec_i128((rx_vec_i128*)outptr + 0, state0); + rx_store_vec_i128((rx_vec_i128*)outptr + 1, state1); + rx_store_vec_i128((rx_vec_i128*)outptr + 2, state2); + rx_store_vec_i128((rx_vec_i128*)outptr + 3, state3); + + outptr += 64; + } +} + +template void fillAes4Rx4(void *state, size_t outputSize, void *buffer); +template void fillAes4Rx4(void *state, size_t outputSize, void *buffer); diff --git a/src/crypto/randomx/aes_hash.hpp b/src/crypto/randomx/aes_hash.hpp new file mode 100644 index 00000000..b4d0e940 --- /dev/null +++ b/src/crypto/randomx/aes_hash.hpp @@ -0,0 +1,40 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include + +template +void hashAes1Rx4(const void *input, size_t inputSize, void *hash); + +template +void fillAes1Rx4(void *state, size_t outputSize, void *buffer); + +template +void fillAes4Rx4(void *state, size_t outputSize, void *buffer); diff --git a/src/crypto/randomx/allocator.cpp b/src/crypto/randomx/allocator.cpp new file mode 100644 index 00000000..2ddbed98 --- /dev/null +++ b/src/crypto/randomx/allocator.cpp @@ -0,0 +1,60 @@ +/* +Copyright (c) 2018-2019, tevador + +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 +#include "allocator.hpp" +#include "intrin_portable.h" +#include "virtual_memory.hpp" +#include "common.hpp" + +namespace randomx { + + template + void* AlignedAllocator::allocMemory(size_t count) { + void *mem = rx_aligned_alloc(count, alignment); + if (mem == nullptr) + throw std::bad_alloc(); + return mem; + } + + template + void AlignedAllocator::freeMemory(void* ptr, size_t count) { + rx_aligned_free(ptr); + } + + template class AlignedAllocator; + + void* LargePageAllocator::allocMemory(size_t count) { + return allocLargePagesMemory(count); + } + + void LargePageAllocator::freeMemory(void* ptr, size_t count) { + freePagedMemory(ptr, count); + }; + +} \ No newline at end of file diff --git a/src/crypto/randomx/allocator.hpp b/src/crypto/randomx/allocator.hpp new file mode 100644 index 00000000..d7aa3f95 --- /dev/null +++ b/src/crypto/randomx/allocator.hpp @@ -0,0 +1,46 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include + +namespace randomx { + + template + struct AlignedAllocator { + static void* allocMemory(size_t); + static void freeMemory(void*, size_t); + }; + + struct LargePageAllocator { + static void* allocMemory(size_t); + static void freeMemory(void*, size_t); + }; + +} \ No newline at end of file diff --git a/src/crypto/randomx/argon2.h b/src/crypto/randomx/argon2.h new file mode 100644 index 00000000..9d427159 --- /dev/null +++ b/src/crypto/randomx/argon2.h @@ -0,0 +1,229 @@ +/* +Copyright (c) 2018-2019, tevador + +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. +*/ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +#pragma once + +#include +#include +#include + +/* + * Argon2 input parameter restrictions + */ + + /* Minimum and maximum number of lanes (degree of parallelism) */ +#define ARGON2_MIN_LANES UINT32_C(1) +#define ARGON2_MAX_LANES UINT32_C(0xFFFFFF) + +/* Minimum and maximum number of threads */ +#define ARGON2_MIN_THREADS UINT32_C(1) +#define ARGON2_MAX_THREADS UINT32_C(0xFFFFFF) + +/* Number of synchronization points between lanes per pass */ +#define ARGON2_SYNC_POINTS UINT32_C(4) + +/* Minimum and maximum digest size in bytes */ +#define ARGON2_MIN_OUTLEN UINT32_C(4) +#define ARGON2_MAX_OUTLEN UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */ +#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */ + +#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b)) +/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */ +#define ARGON2_MAX_MEMORY_BITS \ + ARGON2_MIN(UINT32_C(32), (sizeof(void *) * CHAR_BIT - 10 - 1)) +#define ARGON2_MAX_MEMORY \ + ARGON2_MIN(UINT32_C(0xFFFFFFFF), UINT64_C(1) << ARGON2_MAX_MEMORY_BITS) + +/* Minimum and maximum number of passes */ +#define ARGON2_MIN_TIME UINT32_C(1) +#define ARGON2_MAX_TIME UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum password length in bytes */ +#define ARGON2_MIN_PWD_LENGTH UINT32_C(0) +#define ARGON2_MAX_PWD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum associated data length in bytes */ +#define ARGON2_MIN_AD_LENGTH UINT32_C(0) +#define ARGON2_MAX_AD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum salt length in bytes */ +#define ARGON2_MIN_SALT_LENGTH UINT32_C(8) +#define ARGON2_MAX_SALT_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum key length in bytes */ +#define ARGON2_MIN_SECRET UINT32_C(0) +#define ARGON2_MAX_SECRET UINT32_C(0xFFFFFFFF) + +/* Flags to determine which fields are securely wiped (default = no wipe). */ +#define ARGON2_DEFAULT_FLAGS UINT32_C(0) +#define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0) +#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1) + + +/* Error codes */ +typedef enum Argon2_ErrorCodes { + ARGON2_OK = 0, + + ARGON2_OUTPUT_PTR_NULL = -1, + + ARGON2_OUTPUT_TOO_SHORT = -2, + ARGON2_OUTPUT_TOO_LONG = -3, + + ARGON2_PWD_TOO_SHORT = -4, + ARGON2_PWD_TOO_LONG = -5, + + ARGON2_SALT_TOO_SHORT = -6, + ARGON2_SALT_TOO_LONG = -7, + + ARGON2_AD_TOO_SHORT = -8, + ARGON2_AD_TOO_LONG = -9, + + ARGON2_SECRET_TOO_SHORT = -10, + ARGON2_SECRET_TOO_LONG = -11, + + ARGON2_TIME_TOO_SMALL = -12, + ARGON2_TIME_TOO_LARGE = -13, + + ARGON2_MEMORY_TOO_LITTLE = -14, + ARGON2_MEMORY_TOO_MUCH = -15, + + ARGON2_LANES_TOO_FEW = -16, + ARGON2_LANES_TOO_MANY = -17, + + ARGON2_PWD_PTR_MISMATCH = -18, /* NULL ptr with non-zero length */ + ARGON2_SALT_PTR_MISMATCH = -19, /* NULL ptr with non-zero length */ + ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */ + ARGON2_AD_PTR_MISMATCH = -21, /* NULL ptr with non-zero length */ + + ARGON2_MEMORY_ALLOCATION_ERROR = -22, + + ARGON2_FREE_MEMORY_CBK_NULL = -23, + ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24, + + ARGON2_INCORRECT_PARAMETER = -25, + ARGON2_INCORRECT_TYPE = -26, + + ARGON2_OUT_PTR_MISMATCH = -27, + + ARGON2_THREADS_TOO_FEW = -28, + ARGON2_THREADS_TOO_MANY = -29, + + ARGON2_MISSING_ARGS = -30, + + ARGON2_ENCODING_FAIL = -31, + + ARGON2_DECODING_FAIL = -32, + + ARGON2_THREAD_FAIL = -33, + + ARGON2_DECODING_LENGTH_FAIL = -34, + + ARGON2_VERIFY_MISMATCH = -35 +} argon2_error_codes; + +/* Memory allocator types --- for external allocation */ +typedef int(*allocate_fptr)(uint8_t **memory, size_t bytes_to_allocate); +typedef void(*deallocate_fptr)(uint8_t *memory, size_t bytes_to_allocate); + +/* Argon2 external data structures */ + +/* + ***** + * Context: structure to hold Argon2 inputs: + * output array and its length, + * password and its length, + * salt and its length, + * secret and its length, + * associated data and its length, + * number of passes, amount of used memory (in KBytes, can be rounded up a bit) + * number of parallel threads that will be run. + * All the parameters above affect the output hash value. + * Additionally, two function pointers can be provided to allocate and + * deallocate the memory (if NULL, memory will be allocated internally). + * Also, three flags indicate whether to erase password, secret as soon as they + * are pre-hashed (and thus not needed anymore), and the entire memory + ***** + * Simplest situation: you have output array out[8], password is stored in + * pwd[32], salt is stored in salt[16], you do not have keys nor associated + * data. You need to spend 1 GB of RAM and you run 5 passes of Argon2d with + * 4 parallel lanes. + * You want to erase the password, but you're OK with last pass not being + * erased. You want to use the default memory allocator. + * Then you initialize: + Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false) + */ +typedef struct Argon2_Context { + uint8_t *out; /* output array */ + uint32_t outlen; /* digest length */ + + uint8_t *pwd; /* password array */ + uint32_t pwdlen; /* password length */ + + uint8_t *salt; /* salt array */ + uint32_t saltlen; /* salt length */ + + uint8_t *secret; /* key array */ + uint32_t secretlen; /* key length */ + + uint8_t *ad; /* associated data array */ + uint32_t adlen; /* associated data length */ + + uint32_t t_cost; /* number of passes */ + uint32_t m_cost; /* amount of memory requested (KB) */ + uint32_t lanes; /* number of lanes */ + uint32_t threads; /* maximum number of threads */ + + uint32_t version; /* version number */ + + allocate_fptr allocate_cbk; /* pointer to memory allocator */ + deallocate_fptr free_cbk; /* pointer to memory deallocator */ + + uint32_t flags; /* array of bool options */ +} argon2_context; + +/* Argon2 primitive type */ +typedef enum Argon2_type { + Argon2_d = 0, + Argon2_i = 1, + Argon2_id = 2 +} argon2_type; + +/* Version of the algorithm */ +typedef enum Argon2_version { + ARGON2_VERSION_10 = 0x10, + ARGON2_VERSION_13 = 0x13, + ARGON2_VERSION_NUMBER = ARGON2_VERSION_13 +} argon2_version; diff --git a/src/crypto/randomx/argon2_core.c b/src/crypto/randomx/argon2_core.c new file mode 100644 index 00000000..e9174222 --- /dev/null +++ b/src/crypto/randomx/argon2_core.c @@ -0,0 +1,516 @@ +/* +Copyright (c) 2018-2019, tevador + +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. +*/ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + + /*For memory wiping*/ +#ifdef _MSC_VER +#include +#include /* For SecureZeroMemory */ +#endif +#if defined __STDC_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 +#endif +#define VC_GE_2005(version) (version >= 1400) + +#include +#include +#include + +#include "argon2_core.h" +#include "blake2/blake2.h" +#include "blake2/blake2-impl.h" + +#ifdef GENKAT +#include "genkat.h" +#endif + +#if defined(__clang__) +#if __has_attribute(optnone) +#define NOT_OPTIMIZED __attribute__((optnone)) +#endif +#elif defined(__GNUC__) +#define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if GCC_VERSION >= 40400 +#define NOT_OPTIMIZED __attribute__((optimize("O0"))) +#endif +#endif +#ifndef NOT_OPTIMIZED +#define NOT_OPTIMIZED +#endif + +/***************Instance and Position constructors**********/ +void rxa2_init_block_value(block *b, uint8_t in) { memset(b->v, in, sizeof(b->v)); } + +void rxa2_copy_block(block *dst, const block *src) { + memcpy(dst->v, src->v, sizeof(uint64_t) * ARGON2_QWORDS_IN_BLOCK); +} + +void rxa2_xor_block(block *dst, const block *src) { + int i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] ^= src->v[i]; + } +} + +static void load_block(block *dst, const void *input) { + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] = load64((const uint8_t *)input + i * sizeof(dst->v[i])); + } +} + +static void store_block(void *output, const block *src) { + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]); + } +} + +/***************Memory functions*****************/ + +int rxa2_allocate_memory(const argon2_context *context, uint8_t **memory, + size_t num, size_t size) { + size_t memory_size = num * size; + if (memory == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + /* 1. Check for multiplication overflow */ + if (size != 0 && memory_size / size != num) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + /* 2. Try to allocate with appropriate allocator */ + if (context->allocate_cbk) { + (context->allocate_cbk)(memory, memory_size); + } + else { + *memory = (uint8_t*)malloc(memory_size); + } + + if (*memory == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + return ARGON2_OK; +} + +void rxa2_free_memory(const argon2_context *context, uint8_t *memory, + size_t num, size_t size) { + size_t memory_size = num * size; + rxa2_clear_internal_memory(memory, memory_size); + if (context->free_cbk) { + (context->free_cbk)(memory, memory_size); + } + else { + free(memory); + } +} + +void NOT_OPTIMIZED rxa2_secure_wipe_memory(void *v, size_t n) { +#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER) + SecureZeroMemory(v, n); +#elif defined memset_s + memset_s(v, n, 0, n); +#elif defined(__OpenBSD__) + explicit_bzero(v, n); +#else + static void *(*const volatile memset_sec)(void *, int, size_t) = &memset; + memset_sec(v, 0, n); +#endif +} + +/* Memory clear flag defaults to true. */ +#define FLAG_clear_internal_memory 0 +void rxa2_clear_internal_memory(void *v, size_t n) { + if (FLAG_clear_internal_memory && v) { + rxa2_secure_wipe_memory(v, n); + } +} + +uint32_t rxa2_index_alpha(const argon2_instance_t *instance, + const argon2_position_t *position, uint32_t pseudo_rand, + int same_lane) { + /* + * Pass 0: + * This lane : all already finished segments plus already constructed + * blocks in this segment + * Other lanes : all already finished segments + * Pass 1+: + * This lane : (SYNC_POINTS - 1) last segments plus already constructed + * blocks in this segment + * Other lanes : (SYNC_POINTS - 1) last segments + */ + uint32_t reference_area_size; + uint64_t relative_position; + uint32_t start_position, absolute_position; + + if (0 == position->pass) { + /* First pass */ + if (0 == position->slice) { + /* First slice */ + reference_area_size = + position->index - 1; /* all but the previous */ + } + else { + if (same_lane) { + /* The same lane => add current segment */ + reference_area_size = + position->slice * instance->segment_length + + position->index - 1; + } + else { + reference_area_size = + position->slice * instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + } + else { + /* Second pass */ + if (same_lane) { + reference_area_size = instance->lane_length - + instance->segment_length + position->index - + 1; + } + else { + reference_area_size = instance->lane_length - + instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + + /* 1.2.4. Mapping pseudo_rand to 0.. and produce + * relative position */ + relative_position = pseudo_rand; + relative_position = relative_position * relative_position >> 32; + relative_position = reference_area_size - 1 - + (reference_area_size * relative_position >> 32); + + /* 1.2.5 Computing starting position */ + start_position = 0; + + if (0 != position->pass) { + start_position = (position->slice == ARGON2_SYNC_POINTS - 1) + ? 0 + : (position->slice + 1) * instance->segment_length; + } + + /* 1.2.6. Computing absolute position */ + absolute_position = (start_position + relative_position) % + instance->lane_length; /* absolute position */ + return absolute_position; +} + +/* Single-threaded version for p=1 case */ +static int fill_memory_blocks_st(argon2_instance_t *instance) { + uint32_t r, s, l; + + for (r = 0; r < instance->passes; ++r) { + for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { + for (l = 0; l < instance->lanes; ++l) { + argon2_position_t position = { r, l, (uint8_t)s, 0 }; + rxa2_fill_segment(instance, position); + } + } +#ifdef GENKAT + internal_kat(instance, r); /* Print all memory blocks */ +#endif + } + return ARGON2_OK; +} + +int rxa2_fill_memory_blocks(argon2_instance_t *instance) { + if (instance == NULL || instance->lanes == 0) { + return ARGON2_INCORRECT_PARAMETER; + } + return fill_memory_blocks_st(instance); +} + +int rxa2_validate_inputs(const argon2_context *context) { + if (NULL == context) { + return ARGON2_INCORRECT_PARAMETER; + } + + if (NULL == context->out) { + return ARGON2_OUTPUT_PTR_NULL; + } + + /* Validate output length */ + if (ARGON2_MIN_OUTLEN > context->outlen) { + return ARGON2_OUTPUT_TOO_SHORT; + } + + if (ARGON2_MAX_OUTLEN < context->outlen) { + return ARGON2_OUTPUT_TOO_LONG; + } + + /* Validate password (required param) */ + if (NULL == context->pwd) { + if (0 != context->pwdlen) { + return ARGON2_PWD_PTR_MISMATCH; + } + } + + if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) { + return ARGON2_PWD_TOO_SHORT; + } + + if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) { + return ARGON2_PWD_TOO_LONG; + } + + /* Validate salt (required param) */ + if (NULL == context->salt) { + if (0 != context->saltlen) { + return ARGON2_SALT_PTR_MISMATCH; + } + } + + if (ARGON2_MIN_SALT_LENGTH > context->saltlen) { + return ARGON2_SALT_TOO_SHORT; + } + + if (ARGON2_MAX_SALT_LENGTH < context->saltlen) { + return ARGON2_SALT_TOO_LONG; + } + + /* Validate secret (optional param) */ + if (NULL == context->secret) { + if (0 != context->secretlen) { + return ARGON2_SECRET_PTR_MISMATCH; + } + } + else { + if (ARGON2_MIN_SECRET > context->secretlen) { + return ARGON2_SECRET_TOO_SHORT; + } + if (ARGON2_MAX_SECRET < context->secretlen) { + return ARGON2_SECRET_TOO_LONG; + } + } + + /* Validate associated data (optional param) */ + if (NULL == context->ad) { + if (0 != context->adlen) { + return ARGON2_AD_PTR_MISMATCH; + } + } + else { + if (ARGON2_MIN_AD_LENGTH > context->adlen) { + return ARGON2_AD_TOO_SHORT; + } + if (ARGON2_MAX_AD_LENGTH < context->adlen) { + return ARGON2_AD_TOO_LONG; + } + } + + /* Validate memory cost */ + if (ARGON2_MIN_MEMORY > context->m_cost) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + if (ARGON2_MAX_MEMORY < context->m_cost) { + return ARGON2_MEMORY_TOO_MUCH; + } + + if (context->m_cost < 8 * context->lanes) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + /* Validate time cost */ + if (ARGON2_MIN_TIME > context->t_cost) { + return ARGON2_TIME_TOO_SMALL; + } + + if (ARGON2_MAX_TIME < context->t_cost) { + return ARGON2_TIME_TOO_LARGE; + } + + /* Validate lanes */ + if (ARGON2_MIN_LANES > context->lanes) { + return ARGON2_LANES_TOO_FEW; + } + + if (ARGON2_MAX_LANES < context->lanes) { + return ARGON2_LANES_TOO_MANY; + } + + /* Validate threads */ + if (ARGON2_MIN_THREADS > context->threads) { + return ARGON2_THREADS_TOO_FEW; + } + + if (ARGON2_MAX_THREADS < context->threads) { + return ARGON2_THREADS_TOO_MANY; + } + + if (NULL != context->allocate_cbk && NULL == context->free_cbk) { + return ARGON2_FREE_MEMORY_CBK_NULL; + } + + if (NULL == context->allocate_cbk && NULL != context->free_cbk) { + return ARGON2_ALLOCATE_MEMORY_CBK_NULL; + } + + return ARGON2_OK; +} + +void rxa2_fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance) { + uint32_t l; + /* Make the first and second block in each lane as G(H0||0||i) or + G(H0||1||i) */ + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + for (l = 0; l < instance->lanes; ++l) { + + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0); + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); + rxa2_blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->memory[l * instance->lane_length + 0], + blockhash_bytes); + + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1); + rxa2_blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->memory[l * instance->lane_length + 1], + blockhash_bytes); + } + rxa2_clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE); +} + +void rxa2_initial_hash(uint8_t *blockhash, argon2_context *context, argon2_type type) { + blake2b_state BlakeHash; + uint8_t value[sizeof(uint32_t)]; + + if (NULL == context || NULL == blockhash) { + return; + } + + blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH); + + store32(&value, context->lanes); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->outlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->m_cost); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->t_cost); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->version); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, (uint32_t)type); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->pwdlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->pwd != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->pwd, + context->pwdlen); + + if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) { + rxa2_secure_wipe_memory(context->pwd, context->pwdlen); + context->pwdlen = 0; + } + } + + store32(&value, context->saltlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->salt != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->salt, context->saltlen); + } + + store32(&value, context->secretlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->secret != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->secret, + context->secretlen); + + if (context->flags & ARGON2_FLAG_CLEAR_SECRET) { + rxa2_secure_wipe_memory(context->secret, context->secretlen); + context->secretlen = 0; + } + } + + store32(&value, context->adlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->ad != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->ad, + context->adlen); + } + + blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH); +} + +int rxa2_argon_initialize(argon2_instance_t *instance, argon2_context *context) { + uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; + int result = ARGON2_OK; + + if (instance == NULL || context == NULL) + return ARGON2_INCORRECT_PARAMETER; + instance->context_ptr = context; + + /* 1. Memory allocation */ + /*result = allocate_memory(context, (uint8_t **)&(instance->memory), instance->memory_blocks, sizeof(block)); + if (result != ARGON2_OK) { + return result; + }*/ + + /* 2. Initial hashing */ + /* H_0 + 8 extra bytes to produce the first blocks */ + /* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */ + /* Hashing all inputs */ + rxa2_initial_hash(blockhash, context, instance->type); + /* Zeroing 8 extra bytes */ + rxa2_clear_internal_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, + ARGON2_PREHASH_SEED_LENGTH - + ARGON2_PREHASH_DIGEST_LENGTH); + + /* 3. Creating first blocks, we always have at least two blocks in a slice + */ + rxa2_fill_first_blocks(blockhash, instance); + /* Clearing the hash */ + rxa2_clear_internal_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH); + + return ARGON2_OK; +} diff --git a/src/crypto/randomx/argon2_core.h b/src/crypto/randomx/argon2_core.h new file mode 100644 index 00000000..efd56d99 --- /dev/null +++ b/src/crypto/randomx/argon2_core.h @@ -0,0 +1,254 @@ +/* +Copyright (c) 2018-2019, tevador + +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. +*/ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +#ifndef ARGON2_CORE_H +#define ARGON2_CORE_H + +#include +#include "argon2.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#define CONST_CAST(x) (x)(uintptr_t) + + /**********************Argon2 internal constants*******************************/ + +enum argon2_core_constants { + /* Memory block size in bytes */ + ARGON2_BLOCK_SIZE = 1024, + ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8, + ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16, + ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32, + ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64, + + /* Number of pseudo-random values generated by one call to Blake in Argon2i + to + generate reference block positions */ + ARGON2_ADDRESSES_IN_BLOCK = 128, + + /* Pre-hashing digest length and its extension*/ + ARGON2_PREHASH_DIGEST_LENGTH = 64, + ARGON2_PREHASH_SEED_LENGTH = 72 +}; + +/*************************Argon2 internal data types***********************/ + +/* + * Structure for the (1KB) memory block implemented as 128 64-bit words. + * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no + * bounds checking). + */ +typedef struct block_ { uint64_t v[ARGON2_QWORDS_IN_BLOCK]; } block; + +/*****************Functions that work with the block******************/ + +/* Initialize each byte of the block with @in */ +void rxa2_init_block_value(block *b, uint8_t in); + +/* Copy block @src to block @dst */ +void rxa2_copy_block(block *dst, const block *src); + +/* XOR @src onto @dst bytewise */ +void rxa2_xor_block(block *dst, const block *src); + +/* + * Argon2 instance: memory pointer, number of passes, amount of memory, type, + * and derived values. + * Used to evaluate the number and location of blocks to construct in each + * thread + */ +typedef struct Argon2_instance_t { + block *memory; /* Memory pointer */ + uint32_t version; + uint32_t passes; /* Number of passes */ + uint32_t memory_blocks; /* Number of blocks in memory */ + uint32_t segment_length; + uint32_t lane_length; + uint32_t lanes; + uint32_t threads; + argon2_type type; + int print_internals; /* whether to print the memory blocks */ + argon2_context *context_ptr; /* points back to original context */ +} argon2_instance_t; + +/* + * Argon2 position: where we construct the block right now. Used to distribute + * work between threads. + */ +typedef struct Argon2_position_t { + uint32_t pass; + uint32_t lane; + uint8_t slice; + uint32_t index; +} argon2_position_t; + +/*Struct that holds the inputs for thread handling FillSegment*/ +typedef struct Argon2_thread_data { + argon2_instance_t *instance_ptr; + argon2_position_t pos; +} argon2_thread_data; + +/*************************Argon2 core functions********************************/ + +/* Allocates memory to the given pointer, uses the appropriate allocator as + * specified in the context. Total allocated memory is num*size. + * @param context argon2_context which specifies the allocator + * @param memory pointer to the pointer to the memory + * @param size the size in bytes for each element to be allocated + * @param num the number of elements to be allocated + * @return ARGON2_OK if @memory is a valid pointer and memory is allocated + */ +int rxa2_allocate_memory(const argon2_context *context, uint8_t **memory, + size_t num, size_t size); + +/* + * Frees memory at the given pointer, uses the appropriate deallocator as + * specified in the context. Also cleans the memory using clear_internal_memory. + * @param context argon2_context which specifies the deallocator + * @param memory pointer to buffer to be freed + * @param size the size in bytes for each element to be deallocated + * @param num the number of elements to be deallocated + */ +void rxa2_free_memory(const argon2_context *context, uint8_t *memory, + size_t num, size_t size); + +/* Function that securely cleans the memory. This ignores any flags set + * regarding clearing memory. Usually one just calls clear_internal_memory. + * @param mem Pointer to the memory + * @param s Memory size in bytes + */ +void rxa2_secure_wipe_memory(void *v, size_t n); + +/* Function that securely clears the memory if FLAG_clear_internal_memory is + * set. If the flag isn't set, this function does nothing. + * @param mem Pointer to the memory + * @param s Memory size in bytes + */ +void rxa2_clear_internal_memory(void *v, size_t n); + +/* + * Computes absolute position of reference block in the lane following a skewed + * distribution and using a pseudo-random value as input + * @param instance Pointer to the current instance + * @param position Pointer to the current position + * @param pseudo_rand 32-bit pseudo-random value used to determine the position + * @param same_lane Indicates if the block will be taken from the current lane. + * If so we can reference the current segment + * @pre All pointers must be valid + */ +uint32_t rxa2_index_alpha(const argon2_instance_t *instance, + const argon2_position_t *position, uint32_t pseudo_rand, + int same_lane); + +/* + * Function that validates all inputs against predefined restrictions and return + * an error code + * @param context Pointer to current Argon2 context + * @return ARGON2_OK if everything is all right, otherwise one of error codes + * (all defined in + */ +int rxa2_validate_inputs(const argon2_context *context); + +/* + * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears + * password and secret if needed + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param blockhash Buffer for pre-hashing digest + * @param type Argon2 type + * @pre @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes + * allocated + */ +void rxa2_initial_hash(uint8_t *blockhash, argon2_context *context, + argon2_type type); + +/* + * Function creates first 2 blocks per lane + * @param instance Pointer to the current instance + * @param blockhash Pointer to the pre-hashing digest + * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values + */ +void rxa2_fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance); + +/* + * Function allocates memory, hashes the inputs with Blake, and creates first + * two blocks. Returns the pointer to the main memory with 2 blocks per lane + * initialized + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param instance Current Argon2 instance + * @return Zero if successful, -1 if memory failed to allocate. @context->state + * will be modified if successful. + */ +int rxa2_argon_initialize(argon2_instance_t *instance, argon2_context *context); + +/* + * XORing the last block of each lane, hashing it, making the tag. Deallocates + * the memory. + * @param context Pointer to current Argon2 context (use only the out parameters + * from it) + * @param instance Pointer to current instance of Argon2 + * @pre instance->state must point to necessary amount of memory + * @pre context->out must point to outlen bytes of memory + * @pre if context->free_cbk is not NULL, it should point to a function that + * deallocates memory + */ +void rxa2_finalize(const argon2_context *context, argon2_instance_t *instance); + +/* + * Function that fills the segment using previous segments also from other + * threads + * @param context current context + * @param instance Pointer to the current instance + * @param position Current position + * @pre all block pointers must be valid + */ +void rxa2_fill_segment(const argon2_instance_t *instance, + argon2_position_t position); + +/* + * Function that fills the entire memory t_cost times based on the first two + * blocks in each lane + * @param instance Pointer to the current instance + * @return ARGON2_OK if successful, @context->state + */ +int rxa2_fill_memory_blocks(argon2_instance_t *instance); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/src/crypto/randomx/argon2_ref.c b/src/crypto/randomx/argon2_ref.c new file mode 100644 index 00000000..018b985b --- /dev/null +++ b/src/crypto/randomx/argon2_ref.c @@ -0,0 +1,214 @@ +/* +Copyright (c) 2018-2019, tevador + +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. +*/ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +#include +#include +#include + +#include "argon2.h" +#include "argon2_core.h" + +#include "blake2/blamka-round-ref.h" +#include "blake2/blake2-impl.h" +#include "blake2/blake2.h" + + /* + * Function fills a new memory block and optionally XORs the old block over the new one. + * @next_block must be initialized. + * @param prev_block Pointer to the previous block + * @param ref_block Pointer to the reference block + * @param next_block Pointer to the block to be constructed + * @param with_xor Whether to XOR into the new block (1) or just overwrite (0) + * @pre all block pointers must be valid + */ +static void fill_block(const block *prev_block, const block *ref_block, + block *next_block, int with_xor) { + block blockR, block_tmp; + unsigned i; + + rxa2_copy_block(&blockR, ref_block); + rxa2_xor_block(&blockR, prev_block); + rxa2_copy_block(&block_tmp, &blockR); + /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */ + if (with_xor) { + /* Saving the next block contents for XOR over: */ + rxa2_xor_block(&block_tmp, next_block); + /* Now blockR = ref_block + prev_block and + block_tmp = ref_block + prev_block + next_block */ + } + + /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then + (16,17,..31)... finally (112,113,...127) */ + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND_NOMSG( + blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], + blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], + blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], + blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], + blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], + blockR.v[16 * i + 15]); + } + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + for (i = 0; i < 8; i++) { + BLAKE2_ROUND_NOMSG( + blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], + blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], + blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], + blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], + blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], + blockR.v[2 * i + 113]); + } + + rxa2_copy_block(next_block, &block_tmp); + rxa2_xor_block(next_block, &blockR); +} + +static void next_addresses(block *address_block, block *input_block, + const block *zero_block) { + input_block->v[6]++; + fill_block(zero_block, input_block, address_block, 0); + fill_block(zero_block, address_block, address_block, 0); +} + +void rxa2_fill_segment(const argon2_instance_t *instance, + argon2_position_t position) { + block *ref_block = NULL, *curr_block = NULL; + block address_block, input_block, zero_block; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index; + uint32_t i; + int data_independent_addressing; + + if (instance == NULL) { + return; + } + + data_independent_addressing = + (instance->type == Argon2_i) || + (instance->type == Argon2_id && (position.pass == 0) && + (position.slice < ARGON2_SYNC_POINTS / 2)); + + if (data_independent_addressing) { + rxa2_init_block_value(&zero_block, 0); + rxa2_init_block_value(&input_block, 0); + + input_block.v[0] = position.pass; + input_block.v[1] = position.lane; + input_block.v[2] = position.slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + + /* Don't forget to generate the first block of addresses: */ + if (data_independent_addressing) { + next_addresses(&address_block, &input_block, &zero_block); + } + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } + else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + next_addresses(&address_block, &input_block, &zero_block); + } + pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } + else { + pseudo_rand = instance->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = rxa2_index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = + instance->memory + instance->lane_length * ref_lane + ref_index; + curr_block = instance->memory + curr_offset; + if (ARGON2_VERSION_10 == instance->version) { + /* version 1.2.1 and earlier: overwrite, not XOR */ + fill_block(instance->memory + prev_offset, ref_block, curr_block, 0); + } + else { + if (0 == position.pass) { + fill_block(instance->memory + prev_offset, ref_block, + curr_block, 0); + } + else { + fill_block(instance->memory + prev_offset, ref_block, + curr_block, 1); + } + } + } +} diff --git a/src/crypto/randomx/asm/program_epilogue_linux.inc b/src/crypto/randomx/asm/program_epilogue_linux.inc new file mode 100644 index 00000000..eaacae54 --- /dev/null +++ b/src/crypto/randomx/asm/program_epilogue_linux.inc @@ -0,0 +1,10 @@ + ;# restore callee-saved registers - System V AMD64 ABI + pop r15 + pop r14 + pop r13 + pop r12 + pop rbp + pop rbx + + ;# program finished + ret 0 \ No newline at end of file diff --git a/src/crypto/randomx/asm/program_epilogue_store.inc b/src/crypto/randomx/asm/program_epilogue_store.inc new file mode 100644 index 00000000..b94fa4d9 --- /dev/null +++ b/src/crypto/randomx/asm/program_epilogue_store.inc @@ -0,0 +1,19 @@ + ;# save VM register values + pop rcx + mov qword ptr [rcx+0], r8 + mov qword ptr [rcx+8], r9 + mov qword ptr [rcx+16], r10 + mov qword ptr [rcx+24], r11 + mov qword ptr [rcx+32], r12 + mov qword ptr [rcx+40], r13 + mov qword ptr [rcx+48], r14 + mov qword ptr [rcx+56], r15 + movdqa xmmword ptr [rcx+64], xmm0 + movdqa xmmword ptr [rcx+80], xmm1 + movdqa xmmword ptr [rcx+96], xmm2 + movdqa xmmword ptr [rcx+112], xmm3 + lea rcx, [rcx+64] + movdqa xmmword ptr [rcx+64], xmm4 + movdqa xmmword ptr [rcx+80], xmm5 + movdqa xmmword ptr [rcx+96], xmm6 + movdqa xmmword ptr [rcx+112], xmm7 \ No newline at end of file diff --git a/src/crypto/randomx/asm/program_epilogue_win64.inc b/src/crypto/randomx/asm/program_epilogue_win64.inc new file mode 100644 index 00000000..8d70a0a3 --- /dev/null +++ b/src/crypto/randomx/asm/program_epilogue_win64.inc @@ -0,0 +1,24 @@ + ;# restore callee-saved registers - Microsoft x64 calling convention + movdqu xmm15, xmmword ptr [rsp] + movdqu xmm14, xmmword ptr [rsp+16] + movdqu xmm13, xmmword ptr [rsp+32] + movdqu xmm12, xmmword ptr [rsp+48] + movdqu xmm11, xmmword ptr [rsp+64] + add rsp, 80 + movdqu xmm10, xmmword ptr [rsp] + movdqu xmm9, xmmword ptr [rsp+16] + movdqu xmm8, xmmword ptr [rsp+32] + movdqu xmm7, xmmword ptr [rsp+48] + movdqu xmm6, xmmword ptr [rsp+64] + add rsp, 80 + pop r15 + pop r14 + pop r13 + pop r12 + pop rsi + pop rdi + pop rbp + pop rbx + + ;# program finished + ret diff --git a/src/crypto/randomx/asm/program_loop_load.inc b/src/crypto/randomx/asm/program_loop_load.inc new file mode 100644 index 00000000..374af66a --- /dev/null +++ b/src/crypto/randomx/asm/program_loop_load.inc @@ -0,0 +1,32 @@ + mov rdx, rax + and eax, RANDOMX_SCRATCHPAD_MASK + lea rcx, [rsi+rax] + push rcx + xor r8, qword ptr [rcx+0] + xor r9, qword ptr [rcx+8] + xor r10, qword ptr [rcx+16] + xor r11, qword ptr [rcx+24] + xor r12, qword ptr [rcx+32] + xor r13, qword ptr [rcx+40] + xor r14, qword ptr [rcx+48] + xor r15, qword ptr [rcx+56] + ror rdx, 32 + and edx, RANDOMX_SCRATCHPAD_MASK + lea rcx, [rsi+rdx] + push rcx + cvtdq2pd xmm0, qword ptr [rcx+0] + cvtdq2pd xmm1, qword ptr [rcx+8] + cvtdq2pd xmm2, qword ptr [rcx+16] + cvtdq2pd xmm3, qword ptr [rcx+24] + cvtdq2pd xmm4, qword ptr [rcx+32] + cvtdq2pd xmm5, qword ptr [rcx+40] + cvtdq2pd xmm6, qword ptr [rcx+48] + cvtdq2pd xmm7, qword ptr [rcx+56] + andps xmm4, xmm13 + andps xmm5, xmm13 + andps xmm6, xmm13 + andps xmm7, xmm13 + orps xmm4, xmm14 + orps xmm5, xmm14 + orps xmm6, xmm14 + orps xmm7, xmm14 diff --git a/src/crypto/randomx/asm/program_loop_store.inc b/src/crypto/randomx/asm/program_loop_store.inc new file mode 100644 index 00000000..53164cb0 --- /dev/null +++ b/src/crypto/randomx/asm/program_loop_store.inc @@ -0,0 +1,19 @@ + xor eax, eax + pop rcx + mov qword ptr [rcx+0], r8 + mov qword ptr [rcx+8], r9 + mov qword ptr [rcx+16], r10 + mov qword ptr [rcx+24], r11 + mov qword ptr [rcx+32], r12 + mov qword ptr [rcx+40], r13 + mov qword ptr [rcx+48], r14 + mov qword ptr [rcx+56], r15 + pop rcx + xorpd xmm0, xmm4 + xorpd xmm1, xmm5 + xorpd xmm2, xmm6 + xorpd xmm3, xmm7 + movapd xmmword ptr [rcx+0], xmm0 + movapd xmmword ptr [rcx+16], xmm1 + movapd xmmword ptr [rcx+32], xmm2 + movapd xmmword ptr [rcx+48], xmm3 diff --git a/src/crypto/randomx/asm/program_prologue_linux.inc b/src/crypto/randomx/asm/program_prologue_linux.inc new file mode 100644 index 00000000..ffde152c --- /dev/null +++ b/src/crypto/randomx/asm/program_prologue_linux.inc @@ -0,0 +1,34 @@ + ;# callee-saved registers - System V AMD64 ABI + push rbx + push rbp + push r12 + push r13 + push r14 + push r15 + + ;# function arguments + mov rbx, rcx ;# loop counter + push rdi ;# RegisterFile& registerFile + mov rcx, rdi + mov rbp, qword ptr [rsi] ;# "mx", "ma" + mov rdi, qword ptr [rsi+8] ;# uint8_t* dataset + mov rsi, rdx ;# uint8_t* scratchpad + + mov rax, rbp + + ;# zero integer registers + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + ;# load constant registers + lea rcx, [rcx+120] + movapd xmm8, xmmword ptr [rcx+72] + movapd xmm9, xmmword ptr [rcx+88] + movapd xmm10, xmmword ptr [rcx+104] + movapd xmm11, xmmword ptr [rcx+120] diff --git a/src/crypto/randomx/asm/program_prologue_win64.inc b/src/crypto/randomx/asm/program_prologue_win64.inc new file mode 100644 index 00000000..590a98de --- /dev/null +++ b/src/crypto/randomx/asm/program_prologue_win64.inc @@ -0,0 +1,47 @@ + ;# callee-saved registers - Microsoft x64 calling convention + push rbx + push rbp + push rdi + push rsi + push r12 + push r13 + push r14 + push r15 + sub rsp, 80 + movdqu xmmword ptr [rsp+64], xmm6 + movdqu xmmword ptr [rsp+48], xmm7 + movdqu xmmword ptr [rsp+32], xmm8 + movdqu xmmword ptr [rsp+16], xmm9 + movdqu xmmword ptr [rsp+0], xmm10 + sub rsp, 80 + movdqu xmmword ptr [rsp+64], xmm11 + movdqu xmmword ptr [rsp+48], xmm12 + movdqu xmmword ptr [rsp+32], xmm13 + movdqu xmmword ptr [rsp+16], xmm14 + movdqu xmmword ptr [rsp+0], xmm15 + + ;# function arguments + push rcx ;# RegisterFile& registerFile + mov rbp, qword ptr [rdx] ;# "mx", "ma" + mov rdi, qword ptr [rdx+8] ;# uint8_t* dataset + mov rsi, r8 ;# uint8_t* scratchpad + mov rbx, r9 ;# loop counter + + mov rax, rbp + + ;# zero integer registers + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + ;# load constant registers + lea rcx, [rcx+120] + movapd xmm8, xmmword ptr [rcx+72] + movapd xmm9, xmmword ptr [rcx+88] + movapd xmm10, xmmword ptr [rcx+104] + movapd xmm11, xmmword ptr [rcx+120] diff --git a/src/crypto/randomx/asm/program_read_dataset.inc b/src/crypto/randomx/asm/program_read_dataset.inc new file mode 100644 index 00000000..b81d0c32 --- /dev/null +++ b/src/crypto/randomx/asm/program_read_dataset.inc @@ -0,0 +1,17 @@ + xor rbp, rax ;# modify "mx" + mov edx, ebp ;# edx = mx + and edx, RANDOMX_DATASET_BASE_MASK + prefetchnta byte ptr [rdi+rdx] + ror rbp, 32 ;# swap "ma" and "mx" + mov edx, ebp ;# edx = ma + and edx, RANDOMX_DATASET_BASE_MASK + lea rcx, [rdi+rdx] ;# dataset cache line + xor r8, qword ptr [rcx+0] + xor r9, qword ptr [rcx+8] + xor r10, qword ptr [rcx+16] + xor r11, qword ptr [rcx+24] + xor r12, qword ptr [rcx+32] + xor r13, qword ptr [rcx+40] + xor r14, qword ptr [rcx+48] + xor r15, qword ptr [rcx+56] + \ No newline at end of file diff --git a/src/crypto/randomx/asm/program_read_dataset_sshash_fin.inc b/src/crypto/randomx/asm/program_read_dataset_sshash_fin.inc new file mode 100644 index 00000000..f5a067d2 --- /dev/null +++ b/src/crypto/randomx/asm/program_read_dataset_sshash_fin.inc @@ -0,0 +1,10 @@ + mov rbx, qword ptr [rsp+64] + xor r8, qword ptr [rsp+56] + xor r9, qword ptr [rsp+48] + xor r10, qword ptr [rsp+40] + xor r11, qword ptr [rsp+32] + xor r12, qword ptr [rsp+24] + xor r13, qword ptr [rsp+16] + xor r14, qword ptr [rsp+8] + xor r15, qword ptr [rsp+0] + add rsp, 72 \ No newline at end of file diff --git a/src/crypto/randomx/asm/program_read_dataset_sshash_init.inc b/src/crypto/randomx/asm/program_read_dataset_sshash_init.inc new file mode 100644 index 00000000..6fe9525d --- /dev/null +++ b/src/crypto/randomx/asm/program_read_dataset_sshash_init.inc @@ -0,0 +1,17 @@ + sub rsp, 72 + mov qword ptr [rsp+64], rbx + mov qword ptr [rsp+56], r8 + mov qword ptr [rsp+48], r9 + mov qword ptr [rsp+40], r10 + mov qword ptr [rsp+32], r11 + mov qword ptr [rsp+24], r12 + mov qword ptr [rsp+16], r13 + mov qword ptr [rsp+8], r14 + mov qword ptr [rsp+0], r15 + xor rbp, rax ;# modify "mx" + ror rbp, 32 ;# swap "ma" and "mx" + mov ebx, ebp ;# ecx = ma + and ebx, RANDOMX_DATASET_BASE_MASK + shr ebx, 6 ;# ebx = Dataset block number + ;# add ebx, datasetOffset / 64 + ;# call 32768 \ No newline at end of file diff --git a/src/crypto/randomx/asm/program_sshash_constants.inc b/src/crypto/randomx/asm/program_sshash_constants.inc new file mode 100644 index 00000000..53dc1755 --- /dev/null +++ b/src/crypto/randomx/asm/program_sshash_constants.inc @@ -0,0 +1,24 @@ +r0_mul: + ;#/ 6364136223846793005 + db 45, 127, 149, 76, 45, 244, 81, 88 +r1_add: + ;#/ 9298411001130361340 + db 252, 161, 245, 89, 138, 151, 10, 129 +r2_add: + ;#/ 12065312585734608966 + db 70, 216, 194, 56, 223, 153, 112, 167 +r3_add: + ;#/ 9306329213124626780 + db 92, 73, 34, 191, 28, 185, 38, 129 +r4_add: + ;#/ 5281919268842080866 + db 98, 138, 159, 23, 151, 37, 77, 73 +r5_add: + ;#/ 10536153434571861004 + db 12, 236, 170, 206, 185, 239, 55, 146 +r6_add: + ;#/ 3398623926847679864 + db 120, 45, 230, 108, 116, 86, 42, 47 +r7_add: + ;#/ 9549104520008361294 + db 78, 229, 44, 182, 247, 59, 133, 132 \ No newline at end of file diff --git a/src/crypto/randomx/asm/program_sshash_load.inc b/src/crypto/randomx/asm/program_sshash_load.inc new file mode 100644 index 00000000..53513569 --- /dev/null +++ b/src/crypto/randomx/asm/program_sshash_load.inc @@ -0,0 +1,8 @@ + xor r8, qword ptr [rbx+0] + xor r9, qword ptr [rbx+8] + xor r10, qword ptr [rbx+16] + xor r11, qword ptr [rbx+24] + xor r12, qword ptr [rbx+32] + xor r13, qword ptr [rbx+40] + xor r14, qword ptr [rbx+48] + xor r15, qword ptr [rbx+56] \ No newline at end of file diff --git a/src/crypto/randomx/asm/program_sshash_prefetch.inc b/src/crypto/randomx/asm/program_sshash_prefetch.inc new file mode 100644 index 00000000..26efb515 --- /dev/null +++ b/src/crypto/randomx/asm/program_sshash_prefetch.inc @@ -0,0 +1,4 @@ + and rbx, RANDOMX_CACHE_MASK + shl rbx, 6 + add rbx, rdi + prefetchnta byte ptr [rbx] \ No newline at end of file diff --git a/src/crypto/randomx/asm/program_xmm_constants.inc b/src/crypto/randomx/asm/program_xmm_constants.inc new file mode 100644 index 00000000..296237a4 --- /dev/null +++ b/src/crypto/randomx/asm/program_xmm_constants.inc @@ -0,0 +1,6 @@ +mantissaMask: + db 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 0 +exp240: + db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +scaleMask: + db 0, 0, 0, 0, 0, 0, 240, 128, 0, 0, 0, 0, 0, 0, 240, 128 \ No newline at end of file diff --git a/src/crypto/randomx/asm/randomx_reciprocal.inc b/src/crypto/randomx/asm/randomx_reciprocal.inc new file mode 100644 index 00000000..e1f22fdc --- /dev/null +++ b/src/crypto/randomx/asm/randomx_reciprocal.inc @@ -0,0 +1,7 @@ + mov edx, 1 + mov r8, rcx + xor eax, eax + bsr rcx, rcx + shl rdx, cl + div r8 + ret \ No newline at end of file diff --git a/src/crypto/randomx/blake2/blake2-impl.h b/src/crypto/randomx/blake2/blake2-impl.h new file mode 100644 index 00000000..617f7c8a --- /dev/null +++ b/src/crypto/randomx/blake2/blake2-impl.h @@ -0,0 +1,76 @@ +/* +Copyright (c) 2018-2019, tevador + +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. +*/ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +#ifndef PORTABLE_BLAKE2_IMPL_H +#define PORTABLE_BLAKE2_IMPL_H + +#include + +#include "endian.h" + +static FORCE_INLINE uint64_t load48(const void *src) { + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + return w; +} + +static FORCE_INLINE void store48(void *dst, uint64_t w) { + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +} + +static FORCE_INLINE uint32_t rotr32(const uint32_t w, const unsigned c) { + return (w >> c) | (w << (32 - c)); +} + +static FORCE_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) { + return (w >> c) | (w << (64 - c)); +} + +#endif diff --git a/src/crypto/randomx/blake2/blake2.h b/src/crypto/randomx/blake2/blake2.h new file mode 100644 index 00000000..7ac301ce --- /dev/null +++ b/src/crypto/randomx/blake2/blake2.h @@ -0,0 +1,107 @@ +/* +Copyright (c) 2018-2019, tevador + +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. +*/ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +#ifndef PORTABLE_BLAKE2_H +#define PORTABLE_BLAKE2_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + enum blake2b_constant { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 + }; + +#pragma pack(push, 1) + typedef struct __blake2b_param { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint64_t node_offset; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ + } blake2b_param; +#pragma pack(pop) + + typedef struct __blake2b_state { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + unsigned buflen; + unsigned outlen; + uint8_t last_node; + } blake2b_state; + + /* Ensure param structs have not been wrongly padded */ + /* Poor man's static_assert */ + enum { + blake2_size_check_0 = 1 / !!(CHAR_BIT == 8), + blake2_size_check_2 = + 1 / !!(sizeof(blake2b_param) == sizeof(uint64_t) * CHAR_BIT) + }; + + /* Streaming API */ + int blake2b_init(blake2b_state *S, size_t outlen); + int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, + size_t keylen); + int blake2b_init_param(blake2b_state *S, const blake2b_param *P); + int blake2b_update(blake2b_state *S, const void *in, size_t inlen); + int blake2b_final(blake2b_state *S, void *out, size_t outlen); + + /* Simple API */ + int blake2b(void *out, size_t outlen, const void *in, size_t inlen, + const void *key, size_t keylen); + + /* Argon2 Team - Begin Code */ + int rxa2_blake2b_long(void *out, size_t outlen, const void *in, size_t inlen); + /* Argon2 Team - End Code */ + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/src/crypto/randomx/blake2/blake2b.c b/src/crypto/randomx/blake2/blake2b.c new file mode 100644 index 00000000..5931ee5c --- /dev/null +++ b/src/crypto/randomx/blake2/blake2b.c @@ -0,0 +1,409 @@ +/* +Copyright (c) 2018-2019, tevador + +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. +*/ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +static const uint64_t blake2b_IV[8] = { + UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b), + UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1), + UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f), + UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179) }; + +static const unsigned int blake2b_sigma[12][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, +}; + +static FORCE_INLINE void blake2b_set_lastnode(blake2b_state *S) { + S->f[1] = (uint64_t)-1; +} + +static FORCE_INLINE void blake2b_set_lastblock(blake2b_state *S) { + if (S->last_node) { + blake2b_set_lastnode(S); + } + S->f[0] = (uint64_t)-1; +} + +static FORCE_INLINE void blake2b_increment_counter(blake2b_state *S, + uint64_t inc) { + S->t[0] += inc; + S->t[1] += (S->t[0] < inc); +} + +static FORCE_INLINE void blake2b_invalidate_state(blake2b_state *S) { + //clear_internal_memory(S, sizeof(*S)); /* wipe */ + blake2b_set_lastblock(S); /* invalidate for further use */ +} + +static FORCE_INLINE void blake2b_init0(blake2b_state *S) { + memset(S, 0, sizeof(*S)); + memcpy(S->h, blake2b_IV, sizeof(S->h)); +} + +int blake2b_init_param(blake2b_state *S, const blake2b_param *P) { + const unsigned char *p = (const unsigned char *)P; + unsigned int i; + + if (NULL == P || NULL == S) { + return -1; + } + + blake2b_init0(S); + /* IV XOR Parameter Block */ + for (i = 0; i < 8; ++i) { + S->h[i] ^= load64(&p[i * sizeof(S->h[i])]); + } + S->outlen = P->digest_length; + return 0; +} + +/* Sequential blake2b initialization */ +int blake2b_init(blake2b_state *S, size_t outlen) { + blake2b_param P; + + if (S == NULL) { + return -1; + } + + if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + /* Setup Parameter Block for unkeyed BLAKE2 */ + P.digest_length = (uint8_t)outlen; + P.key_length = 0; + P.fanout = 1; + P.depth = 1; + P.leaf_length = 0; + P.node_offset = 0; + P.node_depth = 0; + P.inner_length = 0; + memset(P.reserved, 0, sizeof(P.reserved)); + memset(P.salt, 0, sizeof(P.salt)); + memset(P.personal, 0, sizeof(P.personal)); + + return blake2b_init_param(S, &P); +} + +int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, size_t keylen) { + blake2b_param P; + + if (S == NULL) { + return -1; + } + + if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + /* Setup Parameter Block for keyed BLAKE2 */ + P.digest_length = (uint8_t)outlen; + P.key_length = (uint8_t)keylen; + P.fanout = 1; + P.depth = 1; + P.leaf_length = 0; + P.node_offset = 0; + P.node_depth = 0; + P.inner_length = 0; + memset(P.reserved, 0, sizeof(P.reserved)); + memset(P.salt, 0, sizeof(P.salt)); + memset(P.personal, 0, sizeof(P.personal)); + + if (blake2b_init_param(S, &P) < 0) { + blake2b_invalidate_state(S); + return -1; + } + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset(block, 0, BLAKE2B_BLOCKBYTES); + memcpy(block, key, keylen); + blake2b_update(S, block, BLAKE2B_BLOCKBYTES); + /* Burn the key from stack */ + //clear_internal_memory(block, BLAKE2B_BLOCKBYTES); + } + return 0; +} + +static void blake2b_compress(blake2b_state *S, const uint8_t *block) { + uint64_t m[16]; + uint64_t v[16]; + unsigned int i, r; + + for (i = 0; i < 16; ++i) { + m[i] = load64(block + i * sizeof(m[i])); + } + + for (i = 0; i < 8; ++i) { + v[i] = S->h[i]; + } + + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + +#define G(r, i, a, b, c, d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define ROUND(r) \ + do { \ + G(r, 0, v[0], v[4], v[8], v[12]); \ + G(r, 1, v[1], v[5], v[9], v[13]); \ + G(r, 2, v[2], v[6], v[10], v[14]); \ + G(r, 3, v[3], v[7], v[11], v[15]); \ + G(r, 4, v[0], v[5], v[10], v[15]); \ + G(r, 5, v[1], v[6], v[11], v[12]); \ + G(r, 6, v[2], v[7], v[8], v[13]); \ + G(r, 7, v[3], v[4], v[9], v[14]); \ + } while ((void)0, 0) + + for (r = 0; r < 12; ++r) { + ROUND(r); + } + + for (i = 0; i < 8; ++i) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } + +#undef G +#undef ROUND +} + +int blake2b_update(blake2b_state *S, const void *in, size_t inlen) { + const uint8_t *pin = (const uint8_t *)in; + + if (inlen == 0) { + return 0; + } + + /* Sanity check */ + if (S == NULL || in == NULL) { + return -1; + } + + /* Is this a reused state? */ + if (S->f[0] != 0) { + return -1; + } + + if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) { + /* Complete current block */ + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + memcpy(&S->buf[left], pin, fill); + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, S->buf); + S->buflen = 0; + inlen -= fill; + pin += fill; + /* Avoid buffer copies when possible */ + while (inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, pin); + inlen -= BLAKE2B_BLOCKBYTES; + pin += BLAKE2B_BLOCKBYTES; + } + } + memcpy(&S->buf[S->buflen], pin, inlen); + S->buflen += (unsigned int)inlen; + return 0; +} + +int blake2b_final(blake2b_state *S, void *out, size_t outlen) { + uint8_t buffer[BLAKE2B_OUTBYTES] = { 0 }; + unsigned int i; + + /* Sanity checks */ + if (S == NULL || out == NULL || outlen < S->outlen) { + return -1; + } + + /* Is this a reused state? */ + if (S->f[0] != 0) { + return -1; + } + + blake2b_increment_counter(S, S->buflen); + blake2b_set_lastblock(S); + memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ + blake2b_compress(S, S->buf); + + for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */ + store64(buffer + sizeof(S->h[i]) * i, S->h[i]); + } + + memcpy(out, buffer, S->outlen); + //clear_internal_memory(buffer, sizeof(buffer)); + //clear_internal_memory(S->buf, sizeof(S->buf)); + //clear_internal_memory(S->h, sizeof(S->h)); + return 0; +} + +int blake2b(void *out, size_t outlen, const void *in, size_t inlen, + const void *key, size_t keylen) { + blake2b_state S; + int ret = -1; + + /* Verify parameters */ + if (NULL == in && inlen > 0) { + goto fail; + } + + if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) { + goto fail; + } + + if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) { + goto fail; + } + + if (keylen > 0) { + if (blake2b_init_key(&S, outlen, key, keylen) < 0) { + goto fail; + } + } + else { + if (blake2b_init(&S, outlen) < 0) { + goto fail; + } + } + + if (blake2b_update(&S, in, inlen) < 0) { + goto fail; + } + ret = blake2b_final(&S, out, outlen); + +fail: + //clear_internal_memory(&S, sizeof(S)); + return ret; +} + +/* Argon2 Team - Begin Code */ +int rxa2_blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) { + uint8_t *out = (uint8_t *)pout; + blake2b_state blake_state; + uint8_t outlen_bytes[sizeof(uint32_t)] = { 0 }; + int ret = -1; + + if (outlen > UINT32_MAX) { + goto fail; + } + + /* Ensure little-endian byte order! */ + store32(outlen_bytes, (uint32_t)outlen); + +#define TRY(statement) \ + do { \ + ret = statement; \ + if (ret < 0) { \ + goto fail; \ + } \ + } while ((void)0, 0) + + if (outlen <= BLAKE2B_OUTBYTES) { + TRY(blake2b_init(&blake_state, outlen)); + TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + TRY(blake2b_update(&blake_state, in, inlen)); + TRY(blake2b_final(&blake_state, out, outlen)); + } + else { + uint32_t toproduce; + uint8_t out_buffer[BLAKE2B_OUTBYTES]; + uint8_t in_buffer[BLAKE2B_OUTBYTES]; + TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES)); + TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + TRY(blake2b_update(&blake_state, in, inlen)); + TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES)); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce = (uint32_t)outlen - BLAKE2B_OUTBYTES / 2; + + while (toproduce > BLAKE2B_OUTBYTES) { + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer, + BLAKE2B_OUTBYTES, NULL, 0)); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce -= BLAKE2B_OUTBYTES / 2; + } + + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL, + 0)); + memcpy(out, out_buffer, toproduce); + } +fail: + //clear_internal_memory(&blake_state, sizeof(blake_state)); + return ret; +#undef TRY +} +/* Argon2 Team - End Code */ + diff --git a/src/crypto/randomx/blake2/blamka-round-ref.h b/src/crypto/randomx/blake2/blamka-round-ref.h new file mode 100644 index 00000000..f1fb50bf --- /dev/null +++ b/src/crypto/randomx/blake2/blamka-round-ref.h @@ -0,0 +1,73 @@ +/* +Copyright (c) 2018-2019, tevador + +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. +*/ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +#ifndef BLAKE_ROUND_MKA_H +#define BLAKE_ROUND_MKA_H + +#include "blake2.h" +#include "blake2-impl.h" + + /* designed by the Lyra PHC team */ +static FORCE_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) { + const uint64_t m = UINT64_C(0xFFFFFFFF); + const uint64_t xy = (x & m) * (y & m); + return x + y + 2 * xy; +} + +#define G(a, b, c, d) \ + do { \ + a = fBlaMka(a, b); \ + d = rotr64(d ^ a, 32); \ + c = fBlaMka(c, d); \ + b = rotr64(b ^ c, 24); \ + a = fBlaMka(a, b); \ + d = rotr64(d ^ a, 16); \ + c = fBlaMka(c, d); \ + b = rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, \ + v12, v13, v14, v15) \ + do { \ + G(v0, v4, v8, v12); \ + G(v1, v5, v9, v13); \ + G(v2, v6, v10, v14); \ + G(v3, v7, v11, v15); \ + G(v0, v5, v10, v15); \ + G(v1, v6, v11, v12); \ + G(v2, v7, v8, v13); \ + G(v3, v4, v9, v14); \ + } while ((void)0, 0) + +#endif diff --git a/src/crypto/randomx/blake2/endian.h b/src/crypto/randomx/blake2/endian.h new file mode 100644 index 00000000..c7afed26 --- /dev/null +++ b/src/crypto/randomx/blake2/endian.h @@ -0,0 +1,107 @@ +#pragma once +#include +#include + +#if defined(_MSC_VER) +#define FORCE_INLINE __inline +#elif defined(__GNUC__) || defined(__clang__) +#define FORCE_INLINE __inline__ +#else +#define FORCE_INLINE +#endif + + /* Argon2 Team - Begin Code */ + /* + Not an exhaustive list, but should cover the majority of modern platforms + Additionally, the code will always be correct---this is only a performance + tweak. + */ +#if (defined(__BYTE_ORDER__) && \ + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ + defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \ + defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) || \ + defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_ARM) +#define NATIVE_LITTLE_ENDIAN +#endif + /* Argon2 Team - End Code */ + +static FORCE_INLINE uint32_t load32(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = (const uint8_t *)src; + uint32_t w = *p++; + w |= (uint32_t)(*p++) << 8; + w |= (uint32_t)(*p++) << 16; + w |= (uint32_t)(*p++) << 24; + return w; +#endif +} + +static FORCE_INLINE uint64_t load64_native(const void *src) { + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static FORCE_INLINE uint64_t load64(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + return load64_native(src); +#else + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + w |= (uint64_t)(*p++) << 48; + w |= (uint64_t)(*p++) << 56; + return w; +#endif +} + +static FORCE_INLINE void store32(void *dst, uint32_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +static FORCE_INLINE void store64_native(void *dst, uint64_t w) { + memcpy(dst, &w, sizeof w); +} + +static FORCE_INLINE void store64(void *dst, uint64_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + store64_native(dst, w); +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} diff --git a/src/crypto/randomx/blake2_generator.cpp b/src/crypto/randomx/blake2_generator.cpp new file mode 100644 index 00000000..dcf51cec --- /dev/null +++ b/src/crypto/randomx/blake2_generator.cpp @@ -0,0 +1,62 @@ +/* +Copyright (c) 2018-2019, tevador + +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 +#include "blake2/blake2.h" +#include "blake2/endian.h" +#include "blake2_generator.hpp" + +namespace randomx { + + constexpr int maxSeedSize = 60; + + Blake2Generator::Blake2Generator(const void* seed, size_t seedSize, int nonce) : dataIndex(sizeof(data)) { + memset(data, 0, sizeof(data)); + memcpy(data, seed, seedSize > maxSeedSize ? maxSeedSize : seedSize); + store32(&data[maxSeedSize], nonce); + } + + uint8_t Blake2Generator::getByte() { + checkData(1); + return data[dataIndex++]; + } + + uint32_t Blake2Generator::getInt32() { + checkData(4); + auto ret = load32(&data[dataIndex]); + dataIndex += 4; + return ret; + } + + void Blake2Generator::checkData(const size_t bytesNeeded) { + if (dataIndex + bytesNeeded > sizeof(data)) { + blake2b(data, sizeof(data), data, sizeof(data), nullptr, 0); + dataIndex = 0; + } + } +} \ No newline at end of file diff --git a/src/crypto/randomx/blake2_generator.hpp b/src/crypto/randomx/blake2_generator.hpp new file mode 100644 index 00000000..b5ac0801 --- /dev/null +++ b/src/crypto/randomx/blake2_generator.hpp @@ -0,0 +1,46 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include + +namespace randomx { + + class Blake2Generator { + public: + Blake2Generator(const void* seed, size_t seedSize, int nonce = 0); + uint8_t getByte(); + uint32_t getInt32(); + private: + void checkData(const size_t); + + uint8_t data[64]; + size_t dataIndex; + }; +} \ No newline at end of file diff --git a/src/crypto/randomx/bytecode_machine.cpp b/src/crypto/randomx/bytecode_machine.cpp new file mode 100644 index 00000000..8447318e --- /dev/null +++ b/src/crypto/randomx/bytecode_machine.cpp @@ -0,0 +1,482 @@ +/* +Copyright (c) 2019, tevador + +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 "bytecode_machine.hpp" +#include "reciprocal.h" + +namespace randomx { + + const int_reg_t BytecodeMachine::zero = 0; + +#define INSTR_CASE(x) case InstructionType::x: \ + exe_ ## x(ibc, pc, scratchpad, config); \ + break; + + void BytecodeMachine::executeInstruction(RANDOMX_EXE_ARGS) { + switch (ibc.type) + { + INSTR_CASE(IADD_RS) + INSTR_CASE(IADD_M) + INSTR_CASE(ISUB_R) + INSTR_CASE(ISUB_M) + INSTR_CASE(IMUL_R) + INSTR_CASE(IMUL_M) + INSTR_CASE(IMULH_R) + INSTR_CASE(IMULH_M) + INSTR_CASE(ISMULH_R) + INSTR_CASE(ISMULH_M) + INSTR_CASE(INEG_R) + INSTR_CASE(IXOR_R) + INSTR_CASE(IXOR_M) + INSTR_CASE(IROR_R) + INSTR_CASE(IROL_R) + INSTR_CASE(ISWAP_R) + INSTR_CASE(FSWAP_R) + INSTR_CASE(FADD_R) + INSTR_CASE(FADD_M) + INSTR_CASE(FSUB_R) + INSTR_CASE(FSUB_M) + INSTR_CASE(FSCAL_R) + INSTR_CASE(FMUL_R) + INSTR_CASE(FDIV_M) + INSTR_CASE(FSQRT_R) + INSTR_CASE(CBRANCH) + INSTR_CASE(CFROUND) + INSTR_CASE(ISTORE) + + case InstructionType::NOP: + break; + + case InstructionType::IMUL_RCP: //executed as IMUL_R + default: + UNREACHABLE; + } + } + + void BytecodeMachine::compileInstruction(RANDOMX_GEN_ARGS) { + int opcode = instr.opcode; + + if (opcode < RandomX_CurrentConfig.CEIL_IADD_RS) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::IADD_RS; + ibc.idst = &nreg->r[dst]; + if (dst != RegisterNeedsDisplacement) { + ibc.isrc = &nreg->r[src]; + ibc.shift = instr.getModShift(); + ibc.imm = 0; + } + else { + ibc.isrc = &nreg->r[src]; + ibc.shift = instr.getModShift(); + ibc.imm = signExtend2sCompl(instr.getImm32()); + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_IADD_M) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::IADD_M; + ibc.idst = &nreg->r[dst]; + ibc.imm = signExtend2sCompl(instr.getImm32()); + if (src != dst) { + ibc.isrc = &nreg->r[src]; + ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + } + else { + ibc.isrc = &zero; + ibc.memMask = ScratchpadL3Mask; + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_ISUB_R) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::ISUB_R; + ibc.idst = &nreg->r[dst]; + if (src != dst) { + ibc.isrc = &nreg->r[src]; + } + else { + ibc.imm = signExtend2sCompl(instr.getImm32()); + ibc.isrc = &ibc.imm; + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_ISUB_M) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::ISUB_M; + ibc.idst = &nreg->r[dst]; + ibc.imm = signExtend2sCompl(instr.getImm32()); + if (src != dst) { + ibc.isrc = &nreg->r[src]; + ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + } + else { + ibc.isrc = &zero; + ibc.memMask = ScratchpadL3Mask; + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_IMUL_R) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::IMUL_R; + ibc.idst = &nreg->r[dst]; + if (src != dst) { + ibc.isrc = &nreg->r[src]; + } + else { + ibc.imm = signExtend2sCompl(instr.getImm32()); + ibc.isrc = &ibc.imm; + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_IMUL_M) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::IMUL_M; + ibc.idst = &nreg->r[dst]; + ibc.imm = signExtend2sCompl(instr.getImm32()); + if (src != dst) { + ibc.isrc = &nreg->r[src]; + ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + } + else { + ibc.isrc = &zero; + ibc.memMask = ScratchpadL3Mask; + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_IMULH_R) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::IMULH_R; + ibc.idst = &nreg->r[dst]; + ibc.isrc = &nreg->r[src]; + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_IMULH_M) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::IMULH_M; + ibc.idst = &nreg->r[dst]; + ibc.imm = signExtend2sCompl(instr.getImm32()); + if (src != dst) { + ibc.isrc = &nreg->r[src]; + ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + } + else { + ibc.isrc = &zero; + ibc.memMask = ScratchpadL3Mask; + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_ISMULH_R) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::ISMULH_R; + ibc.idst = &nreg->r[dst]; + ibc.isrc = &nreg->r[src]; + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_ISMULH_M) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::ISMULH_M; + ibc.idst = &nreg->r[dst]; + ibc.imm = signExtend2sCompl(instr.getImm32()); + if (src != dst) { + ibc.isrc = &nreg->r[src]; + ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + } + else { + ibc.isrc = &zero; + ibc.memMask = ScratchpadL3Mask; + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_IMUL_RCP) { + uint64_t divisor = instr.getImm32(); + if (!isPowerOf2(divisor)) { + auto dst = instr.dst % RegistersCount; + ibc.type = InstructionType::IMUL_R; + ibc.idst = &nreg->r[dst]; + ibc.imm = randomx_reciprocal(divisor); + ibc.isrc = &ibc.imm; + registerUsage[dst] = i; + } + else { + ibc.type = InstructionType::NOP; + } + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_INEG_R) { + auto dst = instr.dst % RegistersCount; + ibc.type = InstructionType::INEG_R; + ibc.idst = &nreg->r[dst]; + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_IXOR_R) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::IXOR_R; + ibc.idst = &nreg->r[dst]; + if (src != dst) { + ibc.isrc = &nreg->r[src]; + } + else { + ibc.imm = signExtend2sCompl(instr.getImm32()); + ibc.isrc = &ibc.imm; + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_IXOR_M) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::IXOR_M; + ibc.idst = &nreg->r[dst]; + ibc.imm = signExtend2sCompl(instr.getImm32()); + if (src != dst) { + ibc.isrc = &nreg->r[src]; + ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + } + else { + ibc.isrc = &zero; + ibc.memMask = ScratchpadL3Mask; + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_IROR_R) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::IROR_R; + ibc.idst = &nreg->r[dst]; + if (src != dst) { + ibc.isrc = &nreg->r[src]; + } + else { + ibc.imm = instr.getImm32(); + ibc.isrc = &ibc.imm; + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_IROL_R) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::IROL_R; + ibc.idst = &nreg->r[dst]; + if (src != dst) { + ibc.isrc = &nreg->r[src]; + } + else { + ibc.imm = instr.getImm32(); + ibc.isrc = &ibc.imm; + } + registerUsage[dst] = i; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_ISWAP_R) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + if (src != dst) { + ibc.idst = &nreg->r[dst]; + ibc.isrc = &nreg->r[src]; + ibc.type = InstructionType::ISWAP_R; + registerUsage[dst] = i; + registerUsage[src] = i; + } + else { + ibc.type = InstructionType::NOP; + } + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_FSWAP_R) { + auto dst = instr.dst % RegistersCount; + ibc.type = InstructionType::FSWAP_R; + if (dst < RegisterCountFlt) + ibc.fdst = &nreg->f[dst]; + else + ibc.fdst = &nreg->e[dst - RegisterCountFlt]; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_FADD_R) { + auto dst = instr.dst % RegisterCountFlt; + auto src = instr.src % RegisterCountFlt; + ibc.type = InstructionType::FADD_R; + ibc.fdst = &nreg->f[dst]; + ibc.fsrc = &nreg->a[src]; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_FADD_M) { + auto dst = instr.dst % RegisterCountFlt; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::FADD_M; + ibc.fdst = &nreg->f[dst]; + ibc.isrc = &nreg->r[src]; + ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + ibc.imm = signExtend2sCompl(instr.getImm32()); + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_FSUB_R) { + auto dst = instr.dst % RegisterCountFlt; + auto src = instr.src % RegisterCountFlt; + ibc.type = InstructionType::FSUB_R; + ibc.fdst = &nreg->f[dst]; + ibc.fsrc = &nreg->a[src]; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_FSUB_M) { + auto dst = instr.dst % RegisterCountFlt; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::FSUB_M; + ibc.fdst = &nreg->f[dst]; + ibc.isrc = &nreg->r[src]; + ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + ibc.imm = signExtend2sCompl(instr.getImm32()); + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_FSCAL_R) { + auto dst = instr.dst % RegisterCountFlt; + ibc.fdst = &nreg->f[dst]; + ibc.type = InstructionType::FSCAL_R; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_FMUL_R) { + auto dst = instr.dst % RegisterCountFlt; + auto src = instr.src % RegisterCountFlt; + ibc.type = InstructionType::FMUL_R; + ibc.fdst = &nreg->e[dst]; + ibc.fsrc = &nreg->a[src]; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_FDIV_M) { + auto dst = instr.dst % RegisterCountFlt; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::FDIV_M; + ibc.fdst = &nreg->e[dst]; + ibc.isrc = &nreg->r[src]; + ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + ibc.imm = signExtend2sCompl(instr.getImm32()); + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_FSQRT_R) { + auto dst = instr.dst % RegisterCountFlt; + ibc.type = InstructionType::FSQRT_R; + ibc.fdst = &nreg->e[dst]; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_CBRANCH) { + ibc.type = InstructionType::CBRANCH; + //jump condition + int creg = instr.dst % RegistersCount; + ibc.idst = &nreg->r[creg]; + ibc.target = registerUsage[creg]; + int shift = instr.getModCond() + RandomX_CurrentConfig.JumpOffset; + ibc.imm = signExtend2sCompl(instr.getImm32()) | (1ULL << shift); + if (RandomX_CurrentConfig.JumpOffset > 0 || shift > 0) //clear the bit below the condition mask - this limits the number of successive jumps to 2 + ibc.imm &= ~(1ULL << (shift - 1)); + ibc.memMask = RandomX_CurrentConfig.ConditionMask_Calculated << shift; + //mark all registers as used + for (unsigned j = 0; j < RegistersCount; ++j) { + registerUsage[j] = i; + } + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_CFROUND) { + auto src = instr.src % RegistersCount; + ibc.isrc = &nreg->r[src]; + ibc.type = InstructionType::CFROUND; + ibc.imm = instr.getImm32() & 63; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_ISTORE) { + auto dst = instr.dst % RegistersCount; + auto src = instr.src % RegistersCount; + ibc.type = InstructionType::ISTORE; + ibc.idst = &nreg->r[dst]; + ibc.isrc = &nreg->r[src]; + ibc.imm = signExtend2sCompl(instr.getImm32()); + if (instr.getModCond() < StoreL3Condition) + ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + else + ibc.memMask = ScratchpadL3Mask; + return; + } + + if (opcode < RandomX_CurrentConfig.CEIL_NOP) { + ibc.type = InstructionType::NOP; + return; + } + + UNREACHABLE; + } +} diff --git a/src/crypto/randomx/bytecode_machine.hpp b/src/crypto/randomx/bytecode_machine.hpp new file mode 100644 index 00000000..c4175b70 --- /dev/null +++ b/src/crypto/randomx/bytecode_machine.hpp @@ -0,0 +1,288 @@ +/* +Copyright (c) 2019, tevador + +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 + +#include "common.hpp" +#include "intrin_portable.h" +#include "instruction.hpp" +#include "program.hpp" + +namespace randomx { + + //register file in machine byte order + struct NativeRegisterFile { + int_reg_t r[RegistersCount] = { 0 }; + rx_vec_f128 f[RegisterCountFlt]; + rx_vec_f128 e[RegisterCountFlt]; + rx_vec_f128 a[RegisterCountFlt]; + }; + + struct InstructionByteCode { + union { + int_reg_t* idst; + rx_vec_f128* fdst; + }; + union { + const int_reg_t* isrc; + const rx_vec_f128* fsrc; + }; + union { + uint64_t imm; + int64_t simm; + }; + InstructionType type; + union { + int16_t target; + uint16_t shift; + }; + uint32_t memMask; + }; + +#define RANDOMX_EXE_ARGS InstructionByteCode& ibc, int& pc, uint8_t* scratchpad, ProgramConfiguration& config +#define RANDOMX_GEN_ARGS Instruction& instr, int i, InstructionByteCode& ibc + + class BytecodeMachine; + + typedef void(BytecodeMachine::*InstructionGenBytecode)(RANDOMX_GEN_ARGS); + + class BytecodeMachine { + public: + void beginCompilation(NativeRegisterFile& regFile) { + for (unsigned i = 0; i < RegistersCount; ++i) { + registerUsage[i] = -1; + } + nreg = ®File; + } + + void compileProgram(Program& program, InstructionByteCode* bytecode, NativeRegisterFile& regFile) { + beginCompilation(regFile); + for (unsigned i = 0; i < RandomX_CurrentConfig.ProgramSize; ++i) { + auto& instr = program(i); + auto& ibc = bytecode[i]; + compileInstruction(instr, i, ibc); + } + } + + static void executeBytecode(InstructionByteCode* bytecode, uint8_t* scratchpad, ProgramConfiguration& config) { + for (int pc = 0; pc < RandomX_CurrentConfig.ProgramSize; ++pc) { + auto& ibc = bytecode[pc]; + executeInstruction(ibc, pc, scratchpad, config); + } + } + + void compileInstruction(RANDOMX_GEN_ARGS) +#ifdef RANDOMX_GEN_TABLE + { + auto generator = genTable[instr.opcode]; + (this->*generator)(instr, i, ibc); + } +#else + ; +#endif + + static void executeInstruction(RANDOMX_EXE_ARGS); + + static void exe_IADD_RS(RANDOMX_EXE_ARGS) { + *ibc.idst += (*ibc.isrc << ibc.shift) + ibc.imm; + } + + static void exe_IADD_M(RANDOMX_EXE_ARGS) { + *ibc.idst += load64(getScratchpadAddress(ibc, scratchpad)); + } + + static void exe_ISUB_R(RANDOMX_EXE_ARGS) { + *ibc.idst -= *ibc.isrc; + } + + static void exe_ISUB_M(RANDOMX_EXE_ARGS) { + *ibc.idst -= load64(getScratchpadAddress(ibc, scratchpad)); + } + + static void exe_IMUL_R(RANDOMX_EXE_ARGS) { + *ibc.idst *= *ibc.isrc; + } + + static void exe_IMUL_M(RANDOMX_EXE_ARGS) { + *ibc.idst *= load64(getScratchpadAddress(ibc, scratchpad)); + } + + static void exe_IMULH_R(RANDOMX_EXE_ARGS) { + *ibc.idst = mulh(*ibc.idst, *ibc.isrc); + } + + static void exe_IMULH_M(RANDOMX_EXE_ARGS) { + *ibc.idst = mulh(*ibc.idst, load64(getScratchpadAddress(ibc, scratchpad))); + } + + static void exe_ISMULH_R(RANDOMX_EXE_ARGS) { + *ibc.idst = smulh(unsigned64ToSigned2sCompl(*ibc.idst), unsigned64ToSigned2sCompl(*ibc.isrc)); + } + + static void exe_ISMULH_M(RANDOMX_EXE_ARGS) { + *ibc.idst = smulh(unsigned64ToSigned2sCompl(*ibc.idst), unsigned64ToSigned2sCompl(load64(getScratchpadAddress(ibc, scratchpad)))); + } + + static void exe_INEG_R(RANDOMX_EXE_ARGS) { + *ibc.idst = ~(*ibc.idst) + 1; //two's complement negative + } + + static void exe_IXOR_R(RANDOMX_EXE_ARGS) { + *ibc.idst ^= *ibc.isrc; + } + + static void exe_IXOR_M(RANDOMX_EXE_ARGS) { + *ibc.idst ^= load64(getScratchpadAddress(ibc, scratchpad)); + } + + static void exe_IROR_R(RANDOMX_EXE_ARGS) { + *ibc.idst = rotr(*ibc.idst, *ibc.isrc & 63); + } + + static void exe_IROL_R(RANDOMX_EXE_ARGS) { + *ibc.idst = rotl(*ibc.idst, *ibc.isrc & 63); + } + + static void exe_ISWAP_R(RANDOMX_EXE_ARGS) { + int_reg_t temp = *ibc.isrc; + *(int_reg_t*)ibc.isrc = *ibc.idst; + *ibc.idst = temp; + } + + static void exe_FSWAP_R(RANDOMX_EXE_ARGS) { + *ibc.fdst = rx_swap_vec_f128(*ibc.fdst); + } + + static void exe_FADD_R(RANDOMX_EXE_ARGS) { + *ibc.fdst = rx_add_vec_f128(*ibc.fdst, *ibc.fsrc); + } + + static void exe_FADD_M(RANDOMX_EXE_ARGS) { + rx_vec_f128 fsrc = rx_cvt_packed_int_vec_f128(getScratchpadAddress(ibc, scratchpad)); + *ibc.fdst = rx_add_vec_f128(*ibc.fdst, fsrc); + } + + static void exe_FSUB_R(RANDOMX_EXE_ARGS) { + *ibc.fdst = rx_sub_vec_f128(*ibc.fdst, *ibc.fsrc); + } + + static void exe_FSUB_M(RANDOMX_EXE_ARGS) { + rx_vec_f128 fsrc = rx_cvt_packed_int_vec_f128(getScratchpadAddress(ibc, scratchpad)); + *ibc.fdst = rx_sub_vec_f128(*ibc.fdst, fsrc); + } + + static void exe_FSCAL_R(RANDOMX_EXE_ARGS) { + const rx_vec_f128 mask = rx_set1_vec_f128(0x80F0000000000000); + *ibc.fdst = rx_xor_vec_f128(*ibc.fdst, mask); + } + + static void exe_FMUL_R(RANDOMX_EXE_ARGS) { + *ibc.fdst = rx_mul_vec_f128(*ibc.fdst, *ibc.fsrc); + } + + static void exe_FDIV_M(RANDOMX_EXE_ARGS) { + rx_vec_f128 fsrc = maskRegisterExponentMantissa( + config, + rx_cvt_packed_int_vec_f128(getScratchpadAddress(ibc, scratchpad)) + ); + *ibc.fdst = rx_div_vec_f128(*ibc.fdst, fsrc); + } + + static void exe_FSQRT_R(RANDOMX_EXE_ARGS) { + *ibc.fdst = rx_sqrt_vec_f128(*ibc.fdst); + } + + static void exe_CBRANCH(RANDOMX_EXE_ARGS) { + *ibc.idst += ibc.imm; + if ((*ibc.idst & ibc.memMask) == 0) { + pc = ibc.target; + } + } + + static void exe_CFROUND(RANDOMX_EXE_ARGS) { + rx_set_rounding_mode(rotr(*ibc.isrc, ibc.imm) % 4); + } + + static void exe_ISTORE(RANDOMX_EXE_ARGS) { + store64(scratchpad + ((*ibc.idst + ibc.imm) & ibc.memMask), *ibc.isrc); + } + protected: + static rx_vec_f128 maskRegisterExponentMantissa(ProgramConfiguration& config, rx_vec_f128 x) { + const rx_vec_f128 xmantissaMask = rx_set_vec_f128(dynamicMantissaMask, dynamicMantissaMask); + const rx_vec_f128 xexponentMask = rx_load_vec_f128((const double*)&config.eMask); + x = rx_and_vec_f128(x, xmantissaMask); + x = rx_or_vec_f128(x, xexponentMask); + return x; + } + + private: + static const int_reg_t zero; + int registerUsage[RegistersCount]; + NativeRegisterFile* nreg; + + static void* getScratchpadAddress(InstructionByteCode& ibc, uint8_t* scratchpad) { + uint32_t addr = (*ibc.isrc + ibc.imm) & ibc.memMask; + return scratchpad + addr; + } + +#ifdef RANDOMX_GEN_TABLE + static InstructionGenBytecode genTable[256]; + + void gen_IADD_RS(RANDOMX_GEN_ARGS); + void gen_IADD_M(RANDOMX_GEN_ARGS); + void gen_ISUB_R(RANDOMX_GEN_ARGS); + void gen_ISUB_M(RANDOMX_GEN_ARGS); + void gen_IMUL_R(RANDOMX_GEN_ARGS); + void gen_IMUL_M(RANDOMX_GEN_ARGS); + void gen_IMULH_R(RANDOMX_GEN_ARGS); + void gen_IMULH_M(RANDOMX_GEN_ARGS); + void gen_ISMULH_R(RANDOMX_GEN_ARGS); + void gen_ISMULH_M(RANDOMX_GEN_ARGS); + void gen_IMUL_RCP(RANDOMX_GEN_ARGS); + void gen_INEG_R(RANDOMX_GEN_ARGS); + void gen_IXOR_R(RANDOMX_GEN_ARGS); + void gen_IXOR_M(RANDOMX_GEN_ARGS); + void gen_IROR_R(RANDOMX_GEN_ARGS); + void gen_IROL_R(RANDOMX_GEN_ARGS); + void gen_ISWAP_R(RANDOMX_GEN_ARGS); + void gen_FSWAP_R(RANDOMX_GEN_ARGS); + void gen_FADD_R(RANDOMX_GEN_ARGS); + void gen_FADD_M(RANDOMX_GEN_ARGS); + void gen_FSUB_R(RANDOMX_GEN_ARGS); + void gen_FSUB_M(RANDOMX_GEN_ARGS); + void gen_FSCAL_R(RANDOMX_GEN_ARGS); + void gen_FMUL_R(RANDOMX_GEN_ARGS); + void gen_FDIV_M(RANDOMX_GEN_ARGS); + void gen_FSQRT_R(RANDOMX_GEN_ARGS); + void gen_CBRANCH(RANDOMX_GEN_ARGS); + void gen_CFROUND(RANDOMX_GEN_ARGS); + void gen_ISTORE(RANDOMX_GEN_ARGS); + void gen_NOP(RANDOMX_GEN_ARGS); +#endif + }; +} diff --git a/src/crypto/randomx/common.hpp b/src/crypto/randomx/common.hpp new file mode 100644 index 00000000..6f60f606 --- /dev/null +++ b/src/crypto/randomx/common.hpp @@ -0,0 +1,173 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include +#include +#include "blake2/endian.h" +#include "configuration.h" +#include "randomx.h" + +namespace randomx { + + //static_assert(RANDOMX_ARGON_MEMORY > 0, "RANDOMX_ARGON_MEMORY must be greater than 0."); + //static_assert((RANDOMX_ARGON_MEMORY & (RANDOMX_ARGON_MEMORY - 1)) == 0, "RANDOMX_ARGON_MEMORY must be a power of 2."); + //static_assert(RANDOMX_DATASET_BASE_SIZE >= 64, "RANDOMX_DATASET_BASE_SIZE must be at least 64."); + //static_assert((RANDOMX_DATASET_BASE_SIZE & (RANDOMX_DATASET_BASE_SIZE - 1)) == 0, "RANDOMX_DATASET_BASE_SIZE must be a power of 2."); + //static_assert(RANDOMX_DATASET_BASE_SIZE <= 4294967296ULL, "RANDOMX_DATASET_BASE_SIZE must not exceed 4294967296."); + //static_assert(RANDOMX_DATASET_EXTRA_SIZE % 64 == 0, "RANDOMX_DATASET_EXTRA_SIZE must be divisible by 64."); + //static_assert((uint64_t)RANDOMX_DATASET_BASE_SIZE + RANDOMX_DATASET_EXTRA_SIZE <= 17179869184, "Dataset size must not exceed 16 GiB."); + //static_assert(RANDOMX_PROGRAM_SIZE > 0, "RANDOMX_PROGRAM_SIZE must be greater than 0"); + //static_assert(RANDOMX_PROGRAM_ITERATIONS > 0, "RANDOMX_PROGRAM_ITERATIONS must be greater than 0"); + //static_assert(RANDOMX_PROGRAM_COUNT > 0, "RANDOMX_PROGRAM_COUNT must be greater than 0"); + //static_assert((RANDOMX_SCRATCHPAD_L3 & (RANDOMX_SCRATCHPAD_L3 - 1)) == 0, "RANDOMX_SCRATCHPAD_L3 must be a power of 2."); + //static_assert(RANDOMX_SCRATCHPAD_L3 >= RANDOMX_SCRATCHPAD_L2, "RANDOMX_SCRATCHPAD_L3 must be greater than or equal to RANDOMX_SCRATCHPAD_L2."); + //static_assert((RANDOMX_SCRATCHPAD_L2 & (RANDOMX_SCRATCHPAD_L2 - 1)) == 0, "RANDOMX_SCRATCHPAD_L2 must be a power of 2."); + //static_assert(RANDOMX_SCRATCHPAD_L2 >= RANDOMX_SCRATCHPAD_L1, "RANDOMX_SCRATCHPAD_L2 must be greater than or equal to RANDOMX_SCRATCHPAD_L1."); + //static_assert(RANDOMX_SCRATCHPAD_L1 >= 64, "RANDOMX_SCRATCHPAD_L1 must be at least 64."); + //static_assert((RANDOMX_SCRATCHPAD_L1 & (RANDOMX_SCRATCHPAD_L1 - 1)) == 0, "RANDOMX_SCRATCHPAD_L1 must be a power of 2."); + //static_assert(RANDOMX_CACHE_ACCESSES > 1, "RANDOMX_CACHE_ACCESSES must be greater than 1"); + //static_assert(RANDOMX_SUPERSCALAR_LATENCY > 0, "RANDOMX_SUPERSCALAR_LATENCY must be greater than 0"); + //static_assert(RANDOMX_JUMP_BITS > 0, "RANDOMX_JUMP_BITS must be greater than 0."); + //static_assert(RANDOMX_JUMP_OFFSET >= 0, "RANDOMX_JUMP_OFFSET must be greater than or equal to 0."); + //static_assert(RANDOMX_JUMP_BITS + RANDOMX_JUMP_OFFSET <= 16, "RANDOMX_JUMP_BITS + RANDOMX_JUMP_OFFSET must not exceed 16."); + + //constexpr int wtSum = RANDOMX_FREQ_IADD_RS + RANDOMX_FREQ_IADD_M + RANDOMX_FREQ_ISUB_R + \ + // RANDOMX_FREQ_ISUB_M + RANDOMX_FREQ_IMUL_R + RANDOMX_FREQ_IMUL_M + RANDOMX_FREQ_IMULH_R + \ + // RANDOMX_FREQ_IMULH_M + RANDOMX_FREQ_ISMULH_R + RANDOMX_FREQ_ISMULH_M + RANDOMX_FREQ_IMUL_RCP + \ + // RANDOMX_FREQ_INEG_R + RANDOMX_FREQ_IXOR_R + RANDOMX_FREQ_IXOR_M + RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R + RANDOMX_FREQ_ISWAP_R + \ + // RANDOMX_FREQ_FSWAP_R + RANDOMX_FREQ_FADD_R + RANDOMX_FREQ_FADD_M + RANDOMX_FREQ_FSUB_R + RANDOMX_FREQ_FSUB_M + \ + // RANDOMX_FREQ_FSCAL_R + RANDOMX_FREQ_FMUL_R + RANDOMX_FREQ_FDIV_M + RANDOMX_FREQ_FSQRT_R + RANDOMX_FREQ_CBRANCH + \ + // RANDOMX_FREQ_CFROUND + RANDOMX_FREQ_ISTORE + RANDOMX_FREQ_NOP; + + //static_assert(wtSum == 256, "Sum of instruction frequencies must be 256."); + + + constexpr uint32_t ArgonBlockSize = 1024; + constexpr int SuperscalarMaxSize = 3 * RANDOMX_SUPERSCALAR_MAX_LATENCY + 2; + constexpr size_t CacheLineSize = RANDOMX_DATASET_ITEM_SIZE; + #define ScratchpadSize RandomX_CurrentConfig.ScratchpadL3_Size + #define CacheLineAlignMask RandomX_CurrentConfig.CacheLineAlignMask_Calculated + #define DatasetExtraItems RandomX_CurrentConfig.DatasetExtraItems_Calculated + constexpr int StoreL3Condition = 14; + + //Prevent some unsafe configurations. +#ifndef RANDOMX_UNSAFE + //static_assert((uint64_t)ArgonBlockSize * RANDOMX_CACHE_ACCESSES * RANDOMX_ARGON_MEMORY + 33554432 >= (uint64_t)RANDOMX_DATASET_BASE_SIZE + RANDOMX_DATASET_EXTRA_SIZE, "Unsafe configuration: Memory-time tradeoffs"); + //static_assert((128 + RANDOMX_PROGRAM_SIZE * RANDOMX_FREQ_ISTORE / 256) * (RANDOMX_PROGRAM_COUNT * RANDOMX_PROGRAM_ITERATIONS) >= RANDOMX_SCRATCHPAD_L3, "Unsafe configuration: Insufficient Scratchpad writes"); + //static_assert(RANDOMX_PROGRAM_COUNT > 1, "Unsafe configuration: Program filtering strategies"); + //static_assert(RANDOMX_PROGRAM_SIZE >= 64, "Unsafe configuration: Low program entropy"); + //static_assert(RANDOMX_PROGRAM_ITERATIONS >= 400, "Unsafe configuration: High compilation overhead"); +#endif + +#ifdef TRACE + constexpr bool trace = true; +#else + constexpr bool trace = false; +#endif + +#ifndef UNREACHABLE +#ifdef __GNUC__ +#define UNREACHABLE __builtin_unreachable() +#elif _MSC_VER +#define UNREACHABLE __assume(false) +#else +#define UNREACHABLE +#endif +#endif + +#if defined(_M_X64) || defined(__x86_64__) + #define RANDOMX_HAVE_COMPILER 1 + class JitCompilerX86; + using JitCompiler = JitCompilerX86; +#elif defined(__aarch64__) + #define RANDOMX_HAVE_COMPILER 0 + class JitCompilerA64; + using JitCompiler = JitCompilerA64; +#else + #define RANDOMX_HAVE_COMPILER 0 + class JitCompilerFallback; + using JitCompiler = JitCompilerFallback; +#endif + + using addr_t = uint32_t; + + using int_reg_t = uint64_t; + + struct fpu_reg_t { + double lo; + double hi; + }; + + #define ScratchpadL1Mask RandomX_CurrentConfig.ScratchpadL1Mask_Calculated + #define ScratchpadL1Mask16 RandomX_CurrentConfig.ScratchpadL1Mask16_Calculated + #define ScratchpadL2Mask RandomX_CurrentConfig.ScratchpadL2Mask_Calculated + #define ScratchpadL2Mask16 RandomX_CurrentConfig.ScratchpadL2Mask16_Calculated + #define ScratchpadL3Mask RandomX_CurrentConfig.ScratchpadL3Mask_Calculated + #define ScratchpadL3Mask64 RandomX_CurrentConfig.ScratchpadL3Mask64_Calculated + constexpr int RegistersCount = 8; + constexpr int RegisterCountFlt = RegistersCount / 2; + constexpr int RegisterNeedsDisplacement = 5; //x86 r13 register + constexpr int RegisterNeedsSib = 4; //x86 r12 register + + inline bool isPowerOf2(uint64_t x) { + return (x & (x - 1)) == 0; + } + + constexpr int mantissaSize = 52; + constexpr int exponentSize = 11; + constexpr uint64_t mantissaMask = (1ULL << mantissaSize) - 1; + constexpr uint64_t exponentMask = (1ULL << exponentSize) - 1; + constexpr int exponentBias = 1023; + constexpr int dynamicExponentBits = 4; + constexpr int staticExponentBits = 4; + constexpr uint64_t constExponentBits = 0x300; + constexpr uint64_t dynamicMantissaMask = (1ULL << (mantissaSize + dynamicExponentBits)) - 1; + + struct MemoryRegisters { + addr_t mx, ma; + uint8_t* memory = nullptr; + }; + + //register file in little-endian byte order + struct RegisterFile { + int_reg_t r[RegistersCount]; + fpu_reg_t f[RegisterCountFlt]; + fpu_reg_t e[RegisterCountFlt]; + fpu_reg_t a[RegisterCountFlt]; + }; + + typedef void(ProgramFunc)(RegisterFile&, MemoryRegisters&, uint8_t* /* scratchpad */, uint64_t); + typedef void(DatasetInitFunc)(randomx_cache* cache, uint8_t* dataset, uint32_t startBlock, uint32_t endBlock); + + typedef void(DatasetDeallocFunc)(randomx_dataset*); + typedef void(CacheDeallocFunc)(randomx_cache*); + typedef void(CacheInitializeFunc)(randomx_cache*, const void*, size_t); +} diff --git a/src/crypto/randomx/configuration.h b/src/crypto/randomx/configuration.h new file mode 100644 index 00000000..678cb2f8 --- /dev/null +++ b/src/crypto/randomx/configuration.h @@ -0,0 +1,47 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +// Increase it if some configs use more cache accesses +#define RANDOMX_CACHE_MAX_ACCESSES 16 + +// Increase it if some configs use larger superscalar latency +#define RANDOMX_SUPERSCALAR_MAX_LATENCY 256 + +// Increase it if some configs use larger cache +#define RANDOMX_CACHE_MAX_SIZE 268435456 + +// Increase it if some configs use larger dataset +#define RANDOMX_DATASET_MAX_SIZE 2181038080 + +// Increase it if some configs use larger programs +#define RANDOMX_PROGRAM_MAX_SIZE 512 + +// Increase it if some configs use larger scratchpad +#define RANDOMX_SCRATCHPAD_L3_MAX_SIZE 2097152 diff --git a/src/crypto/randomx/dataset.cpp b/src/crypto/randomx/dataset.cpp new file mode 100644 index 00000000..3951b55b --- /dev/null +++ b/src/crypto/randomx/dataset.cpp @@ -0,0 +1,189 @@ +/* +Copyright (c) 2018-2019, tevador + +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. +*/ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +#include +#include +#include +#include +#include +#include + +#include "common.hpp" +#include "dataset.hpp" +#include "virtual_memory.hpp" +#include "superscalar.hpp" +#include "blake2_generator.hpp" +#include "reciprocal.h" +#include "blake2/endian.h" +#include "argon2.h" +#include "argon2_core.h" +#include "jit_compiler.hpp" +#include "intrin_portable.h" + +//static_assert(RANDOMX_ARGON_MEMORY % (RANDOMX_ARGON_LANES * ARGON2_SYNC_POINTS) == 0, "RANDOMX_ARGON_MEMORY - invalid value"); +static_assert(ARGON2_BLOCK_SIZE == randomx::ArgonBlockSize, "Unpexpected value of ARGON2_BLOCK_SIZE"); + +namespace randomx { + + template + void deallocCache(randomx_cache* cache) { + if (cache->memory != nullptr) + Allocator::freeMemory(cache->memory, RANDOMX_CACHE_MAX_SIZE); + if (cache->jit != nullptr) + delete cache->jit; + } + + template void deallocCache(randomx_cache* cache); + template void deallocCache(randomx_cache* cache); + + void initCache(randomx_cache* cache, const void* key, size_t keySize) { + uint32_t memory_blocks, segment_length; + argon2_instance_t instance; + argon2_context context; + + context.out = nullptr; + context.outlen = 0; + context.pwd = CONST_CAST(uint8_t *)key; + context.pwdlen = (uint32_t)keySize; + context.salt = CONST_CAST(uint8_t *)RandomX_CurrentConfig.ArgonSalt; + context.saltlen = (uint32_t)strlen(RandomX_CurrentConfig.ArgonSalt); + context.secret = NULL; + context.secretlen = 0; + context.ad = NULL; + context.adlen = 0; + context.t_cost = RandomX_CurrentConfig.ArgonIterations; + context.m_cost = RandomX_CurrentConfig.ArgonMemory; + context.lanes = RandomX_CurrentConfig.ArgonLanes; + context.threads = 1; + context.allocate_cbk = NULL; + context.free_cbk = NULL; + context.flags = ARGON2_DEFAULT_FLAGS; + context.version = ARGON2_VERSION_NUMBER; + + /* 2. Align memory size */ + /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */ + memory_blocks = context.m_cost; + + segment_length = memory_blocks / (context.lanes * ARGON2_SYNC_POINTS); + + instance.version = context.version; + instance.memory = NULL; + instance.passes = context.t_cost; + instance.memory_blocks = memory_blocks; + instance.segment_length = segment_length; + instance.lane_length = segment_length * ARGON2_SYNC_POINTS; + instance.lanes = context.lanes; + instance.threads = context.threads; + instance.type = Argon2_d; + instance.memory = (block*)cache->memory; + + if (instance.threads > instance.lanes) { + instance.threads = instance.lanes; + } + + /* 3. Initialization: Hashing inputs, allocating memory, filling first + * blocks + */ + rxa2_argon_initialize(&instance, &context); + + rxa2_fill_memory_blocks(&instance); + + cache->reciprocalCache.clear(); + randomx::Blake2Generator gen(key, keySize); + for (int i = 0; i < RandomX_CurrentConfig.CacheAccesses; ++i) { + randomx::generateSuperscalar(cache->programs[i], gen); + for (unsigned j = 0; j < cache->programs[i].getSize(); ++j) { + auto& instr = cache->programs[i](j); + if ((SuperscalarInstructionType)instr.opcode == SuperscalarInstructionType::IMUL_RCP) { + auto rcp = randomx_reciprocal(instr.getImm32()); + instr.setImm32(cache->reciprocalCache.size()); + cache->reciprocalCache.push_back(rcp); + } + } + } + } + + void initCacheCompile(randomx_cache* cache, const void* key, size_t keySize) { + initCache(cache, key, keySize); + cache->jit->generateSuperscalarHash(cache->programs, cache->reciprocalCache); + cache->jit->generateDatasetInitCode(); + } + + constexpr uint64_t superscalarMul0 = 6364136223846793005ULL; + constexpr uint64_t superscalarAdd1 = 9298411001130361340ULL; + constexpr uint64_t superscalarAdd2 = 12065312585734608966ULL; + constexpr uint64_t superscalarAdd3 = 9306329213124626780ULL; + constexpr uint64_t superscalarAdd4 = 5281919268842080866ULL; + constexpr uint64_t superscalarAdd5 = 10536153434571861004ULL; + constexpr uint64_t superscalarAdd6 = 3398623926847679864ULL; + constexpr uint64_t superscalarAdd7 = 9549104520008361294ULL; + + static inline uint8_t* getMixBlock(uint64_t registerValue, uint8_t *memory) { + const uint32_t mask = (RandomX_CurrentConfig.ArgonMemory * randomx::ArgonBlockSize) / CacheLineSize - 1; + return memory + (registerValue & mask) * CacheLineSize; + } + + void initDatasetItem(randomx_cache* cache, uint8_t* out, uint64_t itemNumber) { + int_reg_t rl[8]; + uint8_t* mixBlock; + uint64_t registerValue = itemNumber; + rl[0] = (itemNumber + 1) * superscalarMul0; + rl[1] = rl[0] ^ superscalarAdd1; + rl[2] = rl[0] ^ superscalarAdd2; + rl[3] = rl[0] ^ superscalarAdd3; + rl[4] = rl[0] ^ superscalarAdd4; + rl[5] = rl[0] ^ superscalarAdd5; + rl[6] = rl[0] ^ superscalarAdd6; + rl[7] = rl[0] ^ superscalarAdd7; + for (unsigned i = 0; i < RandomX_CurrentConfig.CacheAccesses; ++i) { + mixBlock = getMixBlock(registerValue, cache->memory); + rx_prefetch_nta(mixBlock); + SuperscalarProgram& prog = cache->programs[i]; + + executeSuperscalar(rl, prog, &cache->reciprocalCache); + + for (unsigned q = 0; q < 8; ++q) + rl[q] ^= load64_native(mixBlock + 8 * q); + + registerValue = rl[prog.getAddressRegister()]; + } + + memcpy(out, &rl, CacheLineSize); + } + + void initDataset(randomx_cache* cache, uint8_t* dataset, uint32_t startItem, uint32_t endItem) { + for (uint32_t itemNumber = startItem; itemNumber < endItem; ++itemNumber, dataset += CacheLineSize) + initDatasetItem(cache, dataset, itemNumber); + } +} diff --git a/src/crypto/randomx/dataset.hpp b/src/crypto/randomx/dataset.hpp new file mode 100644 index 00000000..42d4f05e --- /dev/null +++ b/src/crypto/randomx/dataset.hpp @@ -0,0 +1,80 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include +#include +#include "common.hpp" +#include "superscalar_program.hpp" +#include "allocator.hpp" + +/* Global scope for C binding */ +struct randomx_dataset { + uint8_t* memory = nullptr; + randomx::DatasetDeallocFunc* dealloc; +}; + +/* Global scope for C binding */ +struct randomx_cache { + uint8_t* memory = nullptr; + randomx::CacheDeallocFunc* dealloc; + randomx::JitCompiler* jit; + randomx::CacheInitializeFunc* initialize; + randomx::DatasetInitFunc* datasetInit; + randomx::SuperscalarProgram programs[RANDOMX_CACHE_MAX_ACCESSES]; + std::vector reciprocalCache; + + bool isInitialized() { + return programs[0].getSize() != 0; + } +}; + +//A pointer to a standard-layout struct object points to its initial member +static_assert(std::is_standard_layout(), "randomx_dataset must be a standard-layout struct"); +static_assert(std::is_standard_layout(), "randomx_cache must be a standard-layout struct"); + +namespace randomx { + + using DefaultAllocator = AlignedAllocator; + + template + void deallocDataset(randomx_dataset* dataset) { + if (dataset->memory != nullptr) + Allocator::freeMemory(dataset->memory, RANDOMX_DATASET_MAX_SIZE); + } + + template + void deallocCache(randomx_cache* cache); + + void initCache(randomx_cache*, const void*, size_t); + void initCacheCompile(randomx_cache*, const void*, size_t); + void initDatasetItem(randomx_cache* cache, uint8_t* out, uint64_t blockNumber); + void initDataset(randomx_cache* cache, uint8_t* dataset, uint32_t startBlock, uint32_t endBlock); +} diff --git a/src/crypto/randomx/instruction.hpp b/src/crypto/randomx/instruction.hpp new file mode 100644 index 00000000..1904afc0 --- /dev/null +++ b/src/crypto/randomx/instruction.hpp @@ -0,0 +1,102 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include +#include "blake2/endian.h" + +namespace randomx { + + class Instruction; + + enum class InstructionType : uint16_t { + IADD_RS = 0, + IADD_M = 1, + ISUB_R = 2, + ISUB_M = 3, + IMUL_R = 4, + IMUL_M = 5, + IMULH_R = 6, + IMULH_M = 7, + ISMULH_R = 8, + ISMULH_M = 9, + IMUL_RCP = 10, + INEG_R = 11, + IXOR_R = 12, + IXOR_M = 13, + IROR_R = 14, + IROL_R = 15, + ISWAP_R = 16, + FSWAP_R = 17, + FADD_R = 18, + FADD_M = 19, + FSUB_R = 20, + FSUB_M = 21, + FSCAL_R = 22, + FMUL_R = 23, + FDIV_M = 24, + FSQRT_R = 25, + CBRANCH = 26, + CFROUND = 27, + ISTORE = 28, + NOP = 29, + }; + + class Instruction { + public: + uint32_t getImm32() const { + return load32(&imm32); + } + void setImm32(uint32_t val) { + return store32(&imm32, val); + } + int getModMem() const { + return mod % 4; //bits 0-1 + } + int getModShift() const { + return (mod >> 2) % 4; //bits 2-3 + } + int getModCond() const { + return mod >> 4; //bits 4-7 + } + void setMod(uint8_t val) { + mod = val; + } + + uint8_t opcode; + uint8_t dst; + uint8_t src; + uint8_t mod; + uint32_t imm32; + }; + + static_assert(sizeof(Instruction) == 8, "Invalid size of struct randomx::Instruction"); + static_assert(std::is_standard_layout(), "randomx::Instruction must be a standard-layout struct"); +} diff --git a/src/crypto/randomx/instructions_portable.cpp b/src/crypto/randomx/instructions_portable.cpp new file mode 100644 index 00000000..797c84c4 --- /dev/null +++ b/src/crypto/randomx/instructions_portable.cpp @@ -0,0 +1,193 @@ +/* +Copyright (c) 2018-2019, tevador + +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 +#include +#include "common.hpp" +#include "intrin_portable.h" +#include "blake2/endian.h" + +#if defined(__SIZEOF_INT128__) + typedef unsigned __int128 uint128_t; + typedef __int128 int128_t; + uint64_t mulh(uint64_t a, uint64_t b) { + return ((uint128_t)a * b) >> 64; + } + int64_t smulh(int64_t a, int64_t b) { + return ((int128_t)a * b) >> 64; + } + #define HAVE_MULH + #define HAVE_SMULH +#endif + +#if defined(_MSC_VER) + #define HAS_VALUE(X) X ## 0 + #define EVAL_DEFINE(X) HAS_VALUE(X) + #include + #include + + uint64_t rotl(uint64_t x, unsigned int c) { + return _rotl64(x, c); + } + uint64_t rotr(uint64_t x, unsigned int c) { + return _rotr64(x, c); + } + #define HAVE_ROTL + #define HAVE_ROTR + + #if EVAL_DEFINE(__MACHINEARM64_X64(1)) + uint64_t mulh(uint64_t a, uint64_t b) { + return __umulh(a, b); + } + #define HAVE_MULH + #endif + + #if EVAL_DEFINE(__MACHINEX64(1)) + int64_t smulh(int64_t a, int64_t b) { + int64_t hi; + _mul128(a, b, &hi); + return hi; + } + #define HAVE_SMULH + #endif + + static void setRoundMode_(uint32_t mode) { + _controlfp(mode, _MCW_RC); + } + #define HAVE_SETROUNDMODE_IMPL +#endif + +#ifndef HAVE_SETROUNDMODE_IMPL + static void setRoundMode_(uint32_t mode) { + fesetround(mode); + } +#endif + +#ifndef HAVE_ROTR + uint64_t rotr(uint64_t a, unsigned int b) { + return (a >> b) | (a << (-b & 63)); + } + #define HAVE_ROTR +#endif + +#ifndef HAVE_ROTL + uint64_t rotl(uint64_t a, unsigned int b) { + return (a << b) | (a >> (-b & 63)); + } + #define HAVE_ROTL +#endif + +#ifndef HAVE_MULH + #define LO(x) ((x)&0xffffffff) + #define HI(x) ((x)>>32) + uint64_t mulh(uint64_t a, uint64_t b) { + uint64_t ah = HI(a), al = LO(a); + uint64_t bh = HI(b), bl = LO(b); + uint64_t x00 = al * bl; + uint64_t x01 = al * bh; + uint64_t x10 = ah * bl; + uint64_t x11 = ah * bh; + uint64_t m1 = LO(x10) + LO(x01) + HI(x00); + uint64_t m2 = HI(x10) + HI(x01) + LO(x11) + HI(m1); + uint64_t m3 = HI(x11) + HI(m2); + + return (m3 << 32) + LO(m2); + } + #define HAVE_MULH +#endif + +#ifndef HAVE_SMULH + int64_t smulh(int64_t a, int64_t b) { + int64_t hi = mulh(a, b); + if (a < 0LL) hi -= b; + if (b < 0LL) hi -= a; + return hi; + } + #define HAVE_SMULH +#endif + +#ifdef RANDOMX_DEFAULT_FENV + +void rx_reset_float_state() { + setRoundMode_(FE_TONEAREST); + rx_set_double_precision(); //set precision to 53 bits if needed by the platform +} + +void rx_set_rounding_mode(uint32_t mode) { + switch (mode & 3) { + case RoundDown: + setRoundMode_(FE_DOWNWARD); + break; + case RoundUp: + setRoundMode_(FE_UPWARD); + break; + case RoundToZero: + setRoundMode_(FE_TOWARDZERO); + break; + case RoundToNearest: + setRoundMode_(FE_TONEAREST); + break; + default: + UNREACHABLE; + } +} + +#endif + +#ifdef RANDOMX_USE_X87 + +#ifdef _M_IX86 + +void rx_set_double_precision() { + _control87(_PC_53, _MCW_PC); +} + +#elif defined(__i386) + +void rx_set_double_precision() { + uint16_t volatile x87cw; + asm volatile("fstcw %0" : "=m" (x87cw)); + x87cw &= ~0x300; + x87cw |= 0x200; + asm volatile("fldcw %0" : : "m" (x87cw)); +} + +#endif + +#endif //RANDOMX_USE_X87 + +union double_ser_t { + double f; + uint64_t i; +}; + +double loadDoublePortable(const void* addr) { + double_ser_t ds; + ds.i = load64(addr); + return ds.f; +} diff --git a/src/crypto/randomx/intrin_portable.h b/src/crypto/randomx/intrin_portable.h new file mode 100644 index 00000000..b4f1b503 --- /dev/null +++ b/src/crypto/randomx/intrin_portable.h @@ -0,0 +1,605 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include "blake2/endian.h" + +constexpr int32_t unsigned32ToSigned2sCompl(uint32_t x) { + return (-1 == ~0) ? (int32_t)x : (x > INT32_MAX ? (-(int32_t)(UINT32_MAX - x) - 1) : (int32_t)x); +} + +constexpr int64_t unsigned64ToSigned2sCompl(uint64_t x) { + return (-1 == ~0) ? (int64_t)x : (x > INT64_MAX ? (-(int64_t)(UINT64_MAX - x) - 1) : (int64_t)x); +} + +constexpr uint64_t signExtend2sCompl(uint32_t x) { + return (-1 == ~0) ? (int64_t)(int32_t)(x) : (x > INT32_MAX ? (x | 0xffffffff00000000ULL) : (uint64_t)x); +} + +constexpr int RoundToNearest = 0; +constexpr int RoundDown = 1; +constexpr int RoundUp = 2; +constexpr int RoundToZero = 3; + +//MSVC doesn't define __SSE2__, so we have to define it manually if SSE2 is available +#if !defined(__SSE2__) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP == 2)) +#define __SSE2__ 1 +#endif + +//MSVC doesn't define __AES__ +#if defined(_MSC_VER) && defined(__SSE2__) +#define __AES__ +#endif + +//the library "sqrt" function provided by MSVC for x86 targets doesn't give +//the correct results, so we have to use inline assembly to call x87 fsqrt directly +#if !defined(__SSE2__) +#if defined(_M_IX86) +inline double __cdecl rx_sqrt(double x) { + __asm { + fld x + fsqrt + } +} +#define rx_sqrt rx_sqrt + +void rx_set_double_precision(); +#define RANDOMX_USE_X87 + +#elif defined(__i386) + +void rx_set_double_precision(); +#define RANDOMX_USE_X87 + +#endif +#endif //__SSE2__ + +#if !defined(rx_sqrt) +#define rx_sqrt sqrt +#endif + +#if !defined(RANDOMX_USE_X87) +#define rx_set_double_precision(x) +#endif + +#ifdef __SSE2__ +#ifdef __GNUC__ +#include +#else +#include +#endif + +typedef __m128i rx_vec_i128; +typedef __m128d rx_vec_f128; + +#define rx_aligned_alloc(a, b) _mm_malloc(a,b) +#define rx_aligned_free(a) _mm_free(a) +#define rx_prefetch_nta(x) _mm_prefetch((const char *)(x), _MM_HINT_NTA) + +#define rx_load_vec_f128 _mm_load_pd +#define rx_store_vec_f128 _mm_store_pd +#define rx_add_vec_f128 _mm_add_pd +#define rx_sub_vec_f128 _mm_sub_pd +#define rx_mul_vec_f128 _mm_mul_pd +#define rx_div_vec_f128 _mm_div_pd +#define rx_sqrt_vec_f128 _mm_sqrt_pd + +FORCE_INLINE rx_vec_f128 rx_swap_vec_f128(rx_vec_f128 a) { + return _mm_shuffle_pd(a, a, 1); +} + +FORCE_INLINE rx_vec_f128 rx_set_vec_f128(uint64_t x1, uint64_t x0) { + return _mm_castsi128_pd(_mm_set_epi64x(x1, x0)); +} + +FORCE_INLINE rx_vec_f128 rx_set1_vec_f128(uint64_t x) { + return _mm_castsi128_pd(_mm_set1_epi64x(x)); +} + +#define rx_xor_vec_f128 _mm_xor_pd +#define rx_and_vec_f128 _mm_and_pd +#define rx_or_vec_f128 _mm_or_pd + +#ifdef __AES__ + +#define rx_aesenc_vec_i128 _mm_aesenc_si128 +#define rx_aesdec_vec_i128 _mm_aesdec_si128 + +#define HAVE_AES + +#endif //__AES__ + +FORCE_INLINE int rx_vec_i128_x(rx_vec_i128 a) { + return _mm_cvtsi128_si32(a); +} + +FORCE_INLINE int rx_vec_i128_y(rx_vec_i128 a) { + return _mm_cvtsi128_si32(_mm_shuffle_epi32(a, 0x55)); +} + +FORCE_INLINE int rx_vec_i128_z(rx_vec_i128 a) { + return _mm_cvtsi128_si32(_mm_shuffle_epi32(a, 0xaa)); +} + +FORCE_INLINE int rx_vec_i128_w(rx_vec_i128 a) { + return _mm_cvtsi128_si32(_mm_shuffle_epi32(a, 0xff)); +} + +#define rx_set_int_vec_i128 _mm_set_epi32 +#define rx_xor_vec_i128 _mm_xor_si128 +#define rx_load_vec_i128 _mm_load_si128 +#define rx_store_vec_i128 _mm_store_si128 + +FORCE_INLINE rx_vec_f128 rx_cvt_packed_int_vec_f128(const void* addr) { + __m128i ix = _mm_loadl_epi64((const __m128i*)addr); + return _mm_cvtepi32_pd(ix); +} + +constexpr uint32_t rx_mxcsr_default = 0x9FC0; //Flush to zero, denormals are zero, default rounding mode, all exceptions disabled + +FORCE_INLINE void rx_reset_float_state() { + _mm_setcsr(rx_mxcsr_default); +} + +FORCE_INLINE void rx_set_rounding_mode(uint32_t mode) { + _mm_setcsr(rx_mxcsr_default | (mode << 13)); +} + +#elif defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__) //sadly only POWER7 and newer will be able to use SIMD acceleration. Earlier processors cant use doubles or 64 bit integers with SIMD +#include +#include +#include +#include +#undef vector +#undef pixel +#undef bool + +typedef __vector uint8_t __m128i; +typedef __vector uint32_t __m128l; +typedef __vector int __m128li; +typedef __vector uint64_t __m128ll; +typedef __vector double __m128d; + +typedef __m128i rx_vec_i128; +typedef __m128d rx_vec_f128; +typedef union{ + rx_vec_i128 i; + rx_vec_f128 d; + uint64_t u64[2]; + double d64[2]; + uint32_t u32[4]; + int i32[4]; +} vec_u; + +#define rx_aligned_alloc(a, b) malloc(a) +#define rx_aligned_free(a) free(a) +#define rx_prefetch_nta(x) + +/* Splat 64-bit long long to 2 64-bit long longs */ +FORCE_INLINE __m128i vec_splat2sd (int64_t scalar) +{ return (__m128i) vec_splats (scalar); } + +FORCE_INLINE rx_vec_f128 rx_load_vec_f128(const double* pd) { +#if defined(NATIVE_LITTLE_ENDIAN) + return (rx_vec_f128)vec_vsx_ld(0,pd); +#else + vec_u t; + t.u64[0] = load64(pd + 0); + t.u64[1] = load64(pd + 1); + return (rx_vec_f128)t.d; +#endif +} + +FORCE_INLINE void rx_store_vec_f128(double* mem_addr, rx_vec_f128 a) { +#if defined(NATIVE_LITTLE_ENDIAN) + vec_vsx_st(a,0,(rx_vec_f128*)mem_addr); +#else + vec_u _a; + _a.d = a; + store64(mem_addr + 0, _a.u64[0]); + store64(mem_addr + 1, _a.u64[1]); +#endif +} + +FORCE_INLINE rx_vec_f128 rx_swap_vec_f128(rx_vec_f128 a) { + return (rx_vec_f128)vec_perm((__m128i)a,(__m128i)a,(__m128i){8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7}); +} + +FORCE_INLINE rx_vec_f128 rx_add_vec_f128(rx_vec_f128 a, rx_vec_f128 b) { + return (rx_vec_f128)vec_add(a,b); +} + +FORCE_INLINE rx_vec_f128 rx_sub_vec_f128(rx_vec_f128 a, rx_vec_f128 b) { + return (rx_vec_f128)vec_sub(a,b); +} + +FORCE_INLINE rx_vec_f128 rx_mul_vec_f128(rx_vec_f128 a, rx_vec_f128 b) { + return (rx_vec_f128)vec_mul(a,b); +} + +FORCE_INLINE rx_vec_f128 rx_div_vec_f128(rx_vec_f128 a, rx_vec_f128 b) { + return (rx_vec_f128)vec_div(a,b); +} + +FORCE_INLINE rx_vec_f128 rx_sqrt_vec_f128(rx_vec_f128 a) { + return (rx_vec_f128)vec_sqrt(a); +} + +FORCE_INLINE rx_vec_i128 rx_set1_long_vec_i128(uint64_t a) { + return (rx_vec_i128)vec_splat2sd(a); +} + +FORCE_INLINE rx_vec_f128 rx_vec_i128_vec_f128(rx_vec_i128 a) { + return (rx_vec_f128)a; +} + +FORCE_INLINE rx_vec_f128 rx_set_vec_f128(uint64_t x1, uint64_t x0) { + return (rx_vec_f128)(__m128ll){x0,x1}; +} + +FORCE_INLINE rx_vec_f128 rx_set1_vec_f128(uint64_t x) { + return (rx_vec_f128)vec_splat2sd(x); +} + +FORCE_INLINE rx_vec_f128 rx_xor_vec_f128(rx_vec_f128 a, rx_vec_f128 b) { + return (rx_vec_f128)vec_xor(a,b); +} + +FORCE_INLINE rx_vec_f128 rx_and_vec_f128(rx_vec_f128 a, rx_vec_f128 b) { + return (rx_vec_f128)vec_and(a,b); +} + +FORCE_INLINE rx_vec_f128 rx_or_vec_f128(rx_vec_f128 a, rx_vec_f128 b) { + return (rx_vec_f128)vec_or(a,b); +} + +#if defined(__CRYPTO__) + +FORCE_INLINE __m128ll vrev(__m128i v){ +#if defined(NATIVE_LITTLE_ENDIAN) + return (__m128ll)vec_perm((__m128i)v,(__m128i){0},(__m128i){15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}); +#else + return (__m128ll)vec_perm((__m128i)v,(__m128i){0},(__m128i){3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12}); +#endif +} + +FORCE_INLINE rx_vec_i128 rx_aesenc_vec_i128(rx_vec_i128 v, rx_vec_i128 rkey) { + __m128ll _v = vrev(v); + __m128ll _rkey = vrev(rkey); + __m128ll result = vrev((__m128i)__builtin_crypto_vcipher(_v,_rkey)); + return (rx_vec_i128)result; +} + +FORCE_INLINE rx_vec_i128 rx_aesdec_vec_i128(rx_vec_i128 v, rx_vec_i128 rkey) { + __m128ll _v = vrev(v); + __m128ll zero = (__m128ll){0}; + __m128ll out = vrev((__m128i)__builtin_crypto_vncipher(_v,zero)); + return (rx_vec_i128)vec_xor((__m128i)out,rkey); +} +#define HAVE_AES + +#endif //__CRYPTO__ + +FORCE_INLINE int rx_vec_i128_x(rx_vec_i128 a) { + vec_u _a; + _a.i = a; + return _a.i32[0]; +} + +FORCE_INLINE int rx_vec_i128_y(rx_vec_i128 a) { + vec_u _a; + _a.i = a; + return _a.i32[1]; +} + +FORCE_INLINE int rx_vec_i128_z(rx_vec_i128 a) { + vec_u _a; + _a.i = a; + return _a.i32[2]; +} + +FORCE_INLINE int rx_vec_i128_w(rx_vec_i128 a) { + vec_u _a; + _a.i = a; + return _a.i32[3]; +} + +FORCE_INLINE rx_vec_i128 rx_set_int_vec_i128(int _I3, int _I2, int _I1, int _I0) { + return (rx_vec_i128)((__m128li){_I0,_I1,_I2,_I3}); +}; + +FORCE_INLINE rx_vec_i128 rx_xor_vec_i128(rx_vec_i128 _A, rx_vec_i128 _B) { + return (rx_vec_i128)vec_xor(_A,_B); +} + +FORCE_INLINE rx_vec_i128 rx_load_vec_i128(rx_vec_i128 const *_P) { +#if defined(NATIVE_LITTLE_ENDIAN) + return *_P; +#else + uint32_t* ptr = (uint32_t*)_P; + vec_u c; + c.u32[0] = load32(ptr + 0); + c.u32[1] = load32(ptr + 1); + c.u32[2] = load32(ptr + 2); + c.u32[3] = load32(ptr + 3); + return (rx_vec_i128)c.i; +#endif +} + +FORCE_INLINE void rx_store_vec_i128(rx_vec_i128 *_P, rx_vec_i128 _B) { +#if defined(NATIVE_LITTLE_ENDIAN) + *_P = _B; +#else + uint32_t* ptr = (uint32_t*)_P; + vec_u B; + B.i = _B; + store32(ptr + 0, B.u32[0]); + store32(ptr + 1, B.u32[1]); + store32(ptr + 2, B.u32[2]); + store32(ptr + 3, B.u32[3]); +#endif +} + +FORCE_INLINE rx_vec_f128 rx_cvt_packed_int_vec_f128(const void* addr) { + vec_u x; + x.d64[0] = (double)unsigned32ToSigned2sCompl(load32((uint8_t*)addr + 0)); + x.d64[1] = (double)unsigned32ToSigned2sCompl(load32((uint8_t*)addr + 4)); + return (rx_vec_f128)x.d; +} + +#define RANDOMX_DEFAULT_FENV + +void rx_reset_float_state(); + +void rx_set_rounding_mode(uint32_t mode); + +#else //end altivec + +#include +#include +#include +#include + +typedef union { + uint64_t u64[2]; + uint32_t u32[4]; + uint16_t u16[8]; + uint8_t u8[16]; +} rx_vec_i128; + +typedef union { + struct { + double lo; + double hi; + }; + rx_vec_i128 i; +} rx_vec_f128; + +#define rx_aligned_alloc(a, b) malloc(a) +#define rx_aligned_free(a) free(a) +#define rx_prefetch_nta(x) + +FORCE_INLINE rx_vec_f128 rx_load_vec_f128(const double* pd) { + rx_vec_f128 x; + x.i.u64[0] = load64(pd + 0); + x.i.u64[1] = load64(pd + 1); + return x; +} + +FORCE_INLINE void rx_store_vec_f128(double* mem_addr, rx_vec_f128 a) { + store64(mem_addr + 0, a.i.u64[0]); + store64(mem_addr + 1, a.i.u64[1]); +} + +FORCE_INLINE rx_vec_f128 rx_swap_vec_f128(rx_vec_f128 a) { + double temp = a.hi; + a.hi = a.lo; + a.lo = temp; + return a; +} + +FORCE_INLINE rx_vec_f128 rx_add_vec_f128(rx_vec_f128 a, rx_vec_f128 b) { + rx_vec_f128 x; + x.lo = a.lo + b.lo; + x.hi = a.hi + b.hi; + return x; +} + +FORCE_INLINE rx_vec_f128 rx_sub_vec_f128(rx_vec_f128 a, rx_vec_f128 b) { + rx_vec_f128 x; + x.lo = a.lo - b.lo; + x.hi = a.hi - b.hi; + return x; +} + +FORCE_INLINE rx_vec_f128 rx_mul_vec_f128(rx_vec_f128 a, rx_vec_f128 b) { + rx_vec_f128 x; + x.lo = a.lo * b.lo; + x.hi = a.hi * b.hi; + return x; +} + +FORCE_INLINE rx_vec_f128 rx_div_vec_f128(rx_vec_f128 a, rx_vec_f128 b) { + rx_vec_f128 x; + x.lo = a.lo / b.lo; + x.hi = a.hi / b.hi; + return x; +} + +FORCE_INLINE rx_vec_f128 rx_sqrt_vec_f128(rx_vec_f128 a) { + rx_vec_f128 x; + x.lo = rx_sqrt(a.lo); + x.hi = rx_sqrt(a.hi); + return x; +} + +FORCE_INLINE rx_vec_i128 rx_set1_long_vec_i128(uint64_t a) { + rx_vec_i128 x; + x.u64[0] = a; + x.u64[1] = a; + return x; +} + +FORCE_INLINE rx_vec_f128 rx_vec_i128_vec_f128(rx_vec_i128 a) { + rx_vec_f128 x; + x.i = a; + return x; +} + +FORCE_INLINE rx_vec_f128 rx_set_vec_f128(uint64_t x1, uint64_t x0) { + rx_vec_f128 v; + v.i.u64[0] = x0; + v.i.u64[1] = x1; + return v; +} + +FORCE_INLINE rx_vec_f128 rx_set1_vec_f128(uint64_t x) { + rx_vec_f128 v; + v.i.u64[0] = x; + v.i.u64[1] = 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]; + x.i.u64[1] = a.i.u64[1] ^ b.i.u64[1]; + return x; +} + +FORCE_INLINE rx_vec_f128 rx_and_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]; + x.i.u64[1] = a.i.u64[1] & b.i.u64[1]; + return x; +} + +FORCE_INLINE rx_vec_f128 rx_or_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]; + x.i.u64[1] = a.i.u64[1] | b.i.u64[1]; + return x; +} + +FORCE_INLINE int rx_vec_i128_x(rx_vec_i128 a) { + return a.u32[0]; +} + +FORCE_INLINE int rx_vec_i128_y(rx_vec_i128 a) { + return a.u32[1]; +} + +FORCE_INLINE int rx_vec_i128_z(rx_vec_i128 a) { + return a.u32[2]; +} + +FORCE_INLINE int rx_vec_i128_w(rx_vec_i128 a) { + return a.u32[3]; +} + +FORCE_INLINE rx_vec_i128 rx_set_int_vec_i128(int _I3, int _I2, int _I1, int _I0) { + rx_vec_i128 v; + v.u32[0] = _I0; + v.u32[1] = _I1; + v.u32[2] = _I2; + v.u32[3] = _I3; + return v; +}; + +FORCE_INLINE rx_vec_i128 rx_xor_vec_i128(rx_vec_i128 _A, rx_vec_i128 _B) { + rx_vec_i128 c; + c.u32[0] = _A.u32[0] ^ _B.u32[0]; + c.u32[1] = _A.u32[1] ^ _B.u32[1]; + c.u32[2] = _A.u32[2] ^ _B.u32[2]; + c.u32[3] = _A.u32[3] ^ _B.u32[3]; + return c; +} + +FORCE_INLINE rx_vec_i128 rx_load_vec_i128(rx_vec_i128 const*_P) { +#if defined(NATIVE_LITTLE_ENDIAN) + return *_P; +#else + uint32_t* ptr = (uint32_t*)_P; + rx_vec_i128 c; + c.u32[0] = load32(ptr + 0); + c.u32[1] = load32(ptr + 1); + c.u32[2] = load32(ptr + 2); + c.u32[3] = load32(ptr + 3); + return c; +#endif +} + +FORCE_INLINE void rx_store_vec_i128(rx_vec_i128 *_P, rx_vec_i128 _B) { +#if defined(NATIVE_LITTLE_ENDIAN) + *_P = _B; +#else + uint32_t* ptr = (uint32_t*)_P; + store32(ptr + 0, _B.u32[0]); + store32(ptr + 1, _B.u32[1]); + store32(ptr + 2, _B.u32[2]); + store32(ptr + 3, _B.u32[3]); +#endif +} + +FORCE_INLINE rx_vec_f128 rx_cvt_packed_int_vec_f128(const void* addr) { + rx_vec_f128 x; + x.lo = (double)unsigned32ToSigned2sCompl(load32((uint8_t*)addr + 0)); + x.hi = (double)unsigned32ToSigned2sCompl(load32((uint8_t*)addr + 4)); + return x; +} + +#define RANDOMX_DEFAULT_FENV + +void rx_reset_float_state(); + +void rx_set_rounding_mode(uint32_t mode); + +#endif + +#ifndef HAVE_AES +static const char* platformError = "Platform doesn't support hardware AES"; + +#include + +FORCE_INLINE rx_vec_i128 rx_aesenc_vec_i128(rx_vec_i128 v, rx_vec_i128 rkey) { + throw std::runtime_error(platformError); +} + +FORCE_INLINE rx_vec_i128 rx_aesdec_vec_i128(rx_vec_i128 v, rx_vec_i128 rkey) { + throw std::runtime_error(platformError); +} +#endif + +double loadDoublePortable(const void* addr); +uint64_t mulh(uint64_t, uint64_t); +int64_t smulh(int64_t, int64_t); +uint64_t rotl(uint64_t, unsigned int); +uint64_t rotr(uint64_t, unsigned int); diff --git a/src/crypto/randomx/jit_compiler.hpp b/src/crypto/randomx/jit_compiler.hpp new file mode 100644 index 00000000..bd9c2b0e --- /dev/null +++ b/src/crypto/randomx/jit_compiler.hpp @@ -0,0 +1,37 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#if defined(_M_X64) || defined(__x86_64__) +#include "jit_compiler_x86.hpp" +#elif defined(__aarch64__) +#include "jit_compiler_a64.hpp" +#else +#include "jit_compiler_fallback.hpp" +#endif diff --git a/src/crypto/randomx/jit_compiler_a64.hpp b/src/crypto/randomx/jit_compiler_a64.hpp new file mode 100644 index 00000000..58aa25c4 --- /dev/null +++ b/src/crypto/randomx/jit_compiler_a64.hpp @@ -0,0 +1,73 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include +#include +#include "common.hpp" + +namespace randomx { + + class Program; + class ProgramConfiguration; + class SuperscalarProgram; + + class JitCompilerA64 { + public: + JitCompilerA64() { + throw std::runtime_error("ARM64 JIT compiler is not implemented yet."); + } + void generateProgram(Program&, ProgramConfiguration&) { + + } + void generateProgramLight(Program&, ProgramConfiguration&, uint32_t) { + + } + template + void generateSuperscalarHash(SuperscalarProgram(&programs)[N], std::vector &) { + + } + void generateDatasetInitCode() { + + } + ProgramFunc* getProgramFunc() { + return nullptr; + } + DatasetInitFunc* getDatasetInitFunc() { + return nullptr; + } + uint8_t* getCode() { + return nullptr; + } + size_t getCodeSize() { + return 0; + } + }; +} \ No newline at end of file diff --git a/src/crypto/randomx/jit_compiler_fallback.hpp b/src/crypto/randomx/jit_compiler_fallback.hpp new file mode 100644 index 00000000..8103a632 --- /dev/null +++ b/src/crypto/randomx/jit_compiler_fallback.hpp @@ -0,0 +1,73 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include +#include +#include "common.hpp" + +namespace randomx { + + class Program; + class ProgramConfiguration; + class SuperscalarProgram; + + class JitCompilerFallback { + public: + JitCompilerFallback() { + throw std::runtime_error("JIT compilation is not supported on this platform"); + } + void generateProgram(Program&, ProgramConfiguration&) { + + } + void generateProgramLight(Program&, ProgramConfiguration&, uint32_t) { + + } + template + void generateSuperscalarHash(SuperscalarProgram(&programs)[N], std::vector &) { + + } + void generateDatasetInitCode() { + + } + ProgramFunc* getProgramFunc() { + return nullptr; + } + DatasetInitFunc* getDatasetInitFunc() { + return nullptr; + } + uint8_t* getCode() { + return nullptr; + } + size_t getCodeSize() { + return 0; + } + }; +} \ No newline at end of file diff --git a/src/crypto/randomx/jit_compiler_x86.cpp b/src/crypto/randomx/jit_compiler_x86.cpp new file mode 100644 index 00000000..8870a018 --- /dev/null +++ b/src/crypto/randomx/jit_compiler_x86.cpp @@ -0,0 +1,774 @@ +/* +Copyright (c) 2018-2019, tevador + +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 +#include +#include +#include "jit_compiler_x86.hpp" +#include "jit_compiler_x86_static.hpp" +#include "superscalar.hpp" +#include "program.hpp" +#include "reciprocal.h" +#include "virtual_memory.hpp" + +namespace randomx { + /* + + REGISTER ALLOCATION: + + ; rax -> temporary + ; rbx -> iteration counter "ic" + ; rcx -> temporary + ; rdx -> temporary + ; rsi -> scratchpad pointer + ; rdi -> dataset pointer + ; rbp -> memory registers "ma" (high 32 bits), "mx" (low 32 bits) + ; rsp -> stack pointer + ; r8 -> "r0" + ; r9 -> "r1" + ; r10 -> "r2" + ; r11 -> "r3" + ; r12 -> "r4" + ; r13 -> "r5" + ; r14 -> "r6" + ; r15 -> "r7" + ; xmm0 -> "f0" + ; xmm1 -> "f1" + ; xmm2 -> "f2" + ; xmm3 -> "f3" + ; xmm4 -> "e0" + ; xmm5 -> "e1" + ; xmm6 -> "e2" + ; xmm7 -> "e3" + ; xmm8 -> "a0" + ; xmm9 -> "a1" + ; xmm10 -> "a2" + ; xmm11 -> "a3" + ; xmm12 -> temporary + ; xmm13 -> E 'and' mask = 0x00ffffffffffffff00ffffffffffffff + ; xmm14 -> E 'or' mask = 0x3*00000000******3*00000000****** + ; xmm15 -> scale mask = 0x81f000000000000081f0000000000000 + + */ + + const uint8_t* codePrologue = (uint8_t*)&randomx_program_prologue; + const uint8_t* codeLoopBegin = (uint8_t*)&randomx_program_loop_begin; + const uint8_t* codeLoopLoad = (uint8_t*)&randomx_program_loop_load; + const uint8_t* codeProgamStart = (uint8_t*)&randomx_program_start; + const uint8_t* codeReadDataset = (uint8_t*)&randomx_program_read_dataset; + const uint8_t* codeReadDatasetLightSshInit = (uint8_t*)&randomx_program_read_dataset_sshash_init; + const uint8_t* codeReadDatasetLightSshFin = (uint8_t*)&randomx_program_read_dataset_sshash_fin; + const uint8_t* codeDatasetInit = (uint8_t*)&randomx_dataset_init; + const uint8_t* codeLoopStore = (uint8_t*)&randomx_program_loop_store; + const uint8_t* codeLoopEnd = (uint8_t*)&randomx_program_loop_end; + const uint8_t* codeEpilogue = (uint8_t*)&randomx_program_epilogue; + const uint8_t* codeProgramEnd = (uint8_t*)&randomx_program_end; + const uint8_t* codeShhLoad = (uint8_t*)&randomx_sshash_load; + const uint8_t* codeShhPrefetch = (uint8_t*)&randomx_sshash_prefetch; + const uint8_t* codeShhEnd = (uint8_t*)&randomx_sshash_end; + const uint8_t* codeShhInit = (uint8_t*)&randomx_sshash_init; + + const int32_t prologueSize = codeLoopBegin - codePrologue; + const int32_t loopLoadSize = codeProgamStart - codeLoopLoad; + const int32_t readDatasetSize = codeReadDatasetLightSshInit - codeReadDataset; + const int32_t readDatasetLightInitSize = codeReadDatasetLightSshFin - codeReadDatasetLightSshInit; + const int32_t readDatasetLightFinSize = codeLoopStore - codeReadDatasetLightSshFin; + const int32_t loopStoreSize = codeLoopEnd - codeLoopStore; + const int32_t datasetInitSize = codeEpilogue - codeDatasetInit; + const int32_t epilogueSize = codeShhLoad - codeEpilogue; + const int32_t codeSshLoadSize = codeShhPrefetch - codeShhLoad; + const int32_t codeSshPrefetchSize = codeShhEnd - codeShhPrefetch; + const int32_t codeSshInitSize = codeProgramEnd - codeShhInit; + + const int32_t epilogueOffset = CodeSize - epilogueSize; + constexpr int32_t superScalarHashOffset = 32768; + + static const uint8_t REX_ADD_RR[] = { 0x4d, 0x03 }; + static const uint8_t REX_ADD_RM[] = { 0x4c, 0x03 }; + static const uint8_t REX_SUB_RR[] = { 0x4d, 0x2b }; + static const uint8_t REX_SUB_RM[] = { 0x4c, 0x2b }; + static const uint8_t REX_MOV_RR[] = { 0x41, 0x8b }; + static const uint8_t REX_MOV_RR64[] = { 0x49, 0x8b }; + static const uint8_t REX_MOV_R64R[] = { 0x4c, 0x8b }; + static const uint8_t REX_IMUL_RR[] = { 0x4d, 0x0f, 0xaf }; + static const uint8_t REX_IMUL_RRI[] = { 0x4d, 0x69 }; + static const uint8_t REX_IMUL_RM[] = { 0x4c, 0x0f, 0xaf }; + static const uint8_t REX_MUL_R[] = { 0x49, 0xf7 }; + static const uint8_t REX_MUL_M[] = { 0x48, 0xf7 }; + static const uint8_t REX_81[] = { 0x49, 0x81 }; + static const uint8_t AND_EAX_I = 0x25; + static const uint8_t MOV_EAX_I = 0xb8; + static const uint8_t MOV_RAX_I[] = { 0x48, 0xb8 }; + static const uint8_t MOV_RCX_I[] = { 0x48, 0xb9 }; + static const uint8_t REX_LEA[] = { 0x4f, 0x8d }; + static const uint8_t REX_MUL_MEM[] = { 0x48, 0xf7, 0x24, 0x0e }; + static const uint8_t REX_IMUL_MEM[] = { 0x48, 0xf7, 0x2c, 0x0e }; + static const uint8_t REX_SHR_RAX[] = { 0x48, 0xc1, 0xe8 }; + static const uint8_t RAX_ADD_SBB_1[] = { 0x48, 0x83, 0xC0, 0x01, 0x48, 0x83, 0xD8, 0x00 }; + static const uint8_t MUL_RCX[] = { 0x48, 0xf7, 0xe1 }; + static const uint8_t REX_SHR_RDX[] = { 0x48, 0xc1, 0xea }; + static const uint8_t REX_SH[] = { 0x49, 0xc1 }; + static const uint8_t MOV_RCX_RAX_SAR_RCX_63[] = { 0x48, 0x89, 0xc1, 0x48, 0xc1, 0xf9, 0x3f }; + static const uint8_t AND_ECX_I[] = { 0x81, 0xe1 }; + static const uint8_t ADD_RAX_RCX[] = { 0x48, 0x01, 0xC8 }; + static const uint8_t SAR_RAX_I8[] = { 0x48, 0xC1, 0xF8 }; + static const uint8_t NEG_RAX[] = { 0x48, 0xF7, 0xD8 }; + static const uint8_t ADD_R_RAX[] = { 0x4C, 0x03 }; + static const uint8_t XOR_EAX_EAX[] = { 0x33, 0xC0 }; + static const uint8_t ADD_RDX_R[] = { 0x4c, 0x01 }; + static const uint8_t SUB_RDX_R[] = { 0x4c, 0x29 }; + static const uint8_t SAR_RDX_I8[] = { 0x48, 0xC1, 0xFA }; + static const uint8_t TEST_RDX_RDX[] = { 0x48, 0x85, 0xD2 }; + static const uint8_t SETS_AL_ADD_RDX_RAX[] = { 0x0F, 0x98, 0xC0, 0x48, 0x03, 0xD0 }; + static const uint8_t REX_NEG[] = { 0x49, 0xF7 }; + static const uint8_t REX_XOR_RR[] = { 0x4D, 0x33 }; + static const uint8_t REX_XOR_RI[] = { 0x49, 0x81 }; + static const uint8_t REX_XOR_RM[] = { 0x4c, 0x33 }; + static const uint8_t REX_ROT_CL[] = { 0x49, 0xd3 }; + static const uint8_t REX_ROT_I8[] = { 0x49, 0xc1 }; + static const uint8_t SHUFPD[] = { 0x66, 0x0f, 0xc6 }; + static const uint8_t REX_ADDPD[] = { 0x66, 0x41, 0x0f, 0x58 }; + static const uint8_t REX_CVTDQ2PD_XMM12[] = { 0xf3, 0x44, 0x0f, 0xe6, 0x24, 0x06 }; + static const uint8_t REX_SUBPD[] = { 0x66, 0x41, 0x0f, 0x5c }; + static const uint8_t REX_XORPS[] = { 0x41, 0x0f, 0x57 }; + static const uint8_t REX_MULPD[] = { 0x66, 0x41, 0x0f, 0x59 }; + static const uint8_t REX_MAXPD[] = { 0x66, 0x41, 0x0f, 0x5f }; + static const uint8_t REX_DIVPD[] = { 0x66, 0x41, 0x0f, 0x5e }; + static const uint8_t SQRTPD[] = { 0x66, 0x0f, 0x51 }; + static const uint8_t AND_OR_MOV_LDMXCSR[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x50, 0x0F, 0xAE, 0x14, 0x24, 0x58 }; + static const uint8_t ROL_RAX[] = { 0x48, 0xc1, 0xc0 }; + static const uint8_t XOR_ECX_ECX[] = { 0x33, 0xC9 }; + static const uint8_t REX_CMP_R32I[] = { 0x41, 0x81 }; + static const uint8_t REX_CMP_M32I[] = { 0x81, 0x3c, 0x06 }; + static const uint8_t MOVAPD[] = { 0x66, 0x0f, 0x29 }; + static const uint8_t REX_MOV_MR[] = { 0x4c, 0x89 }; + static const uint8_t REX_XOR_EAX[] = { 0x41, 0x33 }; + static const uint8_t SUB_EBX[] = { 0x83, 0xEB, 0x01 }; + static const uint8_t JNZ[] = { 0x0f, 0x85 }; + static const uint8_t JMP = 0xe9; + static const uint8_t REX_XOR_RAX_R64[] = { 0x49, 0x33 }; + static const uint8_t REX_XCHG[] = { 0x4d, 0x87 }; + static const uint8_t REX_ANDPS_XMM12[] = { 0x45, 0x0F, 0x54, 0xE5, 0x45, 0x0F, 0x56, 0xE6 }; + static const uint8_t REX_PADD[] = { 0x66, 0x44, 0x0f }; + static const uint8_t PADD_OPCODES[] = { 0xfc, 0xfd, 0xfe, 0xd4 }; + static const uint8_t CALL = 0xe8; + static const uint8_t REX_ADD_I[] = { 0x49, 0x81 }; + static const uint8_t REX_TEST[] = { 0x49, 0xF7 }; + static const uint8_t JZ[] = { 0x0f, 0x84 }; + static const uint8_t RET = 0xc3; + static const uint8_t LEA_32[] = { 0x67, 0x41, 0x8d }; + static const uint8_t MOVNTI[] = { 0x4c, 0x0f, 0xc3 }; + static const uint8_t ADD_EBX_I[] = { 0x81, 0xc3 }; + + static const uint8_t NOP1[] = { 0x90 }; + static const uint8_t NOP2[] = { 0x66, 0x90 }; + static const uint8_t NOP3[] = { 0x66, 0x66, 0x90 }; + static const uint8_t NOP4[] = { 0x0F, 0x1F, 0x40, 0x00 }; + static const uint8_t NOP5[] = { 0x0F, 0x1F, 0x44, 0x00, 0x00 }; + static const uint8_t NOP6[] = { 0x66, 0x0F, 0x1F, 0x44, 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* NOPX[] = { NOP1, NOP2, NOP3, NOP4, NOP5, NOP6, NOP7, NOP8 }; + + size_t JitCompilerX86::getCodeSize() { + return codePos - prologueSize; + } + + JitCompilerX86::JitCompilerX86() { + code = (uint8_t*)allocExecutableMemory(CodeSize); + memcpy(code, codePrologue, prologueSize); + memcpy(code + epilogueOffset, codeEpilogue, epilogueSize); + } + + JitCompilerX86::~JitCompilerX86() { + freePagedMemory(code, CodeSize); + } + + void JitCompilerX86::generateProgram(Program& prog, ProgramConfiguration& pcfg) { + generateProgramPrologue(prog, pcfg); + memcpy(code + codePos, RandomX_CurrentConfig.codeReadDatasetTweaked, readDatasetSize); + codePos += readDatasetSize; + generateProgramEpilogue(prog); + } + + void JitCompilerX86::generateProgramLight(Program& prog, ProgramConfiguration& pcfg, uint32_t datasetOffset) { + generateProgramPrologue(prog, pcfg); + emit(RandomX_CurrentConfig.codeReadDatasetLightSshInitTweaked, readDatasetLightInitSize); + emit(ADD_EBX_I); + emit32(datasetOffset / CacheLineSize); + emitByte(CALL); + emit32(superScalarHashOffset - (codePos + 4)); + emit(codeReadDatasetLightSshFin, readDatasetLightFinSize); + generateProgramEpilogue(prog); + } + + template + void JitCompilerX86::generateSuperscalarHash(SuperscalarProgram(&programs)[N], std::vector &reciprocalCache) { + memcpy(code + superScalarHashOffset, codeShhInit, codeSshInitSize); + codePos = superScalarHashOffset + codeSshInitSize; + for (unsigned j = 0; j < RandomX_CurrentConfig.CacheAccesses; ++j) { + SuperscalarProgram& prog = programs[j]; + for (unsigned i = 0; i < prog.getSize(); ++i) { + Instruction& instr = prog(i); + generateSuperscalarCode(instr, reciprocalCache); + } + emit(codeShhLoad, codeSshLoadSize); + if (j < RandomX_CurrentConfig.CacheAccesses - 1) { + emit(REX_MOV_RR64); + emitByte(0xd8 + prog.getAddressRegister()); + emit(RandomX_CurrentConfig.codeShhPrefetchTweaked, codeSshPrefetchSize); +#ifdef RANDOMX_ALIGN + int align = (codePos % 16); + while (align != 0) { + int nopSize = 16 - align; + if (nopSize > 8) nopSize = 8; + emit(NOPX[nopSize - 1], nopSize); + align = (codePos % 16); + } +#endif + } + } + emitByte(RET); + } + + template + void JitCompilerX86::generateSuperscalarHash(SuperscalarProgram(&programs)[RANDOMX_CACHE_MAX_ACCESSES], std::vector &reciprocalCache); + + void JitCompilerX86::generateDatasetInitCode() { + memcpy(code, codeDatasetInit, datasetInitSize); + } + + void JitCompilerX86::generateProgramPrologue(Program& prog, ProgramConfiguration& pcfg) { + instructionOffsets.clear(); + for (unsigned i = 0; i < 8; ++i) { + registerUsage[i] = -1; + } + codePos = prologueSize; + memcpy(code + codePos - 48, &pcfg.eMask, sizeof(pcfg.eMask)); + emit(REX_XOR_RAX_R64); + emitByte(0xc0 + pcfg.readReg0); + emit(REX_XOR_RAX_R64); + emitByte(0xc0 + pcfg.readReg1); + memcpy(code + codePos, RandomX_CurrentConfig.codeLoopLoadTweaked, loopLoadSize); + codePos += loopLoadSize; + for (unsigned i = 0; i < prog.getSize(); ++i) { + Instruction& instr = prog(i); + instr.src %= RegistersCount; + instr.dst %= RegistersCount; + generateCode(instr, i); + } + emit(REX_MOV_RR); + emitByte(0xc0 + pcfg.readReg2); + emit(REX_XOR_EAX); + emitByte(0xc0 + pcfg.readReg3); + } + + void JitCompilerX86::generateProgramEpilogue(Program& prog) { + memcpy(code + codePos, codeLoopStore, loopStoreSize); + codePos += loopStoreSize; + emit(SUB_EBX); + emit(JNZ); + emit32(prologueSize - codePos - 4); + emitByte(JMP); + emit32(epilogueOffset - codePos - 4); + } + + void JitCompilerX86::generateCode(Instruction& instr, int i) { + instructionOffsets.push_back(codePos); + auto generator = engine[instr.opcode]; + (this->*generator)(instr, i); + } + + void JitCompilerX86::generateSuperscalarCode(Instruction& instr, std::vector &reciprocalCache) { + switch ((SuperscalarInstructionType)instr.opcode) + { + case randomx::SuperscalarInstructionType::ISUB_R: + emit(REX_SUB_RR); + emitByte(0xc0 + 8 * instr.dst + instr.src); + break; + case randomx::SuperscalarInstructionType::IXOR_R: + emit(REX_XOR_RR); + emitByte(0xc0 + 8 * instr.dst + instr.src); + break; + case randomx::SuperscalarInstructionType::IADD_RS: + emit(REX_LEA); + emitByte(0x04 + 8 * instr.dst); + genSIB(instr.getModShift(), instr.src, instr.dst); + break; + case randomx::SuperscalarInstructionType::IMUL_R: + emit(REX_IMUL_RR); + emitByte(0xc0 + 8 * instr.dst + instr.src); + break; + case randomx::SuperscalarInstructionType::IROR_C: + emit(REX_ROT_I8); + emitByte(0xc8 + instr.dst); + emitByte(instr.getImm32() & 63); + break; + case randomx::SuperscalarInstructionType::IADD_C7: + emit(REX_81); + emitByte(0xc0 + instr.dst); + emit32(instr.getImm32()); + break; + case randomx::SuperscalarInstructionType::IXOR_C7: + emit(REX_XOR_RI); + emitByte(0xf0 + instr.dst); + emit32(instr.getImm32()); + break; + case randomx::SuperscalarInstructionType::IADD_C8: + emit(REX_81); + emitByte(0xc0 + instr.dst); + emit32(instr.getImm32()); +#ifdef RANDOMX_ALIGN + emit(NOP1); +#endif + break; + case randomx::SuperscalarInstructionType::IXOR_C8: + emit(REX_XOR_RI); + emitByte(0xf0 + instr.dst); + emit32(instr.getImm32()); +#ifdef RANDOMX_ALIGN + emit(NOP1); +#endif + break; + case randomx::SuperscalarInstructionType::IADD_C9: + emit(REX_81); + emitByte(0xc0 + instr.dst); + emit32(instr.getImm32()); +#ifdef RANDOMX_ALIGN + emit(NOP2); +#endif + break; + case randomx::SuperscalarInstructionType::IXOR_C9: + emit(REX_XOR_RI); + emitByte(0xf0 + instr.dst); + emit32(instr.getImm32()); +#ifdef RANDOMX_ALIGN + emit(NOP2); +#endif + break; + case randomx::SuperscalarInstructionType::IMULH_R: + emit(REX_MOV_RR64); + emitByte(0xc0 + instr.dst); + emit(REX_MUL_R); + emitByte(0xe0 + instr.src); + emit(REX_MOV_R64R); + emitByte(0xc2 + 8 * instr.dst); + break; + case randomx::SuperscalarInstructionType::ISMULH_R: + emit(REX_MOV_RR64); + emitByte(0xc0 + instr.dst); + emit(REX_MUL_R); + emitByte(0xe8 + instr.src); + emit(REX_MOV_R64R); + emitByte(0xc2 + 8 * instr.dst); + break; + case randomx::SuperscalarInstructionType::IMUL_RCP: + emit(MOV_RAX_I); + emit64(reciprocalCache[instr.getImm32()]); + emit(REX_IMUL_RM); + emitByte(0xc0 + 8 * instr.dst); + break; + default: + UNREACHABLE; + } + } + + void JitCompilerX86::genAddressReg(Instruction& instr, bool rax = true) { + emit(LEA_32); + emitByte(0x80 + instr.src + (rax ? 0 : 8)); + if (instr.src == RegisterNeedsSib) { + emitByte(0x24); + } + emit32(instr.getImm32()); + if (rax) + emitByte(AND_EAX_I); + else + emit(AND_ECX_I); + emit32(instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + } + + void JitCompilerX86::genAddressRegDst(Instruction& instr) { + emit(LEA_32); + emitByte(0x80 + instr.dst); + if (instr.dst == RegisterNeedsSib) { + emitByte(0x24); + } + emit32(instr.getImm32()); + emitByte(AND_EAX_I); + if (instr.getModCond() < StoreL3Condition) { + emit32(instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + } + else { + emit32(ScratchpadL3Mask); + } + } + + void JitCompilerX86::genAddressImm(Instruction& instr) { + emit32(instr.getImm32() & ScratchpadL3Mask); + } + + void JitCompilerX86::h_IADD_RS(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + emit(REX_LEA); + if (instr.dst == RegisterNeedsDisplacement) + emitByte(0xac); + else + emitByte(0x04 + 8 * instr.dst); + genSIB(instr.getModShift(), instr.src, instr.dst); + if (instr.dst == RegisterNeedsDisplacement) + emit32(instr.getImm32()); + } + + void JitCompilerX86::h_IADD_M(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + if (instr.src != instr.dst) { + genAddressReg(instr); + emit(REX_ADD_RM); + emitByte(0x04 + 8 * instr.dst); + emitByte(0x06); + } + else { + emit(REX_ADD_RM); + emitByte(0x86 + 8 * instr.dst); + genAddressImm(instr); + } + } + + void JitCompilerX86::genSIB(int scale, int index, int base) { + emitByte((scale << 6) | (index << 3) | base); + } + + void JitCompilerX86::h_ISUB_R(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + if (instr.src != instr.dst) { + emit(REX_SUB_RR); + emitByte(0xc0 + 8 * instr.dst + instr.src); + } + else { + emit(REX_81); + emitByte(0xe8 + instr.dst); + emit32(instr.getImm32()); + } + } + + void JitCompilerX86::h_ISUB_M(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + if (instr.src != instr.dst) { + genAddressReg(instr); + emit(REX_SUB_RM); + emitByte(0x04 + 8 * instr.dst); + emitByte(0x06); + } + else { + emit(REX_SUB_RM); + emitByte(0x86 + 8 * instr.dst); + genAddressImm(instr); + } + } + + void JitCompilerX86::h_IMUL_R(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + if (instr.src != instr.dst) { + emit(REX_IMUL_RR); + emitByte(0xc0 + 8 * instr.dst + instr.src); + } + else { + emit(REX_IMUL_RRI); + emitByte(0xc0 + 9 * instr.dst); + emit32(instr.getImm32()); + } + } + + void JitCompilerX86::h_IMUL_M(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + if (instr.src != instr.dst) { + genAddressReg(instr); + emit(REX_IMUL_RM); + emitByte(0x04 + 8 * instr.dst); + emitByte(0x06); + } + else { + emit(REX_IMUL_RM); + emitByte(0x86 + 8 * instr.dst); + genAddressImm(instr); + } + } + + void JitCompilerX86::h_IMULH_R(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + emit(REX_MOV_RR64); + emitByte(0xc0 + instr.dst); + emit(REX_MUL_R); + emitByte(0xe0 + instr.src); + emit(REX_MOV_R64R); + emitByte(0xc2 + 8 * instr.dst); + } + + void JitCompilerX86::h_IMULH_M(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + if (instr.src != instr.dst) { + genAddressReg(instr, false); + emit(REX_MOV_RR64); + emitByte(0xc0 + instr.dst); + emit(REX_MUL_MEM); + } + else { + emit(REX_MOV_RR64); + emitByte(0xc0 + instr.dst); + emit(REX_MUL_M); + emitByte(0xa6); + genAddressImm(instr); + } + emit(REX_MOV_R64R); + emitByte(0xc2 + 8 * instr.dst); + } + + void JitCompilerX86::h_ISMULH_R(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + emit(REX_MOV_RR64); + emitByte(0xc0 + instr.dst); + emit(REX_MUL_R); + emitByte(0xe8 + instr.src); + emit(REX_MOV_R64R); + emitByte(0xc2 + 8 * instr.dst); + } + + void JitCompilerX86::h_ISMULH_M(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + if (instr.src != instr.dst) { + genAddressReg(instr, false); + emit(REX_MOV_RR64); + emitByte(0xc0 + instr.dst); + emit(REX_IMUL_MEM); + } + else { + emit(REX_MOV_RR64); + emitByte(0xc0 + instr.dst); + emit(REX_MUL_M); + emitByte(0xae); + genAddressImm(instr); + } + emit(REX_MOV_R64R); + emitByte(0xc2 + 8 * instr.dst); + } + + void JitCompilerX86::h_IMUL_RCP(Instruction& instr, int i) { + uint64_t divisor = instr.getImm32(); + if (!isPowerOf2(divisor)) { + registerUsage[instr.dst] = i; + emit(MOV_RAX_I); + emit64(randomx_reciprocal_fast(divisor)); + emit(REX_IMUL_RM); + emitByte(0xc0 + 8 * instr.dst); + } + } + + void JitCompilerX86::h_INEG_R(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + emit(REX_NEG); + emitByte(0xd8 + instr.dst); + } + + void JitCompilerX86::h_IXOR_R(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + if (instr.src != instr.dst) { + emit(REX_XOR_RR); + emitByte(0xc0 + 8 * instr.dst + instr.src); + } + else { + emit(REX_XOR_RI); + emitByte(0xf0 + instr.dst); + emit32(instr.getImm32()); + } + } + + void JitCompilerX86::h_IXOR_M(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + if (instr.src != instr.dst) { + genAddressReg(instr); + emit(REX_XOR_RM); + emitByte(0x04 + 8 * instr.dst); + emitByte(0x06); + } + else { + emit(REX_XOR_RM); + emitByte(0x86 + 8 * instr.dst); + genAddressImm(instr); + } + } + + void JitCompilerX86::h_IROR_R(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + if (instr.src != instr.dst) { + emit(REX_MOV_RR); + emitByte(0xc8 + instr.src); + emit(REX_ROT_CL); + emitByte(0xc8 + instr.dst); + } + else { + emit(REX_ROT_I8); + emitByte(0xc8 + instr.dst); + emitByte(instr.getImm32() & 63); + } + } + + void JitCompilerX86::h_IROL_R(Instruction& instr, int i) { + registerUsage[instr.dst] = i; + if (instr.src != instr.dst) { + emit(REX_MOV_RR); + emitByte(0xc8 + instr.src); + emit(REX_ROT_CL); + emitByte(0xc0 + instr.dst); + } + else { + emit(REX_ROT_I8); + emitByte(0xc0 + instr.dst); + emitByte(instr.getImm32() & 63); + } + } + + void JitCompilerX86::h_ISWAP_R(Instruction& instr, int i) { + if (instr.src != instr.dst) { + registerUsage[instr.dst] = i; + registerUsage[instr.src] = i; + emit(REX_XCHG); + emitByte(0xc0 + instr.src + 8 * instr.dst); + } + } + + void JitCompilerX86::h_FSWAP_R(Instruction& instr, int i) { + emit(SHUFPD); + emitByte(0xc0 + 9 * instr.dst); + emitByte(1); + } + + void JitCompilerX86::h_FADD_R(Instruction& instr, int i) { + instr.dst %= RegisterCountFlt; + instr.src %= RegisterCountFlt; + emit(REX_ADDPD); + emitByte(0xc0 + instr.src + 8 * instr.dst); + } + + void JitCompilerX86::h_FADD_M(Instruction& instr, int i) { + instr.dst %= RegisterCountFlt; + genAddressReg(instr); + emit(REX_CVTDQ2PD_XMM12); + emit(REX_ADDPD); + emitByte(0xc4 + 8 * instr.dst); + } + + void JitCompilerX86::h_FSUB_R(Instruction& instr, int i) { + instr.dst %= RegisterCountFlt; + instr.src %= RegisterCountFlt; + emit(REX_SUBPD); + emitByte(0xc0 + instr.src + 8 * instr.dst); + } + + void JitCompilerX86::h_FSUB_M(Instruction& instr, int i) { + instr.dst %= RegisterCountFlt; + genAddressReg(instr); + emit(REX_CVTDQ2PD_XMM12); + emit(REX_SUBPD); + emitByte(0xc4 + 8 * instr.dst); + } + + void JitCompilerX86::h_FSCAL_R(Instruction& instr, int i) { + instr.dst %= RegisterCountFlt; + emit(REX_XORPS); + emitByte(0xc7 + 8 * instr.dst); + } + + void JitCompilerX86::h_FMUL_R(Instruction& instr, int i) { + instr.dst %= RegisterCountFlt; + instr.src %= RegisterCountFlt; + emit(REX_MULPD); + emitByte(0xe0 + instr.src + 8 * instr.dst); + } + + void JitCompilerX86::h_FDIV_M(Instruction& instr, int i) { + instr.dst %= RegisterCountFlt; + genAddressReg(instr); + emit(REX_CVTDQ2PD_XMM12); + emit(REX_ANDPS_XMM12); + emit(REX_DIVPD); + emitByte(0xe4 + 8 * instr.dst); + } + + void JitCompilerX86::h_FSQRT_R(Instruction& instr, int i) { + instr.dst %= RegisterCountFlt; + emit(SQRTPD); + emitByte(0xe4 + 9 * instr.dst); + } + + void JitCompilerX86::h_CFROUND(Instruction& instr, int i) { + emit(REX_MOV_RR64); + emitByte(0xc0 + instr.src); + int rotate = (13 - (instr.getImm32() & 63)) & 63; + if (rotate != 0) { + emit(ROL_RAX); + emitByte(rotate); + } + emit(AND_OR_MOV_LDMXCSR); + } + + void JitCompilerX86::h_CBRANCH(Instruction& instr, int i) { + int reg = instr.dst; + int target = registerUsage[reg] + 1; + emit(REX_ADD_I); + emitByte(0xc0 + reg); + int shift = instr.getModCond() + RandomX_CurrentConfig.JumpOffset; + uint32_t imm = instr.getImm32() | (1UL << shift); + if (RandomX_CurrentConfig.JumpOffset > 0 || shift > 0) + imm &= ~(1UL << (shift - 1)); + emit32(imm); + emit(REX_TEST); + emitByte(0xc0 + reg); + emit32(RandomX_CurrentConfig.ConditionMask_Calculated << shift); + emit(JZ); + emit32(instructionOffsets[target] - (codePos + 4)); + //mark all registers as used + for (unsigned j = 0; j < RegistersCount; ++j) { + registerUsage[j] = i; + } + } + + void JitCompilerX86::h_ISTORE(Instruction& instr, int i) { + genAddressRegDst(instr); + emit(REX_MOV_MR); + emitByte(0x04 + 8 * instr.src); + emitByte(0x06); + } + + void JitCompilerX86::h_NOP(Instruction& instr, int i) { + emit(NOP1); + } + + InstructionGeneratorX86 JitCompilerX86::engine[256] = {}; + +} diff --git a/src/crypto/randomx/jit_compiler_x86.hpp b/src/crypto/randomx/jit_compiler_x86.hpp new file mode 100644 index 00000000..a81c8f4e --- /dev/null +++ b/src/crypto/randomx/jit_compiler_x86.hpp @@ -0,0 +1,141 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include +#include +#include "common.hpp" + +namespace randomx { + + class Program; + class ProgramConfiguration; + class SuperscalarProgram; + class JitCompilerX86; + class Instruction; + + typedef void(JitCompilerX86::*InstructionGeneratorX86)(Instruction&, int); + + constexpr uint32_t CodeSize = 64 * 1024; + + class JitCompilerX86 { + public: + JitCompilerX86(); + ~JitCompilerX86(); + void generateProgram(Program&, ProgramConfiguration&); + void generateProgramLight(Program&, ProgramConfiguration&, uint32_t); + template + void generateSuperscalarHash(SuperscalarProgram (&programs)[N], std::vector &); + void generateDatasetInitCode(); + ProgramFunc* getProgramFunc() { + return (ProgramFunc*)code; + } + DatasetInitFunc* getDatasetInitFunc() { + return (DatasetInitFunc*)code; + } + uint8_t* getCode() { + return code; + } + size_t getCodeSize(); + + static InstructionGeneratorX86 engine[256]; + std::vector instructionOffsets; + int registerUsage[RegistersCount]; + uint8_t* code; + int32_t codePos; + + void generateProgramPrologue(Program&, ProgramConfiguration&); + void generateProgramEpilogue(Program&); + void genAddressReg(Instruction&, bool); + void genAddressRegDst(Instruction&); + void genAddressImm(Instruction&); + void genSIB(int scale, int index, int base); + + void generateCode(Instruction&, int); + void generateSuperscalarCode(Instruction &, std::vector &); + + void emitByte(uint8_t val) { + code[codePos] = val; + codePos++; + } + + void emit32(uint32_t val) { + memcpy(code + codePos, &val, sizeof val); + codePos += sizeof val; + } + + void emit64(uint64_t val) { + memcpy(code + codePos, &val, sizeof val); + codePos += sizeof val; + } + + template + void emit(const uint8_t (&src)[N]) { + emit(src, N); + } + + void emit(const uint8_t* src, size_t count) { + memcpy(code + codePos, src, count); + codePos += count; + } + + void h_IADD_RS(Instruction&, int); + void h_IADD_M(Instruction&, int); + void h_ISUB_R(Instruction&, int); + void h_ISUB_M(Instruction&, int); + void h_IMUL_R(Instruction&, int); + void h_IMUL_M(Instruction&, int); + void h_IMULH_R(Instruction&, int); + void h_IMULH_M(Instruction&, int); + void h_ISMULH_R(Instruction&, int); + void h_ISMULH_M(Instruction&, int); + void h_IMUL_RCP(Instruction&, int); + void h_INEG_R(Instruction&, int); + void h_IXOR_R(Instruction&, int); + void h_IXOR_M(Instruction&, int); + void h_IROR_R(Instruction&, int); + void h_IROL_R(Instruction&, int); + void h_ISWAP_R(Instruction&, int); + void h_FSWAP_R(Instruction&, int); + void h_FADD_R(Instruction&, int); + void h_FADD_M(Instruction&, int); + void h_FSUB_R(Instruction&, int); + void h_FSUB_M(Instruction&, int); + void h_FSCAL_R(Instruction&, int); + void h_FMUL_R(Instruction&, int); + void h_FDIV_M(Instruction&, int); + void h_FSQRT_R(Instruction&, int); + void h_CBRANCH(Instruction&, int); + void h_CFROUND(Instruction&, int); + void h_ISTORE(Instruction&, int); + void h_NOP(Instruction&, int); + }; + +} \ No newline at end of file diff --git a/src/crypto/randomx/jit_compiler_x86_static.S b/src/crypto/randomx/jit_compiler_x86_static.S new file mode 100644 index 00000000..9cffaab5 --- /dev/null +++ b/src/crypto/randomx/jit_compiler_x86_static.S @@ -0,0 +1,208 @@ +# Copyright (c) 2018-2019, tevador +# +# 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. + +.intel_syntax noprefix +#if defined(__APPLE__) +.text +#define DECL(x) _##x +#else +.section .text +#define DECL(x) x +#endif + +#if defined(__WIN32__) || defined(__CYGWIN__) +#define WINABI +#endif + +.global DECL(randomx_program_prologue) +.global DECL(randomx_program_loop_begin) +.global DECL(randomx_program_loop_load) +.global DECL(randomx_program_start) +.global DECL(randomx_program_read_dataset) +.global DECL(randomx_program_read_dataset_sshash_init) +.global DECL(randomx_program_read_dataset_sshash_fin) +.global DECL(randomx_program_loop_store) +.global DECL(randomx_program_loop_end) +.global DECL(randomx_dataset_init) +.global DECL(randomx_program_epilogue) +.global DECL(randomx_sshash_load) +.global DECL(randomx_sshash_prefetch) +.global DECL(randomx_sshash_end) +.global DECL(randomx_sshash_init) +.global DECL(randomx_program_end) +.global DECL(randomx_reciprocal_fast) + +#define RANDOMX_SCRATCHPAD_MASK 2097088 +#define RANDOMX_DATASET_BASE_MASK 2147483584 +#define RANDOMX_CACHE_MASK 4194303 + +#define db .byte + +.balign 64 +DECL(randomx_program_prologue): +#if defined(WINABI) + #include "asm/program_prologue_win64.inc" +#else + #include "asm/program_prologue_linux.inc" +#endif + movapd xmm13, xmmword ptr mantissaMask[rip] + movapd xmm14, xmmword ptr exp240[rip] + movapd xmm15, xmmword ptr scaleMask[rip] + jmp DECL(randomx_program_loop_begin) + +.balign 64 + #include "asm/program_xmm_constants.inc" + +.balign 64 +DECL(randomx_program_loop_begin): + nop + +DECL(randomx_program_loop_load): + #include "asm/program_loop_load.inc" + +DECL(randomx_program_start): + nop + +DECL(randomx_program_read_dataset): + #include "asm/program_read_dataset.inc" + +DECL(randomx_program_read_dataset_sshash_init): + #include "asm/program_read_dataset_sshash_init.inc" + +DECL(randomx_program_read_dataset_sshash_fin): + #include "asm/program_read_dataset_sshash_fin.inc" + +DECL(randomx_program_loop_store): + #include "asm/program_loop_store.inc" + +DECL(randomx_program_loop_end): + nop + +.balign 64 +DECL(randomx_dataset_init): + push rbx + push rbp + push r12 + push r13 + push r14 + push r15 +#if defined(WINABI) + push rdi + push rsi + mov rdi, qword ptr [rcx] ;# cache->memory + mov rsi, rdx ;# dataset + mov rbp, r8 ;# block index + push r9 ;# max. block index +#else + mov rdi, qword ptr [rdi] ;# cache->memory + ;# dataset in rsi + mov rbp, rdx ;# block index + push rcx ;# max. block index +#endif +init_block_loop: + prefetchw byte ptr [rsi] + mov rbx, rbp + .byte 232 ;# 0xE8 = call + ;# .set CALL_LOC, + .int 32768 - (call_offset - DECL(randomx_dataset_init)) +call_offset: + mov qword ptr [rsi+0], r8 + mov qword ptr [rsi+8], r9 + mov qword ptr [rsi+16], r10 + mov qword ptr [rsi+24], r11 + mov qword ptr [rsi+32], r12 + mov qword ptr [rsi+40], r13 + mov qword ptr [rsi+48], r14 + mov qword ptr [rsi+56], r15 + add rbp, 1 + add rsi, 64 + cmp rbp, qword ptr [rsp] + jb init_block_loop + pop rax +#if defined(WINABI) + pop rsi + pop rdi +#endif + pop r15 + pop r14 + pop r13 + pop r12 + pop rbp + pop rbx + ret + +.balign 64 +DECL(randomx_program_epilogue): + #include "asm/program_epilogue_store.inc" +#if defined(WINABI) + #include "asm/program_epilogue_win64.inc" +#else + #include "asm/program_epilogue_linux.inc" +#endif + +.balign 64 +DECL(randomx_sshash_load): + #include "asm/program_sshash_load.inc" + +DECL(randomx_sshash_prefetch): + #include "asm/program_sshash_prefetch.inc" + +DECL(randomx_sshash_end): + nop + +.balign 64 +DECL(randomx_sshash_init): + lea r8, [rbx+1] + #include "asm/program_sshash_prefetch.inc" + imul r8, qword ptr r0_mul[rip] + mov r9, qword ptr r1_add[rip] + xor r9, r8 + mov r10, qword ptr r2_add[rip] + xor r10, r8 + mov r11, qword ptr r3_add[rip] + xor r11, r8 + mov r12, qword ptr r4_add[rip] + xor r12, r8 + mov r13, qword ptr r5_add[rip] + xor r13, r8 + mov r14, qword ptr r6_add[rip] + xor r14, r8 + mov r15, qword ptr r7_add[rip] + xor r15, r8 + jmp DECL(randomx_program_end) + +.balign 64 + #include "asm/program_sshash_constants.inc" + +.balign 64 +DECL(randomx_program_end): + nop + +DECL(randomx_reciprocal_fast): +#if !defined(WINABI) + mov rcx, rdi +#endif + #include "asm/randomx_reciprocal.inc" diff --git a/src/crypto/randomx/jit_compiler_x86_static.asm b/src/crypto/randomx/jit_compiler_x86_static.asm new file mode 100644 index 00000000..5ecfb435 --- /dev/null +++ b/src/crypto/randomx/jit_compiler_x86_static.asm @@ -0,0 +1,199 @@ +; Copyright (c) 2018-2019, tevador +; +; 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. + +IFDEF RAX + +_RANDOMX_JITX86_STATIC SEGMENT PAGE READ EXECUTE + +PUBLIC randomx_program_prologue +PUBLIC randomx_program_loop_begin +PUBLIC randomx_program_loop_load +PUBLIC randomx_program_start +PUBLIC randomx_program_read_dataset +PUBLIC randomx_program_read_dataset_sshash_init +PUBLIC randomx_program_read_dataset_sshash_fin +PUBLIC randomx_dataset_init +PUBLIC randomx_program_loop_store +PUBLIC randomx_program_loop_end +PUBLIC randomx_program_epilogue +PUBLIC randomx_sshash_load +PUBLIC randomx_sshash_prefetch +PUBLIC randomx_sshash_end +PUBLIC randomx_sshash_init +PUBLIC randomx_program_end +PUBLIC randomx_reciprocal_fast + +RANDOMX_SCRATCHPAD_MASK EQU 2097088 +RANDOMX_DATASET_BASE_MASK EQU 2147483584 +RANDOMX_CACHE_MASK EQU 4194303 + +ALIGN 64 +randomx_program_prologue PROC + include asm/program_prologue_win64.inc + movapd xmm13, xmmword ptr [mantissaMask] + movapd xmm14, xmmword ptr [exp240] + movapd xmm15, xmmword ptr [scaleMask] + jmp randomx_program_loop_begin +randomx_program_prologue ENDP + +ALIGN 64 + include asm/program_xmm_constants.inc + +ALIGN 64 +randomx_program_loop_begin PROC + nop +randomx_program_loop_begin ENDP + +randomx_program_loop_load PROC + include asm/program_loop_load.inc +randomx_program_loop_load ENDP + +randomx_program_start PROC + nop +randomx_program_start ENDP + +randomx_program_read_dataset PROC + include asm/program_read_dataset.inc +randomx_program_read_dataset ENDP + +randomx_program_read_dataset_sshash_init PROC + include asm/program_read_dataset_sshash_init.inc +randomx_program_read_dataset_sshash_init ENDP + +randomx_program_read_dataset_sshash_fin PROC + include asm/program_read_dataset_sshash_fin.inc +randomx_program_read_dataset_sshash_fin ENDP + +randomx_program_loop_store PROC + include asm/program_loop_store.inc +randomx_program_loop_store ENDP + +randomx_program_loop_end PROC + nop +randomx_program_loop_end ENDP + +ALIGN 64 +randomx_dataset_init PROC + push rbx + push rbp + push rdi + push rsi + push r12 + push r13 + push r14 + push r15 + mov rdi, qword ptr [rcx] ;# cache->memory + mov rsi, rdx ;# dataset + mov rbp, r8 ;# block index + push r9 ;# max. block index +init_block_loop: + prefetchw byte ptr [rsi] + mov rbx, rbp + db 232 ;# 0xE8 = call + dd 32768 - distance + distance equ $ - offset randomx_dataset_init + mov qword ptr [rsi+0], r8 + mov qword ptr [rsi+8], r9 + mov qword ptr [rsi+16], r10 + mov qword ptr [rsi+24], r11 + mov qword ptr [rsi+32], r12 + mov qword ptr [rsi+40], r13 + mov qword ptr [rsi+48], r14 + mov qword ptr [rsi+56], r15 + add rbp, 1 + add rsi, 64 + cmp rbp, qword ptr [rsp] + jb init_block_loop + pop r9 + pop r15 + pop r14 + pop r13 + pop r12 + pop rsi + pop rdi + pop rbp + pop rbx + ret +randomx_dataset_init ENDP + +ALIGN 64 +randomx_program_epilogue PROC + include asm/program_epilogue_store.inc + include asm/program_epilogue_win64.inc +randomx_program_epilogue ENDP + +ALIGN 64 +randomx_sshash_load PROC + include asm/program_sshash_load.inc +randomx_sshash_load ENDP + +randomx_sshash_prefetch PROC + include asm/program_sshash_prefetch.inc +randomx_sshash_prefetch ENDP + +randomx_sshash_end PROC + nop +randomx_sshash_end ENDP + +ALIGN 64 +randomx_sshash_init PROC + lea r8, [rbx+1] + include asm/program_sshash_prefetch.inc + imul r8, qword ptr [r0_mul] + mov r9, qword ptr [r1_add] + xor r9, r8 + mov r10, qword ptr [r2_add] + xor r10, r8 + mov r11, qword ptr [r3_add] + xor r11, r8 + mov r12, qword ptr [r4_add] + xor r12, r8 + mov r13, qword ptr [r5_add] + xor r13, r8 + mov r14, qword ptr [r6_add] + xor r14, r8 + mov r15, qword ptr [r7_add] + xor r15, r8 + jmp randomx_program_end +randomx_sshash_init ENDP + +ALIGN 64 + include asm/program_sshash_constants.inc + +ALIGN 64 +randomx_program_end PROC + nop +randomx_program_end ENDP + +randomx_reciprocal_fast PROC + include asm/randomx_reciprocal.inc +randomx_reciprocal_fast ENDP + +_RANDOMX_JITX86_STATIC ENDS + +ENDIF + +END \ No newline at end of file diff --git a/src/crypto/randomx/jit_compiler_x86_static.hpp b/src/crypto/randomx/jit_compiler_x86_static.hpp new file mode 100644 index 00000000..ba196862 --- /dev/null +++ b/src/crypto/randomx/jit_compiler_x86_static.hpp @@ -0,0 +1,48 @@ +/* +Copyright (c) 2018-2019, tevador + +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_prologue(); + void randomx_program_loop_begin(); + void randomx_program_loop_load(); + void randomx_program_start(); + void randomx_program_read_dataset(); + void randomx_program_read_dataset_sshash_init(); + void randomx_program_read_dataset_sshash_fin(); + void randomx_program_loop_store(); + void randomx_program_loop_end(); + void randomx_dataset_init(); + void randomx_program_epilogue(); + void randomx_sshash_load(); + void randomx_sshash_prefetch(); + void randomx_sshash_end(); + void randomx_sshash_init(); + void randomx_program_end(); +} diff --git a/src/crypto/randomx/program.hpp b/src/crypto/randomx/program.hpp new file mode 100644 index 00000000..ef8ac748 --- /dev/null +++ b/src/crypto/randomx/program.hpp @@ -0,0 +1,60 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include "common.hpp" +#include "instruction.hpp" +#include "blake2/endian.h" + +namespace randomx { + + struct ProgramConfiguration { + uint64_t eMask[2]; + uint32_t readReg0, readReg1, readReg2, readReg3; + }; + + class Program { + public: + Instruction& operator()(int pc) { + return programBuffer[pc]; + } + uint64_t getEntropy(int i) { + return load64(&entropyBuffer[i]); + } + uint32_t getSize() { + return RandomX_CurrentConfig.ProgramSize; + } + private: + uint64_t entropyBuffer[16]; + Instruction programBuffer[RANDOMX_PROGRAM_MAX_SIZE]; + }; + + static_assert(sizeof(Program) % 64 == 0, "Invalid size of class randomx::Program"); +} diff --git a/src/crypto/randomx/randomx.cpp b/src/crypto/randomx/randomx.cpp new file mode 100644 index 00000000..dde838b9 --- /dev/null +++ b/src/crypto/randomx/randomx.cpp @@ -0,0 +1,476 @@ +/* +Copyright (c) 2018-2019, tevador + +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 "randomx.h" +#include "dataset.hpp" +#include "vm_interpreted.hpp" +#include "vm_interpreted_light.hpp" +#include "vm_compiled.hpp" +#include "vm_compiled_light.hpp" +#include "blake2/blake2.h" +#include "jit_compiler_x86_static.hpp" +#include + +RandomX_ConfigurationWownero::RandomX_ConfigurationWownero() +{ + ArgonSalt = "RandomWOW\x01"; + ProgramIterations = 1024; + ProgramCount = 16; + ScratchpadL2_Size = 131072; + ScratchpadL3_Size = 1048576; + + RANDOMX_FREQ_IROR_R = 10; + RANDOMX_FREQ_IROL_R = 0; + RANDOMX_FREQ_FSWAP_R = 8; + RANDOMX_FREQ_FADD_R = 20; + RANDOMX_FREQ_FSUB_R = 20; + RANDOMX_FREQ_FMUL_R = 20; + + fillAes4Rx4_Key[0] = rx_set_int_vec_i128(0xcf359e95, 0x141f82b7, 0x7ffbe4a6, 0xf890465d); + fillAes4Rx4_Key[1] = rx_set_int_vec_i128(0x6741ffdc, 0xbd5c5ac3, 0xfee8278a, 0x6a55c450); + fillAes4Rx4_Key[2] = rx_set_int_vec_i128(0x3d324aac, 0xa7279ad2, 0xd524fde4, 0x114c47a4); + fillAes4Rx4_Key[3] = rx_set_int_vec_i128(0x76f6db08, 0x42d3dbd9, 0x99a9aeff, 0x810c3a2a); + fillAes4Rx4_Key[4] = fillAes4Rx4_Key[0]; + fillAes4Rx4_Key[5] = fillAes4Rx4_Key[1]; + fillAes4Rx4_Key[6] = fillAes4Rx4_Key[2]; + fillAes4Rx4_Key[7] = fillAes4Rx4_Key[3]; +} + +RandomX_ConfigurationLoki::RandomX_ConfigurationLoki() +{ + ArgonIterations = 4; + ArgonLanes = 2; + ArgonSalt = "RandomXL\x12"; + ProgramSize = 320; + ProgramCount = 7; +} + +RandomX_ConfigurationBase::RandomX_ConfigurationBase() + : ArgonMemory(262144) + , ArgonIterations(3) + , ArgonLanes(1) + , ArgonSalt("RandomX\x03") + , CacheAccesses(8) + , SuperscalarLatency(170) + , DatasetBaseSize(2147483648) + , DatasetExtraSize(33554368) + , ScratchpadL1_Size(16384) + , ScratchpadL2_Size(262144) + , ScratchpadL3_Size(2097152) + , ProgramSize(256) + , ProgramIterations(2048) + , ProgramCount(8) + , JumpBits(8) + , JumpOffset(8) + , RANDOMX_FREQ_IADD_RS(25) + , RANDOMX_FREQ_IADD_M(7) + , RANDOMX_FREQ_ISUB_R(16) + , RANDOMX_FREQ_ISUB_M(7) + , RANDOMX_FREQ_IMUL_R(16) + , RANDOMX_FREQ_IMUL_M(4) + , RANDOMX_FREQ_IMULH_R(4) + , RANDOMX_FREQ_IMULH_M(1) + , RANDOMX_FREQ_ISMULH_R(4) + , RANDOMX_FREQ_ISMULH_M(1) + , RANDOMX_FREQ_IMUL_RCP(8) + , RANDOMX_FREQ_INEG_R(2) + , RANDOMX_FREQ_IXOR_R(15) + , RANDOMX_FREQ_IXOR_M(5) + , RANDOMX_FREQ_IROR_R(8) + , RANDOMX_FREQ_IROL_R(2) + , RANDOMX_FREQ_ISWAP_R(4) + , RANDOMX_FREQ_FSWAP_R(4) + , RANDOMX_FREQ_FADD_R(16) + , RANDOMX_FREQ_FADD_M(5) + , RANDOMX_FREQ_FSUB_R(16) + , RANDOMX_FREQ_FSUB_M(5) + , RANDOMX_FREQ_FSCAL_R(6) + , RANDOMX_FREQ_FMUL_R(32) + , RANDOMX_FREQ_FDIV_M(4) + , RANDOMX_FREQ_FSQRT_R(6) + , RANDOMX_FREQ_CBRANCH(16) + , RANDOMX_FREQ_CFROUND(1) + , RANDOMX_FREQ_ISTORE(16) + , RANDOMX_FREQ_NOP(0) +{ + fillAes4Rx4_Key[0] = rx_set_int_vec_i128(0x99e5d23f, 0x2f546d2b, 0xd1833ddb, 0x6421aadd); + fillAes4Rx4_Key[1] = rx_set_int_vec_i128(0xa5dfcde5, 0x06f79d53, 0xb6913f55, 0xb20e3450); + fillAes4Rx4_Key[2] = rx_set_int_vec_i128(0x171c02bf, 0x0aa4679f, 0x515e7baf, 0x5c3ed904); + fillAes4Rx4_Key[3] = rx_set_int_vec_i128(0xd8ded291, 0xcd673785, 0xe78f5d08, 0x85623763); + fillAes4Rx4_Key[4] = rx_set_int_vec_i128(0x229effb4, 0x3d518b6d, 0xe3d6a7a6, 0xb5826f73); + fillAes4Rx4_Key[5] = rx_set_int_vec_i128(0xb272b7d2, 0xe9024d4e, 0x9c10b3d9, 0xc7566bf3); + fillAes4Rx4_Key[6] = rx_set_int_vec_i128(0xf63befa7, 0x2ba9660a, 0xf765a38b, 0xf273c9e7); + fillAes4Rx4_Key[7] = rx_set_int_vec_i128(0xc0b0762d, 0x0c06d1fd, 0x915839de, 0x7a7cd609); + +#if defined(_M_X64) || defined(__x86_64__) + { + const uint8_t* a = (const uint8_t*)&randomx_sshash_prefetch; + const uint8_t* b = (const uint8_t*)&randomx_sshash_end; + memcpy(codeShhPrefetchTweaked, a, b - a); + } + { + const uint8_t* a = (const uint8_t*)&randomx_program_read_dataset; + const uint8_t* b = (const uint8_t*)&randomx_program_read_dataset_sshash_init; + memcpy(codeReadDatasetTweaked, a, b - a); + } + { + const uint8_t* a = (const uint8_t*)&randomx_program_read_dataset_sshash_init; + const uint8_t* b = (const uint8_t*)&randomx_program_read_dataset_sshash_fin; + memcpy(codeReadDatasetLightSshInitTweaked, a, b - a); + } + { + const uint8_t* a = (const uint8_t*)&randomx_program_loop_load; + const uint8_t* b = (const uint8_t*)&randomx_program_start; + memcpy(codeLoopLoadTweaked, a, b - a); + } +#endif +} + +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; + ScratchpadL2Mask16_Calculated = (ScratchpadL2_Size / sizeof(uint64_t) / 2 - 1) * 16; + 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*)(codeLoopLoadTweaked + 4) = ScratchpadL3Mask64_Calculated; + *(uint32_t*)(codeLoopLoadTweaked + 50) = ScratchpadL3Mask64_Calculated; +#endif + + ConditionMask_Calculated = (1 << JumpBits) - 1; + + constexpr int CEIL_NULL = 0; + int k = 0; + +#if defined(_M_X64) || defined(__x86_64__) +#define JIT_HANDLE(x, prev) randomx::JitCompilerX86::engine[k] = &randomx::JitCompilerX86::h_##x +#else +#define JIT_HANDLE(x, prev) +#endif + +#define INST_HANDLE(x, prev) \ + CEIL_##x = CEIL_##prev + RANDOMX_FREQ_##x; \ + for (; k < CEIL_##x; ++k) { JIT_HANDLE(x, prev); } + + INST_HANDLE(IADD_RS, NULL); + INST_HANDLE(IADD_M, IADD_RS); + INST_HANDLE(ISUB_R, IADD_M); + INST_HANDLE(ISUB_M, ISUB_R); + INST_HANDLE(IMUL_R, ISUB_M); + INST_HANDLE(IMUL_M, IMUL_R); + INST_HANDLE(IMULH_R, IMUL_M); + INST_HANDLE(IMULH_M, IMULH_R); + INST_HANDLE(ISMULH_R, IMULH_M); + INST_HANDLE(ISMULH_M, ISMULH_R); + INST_HANDLE(IMUL_RCP, ISMULH_M); + INST_HANDLE(INEG_R, IMUL_RCP); + INST_HANDLE(IXOR_R, INEG_R); + INST_HANDLE(IXOR_M, IXOR_R); + INST_HANDLE(IROR_R, IXOR_M); + INST_HANDLE(IROL_R, IROR_R); + INST_HANDLE(ISWAP_R, IROL_R); + INST_HANDLE(FSWAP_R, ISWAP_R); + INST_HANDLE(FADD_R, FSWAP_R); + INST_HANDLE(FADD_M, FADD_R); + INST_HANDLE(FSUB_R, FADD_M); + INST_HANDLE(FSUB_M, FSUB_R); + INST_HANDLE(FSCAL_R, FSUB_M); + INST_HANDLE(FMUL_R, FSCAL_R); + INST_HANDLE(FDIV_M, FMUL_R); + INST_HANDLE(FSQRT_R, FDIV_M); + INST_HANDLE(CBRANCH, FSQRT_R); + INST_HANDLE(CFROUND, CBRANCH); + INST_HANDLE(ISTORE, CFROUND); + INST_HANDLE(NOP, ISTORE); +#undef INST_HANDLE +} + +RandomX_ConfigurationMonero RandomX_MoneroConfig; +RandomX_ConfigurationWownero RandomX_WowneroConfig; +RandomX_ConfigurationLoki RandomX_LokiConfig; + +RandomX_ConfigurationBase RandomX_CurrentConfig; + +extern "C" { + + randomx_cache *randomx_alloc_cache(randomx_flags flags) { + randomx_cache *cache; + + try { + cache = new randomx_cache(); + switch (flags & (RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES)) { + case RANDOMX_FLAG_DEFAULT: + cache->dealloc = &randomx::deallocCache; + cache->jit = nullptr; + cache->initialize = &randomx::initCache; + cache->datasetInit = &randomx::initDataset; + cache->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(RANDOMX_CACHE_MAX_SIZE); + break; + + case RANDOMX_FLAG_JIT: + cache->dealloc = &randomx::deallocCache; + cache->jit = new randomx::JitCompiler(); + cache->initialize = &randomx::initCacheCompile; + cache->datasetInit = cache->jit->getDatasetInitFunc(); + cache->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(RANDOMX_CACHE_MAX_SIZE); + break; + + case RANDOMX_FLAG_LARGE_PAGES: + cache->dealloc = &randomx::deallocCache; + cache->jit = nullptr; + cache->initialize = &randomx::initCache; + cache->datasetInit = &randomx::initDataset; + cache->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(RANDOMX_CACHE_MAX_SIZE); + break; + + case RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES: + cache->dealloc = &randomx::deallocCache; + cache->jit = new randomx::JitCompiler(); + cache->initialize = &randomx::initCacheCompile; + cache->datasetInit = cache->jit->getDatasetInitFunc(); + cache->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(RANDOMX_CACHE_MAX_SIZE); + break; + + default: + UNREACHABLE; + } + } + catch (std::exception &ex) { + if (cache != nullptr) { + randomx_release_cache(cache); + cache = nullptr; + } + } + + return cache; + } + + void randomx_init_cache(randomx_cache *cache, const void *key, size_t keySize) { + assert(cache != nullptr); + assert(keySize == 0 || key != nullptr); + cache->initialize(cache, key, keySize); + } + + void randomx_release_cache(randomx_cache* cache) { + assert(cache != nullptr); + cache->dealloc(cache); + delete cache; + } + + randomx_dataset *randomx_alloc_dataset(randomx_flags flags) { + randomx_dataset *dataset; + + try { + dataset = new randomx_dataset(); + if (flags & RANDOMX_FLAG_LARGE_PAGES) { + dataset->dealloc = &randomx::deallocDataset; + dataset->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(RANDOMX_DATASET_MAX_SIZE); + } + else { + dataset->dealloc = &randomx::deallocDataset; + dataset->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(RANDOMX_DATASET_MAX_SIZE); + } + } + catch (std::exception &ex) { + if (dataset != nullptr) { + randomx_release_dataset(dataset); + dataset = nullptr; + } + } + + return dataset; + } + + #define DatasetItemCount ((RandomX_CurrentConfig.DatasetBaseSize + RandomX_CurrentConfig.DatasetExtraSize) / RANDOMX_DATASET_ITEM_SIZE) + + unsigned long randomx_dataset_item_count() { + return DatasetItemCount; + } + + void randomx_init_dataset(randomx_dataset *dataset, randomx_cache *cache, unsigned long startItem, unsigned long itemCount) { + assert(dataset != nullptr); + assert(cache != nullptr); + assert(startItem < DatasetItemCount && itemCount <= DatasetItemCount); + assert(startItem + itemCount <= DatasetItemCount); + cache->datasetInit(cache, dataset->memory + startItem * randomx::CacheLineSize, startItem, startItem + itemCount); + } + + void *randomx_get_dataset_memory(randomx_dataset *dataset) { + assert(dataset != nullptr); + return dataset->memory; + } + + void randomx_release_dataset(randomx_dataset *dataset) { + assert(dataset != nullptr); + dataset->dealloc(dataset); + delete dataset; + } + + randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset) { + assert(cache != nullptr || (flags & RANDOMX_FLAG_FULL_MEM)); + assert(cache == nullptr || cache->isInitialized()); + assert(dataset != nullptr || !(flags & RANDOMX_FLAG_FULL_MEM)); + + randomx_vm *vm = nullptr; + + try { + switch (flags & (RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES)) { + case RANDOMX_FLAG_DEFAULT: + vm = new randomx::InterpretedLightVmDefault(); + break; + + case RANDOMX_FLAG_FULL_MEM: + vm = new randomx::InterpretedVmDefault(); + break; + + case RANDOMX_FLAG_JIT: + vm = new randomx::CompiledLightVmDefault(); + break; + + case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT: + vm = new randomx::CompiledVmDefault(); + break; + + case RANDOMX_FLAG_HARD_AES: + vm = new randomx::InterpretedLightVmHardAes(); + break; + + case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_HARD_AES: + vm = new randomx::InterpretedVmHardAes(); + break; + + case RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES: + vm = new randomx::CompiledLightVmHardAes(); + break; + + case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES: + vm = new randomx::CompiledVmHardAes(); + break; + + case RANDOMX_FLAG_LARGE_PAGES: + vm = new randomx::InterpretedLightVmLargePage(); + break; + + case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_LARGE_PAGES: + vm = new randomx::InterpretedVmLargePage(); + break; + + case RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES: + vm = new randomx::CompiledLightVmLargePage(); + break; + + case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES: + vm = new randomx::CompiledVmLargePage(); + break; + + case RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: + vm = new randomx::InterpretedLightVmLargePageHardAes(); + break; + + case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: + vm = new randomx::InterpretedVmLargePageHardAes(); + break; + + case RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: + vm = new randomx::CompiledLightVmLargePageHardAes(); + break; + + case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: + vm = new randomx::CompiledVmLargePageHardAes(); + break; + + default: + UNREACHABLE; + } + + if(cache != nullptr) + vm->setCache(cache); + + if(dataset != nullptr) + vm->setDataset(dataset); + + vm->allocate(); + } + catch (std::exception &ex) { + delete vm; + vm = nullptr; + } + + return vm; + } + + void randomx_vm_set_cache(randomx_vm *machine, randomx_cache* cache) { + assert(machine != nullptr); + assert(cache != nullptr && cache->isInitialized()); + machine->setCache(cache); + } + + void randomx_vm_set_dataset(randomx_vm *machine, randomx_dataset *dataset) { + assert(machine != nullptr); + assert(dataset != nullptr); + machine->setDataset(dataset); + } + + void randomx_destroy_vm(randomx_vm *machine) { + assert(machine != nullptr); + delete machine; + } + + void randomx_calculate_hash(randomx_vm *machine, const void *input, size_t inputSize, void *output) { + assert(machine != nullptr); + assert(inputSize == 0 || input != nullptr); + assert(output != nullptr); + alignas(16) uint64_t tempHash[8]; + int blakeResult = blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0); + assert(blakeResult == 0); + machine->initScratchpad(&tempHash); + machine->resetRoundingMode(); + for (int chain = 0; chain < RandomX_CurrentConfig.ProgramCount - 1; ++chain) { + machine->run(&tempHash); + blakeResult = blake2b(tempHash, sizeof(tempHash), machine->getRegisterFile(), sizeof(randomx::RegisterFile), nullptr, 0); + assert(blakeResult == 0); + } + machine->run(&tempHash); + machine->getFinalResult(output, RANDOMX_HASH_SIZE); + } + +} diff --git a/src/crypto/randomx/randomx.h b/src/crypto/randomx/randomx.h new file mode 100644 index 00000000..cd07ac64 --- /dev/null +++ b/src/crypto/randomx/randomx.h @@ -0,0 +1,332 @@ +/* +Copyright (c) 2018-2019, tevador + +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. +*/ + +#ifndef RANDOMX_H +#define RANDOMX_H + +#include +#include +#include +#include "intrin_portable.h" + +#define RANDOMX_HASH_SIZE 32 +#define RANDOMX_DATASET_ITEM_SIZE 64 + +#ifndef RANDOMX_EXPORT +#define RANDOMX_EXPORT +#endif + +typedef enum { + RANDOMX_FLAG_DEFAULT = 0, + RANDOMX_FLAG_LARGE_PAGES = 1, + RANDOMX_FLAG_HARD_AES = 2, + RANDOMX_FLAG_FULL_MEM = 4, + RANDOMX_FLAG_JIT = 8, +} randomx_flags; + +typedef struct randomx_dataset randomx_dataset; +typedef struct randomx_cache randomx_cache; +typedef struct randomx_vm randomx_vm; + +struct RandomX_ConfigurationBase +{ + RandomX_ConfigurationBase(); + + void Apply(); + + uint32_t ArgonMemory; + uint32_t ArgonIterations; + uint32_t ArgonLanes; + const char* ArgonSalt; + uint32_t CacheAccesses; + uint32_t SuperscalarLatency; + + uint32_t DatasetBaseSize; + uint32_t DatasetExtraSize; + + uint32_t ScratchpadL1_Size; + uint32_t ScratchpadL2_Size; + uint32_t ScratchpadL3_Size; + + uint32_t ProgramSize; + uint32_t ProgramIterations; + uint32_t ProgramCount; + + uint32_t JumpBits; + uint32_t JumpOffset; + + uint32_t RANDOMX_FREQ_IADD_RS; + uint32_t RANDOMX_FREQ_IADD_M; + uint32_t RANDOMX_FREQ_ISUB_R; + uint32_t RANDOMX_FREQ_ISUB_M; + uint32_t RANDOMX_FREQ_IMUL_R; + uint32_t RANDOMX_FREQ_IMUL_M; + uint32_t RANDOMX_FREQ_IMULH_R; + uint32_t RANDOMX_FREQ_IMULH_M; + uint32_t RANDOMX_FREQ_ISMULH_R; + uint32_t RANDOMX_FREQ_ISMULH_M; + uint32_t RANDOMX_FREQ_IMUL_RCP; + uint32_t RANDOMX_FREQ_INEG_R; + uint32_t RANDOMX_FREQ_IXOR_R; + uint32_t RANDOMX_FREQ_IXOR_M; + uint32_t RANDOMX_FREQ_IROR_R; + uint32_t RANDOMX_FREQ_IROL_R; + uint32_t RANDOMX_FREQ_ISWAP_R; + uint32_t RANDOMX_FREQ_FSWAP_R; + uint32_t RANDOMX_FREQ_FADD_R; + uint32_t RANDOMX_FREQ_FADD_M; + uint32_t RANDOMX_FREQ_FSUB_R; + uint32_t RANDOMX_FREQ_FSUB_M; + uint32_t RANDOMX_FREQ_FSCAL_R; + uint32_t RANDOMX_FREQ_FMUL_R; + uint32_t RANDOMX_FREQ_FDIV_M; + uint32_t RANDOMX_FREQ_FSQRT_R; + uint32_t RANDOMX_FREQ_CBRANCH; + uint32_t RANDOMX_FREQ_CFROUND; + uint32_t RANDOMX_FREQ_ISTORE; + uint32_t RANDOMX_FREQ_NOP; + + rx_vec_i128 fillAes4Rx4_Key[8]; + + uint8_t codeShhPrefetchTweaked[20]; + uint8_t codeReadDatasetTweaked[64]; + uint8_t codeReadDatasetLightSshInitTweaked[68]; + uint8_t codeLoopLoadTweaked[140]; + + uint32_t CacheLineAlignMask_Calculated; + uint32_t DatasetExtraItems_Calculated; + + uint32_t ScratchpadL1Mask_Calculated; + uint32_t ScratchpadL1Mask16_Calculated; + uint32_t ScratchpadL2Mask_Calculated; + uint32_t ScratchpadL2Mask16_Calculated; + uint32_t ScratchpadL3Mask_Calculated; + uint32_t ScratchpadL3Mask64_Calculated; + + uint32_t ConditionMask_Calculated; + + int CEIL_IADD_RS; + int CEIL_IADD_M; + int CEIL_ISUB_R; + int CEIL_ISUB_M; + int CEIL_IMUL_R; + int CEIL_IMUL_M; + int CEIL_IMULH_R; + int CEIL_IMULH_M; + int CEIL_ISMULH_R; + int CEIL_ISMULH_M; + int CEIL_IMUL_RCP; + int CEIL_INEG_R; + int CEIL_IXOR_R; + int CEIL_IXOR_M; + int CEIL_IROR_R; + int CEIL_IROL_R; + int CEIL_ISWAP_R; + int CEIL_FSWAP_R; + int CEIL_FADD_R; + int CEIL_FADD_M; + int CEIL_FSUB_R; + int CEIL_FSUB_M; + int CEIL_FSCAL_R; + int CEIL_FMUL_R; + int CEIL_FDIV_M; + int CEIL_FSQRT_R; + int CEIL_CBRANCH; + int CEIL_CFROUND; + int CEIL_ISTORE; + int CEIL_NOP; +}; + +struct RandomX_ConfigurationMonero : public RandomX_ConfigurationBase {}; +struct RandomX_ConfigurationWownero : public RandomX_ConfigurationBase { RandomX_ConfigurationWownero(); }; +struct RandomX_ConfigurationLoki : public RandomX_ConfigurationBase { RandomX_ConfigurationLoki(); }; + +extern RandomX_ConfigurationMonero RandomX_MoneroConfig; +extern RandomX_ConfigurationWownero RandomX_WowneroConfig; +extern RandomX_ConfigurationLoki RandomX_LokiConfig; + +extern RandomX_ConfigurationBase RandomX_CurrentConfig; + +template +void randomx_apply_config(const T& config) +{ + static_assert(sizeof(T) == sizeof(RandomX_ConfigurationBase), "Invalid RandomX configuration struct size"); + static_assert(std::is_base_of::value, "Incompatible RandomX configuration struct"); + RandomX_CurrentConfig = config; + RandomX_CurrentConfig.Apply(); +} + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Creates a randomx_cache structure and allocates memory for RandomX Cache. + * + * @param flags is any combination of these 2 flags (each flag can be set or not set): + * RANDOMX_FLAG_LARGE_PAGES - allocate memory in large pages + * RANDOMX_FLAG_JIT - create cache structure with JIT compilation support; this makes + * subsequent Dataset initialization faster + * + * @return Pointer to an allocated randomx_cache structure. + * NULL is returned if memory allocation fails or if the RANDOMX_FLAG_JIT + * is set and JIT compilation is not supported on the current platform. + */ +RANDOMX_EXPORT randomx_cache *randomx_alloc_cache(randomx_flags flags); + +/** + * Initializes the cache memory and SuperscalarHash using the provided key value. + * + * @param cache is a pointer to a previously allocated randomx_cache structure. Must not be NULL. + * @param key is a pointer to memory which contains the key value. Must not be NULL. + * @param keySize is the number of bytes of the key. +*/ +RANDOMX_EXPORT void randomx_init_cache(randomx_cache *cache, const void *key, size_t keySize); + +/** + * Releases all memory occupied by the randomx_cache structure. + * + * @param cache is a pointer to a previously allocated randomx_cache structure. +*/ +RANDOMX_EXPORT void randomx_release_cache(randomx_cache* cache); + +/** + * Creates a randomx_dataset structure and allocates memory for RandomX Dataset. + * + * @param flags is the initialization flags. Only one flag is supported (can be set or not set): + * RANDOMX_FLAG_LARGE_PAGES - allocate memory in large pages + * + * @return Pointer to an allocated randomx_dataset structure. + * NULL is returned if memory allocation fails. + */ +RANDOMX_EXPORT randomx_dataset *randomx_alloc_dataset(randomx_flags flags); + +/** + * Gets the number of items contained in the dataset. + * + * @return the number of items contained in the dataset. +*/ +RANDOMX_EXPORT unsigned long randomx_dataset_item_count(void); + +/** + * Initializes dataset items. + * + * Note: In order to use the Dataset, all items from 0 to (randomx_dataset_item_count() - 1) must be initialized. + * This may be done by several calls to this function using non-overlapping item sequences. + * + * @param dataset is a pointer to a previously allocated randomx_dataset structure. Must not be NULL. + * @param cache is a pointer to a previously allocated and initialized randomx_cache structure. Must not be NULL. + * @param startItem is the item number where intialization should start. + * @param itemCount is the number of items that should be initialized. +*/ +RANDOMX_EXPORT void randomx_init_dataset(randomx_dataset *dataset, randomx_cache *cache, unsigned long startItem, unsigned long itemCount); + +/** + * Returns a pointer to the internal memory buffer of the dataset structure. The size + * of the internal memory buffer is randomx_dataset_item_count() * RANDOMX_DATASET_ITEM_SIZE. + * + * @param dataset is dataset is a pointer to a previously allocated randomx_dataset structure. Must not be NULL. + * + * @return Pointer to the internal memory buffer of the dataset structure. +*/ +RANDOMX_EXPORT void *randomx_get_dataset_memory(randomx_dataset *dataset); + +/** + * Releases all memory occupied by the randomx_dataset structure. + * + * @param dataset is a pointer to a previously allocated randomx_dataset structure. +*/ +RANDOMX_EXPORT void randomx_release_dataset(randomx_dataset *dataset); + +/** + * Creates and initializes a RandomX virtual machine. + * + * @param flags is any combination of these 4 flags (each flag can be set or not set): + * RANDOMX_FLAG_LARGE_PAGES - allocate scratchpad memory in large pages + * RANDOMX_FLAG_HARD_AES - virtual machine will use hardware accelerated AES + * RANDOMX_FLAG_FULL_MEM - virtual machine will use the full dataset + * RANDOMX_FLAG_JIT - virtual machine will use a JIT compiler + * The numeric values of the flags are ordered so that a higher value will provide + * faster hash calculation and a lower numeric value will provide higher portability. + * Using RANDOMX_FLAG_DEFAULT (all flags not set) works on all platforms, but is the slowest. + * @param cache is a pointer to an initialized randomx_cache structure. Can be + * NULL if RANDOMX_FLAG_FULL_MEM is set. + * @param dataset is a pointer to a randomx_dataset structure. Can be NULL + * if RANDOMX_FLAG_FULL_MEM is not set. + * + * @return Pointer to an initialized randomx_vm structure. + * Returns NULL if: + * (1) Scratchpad memory allocation fails. + * (2) The requested initialization flags are not supported on the current platform. + * (3) cache parameter is NULL and RANDOMX_FLAG_FULL_MEM is not set + * (4) dataset parameter is NULL and RANDOMX_FLAG_FULL_MEM is set +*/ +RANDOMX_EXPORT randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset); + +/** + * Reinitializes a virtual machine with a new Cache. This function should be called anytime + * the Cache is reinitialized with a new key. + * + * @param machine is a pointer to a randomx_vm structure that was initialized + * without RANDOMX_FLAG_FULL_MEM. Must not be NULL. + * @param cache is a pointer to an initialized randomx_cache structure. Must not be NULL. +*/ +RANDOMX_EXPORT void randomx_vm_set_cache(randomx_vm *machine, randomx_cache* cache); + +/** + * Reinitializes a virtual machine with a new Dataset. + * + * @param machine is a pointer to a randomx_vm structure that was initialized + * with RANDOMX_FLAG_FULL_MEM. Must not be NULL. + * @param dataset is a pointer to an initialized randomx_dataset structure. Must not be NULL. +*/ +RANDOMX_EXPORT void randomx_vm_set_dataset(randomx_vm *machine, randomx_dataset *dataset); + +/** + * Releases all memory occupied by the randomx_vm structure. + * + * @param machine is a pointer to a previously created randomx_vm structure. +*/ +RANDOMX_EXPORT void randomx_destroy_vm(randomx_vm *machine); + +/** + * Calculates a RandomX hash value. + * + * @param machine is a pointer to a randomx_vm structure. Must not be NULL. + * @param input is a pointer to memory to be hashed. Must not be NULL. + * @param inputSize is the number of bytes to be hashed. + * @param output is a pointer to memory where the hash will be stored. Must not + * be NULL and at least RANDOMX_HASH_SIZE bytes must be available for writing. +*/ +RANDOMX_EXPORT void randomx_calculate_hash(randomx_vm *machine, const void *input, size_t inputSize, void *output); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/src/crypto/randomx/reciprocal.c b/src/crypto/randomx/reciprocal.c new file mode 100644 index 00000000..22620f53 --- /dev/null +++ b/src/crypto/randomx/reciprocal.c @@ -0,0 +1,80 @@ +/* +Copyright (c) 2018-2019, tevador + +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 +#include "reciprocal.h" + +/* + Calculates rcp = 2**x / divisor for highest integer x such that rcp < 2**64. + divisor must not be 0 or a power of 2 + + Equivalent x86 assembly (divisor in rcx): + + mov edx, 1 + mov r8, rcx + xor eax, eax + bsr rcx, rcx + shl rdx, cl + div r8 + ret + +*/ +uint64_t randomx_reciprocal(uint64_t divisor) { + + assert(divisor != 0); + + const uint64_t p2exp63 = 1ULL << 63; + + uint64_t quotient = p2exp63 / divisor, remainder = p2exp63 % divisor; + + unsigned bsr = 0; //highest set bit in divisor + + for (uint64_t bit = divisor; bit > 0; bit >>= 1) + bsr++; + + for (unsigned shift = 0; shift < bsr; shift++) { + if (remainder >= divisor - remainder) { + quotient = quotient * 2 + 1; + remainder = remainder * 2 - divisor; + } + else { + quotient = quotient * 2; + remainder = remainder * 2; + } + } + + return quotient; +} + +#if !RANDOMX_HAVE_FAST_RECIPROCAL + +uint64_t randomx_reciprocal_fast(uint64_t divisor) { + return randomx_reciprocal(divisor); +} + +#endif diff --git a/src/crypto/randomx/reciprocal.h b/src/crypto/randomx/reciprocal.h new file mode 100644 index 00000000..8858df2b --- /dev/null +++ b/src/crypto/randomx/reciprocal.h @@ -0,0 +1,48 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include + +#if defined(_M_X64) || defined(__x86_64__) +#define RANDOMX_HAVE_FAST_RECIPROCAL 1 +#else +#define RANDOMX_HAVE_FAST_RECIPROCAL 0 +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +uint64_t randomx_reciprocal(uint64_t); +uint64_t randomx_reciprocal_fast(uint64_t); + +#if defined(__cplusplus) +} +#endif diff --git a/src/crypto/randomx/soft_aes.cpp b/src/crypto/randomx/soft_aes.cpp new file mode 100644 index 00000000..3e82fa2e --- /dev/null +++ b/src/crypto/randomx/soft_aes.cpp @@ -0,0 +1,364 @@ +/* +Copyright (c) 2018-2019, tevador + +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 "soft_aes.h" + +alignas(16) const uint8_t sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, +}; + +alignas(16) const uint32_t lutEnc0[256] = { + 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, + 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, + 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, + 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, + 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, + 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, + 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, + 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, + 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, + 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, + 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, + 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, + 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, + 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, + 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, + 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, + 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, + 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, + 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, + 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, + 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, + 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, + 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, + 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, + 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, + 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, + 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, + 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, + 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, + 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, + 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, + 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c, +}; + +alignas(16) const uint32_t lutEnc1[256] = { + 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, + 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, + 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, + 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, + 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, + 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, + 0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, + 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, + 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, + 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, + 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, + 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, + 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, + 0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, + 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, + 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, + 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, + 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, + 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, + 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, + 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, + 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, + 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, + 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, + 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, + 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, + 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, + 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, + 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, + 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, + 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, + 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a, +}; + +alignas(16) const uint32_t lutEnc2[256] = { + 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, + 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, + 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, + 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, + 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, + 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, + 0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, + 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, + 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, + 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, + 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, + 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, + 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, + 0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, + 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, + 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, + 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, + 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, + 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, + 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, + 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, + 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, + 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, + 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, + 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, + 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, + 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, + 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, + 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, + 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, + 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, + 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16, +}; + +alignas(16) const uint32_t lutEnc3[256] = { + 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, + 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, + 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, + 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, + 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, + 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, + 0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, + 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, + 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, + 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, + 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, + 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, + 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, + 0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, + 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, + 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, + 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, + 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, + 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, + 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, + 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, + 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, + 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, + 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, + 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, + 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, + 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, + 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, + 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, + 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, + 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, + 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616, +}; + +alignas(16) const uint32_t lutDec0[256] = { + 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, + 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, + 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, + 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, + 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, + 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, + 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, + 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, + 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4, + 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, + 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060, + 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, + 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, + 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, + 0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, + 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, + 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, + 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, + 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177, + 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, + 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, + 0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, + 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, + 0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef, + 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, + 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117, + 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546, + 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, + 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, + 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, + 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff, + 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0, +}; + +alignas(16) const uint32_t lutDec1[256] = { + 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x03e34b93, + 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f, + 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, + 0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, + 0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, + 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, + 0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357, 0xab55662a, + 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5, 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, + 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a, + 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, + 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff, + 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db, + 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, + 0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, + 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, + 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, + 0x19f15785, 0x0775af4c, 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, + 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, + 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, 0x52860dec, 0xe3c177d0, + 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, + 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, + 0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, + 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, + 0x7826cd09, 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, + 0x9be7bad9, 0x366f4ace, 0x099fead4, 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, + 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, + 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f, + 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, + 0x61d79a8c, 0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c, + 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, + 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, + 0x01a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042, +}; + +alignas(16) const uint32_t lutDec2[256] = { + 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303, + 0x302055fa, 0x76adf66d, 0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3, + 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, + 0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, + 0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, + 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, + 0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, + 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, + 0xcf8a2b1c, 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be, 0x34d11f62, 0xa6c48afe, + 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, + 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, 0xc471055d, 0x06046fd4, 0x5060ff15, + 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee, + 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, + 0x0efdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, + 0x0a0cb167, 0x57930fe7, 0xeeb4d296, 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, + 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, + 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60, 0x01f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, + 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, + 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, 0x860dec52, 0xc177d0e3, + 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, + 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf, + 0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, + 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, + 0x26cd0978, 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, + 0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, + 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x04f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, + 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51, + 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, + 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1, + 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, + 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0x0dff4195, + 0xa8397101, 0x0c08deb3, 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257, +}; + +alignas(16) const uint32_t lutDec3[256] = { + 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3, + 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362, + 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, + 0x03e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, + 0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, + 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, + 0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, + 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, + 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05, 0xd11f6234, 0xc48afea6, + 0x349d532e, 0xa2a055f3, 0x0532e18a, 0xa475ebf6, 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, + 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, 0x71055dc4, 0x046fd406, 0x60ff1550, + 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19, 0x79dbeec8, + 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, + 0xfdfbff0e, 0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, + 0x0cb1670a, 0x930fe757, 0xb4d296ee, 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, + 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, + 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, + 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, + 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, 0x0dec5286, 0x77d0e3c1, + 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, + 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad, + 0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, + 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, + 0xcd097826, 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, + 0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, + 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, + 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165, + 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, + 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147, + 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, + 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, + 0x397101a8, 0x08deb30c, 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8, +}; + +rx_vec_i128 soft_aesenc(rx_vec_i128 in, rx_vec_i128 key) { + uint32_t s0, s1, s2, s3; + + s0 = rx_vec_i128_w(in); + s1 = rx_vec_i128_z(in); + s2 = rx_vec_i128_y(in); + s3 = rx_vec_i128_x(in); + + rx_vec_i128 out = rx_set_int_vec_i128( + (lutEnc0[s0 & 0xff] ^ lutEnc1[(s3 >> 8) & 0xff] ^ lutEnc2[(s2 >> 16) & 0xff] ^ lutEnc3[s1 >> 24]), + (lutEnc0[s1 & 0xff] ^ lutEnc1[(s0 >> 8) & 0xff] ^ lutEnc2[(s3 >> 16) & 0xff] ^ lutEnc3[s2 >> 24]), + (lutEnc0[s2 & 0xff] ^ lutEnc1[(s1 >> 8) & 0xff] ^ lutEnc2[(s0 >> 16) & 0xff] ^ lutEnc3[s3 >> 24]), + (lutEnc0[s3 & 0xff] ^ lutEnc1[(s2 >> 8) & 0xff] ^ lutEnc2[(s1 >> 16) & 0xff] ^ lutEnc3[s0 >> 24]) + ); + + return rx_xor_vec_i128(out, key); +} + +rx_vec_i128 soft_aesdec(rx_vec_i128 in, rx_vec_i128 key) { + uint32_t s0, s1, s2, s3; + + s0 = rx_vec_i128_w(in); + s1 = rx_vec_i128_z(in); + s2 = rx_vec_i128_y(in); + s3 = rx_vec_i128_x(in); + + rx_vec_i128 out = rx_set_int_vec_i128( + (lutDec0[s0 & 0xff] ^ lutDec1[(s1 >> 8) & 0xff] ^ lutDec2[(s2 >> 16) & 0xff] ^ lutDec3[s3 >> 24]), + (lutDec0[s1 & 0xff] ^ lutDec1[(s2 >> 8) & 0xff] ^ lutDec2[(s3 >> 16) & 0xff] ^ lutDec3[s0 >> 24]), + (lutDec0[s2 & 0xff] ^ lutDec1[(s3 >> 8) & 0xff] ^ lutDec2[(s0 >> 16) & 0xff] ^ lutDec3[s1 >> 24]), + (lutDec0[s3 & 0xff] ^ lutDec1[(s0 >> 8) & 0xff] ^ lutDec2[(s1 >> 16) & 0xff] ^ lutDec3[s2 >> 24]) + ); + + return rx_xor_vec_i128(out, key); +} diff --git a/src/crypto/randomx/soft_aes.h b/src/crypto/randomx/soft_aes.h new file mode 100644 index 00000000..254f8d63 --- /dev/null +++ b/src/crypto/randomx/soft_aes.h @@ -0,0 +1,46 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include "intrin_portable.h" + +rx_vec_i128 soft_aesenc(rx_vec_i128 in, rx_vec_i128 key); + +rx_vec_i128 soft_aesdec(rx_vec_i128 in, rx_vec_i128 key); + +template +inline rx_vec_i128 aesenc(rx_vec_i128 in, rx_vec_i128 key) { + return soft ? soft_aesenc(in, key) : rx_aesenc_vec_i128(in, key); +} + +template +inline rx_vec_i128 aesdec(rx_vec_i128 in, rx_vec_i128 key) { + return soft ? soft_aesdec(in, key) : rx_aesdec_vec_i128(in, key); +} \ No newline at end of file diff --git a/src/crypto/randomx/superscalar.cpp b/src/crypto/randomx/superscalar.cpp new file mode 100644 index 00000000..c0d496b9 --- /dev/null +++ b/src/crypto/randomx/superscalar.cpp @@ -0,0 +1,891 @@ +/* +Copyright (c) 2018-2019, tevador + +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 "configuration.h" +#include "program.hpp" +#include "blake2/endian.h" +#include "superscalar.hpp" +#include "intrin_portable.h" +#include "reciprocal.h" + +namespace randomx { + + static bool isMultiplication(SuperscalarInstructionType type) { + return type == SuperscalarInstructionType::IMUL_R || type == SuperscalarInstructionType::IMULH_R || type == SuperscalarInstructionType::ISMULH_R || type == SuperscalarInstructionType::IMUL_RCP; + } + + //uOPs (micro-ops) are represented only by the execution port they can go to + namespace ExecutionPort { + using type = int; + constexpr type Null = 0; + constexpr type P0 = 1; + constexpr type P1 = 2; + constexpr type P5 = 4; + constexpr type P01 = P0 | P1; + constexpr type P05 = P0 | P5; + constexpr type P015 = P0 | P1 | P5; + } + + //Macro-operation as output of the x86 decoder + //Usually one macro-op = one x86 instruction, but 2 instructions are sometimes fused into 1 macro-op + //Macro-op can consist of 1 or 2 uOPs. + class MacroOp { + public: + MacroOp(const char* name, int size) + : name_(name), size_(size), latency_(0), uop1_(ExecutionPort::Null), uop2_(ExecutionPort::Null) {} + MacroOp(const char* name, int size, int latency, ExecutionPort::type uop) + : name_(name), size_(size), latency_(latency), uop1_(uop), uop2_(ExecutionPort::Null) {} + MacroOp(const char* name, int size, int latency, ExecutionPort::type uop1, ExecutionPort::type uop2) + : name_(name), size_(size), latency_(latency), uop1_(uop1), uop2_(uop2) {} + MacroOp(const MacroOp& parent, bool dependent) + : name_(parent.name_), size_(parent.size_), latency_(parent.latency_), uop1_(parent.uop1_), uop2_(parent.uop2_), dependent_(dependent) {} + const char* getName() const { + return name_; + } + int getSize() const { + return size_; + } + int getLatency() const { + return latency_; + } + ExecutionPort::type getUop1() const { + return uop1_; + } + ExecutionPort::type getUop2() const { + return uop2_; + } + bool isSimple() const { + return uop2_ == ExecutionPort::Null; + } + bool isEliminated() const { + return uop1_ == ExecutionPort::Null; + } + bool isDependent() const { + return dependent_; + } + static const MacroOp Add_rr; + static const MacroOp Add_ri; + static const MacroOp Lea_sib; + static const MacroOp Sub_rr; + static const MacroOp Imul_rr; + static const MacroOp Imul_r; + static const MacroOp Mul_r; + static const MacroOp Mov_rr; + static const MacroOp Mov_ri64; + static const MacroOp Xor_rr; + static const MacroOp Xor_ri; + static const MacroOp Ror_rcl; + static const MacroOp Ror_ri; + static const MacroOp TestJz_fused; + static const MacroOp Xor_self; + static const MacroOp Cmp_ri; + static const MacroOp Setcc_r; + private: + const char* name_; + int size_; + int latency_; + ExecutionPort::type uop1_; + ExecutionPort::type uop2_; + bool dependent_ = false; + }; + + //Size: 3 bytes + const MacroOp MacroOp::Add_rr = MacroOp("add r,r", 3, 1, ExecutionPort::P015); + const MacroOp MacroOp::Sub_rr = MacroOp("sub r,r", 3, 1, ExecutionPort::P015); + const MacroOp MacroOp::Xor_rr = MacroOp("xor r,r", 3, 1, ExecutionPort::P015); + const MacroOp MacroOp::Imul_r = MacroOp("imul r", 3, 4, ExecutionPort::P1, ExecutionPort::P5); + const MacroOp MacroOp::Mul_r = MacroOp("mul r", 3, 4, ExecutionPort::P1, ExecutionPort::P5); + const MacroOp MacroOp::Mov_rr = MacroOp("mov r,r", 3); + + //Size: 4 bytes + const MacroOp MacroOp::Lea_sib = MacroOp("lea r,r+r*s", 4, 1, ExecutionPort::P01); + const MacroOp MacroOp::Imul_rr = MacroOp("imul r,r", 4, 3, ExecutionPort::P1); + const MacroOp MacroOp::Ror_ri = MacroOp("ror r,i", 4, 1, ExecutionPort::P05); + + //Size: 7 bytes (can be optionally padded with nop to 8 or 9 bytes) + const MacroOp MacroOp::Add_ri = MacroOp("add r,i", 7, 1, ExecutionPort::P015); + const MacroOp MacroOp::Xor_ri = MacroOp("xor r,i", 7, 1, ExecutionPort::P015); + + //Size: 10 bytes + const MacroOp MacroOp::Mov_ri64 = MacroOp("mov rax,i64", 10, 1, ExecutionPort::P015); + + //Unused: + const MacroOp MacroOp::Ror_rcl = MacroOp("ror r,cl", 3, 1, ExecutionPort::P0, ExecutionPort::P5); + const MacroOp MacroOp::Xor_self = MacroOp("xor rcx,rcx", 3); + const MacroOp MacroOp::Cmp_ri = MacroOp("cmp r,i", 7, 1, ExecutionPort::P015); + const MacroOp MacroOp::Setcc_r = MacroOp("setcc cl", 3, 1, ExecutionPort::P05); + const MacroOp MacroOp::TestJz_fused = MacroOp("testjz r,i", 13, 0, ExecutionPort::P5); + + const MacroOp IMULH_R_ops_array[] = { MacroOp::Mov_rr, MacroOp::Mul_r, MacroOp::Mov_rr }; + const MacroOp ISMULH_R_ops_array[] = { MacroOp::Mov_rr, MacroOp::Imul_r, MacroOp::Mov_rr }; + const MacroOp IMUL_RCP_ops_array[] = { MacroOp::Mov_ri64, MacroOp(MacroOp::Imul_rr, true) }; + + class SuperscalarInstructionInfo { + public: + const char* getName() const { + return name_; + } + int getSize() const { + return ops_.size(); + } + bool isSimple() const { + return getSize() == 1; + } + int getLatency() const { + return latency_; + } + const MacroOp& getOp(int index) const { + return ops_[index]; + } + SuperscalarInstructionType getType() const { + return type_; + } + int getResultOp() const { + return resultOp_; + } + int getDstOp() const { + return dstOp_; + } + int getSrcOp() const { + return srcOp_; + } + static const SuperscalarInstructionInfo ISUB_R; + static const SuperscalarInstructionInfo IXOR_R; + static const SuperscalarInstructionInfo IADD_RS; + static const SuperscalarInstructionInfo IMUL_R; + static const SuperscalarInstructionInfo IROR_C; + static const SuperscalarInstructionInfo IADD_C7; + static const SuperscalarInstructionInfo IXOR_C7; + static const SuperscalarInstructionInfo IADD_C8; + static const SuperscalarInstructionInfo IXOR_C8; + static const SuperscalarInstructionInfo IADD_C9; + static const SuperscalarInstructionInfo IXOR_C9; + static const SuperscalarInstructionInfo IMULH_R; + static const SuperscalarInstructionInfo ISMULH_R; + static const SuperscalarInstructionInfo IMUL_RCP; + static const SuperscalarInstructionInfo NOP; + private: + const char* name_; + SuperscalarInstructionType type_; + std::vector ops_; + int latency_; + int resultOp_ = 0; + int dstOp_ = 0; + int srcOp_; + + SuperscalarInstructionInfo(const char* name) + : name_(name), type_(SuperscalarInstructionType::INVALID), latency_(0) {} + SuperscalarInstructionInfo(const char* name, SuperscalarInstructionType type, const MacroOp& op, int srcOp) + : name_(name), type_(type), latency_(op.getLatency()), srcOp_(srcOp) { + ops_.push_back(MacroOp(op)); + } + template + SuperscalarInstructionInfo(const char* name, SuperscalarInstructionType type, const MacroOp(&arr)[N], int resultOp, int dstOp, int srcOp) + : name_(name), type_(type), latency_(0), resultOp_(resultOp), dstOp_(dstOp), srcOp_(srcOp) { + for (unsigned i = 0; i < N; ++i) { + ops_.push_back(MacroOp(arr[i])); + latency_ += ops_.back().getLatency(); + } + static_assert(N > 1, "Invalid array size"); + } + }; + + const SuperscalarInstructionInfo SuperscalarInstructionInfo::ISUB_R = SuperscalarInstructionInfo("ISUB_R", SuperscalarInstructionType::ISUB_R, MacroOp::Sub_rr, 0); + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IXOR_R = SuperscalarInstructionInfo("IXOR_R", SuperscalarInstructionType::IXOR_R, MacroOp::Xor_rr, 0); + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IADD_RS = SuperscalarInstructionInfo("IADD_RS", SuperscalarInstructionType::IADD_RS, MacroOp::Lea_sib, 0); + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IMUL_R = SuperscalarInstructionInfo("IMUL_R", SuperscalarInstructionType::IMUL_R, MacroOp::Imul_rr, 0); + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IROR_C = SuperscalarInstructionInfo("IROR_C", SuperscalarInstructionType::IROR_C, MacroOp::Ror_ri, -1); + + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IADD_C7 = SuperscalarInstructionInfo("IADD_C7", SuperscalarInstructionType::IADD_C7, MacroOp::Add_ri, -1); + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IXOR_C7 = SuperscalarInstructionInfo("IXOR_C7", SuperscalarInstructionType::IXOR_C7, MacroOp::Xor_ri, -1); + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IADD_C8 = SuperscalarInstructionInfo("IADD_C8", SuperscalarInstructionType::IADD_C8, MacroOp::Add_ri, -1); + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IXOR_C8 = SuperscalarInstructionInfo("IXOR_C8", SuperscalarInstructionType::IXOR_C8, MacroOp::Xor_ri, -1); + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IADD_C9 = SuperscalarInstructionInfo("IADD_C9", SuperscalarInstructionType::IADD_C9, MacroOp::Add_ri, -1); + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IXOR_C9 = SuperscalarInstructionInfo("IXOR_C9", SuperscalarInstructionType::IXOR_C9, MacroOp::Xor_ri, -1); + + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IMULH_R = SuperscalarInstructionInfo("IMULH_R", SuperscalarInstructionType::IMULH_R, IMULH_R_ops_array, 1, 0, 1); + const SuperscalarInstructionInfo SuperscalarInstructionInfo::ISMULH_R = SuperscalarInstructionInfo("ISMULH_R", SuperscalarInstructionType::ISMULH_R, ISMULH_R_ops_array, 1, 0, 1); + const SuperscalarInstructionInfo SuperscalarInstructionInfo::IMUL_RCP = SuperscalarInstructionInfo("IMUL_RCP", SuperscalarInstructionType::IMUL_RCP, IMUL_RCP_ops_array, 1, 1, -1); + + const SuperscalarInstructionInfo SuperscalarInstructionInfo::NOP = SuperscalarInstructionInfo("NOP"); + + //these are some of the options how to split a 16-byte window into 3 or 4 x86 instructions. + //RandomX uses instructions with a native size of 3 (sub, xor, mul, mov), 4 (lea, mul), 7 (xor, add immediate) or 10 bytes (mov 64-bit immediate). + //Slots with sizes of 8 or 9 bytes need to be padded with a nop instruction. + const int buffer0[] = { 4, 8, 4 }; + const int buffer1[] = { 7, 3, 3, 3 }; + const int buffer2[] = { 3, 7, 3, 3 }; + const int buffer3[] = { 4, 9, 3 }; + const int buffer4[] = { 4, 4, 4, 4 }; + const int buffer5[] = { 3, 3, 10 }; + + class DecoderBuffer { + public: + static const DecoderBuffer Default; + template + DecoderBuffer(const char* name, int index, const int(&arr)[N]) + : name_(name), index_(index), counts_(arr), opsCount_(N) {} + const int* getCounts() const { + return counts_; + } + int getSize() const { + return opsCount_; + } + int getIndex() const { + return index_; + } + const char* getName() const { + return name_; + } + const DecoderBuffer* fetchNext(SuperscalarInstructionType instrType, int cycle, int mulCount, Blake2Generator& gen) const { + //If the current RandomX instruction is "IMULH", the next fetch configuration must be 3-3-10 + //because the full 128-bit multiplication instruction is 3 bytes long and decodes to 2 uOPs on Intel CPUs. + //Intel CPUs can decode at most 4 uOPs per cycle, so this requires a 2-1-1 configuration for a total of 3 macro ops. + if (instrType == SuperscalarInstructionType::IMULH_R || instrType == SuperscalarInstructionType::ISMULH_R) + return &decodeBuffer3310; + + //To make sure that the multiplication port is saturated, a 4-4-4-4 configuration is generated if the number of multiplications + //is lower than the number of cycles. + if (mulCount < cycle + 1) + return &decodeBuffer4444; + + //If the current RandomX instruction is "IMUL_RCP", the next buffer must begin with a 4-byte slot for multiplication. + if(instrType == SuperscalarInstructionType::IMUL_RCP) + return (gen.getByte() & 1) ? &decodeBuffer484 : &decodeBuffer493; + + //Default: select a random fetch configuration. + return fetchNextDefault(gen); + } + private: + const char* name_; + int index_; + const int* counts_; + int opsCount_; + DecoderBuffer() : index_(-1) {} + static const DecoderBuffer decodeBuffer484; + static const DecoderBuffer decodeBuffer7333; + static const DecoderBuffer decodeBuffer3733; + static const DecoderBuffer decodeBuffer493; + static const DecoderBuffer decodeBuffer4444; + static const DecoderBuffer decodeBuffer3310; + static const DecoderBuffer* decodeBuffers[4]; + const DecoderBuffer* fetchNextDefault(Blake2Generator& gen) const { + return decodeBuffers[gen.getByte() & 3]; + } + }; + + const DecoderBuffer DecoderBuffer::decodeBuffer484 = DecoderBuffer("4,8,4", 0, buffer0); + const DecoderBuffer DecoderBuffer::decodeBuffer7333 = DecoderBuffer("7,3,3,3", 1, buffer1); + const DecoderBuffer DecoderBuffer::decodeBuffer3733 = DecoderBuffer("3,7,3,3", 2, buffer2); + const DecoderBuffer DecoderBuffer::decodeBuffer493 = DecoderBuffer("4,9,3", 3, buffer3); + const DecoderBuffer DecoderBuffer::decodeBuffer4444 = DecoderBuffer("4,4,4,4", 4, buffer4); + const DecoderBuffer DecoderBuffer::decodeBuffer3310 = DecoderBuffer("3,3,10", 5, buffer5); + + const DecoderBuffer* DecoderBuffer::decodeBuffers[4] = { + &DecoderBuffer::decodeBuffer484, + &DecoderBuffer::decodeBuffer7333, + &DecoderBuffer::decodeBuffer3733, + &DecoderBuffer::decodeBuffer493, + }; + + const DecoderBuffer DecoderBuffer::Default = DecoderBuffer(); + + const SuperscalarInstructionInfo* slot_3[] = { &SuperscalarInstructionInfo::ISUB_R, &SuperscalarInstructionInfo::IXOR_R }; + const SuperscalarInstructionInfo* slot_3L[] = { &SuperscalarInstructionInfo::ISUB_R, &SuperscalarInstructionInfo::IXOR_R, &SuperscalarInstructionInfo::IMULH_R, &SuperscalarInstructionInfo::ISMULH_R }; + const SuperscalarInstructionInfo* slot_4[] = { &SuperscalarInstructionInfo::IROR_C, &SuperscalarInstructionInfo::IADD_RS }; + const SuperscalarInstructionInfo* slot_7[] = { &SuperscalarInstructionInfo::IXOR_C7, &SuperscalarInstructionInfo::IADD_C7 }; + const SuperscalarInstructionInfo* slot_8[] = { &SuperscalarInstructionInfo::IXOR_C8, &SuperscalarInstructionInfo::IADD_C8 }; + const SuperscalarInstructionInfo* slot_9[] = { &SuperscalarInstructionInfo::IXOR_C9, &SuperscalarInstructionInfo::IADD_C9 }; + const SuperscalarInstructionInfo* slot_10 = &SuperscalarInstructionInfo::IMUL_RCP; + + static bool selectRegister(std::vector& availableRegisters, Blake2Generator& gen, int& reg) { + int index; + if (availableRegisters.size() == 0) + return false; + + if (availableRegisters.size() > 1) { + index = gen.getInt32() % availableRegisters.size(); + } + else { + index = 0; + } + reg = availableRegisters[index]; + return true; + } + + class RegisterInfo { + public: + RegisterInfo() : latency(0), lastOpGroup(SuperscalarInstructionType::INVALID), lastOpPar(-1), value(0) {} + int latency; + SuperscalarInstructionType lastOpGroup; + int lastOpPar; + int value; + }; + + //"SuperscalarInstruction" consists of one or more macro-ops + class SuperscalarInstruction { + public: + void toInstr(Instruction& instr) { //translate to a RandomX instruction format + instr.opcode = (int)getType(); + instr.dst = dst_; + instr.src = src_ >= 0 ? src_ : dst_; + instr.setMod(mod_); + instr.setImm32(imm32_); + } + + void createForSlot(Blake2Generator& gen, int slotSize, int fetchType, bool isLast, bool isFirst) { + switch (slotSize) + { + case 3: + //if this is the last slot, we can also select "IMULH" instructions + if (isLast) { + create(slot_3L[gen.getByte() & 3], gen); + } + else { + create(slot_3[gen.getByte() & 1], gen); + } + break; + case 4: + //if this is the 4-4-4-4 buffer, issue multiplications as the first 3 instructions + if (fetchType == 4 && !isLast) { + create(&SuperscalarInstructionInfo::IMUL_R, gen); + } + else { + create(slot_4[gen.getByte() & 1], gen); + } + break; + case 7: + create(slot_7[gen.getByte() & 1], gen); + break; + case 8: + create(slot_8[gen.getByte() & 1], gen); + break; + case 9: + create(slot_9[gen.getByte() & 1], gen); + break; + case 10: + create(slot_10, gen); + break; + default: + UNREACHABLE; + } + } + + void create(const SuperscalarInstructionInfo* info, Blake2Generator& gen) { + info_ = info; + reset(); + switch (info->getType()) + { + case SuperscalarInstructionType::ISUB_R: { + mod_ = 0; + imm32_ = 0; + opGroup_ = SuperscalarInstructionType::IADD_RS; + groupParIsSource_ = true; + } break; + + case SuperscalarInstructionType::IXOR_R: { + mod_ = 0; + imm32_ = 0; + opGroup_ = SuperscalarInstructionType::IXOR_R; + groupParIsSource_ = true; + } break; + + case SuperscalarInstructionType::IADD_RS: { + mod_ = gen.getByte(); + imm32_ = 0; + opGroup_ = SuperscalarInstructionType::IADD_RS; + groupParIsSource_ = true; + } break; + + case SuperscalarInstructionType::IMUL_R: { + mod_ = 0; + imm32_ = 0; + opGroup_ = SuperscalarInstructionType::IMUL_R; + groupParIsSource_ = true; + } break; + + case SuperscalarInstructionType::IROR_C: { + mod_ = 0; + do { + imm32_ = gen.getByte() & 63; + } while (imm32_ == 0); + opGroup_ = SuperscalarInstructionType::IROR_C; + opGroupPar_ = -1; + } break; + + case SuperscalarInstructionType::IADD_C7: + case SuperscalarInstructionType::IADD_C8: + case SuperscalarInstructionType::IADD_C9: { + mod_ = 0; + imm32_ = gen.getInt32(); + opGroup_ = SuperscalarInstructionType::IADD_C7; + opGroupPar_ = -1; + } break; + + case SuperscalarInstructionType::IXOR_C7: + case SuperscalarInstructionType::IXOR_C8: + case SuperscalarInstructionType::IXOR_C9: { + mod_ = 0; + imm32_ = gen.getInt32(); + opGroup_ = SuperscalarInstructionType::IXOR_C7; + opGroupPar_ = -1; + } break; + + case SuperscalarInstructionType::IMULH_R: { + canReuse_ = true; + mod_ = 0; + imm32_ = 0; + opGroup_ = SuperscalarInstructionType::IMULH_R; + opGroupPar_ = gen.getInt32(); + } break; + + case SuperscalarInstructionType::ISMULH_R: { + canReuse_ = true; + mod_ = 0; + imm32_ = 0; + opGroup_ = SuperscalarInstructionType::ISMULH_R; + opGroupPar_ = gen.getInt32(); + } break; + + case SuperscalarInstructionType::IMUL_RCP: { + mod_ = 0; + do { + imm32_ = gen.getInt32(); + } while ((imm32_ & (imm32_ - 1)) == 0); + opGroup_ = SuperscalarInstructionType::IMUL_RCP; + opGroupPar_ = -1; + } break; + + default: + break; + } + } + + bool selectDestination(int cycle, bool allowChainedMul, RegisterInfo (®isters)[8], Blake2Generator& gen) { + /*if (allowChainedMultiplication && opGroup_ == SuperscalarInstructionType::IMUL_R) + std::cout << "Selecting destination with chained MUL enabled" << std::endl;*/ + std::vector availableRegisters; + //Conditions for the destination register: + // * value must be ready at the required cycle + // * cannot be the same as the source register unless the instruction allows it + // - this avoids optimizable instructions such as "xor r, r" or "sub r, r" + // * register cannot be multiplied twice in a row unless allowChainedMul is true + // - this avoids accumulation of trailing zeroes in registers due to excessive multiplication + // - allowChainedMul is set to true if an attempt to find source/destination registers failed (this is quite rare, but prevents a catastrophic failure of the generator) + // * either the last instruction applied to the register or its source must be different than this instruction + // - this avoids optimizable instruction sequences such as "xor r1, r2; xor r1, r2" or "ror r, C1; ror r, C2" or "add r, C1; add r, C2" + // * register r5 cannot be the destination of the IADD_RS instruction (limitation of the x86 lea instruction) + for (unsigned i = 0; i < 8; ++i) { + if (registers[i].latency <= cycle && (canReuse_ || i != src_) && (allowChainedMul || opGroup_ != SuperscalarInstructionType::IMUL_R || registers[i].lastOpGroup != SuperscalarInstructionType::IMUL_R) && (registers[i].lastOpGroup != opGroup_ || registers[i].lastOpPar != opGroupPar_) && (info_->getType() != SuperscalarInstructionType::IADD_RS || i != RegisterNeedsDisplacement)) + availableRegisters.push_back(i); + } + return selectRegister(availableRegisters, gen, dst_); + } + + bool selectSource(int cycle, RegisterInfo(®isters)[8], Blake2Generator& gen) { + std::vector availableRegisters; + //all registers that are ready at the cycle + for (unsigned i = 0; i < 8; ++i) { + if (registers[i].latency <= cycle) + availableRegisters.push_back(i); + } + //if there are only 2 available registers for IADD_RS and one of them is r5, select it as the source because it cannot be the destination + if (availableRegisters.size() == 2 && info_->getType() == SuperscalarInstructionType::IADD_RS) { + if (availableRegisters[0] == RegisterNeedsDisplacement || availableRegisters[1] == RegisterNeedsDisplacement) { + opGroupPar_ = src_ = RegisterNeedsDisplacement; + return true; + } + } + if (selectRegister(availableRegisters, gen, src_)) { + if (groupParIsSource_) + opGroupPar_ = src_; + return true; + } + return false; + } + + SuperscalarInstructionType getType() { + return info_->getType(); + } + int getSource() { + return src_; + } + int getDestination() { + return dst_; + } + SuperscalarInstructionType getGroup() { + return opGroup_; + } + int getGroupPar() { + return opGroupPar_; + } + + const SuperscalarInstructionInfo& getInfo() const { + return *info_; + } + + static const SuperscalarInstruction Null; + + private: + const SuperscalarInstructionInfo* info_; + int src_ = -1; + int dst_ = -1; + int mod_; + uint32_t imm32_; + SuperscalarInstructionType opGroup_; + int opGroupPar_; + bool canReuse_ = false; + bool groupParIsSource_ = false; + + void reset() { + src_ = dst_ = -1; + canReuse_ = groupParIsSource_ = false; + } + + SuperscalarInstruction(const SuperscalarInstructionInfo* info) : info_(info) { + } + }; + + const SuperscalarInstruction SuperscalarInstruction::Null = SuperscalarInstruction(&SuperscalarInstructionInfo::NOP); + + constexpr int CYCLE_MAP_SIZE = RANDOMX_SUPERSCALAR_MAX_LATENCY + 4; + constexpr int LOOK_FORWARD_CYCLES = 4; + constexpr int MAX_THROWAWAY_COUNT = 256; + + template + static int scheduleUop(ExecutionPort::type uop, ExecutionPort::type(&portBusy)[CYCLE_MAP_SIZE][3], int cycle) { + //The scheduling here is done optimistically by checking port availability in order P5 -> P0 -> P1 to not overload + //port P1 (multiplication) by instructions that can go to any port. + for (; cycle < RandomX_CurrentConfig.SuperscalarLatency + 4; ++cycle) { + if ((uop & ExecutionPort::P5) != 0 && !portBusy[cycle][2]) { + if (commit) { + if (trace) std::cout << "; P5 at cycle " << cycle << std::endl; + portBusy[cycle][2] = uop; + } + return cycle; + } + if ((uop & ExecutionPort::P0) != 0 && !portBusy[cycle][0]) { + if (commit) { + if (trace) std::cout << "; P0 at cycle " << cycle << std::endl; + portBusy[cycle][0] = uop; + } + return cycle; + } + if ((uop & ExecutionPort::P1) != 0 && !portBusy[cycle][1]) { + if (commit) { + if (trace) std::cout << "; P1 at cycle " << cycle << std::endl; + portBusy[cycle][1] = uop; + } + return cycle; + } + } + return -1; + } + + template + static int scheduleMop(const MacroOp& mop, ExecutionPort::type(&portBusy)[CYCLE_MAP_SIZE][3], int cycle, int depCycle) { + //if this macro-op depends on the previous one, increase the starting cycle if needed + //this handles an explicit dependency chain in IMUL_RCP + if (mop.isDependent()) { + cycle = (cycle > depCycle) ? cycle : depCycle; + } + //move instructions are eliminated and don't need an execution unit + if (mop.isEliminated()) { + if (commit) + if (trace) std::cout << "; (eliminated)" << std::endl; + return cycle; + } + else if (mop.isSimple()) { + //this macro-op has only one uOP + return scheduleUop(mop.getUop1(), portBusy, cycle); + } + else { + //macro-ops with 2 uOPs are scheduled conservatively by requiring both uOPs to execute in the same cycle + for (; cycle < RandomX_CurrentConfig.SuperscalarLatency + 4; ++cycle) { + + int cycle1 = scheduleUop(mop.getUop1(), portBusy, cycle); + int cycle2 = scheduleUop(mop.getUop2(), portBusy, cycle); + + if (cycle1 == cycle2) { + if (commit) { + scheduleUop(mop.getUop1(), portBusy, cycle1); + scheduleUop(mop.getUop2(), portBusy, cycle2); + } + return cycle1; + } + } + } + + return -1; + } + + void generateSuperscalar(SuperscalarProgram& prog, Blake2Generator& gen) { + + ExecutionPort::type portBusy[CYCLE_MAP_SIZE][3]; + memset(portBusy, 0, sizeof(portBusy)); + RegisterInfo registers[8]; + + const DecoderBuffer* decodeBuffer = &DecoderBuffer::Default; + SuperscalarInstruction currentInstruction = SuperscalarInstruction::Null; + int macroOpIndex = 0; + int codeSize = 0; + int macroOpCount = 0; + int cycle = 0; + int depCycle = 0; + int retireCycle = 0; + bool portsSaturated = false; + int programSize = 0; + int mulCount = 0; + int decodeCycle; + int throwAwayCount = 0; + + //decode instructions for RANDOMX_SUPERSCALAR_LATENCY cycles or until an execution port is saturated. + //Each decode cycle decodes 16 bytes of x86 code. + //Since a decode cycle produces on average 3.45 macro-ops and there are only 3 ALU ports, execution ports are always + //saturated first. The cycle limit is present only to guarantee loop termination. + //Program size is limited to SuperscalarMaxSize instructions. + for (decodeCycle = 0; decodeCycle < RandomX_CurrentConfig.SuperscalarLatency && !portsSaturated && programSize < 3 * RandomX_CurrentConfig.SuperscalarLatency + 2; ++decodeCycle) { + + //select a decode configuration + decodeBuffer = decodeBuffer->fetchNext(currentInstruction.getType(), decodeCycle, mulCount, gen); + if (trace) std::cout << "; ------------- fetch cycle " << cycle << " (" << decodeBuffer->getName() << ")" << std::endl; + + int bufferIndex = 0; + + //fill all instruction slots in the current decode buffer + while (bufferIndex < decodeBuffer->getSize()) { + int topCycle = cycle; + + //if we have issued all macro-ops for the current RandomX instruction, create a new instruction + if (macroOpIndex >= currentInstruction.getInfo().getSize()) { + if (portsSaturated || programSize >= 3 * RandomX_CurrentConfig.SuperscalarLatency + 2) + break; + //select an instruction so that the first macro-op fits into the current slot + currentInstruction.createForSlot(gen, decodeBuffer->getCounts()[bufferIndex], decodeBuffer->getIndex(), decodeBuffer->getSize() == bufferIndex + 1, bufferIndex == 0); + macroOpIndex = 0; + if (trace) std::cout << "; " << currentInstruction.getInfo().getName() << std::endl; + } + const MacroOp& mop = currentInstruction.getInfo().getOp(macroOpIndex); + if (trace) std::cout << mop.getName() << " "; + + //calculate the earliest cycle when this macro-op (all of its uOPs) can be scheduled for execution + int scheduleCycle = scheduleMop(mop, portBusy, cycle, depCycle); + if (scheduleCycle < 0) { + if (trace) std::cout << "Unable to map operation '" << mop.getName() << "' to execution port (cycle " << cycle << ")" << std::endl; + //__debugbreak(); + portsSaturated = true; + break; + } + + //find a source register (if applicable) that will be ready when this instruction executes + if (macroOpIndex == currentInstruction.getInfo().getSrcOp()) { + int forward; + //if no suitable operand is ready, look up to LOOK_FORWARD_CYCLES forward + for (forward = 0; forward < LOOK_FORWARD_CYCLES && !currentInstruction.selectSource(scheduleCycle, registers, gen); ++forward) { + if (trace) std::cout << "; src STALL at cycle " << cycle << std::endl; + ++scheduleCycle; + ++cycle; + } + //if no register was found, throw the instruction away and try another one + if (forward == LOOK_FORWARD_CYCLES) { + if (throwAwayCount < MAX_THROWAWAY_COUNT) { + throwAwayCount++; + macroOpIndex = currentInstruction.getInfo().getSize(); + if (trace) std::cout << "; THROW away " << currentInstruction.getInfo().getName() << std::endl; + //cycle = topCycle; + continue; + } + //abort this decode buffer + if (trace) std::cout << "Aborting at cycle " << cycle << " with decode buffer " << decodeBuffer->getName() << " - source registers not available for operation " << currentInstruction.getInfo().getName() << std::endl; + currentInstruction = SuperscalarInstruction::Null; + break; + } + if (trace) std::cout << "; src = r" << currentInstruction.getSource() << std::endl; + } + //find a destination register that will be ready when this instruction executes + if (macroOpIndex == currentInstruction.getInfo().getDstOp()) { + int forward; + for (forward = 0; forward < LOOK_FORWARD_CYCLES && !currentInstruction.selectDestination(scheduleCycle, throwAwayCount > 0, registers, gen); ++forward) { + if (trace) std::cout << "; dst STALL at cycle " << cycle << std::endl; + ++scheduleCycle; + ++cycle; + } + if (forward == LOOK_FORWARD_CYCLES) { //throw instruction away + if (throwAwayCount < MAX_THROWAWAY_COUNT) { + throwAwayCount++; + macroOpIndex = currentInstruction.getInfo().getSize(); + if (trace) std::cout << "; THROW away " << currentInstruction.getInfo().getName() << std::endl; + //cycle = topCycle; + continue; + } + //abort this decode buffer + if (trace) std::cout << "Aborting at cycle " << cycle << " with decode buffer " << decodeBuffer->getName() << " - destination registers not available" << std::endl; + currentInstruction = SuperscalarInstruction::Null; + break; + } + if (trace) std::cout << "; dst = r" << currentInstruction.getDestination() << std::endl; + } + throwAwayCount = 0; + + //recalculate when the instruction can be scheduled for execution based on operand availability + scheduleCycle = scheduleMop(mop, portBusy, scheduleCycle, scheduleCycle); + + //calculate when the result will be ready + depCycle = scheduleCycle + mop.getLatency(); + + //if this instruction writes the result, modify register information + // RegisterInfo.latency - which cycle the register will be ready + // RegisterInfo.lastOpGroup - the last operation that was applied to the register + // RegisterInfo.lastOpPar - the last operation source value (-1 = constant, 0-7 = register) + if (macroOpIndex == currentInstruction.getInfo().getResultOp()) { + int dst = currentInstruction.getDestination(); + RegisterInfo& ri = registers[dst]; + retireCycle = depCycle; + ri.latency = retireCycle; + ri.lastOpGroup = currentInstruction.getGroup(); + ri.lastOpPar = currentInstruction.getGroupPar(); + if (trace) std::cout << "; RETIRED at cycle " << retireCycle << std::endl; + } + codeSize += mop.getSize(); + bufferIndex++; + macroOpIndex++; + macroOpCount++; + + //terminating condition + if (scheduleCycle >= RandomX_CurrentConfig.SuperscalarLatency) { + portsSaturated = true; + } + cycle = topCycle; + + //when all macro-ops of the current instruction have been issued, add the instruction into the program + if (macroOpIndex >= currentInstruction.getInfo().getSize()) { + currentInstruction.toInstr(prog(programSize++)); + mulCount += isMultiplication(currentInstruction.getType()); + } + } + ++cycle; + } + + double ipc = (macroOpCount / (double)retireCycle); + + memset(prog.asicLatencies, 0, sizeof(prog.asicLatencies)); + + //Calculate ASIC latency: + //Assumes 1 cycle latency for all operations and unlimited parallelization. + for (int i = 0; i < programSize; ++i) { + Instruction& instr = prog(i); + int latDst = prog.asicLatencies[instr.dst] + 1; + int latSrc = instr.dst != instr.src ? prog.asicLatencies[instr.src] + 1 : 0; + prog.asicLatencies[instr.dst] = (latDst > latSrc) ? latDst : latSrc; + } + + //address register is the register with the highest ASIC latency + int asicLatencyMax = 0; + int addressReg = 0; + for (int i = 0; i < 8; ++i) { + if (prog.asicLatencies[i] > asicLatencyMax) { + asicLatencyMax = prog.asicLatencies[i]; + addressReg = i; + } + prog.cpuLatencies[i] = registers[i].latency; + } + + prog.setSize(programSize); + prog.setAddressRegister(addressReg); + + prog.cpuLatency = retireCycle; + prog.asicLatency = asicLatencyMax; + prog.codeSize = codeSize; + prog.macroOps = macroOpCount; + prog.decodeCycles = decodeCycle; + prog.ipc = ipc; + prog.mulCount = mulCount; + + + /*if(INFO) std::cout << "; ALU port utilization:" << std::endl; + if (INFO) std::cout << "; (* = in use, _ = idle)" << std::endl; + + int portCycles = 0; + for (int i = 0; i < RandomX_Config.SuperscalarLatency + 4; ++i) { + std::cout << "; " << std::setw(3) << i << " "; + for (int j = 0; j < 3; ++j) { + std::cout << (portBusy[i][j] ? '*' : '_'); + portCycles += !!portBusy[i][j]; + } + std::cout << std::endl; + }*/ + } + + void executeSuperscalar(int_reg_t(&r)[8], SuperscalarProgram& prog, std::vector *reciprocals) { + for (unsigned j = 0; j < prog.getSize(); ++j) { + Instruction& instr = prog(j); + switch ((SuperscalarInstructionType)instr.opcode) + { + case SuperscalarInstructionType::ISUB_R: + r[instr.dst] -= r[instr.src]; + break; + case SuperscalarInstructionType::IXOR_R: + r[instr.dst] ^= r[instr.src]; + break; + case SuperscalarInstructionType::IADD_RS: + r[instr.dst] += r[instr.src] << instr.getModShift(); + break; + case SuperscalarInstructionType::IMUL_R: + r[instr.dst] *= r[instr.src]; + break; + case SuperscalarInstructionType::IROR_C: + r[instr.dst] = rotr(r[instr.dst], instr.getImm32()); + break; + case SuperscalarInstructionType::IADD_C7: + case SuperscalarInstructionType::IADD_C8: + case SuperscalarInstructionType::IADD_C9: + r[instr.dst] += signExtend2sCompl(instr.getImm32()); + break; + case SuperscalarInstructionType::IXOR_C7: + case SuperscalarInstructionType::IXOR_C8: + case SuperscalarInstructionType::IXOR_C9: + r[instr.dst] ^= signExtend2sCompl(instr.getImm32()); + break; + case SuperscalarInstructionType::IMULH_R: + r[instr.dst] = mulh(r[instr.dst], r[instr.src]); + break; + case SuperscalarInstructionType::ISMULH_R: + r[instr.dst] = smulh(r[instr.dst], r[instr.src]); + break; + case SuperscalarInstructionType::IMUL_RCP: + if (reciprocals != nullptr) + r[instr.dst] *= (*reciprocals)[instr.getImm32()]; + else + r[instr.dst] *= randomx_reciprocal(instr.getImm32()); + break; + default: + UNREACHABLE; + } + } + } +} diff --git a/src/crypto/randomx/superscalar.hpp b/src/crypto/randomx/superscalar.hpp new file mode 100644 index 00000000..bc101c45 --- /dev/null +++ b/src/crypto/randomx/superscalar.hpp @@ -0,0 +1,60 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include +#include "superscalar_program.hpp" +#include "blake2_generator.hpp" + +namespace randomx { + // Intel Ivy Bridge reference + enum class SuperscalarInstructionType { //uOPs (decode) execution ports latency code size + ISUB_R = 0, //1 p015 1 3 (sub) + IXOR_R = 1, //1 p015 1 3 (xor) + IADD_RS = 2, //1 p01 1 4 (lea) + IMUL_R = 3, //1 p1 3 4 (imul) + IROR_C = 4, //1 p05 1 4 (ror) + IADD_C7 = 5, //1 p015 1 7 (add) + IXOR_C7 = 6, //1 p015 1 7 (xor) + IADD_C8 = 7, //1+0 p015 1 7+1 (add+nop) + IXOR_C8 = 8, //1+0 p015 1 7+1 (xor+nop) + IADD_C9 = 9, //1+0 p015 1 7+2 (add+nop) + IXOR_C9 = 10, //1+0 p015 1 7+2 (xor+nop) + IMULH_R = 11, //1+2+1 0+(p1,p5)+0 3 3+3+3 (mov+mul+mov) + ISMULH_R = 12, //1+2+1 0+(p1,p5)+0 3 3+3+3 (mov+imul+mov) + IMUL_RCP = 13, //1+1 p015+p1 4 10+4 (mov+imul) + + COUNT = 14, + INVALID = -1 + }; + + void generateSuperscalar(SuperscalarProgram& prog, Blake2Generator& gen); + void executeSuperscalar(uint64_t(&r)[8], SuperscalarProgram& prog, std::vector *reciprocals = nullptr); +} \ No newline at end of file diff --git a/src/crypto/randomx/superscalar_program.hpp b/src/crypto/randomx/superscalar_program.hpp new file mode 100644 index 00000000..dbb0b163 --- /dev/null +++ b/src/crypto/randomx/superscalar_program.hpp @@ -0,0 +1,73 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include "instruction.hpp" +#include "common.hpp" + +namespace randomx { + + class SuperscalarProgram { + public: + Instruction& operator()(int pc) { + return programBuffer[pc]; + } + uint32_t getSize() { + return size; + } + void setSize(uint32_t val) { + size = val; + } + int getAddressRegister() { + return addrReg; + } + void setAddressRegister(int val) { + addrReg = val; + } + + Instruction programBuffer[SuperscalarMaxSize]; + uint32_t size +#ifndef NDEBUG + = 0 +#endif + ; + int addrReg; + double ipc; + int codeSize; + int macroOps; + int decodeCycles; + int cpuLatency; + int asicLatency; + int mulCount; + int cpuLatencies[8]; + int asicLatencies[8]; + }; + +} \ No newline at end of file diff --git a/src/crypto/randomx/virtual_machine.cpp b/src/crypto/randomx/virtual_machine.cpp new file mode 100644 index 00000000..caa1efbf --- /dev/null +++ b/src/crypto/randomx/virtual_machine.cpp @@ -0,0 +1,137 @@ +/* +Copyright (c) 2018-2019, tevador + +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 +#include +#include +#include "virtual_machine.hpp" +#include "common.hpp" +#include "aes_hash.hpp" +#include "blake2/blake2.h" +#include "intrin_portable.h" +#include "allocator.hpp" + +randomx_vm::~randomx_vm() { + +} + +void randomx_vm::resetRoundingMode() { + rx_reset_float_state(); +} + +namespace randomx { + + static inline uint64_t getSmallPositiveFloatBits(uint64_t entropy) { + auto exponent = entropy >> 59; //0..31 + auto mantissa = entropy & mantissaMask; + exponent += exponentBias; + exponent &= exponentMask; + exponent <<= mantissaSize; + return exponent | mantissa; + } + + static inline uint64_t getStaticExponent(uint64_t entropy) { + auto exponent = constExponentBits; + exponent |= (entropy >> (64 - staticExponentBits)) << dynamicExponentBits; + exponent <<= mantissaSize; + return exponent; + } + + static inline uint64_t getFloatMask(uint64_t entropy) { + constexpr uint64_t mask22bit = (1ULL << 22) - 1; + return (entropy & mask22bit) | getStaticExponent(entropy); + } + +} + +void randomx_vm::initialize() { + store64(®.a[0].lo, randomx::getSmallPositiveFloatBits(program.getEntropy(0))); + store64(®.a[0].hi, randomx::getSmallPositiveFloatBits(program.getEntropy(1))); + store64(®.a[1].lo, randomx::getSmallPositiveFloatBits(program.getEntropy(2))); + store64(®.a[1].hi, randomx::getSmallPositiveFloatBits(program.getEntropy(3))); + store64(®.a[2].lo, randomx::getSmallPositiveFloatBits(program.getEntropy(4))); + store64(®.a[2].hi, randomx::getSmallPositiveFloatBits(program.getEntropy(5))); + store64(®.a[3].lo, randomx::getSmallPositiveFloatBits(program.getEntropy(6))); + store64(®.a[3].hi, randomx::getSmallPositiveFloatBits(program.getEntropy(7))); + mem.ma = program.getEntropy(8) & CacheLineAlignMask; + mem.mx = program.getEntropy(10); + auto addressRegisters = program.getEntropy(12); + config.readReg0 = 0 + (addressRegisters & 1); + addressRegisters >>= 1; + config.readReg1 = 2 + (addressRegisters & 1); + addressRegisters >>= 1; + config.readReg2 = 4 + (addressRegisters & 1); + addressRegisters >>= 1; + config.readReg3 = 6 + (addressRegisters & 1); + datasetOffset = (program.getEntropy(13) % (DatasetExtraItems + 1)) * randomx::CacheLineSize; + store64(&config.eMask[0], randomx::getFloatMask(program.getEntropy(14))); + store64(&config.eMask[1], randomx::getFloatMask(program.getEntropy(15))); +} + +namespace randomx { + + alignas(16) volatile static rx_vec_i128 aesDummy; + + template + VmBase::~VmBase() { + Allocator::freeMemory(scratchpad, RANDOMX_SCRATCHPAD_L3_MAX_SIZE); + } + + template + void VmBase::allocate() { + if (datasetPtr == nullptr) + throw std::invalid_argument("Cache/Dataset not set"); + if (!softAes) { //if hardware AES is not supported, it's better to fail now than to return a ticking bomb + rx_vec_i128 tmp = rx_load_vec_i128((const rx_vec_i128*)&aesDummy); + tmp = rx_aesenc_vec_i128(tmp, tmp); + rx_store_vec_i128((rx_vec_i128*)&aesDummy, tmp); + } + scratchpad = (uint8_t*)Allocator::allocMemory(RANDOMX_SCRATCHPAD_L3_MAX_SIZE); + } + + template + void VmBase::getFinalResult(void* out, size_t outSize) { + hashAes1Rx4(scratchpad, ScratchpadSize, ®.a); + blake2b(out, outSize, ®, sizeof(RegisterFile), nullptr, 0); + } + + template + void VmBase::initScratchpad(void* seed) { + fillAes1Rx4(seed, ScratchpadSize, scratchpad); + } + + template + void VmBase::generateProgram(void* seed) { + fillAes4Rx4(seed, sizeof(program), &program); + } + + template class VmBase, false>; + template class VmBase, true>; + template class VmBase; + template class VmBase; +} \ No newline at end of file diff --git a/src/crypto/randomx/virtual_machine.hpp b/src/crypto/randomx/virtual_machine.hpp new file mode 100644 index 00000000..488994df --- /dev/null +++ b/src/crypto/randomx/virtual_machine.hpp @@ -0,0 +1,83 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include "common.hpp" +#include "program.hpp" + +/* Global namespace for C binding */ +class randomx_vm { +public: + virtual ~randomx_vm() = 0; + virtual void allocate() = 0; + virtual void getFinalResult(void* out, size_t outSize) = 0; + virtual void setDataset(randomx_dataset* dataset) { } + virtual void setCache(randomx_cache* cache) { } + virtual void initScratchpad(void* seed) = 0; + virtual void run(void* seed) = 0; + void resetRoundingMode(); + randomx::RegisterFile *getRegisterFile() { + return ® + } + const void* getScratchpad() { + return scratchpad; + } + const randomx::Program& getProgram() + { + return program; + } +protected: + void initialize(); + alignas(64) randomx::Program program; + alignas(64) randomx::RegisterFile reg; + alignas(16) randomx::ProgramConfiguration config; + randomx::MemoryRegisters mem; + uint8_t* scratchpad; + union { + randomx_cache* cachePtr = nullptr; + randomx_dataset* datasetPtr; + }; + uint64_t datasetOffset; +}; + +namespace randomx { + + template + class VmBase : public randomx_vm { + public: + ~VmBase() override; + void allocate() override; + void initScratchpad(void* seed) override; + void getFinalResult(void* out, size_t outSize) override; + protected: + void generateProgram(void* seed); + }; + +} \ No newline at end of file diff --git a/src/crypto/randomx/virtual_memory.cpp b/src/crypto/randomx/virtual_memory.cpp new file mode 100644 index 00000000..925e8e86 --- /dev/null +++ b/src/crypto/randomx/virtual_memory.cpp @@ -0,0 +1,105 @@ +/* +Copyright (c) 2018-2019, tevador + +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 "virtual_memory.hpp" + +#include + +#if defined(_WIN32) || defined(__CYGWIN__) +#include +#else +#ifdef __APPLE__ +#include +#endif +#include +#include +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +std::string getErrorMessage(const char* function) { + LPSTR messageBuffer = nullptr; + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + std::string message(messageBuffer, size); + LocalFree(messageBuffer); + return std::string(function) + std::string(": ") + message; +} +#endif + +void* allocExecutableMemory(std::size_t bytes) { + void* mem; +#if defined(_WIN32) || defined(__CYGWIN__) + mem = VirtualAlloc(nullptr, bytes, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (mem == nullptr) + throw std::runtime_error(getErrorMessage("allocExecutableMemory - VirtualAlloc")); +#else + mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (mem == MAP_FAILED) + throw std::runtime_error("allocExecutableMemory - mmap failed"); +#endif + return mem; +} + +constexpr std::size_t align(std::size_t pos, std::size_t align) { + return ((pos - 1) / align + 1) * align; +} + +void* allocLargePagesMemory(std::size_t bytes) { + void* mem; +#if defined(_WIN32) || defined(__CYGWIN__) + auto pageMinimum = GetLargePageMinimum(); + if (pageMinimum > 0) + mem = VirtualAlloc(NULL, align(bytes, pageMinimum), MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE); + else + throw std::runtime_error("allocLargePagesMemory - Large pages are not supported"); + if (mem == nullptr) + throw std::runtime_error(getErrorMessage("allocLargePagesMemory - VirtualAlloc")); +#else +#ifdef __APPLE__ + mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0); +#elif defined(__FreeBSD__) + mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER, -1, 0); +#else + mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, -1, 0); +#endif + if (mem == MAP_FAILED) + throw std::runtime_error("allocLargePagesMemory - mmap failed"); +#endif + return mem; +} + +void freePagedMemory(void* ptr, std::size_t bytes) { +#if defined(_WIN32) || defined(__CYGWIN__) + VirtualFree(ptr, 0, MEM_RELEASE); +#else + munmap(ptr, bytes); +#endif +} diff --git a/src/crypto/randomx/virtual_memory.hpp b/src/crypto/randomx/virtual_memory.hpp new file mode 100644 index 00000000..d3b31db1 --- /dev/null +++ b/src/crypto/randomx/virtual_memory.hpp @@ -0,0 +1,35 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include + +void* allocExecutableMemory(std::size_t); +void* allocLargePagesMemory(std::size_t); +void freePagedMemory(void*, std::size_t); diff --git a/src/crypto/randomx/vm_compiled.cpp b/src/crypto/randomx/vm_compiled.cpp new file mode 100644 index 00000000..7f621a33 --- /dev/null +++ b/src/crypto/randomx/vm_compiled.cpp @@ -0,0 +1,60 @@ +/* +Copyright (c) 2018-2019, tevador + +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 "vm_compiled.hpp" +#include "common.hpp" + +namespace randomx { + + static_assert(sizeof(MemoryRegisters) == 2 * sizeof(addr_t) + sizeof(uintptr_t), "Invalid alignment of struct randomx::MemoryRegisters"); + static_assert(sizeof(RegisterFile) == 256, "Invalid alignment of struct randomx::RegisterFile"); + + template + void CompiledVm::setDataset(randomx_dataset* dataset) { + datasetPtr = dataset; + } + + template + void CompiledVm::run(void* seed) { + VmBase::generateProgram(seed); + randomx_vm::initialize(); + compiler.generateProgram(program, config); + mem.memory = datasetPtr->memory + datasetOffset; + execute(); + } + + template + void CompiledVm::execute() { + compiler.getProgramFunc()(reg, mem, scratchpad, RandomX_CurrentConfig.ProgramIterations); + } + + template class CompiledVm, false>; + template class CompiledVm, true>; + template class CompiledVm; + template class CompiledVm; +} \ No newline at end of file diff --git a/src/crypto/randomx/vm_compiled.hpp b/src/crypto/randomx/vm_compiled.hpp new file mode 100644 index 00000000..856f00d8 --- /dev/null +++ b/src/crypto/randomx/vm_compiled.hpp @@ -0,0 +1,72 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include +#include "virtual_machine.hpp" +#include "jit_compiler.hpp" +#include "allocator.hpp" +#include "dataset.hpp" + +namespace randomx { + + template + class CompiledVm : public VmBase { + public: + void* operator new(size_t size) { + void* ptr = AlignedAllocator::allocMemory(size); + if (ptr == nullptr) + throw std::bad_alloc(); + return ptr; + } + void operator delete(void* ptr) { + AlignedAllocator::freeMemory(ptr, sizeof(CompiledVm)); + } + void setDataset(randomx_dataset* dataset) override; + void run(void* seed) override; + + using VmBase::mem; + using VmBase::program; + using VmBase::config; + using VmBase::reg; + using VmBase::scratchpad; + using VmBase::datasetPtr; + using VmBase::datasetOffset; + protected: + void execute(); + + JitCompiler compiler; + }; + + using CompiledVmDefault = CompiledVm, true>; + using CompiledVmHardAes = CompiledVm, false>; + using CompiledVmLargePage = CompiledVm; + using CompiledVmLargePageHardAes = CompiledVm; +} diff --git a/src/crypto/randomx/vm_compiled_light.cpp b/src/crypto/randomx/vm_compiled_light.cpp new file mode 100644 index 00000000..c083f4aa --- /dev/null +++ b/src/crypto/randomx/vm_compiled_light.cpp @@ -0,0 +1,54 @@ +/* +Copyright (c) 2018-2019, tevador + +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 "vm_compiled_light.hpp" +#include "common.hpp" +#include + +namespace randomx { + + template + void CompiledLightVm::setCache(randomx_cache* cache) { + cachePtr = cache; + mem.memory = cache->memory; + compiler.generateSuperscalarHash(cache->programs, cache->reciprocalCache); + } + + template + void CompiledLightVm::run(void* seed) { + VmBase::generateProgram(seed); + randomx_vm::initialize(); + compiler.generateProgramLight(program, config, datasetOffset); + CompiledVm::execute(); + } + + template class CompiledLightVm, false>; + template class CompiledLightVm, true>; + template class CompiledLightVm; + template class CompiledLightVm; +} \ No newline at end of file diff --git a/src/crypto/randomx/vm_compiled_light.hpp b/src/crypto/randomx/vm_compiled_light.hpp new file mode 100644 index 00000000..6af82bbe --- /dev/null +++ b/src/crypto/randomx/vm_compiled_light.hpp @@ -0,0 +1,64 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include "vm_compiled.hpp" + +namespace randomx { + + template + class CompiledLightVm : public CompiledVm { + public: + void* operator new(size_t size) { + void* ptr = AlignedAllocator::allocMemory(size); + if (ptr == nullptr) + throw std::bad_alloc(); + return ptr; + } + void operator delete(void* ptr) { + AlignedAllocator::freeMemory(ptr, sizeof(CompiledLightVm)); + } + void setCache(randomx_cache* cache) override; + void setDataset(randomx_dataset* dataset) override { } + void run(void* seed) override; + + using CompiledVm::mem; + using CompiledVm::compiler; + using CompiledVm::program; + using CompiledVm::config; + using CompiledVm::cachePtr; + using CompiledVm::datasetOffset; + }; + + using CompiledLightVmDefault = CompiledLightVm, true>; + using CompiledLightVmHardAes = CompiledLightVm, false>; + using CompiledLightVmLargePage = CompiledLightVm; + using CompiledLightVmLargePageHardAes = CompiledLightVm; +} \ No newline at end of file diff --git a/src/crypto/randomx/vm_interpreted.cpp b/src/crypto/randomx/vm_interpreted.cpp new file mode 100644 index 00000000..236d3efe --- /dev/null +++ b/src/crypto/randomx/vm_interpreted.cpp @@ -0,0 +1,125 @@ +/* +Copyright (c) 2018-2019, tevador + +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 "vm_interpreted.hpp" +#include "dataset.hpp" +#include "intrin_portable.h" +#include "reciprocal.h" + +namespace randomx { + + template + void InterpretedVm::setDataset(randomx_dataset* dataset) { + datasetPtr = dataset; + mem.memory = dataset->memory; + } + + template + void InterpretedVm::run(void* seed) { + VmBase::generateProgram(seed); + randomx_vm::initialize(); + execute(); + } + + template + void InterpretedVm::execute() { + + NativeRegisterFile nreg; + + for(unsigned i = 0; i < RegisterCountFlt; ++i) + nreg.a[i] = rx_load_vec_f128(®.a[i].lo); + + compileProgram(program, bytecode, nreg); + + uint32_t spAddr0 = mem.mx; + uint32_t spAddr1 = mem.ma; + + for(unsigned ic = 0; ic < RandomX_CurrentConfig.ProgramIterations; ++ic) { + uint64_t spMix = nreg.r[config.readReg0] ^ nreg.r[config.readReg1]; + spAddr0 ^= spMix; + spAddr0 &= ScratchpadL3Mask64; + spAddr1 ^= spMix >> 32; + spAddr1 &= ScratchpadL3Mask64; + + for (unsigned i = 0; i < RegistersCount; ++i) + nreg.r[i] ^= load64(scratchpad + spAddr0 + 8 * i); + + for (unsigned i = 0; i < RegisterCountFlt; ++i) + nreg.f[i] = rx_cvt_packed_int_vec_f128(scratchpad + spAddr1 + 8 * i); + + for (unsigned i = 0; i < RegisterCountFlt; ++i) + nreg.e[i] = maskRegisterExponentMantissa(config, rx_cvt_packed_int_vec_f128(scratchpad + spAddr1 + 8 * (RegisterCountFlt + i))); + + executeBytecode(bytecode, scratchpad, config); + + mem.mx ^= nreg.r[config.readReg2] ^ nreg.r[config.readReg3]; + mem.mx &= CacheLineAlignMask; + datasetPrefetch(datasetOffset + mem.mx); + datasetRead(datasetOffset + mem.ma, nreg.r); + std::swap(mem.mx, mem.ma); + + for (unsigned i = 0; i < RegistersCount; ++i) + store64(scratchpad + spAddr1 + 8 * i, nreg.r[i]); + + for (unsigned i = 0; i < RegisterCountFlt; ++i) + nreg.f[i] = rx_xor_vec_f128(nreg.f[i], nreg.e[i]); + + for (unsigned i = 0; i < RegisterCountFlt; ++i) + rx_store_vec_f128((double*)(scratchpad + spAddr0 + 16 * i), nreg.f[i]); + + spAddr0 = 0; + spAddr1 = 0; + } + + for (unsigned i = 0; i < RegistersCount; ++i) + store64(®.r[i], nreg.r[i]); + + for (unsigned i = 0; i < RegisterCountFlt; ++i) + rx_store_vec_f128(®.f[i].lo, nreg.f[i]); + + for (unsigned i = 0; i < RegisterCountFlt; ++i) + rx_store_vec_f128(®.e[i].lo, nreg.e[i]); + } + + template + void InterpretedVm::datasetRead(uint64_t address, int_reg_t(&r)[RegistersCount]) { + uint64_t* datasetLine = (uint64_t*)(mem.memory + address); + for (int i = 0; i < RegistersCount; ++i) + r[i] ^= datasetLine[i]; + } + + template + void InterpretedVm::datasetPrefetch(uint64_t address) { + rx_prefetch_nta(mem.memory + address); + } + + template class InterpretedVm, false>; + template class InterpretedVm, true>; + template class InterpretedVm; + template class InterpretedVm; +} \ No newline at end of file diff --git a/src/crypto/randomx/vm_interpreted.hpp b/src/crypto/randomx/vm_interpreted.hpp new file mode 100644 index 00000000..99c88852 --- /dev/null +++ b/src/crypto/randomx/vm_interpreted.hpp @@ -0,0 +1,75 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include +#include "common.hpp" +#include "virtual_machine.hpp" +#include "bytecode_machine.hpp" +#include "intrin_portable.h" +#include "allocator.hpp" + +namespace randomx { + + template + class InterpretedVm : public VmBase, public BytecodeMachine { + public: + using VmBase::mem; + using VmBase::scratchpad; + using VmBase::program; + using VmBase::config; + using VmBase::reg; + using VmBase::datasetPtr; + using VmBase::datasetOffset; + void* operator new(size_t size) { + void* ptr = AlignedAllocator::allocMemory(size); + if (ptr == nullptr) + throw std::bad_alloc(); + return ptr; + } + void operator delete(void* ptr) { + AlignedAllocator::freeMemory(ptr, sizeof(InterpretedVm)); + } + void run(void* seed) override; + void setDataset(randomx_dataset* dataset) override; + protected: + virtual void datasetRead(uint64_t blockNumber, int_reg_t(&r)[RegistersCount]); + virtual void datasetPrefetch(uint64_t blockNumber); + private: + void execute(); + + InstructionByteCode bytecode[RANDOMX_PROGRAM_MAX_SIZE]; + }; + + using InterpretedVmDefault = InterpretedVm, true>; + using InterpretedVmHardAes = InterpretedVm, false>; + using InterpretedVmLargePage = InterpretedVm; + using InterpretedVmLargePageHardAes = InterpretedVm; +} \ No newline at end of file diff --git a/src/crypto/randomx/vm_interpreted_light.cpp b/src/crypto/randomx/vm_interpreted_light.cpp new file mode 100644 index 00000000..c54b32f6 --- /dev/null +++ b/src/crypto/randomx/vm_interpreted_light.cpp @@ -0,0 +1,55 @@ +/* +Copyright (c) 2018-2019, tevador + +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 "vm_interpreted_light.hpp" +#include "dataset.hpp" + +namespace randomx { + + template + void InterpretedLightVm::setCache(randomx_cache* cache) { + cachePtr = cache; + mem.memory = cache->memory; + } + + template + void InterpretedLightVm::datasetRead(uint64_t address, int_reg_t(&r)[8]) { + uint32_t itemNumber = address / CacheLineSize; + int_reg_t rl[8]; + + initDatasetItem(cachePtr, (uint8_t*)rl, itemNumber); + + for (unsigned q = 0; q < 8; ++q) + r[q] ^= rl[q]; + } + + template class InterpretedLightVm, false>; + template class InterpretedLightVm, true>; + template class InterpretedLightVm; + template class InterpretedLightVm; +} diff --git a/src/crypto/randomx/vm_interpreted_light.hpp b/src/crypto/randomx/vm_interpreted_light.hpp new file mode 100644 index 00000000..02d678f6 --- /dev/null +++ b/src/crypto/randomx/vm_interpreted_light.hpp @@ -0,0 +1,61 @@ +/* +Copyright (c) 2018-2019, tevador + +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 + +#include +#include "vm_interpreted.hpp" + +namespace randomx { + + template + class InterpretedLightVm : public InterpretedVm { + public: + using VmBase::mem; + using VmBase::cachePtr; + void* operator new(size_t size) { + void* ptr = AlignedAllocator::allocMemory(size); + if (ptr == nullptr) + throw std::bad_alloc(); + return ptr; + } + void operator delete(void* ptr) { + AlignedAllocator::freeMemory(ptr, sizeof(InterpretedLightVm)); + } + void setDataset(randomx_dataset* dataset) override { } + void setCache(randomx_cache* cache) override; + protected: + void datasetRead(uint64_t address, int_reg_t(&r)[8]) override; + void datasetPrefetch(uint64_t address) override { } + }; + + using InterpretedLightVmDefault = InterpretedLightVm, true>; + using InterpretedLightVmHardAes = InterpretedLightVm, false>; + using InterpretedLightVmLargePage = InterpretedLightVm; + using InterpretedLightVmLargePageHardAes = InterpretedLightVm; +} diff --git a/src/workers/CpuThread.cpp b/src/workers/CpuThread.cpp index de99a0cd..7e5a039f 100644 --- a/src/workers/CpuThread.cpp +++ b/src/workers/CpuThread.cpp @@ -391,6 +391,7 @@ xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant a cryptonight_quad_hash, cryptonight_penta_hash, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI # ifdef XMRIG_ALGO_CN_LITE cryptonight_single_hash, @@ -431,6 +432,7 @@ xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant a nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI # else nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 @@ -450,6 +452,7 @@ xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant a nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI # endif # ifdef XMRIG_ALGO_CN_HEAVY @@ -503,6 +506,7 @@ xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant a nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI # else nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 @@ -522,6 +526,7 @@ xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant a nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI # endif # ifdef XMRIG_ALGO_CN_PICO @@ -554,6 +559,7 @@ xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant a nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI # else nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 @@ -573,6 +579,7 @@ xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant a nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI # endif nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 @@ -592,6 +599,7 @@ xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant a nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI }; static_assert(count == sizeof(func_table) / sizeof(func_table[0]), "func_table size mismatch"); diff --git a/src/workers/MultiWorker.cpp b/src/workers/MultiWorker.cpp index d17a2c2e..86ff3fc4 100644 --- a/src/workers/MultiWorker.cpp +++ b/src/workers/MultiWorker.cpp @@ -162,9 +162,9 @@ void MultiWorker::start() const xmrig::Variant v = m_state.job.algorithm().variant(); # ifdef XMRIG_ALGO_RANDOMX - if (v == xmrig::VARIANT_RX_WOW) { + if ((v == xmrig::VARIANT_RX_WOW) || (v == xmrig::VARIANT_RX_LOKI)) { allocateRandomX_VM(); - Workers::updateDataset(m_state.job.seedHash(), m_totalWays); + Workers::updateDataset(m_state.job.seedHash(), v, m_totalWays); randomx_calculate_hash(m_rx_vm, m_state.blob, m_state.job.size(), m_hash); } else diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index 458db4a5..f3d2a663 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -65,6 +65,7 @@ uv_rwlock_t Workers::m_rx_dataset_lock; randomx_cache *Workers::m_rx_cache = nullptr; randomx_dataset *Workers::m_rx_dataset = nullptr; uint8_t Workers::m_rx_seed_hash[32] = {}; +xmrig::Variant Workers::m_rx_variant = xmrig::VARIANT_MAX; std::atomic Workers::m_rx_dataset_init_thread_counter = {}; #endif @@ -380,10 +381,10 @@ void Workers::start(IWorker *worker) #ifdef XMRIG_ALGO_RANDOMX -void Workers::updateDataset(const uint8_t* seed_hash, const uint32_t num_threads) +void Workers::updateDataset(const uint8_t* seed_hash, xmrig::Variant variant, const uint32_t num_threads) { // Check if we need to update cache and dataset - if (memcmp(m_rx_seed_hash, seed_hash, sizeof(m_rx_seed_hash)) == 0) + if ((memcmp(m_rx_seed_hash, seed_hash, sizeof(m_rx_seed_hash)) == 0) && (m_rx_variant == variant)) return; const uint32_t thread_id = m_rx_dataset_init_thread_counter++; @@ -400,10 +401,24 @@ void Workers::updateDataset(const uint8_t* seed_hash, const uint32_t num_threads // One of the threads updates cache uv_rwlock_wrlock(&m_rx_dataset_lock); + + if (m_rx_variant != variant) { + switch (variant) { + case xmrig::VARIANT_RX_WOW: + randomx_apply_config(RandomX_WowneroConfig); + break; + case xmrig::VARIANT_RX_LOKI: + randomx_apply_config(RandomX_LokiConfig); + break; + } + m_rx_variant = variant; + } + if (memcmp(m_rx_seed_hash, seed_hash, sizeof(m_rx_seed_hash)) != 0) { memcpy(m_rx_seed_hash, seed_hash, sizeof(m_rx_seed_hash)); randomx_init_cache(m_rx_cache, m_rx_seed_hash, sizeof(m_rx_seed_hash)); } + uv_rwlock_wrunlock(&m_rx_dataset_lock); // All threads update dataset diff --git a/src/workers/Workers.h b/src/workers/Workers.h index 1ea11960..3a52073c 100644 --- a/src/workers/Workers.h +++ b/src/workers/Workers.h @@ -77,7 +77,7 @@ public: # endif # ifdef XMRIG_ALGO_RANDOMX - static void updateDataset(const uint8_t* seed_hash, uint32_t num_threads); + static void updateDataset(const uint8_t* seed_hash, xmrig::Variant variant, uint32_t num_threads); static randomx_dataset* getDataset(); # endif @@ -131,6 +131,7 @@ private: static randomx_cache *m_rx_cache; static randomx_dataset *m_rx_dataset; static uint8_t m_rx_seed_hash[32]; + static xmrig::Variant m_rx_variant; static std::atomic m_rx_dataset_init_thread_counter; # endif }; From 915729bec69e39a6c3c49ba9def5ddaa834b1fee Mon Sep 17 00:00:00 2001 From: SChernykh Date: Mon, 1 Jul 2019 20:48:51 +0200 Subject: [PATCH 14/65] Fixed MingGW compilation --- CMakeLists.txt | 5 ++++- cmake/flags.cmake | 2 +- src/crypto/randomx/bytecode_machine.hpp | 6 +++--- src/crypto/randomx/common.hpp | 14 +++++++------- src/crypto/randomx/instructions_portable.cpp | 20 ++++++++++---------- src/crypto/randomx/intrin_portable.h | 4 ++-- src/crypto/randomx/superscalar.cpp | 2 +- src/workers/Workers.cpp | 3 +++ 8 files changed, 31 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 57af7068..7e3cf2a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,13 +185,16 @@ if (WITH_RANDOMX) src/crypto/randomx/vm_compiled_light.cpp src/crypto/randomx/blake2/blake2b.c ) + if (NOT ARCH_ID) + set(ARCH_ID ${CMAKE_HOST_SYSTEM_PROCESSOR}) + endif() if (CMAKE_C_COMPILER_ID MATCHES MSVC) enable_language(ASM_MASM) list(APPEND SOURCES_CRYPTO src/crypto/randomx/jit_compiler_x86_static.asm src/crypto/randomx/jit_compiler_x86.cpp ) - elseif (ARCH_ID STREQUAL "x86_64" OR ARCH_ID STREQUAL "x86-64" OR ARCH_ID STREQUAL "amd64") + elseif (ARCH_ID STREQUAL "x86_64" OR ARCH_ID STREQUAL "x86-64" OR ARCH_ID STREQUAL "amd64" OR ARCH_ID STREQUAL "AMD64") list(APPEND SOURCES_CRYPTO src/crypto/randomx/jit_compiler_x86_static.S src/crypto/randomx/jit_compiler_x86.cpp diff --git a/cmake/flags.cmake b/cmake/flags.cmake index d0036628..3a0add7a 100644 --- a/cmake/flags.cmake +++ b/cmake/flags.cmake @@ -17,7 +17,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-strict-aliasing") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-exceptions -fno-rtti -Wno-class-memaccess") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fexceptions -fno-rtti -Wno-class-memaccess") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -s") if (XMRIG_ARMv8) diff --git a/src/crypto/randomx/bytecode_machine.hpp b/src/crypto/randomx/bytecode_machine.hpp index c4175b70..3b05f378 100644 --- a/src/crypto/randomx/bytecode_machine.hpp +++ b/src/crypto/randomx/bytecode_machine.hpp @@ -161,11 +161,11 @@ namespace randomx { } static void exe_IROR_R(RANDOMX_EXE_ARGS) { - *ibc.idst = rotr(*ibc.idst, *ibc.isrc & 63); + *ibc.idst = rotr64(*ibc.idst, *ibc.isrc & 63); } static void exe_IROL_R(RANDOMX_EXE_ARGS) { - *ibc.idst = rotl(*ibc.idst, *ibc.isrc & 63); + *ibc.idst = rotl64(*ibc.idst, *ibc.isrc & 63); } static void exe_ISWAP_R(RANDOMX_EXE_ARGS) { @@ -225,7 +225,7 @@ namespace randomx { } static void exe_CFROUND(RANDOMX_EXE_ARGS) { - rx_set_rounding_mode(rotr(*ibc.isrc, ibc.imm) % 4); + rx_set_rounding_mode(rotr64(*ibc.isrc, ibc.imm) % 4); } static void exe_ISTORE(RANDOMX_EXE_ARGS) { diff --git a/src/crypto/randomx/common.hpp b/src/crypto/randomx/common.hpp index 6f60f606..7f7ea0ed 100644 --- a/src/crypto/randomx/common.hpp +++ b/src/crypto/randomx/common.hpp @@ -59,13 +59,13 @@ namespace randomx { //static_assert(RANDOMX_JUMP_OFFSET >= 0, "RANDOMX_JUMP_OFFSET must be greater than or equal to 0."); //static_assert(RANDOMX_JUMP_BITS + RANDOMX_JUMP_OFFSET <= 16, "RANDOMX_JUMP_BITS + RANDOMX_JUMP_OFFSET must not exceed 16."); - //constexpr int wtSum = RANDOMX_FREQ_IADD_RS + RANDOMX_FREQ_IADD_M + RANDOMX_FREQ_ISUB_R + \ - // RANDOMX_FREQ_ISUB_M + RANDOMX_FREQ_IMUL_R + RANDOMX_FREQ_IMUL_M + RANDOMX_FREQ_IMULH_R + \ - // RANDOMX_FREQ_IMULH_M + RANDOMX_FREQ_ISMULH_R + RANDOMX_FREQ_ISMULH_M + RANDOMX_FREQ_IMUL_RCP + \ - // RANDOMX_FREQ_INEG_R + RANDOMX_FREQ_IXOR_R + RANDOMX_FREQ_IXOR_M + RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R + RANDOMX_FREQ_ISWAP_R + \ - // RANDOMX_FREQ_FSWAP_R + RANDOMX_FREQ_FADD_R + RANDOMX_FREQ_FADD_M + RANDOMX_FREQ_FSUB_R + RANDOMX_FREQ_FSUB_M + \ - // RANDOMX_FREQ_FSCAL_R + RANDOMX_FREQ_FMUL_R + RANDOMX_FREQ_FDIV_M + RANDOMX_FREQ_FSQRT_R + RANDOMX_FREQ_CBRANCH + \ - // RANDOMX_FREQ_CFROUND + RANDOMX_FREQ_ISTORE + RANDOMX_FREQ_NOP; + /*constexpr int wtSum = RANDOMX_FREQ_IADD_RS + RANDOMX_FREQ_IADD_M + RANDOMX_FREQ_ISUB_R + \ + RANDOMX_FREQ_ISUB_M + RANDOMX_FREQ_IMUL_R + RANDOMX_FREQ_IMUL_M + RANDOMX_FREQ_IMULH_R + \ + RANDOMX_FREQ_IMULH_M + RANDOMX_FREQ_ISMULH_R + RANDOMX_FREQ_ISMULH_M + RANDOMX_FREQ_IMUL_RCP + \ + RANDOMX_FREQ_INEG_R + RANDOMX_FREQ_IXOR_R + RANDOMX_FREQ_IXOR_M + RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R + RANDOMX_FREQ_ISWAP_R + \ + RANDOMX_FREQ_FSWAP_R + RANDOMX_FREQ_FADD_R + RANDOMX_FREQ_FADD_M + RANDOMX_FREQ_FSUB_R + RANDOMX_FREQ_FSUB_M + \ + RANDOMX_FREQ_FSCAL_R + RANDOMX_FREQ_FMUL_R + RANDOMX_FREQ_FDIV_M + RANDOMX_FREQ_FSQRT_R + RANDOMX_FREQ_CBRANCH + \ + RANDOMX_FREQ_CFROUND + RANDOMX_FREQ_ISTORE + RANDOMX_FREQ_NOP;*/ //static_assert(wtSum == 256, "Sum of instruction frequencies must be 256."); diff --git a/src/crypto/randomx/instructions_portable.cpp b/src/crypto/randomx/instructions_portable.cpp index 797c84c4..8c466ebe 100644 --- a/src/crypto/randomx/instructions_portable.cpp +++ b/src/crypto/randomx/instructions_portable.cpp @@ -51,14 +51,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include - uint64_t rotl(uint64_t x, unsigned int c) { + uint64_t rotl64(uint64_t x, unsigned int c) { return _rotl64(x, c); } - uint64_t rotr(uint64_t x, unsigned int c) { + uint64_t rotr64(uint64_t x, unsigned int c) { return _rotr64(x, c); } - #define HAVE_ROTL - #define HAVE_ROTR + #define HAVE_ROTL64 + #define HAVE_ROTR64 #if EVAL_DEFINE(__MACHINEARM64_X64(1)) uint64_t mulh(uint64_t a, uint64_t b) { @@ -88,18 +88,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. } #endif -#ifndef HAVE_ROTR - uint64_t rotr(uint64_t a, unsigned int b) { +#ifndef HAVE_ROTR64 + uint64_t rotr64(uint64_t a, unsigned int b) { return (a >> b) | (a << (-b & 63)); } - #define HAVE_ROTR + #define HAVE_ROTR64 #endif -#ifndef HAVE_ROTL - uint64_t rotl(uint64_t a, unsigned int b) { +#ifndef HAVE_ROTL64 + uint64_t rotl64(uint64_t a, unsigned int b) { return (a << b) | (a >> (-b & 63)); } - #define HAVE_ROTL + #define HAVE_ROTL64 #endif #ifndef HAVE_MULH diff --git a/src/crypto/randomx/intrin_portable.h b/src/crypto/randomx/intrin_portable.h index b4f1b503..83acbe65 100644 --- a/src/crypto/randomx/intrin_portable.h +++ b/src/crypto/randomx/intrin_portable.h @@ -601,5 +601,5 @@ FORCE_INLINE rx_vec_i128 rx_aesdec_vec_i128(rx_vec_i128 v, rx_vec_i128 rkey) { double loadDoublePortable(const void* addr); uint64_t mulh(uint64_t, uint64_t); int64_t smulh(int64_t, int64_t); -uint64_t rotl(uint64_t, unsigned int); -uint64_t rotr(uint64_t, unsigned int); +uint64_t rotl64(uint64_t, unsigned int); +uint64_t rotr64(uint64_t, unsigned int); diff --git a/src/crypto/randomx/superscalar.cpp b/src/crypto/randomx/superscalar.cpp index c0d496b9..da605622 100644 --- a/src/crypto/randomx/superscalar.cpp +++ b/src/crypto/randomx/superscalar.cpp @@ -859,7 +859,7 @@ namespace randomx { r[instr.dst] *= r[instr.src]; break; case SuperscalarInstructionType::IROR_C: - r[instr.dst] = rotr(r[instr.dst], instr.getImm32()); + r[instr.dst] = rotr64(r[instr.dst], instr.getImm32()); break; case SuperscalarInstructionType::IADD_C7: case SuperscalarInstructionType::IADD_C8: diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index f3d2a663..a913ee51 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -410,6 +410,9 @@ void Workers::updateDataset(const uint8_t* seed_hash, xmrig::Variant variant, co case xmrig::VARIANT_RX_LOKI: randomx_apply_config(RandomX_LokiConfig); break; + default: + randomx_apply_config(RandomX_MoneroConfig); + break; } m_rx_variant = variant; } From ee9538ab226b372e2919283648f55181846f8945 Mon Sep 17 00:00:00 2001 From: XMRig Date: Tue, 2 Jul 2019 22:38:09 +0700 Subject: [PATCH 15/65] Fixed, client was stuck on some pools. --- src/base/net/stratum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 7ee0228b..c07f2369 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -739,7 +739,7 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co LOG_ERR("[%s] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", url(), message, error["code"].GetInt()); } - if (isCriticalError(message)) { + if (m_id == 1 || isCriticalError(message)) { close(); } From b92807e8d83eddd6677cc811b6b97436b72c52ec Mon Sep 17 00:00:00 2001 From: XMRig Date: Tue, 2 Jul 2019 22:56:28 +0700 Subject: [PATCH 16/65] Added support for multi-algorithm CPU threads settings. --- CMakeLists.txt | 10 +- src/backend/Threads.cpp | 145 ++++++++++++++++++ src/backend/Threads.h | 67 ++++++++ src/backend/backend.cmake | 12 ++ src/backend/cpu/CpuConfig.cpp | 52 ++++++- src/backend/cpu/CpuConfig.h | 14 +- src/backend/cpu/CpuThread.cpp | 71 +++++++++ src/backend/cpu/CpuThread.h | 63 ++++++++ src/backend/cpu/cpu.cmake | 8 +- src/backend/cpu/interfaces/ICpuInfo.h | 21 ++- src/backend/cpu/platform/AdvancedCpuInfo.cpp | 76 ++++++--- src/backend/cpu/platform/AdvancedCpuInfo.h | 29 ++-- src/backend/cpu/platform/BasicCpuInfo.cpp | 27 +++- src/backend/cpu/platform/BasicCpuInfo.h | 21 +-- src/core/config/Config.cpp | 10 +- src/core/config/Config.h | 6 +- src/crypto/common/Algorithm.cpp | 15 ++ src/crypto/common/Algorithm.h | 3 + src/crypto/common/Assembly.h | 4 +- .../{CpuThread.cpp => CpuThreadLegacy.cpp} | 26 ++-- .../{CpuThread.h => CpuThreadLegacy.h} | 14 +- src/workers/MultiWorker.cpp | 2 +- src/workers/Worker.cpp | 4 +- src/workers/Worker.h | 4 +- 24 files changed, 595 insertions(+), 109 deletions(-) create mode 100644 src/backend/Threads.cpp create mode 100644 src/backend/Threads.h create mode 100644 src/backend/backend.cmake create mode 100644 src/backend/cpu/CpuThread.cpp create mode 100644 src/backend/cpu/CpuThread.h rename src/workers/{CpuThread.cpp => CpuThreadLegacy.cpp} (78%) rename src/workers/{CpuThread.h => CpuThreadLegacy.h} (83%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7320b63d..ef4f8cee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,13 +18,13 @@ option(WITH_EMBEDDED_CONFIG "Enable internal embedded JSON config" OFF) include (CheckIncludeFile) include (cmake/cpu.cmake) include (src/base/base.cmake) -include (src/backend/cpu/cpu.cmake) +include (src/backend/backend.cmake) set(HEADERS "${HEADERS_BASE}" "${HEADERS_BASE_HTTP}" - "${HEADERS_CPU}" + "${HEADERS_BACKEND}" src/api/interfaces/IApiListener.h src/App.h src/common/Platform.h @@ -45,7 +45,7 @@ set(HEADERS src/net/strategies/DonateStrategy.h src/Summary.h src/version.h - src/workers/CpuThread.h + src/workers/CpuThreadLegacy.h src/workers/Hashrate.h src/workers/MultiWorker.h src/workers/ThreadHandle.h @@ -83,7 +83,7 @@ endif() set(SOURCES "${SOURCES_BASE}" "${SOURCES_BASE_HTTP}" - "${SOURCES_CPU}" + "${SOURCES_BACKEND}" src/App.cpp src/common/Platform.cpp src/core/config/Config.cpp @@ -94,7 +94,7 @@ set(SOURCES src/net/NetworkState.cpp src/net/strategies/DonateStrategy.cpp src/Summary.cpp - src/workers/CpuThread.cpp + src/workers/CpuThreadLegacy.cpp src/workers/Hashrate.cpp src/workers/MultiWorker.cpp src/workers/ThreadHandle.cpp diff --git a/src/backend/Threads.cpp b/src/backend/Threads.cpp new file mode 100644 index 00000000..11e1ec15 --- /dev/null +++ b/src/backend/Threads.cpp @@ -0,0 +1,145 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/cpu/CpuThread.h" +#include "backend/Threads.h" +#include "rapidjson/document.h" + + +template +const std::vector &xmrig::Threads::get(const String &profileName) const +{ + static std::vector empty; + if (profileName.isNull() || !has(profileName)) { + return empty; + } + + return m_profiles.at(profileName); +} + + +template +xmrig::String xmrig::Threads::profileName(const Algorithm &algorithm, bool strict) const +{ + if (isDisabled(algorithm)) { + return String(); + } + + const String name = algorithm.shortName(); + if (has(name)) { + return name; + } + + if (m_aliases.count(algorithm) > 0) { + return m_aliases.at(algorithm); + } + + if (!strict && name.contains("/")) { + const String base = name.split('/').at(0); + if (has(base)) { + return base; + } + } + + return String(); +} + + +template +void xmrig::Threads::read(const rapidjson::Value &value) +{ + using namespace rapidjson; + + for (auto &member : value.GetObject()) { + if (member.value.IsArray()) { + std::vector threads; + + for (auto &v : member.value.GetArray()) { + T thread(v); + if (thread.isValid()) { + threads.push_back(std::move(thread)); + } + } + + if (!threads.empty()) { + move(member.name.GetString(), std::move(threads)); + } + + continue; + } + + const Algorithm algo(member.name.GetString()); + if (!algo.isValid()) { + continue; + } + + if (member.value.IsBool() && member.value.IsFalse()) { + disable(algo); + continue; + } + + if (member.value.IsString()) { + if (has(member.value.GetString())) { + m_aliases.insert({ algo, member.value.GetString() }); + } + else { + m_disabled.insert(algo); + } + } + } +} + + +template +void xmrig::Threads::toJSON(rapidjson::Value &out, rapidjson::Document &doc) const +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + for (const auto &kv : m_profiles) { + Value arr(kArrayType); + + for (const T &thread : kv.second) { + arr.PushBack(thread.toJSON(doc), allocator); + } + + out.AddMember(kv.first.toJSON(), arr, allocator); + } + + for (const Algorithm &algo : m_disabled) { + out.AddMember(StringRef(algo.shortName()), false, allocator); + } + + for (const auto &kv : m_aliases) { + out.AddMember(StringRef(kv.first.shortName()), kv.second.toJSON(), allocator); + } +} + + +namespace xmrig { + +template class Threads; + +} // namespace xmrig diff --git a/src/backend/Threads.h b/src/backend/Threads.h new file mode 100644 index 00000000..70bc02a4 --- /dev/null +++ b/src/backend/Threads.h @@ -0,0 +1,67 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_THREADS_H +#define XMRIG_THREADS_H + + +#include +#include + + +#include "base/tools/String.h" +#include "crypto/common/Algorithm.h" +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +template +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 isExist(const Algorithm &algo) const { return isDisabled(algo) || m_aliases.count(algo) > 0 || has(algo.shortName()); } + inline const std::vector &get(const Algorithm &algo, bool strict = false) const { return get(profileName(algo, strict)); } + inline void disable(const Algorithm &algo) { m_disabled.insert(algo); } + inline void move(const char *profile, std::vector &&threads) { m_profiles.insert({ profile, threads }); } + + const std::vector &get(const String &profileName) const; + String profileName(const Algorithm &algorithm, bool strict = false) const; + void read(const rapidjson::Value &value); + void toJSON(rapidjson::Value &out, rapidjson::Document &doc) const; + +private: + std::map m_aliases; + std::map > m_profiles; + std::set m_disabled; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_THREADS_H */ diff --git a/src/backend/backend.cmake b/src/backend/backend.cmake new file mode 100644 index 00000000..750cc9cb --- /dev/null +++ b/src/backend/backend.cmake @@ -0,0 +1,12 @@ +include (src/backend/cpu/cpu.cmake) + + +set(HEADERS_BACKEND + "${HEADERS_CPU}" + src/backend/Threads.h + ) + +set(SOURCES_BACKEND + "${SOURCES_CPU}" + src/backend/Threads.cpp + ) diff --git a/src/backend/cpu/CpuConfig.cpp b/src/backend/cpu/CpuConfig.cpp index 5284d607..34dcff44 100644 --- a/src/backend/cpu/CpuConfig.cpp +++ b/src/backend/cpu/CpuConfig.cpp @@ -31,17 +31,34 @@ namespace xmrig { - +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 *kPriority = "priority"; - #ifdef XMRIG_FEATURE_ASM static const char *kAsm = "asm"; #endif +#ifdef XMRIG_ALGO_CN_GPU +static const char *kCnGPU = "cn/gpu"; +#endif + +#ifdef XMRIG_ALGO_CN_LITE +static const char *kCnLite = "cn-lite"; +#endif + +#ifdef XMRIG_ALGO_CN_HEAVY +static const char *kCnHeavy = "cn-heavy"; +#endif + +#ifdef XMRIG_ALGO_CN_PICO +static const char *kCnPico = "cn-pico"; +#endif + +extern template class Threads; + } @@ -59,7 +76,6 @@ bool xmrig::CpuConfig::isHwAES() const rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const { using namespace rapidjson; - auto &allocator = doc.GetAllocator(); Value obj(kObjectType); @@ -73,6 +89,8 @@ rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const obj.AddMember(StringRef(kAsm), m_assembly.toJSON(), allocator); # endif + m_threads.toJSON(obj, doc); + return obj; } @@ -89,6 +107,34 @@ void xmrig::CpuConfig::read(const rapidjson::Value &value) # ifdef XMRIG_FEATURE_ASM m_assembly = Json::getValue(value, kAsm); # endif + + m_threads.read(value); + } + else if (value.IsBool() && value.IsFalse()) { + m_enabled = false; + } + else { + m_shouldSave = true; + + m_threads.disable(Algorithm::CN_0); + m_threads.move(kCn, Cpu::info()->threads(Algorithm::CN_0)); + +# ifdef XMRIG_ALGO_CN_GPU + m_threads.move(kCnGPU, Cpu::info()->threads(Algorithm::CN_GPU)); +# endif + +# ifdef XMRIG_ALGO_CN_LITE + m_threads.disable(Algorithm::CN_LITE_0); + m_threads.move(kCnLite, Cpu::info()->threads(Algorithm::CN_LITE_1)); +# endif + +# ifdef XMRIG_ALGO_CN_HEAVY + m_threads.move(kCnHeavy, Cpu::info()->threads(Algorithm::CN_HEAVY_0)); +# endif + +# ifdef XMRIG_ALGO_CN_PICO + m_threads.move(kCnPico, Cpu::info()->threads(Algorithm::CN_PICO_0)); +# endif } } diff --git a/src/backend/cpu/CpuConfig.h b/src/backend/cpu/CpuConfig.h index 04dd9175..66da3a5f 100644 --- a/src/backend/cpu/CpuConfig.h +++ b/src/backend/cpu/CpuConfig.h @@ -26,6 +26,8 @@ #define XMRIG_CPUCONFIG_H +#include "backend/cpu/CpuThread.h" +#include "backend/Threads.h" #include "crypto/common/Assembly.h" @@ -47,11 +49,12 @@ public: rapidjson::Value toJSON(rapidjson::Document &doc) const; void read(const rapidjson::Value &value); - inline bool isEnabled() const { return m_enabled; } - inline bool isHugePages() const { return m_hugePages; } - inline bool isShouldSave() const { return m_shouldSave; } - inline const Assembly &assembly() const { return m_assembly; } - inline int priority() const { return m_priority; } + inline bool isEnabled() const { return m_enabled; } + inline bool isHugePages() const { return m_hugePages; } + inline bool isShouldSave() const { return m_shouldSave; } + inline const Assembly &assembly() const { return m_assembly; } + inline const Threads &threads() const { return m_threads; } + inline int priority() const { return m_priority; } private: void setAesMode(const rapidjson::Value &aesMode); @@ -63,6 +66,7 @@ private: bool m_hugePages = true; bool m_shouldSave = false; int m_priority = -1; + Threads m_threads; }; diff --git a/src/backend/cpu/CpuThread.cpp b/src/backend/cpu/CpuThread.cpp new file mode 100644 index 00000000..e7132cfa --- /dev/null +++ b/src/backend/cpu/CpuThread.cpp @@ -0,0 +1,71 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/cpu/CpuThread.h" +#include "base/io/json/Json.h" +#include "rapidjson/document.h" + + +namespace xmrig { + + +static const char *kAffinity = "affinity"; +static const char *kIntensity = "intensity"; + + +} + + + +xmrig::CpuThread::CpuThread(const rapidjson::Value &value) +{ + if (value.IsObject()) { + m_intensity = Json::getInt(value, kIntensity, -1); + m_affinity = Json::getInt(value, kAffinity, -1); + } + else if (value.IsInt()) { + m_intensity = 1; + m_affinity = value.GetInt(); + } +} + + +rapidjson::Value xmrig::CpuThread::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + + if (intensity() > 1) { + auto &allocator = doc.GetAllocator(); + + Value obj(kObjectType); + + obj.AddMember(StringRef(kIntensity), m_intensity, allocator); + obj.AddMember(StringRef(kAffinity), m_affinity, allocator); + + return obj; + } + + return Value(m_affinity); +} diff --git a/src/backend/cpu/CpuThread.h b/src/backend/cpu/CpuThread.h new file mode 100644 index 00000000..444b2709 --- /dev/null +++ b/src/backend/cpu/CpuThread.h @@ -0,0 +1,63 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CPUTHREADCONFIG_H +#define XMRIG_CPUTHREADCONFIG_H + + +#include + + +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +class CpuThread +{ +public: + inline constexpr CpuThread(int intensity = 1, int affinity = -1) : m_affinity(affinity), m_intensity(intensity) {} + + CpuThread(const rapidjson::Value &value); + + inline bool isValid() const { return m_intensity >= 1 && m_intensity <= 5; } + inline int affinity() const { return m_affinity; } + inline int intensity() const { return m_intensity; } + + rapidjson::Value toJSON(rapidjson::Document &doc) const; + +private: + int m_affinity = -1; + int m_intensity = -1; +}; + + +typedef std::vector CpuThreads; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_CPUTHREADCONFIG_H */ diff --git a/src/backend/cpu/cpu.cmake b/src/backend/cpu/cpu.cmake index 03ca7075..df9b7cea 100644 --- a/src/backend/cpu/cpu.cmake +++ b/src/backend/cpu/cpu.cmake @@ -1,12 +1,14 @@ set(HEADERS_CPU - src/backend/cpu/Cpu.h - src/backend/cpu/CpuConfig.h - src/backend/cpu/interfaces/ICpuInfo.h + src/backend/cpu/Cpu.h + src/backend/cpu/CpuConfig.h + src/backend/cpu/CpuThread.h + src/backend/cpu/interfaces/ICpuInfo.h ) set(SOURCES_CPU src/backend/cpu/Cpu.cpp src/backend/cpu/CpuConfig.cpp + src/backend/cpu/CpuThread.cpp ) diff --git a/src/backend/cpu/interfaces/ICpuInfo.h b/src/backend/cpu/interfaces/ICpuInfo.h index abff7a6c..74f6baee 100644 --- a/src/backend/cpu/interfaces/ICpuInfo.h +++ b/src/backend/cpu/interfaces/ICpuInfo.h @@ -26,11 +26,9 @@ #define XMRIG_CPUINFO_H -#include -#include - - +#include "backend/cpu/CpuThread.h" #include "crypto/common/Assembly.h" +#include "crypto/common/Algorithm.h" namespace xmrig { @@ -47,18 +45,19 @@ 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 bool isSupported() const = 0; virtual const char *brand() const = 0; - virtual int32_t cores() const = 0; - virtual int32_t L2() const = 0; - virtual int32_t L3() const = 0; - virtual int32_t nodes() const = 0; - virtual int32_t sockets() const = 0; - virtual int32_t threads() 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 optimalThreadsCount(size_t memSize, int maxCpuUsage) const = 0; - virtual Assembly::Id assembly() const = 0; + virtual size_t sockets() 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 fc7f734d..4c3b30ab 100644 --- a/src/backend/cpu/platform/AdvancedCpuInfo.cpp +++ b/src/backend/cpu/platform/AdvancedCpuInfo.cpp @@ -26,51 +26,43 @@ #include #include +#include + #include "backend/cpu/platform/AdvancedCpuInfo.h" xmrig::AdvancedCpuInfo::AdvancedCpuInfo() : - m_aes(false), - m_avx2(false), - m_L2_exclusive(false), - m_brand(), - m_cores(0), - m_L2(0), - m_L3(0), - m_sockets(1), - m_threads(0) + m_brand() { - struct cpu_raw_data_t raw = { 0 }; - struct cpu_id_t data = { 0 }; + struct cpu_raw_data_t raw = {}; + struct cpu_id_t data = {}; cpuid_get_raw_data(&raw); cpu_identify(&raw, &data); strncpy(m_brand, data.brand_str, sizeof(m_brand)); - m_threads = data.total_logical_cpus; - m_sockets = threads() / data.num_logical_cpus; - if (m_sockets == 0) { - m_sockets = 1; - } + m_threads = static_cast(data.total_logical_cpus); + m_sockets = std::max(threads() / static_cast(data.num_logical_cpus), 1); + m_cores = static_cast(data.num_cores) * m_sockets; + m_L3 = data.l3_cache > 0 ? static_cast(data.l3_cache) * m_sockets : 0; - m_cores = data.num_cores * m_sockets; - m_L3 = data.l3_cache > 0 ? data.l3_cache * m_sockets : 0; + const size_t l2 = static_cast(data.l2_cache); // Workaround for AMD CPUs https://github.com/anrieff/libcpuid/issues/97 if (data.vendor == VENDOR_AMD && data.ext_family >= 0x15 && data.ext_family < 0x17) { - m_L2 = data.l2_cache * (cores() / 2) * m_sockets; + m_L2 = l2 * (cores() / 2) * m_sockets; m_L2_exclusive = true; } // Workaround for Intel Pentium Dual-Core, Core Duo, Core 2 Duo, Core 2 Quad and their Xeon homologue // These processors have L2 cache shared by 2 cores. else if (data.vendor == VENDOR_INTEL && data.ext_family == 0x06 && (data.ext_model == 0x0E || data.ext_model == 0x0F || data.ext_model == 0x17)) { - int l2_count_per_socket = cores() > 1 ? cores() / 2 : 1; - m_L2 = data.l2_cache > 0 ? data.l2_cache * l2_count_per_socket * m_sockets : 0; + size_t l2_count_per_socket = cores() > 1 ? cores() / 2 : 1; + m_L2 = data.l2_cache > 0 ? l2 * l2_count_per_socket * m_sockets : 0; } else{ - m_L2 = data.l2_cache > 0 ? data.l2_cache * cores() * m_sockets : 0; + m_L2 = data.l2_cache > 0 ? l2 * cores() * m_sockets : 0; } if (data.flags[CPU_FEATURE_AES]) { @@ -125,3 +117,43 @@ size_t xmrig::AdvancedCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsa return count < 1 ? 1 : count; } + + +xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm) const +{ + if (threads() == 1) { + return CpuThreads(1); + } + +# ifdef XMRIG_ALGO_CN_GPU + if (algorithm == Algorithm::CN_GPU) { + return CpuThreads(threads()); + } +# endif + + size_t cache = 0; + size_t count = 0; + + if (m_L3) { + cache = m_L2_exclusive ? (m_L2 + m_L3) : m_L3; + } + else { + cache = m_L2; + } + + if (cache) { + cache *= 1024; + const size_t memory = algorithm.memory(); + + count = cache / memory; + + if (cache % memory >= memory / 2) { + count++; + } + } + else { + count = threads() / 2; + } + + return CpuThreads(std::max(std::min(count, threads()), 1)); +} diff --git a/src/backend/cpu/platform/AdvancedCpuInfo.h b/src/backend/cpu/platform/AdvancedCpuInfo.h index 83c3d8e5..9852f6bd 100644 --- a/src/backend/cpu/platform/AdvancedCpuInfo.h +++ b/src/backend/cpu/platform/AdvancedCpuInfo.h @@ -39,30 +39,31 @@ public: protected: size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const override; + CpuThreads threads(const Algorithm &algorithm) const override; inline Assembly::Id assembly() const override { return m_assembly; } inline bool hasAES() const override { return m_aes; } inline bool hasAVX2() const override { return m_avx2; } inline bool isSupported() const override { return true; } inline const char *brand() const override { return m_brand; } - inline int32_t cores() const override { return m_cores; } - inline int32_t L2() const override { return m_L2; } - inline int32_t L3() const override { return m_L3; } - inline int32_t nodes() const override { return -1; } - inline int32_t sockets() const override { return m_sockets; } - inline int32_t threads() const override { return m_threads; } + inline size_t cores() const override { return m_cores; } + inline size_t L2() const override { return m_L2; } + inline size_t L3() const override { return m_L3; } + inline size_t nodes() const override { return 0; } + inline size_t sockets() const override { return m_sockets; } + inline size_t threads() const override { return m_threads; } private: Assembly m_assembly; - bool m_aes; - bool m_avx2; - bool m_L2_exclusive; + bool m_aes = false; + bool m_avx2 = false; + bool m_L2_exclusive = false; char m_brand[64]; - int32_t m_cores; - int32_t m_L2; - int32_t m_L3; - int32_t m_sockets; - int32_t m_threads; + size_t m_cores = 0; + size_t m_L2 = 0; + size_t m_L3 = 0; + size_t m_sockets = 1; + size_t m_threads = 0; }; diff --git a/src/backend/cpu/platform/BasicCpuInfo.cpp b/src/backend/cpu/platform/BasicCpuInfo.cpp index 04ff589b..26237468 100644 --- a/src/backend/cpu/platform/BasicCpuInfo.cpp +++ b/src/backend/cpu/platform/BasicCpuInfo.cpp @@ -22,6 +22,7 @@ * along with this program. If not, see . */ +#include #include #include @@ -123,9 +124,9 @@ static inline bool has_ossave() xmrig::BasicCpuInfo::BasicCpuInfo() : m_assembly(Assembly::NONE), + m_brand(), m_aes(has_aes_ni()), m_avx2(has_avx2() && has_ossave()), - m_brand(), m_threads(std::thread::hardware_concurrency()) { cpu_brand_string(m_brand); @@ -158,3 +159,27 @@ size_t xmrig::BasicCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) return count < 1 ? 1 : count; } + + +xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm) const +{ + if (threads() == 1) { + return CpuThreads(1); + } + +# ifdef XMRIG_ALGO_CN_GPU + if (algorithm == Algorithm::CN_GPU) { + return CpuThreads(threads()); + } +# endif + + if (algorithm.family() == Algorithm::CN_LITE || algorithm.family() == Algorithm::CN_PICO) { + return CpuThreads(threads()); + } + + if (algorithm.family() == Algorithm::CN_HEAVY) { + return CpuThreads(std::max(threads() / 4, 1)); + } + + return CpuThreads(std::max(threads() / 2, 1)); +} diff --git a/src/backend/cpu/platform/BasicCpuInfo.h b/src/backend/cpu/platform/BasicCpuInfo.h index 4d4a5163..12c275dd 100644 --- a/src/backend/cpu/platform/BasicCpuInfo.h +++ b/src/backend/cpu/platform/BasicCpuInfo.h @@ -39,25 +39,26 @@ public: protected: size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const override; + CpuThreads threads(const Algorithm &algorithm) const override; inline Assembly::Id assembly() const override { return m_assembly; } inline bool hasAES() const override { return m_aes; } inline bool hasAVX2() const override { return m_avx2; } inline bool isSupported() const override { return true; } inline const char *brand() const override { return m_brand; } - inline int32_t cores() const override { return -1; } - inline int32_t L2() const override { return -1; } - inline int32_t L3() const override { return -1; } - inline int32_t nodes() const override { return -1; } - inline int32_t sockets() const override { return 1; } - inline int32_t threads() const override { return m_threads; } + inline size_t cores() const override { return 0; } + inline size_t L2() const override { return 0; } + inline size_t L3() const override { return 0; } + inline size_t nodes() const override { return 0; } + inline size_t sockets() const override { return 1; } + inline size_t threads() const override { return m_threads; } private: Assembly m_assembly; - bool m_aes; - bool m_avx2; - char m_brand[64]; - int32_t m_threads; + char m_brand[64 + 6]; + const bool m_aes; + const bool m_avx2; + const size_t m_threads; }; diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 33f4cc44..87abbb91 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -36,7 +36,7 @@ #include "rapidjson/document.h" #include "rapidjson/filewritestream.h" #include "rapidjson/prettywriter.h" -#include "workers/CpuThread.h" +#include "workers/CpuThreadLegacy.h" xmrig::Config::Config() : @@ -125,7 +125,7 @@ bool xmrig::Config::finalize() m_threads.mode = Advanced; for (size_t i = 0; i < m_threads.cpu.size(); ++i) { - m_threads.list.push_back(CpuThread::createFromData(i, algorithm, m_threads.cpu[i], m_cpu.priority(), !m_cpu.isHwAES())); + m_threads.list.push_back(CpuThreadLegacy::createFromData(i, algorithm, m_threads.cpu[i], m_cpu.priority(), !m_cpu.isHwAES())); } return true; @@ -134,7 +134,7 @@ bool xmrig::Config::finalize() const AlgoVariant av = getAlgoVariant(); m_threads.mode = m_threads.count ? Simple : Automatic; - const size_t size = CpuThread::multiway(av) * CnAlgo<>::memory(algorithm) / 1024; // FIXME MEMORY + const size_t size = CpuThreadLegacy::multiway(av) * CnAlgo<>::memory(algorithm) / 1024; // FIXME MEMORY if (!m_threads.count) { m_threads.count = Cpu::info()->optimalThreadsCount(size, 100); @@ -147,7 +147,7 @@ bool xmrig::Config::finalize() // } for (size_t i = 0; i < m_threads.count; ++i) { - m_threads.list.push_back(CpuThread::createFromAV(i, algorithm, av, m_threads.mask, m_cpu.priority(), m_cpu.assembly())); + m_threads.list.push_back(CpuThreadLegacy::createFromAV(i, algorithm, av, m_threads.mask, m_cpu.priority(), m_cpu.assembly())); } m_shouldSave = m_threads.mode == Automatic; @@ -175,7 +175,7 @@ void xmrig::Config::setThreads(const rapidjson::Value &threads) } if (value.HasMember("low_power_mode")) { - auto data = CpuThread::parse(value); + auto data = CpuThreadLegacy::parse(value); if (data.valid) { m_threads.cpu.push_back(std::move(data)); diff --git a/src/core/config/Config.h b/src/core/config/Config.h index 76720889..7b765892 100644 --- a/src/core/config/Config.h +++ b/src/core/config/Config.h @@ -34,7 +34,7 @@ #include "base/kernel/config/BaseConfig.h" #include "common/xmrig.h" #include "rapidjson/fwd.h" -#include "workers/CpuThread.h" +#include "workers/CpuThreadLegacy.h" namespace xmrig { @@ -59,7 +59,7 @@ public: void getJSON(rapidjson::Document &doc) const override; inline AlgoVariant algoVariant() const { return m_algoVariant; } - inline bool isShouldSave() const { return (m_shouldSave || m_upgrade) && isAutoSave(); } + inline bool isShouldSave() const { return (m_shouldSave || m_upgrade || m_cpu.isShouldSave()) && isAutoSave(); } inline const CpuConfig &cpu() const { return m_cpu; } inline const std::vector &threads() const { return m_threads.list; } inline int threadsCount() const { return static_cast(m_threads.list.size()); } @@ -81,7 +81,7 @@ private: int64_t mask; size_t count; - std::vector cpu; + std::vector cpu; std::vector list; ThreadsMode mode; }; diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index 66b3ddda..81ee6655 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -30,6 +30,7 @@ #include +#include "crypto/cn/CnAlgo.h" #include "crypto/common/Algorithm.h" #include "rapidjson/document.h" @@ -123,6 +124,20 @@ rapidjson::Value xmrig::Algorithm::toJSON() const } +size_t xmrig::Algorithm::memory() const +{ + if (family() < RANDOM_X) { + return CnAlgo<>::memory(m_id); + } + + if (m_id == RX_WOW) { + return 0x100000; + } + + return 0; +} + + xmrig::Algorithm::Family xmrig::Algorithm::family(Id id) { switch (id) { diff --git a/src/crypto/common/Algorithm.h b/src/crypto/common/Algorithm.h index 92c6f405..08d1c4cd 100644 --- a/src/crypto/common/Algorithm.h +++ b/src/crypto/common/Algorithm.h @@ -94,11 +94,14 @@ public: inline Family family() const { return family(m_id); } inline Id id() const { return m_id; } + inline bool operator!=(Algorithm::Id id) const { return m_id != id; } inline bool operator!=(const Algorithm &other) const { return !isEqual(other); } + inline bool operator==(Algorithm::Id id) const { return m_id == id; } inline bool operator==(const Algorithm &other) const { return isEqual(other); } inline operator Algorithm::Id() const { return m_id; } rapidjson::Value toJSON() const; + size_t memory() const; static Family family(Id id); static Id parse(const char *name); diff --git a/src/crypto/common/Assembly.h b/src/crypto/common/Assembly.h index 0b3f29b3..afd8a536 100644 --- a/src/crypto/common/Assembly.h +++ b/src/crypto/common/Assembly.h @@ -59,10 +59,10 @@ public: inline bool isEqual(const Assembly &other) const { return m_id == other.m_id; } + inline bool operator!=(Assembly::Id id) const { return m_id != id; } inline bool operator!=(const Assembly &other) const { return !isEqual(other); } - inline bool operator!=(const Assembly::Id &id) const { return m_id != id; } + inline bool operator==(Assembly::Id id) const { return m_id == id; } inline bool operator==(const Assembly &other) const { return isEqual(other); } - inline bool operator==(const Assembly::Id &id) const { return m_id == id; } inline operator Assembly::Id() const { return m_id; } private: diff --git a/src/workers/CpuThread.cpp b/src/workers/CpuThreadLegacy.cpp similarity index 78% rename from src/workers/CpuThread.cpp rename to src/workers/CpuThreadLegacy.cpp index 7011da12..df9b9904 100644 --- a/src/workers/CpuThread.cpp +++ b/src/workers/CpuThreadLegacy.cpp @@ -31,14 +31,14 @@ #include "crypto/common/VirtualMemory.h" #include "Mem.h" #include "rapidjson/document.h" -#include "workers/CpuThread.h" +#include "workers/CpuThreadLegacy.h" static const xmrig::CnHash cnHash; -xmrig::CpuThread::CpuThread(size_t index, Algorithm algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly) : +xmrig::CpuThreadLegacy::CpuThreadLegacy(size_t index, Algorithm algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly) : m_algorithm(algorithm), m_av(av), m_assembly(assembly), @@ -52,20 +52,20 @@ xmrig::CpuThread::CpuThread(size_t index, Algorithm algorithm, AlgoVariant av, M } -xmrig::cn_hash_fun xmrig::CpuThread::fn(const Algorithm &algorithm) const +xmrig::cn_hash_fun xmrig::CpuThreadLegacy::fn(const Algorithm &algorithm) const { return cnHash.fn(algorithm, m_av, m_assembly); } -bool xmrig::CpuThread::isSoftAES(AlgoVariant av) +bool xmrig::CpuThreadLegacy::isSoftAES(AlgoVariant av) { return av == AV_SINGLE_SOFT || av == AV_DOUBLE_SOFT || av > AV_PENTA; } -xmrig::CpuThread *xmrig::CpuThread::createFromAV(size_t index, const Algorithm &algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly) +xmrig::CpuThreadLegacy *xmrig::CpuThreadLegacy::createFromAV(size_t index, const Algorithm &algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly) { assert(av > AV_AUTO && av < AV_MAX); @@ -88,11 +88,11 @@ xmrig::CpuThread *xmrig::CpuThread::createFromAV(size_t index, const Algorithm & } } - return new CpuThread(index, algorithm, av, multiway(av), cpuId, priority, isSoftAES(av), false, assembly); + return new CpuThreadLegacy(index, algorithm, av, multiway(av), cpuId, priority, isSoftAES(av), false, assembly); } -xmrig::CpuThread *xmrig::CpuThread::createFromData(size_t index, const Algorithm &algorithm, const CpuThread::Data &data, int priority, bool softAES) +xmrig::CpuThreadLegacy *xmrig::CpuThreadLegacy::createFromData(size_t index, const Algorithm &algorithm, const CpuThreadLegacy::Data &data, int priority, bool softAES) { int av = AV_AUTO; const Multiway multiway = data.multiway; @@ -106,11 +106,11 @@ xmrig::CpuThread *xmrig::CpuThread::createFromData(size_t index, const Algorithm assert(av > AV_AUTO && av < AV_MAX); - return new CpuThread(index, algorithm, static_cast(av), multiway, data.affinity, priority, softAES, false, data.assembly); + return new CpuThreadLegacy(index, algorithm, static_cast(av), multiway, data.affinity, priority, softAES, false, data.assembly); } -xmrig::CpuThread::Data xmrig::CpuThread::parse(const rapidjson::Value &object) +xmrig::CpuThreadLegacy::Data xmrig::CpuThreadLegacy::parse(const rapidjson::Value &object) { Data data; @@ -140,7 +140,7 @@ xmrig::CpuThread::Data xmrig::CpuThread::parse(const rapidjson::Value &object) } -xmrig::IThread::Multiway xmrig::CpuThread::multiway(AlgoVariant av) +xmrig::IThread::Multiway xmrig::CpuThreadLegacy::multiway(AlgoVariant av) { switch (av) { case AV_SINGLE: @@ -172,7 +172,7 @@ xmrig::IThread::Multiway xmrig::CpuThread::multiway(AlgoVariant av) #ifdef APP_DEBUG -void xmrig::CpuThread::print() const +void xmrig::CpuThreadLegacy::print() const { LOG_DEBUG(GREEN_BOLD("CPU thread: ") " index " WHITE_BOLD("%zu") ", multiway " WHITE_BOLD("%d") ", av " WHITE_BOLD("%d") ",", index(), static_cast(multiway()), static_cast(m_av)); @@ -187,7 +187,7 @@ void xmrig::CpuThread::print() const #ifdef XMRIG_FEATURE_API -rapidjson::Value xmrig::CpuThread::toAPI(rapidjson::Document &doc) const +rapidjson::Value xmrig::CpuThreadLegacy::toAPI(rapidjson::Document &doc) const { using namespace rapidjson; @@ -206,7 +206,7 @@ rapidjson::Value xmrig::CpuThread::toAPI(rapidjson::Document &doc) const #endif -rapidjson::Value xmrig::CpuThread::toConfig(rapidjson::Document &doc) const +rapidjson::Value xmrig::CpuThreadLegacy::toConfig(rapidjson::Document &doc) const { using namespace rapidjson; diff --git a/src/workers/CpuThread.h b/src/workers/CpuThreadLegacy.h similarity index 83% rename from src/workers/CpuThread.h rename to src/workers/CpuThreadLegacy.h index a43a0c09..ed69d8ac 100644 --- a/src/workers/CpuThread.h +++ b/src/workers/CpuThreadLegacy.h @@ -22,8 +22,8 @@ * along with this program. If not, see . */ -#ifndef XMRIG_CPUTHREAD_H -#define XMRIG_CPUTHREAD_H +#ifndef XMRIG_CPUTHREADLEGACY_H +#define XMRIG_CPUTHREADLEGACY_H #include "common/xmrig.h" @@ -37,7 +37,7 @@ struct cryptonight_ctx; namespace xmrig { -class CpuThread : public IThread +class CpuThreadLegacy : public IThread { public: struct Data @@ -59,13 +59,13 @@ public: }; - CpuThread(size_t index, Algorithm algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly); + CpuThreadLegacy(size_t index, Algorithm algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly); cn_hash_fun fn(const Algorithm &algorithm) const; static bool isSoftAES(AlgoVariant av); - static CpuThread *createFromAV(size_t index, const Algorithm &algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly); - static CpuThread *createFromData(size_t index, const Algorithm &algorithm, const CpuThread::Data &data, int priority, bool softAES); + static CpuThreadLegacy *createFromAV(size_t index, const Algorithm &algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly); + static CpuThreadLegacy *createFromData(size_t index, const Algorithm &algorithm, const CpuThreadLegacy::Data &data, int priority, bool softAES); static Data parse(const rapidjson::Value &object); static Multiway multiway(AlgoVariant av); @@ -106,4 +106,4 @@ private: } /* namespace xmrig */ -#endif /* XMRIG_CPUTHREAD_H */ +#endif /* XMRIG_CPUTHREADLEGACY_H */ diff --git a/src/workers/MultiWorker.cpp b/src/workers/MultiWorker.cpp index 52e98e0a..0ac026bc 100644 --- a/src/workers/MultiWorker.cpp +++ b/src/workers/MultiWorker.cpp @@ -28,7 +28,7 @@ #include "crypto/cn/CryptoNight_test.h" -#include "workers/CpuThread.h" +#include "workers/CpuThreadLegacy.h" #include "workers/MultiWorker.h" #include "workers/Workers.h" diff --git a/src/workers/Worker.cpp b/src/workers/Worker.cpp index c6ea6d9a..4f69d905 100644 --- a/src/workers/Worker.cpp +++ b/src/workers/Worker.cpp @@ -26,7 +26,7 @@ #include "backend/cpu/Cpu.h" #include "common/Platform.h" -#include "workers/CpuThread.h" +#include "workers/CpuThreadLegacy.h" #include "workers/ThreadHandle.h" #include "workers/Worker.h" @@ -39,7 +39,7 @@ Worker::Worker(ThreadHandle *handle) : m_timestamp(0), m_count(0), m_sequence(0), - m_thread(static_cast(handle->config())) + m_thread(static_cast(handle->config())) { if (xmrig::Cpu::info()->threads() > 1 && m_thread->affinity() != -1L) { Platform::setThreadAffinity(m_thread->affinity()); diff --git a/src/workers/Worker.h b/src/workers/Worker.h index 4710bcc5..3d40257d 100644 --- a/src/workers/Worker.h +++ b/src/workers/Worker.h @@ -37,7 +37,7 @@ class ThreadHandle; namespace xmrig { - class CpuThread; + class CpuThreadLegacy; } @@ -62,7 +62,7 @@ protected: std::atomic m_timestamp; uint64_t m_count; uint64_t m_sequence; - xmrig::CpuThread *m_thread; + xmrig::CpuThreadLegacy *m_thread; }; From 8c02e2082802c317a4f578f37d2f7fe37aad5bd6 Mon Sep 17 00:00:00 2001 From: XMRig Date: Tue, 2 Jul 2019 22:57:08 +0700 Subject: [PATCH 17/65] Quick fixes. --- CMakeLists.txt | 2 +- src/crypto/common/Algorithm.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e3cf2a5..fedbe76b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,7 +194,7 @@ if (WITH_RANDOMX) src/crypto/randomx/jit_compiler_x86_static.asm src/crypto/randomx/jit_compiler_x86.cpp ) - elseif (ARCH_ID STREQUAL "x86_64" OR ARCH_ID STREQUAL "x86-64" OR ARCH_ID STREQUAL "amd64" OR ARCH_ID STREQUAL "AMD64") + elseif (NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8) list(APPEND SOURCES_CRYPTO src/crypto/randomx/jit_compiler_x86_static.S src/crypto/randomx/jit_compiler_x86.cpp diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index 42f45b9d..1bc2a5a6 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -226,6 +226,11 @@ void xmrig::Algorithm::parseVariant(const char *variant) for (size_t i = 0; i < ARRAY_SIZE(variants); i++) { if (strcasecmp(variant, variants[i]) == 0) { m_variant = static_cast(i); + + if (m_variant == VARIANT_RX_WOW || m_variant == VARIANT_RX_LOKI) { // FIXME + m_algo = RANDOM_X; + } + return; } } From 9bf4c2c98f2d24bb673014d3166bbbf3bbd3bfa2 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 6 Jul 2019 11:31:12 +0700 Subject: [PATCH 18/65] Generate "rx" and "rx/wow" sections of CPU threads. --- src/backend/cpu/CpuConfig.cpp | 10 ++++++++++ src/backend/cpu/platform/AdvancedCpuInfo.cpp | 4 ++-- src/crypto/common/Algorithm.cpp | 14 ++++++++++---- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/backend/cpu/CpuConfig.cpp b/src/backend/cpu/CpuConfig.cpp index 34dcff44..b4a9c363 100644 --- a/src/backend/cpu/CpuConfig.cpp +++ b/src/backend/cpu/CpuConfig.cpp @@ -57,6 +57,11 @@ static const char *kCnHeavy = "cn-heavy"; static const char *kCnPico = "cn-pico"; #endif +#ifdef XMRIG_ALGO_RANDOMX +static const char *kRx = "rx"; +static const char *kRxWOW = "rx/wow"; +#endif + extern template class Threads; } @@ -135,6 +140,11 @@ void xmrig::CpuConfig::read(const rapidjson::Value &value) # ifdef XMRIG_ALGO_CN_PICO m_threads.move(kCnPico, Cpu::info()->threads(Algorithm::CN_PICO_0)); # endif + +# ifdef XMRIG_ALGO_RANDOMX + m_threads.move(kRx, Cpu::info()->threads(Algorithm::RX_0)); + m_threads.move(kRxWOW, Cpu::info()->threads(Algorithm::RX_WOW)); +# endif } } diff --git a/src/backend/cpu/platform/AdvancedCpuInfo.cpp b/src/backend/cpu/platform/AdvancedCpuInfo.cpp index 4c3b30ab..b5b2fe91 100644 --- a/src/backend/cpu/platform/AdvancedCpuInfo.cpp +++ b/src/backend/cpu/platform/AdvancedCpuInfo.cpp @@ -22,12 +22,11 @@ * along with this program. If not, see . */ +#include #include #include #include -#include - #include "backend/cpu/platform/AdvancedCpuInfo.h" @@ -144,6 +143,7 @@ xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm) co if (cache) { cache *= 1024; const size_t memory = algorithm.memory(); + assert(memory > 0); count = cache / memory; diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index 4af3fd41..7680ef02 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -130,7 +130,10 @@ rapidjson::Value xmrig::Algorithm::toJSON() const size_t xmrig::Algorithm::memory() const { - if (family() < RANDOM_X) { + const Family f = family(); + assert(f != UNKNOWN); + + if (f < RANDOM_X) { return CnAlgo<>::memory(m_id); } @@ -138,7 +141,7 @@ size_t xmrig::Algorithm::memory() const return 0x100000; } - return 0; + return 0x200000; } @@ -181,12 +184,15 @@ xmrig::Algorithm::Family xmrig::Algorithm::family(Id id) # endif # ifdef XMRIG_ALGO_RANDOMX + case RX_0: case RX_WOW: + case RX_LOKI: return RANDOM_X; # endif - default: - break; + case INVALID: + case MAX: + return UNKNOWN; } return UNKNOWN; From ea1149a971bdf57482649c5ff180b6b6e7a4b87b Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 6 Jul 2019 15:22:19 +0700 Subject: [PATCH 19/65] Added class JobResults. --- CMakeLists.txt | 4 +- src/crypto/common/Algorithm.cpp | 2 + src/net/JobResults.cpp | 139 ++++++++++++++++++ src/net/JobResults.h | 49 ++++++ src/net/Network.cpp | 5 +- src/{ => net}/interfaces/IJobResultListener.h | 0 src/workers/MultiWorker.cpp | 3 +- src/workers/Workers.cpp | 37 ----- src/workers/Workers.h | 7 - 9 files changed, 199 insertions(+), 47 deletions(-) create mode 100644 src/net/JobResults.cpp create mode 100644 src/net/JobResults.h rename src/{ => net}/interfaces/IJobResultListener.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d252af5d..33d3ad70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,11 +35,12 @@ set(HEADERS src/core/config/ConfigTransform.h src/core/config/usage.h src/core/Controller.h - src/interfaces/IJobResultListener.h src/interfaces/IThread.h src/interfaces/IWorker.h src/Mem.h + src/net/interfaces/IJobResultListener.h src/net/JobResult.h + src/net/JobResults.h src/net/Network.h src/net/NetworkState.h src/net/strategies/DonateStrategy.h @@ -90,6 +91,7 @@ set(SOURCES src/core/config/ConfigTransform.cpp src/core/Controller.cpp src/Mem.cpp + src/net/JobResults.cpp src/net/Network.cpp src/net/NetworkState.cpp src/net/strategies/DonateStrategy.cpp diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index 7680ef02..ab63204f 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -137,9 +137,11 @@ size_t xmrig::Algorithm::memory() const return CnAlgo<>::memory(m_id); } +# ifdef XMRIG_ALGO_RANDOMX if (m_id == RX_WOW) { return 0x100000; } +# endif return 0x200000; } diff --git a/src/net/JobResults.cpp b/src/net/JobResults.cpp new file mode 100644 index 00000000..8c65b5e4 --- /dev/null +++ b/src/net/JobResults.cpp @@ -0,0 +1,139 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include + + +#include "base/tools/Handle.h" +#include "net/interfaces/IJobResultListener.h" +#include "net/JobResult.h" +#include "net/JobResults.h" + + +namespace xmrig { + + +class JobResultsPrivate +{ +public: + inline JobResultsPrivate() + { + uv_mutex_init(&m_mutex); + + m_async = new uv_async_t; + m_async->data = this; + + uv_async_init(uv_default_loop(), m_async, JobResultsPrivate::onResult); + } + + + inline ~JobResultsPrivate() + { + Handle::close(m_async); + } + + + void setListener(IJobResultListener *listener) + { + m_listener = listener; + } + + + void submit(const JobResult &result) + { + uv_mutex_lock(&m_mutex); + m_queue.push_back(result); + uv_mutex_unlock(&m_mutex); + + uv_async_send(m_async); + } + + +private: + static void onResult(uv_async_t *handle) + { + static_cast(handle->data)->submit(); + } + + + inline void submit() + { + std::list results; + + uv_mutex_lock(&m_mutex); + while (!m_queue.empty()) { + results.push_back(std::move(m_queue.front())); + m_queue.pop_front(); + } + uv_mutex_unlock(&m_mutex); + + for (auto result : results) { + m_listener->onJobResult(result); + } + + results.clear(); + } + + + IJobResultListener *m_listener = nullptr; + std::list m_queue; + uv_async_t *m_async; + uv_mutex_t m_mutex; +}; + + +static JobResultsPrivate *handler = new JobResultsPrivate(); + + +} // namespace xmrig + + + +void xmrig::JobResults::setListener(IJobResultListener *listener) +{ + assert(handler != nullptr && listener != nullptr); + + handler->setListener(listener); +} + + +void xmrig::JobResults::stop() +{ + delete handler; + + handler = nullptr; +} + + +void xmrig::JobResults::submit(const JobResult &result) +{ + assert(handler != nullptr); + + if (handler) { + handler->submit(result); + } +} diff --git a/src/net/JobResults.h b/src/net/JobResults.h new file mode 100644 index 00000000..e7082acb --- /dev/null +++ b/src/net/JobResults.h @@ -0,0 +1,49 @@ +/* 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_JOBRESULTS_H +#define XMRIG_JOBRESULTS_H + + +namespace xmrig { + + +class IJobResultListener; +class JobResult; + + +class JobResults +{ +public: + static void setListener(IJobResultListener *listener); + static void stop(); + static void submit(const JobResult &result); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_JOBRESULTS_H */ diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 16669f52..c08facb9 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -40,6 +40,7 @@ #include "base/tools/Timer.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "net/JobResults.h" #include "net/Network.h" #include "net/strategies/DonateStrategy.h" #include "rapidjson/document.h" @@ -57,7 +58,7 @@ xmrig::Network::Network(Controller *controller) : m_donate(nullptr), m_timer(nullptr) { - Workers::setListener(this); + JobResults::setListener(this); controller->addListener(this); # ifdef XMRIG_FEATURE_API @@ -77,6 +78,8 @@ xmrig::Network::Network(Controller *controller) : xmrig::Network::~Network() { + JobResults::stop(); + delete m_timer; if (m_donate) { diff --git a/src/interfaces/IJobResultListener.h b/src/net/interfaces/IJobResultListener.h similarity index 100% rename from src/interfaces/IJobResultListener.h rename to src/net/interfaces/IJobResultListener.h diff --git a/src/workers/MultiWorker.cpp b/src/workers/MultiWorker.cpp index dc1292a3..2565e7c4 100644 --- a/src/workers/MultiWorker.cpp +++ b/src/workers/MultiWorker.cpp @@ -28,6 +28,7 @@ #include "crypto/cn/CryptoNight_test.h" +#include "net/JobResults.h" #include "workers/CpuThreadLegacy.h" #include "workers/MultiWorker.h" #include "workers/Workers.h" @@ -170,7 +171,7 @@ void xmrig::MultiWorker::start() for (size_t i = 0; i < N; ++i) { if (*reinterpret_cast(m_hash + (i * 32) + 24) < m_state.job.target()) { - Workers::submit(JobResult(m_state.job.poolId(), m_state.job.id(), m_state.job.clientId(), *nonce(i), m_hash + (i * 32), m_state.job.diff(), m_state.job.algorithm())); + JobResults::submit(JobResult(m_state.job.poolId(), m_state.job.id(), m_state.job.clientId(), *nonce(i), m_hash + (i * 32), m_state.job.diff(), m_state.job.algorithm())); } *nonce(i) += 1; diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index 28590d36..88d73a0b 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -32,7 +32,6 @@ #include "base/tools/Handle.h" #include "core/config/Config.h" #include "core/Controller.h" -#include "interfaces/IJobResultListener.h" #include "interfaces/IThread.h" #include "Mem.h" #include "rapidjson/document.h" @@ -45,15 +44,12 @@ bool Workers::m_active = false; bool Workers::m_enabled = true; Hashrate *Workers::m_hashrate = nullptr; -xmrig::IJobResultListener *Workers::m_listener = nullptr; xmrig::Job Workers::m_job; Workers::LaunchStatus Workers::m_status; std::atomic Workers::m_paused; std::atomic Workers::m_sequence; -std::list Workers::m_queue; std::vector Workers::m_workers; uint64_t Workers::m_ticks = 0; -uv_async_t *Workers::m_async = nullptr; uv_mutex_t Workers::m_mutex; uv_rwlock_t Workers::m_rwlock; uv_timer_t *Workers::m_timer = nullptr; @@ -199,9 +195,6 @@ void Workers::start(xmrig::Controller *controller) m_sequence = 1; m_paused = 1; - m_async = new uv_async_t; - uv_async_init(uv_default_loop(), m_async, Workers::onResult); - m_timer = new uv_timer_t; uv_timer_init(uv_default_loop(), m_timer); uv_timer_start(m_timer, Workers::onTick, 500, 500); @@ -221,7 +214,6 @@ void Workers::start(xmrig::Controller *controller) void Workers::stop() { xmrig::Handle::close(m_timer); - xmrig::Handle::close(m_async); m_hashrate->stop(); m_paused = 0; @@ -233,16 +225,6 @@ void Workers::stop() } -void Workers::submit(const xmrig::JobResult &result) -{ - uv_mutex_lock(&m_mutex); - m_queue.push_back(result); - uv_mutex_unlock(&m_mutex); - - uv_async_send(m_async); -} - - #ifdef XMRIG_FEATURE_API void Workers::threadsSummary(rapidjson::Document &doc) { @@ -306,25 +288,6 @@ void Workers::onReady(void *arg) } -void Workers::onResult(uv_async_t *) -{ - std::list results; - - uv_mutex_lock(&m_mutex); - while (!m_queue.empty()) { - results.push_back(std::move(m_queue.front())); - m_queue.pop_front(); - } - uv_mutex_unlock(&m_mutex); - - for (auto result : results) { - m_listener->onJobResult(result); - } - - results.clear(); -} - - void Workers::onTick(uv_timer_t *) { for (ThreadHandle *handle : m_workers) { diff --git a/src/workers/Workers.h b/src/workers/Workers.h index 96191309..39e872b5 100644 --- a/src/workers/Workers.h +++ b/src/workers/Workers.h @@ -47,7 +47,6 @@ class ThreadHandle; namespace xmrig { class Controller; - class IJobResultListener; } @@ -62,7 +61,6 @@ public: static void setJob(const xmrig::Job &job, bool donate); static void start(xmrig::Controller *controller); static void stop(); - static void submit(const xmrig::JobResult &result); static inline bool isEnabled() { return m_enabled; } static inline bool isOutdated(uint64_t sequence) { return m_sequence.load(std::memory_order_relaxed) != sequence; } @@ -70,7 +68,6 @@ public: static inline Hashrate *hashrate() { return m_hashrate; } static inline uint64_t sequence() { return m_sequence.load(std::memory_order_relaxed); } static inline void pause() { m_active = false; m_paused = 1; m_sequence++; } - static inline void setListener(xmrig::IJobResultListener *listener) { m_listener = listener; } # ifdef XMRIG_FEATURE_API static void threadsSummary(rapidjson::Document &doc); @@ -83,7 +80,6 @@ public: private: static void onReady(void *arg); - static void onResult(uv_async_t *handle); static void onTick(uv_timer_t *handle); static void start(IWorker *worker); @@ -109,15 +105,12 @@ private: static bool m_active; static bool m_enabled; static Hashrate *m_hashrate; - static xmrig::IJobResultListener *m_listener; static xmrig::Job m_job; static LaunchStatus m_status; static std::atomic m_paused; static std::atomic m_sequence; - static std::list m_queue; static std::vector m_workers; static uint64_t m_ticks; - static uv_async_t *m_async; static uv_mutex_t m_mutex; static uv_rwlock_t m_rwlock; static uv_timer_t *m_timer; From f42adafee0b73d4112a7e7362399fe850b629a40 Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 10 Jul 2019 01:53:05 +0700 Subject: [PATCH 20/65] Added classes Rx, RxAlgo, RxCache, RxDataset. --- CMakeLists.txt | 30 ++++-- src/base/io/log/Log.h | 6 ++ src/core/config/Config.cpp | 2 +- src/crypto/common/Algorithm.cpp | 7 +- src/crypto/common/VirtualMemory.h | 2 + src/crypto/common/VirtualMemory_win.cpp | 9 -- src/crypto/rx/Rx.cpp | 134 ++++++++++++++++++++++++ src/crypto/rx/Rx.h | 53 ++++++++++ src/crypto/rx/RxAlgo.cpp | 69 ++++++++++++ src/crypto/rx/RxAlgo.h | 56 ++++++++++ src/crypto/rx/RxCache.cpp | 81 ++++++++++++++ src/crypto/rx/RxCache.h | 70 +++++++++++++ src/crypto/rx/RxDataset.cpp | 124 ++++++++++++++++++++++ src/crypto/rx/RxDataset.h | 72 +++++++++++++ src/net/JobResults.cpp | 2 + src/workers/MultiWorker.cpp | 9 +- src/workers/Workers.cpp | 108 +------------------ src/workers/Workers.h | 14 --- 18 files changed, 704 insertions(+), 144 deletions(-) create mode 100644 src/crypto/rx/Rx.cpp create mode 100644 src/crypto/rx/Rx.h create mode 100644 src/crypto/rx/RxAlgo.cpp create mode 100644 src/crypto/rx/RxAlgo.h create mode 100644 src/crypto/rx/RxCache.cpp create mode 100644 src/crypto/rx/RxCache.h create mode 100644 src/crypto/rx/RxDataset.cpp create mode 100644 src/crypto/rx/RxDataset.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 33d3ad70..c315e1cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,24 +171,32 @@ if (WITH_RANDOMX) set(SOURCES_CRYPTO "${SOURCES_CRYPTO}" src/crypto/randomx/aes_hash.cpp + src/crypto/randomx/allocator.cpp + src/crypto/randomx/argon2_core.c src/crypto/randomx/argon2_ref.c + src/crypto/randomx/blake2_generator.cpp + src/crypto/randomx/blake2/blake2b.c src/crypto/randomx/bytecode_machine.cpp src/crypto/randomx/dataset.cpp - src/crypto/randomx/soft_aes.cpp - src/crypto/randomx/virtual_memory.cpp - src/crypto/randomx/vm_interpreted.cpp - src/crypto/randomx/allocator.cpp + src/crypto/randomx/instructions_portable.cpp src/crypto/randomx/randomx.cpp + src/crypto/randomx/reciprocal.c + src/crypto/randomx/soft_aes.cpp src/crypto/randomx/superscalar.cpp + src/crypto/randomx/virtual_machine.cpp + src/crypto/randomx/virtual_memory.cpp + src/crypto/randomx/vm_compiled_light.cpp src/crypto/randomx/vm_compiled.cpp src/crypto/randomx/vm_interpreted_light.cpp - src/crypto/randomx/argon2_core.c - src/crypto/randomx/blake2_generator.cpp - src/crypto/randomx/instructions_portable.cpp - src/crypto/randomx/reciprocal.c - src/crypto/randomx/virtual_machine.cpp - src/crypto/randomx/vm_compiled_light.cpp - src/crypto/randomx/blake2/blake2b.c + src/crypto/randomx/vm_interpreted.cpp + src/crypto/rx/Rx.cpp + src/crypto/rx/Rx.h + src/crypto/rx/RxAlgo.cpp + src/crypto/rx/RxAlgo.h + src/crypto/rx/RxCache.cpp + src/crypto/rx/RxCache.h + src/crypto/rx/RxDataset.cpp + src/crypto/rx/RxDataset.h ) if (NOT ARCH_ID) set(ARCH_ID ${CMAKE_HOST_SYSTEM_PROCESSOR}) diff --git a/src/base/io/log/Log.h b/src/base/io/log/Log.h index a14ffded..962d1dba 100644 --- a/src/base/io/log/Log.h +++ b/src/base/io/log/Log.h @@ -81,6 +81,9 @@ private: #define WHITE_S CSI "0;37m" // another name for LT.GRAY #define WHITE_BOLD_S CSI "1;37m" // actually white +#define BLUE_BG_S CSI "44m" +#define BLUE_BG_BOLD_S CSI "44;1m" + //color wrappings #define BLACK(x) BLACK_S x CLEAR #define BLACK_BOLD(x) BLACK_BOLD_S x CLEAR @@ -99,6 +102,9 @@ private: #define WHITE(x) WHITE_S x CLEAR #define WHITE_BOLD(x) WHITE_BOLD_S x CLEAR +#define BLUE_BG(x) BLUE_BG_S x CLEAR +#define BLUE_BG_BOLD(x) BLUE_BG_BOLD_S x CLEAR + #define LOG_EMERG(x, ...) xmrig::Log::print(xmrig::Log::EMERG, x, ##__VA_ARGS__) #define LOG_ALERT(x, ...) xmrig::Log::print(xmrig::Log::ALERT, x, ##__VA_ARGS__) diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 87abbb91..784e171c 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -119,7 +119,7 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const bool xmrig::Config::finalize() { - Algorithm algorithm(Algorithm::CN_0); // FIXME algo + Algorithm algorithm(Algorithm::RX_WOW); // FIXME algo if (!m_threads.cpu.empty()) { m_threads.mode = Advanced; diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index ab63204f..2c259d32 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -32,6 +32,7 @@ #include "crypto/cn/CnAlgo.h" #include "crypto/common/Algorithm.h" +#include "crypto/rx/RxAlgo.h" #include "rapidjson/document.h" @@ -138,12 +139,12 @@ size_t xmrig::Algorithm::memory() const } # ifdef XMRIG_ALGO_RANDOMX - if (m_id == RX_WOW) { - return 0x100000; + if (f == RANDOM_X) { + return RxAlgo::l3(m_id); } # endif - return 0x200000; + return 0; } diff --git a/src/crypto/common/VirtualMemory.h b/src/crypto/common/VirtualMemory.h index e8acb017..a83c35ed 100644 --- a/src/crypto/common/VirtualMemory.h +++ b/src/crypto/common/VirtualMemory.h @@ -44,6 +44,8 @@ public: static void freeLargePagesMemory(void *p, size_t size); static void protectExecutableMemory(void *p, size_t size); static void unprotectExecutableMemory(void *p, size_t size); + + static inline constexpr size_t align(size_t pos, size_t align = 2097152) { return ((pos - 1) / align + 1) * align; } }; diff --git a/src/crypto/common/VirtualMemory_win.cpp b/src/crypto/common/VirtualMemory_win.cpp index dd6be14f..7f1d6f43 100644 --- a/src/crypto/common/VirtualMemory_win.cpp +++ b/src/crypto/common/VirtualMemory_win.cpp @@ -32,15 +32,6 @@ #include "crypto/common/VirtualMemory.h" -namespace xmrig { - -constexpr size_t align(size_t pos, size_t align) { - return ((pos - 1) / align + 1) * align; -} - -} - - void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size) { return VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); diff --git a/src/crypto/rx/Rx.cpp b/src/crypto/rx/Rx.cpp new file mode 100644 index 00000000..735169e2 --- /dev/null +++ b/src/crypto/rx/Rx.cpp @@ -0,0 +1,134 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 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 +#include + + +#include "backend/cpu/Cpu.h" +#include "base/io/log/Log.h" +#include "base/tools/Buffer.h" +#include "base/tools/Chrono.h" +#include "crypto/rx/Rx.h" +#include "crypto/rx/RxCache.h" +#include "crypto/rx/RxDataset.h" + + +namespace xmrig { + + +class RxPrivate +{ +public: + inline RxPrivate() + { + uv_mutex_init(&mutex); + } + + + inline ~RxPrivate() + { + delete dataset; + uv_mutex_destroy(&mutex); + } + + + inline void lock() { uv_mutex_lock(&mutex); } + inline void unlock() { uv_mutex_unlock(&mutex); } + + + RxDataset *dataset = nullptr; + uint32_t initThreads = std::thread::hardware_concurrency(); + uv_mutex_t mutex; +}; + + +static RxPrivate *d_ptr = new RxPrivate(); +static const char *tag = BLUE_BG(" rx "); + + +} // namespace xmrig + + +xmrig::RxDataset *xmrig::Rx::dataset(const uint8_t *seed, const Algorithm &algorithm, bool hugePages) +{ + d_ptr->lock(); + + if (!d_ptr->dataset) { + const uint64_t ts = Chrono::steadyMSecs(); + + LOG_INFO("%s" MAGENTA_BOLD(" allocate") CYAN_BOLD(" %zu MiB") BLACK_BOLD(" (%zu+%zu) for RandomX dataset & cache"), + tag, + (RxDataset::size() + RxCache::size()) / 1024 / 1024, + RxDataset::size() / 1024 / 1024, + RxCache::size() / 1024 / 1024 + ); + + d_ptr->dataset = new RxDataset(hugePages); + + const auto hugePages = d_ptr->dataset->hugePages(); + const double percent = hugePages.first == 0 ? 0.0 : static_cast(hugePages.first) / hugePages.second * 100.0; + + LOG_INFO("%s" GREEN(" allocate done") " huge pages %s%u/%u %1.0f%%" CLEAR " %sJIT" BLACK_BOLD(" (%" PRIu64 " ms)"), + tag, + (hugePages.first == hugePages.second ? GREEN_BOLD_S : (hugePages.first == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), + hugePages.first, + hugePages.second, + percent, + d_ptr->dataset->cache()->isJIT() ? GREEN_BOLD_S "+" : RED_BOLD_S "-", + Chrono::steadyMSecs() - ts + ); + } + + if (!d_ptr->dataset->isReady(seed, algorithm)) { + const uint64_t ts = Chrono::steadyMSecs(); + + LOG_INFO("%s" MAGENTA_BOLD(" init dataset") " algo " WHITE_BOLD("%s") " threads " WHITE_BOLD("%u") BLACK_BOLD(" seed %s..."), + tag, + algorithm.shortName(), + d_ptr->initThreads, + Buffer::toHex(seed, 8).data() + ); + + d_ptr->dataset->init(seed, algorithm, d_ptr->initThreads); + + LOG_INFO("%s" GREEN(" init done") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, Chrono::steadyMSecs() - ts); + } + + RxDataset *dataset = d_ptr->dataset; + d_ptr->unlock(); + + return dataset; +} + + +void xmrig::Rx::stop() +{ + delete d_ptr; + + d_ptr = nullptr; +} diff --git a/src/crypto/rx/Rx.h b/src/crypto/rx/Rx.h new file mode 100644 index 00000000..c9d068c6 --- /dev/null +++ b/src/crypto/rx/Rx.h @@ -0,0 +1,53 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 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_RX_H +#define XMRIG_RX_H + + +#include + + +namespace xmrig +{ + + +class Algorithm; +class RxDataset; + + +class Rx +{ +public: + static RxDataset *dataset(const uint8_t *seed, const Algorithm &algorithm, bool hugePages = true); + static void stop(); +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_RX_H */ diff --git a/src/crypto/rx/RxAlgo.cpp b/src/crypto/rx/RxAlgo.cpp new file mode 100644 index 00000000..b0e92e6e --- /dev/null +++ b/src/crypto/rx/RxAlgo.cpp @@ -0,0 +1,69 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 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/randomx/randomx.h" +#include "crypto/rx/RxAlgo.h" + + +xmrig::Algorithm::Id xmrig::RxAlgo::apply(Algorithm::Id algorithm) +{ + switch (algorithm) { + case Algorithm::RX_WOW: + randomx_apply_config(RandomX_WowneroConfig); + break; + + case Algorithm::RX_LOKI: + randomx_apply_config(RandomX_LokiConfig); + break; + + default: + randomx_apply_config(RandomX_MoneroConfig); + break; + } + + return algorithm; +} + + +size_t xmrig::RxAlgo::l3(Algorithm::Id algorithm) +{ + switch (algorithm) { + case Algorithm::RX_0: + return RandomX_MoneroConfig.ScratchpadL3_Size; + + case Algorithm::RX_WOW: + return RandomX_WowneroConfig.ScratchpadL3_Size; + + case Algorithm::RX_LOKI: + return RandomX_LokiConfig.ScratchpadL3_Size; + + default: + break; + } + + return 0; +} diff --git a/src/crypto/rx/RxAlgo.h b/src/crypto/rx/RxAlgo.h new file mode 100644 index 00000000..dd3f0aa7 --- /dev/null +++ b/src/crypto/rx/RxAlgo.h @@ -0,0 +1,56 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 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_RX_ALGO_H +#define XMRIG_RX_ALGO_H + + +#include +#include + + +#include "crypto/common/Algorithm.h" + + +struct RandomX_ConfigurationBase; + + +namespace xmrig +{ + + +class RxAlgo +{ +public: + static Algorithm::Id apply(Algorithm::Id algorithm); + static size_t l3(Algorithm::Id algorithm); +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_RX_ALGO_H */ diff --git a/src/crypto/rx/RxCache.cpp b/src/crypto/rx/RxCache.cpp new file mode 100644 index 00000000..a5e9efb3 --- /dev/null +++ b/src/crypto/rx/RxCache.cpp @@ -0,0 +1,81 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 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/randomx/randomx.h" +#include "crypto/rx/RxCache.h" + + +static_assert(RANDOMX_FLAG_JIT == 8, "RANDOMX_FLAG_JIT flag mismatch"); +static_assert(RANDOMX_FLAG_LARGE_PAGES == 1, "RANDOMX_FLAG_LARGE_PAGES flag mismatch"); + + + +xmrig::RxCache::RxCache(bool hugePages) : + m_seed() +{ + if (hugePages) { + m_flags = RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES; + m_cache = randomx_alloc_cache(static_cast(m_flags)); + } + + if (!m_cache) { + m_flags = RANDOMX_FLAG_JIT; + m_cache = randomx_alloc_cache(static_cast(m_flags)); + } + + if (!m_cache) { + m_flags = RANDOMX_FLAG_DEFAULT; + m_cache = randomx_alloc_cache(static_cast(m_flags)); + } +} + + +xmrig::RxCache::~RxCache() +{ + if (m_cache) { + randomx_release_cache(m_cache); + } +} + + +bool xmrig::RxCache::init(const void *seed) +{ + if (isReady(seed)) { + return false; + } + + memcpy(m_seed, seed, sizeof(m_seed)); + randomx_init_cache(m_cache, m_seed, sizeof(m_seed)); + + return true; +} + + +bool xmrig::RxCache::isReady(const void *seed) const +{ + return memcmp(m_seed, seed, sizeof(m_seed)) == 0; +} diff --git a/src/crypto/rx/RxCache.h b/src/crypto/rx/RxCache.h new file mode 100644 index 00000000..893ebf06 --- /dev/null +++ b/src/crypto/rx/RxCache.h @@ -0,0 +1,70 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 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_RX_CACHE_H +#define XMRIG_RX_CACHE_H + + +#include + + +#include "crypto/randomx/configuration.h" + + +struct randomx_cache; + + +namespace xmrig +{ + + +class RxCache +{ +public: + RxCache(bool hugePages = true); + ~RxCache(); + + inline bool isHugePages() const { return m_flags & 1; } + inline bool isJIT() const { return m_flags & 8; } + inline const uint8_t *seed() const { return m_seed; } + inline randomx_cache *get() const { return m_cache; } + + bool init(const void *seed); + bool isReady(const void *seed) const; + + static inline constexpr size_t size() { return RANDOMX_CACHE_MAX_SIZE; } + +private: + int m_flags = 0; + randomx_cache *m_cache = nullptr; + uint8_t m_seed[32]; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_RX_CACHE_H */ diff --git a/src/crypto/rx/RxDataset.cpp b/src/crypto/rx/RxDataset.cpp new file mode 100644 index 00000000..5c3b9f37 --- /dev/null +++ b/src/crypto/rx/RxDataset.cpp @@ -0,0 +1,124 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 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 + + +#include "crypto/common/VirtualMemory.h" +#include "crypto/randomx/randomx.h" +#include "crypto/rx/RxAlgo.h" +#include "crypto/rx/RxCache.h" +#include "crypto/rx/RxDataset.h" + + +static_assert(RANDOMX_FLAG_LARGE_PAGES == 1, "RANDOMX_FLAG_LARGE_PAGES flag mismatch"); + + +xmrig::RxDataset::RxDataset(bool hugePages) +{ + if (hugePages) { + m_flags = RANDOMX_FLAG_LARGE_PAGES; + m_dataset = randomx_alloc_dataset(static_cast(m_flags)); + } + + if (!m_dataset) { + m_flags = RANDOMX_FLAG_DEFAULT; + m_dataset = randomx_alloc_dataset(static_cast(m_flags)); + } + + m_cache = new RxCache(hugePages); +} + + +xmrig::RxDataset::~RxDataset() +{ + if (m_dataset) { + randomx_release_dataset(m_dataset); + } + + delete m_cache; +} + + +bool xmrig::RxDataset::init(const void *seed, const Algorithm &algorithm, uint32_t numThreads) +{ + if (isReady(seed, algorithm)) { + return false; + } + + if (m_algorithm != algorithm) { + m_algorithm = RxAlgo::apply(algorithm); + } + + cache()->init(seed); + + const uint32_t datasetItemCount = randomx_dataset_item_count(); + + if (numThreads > 1) { + std::vector threads; + threads.reserve(numThreads); + + for (uint32_t i = 0; i < numThreads; ++i) { + const uint32_t a = (datasetItemCount * i) / numThreads; + const uint32_t b = (datasetItemCount * (i + 1)) / numThreads; + threads.emplace_back(randomx_init_dataset, m_dataset, m_cache->get(), a, b - a); + } + + for (uint32_t i = 0; i < numThreads; ++i) { + threads[i].join(); + } + } + else { + randomx_init_dataset(m_dataset, m_cache->get(), 0, datasetItemCount); + } + + return true; +} + + +bool xmrig::RxDataset::isReady(const void *seed, const Algorithm &algorithm) const +{ + return algorithm == m_algorithm && cache()->isReady(seed); +} + + +std::pair xmrig::RxDataset::hugePages() const +{ + constexpr size_t twoMiB = 2u * 1024u * 1024u; + constexpr const size_t total = (VirtualMemory::align(size(), twoMiB) + VirtualMemory::align(RxCache::size(), twoMiB)) / twoMiB; + + size_t count = 0; + if (isHugePages()) { + count += VirtualMemory::align(size(), twoMiB) / twoMiB; + } + + if (m_cache->isHugePages()) { + count += VirtualMemory::align(RxCache::size(), twoMiB) / twoMiB; + } + + return std::pair(count, total); +} diff --git a/src/crypto/rx/RxDataset.h b/src/crypto/rx/RxDataset.h new file mode 100644 index 00000000..7944d52c --- /dev/null +++ b/src/crypto/rx/RxDataset.h @@ -0,0 +1,72 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 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_RX_DATASET_H +#define XMRIG_RX_DATASET_H + + +#include "crypto/common/Algorithm.h" +#include "crypto/randomx/configuration.h" + + +struct randomx_dataset; + + +namespace xmrig +{ + + +class RxCache; + + +class RxDataset +{ +public: + RxDataset(bool hugePages = true); + ~RxDataset(); + + inline bool isHugePages() const { return m_flags & 1; } + inline randomx_dataset *get() const { return m_dataset; } + inline RxCache *cache() const { return m_cache; } + + bool init(const void *seed, const Algorithm &algorithm, uint32_t numThreads); + bool isReady(const void *seed, const Algorithm &algorithm) const; + std::pair hugePages() const; + + static inline constexpr size_t size() { return RANDOMX_DATASET_MAX_SIZE; } + +private: + Algorithm m_algorithm; + int m_flags = 0; + randomx_dataset *m_dataset = nullptr; + RxCache *m_cache = nullptr; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_RX_DATASET_H */ diff --git a/src/net/JobResults.cpp b/src/net/JobResults.cpp index 8c65b5e4..bf0b5e86 100644 --- a/src/net/JobResults.cpp +++ b/src/net/JobResults.cpp @@ -54,6 +54,8 @@ public: inline ~JobResultsPrivate() { Handle::close(m_async); + + uv_mutex_destroy(&m_mutex); } diff --git a/src/workers/MultiWorker.cpp b/src/workers/MultiWorker.cpp index 2565e7c4..059a7171 100644 --- a/src/workers/MultiWorker.cpp +++ b/src/workers/MultiWorker.cpp @@ -28,6 +28,8 @@ #include "crypto/cn/CryptoNight_test.h" +#include "crypto/rx/Rx.h" +#include "crypto/rx/RxDataset.h" #include "net/JobResults.h" #include "workers/CpuThreadLegacy.h" #include "workers/MultiWorker.h" @@ -67,9 +69,11 @@ void xmrig::MultiWorker::allocateRandomX_VM() flags |= RANDOMX_FLAG_HARD_AES; } - m_rx_vm = randomx_create_vm(static_cast(flags), nullptr, Workers::getDataset()); + RxDataset *dataset = Rx::dataset(m_state.job.seedHash(), m_state.job.algorithm()); + + m_rx_vm = randomx_create_vm(static_cast(flags), nullptr, dataset->get()); if (!m_rx_vm) { - m_rx_vm = randomx_create_vm(static_cast(flags - RANDOMX_FLAG_LARGE_PAGES), nullptr, Workers::getDataset()); + m_rx_vm = randomx_create_vm(static_cast(flags - RANDOMX_FLAG_LARGE_PAGES), nullptr, dataset->get()); } } } @@ -160,7 +164,6 @@ void xmrig::MultiWorker::start() # ifdef XMRIG_ALGO_RANDOMX if (m_state.job.algorithm().family() == Algorithm::RANDOM_X) { allocateRandomX_VM(); - Workers::updateDataset(m_state.job.seedHash(), m_totalWays, m_state.job.algorithm()); randomx_calculate_hash(m_rx_vm, m_state.blob, m_state.job.size(), m_hash); } else diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index 88d73a0b..58cccd9e 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -29,9 +29,13 @@ #include "api/Api.h" #include "base/io/log/Log.h" +#include "base/tools/Chrono.h" #include "base/tools/Handle.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "crypto/rx/RxAlgo.h" +#include "crypto/rx/RxCache.h" +#include "crypto/rx/RxDataset.h" #include "interfaces/IThread.h" #include "Mem.h" #include "rapidjson/document.h" @@ -55,15 +59,6 @@ uv_rwlock_t Workers::m_rwlock; uv_timer_t *Workers::m_timer = nullptr; xmrig::Controller *Workers::m_controller = nullptr; -#ifdef XMRIG_ALGO_RANDOMX -uv_rwlock_t Workers::m_rx_dataset_lock; -randomx_cache *Workers::m_rx_cache = nullptr; -randomx_dataset *Workers::m_rx_dataset = nullptr; -uint8_t Workers::m_rx_seed_hash[32] = {}; -xmrig::Algorithm Workers::m_rx_algo; -std::atomic Workers::m_rx_dataset_init_thread_counter = {}; -#endif - xmrig::Job Workers::job() { @@ -176,7 +171,7 @@ void Workers::start(xmrig::Controller *controller) m_controller = controller; const std::vector &threads = controller->config()->threads(); - m_status.algo = xmrig::Algorithm::CN_0; // FIXME algo + m_status.algo = xmrig::Algorithm::RX_WOW; // FIXME algo m_status.threads = threads.size(); for (const xmrig::IThread *thread : threads) { @@ -188,10 +183,6 @@ void Workers::start(xmrig::Controller *controller) uv_mutex_init(&m_mutex); uv_rwlock_init(&m_rwlock); -# ifdef XMRIG_ALGO_RANDOMX - uv_rwlock_init(&m_rx_dataset_lock); -# endif - m_sequence = 1; m_paused = 1; @@ -335,92 +326,3 @@ void Workers::start(IWorker *worker) worker->start(); } - - -#ifdef XMRIG_ALGO_RANDOMX -void Workers::updateDataset(const uint8_t* seed_hash, const uint32_t num_threads, const xmrig::Algorithm &algorithm) -{ - // Check if we need to update cache and dataset - if ((memcmp(m_rx_seed_hash, seed_hash, sizeof(m_rx_seed_hash)) == 0) && (m_rx_algo == algorithm)) - return; - - const uint32_t thread_id = m_rx_dataset_init_thread_counter++; - LOG_DEBUG("Thread %u started updating RandomX dataset", thread_id); - - // Wait for all threads to get here - do { - if (m_sequence.load(std::memory_order_relaxed) == 0) { - // Exit immediately if workers were stopped - return; - } - std::this_thread::yield(); - } while (m_rx_dataset_init_thread_counter.load() != num_threads); - - // One of the threads updates cache - uv_rwlock_wrlock(&m_rx_dataset_lock); - - if (m_rx_algo != algorithm) { - switch (algorithm) { - case xmrig::Algorithm::RX_WOW: - randomx_apply_config(RandomX_WowneroConfig); - break; - - case xmrig::Algorithm::RX_LOKI: - randomx_apply_config(RandomX_LokiConfig); - break; - - default: - randomx_apply_config(RandomX_MoneroConfig); - break; - } - - m_rx_algo = algorithm; - } - - if (memcmp(m_rx_seed_hash, seed_hash, sizeof(m_rx_seed_hash)) != 0) { - memcpy(m_rx_seed_hash, seed_hash, sizeof(m_rx_seed_hash)); - randomx_init_cache(m_rx_cache, m_rx_seed_hash, sizeof(m_rx_seed_hash)); - } - - uv_rwlock_wrunlock(&m_rx_dataset_lock); - - // All threads update dataset - const uint32_t a = (randomx_dataset_item_count() * thread_id) / num_threads; - const uint32_t b = (randomx_dataset_item_count() * (thread_id + 1)) / num_threads; - randomx_init_dataset(m_rx_dataset, m_rx_cache, a, b - a); - - LOG_DEBUG("Thread %u finished updating RandomX dataset", thread_id); - - // Wait for all threads to complete - --m_rx_dataset_init_thread_counter; - do { - if (m_sequence.load(std::memory_order_relaxed) == 0) { - // Exit immediately if workers were stopped - return; - } - std::this_thread::yield(); - } while (m_rx_dataset_init_thread_counter.load() != 0); -} - -randomx_dataset* Workers::getDataset() -{ - if (m_rx_dataset) - return m_rx_dataset; - - uv_rwlock_wrlock(&m_rx_dataset_lock); - if (!m_rx_dataset) { - randomx_dataset* dataset = randomx_alloc_dataset(RANDOMX_FLAG_LARGE_PAGES); - if (!dataset) { - dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT); - } - m_rx_cache = randomx_alloc_cache(static_cast(RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES)); - if (!m_rx_cache) { - m_rx_cache = randomx_alloc_cache(RANDOMX_FLAG_JIT); - } - m_rx_dataset = dataset; - } - uv_rwlock_wrunlock(&m_rx_dataset_lock); - - return m_rx_dataset; -} -#endif diff --git a/src/workers/Workers.h b/src/workers/Workers.h index 39e872b5..8619f973 100644 --- a/src/workers/Workers.h +++ b/src/workers/Workers.h @@ -73,11 +73,6 @@ public: static void threadsSummary(rapidjson::Document &doc); # endif -# ifdef XMRIG_ALGO_RANDOMX - static void updateDataset(const uint8_t* seed_hash, uint32_t num_threads, const xmrig::Algorithm &algorithm); - static randomx_dataset* getDataset(); -# endif - private: static void onReady(void *arg); static void onTick(uv_timer_t *handle); @@ -115,15 +110,6 @@ private: static uv_rwlock_t m_rwlock; static uv_timer_t *m_timer; static xmrig::Controller *m_controller; - -# ifdef XMRIG_ALGO_RANDOMX - static uv_rwlock_t m_rx_dataset_lock; - static randomx_cache *m_rx_cache; - static randomx_dataset *m_rx_dataset; - static uint8_t m_rx_seed_hash[32]; - static xmrig::Algorithm m_rx_algo; - static std::atomic m_rx_dataset_init_thread_counter; -# endif }; From 3bebf778da034d974718b0258ea7b74c3534d649 Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 10 Jul 2019 02:28:45 +0700 Subject: [PATCH 21/65] Fixed build. --- src/api/v1/ApiRouter.cpp | 4 ++-- src/backend/cpu/platform/AdvancedCpuInfo.cpp | 1 + src/backend/cpu/platform/BasicCpuInfo.cpp | 2 +- src/backend/cpu/platform/BasicCpuInfo.h | 2 +- src/backend/cpu/platform/BasicCpuInfo_arm.cpp | 8 +++++++- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp index 0f754e17..ff1ef404 100644 --- a/src/api/v1/ApiRouter.cpp +++ b/src/api/v1/ApiRouter.cpp @@ -22,7 +22,7 @@ * along with this program. If not, see . */ -#include +#include #include #include @@ -44,7 +44,7 @@ static inline rapidjson::Value normalize(double d) { using namespace rapidjson; - if (!isnormal(d)) { + if (!std::isnormal(d)) { return Value(kNullType); } diff --git a/src/backend/cpu/platform/AdvancedCpuInfo.cpp b/src/backend/cpu/platform/AdvancedCpuInfo.cpp index b5b2fe91..f3c4ed23 100644 --- a/src/backend/cpu/platform/AdvancedCpuInfo.cpp +++ b/src/backend/cpu/platform/AdvancedCpuInfo.cpp @@ -22,6 +22,7 @@ * along with this program. If not, see . */ +#include #include #include #include diff --git a/src/backend/cpu/platform/BasicCpuInfo.cpp b/src/backend/cpu/platform/BasicCpuInfo.cpp index 26237468..369392b6 100644 --- a/src/backend/cpu/platform/BasicCpuInfo.cpp +++ b/src/backend/cpu/platform/BasicCpuInfo.cpp @@ -124,8 +124,8 @@ static inline bool has_ossave() xmrig::BasicCpuInfo::BasicCpuInfo() : m_assembly(Assembly::NONE), - m_brand(), m_aes(has_aes_ni()), + m_brand(), m_avx2(has_avx2() && has_ossave()), m_threads(std::thread::hardware_concurrency()) { diff --git a/src/backend/cpu/platform/BasicCpuInfo.h b/src/backend/cpu/platform/BasicCpuInfo.h index 12c275dd..886d59c3 100644 --- a/src/backend/cpu/platform/BasicCpuInfo.h +++ b/src/backend/cpu/platform/BasicCpuInfo.h @@ -55,8 +55,8 @@ protected: private: Assembly m_assembly; + bool m_aes; char m_brand[64 + 6]; - const bool m_aes; const bool m_avx2; const size_t m_threads; }; diff --git a/src/backend/cpu/platform/BasicCpuInfo_arm.cpp b/src/backend/cpu/platform/BasicCpuInfo_arm.cpp index 49e300e4..6702f6f0 100644 --- a/src/backend/cpu/platform/BasicCpuInfo_arm.cpp +++ b/src/backend/cpu/platform/BasicCpuInfo_arm.cpp @@ -37,8 +37,8 @@ xmrig::BasicCpuInfo::BasicCpuInfo() : m_aes(false), - m_avx2(false), m_brand(), + m_avx2(false), m_threads(std::thread::hardware_concurrency()) { # ifdef XMRIG_ARMv8 @@ -61,3 +61,9 @@ size_t xmrig::BasicCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) { return threads(); } + + +xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm) const +{ + return CpuThreads(threads()); +} From 270d3ba6a2bed53d132a4d8960ba867d35776137 Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 10 Jul 2019 10:14:33 +0700 Subject: [PATCH 22/65] Added class RxVm. --- CMakeLists.txt | 2 ++ src/crypto/rx/Rx.cpp | 48 ++++++++++++++++---------- src/crypto/rx/RxCache.h | 2 +- src/crypto/rx/RxDataset.cpp | 4 +++ src/crypto/rx/RxVm.cpp | 68 +++++++++++++++++++++++++++++++++++++ src/crypto/rx/RxVm.h | 61 +++++++++++++++++++++++++++++++++ src/workers/MultiWorker.cpp | 21 +++--------- src/workers/MultiWorker.h | 10 +++--- 8 files changed, 176 insertions(+), 40 deletions(-) create mode 100644 src/crypto/rx/RxVm.cpp create mode 100644 src/crypto/rx/RxVm.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c315e1cf..9094d381 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,6 +197,8 @@ if (WITH_RANDOMX) src/crypto/rx/RxCache.h src/crypto/rx/RxDataset.cpp src/crypto/rx/RxDataset.h + src/crypto/rx/RxVm.cpp + src/crypto/rx/RxVm.h ) if (NOT ARCH_ID) set(ARCH_ID ${CMAKE_HOST_SYSTEM_PROCESSOR}) diff --git a/src/crypto/rx/Rx.cpp b/src/crypto/rx/Rx.cpp index 735169e2..630dd45a 100644 --- a/src/crypto/rx/Rx.cpp +++ b/src/crypto/rx/Rx.cpp @@ -90,29 +90,43 @@ xmrig::RxDataset *xmrig::Rx::dataset(const uint8_t *seed, const Algorithm &algor d_ptr->dataset = new RxDataset(hugePages); - const auto hugePages = d_ptr->dataset->hugePages(); - const double percent = hugePages.first == 0 ? 0.0 : static_cast(hugePages.first) / hugePages.second * 100.0; + if (d_ptr->dataset->get() != nullptr) { + const auto hugePages = d_ptr->dataset->hugePages(); + const double percent = hugePages.first == 0 ? 0.0 : static_cast(hugePages.first) / hugePages.second * 100.0; - LOG_INFO("%s" GREEN(" allocate done") " huge pages %s%u/%u %1.0f%%" CLEAR " %sJIT" BLACK_BOLD(" (%" PRIu64 " ms)"), - tag, - (hugePages.first == hugePages.second ? GREEN_BOLD_S : (hugePages.first == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), - hugePages.first, - hugePages.second, - percent, - d_ptr->dataset->cache()->isJIT() ? GREEN_BOLD_S "+" : RED_BOLD_S "-", - Chrono::steadyMSecs() - ts - ); + LOG_INFO("%s" GREEN(" allocate done") " huge pages %s%u/%u %1.0f%%" CLEAR " %sJIT" BLACK_BOLD(" (%" PRIu64 " ms)"), + tag, + (hugePages.first == hugePages.second ? GREEN_BOLD_S : (hugePages.first == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), + hugePages.first, + hugePages.second, + percent, + d_ptr->dataset->cache()->isJIT() ? GREEN_BOLD_S "+" : RED_BOLD_S "-", + Chrono::steadyMSecs() - ts + ); + } + else { + LOG_WARN(CLEAR "%s" YELLOW_BOLD_S " failed to allocate RandomX dataset, switching to slow mode", tag); + } } if (!d_ptr->dataset->isReady(seed, algorithm)) { const uint64_t ts = Chrono::steadyMSecs(); - LOG_INFO("%s" MAGENTA_BOLD(" init dataset") " algo " WHITE_BOLD("%s") " threads " WHITE_BOLD("%u") BLACK_BOLD(" seed %s..."), - tag, - algorithm.shortName(), - d_ptr->initThreads, - Buffer::toHex(seed, 8).data() - ); + if (d_ptr->dataset->get() != nullptr) { + LOG_INFO("%s" MAGENTA_BOLD(" init dataset") " algo " WHITE_BOLD("%s") " threads " WHITE_BOLD("%u") BLACK_BOLD(" seed %s..."), + tag, + algorithm.shortName(), + d_ptr->initThreads, + Buffer::toHex(seed, 8).data() + ); + } + else { + LOG_INFO("%s" MAGENTA_BOLD(" init cache") " algo " WHITE_BOLD("%s") BLACK_BOLD(" seed %s..."), + tag, + algorithm.shortName(), + Buffer::toHex(seed, 8).data() + ); + } d_ptr->dataset->init(seed, algorithm, d_ptr->initThreads); diff --git a/src/crypto/rx/RxCache.h b/src/crypto/rx/RxCache.h index 893ebf06..c48924a1 100644 --- a/src/crypto/rx/RxCache.h +++ b/src/crypto/rx/RxCache.h @@ -58,7 +58,7 @@ public: static inline constexpr size_t size() { return RANDOMX_CACHE_MAX_SIZE; } private: - int m_flags = 0; + int m_flags = 0; randomx_cache *m_cache = nullptr; uint8_t m_seed[32]; }; diff --git a/src/crypto/rx/RxDataset.cpp b/src/crypto/rx/RxDataset.cpp index 5c3b9f37..603cf578 100644 --- a/src/crypto/rx/RxDataset.cpp +++ b/src/crypto/rx/RxDataset.cpp @@ -76,6 +76,10 @@ bool xmrig::RxDataset::init(const void *seed, const Algorithm &algorithm, uint32 cache()->init(seed); + if (!get()) { + return true; + } + const uint32_t datasetItemCount = randomx_dataset_item_count(); if (numThreads > 1) { diff --git a/src/crypto/rx/RxVm.cpp b/src/crypto/rx/RxVm.cpp new file mode 100644 index 00000000..3ee0f859 --- /dev/null +++ b/src/crypto/rx/RxVm.cpp @@ -0,0 +1,68 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 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/randomx/randomx.h" +#include "crypto/rx/RxCache.h" +#include "crypto/rx/RxDataset.h" +#include "crypto/rx/RxVm.h" + + +xmrig::RxVm::RxVm(RxDataset *dataset, bool hugePages, bool softAes) +{ + m_flags = RANDOMX_FLAG_JIT; + if (hugePages) { + m_flags |= RANDOMX_FLAG_LARGE_PAGES; + } + + if (!softAes) { + m_flags |= RANDOMX_FLAG_HARD_AES; + } + + if (dataset->get()) { + m_flags |= RANDOMX_FLAG_FULL_MEM; + } + + m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache()->get(), dataset->get()); + + if (!m_vm) { + m_flags &= ~RANDOMX_FLAG_LARGE_PAGES; + m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache()->get(), dataset->get()); + } + + if (!m_vm) { + m_flags &= ~RANDOMX_FLAG_JIT; + m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache()->get(), dataset->get()); + } +} + + +xmrig::RxVm::~RxVm() +{ + if (m_vm) { + randomx_destroy_vm(m_vm); + } +} diff --git a/src/crypto/rx/RxVm.h b/src/crypto/rx/RxVm.h new file mode 100644 index 00000000..90af8187 --- /dev/null +++ b/src/crypto/rx/RxVm.h @@ -0,0 +1,61 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 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_RX_VM_H +#define XMRIG_RX_VM_H + + +#include + + +struct randomx_vm; + + +namespace xmrig +{ + + +class RxDataset; + + +class RxVm +{ +public: + RxVm(RxDataset *dataset, bool hugePages, bool softAes); + ~RxVm(); + + inline randomx_vm *get() const { return m_vm; } + +private: + int m_flags = 0; + randomx_vm *m_vm = nullptr; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_RX_CACHE_H */ diff --git a/src/workers/MultiWorker.cpp b/src/workers/MultiWorker.cpp index 059a7171..684d92f9 100644 --- a/src/workers/MultiWorker.cpp +++ b/src/workers/MultiWorker.cpp @@ -29,7 +29,7 @@ #include "crypto/cn/CryptoNight_test.h" #include "crypto/rx/Rx.h" -#include "crypto/rx/RxDataset.h" +#include "crypto/rx/RxVm.h" #include "net/JobResults.h" #include "workers/CpuThreadLegacy.h" #include "workers/MultiWorker.h" @@ -52,9 +52,7 @@ xmrig::MultiWorker::~MultiWorker() Mem::release(m_ctx, N, m_memory); # ifdef XMRIG_ALGO_RANDOMX - if (m_rx_vm) { - randomx_destroy_vm(m_rx_vm); - } + delete m_vm; # endif } @@ -63,18 +61,9 @@ xmrig::MultiWorker::~MultiWorker() template void xmrig::MultiWorker::allocateRandomX_VM() { - if (!m_rx_vm) { - int flags = RANDOMX_FLAG_LARGE_PAGES | RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT; - if (!m_thread->isSoftAES()) { - flags |= RANDOMX_FLAG_HARD_AES; - } - + if (!m_vm) { RxDataset *dataset = Rx::dataset(m_state.job.seedHash(), m_state.job.algorithm()); - - m_rx_vm = randomx_create_vm(static_cast(flags), nullptr, dataset->get()); - if (!m_rx_vm) { - m_rx_vm = randomx_create_vm(static_cast(flags - RANDOMX_FLAG_LARGE_PAGES), nullptr, dataset->get()); - } + m_vm = new RxVm(dataset, true, m_thread->isSoftAES()); } } #endif @@ -164,7 +153,7 @@ void xmrig::MultiWorker::start() # ifdef XMRIG_ALGO_RANDOMX if (m_state.job.algorithm().family() == Algorithm::RANDOM_X) { allocateRandomX_VM(); - randomx_calculate_hash(m_rx_vm, m_state.blob, m_state.job.size(), m_hash); + randomx_calculate_hash(m_vm->get(), m_state.blob, m_state.job.size(), m_hash); } else # endif diff --git a/src/workers/MultiWorker.h b/src/workers/MultiWorker.h index d695e030..0502ad84 100644 --- a/src/workers/MultiWorker.h +++ b/src/workers/MultiWorker.h @@ -27,11 +27,6 @@ #define XMRIG_MULTIWORKER_H -#ifdef XMRIG_ALGO_RANDOMX -# include -#endif - - #include "base/net/stratum/Job.h" #include "Mem.h" #include "net/JobResult.h" @@ -41,6 +36,9 @@ namespace xmrig { +class RxVm; + + template class MultiWorker : public Worker { @@ -81,7 +79,7 @@ private: uint8_t m_hash[N * 32]; # ifdef XMRIG_ALGO_RANDOMX - randomx_vm *m_rx_vm = nullptr; + RxVm *m_vm = nullptr; # endif }; From 8e2219b7c481d8cd692b1103d317254e03626bf7 Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 10 Jul 2019 10:26:10 +0700 Subject: [PATCH 23/65] Fixed RandomX VM creation in some cases. --- src/crypto/rx/RxVm.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/crypto/rx/RxVm.cpp b/src/crypto/rx/RxVm.cpp index 3ee0f859..b02f708e 100644 --- a/src/crypto/rx/RxVm.cpp +++ b/src/crypto/rx/RxVm.cpp @@ -33,7 +33,6 @@ xmrig::RxVm::RxVm(RxDataset *dataset, bool hugePages, bool softAes) { - m_flags = RANDOMX_FLAG_JIT; if (hugePages) { m_flags |= RANDOMX_FLAG_LARGE_PAGES; } @@ -46,6 +45,10 @@ xmrig::RxVm::RxVm(RxDataset *dataset, bool hugePages, bool softAes) m_flags |= RANDOMX_FLAG_FULL_MEM; } + if (dataset->cache()->isJIT()) { + m_flags |= RANDOMX_FLAG_JIT; + } + m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache()->get(), dataset->get()); if (!m_vm) { @@ -54,7 +57,7 @@ xmrig::RxVm::RxVm(RxDataset *dataset, bool hugePages, bool softAes) } if (!m_vm) { - m_flags &= ~RANDOMX_FLAG_JIT; + m_flags &= ~RANDOMX_FLAG_HARD_AES; m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache()->get(), dataset->get()); } } From 6f27037f0759133aea66a366093744e983b49d9b Mon Sep 17 00:00:00 2001 From: XMRig Date: Thu, 11 Jul 2019 16:15:51 +0700 Subject: [PATCH 24/65] Added new nonce allocation method for dynamic/variable threads. --- CMakeLists.txt | 3 + src/core/WorkerJob.h | 143 ++++++++++++++++++++++++++++++++++++ src/crypto/common/Nonce.cpp | 83 +++++++++++++++++++++ src/crypto/common/Nonce.h | 57 ++++++++++++++ src/workers/MultiWorker.cpp | 88 ++++++---------------- src/workers/MultiWorker.h | 19 +---- src/workers/Worker.cpp | 5 +- src/workers/Worker.h | 5 +- src/workers/Workers.cpp | 21 ++++-- src/workers/Workers.h | 7 +- 10 files changed, 336 insertions(+), 95 deletions(-) create mode 100644 src/core/WorkerJob.h create mode 100644 src/crypto/common/Nonce.cpp create mode 100644 src/crypto/common/Nonce.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9094d381..13f787f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ set(HEADERS src/core/config/ConfigTransform.h src/core/config/usage.h src/core/Controller.h + src/core/WorkerJob.h src/interfaces/IThread.h src/interfaces/IWorker.h src/Mem.h @@ -71,6 +72,7 @@ set(HEADERS_CRYPTO src/crypto/cn/soft_aes.h src/crypto/common/Algorithm.h src/crypto/common/keccak.h + src/crypto/common/Nonce.h src/crypto/common/portable/mm_malloc.h src/crypto/common/VirtualMemory.h ) @@ -113,6 +115,7 @@ set(SOURCES_CRYPTO src/crypto/cn/CnHash.cpp src/crypto/common/Algorithm.cpp src/crypto/common/keccak.cpp + src/crypto/common/Nonce.cpp ) if (WIN32) diff --git a/src/core/WorkerJob.h b/src/core/WorkerJob.h new file mode 100644 index 00000000..004c5533 --- /dev/null +++ b/src/core/WorkerJob.h @@ -0,0 +1,143 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_WORKERJOB_H +#define XMRIG_WORKERJOB_H + + +#include +#include + + +#include "base/net/stratum/Job.h" +#include "crypto/common/Nonce.h" + + +namespace xmrig { + + +template +class WorkerJob +{ +public: + inline const Job ¤tJob() const { return m_jobs[index()]; } + inline uint32_t *nonce(size_t i = 0) { return reinterpret_cast(blob() + (i * currentJob().size()) + 39); } + inline uint64_t sequence() const { return m_sequence; } + inline uint8_t *blob() { return m_blobs[index()]; } + inline uint8_t index() const { return m_index; } + + + inline void add(const Job &job, uint64_t sequence, uint32_t reserveCount) + { + m_sequence = sequence; + + if (currentJob() == job) { + return; + } + + if (index() == 1 && job.poolId() >= 0 && job == m_jobs[0]) { + return; + } + + save(job, reserveCount); + } + + + inline void nextRound(uint32_t reserveCount) + { + m_rounds[index()]++; + + if ((m_rounds[index()] % reserveCount) == 0) { + for (size_t i = 0; i < N; ++i) { + *nonce(i) = Nonce::next(index(), *nonce(i), reserveCount, currentJob().isNicehash()); + } + } + else { + for (size_t i = 0; i < N; ++i) { + *nonce(i) += 1; + } + } + } + + +private: + inline void save(const Job &job, uint32_t reserveCount) + { + m_index = job.poolId() == -1 ? 1 : 0; + const size_t size = job.size(); + m_jobs[index()] = job; + m_rounds[index()] = 0; + + for (size_t i = 0; i < N; ++i) { + memcpy(m_blobs[index()] + (i * size), job.blob(), size); + *nonce(i) = Nonce::next(index(), *nonce(i), reserveCount, job.isNicehash()); + } + } + + + alignas(16) uint8_t m_blobs[2][Job::kMaxBlobSize * N]; + Job m_jobs[2]; + uint32_t m_rounds[2] = { 0, 0 }; + uint64_t m_sequence = 0; + uint8_t m_index = 0; +}; + + +template<> +inline uint32_t *xmrig::WorkerJob<1>::nonce(size_t) +{ + return reinterpret_cast(blob() + 39); +} + + +template<> +inline void xmrig::WorkerJob<1>::nextRound(uint32_t reserveCount) +{ + m_rounds[index()]++; + + if ((m_rounds[index()] % reserveCount) == 0) { + *nonce() = Nonce::next(index(), *nonce(), reserveCount, currentJob().isNicehash()); + } + else { + *nonce() += 1; + } +} + + +template<> +inline void xmrig::WorkerJob<1>::save(const Job &job, uint32_t reserveCount) +{ + m_index = job.poolId() == -1 ? 1 : 0; + m_jobs[index()] = job; + m_rounds[index()] = 0; + + memcpy(blob(), job.blob(), job.size()); + *nonce() = Nonce::next(index(), *nonce(), reserveCount, currentJob().isNicehash()); +} + + +} // namespace xmrig + + +#endif /* XMRIG_WORKERJOB_H */ diff --git a/src/crypto/common/Nonce.cpp b/src/crypto/common/Nonce.cpp new file mode 100644 index 00000000..6670308a --- /dev/null +++ b/src/crypto/common/Nonce.cpp @@ -0,0 +1,83 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "crypto/common/Nonce.h" + + +namespace xmrig { + + +std::atomic Nonce::m_sequence; +uint32_t Nonce::m_nonces[2] = { 0, 0 }; + + +static uv_mutex_t mutex; +static Nonce nonce; + + +} // namespace xmrig + + +xmrig::Nonce::Nonce() +{ + m_sequence = 1; + + uv_mutex_init(&mutex); +} + + +uint32_t xmrig::Nonce::next(uint8_t index, uint32_t nonce, uint32_t reserveCount, bool nicehash) +{ + uint32_t next; + + uv_mutex_lock(&mutex); + + if (nicehash) { + next = (nonce & 0xFF000000) | m_nonces[index]; + } + else { + next = m_nonces[index]; + } + + m_nonces[index] += reserveCount; + + uv_mutex_unlock(&mutex); + + return next; +} + + +void xmrig::Nonce::reset(uint8_t index) +{ + uv_mutex_lock(&mutex); + + m_nonces[index] = 0; + m_sequence++; + + uv_mutex_unlock(&mutex); +} diff --git a/src/crypto/common/Nonce.h b/src/crypto/common/Nonce.h new file mode 100644 index 00000000..ea843bc9 --- /dev/null +++ b/src/crypto/common/Nonce.h @@ -0,0 +1,57 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_NONCE_H +#define XMRIG_NONCE_H + + +#include + + +namespace xmrig { + + +class Nonce +{ +public: + Nonce(); + + static inline bool isOutdated(uint64_t sequence) { return m_sequence.load(std::memory_order_relaxed) != sequence; } + static inline uint64_t sequence() { return m_sequence.load(std::memory_order_relaxed); } + static inline void stop() { m_sequence = 0; } + static inline void touch() { m_sequence++; } + + static uint32_t next(uint8_t index, uint32_t nonce, uint32_t reserveCount, bool nicehash); + static void reset(uint8_t index); + +private: + static uint32_t m_nonces[2]; + static std::atomic m_sequence; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_NONCE_H */ diff --git a/src/workers/MultiWorker.cpp b/src/workers/MultiWorker.cpp index 684d92f9..daae9230 100644 --- a/src/workers/MultiWorker.cpp +++ b/src/workers/MultiWorker.cpp @@ -28,6 +28,7 @@ #include "crypto/cn/CryptoNight_test.h" +#include "crypto/common/Nonce.h" #include "crypto/rx/Rx.h" #include "crypto/rx/RxVm.h" #include "net/JobResults.h" @@ -36,6 +37,13 @@ #include "workers/Workers.h" +namespace xmrig { + +static constexpr uint32_t kReserveCount = 4096; + +} // namespace xmrig + + template xmrig::MultiWorker::MultiWorker(ThreadHandle *handle) : Worker(handle) @@ -62,7 +70,7 @@ template void xmrig::MultiWorker::allocateRandomX_VM() { if (!m_vm) { - RxDataset *dataset = Rx::dataset(m_state.job.seedHash(), m_state.job.algorithm()); + RxDataset *dataset = Rx::dataset(m_job.currentJob().seedHash(), m_job.currentJob().algorithm()); m_vm = new RxVm(dataset, true, m_thread->isSoftAES()); } } @@ -131,44 +139,45 @@ bool xmrig::MultiWorker::selfTest() template void xmrig::MultiWorker::start() { - while (Workers::sequence() > 0) { + while (Nonce::sequence() > 0) { if (Workers::isPaused()) { do { std::this_thread::sleep_for(std::chrono::milliseconds(200)); } while (Workers::isPaused()); - if (Workers::sequence() == 0) { + if (Nonce::sequence() == 0) { break; } consumeJob(); } - while (!Workers::isOutdated(m_sequence)) { + while (!Nonce::isOutdated(m_job.sequence())) { if ((m_count & 0x7) == 0) { storeStats(); } + const Job &job = m_job.currentJob(); + # ifdef XMRIG_ALGO_RANDOMX - if (m_state.job.algorithm().family() == Algorithm::RANDOM_X) { + if (job.algorithm().family() == Algorithm::RANDOM_X) { allocateRandomX_VM(); - randomx_calculate_hash(m_vm->get(), m_state.blob, m_state.job.size(), m_hash); + randomx_calculate_hash(m_vm->get(), m_job.blob(), job.size(), m_hash); } else # endif { - m_thread->fn(m_state.job.algorithm())(m_state.blob, m_state.job.size(), m_hash, m_ctx, m_state.job.height()); + m_thread->fn(job.algorithm())(m_job.blob(), job.size(), m_hash, m_ctx, job.height()); } for (size_t i = 0; i < N; ++i) { - if (*reinterpret_cast(m_hash + (i * 32) + 24) < m_state.job.target()) { - JobResults::submit(JobResult(m_state.job.poolId(), m_state.job.id(), m_state.job.clientId(), *nonce(i), m_hash + (i * 32), m_state.job.diff(), m_state.job.algorithm())); + if (*reinterpret_cast(m_hash + (i * 32) + 24) < job.target()) { + JobResults::submit(JobResult(job.poolId(), job.id(), job.clientId(), *m_job.nonce(i), m_hash + (i * 32), job.diff(), job.algorithm())); } - - *nonce(i) += 1; } + m_job.nextRound(kReserveCount); m_count += N; std::this_thread::yield(); @@ -179,18 +188,6 @@ void xmrig::MultiWorker::start() } -template -bool xmrig::MultiWorker::resume(const xmrig::Job &job) -{ - if (m_state.job.poolId() == -1 && job.poolId() >= 0 && job.id() == m_pausedState.job.id()) { - m_state = m_pausedState; - return true; - } - - return false; -} - - template bool xmrig::MultiWorker::verify(const Algorithm &algorithm, const uint8_t *referenceValue) { @@ -215,10 +212,10 @@ bool xmrig::MultiWorker::verify2(const Algorithm &algorithm, const uint8_t *r for (size_t i = 0; i < (sizeof(cn_r_test_input) / sizeof(cn_r_test_input[0])); ++i) { const size_t size = cn_r_test_input[i].size; for (size_t k = 0; k < N; ++k) { - memcpy(m_state.blob + (k * size), cn_r_test_input[i].data, size); + memcpy(m_job.blob() + (k * size), cn_r_test_input[i].data, size); } - func(m_state.blob, size, m_hash, m_ctx, cn_r_test_input[i].height); + func(m_job.blob(), size, m_hash, m_ctx, cn_r_test_input[i].height); for (size_t k = 0; k < N; ++k) { if (memcmp(m_hash + k * 32, referenceValue + i * 32, sizeof m_hash / N) != 0) { @@ -258,46 +255,7 @@ bool MultiWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenc template void xmrig::MultiWorker::consumeJob() { - Job job = Workers::job(); - m_sequence = Workers::sequence(); - if (m_state.job == job) { - return; - } - - save(job); - - if (resume(job)) { - return; - } - - m_state.job = job; - - const size_t size = m_state.job.size(); - memcpy(m_state.blob, m_state.job.blob(), m_state.job.size()); - - if (N > 1) { - for (size_t i = 1; i < N; ++i) { - memcpy(m_state.blob + (i * size), m_state.blob, size); - } - } - - for (size_t i = 0; i < N; ++i) { - if (m_state.job.isNicehash()) { - *nonce(i) = (*nonce(i) & 0xff000000U) + (0xffffffU / m_totalWays * (m_offset + i)); - } - else { - *nonce(i) = 0xffffffffU / m_totalWays * (m_offset + i); - } - } -} - - -template -void xmrig::MultiWorker::save(const Job &job) -{ - if (job.poolId() == -1 && m_state.job.poolId() >= 0) { - m_pausedState = m_state; - } + m_job.add(Workers::job(), Nonce::sequence(), kReserveCount); } diff --git a/src/workers/MultiWorker.h b/src/workers/MultiWorker.h index 0502ad84..2bcb2333 100644 --- a/src/workers/MultiWorker.h +++ b/src/workers/MultiWorker.h @@ -28,6 +28,7 @@ #include "base/net/stratum/Job.h" +#include "core/WorkerJob.h" #include "Mem.h" #include "net/JobResult.h" #include "workers/Worker.h" @@ -55,29 +56,15 @@ private: void allocateRandomX_VM(); # endif - bool resume(const Job &job); bool verify(const Algorithm &algorithm, const uint8_t *referenceValue); bool verify2(const Algorithm &algorithm, const uint8_t *referenceValue); void consumeJob(); - void save(const Job &job); - - inline uint32_t *nonce(size_t index) - { - return reinterpret_cast(m_state.blob + (index * m_state.job.size()) + 39); - } - - struct State - { - alignas(16) uint8_t blob[Job::kMaxBlobSize * N]; - Job job; - }; - cryptonight_ctx *m_ctx[N]; - State m_pausedState; - State m_state; uint8_t m_hash[N * 32]; + WorkerJob m_job; + # ifdef XMRIG_ALGO_RANDOMX RxVm *m_vm = nullptr; # endif diff --git a/src/workers/Worker.cpp b/src/workers/Worker.cpp index 4f69d905..0c61b3cb 100644 --- a/src/workers/Worker.cpp +++ b/src/workers/Worker.cpp @@ -5,7 +5,9 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , + * 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 @@ -38,7 +40,6 @@ Worker::Worker(ThreadHandle *handle) : m_hashCount(0), m_timestamp(0), m_count(0), - m_sequence(0), m_thread(static_cast(handle->config())) { if (xmrig::Cpu::info()->threads() > 1 && m_thread->affinity() != -1L) { diff --git a/src/workers/Worker.h b/src/workers/Worker.h index 3d40257d..13e437d3 100644 --- a/src/workers/Worker.h +++ b/src/workers/Worker.h @@ -5,7 +5,9 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , + * 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 @@ -61,7 +63,6 @@ protected: std::atomic m_hashCount; std::atomic m_timestamp; uint64_t m_count; - uint64_t m_sequence; xmrig::CpuThreadLegacy *m_thread; }; diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index 58cccd9e..1ed27c40 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -33,6 +33,7 @@ #include "base/tools/Handle.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "crypto/common/Nonce.h" #include "crypto/rx/RxAlgo.h" #include "crypto/rx/RxCache.h" #include "crypto/rx/RxDataset.h" @@ -51,7 +52,6 @@ Hashrate *Workers::m_hashrate = nullptr; xmrig::Job Workers::m_job; Workers::LaunchStatus Workers::m_status; std::atomic Workers::m_paused; -std::atomic Workers::m_sequence; std::vector Workers::m_workers; uint64_t Workers::m_ticks = 0; uv_mutex_t Workers::m_mutex; @@ -90,6 +90,15 @@ size_t Workers::threads() } +void Workers::pause() +{ + m_active = false; + m_paused = 1; + + xmrig::Nonce::touch(); +} + + void Workers::printHashrate(bool detail) { assert(m_controller != nullptr); @@ -134,7 +143,7 @@ void Workers::setEnabled(bool enabled) } m_paused = enabled ? 0 : 1; - m_sequence++; + xmrig::Nonce::touch(); } @@ -146,6 +155,9 @@ void Workers::setJob(const xmrig::Job &job, bool donate) if (donate) { m_job.setPoolId(-1); } + + xmrig::Nonce::reset(donate ? 1 : 0); + uv_rwlock_wrunlock(&m_rwlock); m_active = true; @@ -153,7 +165,6 @@ void Workers::setJob(const xmrig::Job &job, bool donate) return; } - m_sequence++; m_paused = 0; } @@ -183,7 +194,6 @@ void Workers::start(xmrig::Controller *controller) uv_mutex_init(&m_mutex); uv_rwlock_init(&m_rwlock); - m_sequence = 1; m_paused = 1; m_timer = new uv_timer_t; @@ -208,7 +218,8 @@ void Workers::stop() m_hashrate->stop(); m_paused = 0; - m_sequence = 0; + + xmrig::Nonce::stop(); for (size_t i = 0; i < m_workers.size(); ++i) { m_workers[i]->join(); diff --git a/src/workers/Workers.h b/src/workers/Workers.h index 8619f973..83777d0d 100644 --- a/src/workers/Workers.h +++ b/src/workers/Workers.h @@ -53,21 +53,19 @@ namespace xmrig { class Workers { public: - static xmrig::Job job(); static size_t hugePages(); static size_t threads(); + static void pause(); static void printHashrate(bool detail); static void setEnabled(bool enabled); static void setJob(const xmrig::Job &job, bool donate); static void start(xmrig::Controller *controller); static void stop(); + static xmrig::Job job(); static inline bool isEnabled() { return m_enabled; } - static inline bool isOutdated(uint64_t sequence) { return m_sequence.load(std::memory_order_relaxed) != sequence; } static inline bool isPaused() { return m_paused.load(std::memory_order_relaxed) == 1; } static inline Hashrate *hashrate() { return m_hashrate; } - static inline uint64_t sequence() { return m_sequence.load(std::memory_order_relaxed); } - static inline void pause() { m_active = false; m_paused = 1; m_sequence++; } # ifdef XMRIG_FEATURE_API static void threadsSummary(rapidjson::Document &doc); @@ -103,7 +101,6 @@ private: static xmrig::Job m_job; static LaunchStatus m_status; static std::atomic m_paused; - static std::atomic m_sequence; static std::vector m_workers; static uint64_t m_ticks; static uv_mutex_t m_mutex; From be7ff62c48adcf2644a48c3c494132bd13a913f9 Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 12 Jul 2019 02:25:07 +0700 Subject: [PATCH 25/65] Removed no longer required code. --- src/workers/ThreadHandle.cpp | 4 +--- src/workers/ThreadHandle.h | 6 +----- src/workers/Worker.cpp | 2 -- src/workers/Worker.h | 2 -- src/workers/Workers.cpp | 5 +---- 5 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/workers/ThreadHandle.cpp b/src/workers/ThreadHandle.cpp index 43ff950c..ced5f326 100644 --- a/src/workers/ThreadHandle.cpp +++ b/src/workers/ThreadHandle.cpp @@ -26,10 +26,8 @@ #include "workers/ThreadHandle.h" -ThreadHandle::ThreadHandle(xmrig::IThread *config, uint32_t offset, size_t totalWays) : +ThreadHandle::ThreadHandle(xmrig::IThread *config) : m_worker(nullptr), - m_totalWays(totalWays), - m_offset(offset), m_config(config) { } diff --git a/src/workers/ThreadHandle.h b/src/workers/ThreadHandle.h index f3e09ce5..c32aabf0 100644 --- a/src/workers/ThreadHandle.h +++ b/src/workers/ThreadHandle.h @@ -40,21 +40,17 @@ class IWorker; class ThreadHandle { public: - ThreadHandle(xmrig::IThread *config, uint32_t offset, size_t totalWays); + ThreadHandle(xmrig::IThread *config); void join(); void start(void (*callback) (void *)); inline IWorker *worker() const { return m_worker; } inline size_t threadId() const { return m_config->index(); } - inline size_t totalWays() const { return m_totalWays; } - inline uint32_t offset() const { return m_offset; } inline void setWorker(IWorker *worker) { assert(worker != nullptr); m_worker = worker; } inline xmrig::IThread *config() const { return m_config; } private: IWorker *m_worker; - size_t m_totalWays; - uint32_t m_offset; uv_thread_t m_thread; xmrig::IThread *m_config; }; diff --git a/src/workers/Worker.cpp b/src/workers/Worker.cpp index 0c61b3cb..3a9b693d 100644 --- a/src/workers/Worker.cpp +++ b/src/workers/Worker.cpp @@ -35,8 +35,6 @@ Worker::Worker(ThreadHandle *handle) : m_id(handle->threadId()), - m_totalWays(handle->totalWays()), - m_offset(handle->offset()), m_hashCount(0), m_timestamp(0), m_count(0), diff --git a/src/workers/Worker.h b/src/workers/Worker.h index 13e437d3..997771b0 100644 --- a/src/workers/Worker.h +++ b/src/workers/Worker.h @@ -57,8 +57,6 @@ protected: void storeStats(); const size_t m_id; - const size_t m_totalWays; - const uint32_t m_offset; MemInfo m_memory; std::atomic m_hashCount; std::atomic m_timestamp; diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index 1ed27c40..72d9a1d1 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -200,11 +200,8 @@ void Workers::start(xmrig::Controller *controller) uv_timer_init(uv_default_loop(), m_timer); uv_timer_start(m_timer, Workers::onTick, 500, 500); - uint32_t offset = 0; - for (xmrig::IThread *thread : threads) { - ThreadHandle *handle = new ThreadHandle(thread, offset, m_status.ways); - offset += thread->multiway(); + ThreadHandle *handle = new ThreadHandle(thread); m_workers.push_back(handle); handle->start(Workers::onReady); From 4643742d13c08d2e95934cf68223976011f655fe Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 13 Jul 2019 00:49:17 +0700 Subject: [PATCH 26/65] Refactoring --- src/base/net/stratum/Client.cpp | 4 +-- src/base/net/stratum/DaemonClient.cpp | 2 +- src/base/net/stratum/Job.cpp | 13 +------ src/base/net/stratum/Job.h | 18 +++++----- src/core/WorkerJob.h | 6 ++-- src/net/JobResult.h | 50 ++++++++++----------------- src/net/Network.cpp | 2 +- src/workers/MultiWorker.cpp | 2 +- src/workers/Workers.cpp | 6 ++-- 9 files changed, 39 insertions(+), 64 deletions(-) diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 63123720..c1519573 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -162,7 +162,7 @@ int64_t xmrig::Client::submit(const JobResult &result) Buffer::toHex(reinterpret_cast(&result.nonce), 4, nonce); nonce[8] = '\0'; - Buffer::toHex(result.result, 32, data); + Buffer::toHex(result.result(), 32, data); data[64] = '\0'; # endif @@ -313,7 +313,7 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } - Job job(m_id, has(), m_pool.algorithm(), m_rpcId); + Job job(has(), m_pool.algorithm(), m_rpcId); if (!job.setId(params["job_id"].GetString())) { *code = 3; diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp index 70cc9151..0c141c7d 100644 --- a/src/base/net/stratum/DaemonClient.cpp +++ b/src/base/net/stratum/DaemonClient.cpp @@ -212,7 +212,7 @@ bool xmrig::DaemonClient::isOutdated(uint64_t height, const char *hash) const bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) { - Job job(m_id, false, m_pool.algorithm(), String()); + Job job(false, m_pool.algorithm(), String()); String blocktemplate = Json::getString(params, kBlocktemplateBlob); if (blocktemplate.isNull() || !job.setBlob(Json::getString(params, "blockhashing_blob"))) { diff --git a/src/base/net/stratum/Job.cpp b/src/base/net/stratum/Job.cpp index 7e846b3b..a383bbf7 100644 --- a/src/base/net/stratum/Job.cpp +++ b/src/base/net/stratum/Job.cpp @@ -34,27 +34,16 @@ xmrig::Job::Job() : - m_nicehash(false), - m_poolId(-2), - m_size(0), - m_diff(0), - m_height(0), - m_target(0), m_blob(), m_seedHash() { } -xmrig::Job::Job(int poolId, bool nicehash, const Algorithm &algorithm, const String &clientId) : +xmrig::Job::Job(bool nicehash, const Algorithm &algorithm, const String &clientId) : m_algorithm(algorithm), m_nicehash(nicehash), - m_poolId(poolId), - m_size(0), m_clientId(clientId), - m_diff(0), - m_height(0), - m_target(0), m_blob(), m_seedHash() { diff --git a/src/base/net/stratum/Job.h b/src/base/net/stratum/Job.h index c229f95c..06d1be79 100644 --- a/src/base/net/stratum/Job.h +++ b/src/base/net/stratum/Job.h @@ -47,7 +47,7 @@ public: static constexpr const size_t kMaxBlobSize = 128; Job(); - Job(int poolId, bool nicehash, const Algorithm &algorithm, const String &clientId); + Job(bool nicehash, const Algorithm &algorithm, const String &clientId); ~Job(); bool isEqual(const Job &other) const; @@ -65,18 +65,18 @@ public: inline const uint32_t *nonce() const { return reinterpret_cast(m_blob + 39); } inline const uint8_t *blob() const { return m_blob; } inline const uint8_t *seedHash() const { return m_seedHash; } - inline int poolId() const { return m_poolId; } inline size_t size() const { return m_size; } inline uint32_t *nonce() { return reinterpret_cast(m_blob + 39); } inline uint64_t diff() const { return m_diff; } inline uint64_t height() const { return m_height; } inline uint64_t target() const { return m_target; } 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 char *algo) { m_algorithm = algo; } inline void setClientId(const String &id) { m_clientId = id; } inline void setHeight(uint64_t height) { m_height = height; } - inline void setPoolId(int poolId) { m_poolId = poolId; } + inline void setIndex(uint8_t index) { m_index = index; } # ifdef XMRIG_PROXY_PROJECT inline char *rawBlob() { return m_rawBlob; } @@ -93,15 +93,15 @@ public: private: Algorithm m_algorithm; - bool m_nicehash; - int m_poolId; - size_t m_size; + bool m_nicehash = false; + size_t m_size = 0; String m_clientId; String m_id; - uint64_t m_diff; - uint64_t m_height; - uint64_t m_target; + uint64_t m_diff = 0; + uint64_t m_height = 0; + uint64_t m_target = 0; uint8_t m_blob[kMaxBlobSize]; + uint8_t m_index = 0; uint8_t m_seedHash[32]; # ifdef XMRIG_PROXY_PROJECT diff --git a/src/core/WorkerJob.h b/src/core/WorkerJob.h index 004c5533..7b598ee6 100644 --- a/src/core/WorkerJob.h +++ b/src/core/WorkerJob.h @@ -56,7 +56,7 @@ public: return; } - if (index() == 1 && job.poolId() >= 0 && job == m_jobs[0]) { + if (index() == 1 && job.index() == 0 && job == m_jobs[0]) { return; } @@ -84,7 +84,7 @@ public: private: inline void save(const Job &job, uint32_t reserveCount) { - m_index = job.poolId() == -1 ? 1 : 0; + m_index = job.index(); const size_t size = job.size(); m_jobs[index()] = job; m_rounds[index()] = 0; @@ -128,7 +128,7 @@ inline void xmrig::WorkerJob<1>::nextRound(uint32_t reserveCount) template<> inline void xmrig::WorkerJob<1>::save(const Job &job, uint32_t reserveCount) { - m_index = job.poolId() == -1 ? 1 : 0; + m_index = job.index(); m_jobs[index()] = job; m_rounds[index()] = 0; diff --git a/src/net/JobResult.h b/src/net/JobResult.h index 9fe1238e..2c2fded5 100644 --- a/src/net/JobResult.h +++ b/src/net/JobResult.h @@ -41,43 +41,31 @@ namespace xmrig { class JobResult { public: - inline JobResult() : poolId(0), nonce(0), diff(0) {} - inline JobResult(int poolId, const String &jobId, const String &clientId, uint32_t nonce, const uint8_t *result, uint64_t diff, const Algorithm &algorithm) : - algorithm(algorithm), - poolId(poolId), - clientId(clientId), - jobId(jobId), + inline JobResult() {} + + inline JobResult(const Job &job, uint32_t nonce, const uint8_t *result) : + algorithm(job.algorithm()), + clientId(job.clientId()), + jobId(job.id()), nonce(nonce), - diff(diff) + diff(job.diff()), + index(job.index()) { - memcpy(this->result, result, sizeof(this->result)); + memcpy(m_result, result, sizeof(m_result)); } + inline const uint8_t *result() const { return m_result; } + inline uint64_t actualDiff() const { return Job::toDiff(reinterpret_cast(m_result)[3]); } - inline JobResult(const Job &job) : poolId(0), nonce(0), diff(0) - { - jobId = job.id(); - clientId = job.clientId(); - poolId = job.poolId(); - diff = job.diff(); - nonce = *job.nonce(); - algorithm = job.algorithm(); - } + const Algorithm algorithm; + const String clientId; + const String jobId; + const uint32_t nonce = 0; + const uint64_t diff = 0; + const uint8_t index = 0; - - inline uint64_t actualDiff() const - { - return Job::toDiff(reinterpret_cast(result)[3]); - } - - - Algorithm algorithm; - int poolId; - String clientId; - String jobId; - uint32_t nonce; - uint64_t diff; - uint8_t result[32]; +private: + uint8_t m_result[32]; }; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index c08facb9..d40bebd1 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -144,7 +144,7 @@ void xmrig::Network::onJob(IStrategy *strategy, IClient *client, const Job &job) void xmrig::Network::onJobResult(const JobResult &result) { - if (result.poolId == -1 && m_donate) { + if (result.index == 1 && m_donate) { m_donate->submit(result); return; } diff --git a/src/workers/MultiWorker.cpp b/src/workers/MultiWorker.cpp index daae9230..1f06455a 100644 --- a/src/workers/MultiWorker.cpp +++ b/src/workers/MultiWorker.cpp @@ -173,7 +173,7 @@ void xmrig::MultiWorker::start() for (size_t i = 0; i < N; ++i) { if (*reinterpret_cast(m_hash + (i * 32) + 24) < job.target()) { - JobResults::submit(JobResult(job.poolId(), job.id(), job.clientId(), *m_job.nonce(i), m_hash + (i * 32), job.diff(), job.algorithm())); + JobResults::submit(JobResult(job, *m_job.nonce(i), m_hash + (i * 32))); } } diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index 72d9a1d1..53a8b712 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -150,11 +150,9 @@ void Workers::setEnabled(bool enabled) void Workers::setJob(const xmrig::Job &job, bool donate) { uv_rwlock_wrlock(&m_rwlock); - m_job = job; - if (donate) { - m_job.setPoolId(-1); - } + m_job = job; + m_job.setIndex(donate ? 1 : 0); xmrig::Nonce::reset(donate ? 1 : 0); From 8b3f2d8fff01b230b47f54dfcbd12ef66beab274 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 13 Jul 2019 16:48:14 +0700 Subject: [PATCH 27/65] Move Platform. --- CMakeLists.txt | 5 ----- src/App.cpp | 1 - src/api/v1/ApiRouter.cpp | 2 +- src/base/base.cmake | 17 +++++++++++++++-- src/base/kernel/Base.cpp | 2 +- src/{common => base/kernel}/Platform.cpp | 0 src/{common => base/kernel}/Platform.h | 9 +++++++++ src/{common => base/kernel}/Platform_mac.cpp | 0 src/{common => base/kernel}/Platform_unix.cpp | 0 src/{common => base/kernel}/Platform_win.cpp | 0 src/base/net/http/HttpClient.cpp | 2 +- .../net/stratum/strategies/FailoverStrategy.cpp | 2 +- .../stratum/strategies/SinglePoolStrategy.cpp | 2 +- src/core/Controller.cpp | 1 - src/net/strategies/DonateStrategy.cpp | 2 +- src/workers/Worker.cpp | 2 +- 16 files changed, 31 insertions(+), 16 deletions(-) rename src/{common => base/kernel}/Platform.cpp (100%) rename src/{common => base/kernel}/Platform.h (90%) rename src/{common => base/kernel}/Platform_mac.cpp (100%) rename src/{common => base/kernel}/Platform_unix.cpp (100%) rename src/{common => base/kernel}/Platform_win.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 13f787f7..a6adda76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,6 @@ set(HEADERS "${HEADERS_BACKEND}" src/api/interfaces/IApiListener.h src/App.h - src/common/Platform.h src/common/xmrig.h src/core/config/Config_default.h src/core/config/Config_platform.h @@ -88,7 +87,6 @@ set(SOURCES "${SOURCES_BASE_HTTP}" "${SOURCES_BACKEND}" src/App.cpp - src/common/Platform.cpp src/core/config/Config.cpp src/core/config/ConfigTransform.cpp src/core/Controller.cpp @@ -123,7 +121,6 @@ if (WIN32) "${SOURCES_OS}" res/app.rc src/App_win.cpp - src/common/Platform_win.cpp src/Mem_win.cpp src/crypto/common/VirtualMemory_win.cpp ) @@ -134,7 +131,6 @@ elseif (APPLE) set(SOURCES_OS "${SOURCES_OS}" src/App_unix.cpp - src/common/Platform_mac.cpp src/Mem_unix.cpp src/crypto/common/VirtualMemory_unix.cpp ) @@ -142,7 +138,6 @@ else() set(SOURCES_OS "${SOURCES_OS}" src/App_unix.cpp - src/common/Platform_unix.cpp src/Mem_unix.cpp src/crypto/common/VirtualMemory_unix.cpp ) diff --git a/src/App.cpp b/src/App.cpp index 6e42ac30..5b2178ac 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -34,7 +34,6 @@ #include "base/io/Console.h" #include "base/io/log/Log.h" #include "base/kernel/Signals.h" -#include "common/Platform.h" #include "core/config/Config.h" #include "core/Controller.h" #include "Mem.h" diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp index ff1ef404..18d97fda 100644 --- a/src/api/v1/ApiRouter.cpp +++ b/src/api/v1/ApiRouter.cpp @@ -31,7 +31,7 @@ #include "api/v1/ApiRouter.h" #include "backend/cpu/Cpu.h" #include "base/kernel/Base.h" -#include "common/Platform.h" +#include "base/kernel/Platform.h" #include "core/config/Config.h" #include "interfaces/IThread.h" #include "rapidjson/document.h" diff --git a/src/base/base.cmake b/src/base/base.cmake index dcc10495..b25d9743 100644 --- a/src/base/base.cmake +++ b/src/base/base.cmake @@ -26,6 +26,7 @@ set(HEADERS_BASE src/base/kernel/interfaces/IStrategyListener.h src/base/kernel/interfaces/ITimerListener.h src/base/kernel/interfaces/IWatcherListener.h + src/base/kernel/Platform.h src/base/kernel/Process.h src/base/kernel/Signals.h src/base/net/dns/Dns.h @@ -63,6 +64,7 @@ set(SOURCES_BASE src/base/kernel/config/BaseConfig.cpp src/base/kernel/config/BaseTransform.cpp src/base/kernel/Entry.cpp + src/base/kernel/Platform.cpp src/base/kernel/Process.cpp src/base/kernel/Signals.cpp src/base/net/dns/Dns.cpp @@ -83,9 +85,20 @@ set(SOURCES_BASE if (WIN32) - set(SOURCES_OS src/base/io/json/Json_win.cpp) + set(SOURCES_OS + src/base/io/json/Json_win.cpp + src/base/kernel/Platform_win.cpp + ) +elseif (APPLE) + set(SOURCES_OS + src/base/io/json/Json_unix.cpp + src/base/kernel/Platform_mac.cpp + ) else() - set(SOURCES_OS src/base/io/json/Json_unix.cpp) + set(SOURCES_OS + src/base/io/json/Json_unix.cpp + src/base/kernel//Platform_unix.cpp + ) endif() diff --git a/src/base/kernel/Base.cpp b/src/base/kernel/Base.cpp index 031daed7..46f32684 100644 --- a/src/base/kernel/Base.cpp +++ b/src/base/kernel/Base.cpp @@ -35,8 +35,8 @@ #include "base/io/Watcher.h" #include "base/kernel/Base.h" #include "base/kernel/interfaces/IBaseListener.h" +#include "base/kernel/Platform.h" #include "base/kernel/Process.h" -#include "common/Platform.h" #include "core/config/Config.h" #include "core/config/ConfigTransform.h" diff --git a/src/common/Platform.cpp b/src/base/kernel/Platform.cpp similarity index 100% rename from src/common/Platform.cpp rename to src/base/kernel/Platform.cpp diff --git a/src/common/Platform.h b/src/base/kernel/Platform.h similarity index 90% rename from src/common/Platform.h rename to src/base/kernel/Platform.h index 85f08a2e..f3c2c719 100644 --- a/src/common/Platform.h +++ b/src/base/kernel/Platform.h @@ -35,6 +35,15 @@ class Platform { public: + static inline bool trySetThreadAffinity(int64_t cpu_id) + { + if (cpu_id < 0) { + return false; + } + + return setThreadAffinity(static_cast(cpu_id)); + } + static bool setThreadAffinity(uint64_t cpu_id); static uint32_t setTimerResolution(uint32_t resolution); static void init(const char *userAgent); diff --git a/src/common/Platform_mac.cpp b/src/base/kernel/Platform_mac.cpp similarity index 100% rename from src/common/Platform_mac.cpp rename to src/base/kernel/Platform_mac.cpp diff --git a/src/common/Platform_unix.cpp b/src/base/kernel/Platform_unix.cpp similarity index 100% rename from src/common/Platform_unix.cpp rename to src/base/kernel/Platform_unix.cpp diff --git a/src/common/Platform_win.cpp b/src/base/kernel/Platform_win.cpp similarity index 100% rename from src/common/Platform_win.cpp rename to src/base/kernel/Platform_win.cpp diff --git a/src/base/net/http/HttpClient.cpp b/src/base/net/http/HttpClient.cpp index 319bb4dd..113e2f13 100644 --- a/src/base/net/http/HttpClient.cpp +++ b/src/base/net/http/HttpClient.cpp @@ -29,10 +29,10 @@ #include "3rdparty/http-parser/http_parser.h" #include "base/io/log/Log.h" +#include "base/kernel/Platform.h" #include "base/net/dns/Dns.h" #include "base/net/http/HttpClient.h" #include "base/tools/Baton.h" -#include "common/Platform.h" namespace xmrig { diff --git a/src/base/net/stratum/strategies/FailoverStrategy.cpp b/src/base/net/stratum/strategies/FailoverStrategy.cpp index d5247229..9545e9e1 100644 --- a/src/base/net/stratum/strategies/FailoverStrategy.cpp +++ b/src/base/net/stratum/strategies/FailoverStrategy.cpp @@ -24,9 +24,9 @@ #include "base/kernel/interfaces/IStrategyListener.h" +#include "base/kernel/Platform.h" #include "base/net/stratum/Client.h" #include "base/net/stratum/strategies/FailoverStrategy.h" -#include "common/Platform.h" #ifdef XMRIG_FEATURE_HTTP diff --git a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp index f432514e..6c6a6fc1 100644 --- a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp +++ b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp @@ -24,9 +24,9 @@ #include "base/kernel/interfaces/IStrategyListener.h" +#include "base/kernel/Platform.h" #include "base/net/stratum/Client.h" #include "base/net/stratum/strategies/SinglePoolStrategy.h" -#include "common/Platform.h" #ifdef XMRIG_FEATURE_HTTP diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index 8e2e03a1..81c67d7c 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -27,7 +27,6 @@ #include "backend/cpu/Cpu.h" -#include "common/Platform.h" #include "core/Controller.h" #include "net/Network.h" diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index 9669db9a..78c7acc5 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -26,13 +26,13 @@ #include +#include "base/kernel/Platform.h" #include "base/net/stratum/Client.h" #include "base/net/stratum/Job.h" #include "base/net/stratum/strategies/FailoverStrategy.h" #include "base/net/stratum/strategies/SinglePoolStrategy.h" #include "base/tools/Buffer.h" #include "base/tools/Timer.h" -#include "common/Platform.h" #include "common/xmrig.h" #include "core/config/Config.h" #include "core/Controller.h" diff --git a/src/workers/Worker.cpp b/src/workers/Worker.cpp index 3a9b693d..d85858af 100644 --- a/src/workers/Worker.cpp +++ b/src/workers/Worker.cpp @@ -27,7 +27,7 @@ #include "backend/cpu/Cpu.h" -#include "common/Platform.h" +#include "base/kernel/Platform.h" #include "workers/CpuThreadLegacy.h" #include "workers/ThreadHandle.h" #include "workers/Worker.h" From dc87ef60620b48ef9b3482583380850ff32bcc2d Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 13 Jul 2019 19:10:17 +0700 Subject: [PATCH 28/65] Removed xmrig.h. --- CMakeLists.txt | 1 - src/Mem_unix.cpp | 1 - src/Mem_win.cpp | 1 - src/base/kernel/config/BaseConfig.h | 1 - src/common/xmrig.h | 78 --------------------------- src/core/config/Config.cpp | 20 +++---- src/core/config/Config.h | 9 ++-- src/crypto/cn/CnHash.h | 16 +++++- src/crypto/cn/CryptoNight_monero.h | 1 - src/crypto/common/Assembly.h | 1 - src/net/strategies/DonateStrategy.cpp | 1 - src/workers/CpuThreadLegacy.cpp | 38 ++++++------- src/workers/CpuThreadLegacy.h | 11 ++-- 13 files changed, 53 insertions(+), 126 deletions(-) delete mode 100644 src/common/xmrig.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a6adda76..48946c7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,6 @@ set(HEADERS "${HEADERS_BACKEND}" src/api/interfaces/IApiListener.h src/App.h - src/common/xmrig.h src/core/config/Config_default.h src/core/config/Config_platform.h src/core/config/Config.h diff --git a/src/Mem_unix.cpp b/src/Mem_unix.cpp index 9bdce0f5..4dc13e93 100644 --- a/src/Mem_unix.cpp +++ b/src/Mem_unix.cpp @@ -29,7 +29,6 @@ #include "base/io/log/Log.h" -#include "common/xmrig.h" #include "crypto/common/portable/mm_malloc.h" #include "crypto/common/VirtualMemory.h" #include "crypto/cn/CryptoNight.h" diff --git a/src/Mem_win.cpp b/src/Mem_win.cpp index 34460e9d..56b4521d 100644 --- a/src/Mem_win.cpp +++ b/src/Mem_win.cpp @@ -31,7 +31,6 @@ #include "base/io/log/Log.h" -#include "common/xmrig.h" #include "crypto/common/portable/mm_malloc.h" #include "crypto/common/VirtualMemory.h" #include "crypto/cn/CryptoNight.h" diff --git a/src/base/kernel/config/BaseConfig.h b/src/base/kernel/config/BaseConfig.h index 48d7c2cf..c5cf29a3 100644 --- a/src/base/kernel/config/BaseConfig.h +++ b/src/base/kernel/config/BaseConfig.h @@ -29,7 +29,6 @@ #include "base/kernel/interfaces/IConfig.h" #include "base/net/http/Http.h" #include "base/net/stratum/Pools.h" -#include "common/xmrig.h" struct option; diff --git a/src/common/xmrig.h b/src/common/xmrig.h deleted file mode 100644 index 169c4c1f..00000000 --- a/src/common/xmrig.h +++ /dev/null @@ -1,78 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef XMRIG_XMRIG_H -#define XMRIG_XMRIG_H - - -namespace xmrig -{ - - -//--av=1 For CPUs with hardware AES. -//--av=2 Lower power mode (double hash) of 1. -//--av=3 Software AES implementation. -//--av=4 Lower power mode (double hash) of 3. -enum AlgoVariant { - AV_AUTO, // --av=0 Automatic mode. - AV_SINGLE, // --av=1 Single hash mode - AV_DOUBLE, // --av=2 Double hash mode - AV_SINGLE_SOFT, // --av=3 Single hash mode (Software AES) - AV_DOUBLE_SOFT, // --av=4 Double hash mode (Software AES) - AV_TRIPLE, // --av=5 Triple hash mode - AV_QUAD, // --av=6 Quard hash mode - AV_PENTA, // --av=7 Penta hash mode - AV_TRIPLE_SOFT, // --av=8 Triple hash mode (Software AES) - AV_QUAD_SOFT, // --av=9 Quard hash mode (Software AES) - AV_PENTA_SOFT, // --av=10 Penta hash mode (Software AES) - AV_MAX -}; - - -enum AlgoVerify { - VERIFY_HW_AES = 1, - VERIFY_SOFT_AES = 2 -}; - - -enum AesMode { - AES_AUTO, - AES_HW, - AES_SOFT -}; - - -enum OclVendor { - OCL_VENDOR_UNKNOWN = -2, - OCL_VENDOR_MANUAL = -1, - OCL_VENDOR_AMD = 0, - OCL_VENDOR_NVIDIA = 1, - OCL_VENDOR_INTEL = 2 -}; - - -} /* namespace xmrig */ - - -#endif /* XMRIG_XMRIG_H */ diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 784e171c..02ef9c90 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -40,7 +40,7 @@ xmrig::Config::Config() : - m_algoVariant(AV_AUTO), + m_algoVariant(CnHash::AV_AUTO), m_shouldSave(false) { } @@ -131,7 +131,7 @@ bool xmrig::Config::finalize() return true; } - const AlgoVariant av = getAlgoVariant(); + const CnHash::AlgoVariant av = getAlgoVariant(); m_threads.mode = m_threads.count ? Simple : Automatic; const size_t size = CpuThreadLegacy::multiway(av) * CnAlgo<>::memory(algorithm) / 1024; // FIXME MEMORY @@ -158,8 +158,8 @@ bool xmrig::Config::finalize() void xmrig::Config::setAlgoVariant(int av) { - if (av >= AV_AUTO && av < AV_MAX) { - m_algoVariant = static_cast(av); + if (av >= CnHash::AV_AUTO && av < CnHash::AV_MAX) { + m_algoVariant = static_cast(av); } } @@ -192,7 +192,7 @@ void xmrig::Config::setThreads(const rapidjson::Value &threads) } -xmrig::AlgoVariant xmrig::Config::getAlgoVariant() const +xmrig::CnHash::AlgoVariant xmrig::Config::getAlgoVariant() const { # ifdef XMRIG_ALGO_CN_LITE // if (m_algorithm.algo() == xmrig::CRYPTONIGHT_LITE) { // FIXME @@ -200,8 +200,8 @@ xmrig::AlgoVariant xmrig::Config::getAlgoVariant() const // } # endif - if (m_algoVariant <= AV_AUTO || m_algoVariant >= AV_MAX) { - return Cpu::info()->hasAES() ? AV_SINGLE : AV_SINGLE_SOFT; + if (m_algoVariant <= CnHash::AV_AUTO || m_algoVariant >= CnHash::AV_MAX) { + return Cpu::info()->hasAES() ? CnHash::AV_SINGLE : CnHash::AV_SINGLE_SOFT; } // if (m_safe && !Cpu::info()->hasAES() && m_algoVariant <= AV_DOUBLE) { @@ -213,10 +213,10 @@ xmrig::AlgoVariant xmrig::Config::getAlgoVariant() const #ifdef XMRIG_ALGO_CN_LITE -xmrig::AlgoVariant xmrig::Config::getAlgoVariantLite() const +xmrig::CnHash::AlgoVariant xmrig::Config::getAlgoVariantLite() const { - if (m_algoVariant <= AV_AUTO || m_algoVariant >= AV_MAX) { - return Cpu::info()->hasAES() ? AV_DOUBLE : AV_DOUBLE_SOFT; + if (m_algoVariant <= CnHash::AV_AUTO || m_algoVariant >= CnHash::AV_MAX) { + return Cpu::info()->hasAES() ? CnHash::AV_DOUBLE : CnHash::AV_DOUBLE_SOFT; } // if (m_safe && !Cpu::info()->hasAES() && m_algoVariant <= AV_DOUBLE) { diff --git a/src/core/config/Config.h b/src/core/config/Config.h index 7b765892..aa547796 100644 --- a/src/core/config/Config.h +++ b/src/core/config/Config.h @@ -32,7 +32,6 @@ #include "backend/cpu/CpuConfig.h" #include "base/kernel/config/BaseConfig.h" -#include "common/xmrig.h" #include "rapidjson/fwd.h" #include "workers/CpuThreadLegacy.h" @@ -58,7 +57,7 @@ public: bool read(const IJsonReader &reader, const char *fileName) override; void getJSON(rapidjson::Document &doc) const override; - inline AlgoVariant algoVariant() const { return m_algoVariant; } + inline CnHash::AlgoVariant algoVariant() const { return m_algoVariant; } inline bool isShouldSave() const { return (m_shouldSave || m_upgrade || m_cpu.isShouldSave()) && isAutoSave(); } inline const CpuConfig &cpu() const { return m_cpu; } inline const std::vector &threads() const { return m_threads.list; } @@ -70,9 +69,9 @@ private: void setAlgoVariant(int av); void setThreads(const rapidjson::Value &threads); - AlgoVariant getAlgoVariant() const; + CnHash::AlgoVariant getAlgoVariant() const; # ifdef XMRIG_ALGO_CN_LITE - AlgoVariant getAlgoVariantLite() const; + CnHash::AlgoVariant getAlgoVariantLite() const; # endif struct Threads @@ -87,7 +86,7 @@ private: }; - AlgoVariant m_algoVariant; + CnHash::AlgoVariant m_algoVariant; bool m_shouldSave; CpuConfig m_cpu; Threads m_threads; diff --git a/src/crypto/cn/CnHash.h b/src/crypto/cn/CnHash.h index b57bff4c..fdfcc9f3 100644 --- a/src/crypto/cn/CnHash.h +++ b/src/crypto/cn/CnHash.h @@ -31,7 +31,6 @@ #include -#include "common/xmrig.h" #include "crypto/cn/CnAlgo.h" #include "crypto/common/Assembly.h" @@ -49,6 +48,21 @@ typedef void (*cn_mainloop_fun)(cryptonight_ctx **ctx); class CnHash { public: + enum AlgoVariant { + AV_AUTO, // --av=0 Automatic mode. + AV_SINGLE, // --av=1 Single hash mode + AV_DOUBLE, // --av=2 Double hash mode + AV_SINGLE_SOFT, // --av=3 Single hash mode (Software AES) + AV_DOUBLE_SOFT, // --av=4 Double hash mode (Software AES) + AV_TRIPLE, // --av=5 Triple hash mode + AV_QUAD, // --av=6 Quard hash mode + AV_PENTA, // --av=7 Penta hash mode + AV_TRIPLE_SOFT, // --av=8 Triple hash mode (Software AES) + AV_QUAD_SOFT, // --av=9 Quard hash mode (Software AES) + AV_PENTA_SOFT, // --av=10 Penta hash mode (Software AES) + AV_MAX + }; + CnHash(); cn_hash_fun fn(const Algorithm &algorithm, AlgoVariant av, Assembly::Id assembly) const; diff --git a/src/crypto/cn/CryptoNight_monero.h b/src/crypto/cn/CryptoNight_monero.h index 13948dcd..dc012bdc 100644 --- a/src/crypto/cn/CryptoNight_monero.h +++ b/src/crypto/cn/CryptoNight_monero.h @@ -178,7 +178,6 @@ #endif #endif -#include "common/xmrig.h" #include "crypto/cn/r/variant4_random_math.h" #define VARIANT4_RANDOM_MATH_INIT(part) \ diff --git a/src/crypto/common/Assembly.h b/src/crypto/common/Assembly.h index afd8a536..5ea29e11 100644 --- a/src/crypto/common/Assembly.h +++ b/src/crypto/common/Assembly.h @@ -26,7 +26,6 @@ #define XMRIG_ASSEMBLY_H -#include "common/xmrig.h" #include "rapidjson/fwd.h" diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index 78c7acc5..2d0a5b43 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -33,7 +33,6 @@ #include "base/net/stratum/strategies/SinglePoolStrategy.h" #include "base/tools/Buffer.h" #include "base/tools/Timer.h" -#include "common/xmrig.h" #include "core/config/Config.h" #include "core/Controller.h" #include "crypto/common/keccak.h" diff --git a/src/workers/CpuThreadLegacy.cpp b/src/workers/CpuThreadLegacy.cpp index df9b9904..b8e33839 100644 --- a/src/workers/CpuThreadLegacy.cpp +++ b/src/workers/CpuThreadLegacy.cpp @@ -38,7 +38,7 @@ static const xmrig::CnHash cnHash; -xmrig::CpuThreadLegacy::CpuThreadLegacy(size_t index, Algorithm algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly) : +xmrig::CpuThreadLegacy::CpuThreadLegacy(size_t index, Algorithm algorithm, CnHash::AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly) : m_algorithm(algorithm), m_av(av), m_assembly(assembly), @@ -59,15 +59,15 @@ xmrig::cn_hash_fun xmrig::CpuThreadLegacy::fn(const Algorithm &algorithm) const -bool xmrig::CpuThreadLegacy::isSoftAES(AlgoVariant av) +bool xmrig::CpuThreadLegacy::isSoftAES(CnHash::AlgoVariant av) { - return av == AV_SINGLE_SOFT || av == AV_DOUBLE_SOFT || av > AV_PENTA; + return av == CnHash::AV_SINGLE_SOFT || av == CnHash::AV_DOUBLE_SOFT || av > CnHash::AV_PENTA; } -xmrig::CpuThreadLegacy *xmrig::CpuThreadLegacy::createFromAV(size_t index, const Algorithm &algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly) +xmrig::CpuThreadLegacy *xmrig::CpuThreadLegacy::createFromAV(size_t index, const Algorithm &algorithm, CnHash::AlgoVariant av, int64_t affinity, int priority, Assembly assembly) { - assert(av > AV_AUTO && av < AV_MAX); + assert(av > CnHash::AV_AUTO && av < CnHash::AV_MAX); int64_t cpuId = -1L; @@ -94,7 +94,7 @@ xmrig::CpuThreadLegacy *xmrig::CpuThreadLegacy::createFromAV(size_t index, const xmrig::CpuThreadLegacy *xmrig::CpuThreadLegacy::createFromData(size_t index, const Algorithm &algorithm, const CpuThreadLegacy::Data &data, int priority, bool softAES) { - int av = AV_AUTO; + int av = CnHash::AV_AUTO; const Multiway multiway = data.multiway; if (multiway <= DoubleWay) { @@ -104,9 +104,9 @@ xmrig::CpuThreadLegacy *xmrig::CpuThreadLegacy::createFromData(size_t index, con av = softAES ? (multiway + 5) : (multiway + 2); } - assert(av > AV_AUTO && av < AV_MAX); + assert(av > CnHash::AV_AUTO && av < CnHash::AV_MAX); - return new CpuThreadLegacy(index, algorithm, static_cast(av), multiway, data.affinity, priority, softAES, false, data.assembly); + return new CpuThreadLegacy(index, algorithm, static_cast(av), multiway, data.affinity, priority, softAES, false, data.assembly); } @@ -140,27 +140,27 @@ xmrig::CpuThreadLegacy::Data xmrig::CpuThreadLegacy::parse(const rapidjson::Valu } -xmrig::IThread::Multiway xmrig::CpuThreadLegacy::multiway(AlgoVariant av) +xmrig::IThread::Multiway xmrig::CpuThreadLegacy::multiway(CnHash::AlgoVariant av) { switch (av) { - case AV_SINGLE: - case AV_SINGLE_SOFT: + case CnHash::AV_SINGLE: + case CnHash::AV_SINGLE_SOFT: return SingleWay; - case AV_DOUBLE_SOFT: - case AV_DOUBLE: + case CnHash::AV_DOUBLE_SOFT: + case CnHash::AV_DOUBLE: return DoubleWay; - case AV_TRIPLE_SOFT: - case AV_TRIPLE: + case CnHash::AV_TRIPLE_SOFT: + case CnHash::AV_TRIPLE: return TripleWay; - case AV_QUAD_SOFT: - case AV_QUAD: + case CnHash::AV_QUAD_SOFT: + case CnHash::AV_QUAD: return QuadWay; - case AV_PENTA_SOFT: - case AV_PENTA: + case CnHash::AV_PENTA_SOFT: + case CnHash::AV_PENTA: return PentaWay; default: diff --git a/src/workers/CpuThreadLegacy.h b/src/workers/CpuThreadLegacy.h index ed69d8ac..4553295c 100644 --- a/src/workers/CpuThreadLegacy.h +++ b/src/workers/CpuThreadLegacy.h @@ -26,7 +26,6 @@ #define XMRIG_CPUTHREADLEGACY_H -#include "common/xmrig.h" #include "crypto/cn/CnHash.h" #include "interfaces/IThread.h" @@ -59,15 +58,15 @@ public: }; - CpuThreadLegacy(size_t index, Algorithm algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly); + CpuThreadLegacy(size_t index, Algorithm algorithm, CnHash::AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly); cn_hash_fun fn(const Algorithm &algorithm) const; - static bool isSoftAES(AlgoVariant av); - static CpuThreadLegacy *createFromAV(size_t index, const Algorithm &algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly); + static bool isSoftAES(CnHash::AlgoVariant av); + static CpuThreadLegacy *createFromAV(size_t index, const Algorithm &algorithm, CnHash::AlgoVariant av, int64_t affinity, int priority, Assembly assembly); static CpuThreadLegacy *createFromData(size_t index, const Algorithm &algorithm, const CpuThreadLegacy::Data &data, int priority, bool softAES); static Data parse(const rapidjson::Value &object); - static Multiway multiway(AlgoVariant av); + static Multiway multiway(CnHash::AlgoVariant av); inline bool isPrefetch() const { return m_prefetch; } inline bool isSoftAES() const { return m_softAES; } @@ -92,7 +91,7 @@ protected: private: const Algorithm m_algorithm; - const AlgoVariant m_av; + const CnHash::AlgoVariant m_av; const Assembly m_assembly; const bool m_prefetch; const bool m_softAES; From ee434a57081b7c61b13b54ab49518a2fc5f23b0b Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 13 Jul 2019 22:15:53 +0700 Subject: [PATCH 29/65] Move files. --- CMakeLists.txt | 7 ----- src/api/v1/ApiRouter.cpp | 2 +- src/backend/backend.cmake | 9 +++--- src/backend/{ => common}/Threads.cpp | 2 +- src/backend/{ => common}/Threads.h | 0 src/{workers => backend/common}/Worker.cpp | 2 +- src/{workers => backend/common}/Worker.h | 2 +- src/{core => backend/common}/WorkerJob.h | 0 src/backend/common/common.cmake | 12 ++++++++ src/{ => backend/common}/interfaces/IThread.h | 0 src/{ => backend/common}/interfaces/IWorker.h | 0 src/backend/cpu/CpuConfig.h | 2 +- .../cpu/CpuWorker.cpp} | 30 +++++++++---------- .../MultiWorker.h => backend/cpu/CpuWorker.h} | 27 ++++++++++++----- src/backend/cpu/cpu.cmake | 12 ++++---- src/workers/CpuThreadLegacy.h | 2 +- src/workers/ThreadHandle.h | 2 +- src/workers/Workers.cpp | 16 ++++------ 18 files changed, 71 insertions(+), 56 deletions(-) rename src/backend/{ => common}/Threads.cpp (99%) rename src/backend/{ => common}/Threads.h (100%) rename src/{workers => backend/common}/Worker.cpp (98%) rename src/{workers => backend/common}/Worker.h (97%) rename src/{core => backend/common}/WorkerJob.h (100%) create mode 100644 src/backend/common/common.cmake rename src/{ => backend/common}/interfaces/IThread.h (100%) rename src/{ => backend/common}/interfaces/IWorker.h (100%) rename src/{workers/MultiWorker.cpp => backend/cpu/CpuWorker.cpp} (90%) rename src/{workers/MultiWorker.h => backend/cpu/CpuWorker.h} (78%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48946c7e..8291f606 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,9 +33,6 @@ set(HEADERS src/core/config/ConfigTransform.h src/core/config/usage.h src/core/Controller.h - src/core/WorkerJob.h - src/interfaces/IThread.h - src/interfaces/IWorker.h src/Mem.h src/net/interfaces/IJobResultListener.h src/net/JobResult.h @@ -47,9 +44,7 @@ set(HEADERS src/version.h src/workers/CpuThreadLegacy.h src/workers/Hashrate.h - src/workers/MultiWorker.h src/workers/ThreadHandle.h - src/workers/Worker.h src/workers/Workers.h ) @@ -97,9 +92,7 @@ set(SOURCES src/Summary.cpp src/workers/CpuThreadLegacy.cpp src/workers/Hashrate.cpp - src/workers/MultiWorker.cpp src/workers/ThreadHandle.cpp - src/workers/Worker.cpp src/workers/Workers.cpp src/xmrig.cpp ) diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp index 18d97fda..5ed94c4b 100644 --- a/src/api/v1/ApiRouter.cpp +++ b/src/api/v1/ApiRouter.cpp @@ -29,11 +29,11 @@ #include "api/interfaces/IApiRequest.h" #include "api/v1/ApiRouter.h" +#include "backend/common/interfaces/IThread.h" #include "backend/cpu/Cpu.h" #include "base/kernel/Base.h" #include "base/kernel/Platform.h" #include "core/config/Config.h" -#include "interfaces/IThread.h" #include "rapidjson/document.h" #include "version.h" #include "workers/Hashrate.h" diff --git a/src/backend/backend.cmake b/src/backend/backend.cmake index 750cc9cb..c37cf262 100644 --- a/src/backend/backend.cmake +++ b/src/backend/backend.cmake @@ -1,12 +1,13 @@ include (src/backend/cpu/cpu.cmake) +include (src/backend/common/common.cmake) set(HEADERS_BACKEND - "${HEADERS_CPU}" - src/backend/Threads.h + "${HEADERS_BACKEND_COMMON}" + "${HEADERS_BACKEND_CPU}" ) set(SOURCES_BACKEND - "${SOURCES_CPU}" - src/backend/Threads.cpp + "${SOURCES_BACKEND_COMMON}" + "${SOURCES_BACKEND_CPU}" ) diff --git a/src/backend/Threads.cpp b/src/backend/common/Threads.cpp similarity index 99% rename from src/backend/Threads.cpp rename to src/backend/common/Threads.cpp index 11e1ec15..4cb9d4c6 100644 --- a/src/backend/Threads.cpp +++ b/src/backend/common/Threads.cpp @@ -23,8 +23,8 @@ */ +#include "backend/common/Threads.h" #include "backend/cpu/CpuThread.h" -#include "backend/Threads.h" #include "rapidjson/document.h" diff --git a/src/backend/Threads.h b/src/backend/common/Threads.h similarity index 100% rename from src/backend/Threads.h rename to src/backend/common/Threads.h diff --git a/src/workers/Worker.cpp b/src/backend/common/Worker.cpp similarity index 98% rename from src/workers/Worker.cpp rename to src/backend/common/Worker.cpp index d85858af..f0457bbb 100644 --- a/src/workers/Worker.cpp +++ b/src/backend/common/Worker.cpp @@ -26,11 +26,11 @@ #include +#include "backend/common/Worker.h" #include "backend/cpu/Cpu.h" #include "base/kernel/Platform.h" #include "workers/CpuThreadLegacy.h" #include "workers/ThreadHandle.h" -#include "workers/Worker.h" Worker::Worker(ThreadHandle *handle) : diff --git a/src/workers/Worker.h b/src/backend/common/Worker.h similarity index 97% rename from src/workers/Worker.h rename to src/backend/common/Worker.h index 997771b0..3e1d202f 100644 --- a/src/workers/Worker.h +++ b/src/backend/common/Worker.h @@ -31,7 +31,7 @@ #include -#include "interfaces/IWorker.h" +#include "backend/common/interfaces/IWorker.h" #include "Mem.h" diff --git a/src/core/WorkerJob.h b/src/backend/common/WorkerJob.h similarity index 100% rename from src/core/WorkerJob.h rename to src/backend/common/WorkerJob.h diff --git a/src/backend/common/common.cmake b/src/backend/common/common.cmake new file mode 100644 index 00000000..e7caa593 --- /dev/null +++ b/src/backend/common/common.cmake @@ -0,0 +1,12 @@ +set(HEADERS_BACKEND_COMMON + src/backend/common/interfaces/IThread.h + src/backend/common/interfaces/IWorker.h + src/backend/common/Threads.h + src/backend/common/Worker.h + src/backend/common/WorkerJob.h + ) + +set(SOURCES_BACKEND_COMMON + src/backend/common/Threads.cpp + src/backend/common/Worker.cpp + ) diff --git a/src/interfaces/IThread.h b/src/backend/common/interfaces/IThread.h similarity index 100% rename from src/interfaces/IThread.h rename to src/backend/common/interfaces/IThread.h diff --git a/src/interfaces/IWorker.h b/src/backend/common/interfaces/IWorker.h similarity index 100% rename from src/interfaces/IWorker.h rename to src/backend/common/interfaces/IWorker.h diff --git a/src/backend/cpu/CpuConfig.h b/src/backend/cpu/CpuConfig.h index 66da3a5f..88222ab1 100644 --- a/src/backend/cpu/CpuConfig.h +++ b/src/backend/cpu/CpuConfig.h @@ -26,8 +26,8 @@ #define XMRIG_CPUCONFIG_H +#include "backend/common/Threads.h" #include "backend/cpu/CpuThread.h" -#include "backend/Threads.h" #include "crypto/common/Assembly.h" diff --git a/src/workers/MultiWorker.cpp b/src/backend/cpu/CpuWorker.cpp similarity index 90% rename from src/workers/MultiWorker.cpp rename to src/backend/cpu/CpuWorker.cpp index 1f06455a..fc98048d 100644 --- a/src/workers/MultiWorker.cpp +++ b/src/backend/cpu/CpuWorker.cpp @@ -27,13 +27,13 @@ #include +#include "backend/cpu/CpuWorker.h" #include "crypto/cn/CryptoNight_test.h" #include "crypto/common/Nonce.h" #include "crypto/rx/Rx.h" #include "crypto/rx/RxVm.h" #include "net/JobResults.h" #include "workers/CpuThreadLegacy.h" -#include "workers/MultiWorker.h" #include "workers/Workers.h" @@ -45,7 +45,7 @@ static constexpr uint32_t kReserveCount = 4096; template -xmrig::MultiWorker::MultiWorker(ThreadHandle *handle) +xmrig::CpuWorker::CpuWorker(ThreadHandle *handle) : Worker(handle) { if (m_thread->algorithm().family() != Algorithm::RANDOM_X) { @@ -55,7 +55,7 @@ xmrig::MultiWorker::MultiWorker(ThreadHandle *handle) template -xmrig::MultiWorker::~MultiWorker() +xmrig::CpuWorker::~CpuWorker() { Mem::release(m_ctx, N, m_memory); @@ -67,7 +67,7 @@ xmrig::MultiWorker::~MultiWorker() #ifdef XMRIG_ALGO_RANDOMX template -void xmrig::MultiWorker::allocateRandomX_VM() +void xmrig::CpuWorker::allocateRandomX_VM() { if (!m_vm) { RxDataset *dataset = Rx::dataset(m_job.currentJob().seedHash(), m_job.currentJob().algorithm()); @@ -78,7 +78,7 @@ void xmrig::MultiWorker::allocateRandomX_VM() template -bool xmrig::MultiWorker::selfTest() +bool xmrig::CpuWorker::selfTest() { if (m_thread->algorithm().family() == Algorithm::CN) { const bool rc = verify(Algorithm::CN_0, test_output_v0) && @@ -137,7 +137,7 @@ bool xmrig::MultiWorker::selfTest() template -void xmrig::MultiWorker::start() +void xmrig::CpuWorker::start() { while (Nonce::sequence() > 0) { if (Workers::isPaused()) { @@ -189,7 +189,7 @@ void xmrig::MultiWorker::start() template -bool xmrig::MultiWorker::verify(const Algorithm &algorithm, const uint8_t *referenceValue) +bool xmrig::CpuWorker::verify(const Algorithm &algorithm, const uint8_t *referenceValue) { cn_hash_fun func = m_thread->fn(algorithm); if (!func) { @@ -202,7 +202,7 @@ bool xmrig::MultiWorker::verify(const Algorithm &algorithm, const uint8_t *re template -bool xmrig::MultiWorker::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) +bool xmrig::CpuWorker::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) { cn_hash_fun func = m_thread->fn(algorithm); if (!func) { @@ -231,7 +231,7 @@ bool xmrig::MultiWorker::verify2(const Algorithm &algorithm, const uint8_t *r namespace xmrig { template<> -bool MultiWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) +bool CpuWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) { cn_hash_fun func = m_thread->fn(algorithm); if (!func) { @@ -253,7 +253,7 @@ bool MultiWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenc template -void xmrig::MultiWorker::consumeJob() +void xmrig::CpuWorker::consumeJob() { m_job.add(Workers::job(), Nonce::sequence(), kReserveCount); } @@ -261,11 +261,11 @@ void xmrig::MultiWorker::consumeJob() namespace xmrig { -template class MultiWorker<1>; -template class MultiWorker<2>; -template class MultiWorker<3>; -template class MultiWorker<4>; -template class MultiWorker<5>; +template class CpuWorker<1>; +template class CpuWorker<2>; +template class CpuWorker<3>; +template class CpuWorker<4>; +template class CpuWorker<5>; } // namespace xmrig diff --git a/src/workers/MultiWorker.h b/src/backend/cpu/CpuWorker.h similarity index 78% rename from src/workers/MultiWorker.h rename to src/backend/cpu/CpuWorker.h index 2bcb2333..7e878b54 100644 --- a/src/workers/MultiWorker.h +++ b/src/backend/cpu/CpuWorker.h @@ -23,15 +23,15 @@ * along with this program. If not, see . */ -#ifndef XMRIG_MULTIWORKER_H -#define XMRIG_MULTIWORKER_H +#ifndef XMRIG_CPUWORKER_H +#define XMRIG_CPUWORKER_H +#include "backend/common/WorkerJob.h" #include "base/net/stratum/Job.h" -#include "core/WorkerJob.h" #include "Mem.h" #include "net/JobResult.h" -#include "workers/Worker.h" +#include "backend/common/Worker.h" namespace xmrig { @@ -41,11 +41,11 @@ class RxVm; template -class MultiWorker : public Worker +class CpuWorker : public Worker { public: - MultiWorker(ThreadHandle *handle); - ~MultiWorker(); + CpuWorker(ThreadHandle *handle); + ~CpuWorker() override; protected: bool selfTest() override; @@ -71,7 +71,18 @@ private: }; +template<> +bool CpuWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenceValue); + + +extern template class CpuWorker<1>; +extern template class CpuWorker<2>; +extern template class CpuWorker<3>; +extern template class CpuWorker<4>; +extern template class CpuWorker<5>; + + } // namespace xmrig -#endif /* XMRIG_MULTIWORKER_H */ +#endif /* XMRIG_CPUWORKER_H */ diff --git a/src/backend/cpu/cpu.cmake b/src/backend/cpu/cpu.cmake index df9b7cea..3e15a9fd 100644 --- a/src/backend/cpu/cpu.cmake +++ b/src/backend/cpu/cpu.cmake @@ -1,14 +1,16 @@ -set(HEADERS_CPU - src/backend/cpu/Cpu.h - src/backend/cpu/CpuConfig.h +set(HEADERS_BACKEND_CPU + src/backend/cpu/Cpu.h + src/backend/cpu/CpuConfig.h src/backend/cpu/CpuThread.h - src/backend/cpu/interfaces/ICpuInfo.h + src/backend/cpu/CpuWorker.h + src/backend/cpu/interfaces/ICpuInfo.h ) -set(SOURCES_CPU +set(SOURCES_BACKEND_CPU src/backend/cpu/Cpu.cpp src/backend/cpu/CpuConfig.cpp src/backend/cpu/CpuThread.cpp + src/backend/cpu/CpuWorker.cpp ) diff --git a/src/workers/CpuThreadLegacy.h b/src/workers/CpuThreadLegacy.h index 4553295c..b803a8c4 100644 --- a/src/workers/CpuThreadLegacy.h +++ b/src/workers/CpuThreadLegacy.h @@ -26,8 +26,8 @@ #define XMRIG_CPUTHREADLEGACY_H +#include "backend/common/interfaces/IThread.h" #include "crypto/cn/CnHash.h" -#include "interfaces/IThread.h" struct cryptonight_ctx; diff --git a/src/workers/ThreadHandle.h b/src/workers/ThreadHandle.h index c32aabf0..aedb4907 100644 --- a/src/workers/ThreadHandle.h +++ b/src/workers/ThreadHandle.h @@ -31,7 +31,7 @@ #include -#include "interfaces/IThread.h" +#include "backend/common/interfaces/IThread.h" class IWorker; diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index 53a8b712..b43546cd 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -28,6 +28,7 @@ #include "api/Api.h" +#include "backend/cpu/CpuWorker.h" #include "base/io/log/Log.h" #include "base/tools/Chrono.h" #include "base/tools/Handle.h" @@ -37,11 +38,9 @@ #include "crypto/rx/RxAlgo.h" #include "crypto/rx/RxCache.h" #include "crypto/rx/RxDataset.h" -#include "interfaces/IThread.h" #include "Mem.h" #include "rapidjson/document.h" #include "workers/Hashrate.h" -#include "workers/MultiWorker.h" #include "workers/ThreadHandle.h" #include "workers/Workers.h" @@ -250,26 +249,23 @@ void Workers::onReady(void *arg) switch (handle->config()->multiway()) { case 1: - worker = new xmrig::MultiWorker<1>(handle); + worker = new xmrig::CpuWorker<1>(handle); break; case 2: - worker = new xmrig::MultiWorker<2>(handle); + worker = new xmrig::CpuWorker<2>(handle); break; case 3: - worker = new xmrig::MultiWorker<3>(handle); + worker = new xmrig::CpuWorker<3>(handle); break; case 4: - worker = new xmrig::MultiWorker<4>(handle); + worker = new xmrig::CpuWorker<4>(handle); break; case 5: - worker = new xmrig::MultiWorker<5>(handle); - break; - - default: + worker = new xmrig::CpuWorker<5>(handle); break; } From dff59fabc241fc1612b614200a0db030000245cc Mon Sep 17 00:00:00 2001 From: XMRig Date: Sun, 14 Jul 2019 00:35:38 +0700 Subject: [PATCH 30/65] Removed CPU specific code from Worker class. --- src/backend/common/Worker.cpp | 27 ++++++++------------------- src/backend/common/Worker.h | 14 ++++---------- src/backend/cpu/CpuWorker.cpp | 6 ++++-- src/backend/cpu/CpuWorker.h | 9 ++++++++- src/base/tools/Chrono.h | 8 ++++++++ src/workers/Hashrate.cpp | 13 ++++--------- src/workers/Workers.cpp | 6 +++--- 7 files changed, 39 insertions(+), 44 deletions(-) diff --git a/src/backend/common/Worker.cpp b/src/backend/common/Worker.cpp index f0457bbb..98da61d4 100644 --- a/src/backend/common/Worker.cpp +++ b/src/backend/common/Worker.cpp @@ -23,36 +23,25 @@ * along with this program. If not, see . */ -#include - #include "backend/common/Worker.h" -#include "backend/cpu/Cpu.h" #include "base/kernel/Platform.h" -#include "workers/CpuThreadLegacy.h" -#include "workers/ThreadHandle.h" +#include "base/tools/Chrono.h" -Worker::Worker(ThreadHandle *handle) : - m_id(handle->threadId()), +xmrig::Worker::Worker(size_t id, int64_t affinity, int priority) : + m_id(id), m_hashCount(0), m_timestamp(0), - m_count(0), - m_thread(static_cast(handle->config())) + m_count(0) { - if (xmrig::Cpu::info()->threads() > 1 && m_thread->affinity() != -1L) { - Platform::setThreadAffinity(m_thread->affinity()); - } - - Platform::setThreadPriority(m_thread->priority()); + Platform::trySetThreadAffinity(affinity); + Platform::setThreadPriority(priority); } -void Worker::storeStats() +void xmrig::Worker::storeStats() { - using namespace std::chrono; - - const uint64_t timestamp = time_point_cast(high_resolution_clock::now()).time_since_epoch().count(); m_hashCount.store(m_count, std::memory_order_relaxed); - m_timestamp.store(timestamp, std::memory_order_relaxed); + m_timestamp.store(Chrono::highResolutionMSecs(), std::memory_order_relaxed); } diff --git a/src/backend/common/Worker.h b/src/backend/common/Worker.h index 3e1d202f..3223a60c 100644 --- a/src/backend/common/Worker.h +++ b/src/backend/common/Worker.h @@ -32,23 +32,16 @@ #include "backend/common/interfaces/IWorker.h" -#include "Mem.h" - - -class ThreadHandle; namespace xmrig { - class CpuThreadLegacy; -} class Worker : public IWorker { public: - Worker(ThreadHandle *handle); + Worker(size_t id, int64_t affinity, int priority); - inline const MemInfo &memory() const { return m_memory; } inline size_t id() const override { return m_id; } inline uint64_t hashCount() const override { return m_hashCount.load(std::memory_order_relaxed); } inline uint64_t timestamp() const override { return m_timestamp.load(std::memory_order_relaxed); } @@ -57,12 +50,13 @@ protected: void storeStats(); const size_t m_id; - MemInfo m_memory; std::atomic m_hashCount; std::atomic m_timestamp; uint64_t m_count; - xmrig::CpuThreadLegacy *m_thread; }; +} // namespace xmrig + + #endif /* XMRIG_WORKER_H */ diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp index fc98048d..e8aa2e3e 100644 --- a/src/backend/cpu/CpuWorker.cpp +++ b/src/backend/cpu/CpuWorker.cpp @@ -34,6 +34,7 @@ #include "crypto/rx/RxVm.h" #include "net/JobResults.h" #include "workers/CpuThreadLegacy.h" +#include "workers/ThreadHandle.h" #include "workers/Workers.h" @@ -45,8 +46,9 @@ static constexpr uint32_t kReserveCount = 4096; template -xmrig::CpuWorker::CpuWorker(ThreadHandle *handle) - : Worker(handle) +xmrig::CpuWorker::CpuWorker(ThreadHandle *handle) : + Worker(handle->threadId(), handle->config()->affinity(), handle->config()->priority()), + m_thread(static_cast(handle->config())) { if (m_thread->algorithm().family() != Algorithm::RANDOM_X) { m_memory = Mem::create(m_ctx, m_thread->algorithm(), N); diff --git a/src/backend/cpu/CpuWorker.h b/src/backend/cpu/CpuWorker.h index 7e878b54..b9adf0f1 100644 --- a/src/backend/cpu/CpuWorker.h +++ b/src/backend/cpu/CpuWorker.h @@ -34,9 +34,13 @@ #include "backend/common/Worker.h" +class ThreadHandle; + + namespace xmrig { +class CpuThreadLegacy; class RxVm; @@ -47,6 +51,8 @@ public: CpuWorker(ThreadHandle *handle); ~CpuWorker() override; + inline const MemInfo &memory() const { return m_memory; } + protected: bool selfTest() override; void start() override; @@ -60,9 +66,10 @@ private: bool verify2(const Algorithm &algorithm, const uint8_t *referenceValue); void consumeJob(); + CpuThreadLegacy *m_thread; cryptonight_ctx *m_ctx[N]; + MemInfo m_memory; uint8_t m_hash[N * 32]; - WorkerJob m_job; # ifdef XMRIG_ALGO_RANDOMX diff --git a/src/base/tools/Chrono.h b/src/base/tools/Chrono.h index d3c14602..e464f361 100644 --- a/src/base/tools/Chrono.h +++ b/src/base/tools/Chrono.h @@ -35,6 +35,14 @@ namespace xmrig { class Chrono { public: + static inline uint64_t highResolutionMSecs() + { + using namespace std::chrono; + + return static_cast(time_point_cast(high_resolution_clock::now()).time_since_epoch().count()); + } + + static inline uint64_t steadyMSecs() { using namespace std::chrono; diff --git a/src/workers/Hashrate.cpp b/src/workers/Hashrate.cpp index 568817cd..0a683caa 100644 --- a/src/workers/Hashrate.cpp +++ b/src/workers/Hashrate.cpp @@ -24,13 +24,13 @@ #include -#include #include #include #include #include "base/io/log/Log.h" +#include "base/tools/Chrono.h" #include "base/tools/Handle.h" #include "core/config/Config.h" #include "core/Controller.h" @@ -98,9 +98,6 @@ double Hashrate::calc(size_t threadId, size_t ms) const return nan(""); } - using namespace std::chrono; - const uint64_t now = time_point_cast(high_resolution_clock::now()).time_since_epoch().count(); - uint64_t earliestHashCount = 0; uint64_t earliestStamp = 0; uint64_t lastestStamp = 0; @@ -119,7 +116,7 @@ double Hashrate::calc(size_t threadId, size_t ms) const lastestHashCnt = m_counts[threadId][idx]; } - if (now - m_timestamps[threadId][idx] > ms) { + if (xmrig::Chrono::highResolutionMSecs() - m_timestamps[threadId][idx] > ms) { haveFullSet = true; break; } @@ -136,10 +133,8 @@ double Hashrate::calc(size_t threadId, size_t ms) const return nan(""); } - double hashes, time; - hashes = (double) lastestHashCnt - earliestHashCount; - time = (double) lastestStamp - earliestStamp; - time /= 1000.0; + const double hashes = static_cast(lastestHashCnt - earliestHashCount); + const double time = static_cast(lastestStamp - earliestStamp) / 1000.0; return hashes / time; } diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index b43546cd..78954d8f 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -299,12 +299,12 @@ void Workers::onTick(uv_timer_t *) void Workers::start(IWorker *worker) { - const Worker *w = static_cast(worker); +// const Worker *w = static_cast(worker); uv_mutex_lock(&m_mutex); m_status.started++; - m_status.pages += w->memory().pages; - m_status.hugePages += w->memory().hugePages; +// m_status.pages += w->memory().pages; +// m_status.hugePages += w->memory().hugePages; if (m_status.started == m_status.threads) { const double percent = (double) m_status.hugePages / m_status.pages * 100.0; From 27f3008d791f53397281557bda3c696088a33ffd Mon Sep 17 00:00:00 2001 From: XMRig Date: Tue, 16 Jul 2019 22:10:50 +0700 Subject: [PATCH 31/65] Added initial support for new style threads launch method. --- CMakeLists.txt | 8 +- src/App.cpp | 17 +- src/api/v1/ApiRouter.cpp | 12 +- src/backend/common/Thread.h | 62 ++++ src/backend/common/WorkerJob.h | 1 - src/backend/common/Workers.cpp | 152 ++++++++ .../common/Workers.h} | 48 ++- src/backend/common/common.cmake | 4 + .../common/interfaces/IBackend.h} | 38 +- src/backend/common/interfaces/IWorker.h | 6 + src/backend/cpu/CpuBackend.cpp | 151 ++++++++ src/backend/cpu/CpuBackend.h | 61 ++++ src/backend/cpu/CpuLaunchData.cpp | 51 +++ src/backend/cpu/CpuLaunchData.h | 67 ++++ src/backend/cpu/CpuThread.h | 16 +- src/backend/cpu/CpuWorker.cpp | 56 +-- src/backend/cpu/CpuWorker.h | 17 +- src/backend/cpu/cpu.cmake | 4 + src/base/io/log/Log.h | 82 ++--- src/core/Controller.cpp | 19 +- src/core/Controller.h | 6 +- src/core/Miner.cpp | 215 ++++++++++++ src/core/Miner.h | 65 ++++ src/crypto/cn/CnHash.cpp | 9 +- src/crypto/cn/CnHash.h | 2 +- src/crypto/common/Nonce.cpp | 29 +- src/crypto/common/Nonce.h | 23 +- src/net/Network.cpp | 8 +- src/workers/CpuThreadLegacy.cpp | 6 +- src/workers/Workers.cpp | 330 ----------------- src/workers/WorkersLegacy.cpp | 331 ++++++++++++++++++ src/workers/{Workers.h => WorkersLegacy.h} | 38 +- 32 files changed, 1429 insertions(+), 505 deletions(-) create mode 100644 src/backend/common/Thread.h create mode 100644 src/backend/common/Workers.cpp rename src/{workers/ThreadHandle.h => backend/common/Workers.h} (64%) rename src/{workers/ThreadHandle.cpp => backend/common/interfaces/IBackend.h} (71%) create mode 100644 src/backend/cpu/CpuBackend.cpp create mode 100644 src/backend/cpu/CpuBackend.h create mode 100644 src/backend/cpu/CpuLaunchData.cpp create mode 100644 src/backend/cpu/CpuLaunchData.h create mode 100644 src/core/Miner.cpp create mode 100644 src/core/Miner.h delete mode 100644 src/workers/Workers.cpp create mode 100644 src/workers/WorkersLegacy.cpp rename src/workers/{Workers.h => WorkersLegacy.h} (76%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8291f606..8749a003 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ set(HEADERS src/core/config/ConfigTransform.h src/core/config/usage.h src/core/Controller.h + src/core/Miner.h src/Mem.h src/net/interfaces/IJobResultListener.h src/net/JobResult.h @@ -44,8 +45,7 @@ set(HEADERS src/version.h src/workers/CpuThreadLegacy.h src/workers/Hashrate.h - src/workers/ThreadHandle.h - src/workers/Workers.h + src/workers/WorkersLegacy.h ) set(HEADERS_CRYPTO @@ -84,6 +84,7 @@ set(SOURCES src/core/config/Config.cpp src/core/config/ConfigTransform.cpp src/core/Controller.cpp + src/core/Miner.cpp src/Mem.cpp src/net/JobResults.cpp src/net/Network.cpp @@ -92,8 +93,7 @@ set(SOURCES src/Summary.cpp src/workers/CpuThreadLegacy.cpp src/workers/Hashrate.cpp - src/workers/ThreadHandle.cpp - src/workers/Workers.cpp + src/workers/WorkersLegacy.cpp src/xmrig.cpp ) diff --git a/src/App.cpp b/src/App.cpp index 5b2178ac..d6c39595 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -36,11 +36,11 @@ #include "base/kernel/Signals.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "core/Miner.h" #include "Mem.h" #include "net/Network.h" #include "Summary.h" #include "version.h" -#include "workers/Workers.h" xmrig::App::App(Process *process) : @@ -86,8 +86,6 @@ int xmrig::App::exec() return 0; } - Workers::start(m_controller); - m_controller->start(); const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); @@ -102,23 +100,17 @@ void xmrig::App::onConsoleCommand(char command) switch (command) { case 'h': case 'H': - Workers::printHashrate(true); + m_controller->miner()->printHashrate(true); break; case 'p': case 'P': - if (Workers::isEnabled()) { - LOG_INFO(YELLOW_BOLD("paused") ", press " MAGENTA_BOLD("r") " to resume"); - Workers::setEnabled(false); - } + m_controller->miner()->setEnabled(false); break; case 'r': case 'R': - if (!Workers::isEnabled()) { - LOG_INFO(GREEN_BOLD("resumed")); - Workers::setEnabled(true); - } + m_controller->miner()->setEnabled(true); break; case 3: @@ -162,6 +154,5 @@ void xmrig::App::close() m_console->stop(); m_controller->stop(); - Workers::stop(); Log::destroy(); } diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp index 5ed94c4b..9e609d13 100644 --- a/src/api/v1/ApiRouter.cpp +++ b/src/api/v1/ApiRouter.cpp @@ -37,7 +37,7 @@ #include "rapidjson/document.h" #include "version.h" #include "workers/Hashrate.h" -#include "workers/Workers.h" +#include "workers/WorkersLegacy.h" static inline rapidjson::Value normalize(double d) @@ -107,13 +107,13 @@ void xmrig::ApiRouter::getHashrate(rapidjson::Value &reply, rapidjson::Document Value total(kArrayType); Value threads(kArrayType); - const Hashrate *hr = Workers::hashrate(); + const Hashrate *hr = WorkersLegacy::hashrate(); total.PushBack(normalize(hr->calc(Hashrate::ShortInterval)), allocator); total.PushBack(normalize(hr->calc(Hashrate::MediumInterval)), allocator); total.PushBack(normalize(hr->calc(Hashrate::LargeInterval)), allocator); - for (size_t i = 0; i < Workers::threads(); i++) { + for (size_t i = 0; i < WorkersLegacy::threads(); i++) { Value thread(kArrayType); thread.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); thread.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); @@ -144,7 +144,7 @@ void xmrig::ApiRouter::getMiner(rapidjson::Value &reply, rapidjson::Document &do reply.AddMember("kind", APP_KIND, allocator); reply.AddMember("ua", StringRef(Platform::userAgent()), allocator); reply.AddMember("cpu", cpu, allocator); - reply.AddMember("hugepages", Workers::hugePages() > 0, allocator); + reply.AddMember("hugepages", WorkersLegacy::hugePages() > 0, allocator); reply.AddMember("donate_level", m_base->config()->pools().donateLevel(), allocator); } @@ -153,9 +153,9 @@ void xmrig::ApiRouter::getThreads(rapidjson::Value &reply, rapidjson::Document & { using namespace rapidjson; auto &allocator = doc.GetAllocator(); - const Hashrate *hr = Workers::hashrate(); + const Hashrate *hr = WorkersLegacy::hashrate(); - Workers::threadsSummary(doc); + WorkersLegacy::threadsSummary(doc); const std::vector &threads = m_base->config()->threads(); Value list(kArrayType); diff --git a/src/backend/common/Thread.h b/src/backend/common/Thread.h new file mode 100644 index 00000000..f1d174ec --- /dev/null +++ b/src/backend/common/Thread.h @@ -0,0 +1,62 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_THREAD_H +#define XMRIG_THREAD_H + + +#include + + +namespace xmrig { + + +class IWorker; + + +template +class Thread +{ +public: + inline Thread(size_t index, const T &config) : m_index(index), m_config(config) {} + inline ~Thread() { uv_thread_join(&m_thread); } + + inline const T &config() const { return m_config; } + inline IWorker *worker() const { return m_worker; } + inline size_t index() const { return m_index; } + inline void setWorker(IWorker *worker) { m_worker = worker; } + inline void start(void (*callback) (void *)) { uv_thread_create(&m_thread, callback, this); } + +private: + const size_t m_index = 0; + const T m_config; + IWorker *m_worker = nullptr; + uv_thread_t m_thread; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_THREAD_H */ diff --git a/src/backend/common/WorkerJob.h b/src/backend/common/WorkerJob.h index 7b598ee6..c9a3d55c 100644 --- a/src/backend/common/WorkerJob.h +++ b/src/backend/common/WorkerJob.h @@ -26,7 +26,6 @@ #define XMRIG_WORKERJOB_H -#include #include diff --git a/src/backend/common/Workers.cpp b/src/backend/common/Workers.cpp new file mode 100644 index 00000000..987ca526 --- /dev/null +++ b/src/backend/common/Workers.cpp @@ -0,0 +1,152 @@ +/* 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 "backend/common/Workers.h" +#include "backend/cpu/CpuWorker.h" +#include "base/io/log/Log.h" + + +namespace xmrig { + + +class WorkersPrivate +{ +public: + inline WorkersPrivate() + { + + } + + + inline ~WorkersPrivate() + { + } +}; + + +} // namespace xmrig + + +template +xmrig::Workers::Workers() : + d_ptr(new WorkersPrivate()) +{ + +} + + +template +xmrig::Workers::~Workers() +{ + delete d_ptr; +} + + +template +void xmrig::Workers::add(const T &data) +{ + m_workers.push_back(new Thread(m_workers.size(), data)); +} + + +template +void xmrig::Workers::start() +{ + for (Thread *worker : m_workers) { + worker->start(Workers::onReady); + } +} + + +template +void xmrig::Workers::stop() +{ + Nonce::stop(T::backend()); + + for (Thread *worker : m_workers) { + delete worker; + } + + m_workers.clear(); + Nonce::touch(T::backend()); +} + + +template +void xmrig::Workers::onReady(void *arg) +{ + printf("ON READY\n"); +} + + +namespace xmrig { + + +template<> +void xmrig::Workers::onReady(void *arg) +{ + auto handle = static_cast* >(arg); + + IWorker *worker = nullptr; + + switch (handle->config().intensity) { + case 1: + worker = new CpuWorker<1>(handle->index(), handle->config()); + break; + + case 2: + worker = new CpuWorker<2>(handle->index(), handle->config()); + break; + + case 3: + worker = new CpuWorker<3>(handle->index(), handle->config()); + break; + + case 4: + worker = new CpuWorker<4>(handle->index(), handle->config()); + break; + + case 5: + worker = new CpuWorker<5>(handle->index(), handle->config()); + break; + } + + handle->setWorker(worker); + + if (!worker->selfTest()) { + LOG_ERR("thread %zu error: \"hash self-test failed\".", handle->worker()->id()); + + return; + } + + worker->start(); +} + + +template class Workers; + + +} // namespace xmrig diff --git a/src/workers/ThreadHandle.h b/src/backend/common/Workers.h similarity index 64% rename from src/workers/ThreadHandle.h rename to src/backend/common/Workers.h index aedb4907..25f81c5b 100644 --- a/src/workers/ThreadHandle.h +++ b/src/backend/common/Workers.h @@ -5,6 +5,7 @@ * 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 , * @@ -22,38 +23,47 @@ * along with this program. If not, see . */ -#ifndef XMRIG_THREADHANDLE_H -#define XMRIG_THREADHANDLE_H +#ifndef XMRIG_WORKERS_H +#define XMRIG_WORKERS_H -#include -#include -#include +#include "backend/common/Thread.h" +#include "backend/cpu/CpuLaunchData.h" -#include "backend/common/interfaces/IThread.h" +namespace xmrig { -class IWorker; +class WorkersPrivate; -class ThreadHandle +template +class Workers { public: - ThreadHandle(xmrig::IThread *config); - void join(); - void start(void (*callback) (void *)); + Workers(); + ~Workers(); - inline IWorker *worker() const { return m_worker; } - inline size_t threadId() const { return m_config->index(); } - inline void setWorker(IWorker *worker) { assert(worker != nullptr); m_worker = worker; } - inline xmrig::IThread *config() const { return m_config; } + void add(const T &data); + void start(); + void stop(); private: - IWorker *m_worker; - uv_thread_t m_thread; - xmrig::IThread *m_config; + static void onReady(void *arg); + + std::vector *> m_workers; + WorkersPrivate *d_ptr; }; -#endif /* XMRIG_THREADHANDLE_H */ +template<> +void Workers::onReady(void *arg); + + +extern template class Workers; + + +} // namespace xmrig + + +#endif /* XMRIG_WORKERS_H */ diff --git a/src/backend/common/common.cmake b/src/backend/common/common.cmake index e7caa593..bb84af58 100644 --- a/src/backend/common/common.cmake +++ b/src/backend/common/common.cmake @@ -1,12 +1,16 @@ set(HEADERS_BACKEND_COMMON + src/backend/common/interfaces/IBackend.h src/backend/common/interfaces/IThread.h src/backend/common/interfaces/IWorker.h + src/backend/common/Thread.h src/backend/common/Threads.h src/backend/common/Worker.h + src/backend/common/Workers.h src/backend/common/WorkerJob.h ) set(SOURCES_BACKEND_COMMON src/backend/common/Threads.cpp src/backend/common/Worker.cpp + src/backend/common/Workers.cpp ) diff --git a/src/workers/ThreadHandle.cpp b/src/backend/common/interfaces/IBackend.h similarity index 71% rename from src/workers/ThreadHandle.cpp rename to src/backend/common/interfaces/IBackend.h index ced5f326..d6fe1695 100644 --- a/src/workers/ThreadHandle.cpp +++ b/src/backend/common/interfaces/IBackend.h @@ -22,24 +22,34 @@ * along with this program. If not, see . */ - -#include "workers/ThreadHandle.h" +#ifndef XMRIG_IBACKEND_H +#define XMRIG_IBACKEND_H -ThreadHandle::ThreadHandle(xmrig::IThread *config) : - m_worker(nullptr), - m_config(config) +#include + + +namespace xmrig { + + +class Job; +class String; + + +class IBackend { -} +public: + virtual ~IBackend() = default; + + virtual const String &profileName() const = 0; + virtual void printHashrate(bool details) = 0; + virtual void setJob(const Job &job) = 0; + virtual void stop() = 0; + virtual void tick(uint64_t ticks) = 0; +}; -void ThreadHandle::join() -{ - uv_thread_join(&m_thread); -} +} // namespace xmrig -void ThreadHandle::start(void (*callback) (void *)) -{ - uv_thread_create(&m_thread, callback, this); -} +#endif // XMRIG_IBACKEND_H diff --git a/src/backend/common/interfaces/IWorker.h b/src/backend/common/interfaces/IWorker.h index 83e9306e..de22de02 100644 --- a/src/backend/common/interfaces/IWorker.h +++ b/src/backend/common/interfaces/IWorker.h @@ -29,6 +29,9 @@ #include +namespace xmrig { + + class IWorker { public: @@ -42,4 +45,7 @@ public: }; +} // namespace xmrig + + #endif // XMRIG_IWORKER_H diff --git a/src/backend/cpu/CpuBackend.cpp b/src/backend/cpu/CpuBackend.cpp new file mode 100644 index 00000000..a1ae5747 --- /dev/null +++ b/src/backend/cpu/CpuBackend.cpp @@ -0,0 +1,151 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/common/Workers.h" +#include "backend/cpu/CpuBackend.h" +#include "base/net/stratum/Job.h" +#include "base/tools/String.h" +#include "core/config/Config.h" +#include "core/Controller.h" + + +#include "base/io/log/Log.h" + + +namespace xmrig { + + +extern template class Threads; + + +class CpuBackendPrivate +{ +public: + inline CpuBackendPrivate(const Miner *miner, Controller *controller) : + miner(miner), + controller(controller) + { + } + + + inline ~CpuBackendPrivate() + { + } + + + inline bool isReady(const Algorithm &nextAlgo) const + { + if (!algo.isValid()) { + return false; + } + + if (nextAlgo == algo) { + return true; + } + + const CpuThreads &nextThreads = controller->config()->cpu().threads().get(nextAlgo); + + return algo.memory() == nextAlgo.memory() + && threads.size() == nextThreads.size() + && std::equal(threads.begin(), threads.end(), nextThreads.begin()); + } + + + Algorithm algo; + const Miner *miner; + Controller *controller; + CpuThreads threads; + String profileName; + Workers workers; +}; + + +} // namespace xmrig + + +xmrig::CpuBackend::CpuBackend(const Miner *miner, Controller *controller) : + d_ptr(new CpuBackendPrivate(miner, controller)) +{ + +} + + +xmrig::CpuBackend::~CpuBackend() +{ + delete d_ptr; +} + + +const xmrig::String &xmrig::CpuBackend::profileName() const +{ + return d_ptr->profileName; +} + + +void xmrig::CpuBackend::printHashrate(bool details) +{ + +} + + +void xmrig::CpuBackend::setJob(const Job &job) +{ + LOG_WARN("PROFILE %s %zu", d_ptr->controller->config()->cpu().threads().profileName(job.algorithm()).data(), job.algorithm().memory()); + + if (d_ptr->isReady(job.algorithm())) { + return; + } + + LOG_INFO(GREEN_BOLD_S "INIT"); + + const CpuConfig &cpu = d_ptr->controller->config()->cpu(); + const Threads &threads = cpu.threads(); + + d_ptr->algo = job.algorithm(); + d_ptr->profileName = threads.profileName(job.algorithm()); + d_ptr->threads = threads.get(d_ptr->profileName); + + LOG_INFO(BLUE_BG_S " %zu ", d_ptr->threads.size()); + + d_ptr->workers.stop(); + + for (const CpuThread &thread : d_ptr->threads) { + d_ptr->workers.add(CpuLaunchData(d_ptr->miner, d_ptr->algo, cpu, thread)); + } + + d_ptr->workers.start(); +} + + +void xmrig::CpuBackend::stop() +{ + d_ptr->workers.stop(); +} + + +void xmrig::CpuBackend::tick(uint64_t ticks) +{ + +} diff --git a/src/backend/cpu/CpuBackend.h b/src/backend/cpu/CpuBackend.h new file mode 100644 index 00000000..d39ab38d --- /dev/null +++ b/src/backend/cpu/CpuBackend.h @@ -0,0 +1,61 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CPUBACKEND_H +#define XMRIG_CPUBACKEND_H + + +#include "backend/common/interfaces/IBackend.h" + + +namespace xmrig { + + +class Controller; +class CpuBackendPrivate; +class Miner; + + +class CpuBackend : public IBackend +{ +public: + CpuBackend(const Miner *miner, Controller *controller); + ~CpuBackend() override; + +protected: + const String &profileName() const override; + void printHashrate(bool details) override; + void setJob(const Job &job) override; + void stop() override; + void tick(uint64_t ticks) override; + +private: + CpuBackendPrivate *d_ptr; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_CPUBACKEND_H */ diff --git a/src/backend/cpu/CpuLaunchData.cpp b/src/backend/cpu/CpuLaunchData.cpp new file mode 100644 index 00000000..68b8e7ae --- /dev/null +++ b/src/backend/cpu/CpuLaunchData.cpp @@ -0,0 +1,51 @@ +/* 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 "backend/cpu/CpuLaunchData.h" +#include "backend/cpu/CpuConfig.h" + + +xmrig::CpuLaunchData::CpuLaunchData(const Miner *miner, const Algorithm &algorithm, const CpuConfig &config, const CpuThread &thread) : + algorithm(algorithm), + assembly(config.assembly()), + hugePages(config.isHugePages()), + hwAES(config.isHwAES()), + intensity(thread.intensity()), + priority(config.priority()), + affinity(thread.affinity()), + miner(miner) +{ +} + + +xmrig::CnHash::AlgoVariant xmrig::CpuLaunchData::av() const +{ + if (intensity <= 2) { + return static_cast(!hwAES ? (intensity + 2) : intensity); + } + + return static_cast(!hwAES ? (intensity + 5) : (intensity + 2)); +} diff --git a/src/backend/cpu/CpuLaunchData.h b/src/backend/cpu/CpuLaunchData.h new file mode 100644 index 00000000..208a68b7 --- /dev/null +++ b/src/backend/cpu/CpuLaunchData.h @@ -0,0 +1,67 @@ +/* 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_CPULAUNCHDATA_H +#define XMRIG_CPULAUNCHDATA_H + + +#include "crypto/cn/CnHash.h" +#include "crypto/common/Algorithm.h" +#include "crypto/common/Assembly.h" +#include "crypto/common/Nonce.h" + + +namespace xmrig { + + +class CpuConfig; +class CpuThread; +class Miner; + + +class CpuLaunchData +{ +public: + CpuLaunchData(const Miner *miner, const Algorithm &algorithm, const CpuConfig &config, const CpuThread &thread); + + CnHash::AlgoVariant av() const; + + inline constexpr static Nonce::Backend backend() { return Nonce::CPU; } + + const Algorithm algorithm; + const Assembly assembly; + const bool hugePages; + const bool hwAES; + const int intensity; + const int priority; + const int64_t affinity; + const Miner *miner; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_CPULAUNCHDATA_H */ diff --git a/src/backend/cpu/CpuThread.h b/src/backend/cpu/CpuThread.h index 444b2709..adaffa68 100644 --- a/src/backend/cpu/CpuThread.h +++ b/src/backend/cpu/CpuThread.h @@ -38,19 +38,23 @@ namespace xmrig { class CpuThread { public: - inline constexpr CpuThread(int intensity = 1, int affinity = -1) : m_affinity(affinity), m_intensity(intensity) {} + inline constexpr CpuThread(int intensity = 1, int64_t affinity = -1) : m_intensity(intensity), m_affinity(affinity) {} CpuThread(const rapidjson::Value &value); - inline bool isValid() const { return m_intensity >= 1 && m_intensity <= 5; } - inline int affinity() const { return m_affinity; } - inline int intensity() const { return m_intensity; } + inline bool isEqual(const CpuThread &other) const { return other.m_affinity == m_affinity && other.m_intensity == m_intensity; } + inline bool isValid() const { return m_intensity >= 1 && m_intensity <= 5; } + inline int intensity() const { return m_intensity; } + inline int64_t affinity() const { return m_affinity; } + + inline bool operator!=(const CpuThread &other) const { return !isEqual(other); } + inline bool operator==(const CpuThread &other) const { return isEqual(other); } rapidjson::Value toJSON(rapidjson::Document &doc) const; private: - int m_affinity = -1; - int m_intensity = -1; + int m_intensity = -1; + int64_t m_affinity = -1; }; diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp index e8aa2e3e..96466252 100644 --- a/src/backend/cpu/CpuWorker.cpp +++ b/src/backend/cpu/CpuWorker.cpp @@ -28,14 +28,17 @@ #include "backend/cpu/CpuWorker.h" +#include "core/Miner.h" #include "crypto/cn/CryptoNight_test.h" #include "crypto/common/Nonce.h" #include "crypto/rx/Rx.h" #include "crypto/rx/RxVm.h" #include "net/JobResults.h" -#include "workers/CpuThreadLegacy.h" -#include "workers/ThreadHandle.h" -#include "workers/Workers.h" + + +#ifdef XMRIG_ALGO_RANDOMX +# include "crypto/randomx/randomx.h" +#endif namespace xmrig { @@ -45,13 +48,18 @@ static constexpr uint32_t kReserveCount = 4096; } // namespace xmrig + template -xmrig::CpuWorker::CpuWorker(ThreadHandle *handle) : - Worker(handle->threadId(), handle->config()->affinity(), handle->config()->priority()), - m_thread(static_cast(handle->config())) +xmrig::CpuWorker::CpuWorker(size_t index, const CpuLaunchData &data) : + Worker(index, data.affinity, data.priority), + m_algorithm(data.algorithm), + m_assembly(data.assembly), + m_hwAES(data.hwAES), + m_av(data.av()), + m_miner(data.miner) { - if (m_thread->algorithm().family() != Algorithm::RANDOM_X) { - m_memory = Mem::create(m_ctx, m_thread->algorithm(), N); + if (m_algorithm.family() != Algorithm::RANDOM_X) { + m_memory = Mem::create(m_ctx, m_algorithm, N); } } @@ -73,7 +81,7 @@ void xmrig::CpuWorker::allocateRandomX_VM() { if (!m_vm) { RxDataset *dataset = Rx::dataset(m_job.currentJob().seedHash(), m_job.currentJob().algorithm()); - m_vm = new RxVm(dataset, true, m_thread->isSoftAES()); + m_vm = new RxVm(dataset, true, !m_hwAES); } } #endif @@ -82,7 +90,7 @@ void xmrig::CpuWorker::allocateRandomX_VM() template bool xmrig::CpuWorker::selfTest() { - if (m_thread->algorithm().family() == Algorithm::CN) { + if (m_algorithm.family() == Algorithm::CN) { const bool rc = verify(Algorithm::CN_0, test_output_v0) && verify(Algorithm::CN_1, test_output_v1) && verify(Algorithm::CN_2, test_output_v2) && @@ -108,14 +116,14 @@ bool xmrig::CpuWorker::selfTest() } # ifdef XMRIG_ALGO_CN_LITE - if (m_thread->algorithm().family() == Algorithm::CN_LITE) { + if (m_algorithm.family() == Algorithm::CN_LITE) { return verify(Algorithm::CN_LITE_0, test_output_v0_lite) && verify(Algorithm::CN_LITE_1, test_output_v1_lite); } # endif # ifdef XMRIG_ALGO_CN_HEAVY - if (m_thread->algorithm().family() == Algorithm::CN_HEAVY) { + if (m_algorithm.family() == Algorithm::CN_HEAVY) { return verify(Algorithm::CN_HEAVY_0, test_output_v0_heavy) && verify(Algorithm::CN_HEAVY_XHV, test_output_xhv_heavy) && verify(Algorithm::CN_HEAVY_TUBE, test_output_tube_heavy); @@ -123,13 +131,13 @@ bool xmrig::CpuWorker::selfTest() # endif # ifdef XMRIG_ALGO_CN_PICO - if (m_thread->algorithm().family() == Algorithm::CN_PICO) { + if (m_algorithm.family() == Algorithm::CN_PICO) { return verify(Algorithm::CN_PICO_0, test_output_pico_trtl); } # endif # ifdef XMRIG_ALGO_RANDOMX - if (m_thread->algorithm().family() == Algorithm::RANDOM_X) { + if (m_algorithm.family() == Algorithm::RANDOM_X) { return true; } # endif @@ -141,21 +149,21 @@ bool xmrig::CpuWorker::selfTest() template void xmrig::CpuWorker::start() { - while (Nonce::sequence() > 0) { - if (Workers::isPaused()) { + while (Nonce::sequence(Nonce::CPU) > 0) { + if (Nonce::isPaused()) { do { std::this_thread::sleep_for(std::chrono::milliseconds(200)); } - while (Workers::isPaused()); + while (Nonce::isPaused()); - if (Nonce::sequence() == 0) { + if (Nonce::sequence(Nonce::CPU) == 0) { break; } consumeJob(); } - while (!Nonce::isOutdated(m_job.sequence())) { + while (!Nonce::isOutdated(Nonce::CPU, m_job.sequence())) { if ((m_count & 0x7) == 0) { storeStats(); } @@ -170,7 +178,7 @@ void xmrig::CpuWorker::start() else # endif { - m_thread->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()); } for (size_t i = 0; i < N; ++i) { @@ -193,7 +201,7 @@ void xmrig::CpuWorker::start() template bool xmrig::CpuWorker::verify(const Algorithm &algorithm, const uint8_t *referenceValue) { - cn_hash_fun func = m_thread->fn(algorithm); + cn_hash_fun func = fn(algorithm); if (!func) { return false; } @@ -206,7 +214,7 @@ bool xmrig::CpuWorker::verify(const Algorithm &algorithm, const uint8_t *refe template bool xmrig::CpuWorker::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) { - cn_hash_fun func = m_thread->fn(algorithm); + cn_hash_fun func = fn(algorithm); if (!func) { return false; } @@ -235,7 +243,7 @@ namespace xmrig { template<> bool CpuWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) { - cn_hash_fun func = m_thread->fn(algorithm); + cn_hash_fun func = fn(algorithm); if (!func) { return false; } @@ -257,7 +265,7 @@ bool CpuWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenceV template void xmrig::CpuWorker::consumeJob() { - m_job.add(Workers::job(), Nonce::sequence(), kReserveCount); + m_job.add(m_miner->job(), Nonce::sequence(Nonce::CPU), kReserveCount); } diff --git a/src/backend/cpu/CpuWorker.h b/src/backend/cpu/CpuWorker.h index b9adf0f1..c67d355b 100644 --- a/src/backend/cpu/CpuWorker.h +++ b/src/backend/cpu/CpuWorker.h @@ -27,20 +27,17 @@ #define XMRIG_CPUWORKER_H +#include "backend/common/Worker.h" #include "backend/common/WorkerJob.h" +#include "backend/cpu/CpuLaunchData.h" #include "base/net/stratum/Job.h" #include "Mem.h" #include "net/JobResult.h" -#include "backend/common/Worker.h" - - -class ThreadHandle; namespace xmrig { -class CpuThreadLegacy; class RxVm; @@ -48,7 +45,7 @@ template class CpuWorker : public Worker { public: - CpuWorker(ThreadHandle *handle); + CpuWorker(size_t index, const CpuLaunchData &data); ~CpuWorker() override; inline const MemInfo &memory() const { return m_memory; } @@ -58,6 +55,8 @@ protected: void start() override; private: + inline cn_hash_fun fn(const Algorithm &algorithm) const { return CnHash::fn(algorithm, m_av, m_assembly); } + # ifdef XMRIG_ALGO_RANDOMX void allocateRandomX_VM(); # endif @@ -66,7 +65,11 @@ private: bool verify2(const Algorithm &algorithm, const uint8_t *referenceValue); void consumeJob(); - CpuThreadLegacy *m_thread; + const Algorithm m_algorithm; + const Assembly m_assembly; + const bool m_hwAES; + const CnHash::AlgoVariant m_av; + const Miner *m_miner; cryptonight_ctx *m_ctx[N]; MemInfo m_memory; uint8_t m_hash[N * 32]; diff --git a/src/backend/cpu/cpu.cmake b/src/backend/cpu/cpu.cmake index 3e15a9fd..871debd3 100644 --- a/src/backend/cpu/cpu.cmake +++ b/src/backend/cpu/cpu.cmake @@ -1,6 +1,8 @@ set(HEADERS_BACKEND_CPU src/backend/cpu/Cpu.h + src/backend/cpu/CpuBackend.h src/backend/cpu/CpuConfig.h + src/backend/cpu/CpuLaunchData.cpp src/backend/cpu/CpuThread.h src/backend/cpu/CpuWorker.h src/backend/cpu/interfaces/ICpuInfo.h @@ -8,7 +10,9 @@ set(HEADERS_BACKEND_CPU set(SOURCES_BACKEND_CPU src/backend/cpu/Cpu.cpp + src/backend/cpu/CpuBackend.cpp src/backend/cpu/CpuConfig.cpp + src/backend/cpu/CpuLaunchData.h src/backend/cpu/CpuThread.cpp src/backend/cpu/CpuWorker.cpp ) diff --git a/src/base/io/log/Log.h b/src/base/io/log/Log.h index 962d1dba..078a8546 100644 --- a/src/base/io/log/Log.h +++ b/src/base/io/log/Log.h @@ -61,49 +61,53 @@ private: }; -#define CSI "\x1B[" // Control Sequence Introducer (ANSI spec name) -#define CLEAR CSI "0m" // all attributes off -#define BRIGHT_BLACK_S CSI "0;90m" // somewhat MD.GRAY -#define BLACK_S CSI "0;30m" -#define BLACK_BOLD_S CSI "1;30m" // another name for GRAY -#define RED_S CSI "0;31m" -#define RED_BOLD_S CSI "1;31m" -#define GREEN_S CSI "0;32m" -#define GREEN_BOLD_S CSI "1;32m" -#define YELLOW_S CSI "0;33m" -#define YELLOW_BOLD_S CSI "1;33m" -#define BLUE_S CSI "0;34m" -#define BLUE_BOLD_S CSI "1;34m" -#define MAGENTA_S CSI "0;35m" -#define MAGENTA_BOLD_S CSI "1;35m" -#define CYAN_S CSI "0;36m" -#define CYAN_BOLD_S CSI "1;36m" -#define WHITE_S CSI "0;37m" // another name for LT.GRAY -#define WHITE_BOLD_S CSI "1;37m" // actually white +#define CSI "\x1B[" // Control Sequence Introducer (ANSI spec name) +#define CLEAR CSI "0m" // all attributes off +#define BRIGHT_BLACK_S CSI "0;90m" // somewhat MD.GRAY +#define BLACK_S CSI "0;30m" +#define BLACK_BOLD_S CSI "1;30m" // another name for GRAY +#define RED_S CSI "0;31m" +#define RED_BOLD_S CSI "1;31m" +#define GREEN_S CSI "0;32m" +#define GREEN_BOLD_S CSI "1;32m" +#define YELLOW_S CSI "0;33m" +#define YELLOW_BOLD_S CSI "1;33m" +#define BLUE_S CSI "0;34m" +#define BLUE_BOLD_S CSI "1;34m" +#define MAGENTA_S CSI "0;35m" +#define MAGENTA_BOLD_S CSI "1;35m" +#define CYAN_S CSI "0;36m" +#define CYAN_BOLD_S CSI "1;36m" +#define WHITE_S CSI "0;37m" // another name for LT.GRAY +#define WHITE_BOLD_S CSI "1;37m" // actually white -#define BLUE_BG_S CSI "44m" -#define BLUE_BG_BOLD_S CSI "44;1m" +#define BLUE_BG_S CSI "44m" +#define BLUE_BG_BOLD_S CSI "44;1m" +#define MAGENTA_BG_S CSI "45m" +#define MAGENTA_BG_BOLD_S CSI "45;1m" //color wrappings -#define BLACK(x) BLACK_S x CLEAR -#define BLACK_BOLD(x) BLACK_BOLD_S x CLEAR -#define RED(x) RED_S x CLEAR -#define RED_BOLD(x) RED_BOLD_S x CLEAR -#define GREEN(x) GREEN_S x CLEAR -#define GREEN_BOLD(x) GREEN_BOLD_S x CLEAR -#define YELLOW(x) YELLOW_S x CLEAR -#define YELLOW_BOLD(x) YELLOW_BOLD_S x CLEAR -#define BLUE(x) BLUE_S x CLEAR -#define BLUE_BOLD(x) BLUE_BOLD_S x CLEAR -#define MAGENTA(x) MAGENTA_S x CLEAR -#define MAGENTA_BOLD(x) MAGENTA_BOLD_S x CLEAR -#define CYAN(x) CYAN_S x CLEAR -#define CYAN_BOLD(x) CYAN_BOLD_S x CLEAR -#define WHITE(x) WHITE_S x CLEAR -#define WHITE_BOLD(x) WHITE_BOLD_S x CLEAR +#define BLACK(x) BLACK_S x CLEAR +#define BLACK_BOLD(x) BLACK_BOLD_S x CLEAR +#define RED(x) RED_S x CLEAR +#define RED_BOLD(x) RED_BOLD_S x CLEAR +#define GREEN(x) GREEN_S x CLEAR +#define GREEN_BOLD(x) GREEN_BOLD_S x CLEAR +#define YELLOW(x) YELLOW_S x CLEAR +#define YELLOW_BOLD(x) YELLOW_BOLD_S x CLEAR +#define BLUE(x) BLUE_S x CLEAR +#define BLUE_BOLD(x) BLUE_BOLD_S x CLEAR +#define MAGENTA(x) MAGENTA_S x CLEAR +#define MAGENTA_BOLD(x) MAGENTA_BOLD_S x CLEAR +#define CYAN(x) CYAN_S x CLEAR +#define CYAN_BOLD(x) CYAN_BOLD_S x CLEAR +#define WHITE(x) WHITE_S x CLEAR +#define WHITE_BOLD(x) WHITE_BOLD_S x CLEAR -#define BLUE_BG(x) BLUE_BG_S x CLEAR -#define BLUE_BG_BOLD(x) BLUE_BG_BOLD_S x CLEAR +#define BLUE_BG(x) BLUE_BG_S x CLEAR +#define BLUE_BG_BOLD(x) BLUE_BG_BOLD_S x CLEAR +#define MAGENTA_BG(x) MAGENTA_BG_S x CLEAR +#define MAGENTA_BG_BOLD(x) MAGENTA_BG_BOLD_S x CLEAR #define LOG_EMERG(x, ...) xmrig::Log::print(xmrig::Log::EMERG, x, ##__VA_ARGS__) diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index 81c67d7c..54c9ee34 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -28,12 +28,12 @@ #include "backend/cpu/Cpu.h" #include "core/Controller.h" +#include "core/Miner.h" #include "net/Network.h" xmrig::Controller::Controller(Process *process) : - Base(process), - m_network(nullptr) + Base(process) { } @@ -68,6 +68,8 @@ void xmrig::Controller::start() { Base::start(); + m_miner = new Miner(this); + network()->connect(); } @@ -78,6 +80,19 @@ void xmrig::Controller::stop() delete m_network; m_network = nullptr; + + m_miner->stop(); + + delete m_miner; + m_miner = nullptr; +} + + +xmrig::Miner *xmrig::Controller::miner() const +{ + assert(m_miner != nullptr); + + return m_miner; } diff --git a/src/core/Controller.h b/src/core/Controller.h index 02f9ca92..da7ba368 100644 --- a/src/core/Controller.h +++ b/src/core/Controller.h @@ -32,6 +32,8 @@ namespace xmrig { +class Job; +class Miner; class Network; @@ -46,10 +48,12 @@ public: void start() override; void stop() override; + Miner *miner() const; Network *network() const; private: - Network *m_network; + Miner *m_miner = nullptr; + Network *m_network = nullptr; }; diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp new file mode 100644 index 00000000..1f819694 --- /dev/null +++ b/src/core/Miner.cpp @@ -0,0 +1,215 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "backend/cpu/CpuBackend.h" +#include "base/io/log/Log.h" +#include "base/net/stratum/Job.h" +#include "base/tools/Timer.h" +#include "core/config/Config.h" +#include "core/Controller.h" +#include "core/Miner.h" +#include "crypto/common/Nonce.h" + +#include "base/tools/Chrono.h" + + +namespace xmrig { + + +class MinerPrivate +{ +public: + inline MinerPrivate(Controller *controller) : controller(controller) + { + uv_rwlock_init(&rwlock); + } + + + inline ~MinerPrivate() + { + uv_rwlock_destroy(&rwlock); + + delete timer; + + for (IBackend *backend : backends) { + delete backend; + } + } + + + inline void handleJobChange() + { + active = true; + if (enabled) { + Nonce::pause(false);; + } + + for (IBackend *backend : backends) { + backend->setJob(job); + } + + if (ticks == 0) { + ticks++; + timer->start(500, 500); + } + } + + + bool active = false; + bool enabled = true; + Controller *controller; + Job job; + std::vector backends; + Timer *timer = nullptr; + uint64_t ticks = 0; + uv_rwlock_t rwlock; +}; + + +} // namespace xmrig + + + +xmrig::Miner::Miner(Controller *controller) + : d_ptr(new MinerPrivate(controller)) +{ + d_ptr->timer = new Timer(this); + + d_ptr->backends.push_back(new CpuBackend(this, controller)); +} + + +xmrig::Miner::~Miner() +{ + delete d_ptr; +} + + +bool xmrig::Miner::isEnabled() const +{ + return d_ptr->enabled; +} + + +xmrig::Job xmrig::Miner::job() const +{ + uv_rwlock_rdlock(&d_ptr->rwlock); + Job job = d_ptr->job; + uv_rwlock_rdunlock(&d_ptr->rwlock); + + return job; +} + + +void xmrig::Miner::pause() +{ + d_ptr->active = false; + + Nonce::pause(true); + Nonce::touch(); +} + + +void xmrig::Miner::printHashrate(bool details) +{ + for (IBackend *backend : d_ptr->backends) { + backend->printHashrate(details); + } +} + + +void xmrig::Miner::setEnabled(bool enabled) +{ + if (d_ptr->enabled == enabled) { + return; + } + + d_ptr->enabled = enabled; + + if (enabled) { + LOG_INFO(GREEN_BOLD("resumed")); + } + else { + LOG_INFO(YELLOW_BOLD("paused") ", press " MAGENTA_BG_BOLD(" r ") " to resume"); + } + + if (!d_ptr->active) { + return; + } + + Nonce::pause(!enabled); + Nonce::touch(); +} + + +void xmrig::Miner::setJob(const Job &job, bool donate) +{ + uv_rwlock_wrlock(&d_ptr->rwlock); + + const uint8_t index = donate ? 1 : 0; + + d_ptr->job = job; + d_ptr->job.setIndex(index); + + Nonce::reset(index); + + uv_rwlock_wrunlock(&d_ptr->rwlock); + + d_ptr->handleJobChange(); +} + + +void xmrig::Miner::stop() +{ +// xmrig::Handle::close(m_timer); +// m_hashrate->stop(); + + Nonce::stop(); + +// for (size_t i = 0; i < m_workers.size(); ++i) { +// m_workers[i]->join(); +// } + + for (IBackend *backend : d_ptr->backends) { + backend->stop(); + } +} + + +void xmrig::Miner::onTimer(const Timer *) +{ + for (IBackend *backend : d_ptr->backends) { + backend->tick(d_ptr->ticks); + } + + if ((d_ptr->ticks % (d_ptr->controller->config()->printTime() * 2)) == 0) { + printHashrate(false); + } + + d_ptr->ticks++; +} diff --git a/src/core/Miner.h b/src/core/Miner.h new file mode 100644 index 00000000..e7904575 --- /dev/null +++ b/src/core/Miner.h @@ -0,0 +1,65 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_MINER_H +#define XMRIG_MINER_H + + +#include "base/kernel/interfaces/ITimerListener.h" + + +namespace xmrig { + + +class Controller; +class Job; +class MinerPrivate; + + +class Miner : public ITimerListener +{ +public: + Miner(Controller *controller); + ~Miner() override; + + bool isEnabled() const; + Job job() const; + void pause(); + void printHashrate(bool details); + void setEnabled(bool enabled); + void setJob(const Job &job, bool donate); + void stop(); + +protected: + void onTimer(const Timer *timer) override; + +private: + MinerPrivate *d_ptr; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_MINER_H */ diff --git a/src/crypto/cn/CnHash.cpp b/src/crypto/cn/CnHash.cpp index 6582db10..40f4fbba 100644 --- a/src/crypto/cn/CnHash.cpp +++ b/src/crypto/cn/CnHash.cpp @@ -202,6 +202,9 @@ static void patchAsmVariants() #endif +static const xmrig::CnHash cnHash; + + xmrig::CnHash::CnHash() { ADD_FN(Algorithm::CN_0); @@ -252,18 +255,18 @@ xmrig::CnHash::CnHash() } -xmrig::cn_hash_fun xmrig::CnHash::fn(const Algorithm &algorithm, AlgoVariant av, Assembly::Id assembly) const +xmrig::cn_hash_fun xmrig::CnHash::fn(const Algorithm &algorithm, AlgoVariant av, Assembly::Id assembly) { if (!algorithm.isValid()) { return nullptr; } # ifdef XMRIG_FEATURE_ASM - cn_hash_fun fun = m_map[algorithm][av][assembly == Assembly::AUTO ? Cpu::info()->assembly() : assembly]; + cn_hash_fun fun = cnHash.m_map[algorithm][av][assembly == Assembly::AUTO ? Cpu::info()->assembly() : assembly]; if (fun) { return fun; } # endif - return m_map[algorithm][av][Assembly::NONE]; + return cnHash.m_map[algorithm][av][Assembly::NONE]; } diff --git a/src/crypto/cn/CnHash.h b/src/crypto/cn/CnHash.h index fdfcc9f3..e4a7ebd2 100644 --- a/src/crypto/cn/CnHash.h +++ b/src/crypto/cn/CnHash.h @@ -65,7 +65,7 @@ public: CnHash(); - cn_hash_fun fn(const Algorithm &algorithm, AlgoVariant av, Assembly::Id assembly) const; + static cn_hash_fun fn(const Algorithm &algorithm, AlgoVariant av, Assembly::Id assembly); private: cn_hash_fun m_map[Algorithm::MAX][AV_MAX][Assembly::MAX] = {}; diff --git a/src/crypto/common/Nonce.cpp b/src/crypto/common/Nonce.cpp index 6670308a..45c7001a 100644 --- a/src/crypto/common/Nonce.cpp +++ b/src/crypto/common/Nonce.cpp @@ -32,7 +32,8 @@ namespace xmrig { -std::atomic Nonce::m_sequence; +std::atomic Nonce::m_paused; +std::atomic Nonce::m_sequence[Nonce::MAX]; uint32_t Nonce::m_nonces[2] = { 0, 0 }; @@ -45,7 +46,11 @@ static Nonce nonce; xmrig::Nonce::Nonce() { - m_sequence = 1; + m_paused = true; + + for (int i = 0; i < MAX; ++i) { + m_sequence[i] = 1; + } uv_mutex_init(&mutex); } @@ -77,7 +82,25 @@ void xmrig::Nonce::reset(uint8_t index) uv_mutex_lock(&mutex); m_nonces[index] = 0; - m_sequence++; + touch(); uv_mutex_unlock(&mutex); } + + +void xmrig::Nonce::stop() +{ + pause(false); + + for (int i = 0; i < MAX; ++i) { + m_sequence[i] = 0; + } +} + + +void xmrig::Nonce::touch() +{ + for (int i = 0; i < MAX; ++i) { + m_sequence[i]++; + } +} diff --git a/src/crypto/common/Nonce.h b/src/crypto/common/Nonce.h index ea843bc9..401139fd 100644 --- a/src/crypto/common/Nonce.h +++ b/src/crypto/common/Nonce.h @@ -35,19 +35,32 @@ namespace xmrig { class Nonce { public: + enum Backend { + CPU, + OPENCL, + CUDA, + MAX + }; + + Nonce(); - static inline bool isOutdated(uint64_t sequence) { return m_sequence.load(std::memory_order_relaxed) != sequence; } - static inline uint64_t sequence() { return m_sequence.load(std::memory_order_relaxed); } - static inline void stop() { m_sequence = 0; } - static inline void touch() { m_sequence++; } + static inline bool isOutdated(Backend backend, uint64_t sequence) { return m_sequence[backend].load(std::memory_order_relaxed) != sequence; } + static inline bool isPaused() { return m_paused.load(std::memory_order_relaxed); } + static inline uint64_t sequence(Backend backend) { return m_sequence[backend].load(std::memory_order_relaxed); } + static inline void pause(bool paused) { m_paused = paused; } + static inline void stop(Backend backend) { m_sequence[backend] = 0; } + static inline void touch(Backend backend) { m_sequence[backend]++; } static uint32_t next(uint8_t index, uint32_t nonce, uint32_t reserveCount, bool nicehash); static void reset(uint8_t index); + static void stop(); + static void touch(); private: + static std::atomic m_paused; + static std::atomic m_sequence[MAX]; static uint32_t m_nonces[2]; - static std::atomic m_sequence; }; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index d40bebd1..6622a080 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -40,11 +40,12 @@ #include "base/tools/Timer.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "core/Miner.h" +#include "net/JobResult.h" #include "net/JobResults.h" #include "net/Network.h" #include "net/strategies/DonateStrategy.h" #include "rapidjson/document.h" -#include "workers/Workers.h" #ifdef XMRIG_FEATURE_API @@ -163,7 +164,8 @@ void xmrig::Network::onPause(IStrategy *strategy) if (!m_strategy->isActive()) { LOG_ERR("no active pools, stop mining"); m_state.stop(); - return Workers::pause(); + + return m_controller->miner()->pause(); } } @@ -212,7 +214,7 @@ void xmrig::Network::setJob(IClient *client, const Job &job, bool donate) } m_state.diff = job.diff(); - Workers::setJob(job, donate); + m_controller->miner()->setJob(job, donate); } diff --git a/src/workers/CpuThreadLegacy.cpp b/src/workers/CpuThreadLegacy.cpp index b8e33839..a560d33f 100644 --- a/src/workers/CpuThreadLegacy.cpp +++ b/src/workers/CpuThreadLegacy.cpp @@ -34,10 +34,6 @@ #include "workers/CpuThreadLegacy.h" - -static const xmrig::CnHash cnHash; - - xmrig::CpuThreadLegacy::CpuThreadLegacy(size_t index, Algorithm algorithm, CnHash::AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly) : m_algorithm(algorithm), m_av(av), @@ -54,7 +50,7 @@ xmrig::CpuThreadLegacy::CpuThreadLegacy(size_t index, Algorithm algorithm, CnHas xmrig::cn_hash_fun xmrig::CpuThreadLegacy::fn(const Algorithm &algorithm) const { - return cnHash.fn(algorithm, m_av, m_assembly); + return CnHash::fn(algorithm, m_av, m_assembly); } diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp deleted file mode 100644 index 78954d8f..00000000 --- a/src/workers/Workers.cpp +++ /dev/null @@ -1,330 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - - -#include "api/Api.h" -#include "backend/cpu/CpuWorker.h" -#include "base/io/log/Log.h" -#include "base/tools/Chrono.h" -#include "base/tools/Handle.h" -#include "core/config/Config.h" -#include "core/Controller.h" -#include "crypto/common/Nonce.h" -#include "crypto/rx/RxAlgo.h" -#include "crypto/rx/RxCache.h" -#include "crypto/rx/RxDataset.h" -#include "Mem.h" -#include "rapidjson/document.h" -#include "workers/Hashrate.h" -#include "workers/ThreadHandle.h" -#include "workers/Workers.h" - - -bool Workers::m_active = false; -bool Workers::m_enabled = true; -Hashrate *Workers::m_hashrate = nullptr; -xmrig::Job Workers::m_job; -Workers::LaunchStatus Workers::m_status; -std::atomic Workers::m_paused; -std::vector Workers::m_workers; -uint64_t Workers::m_ticks = 0; -uv_mutex_t Workers::m_mutex; -uv_rwlock_t Workers::m_rwlock; -uv_timer_t *Workers::m_timer = nullptr; -xmrig::Controller *Workers::m_controller = nullptr; - - -xmrig::Job Workers::job() -{ - uv_rwlock_rdlock(&m_rwlock); - xmrig::Job job = m_job; - uv_rwlock_rdunlock(&m_rwlock); - - return job; -} - - -size_t Workers::hugePages() -{ - uv_mutex_lock(&m_mutex); - const size_t hugePages = m_status.hugePages; - uv_mutex_unlock(&m_mutex); - - return hugePages; -} - - -size_t Workers::threads() -{ - uv_mutex_lock(&m_mutex); - const size_t threads = m_status.threads; - uv_mutex_unlock(&m_mutex); - - return threads; -} - - -void Workers::pause() -{ - m_active = false; - m_paused = 1; - - xmrig::Nonce::touch(); -} - - -void Workers::printHashrate(bool detail) -{ - assert(m_controller != nullptr); - if (!m_controller) { - return; - } - - if (detail) { - char num1[8] = { 0 }; - char num2[8] = { 0 }; - char num3[8] = { 0 }; - - xmrig::Log::print(WHITE_BOLD_S "| THREAD | AFFINITY | 10s H/s | 60s H/s | 15m H/s |"); - - size_t i = 0; - for (const xmrig::IThread *thread : m_controller->config()->threads()) { - xmrig::Log::print("| %6zu | %8" PRId64 " | %7s | %7s | %7s |", - thread->index(), - thread->affinity(), - Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::ShortInterval), num1, sizeof num1), - Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::MediumInterval), num2, sizeof num2), - Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::LargeInterval), num3, sizeof num3) - ); - - i++; - } - } - - m_hashrate->print(); -} - - -void Workers::setEnabled(bool enabled) -{ - if (m_enabled == enabled) { - return; - } - - m_enabled = enabled; - if (!m_active) { - return; - } - - m_paused = enabled ? 0 : 1; - xmrig::Nonce::touch(); -} - - -void Workers::setJob(const xmrig::Job &job, bool donate) -{ - uv_rwlock_wrlock(&m_rwlock); - - m_job = job; - m_job.setIndex(donate ? 1 : 0); - - xmrig::Nonce::reset(donate ? 1 : 0); - - uv_rwlock_wrunlock(&m_rwlock); - - m_active = true; - if (!m_enabled) { - return; - } - - m_paused = 0; -} - - -void Workers::start(xmrig::Controller *controller) -{ -# ifdef APP_DEBUG - LOG_NOTICE("THREADS ------------------------------------------------------------------"); - for (const xmrig::IThread *thread : controller->config()->threads()) { - thread->print(); - } - LOG_NOTICE("--------------------------------------------------------------------------"); -# endif - - m_controller = controller; - - const std::vector &threads = controller->config()->threads(); - m_status.algo = xmrig::Algorithm::RX_WOW; // FIXME algo - m_status.threads = threads.size(); - - for (const xmrig::IThread *thread : threads) { - m_status.ways += thread->multiway(); - } - - m_hashrate = new Hashrate(threads.size(), controller); - - uv_mutex_init(&m_mutex); - uv_rwlock_init(&m_rwlock); - - m_paused = 1; - - m_timer = new uv_timer_t; - uv_timer_init(uv_default_loop(), m_timer); - uv_timer_start(m_timer, Workers::onTick, 500, 500); - - for (xmrig::IThread *thread : threads) { - ThreadHandle *handle = new ThreadHandle(thread); - - m_workers.push_back(handle); - handle->start(Workers::onReady); - } -} - - -void Workers::stop() -{ - xmrig::Handle::close(m_timer); - m_hashrate->stop(); - - m_paused = 0; - - xmrig::Nonce::stop(); - - for (size_t i = 0; i < m_workers.size(); ++i) { - m_workers[i]->join(); - } -} - - -#ifdef XMRIG_FEATURE_API -void Workers::threadsSummary(rapidjson::Document &doc) -{ - uv_mutex_lock(&m_mutex); - const uint64_t pages[2] = { m_status.hugePages, m_status.pages }; - const uint64_t memory = m_status.ways * xmrig::CnAlgo<>::memory(m_status.algo); - uv_mutex_unlock(&m_mutex); - - auto &allocator = doc.GetAllocator(); - - rapidjson::Value hugepages(rapidjson::kArrayType); - hugepages.PushBack(pages[0], allocator); - hugepages.PushBack(pages[1], allocator); - - doc.AddMember("hugepages", hugepages, allocator); - doc.AddMember("memory", memory, allocator); -} -#endif - - -void Workers::onReady(void *arg) -{ - auto handle = static_cast(arg); - - IWorker *worker = nullptr; - - switch (handle->config()->multiway()) { - case 1: - worker = new xmrig::CpuWorker<1>(handle); - break; - - case 2: - worker = new xmrig::CpuWorker<2>(handle); - break; - - case 3: - worker = new xmrig::CpuWorker<3>(handle); - break; - - case 4: - worker = new xmrig::CpuWorker<4>(handle); - break; - - case 5: - worker = new xmrig::CpuWorker<5>(handle); - break; - } - - handle->setWorker(worker); - - if (!worker->selfTest()) { - LOG_ERR("thread %zu error: \"hash self-test failed\".", handle->worker()->id()); - - return; - } - - start(worker); -} - - -void Workers::onTick(uv_timer_t *) -{ - for (ThreadHandle *handle : m_workers) { - if (!handle->worker()) { - return; - } - - m_hashrate->add(handle->threadId(), handle->worker()->hashCount(), handle->worker()->timestamp()); - } - - if ((m_ticks++ & 0xF) == 0) { - m_hashrate->updateHighest(); - } -} - - -void Workers::start(IWorker *worker) -{ -// const Worker *w = static_cast(worker); - - uv_mutex_lock(&m_mutex); - m_status.started++; -// m_status.pages += w->memory().pages; -// m_status.hugePages += w->memory().hugePages; - - if (m_status.started == m_status.threads) { - const double percent = (double) m_status.hugePages / m_status.pages * 100.0; - const size_t memory = m_status.ways * xmrig::CnAlgo<>::memory(m_status.algo) / 1024; - -# ifdef XMRIG_ALGO_RANDOMX - if (m_status.algo.family() == xmrig::Algorithm::RANDOM_X) { - LOG_INFO(GREEN_BOLD("READY (CPU)") " threads " CYAN_BOLD("%zu(%zu)") " memory " CYAN_BOLD("%zu KB") "", - m_status.threads, m_status.ways, memory); - } else -# endif - { - LOG_INFO(GREEN_BOLD("READY (CPU)") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") "", - m_status.threads, m_status.ways, - (m_status.hugePages == m_status.pages ? GREEN_BOLD_S : (m_status.hugePages == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), - m_status.hugePages, m_status.pages, percent, memory); - } - } - - uv_mutex_unlock(&m_mutex); - - worker->start(); -} diff --git a/src/workers/WorkersLegacy.cpp b/src/workers/WorkersLegacy.cpp new file mode 100644 index 00000000..29571608 --- /dev/null +++ b/src/workers/WorkersLegacy.cpp @@ -0,0 +1,331 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + + +#include "api/Api.h" +#include "backend/cpu/CpuWorker.h" +#include "base/io/log/Log.h" +#include "base/tools/Chrono.h" +#include "base/tools/Handle.h" +#include "core/config/Config.h" +#include "core/Controller.h" +#include "crypto/common/Nonce.h" +#include "crypto/rx/RxAlgo.h" +#include "crypto/rx/RxCache.h" +#include "crypto/rx/RxDataset.h" +#include "Mem.h" +#include "rapidjson/document.h" +#include "workers/Hashrate.h" +#include "workers/WorkersLegacy.h" + + +bool WorkersLegacy::m_active = false; +bool WorkersLegacy::m_enabled = true; +Hashrate *WorkersLegacy::m_hashrate = nullptr; +xmrig::Job WorkersLegacy::m_job; +WorkersLegacy::LaunchStatus WorkersLegacy::m_status; +std::vector* > WorkersLegacy::m_workers; +uint64_t WorkersLegacy::m_ticks = 0; +uv_mutex_t WorkersLegacy::m_mutex; +uv_rwlock_t WorkersLegacy::m_rwlock; +//uv_timer_t *Workers::m_timer = nullptr; +xmrig::Controller *WorkersLegacy::m_controller = nullptr; + + +//xmrig::Job WorkersLegacy::job() +//{ +// uv_rwlock_rdlock(&m_rwlock); +// xmrig::Job job = m_job; +// uv_rwlock_rdunlock(&m_rwlock); + +// return job; +//} + + +size_t WorkersLegacy::hugePages() +{ + uv_mutex_lock(&m_mutex); + const size_t hugePages = m_status.hugePages; + uv_mutex_unlock(&m_mutex); + + return hugePages; +} + + +size_t WorkersLegacy::threads() +{ + uv_mutex_lock(&m_mutex); + const size_t threads = m_status.threads; + uv_mutex_unlock(&m_mutex); + + return threads; +} + + +//void Workers::pause() +//{ +// m_active = false; + +// xmrig::Nonce::pause(true); +// xmrig::Nonce::touch(); +//} + + +//void Workers::printHashrate(bool detail) +//{ +// assert(m_controller != nullptr); +// if (!m_controller) { +// return; +// } + +// if (detail) { +// char num1[8] = { 0 }; +// char num2[8] = { 0 }; +// char num3[8] = { 0 }; + +// xmrig::Log::print(WHITE_BOLD_S "| THREAD | AFFINITY | 10s H/s | 60s H/s | 15m H/s |"); + +// size_t i = 0; +// for (const xmrig::IThread *thread : m_controller->config()->threads()) { +// xmrig::Log::print("| %6zu | %8" PRId64 " | %7s | %7s | %7s |", +// thread->index(), +// thread->affinity(), +// Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::ShortInterval), num1, sizeof num1), +// Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::MediumInterval), num2, sizeof num2), +// Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::LargeInterval), num3, sizeof num3) +// ); + +// i++; +// } +// } + +// m_hashrate->print(); +//} + + +//void Workers::setEnabled(bool enabled) +//{ +// if (m_enabled == enabled) { +// return; +// } + +// m_enabled = enabled; +// if (!m_active) { +// return; +// } + +// xmrig::Nonce::pause(!enabled); +// xmrig::Nonce::touch(); +//} + + +//void Workers::setJob(const xmrig::Job &job, bool donate) +//{ +// uv_rwlock_wrlock(&m_rwlock); + +// m_job = job; +// m_job.setIndex(donate ? 1 : 0); + +// xmrig::Nonce::reset(donate ? 1 : 0); + +// uv_rwlock_wrunlock(&m_rwlock); + +// m_active = true; +// if (!m_enabled) { +// return; +// } + +// xmrig::Nonce::pause(false); +//} + + +void WorkersLegacy::start(xmrig::Controller *controller) +{ + using namespace xmrig; + +# ifdef APP_DEBUG + LOG_NOTICE("THREADS ------------------------------------------------------------------"); + for (const xmrig::IThread *thread : controller->config()->threads()) { + thread->print(); + } + LOG_NOTICE("--------------------------------------------------------------------------"); +# endif + + m_controller = controller; + + m_status.algo = xmrig::Algorithm::RX_WOW; // FIXME algo + const CpuThreads &threads = controller->config()->cpu().threads().get(m_status.algo); + m_status.threads = threads.size(); + + for (const CpuThread &thread : threads) { + m_status.ways += thread.intensity(); + } + + m_hashrate = new Hashrate(threads.size(), controller); + + uv_mutex_init(&m_mutex); + uv_rwlock_init(&m_rwlock); + +// m_timer = new uv_timer_t; +// uv_timer_init(uv_default_loop(), m_timer); +// uv_timer_start(m_timer, Workers::onTick, 500, 500); + +// size_t index = 0; +// for (const CpuThread &thread : threads) { +// Thread *handle = new Thread(index++, CpuLaunchData(m_status.algo, controller->config()->cpu(), thread)); + +// m_workers.push_back(handle); +// handle->start(WorkersLegacy::onReady); +// } +} + + +//void Workers::stop() +//{ +// xmrig::Handle::close(m_timer); +// m_hashrate->stop(); + +// xmrig::Nonce::stop(); + +// for (size_t i = 0; i < m_workers.size(); ++i) { +// m_workers[i]->join(); +// } +//} + + +#ifdef XMRIG_FEATURE_API +void WorkersLegacy::threadsSummary(rapidjson::Document &doc) +{ + uv_mutex_lock(&m_mutex); + const uint64_t pages[2] = { m_status.hugePages, m_status.pages }; + const uint64_t memory = m_status.ways * xmrig::CnAlgo<>::memory(m_status.algo); + uv_mutex_unlock(&m_mutex); + + auto &allocator = doc.GetAllocator(); + + rapidjson::Value hugepages(rapidjson::kArrayType); + hugepages.PushBack(pages[0], allocator); + hugepages.PushBack(pages[1], allocator); + + doc.AddMember("hugepages", hugepages, allocator); + doc.AddMember("memory", memory, allocator); +} +#endif + + +//void WorkersLegacy::onReady(void *arg) +//{ +// using namespace xmrig; + +// auto handle = static_cast* >(arg); + +// xmrig::IWorker *worker = nullptr; + +// switch (handle->config().intensity) { +// case 1: +// worker = new CpuWorker<1>(handle->index(), handle->config()); +// break; + +// case 2: +// worker = new CpuWorker<2>(handle->index(), handle->config()); +// break; + +// case 3: +// worker = new CpuWorker<3>(handle->index(), handle->config()); +// break; + +// case 4: +// worker = new CpuWorker<4>(handle->index(), handle->config()); +// break; + +// case 5: +// worker = new CpuWorker<5>(handle->index(), handle->config()); +// break; +// } + +// handle->setWorker(worker); + +// if (!worker->selfTest()) { +// LOG_ERR("thread %zu error: \"hash self-test failed\".", handle->worker()->id()); + +// return; +// } + +// start(worker); +//} + + +void WorkersLegacy::onTick(uv_timer_t *) +{ + using namespace xmrig; + + for (Thread *handle : m_workers) { + if (!handle->worker()) { + return; + } + + m_hashrate->add(handle->index(), handle->worker()->hashCount(), handle->worker()->timestamp()); + } + + if ((m_ticks++ & 0xF) == 0) { + m_hashrate->updateHighest(); + } +} + + +void WorkersLegacy::start(xmrig::IWorker *worker) +{ +// const Worker *w = static_cast(worker); + + uv_mutex_lock(&m_mutex); + m_status.started++; +// m_status.pages += w->memory().pages; +// m_status.hugePages += w->memory().hugePages; + + if (m_status.started == m_status.threads) { + const double percent = (double) m_status.hugePages / m_status.pages * 100.0; + const size_t memory = m_status.ways * xmrig::CnAlgo<>::memory(m_status.algo) / 1024; + +# ifdef XMRIG_ALGO_RANDOMX + if (m_status.algo.family() == xmrig::Algorithm::RANDOM_X) { + LOG_INFO(GREEN_BOLD("READY (CPU)") " threads " CYAN_BOLD("%zu(%zu)") " memory " CYAN_BOLD("%zu KB") "", + m_status.threads, m_status.ways, memory); + } else +# endif + { + LOG_INFO(GREEN_BOLD("READY (CPU)") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") "", + m_status.threads, m_status.ways, + (m_status.hugePages == m_status.pages ? GREEN_BOLD_S : (m_status.hugePages == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), + m_status.hugePages, m_status.pages, percent, memory); + } + } + + uv_mutex_unlock(&m_mutex); + + worker->start(); +} diff --git a/src/workers/Workers.h b/src/workers/WorkersLegacy.h similarity index 76% rename from src/workers/Workers.h rename to src/workers/WorkersLegacy.h index 83777d0d..5ee53dbf 100644 --- a/src/workers/Workers.h +++ b/src/workers/WorkersLegacy.h @@ -22,8 +22,8 @@ * along with this program. If not, see . */ -#ifndef XMRIG_WORKERS_H -#define XMRIG_WORKERS_H +#ifndef XMRIG_WORKERSLEGACY_H +#define XMRIG_WORKERSLEGACY_H #include @@ -35,36 +35,37 @@ # include #endif +#include "backend/common/Thread.h" +#include "backend/cpu/CpuLaunchData.h" #include "base/net/stratum/Job.h" #include "net/JobResult.h" #include "rapidjson/fwd.h" class Hashrate; -class IWorker; -class ThreadHandle; namespace xmrig { + class IWorker; class Controller; + class ThreadHandle; } -class Workers +class WorkersLegacy { public: static size_t hugePages(); static size_t threads(); - static void pause(); - static void printHashrate(bool detail); - static void setEnabled(bool enabled); - static void setJob(const xmrig::Job &job, bool donate); +// static void pause(); +// static void printHashrate(bool detail); +// static void setEnabled(bool enabled); +// static void setJob(const xmrig::Job &job, bool donate); static void start(xmrig::Controller *controller); - static void stop(); - static xmrig::Job job(); +// static void stop(); +// static xmrig::Job job(); - static inline bool isEnabled() { return m_enabled; } - static inline bool isPaused() { return m_paused.load(std::memory_order_relaxed) == 1; } +// static inline bool isEnabled() { return m_enabled; } static inline Hashrate *hashrate() { return m_hashrate; } # ifdef XMRIG_FEATURE_API @@ -72,9 +73,9 @@ public: # endif private: - static void onReady(void *arg); +// static void onReady(void *arg); static void onTick(uv_timer_t *handle); - static void start(IWorker *worker); + static void start(xmrig::IWorker *worker); class LaunchStatus { @@ -100,14 +101,13 @@ private: static Hashrate *m_hashrate; static xmrig::Job m_job; static LaunchStatus m_status; - static std::atomic m_paused; - static std::vector m_workers; + static std::vector* > m_workers; static uint64_t m_ticks; static uv_mutex_t m_mutex; static uv_rwlock_t m_rwlock; - static uv_timer_t *m_timer; +// static uv_timer_t *m_timer; static xmrig::Controller *m_controller; }; -#endif /* XMRIG_WORKERS_H */ +#endif /* XMRIG_WORKERSLEGACY_H */ From 5699147aabe84a413c73e1e74dc6d416b100b885 Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 17 Jul 2019 01:28:42 +0700 Subject: [PATCH 32/65] Restored printable hashrate. --- CMakeLists.txt | 2 - src/api/v1/ApiRouter.cpp | 86 +++++++++--------- src/api/v1/ApiRouter.h | 2 +- src/{workers => backend/common}/Hashrate.cpp | 72 +++++---------- src/{workers => backend/common}/Hashrate.h | 14 +-- src/backend/common/Workers.cpp | 40 +++++++- src/backend/common/Workers.h | 3 + src/backend/common/common.cmake | 2 + src/backend/common/interfaces/IBackend.h | 2 + src/backend/cpu/CpuBackend.cpp | 32 ++++++- src/backend/cpu/CpuBackend.h | 1 + src/core/Miner.cpp | 35 ++++++- src/core/Miner.h | 5 + src/workers/WorkersLegacy.cpp | 96 +++----------------- src/workers/WorkersLegacy.h | 8 +- 15 files changed, 196 insertions(+), 204 deletions(-) rename src/{workers => backend/common}/Hashrate.cpp (71%) rename src/{workers => backend/common}/Hashrate.h (90%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8749a003..543836c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,6 @@ set(HEADERS src/Summary.h src/version.h src/workers/CpuThreadLegacy.h - src/workers/Hashrate.h src/workers/WorkersLegacy.h ) @@ -92,7 +91,6 @@ set(SOURCES src/net/strategies/DonateStrategy.cpp src/Summary.cpp src/workers/CpuThreadLegacy.cpp - src/workers/Hashrate.cpp src/workers/WorkersLegacy.cpp src/xmrig.cpp ) diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp index 9e609d13..48a92c93 100644 --- a/src/api/v1/ApiRouter.cpp +++ b/src/api/v1/ApiRouter.cpp @@ -36,7 +36,7 @@ #include "core/config/Config.h" #include "rapidjson/document.h" #include "version.h" -#include "workers/Hashrate.h" +//#include "workers/Hashrate.h" #include "workers/WorkersLegacy.h" @@ -69,7 +69,7 @@ void xmrig::ApiRouter::onRequest(IApiRequest &request) if (request.url() == "/1/summary" || request.url() == "/api.json") { request.accept(); getMiner(request.reply(), request.doc()); - getHashrate(request.reply(), request.doc()); +// getHashrate(request.reply(), request.doc()); } else if (request.url() == "/1/threads") { request.accept(); @@ -98,35 +98,35 @@ void xmrig::ApiRouter::onRequest(IApiRequest &request) } -void xmrig::ApiRouter::getHashrate(rapidjson::Value &reply, rapidjson::Document &doc) const -{ - using namespace rapidjson; - auto &allocator = doc.GetAllocator(); +//void xmrig::ApiRouter::getHashrate(rapidjson::Value &reply, rapidjson::Document &doc) const +//{ +// using namespace rapidjson; +// auto &allocator = doc.GetAllocator(); - Value hashrate(kObjectType); - Value total(kArrayType); - Value threads(kArrayType); +// Value hashrate(kObjectType); +// Value total(kArrayType); +// Value threads(kArrayType); - const Hashrate *hr = WorkersLegacy::hashrate(); +// const Hashrate *hr = WorkersLegacy::hashrate(); - total.PushBack(normalize(hr->calc(Hashrate::ShortInterval)), allocator); - total.PushBack(normalize(hr->calc(Hashrate::MediumInterval)), allocator); - total.PushBack(normalize(hr->calc(Hashrate::LargeInterval)), allocator); +// total.PushBack(normalize(hr->calc(Hashrate::ShortInterval)), allocator); +// total.PushBack(normalize(hr->calc(Hashrate::MediumInterval)), allocator); +// total.PushBack(normalize(hr->calc(Hashrate::LargeInterval)), allocator); - for (size_t i = 0; i < WorkersLegacy::threads(); i++) { - Value thread(kArrayType); - thread.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); - thread.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); - thread.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); +// for (size_t i = 0; i < WorkersLegacy::threads(); i++) { +// Value thread(kArrayType); +// thread.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); +// thread.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); +// thread.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); - threads.PushBack(thread, allocator); - } +// threads.PushBack(thread, allocator); +// } - hashrate.AddMember("total", total, allocator); - hashrate.AddMember("highest", normalize(hr->highest()), allocator); - hashrate.AddMember("threads", threads, allocator); - reply.AddMember("hashrate", hashrate, allocator); -} +// hashrate.AddMember("total", total, allocator); +// hashrate.AddMember("highest", normalize(hr->highest()), allocator); +// hashrate.AddMember("threads", threads, allocator); +// reply.AddMember("hashrate", hashrate, allocator); +//} void xmrig::ApiRouter::getMiner(rapidjson::Value &reply, rapidjson::Document &doc) const @@ -151,29 +151,29 @@ void xmrig::ApiRouter::getMiner(rapidjson::Value &reply, rapidjson::Document &do void xmrig::ApiRouter::getThreads(rapidjson::Value &reply, rapidjson::Document &doc) const { - using namespace rapidjson; - auto &allocator = doc.GetAllocator(); - const Hashrate *hr = WorkersLegacy::hashrate(); +// using namespace rapidjson; +// auto &allocator = doc.GetAllocator(); +// const Hashrate *hr = WorkersLegacy::hashrate(); - WorkersLegacy::threadsSummary(doc); +// WorkersLegacy::threadsSummary(doc); - const std::vector &threads = m_base->config()->threads(); - Value list(kArrayType); +// const std::vector &threads = m_base->config()->threads(); +// Value list(kArrayType); - size_t i = 0; - for (const xmrig::IThread *thread : threads) { - Value value = thread->toAPI(doc); +// size_t i = 0; +// for (const xmrig::IThread *thread : threads) { +// Value value = thread->toAPI(doc); - Value hashrate(kArrayType); - hashrate.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); - hashrate.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); - hashrate.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); +// Value hashrate(kArrayType); +// hashrate.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); +// hashrate.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); +// hashrate.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); - i++; +// i++; - value.AddMember("hashrate", hashrate, allocator); - list.PushBack(value, allocator); - } +// value.AddMember("hashrate", hashrate, allocator); +// list.PushBack(value, allocator); +// } - reply.AddMember("threads", list, allocator); +// reply.AddMember("threads", list, allocator); } diff --git a/src/api/v1/ApiRouter.h b/src/api/v1/ApiRouter.h index bdbbaea4..e2b9bd25 100644 --- a/src/api/v1/ApiRouter.h +++ b/src/api/v1/ApiRouter.h @@ -49,7 +49,7 @@ protected: void onRequest(IApiRequest &request) override; private: - void getHashrate(rapidjson::Value &reply, rapidjson::Document &doc) const; +// void getHashrate(rapidjson::Value &reply, rapidjson::Document &doc) const; void getMiner(rapidjson::Value &reply, rapidjson::Document &doc) const; void getThreads(rapidjson::Value &reply, rapidjson::Document &doc) const; diff --git a/src/workers/Hashrate.cpp b/src/backend/common/Hashrate.cpp similarity index 71% rename from src/workers/Hashrate.cpp rename to src/backend/common/Hashrate.cpp index 0a683caa..6ffd45b7 100644 --- a/src/workers/Hashrate.cpp +++ b/src/backend/common/Hashrate.cpp @@ -29,12 +29,9 @@ #include -#include "base/io/log/Log.h" #include "base/tools/Chrono.h" #include "base/tools/Handle.h" -#include "core/config/Config.h" -#include "core/Controller.h" -#include "workers/Hashrate.h" +#include "backend/common/Hashrate.h" inline static const char *format(double h, char *buf, size_t size) @@ -48,10 +45,9 @@ inline static const char *format(double h, char *buf, size_t size) } -Hashrate::Hashrate(size_t threads, xmrig::Controller *controller) : +xmrig::Hashrate::Hashrate(size_t threads) : m_highest(0.0), - m_threads(threads), - m_timer(nullptr) + m_threads(threads) { m_counts = new uint64_t*[threads]; m_timestamps = new uint64_t*[threads]; @@ -62,20 +58,23 @@ Hashrate::Hashrate(size_t threads, xmrig::Controller *controller) : m_timestamps[i] = new uint64_t[kBucketSize](); m_top[i] = 0; } - - const int printTime = controller->config()->printTime(); - - if (printTime > 0) { - m_timer = new uv_timer_t; - uv_timer_init(uv_default_loop(), m_timer); - m_timer->data = this; - - uv_timer_start(m_timer, Hashrate::onReport, (printTime + 4) * 1000, printTime * 1000); - } } -double Hashrate::calc(size_t ms) const +xmrig::Hashrate::~Hashrate() +{ + for (size_t i = 0; i < m_threads; i++) { + delete [] m_counts[i]; + delete [] m_timestamps[i]; + } + + delete [] m_counts; + delete [] m_timestamps; + delete [] m_top; +} + + +double xmrig::Hashrate::calc(size_t ms) const { double result = 0.0; double data; @@ -91,7 +90,7 @@ double Hashrate::calc(size_t ms) const } -double Hashrate::calc(size_t threadId, size_t ms) const +double xmrig::Hashrate::calc(size_t threadId, size_t ms) const { assert(threadId < m_threads); if (threadId >= m_threads) { @@ -140,7 +139,7 @@ double Hashrate::calc(size_t threadId, size_t ms) const } -void Hashrate::add(size_t threadId, uint64_t count, uint64_t timestamp) +void xmrig::Hashrate::add(size_t threadId, uint64_t count, uint64_t timestamp) { const size_t top = m_top[threadId]; m_counts[threadId][top] = count; @@ -150,30 +149,7 @@ void Hashrate::add(size_t threadId, uint64_t count, uint64_t timestamp) } -void Hashrate::print() const -{ - char num1[8] = { 0 }; - char num2[8] = { 0 }; - char num3[8] = { 0 }; - char num4[8] = { 0 }; - - LOG_INFO(WHITE_BOLD("speed") " 10s/60s/15m " CYAN_BOLD("%s") CYAN(" %s %s ") CYAN_BOLD("H/s") " max " CYAN_BOLD("%s H/s"), - format(calc(ShortInterval), num1, sizeof(num1)), - format(calc(MediumInterval), num2, sizeof(num2)), - format(calc(LargeInterval), num3, sizeof(num3)), - format(m_highest, num4, sizeof(num4)) - ); -} - - -void Hashrate::stop() -{ - xmrig::Handle::close(m_timer); - m_timer = nullptr; -} - - -void Hashrate::updateHighest() +void xmrig::Hashrate::updateHighest() { double highest = calc(ShortInterval); if (isnormal(highest) && highest > m_highest) { @@ -182,13 +158,7 @@ void Hashrate::updateHighest() } -const char *Hashrate::format(double h, char *buf, size_t size) +const char *xmrig::Hashrate::format(double h, char *buf, size_t size) { return ::format(h, buf, size); } - - -void Hashrate::onReport(uv_timer_t *handle) -{ - static_cast(handle->data)->print(); -} diff --git a/src/workers/Hashrate.h b/src/backend/common/Hashrate.h similarity index 90% rename from src/workers/Hashrate.h rename to src/backend/common/Hashrate.h index d27b289e..1787bf6a 100644 --- a/src/workers/Hashrate.h +++ b/src/backend/common/Hashrate.h @@ -27,12 +27,9 @@ #include -#include namespace xmrig { - class Controller; -} class Hashrate @@ -44,12 +41,11 @@ public: LargeInterval = 900000 }; - Hashrate(size_t threads, xmrig::Controller *controller); + Hashrate(size_t threads); + ~Hashrate(); double calc(size_t ms) const; double calc(size_t threadId, size_t ms) const; void add(size_t threadId, uint64_t count, uint64_t timestamp); - void print() const; - void stop(); void updateHighest(); inline double highest() const { return m_highest; } @@ -58,8 +54,6 @@ public: static const char *format(double h, char *buf, size_t size); private: - static void onReport(uv_timer_t *handle); - constexpr static size_t kBucketSize = 2 << 11; constexpr static size_t kBucketMask = kBucketSize - 1; @@ -68,8 +62,10 @@ private: uint32_t* m_top; uint64_t** m_counts; uint64_t** m_timestamps; - uv_timer_t *m_timer; }; +} // namespace xmrig + + #endif /* XMRIG_HASHRATE_H */ diff --git a/src/backend/common/Workers.cpp b/src/backend/common/Workers.cpp index 987ca526..c4ac38a5 100644 --- a/src/backend/common/Workers.cpp +++ b/src/backend/common/Workers.cpp @@ -24,6 +24,7 @@ */ +#include "backend/common/Hashrate.h" #include "backend/common/Workers.h" #include "backend/cpu/CpuWorker.h" #include "base/io/log/Log.h" @@ -37,13 +38,16 @@ class WorkersPrivate public: inline WorkersPrivate() { - } inline ~WorkersPrivate() { + delete hashrate; } + + + Hashrate *hashrate = nullptr; }; @@ -65,6 +69,13 @@ xmrig::Workers::~Workers() } +template +const xmrig::Hashrate *xmrig::Workers::hashrate() const +{ + return d_ptr->hashrate; +} + + template void xmrig::Workers::add(const T &data) { @@ -75,6 +86,8 @@ void xmrig::Workers::add(const T &data) template void xmrig::Workers::start() { + d_ptr->hashrate = new Hashrate(m_workers.size()); + for (Thread *worker : m_workers) { worker->start(Workers::onReady); } @@ -92,13 +105,34 @@ void xmrig::Workers::stop() m_workers.clear(); Nonce::touch(T::backend()); + + delete d_ptr->hashrate; + d_ptr->hashrate = nullptr; } template -void xmrig::Workers::onReady(void *arg) +void xmrig::Workers::tick(uint64_t) +{ + if (!d_ptr->hashrate) { + return; + } + + for (Thread *handle : m_workers) { + if (!handle->worker()) { + return; + } + + d_ptr->hashrate->add(handle->index(), handle->worker()->hashCount(), handle->worker()->timestamp()); + } + + d_ptr->hashrate->updateHighest(); +} + + +template +void xmrig::Workers::onReady(void *) { - printf("ON READY\n"); } diff --git a/src/backend/common/Workers.h b/src/backend/common/Workers.h index 25f81c5b..3ef4b015 100644 --- a/src/backend/common/Workers.h +++ b/src/backend/common/Workers.h @@ -34,6 +34,7 @@ namespace xmrig { +class Hashrate; class WorkersPrivate; @@ -44,9 +45,11 @@ public: Workers(); ~Workers(); + const Hashrate *hashrate() const; void add(const T &data); void start(); void stop(); + void tick(uint64_t ticks); private: static void onReady(void *arg); diff --git a/src/backend/common/common.cmake b/src/backend/common/common.cmake index bb84af58..c470ea50 100644 --- a/src/backend/common/common.cmake +++ b/src/backend/common/common.cmake @@ -2,6 +2,7 @@ set(HEADERS_BACKEND_COMMON src/backend/common/interfaces/IBackend.h src/backend/common/interfaces/IThread.h src/backend/common/interfaces/IWorker.h + src/backend/common/Hashrate.h src/backend/common/Thread.h src/backend/common/Threads.h src/backend/common/Worker.h @@ -10,6 +11,7 @@ set(HEADERS_BACKEND_COMMON ) set(SOURCES_BACKEND_COMMON + src/backend/common/Hashrate.cpp src/backend/common/Threads.cpp src/backend/common/Worker.cpp src/backend/common/Workers.cpp diff --git a/src/backend/common/interfaces/IBackend.h b/src/backend/common/interfaces/IBackend.h index d6fe1695..69ed4c8c 100644 --- a/src/backend/common/interfaces/IBackend.h +++ b/src/backend/common/interfaces/IBackend.h @@ -32,6 +32,7 @@ namespace xmrig { +class Hashrate; class Job; class String; @@ -41,6 +42,7 @@ class IBackend public: virtual ~IBackend() = default; + virtual const Hashrate *hashrate() const = 0; virtual const String &profileName() const = 0; virtual void printHashrate(bool details) = 0; virtual void setJob(const Job &job) = 0; diff --git a/src/backend/cpu/CpuBackend.cpp b/src/backend/cpu/CpuBackend.cpp index a1ae5747..c8d38ca6 100644 --- a/src/backend/cpu/CpuBackend.cpp +++ b/src/backend/cpu/CpuBackend.cpp @@ -23,17 +23,16 @@ */ +#include "backend/common/Hashrate.h" #include "backend/common/Workers.h" #include "backend/cpu/CpuBackend.h" +#include "base/io/log/Log.h" #include "base/net/stratum/Job.h" #include "base/tools/String.h" #include "core/config/Config.h" #include "core/Controller.h" -#include "base/io/log/Log.h" - - namespace xmrig { @@ -98,6 +97,12 @@ xmrig::CpuBackend::~CpuBackend() } +const xmrig::Hashrate *xmrig::CpuBackend::hashrate() const +{ + return d_ptr->workers.hashrate(); +} + + const xmrig::String &xmrig::CpuBackend::profileName() const { return d_ptr->profileName; @@ -106,7 +111,26 @@ const xmrig::String &xmrig::CpuBackend::profileName() const void xmrig::CpuBackend::printHashrate(bool details) { + if (!details || !hashrate()) { + return; + } + char num[8 * 3] = { 0 }; + + Log::print(WHITE_BOLD_S "| CPU THREAD | AFFINITY | 10s H/s | 60s H/s | 15m H/s |"); + + size_t i = 0; + for (const CpuThread &thread : d_ptr->threads) { + Log::print("| %13zu | %8" PRId64 " | %7s | %7s | %7s |", + i, + thread.affinity(), + Hashrate::format(hashrate()->calc(i, Hashrate::ShortInterval), num, sizeof num / 3), + 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) + ); + + i++; + } } @@ -147,5 +171,5 @@ void xmrig::CpuBackend::stop() void xmrig::CpuBackend::tick(uint64_t ticks) { - + d_ptr->workers.tick(ticks); } diff --git a/src/backend/cpu/CpuBackend.h b/src/backend/cpu/CpuBackend.h index d39ab38d..a7b742eb 100644 --- a/src/backend/cpu/CpuBackend.h +++ b/src/backend/cpu/CpuBackend.h @@ -44,6 +44,7 @@ public: ~CpuBackend() override; protected: + const Hashrate *hashrate() const override; const String &profileName() const override; void printHashrate(bool details) override; void setJob(const Job &job) override; diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 1f819694..83ce2206 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -26,6 +26,7 @@ #include +#include "backend/common/Hashrate.h" #include "backend/cpu/CpuBackend.h" #include "base/io/log/Log.h" #include "base/net/stratum/Job.h" @@ -35,8 +36,6 @@ #include "core/Miner.h" #include "crypto/common/Nonce.h" -#include "base/tools/Chrono.h" - namespace xmrig { @@ -83,6 +82,7 @@ public: bool active = false; bool enabled = true; Controller *controller; + double maxHashrate = 0.0; Job job; std::vector backends; Timer *timer = nullptr; @@ -116,6 +116,12 @@ bool xmrig::Miner::isEnabled() const } +const std::vector &xmrig::Miner::backends() const +{ + return d_ptr->backends; +} + + xmrig::Job xmrig::Miner::job() const { uv_rwlock_rdlock(&d_ptr->rwlock); @@ -137,9 +143,26 @@ void xmrig::Miner::pause() void xmrig::Miner::printHashrate(bool details) { + char num[8 * 4] = { 0 }; + double speed[3] = { 0.0 }; + for (IBackend *backend : d_ptr->backends) { + const Hashrate *hashrate = backend->hashrate(); + if (hashrate) { + speed[0] += hashrate->calc(Hashrate::ShortInterval); + speed[1] += hashrate->calc(Hashrate::MediumInterval); + speed[2] += hashrate->calc(Hashrate::LargeInterval); + } + backend->printHashrate(details); } + + LOG_INFO(WHITE_BOLD("speed") " 10s/60s/15m " CYAN_BOLD("%s") CYAN(" %s %s ") CYAN_BOLD("H/s") " max " CYAN_BOLD("%s H/s"), + Hashrate::format(speed[0], num, sizeof(num) / 4), + Hashrate::format(speed[1], num + 8, sizeof(num) / 4), + Hashrate::format(speed[2], num + 8 * 2, sizeof(num) / 4 ), + Hashrate::format(d_ptr->maxHashrate, num + 8 * 3, sizeof(num) / 4) + ); } @@ -203,10 +226,18 @@ void xmrig::Miner::stop() void xmrig::Miner::onTimer(const Timer *) { + double maxHashrate = 0.0; + for (IBackend *backend : d_ptr->backends) { backend->tick(d_ptr->ticks); + + if (backend->hashrate()) { + maxHashrate += backend->hashrate()->calc(Hashrate::ShortInterval); + } } + d_ptr->maxHashrate = std::max(d_ptr->maxHashrate, maxHashrate); + if ((d_ptr->ticks % (d_ptr->controller->config()->printTime() * 2)) == 0) { printHashrate(false); } diff --git a/src/core/Miner.h b/src/core/Miner.h index e7904575..f32524a7 100644 --- a/src/core/Miner.h +++ b/src/core/Miner.h @@ -26,6 +26,9 @@ #define XMRIG_MINER_H +#include + + #include "base/kernel/interfaces/ITimerListener.h" @@ -35,6 +38,7 @@ namespace xmrig { class Controller; class Job; class MinerPrivate; +class IBackend; class Miner : public ITimerListener @@ -44,6 +48,7 @@ public: ~Miner() override; bool isEnabled() const; + const std::vector &backends() const; Job job() const; void pause(); void printHashrate(bool details); diff --git a/src/workers/WorkersLegacy.cpp b/src/workers/WorkersLegacy.cpp index 29571608..0db0a3cf 100644 --- a/src/workers/WorkersLegacy.cpp +++ b/src/workers/WorkersLegacy.cpp @@ -40,13 +40,13 @@ #include "crypto/rx/RxDataset.h" #include "Mem.h" #include "rapidjson/document.h" -#include "workers/Hashrate.h" +//#include "workers/Hashrate.h" #include "workers/WorkersLegacy.h" bool WorkersLegacy::m_active = false; bool WorkersLegacy::m_enabled = true; -Hashrate *WorkersLegacy::m_hashrate = nullptr; +//Hashrate *WorkersLegacy::m_hashrate = nullptr; xmrig::Job WorkersLegacy::m_job; WorkersLegacy::LaunchStatus WorkersLegacy::m_status; std::vector* > WorkersLegacy::m_workers; @@ -96,38 +96,6 @@ size_t WorkersLegacy::threads() //} -//void Workers::printHashrate(bool detail) -//{ -// assert(m_controller != nullptr); -// if (!m_controller) { -// return; -// } - -// if (detail) { -// char num1[8] = { 0 }; -// char num2[8] = { 0 }; -// char num3[8] = { 0 }; - -// xmrig::Log::print(WHITE_BOLD_S "| THREAD | AFFINITY | 10s H/s | 60s H/s | 15m H/s |"); - -// size_t i = 0; -// for (const xmrig::IThread *thread : m_controller->config()->threads()) { -// xmrig::Log::print("| %6zu | %8" PRId64 " | %7s | %7s | %7s |", -// thread->index(), -// thread->affinity(), -// Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::ShortInterval), num1, sizeof num1), -// Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::MediumInterval), num2, sizeof num2), -// Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::LargeInterval), num3, sizeof num3) -// ); - -// i++; -// } -// } - -// m_hashrate->print(); -//} - - //void Workers::setEnabled(bool enabled) //{ // if (m_enabled == enabled) { @@ -186,7 +154,7 @@ void WorkersLegacy::start(xmrig::Controller *controller) m_status.ways += thread.intensity(); } - m_hashrate = new Hashrate(threads.size(), controller); +// m_hashrate = new Hashrate(threads.size(), controller); uv_mutex_init(&m_mutex); uv_rwlock_init(&m_rwlock); @@ -238,66 +206,24 @@ void WorkersLegacy::threadsSummary(rapidjson::Document &doc) #endif -//void WorkersLegacy::onReady(void *arg) +//void WorkersLegacy::onTick(uv_timer_t *) //{ // using namespace xmrig; -// auto handle = static_cast* >(arg); +// for (Thread *handle : m_workers) { +// if (!handle->worker()) { +// return; +// } -// xmrig::IWorker *worker = nullptr; - -// switch (handle->config().intensity) { -// case 1: -// worker = new CpuWorker<1>(handle->index(), handle->config()); -// break; - -// case 2: -// worker = new CpuWorker<2>(handle->index(), handle->config()); -// break; - -// case 3: -// worker = new CpuWorker<3>(handle->index(), handle->config()); -// break; - -// case 4: -// worker = new CpuWorker<4>(handle->index(), handle->config()); -// break; - -// case 5: -// worker = new CpuWorker<5>(handle->index(), handle->config()); -// break; +// m_hashrate->add(handle->index(), handle->worker()->hashCount(), handle->worker()->timestamp()); // } -// handle->setWorker(worker); - -// if (!worker->selfTest()) { -// LOG_ERR("thread %zu error: \"hash self-test failed\".", handle->worker()->id()); - -// return; +// if ((m_ticks++ & 0xF) == 0) { +// m_hashrate->updateHighest(); // } - -// start(worker); //} -void WorkersLegacy::onTick(uv_timer_t *) -{ - using namespace xmrig; - - for (Thread *handle : m_workers) { - if (!handle->worker()) { - return; - } - - m_hashrate->add(handle->index(), handle->worker()->hashCount(), handle->worker()->timestamp()); - } - - if ((m_ticks++ & 0xF) == 0) { - m_hashrate->updateHighest(); - } -} - - void WorkersLegacy::start(xmrig::IWorker *worker) { // const Worker *w = static_cast(worker); diff --git a/src/workers/WorkersLegacy.h b/src/workers/WorkersLegacy.h index 5ee53dbf..be9e417a 100644 --- a/src/workers/WorkersLegacy.h +++ b/src/workers/WorkersLegacy.h @@ -42,7 +42,7 @@ #include "rapidjson/fwd.h" -class Hashrate; +//class Hashrate; namespace xmrig { @@ -66,7 +66,7 @@ public: // static xmrig::Job job(); // static inline bool isEnabled() { return m_enabled; } - static inline Hashrate *hashrate() { return m_hashrate; } +// static inline Hashrate *hashrate() { return m_hashrate; } # ifdef XMRIG_FEATURE_API static void threadsSummary(rapidjson::Document &doc); @@ -74,7 +74,7 @@ public: private: // static void onReady(void *arg); - static void onTick(uv_timer_t *handle); +// static void onTick(uv_timer_t *handle); static void start(xmrig::IWorker *worker); class LaunchStatus @@ -98,7 +98,7 @@ private: static bool m_active; static bool m_enabled; - static Hashrate *m_hashrate; +// static Hashrate *m_hashrate; static xmrig::Job m_job; static LaunchStatus m_status; static std::vector* > m_workers; From 20313cbc569442f1a7440607c7885ade2f207241 Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 17 Jul 2019 04:33:11 +0700 Subject: [PATCH 33/65] Implemented unified cryptonight and RandomX scratchpad memory. --- CMakeLists.txt | 2 + src/Mem.cpp | 51 ------------------ src/Mem.h | 2 - src/api/v1/ApiRouter.cpp | 2 +- src/backend/common/Worker.h | 7 +-- src/backend/common/interfaces/IWorker.h | 14 +++-- src/backend/cpu/CpuBackend.cpp | 10 ++-- src/backend/cpu/CpuWorker.cpp | 48 ++++++++++++----- src/backend/cpu/CpuWorker.h | 7 +-- src/crypto/cn/CnCtx.cpp | 60 +++++++++++++++++++++ src/crypto/cn/CnCtx.h | 52 ++++++++++++++++++ src/crypto/common/VirtualMemory.h | 20 +++++++ src/crypto/common/VirtualMemory_unix.cpp | 42 +++++++++++++++ src/crypto/common/VirtualMemory_win.cpp | 31 +++++++++++ src/crypto/randomx/randomx.cpp | 44 +++------------ src/crypto/randomx/randomx.h | 2 +- src/crypto/randomx/virtual_machine.cpp | 40 ++++++-------- src/crypto/randomx/virtual_machine.hpp | 19 ++++--- src/crypto/randomx/vm_compiled.cpp | 22 ++++---- src/crypto/randomx/vm_compiled.hpp | 28 +++++----- src/crypto/randomx/vm_compiled_light.cpp | 20 ++++--- src/crypto/randomx/vm_compiled_light.hpp | 27 +++++----- src/crypto/randomx/vm_interpreted.cpp | 30 +++++------ src/crypto/randomx/vm_interpreted.hpp | 31 ++++++----- src/crypto/randomx/vm_interpreted_light.cpp | 14 +++-- src/crypto/randomx/vm_interpreted_light.hpp | 18 ++++--- src/crypto/rx/RxVm.cpp | 18 +------ src/crypto/rx/RxVm.h | 2 +- src/workers/WorkersLegacy.cpp | 58 ++++++++++---------- src/workers/WorkersLegacy.h | 10 ++-- 30 files changed, 434 insertions(+), 297 deletions(-) create mode 100644 src/crypto/cn/CnCtx.cpp create mode 100644 src/crypto/cn/CnCtx.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 543836c8..f8a56c48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ set(HEADERS_CRYPTO src/crypto/cn/c_jh.h src/crypto/cn/c_skein.h src/crypto/cn/CnAlgo.h + src/crypto/cn/CnCtx.h src/crypto/cn/CnHash.h src/crypto/cn/CryptoNight_monero.h src/crypto/cn/CryptoNight_test.h @@ -100,6 +101,7 @@ set(SOURCES_CRYPTO src/crypto/cn/c_groestl.c src/crypto/cn/c_jh.c src/crypto/cn/c_skein.c + src/crypto/cn/CnCtx.cpp src/crypto/cn/CnHash.cpp src/crypto/common/Algorithm.cpp src/crypto/common/keccak.cpp diff --git a/src/Mem.cpp b/src/Mem.cpp index e8eabe3b..5fcea306 100644 --- a/src/Mem.cpp +++ b/src/Mem.cpp @@ -24,59 +24,8 @@ */ -#include - - -#include "crypto/cn/CryptoNight.h" -#include "crypto/common/portable/mm_malloc.h" -#include "crypto/common/VirtualMemory.h" #include "Mem.h" bool Mem::m_enabled = true; int Mem::m_flags = 0; - - -MemInfo Mem::create(cryptonight_ctx **ctx, const xmrig::Algorithm &algorithm, size_t count) -{ - using namespace xmrig; - - constexpr CnAlgo props; - - MemInfo info; - info.size = props.memory(algorithm.id()) * count; - - constexpr const size_t align_size = 2 * 1024 * 1024; - info.size = ((info.size + align_size - 1) / align_size) * align_size; - info.pages = info.size / align_size; - - allocate(info, m_enabled); - - for (size_t i = 0; i < count; ++i) { - cryptonight_ctx *c = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 4096)); - c->memory = info.memory + (i * props.memory(algorithm.id())); - - c->generated_code = reinterpret_cast(VirtualMemory::allocateExecutableMemory(0x4000)); - c->generated_code_data.algo = Algorithm::INVALID; - c->generated_code_data.height = std::numeric_limits::max(); - - ctx[i] = c; - } - - return info; -} - - -void Mem::release(cryptonight_ctx **ctx, size_t count, MemInfo &info) -{ - if (info.memory == nullptr) { - return; - } - - release(info); - - for (size_t i = 0; i < count; ++i) { - _mm_free(ctx[i]); - } -} - diff --git a/src/Mem.h b/src/Mem.h index 5c60d281..8e5c418b 100644 --- a/src/Mem.h +++ b/src/Mem.h @@ -56,9 +56,7 @@ public: Lock = 4 }; - static MemInfo create(cryptonight_ctx **ctx, const xmrig::Algorithm &algorithm, size_t count); static void init(bool enabled); - static void release(cryptonight_ctx **ctx, size_t count, MemInfo &info); static inline bool isHugepagesAvailable() { return (m_flags & HugepagesAvailable) != 0; } diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp index 48a92c93..2e6a815c 100644 --- a/src/api/v1/ApiRouter.cpp +++ b/src/api/v1/ApiRouter.cpp @@ -144,7 +144,7 @@ void xmrig::ApiRouter::getMiner(rapidjson::Value &reply, rapidjson::Document &do reply.AddMember("kind", APP_KIND, allocator); reply.AddMember("ua", StringRef(Platform::userAgent()), allocator); reply.AddMember("cpu", cpu, allocator); - reply.AddMember("hugepages", WorkersLegacy::hugePages() > 0, allocator); + reply.AddMember("hugepages", false, allocator); // FIXME hugepages reply.AddMember("donate_level", m_base->config()->pools().donateLevel(), allocator); } diff --git a/src/backend/common/Worker.h b/src/backend/common/Worker.h index 3223a60c..faebf128 100644 --- a/src/backend/common/Worker.h +++ b/src/backend/common/Worker.h @@ -42,9 +42,10 @@ class Worker : public IWorker public: Worker(size_t id, int64_t affinity, int priority); - inline size_t id() const override { return m_id; } - inline uint64_t hashCount() const override { return m_hashCount.load(std::memory_order_relaxed); } - inline uint64_t timestamp() const override { return m_timestamp.load(std::memory_order_relaxed); } + inline const VirtualMemory *memory() const override { return nullptr; } + inline size_t id() const override { return m_id; } + inline uint64_t hashCount() const override { return m_hashCount.load(std::memory_order_relaxed); } + inline uint64_t timestamp() const override { return m_timestamp.load(std::memory_order_relaxed); } protected: void storeStats(); diff --git a/src/backend/common/interfaces/IWorker.h b/src/backend/common/interfaces/IWorker.h index de22de02..5c99680b 100644 --- a/src/backend/common/interfaces/IWorker.h +++ b/src/backend/common/interfaces/IWorker.h @@ -32,16 +32,20 @@ namespace xmrig { +class VirtualMemory; + + class IWorker { public: virtual ~IWorker() = default; - virtual bool selfTest() = 0; - virtual size_t id() const = 0; - virtual uint64_t hashCount() const = 0; - virtual uint64_t timestamp() const = 0; - virtual void start() = 0; + virtual bool selfTest() = 0; + virtual const VirtualMemory *memory() const = 0; + virtual size_t id() const = 0; + virtual uint64_t hashCount() const = 0; + virtual uint64_t timestamp() const = 0; + virtual void start() = 0; }; diff --git a/src/backend/cpu/CpuBackend.cpp b/src/backend/cpu/CpuBackend.cpp index c8d38ca6..a0463832 100644 --- a/src/backend/cpu/CpuBackend.cpp +++ b/src/backend/cpu/CpuBackend.cpp @@ -136,14 +136,10 @@ void xmrig::CpuBackend::printHashrate(bool details) void xmrig::CpuBackend::setJob(const Job &job) { - LOG_WARN("PROFILE %s %zu", d_ptr->controller->config()->cpu().threads().profileName(job.algorithm()).data(), job.algorithm().memory()); - if (d_ptr->isReady(job.algorithm())) { return; } - LOG_INFO(GREEN_BOLD_S "INIT"); - const CpuConfig &cpu = d_ptr->controller->config()->cpu(); const Threads &threads = cpu.threads(); @@ -151,7 +147,11 @@ void xmrig::CpuBackend::setJob(const Job &job) d_ptr->profileName = threads.profileName(job.algorithm()); d_ptr->threads = threads.get(d_ptr->profileName); - LOG_INFO(BLUE_BG_S " %zu ", d_ptr->threads.size()); + LOG_INFO(GREEN_BOLD("CPU") " use profile " BLUE_BG(WHITE_BOLD_S " %s ") WHITE_BOLD_S " (" CYAN_BOLD("%zu") WHITE_BOLD(" threads)") " scratchpad " CYAN_BOLD("%zu KB"), + d_ptr->profileName.data(), + d_ptr->threads.size(), + d_ptr->algo.memory() / 1024 + ); d_ptr->workers.stop(); diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp index 96466252..356dfb1b 100644 --- a/src/backend/cpu/CpuWorker.cpp +++ b/src/backend/cpu/CpuWorker.cpp @@ -29,8 +29,10 @@ #include "backend/cpu/CpuWorker.h" #include "core/Miner.h" +#include "crypto/cn/CnCtx.h" #include "crypto/cn/CryptoNight_test.h" #include "crypto/common/Nonce.h" +#include "crypto/common/VirtualMemory.h" #include "crypto/rx/Rx.h" #include "crypto/rx/RxVm.h" #include "net/JobResults.h" @@ -56,18 +58,18 @@ xmrig::CpuWorker::CpuWorker(size_t index, const CpuLaunchData &data) : m_assembly(data.assembly), m_hwAES(data.hwAES), m_av(data.av()), - m_miner(data.miner) + m_miner(data.miner), + m_ctx() { - if (m_algorithm.family() != Algorithm::RANDOM_X) { - m_memory = Mem::create(m_ctx, m_algorithm, N); - } + m_memory = new VirtualMemory(m_algorithm.memory() * N, data.hugePages); } template xmrig::CpuWorker::~CpuWorker() { - Mem::release(m_ctx, N, m_memory); + CnCtx::release(m_ctx, N); + delete m_memory; # ifdef XMRIG_ALGO_RANDOMX delete m_vm; @@ -81,7 +83,7 @@ void xmrig::CpuWorker::allocateRandomX_VM() { if (!m_vm) { RxDataset *dataset = Rx::dataset(m_job.currentJob().seedHash(), m_job.currentJob().algorithm()); - m_vm = new RxVm(dataset, true, !m_hwAES); + m_vm = new RxVm(dataset, m_memory->scratchpad(), !m_hwAES); } } #endif @@ -90,6 +92,14 @@ void xmrig::CpuWorker::allocateRandomX_VM() template bool xmrig::CpuWorker::selfTest() { +# ifdef XMRIG_ALGO_RANDOMX + if (m_algorithm.family() == Algorithm::RANDOM_X) { + return true; + } +# endif + + allocateCnCtx(); + if (m_algorithm.family() == Algorithm::CN) { const bool rc = verify(Algorithm::CN_0, test_output_v0) && verify(Algorithm::CN_1, test_output_v1) && @@ -136,12 +146,6 @@ bool xmrig::CpuWorker::selfTest() } # endif -# ifdef XMRIG_ALGO_RANDOMX - if (m_algorithm.family() == Algorithm::RANDOM_X) { - return true; - } -# endif - return false; } @@ -172,7 +176,6 @@ void xmrig::CpuWorker::start() # ifdef XMRIG_ALGO_RANDOMX if (job.algorithm().family() == Algorithm::RANDOM_X) { - allocateRandomX_VM(); randomx_calculate_hash(m_vm->get(), m_job.blob(), job.size(), m_hash); } else @@ -262,10 +265,29 @@ bool CpuWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenceV } // namespace xmrig +template +void xmrig::CpuWorker::allocateCnCtx() +{ + if (m_ctx[0] == nullptr) { + CnCtx::create(m_ctx, m_memory->scratchpad(), m_memory->size(), N); + } +} + + template void xmrig::CpuWorker::consumeJob() { m_job.add(m_miner->job(), Nonce::sequence(Nonce::CPU), kReserveCount); + +# ifdef XMRIG_ALGO_RANDOMX + if (m_job.currentJob().algorithm().family() == Algorithm::RANDOM_X) { + allocateRandomX_VM(); + } + else +# endif + { + allocateCnCtx(); + } } diff --git a/src/backend/cpu/CpuWorker.h b/src/backend/cpu/CpuWorker.h index c67d355b..c0f9dfaf 100644 --- a/src/backend/cpu/CpuWorker.h +++ b/src/backend/cpu/CpuWorker.h @@ -48,12 +48,12 @@ public: CpuWorker(size_t index, const CpuLaunchData &data); ~CpuWorker() override; - inline const MemInfo &memory() const { return m_memory; } - protected: bool selfTest() override; void start() override; + inline const VirtualMemory *memory() const override { return m_memory; } + private: inline cn_hash_fun fn(const Algorithm &algorithm) const { return CnHash::fn(algorithm, m_av, m_assembly); } @@ -63,6 +63,7 @@ private: bool verify(const Algorithm &algorithm, const uint8_t *referenceValue); bool verify2(const Algorithm &algorithm, const uint8_t *referenceValue); + void allocateCnCtx(); void consumeJob(); const Algorithm m_algorithm; @@ -71,8 +72,8 @@ private: const CnHash::AlgoVariant m_av; const Miner *m_miner; cryptonight_ctx *m_ctx[N]; - MemInfo m_memory; uint8_t m_hash[N * 32]; + VirtualMemory *m_memory = nullptr; WorkerJob m_job; # ifdef XMRIG_ALGO_RANDOMX diff --git a/src/crypto/cn/CnCtx.cpp b/src/crypto/cn/CnCtx.cpp new file mode 100644 index 00000000..5d41bca0 --- /dev/null +++ b/src/crypto/cn/CnCtx.cpp @@ -0,0 +1,60 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 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 + + +#include "crypto/cn/CnCtx.h" +#include "crypto/cn/CryptoNight.h" +#include "crypto/common/Algorithm.h" +#include "crypto/common/portable/mm_malloc.h" +#include "crypto/common/VirtualMemory.h" + + +void xmrig::CnCtx::create(cryptonight_ctx **ctx, uint8_t *memory, size_t size, size_t count) +{ + for (size_t i = 0; i < count; ++i) { + cryptonight_ctx *c = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 4096)); + c->memory = memory + (i * size); + + c->generated_code = reinterpret_cast(VirtualMemory::allocateExecutableMemory(0x4000)); + c->generated_code_data.algo = Algorithm::INVALID; + c->generated_code_data.height = std::numeric_limits::max(); + + ctx[i] = c; + } +} + + +void xmrig::CnCtx::release(cryptonight_ctx **ctx, size_t count) +{ + if (ctx[0] == nullptr) { + return; + } + + for (size_t i = 0; i < count; ++i) { + _mm_free(ctx[i]); + } +} diff --git a/src/crypto/cn/CnCtx.h b/src/crypto/cn/CnCtx.h new file mode 100644 index 00000000..7b0adbec --- /dev/null +++ b/src/crypto/cn/CnCtx.h @@ -0,0 +1,52 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 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_CN_CTX_H +#define XMRIG_CN_CTX_H + + +#include +#include + + +struct cryptonight_ctx; + + +namespace xmrig +{ + + +class CnCtx +{ +public: + static void create(cryptonight_ctx **ctx, uint8_t *memory, size_t size, size_t count); + static void release(cryptonight_ctx **ctx, size_t count); +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_CN_CTX_H */ diff --git a/src/crypto/common/VirtualMemory.h b/src/crypto/common/VirtualMemory.h index a83c35ed..98212e40 100644 --- a/src/crypto/common/VirtualMemory.h +++ b/src/crypto/common/VirtualMemory.h @@ -38,6 +38,15 @@ namespace xmrig { class VirtualMemory { public: + inline VirtualMemory() {} + VirtualMemory(size_t size, bool hugePages = true, size_t align = 64); + ~VirtualMemory(); + + inline bool isHugePages() const { return m_flags & HUGEPAGES; } + inline size_t hugePages() const { return isHugePages() ? (align(size()) / 2097152) : 0; } + inline size_t size() const { return m_size; } + inline uint8_t *scratchpad() const { return m_scratchpad; } + static void *allocateExecutableMemory(size_t size); static void *allocateLargePagesMemory(size_t size); static void flushInstructionCache(void *p, size_t size); @@ -46,6 +55,17 @@ public: static void unprotectExecutableMemory(void *p, size_t size); static inline constexpr size_t align(size_t pos, size_t align = 2097152) { return ((pos - 1) / align + 1) * align; } + +private: + enum Flags { + HUGEPAGES_AVAILABLE = 1, + HUGEPAGES = 2, + LOCK = 4 + }; + + int m_flags = 0; + size_t m_size = 0; + uint8_t *m_scratchpad = nullptr; }; diff --git a/src/crypto/common/VirtualMemory_unix.cpp b/src/crypto/common/VirtualMemory_unix.cpp index beac976d..665fc02b 100644 --- a/src/crypto/common/VirtualMemory_unix.cpp +++ b/src/crypto/common/VirtualMemory_unix.cpp @@ -29,6 +29,7 @@ #include +#include "crypto/common/portable/mm_malloc.h" #include "crypto/common/VirtualMemory.h" @@ -37,6 +38,47 @@ #endif +xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) : + m_size(VirtualMemory::align(size)) +{ + if (hugePages) { + m_scratchpad = static_cast(allocateLargePagesMemory(m_size)); + if (m_scratchpad) { + m_flags |= HUGEPAGES; + + madvise(m_scratchpad, size, MADV_RANDOM | MADV_WILLNEED); + + if (mlock(m_scratchpad, m_size) == 0) { + m_flags |= LOCK; + } + + return; + } + } + + m_scratchpad = static_cast(_mm_malloc(m_size, align)); +} + + +xmrig::VirtualMemory::~VirtualMemory() +{ + if (!m_scratchpad) { + return; + } + + if (isHugePages()) { + if (m_flags & LOCK) { + munlock(m_scratchpad, m_size); + } + + freeLargePagesMemory(m_scratchpad, m_size); + } + else { + _mm_free(m_scratchpad); + } +} + + void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size) { diff --git a/src/crypto/common/VirtualMemory_win.cpp b/src/crypto/common/VirtualMemory_win.cpp index 7f1d6f43..7aa98f89 100644 --- a/src/crypto/common/VirtualMemory_win.cpp +++ b/src/crypto/common/VirtualMemory_win.cpp @@ -32,6 +32,37 @@ #include "crypto/common/VirtualMemory.h" +xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) : + m_size(VirtualMemory::align(size)) +{ + if (hugePages) { + m_scratchpad = static_cast(allocateLargePagesMemory(m_size)); + if (m_scratchpad) { + m_flags |= HUGEPAGES; + + return; + } + } + + m_scratchpad = static_cast(_mm_malloc(m_size, align)); +} + + +xmrig::VirtualMemory::~VirtualMemory() +{ + if (!m_scratchpad) { + return; + } + + if (isHugePages()) { + freeLargePagesMemory(m_scratchpad, m_size); + } + else { + _mm_free(m_scratchpad); + } +} + + void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size) { return VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); diff --git a/src/crypto/randomx/randomx.cpp b/src/crypto/randomx/randomx.cpp index dde838b9..df5fc9cb 100644 --- a/src/crypto/randomx/randomx.cpp +++ b/src/crypto/randomx/randomx.cpp @@ -345,7 +345,7 @@ extern "C" { delete dataset; } - randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset) { + randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset, uint8_t *scratchpad) { assert(cache != nullptr || (flags & RANDOMX_FLAG_FULL_MEM)); assert(cache == nullptr || cache->isInitialized()); assert(dataset != nullptr || !(flags & RANDOMX_FLAG_FULL_MEM)); @@ -353,7 +353,7 @@ extern "C" { randomx_vm *vm = nullptr; try { - switch (flags & (RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES)) { + switch (flags & (RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES)) { case RANDOMX_FLAG_DEFAULT: vm = new randomx::InterpretedLightVmDefault(); break; @@ -386,49 +386,19 @@ extern "C" { vm = new randomx::CompiledVmHardAes(); break; - case RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::InterpretedLightVmLargePage(); - break; - - case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::InterpretedVmLargePage(); - break; - - case RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::CompiledLightVmLargePage(); - break; - - case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::CompiledVmLargePage(); - break; - - case RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::InterpretedLightVmLargePageHardAes(); - break; - - case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::InterpretedVmLargePageHardAes(); - break; - - case RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::CompiledLightVmLargePageHardAes(); - break; - - case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::CompiledVmLargePageHardAes(); - break; - default: UNREACHABLE; } - if(cache != nullptr) + if (cache != nullptr) { vm->setCache(cache); + } - if(dataset != nullptr) + if (dataset != nullptr) { vm->setDataset(dataset); + } - vm->allocate(); + vm->setScratchpad(scratchpad); } catch (std::exception &ex) { delete vm; diff --git a/src/crypto/randomx/randomx.h b/src/crypto/randomx/randomx.h index cd07ac64..d688189f 100644 --- a/src/crypto/randomx/randomx.h +++ b/src/crypto/randomx/randomx.h @@ -286,7 +286,7 @@ RANDOMX_EXPORT void randomx_release_dataset(randomx_dataset *dataset); * (3) cache parameter is NULL and RANDOMX_FLAG_FULL_MEM is not set * (4) dataset parameter is NULL and RANDOMX_FLAG_FULL_MEM is set */ -RANDOMX_EXPORT randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset); +RANDOMX_EXPORT randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset, uint8_t *scratchpad); /** * Reinitializes a virtual machine with a new Cache. This function should be called anytime diff --git a/src/crypto/randomx/virtual_machine.cpp b/src/crypto/randomx/virtual_machine.cpp index caa1efbf..6560dc95 100644 --- a/src/crypto/randomx/virtual_machine.cpp +++ b/src/crypto/randomx/virtual_machine.cpp @@ -95,43 +95,35 @@ void randomx_vm::initialize() { namespace randomx { - alignas(16) volatile static rx_vec_i128 aesDummy; - - template - VmBase::~VmBase() { - Allocator::freeMemory(scratchpad, RANDOMX_SCRATCHPAD_L3_MAX_SIZE); + template + VmBase::~VmBase() { } - template - void VmBase::allocate() { - if (datasetPtr == nullptr) + template + void VmBase::setScratchpad(uint8_t *scratchpad) { + if (datasetPtr == nullptr) { throw std::invalid_argument("Cache/Dataset not set"); - if (!softAes) { //if hardware AES is not supported, it's better to fail now than to return a ticking bomb - rx_vec_i128 tmp = rx_load_vec_i128((const rx_vec_i128*)&aesDummy); - tmp = rx_aesenc_vec_i128(tmp, tmp); - rx_store_vec_i128((rx_vec_i128*)&aesDummy, tmp); } - scratchpad = (uint8_t*)Allocator::allocMemory(RANDOMX_SCRATCHPAD_L3_MAX_SIZE); + + this->scratchpad = scratchpad; } - template - void VmBase::getFinalResult(void* out, size_t outSize) { + template + void VmBase::getFinalResult(void* out, size_t outSize) { hashAes1Rx4(scratchpad, ScratchpadSize, ®.a); blake2b(out, outSize, ®, sizeof(RegisterFile), nullptr, 0); } - template - void VmBase::initScratchpad(void* seed) { + template + void VmBase::initScratchpad(void* seed) { fillAes1Rx4(seed, ScratchpadSize, scratchpad); } - template - void VmBase::generateProgram(void* seed) { + template + void VmBase::generateProgram(void* seed) { fillAes4Rx4(seed, sizeof(program), &program); } - template class VmBase, false>; - template class VmBase, true>; - template class VmBase; - template class VmBase; -} \ No newline at end of file + template class VmBase; + template class VmBase; +} diff --git a/src/crypto/randomx/virtual_machine.hpp b/src/crypto/randomx/virtual_machine.hpp index 488994df..cba79d72 100644 --- a/src/crypto/randomx/virtual_machine.hpp +++ b/src/crypto/randomx/virtual_machine.hpp @@ -33,26 +33,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "program.hpp" /* Global namespace for C binding */ -class randomx_vm { +class randomx_vm +{ public: virtual ~randomx_vm() = 0; - virtual void allocate() = 0; + virtual void setScratchpad(uint8_t *scratchpad) = 0; virtual void getFinalResult(void* out, size_t outSize) = 0; virtual void setDataset(randomx_dataset* dataset) { } virtual void setCache(randomx_cache* cache) { } virtual void initScratchpad(void* seed) = 0; virtual void run(void* seed) = 0; void resetRoundingMode(); + randomx::RegisterFile *getRegisterFile() { return ® } + const void* getScratchpad() { return scratchpad; } + const randomx::Program& getProgram() { return program; } + protected: void initialize(); alignas(64) randomx::Program program; @@ -69,15 +74,17 @@ protected: namespace randomx { - template - class VmBase : public randomx_vm { + template + class VmBase : public randomx_vm + { public: ~VmBase() override; - void allocate() override; + void setScratchpad(uint8_t *scratchpad) override; void initScratchpad(void* seed) override; void getFinalResult(void* out, size_t outSize) override; + protected: void generateProgram(void* seed); }; -} \ No newline at end of file +} diff --git a/src/crypto/randomx/vm_compiled.cpp b/src/crypto/randomx/vm_compiled.cpp index 7f621a33..4d14c793 100644 --- a/src/crypto/randomx/vm_compiled.cpp +++ b/src/crypto/randomx/vm_compiled.cpp @@ -34,27 +34,25 @@ namespace randomx { static_assert(sizeof(MemoryRegisters) == 2 * sizeof(addr_t) + sizeof(uintptr_t), "Invalid alignment of struct randomx::MemoryRegisters"); static_assert(sizeof(RegisterFile) == 256, "Invalid alignment of struct randomx::RegisterFile"); - template - void CompiledVm::setDataset(randomx_dataset* dataset) { + template + void CompiledVm::setDataset(randomx_dataset* dataset) { datasetPtr = dataset; } - template - void CompiledVm::run(void* seed) { - VmBase::generateProgram(seed); + template + void CompiledVm::run(void* seed) { + VmBase::generateProgram(seed); randomx_vm::initialize(); compiler.generateProgram(program, config); mem.memory = datasetPtr->memory + datasetOffset; execute(); } - template - void CompiledVm::execute() { + template + void CompiledVm::execute() { compiler.getProgramFunc()(reg, mem, scratchpad, RandomX_CurrentConfig.ProgramIterations); } - template class CompiledVm, false>; - template class CompiledVm, true>; - template class CompiledVm; - template class CompiledVm; -} \ No newline at end of file + template class CompiledVm; + template class CompiledVm; +} diff --git a/src/crypto/randomx/vm_compiled.hpp b/src/crypto/randomx/vm_compiled.hpp index 856f00d8..05b34b9c 100644 --- a/src/crypto/randomx/vm_compiled.hpp +++ b/src/crypto/randomx/vm_compiled.hpp @@ -37,8 +37,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - class CompiledVm : public VmBase { + template + class CompiledVm : public VmBase + { public: void* operator new(size_t size) { void* ptr = AlignedAllocator::allocMemory(size); @@ -46,27 +47,28 @@ namespace randomx { throw std::bad_alloc(); return ptr; } + void operator delete(void* ptr) { AlignedAllocator::freeMemory(ptr, sizeof(CompiledVm)); } + void setDataset(randomx_dataset* dataset) override; void run(void* seed) override; - using VmBase::mem; - using VmBase::program; - using VmBase::config; - using VmBase::reg; - using VmBase::scratchpad; - using VmBase::datasetPtr; - using VmBase::datasetOffset; + using VmBase::mem; + using VmBase::program; + using VmBase::config; + using VmBase::reg; + using VmBase::scratchpad; + using VmBase::datasetPtr; + using VmBase::datasetOffset; + protected: void execute(); JitCompiler compiler; }; - using CompiledVmDefault = CompiledVm, true>; - using CompiledVmHardAes = CompiledVm, false>; - using CompiledVmLargePage = CompiledVm; - using CompiledVmLargePageHardAes = CompiledVm; + using CompiledVmDefault = CompiledVm; + using CompiledVmHardAes = CompiledVm; } diff --git a/src/crypto/randomx/vm_compiled_light.cpp b/src/crypto/randomx/vm_compiled_light.cpp index c083f4aa..6009216b 100644 --- a/src/crypto/randomx/vm_compiled_light.cpp +++ b/src/crypto/randomx/vm_compiled_light.cpp @@ -32,23 +32,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - void CompiledLightVm::setCache(randomx_cache* cache) { + template + void CompiledLightVm::setCache(randomx_cache* cache) { cachePtr = cache; mem.memory = cache->memory; compiler.generateSuperscalarHash(cache->programs, cache->reciprocalCache); } - template - void CompiledLightVm::run(void* seed) { - VmBase::generateProgram(seed); + template + void CompiledLightVm::run(void* seed) { + VmBase::generateProgram(seed); randomx_vm::initialize(); compiler.generateProgramLight(program, config, datasetOffset); - CompiledVm::execute(); + CompiledVm::execute(); } - template class CompiledLightVm, false>; - template class CompiledLightVm, true>; - template class CompiledLightVm; - template class CompiledLightVm; -} \ No newline at end of file + template class CompiledLightVm; + template class CompiledLightVm; +} diff --git a/src/crypto/randomx/vm_compiled_light.hpp b/src/crypto/randomx/vm_compiled_light.hpp index 6af82bbe..6cd3cb20 100644 --- a/src/crypto/randomx/vm_compiled_light.hpp +++ b/src/crypto/randomx/vm_compiled_light.hpp @@ -33,8 +33,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - class CompiledLightVm : public CompiledVm { + template + class CompiledLightVm : public CompiledVm + { public: void* operator new(size_t size) { void* ptr = AlignedAllocator::allocMemory(size); @@ -42,23 +43,23 @@ namespace randomx { throw std::bad_alloc(); return ptr; } + void operator delete(void* ptr) { AlignedAllocator::freeMemory(ptr, sizeof(CompiledLightVm)); } + void setCache(randomx_cache* cache) override; void setDataset(randomx_dataset* dataset) override { } void run(void* seed) override; - using CompiledVm::mem; - using CompiledVm::compiler; - using CompiledVm::program; - using CompiledVm::config; - using CompiledVm::cachePtr; - using CompiledVm::datasetOffset; + using CompiledVm::mem; + using CompiledVm::compiler; + using CompiledVm::program; + using CompiledVm::config; + using CompiledVm::cachePtr; + using CompiledVm::datasetOffset; }; - using CompiledLightVmDefault = CompiledLightVm, true>; - using CompiledLightVmHardAes = CompiledLightVm, false>; - using CompiledLightVmLargePage = CompiledLightVm; - using CompiledLightVmLargePageHardAes = CompiledLightVm; -} \ No newline at end of file + using CompiledLightVmDefault = CompiledLightVm; + using CompiledLightVmHardAes = CompiledLightVm; +} diff --git a/src/crypto/randomx/vm_interpreted.cpp b/src/crypto/randomx/vm_interpreted.cpp index 236d3efe..f4c1e05c 100644 --- a/src/crypto/randomx/vm_interpreted.cpp +++ b/src/crypto/randomx/vm_interpreted.cpp @@ -33,21 +33,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - void InterpretedVm::setDataset(randomx_dataset* dataset) { + template + void InterpretedVm::setDataset(randomx_dataset* dataset) { datasetPtr = dataset; mem.memory = dataset->memory; } - template - void InterpretedVm::run(void* seed) { - VmBase::generateProgram(seed); + template + void InterpretedVm::run(void* seed) { + VmBase::generateProgram(seed); randomx_vm::initialize(); execute(); } - template - void InterpretedVm::execute() { + template + void InterpretedVm::execute() { NativeRegisterFile nreg; @@ -106,20 +106,18 @@ namespace randomx { rx_store_vec_f128(®.e[i].lo, nreg.e[i]); } - template - void InterpretedVm::datasetRead(uint64_t address, int_reg_t(&r)[RegistersCount]) { + template + void InterpretedVm::datasetRead(uint64_t address, int_reg_t(&r)[RegistersCount]) { uint64_t* datasetLine = (uint64_t*)(mem.memory + address); for (int i = 0; i < RegistersCount; ++i) r[i] ^= datasetLine[i]; } - template - void InterpretedVm::datasetPrefetch(uint64_t address) { + template + void InterpretedVm::datasetPrefetch(uint64_t address) { rx_prefetch_nta(mem.memory + address); } - template class InterpretedVm, false>; - template class InterpretedVm, true>; - template class InterpretedVm; - template class InterpretedVm; -} \ No newline at end of file + template class InterpretedVm; + template class InterpretedVm; +} diff --git a/src/crypto/randomx/vm_interpreted.hpp b/src/crypto/randomx/vm_interpreted.hpp index 99c88852..1dc9ab6d 100644 --- a/src/crypto/randomx/vm_interpreted.hpp +++ b/src/crypto/randomx/vm_interpreted.hpp @@ -38,38 +38,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - class InterpretedVm : public VmBase, public BytecodeMachine { + template + class InterpretedVm : public VmBase, public BytecodeMachine { public: - using VmBase::mem; - using VmBase::scratchpad; - using VmBase::program; - using VmBase::config; - using VmBase::reg; - using VmBase::datasetPtr; - using VmBase::datasetOffset; + using VmBase::mem; + using VmBase::scratchpad; + using VmBase::program; + using VmBase::config; + using VmBase::reg; + using VmBase::datasetPtr; + using VmBase::datasetOffset; + void* operator new(size_t size) { void* ptr = AlignedAllocator::allocMemory(size); if (ptr == nullptr) throw std::bad_alloc(); return ptr; } + void operator delete(void* ptr) { AlignedAllocator::freeMemory(ptr, sizeof(InterpretedVm)); } + void run(void* seed) override; void setDataset(randomx_dataset* dataset) override; + protected: virtual void datasetRead(uint64_t blockNumber, int_reg_t(&r)[RegistersCount]); virtual void datasetPrefetch(uint64_t blockNumber); + private: void execute(); InstructionByteCode bytecode[RANDOMX_PROGRAM_MAX_SIZE]; }; - using InterpretedVmDefault = InterpretedVm, true>; - using InterpretedVmHardAes = InterpretedVm, false>; - using InterpretedVmLargePage = InterpretedVm; - using InterpretedVmLargePageHardAes = InterpretedVm; -} \ No newline at end of file + using InterpretedVmDefault = InterpretedVm; + using InterpretedVmHardAes = InterpretedVm; +} diff --git a/src/crypto/randomx/vm_interpreted_light.cpp b/src/crypto/randomx/vm_interpreted_light.cpp index c54b32f6..9c97187b 100644 --- a/src/crypto/randomx/vm_interpreted_light.cpp +++ b/src/crypto/randomx/vm_interpreted_light.cpp @@ -31,14 +31,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - void InterpretedLightVm::setCache(randomx_cache* cache) { + template + void InterpretedLightVm::setCache(randomx_cache* cache) { cachePtr = cache; mem.memory = cache->memory; } - template - void InterpretedLightVm::datasetRead(uint64_t address, int_reg_t(&r)[8]) { + template + void InterpretedLightVm::datasetRead(uint64_t address, int_reg_t(&r)[8]) { uint32_t itemNumber = address / CacheLineSize; int_reg_t rl[8]; @@ -48,8 +48,6 @@ namespace randomx { r[q] ^= rl[q]; } - template class InterpretedLightVm, false>; - template class InterpretedLightVm, true>; - template class InterpretedLightVm; - template class InterpretedLightVm; + template class InterpretedLightVm; + template class InterpretedLightVm; } diff --git a/src/crypto/randomx/vm_interpreted_light.hpp b/src/crypto/randomx/vm_interpreted_light.hpp index 02d678f6..1a35c580 100644 --- a/src/crypto/randomx/vm_interpreted_light.hpp +++ b/src/crypto/randomx/vm_interpreted_light.hpp @@ -33,29 +33,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - class InterpretedLightVm : public InterpretedVm { + template + class InterpretedLightVm : public InterpretedVm { public: - using VmBase::mem; - using VmBase::cachePtr; + using VmBase::mem; + using VmBase::cachePtr; + void* operator new(size_t size) { void* ptr = AlignedAllocator::allocMemory(size); if (ptr == nullptr) throw std::bad_alloc(); return ptr; } + void operator delete(void* ptr) { AlignedAllocator::freeMemory(ptr, sizeof(InterpretedLightVm)); } + void setDataset(randomx_dataset* dataset) override { } void setCache(randomx_cache* cache) override; + protected: void datasetRead(uint64_t address, int_reg_t(&r)[8]) override; void datasetPrefetch(uint64_t address) override { } }; - using InterpretedLightVmDefault = InterpretedLightVm, true>; - using InterpretedLightVmHardAes = InterpretedLightVm, false>; - using InterpretedLightVmLargePage = InterpretedLightVm; - using InterpretedLightVmLargePageHardAes = InterpretedLightVm; + using InterpretedLightVmDefault = InterpretedLightVm; + using InterpretedLightVmHardAes = InterpretedLightVm; } diff --git a/src/crypto/rx/RxVm.cpp b/src/crypto/rx/RxVm.cpp index b02f708e..6426443a 100644 --- a/src/crypto/rx/RxVm.cpp +++ b/src/crypto/rx/RxVm.cpp @@ -31,12 +31,8 @@ #include "crypto/rx/RxVm.h" -xmrig::RxVm::RxVm(RxDataset *dataset, bool hugePages, bool softAes) +xmrig::RxVm::RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes) { - if (hugePages) { - m_flags |= RANDOMX_FLAG_LARGE_PAGES; - } - if (!softAes) { m_flags |= RANDOMX_FLAG_HARD_AES; } @@ -49,17 +45,7 @@ xmrig::RxVm::RxVm(RxDataset *dataset, bool hugePages, bool softAes) m_flags |= RANDOMX_FLAG_JIT; } - m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache()->get(), dataset->get()); - - if (!m_vm) { - m_flags &= ~RANDOMX_FLAG_LARGE_PAGES; - m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache()->get(), dataset->get()); - } - - if (!m_vm) { - m_flags &= ~RANDOMX_FLAG_HARD_AES; - m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache()->get(), dataset->get()); - } + m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache()->get(), dataset->get(), scratchpad); } diff --git a/src/crypto/rx/RxVm.h b/src/crypto/rx/RxVm.h index 90af8187..d7e617e4 100644 --- a/src/crypto/rx/RxVm.h +++ b/src/crypto/rx/RxVm.h @@ -44,7 +44,7 @@ class RxDataset; class RxVm { public: - RxVm(RxDataset *dataset, bool hugePages, bool softAes); + RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes); ~RxVm(); inline randomx_vm *get() const { return m_vm; } diff --git a/src/workers/WorkersLegacy.cpp b/src/workers/WorkersLegacy.cpp index 0db0a3cf..4d6f9de9 100644 --- a/src/workers/WorkersLegacy.cpp +++ b/src/workers/WorkersLegacy.cpp @@ -67,24 +67,24 @@ xmrig::Controller *WorkersLegacy::m_controller = nullptr; //} -size_t WorkersLegacy::hugePages() -{ - uv_mutex_lock(&m_mutex); - const size_t hugePages = m_status.hugePages; - uv_mutex_unlock(&m_mutex); +//size_t WorkersLegacy::hugePages() +//{ +// uv_mutex_lock(&m_mutex); +// const size_t hugePages = m_status.hugePages; +// uv_mutex_unlock(&m_mutex); - return hugePages; -} +// return hugePages; +//} -size_t WorkersLegacy::threads() -{ - uv_mutex_lock(&m_mutex); - const size_t threads = m_status.threads; - uv_mutex_unlock(&m_mutex); +//size_t WorkersLegacy::threads() +//{ +// uv_mutex_lock(&m_mutex); +// const size_t threads = m_status.threads; +// uv_mutex_unlock(&m_mutex); - return threads; -} +// return threads; +//} //void Workers::pause() @@ -186,24 +186,24 @@ void WorkersLegacy::start(xmrig::Controller *controller) //} -#ifdef XMRIG_FEATURE_API -void WorkersLegacy::threadsSummary(rapidjson::Document &doc) -{ - uv_mutex_lock(&m_mutex); - const uint64_t pages[2] = { m_status.hugePages, m_status.pages }; - const uint64_t memory = m_status.ways * xmrig::CnAlgo<>::memory(m_status.algo); - uv_mutex_unlock(&m_mutex); +//#ifdef XMRIG_FEATURE_API +//void WorkersLegacy::threadsSummary(rapidjson::Document &doc) +//{ +// uv_mutex_lock(&m_mutex); +// const uint64_t pages[2] = { m_status.hugePages, m_status.pages }; +// const uint64_t memory = m_status.ways * xmrig::CnAlgo<>::memory(m_status.algo); +// uv_mutex_unlock(&m_mutex); - auto &allocator = doc.GetAllocator(); +// auto &allocator = doc.GetAllocator(); - rapidjson::Value hugepages(rapidjson::kArrayType); - hugepages.PushBack(pages[0], allocator); - hugepages.PushBack(pages[1], allocator); +// rapidjson::Value hugepages(rapidjson::kArrayType); +// hugepages.PushBack(pages[0], allocator); +// hugepages.PushBack(pages[1], allocator); - doc.AddMember("hugepages", hugepages, allocator); - doc.AddMember("memory", memory, allocator); -} -#endif +// doc.AddMember("hugepages", hugepages, allocator); +// doc.AddMember("memory", memory, allocator); +//} +//#endif //void WorkersLegacy::onTick(uv_timer_t *) diff --git a/src/workers/WorkersLegacy.h b/src/workers/WorkersLegacy.h index be9e417a..d8ab1e59 100644 --- a/src/workers/WorkersLegacy.h +++ b/src/workers/WorkersLegacy.h @@ -55,8 +55,8 @@ namespace xmrig { class WorkersLegacy { public: - static size_t hugePages(); - static size_t threads(); +// static size_t hugePages(); +// static size_t threads(); // static void pause(); // static void printHashrate(bool detail); // static void setEnabled(bool enabled); @@ -68,9 +68,9 @@ public: // static inline bool isEnabled() { return m_enabled; } // static inline Hashrate *hashrate() { return m_hashrate; } -# ifdef XMRIG_FEATURE_API - static void threadsSummary(rapidjson::Document &doc); -# endif +//# ifdef XMRIG_FEATURE_API +// static void threadsSummary(rapidjson::Document &doc); +//# endif private: // static void onReady(void *arg); From 2bf5ffb2df492734ffc69db1582effac4d28607f Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 17 Jul 2019 04:57:58 +0700 Subject: [PATCH 34/65] Class Mem replaced to VirtualMemory. --- CMakeLists.txt | 5 - src/App.cpp | 4 +- src/Mem.cpp | 31 ---- src/Mem.h | 72 --------- src/Mem_unix.cpp | 88 ----------- src/Mem_win.cpp | 184 ----------------------- src/Summary.cpp | 4 +- src/backend/common/interfaces/IWorker.h | 1 + src/core/Miner.cpp | 1 + src/crypto/common/VirtualMemory.h | 4 + src/crypto/common/VirtualMemory_unix.cpp | 11 ++ src/crypto/common/VirtualMemory_win.cpp | 126 ++++++++++++++++ 12 files changed, 147 insertions(+), 384 deletions(-) delete mode 100644 src/Mem.cpp delete mode 100644 src/Mem.h delete mode 100644 src/Mem_unix.cpp delete mode 100644 src/Mem_win.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f8a56c48..97491518 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,6 @@ set(HEADERS src/core/config/usage.h src/core/Controller.h src/core/Miner.h - src/Mem.h src/net/interfaces/IJobResultListener.h src/net/JobResult.h src/net/JobResults.h @@ -85,7 +84,6 @@ set(SOURCES src/core/config/ConfigTransform.cpp src/core/Controller.cpp src/core/Miner.cpp - src/Mem.cpp src/net/JobResults.cpp src/net/Network.cpp src/net/NetworkState.cpp @@ -113,7 +111,6 @@ if (WIN32) "${SOURCES_OS}" res/app.rc src/App_win.cpp - src/Mem_win.cpp src/crypto/common/VirtualMemory_win.cpp ) @@ -123,14 +120,12 @@ elseif (APPLE) set(SOURCES_OS "${SOURCES_OS}" src/App_unix.cpp - src/Mem_unix.cpp src/crypto/common/VirtualMemory_unix.cpp ) else() set(SOURCES_OS "${SOURCES_OS}" src/App_unix.cpp - src/Mem_unix.cpp src/crypto/common/VirtualMemory_unix.cpp ) diff --git a/src/App.cpp b/src/App.cpp index d6c39595..ccbaad4f 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -37,7 +37,7 @@ #include "core/config/Config.h" #include "core/Controller.h" #include "core/Miner.h" -#include "Mem.h" +#include "crypto/common/VirtualMemory.h" #include "net/Network.h" #include "Summary.h" #include "version.h" @@ -76,7 +76,7 @@ int xmrig::App::exec() background(); - Mem::init(m_controller->config()->cpu().isHugePages()); + VirtualMemory::init(m_controller->config()->cpu().isHugePages()); Summary::print(m_controller); diff --git a/src/Mem.cpp b/src/Mem.cpp deleted file mode 100644 index 5fcea306..00000000 --- a/src/Mem.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018 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 "Mem.h" - - -bool Mem::m_enabled = true; -int Mem::m_flags = 0; diff --git a/src/Mem.h b/src/Mem.h deleted file mode 100644 index 8e5c418b..00000000 --- a/src/Mem.h +++ /dev/null @@ -1,72 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018 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_MEM_H -#define XMRIG_MEM_H - - -#include -#include - - -#include "crypto/cn/CnAlgo.h" - - -struct cryptonight_ctx; - - -struct MemInfo -{ - alignas(16) uint8_t *memory = nullptr; - - size_t hugePages = 0; - size_t pages = 0; - size_t size = 0; -}; - - -class Mem -{ -public: - enum Flags { - HugepagesAvailable = 1, - HugepagesEnabled = 2, - Lock = 4 - }; - - static void init(bool enabled); - - static inline bool isHugepagesAvailable() { return (m_flags & HugepagesAvailable) != 0; } - -private: - static void allocate(MemInfo &info, bool enabled); - static void release(MemInfo &info); - - static int m_flags; - static bool m_enabled; -}; - - -#endif /* XMRIG_MEM_H */ diff --git a/src/Mem_unix.cpp b/src/Mem_unix.cpp deleted file mode 100644 index 4dc13e93..00000000 --- a/src/Mem_unix.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018 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 -#include - - -#include "base/io/log/Log.h" -#include "crypto/common/portable/mm_malloc.h" -#include "crypto/common/VirtualMemory.h" -#include "crypto/cn/CryptoNight.h" -#include "Mem.h" - - -#if defined(__APPLE__) -# include -#endif - - -void Mem::init(bool enabled) -{ - m_enabled = enabled; -} - - -void Mem::allocate(MemInfo &info, bool enabled) -{ - info.hugePages = 0; - - if (!enabled) { - info.memory = static_cast(_mm_malloc(info.size, 4096)); - - return; - } - - info.memory = static_cast(xmrig::VirtualMemory::allocateLargePagesMemory(info.size)); - if (!info.memory) { - return allocate(info, false);; - } - - info.hugePages = info.pages; - - if (madvise(info.memory, info.size, MADV_RANDOM | MADV_WILLNEED) != 0) { - LOG_ERR("madvise failed"); - } - - if (mlock(info.memory, info.size) == 0) { - m_flags |= Lock; - } -} - - -void Mem::release(MemInfo &info) -{ - if (info.hugePages) { - if (m_flags & Lock) { - munlock(info.memory, info.size); - } - - xmrig::VirtualMemory::freeLargePagesMemory(info.memory, info.size); - } - else { - _mm_free(info.memory); - } -} diff --git a/src/Mem_win.cpp b/src/Mem_win.cpp deleted file mode 100644 index 56b4521d..00000000 --- a/src/Mem_win.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018 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 -#include -#include -#include - - -#include "base/io/log/Log.h" -#include "crypto/common/portable/mm_malloc.h" -#include "crypto/common/VirtualMemory.h" -#include "crypto/cn/CryptoNight.h" -#include "Mem.h" - - -/***************************************************************** -SetLockPagesPrivilege: a function to obtain or -release the privilege of locking physical pages. - -Inputs: - -HANDLE hProcess: Handle for the process for which the -privilege is needed - -BOOL bEnable: Enable (TRUE) or disable? - -Return value: TRUE indicates success, FALSE failure. - -*****************************************************************/ -/** - * AWE Example: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366531(v=vs.85).aspx - * Creating a File Mapping Using Large Pages: https://msdn.microsoft.com/en-us/library/aa366543(VS.85).aspx - */ -static BOOL SetLockPagesPrivilege() { - HANDLE token; - - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) != TRUE) { - return FALSE; - } - - TOKEN_PRIVILEGES tp; - tp.PrivilegeCount = 1; - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - - if (LookupPrivilegeValue(nullptr, SE_LOCK_MEMORY_NAME, &(tp.Privileges[0].Luid)) != TRUE) { - return FALSE; - } - - BOOL rc = AdjustTokenPrivileges(token, FALSE, (PTOKEN_PRIVILEGES) &tp, 0, nullptr, nullptr); - if (rc != TRUE || GetLastError() != ERROR_SUCCESS) { - return FALSE; - } - - CloseHandle(token); - - return TRUE; -} - - -static LSA_UNICODE_STRING StringToLsaUnicodeString(LPCTSTR string) { - LSA_UNICODE_STRING lsaString; - - DWORD dwLen = (DWORD) wcslen(string); - lsaString.Buffer = (LPWSTR) string; - lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR)); - lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR)); - return lsaString; -} - - -static BOOL ObtainLockPagesPrivilege() { - HANDLE token; - PTOKEN_USER user = nullptr; - - if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) == TRUE) { - DWORD size = 0; - - GetTokenInformation(token, TokenUser, nullptr, 0, &size); - if (size) { - user = (PTOKEN_USER) LocalAlloc(LPTR, size); - } - - GetTokenInformation(token, TokenUser, user, size, &size); - CloseHandle(token); - } - - if (!user) { - return FALSE; - } - - LSA_HANDLE handle; - LSA_OBJECT_ATTRIBUTES attributes; - ZeroMemory(&attributes, sizeof(attributes)); - - BOOL result = FALSE; - if (LsaOpenPolicy(nullptr, &attributes, POLICY_ALL_ACCESS, &handle) == 0) { - LSA_UNICODE_STRING str = StringToLsaUnicodeString(_T(SE_LOCK_MEMORY_NAME)); - - if (LsaAddAccountRights(handle, user->User.Sid, &str, 1) == 0) { - LOG_NOTICE("Huge pages support was successfully enabled, but reboot required to use it"); - result = TRUE; - } - - LsaClose(handle); - } - - LocalFree(user); - return result; -} - - -static BOOL TrySetLockPagesPrivilege() { - if (SetLockPagesPrivilege()) { - return TRUE; - } - - return ObtainLockPagesPrivilege() && SetLockPagesPrivilege(); -} - - -void Mem::init(bool enabled) -{ - m_enabled = enabled; - - if (enabled && TrySetLockPagesPrivilege()) { - m_flags |= HugepagesAvailable; - } -} - - -void Mem::allocate(MemInfo &info, bool enabled) -{ - info.hugePages = 0; - - if (!enabled) { - info.memory = static_cast(_mm_malloc(info.size, 4096)); - - return; - } - - info.memory = static_cast(xmrig::VirtualMemory::allocateLargePagesMemory(info.size)); - if (info.memory) { - info.hugePages = info.pages; - - return; - } - - allocate(info, false); -} - - -void Mem::release(MemInfo &info) -{ - if (info.hugePages) { - xmrig::VirtualMemory::freeLargePagesMemory(info.memory, info.size); - } - else { - _mm_free(info.memory); - } -} diff --git a/src/Summary.cpp b/src/Summary.cpp index 59e540d4..af7cad09 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -34,7 +34,7 @@ #include "core/config/Config.h" #include "core/Controller.h" #include "crypto/common/Assembly.h" -#include "Mem.h" +#include "crypto/common/VirtualMemory.h" #include "Summary.h" #include "version.h" @@ -59,7 +59,7 @@ inline static const char *asmName(xmrig::Assembly::Id assembly) static void print_memory(xmrig::Config *) { # ifdef _WIN32 xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") "%s", - "HUGE PAGES", Mem::isHugepagesAvailable() ? GREEN_BOLD("available") : RED_BOLD("unavailable")); + "HUGE PAGES", xmrig::VirtualMemory::isHugepagesAvailable() ? GREEN_BOLD("available") : RED_BOLD("unavailable")); # endif } diff --git a/src/backend/common/interfaces/IWorker.h b/src/backend/common/interfaces/IWorker.h index 5c99680b..0d7fe1d2 100644 --- a/src/backend/common/interfaces/IWorker.h +++ b/src/backend/common/interfaces/IWorker.h @@ -27,6 +27,7 @@ #include +#include namespace xmrig { diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 83ce2206..1764a79e 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -23,6 +23,7 @@ */ +#include #include diff --git a/src/crypto/common/VirtualMemory.h b/src/crypto/common/VirtualMemory.h index 98212e40..e2a5ac22 100644 --- a/src/crypto/common/VirtualMemory.h +++ b/src/crypto/common/VirtualMemory.h @@ -51,9 +51,11 @@ public: static void *allocateLargePagesMemory(size_t size); static void flushInstructionCache(void *p, size_t size); static void freeLargePagesMemory(void *p, size_t size); + static void init(bool hugePages); static void protectExecutableMemory(void *p, size_t size); static void unprotectExecutableMemory(void *p, size_t size); + static inline bool isHugepagesAvailable() { return (m_globalFlags & HUGEPAGES_AVAILABLE) != 0; } static inline constexpr size_t align(size_t pos, size_t align = 2097152) { return ((pos - 1) / align + 1) * align; } private: @@ -63,6 +65,8 @@ private: LOCK = 4 }; + static int m_globalFlags; + int m_flags = 0; size_t m_size = 0; uint8_t *m_scratchpad = nullptr; diff --git a/src/crypto/common/VirtualMemory_unix.cpp b/src/crypto/common/VirtualMemory_unix.cpp index 665fc02b..310a043a 100644 --- a/src/crypto/common/VirtualMemory_unix.cpp +++ b/src/crypto/common/VirtualMemory_unix.cpp @@ -38,6 +38,9 @@ #endif +int xmrig::VirtualMemory::m_globalFlags = 0; + + xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) : m_size(VirtualMemory::align(size)) { @@ -120,6 +123,14 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t size) } +void xmrig::VirtualMemory::init(bool hugePages) +{ + if (hugePages) { + m_globalFlags = HUGEPAGES | HUGEPAGES_AVAILABLE; + } +} + + void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size) { mprotect(p, size, PROT_READ | PROT_EXEC); diff --git a/src/crypto/common/VirtualMemory_win.cpp b/src/crypto/common/VirtualMemory_win.cpp index 7aa98f89..7bdb6365 100644 --- a/src/crypto/common/VirtualMemory_win.cpp +++ b/src/crypto/common/VirtualMemory_win.cpp @@ -27,11 +27,123 @@ #include #include +#include +#include +#include "base/io/log/Log.h" +#include "crypto/common/portable/mm_malloc.h" #include "crypto/common/VirtualMemory.h" +/***************************************************************** +SetLockPagesPrivilege: a function to obtain or +release the privilege of locking physical pages. + +Inputs: + +HANDLE hProcess: Handle for the process for which the +privilege is needed + +BOOL bEnable: Enable (TRUE) or disable? + +Return value: TRUE indicates success, FALSE failure. + +*****************************************************************/ +/** + * AWE Example: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366531(v=vs.85).aspx + * Creating a File Mapping Using Large Pages: https://msdn.microsoft.com/en-us/library/aa366543(VS.85).aspx + */ +static BOOL SetLockPagesPrivilege() { + HANDLE token; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) != TRUE) { + return FALSE; + } + + TOKEN_PRIVILEGES tp; + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (LookupPrivilegeValue(nullptr, SE_LOCK_MEMORY_NAME, &(tp.Privileges[0].Luid)) != TRUE) { + return FALSE; + } + + BOOL rc = AdjustTokenPrivileges(token, FALSE, (PTOKEN_PRIVILEGES) &tp, 0, nullptr, nullptr); + if (rc != TRUE || GetLastError() != ERROR_SUCCESS) { + return FALSE; + } + + CloseHandle(token); + + return TRUE; +} + + +static LSA_UNICODE_STRING StringToLsaUnicodeString(LPCTSTR string) { + LSA_UNICODE_STRING lsaString; + + DWORD dwLen = (DWORD) wcslen(string); + lsaString.Buffer = (LPWSTR) string; + lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR)); + lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR)); + return lsaString; +} + + +static BOOL ObtainLockPagesPrivilege() { + HANDLE token; + PTOKEN_USER user = nullptr; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) == TRUE) { + DWORD size = 0; + + GetTokenInformation(token, TokenUser, nullptr, 0, &size); + if (size) { + user = (PTOKEN_USER) LocalAlloc(LPTR, size); + } + + GetTokenInformation(token, TokenUser, user, size, &size); + CloseHandle(token); + } + + if (!user) { + return FALSE; + } + + LSA_HANDLE handle; + LSA_OBJECT_ATTRIBUTES attributes; + ZeroMemory(&attributes, sizeof(attributes)); + + BOOL result = FALSE; + if (LsaOpenPolicy(nullptr, &attributes, POLICY_ALL_ACCESS, &handle) == 0) { + LSA_UNICODE_STRING str = StringToLsaUnicodeString(_T(SE_LOCK_MEMORY_NAME)); + + if (LsaAddAccountRights(handle, user->User.Sid, &str, 1) == 0) { + LOG_NOTICE("Huge pages support was successfully enabled, but reboot required to use it"); + result = TRUE; + } + + LsaClose(handle); + } + + LocalFree(user); + return result; +} + + +static BOOL TrySetLockPagesPrivilege() { + if (SetLockPagesPrivilege()) { + return TRUE; + } + + return ObtainLockPagesPrivilege() && SetLockPagesPrivilege(); +} + + +int xmrig::VirtualMemory::m_globalFlags = 0; + + xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) : m_size(VirtualMemory::align(size)) { @@ -94,6 +206,20 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t) } +void xmrig::VirtualMemory::init(bool hugePages) +{ + if (!hugePages) { + return; + } + + m_globalFlags = HUGEPAGES; + + if (TrySetLockPagesPrivilege()) { + m_globalFlags |= HUGEPAGES_AVAILABLE; + } +} + + void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size) { DWORD oldProtect; From bcae974ea1b3dfed8797e161c3852c95c4c76c9b Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 17 Jul 2019 05:01:12 +0700 Subject: [PATCH 35/65] Fixed build. --- src/backend/cpu/CpuWorker.h | 1 - src/crypto/cn/r/CryptonightR_gen.cpp | 1 - src/workers/CpuThreadLegacy.cpp | 1 - src/workers/WorkersLegacy.cpp | 1 - 4 files changed, 4 deletions(-) diff --git a/src/backend/cpu/CpuWorker.h b/src/backend/cpu/CpuWorker.h index c0f9dfaf..4cdd10f8 100644 --- a/src/backend/cpu/CpuWorker.h +++ b/src/backend/cpu/CpuWorker.h @@ -31,7 +31,6 @@ #include "backend/common/WorkerJob.h" #include "backend/cpu/CpuLaunchData.h" #include "base/net/stratum/Job.h" -#include "Mem.h" #include "net/JobResult.h" diff --git a/src/crypto/cn/r/CryptonightR_gen.cpp b/src/crypto/cn/r/CryptonightR_gen.cpp index 3037327a..3b80f805 100644 --- a/src/crypto/cn/r/CryptonightR_gen.cpp +++ b/src/crypto/cn/r/CryptonightR_gen.cpp @@ -31,7 +31,6 @@ typedef void(*void_func)(); #include "crypto/cn/asm/CryptonightR_template.h" #include "crypto/common/Assembly.h" #include "crypto/common/VirtualMemory.h" -#include "Mem.h" static inline void add_code(uint8_t* &p, void (*p1)(), void (*p2)()) diff --git a/src/workers/CpuThreadLegacy.cpp b/src/workers/CpuThreadLegacy.cpp index a560d33f..b5d457c7 100644 --- a/src/workers/CpuThreadLegacy.cpp +++ b/src/workers/CpuThreadLegacy.cpp @@ -29,7 +29,6 @@ #include "crypto/cn/CnHash.h" #include "crypto/common/Assembly.h" #include "crypto/common/VirtualMemory.h" -#include "Mem.h" #include "rapidjson/document.h" #include "workers/CpuThreadLegacy.h" diff --git a/src/workers/WorkersLegacy.cpp b/src/workers/WorkersLegacy.cpp index 4d6f9de9..e7191116 100644 --- a/src/workers/WorkersLegacy.cpp +++ b/src/workers/WorkersLegacy.cpp @@ -38,7 +38,6 @@ #include "crypto/rx/RxAlgo.h" #include "crypto/rx/RxCache.h" #include "crypto/rx/RxDataset.h" -#include "Mem.h" #include "rapidjson/document.h" //#include "workers/Hashrate.h" #include "workers/WorkersLegacy.h" From 4f49533e9876fe9902809a0599bed22e570157cc Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 17 Jul 2019 05:33:13 +0700 Subject: [PATCH 36/65] Fixed warnings. --- src/backend/common/Hashrate.h | 1 + src/crypto/randomx/argon2_core.c | 13 ++++++------- src/crypto/randomx/bytecode_machine.hpp | 2 +- src/crypto/randomx/dataset.cpp | 2 +- src/crypto/randomx/jit_compiler_x86.cpp | 2 +- src/crypto/randomx/randomx.cpp | 12 +++++------- src/crypto/randomx/superscalar.cpp | 12 ++++++------ 7 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/backend/common/Hashrate.h b/src/backend/common/Hashrate.h index 1787bf6a..2187c0be 100644 --- a/src/backend/common/Hashrate.h +++ b/src/backend/common/Hashrate.h @@ -26,6 +26,7 @@ #define XMRIG_HASHRATE_H +#include #include diff --git a/src/crypto/randomx/argon2_core.c b/src/crypto/randomx/argon2_core.c index e9174222..4b8fa43d 100644 --- a/src/crypto/randomx/argon2_core.c +++ b/src/crypto/randomx/argon2_core.c @@ -90,12 +90,12 @@ static void load_block(block *dst, const void *input) { } } -static void store_block(void *output, const block *src) { - unsigned i; - for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { - store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]); - } -} +//static void store_block(void *output, const block *src) { +// unsigned i; +// for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { +// store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]); +// } +//} /***************Memory functions*****************/ @@ -484,7 +484,6 @@ void rxa2_initial_hash(uint8_t *blockhash, argon2_context *context, argon2_type int rxa2_argon_initialize(argon2_instance_t *instance, argon2_context *context) { uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; - int result = ARGON2_OK; if (instance == NULL || context == NULL) return ARGON2_INCORRECT_PARAMETER; diff --git a/src/crypto/randomx/bytecode_machine.hpp b/src/crypto/randomx/bytecode_machine.hpp index 3b05f378..810f854a 100644 --- a/src/crypto/randomx/bytecode_machine.hpp +++ b/src/crypto/randomx/bytecode_machine.hpp @@ -90,7 +90,7 @@ namespace randomx { } static void executeBytecode(InstructionByteCode* bytecode, uint8_t* scratchpad, ProgramConfiguration& config) { - for (int pc = 0; pc < RandomX_CurrentConfig.ProgramSize; ++pc) { + for (int pc = 0; pc < static_cast(RandomX_CurrentConfig.ProgramSize); ++pc) { auto& ibc = bytecode[pc]; executeInstruction(ibc, pc, scratchpad, config); } diff --git a/src/crypto/randomx/dataset.cpp b/src/crypto/randomx/dataset.cpp index 3951b55b..b094b1cb 100644 --- a/src/crypto/randomx/dataset.cpp +++ b/src/crypto/randomx/dataset.cpp @@ -121,7 +121,7 @@ namespace randomx { cache->reciprocalCache.clear(); randomx::Blake2Generator gen(key, keySize); - for (int i = 0; i < RandomX_CurrentConfig.CacheAccesses; ++i) { + for (uint32_t i = 0; i < RandomX_CurrentConfig.CacheAccesses; ++i) { randomx::generateSuperscalar(cache->programs[i], gen); for (unsigned j = 0; j < cache->programs[i].getSize(); ++j) { auto& instr = cache->programs[i](j); diff --git a/src/crypto/randomx/jit_compiler_x86.cpp b/src/crypto/randomx/jit_compiler_x86.cpp index 8870a018..6f04e28a 100644 --- a/src/crypto/randomx/jit_compiler_x86.cpp +++ b/src/crypto/randomx/jit_compiler_x86.cpp @@ -194,7 +194,7 @@ namespace randomx { 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* NOPX[] = { NOP1, NOP2, NOP3, NOP4, NOP5, NOP6, NOP7, NOP8 }; +// static const uint8_t* NOPX[] = { NOP1, NOP2, NOP3, NOP4, NOP5, NOP6, NOP7, NOP8 }; size_t JitCompilerX86::getCodeSize() { return codePos - prologueSize; diff --git a/src/crypto/randomx/randomx.cpp b/src/crypto/randomx/randomx.cpp index df5fc9cb..9e88bc6d 100644 --- a/src/crypto/randomx/randomx.cpp +++ b/src/crypto/randomx/randomx.cpp @@ -233,7 +233,7 @@ RandomX_ConfigurationBase RandomX_CurrentConfig; extern "C" { randomx_cache *randomx_alloc_cache(randomx_flags flags) { - randomx_cache *cache; + randomx_cache *cache = nullptr; try { cache = new randomx_cache(); @@ -297,7 +297,7 @@ extern "C" { } randomx_dataset *randomx_alloc_dataset(randomx_flags flags) { - randomx_dataset *dataset; + randomx_dataset *dataset = nullptr; try { dataset = new randomx_dataset(); @@ -430,14 +430,12 @@ extern "C" { assert(inputSize == 0 || input != nullptr); assert(output != nullptr); alignas(16) uint64_t tempHash[8]; - int blakeResult = blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0); - assert(blakeResult == 0); + blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0); machine->initScratchpad(&tempHash); machine->resetRoundingMode(); - for (int chain = 0; chain < RandomX_CurrentConfig.ProgramCount - 1; ++chain) { + for (uint32_t chain = 0; chain < RandomX_CurrentConfig.ProgramCount - 1; ++chain) { machine->run(&tempHash); - blakeResult = blake2b(tempHash, sizeof(tempHash), machine->getRegisterFile(), sizeof(randomx::RegisterFile), nullptr, 0); - assert(blakeResult == 0); + 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/superscalar.cpp b/src/crypto/randomx/superscalar.cpp index da605622..0ca1fe69 100644 --- a/src/crypto/randomx/superscalar.cpp +++ b/src/crypto/randomx/superscalar.cpp @@ -500,7 +500,7 @@ namespace randomx { // * either the last instruction applied to the register or its source must be different than this instruction // - this avoids optimizable instruction sequences such as "xor r1, r2; xor r1, r2" or "ror r, C1; ror r, C2" or "add r, C1; add r, C2" // * register r5 cannot be the destination of the IADD_RS instruction (limitation of the x86 lea instruction) - for (unsigned i = 0; i < 8; ++i) { + for (int i = 0; i < 8; ++i) { if (registers[i].latency <= cycle && (canReuse_ || i != src_) && (allowChainedMul || opGroup_ != SuperscalarInstructionType::IMUL_R || registers[i].lastOpGroup != SuperscalarInstructionType::IMUL_R) && (registers[i].lastOpGroup != opGroup_ || registers[i].lastOpPar != opGroupPar_) && (info_->getType() != SuperscalarInstructionType::IADD_RS || i != RegisterNeedsDisplacement)) availableRegisters.push_back(i); } @@ -581,7 +581,7 @@ namespace randomx { static int scheduleUop(ExecutionPort::type uop, ExecutionPort::type(&portBusy)[CYCLE_MAP_SIZE][3], int cycle) { //The scheduling here is done optimistically by checking port availability in order P5 -> P0 -> P1 to not overload //port P1 (multiplication) by instructions that can go to any port. - for (; cycle < RandomX_CurrentConfig.SuperscalarLatency + 4; ++cycle) { + for (; cycle < static_cast(RandomX_CurrentConfig.SuperscalarLatency) + 4; ++cycle) { if ((uop & ExecutionPort::P5) != 0 && !portBusy[cycle][2]) { if (commit) { if (trace) std::cout << "; P5 at cycle " << cycle << std::endl; @@ -626,7 +626,7 @@ namespace randomx { } else { //macro-ops with 2 uOPs are scheduled conservatively by requiring both uOPs to execute in the same cycle - for (; cycle < RandomX_CurrentConfig.SuperscalarLatency + 4; ++cycle) { + for (; cycle < static_cast(RandomX_CurrentConfig.SuperscalarLatency) + 4; ++cycle) { int cycle1 = scheduleUop(mop.getUop1(), portBusy, cycle); int cycle2 = scheduleUop(mop.getUop2(), portBusy, cycle); @@ -669,7 +669,7 @@ namespace randomx { //Since a decode cycle produces on average 3.45 macro-ops and there are only 3 ALU ports, execution ports are always //saturated first. The cycle limit is present only to guarantee loop termination. //Program size is limited to SuperscalarMaxSize instructions. - for (decodeCycle = 0; decodeCycle < RandomX_CurrentConfig.SuperscalarLatency && !portsSaturated && programSize < 3 * RandomX_CurrentConfig.SuperscalarLatency + 2; ++decodeCycle) { + for (decodeCycle = 0; decodeCycle < static_cast(RandomX_CurrentConfig.SuperscalarLatency) && !portsSaturated && programSize < 3 * static_cast(RandomX_CurrentConfig.SuperscalarLatency) + 2; ++decodeCycle) { //select a decode configuration decodeBuffer = decodeBuffer->fetchNext(currentInstruction.getType(), decodeCycle, mulCount, gen); @@ -683,7 +683,7 @@ namespace randomx { //if we have issued all macro-ops for the current RandomX instruction, create a new instruction if (macroOpIndex >= currentInstruction.getInfo().getSize()) { - if (portsSaturated || programSize >= 3 * RandomX_CurrentConfig.SuperscalarLatency + 2) + if (portsSaturated || programSize >= 3 * static_cast(RandomX_CurrentConfig.SuperscalarLatency) + 2) break; //select an instruction so that the first macro-op fits into the current slot currentInstruction.createForSlot(gen, decodeBuffer->getCounts()[bufferIndex], decodeBuffer->getIndex(), decodeBuffer->getSize() == bufferIndex + 1, bufferIndex == 0); @@ -777,7 +777,7 @@ namespace randomx { macroOpCount++; //terminating condition - if (scheduleCycle >= RandomX_CurrentConfig.SuperscalarLatency) { + if (scheduleCycle >= static_cast(RandomX_CurrentConfig.SuperscalarLatency)) { portsSaturated = true; } cycle = topCycle; From 8ce00adda4bb607f8bee5c69c8673921059ac3ce Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 17 Jul 2019 14:54:08 +0700 Subject: [PATCH 37/65] Restored "CPU READY" message. --- CMakeLists.txt | 2 - src/api/v1/ApiRouter.cpp | 2 - src/backend/common/Thread.h | 5 +- src/backend/common/Workers.cpp | 13 +- src/backend/common/Workers.h | 1 + src/backend/common/interfaces/IBackend.h | 2 + src/backend/cpu/CpuBackend.cpp | 106 ++++++++-- src/backend/cpu/CpuBackend.h | 3 +- src/core/Miner.cpp | 9 +- src/crypto/common/VirtualMemory.h | 7 +- src/crypto/rx/Rx.cpp | 2 +- src/workers/WorkersLegacy.cpp | 256 ----------------------- src/workers/WorkersLegacy.h | 113 ---------- 13 files changed, 114 insertions(+), 407 deletions(-) delete mode 100644 src/workers/WorkersLegacy.cpp delete mode 100644 src/workers/WorkersLegacy.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 97491518..89be20ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,6 @@ set(HEADERS src/Summary.h src/version.h src/workers/CpuThreadLegacy.h - src/workers/WorkersLegacy.h ) set(HEADERS_CRYPTO @@ -90,7 +89,6 @@ set(SOURCES src/net/strategies/DonateStrategy.cpp src/Summary.cpp src/workers/CpuThreadLegacy.cpp - src/workers/WorkersLegacy.cpp src/xmrig.cpp ) diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp index 2e6a815c..2a5bd3d0 100644 --- a/src/api/v1/ApiRouter.cpp +++ b/src/api/v1/ApiRouter.cpp @@ -36,8 +36,6 @@ #include "core/config/Config.h" #include "rapidjson/document.h" #include "version.h" -//#include "workers/Hashrate.h" -#include "workers/WorkersLegacy.h" static inline rapidjson::Value normalize(double d) diff --git a/src/backend/common/Thread.h b/src/backend/common/Thread.h index f1d174ec..b62d880c 100644 --- a/src/backend/common/Thread.h +++ b/src/backend/common/Thread.h @@ -32,6 +32,7 @@ namespace xmrig { +class IBackend; class IWorker; @@ -39,10 +40,11 @@ template class Thread { public: - inline Thread(size_t index, const T &config) : m_index(index), m_config(config) {} + inline Thread(IBackend *backend, size_t index, const T &config) : m_index(index), m_config(config), m_backend(backend) {} inline ~Thread() { uv_thread_join(&m_thread); } inline const T &config() const { return m_config; } + inline IBackend *backend() const { return m_backend; } inline IWorker *worker() const { return m_worker; } inline size_t index() const { return m_index; } inline void setWorker(IWorker *worker) { m_worker = worker; } @@ -51,6 +53,7 @@ public: private: const size_t m_index = 0; const T m_config; + IBackend *m_backend; IWorker *m_worker = nullptr; uv_thread_t m_thread; }; diff --git a/src/backend/common/Workers.cpp b/src/backend/common/Workers.cpp index c4ac38a5..629b564b 100644 --- a/src/backend/common/Workers.cpp +++ b/src/backend/common/Workers.cpp @@ -25,6 +25,7 @@ #include "backend/common/Hashrate.h" +#include "backend/common/interfaces/IBackend.h" #include "backend/common/Workers.h" #include "backend/cpu/CpuWorker.h" #include "base/io/log/Log.h" @@ -48,6 +49,7 @@ public: Hashrate *hashrate = nullptr; + IBackend *backend = nullptr; }; @@ -79,7 +81,14 @@ const xmrig::Hashrate *xmrig::Workers::hashrate() const template void xmrig::Workers::add(const T &data) { - m_workers.push_back(new Thread(m_workers.size(), data)); + m_workers.push_back(new Thread(d_ptr->backend, m_workers.size(), data)); +} + + +template +void xmrig::Workers::setBackend(IBackend *backend) +{ + d_ptr->backend = backend; } @@ -176,7 +185,7 @@ void xmrig::Workers::onReady(void *arg) return; } - worker->start(); + handle->backend()->start(worker); } diff --git a/src/backend/common/Workers.h b/src/backend/common/Workers.h index 3ef4b015..c13f5e77 100644 --- a/src/backend/common/Workers.h +++ b/src/backend/common/Workers.h @@ -47,6 +47,7 @@ public: const Hashrate *hashrate() const; void add(const T &data); + void setBackend(IBackend *backend); void start(); void stop(); void tick(uint64_t ticks); diff --git a/src/backend/common/interfaces/IBackend.h b/src/backend/common/interfaces/IBackend.h index 69ed4c8c..8ad7bb53 100644 --- a/src/backend/common/interfaces/IBackend.h +++ b/src/backend/common/interfaces/IBackend.h @@ -33,6 +33,7 @@ namespace xmrig { class Hashrate; +class IWorker; class Job; class String; @@ -46,6 +47,7 @@ public: virtual const String &profileName() const = 0; virtual void printHashrate(bool details) = 0; virtual void setJob(const Job &job) = 0; + virtual void start(IWorker *worker) = 0; virtual void stop() = 0; virtual void tick(uint64_t ticks) = 0; }; diff --git a/src/backend/cpu/CpuBackend.cpp b/src/backend/cpu/CpuBackend.cpp index a0463832..bdb592ff 100644 --- a/src/backend/cpu/CpuBackend.cpp +++ b/src/backend/cpu/CpuBackend.cpp @@ -23,7 +23,11 @@ */ +#include + + #include "backend/common/Hashrate.h" +#include "backend/common/interfaces/IWorker.h" #include "backend/common/Workers.h" #include "backend/cpu/CpuBackend.h" #include "base/io/log/Log.h" @@ -31,6 +35,7 @@ #include "base/tools/String.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "crypto/common/VirtualMemory.h" namespace xmrig { @@ -39,18 +44,41 @@ namespace xmrig { extern template class Threads; +struct LaunchStatus +{ +public: + inline void reset() + { + hugePages = 0; + memory = 0; + pages = 0; + started = 0; + threads = 0; + ways = 0; + } + + size_t hugePages; + size_t memory; + size_t pages; + size_t started; + size_t threads; + size_t ways; +}; + + class CpuBackendPrivate { public: - inline CpuBackendPrivate(const Miner *miner, Controller *controller) : - miner(miner), + inline CpuBackendPrivate(Controller *controller) : controller(controller) { + uv_mutex_init(&mutex); } inline ~CpuBackendPrivate() { + uv_mutex_destroy(&mutex); } @@ -72,11 +100,42 @@ public: } + inline void start(const Job &job) + { + const CpuConfig &cpu = controller->config()->cpu(); + + algo = job.algorithm(); + profileName = cpu.threads().profileName(job.algorithm()); + threads = cpu.threads().get(profileName); + + LOG_INFO(GREEN_BOLD("CPU") " use profile " BLUE_BG(WHITE_BOLD_S " %s ") WHITE_BOLD_S " (" CYAN_BOLD("%zu") WHITE_BOLD(" threads)") " scratchpad " CYAN_BOLD("%zu KB"), + profileName.data(), + threads.size(), + algo.memory() / 1024 + ); + + workers.stop(); + + status.reset(); + status.memory = algo.memory(); + status.threads = threads.size(); + + for (const CpuThread &thread : threads) { + workers.add(CpuLaunchData(controller->miner(), algo, cpu, thread)); + + status.ways += static_cast(thread.intensity()); + } + + workers.start(); + } + + Algorithm algo; - const Miner *miner; Controller *controller; CpuThreads threads; + LaunchStatus status; String profileName; + uv_mutex_t mutex; Workers workers; }; @@ -84,10 +143,10 @@ public: } // namespace xmrig -xmrig::CpuBackend::CpuBackend(const Miner *miner, Controller *controller) : - d_ptr(new CpuBackendPrivate(miner, controller)) +xmrig::CpuBackend::CpuBackend(Controller *controller) : + d_ptr(new CpuBackendPrivate(controller)) { - + d_ptr->workers.setBackend(this); } @@ -140,26 +199,33 @@ void xmrig::CpuBackend::setJob(const Job &job) return; } - const CpuConfig &cpu = d_ptr->controller->config()->cpu(); - const Threads &threads = cpu.threads(); + d_ptr->start(job); +} - d_ptr->algo = job.algorithm(); - d_ptr->profileName = threads.profileName(job.algorithm()); - d_ptr->threads = threads.get(d_ptr->profileName); - LOG_INFO(GREEN_BOLD("CPU") " use profile " BLUE_BG(WHITE_BOLD_S " %s ") WHITE_BOLD_S " (" CYAN_BOLD("%zu") WHITE_BOLD(" threads)") " scratchpad " CYAN_BOLD("%zu KB"), - d_ptr->profileName.data(), - d_ptr->threads.size(), - d_ptr->algo.memory() / 1024 - ); +void xmrig::CpuBackend::start(IWorker *worker) +{ + uv_mutex_lock(&d_ptr->mutex); - d_ptr->workers.stop(); + const auto pages = worker->memory()->hugePages(); - for (const CpuThread &thread : d_ptr->threads) { - d_ptr->workers.add(CpuLaunchData(d_ptr->miner, d_ptr->algo, cpu, thread)); + d_ptr->status.started++; + d_ptr->status.hugePages += pages.first; + d_ptr->status.pages += pages.second; + + if (d_ptr->status.started == d_ptr->status.threads) { + const double percent = d_ptr->status.hugePages == 0 ? 0.0 : static_cast(d_ptr->status.hugePages) / d_ptr->status.pages * 100.0; + const size_t memory = d_ptr->status.ways * d_ptr->status.memory / 1024; + + LOG_INFO(GREEN_BOLD("CPU READY") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") "", + d_ptr->status.threads, d_ptr->status.ways, + (d_ptr->status.hugePages == d_ptr->status.pages ? GREEN_BOLD_S : (d_ptr->status.hugePages == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), + d_ptr->status.hugePages, d_ptr->status.pages, percent, memory); } - d_ptr->workers.start(); + uv_mutex_unlock(&d_ptr->mutex); + + worker->start(); } diff --git a/src/backend/cpu/CpuBackend.h b/src/backend/cpu/CpuBackend.h index a7b742eb..aabccb49 100644 --- a/src/backend/cpu/CpuBackend.h +++ b/src/backend/cpu/CpuBackend.h @@ -40,7 +40,7 @@ class Miner; class CpuBackend : public IBackend { public: - CpuBackend(const Miner *miner, Controller *controller); + CpuBackend(Controller *controller); ~CpuBackend() override; protected: @@ -48,6 +48,7 @@ protected: const String &profileName() const override; void printHashrate(bool details) override; void setJob(const Job &job) override; + void start(IWorker *worker) override; void stop() override; void tick(uint64_t ticks) override; diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 1764a79e..40321662 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -101,7 +101,7 @@ xmrig::Miner::Miner(Controller *controller) { d_ptr->timer = new Timer(this); - d_ptr->backends.push_back(new CpuBackend(this, controller)); + d_ptr->backends.push_back(new CpuBackend(controller)); } @@ -210,15 +210,8 @@ void xmrig::Miner::setJob(const Job &job, bool donate) void xmrig::Miner::stop() { -// xmrig::Handle::close(m_timer); -// m_hashrate->stop(); - Nonce::stop(); -// for (size_t i = 0; i < m_workers.size(); ++i) { -// m_workers[i]->join(); -// } - for (IBackend *backend : d_ptr->backends) { backend->stop(); } diff --git a/src/crypto/common/VirtualMemory.h b/src/crypto/common/VirtualMemory.h index e2a5ac22..44f77a23 100644 --- a/src/crypto/common/VirtualMemory.h +++ b/src/crypto/common/VirtualMemory.h @@ -30,6 +30,7 @@ #include #include +#include namespace xmrig { @@ -43,10 +44,14 @@ public: ~VirtualMemory(); inline bool isHugePages() const { return m_flags & HUGEPAGES; } - inline size_t hugePages() const { return isHugePages() ? (align(size()) / 2097152) : 0; } inline size_t size() const { return m_size; } inline uint8_t *scratchpad() const { return m_scratchpad; } + inline std::pair hugePages() const + { + return std::pair(isHugePages() ? (align(size()) / 2097152) : 0, align(size()) / 2097152); + } + static void *allocateExecutableMemory(size_t size); static void *allocateLargePagesMemory(size_t size); static void flushInstructionCache(void *p, size_t size); diff --git a/src/crypto/rx/Rx.cpp b/src/crypto/rx/Rx.cpp index 630dd45a..7f482034 100644 --- a/src/crypto/rx/Rx.cpp +++ b/src/crypto/rx/Rx.cpp @@ -113,7 +113,7 @@ xmrig::RxDataset *xmrig::Rx::dataset(const uint8_t *seed, const Algorithm &algor const uint64_t ts = Chrono::steadyMSecs(); if (d_ptr->dataset->get() != nullptr) { - LOG_INFO("%s" MAGENTA_BOLD(" init dataset") " algo " WHITE_BOLD("%s") " threads " WHITE_BOLD("%u") BLACK_BOLD(" seed %s..."), + LOG_INFO("%s" MAGENTA_BOLD(" init dataset") " algo " WHITE_BOLD("%s (") CYAN_BOLD("%u") WHITE_BOLD(" threads)") BLACK_BOLD(" seed %s..."), tag, algorithm.shortName(), d_ptr->initThreads, diff --git a/src/workers/WorkersLegacy.cpp b/src/workers/WorkersLegacy.cpp deleted file mode 100644 index e7191116..00000000 --- a/src/workers/WorkersLegacy.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - - -#include "api/Api.h" -#include "backend/cpu/CpuWorker.h" -#include "base/io/log/Log.h" -#include "base/tools/Chrono.h" -#include "base/tools/Handle.h" -#include "core/config/Config.h" -#include "core/Controller.h" -#include "crypto/common/Nonce.h" -#include "crypto/rx/RxAlgo.h" -#include "crypto/rx/RxCache.h" -#include "crypto/rx/RxDataset.h" -#include "rapidjson/document.h" -//#include "workers/Hashrate.h" -#include "workers/WorkersLegacy.h" - - -bool WorkersLegacy::m_active = false; -bool WorkersLegacy::m_enabled = true; -//Hashrate *WorkersLegacy::m_hashrate = nullptr; -xmrig::Job WorkersLegacy::m_job; -WorkersLegacy::LaunchStatus WorkersLegacy::m_status; -std::vector* > WorkersLegacy::m_workers; -uint64_t WorkersLegacy::m_ticks = 0; -uv_mutex_t WorkersLegacy::m_mutex; -uv_rwlock_t WorkersLegacy::m_rwlock; -//uv_timer_t *Workers::m_timer = nullptr; -xmrig::Controller *WorkersLegacy::m_controller = nullptr; - - -//xmrig::Job WorkersLegacy::job() -//{ -// uv_rwlock_rdlock(&m_rwlock); -// xmrig::Job job = m_job; -// uv_rwlock_rdunlock(&m_rwlock); - -// return job; -//} - - -//size_t WorkersLegacy::hugePages() -//{ -// uv_mutex_lock(&m_mutex); -// const size_t hugePages = m_status.hugePages; -// uv_mutex_unlock(&m_mutex); - -// return hugePages; -//} - - -//size_t WorkersLegacy::threads() -//{ -// uv_mutex_lock(&m_mutex); -// const size_t threads = m_status.threads; -// uv_mutex_unlock(&m_mutex); - -// return threads; -//} - - -//void Workers::pause() -//{ -// m_active = false; - -// xmrig::Nonce::pause(true); -// xmrig::Nonce::touch(); -//} - - -//void Workers::setEnabled(bool enabled) -//{ -// if (m_enabled == enabled) { -// return; -// } - -// m_enabled = enabled; -// if (!m_active) { -// return; -// } - -// xmrig::Nonce::pause(!enabled); -// xmrig::Nonce::touch(); -//} - - -//void Workers::setJob(const xmrig::Job &job, bool donate) -//{ -// uv_rwlock_wrlock(&m_rwlock); - -// m_job = job; -// m_job.setIndex(donate ? 1 : 0); - -// xmrig::Nonce::reset(donate ? 1 : 0); - -// uv_rwlock_wrunlock(&m_rwlock); - -// m_active = true; -// if (!m_enabled) { -// return; -// } - -// xmrig::Nonce::pause(false); -//} - - -void WorkersLegacy::start(xmrig::Controller *controller) -{ - using namespace xmrig; - -# ifdef APP_DEBUG - LOG_NOTICE("THREADS ------------------------------------------------------------------"); - for (const xmrig::IThread *thread : controller->config()->threads()) { - thread->print(); - } - LOG_NOTICE("--------------------------------------------------------------------------"); -# endif - - m_controller = controller; - - m_status.algo = xmrig::Algorithm::RX_WOW; // FIXME algo - const CpuThreads &threads = controller->config()->cpu().threads().get(m_status.algo); - m_status.threads = threads.size(); - - for (const CpuThread &thread : threads) { - m_status.ways += thread.intensity(); - } - -// m_hashrate = new Hashrate(threads.size(), controller); - - uv_mutex_init(&m_mutex); - uv_rwlock_init(&m_rwlock); - -// m_timer = new uv_timer_t; -// uv_timer_init(uv_default_loop(), m_timer); -// uv_timer_start(m_timer, Workers::onTick, 500, 500); - -// size_t index = 0; -// for (const CpuThread &thread : threads) { -// Thread *handle = new Thread(index++, CpuLaunchData(m_status.algo, controller->config()->cpu(), thread)); - -// m_workers.push_back(handle); -// handle->start(WorkersLegacy::onReady); -// } -} - - -//void Workers::stop() -//{ -// xmrig::Handle::close(m_timer); -// m_hashrate->stop(); - -// xmrig::Nonce::stop(); - -// for (size_t i = 0; i < m_workers.size(); ++i) { -// m_workers[i]->join(); -// } -//} - - -//#ifdef XMRIG_FEATURE_API -//void WorkersLegacy::threadsSummary(rapidjson::Document &doc) -//{ -// uv_mutex_lock(&m_mutex); -// const uint64_t pages[2] = { m_status.hugePages, m_status.pages }; -// const uint64_t memory = m_status.ways * xmrig::CnAlgo<>::memory(m_status.algo); -// uv_mutex_unlock(&m_mutex); - -// auto &allocator = doc.GetAllocator(); - -// rapidjson::Value hugepages(rapidjson::kArrayType); -// hugepages.PushBack(pages[0], allocator); -// hugepages.PushBack(pages[1], allocator); - -// doc.AddMember("hugepages", hugepages, allocator); -// doc.AddMember("memory", memory, allocator); -//} -//#endif - - -//void WorkersLegacy::onTick(uv_timer_t *) -//{ -// using namespace xmrig; - -// for (Thread *handle : m_workers) { -// if (!handle->worker()) { -// return; -// } - -// m_hashrate->add(handle->index(), handle->worker()->hashCount(), handle->worker()->timestamp()); -// } - -// if ((m_ticks++ & 0xF) == 0) { -// m_hashrate->updateHighest(); -// } -//} - - -void WorkersLegacy::start(xmrig::IWorker *worker) -{ -// const Worker *w = static_cast(worker); - - uv_mutex_lock(&m_mutex); - m_status.started++; -// m_status.pages += w->memory().pages; -// m_status.hugePages += w->memory().hugePages; - - if (m_status.started == m_status.threads) { - const double percent = (double) m_status.hugePages / m_status.pages * 100.0; - const size_t memory = m_status.ways * xmrig::CnAlgo<>::memory(m_status.algo) / 1024; - -# ifdef XMRIG_ALGO_RANDOMX - if (m_status.algo.family() == xmrig::Algorithm::RANDOM_X) { - LOG_INFO(GREEN_BOLD("READY (CPU)") " threads " CYAN_BOLD("%zu(%zu)") " memory " CYAN_BOLD("%zu KB") "", - m_status.threads, m_status.ways, memory); - } else -# endif - { - LOG_INFO(GREEN_BOLD("READY (CPU)") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") "", - m_status.threads, m_status.ways, - (m_status.hugePages == m_status.pages ? GREEN_BOLD_S : (m_status.hugePages == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), - m_status.hugePages, m_status.pages, percent, memory); - } - } - - uv_mutex_unlock(&m_mutex); - - worker->start(); -} diff --git a/src/workers/WorkersLegacy.h b/src/workers/WorkersLegacy.h deleted file mode 100644 index d8ab1e59..00000000 --- a/src/workers/WorkersLegacy.h +++ /dev/null @@ -1,113 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef XMRIG_WORKERSLEGACY_H -#define XMRIG_WORKERSLEGACY_H - - -#include -#include -#include -#include - -#ifdef XMRIG_ALGO_RANDOMX -# include -#endif - -#include "backend/common/Thread.h" -#include "backend/cpu/CpuLaunchData.h" -#include "base/net/stratum/Job.h" -#include "net/JobResult.h" -#include "rapidjson/fwd.h" - - -//class Hashrate; - - -namespace xmrig { - class IWorker; - class Controller; - class ThreadHandle; -} - - -class WorkersLegacy -{ -public: -// static size_t hugePages(); -// static size_t threads(); -// static void pause(); -// static void printHashrate(bool detail); -// static void setEnabled(bool enabled); -// static void setJob(const xmrig::Job &job, bool donate); - static void start(xmrig::Controller *controller); -// static void stop(); -// static xmrig::Job job(); - -// static inline bool isEnabled() { return m_enabled; } -// static inline Hashrate *hashrate() { return m_hashrate; } - -//# ifdef XMRIG_FEATURE_API -// static void threadsSummary(rapidjson::Document &doc); -//# endif - -private: -// static void onReady(void *arg); -// static void onTick(uv_timer_t *handle); - static void start(xmrig::IWorker *worker); - - class LaunchStatus - { - public: - inline LaunchStatus() : - hugePages(0), - pages(0), - started(0), - threads(0), - ways(0) - {} - - size_t hugePages; - size_t pages; - size_t started; - size_t threads; - size_t ways; - xmrig::Algorithm algo; - }; - - static bool m_active; - static bool m_enabled; -// static Hashrate *m_hashrate; - static xmrig::Job m_job; - static LaunchStatus m_status; - static std::vector* > m_workers; - static uint64_t m_ticks; - static uv_mutex_t m_mutex; - static uv_rwlock_t m_rwlock; -// static uv_timer_t *m_timer; - static xmrig::Controller *m_controller; -}; - - -#endif /* XMRIG_WORKERSLEGACY_H */ From 630a5dce676d5492fc81518853fef329e9dd4240 Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 17 Jul 2019 15:09:37 +0700 Subject: [PATCH 38/65] Improved log. --- src/backend/cpu/CpuBackend.cpp | 17 +++++++++++++++-- src/core/config/Config.cpp | 9 --------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/backend/cpu/CpuBackend.cpp b/src/backend/cpu/CpuBackend.cpp index bdb592ff..f325d0ff 100644 --- a/src/backend/cpu/CpuBackend.cpp +++ b/src/backend/cpu/CpuBackend.cpp @@ -32,6 +32,7 @@ #include "backend/cpu/CpuBackend.h" #include "base/io/log/Log.h" #include "base/net/stratum/Job.h" +#include "base/tools/Chrono.h" #include "base/tools/String.h" #include "core/config/Config.h" #include "core/Controller.h" @@ -55,6 +56,7 @@ public: started = 0; threads = 0; ways = 0; + ts = Chrono::steadyMSecs(); } size_t hugePages; @@ -63,6 +65,7 @@ public: size_t started; size_t threads; size_t ways; + uint64_t ts; }; @@ -108,6 +111,14 @@ public: profileName = cpu.threads().profileName(job.algorithm()); threads = cpu.threads().get(profileName); + if (profileName.isNull() || threads.empty()) { + workers.stop(); + + LOG_WARN(YELLOW_BOLD_S "CPU disabled, no suitable configuration for algo %s", job.algorithm().shortName()); + + return; + } + LOG_INFO(GREEN_BOLD("CPU") " use profile " BLUE_BG(WHITE_BOLD_S " %s ") WHITE_BOLD_S " (" CYAN_BOLD("%zu") WHITE_BOLD(" threads)") " scratchpad " CYAN_BOLD("%zu KB"), profileName.data(), threads.size(), @@ -217,10 +228,12 @@ void xmrig::CpuBackend::start(IWorker *worker) const double percent = d_ptr->status.hugePages == 0 ? 0.0 : static_cast(d_ptr->status.hugePages) / d_ptr->status.pages * 100.0; const size_t memory = d_ptr->status.ways * d_ptr->status.memory / 1024; - LOG_INFO(GREEN_BOLD("CPU READY") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") "", + LOG_INFO(GREEN_BOLD("CPU READY") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") BLACK_BOLD(" (%" PRIu64 " ms)"), d_ptr->status.threads, d_ptr->status.ways, (d_ptr->status.hugePages == d_ptr->status.pages ? GREEN_BOLD_S : (d_ptr->status.hugePages == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), - d_ptr->status.hugePages, d_ptr->status.pages, percent, memory); + d_ptr->status.hugePages, d_ptr->status.pages, percent, memory, + Chrono::steadyMSecs() - d_ptr->status.ts + ); } uv_mutex_unlock(&d_ptr->mutex); diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 02ef9c90..09728b4e 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -79,15 +79,6 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const doc.AddMember("background", isBackground(), allocator); doc.AddMember("colors", Log::colors, allocator); -// if (affinity() != -1L) { -// snprintf(affinity_tmp, sizeof(affinity_tmp) - 1, "0x%" PRIX64, affinity()); -// doc.AddMember("cpu-affinity", StringRef(affinity_tmp), allocator); -// } -// else { -// doc.AddMember("cpu-affinity", kNullType, allocator); -// } - - doc.AddMember("cpu", m_cpu.toJSON(doc), allocator); doc.AddMember("donate-level", m_pools.donateLevel(), allocator); From 6f93b7b38d164c8f6ed90885375ddbe63126b9df Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 17 Jul 2019 15:28:59 +0700 Subject: [PATCH 39/65] Removed unused code. --- CMakeLists.txt | 2 - src/Summary.cpp | 28 +-- src/backend/cpu/interfaces/ICpuInfo.h | 1 - src/backend/cpu/platform/AdvancedCpuInfo.cpp | 39 ---- src/backend/cpu/platform/AdvancedCpuInfo.h | 1 - src/backend/cpu/platform/BasicCpuInfo.cpp | 8 - src/backend/cpu/platform/BasicCpuInfo.h | 1 - src/backend/cpu/platform/BasicCpuInfo_arm.cpp | 6 - src/core/config/Config.cpp | 155 +------------ src/core/config/Config.h | 42 +--- src/workers/CpuThreadLegacy.cpp | 219 ------------------ src/workers/CpuThreadLegacy.h | 108 --------- 12 files changed, 19 insertions(+), 591 deletions(-) delete mode 100644 src/workers/CpuThreadLegacy.cpp delete mode 100644 src/workers/CpuThreadLegacy.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 89be20ec..4d205f55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,7 +42,6 @@ set(HEADERS src/net/strategies/DonateStrategy.h src/Summary.h src/version.h - src/workers/CpuThreadLegacy.h ) set(HEADERS_CRYPTO @@ -88,7 +87,6 @@ set(SOURCES src/net/NetworkState.cpp src/net/strategies/DonateStrategy.cpp src/Summary.cpp - src/workers/CpuThreadLegacy.cpp src/xmrig.cpp ) diff --git a/src/Summary.cpp b/src/Summary.cpp index af7cad09..36f59ba3 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -84,29 +84,11 @@ static void print_cpu(xmrig::Config *) static void print_threads(xmrig::Config *config) { - if (config->threadsMode() != xmrig::Config::Advanced) { - char buf[32] = { 0 }; -// if (config->affinity() != -1L) { -// snprintf(buf, sizeof buf, ", affinity=0x%" PRIX64, config->affinity()); -// } - - xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%d") WHITE_BOLD(", av=%d, %sdonate=%d%%") WHITE_BOLD("%s"), - "THREADS", - config->threadsCount(), - config->algoVariant(), - config->pools().donateLevel() == 0 ? RED_BOLD_S : "", - config->pools().donateLevel(), - buf - ); - } - else { - xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%d") WHITE_BOLD(", %sdonate=%d%%"), - "THREADS", - config->threadsCount(), - config->pools().donateLevel() == 0 ? RED_BOLD_S : "", - config->pools().donateLevel() - ); - } + xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s%d%%"), + "DONATE", + config->pools().donateLevel() == 0 ? RED_BOLD_S : "", + config->pools().donateLevel() + ); # ifdef XMRIG_FEATURE_ASM if (config->cpu().assembly() == xmrig::Assembly::AUTO) { diff --git a/src/backend/cpu/interfaces/ICpuInfo.h b/src/backend/cpu/interfaces/ICpuInfo.h index 74f6baee..5848db89 100644 --- a/src/backend/cpu/interfaces/ICpuInfo.h +++ b/src/backend/cpu/interfaces/ICpuInfo.h @@ -55,7 +55,6 @@ public: virtual size_t L2() const = 0; virtual size_t L3() const = 0; virtual size_t nodes() const = 0; - virtual size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const = 0; virtual size_t sockets() 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 f3c4ed23..45b0dd66 100644 --- a/src/backend/cpu/platform/AdvancedCpuInfo.cpp +++ b/src/backend/cpu/platform/AdvancedCpuInfo.cpp @@ -80,45 +80,6 @@ xmrig::AdvancedCpuInfo::AdvancedCpuInfo() : } -size_t xmrig::AdvancedCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) const -{ - if (threads() == 1) { - return 1; - } - - size_t cache = 0; - if (m_L3) { - cache = m_L2_exclusive ? (m_L2 + m_L3) : m_L3; - } - else { - cache = m_L2; - } - - size_t count = 0; - - if (cache) { - count = cache / memSize; - - if (cache % memSize >= memSize / 2) { - count++; - } - } - else { - count = threads() / 2; - } - - if (count > (size_t) threads()) { - count = threads(); - } - - if (((float) count / threads() * 100) > maxCpuUsage) { - count = (int) ceil((float) threads() * (maxCpuUsage / 100.0)); - } - - return count < 1 ? 1 : count; -} - - xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm) const { if (threads() == 1) { diff --git a/src/backend/cpu/platform/AdvancedCpuInfo.h b/src/backend/cpu/platform/AdvancedCpuInfo.h index 9852f6bd..889fba00 100644 --- a/src/backend/cpu/platform/AdvancedCpuInfo.h +++ b/src/backend/cpu/platform/AdvancedCpuInfo.h @@ -38,7 +38,6 @@ public: AdvancedCpuInfo(); protected: - size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const override; CpuThreads threads(const Algorithm &algorithm) const override; inline Assembly::Id assembly() const override { return m_assembly; } diff --git a/src/backend/cpu/platform/BasicCpuInfo.cpp b/src/backend/cpu/platform/BasicCpuInfo.cpp index 369392b6..f30466fe 100644 --- a/src/backend/cpu/platform/BasicCpuInfo.cpp +++ b/src/backend/cpu/platform/BasicCpuInfo.cpp @@ -153,14 +153,6 @@ xmrig::BasicCpuInfo::BasicCpuInfo() : } -size_t xmrig::BasicCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) const -{ - const size_t count = threads() / 2; - - return count < 1 ? 1 : count; -} - - xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm) const { if (threads() == 1) { diff --git a/src/backend/cpu/platform/BasicCpuInfo.h b/src/backend/cpu/platform/BasicCpuInfo.h index 886d59c3..12d0e037 100644 --- a/src/backend/cpu/platform/BasicCpuInfo.h +++ b/src/backend/cpu/platform/BasicCpuInfo.h @@ -38,7 +38,6 @@ public: BasicCpuInfo(); protected: - size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const override; CpuThreads threads(const Algorithm &algorithm) const override; inline Assembly::Id assembly() const override { return m_assembly; } diff --git a/src/backend/cpu/platform/BasicCpuInfo_arm.cpp b/src/backend/cpu/platform/BasicCpuInfo_arm.cpp index 6702f6f0..3d733535 100644 --- a/src/backend/cpu/platform/BasicCpuInfo_arm.cpp +++ b/src/backend/cpu/platform/BasicCpuInfo_arm.cpp @@ -57,12 +57,6 @@ xmrig::BasicCpuInfo::BasicCpuInfo() : } -size_t xmrig::BasicCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) const -{ - return threads(); -} - - xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm) const { return CpuThreads(threads()); diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 09728b4e..d6336b67 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -36,12 +36,9 @@ #include "rapidjson/document.h" #include "rapidjson/filewritestream.h" #include "rapidjson/prettywriter.h" -#include "workers/CpuThreadLegacy.h" -xmrig::Config::Config() : - m_algoVariant(CnHash::AV_AUTO), - m_shouldSave(false) +xmrig::Config::Config() : BaseConfig() { } @@ -54,10 +51,7 @@ bool xmrig::Config::read(const IJsonReader &reader, const char *fileName) m_cpu.read(reader.getValue("cpu")); - setAlgoVariant(reader.getInt("av")); - setThreads(reader.getValue("threads")); - - return finalize(); + return true; } @@ -72,148 +66,21 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const Value api(kObjectType); api.AddMember("id", m_apiId.toJSON(), allocator); api.AddMember("worker-id", m_apiWorkerId.toJSON(), allocator); - doc.AddMember("api", api, allocator); - doc.AddMember("http", m_http.toJSON(doc), allocator); - doc.AddMember("autosave", isAutoSave(), allocator); - doc.AddMember("av", algoVariant(), allocator); - doc.AddMember("background", isBackground(), allocator); - doc.AddMember("colors", Log::colors, allocator); - - doc.AddMember("cpu", m_cpu.toJSON(doc), allocator); + doc.AddMember("api", api, allocator); + doc.AddMember("autosave", isAutoSave(), allocator); + doc.AddMember("background", isBackground(), allocator); + doc.AddMember("colors", Log::colors, allocator); + doc.AddMember("cpu", m_cpu.toJSON(doc), allocator); doc.AddMember("donate-level", m_pools.donateLevel(), allocator); doc.AddMember("donate-over-proxy", m_pools.proxyDonate(), allocator); + doc.AddMember("http", m_http.toJSON(doc), allocator); doc.AddMember("log-file", m_logFile.toJSON(), allocator); doc.AddMember("pools", m_pools.toJSON(doc), allocator); doc.AddMember("print-time", printTime(), allocator); doc.AddMember("retries", m_pools.retries(), allocator); doc.AddMember("retry-pause", m_pools.retryPause(), allocator); - - if (threadsMode() != Simple) { - Value threads(kArrayType); - - for (const IThread *thread : m_threads.list) { - threads.PushBack(thread->toConfig(doc), allocator); - } - - doc.AddMember("threads", threads, allocator); - } - else { - doc.AddMember("threads", threadsCount(), allocator); - } - - doc.AddMember("user-agent", m_userAgent.toJSON(), allocator); - doc.AddMember("syslog", isSyslog(), allocator); - doc.AddMember("watch", m_watch, allocator); + doc.AddMember("syslog", isSyslog(), allocator); + doc.AddMember("user-agent", m_userAgent.toJSON(), allocator); + doc.AddMember("watch", m_watch, allocator); } - - -bool xmrig::Config::finalize() -{ - Algorithm algorithm(Algorithm::RX_WOW); // FIXME algo - - if (!m_threads.cpu.empty()) { - m_threads.mode = Advanced; - - for (size_t i = 0; i < m_threads.cpu.size(); ++i) { - m_threads.list.push_back(CpuThreadLegacy::createFromData(i, algorithm, m_threads.cpu[i], m_cpu.priority(), !m_cpu.isHwAES())); - } - - return true; - } - - const CnHash::AlgoVariant av = getAlgoVariant(); - m_threads.mode = m_threads.count ? Simple : Automatic; - - const size_t size = CpuThreadLegacy::multiway(av) * CnAlgo<>::memory(algorithm) / 1024; // FIXME MEMORY - - if (!m_threads.count) { - m_threads.count = Cpu::info()->optimalThreadsCount(size, 100); - } -// else if (m_safe) { -// const size_t count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); -// if (m_threads.count > count) { -// m_threads.count = count; -// } -// } - - for (size_t i = 0; i < m_threads.count; ++i) { - m_threads.list.push_back(CpuThreadLegacy::createFromAV(i, algorithm, av, m_threads.mask, m_cpu.priority(), m_cpu.assembly())); - } - - m_shouldSave = m_threads.mode == Automatic; - - return true; -} - - -void xmrig::Config::setAlgoVariant(int av) -{ - if (av >= CnHash::AV_AUTO && av < CnHash::AV_MAX) { - m_algoVariant = static_cast(av); - } -} - - -void xmrig::Config::setThreads(const rapidjson::Value &threads) -{ - if (threads.IsArray()) { - m_threads.cpu.clear(); - - for (const rapidjson::Value &value : threads.GetArray()) { - if (!value.IsObject()) { - continue; - } - - if (value.HasMember("low_power_mode")) { - auto data = CpuThreadLegacy::parse(value); - - if (data.valid) { - m_threads.cpu.push_back(std::move(data)); - } - } - } - } - else if (threads.IsUint()) { - const unsigned count = threads.GetUint(); - if (count < 1024) { - m_threads.count = count; - } - } -} - - -xmrig::CnHash::AlgoVariant xmrig::Config::getAlgoVariant() const -{ -# ifdef XMRIG_ALGO_CN_LITE -// if (m_algorithm.algo() == xmrig::CRYPTONIGHT_LITE) { // FIXME -// return getAlgoVariantLite(); -// } -# endif - - if (m_algoVariant <= CnHash::AV_AUTO || m_algoVariant >= CnHash::AV_MAX) { - return Cpu::info()->hasAES() ? CnHash::AV_SINGLE : CnHash::AV_SINGLE_SOFT; - } - -// if (m_safe && !Cpu::info()->hasAES() && m_algoVariant <= AV_DOUBLE) { -// return static_cast(m_algoVariant + 2); -// } - - return m_algoVariant; -} - - -#ifdef XMRIG_ALGO_CN_LITE -xmrig::CnHash::AlgoVariant xmrig::Config::getAlgoVariantLite() const -{ - if (m_algoVariant <= CnHash::AV_AUTO || m_algoVariant >= CnHash::AV_MAX) { - return Cpu::info()->hasAES() ? CnHash::AV_DOUBLE : CnHash::AV_DOUBLE_SOFT; - } - -// if (m_safe && !Cpu::info()->hasAES() && m_algoVariant <= AV_DOUBLE) { -// return static_cast(m_algoVariant + 2); -// } - - return m_algoVariant; -} -#endif diff --git a/src/core/config/Config.h b/src/core/config/Config.h index aa547796..e6b5c735 100644 --- a/src/core/config/Config.h +++ b/src/core/config/Config.h @@ -27,13 +27,11 @@ #include -#include #include "backend/cpu/CpuConfig.h" #include "base/kernel/config/BaseConfig.h" #include "rapidjson/fwd.h" -#include "workers/CpuThreadLegacy.h" namespace xmrig { @@ -45,51 +43,17 @@ class IThread; class Config : public BaseConfig { public: - enum ThreadsMode { - Automatic, - Simple, - Advanced - }; - - Config(); bool read(const IJsonReader &reader, const char *fileName) override; void getJSON(rapidjson::Document &doc) const override; - inline CnHash::AlgoVariant algoVariant() const { return m_algoVariant; } - inline bool isShouldSave() const { return (m_shouldSave || m_upgrade || m_cpu.isShouldSave()) && isAutoSave(); } - inline const CpuConfig &cpu() const { return m_cpu; } - inline const std::vector &threads() const { return m_threads.list; } - inline int threadsCount() const { return static_cast(m_threads.list.size()); } - inline ThreadsMode threadsMode() const { return m_threads.mode; } + inline bool isShouldSave() const { return (m_shouldSave || m_upgrade || m_cpu.isShouldSave()) && isAutoSave(); } + inline const CpuConfig &cpu() const { return m_cpu; } private: - bool finalize(); - void setAlgoVariant(int av); - void setThreads(const rapidjson::Value &threads); - - CnHash::AlgoVariant getAlgoVariant() const; -# ifdef XMRIG_ALGO_CN_LITE - CnHash::AlgoVariant getAlgoVariantLite() const; -# endif - - struct Threads - { - inline Threads() : mask(-1L), count(0), mode(Automatic) {} - - int64_t mask; - size_t count; - std::vector cpu; - std::vector list; - ThreadsMode mode; - }; - - - CnHash::AlgoVariant m_algoVariant; - bool m_shouldSave; + bool m_shouldSave = false; CpuConfig m_cpu; - Threads m_threads; }; diff --git a/src/workers/CpuThreadLegacy.cpp b/src/workers/CpuThreadLegacy.cpp deleted file mode 100644 index b5d457c7..00000000 --- a/src/workers/CpuThreadLegacy.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - - -#include "base/io/log/Log.h" -#include "crypto/cn/CnHash.h" -#include "crypto/common/Assembly.h" -#include "crypto/common/VirtualMemory.h" -#include "rapidjson/document.h" -#include "workers/CpuThreadLegacy.h" - - -xmrig::CpuThreadLegacy::CpuThreadLegacy(size_t index, Algorithm algorithm, CnHash::AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly) : - m_algorithm(algorithm), - m_av(av), - m_assembly(assembly), - m_prefetch(prefetch), - m_softAES(softAES), - m_priority(priority), - m_affinity(affinity), - m_multiway(multiway), - m_index(index) -{ -} - - -xmrig::cn_hash_fun xmrig::CpuThreadLegacy::fn(const Algorithm &algorithm) const -{ - return CnHash::fn(algorithm, m_av, m_assembly); -} - - - -bool xmrig::CpuThreadLegacy::isSoftAES(CnHash::AlgoVariant av) -{ - return av == CnHash::AV_SINGLE_SOFT || av == CnHash::AV_DOUBLE_SOFT || av > CnHash::AV_PENTA; -} - - -xmrig::CpuThreadLegacy *xmrig::CpuThreadLegacy::createFromAV(size_t index, const Algorithm &algorithm, CnHash::AlgoVariant av, int64_t affinity, int priority, Assembly assembly) -{ - assert(av > CnHash::AV_AUTO && av < CnHash::AV_MAX); - - int64_t cpuId = -1L; - - if (affinity != -1L) { - size_t idx = 0; - - for (size_t i = 0; i < 64; i++) { - if (!(affinity & (1ULL << i))) { - continue; - } - - if (idx == index) { - cpuId = i; - break; - } - - idx++; - } - } - - return new CpuThreadLegacy(index, algorithm, av, multiway(av), cpuId, priority, isSoftAES(av), false, assembly); -} - - -xmrig::CpuThreadLegacy *xmrig::CpuThreadLegacy::createFromData(size_t index, const Algorithm &algorithm, const CpuThreadLegacy::Data &data, int priority, bool softAES) -{ - int av = CnHash::AV_AUTO; - const Multiway multiway = data.multiway; - - if (multiway <= DoubleWay) { - av = softAES ? (multiway + 2) : multiway; - } - else { - av = softAES ? (multiway + 5) : (multiway + 2); - } - - assert(av > CnHash::AV_AUTO && av < CnHash::AV_MAX); - - return new CpuThreadLegacy(index, algorithm, static_cast(av), multiway, data.affinity, priority, softAES, false, data.assembly); -} - - -xmrig::CpuThreadLegacy::Data xmrig::CpuThreadLegacy::parse(const rapidjson::Value &object) -{ - Data data; - - const auto &multiway = object["low_power_mode"]; - if (multiway.IsBool()) { - data.multiway = multiway.IsTrue() ? DoubleWay : SingleWay; - data.valid = true; - } - else if (multiway.IsUint()) { - data.setMultiway(multiway.GetInt()); - } - - if (!data.valid) { - return data; - } - - const auto &affinity = object["affine_to_cpu"]; - if (affinity.IsUint64()) { - data.affinity = affinity.GetInt64(); - } - -# ifdef XMRIG_FEATURE_ASM - data.assembly = object["asm"]; -# endif - - return data; -} - - -xmrig::IThread::Multiway xmrig::CpuThreadLegacy::multiway(CnHash::AlgoVariant av) -{ - switch (av) { - case CnHash::AV_SINGLE: - case CnHash::AV_SINGLE_SOFT: - return SingleWay; - - case CnHash::AV_DOUBLE_SOFT: - case CnHash::AV_DOUBLE: - return DoubleWay; - - case CnHash::AV_TRIPLE_SOFT: - case CnHash::AV_TRIPLE: - return TripleWay; - - case CnHash::AV_QUAD_SOFT: - case CnHash::AV_QUAD: - return QuadWay; - - case CnHash::AV_PENTA_SOFT: - case CnHash::AV_PENTA: - return PentaWay; - - default: - break; - } - - return SingleWay; -} - - -#ifdef APP_DEBUG -void xmrig::CpuThreadLegacy::print() const -{ - LOG_DEBUG(GREEN_BOLD("CPU thread: ") " index " WHITE_BOLD("%zu") ", multiway " WHITE_BOLD("%d") ", av " WHITE_BOLD("%d") ",", - index(), static_cast(multiway()), static_cast(m_av)); - -# ifdef XMRIG_FEATURE_ASM - LOG_DEBUG(" assembly: %s, affine_to_cpu: %" PRId64, m_assembly.toString(), affinity()); -# else - LOG_DEBUG(" affine_to_cpu: %" PRId64, affinity()); -# endif -} -#endif - - -#ifdef XMRIG_FEATURE_API -rapidjson::Value xmrig::CpuThreadLegacy::toAPI(rapidjson::Document &doc) const -{ - using namespace rapidjson; - - Value obj(kObjectType); - auto &allocator = doc.GetAllocator(); - - obj.AddMember("type", "cpu", allocator); - obj.AddMember("av", m_av, allocator); - obj.AddMember("low_power_mode", multiway(), allocator); - obj.AddMember("affine_to_cpu", affinity(), allocator); - obj.AddMember("priority", priority(), allocator); - obj.AddMember("soft_aes", isSoftAES(), allocator); - - return obj; -} -#endif - - -rapidjson::Value xmrig::CpuThreadLegacy::toConfig(rapidjson::Document &doc) const -{ - using namespace rapidjson; - - Value obj(kObjectType); - auto &allocator = doc.GetAllocator(); - - obj.AddMember("low_power_mode", multiway(), allocator); - obj.AddMember("affine_to_cpu", affinity() == -1L ? Value(kFalseType) : Value(affinity()), allocator); - -# ifdef XMRIG_FEATURE_ASM - obj.AddMember("asm", m_assembly.toJSON(), allocator); -# endif - - return obj; -} diff --git a/src/workers/CpuThreadLegacy.h b/src/workers/CpuThreadLegacy.h deleted file mode 100644 index b803a8c4..00000000 --- a/src/workers/CpuThreadLegacy.h +++ /dev/null @@ -1,108 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef XMRIG_CPUTHREADLEGACY_H -#define XMRIG_CPUTHREADLEGACY_H - - -#include "backend/common/interfaces/IThread.h" -#include "crypto/cn/CnHash.h" - - -struct cryptonight_ctx; - - -namespace xmrig { - - -class CpuThreadLegacy : public IThread -{ -public: - struct Data - { - inline Data() : valid(false), affinity(-1L), multiway(SingleWay) {} - - inline void setMultiway(int value) - { - if (value >= SingleWay && value <= PentaWay) { - multiway = static_cast(value); - valid = true; - } - } - - Assembly assembly; - bool valid; - int64_t affinity; - Multiway multiway; - }; - - - CpuThreadLegacy(size_t index, Algorithm algorithm, CnHash::AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly); - - cn_hash_fun fn(const Algorithm &algorithm) const; - - static bool isSoftAES(CnHash::AlgoVariant av); - static CpuThreadLegacy *createFromAV(size_t index, const Algorithm &algorithm, CnHash::AlgoVariant av, int64_t affinity, int priority, Assembly assembly); - static CpuThreadLegacy *createFromData(size_t index, const Algorithm &algorithm, const CpuThreadLegacy::Data &data, int priority, bool softAES); - static Data parse(const rapidjson::Value &object); - static Multiway multiway(CnHash::AlgoVariant av); - - inline bool isPrefetch() const { return m_prefetch; } - inline bool isSoftAES() const { return m_softAES; } - - inline Algorithm algorithm() const override { return m_algorithm; } - inline int priority() const override { return m_priority; } - inline int64_t affinity() const override { return m_affinity; } - inline Multiway multiway() const override { return m_multiway; } - inline size_t index() const override { return m_index; } - inline Type type() const override { return CPU; } - -protected: -# ifdef APP_DEBUG - void print() const override; -# endif - -# ifdef XMRIG_FEATURE_API - rapidjson::Value toAPI(rapidjson::Document &doc) const override; -# endif - - rapidjson::Value toConfig(rapidjson::Document &doc) const override; - -private: - const Algorithm m_algorithm; - const CnHash::AlgoVariant m_av; - const Assembly m_assembly; - const bool m_prefetch; - const bool m_softAES; - const int m_priority; - const int64_t m_affinity; - const Multiway m_multiway; - const size_t m_index; -}; - - -} /* namespace xmrig */ - - -#endif /* XMRIG_CPUTHREADLEGACY_H */ From 871bc3e1801c979a51e244b5c4485743684ccd62 Mon Sep 17 00:00:00 2001 From: XMRig Date: Thu, 18 Jul 2019 04:21:14 +0700 Subject: [PATCH 40/65] Fixed bugs. --- src/backend/common/Thread.h | 6 ++++-- src/backend/cpu/CpuWorker.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/backend/common/Thread.h b/src/backend/common/Thread.h index b62d880c..36367ece 100644 --- a/src/backend/common/Thread.h +++ b/src/backend/common/Thread.h @@ -29,11 +29,13 @@ #include +#include "backend/common/interfaces/IWorker.h" + + namespace xmrig { class IBackend; -class IWorker; template @@ -41,7 +43,7 @@ class Thread { public: inline Thread(IBackend *backend, size_t index, const T &config) : m_index(index), m_config(config), m_backend(backend) {} - inline ~Thread() { uv_thread_join(&m_thread); } + inline ~Thread() { uv_thread_join(&m_thread); delete m_worker; } inline const T &config() const { return m_config; } inline IBackend *backend() const { return m_backend; } diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp index 356dfb1b..4318b8ce 100644 --- a/src/backend/cpu/CpuWorker.cpp +++ b/src/backend/cpu/CpuWorker.cpp @@ -158,7 +158,7 @@ void xmrig::CpuWorker::start() do { std::this_thread::sleep_for(std::chrono::milliseconds(200)); } - while (Nonce::isPaused()); + while (Nonce::isPaused() && Nonce::sequence(Nonce::CPU) > 0); if (Nonce::sequence(Nonce::CPU) == 0) { break; From f590cf58fb9f2b0899354402213087832610bf87 Mon Sep 17 00:00:00 2001 From: XMRig Date: Thu, 18 Jul 2019 19:11:45 +0700 Subject: [PATCH 41/65] Added support for threads restart if config changed. --- src/backend/common/Workers.cpp | 13 ++--- src/backend/common/Workers.h | 3 +- src/backend/common/interfaces/IBackend.h | 16 +++--- src/backend/cpu/CpuBackend.cpp | 73 ++++++++++-------------- src/backend/cpu/CpuBackend.h | 1 + src/backend/cpu/CpuConfig.cpp | 19 ++++++ src/backend/cpu/CpuConfig.h | 2 + src/backend/cpu/CpuLaunchData.cpp | 13 +++++ src/backend/cpu/CpuLaunchData.h | 4 ++ src/base/net/stratum/Pool.cpp | 3 +- src/core/Miner.cpp | 16 ++++++ src/core/Miner.h | 4 +- 12 files changed, 105 insertions(+), 62 deletions(-) diff --git a/src/backend/common/Workers.cpp b/src/backend/common/Workers.cpp index 629b564b..d70546d3 100644 --- a/src/backend/common/Workers.cpp +++ b/src/backend/common/Workers.cpp @@ -78,13 +78,6 @@ const xmrig::Hashrate *xmrig::Workers::hashrate() const } -template -void xmrig::Workers::add(const T &data) -{ - m_workers.push_back(new Thread(d_ptr->backend, m_workers.size(), data)); -} - - template void xmrig::Workers::setBackend(IBackend *backend) { @@ -93,8 +86,12 @@ void xmrig::Workers::setBackend(IBackend *backend) template -void xmrig::Workers::start() +void xmrig::Workers::start(const std::vector &data) { + for (const T &item : data) { + m_workers.push_back(new Thread(d_ptr->backend, m_workers.size(), item)); + } + d_ptr->hashrate = new Hashrate(m_workers.size()); for (Thread *worker : m_workers) { diff --git a/src/backend/common/Workers.h b/src/backend/common/Workers.h index c13f5e77..32d9458a 100644 --- a/src/backend/common/Workers.h +++ b/src/backend/common/Workers.h @@ -46,9 +46,8 @@ public: ~Workers(); const Hashrate *hashrate() const; - void add(const T &data); void setBackend(IBackend *backend); - void start(); + void start(const std::vector &data); void stop(); void tick(uint64_t ticks); diff --git a/src/backend/common/interfaces/IBackend.h b/src/backend/common/interfaces/IBackend.h index 8ad7bb53..6fe917cb 100644 --- a/src/backend/common/interfaces/IBackend.h +++ b/src/backend/common/interfaces/IBackend.h @@ -32,6 +32,7 @@ namespace xmrig { +class Algorithm; class Hashrate; class IWorker; class Job; @@ -43,13 +44,14 @@ class IBackend public: virtual ~IBackend() = default; - virtual const Hashrate *hashrate() const = 0; - virtual const String &profileName() const = 0; - virtual void printHashrate(bool details) = 0; - virtual void setJob(const Job &job) = 0; - virtual void start(IWorker *worker) = 0; - virtual void stop() = 0; - virtual void tick(uint64_t ticks) = 0; + virtual bool isEnabled(const Algorithm &algorithm) const = 0; + virtual const Hashrate *hashrate() const = 0; + virtual const String &profileName() const = 0; + virtual void printHashrate(bool details) = 0; + virtual void setJob(const Job &job) = 0; + virtual void start(IWorker *worker) = 0; + virtual void stop() = 0; + virtual void tick(uint64_t ticks) = 0; }; diff --git a/src/backend/cpu/CpuBackend.cpp b/src/backend/cpu/CpuBackend.cpp index f325d0ff..15a0c359 100644 --- a/src/backend/cpu/CpuBackend.cpp +++ b/src/backend/cpu/CpuBackend.cpp @@ -85,40 +85,8 @@ public: } - inline bool isReady(const Algorithm &nextAlgo) const + inline void start() { - if (!algo.isValid()) { - return false; - } - - if (nextAlgo == algo) { - return true; - } - - const CpuThreads &nextThreads = controller->config()->cpu().threads().get(nextAlgo); - - return algo.memory() == nextAlgo.memory() - && threads.size() == nextThreads.size() - && std::equal(threads.begin(), threads.end(), nextThreads.begin()); - } - - - inline void start(const Job &job) - { - const CpuConfig &cpu = controller->config()->cpu(); - - algo = job.algorithm(); - profileName = cpu.threads().profileName(job.algorithm()); - threads = cpu.threads().get(profileName); - - if (profileName.isNull() || threads.empty()) { - workers.stop(); - - LOG_WARN(YELLOW_BOLD_S "CPU disabled, no suitable configuration for algo %s", job.algorithm().shortName()); - - return; - } - LOG_INFO(GREEN_BOLD("CPU") " use profile " BLUE_BG(WHITE_BOLD_S " %s ") WHITE_BOLD_S " (" CYAN_BOLD("%zu") WHITE_BOLD(" threads)") " scratchpad " CYAN_BOLD("%zu KB"), profileName.data(), threads.size(), @@ -131,20 +99,18 @@ public: status.memory = algo.memory(); status.threads = threads.size(); - for (const CpuThread &thread : threads) { - workers.add(CpuLaunchData(controller->miner(), algo, cpu, thread)); - - status.ways += static_cast(thread.intensity()); + for (const CpuLaunchData &data : threads) { + status.ways += static_cast(data.intensity); } - workers.start(); + workers.start(threads); } Algorithm algo; Controller *controller; - CpuThreads threads; LaunchStatus status; + std::vector threads; String profileName; uv_mutex_t mutex; Workers workers; @@ -167,6 +133,12 @@ xmrig::CpuBackend::~CpuBackend() } +bool xmrig::CpuBackend::isEnabled(const Algorithm &algorithm) const +{ + return !d_ptr->controller->config()->cpu().threads().get(algorithm).empty(); +} + + const xmrig::Hashrate *xmrig::CpuBackend::hashrate() const { return d_ptr->workers.hashrate(); @@ -190,10 +162,10 @@ void xmrig::CpuBackend::printHashrate(bool details) Log::print(WHITE_BOLD_S "| CPU THREAD | AFFINITY | 10s H/s | 60s H/s | 15m H/s |"); size_t i = 0; - for (const CpuThread &thread : d_ptr->threads) { + for (const CpuLaunchData &data : d_ptr->threads) { Log::print("| %13zu | %8" PRId64 " | %7s | %7s | %7s |", i, - thread.affinity(), + data.affinity, Hashrate::format(hashrate()->calc(i, Hashrate::ShortInterval), num, sizeof num / 3), 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) @@ -206,11 +178,26 @@ void xmrig::CpuBackend::printHashrate(bool details) void xmrig::CpuBackend::setJob(const Job &job) { - if (d_ptr->isReady(job.algorithm())) { + const CpuConfig &cpu = d_ptr->controller->config()->cpu(); + + std::vector threads = cpu.get(d_ptr->controller->miner(), job.algorithm()); + if (d_ptr->threads.size() == threads.size() && std::equal(d_ptr->threads.begin(), d_ptr->threads.end(), threads.begin())) { return; } - d_ptr->start(job); + d_ptr->algo = job.algorithm(); + d_ptr->profileName = cpu.threads().profileName(job.algorithm()); + + if (d_ptr->profileName.isNull() || threads.empty()) { + d_ptr->workers.stop(); + + LOG_WARN(YELLOW_BOLD_S "CPU disabled, no suitable configuration for algo %s", job.algorithm().shortName()); + + return; + } + + d_ptr->threads = std::move(threads); + d_ptr->start(); } diff --git a/src/backend/cpu/CpuBackend.h b/src/backend/cpu/CpuBackend.h index aabccb49..543d4459 100644 --- a/src/backend/cpu/CpuBackend.h +++ b/src/backend/cpu/CpuBackend.h @@ -44,6 +44,7 @@ public: ~CpuBackend() override; protected: + bool isEnabled(const Algorithm &algorithm) const override; const Hashrate *hashrate() const override; const String &profileName() const override; void printHashrate(bool details) override; diff --git a/src/backend/cpu/CpuConfig.cpp b/src/backend/cpu/CpuConfig.cpp index b4a9c363..457f7ef4 100644 --- a/src/backend/cpu/CpuConfig.cpp +++ b/src/backend/cpu/CpuConfig.cpp @@ -100,6 +100,25 @@ rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const } +std::vector xmrig::CpuConfig::get(const Miner *miner, const Algorithm &algorithm) const +{ + std::vector out; + const std::vector &threads = m_threads.get(algorithm); + + if (threads.empty()) { + return out; + } + + out.reserve(threads.size()); + + for (const CpuThread &thread : threads) { + out.push_back(CpuLaunchData(miner, algorithm, *this, thread)); + } + + return out; +} + + void xmrig::CpuConfig::read(const rapidjson::Value &value) { if (value.IsObject()) { diff --git a/src/backend/cpu/CpuConfig.h b/src/backend/cpu/CpuConfig.h index 88222ab1..8ff8b77c 100644 --- a/src/backend/cpu/CpuConfig.h +++ b/src/backend/cpu/CpuConfig.h @@ -27,6 +27,7 @@ #include "backend/common/Threads.h" +#include "backend/cpu/CpuLaunchData.h" #include "backend/cpu/CpuThread.h" #include "crypto/common/Assembly.h" @@ -47,6 +48,7 @@ public: bool isHwAES() const; rapidjson::Value toJSON(rapidjson::Document &doc) const; + std::vector get(const Miner *miner, const Algorithm &algorithm) const; void read(const rapidjson::Value &value); inline bool isEnabled() const { return m_enabled; } diff --git a/src/backend/cpu/CpuLaunchData.cpp b/src/backend/cpu/CpuLaunchData.cpp index 68b8e7ae..6fa458aa 100644 --- a/src/backend/cpu/CpuLaunchData.cpp +++ b/src/backend/cpu/CpuLaunchData.cpp @@ -41,6 +41,19 @@ xmrig::CpuLaunchData::CpuLaunchData(const Miner *miner, const Algorithm &algorit } +bool xmrig::CpuLaunchData::isEqual(const CpuLaunchData &other) const +{ + return (algorithm.memory() == other.algorithm.memory() + && assembly == other.assembly + && hugePages == other.hugePages + && hwAES == other.hwAES + && intensity == other.intensity + && priority == other.priority + && affinity == other.affinity + ); +} + + xmrig::CnHash::AlgoVariant xmrig::CpuLaunchData::av() const { if (intensity <= 2) { diff --git a/src/backend/cpu/CpuLaunchData.h b/src/backend/cpu/CpuLaunchData.h index 208a68b7..bb18816a 100644 --- a/src/backend/cpu/CpuLaunchData.h +++ b/src/backend/cpu/CpuLaunchData.h @@ -46,10 +46,14 @@ class CpuLaunchData public: CpuLaunchData(const Miner *miner, const Algorithm &algorithm, const CpuConfig &config, const CpuThread &thread); + bool isEqual(const CpuLaunchData &other) const; CnHash::AlgoVariant av() const; inline constexpr static Nonce::Backend backend() { return Nonce::CPU; } + inline bool operator!=(const CpuLaunchData &other) const { return !isEqual(other); } + inline bool operator==(const CpuLaunchData &other) const { return isEqual(other); } + const Algorithm algorithm; const Assembly assembly; const bool hugePages; diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index b11e1159..4d15ea47 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -192,7 +192,8 @@ bool xmrig::Pool::isEqual(const Pool &other) const && m_rigId == other.m_rigId && m_url == other.m_url && m_user == other.m_user - && m_pollInterval == other.m_pollInterval); + && m_pollInterval == other.m_pollInterval + ); } diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 40321662..4135e8ab 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -99,6 +99,8 @@ public: xmrig::Miner::Miner(Controller *controller) : d_ptr(new MinerPrivate(controller)) { + controller->addListener(this); + d_ptr->timer = new Timer(this); d_ptr->backends.push_back(new CpuBackend(controller)); @@ -218,6 +220,20 @@ void xmrig::Miner::stop() } +void xmrig::Miner::onConfigChanged(Config *config, Config *previousConfig) +{ + if (config->pools() != previousConfig->pools() && config->pools().active() > 0) { + return; + } + + const Job job = this->job(); + + for (IBackend *backend : d_ptr->backends) { + backend->setJob(job); + } +} + + void xmrig::Miner::onTimer(const Timer *) { double maxHashrate = 0.0; diff --git a/src/core/Miner.h b/src/core/Miner.h index f32524a7..23497eae 100644 --- a/src/core/Miner.h +++ b/src/core/Miner.h @@ -29,6 +29,7 @@ #include +#include "base/kernel/interfaces/IBaseListener.h" #include "base/kernel/interfaces/ITimerListener.h" @@ -41,7 +42,7 @@ class MinerPrivate; class IBackend; -class Miner : public ITimerListener +class Miner : public ITimerListener, public IBaseListener { public: Miner(Controller *controller); @@ -57,6 +58,7 @@ public: void stop(); protected: + void onConfigChanged(Config *config, Config *previousConfig) override; void onTimer(const Timer *timer) override; private: From 0ab26a16193e79d7ddf848e35d390fdae5469c23 Mon Sep 17 00:00:00 2001 From: XMRig Date: Thu, 18 Jul 2019 22:35:15 +0700 Subject: [PATCH 42/65] Restored algo field in login request. --- src/backend/cpu/CpuWorker.cpp | 4 ++ .../kernel/interfaces/IStrategyListener.h | 3 +- src/base/net/stratum/Client.cpp | 13 ----- .../stratum/strategies/FailoverStrategy.cpp | 8 +++- .../net/stratum/strategies/FailoverStrategy.h | 6 +-- .../stratum/strategies/SinglePoolStrategy.cpp | 8 +++- .../stratum/strategies/SinglePoolStrategy.h | 6 +-- src/core/Miner.cpp | 48 +++++++++++++++++-- src/core/Miner.h | 2 + src/crypto/common/Algorithm.h | 2 +- src/net/Network.cpp | 15 ++++++ src/net/Network.h | 1 + src/net/strategies/DonateStrategy.cpp | 43 ++++++++++++++--- src/net/strategies/DonateStrategy.h | 5 +- 14 files changed, 129 insertions(+), 35 deletions(-) diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp index 4318b8ce..e35c5155 100644 --- a/src/backend/cpu/CpuWorker.cpp +++ b/src/backend/cpu/CpuWorker.cpp @@ -174,6 +174,10 @@ void xmrig::CpuWorker::start() const Job &job = m_job.currentJob(); + if (job.algorithm().memory() != m_algorithm.memory()) { + break; + } + # ifdef XMRIG_ALGO_RANDOMX if (job.algorithm().family() == Algorithm::RANDOM_X) { randomx_calculate_hash(m_vm->get(), m_job.blob(), job.size(), m_hash); diff --git a/src/base/kernel/interfaces/IStrategyListener.h b/src/base/kernel/interfaces/IStrategyListener.h index 2e63449b..01e668d4 100644 --- a/src/base/kernel/interfaces/IStrategyListener.h +++ b/src/base/kernel/interfaces/IStrategyListener.h @@ -26,7 +26,7 @@ #define XMRIG_ISTRATEGYLISTENER_H -#include +#include "rapidjson/fwd.h" namespace xmrig { @@ -45,6 +45,7 @@ public: virtual void onActive(IStrategy *strategy, IClient *client) = 0; virtual void onJob(IStrategy *strategy, IClient *client, const Job &job) = 0; + virtual void onLogin(IStrategy *strategy, IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) = 0; virtual void onPause(IStrategy *strategy) = 0; virtual void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) = 0; }; diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index c1519573..0be86eca 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -575,19 +575,6 @@ void xmrig::Client::login() params.AddMember("rigid", m_pool.rigId().toJSON(), allocator); } -//# ifdef XMRIG_PROXY_PROJECT FIXME -// if (m_pool.algorithm().variant() != xmrig::VARIANT_AUTO) -//# endif -// { -// Value algo(kArrayType); - -// for (const auto &a : m_pool.algorithms()) { -// algo.PushBack(StringRef(a.shortName()), allocator); -// } - -// params.AddMember("algo", algo, allocator); -// } - m_listener->onLogin(this, doc, params); JsonRequest::create(doc, 1, "login", params); diff --git a/src/base/net/stratum/strategies/FailoverStrategy.cpp b/src/base/net/stratum/strategies/FailoverStrategy.cpp index 9545e9e1..4a35f3a5 100644 --- a/src/base/net/stratum/strategies/FailoverStrategy.cpp +++ b/src/base/net/stratum/strategies/FailoverStrategy.cpp @@ -113,7 +113,7 @@ void xmrig::FailoverStrategy::resume() } -void xmrig::FailoverStrategy::setAlgo(const xmrig::Algorithm &algo) +void xmrig::FailoverStrategy::setAlgo(const Algorithm &algo) { for (IClient *client : m_pools) { client->setAlgo(algo); @@ -163,6 +163,12 @@ void xmrig::FailoverStrategy::onClose(IClient *client, int failures) } +void xmrig::FailoverStrategy::onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) +{ + m_listener->onLogin(this, client, doc, params); +} + + void xmrig::FailoverStrategy::onJobReceived(IClient *client, const Job &job, const rapidjson::Value &) { if (m_active == client->id()) { diff --git a/src/base/net/stratum/strategies/FailoverStrategy.h b/src/base/net/stratum/strategies/FailoverStrategy.h index b1fe8bac..5336a634 100644 --- a/src/base/net/stratum/strategies/FailoverStrategy.h +++ b/src/base/net/stratum/strategies/FailoverStrategy.h @@ -51,9 +51,8 @@ public: void add(const Pool &pool); protected: - inline bool isActive() const override { return m_active >= 0; } - inline IClient *client() const override { return isActive() ? active() : m_pools[m_index]; } - inline void onLogin(IClient *, rapidjson::Document &, rapidjson::Value &) override {} + inline bool isActive() const override { return m_active >= 0; } + inline IClient *client() const override { return isActive() ? active() : m_pools[m_index]; } int64_t submit(const JobResult &result) override; void connect() override; @@ -64,6 +63,7 @@ protected: void onClose(IClient *client, int failures) override; void onJobReceived(IClient *client, const Job &job, const rapidjson::Value ¶ms) override; + void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; void onLoginSuccess(IClient *client) override; void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override; diff --git a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp index 6c6a6fc1..5f09d174 100644 --- a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp +++ b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp @@ -84,7 +84,7 @@ void xmrig::SinglePoolStrategy::resume() } -void xmrig::SinglePoolStrategy::setAlgo(const xmrig::Algorithm &algo) +void xmrig::SinglePoolStrategy::setAlgo(const Algorithm &algo) { m_client->setAlgo(algo); } @@ -119,6 +119,12 @@ void xmrig::SinglePoolStrategy::onJobReceived(IClient *client, const Job &job, c } +void xmrig::SinglePoolStrategy::onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) +{ + m_listener->onLogin(this, client, doc, params); +} + + void xmrig::SinglePoolStrategy::onLoginSuccess(IClient *client) { m_active = true; diff --git a/src/base/net/stratum/strategies/SinglePoolStrategy.h b/src/base/net/stratum/strategies/SinglePoolStrategy.h index af0bd7d6..04eef40e 100644 --- a/src/base/net/stratum/strategies/SinglePoolStrategy.h +++ b/src/base/net/stratum/strategies/SinglePoolStrategy.h @@ -45,9 +45,8 @@ public: ~SinglePoolStrategy() override; protected: - inline bool isActive() const override { return m_active; } - inline IClient *client() const override { return m_client; } - inline void onLogin(IClient *, rapidjson::Document &, rapidjson::Value &) override {} + inline bool isActive() const override { return m_active; } + inline IClient *client() const override { return m_client; } int64_t submit(const JobResult &result) override; void connect() override; @@ -58,6 +57,7 @@ protected: void onClose(IClient *client, int failures) override; void onJobReceived(IClient *client, const Job &job, const rapidjson::Value ¶ms) override; + void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; void onLoginSuccess(IClient *client) override; void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override; diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 4135e8ab..891a0f34 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -62,17 +62,46 @@ public: } + bool isEnabled(const Algorithm &algorithm) const + { + for (IBackend *backend : backends) { + if (backend->isEnabled(algorithm)) { + return true; + } + } + + return false; + } + + + inline void rebuild() + { + algorithms.clear(); + + for (int i = 0; i < Algorithm::MAX; ++i) { + const Algorithm algo(static_cast(i)); + + if (isEnabled(algo)) { + algorithms.push_back(algo); + } + } + } + + inline void handleJobChange() { active = true; - if (enabled) { - Nonce::pause(false);; - } for (IBackend *backend : backends) { backend->setJob(job); } + if (enabled) { + Nonce::pause(false);; + } + + Nonce::reset(job.index()); + if (ticks == 0) { ticks++; timer->start(500, 500); @@ -80,6 +109,7 @@ public: } + Algorithms algorithms; bool active = false; bool enabled = true; Controller *controller; @@ -104,6 +134,8 @@ xmrig::Miner::Miner(Controller *controller) d_ptr->timer = new Timer(this); d_ptr->backends.push_back(new CpuBackend(controller)); + + d_ptr->rebuild(); } @@ -119,6 +151,12 @@ bool xmrig::Miner::isEnabled() const } +const xmrig::Algorithms &xmrig::Miner::algorithms() const +{ + return d_ptr->algorithms; +} + + const std::vector &xmrig::Miner::backends() const { return d_ptr->backends; @@ -202,8 +240,6 @@ void xmrig::Miner::setJob(const Job &job, bool donate) d_ptr->job = job; d_ptr->job.setIndex(index); - Nonce::reset(index); - uv_rwlock_wrunlock(&d_ptr->rwlock); d_ptr->handleJobChange(); @@ -222,6 +258,8 @@ void xmrig::Miner::stop() void xmrig::Miner::onConfigChanged(Config *config, Config *previousConfig) { + d_ptr->rebuild(); + if (config->pools() != previousConfig->pools() && config->pools().active() > 0) { return; } diff --git a/src/core/Miner.h b/src/core/Miner.h index 23497eae..dd195e29 100644 --- a/src/core/Miner.h +++ b/src/core/Miner.h @@ -31,6 +31,7 @@ #include "base/kernel/interfaces/IBaseListener.h" #include "base/kernel/interfaces/ITimerListener.h" +#include "crypto/common/Algorithm.h" namespace xmrig { @@ -49,6 +50,7 @@ public: ~Miner() override; bool isEnabled() const; + const Algorithms &algorithms() const; const std::vector &backends() const; Job job() const; void pause(); diff --git a/src/crypto/common/Algorithm.h b/src/crypto/common/Algorithm.h index a6ec22be..a1d8ded2 100644 --- a/src/crypto/common/Algorithm.h +++ b/src/crypto/common/Algorithm.h @@ -115,7 +115,7 @@ private: }; -typedef std::vector Algorithms; +typedef std::vector Algorithms; } /* namespace xmrig */ diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 6622a080..a1c1ec8d 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -154,6 +154,21 @@ void xmrig::Network::onJobResult(const JobResult &result) } +void xmrig::Network::onLogin(IStrategy *, IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Value algo(kArrayType); + + for (const auto &a : m_controller->miner()->algorithms()) { + algo.PushBack(StringRef(a.shortName()), allocator); + } + + params.AddMember("algo", algo, allocator); +} + + void xmrig::Network::onPause(IStrategy *strategy) { if (m_donate && m_donate == strategy) { diff --git a/src/net/Network.h b/src/net/Network.h index eaec9472..bf61a9b6 100644 --- a/src/net/Network.h +++ b/src/net/Network.h @@ -63,6 +63,7 @@ protected: void onConfigChanged(Config *config, Config *previousConfig) override; void onJob(IStrategy *strategy, IClient *client, const Job &job) override; void onJobResult(const JobResult &result) override; + void onLogin(IStrategy *strategy, IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; void onPause(IStrategy *strategy) override; void onRequest(IApiRequest &request) override; void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) override; diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index 2d0a5b43..4393cd46 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -23,7 +23,9 @@ */ +#include #include +#include #include "base/kernel/Platform.h" @@ -35,6 +37,7 @@ #include "base/tools/Timer.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "core/Miner.h" #include "crypto/common/keccak.h" #include "net/Network.h" #include "net/strategies/DonateStrategy.h" @@ -57,10 +60,10 @@ static const char *kDonateHostTls = "donate.ssl.xmrig.com"; xmrig::DonateStrategy::DonateStrategy(Controller *controller, IStrategyListener *listener) : m_tls(false), m_userId(), - m_proxy(nullptr), 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), @@ -78,10 +81,6 @@ xmrig::DonateStrategy::DonateStrategy(Controller *controller, IStrategyListener # endif m_pools.push_back(Pool(kDonateHost, 3333, m_userId, nullptr, 0, true)); -// for (Pool &pool : m_pools) { -// pool.adjust(Algorithm()); // FIXME -// } - if (m_pools.size() > 1) { m_strategy = new FailoverStrategy(m_pools, 1, 2, this, true); } @@ -129,6 +128,8 @@ void xmrig::DonateStrategy::connect() void xmrig::DonateStrategy::setAlgo(const xmrig::Algorithm &algo) { + m_algorithm = algo; + m_strategy->setAlgo(algo); } @@ -185,13 +186,14 @@ void xmrig::DonateStrategy::onClose(IClient *, int failures) void xmrig::DonateStrategy::onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) { + using namespace rapidjson; auto &allocator = doc.GetAllocator(); # ifdef XMRIG_FEATURE_TLS if (m_tls) { char buf[40] = { 0 }; snprintf(buf, sizeof(buf), "stratum+ssl://%s", m_pools[0].url().data()); - params.AddMember("url", rapidjson::Value(buf, allocator), allocator); + params.AddMember("url", Value(buf, allocator), allocator); } else { params.AddMember("url", m_pools[1].url().toJSON(), allocator); @@ -199,6 +201,14 @@ void xmrig::DonateStrategy::onLogin(IClient *, rapidjson::Document &doc, rapidjs # else params.AddMember("url", m_pools[0].url().toJSON(), allocator); # endif + + setAlgorithms(doc, params); +} + + +void xmrig::DonateStrategy::onLogin(IStrategy *, IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) +{ + setAlgorithms(doc, params); } @@ -250,6 +260,27 @@ void xmrig::DonateStrategy::idle(double min, double max) } +void xmrig::DonateStrategy::setAlgorithms(rapidjson::Document &doc, rapidjson::Value ¶ms) +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Algorithms algorithms = m_controller->miner()->algorithms(); + const size_t index = static_cast(std::distance(algorithms.begin(), std::find(algorithms.begin(), algorithms.end(), m_algorithm))); + if (index > 0 && index < algorithms.size()) { + std::swap(algorithms[0], algorithms[index]); + } + + Value algo(kArrayType); + + for (const auto &a : algorithms) { + algo.PushBack(StringRef(a.shortName()), allocator); + } + + params.AddMember("algo", algo, allocator); +} + + void xmrig::DonateStrategy::setJob(IClient *client, const Job &job) { if (isActive()) { diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h index c9fc312d..5350aefa 100644 --- a/src/net/strategies/DonateStrategy.h +++ b/src/net/strategies/DonateStrategy.h @@ -70,6 +70,7 @@ protected: void onClose(IClient *client, int failures) override; 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 onTimer(const Timer *timer) override; @@ -87,16 +88,18 @@ private: Client *createProxy(); void idle(double min, double max); + void setAlgorithms(rapidjson::Document &doc, rapidjson::Value ¶ms); void setJob(IClient *client, const Job &job); void setResult(IClient *client, const SubmitResult &result, const char *error); void setState(State state); + Algorithm m_algorithm; bool m_tls; char m_userId[65]; - IClient *m_proxy; const uint64_t m_donateTime; const uint64_t m_idleTime; Controller *m_controller; + IClient *m_proxy; IStrategy *m_strategy; IStrategyListener *m_listener; State m_state; From 88edde804fd750848f138a1d864fe1f090786332 Mon Sep 17 00:00:00 2001 From: XMRig Date: Thu, 18 Jul 2019 23:48:16 +0700 Subject: [PATCH 43/65] Fixed duplicated shares after donation round. --- src/core/Miner.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 891a0f34..1f7f77e9 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -88,7 +88,7 @@ public: } - inline void handleJobChange() + inline void handleJobChange(bool reset) { active = true; @@ -96,12 +96,17 @@ public: backend->setJob(job); } + if (reset) { + Nonce::reset(job.index()); + } + else { + Nonce::touch(); + } + if (enabled) { Nonce::pause(false);; } - Nonce::reset(job.index()); - if (ticks == 0) { ticks++; timer->start(500, 500); @@ -116,6 +121,7 @@ public: double maxHashrate = 0.0; Job job; std::vector backends; + String userJobId; Timer *timer = nullptr; uint64_t ticks = 0; uv_rwlock_t rwlock; @@ -236,13 +242,18 @@ void xmrig::Miner::setJob(const Job &job, bool donate) uv_rwlock_wrlock(&d_ptr->rwlock); const uint8_t index = donate ? 1 : 0; + const bool reset = !(d_ptr->job.index() == 1 && index == 0 && d_ptr->userJobId == job.id()); d_ptr->job = job; d_ptr->job.setIndex(index); + if (index == 0) { + d_ptr->userJobId = job.id(); + } + uv_rwlock_wrunlock(&d_ptr->rwlock); - d_ptr->handleJobChange(); + d_ptr->handleJobChange(reset); } From 691b2fabbf2817f2a1e8c5b69ce22fe9bd13042d Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 19 Jul 2019 00:39:27 +0700 Subject: [PATCH 44/65] Restored algorithm verification. --- src/base/kernel/interfaces/IClientListener.h | 2 + .../kernel/interfaces/IStrategyListener.h | 2 + src/base/net/stratum/Client.cpp | 39 ++++++++----------- src/base/net/stratum/Client.h | 2 +- .../stratum/strategies/FailoverStrategy.cpp | 6 +++ .../net/stratum/strategies/FailoverStrategy.h | 1 + .../stratum/strategies/SinglePoolStrategy.cpp | 6 +++ .../stratum/strategies/SinglePoolStrategy.h | 1 + src/core/Miner.cpp | 6 +++ src/core/Miner.h | 1 + src/net/Network.cpp | 10 +++++ src/net/Network.h | 1 + src/net/strategies/DonateStrategy.h | 2 + 13 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/base/kernel/interfaces/IClientListener.h b/src/base/kernel/interfaces/IClientListener.h index de4dd81d..3583be5a 100644 --- a/src/base/kernel/interfaces/IClientListener.h +++ b/src/base/kernel/interfaces/IClientListener.h @@ -35,6 +35,7 @@ namespace xmrig { +class Algorithm; class IClient; class Job; class SubmitResult; @@ -50,6 +51,7 @@ public: virtual void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) = 0; virtual void onLoginSuccess(IClient *client) = 0; virtual void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) = 0; + virtual void onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok) = 0; }; diff --git a/src/base/kernel/interfaces/IStrategyListener.h b/src/base/kernel/interfaces/IStrategyListener.h index 01e668d4..8b88b506 100644 --- a/src/base/kernel/interfaces/IStrategyListener.h +++ b/src/base/kernel/interfaces/IStrategyListener.h @@ -32,6 +32,7 @@ namespace xmrig { +class Algorithm; class IClient; class IStrategy; class Job; @@ -48,6 +49,7 @@ public: virtual void onLogin(IStrategy *strategy, IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) = 0; virtual void onPause(IStrategy *strategy) = 0; virtual void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) = 0; + virtual void onVerifyAlgorithm(IStrategy *strategy, const IClient *client, const Algorithm &algorithm, bool *ok) = 0; }; diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 0be86eca..618e132c 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -330,14 +330,15 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } - if (params.HasMember("algo")) { - job.setAlgorithm(params["algo"].GetString()); + const char *algo = Json::getString(params, "algo"); + if (algo) { + job.setAlgorithm(algo); } job.setSeedHash(Json::getString(params, "seed_hash")); job.setHeight(Json::getUint64(params, "height")); - if (!verifyAlgorithm(job.algorithm())) { + if (!verifyAlgorithm(job.algorithm(), algo)) { *code = 6; close(); @@ -415,30 +416,24 @@ bool xmrig::Client::send(BIO *bio) } -bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm) const +bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm, const char *algo) const { -//# ifdef XMRIG_PROXY_PROJECT -// if (m_pool.algorithm().variant() == VARIANT_AUTO || m_id == -1) { -// return true; -// } -//# endif + if (!algorithm.isValid()) { + if (!isQuiet()) { + LOG_ERR("[%s] Unknown/unsupported algorithm \"%s\" detected, reconnect", url(), algo); + } -// if (m_pool.algorithm() == algorithm) { // FIXME -// return true; -// } + return false; + } -// if (isQuiet()) { -// return false; -// } + bool ok = true; + m_listener->onVerifyAlgorithm(this, algorithm, &ok); -// if (algorithm.isValid()) { -// LOG_ERR("Incompatible algorithm \"%s\" detected, reconnect", algorithm.name()); -// } -// else { -// LOG_ERR("Unknown/unsupported algorithm detected, reconnect"); -// } + if (!ok && !isQuiet()) { + LOG_ERR("[%s] Incompatible/disabled algorithm \"%s\" detected, reconnect", url(), algorithm.shortName()); + } - return true; + return ok; } diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h index 841e0e0b..46030aba 100644 --- a/src/base/net/stratum/Client.h +++ b/src/base/net/stratum/Client.h @@ -92,7 +92,7 @@ private: bool parseJob(const rapidjson::Value ¶ms, int *code); bool parseLogin(const rapidjson::Value &result, int *code); bool send(BIO *bio); - bool verifyAlgorithm(const Algorithm &algorithm) const; + bool verifyAlgorithm(const Algorithm &algorithm, const char *algo) const; int resolve(const String &host); int64_t send(const rapidjson::Document &doc); int64_t send(size_t size); diff --git a/src/base/net/stratum/strategies/FailoverStrategy.cpp b/src/base/net/stratum/strategies/FailoverStrategy.cpp index 4a35f3a5..48be2ba3 100644 --- a/src/base/net/stratum/strategies/FailoverStrategy.cpp +++ b/src/base/net/stratum/strategies/FailoverStrategy.cpp @@ -202,3 +202,9 @@ void xmrig::FailoverStrategy::onResultAccepted(IClient *client, const SubmitResu { m_listener->onResultAccepted(this, client, result, error); } + + +void xmrig::FailoverStrategy::onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok) +{ + m_listener->onVerifyAlgorithm(this, client, algorithm, ok); +} diff --git a/src/base/net/stratum/strategies/FailoverStrategy.h b/src/base/net/stratum/strategies/FailoverStrategy.h index 5336a634..283d4916 100644 --- a/src/base/net/stratum/strategies/FailoverStrategy.h +++ b/src/base/net/stratum/strategies/FailoverStrategy.h @@ -66,6 +66,7 @@ protected: void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; void onLoginSuccess(IClient *client) override; void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override; + void onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok) override; private: inline IClient *active() const { return m_pools[static_cast(m_active)]; } diff --git a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp index 5f09d174..c923e1c2 100644 --- a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp +++ b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp @@ -136,3 +136,9 @@ void xmrig::SinglePoolStrategy::onResultAccepted(IClient *client, const SubmitRe { m_listener->onResultAccepted(this, client, result, error); } + + +void xmrig::SinglePoolStrategy::onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok) +{ + m_listener->onVerifyAlgorithm(this, client, algorithm, ok); +} diff --git a/src/base/net/stratum/strategies/SinglePoolStrategy.h b/src/base/net/stratum/strategies/SinglePoolStrategy.h index 04eef40e..ea808193 100644 --- a/src/base/net/stratum/strategies/SinglePoolStrategy.h +++ b/src/base/net/stratum/strategies/SinglePoolStrategy.h @@ -60,6 +60,7 @@ protected: void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; void onLoginSuccess(IClient *client) override; void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override; + void onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok) override; private: bool m_active; diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 1f7f77e9..b64d6b95 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -157,6 +157,12 @@ bool xmrig::Miner::isEnabled() const } +bool xmrig::Miner::isEnabled(const Algorithm &algorithm) const +{ + return std::find(d_ptr->algorithms.begin(), d_ptr->algorithms.end(), algorithm) != d_ptr->algorithms.end(); +} + + const xmrig::Algorithms &xmrig::Miner::algorithms() const { return d_ptr->algorithms; diff --git a/src/core/Miner.h b/src/core/Miner.h index dd195e29..333f9250 100644 --- a/src/core/Miner.h +++ b/src/core/Miner.h @@ -50,6 +50,7 @@ public: ~Miner() override; bool isEnabled() const; + bool isEnabled(const Algorithm &algorithm) const; const Algorithms &algorithms() const; const std::vector &backends() const; Job job() const; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index a1c1ec8d..eaff6748 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -213,6 +213,16 @@ void xmrig::Network::onResultAccepted(IStrategy *, IClient *, const SubmitResult } +void xmrig::Network::onVerifyAlgorithm(IStrategy *, const IClient *, const Algorithm &algorithm, bool *ok) +{ + if (!m_controller->miner()->isEnabled(algorithm)) { + *ok = false; + + return; + } +} + + void xmrig::Network::setJob(IClient *client, const Job &job, bool donate) { if (job.height()) { diff --git a/src/net/Network.h b/src/net/Network.h index bf61a9b6..68967713 100644 --- a/src/net/Network.h +++ b/src/net/Network.h @@ -67,6 +67,7 @@ protected: void onPause(IStrategy *strategy) override; void onRequest(IApiRequest &request) override; void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) override; + void onVerifyAlgorithm(IStrategy *strategy, const IClient *client, const Algorithm &algorithm, bool *ok) override; private: constexpr static int kTickInterval = 1 * 1000; diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h index 5350aefa..134127bf 100644 --- a/src/net/strategies/DonateStrategy.h +++ b/src/net/strategies/DonateStrategy.h @@ -57,6 +57,8 @@ 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; From d9164c0b7bc30dd8d6bf3dbfdd442f9fde87c13d Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 19 Jul 2019 02:24:37 +0700 Subject: [PATCH 45/65] Restored "GET /1/summary" endpoint. --- src/api/Api.cpp | 10 +-- src/api/interfaces/IApiListener.h | 2 + src/api/interfaces/IApiRequest.h | 12 ++- src/api/requests/ApiRequest.cpp | 3 +- src/api/requests/ApiRequest.h | 7 +- src/api/requests/HttpApiRequest.cpp | 11 +++ src/api/v1/ApiRouter.cpp | 70 +----------------- src/api/v1/ApiRouter.h | 4 +- src/backend/common/Hashrate.cpp | 15 +++- src/backend/common/Hashrate.h | 4 + src/core/Miner.cpp | 111 ++++++++++++++++++++++++++++ src/core/Miner.h | 7 +- src/net/Network.cpp | 42 ++++++----- src/net/Network.h | 9 ++- 14 files changed, 199 insertions(+), 108 deletions(-) diff --git a/src/api/Api.cpp b/src/api/Api.cpp index a1aeb4c2..11fc2a69 100644 --- a/src/api/Api.cpp +++ b/src/api/Api.cpp @@ -120,7 +120,7 @@ void xmrig::Api::exec(IApiRequest &request) { using namespace rapidjson; - if (request.method() == IApiRequest::METHOD_GET && (request.url() == "/1/summary" || request.url() == "/api.json")) { + if (request.type() == IApiRequest::REQ_SUMMARY) { auto &allocator = request.doc().GetAllocator(); request.accept(); @@ -145,14 +145,6 @@ void xmrig::Api::exec(IApiRequest &request) features.PushBack("tls", allocator); # endif request.reply().AddMember("features", features, allocator); - - Value algorithms(kArrayType); - - for (int i = 0; i < Algorithm::MAX; ++i) { - algorithms.PushBack(StringRef(Algorithm(static_cast(i)).shortName()), allocator); - } - - request.reply().AddMember("algorithms", algorithms, allocator); } for (IApiListener *listener : m_listeners) { diff --git a/src/api/interfaces/IApiListener.h b/src/api/interfaces/IApiListener.h index 7897e375..bbf153a6 100644 --- a/src/api/interfaces/IApiListener.h +++ b/src/api/interfaces/IApiListener.h @@ -35,7 +35,9 @@ class IApiListener public: virtual ~IApiListener() = default; +# ifdef XMRIG_FEATURE_API virtual void onRequest(IApiRequest &request) = 0; +# endif }; diff --git a/src/api/interfaces/IApiRequest.h b/src/api/interfaces/IApiRequest.h index 2c2f5634..8e65a921 100644 --- a/src/api/interfaces/IApiRequest.h +++ b/src/api/interfaces/IApiRequest.h @@ -4,7 +4,9 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2018 XMRig + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,6 +52,12 @@ public: }; + enum RequestType { + REQ_UNKNOWN, + REQ_SUMMARY + }; + + virtual ~IApiRequest() = default; virtual bool isDone() const = 0; @@ -57,9 +65,11 @@ public: virtual bool isRestricted() const = 0; virtual const rapidjson::Value &json() const = 0; virtual const String &url() const = 0; + virtual int version() const = 0; virtual Method method() const = 0; virtual rapidjson::Document &doc() = 0; virtual rapidjson::Value &reply() = 0; + virtual RequestType type() const = 0; virtual Source source() const = 0; virtual void accept() = 0; virtual void done(int status) = 0; diff --git a/src/api/requests/ApiRequest.cpp b/src/api/requests/ApiRequest.cpp index c092a334..3812e419 100644 --- a/src/api/requests/ApiRequest.cpp +++ b/src/api/requests/ApiRequest.cpp @@ -28,8 +28,7 @@ xmrig::ApiRequest::ApiRequest(Source source, bool restricted) : m_restricted(restricted), - m_source(source), - m_state(STATE_NEW) + m_source(source) { } diff --git a/src/api/requests/ApiRequest.h b/src/api/requests/ApiRequest.h index 1754aa9c..05716e29 100644 --- a/src/api/requests/ApiRequest.h +++ b/src/api/requests/ApiRequest.h @@ -43,10 +43,15 @@ protected: inline bool isDone() const override { return m_state == STATE_DONE; } inline bool isNew() const override { return m_state == STATE_NEW; } inline bool isRestricted() const override { return m_restricted; } + inline int version() const override { return m_version; } + inline RequestType type() const override { return m_type; } inline Source source() const override { return m_source; } inline void accept() override { m_state = STATE_ACCEPTED; } inline void done(int) override { m_state = STATE_DONE; } + int m_version = 1; + RequestType m_type = REQ_UNKNOWN; + private: enum State { STATE_NEW, @@ -56,7 +61,7 @@ private: bool m_restricted; Source m_source; - State m_state; + State m_state = STATE_NEW; }; diff --git a/src/api/requests/HttpApiRequest.cpp b/src/api/requests/HttpApiRequest.cpp index e4f2de1e..b4dc1810 100644 --- a/src/api/requests/HttpApiRequest.cpp +++ b/src/api/requests/HttpApiRequest.cpp @@ -35,6 +35,17 @@ xmrig::HttpApiRequest::HttpApiRequest(const HttpData &req, bool restricted) : m_res(req.id()), m_url(req.url.c_str()) { + if (method() == METHOD_GET) { + if (url() == "/1/summary" || url() == "/2/summary" || url() == "/api.json") { + m_type = REQ_SUMMARY; + } + } + + if (url().size() > 4) { + if (memcmp(url().data(), "/2/", 3) == 0) { + m_version = 2; + } + } } diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp index 2a5bd3d0..0e1080a1 100644 --- a/src/api/v1/ApiRouter.cpp +++ b/src/api/v1/ApiRouter.cpp @@ -38,18 +38,6 @@ #include "version.h" -static inline rapidjson::Value normalize(double d) -{ - using namespace rapidjson; - - if (!std::isnormal(d)) { - return Value(kNullType); - } - - return Value(floor(d * 100.0) / 100.0); -} - - xmrig::ApiRouter::ApiRouter(Base *base) : m_base(base) { @@ -64,12 +52,7 @@ xmrig::ApiRouter::~ApiRouter() void xmrig::ApiRouter::onRequest(IApiRequest &request) { if (request.method() == IApiRequest::METHOD_GET) { - if (request.url() == "/1/summary" || request.url() == "/api.json") { - request.accept(); - getMiner(request.reply(), request.doc()); -// getHashrate(request.reply(), request.doc()); - } - else if (request.url() == "/1/threads") { + if (request.url() == "/1/threads") { request.accept(); getThreads(request.reply(), request.doc()); } @@ -96,57 +79,6 @@ void xmrig::ApiRouter::onRequest(IApiRequest &request) } -//void xmrig::ApiRouter::getHashrate(rapidjson::Value &reply, rapidjson::Document &doc) const -//{ -// using namespace rapidjson; -// auto &allocator = doc.GetAllocator(); - -// Value hashrate(kObjectType); -// Value total(kArrayType); -// Value threads(kArrayType); - -// const Hashrate *hr = WorkersLegacy::hashrate(); - -// total.PushBack(normalize(hr->calc(Hashrate::ShortInterval)), allocator); -// total.PushBack(normalize(hr->calc(Hashrate::MediumInterval)), allocator); -// total.PushBack(normalize(hr->calc(Hashrate::LargeInterval)), allocator); - -// for (size_t i = 0; i < WorkersLegacy::threads(); i++) { -// Value thread(kArrayType); -// thread.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); -// thread.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); -// thread.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); - -// threads.PushBack(thread, allocator); -// } - -// hashrate.AddMember("total", total, allocator); -// hashrate.AddMember("highest", normalize(hr->highest()), allocator); -// hashrate.AddMember("threads", threads, allocator); -// reply.AddMember("hashrate", hashrate, allocator); -//} - - -void xmrig::ApiRouter::getMiner(rapidjson::Value &reply, rapidjson::Document &doc) const -{ - using namespace rapidjson; - auto &allocator = doc.GetAllocator(); - - Value cpu(kObjectType); - cpu.AddMember("brand", StringRef(Cpu::info()->brand()), allocator); - cpu.AddMember("aes", Cpu::info()->hasAES(), allocator); - cpu.AddMember("x64", Cpu::info()->isX64(), allocator); - cpu.AddMember("sockets", Cpu::info()->sockets(), allocator); - - reply.AddMember("version", APP_VERSION, allocator); - reply.AddMember("kind", APP_KIND, allocator); - reply.AddMember("ua", StringRef(Platform::userAgent()), allocator); - reply.AddMember("cpu", cpu, allocator); - reply.AddMember("hugepages", false, allocator); // FIXME hugepages - reply.AddMember("donate_level", m_base->config()->pools().donateLevel(), allocator); -} - - void xmrig::ApiRouter::getThreads(rapidjson::Value &reply, rapidjson::Document &doc) const { // using namespace rapidjson; diff --git a/src/api/v1/ApiRouter.h b/src/api/v1/ApiRouter.h index e2b9bd25..ec468d86 100644 --- a/src/api/v1/ApiRouter.h +++ b/src/api/v1/ApiRouter.h @@ -39,7 +39,7 @@ namespace xmrig { class Base; -class ApiRouter : public xmrig::IApiListener +class ApiRouter : public IApiListener { public: ApiRouter(Base *base); @@ -49,8 +49,6 @@ protected: void onRequest(IApiRequest &request) override; private: -// void getHashrate(rapidjson::Value &reply, rapidjson::Document &doc) const; - void getMiner(rapidjson::Value &reply, rapidjson::Document &doc) const; void getThreads(rapidjson::Value &reply, rapidjson::Document &doc) const; Base *m_base; diff --git a/src/backend/common/Hashrate.cpp b/src/backend/common/Hashrate.cpp index 6ffd45b7..a9c63733 100644 --- a/src/backend/common/Hashrate.cpp +++ b/src/backend/common/Hashrate.cpp @@ -29,9 +29,10 @@ #include +#include "backend/common/Hashrate.h" #include "base/tools/Chrono.h" #include "base/tools/Handle.h" -#include "backend/common/Hashrate.h" +#include "rapidjson/document.h" inline static const char *format(double h, char *buf, size_t size) @@ -162,3 +163,15 @@ const char *xmrig::Hashrate::format(double h, char *buf, size_t size) { return ::format(h, buf, size); } + + +rapidjson::Value xmrig::Hashrate::normalize(double d) +{ + using namespace rapidjson; + + if (!std::isnormal(d)) { + return Value(kNullType); + } + + return Value(floor(d * 100.0) / 100.0); +} diff --git a/src/backend/common/Hashrate.h b/src/backend/common/Hashrate.h index 2187c0be..0674c6ab 100644 --- a/src/backend/common/Hashrate.h +++ b/src/backend/common/Hashrate.h @@ -30,6 +30,9 @@ #include +#include "rapidjson/fwd.h" + + namespace xmrig { @@ -53,6 +56,7 @@ public: inline size_t threads() const { return m_threads; } static const char *format(double h, char *buf, size_t size); + static rapidjson::Value normalize(double d); private: constexpr static size_t kBucketSize = 2 << 11; diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index b64d6b95..7114baf9 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -28,14 +28,24 @@ #include "backend/common/Hashrate.h" +#include "backend/cpu/Cpu.h" #include "backend/cpu/CpuBackend.h" #include "base/io/log/Log.h" +#include "base/kernel/Platform.h" #include "base/net/stratum/Job.h" #include "base/tools/Timer.h" #include "core/config/Config.h" #include "core/Controller.h" #include "core/Miner.h" #include "crypto/common/Nonce.h" +#include "rapidjson/document.h" +#include "version.h" + + +#ifdef XMRIG_FEATURE_API +# include "api/Api.h" +# include "api/interfaces/IApiRequest.h" +#endif namespace xmrig { @@ -114,6 +124,90 @@ public: } +# ifdef XMRIG_FEATURE_API + void getMiner(rapidjson::Value &reply, rapidjson::Document &doc, int version) const + { + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Value cpu(kObjectType); + cpu.AddMember("brand", StringRef(Cpu::info()->brand()), allocator); + cpu.AddMember("aes", Cpu::info()->hasAES(), allocator); + cpu.AddMember("x64", Cpu::info()->isX64(), allocator); + cpu.AddMember("sockets", Cpu::info()->sockets(), allocator); + + reply.AddMember("version", APP_VERSION, allocator); + reply.AddMember("kind", APP_KIND, allocator); + reply.AddMember("ua", StringRef(Platform::userAgent()), allocator); + reply.AddMember("cpu", cpu, allocator); + + if (version == 1) { + reply.AddMember("hugepages", false, allocator); + } + + reply.AddMember("donate_level", controller->config()->pools().donateLevel(), allocator); + + Value algo(kArrayType); + + for (const Algorithm &a : algorithms) { + algo.PushBack(StringRef(a.shortName()), allocator); + } + + reply.AddMember("algorithms", algo, allocator); + } + + + void getHashrate(rapidjson::Value &reply, rapidjson::Document &doc, int version) const + { + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Value hashrate(kObjectType); + Value total(kArrayType); + Value threads(kArrayType); + + double t[3] = { 0.0 }; + + for (IBackend *backend : backends) { + const Hashrate *hr = backend->hashrate(); + if (!hr) { + continue; + } + + t[0] += hr->calc(Hashrate::ShortInterval); + t[1] += hr->calc(Hashrate::MediumInterval); + t[2] += hr->calc(Hashrate::LargeInterval); + + if (version > 1) { + continue; + } + + for (size_t i = 0; i < hr->threads(); i++) { + Value thread(kArrayType); + thread.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); + thread.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); + thread.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); + + threads.PushBack(thread, allocator); + } + } + + total.PushBack(Hashrate::normalize(t[0]), allocator); + total.PushBack(Hashrate::normalize(t[1]), allocator); + total.PushBack(Hashrate::normalize(t[2]), allocator); + + hashrate.AddMember("total", total, allocator); + hashrate.AddMember("highest", Hashrate::normalize(maxHashrate), allocator); + + if (version == 1) { + hashrate.AddMember("threads", threads, allocator); + } + + reply.AddMember("hashrate", hashrate, allocator); + } +# endif + + Algorithms algorithms; bool active = false; bool enabled = true; @@ -137,6 +231,10 @@ xmrig::Miner::Miner(Controller *controller) { controller->addListener(this); +# ifdef XMRIG_FEATURE_API + controller->api()->addListener(this); +# endif + d_ptr->timer = new Timer(this); d_ptr->backends.push_back(new CpuBackend(controller)); @@ -309,3 +407,16 @@ void xmrig::Miner::onTimer(const Timer *) d_ptr->ticks++; } + + +#ifdef XMRIG_FEATURE_API +void xmrig::Miner::onRequest(IApiRequest &request) +{ + if (request.type() == IApiRequest::REQ_SUMMARY) { + request.accept(); + + d_ptr->getMiner(request.reply(), request.doc(), request.version()); + d_ptr->getHashrate(request.reply(), request.doc(), request.version()); + } +} +#endif diff --git a/src/core/Miner.h b/src/core/Miner.h index 333f9250..035c0205 100644 --- a/src/core/Miner.h +++ b/src/core/Miner.h @@ -29,6 +29,7 @@ #include +#include "api/interfaces/IApiListener.h" #include "base/kernel/interfaces/IBaseListener.h" #include "base/kernel/interfaces/ITimerListener.h" #include "crypto/common/Algorithm.h" @@ -43,7 +44,7 @@ class MinerPrivate; class IBackend; -class Miner : public ITimerListener, public IBaseListener +class Miner : public ITimerListener, public IBaseListener, public IApiListener { public: Miner(Controller *controller); @@ -64,6 +65,10 @@ protected: void onConfigChanged(Config *config, Config *previousConfig) override; void onTimer(const Timer *timer) override; +# ifdef XMRIG_FEATURE_API + void onRequest(IApiRequest &request) override; +# endif + private: MinerPrivate *d_ptr; }; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index eaff6748..5ee00388 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -185,19 +185,6 @@ void xmrig::Network::onPause(IStrategy *strategy) } -void xmrig::Network::onRequest(IApiRequest &request) -{ -# ifdef XMRIG_FEATURE_API - if (request.method() == IApiRequest::METHOD_GET && (request.url() == "/1/summary" || request.url() == "/api.json")) { - request.accept(); - - getResults(request.reply(), request.doc()); - getConnection(request.reply(), request.doc()); - } -# endif -} - - void xmrig::Network::onResultAccepted(IStrategy *, IClient *, const SubmitResult &result, const char *error) { m_state.add(result, error); @@ -223,6 +210,19 @@ void xmrig::Network::onVerifyAlgorithm(IStrategy *, const IClient *, const Algor } +#ifdef XMRIG_FEATURE_API +void xmrig::Network::onRequest(IApiRequest &request) +{ + if (request.type() == IApiRequest::REQ_SUMMARY) { + request.accept(); + + getResults(request.reply(), request.doc(), request.version()); + getConnection(request.reply(), request.doc(), request.version()); + } +} +#endif + + void xmrig::Network::setJob(IClient *client, const Job &job, bool donate) { if (job.height()) { @@ -256,7 +256,7 @@ void xmrig::Network::tick() #ifdef XMRIG_FEATURE_API -void xmrig::Network::getConnection(rapidjson::Value &reply, rapidjson::Document &doc) const +void xmrig::Network::getConnection(rapidjson::Value &reply, rapidjson::Document &doc, int version) const { using namespace rapidjson; auto &allocator = doc.GetAllocator(); @@ -271,13 +271,16 @@ void xmrig::Network::getConnection(rapidjson::Value &reply, rapidjson::Document connection.AddMember("failures", m_state.failures, allocator); connection.AddMember("tls", m_state.tls().toJSON(), allocator); connection.AddMember("tls-fingerprint", m_state.fingerprint().toJSON(), allocator); - connection.AddMember("error_log", Value(kArrayType), allocator); + + if (version == 1) { + connection.AddMember("error_log", Value(kArrayType), allocator); + } reply.AddMember("connection", connection, allocator); } -void xmrig::Network::getResults(rapidjson::Value &reply, rapidjson::Document &doc) const +void xmrig::Network::getResults(rapidjson::Value &reply, rapidjson::Document &doc, int version) const { using namespace rapidjson; auto &allocator = doc.GetAllocator(); @@ -295,8 +298,11 @@ void xmrig::Network::getResults(rapidjson::Value &reply, rapidjson::Document &do best.PushBack(m_state.topDiff[i], allocator); } - results.AddMember("best", best, allocator); - results.AddMember("error_log", Value(kArrayType), allocator); + results.AddMember("best", best, allocator); + + if (version == 1) { + results.AddMember("error_log", Value(kArrayType), allocator); + } reply.AddMember("results", results, allocator); } diff --git a/src/net/Network.h b/src/net/Network.h index 68967713..ddf6d6f3 100644 --- a/src/net/Network.h +++ b/src/net/Network.h @@ -65,10 +65,13 @@ protected: void onJobResult(const JobResult &result) override; void onLogin(IStrategy *strategy, IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; void onPause(IStrategy *strategy) override; - void onRequest(IApiRequest &request) override; void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) override; void onVerifyAlgorithm(IStrategy *strategy, const IClient *client, const Algorithm &algorithm, bool *ok) override; +# ifdef XMRIG_FEATURE_API + void onRequest(IApiRequest &request) override; +# endif + private: constexpr static int kTickInterval = 1 * 1000; @@ -76,8 +79,8 @@ private: void tick(); # ifdef XMRIG_FEATURE_API - void getConnection(rapidjson::Value &reply, rapidjson::Document &doc) const; - void getResults(rapidjson::Value &reply, rapidjson::Document &doc) const; + void getConnection(rapidjson::Value &reply, rapidjson::Document &doc, int version) const; + void getResults(rapidjson::Value &reply, rapidjson::Document &doc, int version) const; # endif Controller *m_controller; From fa2c9df075c292e23efa35603dc17eae2ca82587 Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 19 Jul 2019 02:39:00 +0700 Subject: [PATCH 46/65] Implemented "enabled" field for CPU backend; --- src/backend/common/interfaces/IBackend.h | 1 + src/backend/cpu/CpuBackend.cpp | 12 ++++++++++++ src/backend/cpu/CpuBackend.h | 1 + 3 files changed, 14 insertions(+) diff --git a/src/backend/common/interfaces/IBackend.h b/src/backend/common/interfaces/IBackend.h index 6fe917cb..ac97759b 100644 --- a/src/backend/common/interfaces/IBackend.h +++ b/src/backend/common/interfaces/IBackend.h @@ -44,6 +44,7 @@ class IBackend public: virtual ~IBackend() = default; + virtual bool isEnabled() const = 0; virtual bool isEnabled(const Algorithm &algorithm) const = 0; virtual const Hashrate *hashrate() const = 0; virtual const String &profileName() const = 0; diff --git a/src/backend/cpu/CpuBackend.cpp b/src/backend/cpu/CpuBackend.cpp index 15a0c359..8ab312f7 100644 --- a/src/backend/cpu/CpuBackend.cpp +++ b/src/backend/cpu/CpuBackend.cpp @@ -133,6 +133,12 @@ xmrig::CpuBackend::~CpuBackend() } +bool xmrig::CpuBackend::isEnabled() const +{ + return d_ptr->controller->config()->cpu().isEnabled(); +} + + bool xmrig::CpuBackend::isEnabled(const Algorithm &algorithm) const { return !d_ptr->controller->config()->cpu().threads().get(algorithm).empty(); @@ -178,6 +184,12 @@ void xmrig::CpuBackend::printHashrate(bool details) void xmrig::CpuBackend::setJob(const Job &job) { + if (!isEnabled()) { + d_ptr->workers.stop(); + d_ptr->threads.clear(); + return; + } + const CpuConfig &cpu = d_ptr->controller->config()->cpu(); std::vector threads = cpu.get(d_ptr->controller->miner(), job.algorithm()); diff --git a/src/backend/cpu/CpuBackend.h b/src/backend/cpu/CpuBackend.h index 543d4459..af59c345 100644 --- a/src/backend/cpu/CpuBackend.h +++ b/src/backend/cpu/CpuBackend.h @@ -44,6 +44,7 @@ public: ~CpuBackend() override; protected: + bool isEnabled() const override; bool isEnabled(const Algorithm &algorithm) const override; const Hashrate *hashrate() const override; const String &profileName() const override; From 1d78e7d60dab7fb03300715e07ef08c8c96575fe Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 19 Jul 2019 04:22:21 +0700 Subject: [PATCH 47/65] "GET /1/threads" replaced to "GET /2/backends". --- src/api/v1/ApiRouter.cpp | 36 +------- src/api/v1/ApiRouter.h | 2 - src/backend/common/interfaces/IBackend.h | 26 ++++-- src/backend/cpu/Cpu.h | 2 + src/backend/cpu/CpuBackend.cpp | 104 +++++++++++++++++++++-- src/backend/cpu/CpuBackend.h | 5 ++ src/core/Miner.cpp | 28 +++++- src/crypto/cn/CnHash.cpp | 2 +- src/crypto/rx/Rx.cpp | 11 +++ src/crypto/rx/Rx.h | 1 + 10 files changed, 159 insertions(+), 58 deletions(-) diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp index 0e1080a1..21e69f2d 100644 --- a/src/api/v1/ApiRouter.cpp +++ b/src/api/v1/ApiRouter.cpp @@ -52,11 +52,7 @@ xmrig::ApiRouter::~ApiRouter() void xmrig::ApiRouter::onRequest(IApiRequest &request) { if (request.method() == IApiRequest::METHOD_GET) { - if (request.url() == "/1/threads") { - request.accept(); - getThreads(request.reply(), request.doc()); - } - else if (request.url() == "/1/config") { + if (request.url() == "/1/config") { if (request.isRestricted()) { return request.done(403); } @@ -77,33 +73,3 @@ void xmrig::ApiRouter::onRequest(IApiRequest &request) } } } - - -void xmrig::ApiRouter::getThreads(rapidjson::Value &reply, rapidjson::Document &doc) const -{ -// using namespace rapidjson; -// auto &allocator = doc.GetAllocator(); -// const Hashrate *hr = WorkersLegacy::hashrate(); - -// WorkersLegacy::threadsSummary(doc); - -// const std::vector &threads = m_base->config()->threads(); -// Value list(kArrayType); - -// size_t i = 0; -// for (const xmrig::IThread *thread : threads) { -// Value value = thread->toAPI(doc); - -// Value hashrate(kArrayType); -// hashrate.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); -// hashrate.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); -// hashrate.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); - -// i++; - -// value.AddMember("hashrate", hashrate, allocator); -// list.PushBack(value, allocator); -// } - -// reply.AddMember("threads", list, allocator); -} diff --git a/src/api/v1/ApiRouter.h b/src/api/v1/ApiRouter.h index ec468d86..008f5bc0 100644 --- a/src/api/v1/ApiRouter.h +++ b/src/api/v1/ApiRouter.h @@ -49,8 +49,6 @@ protected: void onRequest(IApiRequest &request) override; private: - void getThreads(rapidjson::Value &reply, rapidjson::Document &doc) const; - Base *m_base; }; diff --git a/src/backend/common/interfaces/IBackend.h b/src/backend/common/interfaces/IBackend.h index ac97759b..e19e00ba 100644 --- a/src/backend/common/interfaces/IBackend.h +++ b/src/backend/common/interfaces/IBackend.h @@ -29,6 +29,9 @@ #include +#include "rapidjson/fwd.h" + + namespace xmrig { @@ -44,15 +47,20 @@ class IBackend public: virtual ~IBackend() = default; - virtual bool isEnabled() const = 0; - virtual bool isEnabled(const Algorithm &algorithm) const = 0; - virtual const Hashrate *hashrate() const = 0; - virtual const String &profileName() const = 0; - virtual void printHashrate(bool details) = 0; - virtual void setJob(const Job &job) = 0; - virtual void start(IWorker *worker) = 0; - virtual void stop() = 0; - virtual void tick(uint64_t ticks) = 0; + virtual bool isEnabled() const = 0; + virtual bool isEnabled(const Algorithm &algorithm) const = 0; + virtual const Hashrate *hashrate() const = 0; + virtual const String &profileName() const = 0; + virtual const String &type() const = 0; + virtual void printHashrate(bool details) = 0; + virtual void setJob(const Job &job) = 0; + virtual void start(IWorker *worker) = 0; + virtual void stop() = 0; + virtual void tick(uint64_t ticks) = 0; + +# ifdef XMRIG_FEATURE_API + virtual rapidjson::Value toJSON(rapidjson::Document &doc) const = 0; +# endif }; diff --git a/src/backend/cpu/Cpu.h b/src/backend/cpu/Cpu.h index 9c8afced..23cf37e6 100644 --- a/src/backend/cpu/Cpu.h +++ b/src/backend/cpu/Cpu.h @@ -38,6 +38,8 @@ public: static ICpuInfo *info(); 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/CpuBackend.cpp b/src/backend/cpu/CpuBackend.cpp index 8ab312f7..165ed42e 100644 --- a/src/backend/cpu/CpuBackend.cpp +++ b/src/backend/cpu/CpuBackend.cpp @@ -29,6 +29,7 @@ #include "backend/common/Hashrate.h" #include "backend/common/interfaces/IWorker.h" #include "backend/common/Workers.h" +#include "backend/cpu/Cpu.h" #include "backend/cpu/CpuBackend.h" #include "base/io/log/Log.h" #include "base/net/stratum/Job.h" @@ -37,6 +38,9 @@ #include "core/config/Config.h" #include "core/Controller.h" #include "crypto/common/VirtualMemory.h" +#include "crypto/rx/Rx.h" +#include "crypto/rx/RxDataset.h" +#include "rapidjson/document.h" namespace xmrig { @@ -45,6 +49,9 @@ namespace xmrig { extern template class Threads; +static const String kType = "cpu"; + + struct LaunchStatus { public: @@ -59,13 +66,13 @@ public: ts = Chrono::steadyMSecs(); } - size_t hugePages; - size_t memory; - size_t pages; - size_t started; - size_t threads; - size_t ways; - uint64_t ts; + size_t hugePages = 0; + size_t memory = 0; + size_t pages = 0; + size_t started = 0; + size_t threads = 0; + size_t ways = 0; + uint64_t ts = 0; }; @@ -157,6 +164,12 @@ const xmrig::String &xmrig::CpuBackend::profileName() const } +const xmrig::String &xmrig::CpuBackend::type() const +{ + return kType; +} + + void xmrig::CpuBackend::printHashrate(bool details) { if (!details || !hashrate()) { @@ -251,3 +264,80 @@ void xmrig::CpuBackend::tick(uint64_t ticks) { d_ptr->workers.tick(ticks); } + + +#ifdef XMRIG_FEATURE_API +rapidjson::Value xmrig::CpuBackend::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + const CpuConfig &cpu = d_ptr->controller->config()->cpu(); + + Value out(kObjectType); + out.AddMember("type", type().toJSON(), allocator); + out.AddMember("enabled", isEnabled(), allocator); + out.AddMember("algo", d_ptr->algo.toJSON(), allocator); + out.AddMember("profile", profileName().toJSON(), allocator); + out.AddMember("hw-aes", cpu.isHwAES(), allocator); + out.AddMember("priority", cpu.priority(), allocator); + +# ifdef XMRIG_FEATURE_ASM + const Assembly assembly = Cpu::assembly(cpu.assembly()); + out.AddMember("asm", assembly.toJSON(), allocator); +# else + out.AddMember("asm", false, allocator); +# endif + + uv_mutex_lock(&d_ptr->mutex); + uint64_t pages[2] = { d_ptr->status.hugePages, d_ptr->status.pages }; + const size_t ways = d_ptr->status.ways; + uv_mutex_unlock(&d_ptr->mutex); + +# ifdef XMRIG_ALGO_RANDOMX + if (d_ptr->algo.family() == Algorithm::RANDOM_X) { + RxDataset *dataset = Rx::dataset(); + if (dataset) { + const auto rxPages = dataset->hugePages(); + pages[0] += rxPages.first; + pages[1] += rxPages.second; + } + } +# endif + + rapidjson::Value hugepages(rapidjson::kArrayType); + hugepages.PushBack(pages[0], allocator); + hugepages.PushBack(pages[1], allocator); + + out.AddMember("hugepages", hugepages, allocator); + out.AddMember("memory", d_ptr->algo.isValid() ? (ways * d_ptr->algo.memory()) : 0, allocator); + + if (d_ptr->threads.empty() || !hashrate()) { + return out; + } + + Value threads(kArrayType); + const Hashrate *hr = hashrate(); + + size_t i = 0; + for (const CpuLaunchData &data : d_ptr->threads) { + Value thread(kObjectType); + thread.AddMember("intensity", data.intensity, allocator); + thread.AddMember("affinity", data.affinity, allocator); + thread.AddMember("av", data.av(), allocator); + + Value hashrate(kArrayType); + hashrate.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); + hashrate.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); + hashrate.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); + + i++; + + thread.AddMember("hashrate", hashrate, allocator); + threads.PushBack(thread, allocator); + } + + out.AddMember("threads", threads, allocator); + + return out; +} +#endif diff --git a/src/backend/cpu/CpuBackend.h b/src/backend/cpu/CpuBackend.h index af59c345..613e7cb6 100644 --- a/src/backend/cpu/CpuBackend.h +++ b/src/backend/cpu/CpuBackend.h @@ -48,12 +48,17 @@ protected: bool isEnabled(const Algorithm &algorithm) const override; const Hashrate *hashrate() const override; const String &profileName() const override; + const String &type() const override; void printHashrate(bool details) override; void setJob(const Job &job) override; void start(IWorker *worker) override; void stop() override; void tick(uint64_t ticks) override; +# ifdef XMRIG_FEATURE_API + rapidjson::Value toJSON(rapidjson::Document &doc) const override; +# endif + private: CpuBackendPrivate *d_ptr; }; diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 7114baf9..f6acde12 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -205,6 +205,19 @@ public: reply.AddMember("hashrate", hashrate, allocator); } + + + void getBackends(rapidjson::Value &reply, rapidjson::Document &doc) const + { + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + reply.SetArray(); + + for (IBackend *backend : backends) { + reply.PushBack(backend->toJSON(doc), allocator); + } + } # endif @@ -412,11 +425,18 @@ void xmrig::Miner::onTimer(const Timer *) #ifdef XMRIG_FEATURE_API void xmrig::Miner::onRequest(IApiRequest &request) { - if (request.type() == IApiRequest::REQ_SUMMARY) { - request.accept(); + if (request.method() == IApiRequest::METHOD_GET) { + if (request.type() == IApiRequest::REQ_SUMMARY) { + request.accept(); - d_ptr->getMiner(request.reply(), request.doc(), request.version()); - d_ptr->getHashrate(request.reply(), request.doc(), request.version()); + d_ptr->getMiner(request.reply(), request.doc(), request.version()); + d_ptr->getHashrate(request.reply(), request.doc(), request.version()); + } + else if (request.url() == "/2/backends") { + request.accept(); + + d_ptr->getBackends(request.reply(), request.doc()); + } } } #endif diff --git a/src/crypto/cn/CnHash.cpp b/src/crypto/cn/CnHash.cpp index 40f4fbba..a2f8880c 100644 --- a/src/crypto/cn/CnHash.cpp +++ b/src/crypto/cn/CnHash.cpp @@ -262,7 +262,7 @@ xmrig::cn_hash_fun xmrig::CnHash::fn(const Algorithm &algorithm, AlgoVariant av, } # ifdef XMRIG_FEATURE_ASM - cn_hash_fun fun = cnHash.m_map[algorithm][av][assembly == Assembly::AUTO ? Cpu::info()->assembly() : assembly]; + cn_hash_fun fun = cnHash.m_map[algorithm][av][Cpu::assembly(assembly)]; if (fun) { return fun; } diff --git a/src/crypto/rx/Rx.cpp b/src/crypto/rx/Rx.cpp index 7f482034..4125d81f 100644 --- a/src/crypto/rx/Rx.cpp +++ b/src/crypto/rx/Rx.cpp @@ -74,6 +74,17 @@ static const char *tag = BLUE_BG(" rx "); } // namespace xmrig + +xmrig::RxDataset *xmrig::Rx::dataset() +{ + d_ptr->lock(); + RxDataset *dataset = d_ptr->dataset; + d_ptr->unlock(); + + return dataset; +} + + xmrig::RxDataset *xmrig::Rx::dataset(const uint8_t *seed, const Algorithm &algorithm, bool hugePages) { d_ptr->lock(); diff --git a/src/crypto/rx/Rx.h b/src/crypto/rx/Rx.h index c9d068c6..63bb2e14 100644 --- a/src/crypto/rx/Rx.h +++ b/src/crypto/rx/Rx.h @@ -42,6 +42,7 @@ class RxDataset; class Rx { public: + static RxDataset *dataset(); static RxDataset *dataset(const uint8_t *seed, const Algorithm &algorithm, bool hugePages = true); static void stop(); }; From ca7fb33848b9299b9b704e544afcf3abb25089d0 Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 19 Jul 2019 04:41:48 +0700 Subject: [PATCH 48/65] Removed class ApiRouter. --- CMakeLists.txt | 2 -- src/api/Api.cpp | 6 ---- src/api/Api.h | 2 -- src/api/v1/ApiRouter.cpp | 75 ---------------------------------------- src/api/v1/ApiRouter.h | 59 ------------------------------- src/base/kernel/Base.cpp | 30 ++++++++++++++++ src/base/kernel/Base.h | 9 +++-- 7 files changed, 37 insertions(+), 146 deletions(-) delete mode 100644 src/api/v1/ApiRouter.cpp delete mode 100644 src/api/v1/ApiRouter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d205f55..e0290778 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -235,8 +235,6 @@ if (WITH_HTTP) src/api/requests/ApiRequest.h src/api/requests/HttpApiRequest.cpp src/api/requests/HttpApiRequest.h - src/api/v1/ApiRouter.cpp - src/api/v1/ApiRouter.h ) else() set(HTTP_SOURCES "") diff --git a/src/api/Api.cpp b/src/api/Api.cpp index 11fc2a69..9151aa7e 100644 --- a/src/api/Api.cpp +++ b/src/api/Api.cpp @@ -35,7 +35,6 @@ #include "api/Api.h" #include "api/interfaces/IApiListener.h" #include "api/requests/HttpApiRequest.h" -#include "api/v1/ApiRouter.h" #include "base/kernel/Base.h" #include "base/tools/Buffer.h" #include "base/tools/Chrono.h" @@ -61,16 +60,11 @@ xmrig::Api::Api(Base *base) : base->addListener(this); genId(base->config()->apiId()); - - m_v1 = new ApiRouter(base); - addListener(m_v1); } xmrig::Api::~Api() { - delete m_v1; - # ifdef XMRIG_FEATURE_HTTP delete m_httpd; # endif diff --git a/src/api/Api.h b/src/api/Api.h index eef57c3a..f2ed3926 100644 --- a/src/api/Api.h +++ b/src/api/Api.h @@ -36,7 +36,6 @@ namespace xmrig { -class ApiRouter; class Base; class Httpd; class HttpData; @@ -67,7 +66,6 @@ private: void genId(const String &id); void genWorkerId(const String &id); - ApiRouter *m_v1; Base *m_base; char m_id[32]; char m_workerId[128]; diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp deleted file mode 100644 index 21e69f2d..00000000 --- a/src/api/v1/ApiRouter.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - - -#include "api/interfaces/IApiRequest.h" -#include "api/v1/ApiRouter.h" -#include "backend/common/interfaces/IThread.h" -#include "backend/cpu/Cpu.h" -#include "base/kernel/Base.h" -#include "base/kernel/Platform.h" -#include "core/config/Config.h" -#include "rapidjson/document.h" -#include "version.h" - - -xmrig::ApiRouter::ApiRouter(Base *base) : - m_base(base) -{ -} - - -xmrig::ApiRouter::~ApiRouter() -{ -} - - -void xmrig::ApiRouter::onRequest(IApiRequest &request) -{ - if (request.method() == IApiRequest::METHOD_GET) { - if (request.url() == "/1/config") { - if (request.isRestricted()) { - return request.done(403); - } - - request.accept(); - m_base->config()->getJSON(request.doc()); - } - } - else if (request.method() == IApiRequest::METHOD_PUT || request.method() == IApiRequest::METHOD_POST) { - if (request.url() == "/1/config") { - request.accept(); - - if (!m_base->reload(request.json())) { - return request.done(400); - } - - request.done(204); - } - } -} diff --git a/src/api/v1/ApiRouter.h b/src/api/v1/ApiRouter.h deleted file mode 100644 index 008f5bc0..00000000 --- a/src/api/v1/ApiRouter.h +++ /dev/null @@ -1,59 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef XMRIG_APIROUTER_H -#define XMRIG_APIROUTER_H - - -#include "api/interfaces/IApiListener.h" -#include "rapidjson/fwd.h" - - -class Hashrate; - - -namespace xmrig { - - -class Base; - - -class ApiRouter : public IApiListener -{ -public: - ApiRouter(Base *base); - ~ApiRouter() override; - -protected: - void onRequest(IApiRequest &request) override; - -private: - Base *m_base; -}; - - -} // namespace xmrig - - -#endif /* XMRIG_APIROUTER_H */ diff --git a/src/base/kernel/Base.cpp b/src/base/kernel/Base.cpp index 46f32684..d290e7f4 100644 --- a/src/base/kernel/Base.cpp +++ b/src/base/kernel/Base.cpp @@ -48,6 +48,7 @@ #ifdef XMRIG_FEATURE_API # include "api/Api.h" +# include "api/interfaces/IApiRequest.h" #endif @@ -167,6 +168,7 @@ int xmrig::Base::init() # ifdef XMRIG_FEATURE_API d_ptr->api = new Api(this); + d_ptr->api->addListener(this); # endif Platform::init(config()->userAgent()); @@ -288,3 +290,31 @@ void xmrig::Base::onFileChanged(const String &fileName) d_ptr->replace(config); } + + +#ifdef XMRIG_FEATURE_API +void xmrig::Base::onRequest(IApiRequest &request) +{ + if (request.method() == IApiRequest::METHOD_GET) { + if (request.url() == "/1/config") { + if (request.isRestricted()) { + return request.done(403); + } + + request.accept(); + config()->getJSON(request.doc()); + } + } + else if (request.method() == IApiRequest::METHOD_PUT || request.method() == IApiRequest::METHOD_POST) { + if (request.url() == "/1/config") { + request.accept(); + + if (!reload(request.json())) { + return request.done(400); + } + + request.done(204); + } + } +} +#endif diff --git a/src/base/kernel/Base.h b/src/base/kernel/Base.h index 592d3a37..6a33a802 100644 --- a/src/base/kernel/Base.h +++ b/src/base/kernel/Base.h @@ -26,6 +26,7 @@ #define XMRIG_BASE_H +#include "api/interfaces/IApiListener.h" #include "base/kernel/interfaces/IConfigListener.h" #include "base/kernel/interfaces/IWatcherListener.h" #include "rapidjson/fwd.h" @@ -35,13 +36,13 @@ namespace xmrig { class Api; -class Config; class BasePrivate; +class Config; class IBaseListener; class Process; -class Base : public IWatcherListener +class Base : public IWatcherListener, public IApiListener { public: Base(Process *process); @@ -60,6 +61,10 @@ public: protected: void onFileChanged(const String &fileName) override; +# ifdef XMRIG_FEATURE_API + void onRequest(IApiRequest &request) override; +# endif + private: BasePrivate *d_ptr; }; From 2fc54d240a31ac46d8bd9d17e00d96b2080f6088 Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 19 Jul 2019 05:03:14 +0700 Subject: [PATCH 49/65] Fixed build. --- cmake/flags.cmake | 2 +- src/backend/common/Hashrate.cpp | 8 ++++---- src/backend/cpu/CpuBackend.cpp | 2 +- src/core/Miner.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/flags.cmake b/cmake/flags.cmake index 3a0add7a..3f2bd0a0 100644 --- a/cmake/flags.cmake +++ b/cmake/flags.cmake @@ -61,7 +61,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast -funroll-loops -fmerge-all-constants") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-exceptions -fno-rtti -Wno-missing-braces") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fexceptions -fno-rtti -Wno-missing-braces") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -funroll-loops -fmerge-all-constants") if (XMRIG_ARMv8) diff --git a/src/backend/common/Hashrate.cpp b/src/backend/common/Hashrate.cpp index a9c63733..99a9a9c5 100644 --- a/src/backend/common/Hashrate.cpp +++ b/src/backend/common/Hashrate.cpp @@ -24,7 +24,7 @@ #include -#include +#include #include #include @@ -37,7 +37,7 @@ inline static const char *format(double h, char *buf, size_t size) { - if (isnormal(h)) { + if (std::isnormal(h)) { snprintf(buf, size, "%03.1f", h); return buf; } @@ -82,7 +82,7 @@ double xmrig::Hashrate::calc(size_t ms) const for (size_t i = 0; i < m_threads; ++i) { data = calc(i, ms); - if (isnormal(data)) { + if (std::isnormal(data)) { result += data; } } @@ -153,7 +153,7 @@ void xmrig::Hashrate::add(size_t threadId, uint64_t count, uint64_t timestamp) void xmrig::Hashrate::updateHighest() { double highest = calc(ShortInterval); - if (isnormal(highest) && highest > m_highest) { + if (std::isnormal(highest) && highest > m_highest) { m_highest = highest; } } diff --git a/src/backend/cpu/CpuBackend.cpp b/src/backend/cpu/CpuBackend.cpp index 165ed42e..ffc21597 100644 --- a/src/backend/cpu/CpuBackend.cpp +++ b/src/backend/cpu/CpuBackend.cpp @@ -309,7 +309,7 @@ rapidjson::Value xmrig::CpuBackend::toJSON(rapidjson::Document &doc) const hugepages.PushBack(pages[1], allocator); out.AddMember("hugepages", hugepages, allocator); - out.AddMember("memory", d_ptr->algo.isValid() ? (ways * d_ptr->algo.memory()) : 0, allocator); + out.AddMember("memory", static_cast(d_ptr->algo.isValid() ? (ways * d_ptr->algo.memory()) : 0), allocator); if (d_ptr->threads.empty() || !hashrate()) { return out; diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index f6acde12..df83c5e9 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -134,7 +134,7 @@ public: cpu.AddMember("brand", StringRef(Cpu::info()->brand()), allocator); cpu.AddMember("aes", Cpu::info()->hasAES(), allocator); cpu.AddMember("x64", Cpu::info()->isX64(), allocator); - cpu.AddMember("sockets", Cpu::info()->sockets(), allocator); + cpu.AddMember("sockets", static_cast(Cpu::info()->sockets()), allocator); reply.AddMember("version", APP_VERSION, allocator); reply.AddMember("kind", APP_KIND, allocator); From 222cebba7109bf8a1423d8d70d90bdcd5c3319b3 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 20 Jul 2019 00:37:15 +0700 Subject: [PATCH 50/65] Fixed command line config and removed --max-cpu-usage and --safe. --- src/backend/common/Threads.cpp | 75 +++++--- src/backend/common/Threads.h | 2 +- src/backend/cpu/CpuConfig.cpp | 70 ++++---- src/backend/cpu/CpuConfig.h | 4 +- src/backend/cpu/CpuWorker.cpp | 2 +- src/base/base.cmake | 2 - src/base/kernel/config/BaseConfig.cpp | 15 +- src/base/kernel/config/BaseTransform.cpp | 49 ++---- src/base/kernel/config/BaseTransform.h | 4 + src/base/kernel/interfaces/IConfig.h | 9 - src/base/kernel/interfaces/IConfigTransform.h | 3 +- src/core/config/ConfigTransform.cpp | 166 +++++++++++++++++- src/core/config/ConfigTransform.h | 8 +- src/core/config/Config_platform.h | 35 ---- src/core/config/usage.h | 2 - 15 files changed, 283 insertions(+), 163 deletions(-) diff --git a/src/backend/common/Threads.cpp b/src/backend/common/Threads.cpp index 4cb9d4c6..894c404b 100644 --- a/src/backend/common/Threads.cpp +++ b/src/backend/common/Threads.cpp @@ -28,6 +28,15 @@ #include "rapidjson/document.h" +namespace xmrig { + + +static const char *kAsterisk = "*"; + + +} // namespace xmrig + + template const std::vector &xmrig::Threads::get(const String &profileName) const { @@ -41,34 +50,7 @@ const std::vector &xmrig::Threads::get(const String &profileName) const template -xmrig::String xmrig::Threads::profileName(const Algorithm &algorithm, bool strict) const -{ - if (isDisabled(algorithm)) { - return String(); - } - - const String name = algorithm.shortName(); - if (has(name)) { - return name; - } - - if (m_aliases.count(algorithm) > 0) { - return m_aliases.at(algorithm); - } - - if (!strict && name.contains("/")) { - const String base = name.split('/').at(0); - if (has(base)) { - return base; - } - } - - return String(); -} - - -template -void xmrig::Threads::read(const rapidjson::Value &value) +size_t xmrig::Threads::read(const rapidjson::Value &value) { using namespace rapidjson; @@ -109,6 +91,43 @@ void xmrig::Threads::read(const rapidjson::Value &value) } } } + + return m_profiles.size(); +} + + +template +xmrig::String xmrig::Threads::profileName(const Algorithm &algorithm, bool strict) const +{ + if (isDisabled(algorithm)) { + return String(); + } + + const String name = algorithm.shortName(); + if (has(name)) { + return name; + } + + if (m_aliases.count(algorithm) > 0) { + return m_aliases.at(algorithm); + } + + if (strict) { + return String(); + } + + if (name.contains("/")) { + const String base = name.split('/').at(0); + if (has(base)) { + return base; + } + } + + if (has(kAsterisk)) { + return kAsterisk; + } + + return String(); } diff --git a/src/backend/common/Threads.h b/src/backend/common/Threads.h index 70bc02a4..bc9e36fd 100644 --- a/src/backend/common/Threads.h +++ b/src/backend/common/Threads.h @@ -50,8 +50,8 @@ public: inline void move(const char *profile, std::vector &&threads) { m_profiles.insert({ profile, threads }); } const std::vector &get(const String &profileName) const; + size_t read(const rapidjson::Value &value); String profileName(const Algorithm &algorithm, bool strict = false) const; - void read(const rapidjson::Value &value); void toJSON(rapidjson::Value &out, rapidjson::Document &doc) const; private: diff --git a/src/backend/cpu/CpuConfig.cpp b/src/backend/cpu/CpuConfig.cpp index 457f7ef4..4c86ceea 100644 --- a/src/backend/cpu/CpuConfig.cpp +++ b/src/backend/cpu/CpuConfig.cpp @@ -126,48 +126,56 @@ void xmrig::CpuConfig::read(const rapidjson::Value &value) m_hugePages = Json::getBool(value, kHugePages, m_hugePages); setAesMode(Json::getValue(value, kHwAes)); - setPriority(Json::getInt(value, kPriority, -1)); + setPriority(Json::getInt(value, kPriority, -1)); # ifdef XMRIG_FEATURE_ASM m_assembly = Json::getValue(value, kAsm); # endif - m_threads.read(value); + if (!m_threads.read(value)) { + generate(); + } } else if (value.IsBool() && value.IsFalse()) { m_enabled = false; } else { - m_shouldSave = true; - - m_threads.disable(Algorithm::CN_0); - m_threads.move(kCn, Cpu::info()->threads(Algorithm::CN_0)); - -# ifdef XMRIG_ALGO_CN_GPU - m_threads.move(kCnGPU, Cpu::info()->threads(Algorithm::CN_GPU)); -# endif - -# ifdef XMRIG_ALGO_CN_LITE - m_threads.disable(Algorithm::CN_LITE_0); - m_threads.move(kCnLite, Cpu::info()->threads(Algorithm::CN_LITE_1)); -# endif - -# ifdef XMRIG_ALGO_CN_HEAVY - m_threads.move(kCnHeavy, Cpu::info()->threads(Algorithm::CN_HEAVY_0)); -# endif - -# ifdef XMRIG_ALGO_CN_PICO - m_threads.move(kCnPico, Cpu::info()->threads(Algorithm::CN_PICO_0)); -# endif - -# ifdef XMRIG_ALGO_RANDOMX - m_threads.move(kRx, Cpu::info()->threads(Algorithm::RX_0)); - m_threads.move(kRxWOW, Cpu::info()->threads(Algorithm::RX_WOW)); -# endif + generate(); } } +void xmrig::CpuConfig::generate() +{ + m_shouldSave = true; + + m_threads.disable(Algorithm::CN_0); + m_threads.move(kCn, Cpu::info()->threads(Algorithm::CN_0)); + +# ifdef XMRIG_ALGO_CN_GPU + m_threads.move(kCnGPU, Cpu::info()->threads(Algorithm::CN_GPU)); +# endif + +# ifdef XMRIG_ALGO_CN_LITE + m_threads.disable(Algorithm::CN_LITE_0); + m_threads.move(kCnLite, Cpu::info()->threads(Algorithm::CN_LITE_1)); +# endif + +# ifdef XMRIG_ALGO_CN_HEAVY + m_threads.move(kCnHeavy, Cpu::info()->threads(Algorithm::CN_HEAVY_0)); +# endif + +# ifdef XMRIG_ALGO_CN_PICO + m_threads.move(kCnPico, Cpu::info()->threads(Algorithm::CN_PICO_0)); +# endif + +# ifdef XMRIG_ALGO_RANDOMX + m_threads.move(kRx, Cpu::info()->threads(Algorithm::RX_0)); + m_threads.move(kRxWOW, Cpu::info()->threads(Algorithm::RX_WOW)); +# endif +} + + void xmrig::CpuConfig::setAesMode(const rapidjson::Value &aesMode) { if (aesMode.IsBool()) { @@ -177,9 +185,3 @@ void xmrig::CpuConfig::setAesMode(const rapidjson::Value &aesMode) m_aes = AES_AUTO; } } - - -void xmrig::CpuConfig::setPriority(int priority) -{ - m_priority = (priority >= -1 && priority <= 5) ? priority : -1; -} diff --git a/src/backend/cpu/CpuConfig.h b/src/backend/cpu/CpuConfig.h index 8ff8b77c..5b2f3f86 100644 --- a/src/backend/cpu/CpuConfig.h +++ b/src/backend/cpu/CpuConfig.h @@ -59,8 +59,10 @@ public: inline int priority() const { return m_priority; } private: + void generate(); void setAesMode(const rapidjson::Value &aesMode); - void setPriority(int priority); + + inline void setPriority(int priority) { m_priority = (priority >= -1 && priority <= 5) ? priority : -1; } AesMode m_aes = AES_AUTO; Assembly m_assembly; diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp index e35c5155..14ffaa73 100644 --- a/src/backend/cpu/CpuWorker.cpp +++ b/src/backend/cpu/CpuWorker.cpp @@ -273,7 +273,7 @@ template void xmrig::CpuWorker::allocateCnCtx() { if (m_ctx[0] == nullptr) { - CnCtx::create(m_ctx, m_memory->scratchpad(), m_memory->size(), N); + CnCtx::create(m_ctx, m_memory->scratchpad(), m_algorithm.memory(), N); } } diff --git a/src/base/base.cmake b/src/base/base.cmake index b25d9743..ef4da131 100644 --- a/src/base/base.cmake +++ b/src/base/base.cmake @@ -146,5 +146,3 @@ else() remove_definitions(/DXMRIG_FEATURE_HTTP) remove_definitions(/DXMRIG_FEATURE_API) endif() - -add_definitions(/DXMRIG_DEPRECATED) diff --git a/src/base/kernel/config/BaseConfig.cpp b/src/base/kernel/config/BaseConfig.cpp index 489849a3..462639e3 100644 --- a/src/base/kernel/config/BaseConfig.cpp +++ b/src/base/kernel/config/BaseConfig.cpp @@ -139,20 +139,7 @@ bool xmrig::BaseConfig::read(const IJsonReader &reader, const char *fileName) m_apiWorkerId = Json::getString(api, "worker-id"); } -# ifdef XMRIG_DEPRECATED - if (api.IsObject() && api.HasMember("port")) { - m_upgrade = true; - m_http.load(api); - m_http.setEnabled(Json::getUint(api, "port") > 0); - m_http.setHost("0.0.0.0"); - } - else { - m_http.load(reader.getObject("http")); - } -# else - m_http.load(chain.getObject("http")); -# endif - + m_http.load(reader.getObject("http")); m_pools.load(reader); return m_pools.active() > 0; diff --git a/src/base/kernel/config/BaseTransform.cpp b/src/base/kernel/config/BaseTransform.cpp index 615342b9..554565a5 100644 --- a/src/base/kernel/config/BaseTransform.cpp +++ b/src/base/kernel/config/BaseTransform.cpp @@ -87,15 +87,31 @@ void xmrig::BaseTransform::load(JsonChain &chain, Process *process, IConfigTrans LOG_WARN("%s: unsupported non-option argument '%s'", argv[0], argv[optind]); } + transform.finalize(doc); chain.add(std::move(doc)); } +void xmrig::BaseTransform::finalize(rapidjson::Document &doc) +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + if (m_algorithm.isValid() && doc.HasMember(kPools)) { + auto &pools = doc[kPools]; + for (Value &pool : pools.GetArray()) { + pool.AddMember(StringRef("algo"), m_algorithm.toJSON(), allocator); + } + } +} + + void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const char *arg) { switch (key) { case IConfig::AlgorithmKey: /* --algo */ - return set(doc, "algo", arg); + m_algorithm = arg; + break; case IConfig::UserpassKey: /* --userpass */ { @@ -134,13 +150,6 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch case IConfig::LogFileKey: /* --log-file */ return set(doc, "log-file", arg); -# ifdef XMRIG_DEPRECATED - case IConfig::ApiAccessTokenKey: /* --api-access-token */ - fputs("option \"--api-access-token\" deprecated, use \"--http-access-token\" instead.\n", stderr); - fflush(stdout); - return set(doc, kHttp, "access-token", arg); -# endif - case IConfig::HttpAccessTokenKey: /* --http-access-token */ return set(doc, kHttp, "access-token", arg); @@ -162,9 +171,6 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch case IConfig::HttpPort: /* --http-port */ case IConfig::DonateLevelKey: /* --donate-level */ case IConfig::DaemonPollKey: /* --daemon-poll-interval */ -# ifdef XMRIG_DEPRECATED - case IConfig::ApiPort: /* --api-port */ -# endif return transformUint64(doc, key, static_cast(strtol(arg, nullptr, 10))); case IConfig::BackgroundKey: /* --background */ @@ -179,10 +185,6 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch case IConfig::ColorKey: /* --no-color */ case IConfig::HttpRestrictedKey: /* --http-no-restricted */ -# ifdef XMRIG_DEPRECATED - case IConfig::ApiRestrictedKey: /* --api-no-restricted */ - case IConfig::ApiIPv6Key: /* --api-ipv6 */ -# endif return transformBoolean(doc, key, false); default: @@ -217,16 +219,6 @@ void xmrig::BaseTransform::transformBoolean(rapidjson::Document &doc, int key, b case IConfig::ColorKey: /* --no-color */ return set(doc, "colors", enable); -# ifdef XMRIG_DEPRECATED - case IConfig::ApiIPv6Key: /* --api-ipv6 */ - break; - - case IConfig::ApiRestrictedKey: /* --api-no-restricted */ - fputs("option \"--api-no-restricted\" deprecated, use \"--http-no-restricted\" instead.\n", stderr); - fflush(stdout); - return set(doc, kHttp, "restricted", enable); -# endif - case IConfig::HttpRestrictedKey: /* --http-no-restricted */ return set(doc, kHttp, "restricted", enable); @@ -257,13 +249,6 @@ void xmrig::BaseTransform::transformUint64(rapidjson::Document &doc, int key, ui case IConfig::ProxyDonateKey: /* --donate-over-proxy */ return set(doc, "donate-over-proxy", arg); -# ifdef XMRIG_DEPRECATED - case IConfig::ApiPort: /* --api-port */ - fputs("option \"--api-port\" deprecated, use \"--http-port\" instead.\n", stderr); - fflush(stdout); - return set(doc, kHttp, "port", arg); -# endif - case IConfig::HttpPort: /* --http-port */ return set(doc, kHttp, "port", arg); diff --git a/src/base/kernel/config/BaseTransform.h b/src/base/kernel/config/BaseTransform.h index 3952e22b..02b28c12 100644 --- a/src/base/kernel/config/BaseTransform.h +++ b/src/base/kernel/config/BaseTransform.h @@ -49,6 +49,7 @@ public: static void load(JsonChain &chain, Process *process, IConfigTransform &transform); protected: + void finalize(rapidjson::Document &doc) override; void transform(rapidjson::Document &doc, int key, const char *arg) override; @@ -96,6 +97,9 @@ protected: } } +protected: + Algorithm m_algorithm; + private: void transformBoolean(rapidjson::Document &doc, int key, bool enable); diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h index c8189ba5..ba20a0ca 100644 --- a/src/base/kernel/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -73,13 +73,6 @@ public: DaemonKey = 1018, DaemonPollKey = 1019, -# ifdef XMRIG_DEPRECATED - ApiPort = 4000, - ApiAccessTokenKey = 4001, - ApiIPv6Key = 4003, - ApiRestrictedKey = 4004, -# endif - // xmrig common CPUPriorityKey = 1021, NicehashKey = 1006, @@ -90,8 +83,6 @@ public: CPUAffinityKey = 1020, DryRunKey = 5000, HugePagesKey = 1009, - MaxCPUUsageKey = 1004, - SafeKey = 1005, ThreadsKey = 't', // HardwareAESKey = 1011, AssemblyKey = 1015, diff --git a/src/base/kernel/interfaces/IConfigTransform.h b/src/base/kernel/interfaces/IConfigTransform.h index f8854388..8afe8221 100644 --- a/src/base/kernel/interfaces/IConfigTransform.h +++ b/src/base/kernel/interfaces/IConfigTransform.h @@ -42,7 +42,8 @@ class IConfigTransform public: virtual ~IConfigTransform() = default; - virtual void transform(rapidjson::Document &doc, int key, const char *arg) = 0; + virtual void finalize(rapidjson::Document &doc) = 0; + virtual void transform(rapidjson::Document &doc, int key, const char *arg) = 0; }; diff --git a/src/core/config/ConfigTransform.cpp b/src/core/config/ConfigTransform.cpp index 7d313726..38bb42a1 100644 --- a/src/core/config/ConfigTransform.cpp +++ b/src/core/config/ConfigTransform.cpp @@ -23,27 +23,189 @@ */ -#include "core/config/ConfigTransform.h" #include "base/kernel/interfaces/IConfig.h" +#include "core/config/ConfigTransform.h" +#include "crypto/cn/CnHash.h" -xmrig::ConfigTransform::ConfigTransform() +namespace xmrig { + +static const char *kAffinity = "affinity"; +static const char *kAsterisk = "*"; +static const char *kCpu = "cpu"; +static const char *kIntensity = "intensity"; + + +static inline uint64_t intensity(uint64_t av) +{ + switch (av) { + case CnHash::AV_SINGLE: + case CnHash::AV_SINGLE_SOFT: + return 1; + + case CnHash::AV_DOUBLE_SOFT: + case CnHash::AV_DOUBLE: + return 2; + + case CnHash::AV_TRIPLE_SOFT: + case CnHash::AV_TRIPLE: + return 3; + + case CnHash::AV_QUAD_SOFT: + case CnHash::AV_QUAD: + return 4; + + case CnHash::AV_PENTA_SOFT: + case CnHash::AV_PENTA: + return 5; + + default: + break; + } + + return 1; +} + + +static inline bool isHwAes(uint64_t av) +{ + return av == CnHash::AV_SINGLE || av == CnHash::AV_DOUBLE || (av > CnHash::AV_DOUBLE_SOFT && av < CnHash::AV_TRIPLE_SOFT); +} + + +static inline int64_t affinity(uint64_t index, int64_t affinity) +{ + if (affinity == -1L) { + return -1L; + } + + size_t idx = 0; + + for (size_t i = 0; i < 64; i++) { + if (!(static_cast(affinity) & (1ULL << i))) { + continue; + } + + if (idx == index) { + return static_cast(i); + } + + idx++; + } + + return -1L; +} + + +} + + +xmrig::ConfigTransform::ConfigTransform() : BaseTransform() +{ +} + + +void xmrig::ConfigTransform::finalize(rapidjson::Document &doc) +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + BaseTransform::finalize(doc); + + if (m_threads) { + if (!doc.HasMember(kCpu)) { + doc.AddMember(StringRef(kCpu), Value(kObjectType), allocator); + } + + Value threads(kArrayType); + + if (m_intensity > 1) { + for (uint64_t i = 0; i < m_threads; ++i) { + Value thread(kObjectType); + thread.AddMember(StringRef(kIntensity), m_intensity, allocator); + thread.AddMember(StringRef(kAffinity), affinity(i, m_affinity), allocator); + + threads.PushBack(thread, doc.GetAllocator()); + } + } + else { + for (uint64_t i = 0; i < m_threads; ++i) { + threads.PushBack(affinity(i, m_affinity), doc.GetAllocator()); + } + } + + doc[kCpu].AddMember(StringRef(kAsterisk), threads, doc.GetAllocator()); + } } void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const char *arg) { BaseTransform::transform(doc, key, arg); + + switch (key) { + case IConfig::AVKey: /* --av */ + case IConfig::CPUPriorityKey: /* --cpu-priority */ + case IConfig::ThreadsKey: /* --threads */ + return transformUint64(doc, key, static_cast(strtol(arg, nullptr, 10))); + + case IConfig::HugePagesKey: /* --no-huge-pages */ + return transformBoolean(doc, key, false); + + case IConfig::CPUAffinityKey: /* --cpu-affinity */ + { + const char *p = strstr(arg, "0x"); + return transformUint64(doc, key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10)); + } + +# ifndef XMRIG_NO_ASM + case IConfig::AssemblyKey: /* --asm */ + return set(doc, kCpu, "asm", arg); +# endif + + default: + break; + } } void xmrig::ConfigTransform::transformBoolean(rapidjson::Document &doc, int key, bool enable) { + switch (key) { + case IConfig::HugePagesKey: /* --no-huge-pages */ + return set(doc, kCpu, "huge-pages", enable); + + default: + break; + } } void xmrig::ConfigTransform::transformUint64(rapidjson::Document &doc, int key, uint64_t arg) { + using namespace rapidjson; + + switch (key) { + case IConfig::CPUAffinityKey: /* --cpu-affinity */ + m_affinity = static_cast(arg); + break; + + case IConfig::ThreadsKey: /* --threads */ + m_threads = arg; + break; + + case IConfig::AVKey: /* --av */ + m_intensity = intensity(arg); + set(doc, kCpu, "hw-aes", isHwAes(arg)); + break; + + case IConfig::CPUPriorityKey: /* --cpu-priority */ + return set(doc, kCpu, "priority", arg); + + default: + break; + } } + diff --git a/src/core/config/ConfigTransform.h b/src/core/config/ConfigTransform.h index 2d291d8f..440a7169 100644 --- a/src/core/config/ConfigTransform.h +++ b/src/core/config/ConfigTransform.h @@ -5,7 +5,8 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , + * 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 @@ -37,11 +38,16 @@ public: ConfigTransform(); protected: + void finalize(rapidjson::Document &doc) override; void transform(rapidjson::Document &doc, int key, const char *arg) override; private: void transformBoolean(rapidjson::Document &doc, int key, bool enable); void transformUint64(rapidjson::Document &doc, int key, uint64_t arg); + + int64_t m_affinity = -1; + uint64_t m_intensity = 1; + uint64_t m_threads = 0; }; diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h index ca06a703..85ab0b43 100644 --- a/src/core/config/Config_platform.h +++ b/src/core/config/Config_platform.h @@ -62,7 +62,6 @@ static const option options[] = { { "dry-run", 0, nullptr, IConfig::DryRunKey }, { "keepalive", 0, nullptr, IConfig::KeepAliveKey }, { "log-file", 1, nullptr, IConfig::LogFileKey }, - { "max-cpu-usage", 1, nullptr, IConfig::MaxCPUUsageKey }, { "nicehash", 0, nullptr, IConfig::NicehashKey }, { "no-color", 0, nullptr, IConfig::ColorKey }, { "no-huge-pages", 0, nullptr, IConfig::HugePagesKey }, @@ -71,7 +70,6 @@ static const option options[] = { { "print-time", 1, nullptr, IConfig::PrintTimeKey }, { "retries", 1, nullptr, IConfig::RetriesKey }, { "retry-pause", 1, nullptr, IConfig::RetryPauseKey }, - { "safe", 0, nullptr, IConfig::SafeKey }, { "syslog", 0, nullptr, IConfig::SyslogKey }, { "threads", 1, nullptr, IConfig::ThreadsKey }, { "url", 1, nullptr, IConfig::UrlKey }, @@ -84,43 +82,10 @@ static const option options[] = { { "asm", 1, nullptr, IConfig::AssemblyKey }, { "daemon", 0, nullptr, IConfig::DaemonKey }, { "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey }, - -# ifdef XMRIG_DEPRECATED - { "api-port", 1, nullptr, IConfig::ApiPort }, - { "api-access-token", 1, nullptr, IConfig::ApiAccessTokenKey }, - { "api-no-restricted", 0, nullptr, IConfig::ApiRestrictedKey }, - { "api-ipv6", 0, nullptr, IConfig::ApiIPv6Key }, -# endif - { nullptr, 0, nullptr, 0 } }; -static struct option const config_options[] = { - { "algo", 1, nullptr, IConfig::AlgorithmKey }, - { "av", 1, nullptr, IConfig::AVKey }, - { "background", 0, nullptr, IConfig::BackgroundKey }, - { "colors", 0, nullptr, IConfig::ColorKey }, - { "cpu-affinity", 1, nullptr, IConfig::CPUAffinityKey }, - { "cpu-priority", 1, nullptr, IConfig::CPUPriorityKey }, - { "donate-level", 1, nullptr, IConfig::DonateLevelKey }, - { "donate-over-proxy", 1, nullptr, IConfig::ProxyDonateKey }, - { "dry-run", 0, nullptr, IConfig::DryRunKey }, - { "huge-pages", 0, nullptr, IConfig::HugePagesKey }, - { "log-file", 1, nullptr, IConfig::LogFileKey }, - { "max-cpu-usage", 1, nullptr, IConfig::MaxCPUUsageKey }, - { "print-time", 1, nullptr, IConfig::PrintTimeKey }, - { "retries", 1, nullptr, IConfig::RetriesKey }, - { "retry-pause", 1, nullptr, IConfig::RetryPauseKey }, - { "safe", 0, nullptr, IConfig::SafeKey }, - { "syslog", 0, nullptr, IConfig::SyslogKey }, - { "threads", 1, nullptr, IConfig::ThreadsKey }, - { "user-agent", 1, nullptr, IConfig::UserAgentKey }, - { "asm", 1, nullptr, IConfig::AssemblyKey }, - { nullptr, 0, nullptr, 0 } -}; - - } // namespace xmrig diff --git a/src/core/config/usage.h b/src/core/config/usage.h index 42cbc24a..ec3dd589 100644 --- a/src/core/config/usage.h +++ b/src/core/config/usage.h @@ -87,8 +87,6 @@ Options:\n\ -S, --syslog use system log for output messages\n" # endif "\ - --max-cpu-usage=N maximum CPU usage for automatic threads mode (default: 100)\n\ - --safe safe adjust threads and av settings for current CPU\n\ --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 From d2ca254789f9ec8eb3023b5bcc6905e11f243376 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 20 Jul 2019 01:20:50 +0700 Subject: [PATCH 51/65] Disable rx/0 algorithm. --- src/backend/common/Threads.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/common/Threads.h b/src/backend/common/Threads.h index bc9e36fd..126245f6 100644 --- a/src/backend/common/Threads.h +++ b/src/backend/common/Threads.h @@ -43,7 +43,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 isDisabled(const Algorithm &algo) const { return m_disabled.count(algo) > 0 || algo == Algorithm::RX_0; } inline bool isExist(const Algorithm &algo) const { return isDisabled(algo) || m_aliases.count(algo) > 0 || has(algo.shortName()); } inline const std::vector &get(const Algorithm &algo, bool strict = false) const { return get(profileName(algo, strict)); } inline void disable(const Algorithm &algo) { m_disabled.insert(algo); } From dc2c0552e082fd8787c94a0ca1918591943f1ef7 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 20 Jul 2019 01:43:36 +0700 Subject: [PATCH 52/65] Moved current valid algorithm to first position in algo list. --- src/net/Network.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 5ee00388..547a8638 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -27,7 +27,9 @@ #pragma warning(disable:4244) #endif +#include #include +#include #include #include @@ -154,14 +156,23 @@ void xmrig::Network::onJobResult(const JobResult &result) } -void xmrig::Network::onLogin(IStrategy *, IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) +void xmrig::Network::onLogin(IStrategy *, IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) { using namespace rapidjson; auto &allocator = doc.GetAllocator(); + Algorithms algorithms = m_controller->miner()->algorithms(); + const Algorithm algorithm = client->pool().algorithm(); + if (algorithm.isValid()) { + const size_t index = static_cast(std::distance(algorithms.begin(), std::find(algorithms.begin(), algorithms.end(), algorithm))); + if (index > 0 && index < algorithms.size()) { + std::swap(algorithms[0], algorithms[index]); + } + } + Value algo(kArrayType); - for (const auto &a : m_controller->miner()->algorithms()) { + for (const auto &a : algorithms) { algo.PushBack(StringRef(a.shortName()), allocator); } From 3fb180f04e9108925293a6940f0d052ee59176c6 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 20 Jul 2019 05:24:21 +0700 Subject: [PATCH 53/65] Removed --variant option, use --algo instead. --- src/base/kernel/config/BaseTransform.cpp | 15 ++++++++++----- src/base/kernel/interfaces/IConfig.h | 1 - src/core/config/Config_platform.h | 1 - src/core/config/usage.h | 19 ++++++++++++++----- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/base/kernel/config/BaseTransform.cpp b/src/base/kernel/config/BaseTransform.cpp index 554565a5..8043c6e9 100644 --- a/src/base/kernel/config/BaseTransform.cpp +++ b/src/base/kernel/config/BaseTransform.cpp @@ -44,6 +44,7 @@ namespace xmrig { +static const char *kAlgo = "algo"; static const char *kApi = "api"; static const char *kHttp = "http"; static const char *kPools = "pools"; @@ -100,7 +101,9 @@ void xmrig::BaseTransform::finalize(rapidjson::Document &doc) if (m_algorithm.isValid() && doc.HasMember(kPools)) { auto &pools = doc[kPools]; for (Value &pool : pools.GetArray()) { - pool.AddMember(StringRef("algo"), m_algorithm.toJSON(), allocator); + if (!pool.HasMember(kAlgo)) { + pool.AddMember(StringRef(kAlgo), m_algorithm.toJSON(), allocator); + } } } } @@ -110,7 +113,12 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch { switch (key) { case IConfig::AlgorithmKey: /* --algo */ - m_algorithm = arg; + if (!doc.HasMember(kPools)) { + m_algorithm = arg; + } + else { + return add(doc, kPools, kAlgo, arg); + } break; case IConfig::UserpassKey: /* --userpass */ @@ -144,9 +152,6 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch case IConfig::FingerprintKey: /* --tls-fingerprint */ return add(doc, kPools, "tls-fingerprint", arg); - case IConfig::VariantKey: /* --variant */ - return add(doc, kPools, "variant", arg); - case IConfig::LogFileKey: /* --log-file */ return set(doc, "log-file", arg); diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h index ba20a0ca..2697bf01 100644 --- a/src/base/kernel/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -65,7 +65,6 @@ public: UserAgentKey = 1008, UserKey = 'u', UserpassKey = 'O', - VariantKey = 1010, VerboseKey = 1100, TlsKey = 1013, FingerprintKey = 1014, diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h index 85ab0b43..fdd15c96 100644 --- a/src/core/config/Config_platform.h +++ b/src/core/config/Config_platform.h @@ -65,7 +65,6 @@ static const option options[] = { { "nicehash", 0, nullptr, IConfig::NicehashKey }, { "no-color", 0, nullptr, IConfig::ColorKey }, { "no-huge-pages", 0, nullptr, IConfig::HugePagesKey }, - { "variant", 1, nullptr, IConfig::VariantKey }, { "pass", 1, nullptr, IConfig::PasswordKey }, { "print-time", 1, nullptr, IConfig::PrintTimeKey }, { "retries", 1, nullptr, IConfig::RetriesKey }, diff --git a/src/core/config/usage.h b/src/core/config/usage.h index ec3dd589..2d0d5623 100644 --- a/src/core/config/usage.h +++ b/src/core/config/usage.h @@ -36,18 +36,28 @@ static char const usage[] = "\ Usage: " APP_ID " [OPTIONS]\n\ Options:\n\ -a, --algo=ALGO specify the algorithm to use\n\ - cryptonight\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 "\ - cryptonight-lite\n" + cn-lite/1,\n" #endif #ifdef XMRIG_ALGO_CN_HEAVY "\ - cryptonight-heavy\n" + cn-heavy/xhv, cn-heavy/tube, cn-heavy/0,\n" #endif #ifdef XMRIG_ALGO_CN_PICO "\ - cryptonight-pico\n" + cn-pico,\n" +#endif +#ifdef XMRIG_ALGO_RANDOMX +"\ + rx/wow, rx/loki\n" #endif "\ -o, --url=URL URL of mining server\n\ @@ -76,7 +86,6 @@ Options:\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\ - --variant algorithm PoW variant\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\ From 71300fa852917a082255af394687873351fccc66 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 20 Jul 2019 05:35:40 +0700 Subject: [PATCH 54/65] v2.99.0-evo --- src/version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/version.h b/src/version.h index 7e849c7e..309f8873 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 CPU miner" -#define APP_VERSION "2.16.1-evo" +#define APP_VERSION "2.99.0-evo" #define APP_DOMAIN "xmrig.com" #define APP_SITE "www.xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2019 xmrig.com" #define APP_KIND "cpu" #define APP_VER_MAJOR 2 -#define APP_VER_MINOR 16 -#define APP_VER_PATCH 1 +#define APP_VER_MINOR 99 +#define APP_VER_PATCH 0 #ifdef _MSC_VER # if (_MSC_VER >= 1920) From 3d7598b28dd0fdb25279528452fc7f525b232d7d Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 20 Jul 2019 05:57:58 +0700 Subject: [PATCH 55/65] Updated default config example. --- src/config.json | 28 +++++++++------------------- src/core/config/Config_default.h | 28 +++++++++------------------- 2 files changed, 18 insertions(+), 38 deletions(-) diff --git a/src/config.json b/src/config.json index 53df5486..c5ae0676 100644 --- a/src/config.json +++ b/src/config.json @@ -1,9 +1,14 @@ { - "algo": "cryptonight", "api": { "id": null, "worker-id": null }, + "autosave": true, + "background": false, + "colors": true, + "cpu": null, + "donate-level": 5, + "donate-over-proxy": 1, "http": { "enabled": false, "host": "127.0.0.1", @@ -11,41 +16,26 @@ "access-token": null, "restricted": true }, - "asm": true, - "autosave": true, - "av": 0, - "background": false, - "colors": true, - "cpu-affinity": null, - "cpu-priority": null, - "donate-level": 5, - "donate-over-proxy": 1, - "huge-pages": true, - "hw-aes": null, "log-file": null, - "max-cpu-usage": 100, "pools": [ { + "algo": null, "url": "donate.v2.xmrig.com:3333", "user": "YOUR_WALLET_ADDRESS", "pass": "x", "rig-id": null, "nicehash": false, "keepalive": false, - "variant": -1, "enabled": true, "tls": false, "tls-fingerprint": null, - "daemon": false, - "daemon-poll-interval": 1000 + "daemon": false } ], "print-time": 60, "retries": 5, "retry-pause": 5, - "safe": false, - "threads": null, - "user-agent": null, "syslog": false, + "user-agent": null, "watch": true } \ No newline at end of file diff --git a/src/core/config/Config_default.h b/src/core/config/Config_default.h index d6145cf4..2ca0bda5 100644 --- a/src/core/config/Config_default.h +++ b/src/core/config/Config_default.h @@ -33,11 +33,16 @@ namespace xmrig { const static char *default_config = R"===( { - "algo": "cryptonight", "api": { "id": null, "worker-id": null }, + "autosave": true, + "background": false, + "colors": true, + "cpu": null, + "donate-level": 5, + "donate-over-proxy": 1, "http": { "enabled": false, "host": "127.0.0.1", @@ -45,42 +50,27 @@ R"===( "access-token": null, "restricted": true }, - "asm": true, - "autosave": true, - "av": 0, - "background": false, - "colors": true, - "cpu-affinity": null, - "cpu-priority": null, - "donate-level": 5, - "donate-over-proxy": 1, - "huge-pages": true, - "hw-aes": null, "log-file": null, - "max-cpu-usage": 100, "pools": [ { + "algo": null, "url": "donate.v2.xmrig.com:3333", "user": "YOUR_WALLET_ADDRESS", "pass": "x", "rig-id": null, "nicehash": false, "keepalive": false, - "variant": -1, "enabled": true, "tls": false, "tls-fingerprint": null, - "daemon": false, - "daemon-poll-interval": 1000 + "daemon": false } ], "print-time": 60, "retries": 5, "retry-pause": 5, - "safe": false, - "threads": null, - "user-agent": null, "syslog": false, + "user-agent": null, "watch": true } )==="; From e2a5bfa0b40b0aca09f41ddd052c3c3ffdc0950f Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 20 Jul 2019 16:20:11 +0700 Subject: [PATCH 56/65] Better default config. --- src/config.json | 10 +++++++++- src/core/config/Config_default.h | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/config.json b/src/config.json index c5ae0676..57b2984b 100644 --- a/src/config.json +++ b/src/config.json @@ -6,7 +6,15 @@ "autosave": true, "background": false, "colors": true, - "cpu": null, + "cpu": { + "enabled": true, + "huge-pages": true, + "hw-aes": null, + "priority": null, + "asm": true, + "cn/0": false, + "cn-lite/0": false + }, "donate-level": 5, "donate-over-proxy": 1, "http": { diff --git a/src/core/config/Config_default.h b/src/core/config/Config_default.h index 2ca0bda5..06c29566 100644 --- a/src/core/config/Config_default.h +++ b/src/core/config/Config_default.h @@ -40,7 +40,15 @@ R"===( "autosave": true, "background": false, "colors": true, - "cpu": null, + "cpu": { + "enabled": true, + "huge-pages": true, + "hw-aes": null, + "priority": null, + "asm": true, + "cn/0": false, + "cn-lite/0": false + }, "donate-level": 5, "donate-over-proxy": 1, "http": { From c4388fa74c0e33bb2e0e069f0ceeee42411ba6ab Mon Sep 17 00:00:00 2001 From: xmrig Date: Sat, 20 Jul 2019 20:14:34 +0700 Subject: [PATCH 57/65] Update ALGORITHMS.md --- doc/ALGORITHMS.md | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/doc/ALGORITHMS.md b/doc/ALGORITHMS.md index 835a1d49..cc112e5c 100644 --- a/doc/ALGORITHMS.md +++ b/doc/ALGORITHMS.md @@ -1,22 +1,14 @@ # Algorithms -XMRig uses a different way to specify algorithms, compared to other miners. - -Algorithm selection splitted to 2 parts: - - * Global base algorithm per miner or proxy instance, `algo` option. Possible values: `cryptonight`, `cryptonight-lite`, `cryptonight-heavy`. - * Algorithm variant specified separately for each pool, `variant` option. - * [Full table for supported algorithm and variants.](https://github.com/xmrig/xmrig-proxy/blob/master/doc/STRATUM_EXT.md#14-algorithm-names-and-variants) +Since version 3 mining algorithm should specified for each pool separately (`algo` option), earlier versions was use one global `algo` option and per pool `variant` option (this option was removed in v3). If your pool support [mining algorithm negotiation](https://github.com/xmrig/xmrig-proxy/issues/168) you may not specify this option at all. #### Example ```json { - "algo": "cryptonight", - ... "pools": [ { "url": "...", - "variant": 1, + "algo": "cn/r", ... } ], @@ -24,8 +16,7 @@ Algorithm selection splitted to 2 parts: } ``` -## Mining algorithm negotiation -If your pool support [mining algorithm negotiation](https://github.com/xmrig/xmrig-proxy/issues/168) miner will choice proper variant automaticaly and if you choice wrong base algorithm you will see error message. +#### Pools with mining algorithm negotiation support. -Pools with mining algorithm negotiation support. * [www.hashvault.pro](https://www.hashvault.pro/) + * [moneroocean.stream](https://moneroocean.stream) From 484253bf68ecddba6f82796b163469dbca31b7c3 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 20 Jul 2019 20:57:37 +0700 Subject: [PATCH 58/65] Updated algorithms descriptions. --- doc/ALGORITHMS.md | 27 +++++++++++++++++++++++++++ src/crypto/common/Algorithm.h | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/doc/ALGORITHMS.md b/doc/ALGORITHMS.md index cc112e5c..9272ae81 100644 --- a/doc/ALGORITHMS.md +++ b/doc/ALGORITHMS.md @@ -20,3 +20,30 @@ Since version 3 mining algorithm should specified for each pool separately (`alg * [www.hashvault.pro](https://www.hashvault.pro/) * [moneroocean.stream](https://moneroocean.stream) + + ## Algorithm names + +| Name | Memory | Notes | +|-----------------|--------|--------------------------------------------------------------------------------------| +| `cn/0` | 2 MB | CryptoNight (original) | +| `cn/1` | 2 MB | CryptoNight variant 1 also known as `Monero7` and `CryptoNightV7`. | +| `cn/2` | 2 MB | CryptoNight variant 2. | +| `cn/r` | 2 MB | CryptoNightR (Monero's variant 4). | +| `cn/wow` | 2 MB | CryptoNightR (Wownero). | +| `cn/fast` | 2 MB | CryptoNight variant 1 with half iterations. | +| `cn/half` | 2 MB | CryptoNight variant 2 with half iterations (Masari/Torque) | +| `cn/xao` | 2 MB | CryptoNight variant 0 (modified, Alloy only) | +| `cn/rto` | 2 MB | CryptoNight variant 1 (modified, Arto only) | +| `cn/rwz` | 2 MB | CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation (Graft). | +| `cn/zls` | 2 MB | CryptoNight variant 2 with 3/4 iterations (Zelerius). | +| `cn/double` | 2 MB | CryptoNight variant 2 with double iterations (X-CASH). | +| `cn/gpu` | 2 MB | CryptoNight-GPU (RYO). | +| `cn-lite/0` | 1 MB | CryptoNight-Lite variant 0. | +| `cn-lite/1` | 1 MB | CryptoNight-Lite variant 1. | +| `cn-heavy/0` | 4 MB | CryptoNight-Heavy . | +| `cn-heavy/xhv` | 4 MB | CryptoNight-Heavy (modified, TUBE only). | +| `cn-heavy/tube` | 4 MB | CryptoNight-Heavy (modified, Haven Protocol only). | +| `cn-pico` | 256 KB | TurtleCoin (TRTL) | +| `rx/0` | 2 MB | RandomX (reference configuration), reserved for future use. | +| `rx/wow` | 1 MB | RandomWOW (Wownero). | +| `rx/loki` | 2 MB | RandomXL (Loki). | \ No newline at end of file diff --git a/src/crypto/common/Algorithm.h b/src/crypto/common/Algorithm.h index a1d8ded2..3c44ec56 100644 --- a/src/crypto/common/Algorithm.h +++ b/src/crypto/common/Algorithm.h @@ -41,7 +41,7 @@ class Algorithm public: enum Id : int { INVALID = -1, - CN_0, // "cn/0" Original CryptoNight + CN_0, // "cn/0" CryptoNight (original) CN_1, // "cn/1" CryptoNight variant 1 also known as Monero7 and CryptoNightV7 CN_2, // "cn/2" CryptoNight variant 2 CN_R, // "cn/r" CryptoNightR (Monero's variant 4) From d1705a7f74621349737cf4a32a5041f545601afc Mon Sep 17 00:00:00 2001 From: xmrig Date: Sat, 20 Jul 2019 20:59:42 +0700 Subject: [PATCH 59/65] Update ALGORITHMS.md --- doc/ALGORITHMS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ALGORITHMS.md b/doc/ALGORITHMS.md index 9272ae81..07f92271 100644 --- a/doc/ALGORITHMS.md +++ b/doc/ALGORITHMS.md @@ -1,6 +1,6 @@ # Algorithms -Since version 3 mining algorithm should specified for each pool separately (`algo` option), earlier versions was use one global `algo` option and per pool `variant` option (this option was removed in v3). If your pool support [mining algorithm negotiation](https://github.com/xmrig/xmrig-proxy/issues/168) you may not specify this option at all. +Since version 3 mining [algorithm](#algorithm-names) should specified for each pool separately (`algo` option), earlier versions was use one global `algo` option and per pool `variant` option (this option was removed in v3). If your pool support [mining algorithm negotiation](https://github.com/xmrig/xmrig-proxy/issues/168) you may not specify this option at all. #### Example ```json @@ -46,4 +46,4 @@ Since version 3 mining algorithm should specified for each pool separately (`alg | `cn-pico` | 256 KB | TurtleCoin (TRTL) | | `rx/0` | 2 MB | RandomX (reference configuration), reserved for future use. | | `rx/wow` | 1 MB | RandomWOW (Wownero). | -| `rx/loki` | 2 MB | RandomXL (Loki). | \ No newline at end of file +| `rx/loki` | 2 MB | RandomXL (Loki). | From 83f0f2bcadc7f52e4cce6a70b6c8b2cf541b0564 Mon Sep 17 00:00:00 2001 From: xmrig Date: Sat, 20 Jul 2019 23:16:23 +0700 Subject: [PATCH 60/65] Create CPU.md --- doc/CPU.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 doc/CPU.md diff --git a/doc/CPU.md b/doc/CPU.md new file mode 100644 index 00000000..7dd7a00b --- /dev/null +++ b/doc/CPU.md @@ -0,0 +1,56 @@ +# CPU backend + +All CPU related settings contains in one `cpu` object in config file, CPU backend allow specify multiple profiles and allow switch between them without restrictions. Default auto-configuration create reasonable minimum of profiles which cover all supported algorithms. + +### Example + +Example below demonstrate all primary ideas of flexible profiles configuration: + +* `"rx/wow"` Exact match to algorithm `rx/wow`, defined 4 threads without CPU affinity. +* `"cn"` Default failback profile for all `cn/*` algorithms, defined 2 threads with CPU affinity, another failback profiles is `cn-lite`, `cn-heavy` and `rx`. +* `"cn-lite"` Default failback profile for all `cn-lite/*` algorithms, defined 2 double threads with CPU affinity. +* `"custom-profile"` Custom user defined profile. +* `"*"` Failback profile for all unhandled by other profiles algorithms. +* `"cn/r"` Exact match, alias to profile `custom-profile`. +* `"cn/0"` Exact match, disabled algorithm. + +```json +{ + "cpu": { + "enabled": true, + "huge-pages": true, + "hw-aes": null, + "priority": null, + "asm": true, + "rx/wow": [ + -1, + -1, + -1, + -1, + ], + "cn": [ + 0, + 2 + ], + "cn-lite": [ + { + "intensity": 2, + "affinity": 0 + }, + { + "intensity": 2, + "affinity": 2 + } + ], + "custom-profile": [ + 0, + 2, + ], + "*": [ + -1 + ], + "cn/r": "custom-profile", + "cn/0": false + } +} +``` From 7119e4c64cc1ab3dca646aa6eeadf5097790f22d Mon Sep 17 00:00:00 2001 From: xmrig Date: Sat, 20 Jul 2019 23:23:13 +0700 Subject: [PATCH 61/65] Update CPU.md --- doc/CPU.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/CPU.md b/doc/CPU.md index 7dd7a00b..ba662d2c 100644 --- a/doc/CPU.md +++ b/doc/CPU.md @@ -54,3 +54,7 @@ Example below demonstrate all primary ideas of flexible profiles configuration: } } ``` + +### Intensity +This option was known as `low_power_mode`, possible values is range from 1 to 5, for convinient if value 1 used, possible omit this option and specify CPU thread config by only one number: CPU affinity, instead of object. + From c7ba4f8f2fc24391549dc42058909a87c90be2c7 Mon Sep 17 00:00:00 2001 From: xmrig Date: Sat, 20 Jul 2019 23:33:04 +0700 Subject: [PATCH 62/65] Update CPU.md --- doc/CPU.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CPU.md b/doc/CPU.md index ba662d2c..82c0a752 100644 --- a/doc/CPU.md +++ b/doc/CPU.md @@ -1,6 +1,6 @@ # CPU backend -All CPU related settings contains in one `cpu` object in config file, CPU backend allow specify multiple profiles and allow switch between them without restrictions. Default auto-configuration create reasonable minimum of profiles which cover all supported algorithms. +All CPU related settings contains in one `cpu` object in config file, CPU backend allow specify multiple profiles and allow switch between them without restrictions by pool request or config change. Default auto-configuration create reasonable minimum of profiles which cover all supported algorithms. ### Example From 162c3f3d325eef8027d2cd2f67b799fe491491d4 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sun, 21 Jul 2019 00:08:13 +0700 Subject: [PATCH 63/65] Only intensity=1 allowed for RandomX. --- src/backend/cpu/CpuWorker.cpp | 2 +- src/crypto/common/Algorithm.h | 42 +++++++++++++++++------------------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp index 14ffaa73..8eb4cdb1 100644 --- a/src/backend/cpu/CpuWorker.cpp +++ b/src/backend/cpu/CpuWorker.cpp @@ -94,7 +94,7 @@ bool xmrig::CpuWorker::selfTest() { # ifdef XMRIG_ALGO_RANDOMX if (m_algorithm.family() == Algorithm::RANDOM_X) { - return true; + return N == 1; } # endif diff --git a/src/crypto/common/Algorithm.h b/src/crypto/common/Algorithm.h index 3c44ec56..b30a946b 100644 --- a/src/crypto/common/Algorithm.h +++ b/src/crypto/common/Algorithm.h @@ -41,37 +41,37 @@ class Algorithm public: enum Id : int { INVALID = -1, - CN_0, // "cn/0" CryptoNight (original) - CN_1, // "cn/1" CryptoNight variant 1 also known as Monero7 and CryptoNightV7 - CN_2, // "cn/2" CryptoNight variant 2 - CN_R, // "cn/r" CryptoNightR (Monero's variant 4) - CN_WOW, // "cn/wow" CryptoNightR (Wownero) - CN_FAST, // "cn/fast" CryptoNight variant 1 with half iterations - CN_HALF, // "cn/half" CryptoNight variant 2 with half iterations (Masari/Stellite) - CN_XAO, // "cn/xao" Modified CryptoNight variant 0 (Alloy only) - CN_RTO, // "cn/rto" Modified CryptoNight variant 1 (Arto only) - CN_RWZ, // "cn/rwz" CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation (Graft) - CN_ZLS, // "cn/zls" CryptoNight variant 2 with 3/4 iterations (Zelerius) - CN_DOUBLE, // "cn/double" CryptoNight variant 2 with double iterations (X-CASH) + CN_0, // "cn/0" CryptoNight (original). + CN_1, // "cn/1" CryptoNight variant 1 also known as Monero7 and CryptoNightV7. + CN_2, // "cn/2" CryptoNight variant 2. + CN_R, // "cn/r" CryptoNightR (Monero's variant 4). + CN_WOW, // "cn/wow" CryptoNightR (Wownero). + CN_FAST, // "cn/fast" CryptoNight variant 1 with half iterations. + CN_HALF, // "cn/half" CryptoNight variant 2 with half iterations (Masari/Torque). + CN_XAO, // "cn/xao" CryptoNight variant 0 (modified, Alloy only). + CN_RTO, // "cn/rto" CryptoNight variant 1 (modified, Arto only). + CN_RWZ, // "cn/rwz" CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation (Graft). + CN_ZLS, // "cn/zls" CryptoNight variant 2 with 3/4 iterations (Zelerius). + CN_DOUBLE, // "cn/double" CryptoNight variant 2 with double iterations (X-CASH). # ifdef XMRIG_ALGO_CN_GPU - CN_GPU, // "cn/gpu" CryptoNight-GPU (Ryo) + CN_GPU, // "cn/gpu" CryptoNight-GPU (Ryo). # endif # ifdef XMRIG_ALGO_CN_LITE - CN_LITE_0, // "cn-lite/0" CryptoNight-Lite (1 MB) variant 0 - CN_LITE_1, // "cn-lite/1" CryptoNight-Lite (1 MB) variant 1 + CN_LITE_0, // "cn-lite/0" CryptoNight-Lite variant 0. + CN_LITE_1, // "cn-lite/1" CryptoNight-Lite variant 1. # endif # ifdef XMRIG_ALGO_CN_HEAVY - CN_HEAVY_0, // "cn-heavy/0" CryptoNight-Heavy (4 MB) - CN_HEAVY_TUBE, // "cn-heavy/tube" Modified CryptoNight-Heavy (TUBE only) - CN_HEAVY_XHV, // "cn-heavy/xhv" Modified CryptoNight-Heavy (Haven Protocol only) + CN_HEAVY_0, // "cn-heavy/0" CryptoNight-Heavy (4 MB). + CN_HEAVY_TUBE, // "cn-heavy/tube" CryptoNight-Heavy (modified, TUBE only). + CN_HEAVY_XHV, // "cn-heavy/xhv" CryptoNight-Heavy (modified, Haven Protocol only). # endif # ifdef XMRIG_ALGO_CN_PICO CN_PICO_0, // "cn-pico" CryptoNight Turtle (TRTL) # endif # ifdef XMRIG_ALGO_RANDOMX - RX_0, // "rx/0" RandomX (reference configuration) - RX_WOW, // "rx/wow" RandomWOW (Wownero) - RX_LOKI, // "rx/loki" RandomXL (Loki) + RX_0, // "rx/0" RandomX (reference configuration). + RX_WOW, // "rx/wow" RandomWOW (Wownero). + RX_LOKI, // "rx/loki" RandomXL (Loki). # endif MAX }; From 9660dfc7b3eff98495e0b379f30e62d4ef824504 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sun, 21 Jul 2019 04:35:52 +0700 Subject: [PATCH 64/65] Workaround for unsupported intensity option + warning. --- src/backend/common/Threads.h | 2 +- src/backend/common/Workers.cpp | 82 +++++++++++++++++++++++----------- src/backend/common/Workers.h | 3 +- 3 files changed, 60 insertions(+), 27 deletions(-) diff --git a/src/backend/common/Threads.h b/src/backend/common/Threads.h index 126245f6..bc9e36fd 100644 --- a/src/backend/common/Threads.h +++ b/src/backend/common/Threads.h @@ -43,7 +43,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 || algo == Algorithm::RX_0; } + inline bool isDisabled(const Algorithm &algo) const { return m_disabled.count(algo) > 0; } inline bool isExist(const Algorithm &algo) const { return isDisabled(algo) || m_aliases.count(algo) > 0 || has(algo.shortName()); } inline const std::vector &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/Workers.cpp b/src/backend/common/Workers.cpp index d70546d3..6a369c1b 100644 --- a/src/backend/common/Workers.cpp +++ b/src/backend/common/Workers.cpp @@ -137,52 +137,84 @@ void xmrig::Workers::tick(uint64_t) template -void xmrig::Workers::onReady(void *) +xmrig::IWorker *xmrig::Workers::create(Thread *) { + return nullptr; +} + + +template +void xmrig::Workers::onReady(void *arg) +{ + Thread *handle = static_cast* >(arg); + + IWorker *worker = create(handle); + if (!worker || !worker->selfTest()) { + LOG_ERR("thread %zu error: \"hash self-test failed\".", worker->id()); + + return; + } + + handle->setWorker(worker); + handle->backend()->start(worker); } namespace xmrig { -template<> -void xmrig::Workers::onReady(void *arg) +#if defined (XMRIG_ALGO_RANDOMX) || defined (XMRIG_ALGO_CN_GPU) +static void printIntensityWarning(Thread *handle) { - auto handle = static_cast* >(arg); + LOG_WARN("CPU thread %zu warning: \"intensity %d not supported for %s algorithm\".", handle->index(), handle->config().intensity, handle->config().algorithm.shortName()); +} +#endif - IWorker *worker = nullptr; - switch (handle->config().intensity) { +template<> +xmrig::IWorker *xmrig::Workers::create(Thread *handle) +{ + const int intensity = handle->config().intensity; + +# if defined (XMRIG_ALGO_RANDOMX) || defined (XMRIG_ALGO_CN_GPU) + if (intensity > 1) { +# ifdef XMRIG_ALGO_RANDOMX + if (handle->config().algorithm.family() == Algorithm::RANDOM_X) { + printIntensityWarning(handle); + + return new CpuWorker<1>(handle->index(), handle->config()); + } +# endif + +# ifdef XMRIG_ALGO_CN_GPU + if (handle->config().algorithm == Algorithm::CN_GPU) { + printIntensityWarning(handle); + + return new CpuWorker<1>(handle->index(), handle->config()); + } +# endif + } +# endif + + + switch (intensity) { case 1: - worker = new CpuWorker<1>(handle->index(), handle->config()); - break; + return new CpuWorker<1>(handle->index(), handle->config()); case 2: - worker = new CpuWorker<2>(handle->index(), handle->config()); - break; + return new CpuWorker<2>(handle->index(), handle->config()); case 3: - worker = new CpuWorker<3>(handle->index(), handle->config()); - break; + return new CpuWorker<3>(handle->index(), handle->config()); case 4: - worker = new CpuWorker<4>(handle->index(), handle->config()); - break; + return new CpuWorker<4>(handle->index(), handle->config()); case 5: - worker = new CpuWorker<5>(handle->index(), handle->config()); - break; + return new CpuWorker<5>(handle->index(), handle->config()); } - handle->setWorker(worker); - - if (!worker->selfTest()) { - LOG_ERR("thread %zu error: \"hash self-test failed\".", handle->worker()->id()); - - return; - } - - handle->backend()->start(worker); + return nullptr; } diff --git a/src/backend/common/Workers.h b/src/backend/common/Workers.h index 32d9458a..77dd434c 100644 --- a/src/backend/common/Workers.h +++ b/src/backend/common/Workers.h @@ -52,6 +52,7 @@ public: void tick(uint64_t ticks); private: + static IWorker *create(Thread *handle); static void onReady(void *arg); std::vector *> m_workers; @@ -60,7 +61,7 @@ private: template<> -void Workers::onReady(void *arg); +IWorker *Workers::create(Thread *handle); extern template class Workers; From 2d719a28c467ee71e67732fc9f457962f78129cd Mon Sep 17 00:00:00 2001 From: xmrig Date: Sun, 21 Jul 2019 23:57:07 +0700 Subject: [PATCH 65/65] Update CHANGELOG.md --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25fc9ad2..4f6778ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# v2.99.0-beta +- [#1050](https://github.com/xmrig/xmrig/pull/1050) Added RandomXL algorithm for [Loki](https://loki.network/), algorithm name used by miner is `randomx/loki` or `rx/loki`. +- Added [flexible](https://github.com/xmrig/xmrig/blob/evo/doc/CPU.md) multi algorithm configuration. +- Added unlimited switching between incompatible algorithms, all mining options can be changed in runtime. +- Breaked backward compatibility with previous configs and command line, `variant` option replaced to `algo`, global option `algo` removed, all CPU related settings moved to `cpu` object. +- Options `av`, `safe` and `max-cpu-usage` removed. +- Algorithm `cn/msr` renamed to `cn/fast`. +- Algorithm `cn/xtl` removed. +- API endpoint `GET /1/threads` replaced to `GET /2/backends`. + # v2.16.0-beta - [#1036](https://github.com/xmrig/xmrig/pull/1036) Added RandomWOW (RandomX with different preferences) algorithm support for [Wownero](http://wownero.org/). - Algorithm name used by miner is `randomx/wow` or `rx/wow`.