Benchmark refactoring, zero delay submit and unified HTTP layer.

This commit is contained in:
XMRig 2020-11-16 16:22:34 +07:00
parent be8245fc92
commit c1d99bfa09
No known key found for this signature in database
GPG key ID: 446A53638BE94409
21 changed files with 558 additions and 380 deletions

View file

@ -1,289 +0,0 @@
/* XMRig
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "backend/common/Benchmark.h"
#include "3rdparty/fmt/core.h"
#include "backend/common/interfaces/IBackend.h"
#include "backend/common/interfaces/IWorker.h"
#include "base/io/log/Log.h"
#include "base/io/log/Tags.h"
#include "base/net/http/Fetch.h"
#include "base/net/http/HttpData.h"
#include "base/net/http/HttpListener.h"
#include "base/net/stratum/benchmark/BenchConfig.h"
#include "base/net/stratum/Job.h"
#include "base/tools/Chrono.h"
#include <algorithm>
namespace xmrig {
static const std::map<int, std::map<uint32_t, uint64_t> > hashCheck = {
{ Algorithm::RX_0, {
# ifndef NDEBUG
{ 10000U, 0x4A597463865ACF0EULL },
# endif
{ 250000U, 0x7D6054757BB08A63ULL },
{ 500000U, 0x96607546DE1F5ECCULL },
{ 1000000U, 0x898B6E0431C28A6BULL },
{ 2000000U, 0xEE9468F8B40926BCULL },
{ 3000000U, 0xC2BC5D11724813C0ULL },
{ 4000000U, 0x3A2C7B285B87F941ULL },
{ 5000000U, 0x3B5BD2C3A16B450EULL },
{ 6000000U, 0x5CD0602F20C5C7C4ULL },
{ 7000000U, 0x101DE939474B6812ULL },
{ 8000000U, 0x52B765A1B156C6ECULL },
{ 9000000U, 0x323935102AB6B45CULL },
{ 10000000U, 0xB5231262E2792B26ULL }
}},
{ Algorithm::RX_WOW, {
# ifndef NDEBUG
{ 10000U, 0x6B0918757100B338ULL },
# endif
{ 250000U, 0xC7F712C9603E2603ULL },
{ 500000U, 0x21A0E5AAE6DA7D8DULL },
{ 1000000U, 0x0F3E5400B39EA96AULL },
{ 2000000U, 0x85944CCFA2752D1FULL },
{ 3000000U, 0x64AFFCAE991811BAULL },
{ 4000000U, 0x3E4D0B836D3B13BAULL },
{ 5000000U, 0xEB7417D621271166ULL },
{ 6000000U, 0x97FFE10C0949FFA5ULL },
{ 7000000U, 0x84CAC0F8879A4BA1ULL },
{ 8000000U, 0xA1B79F031DA2459FULL },
{ 9000000U, 0x9B65226DA873E65DULL },
{ 10000000U, 0x0F9E00C5A511C200ULL }
}}
};
static const std::map<int, std::map<uint32_t, uint64_t> > hashCheck1T = {
{ Algorithm::RX_0, {
# ifndef NDEBUG
{ 10000U, 0xADFC3A66F79BFE7FULL },
# endif
{ 250000U, 0x90A15B799486F3EBULL },
{ 500000U, 0xAA83118FEE570F9AULL },
{ 1000000U, 0x3DF47B0A427C93D9ULL },
{ 2000000U, 0xED4D639B0AEB85C6ULL },
{ 3000000U, 0x2D4F9B4275A713C3ULL },
{ 4000000U, 0xA9EBE4888377F8D3ULL },
{ 5000000U, 0xB92F81851E180454ULL },
{ 6000000U, 0xFB9F98F63C2F1B7DULL },
{ 7000000U, 0x2CC3D7A779D5AB35ULL },
{ 8000000U, 0x2EEF833EA462F4B1ULL },
{ 9000000U, 0xC6D39EF59213A07CULL },
{ 10000000U, 0x95E6BAE68DD779CDULL }
}},
{ Algorithm::RX_WOW, {
# ifndef NDEBUG
{ 10000U, 0x9EC1B9B8C8C7F082ULL },
# endif
{ 250000U, 0x7B409F096C863207ULL },
{ 500000U, 0x70B7B80D15654216ULL },
{ 1000000U, 0x31301CC550306A59ULL },
{ 2000000U, 0x92F65E9E31116361ULL },
{ 3000000U, 0x7FE8DF6F43BA5285ULL },
{ 4000000U, 0xD6CDA54FE4D9BBF7ULL },
{ 5000000U, 0x73AF673E1A38E2B4ULL },
{ 6000000U, 0x81FDC5C4B45D84E4ULL },
{ 7000000U, 0xAA08CA57666DC874ULL },
{ 8000000U, 0x9DCEFB833FC875BCULL },
{ 9000000U, 0x862F051352CFCA1FULL },
{ 10000000U, 0xC403F220189E8430ULL }
}}
};
} // namespace xmrig
xmrig::Benchmark::Benchmark(const Job &job, size_t workers, const IBackend *backend) :
m_algo(job.algorithm()),
m_backend(backend),
m_workers(workers),
m_id(job.id()),
m_token(job.benchToken()),
m_end(job.benchSize()),
m_hash(job.benchHash())
{
# ifdef XMRIG_FEATURE_HTTP
if (!m_token.isEmpty()) {
m_httpListener = std::make_shared<HttpListener>(this, Tags::bench());
}
# endif
}
bool xmrig::Benchmark::finish(uint64_t totalHashCount)
{
m_reset = true;
m_current = totalHashCount;
if (m_done < m_workers) {
return false;
}
const double dt = static_cast<double>(m_doneTime - m_startTime) / 1000.0;
uint64_t checkData = referenceHash();
const char *color = checkData ? ((m_data == checkData) ? GREEN_BOLD_S : RED_BOLD_S) : BLACK_BOLD_S;
LOG_NOTICE("%s " WHITE_BOLD("benchmark finished in ") CYAN_BOLD("%.3f seconds") WHITE_BOLD_S " hash sum = " CLEAR "%s%016" PRIX64 CLEAR, Tags::bench(), dt, color, m_data);
# ifdef XMRIG_FEATURE_HTTP
if (!m_token.isEmpty()) {
using namespace rapidjson;
Document doc(kObjectType);
auto &allocator = doc.GetAllocator();
doc.AddMember("steady_done_ts", m_doneTime, allocator);
doc.AddMember(StringRef(BenchConfig::kHash), Value(fmt::format("{:016X}", m_data).c_str(), allocator), allocator);
doc.AddMember("backend", m_backend->toJSON(doc), allocator);
send(doc);
}
else
# endif
{
printExit();
}
return true;
}
void xmrig::Benchmark::start()
{
m_startTime = Chrono::steadyMSecs();
# ifdef XMRIG_FEATURE_HTTP
if (!m_token.isEmpty()) {
using namespace rapidjson;
Document doc(kObjectType);
doc.AddMember("steady_start_ts", m_startTime, doc.GetAllocator());
send(doc);
}
# endif
}
void xmrig::Benchmark::printProgress() const
{
if (!m_startTime || !m_current) {
return;
}
const double dt = static_cast<double>(Chrono::steadyMSecs() - m_startTime) / 1000.0;
const double percent = static_cast<double>(m_current) / m_end * 100.0;
LOG_NOTICE("%s " MAGENTA_BOLD("%5.2f%% ") CYAN_BOLD("%" PRIu64) CYAN("/%" PRIu64) BLACK_BOLD(" (%.3fs)"), Tags::bench(), percent, m_current, m_end, dt);
}
void xmrig::Benchmark::tick(IWorker *worker)
{
if (m_reset) {
m_data = 0;
m_done = 0;
m_reset = false;
}
const uint64_t doneTime = worker->benchDoneTime();
if (!doneTime) {
return;
}
++m_done;
m_data ^= worker->benchData();
m_doneTime = std::max(doneTime, m_doneTime);
}
void xmrig::Benchmark::onHttpData(const HttpData &data)
{
# ifdef XMRIG_FEATURE_HTTP
rapidjson::Document doc;
try {
doc = data.json();
} catch (const std::exception &ex) {
return setError(ex.what());
}
if (data.status != 200) {
return setError(data.statusName());
}
if (m_doneTime) {
LOG_NOTICE("%s " WHITE_BOLD("benchmark submitted ") CYAN_BOLD("https://xmrig.com/benchmark/%s"), Tags::bench(), m_id.data());
printExit();
}
# endif
}
uint64_t xmrig::Benchmark::referenceHash() const
{
if (m_hash) {
return m_hash;
}
# ifdef XMRIG_FEATURE_HTTP
if (!m_token.isEmpty()) {
return 0;
}
# endif
uint64_t hash = 0;
try {
const auto& h = (m_workers == 1) ? hashCheck1T : hashCheck;
hash = h.at(m_algo).at(m_end);
} catch (const std::exception &ex) {}
return hash;
}
void xmrig::Benchmark::printExit()
{
LOG_INFO("%s " WHITE_BOLD("press ") MAGENTA_BOLD("Ctrl+C") WHITE_BOLD(" to exit"), Tags::bench());
}
#ifdef XMRIG_FEATURE_HTTP
void xmrig::Benchmark::send(const rapidjson::Value &body)
{
FetchRequest req(HTTP_PATCH, BenchConfig::kApiHost, BenchConfig::kApiPort, fmt::format("/1/benchmark/{}", m_id).c_str(), body, BenchConfig::kApiTLS, true);
req.headers.insert({ "Authorization", fmt::format("Bearer {}", m_token)});
fetch(std::move(req), m_httpListener);
}
void xmrig::Benchmark::setError(const char *message)
{
LOG_ERR("%s " RED("benchmark failed ") RED_BOLD("\"%s\""), Tags::bench(), message);
}
#endif

View file

@ -6,8 +6,8 @@
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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

View file

@ -6,8 +6,8 @@
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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,7 +28,6 @@
#include <atomic>
#include <cstdint>
#include "backend/common/interfaces/IWorker.h"
@ -49,11 +48,6 @@ public:
void getHashrateData(uint64_t& hashCount, uint64_t& timeStamp) const override;
# ifdef XMRIG_FEATURE_BENCHMARK
inline uint64_t benchData() const override { return m_benchData; }
inline uint64_t benchDoneTime() const override { return m_benchDoneTime; }
# endif
protected:
void storeStats();
@ -64,11 +58,6 @@ protected:
uint64_t m_count = 0;
uint64_t m_hashCount[2] = {};
uint64_t m_timestamp[2] = {};
# ifdef XMRIG_FEATURE_BENCHMARK
uint64_t m_benchData = 0;
uint64_t m_benchDoneTime = 0;
# endif
};

View file

@ -47,7 +47,7 @@
#ifdef XMRIG_FEATURE_BENCHMARK
# include "backend/common/Benchmark.h"
# include "backend/common/benchmark/Benchmark.h"
#endif
@ -124,12 +124,6 @@ bool xmrig::Workers<T>::tick(uint64_t)
totalAvailable = false;
}
totalHashCount += n;
# ifdef XMRIG_FEATURE_BENCHMARK
if (d_ptr->benchmark) {
d_ptr->benchmark->tick(worker);
}
# endif
}
}

View file

@ -0,0 +1,108 @@
/* XMRig
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "backend/common/benchmark/BenchState.h"
#include "backend/common/benchmark/BenchState_test.h"
#include "backend/common/interfaces/IBenchListener.h"
#include "base/io/Async.h"
#include "base/tools/Chrono.h"
#include <algorithm>
#include <cassert>
#include <memory>
#include <mutex>
namespace xmrig {
static bool done = false;
static std::mutex mutex;
static std::shared_ptr<Async> async;
static uint32_t remaining = 0;
static uint64_t doneTime = 0;
static uint64_t result = 0;
IBenchListener *BenchState::m_listener = nullptr;
} // namespace xmrig
bool xmrig::BenchState::isDone()
{
return xmrig::done;
}
uint64_t xmrig::BenchState::referenceHash(const Algorithm &algo, uint32_t size, uint32_t threads)
{
uint64_t hash = 0;
try {
const auto &h = (threads == 1) ? hashCheck1T : hashCheck;
hash = h.at(algo).at(size);
} catch (const std::exception &ex) {}
return hash;
}
uint64_t xmrig::BenchState::start(size_t threads, const IBackend *backend)
{
assert(m_listener != nullptr);
remaining = static_cast<uint32_t>(threads);
async = std::make_shared<Async>([] {
m_listener->onBenchDone(result, doneTime);
async.reset();
xmrig::done = true;
});
const uint64_t ts = Chrono::steadyMSecs();
m_listener->onBenchStart(ts, remaining, backend);
return ts;
}
void xmrig::BenchState::destroy()
{
async.reset();
}
void xmrig::BenchState::done(uint64_t data, uint64_t ts)
{
assert(async && remaining > 0);
std::lock_guard<std::mutex> lock(mutex);
result ^= data;
doneTime = std::max(doneTime, ts);
--remaining;
if (remaining == 0) {
async->send();
}
}

View file

@ -0,0 +1,53 @@
/* XMRig
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_BENCHSTATE_H
#define XMRIG_BENCHSTATE_H
#include <cstdint>
namespace xmrig {
class Algorithm;
class IBackend;
class IBenchListener;
class BenchState
{
public:
static bool isDone();
static uint64_t referenceHash(const Algorithm &algo, uint32_t size, uint32_t threads);
static uint64_t start(size_t threads, const IBackend *backend);
static void destroy();
static void done(uint64_t data, uint64_t ts);
inline static void setListener(IBenchListener *listener) { m_listener = listener; }
private:
static IBenchListener *m_listener;
};
} // namespace xmrig
#endif /* XMRIG_BENCHSTATE_H */

View file

@ -0,0 +1,112 @@
/* XMRig
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_BENCHSTATE_TEST_H
#define XMRIG_BENCHSTATE_TEST_H
#include "base/crypto/Algorithm.h"
#include <map>
namespace xmrig {
static const std::map<int, std::map<uint32_t, uint64_t> > hashCheck = {
{ Algorithm::RX_0, {
# ifndef NDEBUG
{ 10000U, 0x4A597463865ACF0EULL },
# endif
{ 250000U, 0x7D6054757BB08A63ULL },
{ 500000U, 0x96607546DE1F5ECCULL },
{ 1000000U, 0x898B6E0431C28A6BULL },
{ 2000000U, 0xEE9468F8B40926BCULL },
{ 3000000U, 0xC2BC5D11724813C0ULL },
{ 4000000U, 0x3A2C7B285B87F941ULL },
{ 5000000U, 0x3B5BD2C3A16B450EULL },
{ 6000000U, 0x5CD0602F20C5C7C4ULL },
{ 7000000U, 0x101DE939474B6812ULL },
{ 8000000U, 0x52B765A1B156C6ECULL },
{ 9000000U, 0x323935102AB6B45CULL },
{ 10000000U, 0xB5231262E2792B26ULL }
}},
{ Algorithm::RX_WOW, {
# ifndef NDEBUG
{ 10000U, 0x6B0918757100B338ULL },
# endif
{ 250000U, 0xC7F712C9603E2603ULL },
{ 500000U, 0x21A0E5AAE6DA7D8DULL },
{ 1000000U, 0x0F3E5400B39EA96AULL },
{ 2000000U, 0x85944CCFA2752D1FULL },
{ 3000000U, 0x64AFFCAE991811BAULL },
{ 4000000U, 0x3E4D0B836D3B13BAULL },
{ 5000000U, 0xEB7417D621271166ULL },
{ 6000000U, 0x97FFE10C0949FFA5ULL },
{ 7000000U, 0x84CAC0F8879A4BA1ULL },
{ 8000000U, 0xA1B79F031DA2459FULL },
{ 9000000U, 0x9B65226DA873E65DULL },
{ 10000000U, 0x0F9E00C5A511C200ULL }
}}
};
static const std::map<int, std::map<uint32_t, uint64_t> > hashCheck1T = {
{ Algorithm::RX_0, {
# ifndef NDEBUG
{ 10000U, 0xADFC3A66F79BFE7FULL },
# endif
{ 250000U, 0x90A15B799486F3EBULL },
{ 500000U, 0xAA83118FEE570F9AULL },
{ 1000000U, 0x3DF47B0A427C93D9ULL },
{ 2000000U, 0xED4D639B0AEB85C6ULL },
{ 3000000U, 0x2D4F9B4275A713C3ULL },
{ 4000000U, 0xA9EBE4888377F8D3ULL },
{ 5000000U, 0xB92F81851E180454ULL },
{ 6000000U, 0xFB9F98F63C2F1B7DULL },
{ 7000000U, 0x2CC3D7A779D5AB35ULL },
{ 8000000U, 0x2EEF833EA462F4B1ULL },
{ 9000000U, 0xC6D39EF59213A07CULL },
{ 10000000U, 0x95E6BAE68DD779CDULL }
}},
{ Algorithm::RX_WOW, {
# ifndef NDEBUG
{ 10000U, 0x9EC1B9B8C8C7F082ULL },
# endif
{ 250000U, 0x7B409F096C863207ULL },
{ 500000U, 0x70B7B80D15654216ULL },
{ 1000000U, 0x31301CC550306A59ULL },
{ 2000000U, 0x92F65E9E31116361ULL },
{ 3000000U, 0x7FE8DF6F43BA5285ULL },
{ 4000000U, 0xD6CDA54FE4D9BBF7ULL },
{ 5000000U, 0x73AF673E1A38E2B4ULL },
{ 6000000U, 0x81FDC5C4B45D84E4ULL },
{ 7000000U, 0xAA08CA57666DC874ULL },
{ 8000000U, 0x9DCEFB833FC875BCULL },
{ 9000000U, 0x862F051352CFCA1FULL },
{ 10000000U, 0xC403F220189E8430ULL }
}}
};
} // namespace xmrig
#endif /* XMRIG_BENCHSTATE_TEST_H */

View file

@ -0,0 +1,60 @@
/* XMRig
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "backend/common/benchmark/Benchmark.h"
#include "backend/common/benchmark/BenchState.h"
#include "base/io/log/Log.h"
#include "base/io/log/Tags.h"
#include "base/net/stratum/Job.h"
#include "base/tools/Chrono.h"
xmrig::Benchmark::Benchmark(const Job &job, size_t workers, const IBackend *backend) :
m_backend(backend),
m_workers(workers),
m_end(job.benchSize())
{
}
bool xmrig::Benchmark::finish(uint64_t totalHashCount)
{
m_current = totalHashCount;
return BenchState::isDone();
}
void xmrig::Benchmark::start()
{
m_startTime = BenchState::start(m_workers, m_backend);
}
void xmrig::Benchmark::printProgress() const
{
if (!m_startTime || !m_current) {
return;
}
const double dt = static_cast<double>(Chrono::steadyMSecs() - m_startTime) / 1000.0;
const double percent = static_cast<double>(m_current) / m_end * 100.0;
LOG_NOTICE("%s " MAGENTA_BOLD("%5.2f%% ") CYAN_BOLD("%" PRIu64) CYAN("/%" PRIu64) BLACK_BOLD(" (%.3fs)"), Tags::bench(), percent, m_current, m_end, dt);
}

View file

@ -20,61 +20,33 @@
#define XMRIG_BENCHMARK_H
#include "base/crypto/Algorithm.h"
#include "base/kernel/interfaces/IHttpListener.h"
#include "base/tools/Object.h"
#include "base/tools/String.h"
#include <memory>
namespace xmrig {
class IBackend;
class IWorker;
class Job;
class Benchmark : public IHttpListener
class Benchmark
{
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(Benchmark)
Benchmark(const Job &job, size_t workers, const IBackend *backend);
~Benchmark() override = default;
~Benchmark() = default;
bool finish(uint64_t totalHashCount);
void printProgress() const;
void start();
void tick(IWorker *worker);
protected:
void onHttpData(const HttpData &data) override;
private:
uint64_t referenceHash() const;
void printExit();
# ifdef XMRIG_FEATURE_HTTP
void send(const rapidjson::Value &body);
void setError(const char *message);
# endif
bool m_reset = false;
const Algorithm m_algo;
const IBackend *m_backend;
const size_t m_workers;
const String m_id;
const String m_token;
const uint64_t m_end;
const uint64_t m_hash;
std::shared_ptr<IHttpListener> m_httpListener;
uint32_t m_done = 0;
uint64_t m_current = 0;
uint64_t m_data = 0;
uint64_t m_doneTime = 0;
uint64_t m_startTime = 0;
};

View file

@ -23,6 +23,15 @@ set(SOURCES_BACKEND_COMMON
)
if (WITH_RANDOMX AND WITH_BENCHMARK)
list(APPEND HEADERS_BACKEND_COMMON src/backend/common/Benchmark.h)
list(APPEND SOURCES_BACKEND_COMMON src/backend/common/Benchmark.cpp)
list(APPEND HEADERS_BACKEND_COMMON
src/backend/common/benchmark/Benchmark.h
src/backend/common/benchmark/BenchState_test.h
src/backend/common/benchmark/BenchState.h
src/backend/common/interfaces/IBenchListener.h
)
list(APPEND SOURCES_BACKEND_COMMON
src/backend/common/benchmark/Benchmark.cpp
src/backend/common/benchmark/BenchState.cpp
)
endif()

View file

@ -0,0 +1,48 @@
/* XMRig
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_IBENCHLISTENER_H
#define XMRIG_IBENCHLISTENER_H
#include "base/tools/Object.h"
namespace xmrig {
class IBackend;
class IBenchListener
{
public:
XMRIG_DISABLE_COPY_MOVE(IBenchListener)
IBenchListener() = default;
virtual ~IBenchListener() = default;
virtual void onBenchDone(uint64_t result, uint64_t ts) = 0;
virtual void onBenchStart(uint64_t ts, uint32_t threads, const IBackend *backend) = 0;
};
} /* namespace xmrig */
#endif // XMRIG_IBENCHLISTENER_H

View file

@ -26,6 +26,9 @@
#define XMRIG_IWORKER_H
#include "base/tools/Object.h"
#include <cstdint>
#include <cstddef>
@ -40,7 +43,10 @@ class Job;
class IWorker
{
public:
virtual ~IWorker() = default;
XMRIG_DISABLE_COPY_MOVE(IWorker)
IWorker() = default;
virtual ~IWorker() = default;
virtual bool selfTest() = 0;
virtual const VirtualMemory *memory() const = 0;
@ -50,11 +56,6 @@ public:
virtual void getHashrateData(uint64_t&, uint64_t&) const = 0;
virtual void start() = 0;
virtual void jobEarlyNotification(const Job&) = 0;
# ifdef XMRIG_FEATURE_BENCHMARK
virtual uint64_t benchData() const = 0;
virtual uint64_t benchDoneTime() const = 0;
# endif
};

View file

@ -56,7 +56,7 @@
#ifdef XMRIG_FEATURE_BENCHMARK
# include "backend/common/Benchmark.h"
# include "backend/common/benchmark/Benchmark.h"
#endif

View file

@ -53,6 +53,11 @@
#endif
#ifdef XMRIG_FEATURE_BENCHMARK
# include "backend/common/benchmark/BenchState.h"
#endif
namespace xmrig {
static constexpr uint32_t kReserveCount = 32768;
@ -245,8 +250,7 @@ void xmrig::CpuWorker<N>::start()
// Stop benchmark when all hashes have been counted
if (done) {
m_benchDoneTime = Chrono::steadyMSecs();
return;
return BenchState::done(m_benchData, Chrono::steadyMSecs());;
}
// Make each hash dependent on the previous one in single thread benchmark to prevent cheating with multiple threads

View file

@ -91,6 +91,10 @@ private:
# ifdef XMRIG_ALGO_RANDOMX
randomx_vm *m_vm = nullptr;
# endif
# ifdef XMRIG_FEATURE_BENCHMARK
uint64_t m_benchData = 0;
# endif
};

View file

@ -119,6 +119,7 @@ namespace xmrig {
class AsyncPrivate
{
public:
Async::Callback callback;
IAsyncListener *listener = nullptr;
uv_async_t *async = nullptr;
};
@ -127,6 +128,16 @@ public:
} // namespace xmrig
xmrig::Async::Async(Callback callback) : d_ptr(new AsyncPrivate())
{
d_ptr->callback = std::move(callback);
d_ptr->async = new uv_async_t;
d_ptr->async->data = this;
uv_async_init(uv_default_loop(), d_ptr->async, [](uv_async_t *handle) { static_cast<Async *>(handle->data)->d_ptr->callback(); });
}
xmrig::Async::Async(IAsyncListener *listener) : d_ptr(new AsyncPrivate())
{
d_ptr->listener = listener;

View file

@ -25,6 +25,9 @@
#include "base/tools/Object.h"
#include <functional>
namespace xmrig {
@ -37,6 +40,9 @@ class Async
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(Async)
using Callback = std::function<void()>;
Async(Callback callback);
Async(IAsyncListener *listener);
~Async();

View file

@ -176,9 +176,7 @@ void xmrig::Job::copy(const Job &other)
# endif
# ifdef XMRIG_FEATURE_BENCHMARK
m_benchSize = other.m_benchSize;
m_benchHash = other.m_benchHash;
m_benchToken = other.m_benchToken;
m_benchSize = other.m_benchSize;
# endif
}
@ -213,8 +211,6 @@ void xmrig::Job::move(Job &&other)
# endif
# ifdef XMRIG_FEATURE_BENCHMARK
m_benchSize = other.m_benchSize;
m_benchHash = other.m_benchHash;
m_benchToken = std::move(other.m_benchToken);
m_benchSize = other.m_benchSize;
# endif
}

View file

@ -112,12 +112,8 @@ public:
inline Job &operator=(Job &&other) noexcept { move(std::move(other)); return *this; }
# ifdef XMRIG_FEATURE_BENCHMARK
inline const String &benchToken() const { return m_benchToken; }
inline uint32_t benchSize() const { return m_benchSize; }
inline uint64_t benchHash() const { return m_benchHash; }
inline void setBenchHash(uint64_t benchHash) { m_benchHash = benchHash; }
inline void setBenchSize(uint32_t size) { m_benchSize = size; }
inline void setBenchToken(const String &token) { m_benchToken = token; }
# endif
private:
@ -146,9 +142,7 @@ private:
# endif
# ifdef XMRIG_FEATURE_BENCHMARK
String m_benchToken;
uint32_t m_benchSize = 0;
uint64_t m_benchHash = 0;
# endif
};

View file

@ -19,6 +19,8 @@
#include "base/net/stratum/benchmark/BenchClient.h"
#include "3rdparty/fmt/core.h"
#include "3rdparty/rapidjson/document.h"
#include "backend/common/benchmark/BenchState.h"
#include "backend/common/interfaces/IBackend.h"
#include "backend/cpu/Cpu.h"
#include "base/io/json/Json.h"
#include "base/io/log/Log.h"
@ -33,7 +35,8 @@
xmrig::BenchClient::BenchClient(const std::shared_ptr<BenchConfig> &benchmark, IClientListener* listener) :
m_listener(listener),
m_benchmark(benchmark)
m_benchmark(benchmark),
m_hash(benchmark->hash())
{
std::vector<char> blob(112 * 2 + 1, '0');
blob.back() = '\0';
@ -43,7 +46,8 @@ xmrig::BenchClient::BenchClient(const std::shared_ptr<BenchConfig> &benchmark, I
m_job.setDiff(std::numeric_limits<uint64_t>::max());
m_job.setHeight(1);
m_job.setBenchSize(m_benchmark->size());
m_job.setBenchHash(m_benchmark->hash());
BenchState::setListener(this);
# ifdef XMRIG_FEATURE_HTTP
if (m_benchmark->isSubmit()) {
@ -54,8 +58,8 @@ xmrig::BenchClient::BenchClient(const std::shared_ptr<BenchConfig> &benchmark, I
if (!m_benchmark->id().isEmpty()) {
m_job.setId(m_benchmark->id());
m_job.setBenchToken(m_benchmark->token());
m_mode = ONLINE_VERIFY;
m_token = m_benchmark->token();
m_mode = ONLINE_VERIFY;
return;
}
@ -63,7 +67,7 @@ xmrig::BenchClient::BenchClient(const std::shared_ptr<BenchConfig> &benchmark, I
m_job.setId("00000000");
if (m_job.benchHash() && m_job.setSeedHash(m_benchmark->seed())) {
if (m_hash && m_job.setSeedHash(m_benchmark->seed())) {
m_mode = STATIC_VERIFY;
return;
@ -74,6 +78,12 @@ xmrig::BenchClient::BenchClient(const std::shared_ptr<BenchConfig> &benchmark, I
}
xmrig::BenchClient::~BenchClient()
{
BenchState::destroy();
}
void xmrig::BenchClient::connect()
{
# ifdef XMRIG_FEATURE_HTTP
@ -100,6 +110,54 @@ void xmrig::BenchClient::setPool(const Pool &pool)
}
void xmrig::BenchClient::onBenchDone(uint64_t result, uint64_t ts)
{
# ifdef XMRIG_FEATURE_HTTP
if (m_mode == ONLINE_BENCH) {
m_doneTime = ts;
rapidjson::Document doc(rapidjson::kObjectType);
auto &allocator = doc.GetAllocator();
doc.AddMember("steady_done_ts", m_doneTime, allocator);
doc.AddMember("hash", rapidjson::Value(fmt::format("{:016X}", result).c_str(), allocator), allocator);
doc.AddMember("backend", m_backend->toJSON(doc), allocator);
update(doc);
}
# endif
const uint64_t ref = referenceHash();
const char *color = ref ? ((result == ref) ? GREEN_BOLD_S : RED_BOLD_S) : BLACK_BOLD_S;
LOG_NOTICE("%s " WHITE_BOLD("benchmark finished in ") CYAN_BOLD("%.3f seconds") WHITE_BOLD_S " hash sum = " CLEAR "%s%016" PRIX64 CLEAR, Tags::bench(), static_cast<double>(ts - m_startTime) / 1000.0, color, result);
if (m_mode != ONLINE_BENCH) {
printExit();
}
}
void xmrig::BenchClient::onBenchStart(uint64_t ts, uint32_t threads, const IBackend *backend)
{
m_startTime = ts;
m_threads = threads;
m_backend = backend;
# ifdef XMRIG_FEATURE_HTTP
if (m_mode == ONLINE_BENCH) {
rapidjson::Document doc(rapidjson::kObjectType);
auto &allocator = doc.GetAllocator();
doc.AddMember("threads", threads, allocator);
doc.AddMember("steady_start_ts", m_startTime, allocator);
update(doc);
}
# endif
}
void xmrig::BenchClient::onHttpData(const HttpData &data)
{
# ifdef XMRIG_FEATURE_HTTP
@ -116,15 +174,39 @@ void xmrig::BenchClient::onHttpData(const HttpData &data)
}
if (m_mode == ONLINE_BENCH) {
startBench(doc);
}
else {
startVerify(doc);
if (!m_startTime) {
return startBench(doc);
}
if (m_doneTime) {
LOG_NOTICE("%s " WHITE_BOLD("benchmark submitted ") CYAN_BOLD("https://xmrig.com/benchmark/%s"), Tags::bench(), m_job.id().data());
printExit();
}
return;
}
startVerify(doc);
# endif
}
uint64_t xmrig::BenchClient::referenceHash() const
{
if (m_hash || m_mode == ONLINE_BENCH) {
return m_hash;
}
return BenchState::referenceHash(m_job.algorithm(), m_job.benchSize(), m_threads);
}
void xmrig::BenchClient::printExit()
{
LOG_INFO("%s " WHITE_BOLD("press ") MAGENTA_BOLD("Ctrl+C") WHITE_BOLD(" to exit"), Tags::bench());
}
void xmrig::BenchClient::start()
{
m_listener->onLoginSuccess(this);
@ -180,7 +262,8 @@ void xmrig::BenchClient::startBench(const rapidjson::Value &value)
{
m_job.setId(Json::getString(value, BenchConfig::kId));
m_job.setSeedHash(Json::getString(value, BenchConfig::kSeed));
m_job.setBenchToken(Json::getString(value, BenchConfig::kToken));
m_token = Json::getString(value, BenchConfig::kToken);
start();
}
@ -190,7 +273,7 @@ void xmrig::BenchClient::startVerify(const rapidjson::Value &value)
{
const char *hash = Json::getString(value, BenchConfig::kHash);
if (hash) {
m_job.setBenchHash(strtoull(hash, nullptr, 16));
m_hash = strtoull(hash, nullptr, 16);
}
m_job.setAlgorithm(Json::getString(value, BenchConfig::kAlgo));
@ -199,4 +282,15 @@ void xmrig::BenchClient::startVerify(const rapidjson::Value &value)
start();
}
void xmrig::BenchClient::update(const rapidjson::Value &body)
{
assert(!m_token.isEmpty());
FetchRequest req(HTTP_PATCH, BenchConfig::kApiHost, BenchConfig::kApiPort, fmt::format("/1/benchmark/{}", m_job.id()).c_str(), body, BenchConfig::kApiTLS, true);
req.headers.insert({ "Authorization", fmt::format("Bearer {}", m_token)});
fetch(std::move(req), m_httpListener);
}
#endif

View file

@ -20,20 +20,21 @@
#define XMRIG_BENCHCLIENT_H
#include "base/net/stratum/Client.h"
#include "backend/common/interfaces/IBenchListener.h"
#include "base/kernel/interfaces/IHttpListener.h"
#include "base/net/stratum/Client.h"
namespace xmrig {
class BenchClient : public IClient, public IHttpListener
class BenchClient : public IClient, public IHttpListener, public IBenchListener
{
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(BenchClient)
BenchClient(const std::shared_ptr<BenchConfig> &benchmark, IClientListener* listener);
~BenchClient() override = default;
~BenchClient() override;
inline bool disconnect() override { return true; }
inline bool hasExtension(Extension) const noexcept override { return false; }
@ -52,7 +53,7 @@ public:
inline int64_t sequence() const override { return 0; }
inline int64_t submit(const JobResult &) override { return 0; }
inline void connect(const Pool &pool) override { setPool(pool); }
inline void deleteLater() override {}
inline void deleteLater() override { delete this; }
inline void setAlgo(const Algorithm &algo) override {}
inline void setEnabled(bool enabled) override {}
inline void setProxy(const ProxyUrl &proxy) override {}
@ -65,6 +66,8 @@ public:
void setPool(const Pool &pool) override;
protected:
void onBenchDone(uint64_t result, uint64_t ts) override;
void onBenchStart(uint64_t ts, uint32_t threads, const IBackend *backend) override;
void onHttpData(const HttpData &data) override;
private:
@ -75,6 +78,8 @@ private:
ONLINE_VERIFY
};
uint64_t referenceHash() const;
void printExit();
void start();
# ifdef XMRIG_FEATURE_HTTP
@ -84,15 +89,22 @@ private:
void setError(const char *message);
void startBench(const rapidjson::Value &value);
void startVerify(const rapidjson::Value &value);
void update(const rapidjson::Value &body);
# endif
const IBackend *m_backend = nullptr;
IClientListener* m_listener;
Job m_job;
Mode m_mode = STATIC_BENCH;
Pool m_pool;
std::shared_ptr<BenchConfig> m_benchmark;
std::shared_ptr<IHttpListener> m_httpListener;
String m_ip;
Mode m_mode = STATIC_BENCH;
String m_token;
uint32_t m_threads = 0;
uint64_t m_doneTime = 0;
uint64_t m_hash = 0;
uint64_t m_startTime = 0;
};