From 9951bd756deb4b5d354ecb8d61e147471c757cbe Mon Sep 17 00:00:00 2001 From: MoneroOcean Date: Wed, 18 Jul 2018 16:49:09 +0200 Subject: [PATCH] Added algo performance calibration (benchmarking) functionality --- CMakeLists.txt | 2 + src/App.cpp | 15 ++++++- src/common/net/Job.cpp | 7 +++ src/common/net/Job.h | 4 ++ src/config.json | 6 +++ src/workers/Benchmark.cpp | 92 +++++++++++++++++++++++++++++++++++++++ src/workers/Benchmark.h | 51 ++++++++++++++++++++++ src/workers/Workers.cpp | 64 +++++++++++++++++++++++++++ src/workers/Workers.h | 4 ++ 9 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 src/workers/Benchmark.cpp create mode 100644 src/workers/Benchmark.h 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/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/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/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 {