diff --git a/src/App.cpp b/src/App.cpp index 22be0ed3d7..b7269cb004 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -95,7 +95,10 @@ int xmrig::App::exec() if (m_controller->config()->isShouldSave()) { m_controller->config()->save(); } - m_controller->config()->benchmark().start(); + if (m_controller->config()->isRebenchAlgo()) { + m_controller->config()->benchmark().flush_perf(); + } + m_controller->config()->benchmark().start_perf(); } else { m_controller->start(); } diff --git a/src/core/MoBenchmark.cpp b/src/core/MoBenchmark.cpp index cea8ec72c6..de9eaae88c 100644 --- a/src/core/MoBenchmark.cpp +++ b/src/core/MoBenchmark.cpp @@ -22,7 +22,6 @@ #include "backend/common/Tags.h" #include "base/io/log/Log.h" #include "base/io/log/Tags.h" -#include "base/net/stratum/Job.h" #include "core/config/Config.h" #include "core/Controller.h" #include "core/Miner.h" @@ -34,38 +33,29 @@ namespace xmrig { -MoBenchmark::MoBenchmark() : m_controller(nullptr), m_isNewBenchRun(true) { - for (BenchAlgo bench_algo = BenchAlgo::MIN; bench_algo != BenchAlgo::MAX; bench_algo = static_cast(bench_algo + 1)) { - m_bench_job[bench_algo] = new Job(false, Algorithm(ba2a[bench_algo]), "benchmark"); - } -} +MoBenchmark::MoBenchmark() : m_controller(nullptr), m_isNewBenchRun(true) {} -MoBenchmark::~MoBenchmark() { - for (BenchAlgo bench_algo = BenchAlgo::MIN; bench_algo != BenchAlgo::MAX; bench_algo = static_cast(bench_algo + 1)) { - delete m_bench_job[bench_algo]; - } -} +MoBenchmark::~MoBenchmark() {} // start performance measurements from the first bench_algo -void MoBenchmark::start() { +void MoBenchmark::start_perf() { JobResults::setListener(this, m_controller->config()->cpu().isHwAES()); // register benchmark as job result listener to compute hashrates there // write text before first benchmark round LOG_INFO("%s " BRIGHT_BLACK_BG(CYAN_BOLD_S " STARTING ALGO PERFORMANCE CALIBRATION (with " MAGENTA_BOLD_S "%i" CYAN_BOLD_S " seconds round) "), Tags::benchmark(), m_controller->config()->benchAlgoTime()); // start benchmarking from first PerfAlgo in the list - start(BenchAlgo::MIN); - m_isNewBenchRun = true; + m_bench_algo = 0; + start(); + m_isNewBenchRun = true; // need to save it to true to save config after benchmark } // end of benchmarks, switch to jobs from the pool (network), fill algo_perf void MoBenchmark::finish() { for (const Algorithm::Id algo : Algorithm::all([this](const Algorithm &algo) { return true; })) { - algo_perf[algo] = get_algo_perf(algo); + if (algo_perf[algo] == 0.0f) algo_perf[algo] = get_algo_perf(algo); } - m_bench_algo = BenchAlgo::INVALID; LOG_INFO("%s " BRIGHT_BLACK_BG(CYAN_BOLD_S " ALGO PERFORMANCE CALIBRATION COMPLETE "), Tags::benchmark()); m_controller->miner()->pause(); // do not compute anything before job from the pool JobResults::stop(); - JobResults::setListener(m_controller->network(), m_controller->config()->cpu().isHwAES()); m_controller->start(); } @@ -77,18 +67,19 @@ rapidjson::Value MoBenchmark::toJSON(rapidjson::Document &doc) const Value obj(kObjectType); for (const Algorithm a : Algorithm::all()) { - if (algo_perf[a.id()] == 0.0f) continue; obj.AddMember(StringRef(a.name()), algo_perf[a.id()], allocator); } return obj; } +void MoBenchmark::flush_perf() { + for (const Algorithm::Id algo : Algorithm::all()) algo_perf[algo] = 0.0f; +} + void MoBenchmark::read(const rapidjson::Value &value) { - for (const Algorithm::Id algo : Algorithm::all()) { - algo_perf[algo] = 0.0f; - } + flush_perf(); if (value.IsObject()) { for (auto &member : value.GetObject()) { const Algorithm algo(member.name.GetString()); @@ -98,100 +89,94 @@ void MoBenchmark::read(const rapidjson::Value &value) } if (member.value.IsDouble()) { algo_perf[algo.id()] = member.value.GetDouble(); - m_isNewBenchRun = false; continue; } if (member.value.IsInt()) { algo_perf[algo.id()] = member.value.GetInt(); - m_isNewBenchRun = false; continue; } LOG_INFO("%s " BRIGHT_BLACK_BG(MAGENTA_BOLD_S " Ignoring wrong value for algo-perf[%s] "), Tags::benchmark(), member.name.GetString()); } } + m_isNewBenchRun = false; + for (int i = 0; bench_algos[i] != Algorithm::INVALID; ++ i) + if (algo_perf[bench_algos[i]] == 0.0f) { + m_isNewBenchRun = true; + return; + } } double MoBenchmark::get_algo_perf(Algorithm::Id algo) const { switch (algo) { - case Algorithm::CN_CCX: return m_bench_algo_perf[BenchAlgo::CN_CCX]; - case Algorithm::CN_0: return m_bench_algo_perf[BenchAlgo::CN_CCX] / 2; - case Algorithm::CN_1: return m_bench_algo_perf[BenchAlgo::CN_R]; - case Algorithm::CN_2: return m_bench_algo_perf[BenchAlgo::CN_R]; - case Algorithm::CN_R: return m_bench_algo_perf[BenchAlgo::CN_R]; - case Algorithm::CN_RTO: return m_bench_algo_perf[BenchAlgo::CN_R]; - case Algorithm::CN_XAO: return m_bench_algo_perf[BenchAlgo::CN_R]; - case Algorithm::CN_FAST: return m_bench_algo_perf[BenchAlgo::CN_R] * 2; - case Algorithm::CN_HALF: return m_bench_algo_perf[BenchAlgo::CN_R] * 2; - case Algorithm::CN_RWZ: return m_bench_algo_perf[BenchAlgo::CN_R] / 3 * 4; - case Algorithm::CN_ZLS: return m_bench_algo_perf[BenchAlgo::CN_R] / 3 * 4; - case Algorithm::CN_DOUBLE: return m_bench_algo_perf[BenchAlgo::CN_R] / 2; - case Algorithm::CN_LITE_0: return m_bench_algo_perf[BenchAlgo::CN_LITE_1]; - case Algorithm::CN_LITE_1: return m_bench_algo_perf[BenchAlgo::CN_LITE_1]; - case Algorithm::CN_HEAVY_XHV: return m_bench_algo_perf[BenchAlgo::CN_HEAVY_XHV]; - case Algorithm::CN_PICO_0: return m_bench_algo_perf[BenchAlgo::CN_PICO_0]; - case Algorithm::CN_PICO_TLO: return m_bench_algo_perf[BenchAlgo::CN_PICO_0]; - case Algorithm::CN_GPU: return m_bench_algo_perf[BenchAlgo::CN_GPU]; - case Algorithm::AR2_CHUKWA_V2: return m_bench_algo_perf[BenchAlgo::AR2_CHUKWA_V2]; - case Algorithm::KAWPOW_RVN: return m_bench_algo_perf[BenchAlgo::KAWPOW_RVN]; - case Algorithm::RX_0: return m_bench_algo_perf[BenchAlgo::RX_0]; - case Algorithm::RX_SFX: return m_bench_algo_perf[BenchAlgo::RX_0]; - case Algorithm::RX_GRAFT: return m_bench_algo_perf[BenchAlgo::RX_GRAFT]; - case Algorithm::RX_ARQ: return m_bench_algo_perf[BenchAlgo::RX_ARQ]; - case Algorithm::RX_XEQ: return m_bench_algo_perf[BenchAlgo::RX_ARQ]; - case Algorithm::RX_XLA: return m_bench_algo_perf[BenchAlgo::RX_XLA]; - case Algorithm::GHOSTRIDER_RTM: return m_bench_algo_perf[BenchAlgo::GHOSTRIDER_RTM]; - case Algorithm::FLEX_KCN: return m_bench_algo_perf[BenchAlgo::FLEX_KCN]; - default: return 0.0f; + case Algorithm::CN_0: return algo_perf[Algorithm::CN_CCX] / 2; + case Algorithm::CN_1: return algo_perf[Algorithm::CN_R]; + case Algorithm::CN_2: return algo_perf[Algorithm::CN_R]; + case Algorithm::CN_RTO: return algo_perf[Algorithm::CN_R]; + case Algorithm::CN_XAO: return algo_perf[Algorithm::CN_R]; + case Algorithm::CN_FAST: return algo_perf[Algorithm::CN_R] * 2; + case Algorithm::CN_HALF: return algo_perf[Algorithm::CN_R] * 2; + case Algorithm::CN_RWZ: return algo_perf[Algorithm::CN_R] / 3 * 4; + case Algorithm::CN_ZLS: return algo_perf[Algorithm::CN_R] / 3 * 4; + case Algorithm::CN_DOUBLE: return algo_perf[Algorithm::CN_R] / 2; + case Algorithm::CN_LITE_0: return algo_perf[Algorithm::CN_LITE_1]; + case Algorithm::CN_PICO_TLO: return algo_perf[Algorithm::CN_PICO_0]; + case Algorithm::RX_SFX: return algo_perf[Algorithm::RX_0]; + case Algorithm::RX_XEQ: return algo_perf[Algorithm::RX_ARQ]; + default: return algo_perf[algo]; } } -// start performance measurements for specified perf bench_algo -void MoBenchmark::start(const BenchAlgo bench_algo) { +// start performance measurements for bench_algos[m_bench_algo] +void MoBenchmark::start() { + const Algorithm algo(bench_algos[m_bench_algo]); + if (algo_perf[algo.id()] > 0.0f) { + run_next_bench_algo(); + return; + } // calculate number of active miner backends in m_enabled_backend_count m_enabled_backend_count = 0; - const Algorithm algo(ba2a[bench_algo]); for (auto backend : m_controller->miner()->backends()) if (backend->isEnabled() && backend->isEnabled(algo)) ++ m_enabled_backend_count; if (m_enabled_backend_count == 0) { - run_next_bench_algo(bench_algo); + LOG_INFO("%s " BRIGHT_BLACK_BG(WHITE_BOLD_S " Algo " MAGENTA_BOLD_S "%s" WHITE_BOLD_S " is skipped due to a disabled backend"), Tags::benchmark(), algo.name()); + run_next_bench_algo(); return; } LOG_INFO("%s " BRIGHT_BLACK_BG(WHITE_BOLD_S " Algo " MAGENTA_BOLD_S "%s" WHITE_BOLD_S " Preparation "), Tags::benchmark(), algo.name()); // prepare test job for benchmark runs ("benchmark" client id is to make sure we can detect benchmark jobs) - Job& job = *m_bench_job[bench_algo]; - job.setId(algo.name()); // need to set different id so that workers will see job change - switch(bench_algo) { - case BenchAlgo::KAWPOW_RVN: - job.setBlob("4c38e8a5f7b2944d1e4274635d828519b97bc64a1f1c7896ecdbb139988aa0e80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - job.setDiff(Job::toDiff(strtoull("000000639c000000", nullptr, 16))); - job.setHeight(1500000); + m_bench_job = Job(false, Algorithm(bench_algos[m_bench_algo]), "benchmark"); + m_bench_job.setId(algo.name()); // need to set different id so that workers will see job change + switch (algo.id()) { + case Algorithm::KAWPOW_RVN: + m_bench_job.setBlob("4c38e8a5f7b2944d1e4274635d828519b97bc64a1f1c7896ecdbb139989aa0e80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + m_bench_job.setDiff(Job::toDiff(strtoull("000000639c000000", nullptr, 16))); + m_bench_job.setHeight(1500000); break; - case BenchAlgo::GHOSTRIDER_RTM: - case BenchAlgo::FLEX_KCN: - job.setBlob("000000208c246d0b90c3b389c4086e8b672ee040d64db5b9648527133e217fbfa48da64c0f3c0a0b0e8350800568b40fbb323ac3ccdf2965de51b9aaeb939b4f11ff81c49b74a16156ff251c00000000"); - job.setDiff(1000); + case Algorithm::GHOSTRIDER_RTM: + case Algorithm::FLEX_KCN: + m_bench_job.setBlob("000000208c246d0b90c3b389c4086e8b672ee040d64db5b9648527133e217fbfa48da64c0f3c0a0b0e8350800568b40fbb323ac3ccdf2965de51b9aaeb939b4f11ff81c49b74a16156ff251c00000000"); + m_bench_job.setDiff(1000); break; default: // 99 here to trigger all future bench_algo versions for auto veriant detection based on block version - job.setBlob("9905A0DBD6BF05CF16E503F3A66F78007CBF34144332ECBFC22ED95C8700383B309ACE1923A0964B00000008BA939A62724C0D7581FCE5761E9D8A0E6A1C3F924FDD8493D1115649C05EB601"); - job.setTarget("FFFFFFFFFFFFFF20"); // set difficulty to 8 cause onJobResult after every 8-th computed hash - job.setHeight(1000); - job.setSeedHash("0000000000000000000000000000000000000000000000000000000000000001"); + m_bench_job.setBlob("9905A0DBD6BF05CF16E503F3A66F78007CBF34144332ECBFC22ED95C8700383B309ACE1923A0964B00000008BA939A62724C0D7581FCE5761E9D8A0E6A1C3F924FDD8493D1115649C05EB601"); + m_bench_job.setTarget("FFFFFFFFFFFFFF20"); // set difficulty to 8 cause onJobResult after every 8-th computed hash + m_bench_job.setHeight(1000); + m_bench_job.setSeedHash("0000000000000000000000000000000000000000000000000000000000000001"); } - m_bench_algo = bench_algo; // current perf bench_algo m_hash_count = 0; // number of hashes calculated for current perf bench_algo m_time_start = 0; // init time of the first result (in ms) during the first onJobResult m_bench_start = 0; // init time of measurements start (in ms) during the first onJobResult m_backends_started.clear(); - m_controller->miner()->setJob(job, false); // set job for workers to compute + m_controller->miner()->setJob(m_bench_job, false); // set job for workers to compute } // run next bench algo or finish benchmark for the last one -void MoBenchmark::run_next_bench_algo(const BenchAlgo bench_algo) { - const BenchAlgo next_bench_algo = static_cast(bench_algo + 1); // compute next perf bench_algo to benchmark - if (next_bench_algo != BenchAlgo::MAX) { - start(next_bench_algo); +void MoBenchmark::run_next_bench_algo() { + ++ m_bench_algo; + if (bench_algos[m_bench_algo] != Algorithm::INVALID) { + start(); } else { finish(); } @@ -203,8 +188,9 @@ void MoBenchmark::onJobResult(const JobResult& result) { static_cast(m_controller->network())->onJobResult(result); return; } + const Algorithm algo(bench_algos[m_bench_algo]); // ignore benchmark results for other perf bench_algo - if (m_bench_algo == BenchAlgo::INVALID || result.jobId != String(Algorithm(ba2a[m_bench_algo]).name())) return; + if (algo.id() == Algorithm::INVALID || result.jobId != String(algo.name())) return; const uint64_t now = get_now(); if (!m_time_start) m_time_start = now; // time of the first result (in ms) m_backends_started.insert(result.backend); @@ -212,7 +198,7 @@ void MoBenchmark::onJobResult(const JobResult& result) { if (m_backends_started.size() < m_enabled_backend_count && (now - m_time_start < static_cast(3*60*1000))) return; ++ m_hash_count; if (!m_bench_start) { - LOG_INFO("%s " BRIGHT_BLACK_BG(WHITE_BOLD_S " Algo " MAGENTA_BOLD_S "%s" WHITE_BOLD_S " Starting test "), Tags::benchmark(), Algorithm(ba2a[m_bench_algo]).name()); + LOG_INFO("%s " BRIGHT_BLACK_BG(WHITE_BOLD_S " Algo " MAGENTA_BOLD_S "%s" WHITE_BOLD_S " Starting test "), Tags::benchmark(), algo.name()); m_bench_start = now; // time of measurements start (in ms) } else if (now - m_bench_start > static_cast(m_controller->config()->benchAlgoTime()*1000)) { // end of benchmark round for m_bench_algo double t[3] = { 0.0 }; @@ -228,16 +214,15 @@ void MoBenchmark::onJobResult(const JobResult& result) { if (!(hashrate = t[1])) if (!(hashrate = t[0])) hashrate = static_cast(m_hash_count) * result.diff / (now - m_bench_start) * 1000.0f; - if (m_bench_algo == KAWPOW_RVN) hashrate /= ((double)0xFFFFFFFFFFFFFFFF) / 0xFF000000; - m_bench_algo_perf[m_bench_algo] = hashrate; // store hashrate result - LOG_INFO("%s " BRIGHT_BLACK_BG(WHITE_BOLD_S " Algo " MAGENTA_BOLD_S "%s" WHITE_BOLD_S " hashrate: " CYAN_BOLD_S "%f "), Tags::benchmark(), Algorithm(ba2a[m_bench_algo]).name(), hashrate); - run_next_bench_algo(m_bench_algo); - } else switch(m_bench_algo) { // Update GhostRider algo job to produce more accurate perf results - case BenchAlgo::GHOSTRIDER_RTM: { - Job& job = *m_bench_job[m_bench_algo]; - uint8_t* blob = job.blob(); + if (algo.id() == Algorithm::KAWPOW_RVN) hashrate /= ((double)0xFFFFFFFFFFFFFFFF) / 0xFF000000; + algo_perf[algo.id()] = hashrate; // store hashrate result + LOG_INFO("%s " BRIGHT_BLACK_BG(WHITE_BOLD_S " Algo " MAGENTA_BOLD_S "%s" WHITE_BOLD_S " hashrate: " CYAN_BOLD_S "%f "), Tags::benchmark(), algo.name(), hashrate); + run_next_bench_algo(); + } else switch (algo.id()) { // Update GhostRider algo job to produce more accurate perf results + case Algorithm::GHOSTRIDER_RTM: { + uint8_t* blob = m_bench_job.blob(); ++ *reinterpret_cast(blob+4); - m_controller->miner()->setJob(job, false); + m_controller->miner()->setJob(m_bench_job, false); break; } default:; diff --git a/src/core/MoBenchmark.h b/src/core/MoBenchmark.h index 8e8c01a1bd..5398bf4e2e 100644 --- a/src/core/MoBenchmark.h +++ b/src/core/MoBenchmark.h @@ -21,6 +21,7 @@ #include #include "net/interfaces/IJobResultListener.h" #include "base/crypto/Algorithm.h" +#include "base/net/stratum/Job.h" #include "rapidjson/fwd.h" #include @@ -33,27 +34,7 @@ class Job; class MoBenchmark : public IJobResultListener { - enum BenchAlgo : int { - FLEX_KCN, // "flex" Flex - GHOSTRIDER_RTM, // "ghostrider" GhostRider - CN_R, // "cn/r" CryptoNightR (Monero's variant 4). - CN_LITE_1, // "cn-lite/1" CryptoNight-Lite variant 1. - CN_HEAVY_XHV, // "cn-heavy/xhv" CryptoNight-Heavy (modified, Haven Protocol only). - CN_PICO_0, // "cn-pico" CryptoNight-Pico. - CN_CCX, // "cn/ccx" Conceal (CCX). - CN_GPU, // "cn/gpu" CryptoNight-GPU (Ryo). - AR2_CHUKWA_V2, // "argon2/chukwav2" Argon2id (Chukwa v2). - KAWPOW_RVN, // "kawpow/rvn" KawPow (RVN) - RX_0, // "rx/0" RandomX (Monero). - RX_GRAFT, // "rx/graft" RandomGraft (Graft). - RX_ARQ, // "rx/arq" RandomARQ (Arqma). - RX_XLA, // "panthera" Panthera (Scala2). - MAX, - MIN = 0, - INVALID = -1, - }; - - const Algorithm::Id ba2a[BenchAlgo::MAX] = { + const Algorithm::Id bench_algos[15] = { Algorithm::FLEX_KCN, Algorithm::GHOSTRIDER_RTM, Algorithm::CN_R, @@ -68,26 +49,26 @@ class MoBenchmark : public IJobResultListener { Algorithm::RX_GRAFT, Algorithm::RX_ARQ, Algorithm::RX_XLA, + Algorithm::INVALID }; - Job* m_bench_job[BenchAlgo::MAX]; - double m_bench_algo_perf[BenchAlgo::MAX]; + Job m_bench_job; Controller *m_controller; // to get access to config and network bool m_isNewBenchRun; // true if benchmark is need to be executed or was executed - MoBenchmark::BenchAlgo m_bench_algo; // current perf algo we benchmark + uint64_t m_bench_algo; // current perf algo number we benchmark (in bench_algos array) uint64_t m_hash_count; // number of hashes calculated for current perf algo uint64_t m_time_start; // time of the first resultt for current perf algo (in ms) uint64_t m_bench_start; // time of measurements start for current perf algo (in ms) after all backends are started unsigned m_enabled_backend_count; // number of active miner backends std::set m_backends_started; // id of backend started for benchmark - uint64_t get_now() const; // get current time in ms - double get_algo_perf(Algorithm::Id algo) const; // get algo perf based on m_bench_algo_perf - void start(const MoBenchmark::BenchAlgo); // start benchmark for specified perf algo - void finish(); // end of benchmarks, switch to jobs from the pool (network), fill algo_perf - void onJobResult(const JobResult&) override; // onJobResult is called after each computed benchmark hash - void run_next_bench_algo(BenchAlgo); // run next bench algo or finish benchmark for the last one + uint64_t get_now() const; // get current time in ms + double get_algo_perf(Algorithm::Id algo) const; // get algo perf based on algo_perf known perf numbers + void start(); // start benchmark for m_bench_algo number + void finish(); // end of benchmarks, switch to jobs from the pool (network), fill algo_perf + void onJobResult(const JobResult&) override; // onJobResult is called after each computed benchmark hash + void run_next_bench_algo(); // run next bench algo or finish benchmark for the last one public: MoBenchmark(); @@ -95,7 +76,8 @@ class MoBenchmark : public IJobResultListener { void set_controller(std::shared_ptr controller) { m_controller = controller.get(); } - void start(); // start benchmarks + void start_perf(); // start benchmarks + void flush_perf(); bool isNewBenchRun() const { return m_isNewBenchRun; } mutable std::map algo_perf;