This commit is contained in:
MoneroOcean 2019-12-14 09:24:11 -08:00
commit 01e2945ab7
125 changed files with 4772 additions and 2073 deletions

View file

@ -27,6 +27,7 @@
#include "crypto/rx/Rx.h"
#include "backend/common/Tags.h"
#include "backend/cpu/CpuConfig.h"
#include "base/io/log/Log.h"
#include "crypto/rx/RxConfig.h"
#include "crypto/rx/RxQueue.h"
@ -38,8 +39,9 @@ namespace xmrig {
class RxPrivate;
static const char *tag = BLUE_BG(WHITE_BOLD_S " rx ") " ";
static RxPrivate *d_ptr = nullptr;
static bool osInitialized = false;
static const char *tag = BLUE_BG(WHITE_BOLD_S " rx ") " ";
static RxPrivate *d_ptr = nullptr;
class RxPrivate
@ -60,7 +62,7 @@ const char *xmrig::rx_tag()
}
bool xmrig::Rx::init(const Job &job, const RxConfig &config, bool hugePages)
bool xmrig::Rx::init(const Job &job, const RxConfig &config, const CpuConfig &cpu)
{
if (job.algorithm().family() != Algorithm::RANDOM_X) {
return true;
@ -70,7 +72,12 @@ bool xmrig::Rx::init(const Job &job, const RxConfig &config, bool hugePages)
return true;
}
d_ptr->queue.enqueue(job, config.nodeset(), config.threads(), hugePages, config.mode());
if (!osInitialized) {
osInit(config);
osInitialized = true;
}
d_ptr->queue.enqueue(job, config.nodeset(), config.threads(cpu.limit()), cpu.isHugePages(), config.isOneGbPages(), config.mode(), cpu.priority());
return false;
}
@ -82,15 +89,15 @@ bool xmrig::Rx::isReady(const Job &job)
}
xmrig::RxDataset *xmrig::Rx::dataset(const Job &job, uint32_t nodeId)
xmrig::HugePagesInfo xmrig::Rx::hugePages()
{
return d_ptr->queue.dataset(job, nodeId);
return d_ptr->queue.hugePages();
}
std::pair<uint32_t, uint32_t> xmrig::Rx::hugePages()
xmrig::RxDataset *xmrig::Rx::dataset(const Job &job, uint32_t nodeId)
{
return d_ptr->queue.hugePages();
return d_ptr->queue.dataset(job, nodeId);
}
@ -106,3 +113,10 @@ void xmrig::Rx::init(IRxListener *listener)
{
d_ptr = new RxPrivate(listener);
}
#if !defined(XMRIG_OS_LINUX) || defined(XMRIG_ARM)
void xmrig::Rx::osInit(const RxConfig &)
{
}
#endif

View file

@ -32,11 +32,15 @@
#include <utility>
#include "crypto/common/HugePagesInfo.h"
namespace xmrig
{
class Algorithm;
class CpuConfig;
class IRxListener;
class Job;
class RxConfig;
@ -46,12 +50,15 @@ class RxDataset;
class Rx
{
public:
static bool init(const Job &job, const RxConfig &config, bool hugePages);
static bool init(const Job &job, const RxConfig &config, const CpuConfig &cpu);
static bool isReady(const Job &job);
static HugePagesInfo hugePages();
static RxDataset *dataset(const Job &job, uint32_t nodeId);
static std::pair<uint32_t, uint32_t> hugePages();
static void destroy();
static void init(IRxListener *listener);
private:
static void osInit(const RxConfig &config);
};

View file

@ -69,20 +69,20 @@ public:
}
inline void createDataset(bool hugePages, RxConfig::Mode mode)
inline void createDataset(bool hugePages, bool oneGbPages, RxConfig::Mode mode)
{
const uint64_t ts = Chrono::steadyMSecs();
m_dataset = new RxDataset(hugePages, true, mode);
m_dataset = new RxDataset(hugePages, oneGbPages, true, mode, 0);
printAllocStatus(ts);
}
inline void initDataset(uint32_t threads)
inline void initDataset(uint32_t threads, int priority)
{
const uint64_t ts = Chrono::steadyMSecs();
m_dataset->init(m_seed.data(), threads);
m_dataset->init(m_seed.data(), threads, priority);
LOG_INFO("%s" GREEN_BOLD("dataset ready") BLACK_BOLD(" (%" PRIu64 " ms)"), rx_tag(), Chrono::steadyMSecs() - ts);
@ -94,18 +94,17 @@ private:
void printAllocStatus(uint64_t ts)
{
if (m_dataset->get() != nullptr) {
const auto pages = m_dataset->hugePages();
const double percent = pages.first == 0 ? 0.0 : static_cast<double>(pages.first) / pages.second * 100.0;
const auto pages = m_dataset->hugePages();
LOG_INFO("%s" GREEN_BOLD("allocated") CYAN_BOLD(" %zu MB") BLACK_BOLD(" (%zu+%zu)") " huge pages %s%1.0f%% %u/%u" CLEAR " %sJIT" BLACK_BOLD(" (%" PRIu64 " ms)"),
rx_tag(),
m_dataset->size() / oneMiB,
pages.size / oneMiB,
RxDataset::maxSize() / oneMiB,
RxCache::maxSize() / oneMiB,
(pages.first == pages.second ? GREEN_BOLD_S : (pages.first == 0 ? RED_BOLD_S : YELLOW_BOLD_S)),
percent,
pages.first,
pages.second,
(pages.isFullyAllocated() ? GREEN_BOLD_S : (pages.allocated == 0 ? RED_BOLD_S : YELLOW_BOLD_S)),
pages.percent(),
pages.allocated,
pages.total,
m_dataset->cache()->isJIT() ? GREEN_BOLD_S "+" : RED_BOLD_S "-",
Chrono::steadyMSecs() - ts
);
@ -137,6 +136,16 @@ xmrig::RxBasicStorage::~RxBasicStorage()
}
xmrig::HugePagesInfo xmrig::RxBasicStorage::hugePages() const
{
if (!d_ptr->dataset()) {
return {};
}
return d_ptr->dataset()->hugePages();
}
xmrig::RxDataset *xmrig::RxBasicStorage::dataset(const Job &job, uint32_t) const
{
if (!d_ptr->isReady(job)) {
@ -147,23 +156,13 @@ xmrig::RxDataset *xmrig::RxBasicStorage::dataset(const Job &job, uint32_t) const
}
std::pair<uint32_t, uint32_t> xmrig::RxBasicStorage::hugePages() const
{
if (!d_ptr->dataset()) {
return { 0U, 0U };
}
return d_ptr->dataset()->hugePages();
}
void xmrig::RxBasicStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode mode)
void xmrig::RxBasicStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages, bool oneGbPages, RxConfig::Mode mode, int priority)
{
d_ptr->setSeed(seed);
if (!d_ptr->dataset()) {
d_ptr->createDataset(hugePages, mode);
d_ptr->createDataset(hugePages, oneGbPages, mode);
}
d_ptr->initDataset(threads);
d_ptr->initDataset(threads, priority);
}

View file

@ -48,9 +48,9 @@ public:
~RxBasicStorage() override;
protected:
HugePagesInfo hugePages() const override;
RxDataset *dataset(const Job &job, uint32_t nodeId) const override;
std::pair<uint32_t, uint32_t> hugePages() const override;
void init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode mode) override;
void init(const RxSeed &seed, uint32_t threads, bool hugePages, bool oneGbPages, RxConfig::Mode mode, int priority) override;
private:
RxBasicStoragePrivate *d_ptr;

View file

@ -35,30 +35,25 @@ static_assert(RANDOMX_FLAG_LARGE_PAGES == 1, "RANDOMX_FLAG_LARGE_PAGES flag mism
xmrig::RxCache::RxCache(bool hugePages)
xmrig::RxCache::RxCache(bool hugePages, uint32_t nodeId)
{
if (hugePages) {
m_flags = RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES;
m_cache = randomx_alloc_cache(static_cast<randomx_flags>(m_flags));
}
m_memory = new VirtualMemory(maxSize(), hugePages, false, false, nodeId);
if (!m_cache) {
m_flags = RANDOMX_FLAG_JIT;
m_cache = randomx_alloc_cache(static_cast<randomx_flags>(m_flags));
}
create(m_memory->raw());
}
if (!m_cache) {
m_flags = RANDOMX_FLAG_DEFAULT;
m_cache = randomx_alloc_cache(static_cast<randomx_flags>(m_flags));
}
xmrig::RxCache::RxCache(uint8_t *memory)
{
create(memory);
}
xmrig::RxCache::~RxCache()
{
if (m_cache) {
randomx_release_cache(m_cache);
}
randomx_release_cache(m_cache);
delete m_memory;
}
@ -75,15 +70,18 @@ bool xmrig::RxCache::init(const Buffer &seed)
}
std::pair<uint32_t, uint32_t> xmrig::RxCache::hugePages() const
xmrig::HugePagesInfo xmrig::RxCache::hugePages() const
{
constexpr size_t twoMiB = 2u * 1024u * 1024u;
constexpr size_t total = VirtualMemory::align(maxSize(), twoMiB) / twoMiB;
uint32_t count = 0;
if (isHugePages()) {
count += total;
}
return { count, total };
return m_memory ? m_memory->hugePages() : HugePagesInfo();
}
void xmrig::RxCache::create(uint8_t *memory)
{
m_cache = randomx_create_cache(RANDOMX_FLAG_JIT, memory);
if (!m_cache) {
m_jit = false;
m_cache = randomx_create_cache(RANDOMX_FLAG_DEFAULT, memory);
}
}

View file

@ -33,6 +33,7 @@
#include "base/tools/Buffer.h"
#include "base/tools/Object.h"
#include "crypto/common/HugePagesInfo.h"
#include "crypto/randomx/configuration.h"
@ -48,24 +49,27 @@ class RxCache
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(RxCache)
RxCache(bool hugePages = true);
RxCache(bool hugePages, uint32_t nodeId);
RxCache(uint8_t *memory);
~RxCache();
inline bool isHugePages() const { return m_flags & 1; }
inline bool isJIT() const { return m_flags & 8; }
inline bool isJIT() const { return m_jit; }
inline const Buffer &seed() const { return m_seed; }
inline randomx_cache *get() const { return m_cache; }
inline size_t size() const { return maxSize(); }
bool init(const Buffer &seed);
std::pair<uint32_t, uint32_t> hugePages() const;
HugePagesInfo hugePages() const;
static inline constexpr size_t maxSize() { return RANDOMX_CACHE_MAX_SIZE; }
private:
void create(uint8_t *memory);
bool m_jit = true;
Buffer m_seed;
int m_flags = 0;
randomx_cache *m_cache = nullptr;
randomx_cache *m_cache = nullptr;
VirtualMemory *m_memory = nullptr;
};

View file

@ -25,11 +25,18 @@
#include "crypto/rx/RxConfig.h"
#include "backend/cpu/Cpu.h"
#include "base/io/json/Json.h"
#include "rapidjson/document.h"
#ifdef XMRIG_FEATURE_HWLOC
# include "backend/cpu/platform/HwlocCpuInfo.h"
#endif
#include <array>
#include <algorithm>
#include <cmath>
#ifdef _MSC_VER
@ -39,11 +46,106 @@
namespace xmrig {
static const char *kInit = "init";
static const char *kMode = "mode";
static const char *kOneGbPages = "1gb-pages";
static const char *kWrmsr = "wrmsr";
#ifdef XMRIG_FEATURE_HWLOC
static const char *kNUMA = "numa";
#endif
static const std::array<const char *, RxConfig::ModeMax> modeNames = { "auto", "fast", "light" };
}
} // namespace xmrig
bool xmrig::RxConfig::read(const rapidjson::Value &value)
{
if (value.IsObject()) {
m_threads = Json::getInt(value, kInit, m_threads);
m_mode = readMode(Json::getValue(value, kMode));
m_wrmsr = readMSR(Json::getValue(value, kWrmsr));
# ifdef XMRIG_OS_LINUX
m_oneGbPages = Json::getBool(value, kOneGbPages, m_oneGbPages);
# endif
# ifdef XMRIG_FEATURE_HWLOC
if (m_mode == LightMode) {
m_numa = false;
return true;
}
const auto &numa = Json::getValue(value, kNUMA);
if (numa.IsArray()) {
m_nodeset.reserve(numa.Size());
for (const auto &node : numa.GetArray()) {
if (node.IsUint()) {
m_nodeset.emplace_back(node.GetUint());
}
}
}
else if (numa.IsBool()) {
m_numa = numa.GetBool();
}
# endif
return true;
}
return false;
}
rapidjson::Value xmrig::RxConfig::toJSON(rapidjson::Document &doc) const
{
using namespace rapidjson;
auto &allocator = doc.GetAllocator();
Value obj(kObjectType);
obj.AddMember(StringRef(kInit), m_threads, allocator);
obj.AddMember(StringRef(kMode), StringRef(modeName()), allocator);
obj.AddMember(StringRef(kOneGbPages), m_oneGbPages, allocator);
if (m_wrmsr < 0 || m_wrmsr == 6) {
obj.AddMember(StringRef(kWrmsr), m_wrmsr == 6, allocator);
}
else {
obj.AddMember(StringRef(kWrmsr), m_wrmsr, allocator);
}
# ifdef XMRIG_FEATURE_HWLOC
if (!m_nodeset.empty()) {
Value numa(kArrayType);
for (uint32_t i : m_nodeset) {
numa.PushBack(i, allocator);
}
obj.AddMember(StringRef(kNUMA), numa, allocator);
}
else {
obj.AddMember(StringRef(kNUMA), m_numa, allocator);
}
# endif
return obj;
}
#ifdef XMRIG_FEATURE_HWLOC
std::vector<uint32_t> xmrig::RxConfig::nodeset() const
{
if (!m_nodeset.empty()) {
return m_nodeset;
}
return (m_numa && Cpu::info()->nodes() > 1) ? static_cast<HwlocCpuInfo *>(Cpu::info())->nodeset() : std::vector<uint32_t>();
}
#endif
const char *xmrig::RxConfig::modeName() const
@ -52,9 +154,31 @@ const char *xmrig::RxConfig::modeName() const
}
uint32_t xmrig::RxConfig::threads() const
uint32_t xmrig::RxConfig::threads(uint32_t limit) const
{
return m_threads < 1 ? static_cast<uint32_t>(Cpu::info()->threads()) : static_cast<uint32_t>(m_threads);
if (m_threads > 0) {
return m_threads;
}
if (limit < 100) {
return std::max(static_cast<uint32_t>(round(Cpu::info()->threads() * (limit / 100.0))), 1U);
}
return Cpu::info()->threads();
}
int xmrig::RxConfig::readMSR(const rapidjson::Value &value) const
{
if (value.IsInt()) {
return std::min(value.GetInt(), 15);
}
if (value.IsBool() && !value.GetBool()) {
return -1;
}
return m_wrmsr;
}

View file

@ -55,16 +55,21 @@ public:
# endif
const char *modeName() const;
uint32_t threads() const;
uint32_t threads(uint32_t limit = 100) const;
inline Mode mode() const { return m_mode; }
inline bool isOneGbPages() const { return m_oneGbPages; }
inline int wrmsr() const { return m_wrmsr; }
inline Mode mode() const { return m_mode; }
private:
int readMSR(const rapidjson::Value &value) const;
Mode readMode(const rapidjson::Value &value) const;
bool m_numa = true;
int m_threads = -1;
Mode m_mode = AutoMode;
bool m_numa = true;
bool m_oneGbPages = false;
int m_threads = -1;
int m_wrmsr = 6;
Mode m_mode = AutoMode;
# ifdef XMRIG_FEATURE_HWLOC
std::vector<uint32_t> m_nodeset;

View file

@ -1,62 +0,0 @@
/* 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-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 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 "crypto/rx/RxConfig.h"
#include "base/io/json/Json.h"
#include "rapidjson/document.h"
namespace xmrig {
static const char *kInit = "init";
static const char *kMode = "mode";
}
rapidjson::Value xmrig::RxConfig::toJSON(rapidjson::Document &doc) const
{
using namespace rapidjson;
auto &allocator = doc.GetAllocator();
Value obj(kObjectType);
obj.AddMember(StringRef(kInit), m_threads, allocator);
obj.AddMember(StringRef(kMode), StringRef(modeName()), allocator);
return obj;
}
bool xmrig::RxConfig::read(const rapidjson::Value &value)
{
if (value.IsObject()) {
m_threads = Json::getInt(value, kInit, m_threads);
m_mode = readMode(Json::getValue(value, kMode));
return true;
}
return false;
}

View file

@ -1,109 +0,0 @@
/* 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-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 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/cpu/Cpu.h"
#include "backend/cpu/platform/HwlocCpuInfo.h"
#include "base/io/json/Json.h"
#include "crypto/rx/RxConfig.h"
#include "rapidjson/document.h"
namespace xmrig {
static const char *kInit = "init";
static const char *kMode = "mode";
static const char *kNUMA = "numa";
}
rapidjson::Value xmrig::RxConfig::toJSON(rapidjson::Document &doc) const
{
using namespace rapidjson;
auto &allocator = doc.GetAllocator();
Value obj(kObjectType);
obj.AddMember(StringRef(kInit), m_threads, allocator);
obj.AddMember(StringRef(kMode), StringRef(modeName()), allocator);
if (!m_nodeset.empty()) {
Value numa(kArrayType);
for (uint32_t i : m_nodeset) {
numa.PushBack(i, allocator);
}
obj.AddMember(StringRef(kNUMA), numa, allocator);
}
else {
obj.AddMember(StringRef(kNUMA), m_numa, allocator);
}
return obj;
}
bool xmrig::RxConfig::read(const rapidjson::Value &value)
{
if (value.IsObject()) {
m_threads = Json::getInt(value, kInit, m_threads);
m_mode = readMode(Json::getValue(value, kMode));
if (m_mode == LightMode) {
m_numa = false;
return true;
}
const auto &numa = Json::getValue(value, kNUMA);
if (numa.IsArray()) {
m_nodeset.reserve(numa.Size());
for (const auto &node : numa.GetArray()) {
if (node.IsUint()) {
m_nodeset.emplace_back(node.GetUint());
}
}
}
else if (numa.IsBool()) {
m_numa = numa.GetBool();
}
return true;
}
return false;
}
std::vector<uint32_t> xmrig::RxConfig::nodeset() const
{
if (!m_nodeset.empty()) {
return m_nodeset;
}
return (m_numa && Cpu::info()->nodes() > 1) ? static_cast<HwlocCpuInfo *>(Cpu::info())->nodeset() : std::vector<uint32_t>();
}

View file

@ -28,8 +28,8 @@
#include "crypto/rx/RxDataset.h"
#include "backend/common/Tags.h"
#include "base/io/log/Log.h"
#include "base/kernel/Platform.h"
#include "crypto/common/VirtualMemory.h"
#include "crypto/randomx/randomx.h"
#include "crypto/rx/RxAlgo.h"
#include "crypto/rx/RxCache.h"
@ -38,21 +38,40 @@
#include <uv.h>
static_assert(RANDOMX_FLAG_LARGE_PAGES == 1, "RANDOMX_FLAG_LARGE_PAGES flag mismatch");
namespace xmrig {
xmrig::RxDataset::RxDataset(bool hugePages, bool cache, RxConfig::Mode mode) :
m_mode(mode)
static void init_dataset_wrapper(randomx_dataset *dataset, randomx_cache *cache, unsigned long startItem, unsigned long itemCount, int priority)
{
allocate(hugePages);
Platform::setThreadPriority(priority);
randomx_init_dataset(dataset, cache, startItem, itemCount);
}
} // namespace xmrig
xmrig::RxDataset::RxDataset(bool hugePages, bool oneGbPages, bool cache, RxConfig::Mode mode, uint32_t node) :
m_mode(mode),
m_node(node)
{
allocate(hugePages, oneGbPages);
if (isOneGbPages()) {
m_cache = new RxCache(m_memory->raw() + VirtualMemory::align(maxSize()));
return;
}
if (cache) {
m_cache = new RxCache(hugePages);
m_cache = new RxCache(hugePages, node);
}
}
xmrig::RxDataset::RxDataset(RxCache *cache) :
m_node(0),
m_cache(cache)
{
}
@ -60,15 +79,14 @@ xmrig::RxDataset::RxDataset(RxCache *cache) :
xmrig::RxDataset::~RxDataset()
{
if (m_dataset) {
randomx_release_dataset(m_dataset);
}
randomx_release_dataset(m_dataset);
delete m_cache;
delete m_memory;
}
bool xmrig::RxDataset::init(const Buffer &seed, uint32_t numThreads)
bool xmrig::RxDataset::init(const Buffer &seed, uint32_t numThreads, int priority)
{
if (!m_cache) {
return false;
@ -89,7 +107,7 @@ bool xmrig::RxDataset::init(const Buffer &seed, uint32_t numThreads)
for (uint64_t i = 0; i < numThreads; ++i) {
const uint32_t a = (datasetItemCount * i) / numThreads;
const uint32_t b = (datasetItemCount * (i + 1)) / numThreads;
threads.emplace_back(randomx_init_dataset, m_dataset, m_cache->get(), a, b - a);
threads.emplace_back(init_dataset_wrapper, m_dataset, m_cache->get(), a, b - a, priority);
}
for (uint32_t i = 0; i < numThreads; ++i) {
@ -97,13 +115,37 @@ bool xmrig::RxDataset::init(const Buffer &seed, uint32_t numThreads)
}
}
else {
randomx_init_dataset(m_dataset, m_cache->get(), 0, datasetItemCount);
init_dataset_wrapper(m_dataset, m_cache->get(), 0, datasetItemCount, priority);
}
return true;
}
bool xmrig::RxDataset::isHugePages() const
{
return m_memory && m_memory->isHugePages();
}
bool xmrig::RxDataset::isOneGbPages() const
{
return m_memory && m_memory->isOneGbPages();
}
xmrig::HugePagesInfo xmrig::RxDataset::hugePages(bool cache) const
{
auto pages = m_memory ? m_memory->hugePages() : HugePagesInfo();
if (cache && m_cache) {
pages += m_cache->hugePages();
}
return pages;
}
size_t xmrig::RxDataset::size(bool cache) const
{
size_t size = 0;
@ -120,29 +162,6 @@ size_t xmrig::RxDataset::size(bool cache) const
}
std::pair<uint32_t, uint32_t> xmrig::RxDataset::hugePages(bool cache) const
{
constexpr size_t twoMiB = 2U * 1024U * 1024U;
constexpr size_t cacheSize = VirtualMemory::align(RxCache::maxSize(), twoMiB) / twoMiB;
size_t total = VirtualMemory::align(maxSize(), twoMiB) / twoMiB;
uint32_t count = 0;
if (isHugePages()) {
count += total;
}
if (cache && m_cache) {
total += cacheSize;
if (m_cache->isHugePages()) {
count += cacheSize;
}
}
return { count, total };
}
void *xmrig::RxDataset::raw() const
{
return m_dataset ? randomx_get_dataset_memory(m_dataset) : nullptr;
@ -159,7 +178,7 @@ void xmrig::RxDataset::setRaw(const void *raw)
}
void xmrig::RxDataset::allocate(bool hugePages)
void xmrig::RxDataset::allocate(bool hugePages, bool oneGbPages)
{
if (m_mode == RxConfig::LightMode) {
LOG_ERR(CLEAR "%s" RED_BOLD_S "fast RandomX mode disabled by config", rx_tag());
@ -173,13 +192,12 @@ void xmrig::RxDataset::allocate(bool hugePages)
return;
}
if (hugePages) {
m_flags = RANDOMX_FLAG_LARGE_PAGES;
m_dataset = randomx_alloc_dataset(static_cast<randomx_flags>(m_flags));
}
m_memory = new VirtualMemory(maxSize(), hugePages, oneGbPages, false, m_node);
m_dataset = randomx_create_dataset(m_memory->raw());
if (!m_dataset) {
m_flags = RANDOMX_FLAG_DEFAULT;
m_dataset = randomx_alloc_dataset(static_cast<randomx_flags>(m_flags));
# ifdef XMRIG_OS_LINUX
if (oneGbPages && !isOneGbPages()) {
LOG_ERR(CLEAR "%s" RED_BOLD_S "failed to allocate RandomX dataset using 1GB pages", rx_tag());
}
# endif
}

View file

@ -30,7 +30,9 @@
#include "base/tools/Object.h"
#include "crypto/common/Algorithm.h"
#include "crypto/common/HugePagesInfo.h"
#include "crypto/randomx/configuration.h"
#include "crypto/randomx/randomx.h"
#include "crypto/rx/RxConfig.h"
@ -43,6 +45,7 @@ namespace xmrig
class Buffer;
class RxCache;
class VirtualMemory;
class RxDataset
@ -50,30 +53,32 @@ class RxDataset
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(RxDataset)
RxDataset(bool hugePages, bool cache, RxConfig::Mode mode);
RxDataset(bool hugePages, bool oneGbPages, bool cache, RxConfig::Mode mode, uint32_t node);
RxDataset(RxCache *cache);
~RxDataset();
inline bool isHugePages() const { return m_flags & 1; }
inline randomx_dataset *get() const { return m_dataset; }
inline RxCache *cache() const { return m_cache; }
inline void setCache(RxCache *cache) { m_cache = cache; }
bool init(const Buffer &seed, uint32_t numThreads);
bool init(const Buffer &seed, uint32_t numThreads, int priority);
bool isHugePages() const;
bool isOneGbPages() const;
HugePagesInfo hugePages(bool cache = true) const;
size_t size(bool cache = true) const;
std::pair<uint32_t, uint32_t> hugePages(bool cache = true) const;
void *raw() const;
void setRaw(const void *raw);
static inline constexpr size_t maxSize() { return RANDOMX_DATASET_MAX_SIZE; }
private:
void allocate(bool hugePages);
void allocate(bool hugePages, bool oneGbPages);
const RxConfig::Mode m_mode = RxConfig::FastMode;
int m_flags = 0;
const uint32_t m_node;
randomx_dataset *m_dataset = nullptr;
RxCache *m_cache = nullptr;
VirtualMemory *m_memory = nullptr;
};

View file

@ -120,18 +120,20 @@ public:
}
inline void createDatasets(bool hugePages)
inline void createDatasets(bool hugePages, bool oneGbPages)
{
const uint64_t ts = Chrono::steadyMSecs();
for (uint32_t node : m_nodeset) {
m_threads.emplace_back(allocate, this, node, hugePages);
m_threads.emplace_back(allocate, this, node, hugePages, oneGbPages);
}
join();
std::thread thread(allocateCache, this, m_nodeset.front(), hugePages);
thread.join();
if (isCacheRequired()) {
std::thread thread(allocateCache, this, m_nodeset.front(), hugePages);
thread.join();
}
if (m_datasets.empty()) {
m_datasets.insert({ m_nodeset.front(), new RxDataset(m_cache) });
@ -139,7 +141,9 @@ public:
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "failed to allocate RandomX datasets, switching to slow mode" BLACK_BOLD(" (%" PRIu64 " ms)"), rx_tag(), Chrono::steadyMSecs() - ts);
}
else {
dataset(m_nodeset.front())->setCache(m_cache);
if (m_cache) {
dataset(m_nodeset.front())->setCache(m_cache);
}
printAllocStatus(ts);
}
@ -148,13 +152,29 @@ public:
}
inline void initDatasets(uint32_t threads)
inline bool isCacheRequired() const
{
if (m_datasets.empty()) {
return true;
}
for (const auto kv : m_datasets) {
if (kv.second->isOneGbPages()) {
return false;
}
}
return true;
}
inline void initDatasets(uint32_t threads, int priority)
{
uint64_t ts = Chrono::steadyMSecs();
auto id = m_nodeset.front();
auto primary = dataset(id);
primary->init(m_seed.data(), threads);
primary->init(m_seed.data(), threads, priority);
printDatasetReady(id, ts);
@ -174,13 +194,11 @@ public:
}
inline std::pair<uint32_t, uint32_t> hugePages() const
inline HugePagesInfo hugePages() const
{
auto pages = m_cache->hugePages();
HugePagesInfo pages;
for (auto const &item : m_datasets) {
const auto p = item.second->hugePages(false);
pages.first += p.first;
pages.second += p.second;
pages += item.second->hugePages();
}
return pages;
@ -188,7 +206,7 @@ public:
private:
static void allocate(RxNUMAStoragePrivate *d_ptr, uint32_t nodeId, bool hugePages)
static void allocate(RxNUMAStoragePrivate *d_ptr, uint32_t nodeId, bool hugePages, bool oneGbPages)
{
const uint64_t ts = Chrono::steadyMSecs();
@ -198,7 +216,7 @@ private:
return;
}
auto dataset = new RxDataset(hugePages, false, RxConfig::FastMode);
auto dataset = new RxDataset(hugePages, oneGbPages, false, RxConfig::FastMode, nodeId);
if (!dataset->get()) {
printSkipped(nodeId, "failed to allocate dataset");
@ -218,7 +236,7 @@ private:
bindToNUMANode(nodeId);
auto cache = new RxCache(hugePages);
auto cache = new RxCache(hugePages, nodeId);
std::lock_guard<std::mutex> lock(mutex);
d_ptr->m_cache = cache;
@ -238,15 +256,14 @@ private:
void printAllocStatus(RxDataset *dataset, uint32_t nodeId, uint64_t ts)
{
const auto pages = dataset->hugePages();
const double percent = pages.first == 0 ? 0.0 : static_cast<double>(pages.first) / pages.second * 100.0;
const auto pages = dataset->hugePages();
LOG_INFO("%s" CYAN_BOLD("#%u ") GREEN_BOLD("allocated") CYAN_BOLD(" %zu MB") " huge pages %s%3.0f%%" CLEAR BLACK_BOLD(" (%" PRIu64 " ms)"),
rx_tag(),
nodeId,
dataset->size() / oneMiB,
(pages.first == pages.second ? GREEN_BOLD_S : RED_BOLD_S),
percent,
pages.size / oneMiB,
(pages.isFullyAllocated() ? GREEN_BOLD_S : RED_BOLD_S),
pages.percent(),
Chrono::steadyMSecs() - ts
);
}
@ -254,15 +271,14 @@ private:
void printAllocStatus(RxCache *cache, uint32_t nodeId, uint64_t ts)
{
const auto pages = cache->hugePages();
const double percent = pages.first == 0 ? 0.0 : static_cast<double>(pages.first) / pages.second * 100.0;
const auto pages = cache->hugePages();
LOG_INFO("%s" CYAN_BOLD("#%u ") GREEN_BOLD("allocated") CYAN_BOLD(" %4zu MB") " huge pages %s%3.0f%%" CLEAR " %sJIT" BLACK_BOLD(" (%" PRIu64 " ms)"),
rx_tag(),
nodeId,
cache->size() / oneMiB,
(pages.first == pages.second ? GREEN_BOLD_S : RED_BOLD_S),
percent,
(pages.isFullyAllocated() ? GREEN_BOLD_S : RED_BOLD_S),
pages.percent(),
cache->isJIT() ? GREEN_BOLD_S "+" : RED_BOLD_S "-",
Chrono::steadyMSecs() - ts
);
@ -271,21 +287,15 @@ private:
void printAllocStatus(uint64_t ts)
{
size_t memory = m_cache->size();
auto pages = hugePages();
const double percent = pages.first == 0 ? 0.0 : static_cast<double>(pages.first) / pages.second * 100.0;
for (auto const &item : m_datasets) {
memory += item.second->size(false);
}
auto pages = hugePages();
LOG_INFO("%s" CYAN_BOLD("-- ") GREEN_BOLD("allocated") CYAN_BOLD(" %4zu MB") " huge pages %s%3.0f%% %u/%u" CLEAR BLACK_BOLD(" (%" PRIu64 " ms)"),
rx_tag(),
memory / oneMiB,
(pages.first == pages.second ? GREEN_BOLD_S : (pages.first == 0 ? RED_BOLD_S : YELLOW_BOLD_S)),
percent,
pages.first,
pages.second,
pages.size / oneMiB,
(pages.isFullyAllocated() ? GREEN_BOLD_S : (pages.allocated == 0 ? RED_BOLD_S : YELLOW_BOLD_S)),
pages.percent(),
pages.allocated,
pages.total,
Chrono::steadyMSecs() - ts
);
}
@ -326,6 +336,16 @@ xmrig::RxNUMAStorage::~RxNUMAStorage()
}
xmrig::HugePagesInfo xmrig::RxNUMAStorage::hugePages() const
{
if (!d_ptr->isAllocated()) {
return {};
}
return d_ptr->hugePages();
}
xmrig::RxDataset *xmrig::RxNUMAStorage::dataset(const Job &job, uint32_t nodeId) const
{
if (!d_ptr->isReady(job)) {
@ -336,23 +356,13 @@ xmrig::RxDataset *xmrig::RxNUMAStorage::dataset(const Job &job, uint32_t nodeId)
}
std::pair<uint32_t, uint32_t> xmrig::RxNUMAStorage::hugePages() const
{
if (!d_ptr->isAllocated()) {
return { 0U, 0U };
}
return d_ptr->hugePages();
}
void xmrig::RxNUMAStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode)
void xmrig::RxNUMAStorage::init(const RxSeed &seed, uint32_t threads, bool hugePages, bool oneGbPages, RxConfig::Mode, int priority)
{
d_ptr->setSeed(seed);
if (!d_ptr->isAllocated()) {
d_ptr->createDatasets(hugePages);
d_ptr->createDatasets(hugePages, oneGbPages);
}
d_ptr->initDatasets(threads);
d_ptr->initDatasets(threads, priority);
}

View file

@ -51,9 +51,9 @@ public:
~RxNUMAStorage() override;
protected:
HugePagesInfo hugePages() const override;
RxDataset *dataset(const Job &job, uint32_t nodeId) const override;
std::pair<uint32_t, uint32_t> hugePages() const override;
void init(const RxSeed &seed, uint32_t threads, bool hugePages, RxConfig::Mode mode) override;
void init(const RxSeed &seed, uint32_t threads, bool hugePages, bool oneGbPages, RxConfig::Mode mode, int priority) override;
private:
RxNUMAStoragePrivate *d_ptr;

View file

@ -86,15 +86,15 @@ xmrig::RxDataset *xmrig::RxQueue::dataset(const Job &job, uint32_t nodeId)
}
std::pair<uint32_t, uint32_t> xmrig::RxQueue::hugePages()
xmrig::HugePagesInfo xmrig::RxQueue::hugePages()
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_storage && m_state == STATE_IDLE ? m_storage->hugePages() : std::pair<uint32_t, uint32_t>(0U, 0U);
return m_storage && m_state == STATE_IDLE ? m_storage->hugePages() : HugePagesInfo();
}
void xmrig::RxQueue::enqueue(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages, RxConfig::Mode mode)
void xmrig::RxQueue::enqueue(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages, bool oneGbPages, RxConfig::Mode mode, int priority)
{
std::unique_lock<std::mutex> lock(m_mutex);
@ -114,7 +114,7 @@ void xmrig::RxQueue::enqueue(const RxSeed &seed, const std::vector<uint32_t> &no
return;
}
m_queue.emplace_back(seed, nodeset, threads, hugePages, mode);
m_queue.emplace_back(seed, nodeset, threads, hugePages, oneGbPages, mode, priority);
m_seed = seed;
m_state = STATE_PENDING;
@ -156,7 +156,7 @@ void xmrig::RxQueue::backgroundInit()
Buffer::toHex(item.seed.data().data(), 8).data()
);
m_storage->init(item.seed, item.threads, item.hugePages, item.mode);
m_storage->init(item.seed, item.threads, item.hugePages, item.oneGbPages, item.mode, item.priority);
lock = std::unique_lock<std::mutex>(m_mutex);

View file

@ -29,6 +29,7 @@
#include "base/tools/Object.h"
#include "crypto/common/HugePagesInfo.h"
#include "crypto/rx/RxConfig.h"
#include "crypto/rx/RxSeed.h"
@ -53,8 +54,10 @@ class RxDataset;
class RxQueueItem
{
public:
RxQueueItem(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages, RxConfig::Mode mode) :
RxQueueItem(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages, bool oneGbPages, RxConfig::Mode mode, int priority) :
hugePages(hugePages),
oneGbPages(oneGbPages),
priority(priority),
mode(mode),
seed(seed),
nodeset(nodeset),
@ -62,6 +65,8 @@ public:
{}
const bool hugePages;
const bool oneGbPages;
const int priority;
const RxConfig::Mode mode;
const RxSeed seed;
const std::vector<uint32_t> nodeset;
@ -79,8 +84,8 @@ public:
bool isReady(const Job &job);
RxDataset *dataset(const Job &job, uint32_t nodeId);
std::pair<uint32_t, uint32_t> hugePages();
void enqueue(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages, RxConfig::Mode mode);
HugePagesInfo hugePages();
void enqueue(const RxSeed &seed, const std::vector<uint32_t> &nodeset, uint32_t threads, bool hugePages, bool oneGbPages, RxConfig::Mode mode, int priority);
private:
enum State {

View file

@ -31,7 +31,7 @@
#include "crypto/rx/RxVm.h"
xmrig::RxVm::RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes)
xmrig::RxVm::RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes, xmrig::Assembly assembly)
{
if (!softAes) {
m_flags |= RANDOMX_FLAG_HARD_AES;
@ -45,6 +45,10 @@ xmrig::RxVm::RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes)
m_flags |= RANDOMX_FLAG_JIT;
}
if ((assembly == Assembly::RYZEN) || ((assembly == Assembly::AUTO) && (Cpu::info()->assembly() == Assembly::RYZEN))) {
m_flags |= RANDOMX_FLAG_RYZEN;
}
m_vm = randomx_create_vm(static_cast<randomx_flags>(m_flags), dataset->cache() ? dataset->cache()->get() : nullptr, dataset->get(), scratchpad);
}

View file

@ -29,6 +29,7 @@
#include "base/tools/Object.h"
#include "backend/cpu/Cpu.h"
#include <cstdint>
@ -49,7 +50,7 @@ class RxVm
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(RxVm);
RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes);
RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes, xmrig::Assembly assembly);
~RxVm();
inline randomx_vm *get() const { return m_vm; }

131
src/crypto/rx/Rx_linux.cpp Normal file
View file

@ -0,0 +1,131 @@
/* 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-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2000 Transmeta Corporation <https://github.com/intel/msr-tools>
* Copyright 2004-2008 H. Peter Anvin <https://github.com/intel/msr-tools>
* Copyright 2016-2019 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 "crypto/rx/Rx.h"
#include "backend/common/Tags.h"
#include "backend/cpu/Cpu.h"
#include "base/io/log/Log.h"
#include "crypto/rx/RxConfig.h"
#include <cctype>
#include <cinttypes>
#include <cstdio>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
namespace xmrig {
static inline int dir_filter(const struct dirent *dirp)
{
return isdigit(dirp->d_name[0]) ? 1 : 0;
}
static bool wrmsr_on_cpu(uint32_t reg, uint32_t cpu, uint64_t value)
{
char msr_file_name[64]{};
sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
int fd = open(msr_file_name, O_WRONLY);
if (fd < 0) {
return false;
}
const bool success = pwrite(fd, &value, sizeof value, reg) == sizeof value;
close(fd);
return success;
}
static bool wrmsr_on_all_cpus(uint32_t reg, uint64_t value)
{
struct dirent **namelist;
int dir_entries = scandir("/dev/cpu", &namelist, dir_filter, 0);
int errors = 0;
while (dir_entries--) {
if (!wrmsr_on_cpu(reg, strtoul(namelist[dir_entries]->d_name, nullptr, 10), value)) {
++errors;
}
free(namelist[dir_entries]);
}
free(namelist);
if (errors) {
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "cannot set MSR 0x%08" PRIx32 " to 0x%08" PRIx64, rx_tag(), reg, value);
}
return errors == 0;
}
static bool wrmsr_modprobe()
{
if (system("/sbin/modprobe msr > /dev/null 2>&1") != 0) {
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "msr kernel module is not available", rx_tag());
return false;
}
return true;
}
} // namespace xmrig
void xmrig::Rx::osInit(const RxConfig &config)
{
if (config.wrmsr() < 0) {
return;
}
if (Cpu::info()->assembly() == Assembly::RYZEN && wrmsr_modprobe()) {
wrmsr_on_all_cpus(0xC0011022, 0x510000);
wrmsr_on_all_cpus(0xC001102b, 0x1808cc16);
wrmsr_on_all_cpus(0xC0011020, 0);
wrmsr_on_all_cpus(0xC0011021, 0x40);
return;
}
if (Cpu::info()->vendor() == ICpuInfo::VENDOR_INTEL && wrmsr_modprobe()) {
wrmsr_on_all_cpus(0x1a4, config.wrmsr());
}
}