Merge branch 'evo' into beta

This commit is contained in:
XMRig 2019-08-03 22:25:26 +07:00
commit 14441ab5f9
24 changed files with 322 additions and 292 deletions

View file

@ -1,3 +1,10 @@
# v2.99.4-beta
- [#1062](https://github.com/xmrig/xmrig/issues/1062) Fixed 32 bit support. **32 bit is slow and deprecated**.
- [#1088](https://github.com/xmrig/xmrig/pull/1088) Fixed macOS compilation.
- [#1095](https://github.com/xmrig/xmrig/pull/1095) Fixed compatibility with hwloc 1.10.x.
- Optimized RandomX initialization and switching, fixed rare crash when re-initialize dataset.
- Fixed ARM build with hwloc.
# v2.99.3-beta # v2.99.3-beta
- [#1082](https://github.com/xmrig/xmrig/issues/1082) Fixed hwloc auto configuration on AMD FX CPUs. - [#1082](https://github.com/xmrig/xmrig/issues/1082) Fixed hwloc auto configuration on AMD FX CPUs.
- Added command line option `--export-topology` for export hwloc topology to a XML file. - Added command line option `--export-topology` for export hwloc topology to a XML file.

View file

@ -34,7 +34,11 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
endif() endif()
if (WIN32) if (WIN32)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -Wl,--large-address-aware")
endif()
else() else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
endif() endif()

View file

@ -26,7 +26,7 @@
#define XMRIG_THREAD_H #define XMRIG_THREAD_H
#include <uv.h> #include <thread>
#include "backend/common/interfaces/IWorker.h" #include "backend/common/interfaces/IWorker.h"
@ -43,21 +43,21 @@ class Thread
{ {
public: public:
inline Thread(IBackend *backend, size_t index, const T &config) : m_index(index), m_config(config), m_backend(backend) {} inline Thread(IBackend *backend, size_t index, const T &config) : m_index(index), m_config(config), m_backend(backend) {}
inline ~Thread() { uv_thread_join(&m_thread); delete m_worker; } inline ~Thread() { m_thread.join(); delete m_worker; }
inline const T &config() const { return m_config; } inline const T &config() const { return m_config; }
inline IBackend *backend() const { return m_backend; } inline IBackend *backend() const { return m_backend; }
inline IWorker *worker() const { return m_worker; } inline IWorker *worker() const { return m_worker; }
inline size_t index() const { return m_index; } inline size_t index() const { return m_index; }
inline void setWorker(IWorker *worker) { m_worker = worker; } inline void setWorker(IWorker *worker) { m_worker = worker; }
inline void start(void (*callback) (void *)) { uv_thread_create(&m_thread, callback, this); } inline void start(void (*callback) (void *)) { m_thread = std::thread(callback, this); }
private: private:
const size_t m_index = 0; const size_t m_index = 0;
const T m_config; const T m_config;
IBackend *m_backend; IBackend *m_backend;
IWorker *m_worker = nullptr; IWorker *m_worker = nullptr;
uv_thread_t m_thread; std::thread m_thread;
}; };

View file

@ -49,6 +49,7 @@ namespace xmrig {
extern template class Threads<CpuThread>; extern template class Threads<CpuThread>;
static const char *tag = CYAN_BG_BOLD(" cpu ");
static const String kType = "cpu"; static const String kType = "cpu";
@ -94,7 +95,8 @@ public:
inline void start() inline void start()
{ {
LOG_INFO(GREEN_BOLD("CPU") " use profile " BLUE_BG(WHITE_BOLD_S " %s ") WHITE_BOLD_S " (" CYAN_BOLD("%zu") WHITE_BOLD(" threads)") " scratchpad " CYAN_BOLD("%zu KB"), LOG_INFO("%s use profile " BLUE_BG(WHITE_BOLD_S " %s ") WHITE_BOLD_S " (" CYAN_BOLD("%zu") WHITE_BOLD(" threads)") " scratchpad " CYAN_BOLD("%zu KB"),
tag,
profileName.data(), profileName.data(),
threads.size(), threads.size(),
algo.memory() / 1024 algo.memory() / 1024
@ -170,12 +172,8 @@ const xmrig::String &xmrig::CpuBackend::type() const
} }
void xmrig::CpuBackend::prepare(const Job &nextJob) void xmrig::CpuBackend::prepare(const Job &)
{ {
if (nextJob.algorithm().family() == Algorithm::RANDOM_X && nextJob.algorithm() != d_ptr->algo) {
d_ptr->workers.stop();
d_ptr->threads.clear();
}
} }
@ -207,9 +205,7 @@ void xmrig::CpuBackend::printHashrate(bool details)
void xmrig::CpuBackend::setJob(const Job &job) void xmrig::CpuBackend::setJob(const Job &job)
{ {
if (!isEnabled()) { if (!isEnabled()) {
d_ptr->workers.stop(); return stop();
d_ptr->threads.clear();
return;
} }
const CpuConfig &cpu = d_ptr->controller->config()->cpu(); const CpuConfig &cpu = d_ptr->controller->config()->cpu();
@ -249,7 +245,8 @@ void xmrig::CpuBackend::start(IWorker *worker)
const double percent = d_ptr->status.hugePages == 0 ? 0.0 : static_cast<double>(d_ptr->status.hugePages) / d_ptr->status.pages * 100.0; const double percent = d_ptr->status.hugePages == 0 ? 0.0 : static_cast<double>(d_ptr->status.hugePages) / d_ptr->status.pages * 100.0;
const size_t memory = d_ptr->status.ways * d_ptr->status.memory / 1024; const size_t memory = d_ptr->status.ways * d_ptr->status.memory / 1024;
LOG_INFO(GREEN_BOLD("CPU READY") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") BLACK_BOLD(" (%" PRIu64 " ms)"), LOG_INFO("%s" GREEN_BOLD(" READY") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") BLACK_BOLD(" (%" PRIu64 " ms)"),
tag,
d_ptr->status.threads, d_ptr->status.ways, d_ptr->status.threads, d_ptr->status.ways,
(d_ptr->status.hugePages == d_ptr->status.pages ? GREEN_BOLD_S : (d_ptr->status.hugePages == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), (d_ptr->status.hugePages == d_ptr->status.pages ? GREEN_BOLD_S : (d_ptr->status.hugePages == 0 ? RED_BOLD_S : YELLOW_BOLD_S)),
d_ptr->status.hugePages, d_ptr->status.pages, percent, memory, d_ptr->status.hugePages, d_ptr->status.pages, percent, memory,
@ -265,7 +262,12 @@ void xmrig::CpuBackend::start(IWorker *worker)
void xmrig::CpuBackend::stop() void xmrig::CpuBackend::stop()
{ {
const uint64_t ts = Chrono::steadyMSecs();
d_ptr->workers.stop(); d_ptr->workers.stop();
d_ptr->threads.clear();
LOG_INFO("%s" YELLOW(" stopped") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, Chrono::steadyMSecs() - ts);
} }

View file

@ -82,7 +82,9 @@ xmrig::CpuWorker<N>::~CpuWorker()
template<size_t N> template<size_t N>
void xmrig::CpuWorker<N>::allocateRandomX_VM() void xmrig::CpuWorker<N>::allocateRandomX_VM()
{ {
while (!Rx::isReady(m_job.currentJob(), m_node)) { RxDataset *dataset = Rx::dataset(m_job.currentJob(), m_node);
while (dataset == nullptr) {
std::this_thread::sleep_for(std::chrono::milliseconds(200)); std::this_thread::sleep_for(std::chrono::milliseconds(200));
if (Nonce::sequence(Nonce::CPU) == 0) { if (Nonce::sequence(Nonce::CPU) == 0) {
@ -90,13 +92,6 @@ void xmrig::CpuWorker<N>::allocateRandomX_VM()
} }
} }
RxDataset *dataset = Rx::dataset(m_node);
assert(dataset != nullptr);
if (!dataset) {
return;
}
if (!m_vm) { if (!m_vm) {
m_vm = new RxVm(dataset, m_memory->scratchpad(), !m_hwAES); m_vm = new RxVm(dataset, m_memory->scratchpad(), !m_hwAES);
} }

View file

@ -39,7 +39,6 @@ if (WITH_HWLOC)
endif() endif()
set(SOURCES_CPUID set(SOURCES_CPUID
src/backend/cpu/platform/BasicCpuInfo.cpp
src/backend/cpu/platform/BasicCpuInfo.h src/backend/cpu/platform/BasicCpuInfo.h
src/backend/cpu/platform/HwlocCpuInfo.cpp src/backend/cpu/platform/HwlocCpuInfo.cpp
src/backend/cpu/platform/HwlocCpuInfo.h src/backend/cpu/platform/HwlocCpuInfo.h
@ -66,7 +65,10 @@ else()
set(SOURCES_CPUID set(SOURCES_CPUID
src/backend/cpu/platform/BasicCpuInfo.h src/backend/cpu/platform/BasicCpuInfo.h
) )
endif()
if (NOT WITH_LIBCPUID)
if (XMRIG_ARM) if (XMRIG_ARM)
set(SOURCES_CPUID ${SOURCES_CPUID} src/backend/cpu/platform/BasicCpuInfo_arm.cpp) set(SOURCES_CPUID ${SOURCES_CPUID} src/backend/cpu/platform/BasicCpuInfo_arm.cpp)
else() else()

View file

@ -36,10 +36,10 @@
xmrig::BasicCpuInfo::BasicCpuInfo() : xmrig::BasicCpuInfo::BasicCpuInfo() :
m_aes(false),
m_brand(), m_brand(),
m_avx2(false), m_threads(std::thread::hardware_concurrency()),
m_threads(std::thread::hardware_concurrency()) m_aes(false),
m_avx2(false)
{ {
# ifdef XMRIG_ARMv8 # ifdef XMRIG_ARMv8
memcpy(m_brand, "ARMv8", 5); memcpy(m_brand, "ARMv8", 5);

View file

@ -32,6 +32,12 @@
#include <hwloc.h> #include <hwloc.h>
#if HWLOC_API_VERSION < 0x00010b00
# define HWLOC_OBJ_PACKAGE HWLOC_OBJ_SOCKET
# define HWLOC_OBJ_NUMANODE HWLOC_OBJ_NODE
#endif
#include "backend/cpu/platform/HwlocCpuInfo.h" #include "backend/cpu/platform/HwlocCpuInfo.h"
#include "base/io/log/Log.h" #include "base/io/log/Log.h"
@ -152,7 +158,21 @@ xmrig::HwlocCpuInfo::HwlocCpuInfo() : BasicCpuInfo(),
# endif # endif
hwloc_obj_t root = hwloc_get_root_obj(m_topology); hwloc_obj_t root = hwloc_get_root_obj(m_topology);
snprintf(m_backend, sizeof m_backend, "hwloc/%s", hwloc_obj_get_info_by_name(root, "hwlocVersion"));
# if HWLOC_API_VERSION >= 0x00010b00
const char *version = hwloc_obj_get_info_by_name(root, "hwlocVersion");
if (version) {
snprintf(m_backend, sizeof m_backend, "hwloc/%s", version);
}
else
# endif
{
snprintf(m_backend, sizeof m_backend, "hwloc/%d.%d.%d",
(HWLOC_API_VERSION>>16)&0x000000ff,
(HWLOC_API_VERSION>>8 )&0x000000ff,
(HWLOC_API_VERSION )&0x000000ff
);
}
findCache(root, 2, 3, [this](hwloc_obj_t found) { this->m_cache[found->attr->cache.depth] += found->attr->cache.size; }); findCache(root, 2, 3, [this](hwloc_obj_t found) { this->m_cache[found->attr->cache.depth] += found->attr->cache.size; });

View file

@ -31,6 +31,7 @@
#include <algorithm> #include <algorithm>
#include <mutex>
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <time.h> #include <time.h>
@ -69,14 +70,11 @@ public:
inline LogPrivate() : inline LogPrivate() :
m_buf() m_buf()
{ {
uv_mutex_init(&m_mutex);
} }
inline ~LogPrivate() inline ~LogPrivate()
{ {
uv_mutex_destroy(&m_mutex);
for (ILogBackend *backend : m_backends) { for (ILogBackend *backend : m_backends) {
delete backend; delete backend;
} }
@ -91,13 +89,14 @@ public:
size_t size = 0; size_t size = 0;
size_t offset = 0; size_t offset = 0;
lock(); std::lock_guard<std::mutex> lock(m_mutex);
timestamp(level, size, offset); timestamp(level, size, offset);
color(level, size); color(level, size);
const int rc = vsnprintf(m_buf + size, sizeof (m_buf) - offset - 32, fmt, args); const int rc = vsnprintf(m_buf + size, sizeof (m_buf) - offset - 32, fmt, args);
if (rc < 0) { if (rc < 0) {
return unlock(); return;
} }
size += std::min(static_cast<size_t>(rc), sizeof (m_buf) - offset - 32); size += std::min(static_cast<size_t>(rc), sizeof (m_buf) - offset - 32);
@ -119,16 +118,10 @@ public:
fputs(txt.c_str(), stdout); fputs(txt.c_str(), stdout);
fflush(stdout); fflush(stdout);
} }
unlock();
} }
private: private:
inline void lock() { uv_mutex_lock(&m_mutex); }
inline void unlock() { uv_mutex_unlock(&m_mutex); }
inline void timestamp(Log::Level level, size_t &size, size_t &offset) inline void timestamp(Log::Level level, size_t &size, size_t &offset)
{ {
if (level == Log::NONE) { if (level == Log::NONE) {
@ -192,8 +185,8 @@ private:
char m_buf[4096]; char m_buf[4096];
std::mutex m_mutex;
std::vector<ILogBackend*> m_backends; std::vector<ILogBackend*> m_backends;
uv_mutex_t m_mutex;
}; };

View file

@ -85,6 +85,8 @@ private:
#define BLUE_BG_BOLD_S CSI "44;1m" #define BLUE_BG_BOLD_S CSI "44;1m"
#define MAGENTA_BG_S CSI "45m" #define MAGENTA_BG_S CSI "45m"
#define MAGENTA_BG_BOLD_S CSI "45;1m" #define MAGENTA_BG_BOLD_S CSI "45;1m"
#define CYAN_BG_S CSI "46m"
#define CYAN_BG_BOLD_S CSI "46;1m"
//color wrappings //color wrappings
#define BLACK(x) BLACK_S x CLEAR #define BLACK(x) BLACK_S x CLEAR
@ -108,6 +110,8 @@ private:
#define BLUE_BG_BOLD(x) BLUE_BG_BOLD_S x CLEAR #define BLUE_BG_BOLD(x) BLUE_BG_BOLD_S x CLEAR
#define MAGENTA_BG(x) MAGENTA_BG_S x CLEAR #define MAGENTA_BG(x) MAGENTA_BG_S x CLEAR
#define MAGENTA_BG_BOLD(x) MAGENTA_BG_BOLD_S x CLEAR #define MAGENTA_BG_BOLD(x) MAGENTA_BG_BOLD_S x CLEAR
#define CYAN_BG(x) CYAN_BG_S x CLEAR
#define CYAN_BG_BOLD(x) CYAN_BG_BOLD_S x CLEAR
#define LOG_EMERG(x, ...) xmrig::Log::print(xmrig::Log::EMERG, x, ##__VA_ARGS__) #define LOG_EMERG(x, ...) xmrig::Log::print(xmrig::Log::EMERG, x, ##__VA_ARGS__)

View file

@ -160,3 +160,20 @@ void xmrig::Job::setDiff(uint64_t diff)
m_rawTarget[16] = '\0'; m_rawTarget[16] = '\0';
# endif # endif
} }
void xmrig::Job::copy(const Job &other)
{
m_algorithm = other.m_algorithm;
m_nicehash = other.m_nicehash;
m_size = other.m_size;
m_clientId = other.m_clientId;
m_id = other.m_id;
m_diff = other.m_diff;
m_height = other.m_height;
m_target = other.m_target;
m_index = other.m_index;
memcpy(m_blob, other.m_blob, sizeof (m_blob));
memcpy(m_seedHash, other.m_seedHash, sizeof(m_seedHash));
}

View file

@ -90,8 +90,11 @@ public:
inline bool operator==(const Job &other) const { return isEqual(other); } inline bool operator==(const Job &other) const { return isEqual(other); }
inline bool operator!=(const Job &other) const { return !isEqual(other); } inline bool operator!=(const Job &other) const { return !isEqual(other); }
inline Job &operator=(const Job &other) { copy(other); return *this; }
private: private:
void copy(const Job &other);
Algorithm m_algorithm; Algorithm m_algorithm;
bool m_nicehash = false; bool m_nicehash = false;
size_t m_size = 0; size_t m_size = 0;

View file

@ -43,6 +43,7 @@ public:
~Buffer(); ~Buffer();
inline bool isEqual(const Buffer &other) const { return m_size == other.m_size && (m_size == 0 || memcmp(m_data, other.m_data, m_size) == 0); }
inline char *data() { return m_data; } inline char *data() { return m_data; }
inline const char *data() const { return m_data; } inline const char *data() const { return m_data; }
inline size_t size() const { return m_size; } inline size_t size() const { return m_size; }
@ -52,8 +53,10 @@ public:
void from(const char *data, size_t size); void from(const char *data, size_t size);
inline Buffer &operator=(const Buffer &other) { from(other); return *this; } inline bool operator!=(const Buffer &other) const { return !isEqual(other); }
inline bool operator==(const Buffer &other) const { return isEqual(other); }
inline Buffer &operator=(Buffer &&other) { move(std::move(other)); return *this; } inline Buffer &operator=(Buffer &&other) { move(std::move(other)); return *this; }
inline Buffer &operator=(const Buffer &other) { from(other); return *this; }
static Buffer allocUnsafe(size_t size); static Buffer allocUnsafe(size_t size);

View file

@ -59,6 +59,10 @@ public:
inline MinerPrivate(Controller *controller) : controller(controller) inline MinerPrivate(Controller *controller) : controller(controller)
{ {
uv_rwlock_init(&rwlock); uv_rwlock_init(&rwlock);
# ifdef XMRIG_ALGO_RANDOMX
Rx::init();
# endif
} }
@ -71,6 +75,10 @@ public:
for (IBackend *backend : backends) { for (IBackend *backend : backends) {
delete backend; delete backend;
} }
# ifdef XMRIG_ALGO_RANDOMX
Rx::destroy();
# endif
} }
@ -353,12 +361,18 @@ void xmrig::Miner::setEnabled(bool enabled)
void xmrig::Miner::setJob(const Job &job, bool donate) void xmrig::Miner::setJob(const Job &job, bool donate)
{ {
d_ptr->algorithm = job.algorithm();
for (IBackend *backend : d_ptr->backends) { for (IBackend *backend : d_ptr->backends) {
backend->prepare(job); backend->prepare(job);
} }
# ifdef XMRIG_ALGO_RANDOMX
if (d_ptr->algorithm.family() == Algorithm::RANDOM_X && job.algorithm().family() == Algorithm::RANDOM_X && !Rx::isReady(job)) {
stop();
}
# endif
d_ptr->algorithm = job.algorithm();
uv_rwlock_wrlock(&d_ptr->rwlock); uv_rwlock_wrlock(&d_ptr->rwlock);
const uint8_t index = donate ? 1 : 0; const uint8_t index = donate ? 1 : 0;
@ -372,7 +386,7 @@ void xmrig::Miner::setJob(const Job &job, bool donate)
} }
# ifdef XMRIG_ALGO_RANDOMX # ifdef XMRIG_ALGO_RANDOMX
Rx::init(job, Rx::init(d_ptr->job,
d_ptr->controller->config()->rx().threads(), d_ptr->controller->config()->rx().threads(),
d_ptr->controller->config()->cpu().isHugePages(), d_ptr->controller->config()->cpu().isHugePages(),
d_ptr->controller->config()->rx().isNUMA() d_ptr->controller->config()->rx().isNUMA()

View file

@ -36,7 +36,10 @@ static const char *kAffinity = "affinity";
static const char *kAsterisk = "*"; static const char *kAsterisk = "*";
static const char *kCpu = "cpu"; static const char *kCpu = "cpu";
static const char *kIntensity = "intensity"; static const char *kIntensity = "intensity";
#ifdef XMRIG_ALGO_RANDOMX
static const char *kRandomX = "randomx"; static const char *kRandomX = "randomx";
#endif
static inline uint64_t intensity(uint64_t av) static inline uint64_t intensity(uint64_t av)

View file

@ -28,6 +28,10 @@
#ifdef XMRIG_FEATURE_HWLOC #ifdef XMRIG_FEATURE_HWLOC
# include <hwloc.h> # include <hwloc.h>
# include "backend/cpu/platform/HwlocCpuInfo.h" # include "backend/cpu/platform/HwlocCpuInfo.h"
#
# if HWLOC_API_VERSION < 0x00010b00
# define HWLOC_OBJ_NUMANODE HWLOC_OBJ_NODE
# endif
#endif #endif

View file

@ -68,9 +68,9 @@ DECL(randomx_program_prologue):
#else #else
#include "asm/program_prologue_linux.inc" #include "asm/program_prologue_linux.inc"
#endif #endif
movapd xmm13, xmmword ptr mantissaMask[rip] movapd xmm13, xmmword ptr [mantissaMask+rip]
movapd xmm14, xmmword ptr exp240[rip] movapd xmm14, xmmword ptr [exp240+rip]
movapd xmm15, xmmword ptr scaleMask[rip] movapd xmm15, xmmword ptr [scaleMask+rip]
jmp DECL(randomx_program_loop_begin) jmp DECL(randomx_program_loop_begin)
.balign 64 .balign 64
@ -177,20 +177,20 @@ DECL(randomx_sshash_end):
DECL(randomx_sshash_init): DECL(randomx_sshash_init):
lea r8, [rbx+1] lea r8, [rbx+1]
#include "asm/program_sshash_prefetch.inc" #include "asm/program_sshash_prefetch.inc"
imul r8, qword ptr r0_mul[rip] imul r8, qword ptr [r0_mul+rip]
mov r9, qword ptr r1_add[rip] mov r9, qword ptr [r1_add+rip]
xor r9, r8 xor r9, r8
mov r10, qword ptr r2_add[rip] mov r10, qword ptr [r2_add+rip]
xor r10, r8 xor r10, r8
mov r11, qword ptr r3_add[rip] mov r11, qword ptr [r3_add+rip]
xor r11, r8 xor r11, r8
mov r12, qword ptr r4_add[rip] mov r12, qword ptr [r4_add+rip]
xor r12, r8 xor r12, r8
mov r13, qword ptr r5_add[rip] mov r13, qword ptr [r5_add+rip]
xor r13, r8 xor r13, r8
mov r14, qword ptr r6_add[rip] mov r14, qword ptr [r6_add+rip]
xor r14, r8 xor r14, r8
mov r15, qword ptr r7_add[rip] mov r15, qword ptr [r7_add+rip]
xor r15, r8 xor r15, r8
jmp DECL(randomx_program_end) jmp DECL(randomx_program_end)

View file

@ -26,80 +26,33 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "virtual_memory.hpp"
#include <stdexcept> #include <stdexcept>
#if defined(_WIN32) || defined(__CYGWIN__)
#include <windows.h>
#else
#ifdef __APPLE__
#include <mach/vm_statistics.h>
#endif
#include <sys/types.h>
#include <sys/mman.h>
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#endif
#if defined(_WIN32) || defined(__CYGWIN__) #include "crypto/common/VirtualMemory.h"
std::string getErrorMessage(const char* function) { #include "virtual_memory.hpp"
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
std::string message(messageBuffer, size);
LocalFree(messageBuffer);
return std::string(function) + std::string(": ") + message;
}
#endif
void* allocExecutableMemory(std::size_t bytes) { void* allocExecutableMemory(std::size_t bytes) {
void* mem; void *mem = xmrig::VirtualMemory::allocateExecutableMemory(bytes);
#if defined(_WIN32) || defined(__CYGWIN__) if (mem == nullptr) {
mem = VirtualAlloc(nullptr, bytes, MEM_COMMIT, PAGE_EXECUTE_READWRITE); throw std::runtime_error("Failed to allocate executable memory");
if (mem == nullptr) }
throw std::runtime_error(getErrorMessage("allocExecutableMemory - VirtualAlloc"));
#else
mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (mem == MAP_FAILED)
throw std::runtime_error("allocExecutableMemory - mmap failed");
#endif
return mem; return mem;
} }
constexpr std::size_t align(std::size_t pos, std::size_t align) {
return ((pos - 1) / align + 1) * align;
}
void* allocLargePagesMemory(std::size_t bytes) { void* allocLargePagesMemory(std::size_t bytes) {
void* mem; void *mem = xmrig::VirtualMemory::allocateLargePagesMemory(bytes);
#if defined(_WIN32) || defined(__CYGWIN__) if (mem == nullptr) {
auto pageMinimum = GetLargePageMinimum(); throw std::runtime_error("Failed to allocate large pages memory");
if (pageMinimum > 0) }
mem = VirtualAlloc(NULL, align(bytes, pageMinimum), MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE);
else
throw std::runtime_error("allocLargePagesMemory - Large pages are not supported");
if (mem == nullptr)
throw std::runtime_error(getErrorMessage("allocLargePagesMemory - VirtualAlloc"));
#else
#ifdef __APPLE__
mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
#elif defined(__FreeBSD__)
mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER, -1, 0);
#else
mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, -1, 0);
#endif
if (mem == MAP_FAILED)
throw std::runtime_error("allocLargePagesMemory - mmap failed");
#endif
return mem; return mem;
} }
void freePagedMemory(void* ptr, std::size_t bytes) { void freePagedMemory(void* ptr, std::size_t bytes) {
#if defined(_WIN32) || defined(__CYGWIN__) xmrig::VirtualMemory::freeLargePagesMemory(ptr, bytes);
VirtualFree(ptr, 0, MEM_RELEASE);
#else
munmap(ptr, bytes);
#endif
} }

View file

@ -26,8 +26,8 @@
#include <map> #include <map>
#include <mutex>
#include <thread> #include <thread>
#include <uv.h>
#ifdef XMRIG_FEATURE_HWLOC #ifdef XMRIG_FEATURE_HWLOC
@ -43,6 +43,7 @@
#include "base/tools/Buffer.h" #include "base/tools/Buffer.h"
#include "base/tools/Chrono.h" #include "base/tools/Chrono.h"
#include "crypto/rx/Rx.h" #include "crypto/rx/Rx.h"
#include "crypto/rx/RxAlgo.h"
#include "crypto/rx/RxCache.h" #include "crypto/rx/RxCache.h"
#include "crypto/rx/RxDataset.h" #include "crypto/rx/RxDataset.h"
@ -50,40 +51,16 @@
namespace xmrig { namespace xmrig {
class RxPrivate;
static const char *tag = BLUE_BG(WHITE_BOLD_S " rx ") " "; static const char *tag = BLUE_BG(WHITE_BOLD_S " rx ") " ";
static RxPrivate *d_ptr = nullptr;
class RxPrivate
{
public:
inline RxPrivate()
{
uv_mutex_init(&mutex);
}
inline ~RxPrivate()
{
for (auto const &item : datasets) {
delete item.second;
}
datasets.clear();
uv_mutex_destroy(&mutex);
}
inline void lock() { uv_mutex_lock(&mutex); }
inline void unlock() { uv_mutex_unlock(&mutex); }
static void allocate(RxPrivate *self, uint32_t nodeId)
{
const uint64_t ts = Chrono::steadyMSecs();
#ifdef XMRIG_FEATURE_HWLOC #ifdef XMRIG_FEATURE_HWLOC
if (self->numa) { static void bindToNUMANode(uint32_t nodeId)
{
hwloc_topology_t topology; hwloc_topology_t topology;
hwloc_topology_init(&topology); hwloc_topology_init(&topology);
hwloc_topology_load(topology); hwloc_topology_load(topology);
@ -103,8 +80,55 @@ public:
hwloc_topology_destroy(topology); hwloc_topology_destroy(topology);
} }
#else
inline static void bindToNUMANode(uint32_t) {}
#endif #endif
class RxPrivate
{
public:
inline RxPrivate() :
m_seed()
{
# ifdef XMRIG_FEATURE_HWLOC
if (Cpu::info()->nodes() > 1) {
for (uint32_t nodeId : HwlocCpuInfo::nodeIndexes()) {
datasets.insert({ nodeId, nullptr });
}
}
else
# endif
{
datasets.insert({ 0, nullptr });
}
}
inline ~RxPrivate()
{
for (auto const &item : datasets) {
delete item.second;
}
datasets.clear();
}
inline bool isNUMA() const { return m_numa; }
inline const Algorithm &algorithm() const { return m_algorithm; }
inline const uint8_t *seed() const { return m_seed; }
inline size_t count() const { return isNUMA() ? datasets.size() : 1; }
static void allocate(uint32_t nodeId)
{
const uint64_t ts = Chrono::steadyMSecs();
if (d_ptr->isNUMA()) {
bindToNUMANode(nodeId);
}
LOG_INFO("%s" CYAN_BOLD("#%u") MAGENTA_BOLD(" allocate") CYAN_BOLD(" %zu MB") BLACK_BOLD(" (%zu+%zu) for RandomX dataset & cache"), LOG_INFO("%s" CYAN_BOLD("#%u") MAGENTA_BOLD(" allocate") CYAN_BOLD(" %zu MB") BLACK_BOLD(" (%zu+%zu) for RandomX dataset & cache"),
tag, tag,
nodeId, nodeId,
@ -113,8 +137,8 @@ public:
RxCache::size() / 1024 / 1024 RxCache::size() / 1024 / 1024
); );
RxDataset *dataset = new RxDataset(self->hugePages); RxDataset *dataset = new RxDataset(d_ptr->m_hugePages);
self->datasets[nodeId] = dataset; d_ptr->datasets[nodeId] = dataset;
if (dataset->get() != nullptr) { if (dataset->get() != nullptr) {
const auto hugePages = dataset->hugePages(); const auto hugePages = dataset->hugePages();
@ -137,43 +161,99 @@ public:
} }
bool hugePages = true; static void initDataset(uint32_t nodeId, uint32_t threads)
bool numa = true; {
std::lock_guard<std::mutex> lock(d_ptr->mutex);
const uint64_t ts = Chrono::steadyMSecs();
d_ptr->getOrAllocate(nodeId)->init(d_ptr->seed(), threads);
d_ptr->m_ready++;
LOG_INFO("%s" CYAN_BOLD("#%u") GREEN(" init done") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, nodeId, Chrono::steadyMSecs() - ts);
}
inline RxDataset *getOrAllocate(uint32_t nodeId)
{
RxDataset *dataset = datasets.at(nodeId);
if (dataset == nullptr) {
# ifdef XMRIG_FEATURE_HWLOC
if (d_ptr->isNUMA()) {
std::thread thread(allocate, nodeId);
thread.join();
} else
# endif
{
allocate(nodeId);
}
dataset = datasets.at(nodeId);
}
return dataset;
}
inline void setState(const Job &job, bool hugePages, bool numa)
{
if (m_algorithm != job.algorithm()) {
m_algorithm = RxAlgo::apply(job.algorithm());
}
m_ready = 0;
m_numa = numa && Cpu::info()->nodes() > 1;
m_hugePages = hugePages;
memcpy(m_seed, job.seedHash(), sizeof(m_seed));
}
inline bool isReady(const Job &job)
{
return m_ready == count() && m_algorithm == job.algorithm() && memcmp(m_seed, job.seedHash(), sizeof(m_seed)) == 0;
}
std::map<uint32_t, RxDataset *> datasets; std::map<uint32_t, RxDataset *> datasets;
uv_mutex_t mutex; std::mutex mutex;
private:
bool m_hugePages = true;
bool m_numa = true;
Algorithm m_algorithm;
size_t m_ready = 0;
uint8_t m_seed[32];
}; };
static RxPrivate *d_ptr = new RxPrivate();
} // namespace xmrig } // namespace xmrig
bool xmrig::Rx::isReady(const Job &job, uint32_t nodeId) bool xmrig::Rx::isReady(const Job &job)
{ {
d_ptr->lock(); std::lock_guard<std::mutex> lock(d_ptr->mutex);
const bool rc = isReady(job.seedHash(), job.algorithm(), d_ptr->numa ? nodeId : 0);
d_ptr->unlock();
return rc; return d_ptr->isReady(job);
} }
xmrig::RxDataset *xmrig::Rx::dataset(uint32_t nodeId) xmrig::RxDataset *xmrig::Rx::dataset(const Job &job, uint32_t nodeId)
{ {
d_ptr->lock(); std::lock_guard<std::mutex> lock(d_ptr->mutex);
RxDataset *dataset = d_ptr->datasets[d_ptr->numa ? nodeId : 0]; if (!d_ptr->isReady(job)) {
d_ptr->unlock(); return nullptr;
}
return dataset; return d_ptr->datasets.at(d_ptr->isNUMA() ? nodeId : 0);
} }
std::pair<size_t, size_t> xmrig::Rx::hugePages() std::pair<size_t, size_t> xmrig::Rx::hugePages()
{ {
std::pair<size_t, size_t> pages(0, 0); std::pair<size_t, size_t> pages(0, 0);
d_ptr->lock(); std::lock_guard<std::mutex> lock(d_ptr->mutex);
for (auto const &item : d_ptr->datasets) { for (auto const &item : d_ptr->datasets) {
if (!item.second) { if (!item.second) {
@ -185,116 +265,59 @@ std::pair<size_t, size_t> xmrig::Rx::hugePages()
pages.second += p.second; pages.second += p.second;
} }
d_ptr->unlock();
return pages; return pages;
} }
void xmrig::Rx::destroy()
{
delete d_ptr;
d_ptr = nullptr;
}
void xmrig::Rx::init()
{
d_ptr = new RxPrivate();
}
void xmrig::Rx::init(const Job &job, int initThreads, bool hugePages, bool numa) void xmrig::Rx::init(const Job &job, int initThreads, bool hugePages, bool numa)
{ {
if (job.algorithm().family() != Algorithm::RANDOM_X) { if (job.algorithm().family() != Algorithm::RANDOM_X) {
return; return;
} }
d_ptr->lock(); std::lock_guard<std::mutex> lock(d_ptr->mutex);
size_t ready = 0;
for (auto const &item : d_ptr->datasets) {
if (isReady(job.seedHash(), job.algorithm(), item.first)) {
ready++;
}
}
if (!d_ptr->datasets.empty() && ready == d_ptr->datasets.size()) {
d_ptr->unlock();
if (d_ptr->isReady(job)) {
return; return;
} }
d_ptr->hugePages = hugePages; d_ptr->setState(job, hugePages, numa);
d_ptr->numa = numa && Cpu::info()->nodes() > 1; const uint32_t threads = initThreads < 1 ? static_cast<uint32_t>(Cpu::info()->threads()) : static_cast<uint32_t>(initThreads);
const uint32_t threads = initThreads < 1 ? static_cast<uint32_t>(Cpu::info()->threads()) const String buf = Buffer::toHex(job.seedHash(), 8);
: static_cast<uint32_t>(initThreads);
LOG_INFO("%s" MAGENTA_BOLD("init dataset%s") " algo " WHITE_BOLD("%s (") CYAN_BOLD("%u") WHITE_BOLD(" threads)") BLACK_BOLD(" seed %s..."),
tag,
d_ptr->count() > 1 ? "s" : "",
job.algorithm().shortName(),
threads,
buf.data()
);
# ifdef XMRIG_FEATURE_HWLOC # ifdef XMRIG_FEATURE_HWLOC
if (d_ptr->numa) { if (d_ptr->isNUMA()) {
for (uint32_t nodeId : HwlocCpuInfo::nodeIndexes()) { for (auto const &item : d_ptr->datasets) {
std::thread thread(initDataset, nodeId, job.seedHash(), job.algorithm(), threads); std::thread thread(RxPrivate::initDataset, item.first, threads);
thread.detach(); thread.detach();
} }
} }
else else
# endif # endif
{ {
std::thread thread(initDataset, 0, job.seedHash(), job.algorithm(), threads); std::thread thread(RxPrivate::initDataset, 0, threads);
thread.detach(); thread.detach();
} }
d_ptr->unlock();
}
void xmrig::Rx::stop()
{
delete d_ptr;
d_ptr = nullptr;
}
bool xmrig::Rx::isReady(const uint8_t *seed, const Algorithm &algorithm, uint32_t nodeId)
{
return !d_ptr->datasets.empty() && d_ptr->datasets[nodeId] != nullptr && d_ptr->datasets[nodeId]->isReady(seed, algorithm);
}
void xmrig::Rx::initDataset(uint32_t nodeId, const uint8_t *seed, const Algorithm &algorithm, uint32_t threads)
{
d_ptr->lock();
RxDataset *dataset = d_ptr->datasets[nodeId];
if (!dataset) {
# ifdef XMRIG_FEATURE_HWLOC
if (d_ptr->numa) {
std::thread thread(RxPrivate::allocate, d_ptr, nodeId);
thread.join();
} else
# endif
{
RxPrivate::allocate(d_ptr, nodeId);
}
dataset = d_ptr->datasets[nodeId];
}
if (!dataset->isReady(seed, algorithm)) {
const uint64_t ts = Chrono::steadyMSecs();
if (dataset->get() != nullptr) {
LOG_INFO("%s" CYAN_BOLD("#%u") MAGENTA_BOLD(" init dataset") " algo " WHITE_BOLD("%s (") CYAN_BOLD("%u") WHITE_BOLD(" threads)") BLACK_BOLD(" seed %s..."),
tag,
nodeId,
algorithm.shortName(),
threads,
Buffer::toHex(seed, 8).data()
);
}
else {
LOG_INFO("%s" CYAN_BOLD("#%u") MAGENTA_BOLD(" init cache") " algo " WHITE_BOLD("%s") BLACK_BOLD(" seed %s..."),
tag,
nodeId,
algorithm.shortName(),
Buffer::toHex(seed, 8).data()
);
}
dataset->init(seed, algorithm, threads);
LOG_INFO("%s" CYAN_BOLD("#%u") GREEN(" init done") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, nodeId, Chrono::steadyMSecs() - ts);
}
d_ptr->unlock();
} }

View file

@ -44,15 +44,12 @@ class Job;
class Rx class Rx
{ {
public: public:
static bool isReady(const Job &job, uint32_t nodeId); static bool isReady(const Job &job);
static RxDataset *dataset(uint32_t nodeId); static RxDataset *dataset(const Job &job, uint32_t nodeId);
static std::pair<size_t, size_t> hugePages(); static std::pair<size_t, size_t> hugePages();
static void destroy();
static void init();
static void init(const Job &job, int initThreads, bool hugePages, bool numa); static void init(const Job &job, int initThreads, bool hugePages, bool numa);
static void stop();
private:
static bool isReady(const uint8_t *seed, const Algorithm &algorithm, uint32_t nodeId);
static void initDataset(uint32_t nodeId, const uint8_t *seed, const Algorithm &algorithm, uint32_t threads);
}; };

View file

@ -53,11 +53,12 @@ public:
inline randomx_cache *get() const { return m_cache; } inline randomx_cache *get() const { return m_cache; }
bool init(const void *seed); bool init(const void *seed);
bool isReady(const void *seed) const;
static inline constexpr size_t size() { return RANDOMX_CACHE_MAX_SIZE; } static inline constexpr size_t size() { return RANDOMX_CACHE_MAX_SIZE; }
private: private:
bool isReady(const void *seed) const;
int m_flags = 0; int m_flags = 0;
randomx_cache *m_cache = nullptr; randomx_cache *m_cache = nullptr;
uint8_t m_seed[32]; uint8_t m_seed[32];

View file

@ -64,16 +64,8 @@ xmrig::RxDataset::~RxDataset()
} }
bool xmrig::RxDataset::init(const void *seed, const Algorithm &algorithm, uint32_t numThreads) bool xmrig::RxDataset::init(const void *seed, uint32_t numThreads)
{ {
if (isReady(seed, algorithm)) {
return false;
}
if (m_algorithm != algorithm) {
m_algorithm = RxAlgo::apply(algorithm);
}
cache()->init(seed); cache()->init(seed);
if (!get()) { if (!get()) {
@ -104,12 +96,6 @@ bool xmrig::RxDataset::init(const void *seed, const Algorithm &algorithm, uint32
} }
bool xmrig::RxDataset::isReady(const void *seed, const Algorithm &algorithm) const
{
return algorithm == m_algorithm && cache()->isReady(seed);
}
std::pair<size_t, size_t> xmrig::RxDataset::hugePages() const std::pair<size_t, size_t> xmrig::RxDataset::hugePages() const
{ {
constexpr size_t twoMiB = 2u * 1024u * 1024u; constexpr size_t twoMiB = 2u * 1024u * 1024u;

View file

@ -52,8 +52,7 @@ public:
inline randomx_dataset *get() const { return m_dataset; } inline randomx_dataset *get() const { return m_dataset; }
inline RxCache *cache() const { return m_cache; } inline RxCache *cache() const { return m_cache; }
bool init(const void *seed, const Algorithm &algorithm, uint32_t numThreads); bool init(const void *seed, uint32_t numThreads);
bool isReady(const void *seed, const Algorithm &algorithm) const;
std::pair<size_t, size_t> hugePages() const; std::pair<size_t, size_t> hugePages() const;
static inline constexpr size_t size() { return RANDOMX_DATASET_MAX_SIZE; } static inline constexpr size_t size() { return RANDOMX_DATASET_MAX_SIZE; }

View file

@ -28,7 +28,7 @@
#define APP_ID "xmrig" #define APP_ID "xmrig"
#define APP_NAME "XMRig" #define APP_NAME "XMRig"
#define APP_DESC "XMRig CPU miner" #define APP_DESC "XMRig CPU miner"
#define APP_VERSION "2.99.3-beta" #define APP_VERSION "2.99.4-evo"
#define APP_DOMAIN "xmrig.com" #define APP_DOMAIN "xmrig.com"
#define APP_SITE "www.xmrig.com" #define APP_SITE "www.xmrig.com"
#define APP_COPYRIGHT "Copyright (C) 2016-2019 xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2019 xmrig.com"
@ -36,7 +36,7 @@
#define APP_VER_MAJOR 2 #define APP_VER_MAJOR 2
#define APP_VER_MINOR 99 #define APP_VER_MINOR 99
#define APP_VER_PATCH 3 #define APP_VER_PATCH 4
#ifdef _MSC_VER #ifdef _MSC_VER
# if (_MSC_VER >= 1920) # if (_MSC_VER >= 1920)