Fixed, benchmark validation on NUMA hardware produced incorrect results in some conditions.

This commit is contained in:
XMRig 2020-11-25 09:35:11 +07:00
parent 09b68f3cdb
commit 8686e08336
No known key found for this signature in database
GPG key ID: 446A53638BE94409
12 changed files with 78 additions and 51 deletions

View file

@ -48,12 +48,11 @@ public:
uint32_t remaining = 0; uint32_t remaining = 0;
uint32_t size; uint32_t size;
uint64_t doneTime = 0; uint64_t doneTime = 0;
uint64_t result = 0;
uint64_t topDiff = 0;
}; };
static BenchStatePrivate *d_ptr = nullptr; static BenchStatePrivate *d_ptr = nullptr;
std::atomic<uint64_t> BenchState::m_data{};
} // namespace xmrig } // namespace xmrig
@ -92,7 +91,7 @@ uint64_t xmrig::BenchState::start(size_t threads, const IBackend *backend)
d_ptr->remaining = static_cast<uint32_t>(threads); d_ptr->remaining = static_cast<uint32_t>(threads);
d_ptr->async = std::make_shared<Async>([] { d_ptr->async = std::make_shared<Async>([] {
d_ptr->listener->onBenchDone(d_ptr->result, d_ptr->topDiff, d_ptr->doneTime); d_ptr->listener->onBenchDone(m_data, 0, d_ptr->doneTime);
destroy(); destroy();
}); });
@ -111,15 +110,15 @@ void xmrig::BenchState::destroy()
} }
void xmrig::BenchState::done(uint64_t data, uint64_t diff, uint64_t ts) void xmrig::BenchState::done()
{ {
assert(d_ptr != nullptr && d_ptr->async && d_ptr->remaining > 0); assert(d_ptr != nullptr && d_ptr->async && d_ptr->remaining > 0);
const uint64_t ts = Chrono::steadyMSecs();
std::lock_guard<std::mutex> lock(d_ptr->mutex); std::lock_guard<std::mutex> lock(d_ptr->mutex);
d_ptr->result ^= data;
d_ptr->doneTime = std::max(d_ptr->doneTime, ts); d_ptr->doneTime = std::max(d_ptr->doneTime, ts);
d_ptr->topDiff = std::max(d_ptr->topDiff, diff);
--d_ptr->remaining; --d_ptr->remaining;
if (d_ptr->remaining == 0) { if (d_ptr->remaining == 0) {

View file

@ -20,6 +20,7 @@
#define XMRIG_BENCHSTATE_H #define XMRIG_BENCHSTATE_H
#include <atomic>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
@ -40,9 +41,15 @@ public:
static uint64_t referenceHash(const Algorithm &algo, uint32_t size, uint32_t threads); static uint64_t referenceHash(const Algorithm &algo, uint32_t size, uint32_t threads);
static uint64_t start(size_t threads, const IBackend *backend); static uint64_t start(size_t threads, const IBackend *backend);
static void destroy(); static void destroy();
static void done(uint64_t data, uint64_t diff, uint64_t ts); static void done();
static void init(IBenchListener *listener, uint32_t size); static void init(IBenchListener *listener, uint32_t size);
static void setSize(uint32_t size); static void setSize(uint32_t size);
inline static uint64_t data() { return m_data; }
inline static void add(uint64_t value) { m_data.fetch_xor(value, std::memory_order_relaxed); }
private:
static std::atomic<uint64_t> m_data;
}; };

View file

@ -347,13 +347,7 @@ void xmrig::CpuBackend::setJob(const Job &job)
const auto &cpu = d_ptr->controller->config()->cpu(); const auto &cpu = d_ptr->controller->config()->cpu();
# ifdef XMRIG_FEATURE_BENCHMARK auto threads = cpu.get(d_ptr->controller->miner(), job.algorithm());
const uint32_t benchSize = BenchState::size();
# else
constexpr uint32_t benchSize = 0;
# endif
auto threads = cpu.get(d_ptr->controller->miner(), job.algorithm(), benchSize);
if (!d_ptr->threads.empty() && d_ptr->threads.size() == threads.size() && std::equal(d_ptr->threads.begin(), d_ptr->threads.end(), threads.begin())) { if (!d_ptr->threads.empty() && d_ptr->threads.size() == threads.size() && std::equal(d_ptr->threads.begin(), d_ptr->threads.end(), threads.begin())) {
return; return;
} }
@ -370,7 +364,7 @@ void xmrig::CpuBackend::setJob(const Job &job)
stop(); stop();
# ifdef XMRIG_FEATURE_BENCHMARK # ifdef XMRIG_FEATURE_BENCHMARK
if (benchSize) { if (BenchState::size()) {
d_ptr->benchmark = std::make_shared<Benchmark>(threads.size(), this); d_ptr->benchmark = std::make_shared<Benchmark>(threads.size(), this);
} }
# endif # endif

View file

@ -113,7 +113,7 @@ size_t xmrig::CpuConfig::memPoolSize() const
} }
std::vector<xmrig::CpuLaunchData> xmrig::CpuConfig::get(const Miner *miner, const Algorithm &algorithm, uint32_t benchSize) const std::vector<xmrig::CpuLaunchData> xmrig::CpuConfig::get(const Miner *miner, const Algorithm &algorithm) const
{ {
std::vector<CpuLaunchData> out; std::vector<CpuLaunchData> out;
const auto &threads = m_threads.get(algorithm); const auto &threads = m_threads.get(algorithm);
@ -126,7 +126,7 @@ std::vector<xmrig::CpuLaunchData> xmrig::CpuConfig::get(const Miner *miner, cons
out.reserve(count); out.reserve(count);
for (const auto &thread : threads.data()) { for (const auto &thread : threads.data()) {
out.emplace_back(miner, algorithm, *this, thread, benchSize, count); out.emplace_back(miner, algorithm, *this, thread, count);
} }
return out; return out;

View file

@ -72,7 +72,7 @@ public:
bool isHwAES() const; bool isHwAES() const;
rapidjson::Value toJSON(rapidjson::Document &doc) const; rapidjson::Value toJSON(rapidjson::Document &doc) const;
size_t memPoolSize() const; size_t memPoolSize() const;
std::vector<CpuLaunchData> get(const Miner *miner, const Algorithm &algorithm, uint32_t benchSize) const; std::vector<CpuLaunchData> get(const Miner *miner, const Algorithm &algorithm) const;
void read(const rapidjson::Value &value); void read(const rapidjson::Value &value);
inline bool isEnabled() const { return m_enabled; } inline bool isEnabled() const { return m_enabled; }

View file

@ -32,7 +32,7 @@
#include <algorithm> #include <algorithm>
xmrig::CpuLaunchData::CpuLaunchData(const Miner *miner, const Algorithm &algorithm, const CpuConfig &config, const CpuThread &thread, uint32_t benchSize, size_t threads) : xmrig::CpuLaunchData::CpuLaunchData(const Miner *miner, const Algorithm &algorithm, const CpuConfig &config, const CpuThread &thread, size_t threads) :
algorithm(algorithm), algorithm(algorithm),
assembly(config.assembly()), assembly(config.assembly()),
astrobwtAVX2(config.astrobwtAVX2()), astrobwtAVX2(config.astrobwtAVX2()),
@ -44,7 +44,6 @@ xmrig::CpuLaunchData::CpuLaunchData(const Miner *miner, const Algorithm &algorit
affinity(thread.affinity()), affinity(thread.affinity()),
miner(miner), miner(miner),
threads(threads), threads(threads),
benchSize(benchSize),
intensity(std::min<uint32_t>(thread.intensity(), algorithm.maxIntensity())) intensity(std::min<uint32_t>(thread.intensity(), algorithm.maxIntensity()))
{ {
} }

View file

@ -44,7 +44,7 @@ class Miner;
class CpuLaunchData class CpuLaunchData
{ {
public: public:
CpuLaunchData(const Miner *miner, const Algorithm &algorithm, const CpuConfig &config, const CpuThread &thread, uint32_t benchSize, size_t threads); CpuLaunchData(const Miner *miner, const Algorithm &algorithm, const CpuConfig &config, const CpuThread &thread, size_t threads);
bool isEqual(const CpuLaunchData &other) const; bool isEqual(const CpuLaunchData &other) const;
CnHash::AlgoVariant av() const; CnHash::AlgoVariant av() const;
@ -67,7 +67,6 @@ public:
const int64_t affinity; const int64_t affinity;
const Miner *miner; const Miner *miner;
const size_t threads; const size_t threads;
const uint32_t benchSize;
const uint32_t intensity; const uint32_t intensity;
}; };

View file

@ -62,20 +62,6 @@ namespace xmrig {
static constexpr uint32_t kReserveCount = 32768; static constexpr uint32_t kReserveCount = 32768;
template<size_t N>
inline bool nextRound(WorkerJob<N> &job, uint32_t benchSize)
{
if (!job.nextRound(benchSize ? 1 : kReserveCount, 1)) {
JobResults::done(job.currentJob());
return false;
}
return true;
}
} // namespace xmrig } // namespace xmrig
@ -92,7 +78,6 @@ xmrig::CpuWorker<N>::CpuWorker(size_t id, const CpuLaunchData &data) :
m_astrobwtMaxSize(data.astrobwtMaxSize * 1000), m_astrobwtMaxSize(data.astrobwtMaxSize * 1000),
m_miner(data.miner), m_miner(data.miner),
m_threads(data.threads), m_threads(data.threads),
m_benchSize(data.benchSize),
m_ctx() m_ctx()
{ {
m_memory = new VirtualMemory(m_algorithm.l3() * N, data.hugePages, false, true, m_node); m_memory = new VirtualMemory(m_algorithm.l3() * N, data.hugePages, false, true, m_node);
@ -241,12 +226,12 @@ void xmrig::CpuWorker<N>::start()
# ifdef XMRIG_FEATURE_BENCHMARK # ifdef XMRIG_FEATURE_BENCHMARK
if (m_benchSize) { if (m_benchSize) {
if (current_job_nonces[0] >= m_benchSize) { if (current_job_nonces[0] >= m_benchSize) {
return BenchState::done(m_benchData, m_benchDiff, Chrono::steadyMSecs());; return BenchState::done();
} }
// Make each hash dependent on the previous one in single thread benchmark to prevent cheating with multiple threads // Make each hash dependent on the previous one in single thread benchmark to prevent cheating with multiple threads
if (m_threads == 1) { if (m_threads == 1) {
*(uint64_t*)(m_job.blob()) ^= m_benchData; *(uint64_t*)(m_job.blob()) ^= BenchState::data();
} }
} }
# endif # endif
@ -260,7 +245,7 @@ void xmrig::CpuWorker<N>::start()
randomx_calculate_hash_first(m_vm, tempHash, m_job.blob(), job.size()); randomx_calculate_hash_first(m_vm, tempHash, m_job.blob(), job.size());
} }
if (!nextRound(m_job, m_benchSize)) { if (!nextRound()) {
break; break;
} }
@ -280,7 +265,7 @@ void xmrig::CpuWorker<N>::start()
fn(job.algorithm())(m_job.blob(), job.size(), m_hash, m_ctx, job.height()); fn(job.algorithm())(m_job.blob(), job.size(), m_hash, m_ctx, job.height());
} }
if (!nextRound(m_job, m_benchSize)) { if (!nextRound()) {
break; break;
}; };
} }
@ -292,8 +277,7 @@ void xmrig::CpuWorker<N>::start()
# ifdef XMRIG_FEATURE_BENCHMARK # ifdef XMRIG_FEATURE_BENCHMARK
if (m_benchSize) { if (m_benchSize) {
if (current_job_nonces[i] < m_benchSize) { if (current_job_nonces[i] < m_benchSize) {
m_benchData ^= value; BenchState::add(value);
m_benchDiff = std::max(m_benchDiff, Job::toDiff(value));
} }
} }
else else
@ -315,6 +299,25 @@ void xmrig::CpuWorker<N>::start()
} }
template<size_t N>
bool xmrig::CpuWorker<N>::nextRound()
{
# ifdef XMRIG_FEATURE_BENCHMARK
const uint32_t count = m_benchSize ? 1U : kReserveCount;
# else
constexpr uint32_t count = kReserveCount;
# endif
if (!m_job.nextRound(count, 1)) {
JobResults::done(m_job.currentJob());
return false;
}
return true;
}
template<size_t N> template<size_t N>
bool xmrig::CpuWorker<N>::verify(const Algorithm &algorithm, const uint8_t *referenceValue) bool xmrig::CpuWorker<N>::verify(const Algorithm &algorithm, const uint8_t *referenceValue)
{ {
@ -395,12 +398,17 @@ void xmrig::CpuWorker<N>::consumeJob()
return; return;
} }
m_job.add(m_miner->job(), m_benchSize ? 1 : kReserveCount, Nonce::CPU); auto job = m_miner->job();
# ifdef XMRIG_FEATURE_BENCHMARK # ifdef XMRIG_FEATURE_BENCHMARK
m_benchData = 0; m_benchSize = job.benchSize();
const uint32_t count = m_benchSize ? 1U : kReserveCount;
# else
constexpr uint32_t count = kReserveCount;
# endif # endif
m_job.add(job, count, Nonce::CPU);
# ifdef XMRIG_ALGO_RANDOMX # ifdef XMRIG_ALGO_RANDOMX
if (m_job.currentJob().algorithm().family() == Algorithm::RANDOM_X) { if (m_job.currentJob().algorithm().family() == Algorithm::RANDOM_X) {
allocateRandomX_VM(); allocateRandomX_VM();

View file

@ -68,6 +68,7 @@ private:
void allocateRandomX_VM(); void allocateRandomX_VM();
# endif # endif
bool nextRound();
bool verify(const Algorithm &algorithm, const uint8_t *referenceValue); bool verify(const Algorithm &algorithm, const uint8_t *referenceValue);
bool verify2(const Algorithm &algorithm, const uint8_t *referenceValue); bool verify2(const Algorithm &algorithm, const uint8_t *referenceValue);
void allocateCnCtx(); void allocateCnCtx();
@ -83,18 +84,16 @@ private:
const int m_astrobwtMaxSize; const int m_astrobwtMaxSize;
const Miner *m_miner; const Miner *m_miner;
const size_t m_threads; const size_t m_threads;
const uint32_t m_benchSize;
cryptonight_ctx *m_ctx[N]; cryptonight_ctx *m_ctx[N];
VirtualMemory *m_memory = nullptr; VirtualMemory *m_memory = nullptr;
WorkerJob<N> m_job; WorkerJob<N> m_job;
# ifdef XMRIG_ALGO_RANDOMX # ifdef XMRIG_ALGO_RANDOMX
randomx_vm *m_vm = nullptr; randomx_vm *m_vm = nullptr;
# endif # endif
# ifdef XMRIG_FEATURE_BENCHMARK # ifdef XMRIG_FEATURE_BENCHMARK
uint64_t m_benchData = 0; uint32_t m_benchSize = 0;
uint64_t m_benchDiff = 0;
# endif # endif
}; };

View file

@ -174,6 +174,10 @@ void xmrig::Job::copy(const Job &other)
memcpy(m_rawBlob, other.m_rawBlob, sizeof(m_rawBlob)); memcpy(m_rawBlob, other.m_rawBlob, sizeof(m_rawBlob));
memcpy(m_rawTarget, other.m_rawTarget, sizeof(m_rawTarget)); memcpy(m_rawTarget, other.m_rawTarget, sizeof(m_rawTarget));
# endif # endif
# ifdef XMRIG_FEATURE_BENCHMARK
m_benchSize = other.m_benchSize;
# endif
} }
@ -205,4 +209,8 @@ void xmrig::Job::move(Job &&other)
memcpy(m_rawBlob, other.m_rawBlob, sizeof(m_rawBlob)); memcpy(m_rawBlob, other.m_rawBlob, sizeof(m_rawBlob));
memcpy(m_rawTarget, other.m_rawTarget, sizeof(m_rawTarget)); memcpy(m_rawTarget, other.m_rawTarget, sizeof(m_rawTarget));
# endif # endif
# ifdef XMRIG_FEATURE_BENCHMARK
m_benchSize = other.m_benchSize;
# endif
} }

View file

@ -111,6 +111,11 @@ public:
inline Job &operator=(const Job &other) { copy(other); return *this; } inline Job &operator=(const Job &other) { copy(other); return *this; }
inline Job &operator=(Job &&other) noexcept { move(std::move(other)); return *this; } inline Job &operator=(Job &&other) noexcept { move(std::move(other)); return *this; }
# ifdef XMRIG_FEATURE_BENCHMARK
inline uint32_t benchSize() const { return m_benchSize; }
inline void setBenchSize(uint32_t size) { m_benchSize = size; }
# endif
private: private:
void copy(const Job &other); void copy(const Job &other);
void move(Job &&other); void move(Job &&other);
@ -135,6 +140,10 @@ private:
char m_rawTarget[24]{}; char m_rawTarget[24]{};
String m_rawSeedHash; String m_rawSeedHash;
# endif # endif
# ifdef XMRIG_FEATURE_BENCHMARK
uint32_t m_benchSize = 0;
# endif
}; };

View file

@ -74,6 +74,9 @@ xmrig::BenchClient::BenchClient(const std::shared_ptr<BenchConfig> &benchmark, I
return; return;
} }
m_job.setBenchSize(m_benchmark->size());
} }
@ -218,6 +221,8 @@ bool xmrig::BenchClient::setSeed(const char *seed)
return false; return false;
} }
m_job.setBenchSize(BenchState::size());
LOG_NOTICE("%s " WHITE_BOLD("seed ") BLACK_BOLD("%s"), tag(), seed); LOG_NOTICE("%s " WHITE_BOLD("seed ") BLACK_BOLD("%s"), tag(), seed);
return true; return true;
@ -285,11 +290,11 @@ void xmrig::BenchClient::onGetReply(const rapidjson::Value &value)
m_hash = strtoull(hash, nullptr, 16); m_hash = strtoull(hash, nullptr, 16);
} }
BenchState::setSize(Json::getUint(value, BenchConfig::kSize));
m_job.setAlgorithm(Json::getString(value, BenchConfig::kAlgo)); m_job.setAlgorithm(Json::getString(value, BenchConfig::kAlgo));
setSeed(Json::getString(value, BenchConfig::kSeed)); setSeed(Json::getString(value, BenchConfig::kSeed));
BenchState::setSize(Json::getUint(value, BenchConfig::kSize));
start(); start();
} }