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

@ -23,40 +23,28 @@
*/
#include "crypto/rx/RxConfig.h"
#include "base/io/json/Json.h"
#include "rapidjson/document.h"
#include "crypto/common/HugePagesInfo.h"
#include "crypto/common/VirtualMemory.h"
namespace xmrig {
static const char *kInit = "init";
static const char *kMode = "mode";
constexpr size_t twoMiB = 2U * 1024U * 1024U;
constexpr size_t oneGiB = 1024U * 1024U * 1024U;
}
} // namespace xmrig
rapidjson::Value xmrig::RxConfig::toJSON(rapidjson::Document &doc) const
xmrig::HugePagesInfo::HugePagesInfo(const VirtualMemory *memory)
{
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;
if (memory->isOneGbPages()) {
size = VirtualMemory::align(memory->size(), oneGiB);
total = size / oneGiB;
allocated = size / oneGiB;
}
else {
size = memory->size();
total = size / twoMiB;
allocated = memory->isHugePages() ? total : 0;
}
return false;
}

View file

@ -0,0 +1,67 @@
/* 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/>.
*/
#ifndef XMRIG_HUGEPAGESINFO_H
#define XMRIG_HUGEPAGESINFO_H
#include <cstdint>
#include <cstddef>
namespace xmrig {
class VirtualMemory;
class HugePagesInfo
{
public:
HugePagesInfo() = default;
HugePagesInfo(const VirtualMemory *memory);
size_t allocated = 0;
size_t total = 0;
size_t size = 0;
inline bool isFullyAllocated() const { return allocated == total; }
inline double percent() const { return allocated == 0 ? 0.0 : static_cast<double>(allocated) / total * 100.0; }
inline void reset() { allocated = 0; total = 0; size = 0; }
inline HugePagesInfo &operator+=(const HugePagesInfo &other)
{
allocated += other.allocated;
total += other.total;
size += other.size;
return *this;
}
};
} /* namespace xmrig */
#endif /* XMRIG_HUGEPAGESINFO_H */

View file

@ -0,0 +1,103 @@
/* 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 <iostream>
#include "crypto/common/LinuxMemory.h"
#include "base/io/log/Log.h"
#include "crypto/common/VirtualMemory.h"
#include "backend/cpu/Cpu.h"
#include <algorithm>
#include <fstream>
#include <string>
#include <mutex>
namespace xmrig {
static std::mutex mutex;
constexpr size_t twoMiB = 2U * 1024U * 1024U;
constexpr size_t oneGiB = 1024U * 1024U * 1024U;
static inline std::string sysfs_path(uint32_t node, bool oneGbPages, bool nr)
{
return "/sys/devices/system/node/node" + std::to_string(node) + "/hugepages/hugepages-" + (oneGbPages ? "1048576" : "2048") + "kB/" + (nr ? "nr" : "free") + "_hugepages";
}
static inline bool write_nr_hugepages(uint32_t node, bool oneGbPages, uint64_t count) { return LinuxMemory::write(sysfs_path(node, oneGbPages, true).c_str(), count); }
static inline int64_t free_hugepages(uint32_t node, bool oneGbPages) { return LinuxMemory::read(sysfs_path(node, oneGbPages, false).c_str()); }
static inline int64_t nr_hugepages(uint32_t node, bool oneGbPages) { return LinuxMemory::read(sysfs_path(node, oneGbPages, true).c_str()); }
} // namespace xmrig
bool xmrig::LinuxMemory::reserve(size_t size, uint32_t node, bool oneGbPages)
{
std::lock_guard<std::mutex> lock(mutex);
const size_t pageSize = oneGbPages ? oneGiB : twoMiB;
const size_t required = VirtualMemory::align(size, pageSize) / pageSize;
const auto available = free_hugepages(node, oneGbPages);
if (available < 0 || static_cast<size_t>(available) >= required) {
return false;
}
return write_nr_hugepages(node, oneGbPages, std::max<size_t>(nr_hugepages(node, oneGbPages), 0) + (required - available));
}
bool xmrig::LinuxMemory::write(const char *path, uint64_t value)
{
std::ofstream file(path, std::ios::out | std::ios::binary | std::ios::trunc);
if (!file.is_open()) {
return false;
}
file << value;
file.flush();
return true;
}
int64_t xmrig::LinuxMemory::read(const char *path)
{
std::ifstream file(path);
if (!file.is_open()) {
return -1;
}
uint64_t value = 0;
file >> value;
return value;
}

View file

@ -0,0 +1,49 @@
/* 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/>.
*/
#ifndef XMRIG_LINUXMEMORY_H
#define XMRIG_LINUXMEMORY_H
#include <cstdint>
#include <cstddef>
namespace xmrig {
class LinuxMemory
{
public:
static bool reserve(size_t size, uint32_t node, bool oneGbPages = false);
static bool write(const char *path, uint64_t value);
static int64_t read(const char *path);
};
} /* namespace xmrig */
#endif /* XMRIG_LINUXMEMORY_H */

View file

@ -47,7 +47,7 @@ xmrig::MemoryPool::MemoryPool(size_t size, bool hugePages, uint32_t node)
return;
}
m_memory = new VirtualMemory(size * pageSize, hugePages, false, node);
m_memory = new VirtualMemory(size * pageSize, hugePages, false, false, node);
}

View file

@ -46,10 +46,13 @@ namespace xmrig {
static IMemoryPool *pool = nullptr;
static std::mutex mutex;
constexpr size_t twoMiB = 2U * 1024U * 1024U;
constexpr size_t oneGiB = 1024U * 1024U * 1024U;
} // namespace xmrig
xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, bool usePool, uint32_t node, size_t alignSize) :
xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, bool oneGbPages, bool usePool, uint32_t node, size_t alignSize) :
m_size(align(size)),
m_node(node)
{
@ -68,6 +71,10 @@ xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, bool usePool, u
}
}
if (oneGbPages && allocateOneGbPagesMemory()) {
return;
}
if (hugePages && allocateLargePagesMemory()) {
return;
}
@ -86,7 +93,7 @@ xmrig::VirtualMemory::~VirtualMemory()
std::lock_guard<std::mutex> lock(mutex);
pool->release(m_node);
}
else if (isHugePages()) {
else if (isHugePages() || isOneGbPages()) {
freeLargePagesMemory();
}
else {
@ -95,6 +102,12 @@ xmrig::VirtualMemory::~VirtualMemory()
}
xmrig::HugePagesInfo xmrig::VirtualMemory::hugePages() const
{
return { this };
}
#ifndef XMRIG_FEATURE_HWLOC
uint32_t xmrig::VirtualMemory::bindToNUMANode(int64_t)
{

View file

@ -29,6 +29,7 @@
#include "base/tools/Object.h"
#include "crypto/common/HugePagesInfo.h"
#include <bitset>
@ -45,22 +46,23 @@ class VirtualMemory
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(VirtualMemory)
VirtualMemory(size_t size, bool hugePages, bool usePool, uint32_t node = 0, size_t alignSize = 64);
VirtualMemory(size_t size, bool hugePages, bool oneGbPages, bool usePool, uint32_t node = 0, size_t alignSize = 64);
~VirtualMemory();
inline bool isHugePages() const { return m_flags.test(FLAG_HUGEPAGES); }
inline bool isOneGbPages() const { return m_flags.test(FLAG_1GB_PAGES); }
inline size_t size() const { return m_size; }
inline uint8_t *raw() const { return m_scratchpad; }
inline uint8_t *scratchpad() const { return m_scratchpad; }
inline std::pair<size_t, size_t> hugePages() const
{
return { isHugePages() ? (align(size()) / 2097152) : 0, align(size()) / 2097152 };
}
HugePagesInfo hugePages() const;
static bool isHugepagesAvailable();
static bool isOneGbPagesAvailable();
static uint32_t bindToNUMANode(int64_t affinity);
static void *allocateExecutableMemory(size_t size);
static void *allocateLargePagesMemory(size_t size);
static void *allocateOneGbPagesMemory(size_t size);
static void destroy();
static void flushInstructionCache(void *p, size_t size);
static void freeLargePagesMemory(void *p, size_t size);
@ -73,6 +75,7 @@ public:
private:
enum Flags {
FLAG_HUGEPAGES,
FLAG_1GB_PAGES,
FLAG_LOCK,
FLAG_EXTERNAL,
FLAG_MAX
@ -81,6 +84,7 @@ private:
static void osInit(bool hugePages);
bool allocateLargePagesMemory();
bool allocateOneGbPagesMemory();
void freeLargePagesMemory();
const size_t m_size;

View file

@ -29,6 +29,7 @@
#include <sys/mman.h>
#include "backend/cpu/Cpu.h"
#include "crypto/common/portable/mm_malloc.h"
#include "crypto/common/VirtualMemory.h"
@ -38,12 +39,30 @@
#endif
#if defined(XMRIG_OS_LINUX)
# if (defined(MAP_HUGE_1GB) || defined(MAP_HUGE_SHIFT))
# define XMRIG_HAS_1GB_PAGES
# endif
# include "crypto/common/LinuxMemory.h"
#endif
bool xmrig::VirtualMemory::isHugepagesAvailable()
{
return true;
}
bool xmrig::VirtualMemory::isOneGbPagesAvailable()
{
# ifdef XMRIG_HAS_1GB_PAGES
return Cpu::info()->hasOneGbPages();
# else
return false;
# endif
}
void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size)
{
# if defined(__APPLE__)
@ -70,6 +89,28 @@ void *xmrig::VirtualMemory::allocateLargePagesMemory(size_t size)
}
void *xmrig::VirtualMemory::allocateOneGbPagesMemory(size_t size)
{
# ifdef XMRIG_HAS_1GB_PAGES
if (isOneGbPagesAvailable()) {
# if defined(MAP_HUGE_1GB)
constexpr int flag_1gb = MAP_HUGE_1GB;
# elif defined(MAP_HUGE_SHIFT)
constexpr int flag_1gb = (30 << MAP_HUGE_SHIFT);
# else
constexpr int flag_1gb = 0;
# endif
void *mem = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE | flag_1gb, 0, 0);
return mem == MAP_FAILED ? nullptr : mem;
}
# endif
return nullptr;
}
void xmrig::VirtualMemory::flushInstructionCache(void *p, size_t size)
{
# ifdef HAVE_BUILTIN_CLEAR_CACHE
@ -103,6 +144,10 @@ void xmrig::VirtualMemory::osInit(bool)
bool xmrig::VirtualMemory::allocateLargePagesMemory()
{
# if defined(XMRIG_OS_LINUX)
LinuxMemory::reserve(m_size, m_node);
# endif
m_scratchpad = static_cast<uint8_t*>(allocateLargePagesMemory(m_size));
if (m_scratchpad) {
m_flags.set(FLAG_HUGEPAGES, true);
@ -120,6 +165,29 @@ bool xmrig::VirtualMemory::allocateLargePagesMemory()
}
bool xmrig::VirtualMemory::allocateOneGbPagesMemory()
{
# if defined(XMRIG_HAS_1GB_PAGES)
LinuxMemory::reserve(m_size, m_node, true);
# endif
m_scratchpad = static_cast<uint8_t*>(allocateOneGbPagesMemory(m_size));
if (m_scratchpad) {
m_flags.set(FLAG_1GB_PAGES, true);
madvise(m_scratchpad, m_size, MADV_RANDOM | MADV_WILLNEED);
if (mlock(m_scratchpad, m_size) == 0) {
m_flags.set(FLAG_LOCK, true);
}
return true;
}
return false;
}
void xmrig::VirtualMemory::freeLargePagesMemory()
{
if (m_flags.test(FLAG_LOCK)) {

View file

@ -156,6 +156,12 @@ bool xmrig::VirtualMemory::isHugepagesAvailable()
}
bool xmrig::VirtualMemory::isOneGbPagesAvailable()
{
return false;
}
void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size)
{
return VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
@ -175,6 +181,12 @@ void *xmrig::VirtualMemory::allocateLargePagesMemory(size_t size)
}
void *xmrig::VirtualMemory::allocateOneGbPagesMemory(size_t)
{
return nullptr;
}
void xmrig::VirtualMemory::flushInstructionCache(void *p, size_t size)
{
::FlushInstructionCache(GetCurrentProcess(), p, size);
@ -221,6 +233,12 @@ bool xmrig::VirtualMemory::allocateLargePagesMemory()
return false;
}
bool xmrig::VirtualMemory::allocateOneGbPagesMemory()
{
m_scratchpad = nullptr;
return false;
}
void xmrig::VirtualMemory::freeLargePagesMemory()
{

View file

@ -43,7 +43,7 @@ namespace randomx {
}
template<size_t alignment>
void AlignedAllocator<alignment>::freeMemory(void* ptr, size_t count) {
void AlignedAllocator<alignment>::freeMemory(void* ptr, size_t) {
rx_aligned_free(ptr);
}

View file

@ -43,4 +43,9 @@ namespace randomx {
static void freeMemory(void*, size_t);
};
struct OneGbPageAllocator {
static void* allocMemory(size_t);
static void freeMemory(void*, size_t);
};
}

View file

@ -0,0 +1,18 @@
mov rcx, rbp ;# ecx = ma
shr rcx, 32
and ecx, RANDOMX_DATASET_BASE_MASK
xor rbp, rax ;# modify "mx"
mov rax, qword ptr [rdi+rcx]
mov edx, ebp ;# edx = mx
and edx, RANDOMX_DATASET_BASE_MASK
prefetchnta byte ptr [rdi+rdx]
ror rbp, 32 ;# swap "ma" and "mx"
xor r8, rax
xor r9, qword ptr [rdi+rcx+8]
xor r10, qword ptr [rdi+rcx+16]
xor r11, qword ptr [rdi+rcx+24]
xor r12, qword ptr [rdi+rcx+32]
xor r13, qword ptr [rdi+rcx+40]
xor r14, qword ptr [rdi+rcx+48]
xor r15, qword ptr [rdi+rcx+56]

View file

@ -167,7 +167,5 @@ namespace randomx {
typedef void(ProgramFunc)(RegisterFile&, MemoryRegisters&, uint8_t* /* scratchpad */, uint64_t);
typedef void(DatasetInitFunc)(randomx_cache* cache, uint8_t* dataset, uint32_t startBlock, uint32_t endBlock);
typedef void(DatasetDeallocFunc)(randomx_dataset*);
typedef void(CacheDeallocFunc)(randomx_cache*);
typedef void(CacheInitializeFunc)(randomx_cache*, const void*, size_t);
}

View file

@ -38,13 +38,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* Global scope for C binding */
struct randomx_dataset {
uint8_t* memory = nullptr;
randomx::DatasetDeallocFunc* dealloc;
};
/* Global scope for C binding */
struct randomx_cache {
uint8_t* memory = nullptr;
randomx::CacheDeallocFunc* dealloc;
randomx::JitCompiler* jit;
randomx::CacheInitializeFunc* initialize;
randomx::DatasetInitFunc* datasetInit;

View file

@ -118,7 +118,7 @@ static void clear_code_cache(char* p1, char* p2)
# endif
}
void JitCompilerA64::generateProgram(Program& program, ProgramConfiguration& config)
void JitCompilerA64::generateProgram(Program& program, ProgramConfiguration& config, uint32_t)
{
uint32_t codePos = MainLoopBegin + 4;

View file

@ -49,7 +49,7 @@ namespace randomx {
JitCompilerA64();
~JitCompilerA64();
void generateProgram(Program&, ProgramConfiguration&);
void generateProgram(Program&, ProgramConfiguration&, uint32_t);
void generateProgramLight(Program&, ProgramConfiguration&, uint32_t);
template<size_t N>

View file

@ -44,7 +44,7 @@ namespace randomx {
JitCompilerFallback() {
throw std::runtime_error("JIT compilation is not supported on this platform");
}
void generateProgram(Program&, ProgramConfiguration&) {
void generateProgram(Program&, ProgramConfiguration&, uint32_t) {
}
void generateProgramLight(Program&, ProgramConfiguration&, uint32_t) {

View file

@ -89,7 +89,6 @@ namespace randomx {
const uint8_t* codeLoopBegin = (uint8_t*)&randomx_program_loop_begin;
const uint8_t* codeLoopLoad = (uint8_t*)&randomx_program_loop_load;
const uint8_t* codeProgamStart = (uint8_t*)&randomx_program_start;
const uint8_t* codeReadDataset = (uint8_t*)&randomx_program_read_dataset;
const uint8_t* codeReadDatasetLightSshInit = (uint8_t*)&randomx_program_read_dataset_sshash_init;
const uint8_t* codeReadDatasetLightSshFin = (uint8_t*)&randomx_program_read_dataset_sshash_fin;
const uint8_t* codeDatasetInit = (uint8_t*)&randomx_dataset_init;
@ -105,7 +104,6 @@ namespace randomx {
const int32_t prefetchScratchpadSize = codePrefetchScratchpadEnd - codePrefetchScratchpad;
const int32_t prologueSize = codeLoopBegin - codePrologue;
const int32_t loopLoadSize = codeProgamStart - codeLoopLoad;
const int32_t readDatasetSize = codeReadDatasetLightSshInit - codeReadDataset;
const int32_t readDatasetLightInitSize = codeReadDatasetLightSshFin - codeReadDatasetLightSshInit;
const int32_t readDatasetLightFinSize = codeLoopStore - codeReadDatasetLightSshFin;
const int32_t loopStoreSize = codeLoopEnd - codeLoopStore;
@ -171,6 +169,7 @@ namespace randomx {
static const uint8_t REX_DIVPD[] = { 0x66, 0x41, 0x0f, 0x5e };
static const uint8_t SQRTPD[] = { 0x66, 0x0f, 0x51 };
static const uint8_t AND_OR_MOV_LDMXCSR[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x89, 0x44, 0x24, 0xFC, 0x0F, 0xAE, 0x54, 0x24, 0xFC };
static const uint8_t AND_OR_MOV_LDMXCSR_RYZEN[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x3B, 0x44, 0x24, 0xFC, 0x74, 0x09, 0x89, 0x44, 0x24, 0xFC, 0x0F, 0xAE, 0x54, 0x24, 0xFC };
static const uint8_t ROL_RAX[] = { 0x48, 0xc1, 0xc0 };
static const uint8_t XOR_ECX_ECX[] = { 0x33, 0xC9 };
static const uint8_t REX_CMP_R32I[] = { 0x41, 0x81 };
@ -301,10 +300,24 @@ namespace randomx {
freePagedMemory(allocatedCode, CodeSize);
}
void JitCompilerX86::generateProgram(Program& prog, ProgramConfiguration& pcfg) {
void JitCompilerX86::generateProgram(Program& prog, ProgramConfiguration& pcfg, uint32_t flags) {
vm_flags = flags;
generateProgramPrologue(prog, pcfg);
memcpy(code + codePos, RandomX_CurrentConfig.codeReadDatasetTweaked, readDatasetSize);
codePos += readDatasetSize;
uint8_t* p;
uint32_t n;
if (flags & RANDOMX_FLAG_RYZEN) {
p = RandomX_CurrentConfig.codeReadDatasetRyzenTweaked;
n = RandomX_CurrentConfig.codeReadDatasetRyzenTweakedSize;
}
else {
p = RandomX_CurrentConfig.codeReadDatasetTweaked;
n = RandomX_CurrentConfig.codeReadDatasetTweakedSize;
}
memcpy(code + codePos, p, n);
codePos += n;
generateProgramEpilogue(prog, pcfg);
}
@ -1000,7 +1013,12 @@ namespace randomx {
emit(ROL_RAX, p, pos);
emitByte(rotate, p, pos);
}
emit(AND_OR_MOV_LDMXCSR, p, pos);
if (vm_flags & RANDOMX_FLAG_RYZEN) {
emit(AND_OR_MOV_LDMXCSR_RYZEN, p, pos);
}
else {
emit(AND_OR_MOV_LDMXCSR, p, pos);
}
codePos = pos;
}

View file

@ -49,7 +49,7 @@ namespace randomx {
public:
JitCompilerX86();
~JitCompilerX86();
void generateProgram(Program&, ProgramConfiguration&);
void generateProgram(Program&, ProgramConfiguration&, uint32_t);
void generateProgramLight(Program&, ProgramConfiguration&, uint32_t);
template<size_t N>
void generateSuperscalarHash(SuperscalarProgram (&programs)[N], std::vector<uint64_t> &);
@ -70,6 +70,7 @@ namespace randomx {
uint8_t* allocatedCode;
uint8_t* code;
int32_t codePos;
uint32_t vm_flags;
static bool BranchesWithin32B;

View file

@ -45,6 +45,7 @@
.global DECL(randomx_program_loop_load)
.global DECL(randomx_program_start)
.global DECL(randomx_program_read_dataset)
.global DECL(randomx_program_read_dataset_ryzen)
.global DECL(randomx_program_read_dataset_sshash_init)
.global DECL(randomx_program_read_dataset_sshash_fin)
.global DECL(randomx_program_loop_store)
@ -92,6 +93,7 @@ DECL(randomx_program_prologue_first_load):
and eax, RANDOMX_SCRATCHPAD_MASK
ror rdx, 32
and edx, RANDOMX_SCRATCHPAD_MASK
stmxcsr dword ptr [rsp-20]
jmp DECL(randomx_program_loop_begin)
.balign 64
@ -110,6 +112,9 @@ DECL(randomx_program_start):
DECL(randomx_program_read_dataset):
#include "asm/program_read_dataset.inc"
DECL(randomx_program_read_dataset_ryzen):
#include "asm/program_read_dataset_ryzen.inc"
DECL(randomx_program_read_dataset_sshash_init):
#include "asm/program_read_dataset_sshash_init.inc"

View file

@ -36,6 +36,7 @@ PUBLIC randomx_program_loop_begin
PUBLIC randomx_program_loop_load
PUBLIC randomx_program_start
PUBLIC randomx_program_read_dataset
PUBLIC randomx_program_read_dataset_ryzen
PUBLIC randomx_program_read_dataset_sshash_init
PUBLIC randomx_program_read_dataset_sshash_fin
PUBLIC randomx_dataset_init
@ -80,6 +81,7 @@ randomx_program_prologue_first_load PROC
and eax, RANDOMX_SCRATCHPAD_MASK
ror rdx, 32
and edx, RANDOMX_SCRATCHPAD_MASK
stmxcsr dword ptr [rsp-20]
jmp randomx_program_loop_begin
randomx_program_prologue_first_load ENDP
@ -103,6 +105,10 @@ randomx_program_read_dataset PROC
include asm/program_read_dataset.inc
randomx_program_read_dataset ENDP
randomx_program_read_dataset_ryzen PROC
include asm/program_read_dataset_ryzen.inc
randomx_program_read_dataset_ryzen ENDP
randomx_program_read_dataset_sshash_init PROC
include asm/program_read_dataset_sshash_init.inc
randomx_program_read_dataset_sshash_init ENDP

View file

@ -37,6 +37,7 @@ extern "C" {
void randomx_program_loop_load();
void randomx_program_start();
void randomx_program_read_dataset();
void randomx_program_read_dataset_ryzen();
void randomx_program_read_dataset_sshash_init();
void randomx_program_read_dataset_sshash_fin();
void randomx_program_loop_store();

View file

@ -157,8 +157,15 @@ RandomX_ConfigurationBase::RandomX_ConfigurationBase()
}
{
const uint8_t* a = (const uint8_t*)&randomx_program_read_dataset;
const uint8_t* b = (const uint8_t*)&randomx_program_read_dataset_sshash_init;
const uint8_t* b = (const uint8_t*)&randomx_program_read_dataset_ryzen;
memcpy(codeReadDatasetTweaked, a, b - a);
codeReadDatasetTweakedSize = b - a;
}
{
const uint8_t* a = (const uint8_t*)&randomx_program_read_dataset_ryzen;
const uint8_t* b = (const uint8_t*)&randomx_program_read_dataset_sshash_init;
memcpy(codeReadDatasetRyzenTweaked, a, b - a);
codeReadDatasetRyzenTweakedSize = b - a;
}
{
const uint8_t* a = (const uint8_t*)&randomx_program_read_dataset_sshash_init;
@ -191,10 +198,11 @@ void RandomX_ConfigurationBase::Apply()
#if defined(_M_X64) || defined(__x86_64__)
*(uint32_t*)(codeShhPrefetchTweaked + 3) = ArgonMemory * 16 - 1;
const uint32_t DatasetBaseMask = DatasetBaseSize - RANDOMX_DATASET_ITEM_SIZE;
*(uint32_t*)(codeReadDatasetTweaked + 7) = DatasetBaseMask;
*(uint32_t*)(codeReadDatasetTweaked + 23) = DatasetBaseMask;
*(uint32_t*)(codeReadDatasetLightSshInitTweaked + 59) = DatasetBaseMask;
// Not needed right now because all variants use default dataset base size
//const uint32_t DatasetBaseMask = DatasetBaseSize - RANDOMX_DATASET_ITEM_SIZE;
//*(uint32_t*)(codeReadDatasetTweaked + 9) = DatasetBaseMask;
//*(uint32_t*)(codeReadDatasetTweaked + 24) = DatasetBaseMask;
//*(uint32_t*)(codeReadDatasetLightSshInitTweaked + 59) = DatasetBaseMask;
*(uint32_t*)(codePrefetchScratchpadTweaked + 4) = ScratchpadL3Mask64_Calculated;
*(uint32_t*)(codePrefetchScratchpadTweaked + 18) = ScratchpadL3Mask64_Calculated;
@ -264,42 +272,24 @@ RandomX_ConfigurationBase RandomX_CurrentConfig;
extern "C" {
randomx_cache *randomx_alloc_cache(randomx_flags flags) {
randomx_cache *randomx_create_cache(randomx_flags flags, uint8_t *memory) {
randomx_cache *cache = nullptr;
try {
cache = new randomx_cache();
switch (flags & (RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES)) {
switch (flags & RANDOMX_FLAG_JIT) {
case RANDOMX_FLAG_DEFAULT:
cache->dealloc = &randomx::deallocCache<randomx::DefaultAllocator>;
cache->jit = nullptr;
cache->initialize = &randomx::initCache;
cache->datasetInit = &randomx::initDataset;
cache->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(RANDOMX_CACHE_MAX_SIZE);
cache->jit = nullptr;
cache->initialize = &randomx::initCache;
cache->datasetInit = &randomx::initDataset;
cache->memory = memory;
break;
case RANDOMX_FLAG_JIT:
cache->dealloc = &randomx::deallocCache<randomx::DefaultAllocator>;
cache->jit = new randomx::JitCompiler();
cache->initialize = &randomx::initCacheCompile;
cache->datasetInit = cache->jit->getDatasetInitFunc();
cache->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(RANDOMX_CACHE_MAX_SIZE);
break;
case RANDOMX_FLAG_LARGE_PAGES:
cache->dealloc = &randomx::deallocCache<randomx::LargePageAllocator>;
cache->jit = nullptr;
cache->initialize = &randomx::initCache;
cache->datasetInit = &randomx::initDataset;
cache->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(RANDOMX_CACHE_MAX_SIZE);
break;
case RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES:
cache->dealloc = &randomx::deallocCache<randomx::LargePageAllocator>;
cache->jit = new randomx::JitCompiler();
cache->initialize = &randomx::initCacheCompile;
cache->datasetInit = cache->jit->getDatasetInitFunc();
cache->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(RANDOMX_CACHE_MAX_SIZE);
cache->jit = new randomx::JitCompiler();
cache->initialize = &randomx::initCacheCompile;
cache->datasetInit = cache->jit->getDatasetInitFunc();
cache->memory = memory;
break;
default:
@ -323,31 +313,12 @@ extern "C" {
}
void randomx_release_cache(randomx_cache* cache) {
assert(cache != nullptr);
cache->dealloc(cache);
delete cache;
}
randomx_dataset *randomx_alloc_dataset(randomx_flags flags) {
randomx_dataset *dataset = nullptr;
try {
dataset = new randomx_dataset();
if (flags & RANDOMX_FLAG_LARGE_PAGES) {
dataset->dealloc = &randomx::deallocDataset<randomx::LargePageAllocator>;
dataset->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(RANDOMX_DATASET_MAX_SIZE);
}
else {
dataset->dealloc = &randomx::deallocDataset<randomx::DefaultAllocator>;
dataset->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(RANDOMX_DATASET_MAX_SIZE);
}
}
catch (std::exception &ex) {
if (dataset != nullptr) {
randomx_release_dataset(dataset);
dataset = nullptr;
}
}
randomx_dataset *randomx_create_dataset(uint8_t *memory) {
auto dataset = new randomx_dataset();
dataset->memory = memory;
return dataset;
}
@ -372,8 +343,6 @@ extern "C" {
}
void randomx_release_dataset(randomx_dataset *dataset) {
assert(dataset != nullptr);
dataset->dealloc(dataset);
delete dataset;
}
@ -431,6 +400,7 @@ extern "C" {
}
vm->setScratchpad(scratchpad);
vm->setFlags(flags);
}
catch (std::exception &ex) {
delete vm;

View file

@ -48,6 +48,8 @@ enum randomx_flags {
RANDOMX_FLAG_HARD_AES = 2,
RANDOMX_FLAG_FULL_MEM = 4,
RANDOMX_FLAG_JIT = 8,
RANDOMX_FLAG_1GB_PAGES = 16,
RANDOMX_FLAG_RYZEN = 64,
};
@ -117,7 +119,10 @@ struct RandomX_ConfigurationBase
rx_vec_i128 fillAes4Rx4_Key[8];
uint8_t codeShhPrefetchTweaked[20];
uint8_t codeReadDatasetTweaked[64];
uint8_t codeReadDatasetTweaked[256];
uint32_t codeReadDatasetTweakedSize;
uint8_t codeReadDatasetRyzenTweaked[256];
uint32_t codeReadDatasetRyzenTweakedSize;
uint8_t codeReadDatasetLightSshInitTweaked[68];
uint8_t codePrefetchScratchpadTweaked[32];
@ -210,7 +215,7 @@ extern "C" {
* NULL is returned if memory allocation fails or if the RANDOMX_FLAG_JIT
* is set and JIT compilation is not supported on the current platform.
*/
RANDOMX_EXPORT randomx_cache *randomx_alloc_cache(randomx_flags flags);
RANDOMX_EXPORT randomx_cache *randomx_create_cache(randomx_flags flags, uint8_t *memory);
/**
* Initializes the cache memory and SuperscalarHash using the provided key value.
@ -237,7 +242,7 @@ RANDOMX_EXPORT void randomx_release_cache(randomx_cache* cache);
* @return Pointer to an allocated randomx_dataset structure.
* NULL is returned if memory allocation fails.
*/
RANDOMX_EXPORT randomx_dataset *randomx_alloc_dataset(randomx_flags flags);
RANDOMX_EXPORT randomx_dataset *randomx_create_dataset(uint8_t *memory);
/**
* Gets the number of items contained in the dataset.

View file

@ -46,6 +46,9 @@ public:
virtual void run(void* seed) = 0;
void resetRoundingMode();
void setFlags(uint32_t flags) { vm_flags = flags; }
uint32_t getFlags() const { return vm_flags; }
randomx::RegisterFile *getRegisterFile() {
return &reg;
}
@ -71,6 +74,7 @@ protected:
randomx_dataset* datasetPtr;
};
uint64_t datasetOffset;
uint32_t vm_flags;
};
namespace randomx {

View file

@ -43,7 +43,7 @@ namespace randomx {
void CompiledVm<softAes>::run(void* seed) {
VmBase<softAes>::generateProgram(seed);
randomx_vm::initialize();
compiler.generateProgram(program, config);
compiler.generateProgram(program, config, randomx_vm::getFlags());
mem.memory = datasetPtr->memory + datasetOffset;
execute();
}

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,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());
}
}