diff --git a/CMakeLists.txt b/CMakeLists.txt index e263808e..90c7d842 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ set(HEADERS src/net/strategies/DonateStrategy.h src/Summary.h src/version.h + src/workers/Benchmark.h src/workers/CpuThread.h src/workers/Handle.h src/workers/Hashrate.h @@ -110,6 +111,7 @@ set(SOURCES src/net/Network.cpp src/net/strategies/DonateStrategy.cpp src/Summary.cpp + src/workers/Benchmark.cpp src/workers/CpuThread.cpp src/workers/Handle.cpp src/workers/Hashrate.cpp diff --git a/src/App.cpp b/src/App.cpp index adcc5752..c2e5ba9c 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -40,6 +41,7 @@ #include "Summary.h" #include "version.h" #include "workers/Workers.h" +#include "workers/Benchmark.h" #ifndef XMRIG_NO_HTTPD @@ -84,6 +86,8 @@ App::~App() # endif } +// this should be global since we register onJobResult using this object method +static Benchmark benchmark; int App::exec() { @@ -125,7 +129,16 @@ int App::exec() Workers::start(m_controller); - m_controller->network()->connect(); + // run benchmark before pool mining or not? + if (m_controller->config()->isCalibrateAlgo()) { + benchmark.set_controller(m_controller); // we need controller there to access config and network objects + Workers::setListener(&benchmark); // register benchmark as job reault listener to compute hashrates there + benchmark.start_perf_bench(xmrig::PerfAlgo::PA_CN); // start benchmarking from first PerfAlgo in the list + } else { + // save config here to have option to store automatically generated "threads" + if (m_controller->config()->isSaveConfig()) m_controller->config()->save(); + m_controller->network()->connect(); + } const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); uv_loop_close(uv_default_loop()); diff --git a/src/common/config/CommonConfig.cpp b/src/common/config/CommonConfig.cpp index 7e43b39d..c9cbc971 100644 --- a/src/common/config/CommonConfig.cpp +++ b/src/common/config/CommonConfig.cpp @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -183,6 +184,14 @@ bool xmrig::CommonConfig::parseBoolean(int key, bool enable) m_dryRun = enable; break; + case IConfig::CalibrateAlgoKey: /* --calibrate-algo */ + m_calibrateAlgo = enable; + break; + + case IConfig::SaveConfigKey: /* --save-config */ + m_saveConfig = enable; + break; + default: break; } @@ -267,6 +276,8 @@ bool xmrig::CommonConfig::parseString(int key, const char *arg) case NicehashKey: /* --nicehash */ case ApiIPv6Key: /* --api-ipv6 */ case DryRunKey: /* --dry-run */ + case CalibrateAlgoKey: /* --calibrate-algo */ + case SaveConfigKey: /* --save-config */ return parseBoolean(key, true); case ColorKey: /* --no-color */ diff --git a/src/common/config/CommonConfig.h b/src/common/config/CommonConfig.h index ffebb6b2..17bab1d8 100644 --- a/src/common/config/CommonConfig.h +++ b/src/common/config/CommonConfig.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -48,6 +49,8 @@ public: inline bool isBackground() const { return m_background; } inline bool isColors() const { return m_colors; } inline bool isDryRun() const { return m_dryRun; } + inline bool isCalibrateAlgo() const { return m_calibrateAlgo; } + inline bool isSaveConfig() const { return m_saveConfig; } inline bool isSyslog() const { return m_syslog; } inline const char *apiToken() const { return m_apiToken.data(); } inline const char *apiWorkerId() const { return m_apiWorkerId.data(); } @@ -87,6 +90,8 @@ protected: bool m_background; bool m_colors; bool m_dryRun; + bool m_calibrateAlgo; + bool m_saveConfig; bool m_syslog; bool m_watch; int m_apiPort; diff --git a/src/common/crypto/Algorithm.cpp b/src/common/crypto/Algorithm.cpp index 31035fb1..c253d9c8 100644 --- a/src/common/crypto/Algorithm.cpp +++ b/src/common/crypto/Algorithm.cpp @@ -7,6 +7,7 @@ * Copyright 2017-2018 XMR-Stak , * Copyright 2018 Lee Clagett * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -223,3 +224,51 @@ const char *xmrig::Algorithm::name(bool shortName) const return "invalid"; } + + +// returns string name of the PerfAlgo +const char *xmrig::Algorithm::perfAlgoName(const xmrig::PerfAlgo pa) { + static const char* perf_algo_names[xmrig::PerfAlgo::PA_MAX] = { + "cn", + "cn-fast", + "cn-lite", + "cn-heavy", + }; + return perf_algo_names[pa]; +} + +// constructs Algorithm from PerfAlgo +xmrig::Algorithm::Algorithm(const xmrig::PerfAlgo pa) { + switch (pa) { + case PA_CN: + m_algo = xmrig::CRYPTONIGHT; + m_variant = xmrig::VARIANT_1; + break; + case PA_CN_FAST: + m_algo = xmrig::CRYPTONIGHT; + m_variant = xmrig::VARIANT_MSR; + break; + case PA_CN_LITE: + m_algo = xmrig::CRYPTONIGHT_LITE; + m_variant = xmrig::VARIANT_1; + break; + case PA_CN_HEAVY: + m_algo = xmrig::CRYPTONIGHT_HEAVY; + m_variant = xmrig::VARIANT_0; + break; + default: + m_algo = xmrig::INVALID_ALGO; + m_variant = xmrig::VARIANT_AUTO; + } +} + +// returns PerfAlgo that corresponds to current Algorithm +xmrig::PerfAlgo xmrig::Algorithm::perf_algo() const { + if (m_variant == VARIANT_MSR) return PA_CN_FAST; + switch (m_algo) { + case CRYPTONIGHT: return PA_CN; + case CRYPTONIGHT_LITE: return PA_CN_LITE; + case CRYPTONIGHT_HEAVY: return PA_CN_HEAVY; + default: return PA_INVALID; + } +} diff --git a/src/common/crypto/Algorithm.h b/src/common/crypto/Algorithm.h index bcf029d8..77e2dfff 100644 --- a/src/common/crypto/Algorithm.h +++ b/src/common/crypto/Algorithm.h @@ -7,6 +7,7 @@ * Copyright 2017-2018 XMR-Stak , * Copyright 2018 Lee Clagett * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -49,6 +50,9 @@ public: setAlgo(algo); } + // constructs Algorithm from PerfAlgo + Algorithm(const xmrig::PerfAlgo); + inline Algorithm(const char *algo) { parseAlgorithm(algo); @@ -56,8 +60,10 @@ public: bool isEqual(const Algorithm &other) const { return m_algo == other.m_algo && m_variant == other.m_variant; } inline Algo algo() const { return m_algo; } + xmrig::PerfAlgo perf_algo() const; // returns PerfAlgo that corresponds to current Algorithm inline const char *name() const { return name(false); } inline const char *shortName() const { return name(true); } + static const char *perfAlgoName(xmrig::PerfAlgo); // returns string name of the PerfAlgo inline Variant variant() const { return m_variant; } inline void setVariant(Variant variant) { m_variant = variant; } diff --git a/src/common/interfaces/IConfig.h b/src/common/interfaces/IConfig.h index 62c7ba94..cd24ac90 100644 --- a/src/common/interfaces/IConfig.h +++ b/src/common/interfaces/IConfig.h @@ -5,6 +5,7 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2016-2018 XMRig + * Copyright 2018 MoneroOcean , * * 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 @@ -67,6 +68,8 @@ public: CPUPriorityKey = 1021, NicehashKey = 1006, PrintTimeKey = 1007, + CalibrateAlgoKey = 10001, + SaveConfigKey = 10002, // xmrig cpu AVKey = 'v', diff --git a/src/common/net/Client.cpp b/src/common/net/Client.cpp index f4553d97..8ca39775 100644 --- a/src/common/net/Client.cpp +++ b/src/common/net/Client.cpp @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -33,6 +34,8 @@ #include "common/log/Log.h" #include "common/net/Client.h" #include "net/JobResult.h" +#include "core/Config.h" // for pconfig to access pconfig->get_algo_perf +#include "workers/Workers.h" // to do Workers::switch_algo #include "rapidjson/document.h" #include "rapidjson/error/en.h" #include "rapidjson/stringbuffer.h" @@ -269,10 +272,6 @@ bool Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } - if (params.HasMember("algo")) { - job.algorithm().parseAlgorithm(params["algo"].GetString()); - } - if (params.HasMember("variant")) { const rapidjson::Value &variant = params["variant"]; @@ -284,6 +283,11 @@ bool Client::parseJob(const rapidjson::Value ¶ms, int *code) } } + // moved algo after variant parsing to override variant that is considered to be outdated now + if (params.HasMember("algo")) { + job.algorithm().parseAlgorithm(params["algo"].GetString()); + } + if (!verifyAlgorithm(job.algorithm())) { *code = 6; @@ -291,6 +295,9 @@ bool Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } + // retarget workers for possible new Algo profile (same algo profile is not reapplied) + Workers::switch_algo(job.algorithm()); + if (m_job != job) { m_jobs++; m_job = std::move(job); @@ -495,6 +502,16 @@ void Client::login() } params.AddMember("algo", algo, allocator); + + // addding algo-perf based on pconfig->get_algo_perf + Value algo_perf(kObjectType); + for (int a = 0; a != xmrig::PerfAlgo::PA_MAX; ++ a) { + const xmrig::PerfAlgo pa = static_cast(a); + Value key(xmrig::Algorithm::perfAlgoName(pa), allocator); + algo_perf.AddMember(key, Value(xmrig::pconfig->get_algo_perf(pa)), allocator); + } + + params.AddMember("algo-perf", algo_perf, allocator); } doc.AddMember("params", params, allocator); diff --git a/src/common/net/Client.h b/src/common/net/Client.h index 4be8badb..f98efe1f 100644 --- a/src/common/net/Client.h +++ b/src/common/net/Client.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -74,7 +75,6 @@ public: inline int id() const { return m_id; } inline SocketState state() const { return m_state; } inline uint16_t port() const { return m_pool.port(); } - inline void setAlgo(const xmrig::Algorithm &algo) { m_pool.setAlgo(algo); } inline void setQuiet(bool quiet) { m_quiet = quiet; } inline void setRetries(int retries) { m_retries = retries; } inline void setRetryPause(int ms) { m_retryPause = ms; } diff --git a/src/common/net/Job.cpp b/src/common/net/Job.cpp index 80b521ea..2e7204fb 100644 --- a/src/common/net/Job.cpp +++ b/src/common/net/Job.cpp @@ -7,6 +7,7 @@ * Copyright 2017-2018 XMR-Stak , * Copyright 2018 Lee Clagett * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -120,6 +121,12 @@ bool Job::setBlob(const char *blob) return true; } +// for algo benchmarking +void Job::setRawBlob(const uint8_t *blob, const size_t size) +{ + memcpy(m_blob, blob, m_size = size); +} + bool Job::setTarget(const char *target) { diff --git a/src/common/net/Job.h b/src/common/net/Job.h index 049eb7d4..050bff48 100644 --- a/src/common/net/Job.h +++ b/src/common/net/Job.h @@ -7,6 +7,7 @@ * Copyright 2017-2018 XMR-Stak , * Copyright 2018 Lee Clagett * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -42,7 +43,10 @@ public: ~Job(); bool setBlob(const char *blob); + void setRawBlob(const uint8_t *blob, const size_t size); // for algo benchmarking bool setTarget(const char *target); + // for algo benchmarking to set PoW variant + void setAlgorithm(const xmrig::Algorithm& algorithm) { m_algorithm = algorithm; } xmrig::Variant variant() const; inline bool isNicehash() const { return m_nicehash; } diff --git a/src/common/net/Pool.cpp b/src/common/net/Pool.cpp index 053f2507..bfe42b51 100644 --- a/src/common/net/Pool.cpp +++ b/src/common/net/Pool.cpp @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -48,6 +49,20 @@ Pool::Pool() : m_keepAlive(0), m_port(kDefaultPort) { + // here xmrig now resuts all possible supported algorithms + m_algorithms.push_back(xmrig::Algorithm(xmrig::CRYPTONIGHT, xmrig::VARIANT_1)); + m_algorithms.push_back(xmrig::Algorithm(xmrig::CRYPTONIGHT, xmrig::VARIANT_0)); + m_algorithms.push_back(xmrig::Algorithm(xmrig::CRYPTONIGHT, xmrig::VARIANT_XTL)); + m_algorithms.push_back(xmrig::Algorithm(xmrig::CRYPTONIGHT, xmrig::VARIANT_MSR)); + m_algorithms.push_back(xmrig::Algorithm(xmrig::CRYPTONIGHT, xmrig::VARIANT_XAO)); + m_algorithms.push_back(xmrig::Algorithm(xmrig::CRYPTONIGHT, xmrig::VARIANT_RTO)); + + m_algorithms.push_back(xmrig::Algorithm(xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_1)); + m_algorithms.push_back(xmrig::Algorithm(xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_0)); + + m_algorithms.push_back(xmrig::Algorithm(xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_0)); + m_algorithms.push_back(xmrig::Algorithm(xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_XHV)); + m_algorithms.push_back(xmrig::Algorithm(xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_TUBE)); } @@ -233,19 +248,8 @@ void Pool::adjust(const xmrig::Algorithm &algorithm) m_algorithm.setAlgo(algorithm.algo()); adjustVariant(algorithm.variant()); } - - rebuild(); } - -void Pool::setAlgo(const xmrig::Algorithm &algorithm) -{ - m_algorithm = algorithm; - - rebuild(); -} - - #ifdef APP_DEBUG void Pool::print() const { @@ -284,18 +288,6 @@ bool Pool::parseIPv6(const char *addr) return true; } - -void 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 Pool::adjustVariant(const xmrig::Variant variantHint) { # ifndef XMRIG_PROXY_PROJECT @@ -364,27 +356,3 @@ void Pool::adjustVariant(const xmrig::Variant variantHint) } # endif } - - -void Pool::rebuild() -{ - m_algorithms.clear(); - - if (!m_algorithm.isValid()) { - return; - } - - m_algorithms.push_back(m_algorithm); - -# ifndef XMRIG_PROXY_PROJECT - addVariant(xmrig::VARIANT_1); - addVariant(xmrig::VARIANT_0); - addVariant(xmrig::VARIANT_XTL); - addVariant(xmrig::VARIANT_TUBE); - addVariant(xmrig::VARIANT_MSR); - addVariant(xmrig::VARIANT_XHV); - addVariant(xmrig::VARIANT_XAO); - addVariant(xmrig::VARIANT_RTO); - addVariant(xmrig::VARIANT_AUTO); -# endif -} diff --git a/src/common/net/Pool.h b/src/common/net/Pool.h index 57a30d1e..04a26818 100644 --- a/src/common/net/Pool.h +++ b/src/common/net/Pool.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -78,7 +79,6 @@ public: bool setUserpass(const char *userpass); rapidjson::Value toJSON(rapidjson::Document &doc) const; void adjust(const xmrig::Algorithm &algorithm); - void setAlgo(const xmrig::Algorithm &algorithm); # ifdef APP_DEBUG void print() const; @@ -86,9 +86,7 @@ public: private: bool parseIPv6(const char *addr); - void addVariant(xmrig::Variant variant); void adjustVariant(const xmrig::Variant variantHint); - void rebuild(); bool m_nicehash; int m_keepAlive; diff --git a/src/common/xmrig.h b/src/common/xmrig.h index 0ff945b9..515c6709 100644 --- a/src/common/xmrig.h +++ b/src/common/xmrig.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -36,6 +37,15 @@ enum Algo { CRYPTONIGHT_HEAVY /* CryptoNight-Heavy (SUMO) */ }; +// algorithms that can has different performance +enum PerfAlgo { + PA_INVALID = -1, + PA_CN, /* CryptoNight (Monero) */ + PA_CN_FAST, /* CryptoNight-Fast (Masari) */ + PA_CN_LITE, /* CryptoNight-Lite (AEON) */ + PA_CN_HEAVY, /* CryptoNight-Heavy (SUMO) */ + PA_MAX +}; //--av=1 For CPUs with hardware AES. //--av=2 Lower power mode (double hash) of 1. diff --git a/src/config.json b/src/config.json index b2dad4c9..b71a470b 100644 --- a/src/config.json +++ b/src/config.json @@ -33,6 +33,12 @@ "retry-pause": 5, "safe": false, "threads": null, + "algo-perf": { + "cn": 1000, + "cn-fast": 2000, + "cn-lite": 2000, + "cn-heavy": 700 + }, "user-agent": null, "watch": false } \ No newline at end of file diff --git a/src/core/Config.cpp b/src/core/Config.cpp index fa6afdb4..f37e2e0f 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -36,6 +37,10 @@ #include "rapidjson/prettywriter.h" #include "workers/CpuThread.h" +// for usage in Client::login to get_algo_perf +namespace xmrig { + Config* pconfig = nullptr; +}; static char affinity_tmp[20] = { 0 }; @@ -48,6 +53,11 @@ xmrig::Config::Config() : xmrig::CommonConfig(), m_maxCpuUsage(75), m_priority(-1) { + // not defined algo performance is considered to be 0 + for (int a = 0; a != xmrig::PerfAlgo::PA_MAX; ++ a) { + const xmrig::PerfAlgo pa = static_cast(a); + m_algo_perf[pa] = 0; + } } @@ -111,18 +121,34 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const doc.AddMember("retry-pause", retryPause(), allocator); doc.AddMember("safe", m_safe, allocator); - if (threadsMode() == Advanced) { - Value threads(kArrayType); + // save extended "threads" based on m_threads + Value threads(kObjectType); + for (int a = 0; a != xmrig::PerfAlgo::PA_MAX; ++ a) { + const xmrig::PerfAlgo pa = static_cast(a); + Value key(xmrig::Algorithm::perfAlgoName(pa), allocator); + if (threadsMode(pa) == Advanced) { + Value threads2(kArrayType); - for (const IThread *thread : m_threads.list) { - threads.PushBack(thread->toConfig(doc), allocator); + for (const IThread *thread : m_threads[pa].list) { + threads2.PushBack(thread->toConfig(doc), allocator); + } + + threads.AddMember(key, threads2, allocator); } + else { + threads.AddMember(key, threadsMode(pa) == Automatic ? Value(kNullType) : Value(threadsCount(pa)), allocator); + } + } + doc.AddMember("threads", threads, allocator); - doc.AddMember("threads", threads, allocator); - } - else { - doc.AddMember("threads", threadsMode() == Automatic ? Value(kNullType) : Value(threadsCount()), allocator); + // save "algo-perf" based on m_algo_perf + Value algo_perf(kObjectType); + for (int a = 0; a != xmrig::PerfAlgo::PA_MAX; ++ a) { + const xmrig::PerfAlgo pa = static_cast(a); + Value key(xmrig::Algorithm::perfAlgoName(pa), allocator); + algo_perf.AddMember(key, Value(m_algo_perf[pa]), allocator); } + doc.AddMember("algo-perf", algo_perf, allocator); doc.AddMember("user-agent", userAgent() ? Value(StringRef(userAgent())).Move() : Value(kNullType).Move(), allocator); @@ -150,34 +176,36 @@ bool xmrig::Config::finalize() return false; } - if (!m_threads.cpu.empty()) { - m_threads.mode = Advanced; - const bool softAES = (m_aesMode == AES_AUTO ? (Cpu::hasAES() ? AES_HW : AES_SOFT) : m_aesMode) == AES_SOFT; + // parse "threads" into m_threads + for (int a = 0; a != xmrig::PerfAlgo::PA_MAX; ++ a) { + const xmrig::PerfAlgo pa = static_cast(a); + if (!m_threads[pa].cpu.empty()) { + m_threads[pa].mode = Advanced; + const bool softAES = (m_aesMode == AES_AUTO ? (Cpu::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[pa].cpu.size(); ++i) { + m_threads[pa].list.push_back(CpuThread::createFromData(i, xmrig::Algorithm(pa).algo(), m_threads[pa].cpu[i], m_priority, softAES)); + } + } else { + const AlgoVariant av = getAlgoVariant(); + m_threads[pa].mode = m_threads[pa].count ? Simple : Automatic; + + const size_t size = CpuThread::multiway(av) * cn_select_memory(xmrig::Algorithm(pa).algo()) / 1024; + + if (!m_threads[pa].count) { + m_threads[pa].count = Cpu::optimalThreadsCount(size, m_maxCpuUsage); + } + else if (m_safe) { + const size_t count = Cpu::optimalThreadsCount(size, m_maxCpuUsage); + if (m_threads[pa].count > count) { + m_threads[pa].count = count; + } + } + + for (size_t i = 0; i < m_threads[pa].count; ++i) { + m_threads[pa].list.push_back(CpuThread::createFromAV(i, xmrig::Algorithm(pa).algo(), av, m_threads[pa].mask, m_priority)); + } } - - return true; - } - - 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; - - if (!m_threads.count) { - m_threads.count = Cpu::optimalThreadsCount(size, m_maxCpuUsage); - } - else if (m_safe) { - const size_t count = Cpu::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)); } return true; @@ -231,7 +259,7 @@ bool xmrig::Config::parseString(int key, const char *arg) case ThreadsKey: /* --threads */ if (strncmp(arg, "all", 3) == 0) { - m_threads.count = Cpu::threads(); + m_threads[m_algorithm.perf_algo()].count = Cpu::threads(); // sets default algo threads return true; } @@ -260,7 +288,7 @@ bool xmrig::Config::parseUint64(int key, uint64_t arg) switch (key) { case CPUAffinityKey: /* --cpu-affinity */ if (arg) { - m_threads.mask = arg; + m_threads[m_algorithm.perf_algo()].mask = arg; // sets default algo threads } break; @@ -272,22 +300,49 @@ bool xmrig::Config::parseUint64(int key, uint64_t arg) } +// parse specific perf algo (or generic) threads config +void xmrig::Config::parseThreadsJSON(const rapidjson::Value &threads, const xmrig::PerfAlgo pa) +{ + for (const rapidjson::Value &value : threads.GetArray()) { + if (!value.IsObject()) { + continue; + } + + if (value.HasMember("low_power_mode")) { + auto data = CpuThread::parse(value); + + if (data.valid) { + m_threads[pa].cpu.push_back(std::move(data)); + } + } + } +} + void xmrig::Config::parseJSON(const rapidjson::Document &doc) { const rapidjson::Value &threads = doc["threads"]; if (threads.IsArray()) { - for (const rapidjson::Value &value : threads.GetArray()) { - if (!value.IsObject()) { - continue; + // parse generic (old) threads + parseThreadsJSON(threads, m_algorithm.perf_algo()); + } else if (threads.IsObject()) { + // parse new specific perf algo threads + for (int a = 0; a != xmrig::PerfAlgo::PA_MAX; ++ a) { + const xmrig::PerfAlgo pa = static_cast(a); + const rapidjson::Value &threads2 = threads[xmrig::Algorithm::perfAlgoName(pa)]; + if (threads2.IsArray()) { + parseThreadsJSON(threads2, pa); } + } + } - if (value.HasMember("low_power_mode")) { - auto data = CpuThread::parse(value); - - if (data.valid) { - m_threads.cpu.push_back(std::move(data)); - } + const rapidjson::Value &algo_perf = doc["algo-perf"]; + if (algo_perf.IsObject()) { + for (int a = 0; a != xmrig::PerfAlgo::PA_MAX; ++ a) { + const xmrig::PerfAlgo pa = static_cast(a); + const rapidjson::Value &key = algo_perf[xmrig::Algorithm::perfAlgoName(pa)]; + if (key.IsDouble()) { + m_algo_perf[pa] = key.GetDouble(); } } } @@ -299,7 +354,7 @@ bool xmrig::Config::parseInt(int key, int arg) switch (key) { case ThreadsKey: /* --threads */ if (arg >= 0 && arg < 1024) { - m_threads.count = arg; + m_threads[m_algorithm.perf_algo()].count = arg; // sets default algo threads } break; diff --git a/src/core/Config.h b/src/core/Config.h index f0f1404f..0bf7488d 100644 --- a/src/core/Config.h +++ b/src/core/Config.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -78,11 +79,25 @@ public: inline AesMode aesMode() const { return m_aesMode; } inline AlgoVariant algoVariant() const { return m_algoVariant; } inline bool isHugePages() const { return m_hugePages; } - inline const std::vector &threads() const { return m_threads.list; } inline int priority() const { return m_priority; } - inline int threadsCount() const { return m_threads.list.size(); } - inline int64_t affinity() const { return m_threads.mask; } - inline ThreadsMode threadsMode() const { return m_threads.mode; } + + // access to m_threads taking into accoun that it is now separated for each perf algo + inline const std::vector &threads(const xmrig::PerfAlgo pa = PA_INVALID) const { + return m_threads[pa == PA_INVALID ? m_algorithm.perf_algo() : pa].list; + } + inline int threadsCount(const xmrig::PerfAlgo pa = PA_INVALID) const { + return m_threads[pa == PA_INVALID ? m_algorithm.perf_algo() : pa].list.size(); + } + inline int64_t affinity(const xmrig::PerfAlgo pa = PA_INVALID) const { + return m_threads[pa == PA_INVALID ? m_algorithm.perf_algo() : pa].mask; + } + inline ThreadsMode threadsMode(const xmrig::PerfAlgo pa = PA_INVALID) const { + return m_threads[pa == PA_INVALID ? m_algorithm.perf_algo() : pa].mode; + } + + // access to perf algo results + inline float get_algo_perf(const xmrig::PerfAlgo pa) const { return m_algo_perf[pa]; } + inline void set_algo_perf(const xmrig::PerfAlgo pa, const float value) { m_algo_perf[pa] = value; } static Config *load(int argc, char **argv, IWatcherListener *listener); @@ -92,6 +107,8 @@ protected: bool parseString(int key, const char *arg) override; bool parseUint64(int key, uint64_t arg) override; void parseJSON(const rapidjson::Document &doc) override; + // parse specific perf algo (or generic) threads config + void parseThreadsJSON(const rapidjson::Value &threads, xmrig::PerfAlgo); private: bool parseInt(int key, int arg); @@ -120,9 +137,14 @@ private: bool m_safe; int m_maxCpuUsage; int m_priority; - Threads m_threads; + // threads config for each perf algo + Threads m_threads[xmrig::PerfAlgo::PA_MAX]; + // perf algo hashrate results + float m_algo_perf[xmrig::PerfAlgo::PA_MAX]; }; +extern Config* pconfig; + } /* namespace xmrig */ diff --git a/src/core/ConfigLoader_platform.h b/src/core/ConfigLoader_platform.h index bc6657d1..05c4545a 100644 --- a/src/core/ConfigLoader_platform.h +++ b/src/core/ConfigLoader_platform.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * * This program is free software: you can redistribute it and/or modify @@ -54,6 +55,7 @@ Options:\n\ cryptonight-heavy\n" #endif "\ + --calibrate-algo run benchmarks before mining to measure hashrates of all supported algos\n\ -o, --url=URL URL of mining server\n\ -O, --userpass=U:P username:password pair for mining server\n\ -u, --user=USERNAME username for mining server\n\ @@ -88,6 +90,7 @@ Options:\n\ --api-worker-id=ID custom worker-id for API\n\ --api-ipv6 enable IPv6 support for API\n\ --api-no-restricted enable full remote access (only if API token set)\n\ + --save-config save config file including generated configuration\n\ -h, --help display this help and exit\n\ -V, --version output version information and exit\n\ "; @@ -110,6 +113,8 @@ static struct option const options[] = { { "cpu-priority", 1, nullptr, xmrig::IConfig::CPUPriorityKey }, { "donate-level", 1, nullptr, xmrig::IConfig::DonateLevelKey }, { "dry-run", 0, nullptr, xmrig::IConfig::DryRunKey }, + { "calibrate-algo", 0, nullptr, xmrig::IConfig::CalibrateAlgoKey }, + { "save-config", 0, nullptr, xmrig::IConfig::SaveConfigKey }, { "help", 0, nullptr, xmrig::IConfig::HelpKey }, { "keepalive", 0, nullptr, xmrig::IConfig::KeepAliveKey }, { "log-file", 1, nullptr, xmrig::IConfig::LogFileKey }, diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index ce73f037..a21c8ad9 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -96,7 +97,8 @@ int xmrig::Controller::init(int argc, char **argv) { Cpu::init(); - d_ptr->config = xmrig::Config::load(argc, argv, this); + // init pconfig global pointer to config + pconfig = d_ptr->config = xmrig::Config::load(argc, argv, this); if (!d_ptr->config) { return 1; } diff --git a/src/workers/Benchmark.cpp b/src/workers/Benchmark.cpp new file mode 100644 index 00000000..b2969f68 --- /dev/null +++ b/src/workers/Benchmark.cpp @@ -0,0 +1,92 @@ +/* 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 , + * Copyright 2018 MoneroOcean , + * + * 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 "workers/Benchmark.h" +#include "workers/Workers.h" +#include "core/Config.h" +#include "net/Network.h" +#include "common/log/Log.h" +#include + +// start performance measurements for specified perf algo +void Benchmark::start_perf_bench(const xmrig::PerfAlgo pa) { + m_pa = pa; // current perf algo + m_hash_count = 0; // number of hashes calculated for current perf algo + m_time_start = get_now(); // time of measurements start (in ms) + Workers::switch_algo(xmrig::Algorithm(pa)); // switch workers to new algo (Algo part) + + // prepare test job for benchmark runs + Job job; + job.setId(xmrig::Algorithm::perfAlgoName(pa)); // need to set different id so that workers will see job change + const static uint8_t test_input[76] = { + 0x99, // 0x99 here to trigger all future algo versions for auto veriant detection based on block version + 0x05, 0xA0, 0xDB, 0xD6, 0xBF, 0x05, 0xCF, 0x16, 0xE5, 0x03, 0xF3, 0xA6, 0x6F, 0x78, 0x00, + 0x7C, 0xBF, 0x34, 0x14, 0x43, 0x32, 0xEC, 0xBF, 0xC2, 0x2E, 0xD9, 0x5C, 0x87, 0x00, 0x38, 0x3B, + 0x30, 0x9A, 0xCE, 0x19, 0x23, 0xA0, 0x96, 0x4B, 0x00, 0x00, 0x00, 0x08, 0xBA, 0x93, 0x9A, 0x62, + 0x72, 0x4C, 0x0D, 0x75, 0x81, 0xFC, 0xE5, 0x76, 0x1E, 0x9D, 0x8A, 0x0E, 0x6A, 0x1C, 0x3F, 0x92, + 0x4F, 0xDD, 0x84, 0x93, 0xD1, 0x11, 0x56, 0x49, 0xC0, 0x5E, 0xB6, 0x01, + }; + job.setRawBlob(test_input, 76); + job.setTarget("FFFFFFFFFFFFFFFF"); // set difficulty to 1 to get to onJobResult after every computed hash + job.setAlgorithm(xmrig::Algorithm(pa)); // set job algo (for Variant part) + if (!m_is_benchmark_time) { // write test before first benchmark round + Log::i()->text(m_controller->config()->isColors() + ? GREEN_BOLD(" >>>>> ") WHITE_BOLD("STARTING ALGO PERFORMANCE CALIBRATION") + : " >>>>> STARTING ALGO PERFORMANCE CALIBRATION" + ); + } + m_is_benchmark_time = true; // benchmarking is in process + Workers::setJob(job, false); // set job for workers to compute +} + +void Benchmark::onJobResult(const JobResult& result) { + if (!m_is_benchmark_time) return; // ignore job results if we already stopeed benchmarking (before new job from the pool comes) + ++ m_hash_count; + const uint64_t now = get_now(); + if (now - m_time_start > m_bench_secs*1000) { // end of becnhmark round for m_pa + const float hashrate = static_cast(m_hash_count) / (now - m_time_start) * 1000.0f; + m_controller->config()->set_algo_perf(m_pa, hashrate); // store hashrate result + Log::i()->text(m_controller->config()->isColors() + ? GREEN_BOLD(" ===> ") CYAN_BOLD("%s") WHITE_BOLD(" hashrate: ") CYAN_BOLD("%f") + : " ===> %s hasrate: %f", + xmrig::Algorithm::perfAlgoName(m_pa), + hashrate + ); + const xmrig::PerfAlgo pa = static_cast(m_pa + 1); // compute next perf algo to benchmark + if (pa != xmrig::PerfAlgo::PA_MAX) { + start_perf_bench(pa); + } else { // en of benchmarks and switching to jobs from the pool (network) + m_is_benchmark_time = false; + if (m_controller->config()->isSaveConfig()) m_controller->config()->save(); // save config with measured algo-perf + Workers::pause(); // do not compute anything before job from the pool + Workers::setListener(m_controller->network()); + m_controller->network()->connect(); + } + } +} + +uint64_t Benchmark::get_now() const { // get current time in ms + using namespace std::chrono; + return time_point_cast(high_resolution_clock::now()).time_since_epoch().count(); +} diff --git a/src/workers/Benchmark.h b/src/workers/Benchmark.h new file mode 100644 index 00000000..479b14b3 --- /dev/null +++ b/src/workers/Benchmark.h @@ -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 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , + * + * 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 . + */ + +#pragma once + +#include + +#include "common/xmrig.h" +#include "interfaces/IJobResultListener.h" +#include "core/Controller.h" + +class Benchmark : public IJobResultListener { + const uint64_t m_bench_secs = 5; // time in seconds to benchmark each perf algo + bool m_is_benchmark_time; // true is we benchmark some perf algo now + xmrig::PerfAlgo m_pa; // current perf algo we benchmark + uint64_t m_hash_count; // number of hashes calculated for current perf algo + uint64_t m_time_start; // time of measurements start for current perf algo (in ms) + xmrig::Controller* m_controller; // to get access to config and network + + uint64_t get_now() const; // get current time in ms + + void onJobResult(const JobResult&) override; // onJobResult is called after each computed benchmark hash + + public: + Benchmark() : m_is_benchmark_time(false) {} + virtual ~Benchmark() {} + + void set_controller(xmrig::Controller* controller) { m_controller = controller; } + void start_perf_bench(const xmrig::PerfAlgo); // start benchmark for specified perf algo +}; diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index 0e75e736..d77bf681 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -194,6 +195,69 @@ void Workers::start(xmrig::Controller *controller) } } +void Workers::soft_stop() // stop current workers leaving uv stuff intact (used in switch_algo) +{ + if (m_hashrate) { + m_hashrate->stop(); + delete m_hashrate; + } + + m_sequence = 0; + m_paused = 0; + + for (size_t i = 0; i < m_workers.size(); ++i) { + m_workers[i]->join(); + delete m_workers[i]; + } + m_workers.clear(); +} + +// setups workers based on specified algorithm (or its basic perf algo more specifically) +void Workers::switch_algo(const xmrig::Algorithm algorithm) +{ + if (m_status.algo == algorithm.algo()) return; + + soft_stop(); + + m_sequence = 1; + m_paused = 1; + + const std::vector &threads = m_controller->config()->threads(algorithm.perf_algo()); + m_status.algo = algorithm.algo(); + m_status.threads = threads.size(); + + // string with multiway thread info + std::string str_threads; + for (const xmrig::IThread *thread : threads) { + if (!str_threads.empty()) str_threads = str_threads + ", "; + str_threads = str_threads + "x" + std::to_string(thread->multiway()); + } + Log::i()->text(m_controller->config()->isColors() + ? GREEN_BOLD(" >>> ") WHITE_BOLD("ALGO CHANGE: ") CYAN_BOLD("%s") ", " CYAN_BOLD("%d (%s)") " thread(s)" + : " >>> ALGO CHANGE: %s, %d (%s) thread(s)", + algorithm.name(), + threads.size(), + str_threads.c_str() + ); + + m_status.ways = 0; + for (const xmrig::IThread *thread : threads) { + m_status.ways += thread->multiway(); + } + + m_hashrate = new Hashrate(threads.size(), m_controller); + + uint32_t offset = 0; + + for (xmrig::IThread *thread : threads) { + Handle *handle = new Handle(thread, offset, m_status.ways); + offset += thread->multiway(); + + m_workers.push_back(handle); + handle->start(Workers::onReady); + } +} + void Workers::stop() { diff --git a/src/workers/Workers.h b/src/workers/Workers.h index 1d619cea..8cfd02d8 100644 --- a/src/workers/Workers.h +++ b/src/workers/Workers.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2016-2018 XMRig , + * Copyright 2018 MoneroOcean , * * 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 @@ -56,6 +57,8 @@ public: static void setEnabled(bool enabled); static void setJob(const Job &job, bool donate); static void start(xmrig::Controller *controller); + // setups workers based on specified algorithm (or its basic perf algo more specifically) + static void switch_algo(xmrig::Algorithm); static void stop(); static void submit(const JobResult &result); @@ -76,6 +79,7 @@ private: static void onResult(uv_async_t *handle); static void onTick(uv_timer_t *handle); static void start(IWorker *worker); + static void soft_stop(); // stop current workers leaving uv stuff intact (used in switch_algo) class LaunchStatus {