diff --git a/src/backend/cpu/CpuConfig.cpp b/src/backend/cpu/CpuConfig.cpp index ab966e701..cfc5e728b 100644 --- a/src/backend/cpu/CpuConfig.cpp +++ b/src/backend/cpu/CpuConfig.cpp @@ -36,6 +36,7 @@ namespace xmrig { static const char *kEnabled = "enabled"; static const char *kHugePages = "huge-pages"; +static const char *kHugePagesJit = "huge-pages-jit"; static const char *kHwAes = "hw-aes"; static const char *kMaxThreadsHint = "max-threads-hint"; static const char *kMemoryPool = "memory-pool"; @@ -76,6 +77,7 @@ rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const obj.AddMember(StringRef(kEnabled), m_enabled, allocator); obj.AddMember(StringRef(kHugePages), m_hugePages, allocator); + obj.AddMember(StringRef(kHugePagesJit), m_hugePagesJit, allocator); obj.AddMember(StringRef(kHwAes), m_aes == AES_AUTO ? Value(kNullType) : Value(m_aes == AES_HW), allocator); obj.AddMember(StringRef(kPriority), priority() != -1 ? Value(priority()) : Value(kNullType), allocator); obj.AddMember(StringRef(kMemoryPool), m_memoryPool < 1 ? Value(m_memoryPool < 0) : Value(m_memoryPool), allocator); @@ -132,10 +134,11 @@ std::vector<xmrig::CpuLaunchData> xmrig::CpuConfig::get(const Miner *miner, cons void xmrig::CpuConfig::read(const rapidjson::Value &value) { if (value.IsObject()) { - m_enabled = Json::getBool(value, kEnabled, m_enabled); - m_hugePages = Json::getBool(value, kHugePages, m_hugePages); - m_limit = Json::getUint(value, kMaxThreadsHint, m_limit); - m_yield = Json::getBool(value, kYield, m_yield); + m_enabled = Json::getBool(value, kEnabled, m_enabled); + m_hugePages = Json::getBool(value, kHugePages, m_hugePages); + m_hugePagesJit = Json::getBool(value, kHugePagesJit, m_hugePagesJit); + m_limit = Json::getUint(value, kMaxThreadsHint, m_limit); + m_yield = Json::getBool(value, kYield, m_yield); setAesMode(Json::getValue(value, kHwAes)); setPriority(Json::getInt(value, kPriority, -1)); diff --git a/src/backend/cpu/CpuConfig.h b/src/backend/cpu/CpuConfig.h index 30166215f..00842f5ae 100644 --- a/src/backend/cpu/CpuConfig.h +++ b/src/backend/cpu/CpuConfig.h @@ -54,6 +54,7 @@ public: inline bool isEnabled() const { return m_enabled; } inline bool isHugePages() const { return m_hugePages; } + inline bool isHugePagesJit() const { return m_hugePagesJit; } inline bool isShouldSave() const { return m_shouldSave; } inline bool isYield() const { return m_yield; } inline const Assembly &assembly() const { return m_assembly; } @@ -76,6 +77,7 @@ private: bool m_astrobwtAVX2 = false; bool m_enabled = true; bool m_hugePages = true; + bool m_hugePagesJit = false; bool m_shouldSave = false; bool m_yield = true; int m_astrobwtMaxSize = 550; diff --git a/src/config.json b/src/config.json index c2bac8614..68fb439f0 100644 --- a/src/config.json +++ b/src/config.json @@ -27,6 +27,7 @@ "cpu": { "enabled": true, "huge-pages": true, + "huge-pages-jit": false, "hw-aes": null, "priority": null, "memory-pool": false, diff --git a/src/core/config/Config_default.h b/src/core/config/Config_default.h index 7e4ed2707..6c8106ca7 100644 --- a/src/core/config/Config_default.h +++ b/src/core/config/Config_default.h @@ -61,6 +61,7 @@ R"===( "cpu": { "enabled": true, "huge-pages": true, + "huge-pages-jit": false, "hw-aes": null, "priority": null, "memory-pool": false, diff --git a/src/crypto/cn/CnCtx.cpp b/src/crypto/cn/CnCtx.cpp index ee151fb30..e92fe22ec 100644 --- a/src/crypto/cn/CnCtx.cpp +++ b/src/crypto/cn/CnCtx.cpp @@ -39,7 +39,7 @@ void xmrig::CnCtx::create(cryptonight_ctx **ctx, uint8_t *memory, size_t size, s cryptonight_ctx *c = static_cast<cryptonight_ctx *>(_mm_malloc(sizeof(cryptonight_ctx), 4096)); c->memory = memory + (i * size); - c->generated_code = reinterpret_cast<cn_mainloop_fun_ms_abi>(VirtualMemory::allocateExecutableMemory(0x4000)); + c->generated_code = reinterpret_cast<cn_mainloop_fun_ms_abi>(VirtualMemory::allocateExecutableMemory(0x4000, false)); c->generated_code_data.algo = Algorithm::INVALID; c->generated_code_data.height = std::numeric_limits<uint64_t>::max(); diff --git a/src/crypto/cn/CnHash.cpp b/src/crypto/cn/CnHash.cpp index 9f5194926..6b7aefdb1 100644 --- a/src/crypto/cn/CnHash.cpp +++ b/src/crypto/cn/CnHash.cpp @@ -139,7 +139,7 @@ static void patchCode(T dst, U src, const uint32_t iterations, const uint32_t ma static void patchAsmVariants() { const int allocation_size = 81920; - auto base = static_cast<uint8_t *>(VirtualMemory::allocateExecutableMemory(allocation_size)); + auto base = static_cast<uint8_t *>(VirtualMemory::allocateExecutableMemory(allocation_size, false)); cn_half_mainloop_ivybridge_asm = reinterpret_cast<cn_mainloop_fun> (base + 0x0000); cn_half_mainloop_ryzen_asm = reinterpret_cast<cn_mainloop_fun> (base + 0x1000); diff --git a/src/crypto/common/MemoryPool.cpp b/src/crypto/common/MemoryPool.cpp index 6e17d752b..59f1af068 100644 --- a/src/crypto/common/MemoryPool.cpp +++ b/src/crypto/common/MemoryPool.cpp @@ -47,7 +47,11 @@ xmrig::MemoryPool::MemoryPool(size_t size, bool hugePages, uint32_t node) return; } - m_memory = new VirtualMemory(size * pageSize, hugePages, false, false, node); + constexpr size_t alignment = 1 << 24; + + m_memory = new VirtualMemory(size * pageSize + alignment, hugePages, false, false, node); + + m_alignOffset = (alignment - (((size_t)m_memory->scratchpad()) % alignment)) % alignment; } @@ -71,7 +75,7 @@ uint8_t *xmrig::MemoryPool::get(size_t size, uint32_t) return nullptr; } - uint8_t *out = m_memory->scratchpad() + m_offset; + uint8_t *out = m_memory->scratchpad() + m_alignOffset + m_offset; m_offset += size; ++m_refs; diff --git a/src/crypto/common/MemoryPool.h b/src/crypto/common/MemoryPool.h index d4d584ab9..c6b4691b8 100644 --- a/src/crypto/common/MemoryPool.h +++ b/src/crypto/common/MemoryPool.h @@ -54,6 +54,7 @@ protected: private: size_t m_refs = 0; size_t m_offset = 0; + size_t m_alignOffset = 0; VirtualMemory *m_memory = nullptr; }; diff --git a/src/crypto/common/VirtualMemory.h b/src/crypto/common/VirtualMemory.h index d7fe783fa..1bfdab805 100644 --- a/src/crypto/common/VirtualMemory.h +++ b/src/crypto/common/VirtualMemory.h @@ -61,7 +61,7 @@ public: static bool isHugepagesAvailable(); static bool isOneGbPagesAvailable(); static uint32_t bindToNUMANode(int64_t affinity); - static void *allocateExecutableMemory(size_t size); + static void *allocateExecutableMemory(size_t size, bool hugePages); static void *allocateLargePagesMemory(size_t size); static void *allocateOneGbPagesMemory(size_t size); static void destroy(); diff --git a/src/crypto/common/VirtualMemory_unix.cpp b/src/crypto/common/VirtualMemory_unix.cpp index 3363cdaae..ad4253c56 100644 --- a/src/crypto/common/VirtualMemory_unix.cpp +++ b/src/crypto/common/VirtualMemory_unix.cpp @@ -63,12 +63,30 @@ bool xmrig::VirtualMemory::isOneGbPagesAvailable() } -void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size) +void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size, bool hugePages) { # if defined(__APPLE__) void *mem = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); # else - void *mem = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + +# if defined(MAP_HUGE_2MB) + constexpr int flag_2mb = MAP_HUGE_2MB; +# elif defined(MAP_HUGE_SHIFT) + constexpr int flag_2mb = (21 << MAP_HUGE_SHIFT); +# else + constexpr int flag_2mb = 0; +# endif + + void *mem = nullptr; + + if (hugePages) { + mem = mmap(0, align(size), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | flag_2mb, -1, 0); + } + + if (!mem) { + void *mem = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + # endif return mem == MAP_FAILED ? nullptr : mem; diff --git a/src/crypto/common/VirtualMemory_win.cpp b/src/crypto/common/VirtualMemory_win.cpp index 370f7c07d..659a94a60 100644 --- a/src/crypto/common/VirtualMemory_win.cpp +++ b/src/crypto/common/VirtualMemory_win.cpp @@ -162,9 +162,19 @@ bool xmrig::VirtualMemory::isOneGbPagesAvailable() } -void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size) +void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size, bool hugePages) { - return VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + void* result = nullptr; + + if (hugePages) { + result = VirtualAlloc(nullptr, align(size), MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_EXECUTE_READWRITE); + } + + if (!result) { + result = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + } + + return result; } diff --git a/src/crypto/randomx/dataset.hpp b/src/crypto/randomx/dataset.hpp index a40cf1d76..34b79d262 100644 --- a/src/crypto/randomx/dataset.hpp +++ b/src/crypto/randomx/dataset.hpp @@ -43,7 +43,7 @@ struct randomx_dataset { /* Global scope for C binding */ struct randomx_cache { uint8_t* memory = nullptr; - randomx::JitCompiler* jit; + randomx::JitCompiler* jit = nullptr; randomx::CacheInitializeFunc* initialize; randomx::DatasetInitFunc* datasetInit; randomx::SuperscalarProgram programs[RANDOMX_CACHE_MAX_ACCESSES]; diff --git a/src/crypto/randomx/jit_compiler_a64.cpp b/src/crypto/randomx/jit_compiler_a64.cpp index 7a601c5b3..964f30a36 100644 --- a/src/crypto/randomx/jit_compiler_a64.cpp +++ b/src/crypto/randomx/jit_compiler_a64.cpp @@ -33,6 +33,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "crypto/randomx/reciprocal.h" #include "crypto/randomx/virtual_memory.hpp" +void randomx_set_huge_pages_jit(bool) {} + namespace ARMV8A { constexpr uint32_t B = 0x14000000; @@ -89,7 +91,7 @@ static size_t CalcDatasetItemSize() constexpr uint32_t IntRegMap[8] = { 4, 5, 6, 7, 12, 13, 14, 15 }; -JitCompilerA64::JitCompilerA64() +JitCompilerA64::JitCompilerA64(bool) : code((uint8_t*) allocExecutableMemory(CodeSize + CalcDatasetItemSize())) , literalPos(ImulRcpLiteralsEnd) , num32bitLiterals(0) diff --git a/src/crypto/randomx/jit_compiler_a64.hpp b/src/crypto/randomx/jit_compiler_a64.hpp index c589b50d2..1683230d6 100644 --- a/src/crypto/randomx/jit_compiler_a64.hpp +++ b/src/crypto/randomx/jit_compiler_a64.hpp @@ -46,7 +46,7 @@ namespace randomx { class JitCompilerA64 { public: - JitCompilerA64(); + explicit JitCompilerA64(bool); ~JitCompilerA64(); void prepare() {} diff --git a/src/crypto/randomx/jit_compiler_fallback.hpp b/src/crypto/randomx/jit_compiler_fallback.hpp index 225076637..1e8a29e4a 100644 --- a/src/crypto/randomx/jit_compiler_fallback.hpp +++ b/src/crypto/randomx/jit_compiler_fallback.hpp @@ -41,7 +41,7 @@ namespace randomx { class JitCompilerFallback { public: - JitCompilerFallback() { + explicit JitCompilerFallback(bool) { throw std::runtime_error("JIT compilation is not supported on this platform"); } void prepare() {} diff --git a/src/crypto/randomx/jit_compiler_x86.cpp b/src/crypto/randomx/jit_compiler_x86.cpp index 437f1040d..ea41c3b10 100644 --- a/src/crypto/randomx/jit_compiler_x86.cpp +++ b/src/crypto/randomx/jit_compiler_x86.cpp @@ -49,6 +49,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # include <cpuid.h> #endif +static bool hugePagesJIT = false; + +void randomx_set_huge_pages_jit(bool hugePages) +{ + hugePagesJIT = hugePages; +} + namespace randomx { /* @@ -175,8 +182,9 @@ namespace randomx { # endif static std::atomic<size_t> codeOffset; + constexpr size_t codeOffsetIncrement = 59 * 64; - JitCompilerX86::JitCompilerX86() { + JitCompilerX86::JitCompilerX86(bool hugePagesEnable) { BranchesWithin32B = xmrig::Cpu::info()->jccErratum(); int32_t info[4]; @@ -186,9 +194,11 @@ namespace randomx { cpuid(0x80000001, info); hasXOP = ((info[2] & (1 << 11)) != 0); - allocatedCode = (uint8_t*)allocExecutableMemory(CodeSize * 2); + allocatedCode = (uint8_t*)allocExecutableMemory(CodeSize * 2, hugePagesJIT && hugePagesEnable); + // Shift code base address to improve caching - all threads will use different L2/L3 cache sets - code = allocatedCode + (codeOffset.fetch_add(59 * 64) % CodeSize); + code = allocatedCode + (codeOffset.fetch_add(codeOffsetIncrement) % CodeSize); + memcpy(code, codePrologue, prologueSize); if (hasXOP) { memcpy(code + prologueSize, codeLoopLoadXOP, loopLoadXOPSize); @@ -207,6 +217,7 @@ namespace randomx { } JitCompilerX86::~JitCompilerX86() { + codeOffset.fetch_sub(codeOffsetIncrement); freePagedMemory(allocatedCode, CodeSize); } diff --git a/src/crypto/randomx/jit_compiler_x86.hpp b/src/crypto/randomx/jit_compiler_x86.hpp index b8e6a9fe7..e65838317 100644 --- a/src/crypto/randomx/jit_compiler_x86.hpp +++ b/src/crypto/randomx/jit_compiler_x86.hpp @@ -47,7 +47,7 @@ namespace randomx { class JitCompilerX86 { public: - JitCompilerX86(); + explicit JitCompilerX86(bool hugePagesEnable); ~JitCompilerX86(); void prepare(); void generateProgram(Program&, ProgramConfiguration&, uint32_t); diff --git a/src/crypto/randomx/randomx.cpp b/src/crypto/randomx/randomx.cpp index 64d62a2d6..9dd4aeee4 100644 --- a/src/crypto/randomx/randomx.cpp +++ b/src/crypto/randomx/randomx.cpp @@ -381,7 +381,7 @@ extern "C" { break; case RANDOMX_FLAG_JIT: - cache->jit = new randomx::JitCompiler(); + cache->jit = new randomx::JitCompiler(false); cache->initialize = &randomx::initCacheCompile; cache->datasetInit = cache->jit->getDatasetInitFunc(); cache->memory = memory; diff --git a/src/crypto/randomx/randomx.h b/src/crypto/randomx/randomx.h index 07fb7077a..9a1fb3c71 100644 --- a/src/crypto/randomx/randomx.h +++ b/src/crypto/randomx/randomx.h @@ -169,6 +169,7 @@ void randomx_apply_config(const T& config) } void randomx_set_scratchpad_prefetch_mode(int mode); +void randomx_set_huge_pages_jit(bool hugePages); #if defined(__cplusplus) extern "C" { diff --git a/src/crypto/randomx/virtual_memory.cpp b/src/crypto/randomx/virtual_memory.cpp index 06165ffb6..1d3825ffa 100644 --- a/src/crypto/randomx/virtual_memory.cpp +++ b/src/crypto/randomx/virtual_memory.cpp @@ -33,8 +33,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "crypto/randomx/virtual_memory.hpp" -void* allocExecutableMemory(std::size_t bytes) { - void *mem = xmrig::VirtualMemory::allocateExecutableMemory(bytes); +void* allocExecutableMemory(std::size_t bytes, bool hugePages) { + void *mem = xmrig::VirtualMemory::allocateExecutableMemory(bytes, hugePages); if (mem == nullptr) { throw std::runtime_error("Failed to allocate executable memory"); } diff --git a/src/crypto/randomx/virtual_memory.hpp b/src/crypto/randomx/virtual_memory.hpp index d3b31db12..e740e35b7 100644 --- a/src/crypto/randomx/virtual_memory.hpp +++ b/src/crypto/randomx/virtual_memory.hpp @@ -30,6 +30,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <cstddef> -void* allocExecutableMemory(std::size_t); +void* allocExecutableMemory(std::size_t, bool); void* allocLargePagesMemory(std::size_t); void freePagedMemory(void*, std::size_t); diff --git a/src/crypto/randomx/vm_compiled.hpp b/src/crypto/randomx/vm_compiled.hpp index 0e9c4eb8e..2ffce558f 100644 --- a/src/crypto/randomx/vm_compiled.hpp +++ b/src/crypto/randomx/vm_compiled.hpp @@ -58,7 +58,7 @@ namespace randomx { protected: void execute(); - JitCompiler compiler; + JitCompiler compiler{ true }; }; using CompiledVmDefault = CompiledVm<1>; diff --git a/src/crypto/rx/Rx.cpp b/src/crypto/rx/Rx.cpp index c8ecc2b39..66725f60c 100644 --- a/src/crypto/rx/Rx.cpp +++ b/src/crypto/rx/Rx.cpp @@ -100,6 +100,7 @@ bool xmrig::Rx::init(const T &seed, const RxConfig &config, const CpuConfig &cpu } randomx_set_scratchpad_prefetch_mode(config.scratchpadPrefetchMode()); + randomx_set_huge_pages_jit(cpu.isHugePagesJit()); if (isReady(seed)) { return true;