Merge pull request #1885 from SChernykh/dev

More precise hashrate calculation
This commit is contained in:
xmrig 2020-10-10 16:35:14 +07:00 committed by GitHub
commit 87a54766eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 190 additions and 39 deletions

View file

@ -48,13 +48,13 @@ inline static const char *format(double h, char *buf, size_t size)
xmrig::Hashrate::Hashrate(size_t threads) : xmrig::Hashrate::Hashrate(size_t threads) :
m_threads(threads) m_threads(threads + 1)
{ {
m_counts = new uint64_t*[threads]; m_counts = new uint64_t*[m_threads];
m_timestamps = new uint64_t*[threads]; m_timestamps = new uint64_t*[m_threads];
m_top = new uint32_t[threads]; m_top = new uint32_t[m_threads];
for (size_t i = 0; i < threads; i++) { for (size_t i = 0; i < m_threads; i++) {
m_counts[i] = new uint64_t[kBucketSize](); m_counts[i] = new uint64_t[kBucketSize]();
m_timestamps[i] = new uint64_t[kBucketSize](); m_timestamps[i] = new uint64_t[kBucketSize]();
m_top[i] = 0; m_top[i] = 0;
@ -77,17 +77,8 @@ xmrig::Hashrate::~Hashrate()
double xmrig::Hashrate::calc(size_t ms) const double xmrig::Hashrate::calc(size_t ms) const
{ {
double result = 0.0; const double data = calc(0, ms);
double data; return std::isnormal(data) ? data : 0.0;
for (size_t i = 0; i < m_threads; ++i) {
data = calc(i, ms);
if (std::isnormal(data)) {
result += data;
}
}
return result;
} }
@ -102,7 +93,7 @@ double xmrig::Hashrate::calc(size_t threadId, size_t ms) const
uint64_t earliestStamp = 0; uint64_t earliestStamp = 0;
bool haveFullSet = false; bool haveFullSet = false;
const uint64_t timeStampLimit = xmrig::Chrono::highResolutionMSecs() - ms; const uint64_t timeStampLimit = xmrig::Chrono::steadyMSecs() - ms;
uint64_t* timestamps = m_timestamps[threadId]; uint64_t* timestamps = m_timestamps[threadId];
uint64_t* counts = m_counts[threadId]; uint64_t* counts = m_counts[threadId];
@ -183,9 +174,9 @@ rapidjson::Value xmrig::Hashrate::toJSON(size_t threadId, rapidjson::Document &d
auto &allocator = doc.GetAllocator(); auto &allocator = doc.GetAllocator();
Value out(kArrayType); Value out(kArrayType);
out.PushBack(normalize(calc(threadId, ShortInterval)), allocator); out.PushBack(normalize(calc(threadId + 1, ShortInterval)), allocator);
out.PushBack(normalize(calc(threadId, MediumInterval)), allocator); out.PushBack(normalize(calc(threadId + 1, MediumInterval)), allocator);
out.PushBack(normalize(calc(threadId, LargeInterval)), allocator); out.PushBack(normalize(calc(threadId + 1, LargeInterval)), allocator);
return out; return out;
} }

View file

@ -0,0 +1,63 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* 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
* 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/HashrateInterpolator.h"
uint64_t xmrig::HashrateInterpolator::interpolate(uint64_t timeStamp) const
{
timeStamp -= LagMS;
std::lock_guard<std::mutex> l(m_lock);
const size_t N = m_data.size();
if (N < 2) {
return 0;
}
for (size_t i = 0; i < N - 1; ++i) {
const auto& a = m_data[i];
const auto& b = m_data[i + 1];
if (a.second <= timeStamp && timeStamp <= b.second) {
return a.first + static_cast<int64_t>(b.first - a.first) * (timeStamp - a.second) / (b.second - a.second);
}
}
return 0;
}
void xmrig::HashrateInterpolator::addDataPoint(uint64_t count, uint64_t timeStamp)
{
std::lock_guard<std::mutex> l(m_lock);
// Clean up old data
while (!m_data.empty() && (timeStamp - m_data.front().second > LagMS * 2)) {
m_data.pop_front();
}
m_data.emplace_back(count, timeStamp);
}

View file

@ -0,0 +1,57 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* 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
* 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_HASHRATE_INTERPOLATOR_H
#define XMRIG_HASHRATE_INTERPOLATOR_H
#include <mutex>
#include <deque>
#include <utility>
namespace xmrig {
class HashrateInterpolator
{
public:
enum {
LagMS = 4000,
};
uint64_t interpolate(uint64_t timeStamp) const;
void addDataPoint(uint64_t count, uint64_t timeStamp);
private:
// Buffer of hashrate counters, used for linear interpolation of past data
mutable std::mutex m_lock;
std::deque<std::pair<uint64_t, uint64_t>> m_data;
};
} // namespace xmrig
#endif /* XMRIG_HASHRATE_INTERPOLATOR_H */

View file

@ -48,7 +48,7 @@ void xmrig::Worker::storeStats()
// Fill in the data for that index // Fill in the data for that index
m_hashCount[index] = m_count; m_hashCount[index] = m_count;
m_timestamp[index] = Chrono::highResolutionMSecs(); m_timestamp[index] = Chrono::steadyMSecs();
// Switch to that index // Switch to that index
// All data will be in memory by the time it completes thanks to std::memory_order_seq_cst // All data will be in memory by the time it completes thanks to std::memory_order_seq_cst

View file

@ -44,6 +44,7 @@ public:
inline const VirtualMemory *memory() const override { return nullptr; } inline const VirtualMemory *memory() const override { return nullptr; }
inline size_t id() const override { return m_id; } inline size_t id() const override { return m_id; }
inline uint64_t rawHashes() const override { return m_count; }
void getHashrateData(uint64_t& hashCount, uint64_t& timeStamp) const override; void getHashrateData(uint64_t& hashCount, uint64_t& timeStamp) const override;
inline void jobEarlyNotification(const Job&) override {} inline void jobEarlyNotification(const Job&) override {}

View file

@ -29,6 +29,7 @@
#include "backend/common/Workers.h" #include "backend/common/Workers.h"
#include "backend/cpu/CpuWorker.h" #include "backend/cpu/CpuWorker.h"
#include "base/io/log/Log.h" #include "base/io/log/Log.h"
#include "base/tools/Chrono.h"
#include "base/tools/Object.h" #include "base/tools/Object.h"
@ -142,13 +143,20 @@ void xmrig::Workers<T>::tick(uint64_t)
return; return;
} }
uint64_t totalHashCount = 0;
for (Thread<T> *handle : m_workers) { for (Thread<T> *handle : m_workers) {
if (handle->worker()) { if (handle->worker()) {
uint64_t hashCount, timeStamp; uint64_t hashCount, timeStamp;
handle->worker()->getHashrateData(hashCount, timeStamp); handle->worker()->getHashrateData(hashCount, timeStamp);
d_ptr->hashrate->add(handle->id(), hashCount, timeStamp); d_ptr->hashrate->add(handle->id() + 1, hashCount, timeStamp);
totalHashCount += handle->worker()->rawHashes();
} }
} }
if (totalHashCount > 0) {
d_ptr->hashrate->add(0, totalHashCount, Chrono::steadyMSecs());
}
} }

View file

@ -1,5 +1,6 @@
set(HEADERS_BACKEND_COMMON set(HEADERS_BACKEND_COMMON
src/backend/common/Hashrate.h src/backend/common/Hashrate.h
src/backend/common/HashrateInterpolator.h
src/backend/common/Tags.h src/backend/common/Tags.h
src/backend/common/interfaces/IBackend.h src/backend/common/interfaces/IBackend.h
src/backend/common/interfaces/IRxListener.h src/backend/common/interfaces/IRxListener.h
@ -15,6 +16,7 @@ set(HEADERS_BACKEND_COMMON
set(SOURCES_BACKEND_COMMON set(SOURCES_BACKEND_COMMON
src/backend/common/Hashrate.cpp src/backend/common/Hashrate.cpp
src/backend/common/HashrateInterpolator.cpp
src/backend/common/Threads.cpp src/backend/common/Threads.cpp
src/backend/common/Worker.cpp src/backend/common/Worker.cpp
src/backend/common/Workers.cpp src/backend/common/Workers.cpp

View file

@ -46,6 +46,7 @@ public:
virtual const VirtualMemory *memory() const = 0; virtual const VirtualMemory *memory() const = 0;
virtual size_t id() const = 0; virtual size_t id() const = 0;
virtual size_t intensity() const = 0; virtual size_t intensity() const = 0;
virtual uint64_t rawHashes() const = 0;
virtual void getHashrateData(uint64_t&, uint64_t&) const = 0; virtual void getHashrateData(uint64_t&, uint64_t&) const = 0;
virtual void start() = 0; virtual void start() = 0;
virtual void jobEarlyNotification(const Job&) = 0; virtual void jobEarlyNotification(const Job&) = 0;

View file

@ -304,9 +304,9 @@ void xmrig::CpuBackend::printHashrate(bool details)
Log::print("| %8zu | %8" PRId64 " | %7s | %7s | %7s |", Log::print("| %8zu | %8" PRId64 " | %7s | %7s | %7s |",
i, i,
data.affinity, data.affinity,
Hashrate::format(hashrate()->calc(i, Hashrate::ShortInterval), num, sizeof num / 3), Hashrate::format(hashrate()->calc(i + 1, Hashrate::ShortInterval), num, sizeof num / 3),
Hashrate::format(hashrate()->calc(i, Hashrate::MediumInterval), num + 8, sizeof num / 3), Hashrate::format(hashrate()->calc(i + 1, Hashrate::MediumInterval), num + 8, sizeof num / 3),
Hashrate::format(hashrate()->calc(i, Hashrate::LargeInterval), num + 8 * 2, sizeof num / 3) Hashrate::format(hashrate()->calc(i + 1, Hashrate::LargeInterval), num + 8 * 2, sizeof num / 3)
); );
i++; i++;

View file

@ -218,9 +218,11 @@ void xmrig::CpuWorker<N>::start()
alignas(16) uint64_t tempHash[8] = {}; alignas(16) uint64_t tempHash[8] = {};
// RandomX is faster, we don't need to store stats so often // RandomX is faster, we don't need to store stats so often
# ifndef XMRIG_ARM
if (m_job.currentJob().algorithm().family() == Algorithm::RANDOM_X) { if (m_job.currentJob().algorithm().family() == Algorithm::RANDOM_X) {
storeStatsMask = 63; storeStatsMask = 63;
} }
# endif
# endif # endif
while (!Nonce::isOutdated(Nonce::CPU, m_job.sequence())) { while (!Nonce::isOutdated(Nonce::CPU, m_job.sequence())) {

View file

@ -409,9 +409,9 @@ void xmrig::CudaBackend::printHashrate(bool details)
Log::print("| %8zu | %8" PRId64 " | %8s | %8s | %8s |" CYAN_BOLD(" #%u") YELLOW(" %s") GREEN(" %s"), Log::print("| %8zu | %8" PRId64 " | %8s | %8s | %8s |" CYAN_BOLD(" #%u") YELLOW(" %s") GREEN(" %s"),
i, i,
data.thread.affinity(), data.thread.affinity(),
Hashrate::format(hashrate()->calc(i, Hashrate::ShortInterval) * scale, num, sizeof num / 3), Hashrate::format(hashrate()->calc(i + 1, Hashrate::ShortInterval) * scale, num, sizeof num / 3),
Hashrate::format(hashrate()->calc(i, Hashrate::MediumInterval) * scale, num + 16, sizeof num / 3), Hashrate::format(hashrate()->calc(i + 1, Hashrate::MediumInterval) * scale, num + 16, sizeof num / 3),
Hashrate::format(hashrate()->calc(i, Hashrate::LargeInterval) * scale, num + 16 * 2, sizeof num / 3), Hashrate::format(hashrate()->calc(i + 1, Hashrate::LargeInterval) * scale, num + 16 * 2, sizeof num / 3),
data.device.index(), data.device.index(),
data.device.topology().toString().data(), data.device.topology().toString().data(),
data.device.name().data() data.device.name().data()
@ -421,9 +421,9 @@ void xmrig::CudaBackend::printHashrate(bool details)
} }
Log::print(WHITE_BOLD_S "| - | - | %8s | %8s | %8s |", Log::print(WHITE_BOLD_S "| - | - | %8s | %8s | %8s |",
Hashrate::format(hashrate()->calc(Hashrate::ShortInterval) * scale, num, sizeof num / 3), Hashrate::format(hashrate_short * scale, num, sizeof num / 3),
Hashrate::format(hashrate()->calc(Hashrate::MediumInterval) * scale, num + 16, sizeof num / 3), Hashrate::format(hashrate_medium * scale, num + 16, sizeof num / 3),
Hashrate::format(hashrate()->calc(Hashrate::LargeInterval) * scale, num + 16 * 2, sizeof num / 3) Hashrate::format(hashrate_large * scale, num + 16 * 2, sizeof num / 3)
); );
} }

View file

@ -120,6 +120,12 @@ xmrig::CudaWorker::~CudaWorker()
} }
uint64_t xmrig::CudaWorker::rawHashes() const
{
return m_hashrateData.interpolate(Chrono::steadyMSecs());
}
void xmrig::CudaWorker::jobEarlyNotification(const Job& job) void xmrig::CudaWorker::jobEarlyNotification(const Job& job)
{ {
if (m_runner) { if (m_runner) {
@ -207,5 +213,8 @@ void xmrig::CudaWorker::storeStats()
m_count += m_runner ? m_runner->processedHashes() : 0; m_count += m_runner ? m_runner->processedHashes() : 0;
const uint64_t timeStamp = Chrono::steadyMSecs();
m_hashrateData.addDataPoint(m_count, timeStamp);
Worker::storeStats(); Worker::storeStats();
} }

View file

@ -27,6 +27,7 @@
#define XMRIG_CUDAWORKER_H #define XMRIG_CUDAWORKER_H
#include "backend/common/HashrateInterpolator.h"
#include "backend/common/Worker.h" #include "backend/common/Worker.h"
#include "backend/common/WorkerJob.h" #include "backend/common/WorkerJob.h"
#include "backend/cuda/CudaLaunchData.h" #include "backend/cuda/CudaLaunchData.h"
@ -49,6 +50,7 @@ public:
~CudaWorker() override; ~CudaWorker() override;
uint64_t rawHashes() const override;
void jobEarlyNotification(const Job&) override; void jobEarlyNotification(const Job&) override;
static std::atomic<bool> ready; static std::atomic<bool> ready;
@ -67,6 +69,8 @@ private:
ICudaRunner *m_runner = nullptr; ICudaRunner *m_runner = nullptr;
WorkerJob<1> m_job; WorkerJob<1> m_job;
uint32_t m_deviceIndex; uint32_t m_deviceIndex;
HashrateInterpolator m_hashrateData;
}; };

View file

@ -385,9 +385,9 @@ void xmrig::OclBackend::printHashrate(bool details)
Log::print("| %8zu | %8" PRId64 " | %8s | %8s | %8s |" CYAN_BOLD(" #%u") YELLOW(" %s") " %s", Log::print("| %8zu | %8" PRId64 " | %8s | %8s | %8s |" CYAN_BOLD(" #%u") YELLOW(" %s") " %s",
i, i,
data.affinity, data.affinity,
Hashrate::format(hashrate()->calc(i, Hashrate::ShortInterval) * scale, num, sizeof num / 3), Hashrate::format(hashrate()->calc(i + 1, Hashrate::ShortInterval) * scale, num, sizeof num / 3),
Hashrate::format(hashrate()->calc(i, Hashrate::MediumInterval) * scale, num + 16, sizeof num / 3), Hashrate::format(hashrate()->calc(i + 1, Hashrate::MediumInterval) * scale, num + 16, sizeof num / 3),
Hashrate::format(hashrate()->calc(i, Hashrate::LargeInterval) * scale, num + 16 * 2, sizeof num / 3), Hashrate::format(hashrate()->calc(i + 1, Hashrate::LargeInterval) * scale, num + 16 * 2, sizeof num / 3),
data.device.index(), data.device.index(),
data.device.topology().toString().data(), data.device.topology().toString().data(),
data.device.printableName().data() data.device.printableName().data()
@ -397,9 +397,9 @@ void xmrig::OclBackend::printHashrate(bool details)
} }
Log::print(WHITE_BOLD_S "| - | - | %8s | %8s | %8s |", Log::print(WHITE_BOLD_S "| - | - | %8s | %8s | %8s |",
Hashrate::format(hashrate()->calc(Hashrate::ShortInterval) * scale, num, sizeof num / 3), Hashrate::format(hashrate_short * scale, num, sizeof num / 3),
Hashrate::format(hashrate()->calc(Hashrate::MediumInterval) * scale, num + 16, sizeof num / 3), Hashrate::format(hashrate_medium * scale, num + 16, sizeof num / 3),
Hashrate::format(hashrate()->calc(Hashrate::LargeInterval) * scale, num + 16 * 2, sizeof num / 3) Hashrate::format(hashrate_large * scale, num + 16 * 2, sizeof num / 3)
); );
} }

View file

@ -140,6 +140,12 @@ xmrig::OclWorker::~OclWorker()
} }
uint64_t xmrig::OclWorker::rawHashes() const
{
return m_hashrateData.interpolate(Chrono::steadyMSecs());
}
void xmrig::OclWorker::jobEarlyNotification(const Job& job) void xmrig::OclWorker::jobEarlyNotification(const Job& job)
{ {
if (m_runner) { if (m_runner) {
@ -247,8 +253,11 @@ void xmrig::OclWorker::storeStats(uint64_t t)
} }
m_count += m_runner->processedHashes(); m_count += m_runner->processedHashes();
const uint64_t timeStamp = Chrono::steadyMSecs();
m_sharedData.setRunTime(Chrono::steadyMSecs() - t); m_hashrateData.addDataPoint(m_count, timeStamp);
m_sharedData.setRunTime(timeStamp - t);
Worker::storeStats(); Worker::storeStats();
} }

View file

@ -27,6 +27,7 @@
#define XMRIG_OCLWORKER_H #define XMRIG_OCLWORKER_H
#include "backend/common/HashrateInterpolator.h"
#include "backend/common/Worker.h" #include "backend/common/Worker.h"
#include "backend/common/WorkerJob.h" #include "backend/common/WorkerJob.h"
#include "backend/opencl/OclLaunchData.h" #include "backend/opencl/OclLaunchData.h"
@ -50,6 +51,7 @@ public:
~OclWorker() override; ~OclWorker() override;
uint64_t rawHashes() const override;
void jobEarlyNotification(const Job&) override; void jobEarlyNotification(const Job&) override;
static std::atomic<bool> ready; static std::atomic<bool> ready;
@ -70,6 +72,8 @@ private:
OclSharedData &m_sharedData; OclSharedData &m_sharedData;
WorkerJob<1> m_job; WorkerJob<1> m_job;
uint32_t m_deviceIndex; uint32_t m_deviceIndex;
HashrateInterpolator m_hashrateData;
}; };

View file

@ -203,7 +203,7 @@ public:
continue; continue;
} }
for (size_t i = 0; i < hr->threads(); i++) { for (size_t i = 1; i < hr->threads(); i++) {
Value thread(kArrayType); Value thread(kArrayType);
thread.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); thread.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::ShortInterval)), allocator);
thread.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); thread.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::MediumInterval)), allocator);