diff --git a/CMakeLists.txt b/CMakeLists.txt index fedbe76b..e0290778 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,40 +18,30 @@ option(WITH_EMBEDDED_CONFIG "Enable internal embedded JSON config" OFF) include (CheckIncludeFile) include (cmake/cpu.cmake) include (src/base/base.cmake) +include (src/backend/backend.cmake) set(HEADERS "${HEADERS_BASE}" "${HEADERS_BASE_HTTP}" + "${HEADERS_BACKEND}" src/api/interfaces/IApiListener.h src/App.h - src/common/cpu/Cpu.h - src/common/crypto/keccak.h - src/common/interfaces/ICpuInfo.h - src/common/Platform.h - src/common/xmrig.h src/core/config/Config_default.h src/core/config/Config_platform.h src/core/config/Config.h src/core/config/ConfigTransform.h src/core/config/usage.h src/core/Controller.h - src/interfaces/IJobResultListener.h - src/interfaces/IThread.h - src/interfaces/IWorker.h - src/Mem.h + src/core/Miner.h + src/net/interfaces/IJobResultListener.h src/net/JobResult.h + src/net/JobResults.h src/net/Network.h src/net/NetworkState.h src/net/strategies/DonateStrategy.h src/Summary.h src/version.h - src/workers/CpuThread.h - src/workers/Hashrate.h - src/workers/MultiWorker.h - src/workers/ThreadHandle.h - src/workers/Worker.h - src/workers/Workers.h ) set(HEADERS_CRYPTO @@ -60,7 +50,9 @@ set(HEADERS_CRYPTO src/crypto/cn/c_groestl.h src/crypto/cn/c_jh.h src/crypto/cn/c_skein.h - src/crypto/cn/CryptoNight_constants.h + src/crypto/cn/CnAlgo.h + src/crypto/cn/CnCtx.h + src/crypto/cn/CnHash.h src/crypto/cn/CryptoNight_monero.h src/crypto/cn/CryptoNight_test.h src/crypto/cn/CryptoNight.h @@ -69,6 +61,8 @@ set(HEADERS_CRYPTO src/crypto/cn/skein_port.h src/crypto/cn/soft_aes.h src/crypto/common/Algorithm.h + src/crypto/common/keccak.h + src/crypto/common/Nonce.h src/crypto/common/portable/mm_malloc.h src/crypto/common/VirtualMemory.h ) @@ -82,32 +76,30 @@ endif() set(SOURCES "${SOURCES_BASE}" "${SOURCES_BASE_HTTP}" + "${SOURCES_BACKEND}" src/App.cpp - src/common/crypto/keccak.cpp - src/common/Platform.cpp src/core/config/Config.cpp src/core/config/ConfigTransform.cpp src/core/Controller.cpp - src/Mem.cpp + src/core/Miner.cpp + src/net/JobResults.cpp src/net/Network.cpp src/net/NetworkState.cpp src/net/strategies/DonateStrategy.cpp src/Summary.cpp - src/workers/CpuThread.cpp - src/workers/Hashrate.cpp - src/workers/MultiWorker.cpp - src/workers/ThreadHandle.cpp - src/workers/Worker.cpp - src/workers/Workers.cpp src/xmrig.cpp ) set(SOURCES_CRYPTO - src/crypto/cn/c_groestl.c src/crypto/cn/c_blake256.c + src/crypto/cn/c_groestl.c src/crypto/cn/c_jh.c src/crypto/cn/c_skein.c + src/crypto/cn/CnCtx.cpp + src/crypto/cn/CnHash.cpp src/crypto/common/Algorithm.cpp + src/crypto/common/keccak.cpp + src/crypto/common/Nonce.cpp ) if (WIN32) @@ -115,8 +107,6 @@ if (WIN32) "${SOURCES_OS}" res/app.rc src/App_win.cpp - src/common/Platform_win.cpp - src/Mem_win.cpp src/crypto/common/VirtualMemory_win.cpp ) @@ -126,16 +116,12 @@ elseif (APPLE) set(SOURCES_OS "${SOURCES_OS}" src/App_unix.cpp - src/common/Platform_mac.cpp - src/Mem_unix.cpp src/crypto/common/VirtualMemory_unix.cpp ) else() set(SOURCES_OS "${SOURCES_OS}" src/App_unix.cpp - src/common/Platform_unix.cpp - src/Mem_unix.cpp src/crypto/common/VirtualMemory_unix.cpp ) @@ -166,24 +152,34 @@ if (WITH_RANDOMX) set(SOURCES_CRYPTO "${SOURCES_CRYPTO}" src/crypto/randomx/aes_hash.cpp + src/crypto/randomx/allocator.cpp + src/crypto/randomx/argon2_core.c src/crypto/randomx/argon2_ref.c + src/crypto/randomx/blake2_generator.cpp + src/crypto/randomx/blake2/blake2b.c src/crypto/randomx/bytecode_machine.cpp src/crypto/randomx/dataset.cpp - src/crypto/randomx/soft_aes.cpp - src/crypto/randomx/virtual_memory.cpp - src/crypto/randomx/vm_interpreted.cpp - src/crypto/randomx/allocator.cpp + src/crypto/randomx/instructions_portable.cpp src/crypto/randomx/randomx.cpp + src/crypto/randomx/reciprocal.c + src/crypto/randomx/soft_aes.cpp src/crypto/randomx/superscalar.cpp + src/crypto/randomx/virtual_machine.cpp + src/crypto/randomx/virtual_memory.cpp + src/crypto/randomx/vm_compiled_light.cpp src/crypto/randomx/vm_compiled.cpp src/crypto/randomx/vm_interpreted_light.cpp - src/crypto/randomx/argon2_core.c - src/crypto/randomx/blake2_generator.cpp - src/crypto/randomx/instructions_portable.cpp - src/crypto/randomx/reciprocal.c - src/crypto/randomx/virtual_machine.cpp - src/crypto/randomx/vm_compiled_light.cpp - src/crypto/randomx/blake2/blake2b.c + src/crypto/randomx/vm_interpreted.cpp + src/crypto/rx/Rx.cpp + src/crypto/rx/Rx.h + src/crypto/rx/RxAlgo.cpp + src/crypto/rx/RxAlgo.h + src/crypto/rx/RxCache.cpp + src/crypto/rx/RxCache.h + src/crypto/rx/RxDataset.cpp + src/crypto/rx/RxDataset.h + src/crypto/rx/RxVm.cpp + src/crypto/rx/RxVm.h ) if (NOT ARCH_ID) set(ARCH_ID ${CMAKE_HOST_SYSTEM_PROCESSOR}) @@ -208,23 +204,6 @@ endif() include(cmake/flags.cmake) -if (WITH_LIBCPUID) - add_subdirectory(src/3rdparty/libcpuid) - - include_directories(src/3rdparty/libcpuid) - set(CPUID_LIB cpuid) - set(SOURCES_CPUID src/core/cpu/AdvancedCpuInfo.h src/core/cpu/AdvancedCpuInfo.cpp src/core/cpu/Cpu.cpp) -else() - add_definitions(/DXMRIG_NO_LIBCPUID) - set(SOURCES_CPUID src/common/cpu/BasicCpuInfo.h src/common/cpu/Cpu.cpp) - - if (XMRIG_ARM) - set(SOURCES_CPUID ${SOURCES_CPUID} src/common/cpu/BasicCpuInfo_arm.cpp) - else() - set(SOURCES_CPUID ${SOURCES_CPUID} src/common/cpu/BasicCpuInfo.cpp) - endif() -endif() - include(cmake/OpenSSL.cmake) include(cmake/asm.cmake) include(cmake/cn-gpu.cmake) @@ -256,8 +235,6 @@ if (WITH_HTTP) src/api/requests/ApiRequest.h src/api/requests/HttpApiRequest.cpp src/api/requests/HttpApiRequest.h - src/api/v1/ApiRouter.cpp - src/api/v1/ApiRouter.h ) else() set(HTTP_SOURCES "") diff --git a/cmake/asm.cmake b/cmake/asm.cmake index 25cccead..e445defd 100644 --- a/cmake/asm.cmake +++ b/cmake/asm.cmake @@ -36,10 +36,17 @@ if (WITH_ASM AND NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8) endif() add_library(${XMRIG_ASM_LIBRARY} STATIC ${XMRIG_ASM_FILES}) - set(XMRIG_ASM_SOURCES src/crypto/cn/Asm.h src/crypto/cn/Asm.cpp src/crypto/cn/r/CryptonightR_gen.cpp) + set(XMRIG_ASM_SOURCES + src/crypto/common/Assembly.h + src/crypto/common/Assembly.cpp + src/crypto/cn/r/CryptonightR_gen.cpp + ) set_property(TARGET ${XMRIG_ASM_LIBRARY} PROPERTY LINKER_LANGUAGE C) + + add_definitions(/DXMRIG_FEATURE_ASM) else() set(XMRIG_ASM_SOURCES "") set(XMRIG_ASM_LIBRARY "") - add_definitions(/DXMRIG_NO_ASM) + + remove_definitions(/DXMRIG_FEATURE_ASM) endif() diff --git a/cmake/flags.cmake b/cmake/flags.cmake index 3a0add7a..3f2bd0a0 100644 --- a/cmake/flags.cmake +++ b/cmake/flags.cmake @@ -61,7 +61,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast -funroll-loops -fmerge-all-constants") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-exceptions -fno-rtti -Wno-missing-braces") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fexceptions -fno-rtti -Wno-missing-braces") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -funroll-loops -fmerge-all-constants") if (XMRIG_ARMv8) diff --git a/src/App.cpp b/src/App.cpp index 66662eb1..ccbaad4f 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -6,7 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018 Lee Clagett - * Copyright 2018 SChernykh + * Copyright 2018-2019 SChernykh * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -30,18 +30,17 @@ #include "api/Api.h" #include "App.h" +#include "backend/cpu/Cpu.h" #include "base/io/Console.h" #include "base/io/log/Log.h" #include "base/kernel/Signals.h" -#include "common/cpu/Cpu.h" -#include "common/Platform.h" #include "core/config/Config.h" #include "core/Controller.h" -#include "Mem.h" +#include "core/Miner.h" +#include "crypto/common/VirtualMemory.h" #include "net/Network.h" #include "Summary.h" #include "version.h" -#include "workers/Workers.h" xmrig::App::App(Process *process) : @@ -77,7 +76,7 @@ int xmrig::App::exec() background(); - Mem::init(m_controller->config()->isHugePages()); + VirtualMemory::init(m_controller->config()->cpu().isHugePages()); Summary::print(m_controller); @@ -87,8 +86,6 @@ int xmrig::App::exec() return 0; } - Workers::start(m_controller); - m_controller->start(); const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); @@ -103,23 +100,17 @@ void xmrig::App::onConsoleCommand(char command) switch (command) { case 'h': case 'H': - Workers::printHashrate(true); + m_controller->miner()->printHashrate(true); break; case 'p': case 'P': - if (Workers::isEnabled()) { - LOG_INFO(YELLOW_BOLD("paused") ", press " MAGENTA_BOLD("r") " to resume"); - Workers::setEnabled(false); - } + m_controller->miner()->setEnabled(false); break; case 'r': case 'R': - if (!Workers::isEnabled()) { - LOG_INFO(GREEN_BOLD("resumed")); - Workers::setEnabled(true); - } + m_controller->miner()->setEnabled(true); break; case 3: @@ -163,6 +154,5 @@ void xmrig::App::close() m_console->stop(); m_controller->stop(); - Workers::stop(); Log::destroy(); } diff --git a/src/Mem_win.cpp b/src/Mem_win.cpp deleted file mode 100644 index 76cbf434..00000000 --- a/src/Mem_win.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018 Lee Clagett - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * 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 . - */ - - -#include -#include -#include -#include - - -#include "base/io/log/Log.h" -#include "common/xmrig.h" -#include "crypto/common/portable/mm_malloc.h" -#include "crypto/common/VirtualMemory.h" -#include "crypto/cn/CryptoNight_constants.h" -#include "crypto/cn/CryptoNight.h" -#include "Mem.h" - - -/***************************************************************** -SetLockPagesPrivilege: a function to obtain or -release the privilege of locking physical pages. - -Inputs: - -HANDLE hProcess: Handle for the process for which the -privilege is needed - -BOOL bEnable: Enable (TRUE) or disable? - -Return value: TRUE indicates success, FALSE failure. - -*****************************************************************/ -/** - * AWE Example: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366531(v=vs.85).aspx - * Creating a File Mapping Using Large Pages: https://msdn.microsoft.com/en-us/library/aa366543(VS.85).aspx - */ -static BOOL SetLockPagesPrivilege() { - HANDLE token; - - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) != TRUE) { - return FALSE; - } - - TOKEN_PRIVILEGES tp; - tp.PrivilegeCount = 1; - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - - if (LookupPrivilegeValue(nullptr, SE_LOCK_MEMORY_NAME, &(tp.Privileges[0].Luid)) != TRUE) { - return FALSE; - } - - BOOL rc = AdjustTokenPrivileges(token, FALSE, (PTOKEN_PRIVILEGES) &tp, 0, nullptr, nullptr); - if (rc != TRUE || GetLastError() != ERROR_SUCCESS) { - return FALSE; - } - - CloseHandle(token); - - return TRUE; -} - - -static LSA_UNICODE_STRING StringToLsaUnicodeString(LPCTSTR string) { - LSA_UNICODE_STRING lsaString; - - DWORD dwLen = (DWORD) wcslen(string); - lsaString.Buffer = (LPWSTR) string; - lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR)); - lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR)); - return lsaString; -} - - -static BOOL ObtainLockPagesPrivilege() { - HANDLE token; - PTOKEN_USER user = nullptr; - - if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) == TRUE) { - DWORD size = 0; - - GetTokenInformation(token, TokenUser, nullptr, 0, &size); - if (size) { - user = (PTOKEN_USER) LocalAlloc(LPTR, size); - } - - GetTokenInformation(token, TokenUser, user, size, &size); - CloseHandle(token); - } - - if (!user) { - return FALSE; - } - - LSA_HANDLE handle; - LSA_OBJECT_ATTRIBUTES attributes; - ZeroMemory(&attributes, sizeof(attributes)); - - BOOL result = FALSE; - if (LsaOpenPolicy(nullptr, &attributes, POLICY_ALL_ACCESS, &handle) == 0) { - LSA_UNICODE_STRING str = StringToLsaUnicodeString(_T(SE_LOCK_MEMORY_NAME)); - - if (LsaAddAccountRights(handle, user->User.Sid, &str, 1) == 0) { - LOG_NOTICE("Huge pages support was successfully enabled, but reboot required to use it"); - result = TRUE; - } - - LsaClose(handle); - } - - LocalFree(user); - return result; -} - - -static BOOL TrySetLockPagesPrivilege() { - if (SetLockPagesPrivilege()) { - return TRUE; - } - - return ObtainLockPagesPrivilege() && SetLockPagesPrivilege(); -} - - -void Mem::init(bool enabled) -{ - m_enabled = enabled; - - if (enabled && TrySetLockPagesPrivilege()) { - m_flags |= HugepagesAvailable; - } -} - - -void Mem::allocate(MemInfo &info, bool enabled) -{ - info.hugePages = 0; - - if (!enabled) { - info.memory = static_cast(_mm_malloc(info.size, 4096)); - - return; - } - - info.memory = static_cast(xmrig::VirtualMemory::allocateLargePagesMemory(info.size)); - if (info.memory) { - info.hugePages = info.pages; - - return; - } - - allocate(info, false); -} - - -void Mem::release(MemInfo &info) -{ - if (info.hugePages) { - xmrig::VirtualMemory::freeLargePagesMemory(info.memory, info.size); - } - else { - _mm_free(info.memory); - } -} diff --git a/src/Summary.cpp b/src/Summary.cpp index 2b28f98d..36f59ba3 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -28,18 +28,18 @@ #include +#include "backend/cpu/Cpu.h" #include "base/io/log/Log.h" #include "base/net/stratum/Pool.h" -#include "common/cpu/Cpu.h" #include "core/config/Config.h" #include "core/Controller.h" -#include "crypto/cn/Asm.h" -#include "Mem.h" +#include "crypto/common/Assembly.h" +#include "crypto/common/VirtualMemory.h" #include "Summary.h" #include "version.h" -#ifndef XMRIG_NO_ASM +#ifdef XMRIG_FEATURE_ASM static const char *coloredAsmNames[] = { RED_BOLD("none"), "auto", @@ -49,7 +49,7 @@ static const char *coloredAsmNames[] = { }; -inline static const char *asmName(xmrig::Assembly assembly) +inline static const char *asmName(xmrig::Assembly::Id assembly) { return coloredAsmNames[assembly]; } @@ -59,7 +59,7 @@ inline static const char *asmName(xmrig::Assembly assembly) static void print_memory(xmrig::Config *) { # ifdef _WIN32 xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") "%s", - "HUGE PAGES", Mem::isHugepagesAvailable() ? GREEN_BOLD("available") : RED_BOLD("unavailable")); + "HUGE PAGES", xmrig::VirtualMemory::isHugepagesAvailable() ? GREEN_BOLD("available") : RED_BOLD("unavailable")); # endif } @@ -76,7 +76,7 @@ static void print_cpu(xmrig::Config *) Cpu::info()->hasAES() ? GREEN_BOLD_S : RED_BOLD_S "-", Cpu::info()->hasAVX2() ? GREEN_BOLD_S : RED_BOLD_S "-" ); -# ifndef XMRIG_NO_LIBCPUID +# ifdef XMRIG_FEATURE_LIBCPUID Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s%.1f MB/%.1f MB"), "CPU L2/L3", Cpu::info()->L2() / 1024.0, Cpu::info()->L3() / 1024.0); # endif } @@ -84,40 +84,20 @@ static void print_cpu(xmrig::Config *) static void print_threads(xmrig::Config *config) { - if (config->threadsMode() != xmrig::Config::Advanced) { - char buf[32] = { 0 }; - if (config->affinity() != -1L) { - snprintf(buf, sizeof buf, ", affinity=0x%" PRIX64, config->affinity()); - } + xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s%d%%"), + "DONATE", + config->pools().donateLevel() == 0 ? RED_BOLD_S : "", + config->pools().donateLevel() + ); - xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%d") WHITE_BOLD(", %s, av=%d, %sdonate=%d%%") WHITE_BOLD("%s"), - "THREADS", - config->threadsCount(), - config->algorithm().shortName(), - config->algoVariant(), - config->pools().donateLevel() == 0 ? RED_BOLD_S : "", - config->pools().donateLevel(), - buf - ); - } - else { - xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%d") WHITE_BOLD(", %s, %sdonate=%d%%"), - "THREADS", - config->threadsCount(), - config->algorithm().shortName(), - config->pools().donateLevel() == 0 ? RED_BOLD_S : "", - config->pools().donateLevel() - ); - } - -# ifndef XMRIG_NO_ASM - if (config->assembly() == xmrig::ASM_AUTO) { +# ifdef XMRIG_FEATURE_ASM + if (config->cpu().assembly() == xmrig::Assembly::AUTO) { const xmrig::Assembly assembly = xmrig::Cpu::info()->assembly(); xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13sauto:%s"), "ASSEMBLY", asmName(assembly)); } else { - xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s%s"), "ASSEMBLY", asmName(config->assembly())); + xmrig::Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s%s"), "ASSEMBLY", asmName(config->cpu().assembly())); } # endif } diff --git a/src/api/Api.cpp b/src/api/Api.cpp index a11325f3..9151aa7e 100644 --- a/src/api/Api.cpp +++ b/src/api/Api.cpp @@ -35,13 +35,13 @@ #include "api/Api.h" #include "api/interfaces/IApiListener.h" #include "api/requests/HttpApiRequest.h" -#include "api/v1/ApiRouter.h" #include "base/kernel/Base.h" #include "base/tools/Buffer.h" #include "base/tools/Chrono.h" -#include "common/crypto/keccak.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "crypto/common/Algorithm.h" +#include "crypto/common/keccak.h" #include "version.h" @@ -60,16 +60,11 @@ xmrig::Api::Api(Base *base) : base->addListener(this); genId(base->config()->apiId()); - - m_v1 = new ApiRouter(base); - addListener(m_v1); } xmrig::Api::~Api() { - delete m_v1; - # ifdef XMRIG_FEATURE_HTTP delete m_httpd; # endif @@ -119,13 +114,31 @@ void xmrig::Api::exec(IApiRequest &request) { using namespace rapidjson; - if (request.method() == IApiRequest::METHOD_GET && (request.url() == "/1/summary" || request.url() == "/api.json")) { + if (request.type() == IApiRequest::REQ_SUMMARY) { auto &allocator = request.doc().GetAllocator(); request.accept(); request.reply().AddMember("id", StringRef(m_id), allocator); request.reply().AddMember("worker_id", StringRef(m_workerId), allocator); request.reply().AddMember("uptime", (Chrono::steadyMSecs() - m_timestamp) / 1000, allocator); + + Value features(kArrayType); +# ifdef XMRIG_FEATURE_API + features.PushBack("api", allocator); +# endif +# ifdef XMRIG_FEATURE_ASM + features.PushBack("asm", allocator); +# endif +# ifdef XMRIG_FEATURE_HTTP + features.PushBack("http", allocator); +# endif +# ifdef XMRIG_FEATURE_LIBCPUID + features.PushBack("cpuid", allocator); +# endif +# ifdef XMRIG_FEATURE_TLS + features.PushBack("tls", allocator); +# endif + request.reply().AddMember("features", features, allocator); } for (IApiListener *listener : m_listeners) { diff --git a/src/api/Api.h b/src/api/Api.h index eef57c3a..f2ed3926 100644 --- a/src/api/Api.h +++ b/src/api/Api.h @@ -36,7 +36,6 @@ namespace xmrig { -class ApiRouter; class Base; class Httpd; class HttpData; @@ -67,7 +66,6 @@ private: void genId(const String &id); void genWorkerId(const String &id); - ApiRouter *m_v1; Base *m_base; char m_id[32]; char m_workerId[128]; diff --git a/src/api/interfaces/IApiListener.h b/src/api/interfaces/IApiListener.h index 7897e375..bbf153a6 100644 --- a/src/api/interfaces/IApiListener.h +++ b/src/api/interfaces/IApiListener.h @@ -35,7 +35,9 @@ class IApiListener public: virtual ~IApiListener() = default; +# ifdef XMRIG_FEATURE_API virtual void onRequest(IApiRequest &request) = 0; +# endif }; diff --git a/src/api/interfaces/IApiRequest.h b/src/api/interfaces/IApiRequest.h index 2c2f5634..8e65a921 100644 --- a/src/api/interfaces/IApiRequest.h +++ b/src/api/interfaces/IApiRequest.h @@ -4,7 +4,9 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2018 XMRig + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * 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 @@ -50,6 +52,12 @@ public: }; + enum RequestType { + REQ_UNKNOWN, + REQ_SUMMARY + }; + + virtual ~IApiRequest() = default; virtual bool isDone() const = 0; @@ -57,9 +65,11 @@ public: virtual bool isRestricted() const = 0; virtual const rapidjson::Value &json() const = 0; virtual const String &url() const = 0; + virtual int version() const = 0; virtual Method method() const = 0; virtual rapidjson::Document &doc() = 0; virtual rapidjson::Value &reply() = 0; + virtual RequestType type() const = 0; virtual Source source() const = 0; virtual void accept() = 0; virtual void done(int status) = 0; diff --git a/src/api/requests/ApiRequest.cpp b/src/api/requests/ApiRequest.cpp index c092a334..3812e419 100644 --- a/src/api/requests/ApiRequest.cpp +++ b/src/api/requests/ApiRequest.cpp @@ -28,8 +28,7 @@ xmrig::ApiRequest::ApiRequest(Source source, bool restricted) : m_restricted(restricted), - m_source(source), - m_state(STATE_NEW) + m_source(source) { } diff --git a/src/api/requests/ApiRequest.h b/src/api/requests/ApiRequest.h index 1754aa9c..05716e29 100644 --- a/src/api/requests/ApiRequest.h +++ b/src/api/requests/ApiRequest.h @@ -43,10 +43,15 @@ protected: inline bool isDone() const override { return m_state == STATE_DONE; } inline bool isNew() const override { return m_state == STATE_NEW; } inline bool isRestricted() const override { return m_restricted; } + inline int version() const override { return m_version; } + inline RequestType type() const override { return m_type; } inline Source source() const override { return m_source; } inline void accept() override { m_state = STATE_ACCEPTED; } inline void done(int) override { m_state = STATE_DONE; } + int m_version = 1; + RequestType m_type = REQ_UNKNOWN; + private: enum State { STATE_NEW, @@ -56,7 +61,7 @@ private: bool m_restricted; Source m_source; - State m_state; + State m_state = STATE_NEW; }; diff --git a/src/api/requests/HttpApiRequest.cpp b/src/api/requests/HttpApiRequest.cpp index e4f2de1e..b4dc1810 100644 --- a/src/api/requests/HttpApiRequest.cpp +++ b/src/api/requests/HttpApiRequest.cpp @@ -35,6 +35,17 @@ xmrig::HttpApiRequest::HttpApiRequest(const HttpData &req, bool restricted) : m_res(req.id()), m_url(req.url.c_str()) { + if (method() == METHOD_GET) { + if (url() == "/1/summary" || url() == "/2/summary" || url() == "/api.json") { + m_type = REQ_SUMMARY; + } + } + + if (url().size() > 4) { + if (memcmp(url().data(), "/2/", 3) == 0) { + m_version = 2; + } + } } diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp deleted file mode 100644 index d066b0b1..00000000 --- a/src/api/v1/ApiRouter.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * 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 . - */ - -#include -#include -#include - - -#include "api/interfaces/IApiRequest.h" -#include "api/v1/ApiRouter.h" -#include "base/kernel/Base.h" -#include "common/cpu/Cpu.h" -#include "common/Platform.h" -#include "core/config/Config.h" -#include "interfaces/IThread.h" -#include "rapidjson/document.h" -#include "version.h" -#include "workers/Hashrate.h" -#include "workers/Workers.h" - - -static inline rapidjson::Value normalize(double d) -{ - using namespace rapidjson; - - if (!isnormal(d)) { - return Value(kNullType); - } - - return Value(floor(d * 100.0) / 100.0); -} - - -xmrig::ApiRouter::ApiRouter(Base *base) : - m_base(base) -{ -} - - -xmrig::ApiRouter::~ApiRouter() -{ -} - - -void xmrig::ApiRouter::onRequest(IApiRequest &request) -{ - if (request.method() == IApiRequest::METHOD_GET) { - if (request.url() == "/1/summary" || request.url() == "/api.json") { - request.accept(); - getMiner(request.reply(), request.doc()); - getHashrate(request.reply(), request.doc()); - } - else if (request.url() == "/1/threads") { - request.accept(); - getThreads(request.reply(), request.doc()); - } - else if (request.url() == "/1/config") { - if (request.isRestricted()) { - return request.done(403); - } - - request.accept(); - m_base->config()->getJSON(request.doc()); - } - } - else if (request.method() == IApiRequest::METHOD_PUT || request.method() == IApiRequest::METHOD_POST) { - if (request.url() == "/1/config") { - request.accept(); - - if (!m_base->reload(request.json())) { - return request.done(400); - } - - request.done(204); - } - } -} - - -void xmrig::ApiRouter::getHashrate(rapidjson::Value &reply, rapidjson::Document &doc) const -{ - using namespace rapidjson; - auto &allocator = doc.GetAllocator(); - - Value hashrate(kObjectType); - Value total(kArrayType); - Value threads(kArrayType); - - const Hashrate *hr = Workers::hashrate(); - - total.PushBack(normalize(hr->calc(Hashrate::ShortInterval)), allocator); - total.PushBack(normalize(hr->calc(Hashrate::MediumInterval)), allocator); - total.PushBack(normalize(hr->calc(Hashrate::LargeInterval)), allocator); - - for (size_t i = 0; i < Workers::threads(); i++) { - Value thread(kArrayType); - thread.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); - thread.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); - thread.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); - - threads.PushBack(thread, allocator); - } - - hashrate.AddMember("total", total, allocator); - hashrate.AddMember("highest", normalize(hr->highest()), allocator); - hashrate.AddMember("threads", threads, allocator); - reply.AddMember("hashrate", hashrate, allocator); -} - - -void xmrig::ApiRouter::getMiner(rapidjson::Value &reply, rapidjson::Document &doc) const -{ - using namespace rapidjson; - auto &allocator = doc.GetAllocator(); - - Value cpu(kObjectType); - cpu.AddMember("brand", StringRef(Cpu::info()->brand()), allocator); - cpu.AddMember("aes", Cpu::info()->hasAES(), allocator); - cpu.AddMember("x64", Cpu::info()->isX64(), allocator); - cpu.AddMember("sockets", Cpu::info()->sockets(), allocator); - - reply.AddMember("version", APP_VERSION, allocator); - reply.AddMember("kind", APP_KIND, allocator); - reply.AddMember("ua", StringRef(Platform::userAgent()), allocator); - reply.AddMember("cpu", cpu, allocator); - reply.AddMember("hugepages", Workers::hugePages() > 0, allocator); - reply.AddMember("donate_level", m_base->config()->pools().donateLevel(), allocator); -} - - -void xmrig::ApiRouter::getThreads(rapidjson::Value &reply, rapidjson::Document &doc) const -{ - using namespace rapidjson; - auto &allocator = doc.GetAllocator(); - const Hashrate *hr = Workers::hashrate(); - - Workers::threadsSummary(doc); - - const std::vector &threads = m_base->config()->threads(); - Value list(kArrayType); - - size_t i = 0; - for (const xmrig::IThread *thread : threads) { - Value value = thread->toAPI(doc); - - Value hashrate(kArrayType); - hashrate.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); - hashrate.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); - hashrate.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); - - i++; - - value.AddMember("hashrate", hashrate, allocator); - list.PushBack(value, allocator); - } - - reply.AddMember("threads", list, allocator); -} diff --git a/src/backend/backend.cmake b/src/backend/backend.cmake new file mode 100644 index 00000000..c37cf262 --- /dev/null +++ b/src/backend/backend.cmake @@ -0,0 +1,13 @@ +include (src/backend/cpu/cpu.cmake) +include (src/backend/common/common.cmake) + + +set(HEADERS_BACKEND + "${HEADERS_BACKEND_COMMON}" + "${HEADERS_BACKEND_CPU}" + ) + +set(SOURCES_BACKEND + "${SOURCES_BACKEND_COMMON}" + "${SOURCES_BACKEND_CPU}" + ) diff --git a/src/workers/Hashrate.cpp b/src/backend/common/Hashrate.cpp similarity index 62% rename from src/workers/Hashrate.cpp rename to src/backend/common/Hashrate.cpp index 568817cd..99a9a9c5 100644 --- a/src/workers/Hashrate.cpp +++ b/src/backend/common/Hashrate.cpp @@ -24,22 +24,20 @@ #include -#include -#include +#include #include #include -#include "base/io/log/Log.h" +#include "backend/common/Hashrate.h" +#include "base/tools/Chrono.h" #include "base/tools/Handle.h" -#include "core/config/Config.h" -#include "core/Controller.h" -#include "workers/Hashrate.h" +#include "rapidjson/document.h" inline static const char *format(double h, char *buf, size_t size) { - if (isnormal(h)) { + if (std::isnormal(h)) { snprintf(buf, size, "%03.1f", h); return buf; } @@ -48,10 +46,9 @@ inline static const char *format(double h, char *buf, size_t size) } -Hashrate::Hashrate(size_t threads, xmrig::Controller *controller) : +xmrig::Hashrate::Hashrate(size_t threads) : m_highest(0.0), - m_threads(threads), - m_timer(nullptr) + m_threads(threads) { m_counts = new uint64_t*[threads]; m_timestamps = new uint64_t*[threads]; @@ -62,27 +59,30 @@ Hashrate::Hashrate(size_t threads, xmrig::Controller *controller) : m_timestamps[i] = new uint64_t[kBucketSize](); m_top[i] = 0; } - - const int printTime = controller->config()->printTime(); - - if (printTime > 0) { - m_timer = new uv_timer_t; - uv_timer_init(uv_default_loop(), m_timer); - m_timer->data = this; - - uv_timer_start(m_timer, Hashrate::onReport, (printTime + 4) * 1000, printTime * 1000); - } } -double Hashrate::calc(size_t ms) const +xmrig::Hashrate::~Hashrate() +{ + for (size_t i = 0; i < m_threads; i++) { + delete [] m_counts[i]; + delete [] m_timestamps[i]; + } + + delete [] m_counts; + delete [] m_timestamps; + delete [] m_top; +} + + +double xmrig::Hashrate::calc(size_t ms) const { double result = 0.0; double data; for (size_t i = 0; i < m_threads; ++i) { data = calc(i, ms); - if (isnormal(data)) { + if (std::isnormal(data)) { result += data; } } @@ -91,16 +91,13 @@ double Hashrate::calc(size_t ms) const } -double Hashrate::calc(size_t threadId, size_t ms) const +double xmrig::Hashrate::calc(size_t threadId, size_t ms) const { assert(threadId < m_threads); if (threadId >= m_threads) { return nan(""); } - using namespace std::chrono; - const uint64_t now = time_point_cast(high_resolution_clock::now()).time_since_epoch().count(); - uint64_t earliestHashCount = 0; uint64_t earliestStamp = 0; uint64_t lastestStamp = 0; @@ -119,7 +116,7 @@ double Hashrate::calc(size_t threadId, size_t ms) const lastestHashCnt = m_counts[threadId][idx]; } - if (now - m_timestamps[threadId][idx] > ms) { + if (xmrig::Chrono::highResolutionMSecs() - m_timestamps[threadId][idx] > ms) { haveFullSet = true; break; } @@ -136,16 +133,14 @@ double Hashrate::calc(size_t threadId, size_t ms) const return nan(""); } - double hashes, time; - hashes = (double) lastestHashCnt - earliestHashCount; - time = (double) lastestStamp - earliestStamp; - time /= 1000.0; + const double hashes = static_cast(lastestHashCnt - earliestHashCount); + const double time = static_cast(lastestStamp - earliestStamp) / 1000.0; return hashes / time; } -void Hashrate::add(size_t threadId, uint64_t count, uint64_t timestamp) +void xmrig::Hashrate::add(size_t threadId, uint64_t count, uint64_t timestamp) { const size_t top = m_top[threadId]; m_counts[threadId][top] = count; @@ -155,45 +150,28 @@ void Hashrate::add(size_t threadId, uint64_t count, uint64_t timestamp) } -void Hashrate::print() const -{ - char num1[8] = { 0 }; - char num2[8] = { 0 }; - char num3[8] = { 0 }; - char num4[8] = { 0 }; - - LOG_INFO(WHITE_BOLD("speed") " 10s/60s/15m " CYAN_BOLD("%s") CYAN(" %s %s ") CYAN_BOLD("H/s") " max " CYAN_BOLD("%s H/s"), - format(calc(ShortInterval), num1, sizeof(num1)), - format(calc(MediumInterval), num2, sizeof(num2)), - format(calc(LargeInterval), num3, sizeof(num3)), - format(m_highest, num4, sizeof(num4)) - ); -} - - -void Hashrate::stop() -{ - xmrig::Handle::close(m_timer); - m_timer = nullptr; -} - - -void Hashrate::updateHighest() +void xmrig::Hashrate::updateHighest() { double highest = calc(ShortInterval); - if (isnormal(highest) && highest > m_highest) { + if (std::isnormal(highest) && highest > m_highest) { m_highest = highest; } } -const char *Hashrate::format(double h, char *buf, size_t size) +const char *xmrig::Hashrate::format(double h, char *buf, size_t size) { return ::format(h, buf, size); } -void Hashrate::onReport(uv_timer_t *handle) +rapidjson::Value xmrig::Hashrate::normalize(double d) { - static_cast(handle->data)->print(); + using namespace rapidjson; + + if (!std::isnormal(d)) { + return Value(kNullType); + } + + return Value(floor(d * 100.0) / 100.0); } diff --git a/src/workers/Hashrate.h b/src/backend/common/Hashrate.h similarity index 90% rename from src/workers/Hashrate.h rename to src/backend/common/Hashrate.h index d27b289e..0674c6ab 100644 --- a/src/workers/Hashrate.h +++ b/src/backend/common/Hashrate.h @@ -26,13 +26,14 @@ #define XMRIG_HASHRATE_H +#include #include -#include + + +#include "rapidjson/fwd.h" namespace xmrig { - class Controller; -} class Hashrate @@ -44,22 +45,20 @@ public: LargeInterval = 900000 }; - Hashrate(size_t threads, xmrig::Controller *controller); + Hashrate(size_t threads); + ~Hashrate(); double calc(size_t ms) const; double calc(size_t threadId, size_t ms) const; void add(size_t threadId, uint64_t count, uint64_t timestamp); - void print() const; - void stop(); void updateHighest(); inline double highest() const { return m_highest; } inline size_t threads() const { return m_threads; } static const char *format(double h, char *buf, size_t size); + static rapidjson::Value normalize(double d); private: - static void onReport(uv_timer_t *handle); - constexpr static size_t kBucketSize = 2 << 11; constexpr static size_t kBucketMask = kBucketSize - 1; @@ -68,8 +67,10 @@ private: uint32_t* m_top; uint64_t** m_counts; uint64_t** m_timestamps; - uv_timer_t *m_timer; }; +} // namespace xmrig + + #endif /* XMRIG_HASHRATE_H */ diff --git a/src/backend/common/Thread.h b/src/backend/common/Thread.h new file mode 100644 index 00000000..36367ece --- /dev/null +++ b/src/backend/common/Thread.h @@ -0,0 +1,67 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_THREAD_H +#define XMRIG_THREAD_H + + +#include + + +#include "backend/common/interfaces/IWorker.h" + + +namespace xmrig { + + +class IBackend; + + +template +class Thread +{ +public: + 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 const T &config() const { return m_config; } + inline IBackend *backend() const { return m_backend; } + inline IWorker *worker() const { return m_worker; } + inline size_t index() const { return m_index; } + inline void setWorker(IWorker *worker) { m_worker = worker; } + inline void start(void (*callback) (void *)) { uv_thread_create(&m_thread, callback, this); } + +private: + const size_t m_index = 0; + const T m_config; + IBackend *m_backend; + IWorker *m_worker = nullptr; + uv_thread_t m_thread; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_THREAD_H */ diff --git a/src/backend/common/Threads.cpp b/src/backend/common/Threads.cpp new file mode 100644 index 00000000..894c404b --- /dev/null +++ b/src/backend/common/Threads.cpp @@ -0,0 +1,164 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include "backend/common/Threads.h" +#include "backend/cpu/CpuThread.h" +#include "rapidjson/document.h" + + +namespace xmrig { + + +static const char *kAsterisk = "*"; + + +} // namespace xmrig + + +template +const std::vector &xmrig::Threads::get(const String &profileName) const +{ + static std::vector empty; + if (profileName.isNull() || !has(profileName)) { + return empty; + } + + return m_profiles.at(profileName); +} + + +template +size_t xmrig::Threads::read(const rapidjson::Value &value) +{ + using namespace rapidjson; + + for (auto &member : value.GetObject()) { + if (member.value.IsArray()) { + std::vector threads; + + for (auto &v : member.value.GetArray()) { + T thread(v); + if (thread.isValid()) { + threads.push_back(std::move(thread)); + } + } + + if (!threads.empty()) { + move(member.name.GetString(), std::move(threads)); + } + + continue; + } + + const Algorithm algo(member.name.GetString()); + if (!algo.isValid()) { + continue; + } + + if (member.value.IsBool() && member.value.IsFalse()) { + disable(algo); + continue; + } + + if (member.value.IsString()) { + if (has(member.value.GetString())) { + m_aliases.insert({ algo, member.value.GetString() }); + } + else { + m_disabled.insert(algo); + } + } + } + + return m_profiles.size(); +} + + +template +xmrig::String xmrig::Threads::profileName(const Algorithm &algorithm, bool strict) const +{ + if (isDisabled(algorithm)) { + return String(); + } + + const String name = algorithm.shortName(); + if (has(name)) { + return name; + } + + if (m_aliases.count(algorithm) > 0) { + return m_aliases.at(algorithm); + } + + if (strict) { + return String(); + } + + if (name.contains("/")) { + const String base = name.split('/').at(0); + if (has(base)) { + return base; + } + } + + if (has(kAsterisk)) { + return kAsterisk; + } + + return String(); +} + + +template +void xmrig::Threads::toJSON(rapidjson::Value &out, rapidjson::Document &doc) const +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + for (const auto &kv : m_profiles) { + Value arr(kArrayType); + + for (const T &thread : kv.second) { + arr.PushBack(thread.toJSON(doc), allocator); + } + + out.AddMember(kv.first.toJSON(), arr, allocator); + } + + for (const Algorithm &algo : m_disabled) { + out.AddMember(StringRef(algo.shortName()), false, allocator); + } + + for (const auto &kv : m_aliases) { + out.AddMember(StringRef(kv.first.shortName()), kv.second.toJSON(), allocator); + } +} + + +namespace xmrig { + +template class Threads; + +} // namespace xmrig diff --git a/src/backend/common/Threads.h b/src/backend/common/Threads.h new file mode 100644 index 00000000..126245f6 --- /dev/null +++ b/src/backend/common/Threads.h @@ -0,0 +1,67 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_THREADS_H +#define XMRIG_THREADS_H + + +#include +#include + + +#include "base/tools/String.h" +#include "crypto/common/Algorithm.h" +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +template +class Threads +{ +public: + inline bool has(const char *profile) const { return m_profiles.count(profile) > 0; } + inline bool isDisabled(const Algorithm &algo) const { return m_disabled.count(algo) > 0 || algo == Algorithm::RX_0; } + inline bool isExist(const Algorithm &algo) const { return isDisabled(algo) || m_aliases.count(algo) > 0 || has(algo.shortName()); } + inline const std::vector &get(const Algorithm &algo, bool strict = false) const { return get(profileName(algo, strict)); } + inline void disable(const Algorithm &algo) { m_disabled.insert(algo); } + inline void move(const char *profile, std::vector &&threads) { m_profiles.insert({ profile, threads }); } + + const std::vector &get(const String &profileName) const; + size_t read(const rapidjson::Value &value); + String profileName(const Algorithm &algorithm, bool strict = false) const; + void toJSON(rapidjson::Value &out, rapidjson::Document &doc) const; + +private: + std::map m_aliases; + std::map > m_profiles; + std::set m_disabled; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_THREADS_H */ diff --git a/src/Mem.h b/src/backend/common/Worker.cpp similarity index 59% rename from src/Mem.h rename to src/backend/common/Worker.cpp index 629f5baa..98da61d4 100644 --- a/src/Mem.h +++ b/src/backend/common/Worker.cpp @@ -23,52 +23,25 @@ * along with this program. If not, see . */ -#ifndef XMRIG_MEM_H -#define XMRIG_MEM_H + +#include "backend/common/Worker.h" +#include "base/kernel/Platform.h" +#include "base/tools/Chrono.h" -#include -#include - - -#include "common/xmrig.h" - - -struct cryptonight_ctx; - - -struct MemInfo +xmrig::Worker::Worker(size_t id, int64_t affinity, int priority) : + m_id(id), + m_hashCount(0), + m_timestamp(0), + m_count(0) { - alignas(16) uint8_t *memory = nullptr; - - size_t hugePages = 0; - size_t pages = 0; - size_t size = 0; -}; + Platform::trySetThreadAffinity(affinity); + Platform::setThreadPriority(priority); +} -class Mem +void xmrig::Worker::storeStats() { -public: - enum Flags { - HugepagesAvailable = 1, - HugepagesEnabled = 2, - Lock = 4 - }; - - static MemInfo create(cryptonight_ctx **ctx, xmrig::Algo algorithm, size_t count); - static void init(bool enabled); - static void release(cryptonight_ctx **ctx, size_t count, MemInfo &info); - - static inline bool isHugepagesAvailable() { return (m_flags & HugepagesAvailable) != 0; } - -private: - static void allocate(MemInfo &info, bool enabled); - static void release(MemInfo &info); - - static int m_flags; - static bool m_enabled; -}; - - -#endif /* XMRIG_MEM_H */ + m_hashCount.store(m_count, std::memory_order_relaxed); + m_timestamp.store(Chrono::highResolutionMSecs(), std::memory_order_relaxed); +} diff --git a/src/workers/Worker.h b/src/backend/common/Worker.h similarity index 67% rename from src/workers/Worker.h rename to src/backend/common/Worker.h index 4710bcc5..faebf128 100644 --- a/src/workers/Worker.h +++ b/src/backend/common/Worker.h @@ -5,7 +5,9 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * 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 @@ -29,41 +31,33 @@ #include -#include "interfaces/IWorker.h" -#include "Mem.h" - - -class ThreadHandle; +#include "backend/common/interfaces/IWorker.h" namespace xmrig { - class CpuThread; -} class Worker : public IWorker { public: - Worker(ThreadHandle *handle); + Worker(size_t id, int64_t affinity, int priority); - inline const MemInfo &memory() const { return m_memory; } - inline size_t id() const override { return m_id; } - inline uint64_t hashCount() const override { return m_hashCount.load(std::memory_order_relaxed); } - inline uint64_t timestamp() const override { return m_timestamp.load(std::memory_order_relaxed); } + inline const VirtualMemory *memory() const override { return nullptr; } + inline size_t id() const override { return m_id; } + inline uint64_t hashCount() const override { return m_hashCount.load(std::memory_order_relaxed); } + inline uint64_t timestamp() const override { return m_timestamp.load(std::memory_order_relaxed); } protected: void storeStats(); const size_t m_id; - const size_t m_totalWays; - const uint32_t m_offset; - MemInfo m_memory; std::atomic m_hashCount; std::atomic m_timestamp; uint64_t m_count; - uint64_t m_sequence; - xmrig::CpuThread *m_thread; }; +} // namespace xmrig + + #endif /* XMRIG_WORKER_H */ diff --git a/src/backend/common/WorkerJob.h b/src/backend/common/WorkerJob.h new file mode 100644 index 00000000..c9a3d55c --- /dev/null +++ b/src/backend/common/WorkerJob.h @@ -0,0 +1,142 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_WORKERJOB_H +#define XMRIG_WORKERJOB_H + + +#include + + +#include "base/net/stratum/Job.h" +#include "crypto/common/Nonce.h" + + +namespace xmrig { + + +template +class WorkerJob +{ +public: + inline const Job ¤tJob() const { return m_jobs[index()]; } + inline uint32_t *nonce(size_t i = 0) { return reinterpret_cast(blob() + (i * currentJob().size()) + 39); } + inline uint64_t sequence() const { return m_sequence; } + inline uint8_t *blob() { return m_blobs[index()]; } + inline uint8_t index() const { return m_index; } + + + inline void add(const Job &job, uint64_t sequence, uint32_t reserveCount) + { + m_sequence = sequence; + + if (currentJob() == job) { + return; + } + + if (index() == 1 && job.index() == 0 && job == m_jobs[0]) { + return; + } + + save(job, reserveCount); + } + + + inline void nextRound(uint32_t reserveCount) + { + m_rounds[index()]++; + + if ((m_rounds[index()] % reserveCount) == 0) { + for (size_t i = 0; i < N; ++i) { + *nonce(i) = Nonce::next(index(), *nonce(i), reserveCount, currentJob().isNicehash()); + } + } + else { + for (size_t i = 0; i < N; ++i) { + *nonce(i) += 1; + } + } + } + + +private: + inline void save(const Job &job, uint32_t reserveCount) + { + m_index = job.index(); + const size_t size = job.size(); + m_jobs[index()] = job; + m_rounds[index()] = 0; + + for (size_t i = 0; i < N; ++i) { + memcpy(m_blobs[index()] + (i * size), job.blob(), size); + *nonce(i) = Nonce::next(index(), *nonce(i), reserveCount, job.isNicehash()); + } + } + + + alignas(16) uint8_t m_blobs[2][Job::kMaxBlobSize * N]; + Job m_jobs[2]; + uint32_t m_rounds[2] = { 0, 0 }; + uint64_t m_sequence = 0; + uint8_t m_index = 0; +}; + + +template<> +inline uint32_t *xmrig::WorkerJob<1>::nonce(size_t) +{ + return reinterpret_cast(blob() + 39); +} + + +template<> +inline void xmrig::WorkerJob<1>::nextRound(uint32_t reserveCount) +{ + m_rounds[index()]++; + + if ((m_rounds[index()] % reserveCount) == 0) { + *nonce() = Nonce::next(index(), *nonce(), reserveCount, currentJob().isNicehash()); + } + else { + *nonce() += 1; + } +} + + +template<> +inline void xmrig::WorkerJob<1>::save(const Job &job, uint32_t reserveCount) +{ + m_index = job.index(); + m_jobs[index()] = job; + m_rounds[index()] = 0; + + memcpy(blob(), job.blob(), job.size()); + *nonce() = Nonce::next(index(), *nonce(), reserveCount, currentJob().isNicehash()); +} + + +} // namespace xmrig + + +#endif /* XMRIG_WORKERJOB_H */ diff --git a/src/backend/common/Workers.cpp b/src/backend/common/Workers.cpp new file mode 100644 index 00000000..d70546d3 --- /dev/null +++ b/src/backend/common/Workers.cpp @@ -0,0 +1,192 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include "backend/common/Hashrate.h" +#include "backend/common/interfaces/IBackend.h" +#include "backend/common/Workers.h" +#include "backend/cpu/CpuWorker.h" +#include "base/io/log/Log.h" + + +namespace xmrig { + + +class WorkersPrivate +{ +public: + inline WorkersPrivate() + { + } + + + inline ~WorkersPrivate() + { + delete hashrate; + } + + + Hashrate *hashrate = nullptr; + IBackend *backend = nullptr; +}; + + +} // namespace xmrig + + +template +xmrig::Workers::Workers() : + d_ptr(new WorkersPrivate()) +{ + +} + + +template +xmrig::Workers::~Workers() +{ + delete d_ptr; +} + + +template +const xmrig::Hashrate *xmrig::Workers::hashrate() const +{ + return d_ptr->hashrate; +} + + +template +void xmrig::Workers::setBackend(IBackend *backend) +{ + d_ptr->backend = backend; +} + + +template +void xmrig::Workers::start(const std::vector &data) +{ + for (const T &item : data) { + m_workers.push_back(new Thread(d_ptr->backend, m_workers.size(), item)); + } + + d_ptr->hashrate = new Hashrate(m_workers.size()); + + for (Thread *worker : m_workers) { + worker->start(Workers::onReady); + } +} + + +template +void xmrig::Workers::stop() +{ + Nonce::stop(T::backend()); + + for (Thread *worker : m_workers) { + delete worker; + } + + m_workers.clear(); + Nonce::touch(T::backend()); + + delete d_ptr->hashrate; + d_ptr->hashrate = nullptr; +} + + +template +void xmrig::Workers::tick(uint64_t) +{ + if (!d_ptr->hashrate) { + return; + } + + for (Thread *handle : m_workers) { + if (!handle->worker()) { + return; + } + + d_ptr->hashrate->add(handle->index(), handle->worker()->hashCount(), handle->worker()->timestamp()); + } + + d_ptr->hashrate->updateHighest(); +} + + +template +void xmrig::Workers::onReady(void *) +{ +} + + +namespace xmrig { + + +template<> +void xmrig::Workers::onReady(void *arg) +{ + auto handle = static_cast* >(arg); + + IWorker *worker = nullptr; + + switch (handle->config().intensity) { + case 1: + worker = new CpuWorker<1>(handle->index(), handle->config()); + break; + + case 2: + worker = new CpuWorker<2>(handle->index(), handle->config()); + break; + + case 3: + worker = new CpuWorker<3>(handle->index(), handle->config()); + break; + + case 4: + worker = new CpuWorker<4>(handle->index(), handle->config()); + break; + + case 5: + worker = new CpuWorker<5>(handle->index(), handle->config()); + break; + } + + handle->setWorker(worker); + + if (!worker->selfTest()) { + LOG_ERR("thread %zu error: \"hash self-test failed\".", handle->worker()->id()); + + return; + } + + handle->backend()->start(worker); +} + + +template class Workers; + + +} // namespace xmrig diff --git a/src/api/v1/ApiRouter.h b/src/backend/common/Workers.h similarity index 66% rename from src/api/v1/ApiRouter.h rename to src/backend/common/Workers.h index bdbbaea4..32d9458a 100644 --- a/src/api/v1/ApiRouter.h +++ b/src/backend/common/Workers.h @@ -5,6 +5,7 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett * Copyright 2018-2019 SChernykh * Copyright 2016-2019 XMRig , * @@ -22,42 +23,50 @@ * along with this program. If not, see . */ -#ifndef XMRIG_APIROUTER_H -#define XMRIG_APIROUTER_H +#ifndef XMRIG_WORKERS_H +#define XMRIG_WORKERS_H -#include "api/interfaces/IApiListener.h" -#include "rapidjson/fwd.h" - - -class Hashrate; +#include "backend/common/Thread.h" +#include "backend/cpu/CpuLaunchData.h" namespace xmrig { -class Base; +class Hashrate; +class WorkersPrivate; -class ApiRouter : public xmrig::IApiListener +template +class Workers { public: - ApiRouter(Base *base); - ~ApiRouter() override; + Workers(); + ~Workers(); -protected: - void onRequest(IApiRequest &request) override; + const Hashrate *hashrate() const; + void setBackend(IBackend *backend); + void start(const std::vector &data); + void stop(); + void tick(uint64_t ticks); private: - void getHashrate(rapidjson::Value &reply, rapidjson::Document &doc) const; - void getMiner(rapidjson::Value &reply, rapidjson::Document &doc) const; - void getThreads(rapidjson::Value &reply, rapidjson::Document &doc) const; + static void onReady(void *arg); - Base *m_base; + std::vector *> m_workers; + WorkersPrivate *d_ptr; }; +template<> +void Workers::onReady(void *arg); + + +extern template class Workers; + + } // namespace xmrig -#endif /* XMRIG_APIROUTER_H */ +#endif /* XMRIG_WORKERS_H */ diff --git a/src/backend/common/common.cmake b/src/backend/common/common.cmake new file mode 100644 index 00000000..c470ea50 --- /dev/null +++ b/src/backend/common/common.cmake @@ -0,0 +1,18 @@ +set(HEADERS_BACKEND_COMMON + src/backend/common/interfaces/IBackend.h + src/backend/common/interfaces/IThread.h + src/backend/common/interfaces/IWorker.h + src/backend/common/Hashrate.h + src/backend/common/Thread.h + src/backend/common/Threads.h + src/backend/common/Worker.h + src/backend/common/Workers.h + src/backend/common/WorkerJob.h + ) + +set(SOURCES_BACKEND_COMMON + src/backend/common/Hashrate.cpp + src/backend/common/Threads.cpp + src/backend/common/Worker.cpp + src/backend/common/Workers.cpp + ) diff --git a/src/backend/common/interfaces/IBackend.h b/src/backend/common/interfaces/IBackend.h new file mode 100644 index 00000000..e19e00ba --- /dev/null +++ b/src/backend/common/interfaces/IBackend.h @@ -0,0 +1,70 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_IBACKEND_H +#define XMRIG_IBACKEND_H + + +#include + + +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +class Algorithm; +class Hashrate; +class IWorker; +class Job; +class String; + + +class IBackend +{ +public: + virtual ~IBackend() = default; + + virtual bool isEnabled() const = 0; + virtual bool isEnabled(const Algorithm &algorithm) const = 0; + virtual const Hashrate *hashrate() const = 0; + virtual const String &profileName() const = 0; + virtual const String &type() const = 0; + virtual void printHashrate(bool details) = 0; + virtual void setJob(const Job &job) = 0; + virtual void start(IWorker *worker) = 0; + virtual void stop() = 0; + virtual void tick(uint64_t ticks) = 0; + +# ifdef XMRIG_FEATURE_API + virtual rapidjson::Value toJSON(rapidjson::Document &doc) const = 0; +# endif +}; + + +} // namespace xmrig + + +#endif // XMRIG_IBACKEND_H diff --git a/src/interfaces/IThread.h b/src/backend/common/interfaces/IThread.h similarity index 95% rename from src/interfaces/IThread.h rename to src/backend/common/interfaces/IThread.h index e74b5bca..3c0a7287 100644 --- a/src/interfaces/IThread.h +++ b/src/backend/common/interfaces/IThread.h @@ -27,7 +27,7 @@ #include -#include "common/xmrig.h" +#include "crypto/common/Algorithm.h" #include "rapidjson/fwd.h" @@ -53,7 +53,7 @@ public: virtual ~IThread() = default; - virtual Algo algorithm() const = 0; + virtual Algorithm algorithm() const = 0; virtual int priority() const = 0; virtual int64_t affinity() const = 0; virtual Multiway multiway() const = 0; diff --git a/src/interfaces/IWorker.h b/src/backend/common/interfaces/IWorker.h similarity index 76% rename from src/interfaces/IWorker.h rename to src/backend/common/interfaces/IWorker.h index 83e9306e..0d7fe1d2 100644 --- a/src/interfaces/IWorker.h +++ b/src/backend/common/interfaces/IWorker.h @@ -27,6 +27,13 @@ #include +#include + + +namespace xmrig { + + +class VirtualMemory; class IWorker @@ -34,12 +41,16 @@ class IWorker public: virtual ~IWorker() = default; - virtual bool selfTest() = 0; - virtual size_t id() const = 0; - virtual uint64_t hashCount() const = 0; - virtual uint64_t timestamp() const = 0; - virtual void start() = 0; + virtual bool selfTest() = 0; + virtual const VirtualMemory *memory() const = 0; + virtual size_t id() const = 0; + virtual uint64_t hashCount() const = 0; + virtual uint64_t timestamp() const = 0; + virtual void start() = 0; }; +} // namespace xmrig + + #endif // XMRIG_IWORKER_H diff --git a/src/core/cpu/Cpu.cpp b/src/backend/cpu/Cpu.cpp similarity index 73% rename from src/core/cpu/Cpu.cpp rename to src/backend/cpu/Cpu.cpp index 773255d2..fdcad5a8 100644 --- a/src/core/cpu/Cpu.cpp +++ b/src/backend/cpu/Cpu.cpp @@ -4,8 +4,9 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * 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 @@ -25,11 +26,13 @@ #include -#include "common/cpu/Cpu.h" +#include "backend/cpu/Cpu.h" -#ifndef XMRIG_NO_LIBCPUID -# include "core/cpu/AdvancedCpuInfo.h" +#ifdef XMRIG_FEATURE_LIBCPUID +# include "backend/cpu/platform/AdvancedCpuInfo.h" +#else +# include "backend/cpu/platform/BasicCpuInfo.h" #endif @@ -48,7 +51,11 @@ void xmrig::Cpu::init() { assert(cpuInfo == nullptr); +# ifdef XMRIG_FEATURE_LIBCPUID cpuInfo = new AdvancedCpuInfo(); +# else + cpuInfo = new BasicCpuInfo(); +# endif } diff --git a/src/common/cpu/Cpu.h b/src/backend/cpu/Cpu.h similarity index 81% rename from src/common/cpu/Cpu.h rename to src/backend/cpu/Cpu.h index 1d5a9fb1..23cf37e6 100644 --- a/src/common/cpu/Cpu.h +++ b/src/backend/cpu/Cpu.h @@ -5,7 +5,8 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * 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 @@ -25,7 +26,7 @@ #define XMRIG_CPU_H -#include "common/interfaces/ICpuInfo.h" +#include "backend/cpu/interfaces/ICpuInfo.h" namespace xmrig { @@ -37,6 +38,8 @@ public: static ICpuInfo *info(); static void init(); static void release(); + + inline static Assembly::Id assembly(Assembly::Id hint) { return hint == Assembly::AUTO ? Cpu::info()->assembly() : hint; } }; diff --git a/src/backend/cpu/CpuBackend.cpp b/src/backend/cpu/CpuBackend.cpp new file mode 100644 index 00000000..ffc21597 --- /dev/null +++ b/src/backend/cpu/CpuBackend.cpp @@ -0,0 +1,343 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include + + +#include "backend/common/Hashrate.h" +#include "backend/common/interfaces/IWorker.h" +#include "backend/common/Workers.h" +#include "backend/cpu/Cpu.h" +#include "backend/cpu/CpuBackend.h" +#include "base/io/log/Log.h" +#include "base/net/stratum/Job.h" +#include "base/tools/Chrono.h" +#include "base/tools/String.h" +#include "core/config/Config.h" +#include "core/Controller.h" +#include "crypto/common/VirtualMemory.h" +#include "crypto/rx/Rx.h" +#include "crypto/rx/RxDataset.h" +#include "rapidjson/document.h" + + +namespace xmrig { + + +extern template class Threads; + + +static const String kType = "cpu"; + + +struct LaunchStatus +{ +public: + inline void reset() + { + hugePages = 0; + memory = 0; + pages = 0; + started = 0; + threads = 0; + ways = 0; + ts = Chrono::steadyMSecs(); + } + + size_t hugePages = 0; + size_t memory = 0; + size_t pages = 0; + size_t started = 0; + size_t threads = 0; + size_t ways = 0; + uint64_t ts = 0; +}; + + +class CpuBackendPrivate +{ +public: + inline CpuBackendPrivate(Controller *controller) : + controller(controller) + { + uv_mutex_init(&mutex); + } + + + inline ~CpuBackendPrivate() + { + uv_mutex_destroy(&mutex); + } + + + 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"), + profileName.data(), + threads.size(), + algo.memory() / 1024 + ); + + workers.stop(); + + status.reset(); + status.memory = algo.memory(); + status.threads = threads.size(); + + for (const CpuLaunchData &data : threads) { + status.ways += static_cast(data.intensity); + } + + workers.start(threads); + } + + + Algorithm algo; + Controller *controller; + LaunchStatus status; + std::vector threads; + String profileName; + uv_mutex_t mutex; + Workers workers; +}; + + +} // namespace xmrig + + +xmrig::CpuBackend::CpuBackend(Controller *controller) : + d_ptr(new CpuBackendPrivate(controller)) +{ + d_ptr->workers.setBackend(this); +} + + +xmrig::CpuBackend::~CpuBackend() +{ + delete d_ptr; +} + + +bool xmrig::CpuBackend::isEnabled() const +{ + return d_ptr->controller->config()->cpu().isEnabled(); +} + + +bool xmrig::CpuBackend::isEnabled(const Algorithm &algorithm) const +{ + return !d_ptr->controller->config()->cpu().threads().get(algorithm).empty(); +} + + +const xmrig::Hashrate *xmrig::CpuBackend::hashrate() const +{ + return d_ptr->workers.hashrate(); +} + + +const xmrig::String &xmrig::CpuBackend::profileName() const +{ + return d_ptr->profileName; +} + + +const xmrig::String &xmrig::CpuBackend::type() const +{ + return kType; +} + + +void xmrig::CpuBackend::printHashrate(bool details) +{ + if (!details || !hashrate()) { + return; + } + + char num[8 * 3] = { 0 }; + + Log::print(WHITE_BOLD_S "| CPU THREAD | AFFINITY | 10s H/s | 60s H/s | 15m H/s |"); + + size_t i = 0; + for (const CpuLaunchData &data : d_ptr->threads) { + Log::print("| %13zu | %8" PRId64 " | %7s | %7s | %7s |", + i, + data.affinity, + Hashrate::format(hashrate()->calc(i, Hashrate::ShortInterval), num, sizeof num / 3), + Hashrate::format(hashrate()->calc(i, Hashrate::MediumInterval), num + 8, sizeof num / 3), + Hashrate::format(hashrate()->calc(i, Hashrate::LargeInterval), num + 8 * 2, sizeof num / 3) + ); + + i++; + } +} + + +void xmrig::CpuBackend::setJob(const Job &job) +{ + if (!isEnabled()) { + d_ptr->workers.stop(); + d_ptr->threads.clear(); + return; + } + + const CpuConfig &cpu = d_ptr->controller->config()->cpu(); + + std::vector threads = cpu.get(d_ptr->controller->miner(), job.algorithm()); + if (d_ptr->threads.size() == threads.size() && std::equal(d_ptr->threads.begin(), d_ptr->threads.end(), threads.begin())) { + return; + } + + d_ptr->algo = job.algorithm(); + d_ptr->profileName = cpu.threads().profileName(job.algorithm()); + + if (d_ptr->profileName.isNull() || threads.empty()) { + d_ptr->workers.stop(); + + LOG_WARN(YELLOW_BOLD_S "CPU disabled, no suitable configuration for algo %s", job.algorithm().shortName()); + + return; + } + + d_ptr->threads = std::move(threads); + d_ptr->start(); +} + + +void xmrig::CpuBackend::start(IWorker *worker) +{ + uv_mutex_lock(&d_ptr->mutex); + + const auto pages = worker->memory()->hugePages(); + + d_ptr->status.started++; + d_ptr->status.hugePages += pages.first; + d_ptr->status.pages += pages.second; + + if (d_ptr->status.started == d_ptr->status.threads) { + const double percent = d_ptr->status.hugePages == 0 ? 0.0 : static_cast(d_ptr->status.hugePages) / d_ptr->status.pages * 100.0; + 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)"), + 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, percent, memory, + Chrono::steadyMSecs() - d_ptr->status.ts + ); + } + + uv_mutex_unlock(&d_ptr->mutex); + + worker->start(); +} + + +void xmrig::CpuBackend::stop() +{ + d_ptr->workers.stop(); +} + + +void xmrig::CpuBackend::tick(uint64_t ticks) +{ + d_ptr->workers.tick(ticks); +} + + +#ifdef XMRIG_FEATURE_API +rapidjson::Value xmrig::CpuBackend::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + const CpuConfig &cpu = d_ptr->controller->config()->cpu(); + + Value out(kObjectType); + out.AddMember("type", type().toJSON(), allocator); + out.AddMember("enabled", isEnabled(), allocator); + out.AddMember("algo", d_ptr->algo.toJSON(), allocator); + out.AddMember("profile", profileName().toJSON(), allocator); + out.AddMember("hw-aes", cpu.isHwAES(), allocator); + out.AddMember("priority", cpu.priority(), allocator); + +# ifdef XMRIG_FEATURE_ASM + const Assembly assembly = Cpu::assembly(cpu.assembly()); + out.AddMember("asm", assembly.toJSON(), allocator); +# else + out.AddMember("asm", false, allocator); +# endif + + uv_mutex_lock(&d_ptr->mutex); + uint64_t pages[2] = { d_ptr->status.hugePages, d_ptr->status.pages }; + const size_t ways = d_ptr->status.ways; + uv_mutex_unlock(&d_ptr->mutex); + +# ifdef XMRIG_ALGO_RANDOMX + if (d_ptr->algo.family() == Algorithm::RANDOM_X) { + RxDataset *dataset = Rx::dataset(); + if (dataset) { + const auto rxPages = dataset->hugePages(); + pages[0] += rxPages.first; + pages[1] += rxPages.second; + } + } +# endif + + rapidjson::Value hugepages(rapidjson::kArrayType); + hugepages.PushBack(pages[0], allocator); + hugepages.PushBack(pages[1], allocator); + + out.AddMember("hugepages", hugepages, allocator); + out.AddMember("memory", static_cast(d_ptr->algo.isValid() ? (ways * d_ptr->algo.memory()) : 0), allocator); + + if (d_ptr->threads.empty() || !hashrate()) { + return out; + } + + Value threads(kArrayType); + const Hashrate *hr = hashrate(); + + size_t i = 0; + for (const CpuLaunchData &data : d_ptr->threads) { + Value thread(kObjectType); + thread.AddMember("intensity", data.intensity, allocator); + thread.AddMember("affinity", data.affinity, allocator); + thread.AddMember("av", data.av(), allocator); + + Value hashrate(kArrayType); + hashrate.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); + hashrate.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); + hashrate.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); + + i++; + + thread.AddMember("hashrate", hashrate, allocator); + threads.PushBack(thread, allocator); + } + + out.AddMember("threads", threads, allocator); + + return out; +} +#endif diff --git a/src/workers/ThreadHandle.h b/src/backend/cpu/CpuBackend.h similarity index 58% rename from src/workers/ThreadHandle.h rename to src/backend/cpu/CpuBackend.h index f3e09ce5..613e7cb6 100644 --- a/src/workers/ThreadHandle.h +++ b/src/backend/cpu/CpuBackend.h @@ -22,42 +22,49 @@ * along with this program. If not, see . */ -#ifndef XMRIG_THREADHANDLE_H -#define XMRIG_THREADHANDLE_H +#ifndef XMRIG_CPUBACKEND_H +#define XMRIG_CPUBACKEND_H -#include -#include -#include +#include "backend/common/interfaces/IBackend.h" -#include "interfaces/IThread.h" +namespace xmrig { -class IWorker; +class Controller; +class CpuBackendPrivate; +class Miner; -class ThreadHandle +class CpuBackend : public IBackend { public: - ThreadHandle(xmrig::IThread *config, uint32_t offset, size_t totalWays); - void join(); - void start(void (*callback) (void *)); + CpuBackend(Controller *controller); + ~CpuBackend() override; - inline IWorker *worker() const { return m_worker; } - inline size_t threadId() const { return m_config->index(); } - inline size_t totalWays() const { return m_totalWays; } - inline uint32_t offset() const { return m_offset; } - inline void setWorker(IWorker *worker) { assert(worker != nullptr); m_worker = worker; } - inline xmrig::IThread *config() const { return m_config; } +protected: + bool isEnabled() const override; + bool isEnabled(const Algorithm &algorithm) const override; + const Hashrate *hashrate() const override; + const String &profileName() const override; + const String &type() const override; + void printHashrate(bool details) override; + void setJob(const Job &job) override; + void start(IWorker *worker) override; + void stop() override; + void tick(uint64_t ticks) override; + +# ifdef XMRIG_FEATURE_API + rapidjson::Value toJSON(rapidjson::Document &doc) const override; +# endif private: - IWorker *m_worker; - size_t m_totalWays; - uint32_t m_offset; - uv_thread_t m_thread; - xmrig::IThread *m_config; + CpuBackendPrivate *d_ptr; }; -#endif /* XMRIG_THREADHANDLE_H */ +} /* namespace xmrig */ + + +#endif /* XMRIG_CPUBACKEND_H */ diff --git a/src/backend/cpu/CpuConfig.cpp b/src/backend/cpu/CpuConfig.cpp new file mode 100644 index 00000000..4c86ceea --- /dev/null +++ b/src/backend/cpu/CpuConfig.cpp @@ -0,0 +1,187 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include "backend/cpu/Cpu.h" +#include "backend/cpu/CpuConfig.h" +#include "base/io/json/Json.h" +#include "rapidjson/document.h" + + +namespace xmrig { + +static const char *kCn = "cn"; +static const char *kEnabled = "enabled"; +static const char *kHugePages = "huge-pages"; +static const char *kHwAes = "hw-aes"; +static const char *kPriority = "priority"; + +#ifdef XMRIG_FEATURE_ASM +static const char *kAsm = "asm"; +#endif + +#ifdef XMRIG_ALGO_CN_GPU +static const char *kCnGPU = "cn/gpu"; +#endif + +#ifdef XMRIG_ALGO_CN_LITE +static const char *kCnLite = "cn-lite"; +#endif + +#ifdef XMRIG_ALGO_CN_HEAVY +static const char *kCnHeavy = "cn-heavy"; +#endif + +#ifdef XMRIG_ALGO_CN_PICO +static const char *kCnPico = "cn-pico"; +#endif + +#ifdef XMRIG_ALGO_RANDOMX +static const char *kRx = "rx"; +static const char *kRxWOW = "rx/wow"; +#endif + +extern template class Threads; + +} + + +xmrig::CpuConfig::CpuConfig() +{ +} + + +bool xmrig::CpuConfig::isHwAES() const +{ + return (m_aes == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aes) == AES_HW; +} + + +rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Value obj(kObjectType); + + obj.AddMember(StringRef(kEnabled), m_enabled, allocator); + obj.AddMember(StringRef(kHugePages), m_hugePages, 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); + +# ifdef XMRIG_FEATURE_ASM + obj.AddMember(StringRef(kAsm), m_assembly.toJSON(), allocator); +# endif + + m_threads.toJSON(obj, doc); + + return obj; +} + + +std::vector xmrig::CpuConfig::get(const Miner *miner, const Algorithm &algorithm) const +{ + std::vector out; + const std::vector &threads = m_threads.get(algorithm); + + if (threads.empty()) { + return out; + } + + out.reserve(threads.size()); + + for (const CpuThread &thread : threads) { + out.push_back(CpuLaunchData(miner, algorithm, *this, thread)); + } + + return out; +} + + +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); + + setAesMode(Json::getValue(value, kHwAes)); + setPriority(Json::getInt(value, kPriority, -1)); + +# ifdef XMRIG_FEATURE_ASM + m_assembly = Json::getValue(value, kAsm); +# endif + + if (!m_threads.read(value)) { + generate(); + } + } + else if (value.IsBool() && value.IsFalse()) { + m_enabled = false; + } + else { + generate(); + } +} + + +void xmrig::CpuConfig::generate() +{ + m_shouldSave = true; + + m_threads.disable(Algorithm::CN_0); + m_threads.move(kCn, Cpu::info()->threads(Algorithm::CN_0)); + +# ifdef XMRIG_ALGO_CN_GPU + m_threads.move(kCnGPU, Cpu::info()->threads(Algorithm::CN_GPU)); +# endif + +# ifdef XMRIG_ALGO_CN_LITE + m_threads.disable(Algorithm::CN_LITE_0); + m_threads.move(kCnLite, Cpu::info()->threads(Algorithm::CN_LITE_1)); +# endif + +# ifdef XMRIG_ALGO_CN_HEAVY + m_threads.move(kCnHeavy, Cpu::info()->threads(Algorithm::CN_HEAVY_0)); +# endif + +# ifdef XMRIG_ALGO_CN_PICO + m_threads.move(kCnPico, Cpu::info()->threads(Algorithm::CN_PICO_0)); +# endif + +# ifdef XMRIG_ALGO_RANDOMX + m_threads.move(kRx, Cpu::info()->threads(Algorithm::RX_0)); + m_threads.move(kRxWOW, Cpu::info()->threads(Algorithm::RX_WOW)); +# endif +} + + +void xmrig::CpuConfig::setAesMode(const rapidjson::Value &aesMode) +{ + if (aesMode.IsBool()) { + m_aes = aesMode.GetBool() ? AES_HW : AES_SOFT; + } + else { + m_aes = AES_AUTO; + } +} diff --git a/src/backend/cpu/CpuConfig.h b/src/backend/cpu/CpuConfig.h new file mode 100644 index 00000000..5b2f3f86 --- /dev/null +++ b/src/backend/cpu/CpuConfig.h @@ -0,0 +1,80 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_CPUCONFIG_H +#define XMRIG_CPUCONFIG_H + + +#include "backend/common/Threads.h" +#include "backend/cpu/CpuLaunchData.h" +#include "backend/cpu/CpuThread.h" +#include "crypto/common/Assembly.h" + + +namespace xmrig { + + +class CpuConfig +{ +public: + enum AesMode { + AES_AUTO, + AES_HW, + AES_SOFT + }; + + CpuConfig(); + + bool isHwAES() const; + rapidjson::Value toJSON(rapidjson::Document &doc) const; + std::vector get(const Miner *miner, const Algorithm &algorithm) const; + void read(const rapidjson::Value &value); + + inline bool isEnabled() const { return m_enabled; } + inline bool isHugePages() const { return m_hugePages; } + inline bool isShouldSave() const { return m_shouldSave; } + inline const Assembly &assembly() const { return m_assembly; } + inline const Threads &threads() const { return m_threads; } + inline int priority() const { return m_priority; } + +private: + void generate(); + void setAesMode(const rapidjson::Value &aesMode); + + inline void setPriority(int priority) { m_priority = (priority >= -1 && priority <= 5) ? priority : -1; } + + AesMode m_aes = AES_AUTO; + Assembly m_assembly; + bool m_enabled = true; + bool m_hugePages = true; + bool m_shouldSave = false; + int m_priority = -1; + Threads m_threads; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_CPUCONFIG_H */ diff --git a/src/Mem_unix.cpp b/src/backend/cpu/CpuLaunchData.cpp similarity index 52% rename from src/Mem_unix.cpp rename to src/backend/cpu/CpuLaunchData.cpp index 9bdce0f5..6fa458aa 100644 --- a/src/Mem_unix.cpp +++ b/src/backend/cpu/CpuLaunchData.cpp @@ -24,66 +24,41 @@ */ -#include -#include +#include "backend/cpu/CpuLaunchData.h" +#include "backend/cpu/CpuConfig.h" -#include "base/io/log/Log.h" -#include "common/xmrig.h" -#include "crypto/common/portable/mm_malloc.h" -#include "crypto/common/VirtualMemory.h" -#include "crypto/cn/CryptoNight.h" -#include "Mem.h" - - -#if defined(__APPLE__) -# include -#endif - - -void Mem::init(bool enabled) +xmrig::CpuLaunchData::CpuLaunchData(const Miner *miner, const Algorithm &algorithm, const CpuConfig &config, const CpuThread &thread) : + algorithm(algorithm), + assembly(config.assembly()), + hugePages(config.isHugePages()), + hwAES(config.isHwAES()), + intensity(thread.intensity()), + priority(config.priority()), + affinity(thread.affinity()), + miner(miner) { - m_enabled = enabled; } -void Mem::allocate(MemInfo &info, bool enabled) +bool xmrig::CpuLaunchData::isEqual(const CpuLaunchData &other) const { - info.hugePages = 0; - - if (!enabled) { - info.memory = static_cast(_mm_malloc(info.size, 4096)); - - return; - } - - info.memory = static_cast(xmrig::VirtualMemory::allocateLargePagesMemory(info.size)); - if (!info.memory) { - return allocate(info, false);; - } - - info.hugePages = info.pages; - - if (madvise(info.memory, info.size, MADV_RANDOM | MADV_WILLNEED) != 0) { - LOG_ERR("madvise failed"); - } - - if (mlock(info.memory, info.size) == 0) { - m_flags |= Lock; - } + return (algorithm.memory() == other.algorithm.memory() + && assembly == other.assembly + && hugePages == other.hugePages + && hwAES == other.hwAES + && intensity == other.intensity + && priority == other.priority + && affinity == other.affinity + ); } -void Mem::release(MemInfo &info) +xmrig::CnHash::AlgoVariant xmrig::CpuLaunchData::av() const { - if (info.hugePages) { - if (m_flags & Lock) { - munlock(info.memory, info.size); - } + if (intensity <= 2) { + return static_cast(!hwAES ? (intensity + 2) : intensity); + } - xmrig::VirtualMemory::freeLargePagesMemory(info.memory, info.size); - } - else { - _mm_free(info.memory); - } + return static_cast(!hwAES ? (intensity + 5) : (intensity + 2)); } diff --git a/src/backend/cpu/CpuLaunchData.h b/src/backend/cpu/CpuLaunchData.h new file mode 100644 index 00000000..bb18816a --- /dev/null +++ b/src/backend/cpu/CpuLaunchData.h @@ -0,0 +1,71 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_CPULAUNCHDATA_H +#define XMRIG_CPULAUNCHDATA_H + + +#include "crypto/cn/CnHash.h" +#include "crypto/common/Algorithm.h" +#include "crypto/common/Assembly.h" +#include "crypto/common/Nonce.h" + + +namespace xmrig { + + +class CpuConfig; +class CpuThread; +class Miner; + + +class CpuLaunchData +{ +public: + CpuLaunchData(const Miner *miner, const Algorithm &algorithm, const CpuConfig &config, const CpuThread &thread); + + bool isEqual(const CpuLaunchData &other) const; + CnHash::AlgoVariant av() const; + + inline constexpr static Nonce::Backend backend() { return Nonce::CPU; } + + inline bool operator!=(const CpuLaunchData &other) const { return !isEqual(other); } + inline bool operator==(const CpuLaunchData &other) const { return isEqual(other); } + + const Algorithm algorithm; + const Assembly assembly; + const bool hugePages; + const bool hwAES; + const int intensity; + const int priority; + const int64_t affinity; + const Miner *miner; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_CPULAUNCHDATA_H */ diff --git a/src/backend/cpu/CpuThread.cpp b/src/backend/cpu/CpuThread.cpp new file mode 100644 index 00000000..e7132cfa --- /dev/null +++ b/src/backend/cpu/CpuThread.cpp @@ -0,0 +1,71 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include "backend/cpu/CpuThread.h" +#include "base/io/json/Json.h" +#include "rapidjson/document.h" + + +namespace xmrig { + + +static const char *kAffinity = "affinity"; +static const char *kIntensity = "intensity"; + + +} + + + +xmrig::CpuThread::CpuThread(const rapidjson::Value &value) +{ + if (value.IsObject()) { + m_intensity = Json::getInt(value, kIntensity, -1); + m_affinity = Json::getInt(value, kAffinity, -1); + } + else if (value.IsInt()) { + m_intensity = 1; + m_affinity = value.GetInt(); + } +} + + +rapidjson::Value xmrig::CpuThread::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + + if (intensity() > 1) { + auto &allocator = doc.GetAllocator(); + + Value obj(kObjectType); + + obj.AddMember(StringRef(kIntensity), m_intensity, allocator); + obj.AddMember(StringRef(kAffinity), m_affinity, allocator); + + return obj; + } + + return Value(m_affinity); +} diff --git a/src/backend/cpu/CpuThread.h b/src/backend/cpu/CpuThread.h new file mode 100644 index 00000000..adaffa68 --- /dev/null +++ b/src/backend/cpu/CpuThread.h @@ -0,0 +1,67 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_CPUTHREADCONFIG_H +#define XMRIG_CPUTHREADCONFIG_H + + +#include + + +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +class CpuThread +{ +public: + inline constexpr CpuThread(int intensity = 1, int64_t affinity = -1) : m_intensity(intensity), m_affinity(affinity) {} + + CpuThread(const rapidjson::Value &value); + + inline bool isEqual(const CpuThread &other) const { return other.m_affinity == m_affinity && other.m_intensity == m_intensity; } + inline bool isValid() const { return m_intensity >= 1 && m_intensity <= 5; } + inline int intensity() const { return m_intensity; } + inline int64_t affinity() const { return m_affinity; } + + inline bool operator!=(const CpuThread &other) const { return !isEqual(other); } + inline bool operator==(const CpuThread &other) const { return isEqual(other); } + + rapidjson::Value toJSON(rapidjson::Document &doc) const; + +private: + int m_intensity = -1; + int64_t m_affinity = -1; +}; + + +typedef std::vector CpuThreads; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_CPUTHREADCONFIG_H */ diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp new file mode 100644 index 00000000..14ffaa73 --- /dev/null +++ b/src/backend/cpu/CpuWorker.cpp @@ -0,0 +1,307 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include + + +#include "backend/cpu/CpuWorker.h" +#include "core/Miner.h" +#include "crypto/cn/CnCtx.h" +#include "crypto/cn/CryptoNight_test.h" +#include "crypto/common/Nonce.h" +#include "crypto/common/VirtualMemory.h" +#include "crypto/rx/Rx.h" +#include "crypto/rx/RxVm.h" +#include "net/JobResults.h" + + +#ifdef XMRIG_ALGO_RANDOMX +# include "crypto/randomx/randomx.h" +#endif + + +namespace xmrig { + +static constexpr uint32_t kReserveCount = 4096; + +} // namespace xmrig + + + +template +xmrig::CpuWorker::CpuWorker(size_t index, const CpuLaunchData &data) : + Worker(index, data.affinity, data.priority), + m_algorithm(data.algorithm), + m_assembly(data.assembly), + m_hwAES(data.hwAES), + m_av(data.av()), + m_miner(data.miner), + m_ctx() +{ + m_memory = new VirtualMemory(m_algorithm.memory() * N, data.hugePages); +} + + +template +xmrig::CpuWorker::~CpuWorker() +{ + CnCtx::release(m_ctx, N); + delete m_memory; + +# ifdef XMRIG_ALGO_RANDOMX + delete m_vm; +# endif +} + + +#ifdef XMRIG_ALGO_RANDOMX +template +void xmrig::CpuWorker::allocateRandomX_VM() +{ + if (!m_vm) { + RxDataset *dataset = Rx::dataset(m_job.currentJob().seedHash(), m_job.currentJob().algorithm()); + m_vm = new RxVm(dataset, m_memory->scratchpad(), !m_hwAES); + } +} +#endif + + +template +bool xmrig::CpuWorker::selfTest() +{ +# ifdef XMRIG_ALGO_RANDOMX + if (m_algorithm.family() == Algorithm::RANDOM_X) { + return true; + } +# endif + + allocateCnCtx(); + + if (m_algorithm.family() == Algorithm::CN) { + const bool rc = verify(Algorithm::CN_0, test_output_v0) && + verify(Algorithm::CN_1, test_output_v1) && + verify(Algorithm::CN_2, test_output_v2) && + verify(Algorithm::CN_FAST, test_output_msr) && + verify(Algorithm::CN_XAO, test_output_xao) && + verify(Algorithm::CN_RTO, test_output_rto) && + verify(Algorithm::CN_HALF, test_output_half) && + verify2(Algorithm::CN_WOW, test_output_wow) && + verify2(Algorithm::CN_R, test_output_r) && + verify(Algorithm::CN_RWZ, test_output_rwz) && + verify(Algorithm::CN_ZLS, test_output_zls) && + verify(Algorithm::CN_DOUBLE, test_output_double); + +# ifdef XMRIG_ALGO_CN_GPU + if (!rc || N > 1) { + return rc; + } + + return verify(Algorithm::CN_GPU, test_output_gpu); +# else + return rc; +# endif + } + +# ifdef XMRIG_ALGO_CN_LITE + if (m_algorithm.family() == Algorithm::CN_LITE) { + return verify(Algorithm::CN_LITE_0, test_output_v0_lite) && + verify(Algorithm::CN_LITE_1, test_output_v1_lite); + } +# endif + +# ifdef XMRIG_ALGO_CN_HEAVY + if (m_algorithm.family() == Algorithm::CN_HEAVY) { + return verify(Algorithm::CN_HEAVY_0, test_output_v0_heavy) && + verify(Algorithm::CN_HEAVY_XHV, test_output_xhv_heavy) && + verify(Algorithm::CN_HEAVY_TUBE, test_output_tube_heavy); + } +# endif + +# ifdef XMRIG_ALGO_CN_PICO + if (m_algorithm.family() == Algorithm::CN_PICO) { + return verify(Algorithm::CN_PICO_0, test_output_pico_trtl); + } +# endif + + return false; +} + + +template +void xmrig::CpuWorker::start() +{ + while (Nonce::sequence(Nonce::CPU) > 0) { + if (Nonce::isPaused()) { + do { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + while (Nonce::isPaused() && Nonce::sequence(Nonce::CPU) > 0); + + if (Nonce::sequence(Nonce::CPU) == 0) { + break; + } + + consumeJob(); + } + + while (!Nonce::isOutdated(Nonce::CPU, m_job.sequence())) { + if ((m_count & 0x7) == 0) { + storeStats(); + } + + const Job &job = m_job.currentJob(); + + if (job.algorithm().memory() != m_algorithm.memory()) { + break; + } + +# ifdef XMRIG_ALGO_RANDOMX + if (job.algorithm().family() == Algorithm::RANDOM_X) { + randomx_calculate_hash(m_vm->get(), m_job.blob(), job.size(), m_hash); + } + else +# endif + { + fn(job.algorithm())(m_job.blob(), job.size(), m_hash, m_ctx, job.height()); + } + + for (size_t i = 0; i < N; ++i) { + if (*reinterpret_cast(m_hash + (i * 32) + 24) < job.target()) { + JobResults::submit(JobResult(job, *m_job.nonce(i), m_hash + (i * 32))); + } + } + + m_job.nextRound(kReserveCount); + m_count += N; + + std::this_thread::yield(); + } + + consumeJob(); + } +} + + +template +bool xmrig::CpuWorker::verify(const Algorithm &algorithm, const uint8_t *referenceValue) +{ + cn_hash_fun func = fn(algorithm); + if (!func) { + return false; + } + + func(test_input, 76, m_hash, m_ctx, 0); + return memcmp(m_hash, referenceValue, sizeof m_hash) == 0; +} + + +template +bool xmrig::CpuWorker::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) +{ + cn_hash_fun func = fn(algorithm); + if (!func) { + return false; + } + + for (size_t i = 0; i < (sizeof(cn_r_test_input) / sizeof(cn_r_test_input[0])); ++i) { + const size_t size = cn_r_test_input[i].size; + for (size_t k = 0; k < N; ++k) { + memcpy(m_job.blob() + (k * size), cn_r_test_input[i].data, size); + } + + func(m_job.blob(), size, m_hash, m_ctx, cn_r_test_input[i].height); + + for (size_t k = 0; k < N; ++k) { + if (memcmp(m_hash + k * 32, referenceValue + i * 32, sizeof m_hash / N) != 0) { + return false; + } + } + } + + return true; +} + + +namespace xmrig { + +template<> +bool CpuWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenceValue) +{ + cn_hash_fun func = fn(algorithm); + if (!func) { + return false; + } + + for (size_t i = 0; i < (sizeof(cn_r_test_input) / sizeof(cn_r_test_input[0])); ++i) { + func(cn_r_test_input[i].data, cn_r_test_input[i].size, m_hash, m_ctx, cn_r_test_input[i].height); + + if (memcmp(m_hash, referenceValue + i * 32, sizeof m_hash) != 0) { + return false; + } + } + + return true; +} + +} // namespace xmrig + + +template +void xmrig::CpuWorker::allocateCnCtx() +{ + if (m_ctx[0] == nullptr) { + CnCtx::create(m_ctx, m_memory->scratchpad(), m_algorithm.memory(), N); + } +} + + +template +void xmrig::CpuWorker::consumeJob() +{ + m_job.add(m_miner->job(), Nonce::sequence(Nonce::CPU), kReserveCount); + +# ifdef XMRIG_ALGO_RANDOMX + if (m_job.currentJob().algorithm().family() == Algorithm::RANDOM_X) { + allocateRandomX_VM(); + } + else +# endif + { + allocateCnCtx(); + } +} + + +namespace xmrig { + +template class CpuWorker<1>; +template class CpuWorker<2>; +template class CpuWorker<3>; +template class CpuWorker<4>; +template class CpuWorker<5>; + +} // namespace xmrig + diff --git a/src/workers/MultiWorker.h b/src/backend/cpu/CpuWorker.h similarity index 57% rename from src/workers/MultiWorker.h rename to src/backend/cpu/CpuWorker.h index bfdf97eb..4cdd10f8 100644 --- a/src/workers/MultiWorker.h +++ b/src/backend/cpu/CpuWorker.h @@ -23,67 +23,76 @@ * along with this program. If not, see . */ -#ifndef XMRIG_MULTIWORKER_H -#define XMRIG_MULTIWORKER_H - - -#ifdef XMRIG_ALGO_RANDOMX -# include -#endif +#ifndef XMRIG_CPUWORKER_H +#define XMRIG_CPUWORKER_H +#include "backend/common/Worker.h" +#include "backend/common/WorkerJob.h" +#include "backend/cpu/CpuLaunchData.h" #include "base/net/stratum/Job.h" -#include "Mem.h" #include "net/JobResult.h" -#include "workers/Worker.h" -class Handle; +namespace xmrig { + + +class RxVm; template -class MultiWorker : public Worker +class CpuWorker : public Worker { public: - MultiWorker(ThreadHandle *handle); - ~MultiWorker(); + CpuWorker(size_t index, const CpuLaunchData &data); + ~CpuWorker() override; protected: bool selfTest() override; void start() override; + inline const VirtualMemory *memory() const override { return m_memory; } + private: + inline cn_hash_fun fn(const Algorithm &algorithm) const { return CnHash::fn(algorithm, m_av, m_assembly); } + # ifdef XMRIG_ALGO_RANDOMX void allocateRandomX_VM(); # endif - bool resume(const xmrig::Job &job); - bool verify(xmrig::Variant variant, const uint8_t *referenceValue); - bool verify2(xmrig::Variant variant, const uint8_t *referenceValue); + bool verify(const Algorithm &algorithm, const uint8_t *referenceValue); + bool verify2(const Algorithm &algorithm, const uint8_t *referenceValue); + void allocateCnCtx(); void consumeJob(); - void save(const xmrig::Job &job); - - inline uint32_t *nonce(size_t index) - { - return reinterpret_cast(m_state.blob + (index * m_state.job.size()) + 39); - } - - struct State - { - alignas(16) uint8_t blob[xmrig::Job::kMaxBlobSize * N]; - xmrig::Job job; - }; - + const Algorithm m_algorithm; + const Assembly m_assembly; + const bool m_hwAES; + const CnHash::AlgoVariant m_av; + const Miner *m_miner; cryptonight_ctx *m_ctx[N]; - State m_pausedState; - State m_state; uint8_t m_hash[N * 32]; + VirtualMemory *m_memory = nullptr; + WorkerJob m_job; # ifdef XMRIG_ALGO_RANDOMX - randomx_vm *m_rx_vm = nullptr; + RxVm *m_vm = nullptr; # endif }; -#endif /* XMRIG_MULTIWORKER_H */ +template<> +bool CpuWorker<1>::verify2(const Algorithm &algorithm, const uint8_t *referenceValue); + + +extern template class CpuWorker<1>; +extern template class CpuWorker<2>; +extern template class CpuWorker<3>; +extern template class CpuWorker<4>; +extern template class CpuWorker<5>; + + +} // namespace xmrig + + +#endif /* XMRIG_CPUWORKER_H */ diff --git a/src/backend/cpu/cpu.cmake b/src/backend/cpu/cpu.cmake new file mode 100644 index 00000000..871debd3 --- /dev/null +++ b/src/backend/cpu/cpu.cmake @@ -0,0 +1,37 @@ +set(HEADERS_BACKEND_CPU + src/backend/cpu/Cpu.h + src/backend/cpu/CpuBackend.h + src/backend/cpu/CpuConfig.h + src/backend/cpu/CpuLaunchData.cpp + src/backend/cpu/CpuThread.h + src/backend/cpu/CpuWorker.h + src/backend/cpu/interfaces/ICpuInfo.h + ) + +set(SOURCES_BACKEND_CPU + src/backend/cpu/Cpu.cpp + src/backend/cpu/CpuBackend.cpp + src/backend/cpu/CpuConfig.cpp + src/backend/cpu/CpuLaunchData.h + src/backend/cpu/CpuThread.cpp + src/backend/cpu/CpuWorker.cpp + ) + + +if (WITH_LIBCPUID) + add_subdirectory(src/3rdparty/libcpuid) + include_directories(src/3rdparty/libcpuid) + add_definitions(/DXMRIG_FEATURE_LIBCPUID) + + set(CPUID_LIB cpuid) + set(SOURCES_CPUID src/backend/cpu/platform/AdvancedCpuInfo.h src/backend/cpu/platform/AdvancedCpuInfo.cpp src/backend/cpu/Cpu.cpp) +else() + remove_definitions(/DXMRIG_FEATURE_LIBCPUID) + set(SOURCES_CPUID src/backend/cpu/platform/BasicCpuInfo.h src/backend/cpu/Cpu.cpp) + + if (XMRIG_ARM) + set(SOURCES_CPUID ${SOURCES_CPUID} src/backend/cpu/platform/BasicCpuInfo_arm.cpp) + else() + set(SOURCES_CPUID ${SOURCES_CPUID} src/backend/cpu/platform/BasicCpuInfo.cpp) + endif() +endif() diff --git a/src/common/interfaces/ICpuInfo.h b/src/backend/cpu/interfaces/ICpuInfo.h similarity index 67% rename from src/common/interfaces/ICpuInfo.h rename to src/backend/cpu/interfaces/ICpuInfo.h index dd4034b3..5848db89 100644 --- a/src/common/interfaces/ICpuInfo.h +++ b/src/backend/cpu/interfaces/ICpuInfo.h @@ -26,11 +26,9 @@ #define XMRIG_CPUINFO_H -#include -#include - - -#include "common/xmrig.h" +#include "backend/cpu/CpuThread.h" +#include "crypto/common/Assembly.h" +#include "crypto/common/Algorithm.h" namespace xmrig { @@ -39,21 +37,26 @@ namespace xmrig { class ICpuInfo { public: - virtual ~ICpuInfo() {} + virtual ~ICpuInfo() = default; +# if defined(__x86_64__) || defined(_M_AMD64) || defined (__arm64__) || defined (__aarch64__) + inline constexpr static bool isX64() { return true; } +# else + inline constexpr static bool isX64() { return false; } +# endif + + virtual Assembly::Id assembly() const = 0; virtual bool hasAES() const = 0; virtual bool hasAVX2() const = 0; virtual bool isSupported() const = 0; - virtual bool isX64() const = 0; virtual const char *brand() const = 0; - virtual int32_t cores() const = 0; - virtual int32_t L2() const = 0; - virtual int32_t L3() const = 0; - virtual int32_t nodes() const = 0; - virtual int32_t sockets() const = 0; - virtual int32_t threads() const = 0; - virtual size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const = 0; - virtual xmrig::Assembly assembly() const = 0; + virtual CpuThreads threads(const Algorithm &algorithm) const = 0; + virtual size_t cores() const = 0; + virtual size_t L2() const = 0; + virtual size_t L3() const = 0; + virtual size_t nodes() const = 0; + virtual size_t sockets() const = 0; + virtual size_t threads() const = 0; }; diff --git a/src/core/cpu/AdvancedCpuInfo.cpp b/src/backend/cpu/platform/AdvancedCpuInfo.cpp similarity index 64% rename from src/core/cpu/AdvancedCpuInfo.cpp rename to src/backend/cpu/platform/AdvancedCpuInfo.cpp index df6a385e..45b0dd66 100644 --- a/src/core/cpu/AdvancedCpuInfo.cpp +++ b/src/backend/cpu/platform/AdvancedCpuInfo.cpp @@ -22,66 +22,57 @@ * along with this program. If not, see . */ +#include +#include #include #include #include -#include "core/cpu/AdvancedCpuInfo.h" +#include "backend/cpu/platform/AdvancedCpuInfo.h" xmrig::AdvancedCpuInfo::AdvancedCpuInfo() : - m_assembly(ASM_NONE), - m_aes(false), - m_avx2(false), - m_L2_exclusive(false), - m_brand(), - m_cores(0), - m_L2(0), - m_L3(0), - m_sockets(1), - m_threads(0) + m_brand() { - struct cpu_raw_data_t raw = { 0 }; - struct cpu_id_t data = { 0 }; + struct cpu_raw_data_t raw = {}; + struct cpu_id_t data = {}; cpuid_get_raw_data(&raw); cpu_identify(&raw, &data); strncpy(m_brand, data.brand_str, sizeof(m_brand)); - m_threads = data.total_logical_cpus; - m_sockets = threads() / data.num_logical_cpus; - if (m_sockets == 0) { - m_sockets = 1; - } + m_threads = static_cast(data.total_logical_cpus); + m_sockets = std::max(threads() / static_cast(data.num_logical_cpus), 1); + m_cores = static_cast(data.num_cores) * m_sockets; + m_L3 = data.l3_cache > 0 ? static_cast(data.l3_cache) * m_sockets : 0; - m_cores = data.num_cores * m_sockets; - m_L3 = data.l3_cache > 0 ? data.l3_cache * m_sockets : 0; + const size_t l2 = static_cast(data.l2_cache); // Workaround for AMD CPUs https://github.com/anrieff/libcpuid/issues/97 if (data.vendor == VENDOR_AMD && data.ext_family >= 0x15 && data.ext_family < 0x17) { - m_L2 = data.l2_cache * (cores() / 2) * m_sockets; + m_L2 = l2 * (cores() / 2) * m_sockets; m_L2_exclusive = true; } // Workaround for Intel Pentium Dual-Core, Core Duo, Core 2 Duo, Core 2 Quad and their Xeon homologue // These processors have L2 cache shared by 2 cores. else if (data.vendor == VENDOR_INTEL && data.ext_family == 0x06 && (data.ext_model == 0x0E || data.ext_model == 0x0F || data.ext_model == 0x17)) { - int l2_count_per_socket = cores() > 1 ? cores() / 2 : 1; - m_L2 = data.l2_cache > 0 ? data.l2_cache * l2_count_per_socket * m_sockets : 0; + size_t l2_count_per_socket = cores() > 1 ? cores() / 2 : 1; + m_L2 = data.l2_cache > 0 ? l2 * l2_count_per_socket * m_sockets : 0; } else{ - m_L2 = data.l2_cache > 0 ? data.l2_cache * cores() * m_sockets : 0; + m_L2 = data.l2_cache > 0 ? l2 * cores() * m_sockets : 0; } if (data.flags[CPU_FEATURE_AES]) { m_aes = true; if (data.vendor == VENDOR_AMD) { - m_assembly = (data.ext_family >= 23) ? ASM_RYZEN : ASM_BULLDOZER; + m_assembly = (data.ext_family >= 23) ? Assembly::RYZEN : Assembly::BULLDOZER; } else if (data.vendor == VENDOR_INTEL) { - m_assembly = ASM_INTEL; + m_assembly = Assembly::INTEL; } } @@ -89,13 +80,21 @@ xmrig::AdvancedCpuInfo::AdvancedCpuInfo() : } -size_t xmrig::AdvancedCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) const +xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm) const { if (threads() == 1) { - return 1; + return CpuThreads(1); } +# ifdef XMRIG_ALGO_CN_GPU + if (algorithm == Algorithm::CN_GPU) { + return CpuThreads(threads()); + } +# endif + size_t cache = 0; + size_t count = 0; + if (m_L3) { cache = m_L2_exclusive ? (m_L2 + m_L3) : m_L3; } @@ -103,12 +102,14 @@ size_t xmrig::AdvancedCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsa cache = m_L2; } - size_t count = 0; - if (cache) { - count = cache / memSize; + cache *= 1024; + const size_t memory = algorithm.memory(); + assert(memory > 0); - if (cache % memSize >= memSize / 2) { + count = cache / memory; + + if (cache % memory >= memory / 2) { count++; } } @@ -116,13 +117,5 @@ size_t xmrig::AdvancedCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsa count = threads() / 2; } - if (count > (size_t) threads()) { - count = threads(); - } - - if (((float) count / threads() * 100) > maxCpuUsage) { - count = (int) ceil((float) threads() * (maxCpuUsage / 100.0)); - } - - return count < 1 ? 1 : count; + return CpuThreads(std::max(std::min(count, threads()), 1)); } diff --git a/src/core/cpu/AdvancedCpuInfo.h b/src/backend/cpu/platform/AdvancedCpuInfo.h similarity index 66% rename from src/core/cpu/AdvancedCpuInfo.h rename to src/backend/cpu/platform/AdvancedCpuInfo.h index 0765da33..889fba00 100644 --- a/src/core/cpu/AdvancedCpuInfo.h +++ b/src/backend/cpu/platform/AdvancedCpuInfo.h @@ -26,7 +26,7 @@ #define XMRIG_ADVANCEDCPUINFO_H -#include "common/interfaces/ICpuInfo.h" +#include "backend/cpu/interfaces/ICpuInfo.h" namespace xmrig { @@ -38,37 +38,31 @@ public: AdvancedCpuInfo(); protected: - size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const override; + CpuThreads threads(const Algorithm &algorithm) const override; - inline Assembly assembly() const override { return m_assembly; } + inline Assembly::Id assembly() const override { return m_assembly; } inline bool hasAES() const override { return m_aes; } inline bool hasAVX2() const override { return m_avx2; } inline bool isSupported() const override { return true; } inline const char *brand() const override { return m_brand; } - inline int32_t cores() const override { return m_cores; } - inline int32_t L2() const override { return m_L2; } - inline int32_t L3() const override { return m_L3; } - inline int32_t nodes() const override { return -1; } - inline int32_t sockets() const override { return m_sockets; } - inline int32_t threads() const override { return m_threads; } - -# if defined(__x86_64__) || defined(_M_AMD64) - inline bool isX64() const override { return true; } -# else - inline bool isX64() const override { return false; } -# endif + inline size_t cores() const override { return m_cores; } + inline size_t L2() const override { return m_L2; } + inline size_t L3() const override { return m_L3; } + inline size_t nodes() const override { return 0; } + inline size_t sockets() const override { return m_sockets; } + inline size_t threads() const override { return m_threads; } private: Assembly m_assembly; - bool m_aes; - bool m_avx2; - bool m_L2_exclusive; + bool m_aes = false; + bool m_avx2 = false; + bool m_L2_exclusive = false; char m_brand[64]; - int32_t m_cores; - int32_t m_L2; - int32_t m_L3; - int32_t m_sockets; - int32_t m_threads; + size_t m_cores = 0; + size_t m_L2 = 0; + size_t m_L3 = 0; + size_t m_sockets = 1; + size_t m_threads = 0; }; diff --git a/src/common/cpu/BasicCpuInfo.cpp b/src/backend/cpu/platform/BasicCpuInfo.cpp similarity index 81% rename from src/common/cpu/BasicCpuInfo.cpp rename to src/backend/cpu/platform/BasicCpuInfo.cpp index d7778bdd..f30466fe 100644 --- a/src/common/cpu/BasicCpuInfo.cpp +++ b/src/backend/cpu/platform/BasicCpuInfo.cpp @@ -22,6 +22,7 @@ * along with this program. If not, see . */ +#include #include #include @@ -45,7 +46,8 @@ #endif -#include "common/cpu/BasicCpuInfo.h" +#include "backend/cpu/platform/BasicCpuInfo.h" +#include "crypto/common/Assembly.h" #define VENDOR_ID (0) @@ -121,15 +123,15 @@ static inline bool has_ossave() xmrig::BasicCpuInfo::BasicCpuInfo() : - m_assembly(ASM_NONE), + m_assembly(Assembly::NONE), m_aes(has_aes_ni()), - m_avx2(has_avx2() && has_ossave()), m_brand(), + m_avx2(has_avx2() && has_ossave()), m_threads(std::thread::hardware_concurrency()) { cpu_brand_string(m_brand); -# ifndef XMRIG_NO_ASM +# ifdef XMRIG_FEATURE_ASM if (hasAES()) { char vendor[13] = { 0 }; int32_t data[4] = { 0 }; @@ -141,19 +143,35 @@ xmrig::BasicCpuInfo::BasicCpuInfo() : memcpy(vendor + 8, &data[2], 4); if (memcmp(vendor, "GenuineIntel", 12) == 0) { - m_assembly = ASM_INTEL; + m_assembly = Assembly::INTEL; } else if (memcmp(vendor, "AuthenticAMD", 12) == 0) { - m_assembly = ASM_RYZEN; + m_assembly = Assembly::RYZEN; } } # endif } -size_t xmrig::BasicCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) const +xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm) const { - const size_t count = threads() / 2; + if (threads() == 1) { + return CpuThreads(1); + } - return count < 1 ? 1 : count; +# ifdef XMRIG_ALGO_CN_GPU + if (algorithm == Algorithm::CN_GPU) { + return CpuThreads(threads()); + } +# endif + + if (algorithm.family() == Algorithm::CN_LITE || algorithm.family() == Algorithm::CN_PICO) { + return CpuThreads(threads()); + } + + if (algorithm.family() == Algorithm::CN_HEAVY) { + return CpuThreads(std::max(threads() / 4, 1)); + } + + return CpuThreads(std::max(threads() / 2, 1)); } diff --git a/src/common/cpu/BasicCpuInfo.h b/src/backend/cpu/platform/BasicCpuInfo.h similarity index 67% rename from src/common/cpu/BasicCpuInfo.h rename to src/backend/cpu/platform/BasicCpuInfo.h index 95857ed2..12d0e037 100644 --- a/src/common/cpu/BasicCpuInfo.h +++ b/src/backend/cpu/platform/BasicCpuInfo.h @@ -26,7 +26,7 @@ #define XMRIG_BASICCPUINFO_H -#include "common/interfaces/ICpuInfo.h" +#include "backend/cpu/interfaces/ICpuInfo.h" namespace xmrig { @@ -38,32 +38,26 @@ public: BasicCpuInfo(); protected: - size_t optimalThreadsCount(size_t memSize, int maxCpuUsage) const override; + CpuThreads threads(const Algorithm &algorithm) const override; - inline Assembly assembly() const override { return m_assembly; } + inline Assembly::Id assembly() const override { return m_assembly; } inline bool hasAES() const override { return m_aes; } inline bool hasAVX2() const override { return m_avx2; } inline bool isSupported() const override { return true; } inline const char *brand() const override { return m_brand; } - inline int32_t cores() const override { return -1; } - inline int32_t L2() const override { return -1; } - inline int32_t L3() const override { return -1; } - inline int32_t nodes() const override { return -1; } - inline int32_t sockets() const override { return 1; } - inline int32_t threads() const override { return m_threads; } - -# if defined(__x86_64__) || defined(_M_AMD64) || defined (__arm64__) || defined (__aarch64__) - inline bool isX64() const override { return true; } -# else - inline bool isX64() const override { return false; } -# endif + inline size_t cores() const override { return 0; } + inline size_t L2() const override { return 0; } + inline size_t L3() const override { return 0; } + inline size_t nodes() const override { return 0; } + inline size_t sockets() const override { return 1; } + inline size_t threads() const override { return m_threads; } private: Assembly m_assembly; bool m_aes; - bool m_avx2; - char m_brand[64]; - int32_t m_threads; + char m_brand[64 + 6]; + const bool m_avx2; + const size_t m_threads; }; diff --git a/src/common/cpu/BasicCpuInfo_arm.cpp b/src/backend/cpu/platform/BasicCpuInfo_arm.cpp similarity index 91% rename from src/common/cpu/BasicCpuInfo_arm.cpp rename to src/backend/cpu/platform/BasicCpuInfo_arm.cpp index dea8de73..3d733535 100644 --- a/src/common/cpu/BasicCpuInfo_arm.cpp +++ b/src/backend/cpu/platform/BasicCpuInfo_arm.cpp @@ -32,13 +32,13 @@ #endif -#include "common/cpu/BasicCpuInfo.h" +#include "backend/cpu/platform/BasicCpuInfo.h" xmrig::BasicCpuInfo::BasicCpuInfo() : m_aes(false), - m_avx2(false), m_brand(), + m_avx2(false), m_threads(std::thread::hardware_concurrency()) { # ifdef XMRIG_ARMv8 @@ -57,7 +57,7 @@ xmrig::BasicCpuInfo::BasicCpuInfo() : } -size_t xmrig::BasicCpuInfo::optimalThreadsCount(size_t memSize, int maxCpuUsage) const +xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm) const { - return threads(); + return CpuThreads(threads()); } diff --git a/src/base/base.cmake b/src/base/base.cmake index dcc10495..ef4da131 100644 --- a/src/base/base.cmake +++ b/src/base/base.cmake @@ -26,6 +26,7 @@ set(HEADERS_BASE src/base/kernel/interfaces/IStrategyListener.h src/base/kernel/interfaces/ITimerListener.h src/base/kernel/interfaces/IWatcherListener.h + src/base/kernel/Platform.h src/base/kernel/Process.h src/base/kernel/Signals.h src/base/net/dns/Dns.h @@ -63,6 +64,7 @@ set(SOURCES_BASE src/base/kernel/config/BaseConfig.cpp src/base/kernel/config/BaseTransform.cpp src/base/kernel/Entry.cpp + src/base/kernel/Platform.cpp src/base/kernel/Process.cpp src/base/kernel/Signals.cpp src/base/net/dns/Dns.cpp @@ -83,9 +85,20 @@ set(SOURCES_BASE if (WIN32) - set(SOURCES_OS src/base/io/json/Json_win.cpp) + set(SOURCES_OS + src/base/io/json/Json_win.cpp + src/base/kernel/Platform_win.cpp + ) +elseif (APPLE) + set(SOURCES_OS + src/base/io/json/Json_unix.cpp + src/base/kernel/Platform_mac.cpp + ) else() - set(SOURCES_OS src/base/io/json/Json_unix.cpp) + set(SOURCES_OS + src/base/io/json/Json_unix.cpp + src/base/kernel//Platform_unix.cpp + ) endif() @@ -133,5 +146,3 @@ else() remove_definitions(/DXMRIG_FEATURE_HTTP) remove_definitions(/DXMRIG_FEATURE_API) endif() - -add_definitions(/DXMRIG_DEPRECATED) diff --git a/src/base/io/log/Log.h b/src/base/io/log/Log.h index a14ffded..078a8546 100644 --- a/src/base/io/log/Log.h +++ b/src/base/io/log/Log.h @@ -61,43 +61,53 @@ private: }; -#define CSI "\x1B[" // Control Sequence Introducer (ANSI spec name) -#define CLEAR CSI "0m" // all attributes off -#define BRIGHT_BLACK_S CSI "0;90m" // somewhat MD.GRAY -#define BLACK_S CSI "0;30m" -#define BLACK_BOLD_S CSI "1;30m" // another name for GRAY -#define RED_S CSI "0;31m" -#define RED_BOLD_S CSI "1;31m" -#define GREEN_S CSI "0;32m" -#define GREEN_BOLD_S CSI "1;32m" -#define YELLOW_S CSI "0;33m" -#define YELLOW_BOLD_S CSI "1;33m" -#define BLUE_S CSI "0;34m" -#define BLUE_BOLD_S CSI "1;34m" -#define MAGENTA_S CSI "0;35m" -#define MAGENTA_BOLD_S CSI "1;35m" -#define CYAN_S CSI "0;36m" -#define CYAN_BOLD_S CSI "1;36m" -#define WHITE_S CSI "0;37m" // another name for LT.GRAY -#define WHITE_BOLD_S CSI "1;37m" // actually white +#define CSI "\x1B[" // Control Sequence Introducer (ANSI spec name) +#define CLEAR CSI "0m" // all attributes off +#define BRIGHT_BLACK_S CSI "0;90m" // somewhat MD.GRAY +#define BLACK_S CSI "0;30m" +#define BLACK_BOLD_S CSI "1;30m" // another name for GRAY +#define RED_S CSI "0;31m" +#define RED_BOLD_S CSI "1;31m" +#define GREEN_S CSI "0;32m" +#define GREEN_BOLD_S CSI "1;32m" +#define YELLOW_S CSI "0;33m" +#define YELLOW_BOLD_S CSI "1;33m" +#define BLUE_S CSI "0;34m" +#define BLUE_BOLD_S CSI "1;34m" +#define MAGENTA_S CSI "0;35m" +#define MAGENTA_BOLD_S CSI "1;35m" +#define CYAN_S CSI "0;36m" +#define CYAN_BOLD_S CSI "1;36m" +#define WHITE_S CSI "0;37m" // another name for LT.GRAY +#define WHITE_BOLD_S CSI "1;37m" // actually white + +#define BLUE_BG_S CSI "44m" +#define BLUE_BG_BOLD_S CSI "44;1m" +#define MAGENTA_BG_S CSI "45m" +#define MAGENTA_BG_BOLD_S CSI "45;1m" //color wrappings -#define BLACK(x) BLACK_S x CLEAR -#define BLACK_BOLD(x) BLACK_BOLD_S x CLEAR -#define RED(x) RED_S x CLEAR -#define RED_BOLD(x) RED_BOLD_S x CLEAR -#define GREEN(x) GREEN_S x CLEAR -#define GREEN_BOLD(x) GREEN_BOLD_S x CLEAR -#define YELLOW(x) YELLOW_S x CLEAR -#define YELLOW_BOLD(x) YELLOW_BOLD_S x CLEAR -#define BLUE(x) BLUE_S x CLEAR -#define BLUE_BOLD(x) BLUE_BOLD_S x CLEAR -#define MAGENTA(x) MAGENTA_S x CLEAR -#define MAGENTA_BOLD(x) MAGENTA_BOLD_S x CLEAR -#define CYAN(x) CYAN_S x CLEAR -#define CYAN_BOLD(x) CYAN_BOLD_S x CLEAR -#define WHITE(x) WHITE_S x CLEAR -#define WHITE_BOLD(x) WHITE_BOLD_S x CLEAR +#define BLACK(x) BLACK_S x CLEAR +#define BLACK_BOLD(x) BLACK_BOLD_S x CLEAR +#define RED(x) RED_S x CLEAR +#define RED_BOLD(x) RED_BOLD_S x CLEAR +#define GREEN(x) GREEN_S x CLEAR +#define GREEN_BOLD(x) GREEN_BOLD_S x CLEAR +#define YELLOW(x) YELLOW_S x CLEAR +#define YELLOW_BOLD(x) YELLOW_BOLD_S x CLEAR +#define BLUE(x) BLUE_S x CLEAR +#define BLUE_BOLD(x) BLUE_BOLD_S x CLEAR +#define MAGENTA(x) MAGENTA_S x CLEAR +#define MAGENTA_BOLD(x) MAGENTA_BOLD_S x CLEAR +#define CYAN(x) CYAN_S x CLEAR +#define CYAN_BOLD(x) CYAN_BOLD_S x CLEAR +#define WHITE(x) WHITE_S x CLEAR +#define WHITE_BOLD(x) WHITE_BOLD_S x CLEAR + +#define BLUE_BG(x) BLUE_BG_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_BOLD(x) MAGENTA_BG_BOLD_S x CLEAR #define LOG_EMERG(x, ...) xmrig::Log::print(xmrig::Log::EMERG, x, ##__VA_ARGS__) diff --git a/src/base/kernel/Base.cpp b/src/base/kernel/Base.cpp index 1083efe9..d290e7f4 100644 --- a/src/base/kernel/Base.cpp +++ b/src/base/kernel/Base.cpp @@ -35,8 +35,8 @@ #include "base/io/Watcher.h" #include "base/kernel/Base.h" #include "base/kernel/interfaces/IBaseListener.h" +#include "base/kernel/Platform.h" #include "base/kernel/Process.h" -#include "common/Platform.h" #include "core/config/Config.h" #include "core/config/ConfigTransform.h" @@ -48,6 +48,7 @@ #ifdef XMRIG_FEATURE_API # include "api/Api.h" +# include "api/interfaces/IApiRequest.h" #endif @@ -167,12 +168,13 @@ int xmrig::Base::init() # ifdef XMRIG_FEATURE_API d_ptr->api = new Api(this); + d_ptr->api->addListener(this); # endif Platform::init(config()->userAgent()); # ifndef XMRIG_PROXY_PROJECT - Platform::setProcessPriority(config()->priority()); + Platform::setProcessPriority(config()->cpu().priority()); # endif if (!config()->isBackground()) { @@ -288,3 +290,31 @@ void xmrig::Base::onFileChanged(const String &fileName) d_ptr->replace(config); } + + +#ifdef XMRIG_FEATURE_API +void xmrig::Base::onRequest(IApiRequest &request) +{ + if (request.method() == IApiRequest::METHOD_GET) { + if (request.url() == "/1/config") { + if (request.isRestricted()) { + return request.done(403); + } + + request.accept(); + config()->getJSON(request.doc()); + } + } + else if (request.method() == IApiRequest::METHOD_PUT || request.method() == IApiRequest::METHOD_POST) { + if (request.url() == "/1/config") { + request.accept(); + + if (!reload(request.json())) { + return request.done(400); + } + + request.done(204); + } + } +} +#endif diff --git a/src/base/kernel/Base.h b/src/base/kernel/Base.h index 592d3a37..6a33a802 100644 --- a/src/base/kernel/Base.h +++ b/src/base/kernel/Base.h @@ -26,6 +26,7 @@ #define XMRIG_BASE_H +#include "api/interfaces/IApiListener.h" #include "base/kernel/interfaces/IConfigListener.h" #include "base/kernel/interfaces/IWatcherListener.h" #include "rapidjson/fwd.h" @@ -35,13 +36,13 @@ namespace xmrig { class Api; -class Config; class BasePrivate; +class Config; class IBaseListener; class Process; -class Base : public IWatcherListener +class Base : public IWatcherListener, public IApiListener { public: Base(Process *process); @@ -60,6 +61,10 @@ public: protected: void onFileChanged(const String &fileName) override; +# ifdef XMRIG_FEATURE_API + void onRequest(IApiRequest &request) override; +# endif + private: BasePrivate *d_ptr; }; diff --git a/src/common/Platform.cpp b/src/base/kernel/Platform.cpp similarity index 100% rename from src/common/Platform.cpp rename to src/base/kernel/Platform.cpp diff --git a/src/common/Platform.h b/src/base/kernel/Platform.h similarity index 90% rename from src/common/Platform.h rename to src/base/kernel/Platform.h index 85f08a2e..f3c2c719 100644 --- a/src/common/Platform.h +++ b/src/base/kernel/Platform.h @@ -35,6 +35,15 @@ class Platform { public: + static inline bool trySetThreadAffinity(int64_t cpu_id) + { + if (cpu_id < 0) { + return false; + } + + return setThreadAffinity(static_cast(cpu_id)); + } + static bool setThreadAffinity(uint64_t cpu_id); static uint32_t setTimerResolution(uint32_t resolution); static void init(const char *userAgent); diff --git a/src/common/Platform_mac.cpp b/src/base/kernel/Platform_mac.cpp similarity index 100% rename from src/common/Platform_mac.cpp rename to src/base/kernel/Platform_mac.cpp diff --git a/src/common/Platform_unix.cpp b/src/base/kernel/Platform_unix.cpp similarity index 100% rename from src/common/Platform_unix.cpp rename to src/base/kernel/Platform_unix.cpp diff --git a/src/common/Platform_win.cpp b/src/base/kernel/Platform_win.cpp similarity index 100% rename from src/common/Platform_win.cpp rename to src/base/kernel/Platform_win.cpp diff --git a/src/base/kernel/config/BaseConfig.cpp b/src/base/kernel/config/BaseConfig.cpp index af2418aa..462639e3 100644 --- a/src/base/kernel/config/BaseConfig.cpp +++ b/src/base/kernel/config/BaseConfig.cpp @@ -60,14 +60,7 @@ #include "version.h" -xmrig::BaseConfig::BaseConfig() : - m_algorithm(CRYPTONIGHT, VARIANT_AUTO), - m_autoSave(true), - m_background(false), - m_dryRun(false), - m_syslog(false), - m_upgrade(false), - m_watch(true) +xmrig::BaseConfig::BaseConfig() { } @@ -146,33 +139,8 @@ bool xmrig::BaseConfig::read(const IJsonReader &reader, const char *fileName) m_apiWorkerId = Json::getString(api, "worker-id"); } -# ifdef XMRIG_DEPRECATED - if (api.IsObject() && api.HasMember("port")) { - m_upgrade = true; - m_http.load(api); - m_http.setEnabled(Json::getUint(api, "port") > 0); - m_http.setHost("0.0.0.0"); - } - else { - m_http.load(reader.getObject("http")); - } -# else - m_http.load(chain.getObject("http")); -# endif - - m_algorithm.parseAlgorithm(reader.getString("algo", "cn")); - - m_pools.load(reader.getArray("pools")); - m_pools.setDonateLevel(reader.getInt("donate-level", kDefaultDonateLevel)); - m_pools.setProxyDonate(reader.getInt("donate-over-proxy", Pools::PROXY_DONATE_AUTO)); - m_pools.setRetries(reader.getInt("retries")); - m_pools.setRetryPause(reader.getInt("retry-pause")); - - if (!m_algorithm.isValid()) { - return false; - } - - m_pools.adjust(m_algorithm); + m_http.load(reader.getObject("http")); + m_pools.load(reader); return m_pools.active() > 0; } diff --git a/src/base/kernel/config/BaseConfig.h b/src/base/kernel/config/BaseConfig.h index f0c52536..c5cf29a3 100644 --- a/src/base/kernel/config/BaseConfig.h +++ b/src/base/kernel/config/BaseConfig.h @@ -29,7 +29,6 @@ #include "base/kernel/interfaces/IConfig.h" #include "base/net/http/Http.h" #include "base/net/stratum/Pools.h" -#include "common/xmrig.h" struct option; @@ -59,7 +58,6 @@ public: inline uint32_t printTime() const { return m_printTime; } inline bool isWatch() const override { return m_watch && !m_fileName.isNull(); } - inline const Algorithm &algorithm() const override { return m_algorithm; } inline const String &fileName() const override { return m_fileName; } inline void setFileName(const char *fileName) override { m_fileName = fileName; } @@ -69,13 +67,12 @@ public: void printVersions(); protected: - Algorithm m_algorithm; - bool m_autoSave; - bool m_background; - bool m_dryRun; - bool m_syslog; - bool m_upgrade; - bool m_watch; + bool m_autoSave = true; + bool m_background = false; + bool m_dryRun = false; + bool m_syslog = false; + bool m_upgrade = false; + bool m_watch = true; Http m_http; Pools m_pools; String m_apiId; diff --git a/src/base/kernel/config/BaseTransform.cpp b/src/base/kernel/config/BaseTransform.cpp index 615342b9..8043c6e9 100644 --- a/src/base/kernel/config/BaseTransform.cpp +++ b/src/base/kernel/config/BaseTransform.cpp @@ -44,6 +44,7 @@ namespace xmrig { +static const char *kAlgo = "algo"; static const char *kApi = "api"; static const char *kHttp = "http"; static const char *kPools = "pools"; @@ -87,15 +88,38 @@ void xmrig::BaseTransform::load(JsonChain &chain, Process *process, IConfigTrans LOG_WARN("%s: unsupported non-option argument '%s'", argv[0], argv[optind]); } + transform.finalize(doc); chain.add(std::move(doc)); } +void xmrig::BaseTransform::finalize(rapidjson::Document &doc) +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + if (m_algorithm.isValid() && doc.HasMember(kPools)) { + auto &pools = doc[kPools]; + for (Value &pool : pools.GetArray()) { + if (!pool.HasMember(kAlgo)) { + pool.AddMember(StringRef(kAlgo), m_algorithm.toJSON(), allocator); + } + } + } +} + + void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const char *arg) { switch (key) { case IConfig::AlgorithmKey: /* --algo */ - return set(doc, "algo", arg); + if (!doc.HasMember(kPools)) { + m_algorithm = arg; + } + else { + return add(doc, kPools, kAlgo, arg); + } + break; case IConfig::UserpassKey: /* --userpass */ { @@ -128,19 +152,9 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch case IConfig::FingerprintKey: /* --tls-fingerprint */ return add(doc, kPools, "tls-fingerprint", arg); - case IConfig::VariantKey: /* --variant */ - return add(doc, kPools, "variant", arg); - case IConfig::LogFileKey: /* --log-file */ return set(doc, "log-file", arg); -# ifdef XMRIG_DEPRECATED - case IConfig::ApiAccessTokenKey: /* --api-access-token */ - fputs("option \"--api-access-token\" deprecated, use \"--http-access-token\" instead.\n", stderr); - fflush(stdout); - return set(doc, kHttp, "access-token", arg); -# endif - case IConfig::HttpAccessTokenKey: /* --http-access-token */ return set(doc, kHttp, "access-token", arg); @@ -162,9 +176,6 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch case IConfig::HttpPort: /* --http-port */ case IConfig::DonateLevelKey: /* --donate-level */ case IConfig::DaemonPollKey: /* --daemon-poll-interval */ -# ifdef XMRIG_DEPRECATED - case IConfig::ApiPort: /* --api-port */ -# endif return transformUint64(doc, key, static_cast(strtol(arg, nullptr, 10))); case IConfig::BackgroundKey: /* --background */ @@ -179,10 +190,6 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch case IConfig::ColorKey: /* --no-color */ case IConfig::HttpRestrictedKey: /* --http-no-restricted */ -# ifdef XMRIG_DEPRECATED - case IConfig::ApiRestrictedKey: /* --api-no-restricted */ - case IConfig::ApiIPv6Key: /* --api-ipv6 */ -# endif return transformBoolean(doc, key, false); default: @@ -217,16 +224,6 @@ void xmrig::BaseTransform::transformBoolean(rapidjson::Document &doc, int key, b case IConfig::ColorKey: /* --no-color */ return set(doc, "colors", enable); -# ifdef XMRIG_DEPRECATED - case IConfig::ApiIPv6Key: /* --api-ipv6 */ - break; - - case IConfig::ApiRestrictedKey: /* --api-no-restricted */ - fputs("option \"--api-no-restricted\" deprecated, use \"--http-no-restricted\" instead.\n", stderr); - fflush(stdout); - return set(doc, kHttp, "restricted", enable); -# endif - case IConfig::HttpRestrictedKey: /* --http-no-restricted */ return set(doc, kHttp, "restricted", enable); @@ -257,13 +254,6 @@ void xmrig::BaseTransform::transformUint64(rapidjson::Document &doc, int key, ui case IConfig::ProxyDonateKey: /* --donate-over-proxy */ return set(doc, "donate-over-proxy", arg); -# ifdef XMRIG_DEPRECATED - case IConfig::ApiPort: /* --api-port */ - fputs("option \"--api-port\" deprecated, use \"--http-port\" instead.\n", stderr); - fflush(stdout); - return set(doc, kHttp, "port", arg); -# endif - case IConfig::HttpPort: /* --http-port */ return set(doc, kHttp, "port", arg); diff --git a/src/base/kernel/config/BaseTransform.h b/src/base/kernel/config/BaseTransform.h index 3952e22b..02b28c12 100644 --- a/src/base/kernel/config/BaseTransform.h +++ b/src/base/kernel/config/BaseTransform.h @@ -49,6 +49,7 @@ public: static void load(JsonChain &chain, Process *process, IConfigTransform &transform); protected: + void finalize(rapidjson::Document &doc) override; void transform(rapidjson::Document &doc, int key, const char *arg) override; @@ -96,6 +97,9 @@ protected: } } +protected: + Algorithm m_algorithm; + private: void transformBoolean(rapidjson::Document &doc, int key, bool enable); diff --git a/src/base/kernel/interfaces/IClientListener.h b/src/base/kernel/interfaces/IClientListener.h index de4dd81d..3583be5a 100644 --- a/src/base/kernel/interfaces/IClientListener.h +++ b/src/base/kernel/interfaces/IClientListener.h @@ -35,6 +35,7 @@ namespace xmrig { +class Algorithm; class IClient; class Job; class SubmitResult; @@ -50,6 +51,7 @@ public: virtual void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) = 0; virtual void onLoginSuccess(IClient *client) = 0; virtual void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) = 0; + virtual void onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok) = 0; }; diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h index 3d0407e6..2697bf01 100644 --- a/src/base/kernel/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -65,7 +65,6 @@ public: UserAgentKey = 1008, UserKey = 'u', UserpassKey = 'O', - VariantKey = 1010, VerboseKey = 1100, TlsKey = 1013, FingerprintKey = 1014, @@ -73,13 +72,6 @@ public: DaemonKey = 1018, DaemonPollKey = 1019, -# ifdef XMRIG_DEPRECATED - ApiPort = 4000, - ApiAccessTokenKey = 4001, - ApiIPv6Key = 4003, - ApiRestrictedKey = 4004, -# endif - // xmrig common CPUPriorityKey = 1021, NicehashKey = 1006, @@ -90,8 +82,6 @@ public: CPUAffinityKey = 1020, DryRunKey = 5000, HugePagesKey = 1009, - MaxCPUUsageKey = 1004, - SafeKey = 1005, ThreadsKey = 't', // HardwareAESKey = 1011, AssemblyKey = 1015, @@ -144,7 +134,6 @@ public: virtual bool isWatch() const = 0; virtual bool read(const IJsonReader &reader, const char *fileName) = 0; virtual bool save() = 0; - virtual const Algorithm &algorithm() const = 0; virtual const String &fileName() const = 0; virtual void getJSON(rapidjson::Document &doc) const = 0; virtual void setFileName(const char *fileName) = 0; diff --git a/src/base/kernel/interfaces/IConfigTransform.h b/src/base/kernel/interfaces/IConfigTransform.h index f8854388..8afe8221 100644 --- a/src/base/kernel/interfaces/IConfigTransform.h +++ b/src/base/kernel/interfaces/IConfigTransform.h @@ -42,7 +42,8 @@ class IConfigTransform public: virtual ~IConfigTransform() = default; - virtual void transform(rapidjson::Document &doc, int key, const char *arg) = 0; + virtual void finalize(rapidjson::Document &doc) = 0; + virtual void transform(rapidjson::Document &doc, int key, const char *arg) = 0; }; diff --git a/src/base/kernel/interfaces/IStrategyListener.h b/src/base/kernel/interfaces/IStrategyListener.h index 2e63449b..8b88b506 100644 --- a/src/base/kernel/interfaces/IStrategyListener.h +++ b/src/base/kernel/interfaces/IStrategyListener.h @@ -26,12 +26,13 @@ #define XMRIG_ISTRATEGYLISTENER_H -#include +#include "rapidjson/fwd.h" namespace xmrig { +class Algorithm; class IClient; class IStrategy; class Job; @@ -45,8 +46,10 @@ public: virtual void onActive(IStrategy *strategy, IClient *client) = 0; virtual void onJob(IStrategy *strategy, IClient *client, const Job &job) = 0; + virtual void onLogin(IStrategy *strategy, IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) = 0; virtual void onPause(IStrategy *strategy) = 0; virtual void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) = 0; + virtual void onVerifyAlgorithm(IStrategy *strategy, const IClient *client, const Algorithm &algorithm, bool *ok) = 0; }; diff --git a/src/base/net/http/HttpClient.cpp b/src/base/net/http/HttpClient.cpp index 319bb4dd..113e2f13 100644 --- a/src/base/net/http/HttpClient.cpp +++ b/src/base/net/http/HttpClient.cpp @@ -29,10 +29,10 @@ #include "3rdparty/http-parser/http_parser.h" #include "base/io/log/Log.h" +#include "base/kernel/Platform.h" #include "base/net/dns/Dns.h" #include "base/net/http/HttpClient.h" #include "base/tools/Baton.h" -#include "common/Platform.h" namespace xmrig { diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index c07f2369..618e132c 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -162,7 +162,7 @@ int64_t xmrig::Client::submit(const JobResult &result) Buffer::toHex(reinterpret_cast(&result.nonce), 4, nonce); nonce[8] = '\0'; - Buffer::toHex(result.result, 32, data); + Buffer::toHex(result.result(), 32, data); data[64] = '\0'; # endif @@ -313,7 +313,7 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } - Job job(m_id, has(), m_pool.algorithm(), m_rpcId); + Job job(has(), m_pool.algorithm(), m_rpcId); if (!job.setId(params["job_id"].GetString())) { *code = 3; @@ -330,25 +330,15 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } - if (params.HasMember("algo")) { - job.setAlgorithm(params["algo"].GetString()); - } - - if (params.HasMember("variant")) { - const rapidjson::Value &variant = params["variant"]; - - if (variant.IsInt()) { - job.setVariant(variant.GetInt()); - } - else if (variant.IsString()){ - job.setVariant(variant.GetString()); - } + const char *algo = Json::getString(params, "algo"); + if (algo) { + job.setAlgorithm(algo); } job.setSeedHash(Json::getString(params, "seed_hash")); job.setHeight(Json::getUint64(params, "height")); - if (!verifyAlgorithm(job.algorithm())) { + if (!verifyAlgorithm(job.algorithm(), algo)) { *code = 6; close(); @@ -426,30 +416,24 @@ bool xmrig::Client::send(BIO *bio) } -bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm) const +bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm, const char *algo) const { -# ifdef XMRIG_PROXY_PROJECT - if (m_pool.algorithm().variant() == VARIANT_AUTO || m_id == -1) { - return true; - } -# endif + if (!algorithm.isValid()) { + if (!isQuiet()) { + LOG_ERR("[%s] Unknown/unsupported algorithm \"%s\" detected, reconnect", url(), algo); + } - if (m_pool.isCompatible(algorithm)) { - return true; - } - - if (isQuiet()) { return false; } - if (algorithm.isValid()) { - LOG_ERR("Incompatible algorithm \"%s\" detected, reconnect", algorithm.name()); - } - else { - LOG_ERR("Unknown/unsupported algorithm detected, reconnect"); + bool ok = true; + m_listener->onVerifyAlgorithm(this, algorithm, &ok); + + if (!ok && !isQuiet()) { + LOG_ERR("[%s] Incompatible/disabled algorithm \"%s\" detected, reconnect", url(), algorithm.shortName()); } - return false; + return ok; } @@ -586,19 +570,6 @@ void xmrig::Client::login() params.AddMember("rigid", m_pool.rigId().toJSON(), allocator); } -# ifdef XMRIG_PROXY_PROJECT - if (m_pool.algorithm().variant() != xmrig::VARIANT_AUTO) -# endif - { - Value algo(kArrayType); - - for (const auto &a : m_pool.algorithms()) { - algo.PushBack(StringRef(a.shortName()), allocator); - } - - params.AddMember("algo", algo, allocator); - } - m_listener->onLogin(this, doc, params); JsonRequest::create(doc, 1, "login", params); diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h index 841e0e0b..46030aba 100644 --- a/src/base/net/stratum/Client.h +++ b/src/base/net/stratum/Client.h @@ -92,7 +92,7 @@ private: bool parseJob(const rapidjson::Value ¶ms, int *code); bool parseLogin(const rapidjson::Value &result, int *code); bool send(BIO *bio); - bool verifyAlgorithm(const Algorithm &algorithm) const; + bool verifyAlgorithm(const Algorithm &algorithm, const char *algo) const; int resolve(const String &host); int64_t send(const rapidjson::Document &doc); int64_t send(size_t size); diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp index 70cc9151..0c141c7d 100644 --- a/src/base/net/stratum/DaemonClient.cpp +++ b/src/base/net/stratum/DaemonClient.cpp @@ -212,7 +212,7 @@ bool xmrig::DaemonClient::isOutdated(uint64_t height, const char *hash) const bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) { - Job job(m_id, false, m_pool.algorithm(), String()); + Job job(false, m_pool.algorithm(), String()); String blocktemplate = Json::getString(params, kBlocktemplateBlob); if (blocktemplate.isNull() || !job.setBlob(Json::getString(params, "blockhashing_blob"))) { diff --git a/src/base/net/stratum/Job.cpp b/src/base/net/stratum/Job.cpp index b4ebb2c0..a383bbf7 100644 --- a/src/base/net/stratum/Job.cpp +++ b/src/base/net/stratum/Job.cpp @@ -34,31 +34,16 @@ xmrig::Job::Job() : - m_autoVariant(false), - m_nicehash(false), - m_poolId(-2), - m_threadId(-1), - m_size(0), - m_diff(0), - m_height(0), - m_target(0), m_blob(), m_seedHash() { } -xmrig::Job::Job(int poolId, bool nicehash, const Algorithm &algorithm, const String &clientId) : +xmrig::Job::Job(bool nicehash, const Algorithm &algorithm, const String &clientId) : m_algorithm(algorithm), - m_autoVariant(algorithm.variant() == VARIANT_AUTO), m_nicehash(nicehash), - m_poolId(poolId), - m_threadId(-1), - m_size(0), m_clientId(clientId), - m_diff(0), - m_height(0), - m_target(0), m_blob(), m_seedHash() { @@ -100,10 +85,6 @@ bool xmrig::Job::setBlob(const char *blob) m_nicehash = true; } - if (m_autoVariant) { - m_algorithm.setVariant(variant()); - } - # ifdef XMRIG_PROXY_PROJECT memset(m_rawBlob, 0, sizeof(m_rawBlob)); memcpy(m_rawBlob, blob, m_size * 2); @@ -169,16 +150,6 @@ bool xmrig::Job::setTarget(const char *target) } -void xmrig::Job::setAlgorithm(const char *algo) -{ - m_algorithm.parseAlgorithm(algo); - - if (m_algorithm.variant() == xmrig::VARIANT_AUTO) { - m_algorithm.setVariant(variant()); - } -} - - void xmrig::Job::setDiff(uint64_t diff) { m_diff = diff; @@ -189,23 +160,3 @@ void xmrig::Job::setDiff(uint64_t diff) m_rawTarget[16] = '\0'; # endif } - - -xmrig::Variant xmrig::Job::variant() const -{ - switch (m_algorithm.algo()) { - case CRYPTONIGHT: - return (m_blob[0] >= 10) ? VARIANT_4 : ((m_blob[0] >= 8) ? VARIANT_2 : VARIANT_1); - - case CRYPTONIGHT_LITE: - return VARIANT_1; - - case CRYPTONIGHT_HEAVY: - return VARIANT_0; - - default: - break; - } - - return m_algorithm.variant(); -} diff --git a/src/base/net/stratum/Job.h b/src/base/net/stratum/Job.h index bc0ec2eb..06d1be79 100644 --- a/src/base/net/stratum/Job.h +++ b/src/base/net/stratum/Job.h @@ -47,14 +47,13 @@ public: static constexpr const size_t kMaxBlobSize = 128; Job(); - Job(int poolId, bool nicehash, const Algorithm &algorithm, const String &clientId); + Job(bool nicehash, const Algorithm &algorithm, const String &clientId); ~Job(); bool isEqual(const Job &other) const; bool setBlob(const char *blob); bool setSeedHash(const char *hash); bool setTarget(const char *target); - void setAlgorithm(const char *algo); void setDiff(uint64_t diff); inline bool isNicehash() const { return m_nicehash; } @@ -66,21 +65,18 @@ public: inline const uint32_t *nonce() const { return reinterpret_cast(m_blob + 39); } inline const uint8_t *blob() const { return m_blob; } inline const uint8_t *seedHash() const { return m_seedHash; } - inline int poolId() const { return m_poolId; } - inline int threadId() const { return m_threadId; } inline size_t size() const { return m_size; } inline uint32_t *nonce() { return reinterpret_cast(m_blob + 39); } inline uint64_t diff() const { return m_diff; } inline uint64_t height() const { return m_height; } inline uint64_t target() const { return m_target; } inline uint8_t fixedByte() const { return *(m_blob + 42); } + inline uint8_t index() const { return m_index; } inline void reset() { m_size = 0; m_diff = 0; } + inline void setAlgorithm(const char *algo) { m_algorithm = algo; } inline void setClientId(const String &id) { m_clientId = id; } inline void setHeight(uint64_t height) { m_height = height; } - inline void setPoolId(int poolId) { m_poolId = poolId; } - inline void setThreadId(int threadId) { m_threadId = threadId; } - inline void setVariant(const char *variant) { m_algorithm.parseVariant(variant); } - inline void setVariant(int variant) { m_algorithm.parseVariant(variant); } + inline void setIndex(uint8_t index) { m_index = index; } # ifdef XMRIG_PROXY_PROJECT inline char *rawBlob() { return m_rawBlob; } @@ -96,20 +92,16 @@ public: inline bool operator!=(const Job &other) const { return !isEqual(other); } private: - Variant variant() const; - Algorithm m_algorithm; - bool m_autoVariant; - bool m_nicehash; - int m_poolId; - int m_threadId; - size_t m_size; + bool m_nicehash = false; + size_t m_size = 0; String m_clientId; String m_id; - uint64_t m_diff; - uint64_t m_height; - uint64_t m_target; + uint64_t m_diff = 0; + uint64_t m_height = 0; + uint64_t m_target = 0; uint8_t m_blob[kMaxBlobSize]; + uint8_t m_index = 0; uint8_t m_seedHash[32]; # ifdef XMRIG_PROXY_PROJECT diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index 7ad4c73a..4d15ea47 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -47,6 +47,7 @@ namespace xmrig { +static const char *kAlgo = "algo"; static const char *kDaemon = "daemon"; static const char *kDaemonPollInterval = "daemon-poll-interval"; static const char *kEnabled = "enabled"; @@ -58,7 +59,6 @@ static const char *kRigId = "rig-id"; static const char *kTls = "tls"; static const char *kUrl = "url"; static const char *kUser = "user"; -static const char *kVariant = "variant"; const String Pool::kDefaultPassword = "x"; const String Pool::kDefaultUser = "x"; @@ -119,6 +119,7 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : m_rigId = Json::getString(object, kRigId); m_fingerprint = Json::getString(object, kFingerprint); m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval); + m_algorithm = Json::getString(object, kAlgo); m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true)); m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash)); @@ -132,15 +133,6 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : else if (keepalive.IsBool()) { setKeepAlive(keepalive.GetBool()); } - - const rapidjson::Value &variant = Json::getValue(object, kVariant); - if (variant.IsString()) { - algorithm().parseVariant(variant.GetString()); - } - else if (variant.IsInt()) { - algorithm().parseVariant(variant.GetInt()); - } - } @@ -166,28 +158,6 @@ xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char } -bool xmrig::Pool::isCompatible(const Algorithm &algorithm) const -{ - if (m_algorithms.empty()) { - return true; - } - - for (const auto &a : m_algorithms) { - if (algorithm == a) { - return true; - } - } - -# ifdef XMRIG_PROXY_PROJECT - if (m_algorithm.algo() == xmrig::CRYPTONIGHT && algorithm.algo() == xmrig::CRYPTONIGHT) { - return m_algorithm.variant() == xmrig::VARIANT_RWZ || m_algorithm.variant() == xmrig::VARIANT_ZLS; - } -# endif - - return false; -} - - bool xmrig::Pool::isEnabled() const { # ifndef XMRIG_FEATURE_TLS @@ -202,7 +172,11 @@ bool xmrig::Pool::isEnabled() const } # endif - return m_flags.test(FLAG_ENABLED) && isValid() && algorithm().isValid(); + if (isDaemon() && !algorithm().isValid()) { + return false; + } + + return m_flags.test(FLAG_ENABLED) && isValid(); } @@ -218,7 +192,8 @@ bool xmrig::Pool::isEqual(const Pool &other) const && m_rigId == other.m_rigId && m_url == other.m_url && m_user == other.m_user - && m_pollInterval == other.m_pollInterval); + && m_pollInterval == other.m_pollInterval + ); } @@ -289,71 +264,39 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const Value obj(kObjectType); + obj.AddMember(StringRef(kAlgo), m_algorithm.toJSON(), allocator); obj.AddMember(StringRef(kUrl), m_url.toJSON(), allocator); obj.AddMember(StringRef(kUser), m_user.toJSON(), allocator); - obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator); - obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator); -# ifndef XMRIG_PROXY_PROJECT - obj.AddMember(StringRef(kNicehash), isNicehash(), allocator); -# endif + if (!isDaemon()) { + obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator); + obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator); - if (m_keepAlive == 0 || m_keepAlive == kKeepAliveTimeout) { - obj.AddMember(StringRef(kKeepalive), m_keepAlive > 0, allocator); - } - else { - obj.AddMember(StringRef(kKeepalive), m_keepAlive, allocator); - } +# ifndef XMRIG_PROXY_PROJECT + obj.AddMember(StringRef(kNicehash), isNicehash(), allocator); +# endif - switch (m_algorithm.variant()) { - case VARIANT_AUTO: - case VARIANT_0: - case VARIANT_1: - obj.AddMember(StringRef(kVariant), m_algorithm.variant(), allocator); - break; - - case VARIANT_2: - obj.AddMember(StringRef(kVariant), 2, allocator); - break; - - default: - obj.AddMember(StringRef(kVariant), StringRef(m_algorithm.variantName()), allocator); - break; + if (m_keepAlive == 0 || m_keepAlive == kKeepAliveTimeout) { + obj.AddMember(StringRef(kKeepalive), m_keepAlive > 0, allocator); + } + else { + obj.AddMember(StringRef(kKeepalive), m_keepAlive, allocator); + } } obj.AddMember(StringRef(kEnabled), m_flags.test(FLAG_ENABLED), allocator); obj.AddMember(StringRef(kTls), isTLS(), allocator); obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator); obj.AddMember(StringRef(kDaemon), m_flags.test(FLAG_DAEMON), allocator); - obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator); + + if (isDaemon()) { + obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator); + } return obj; } -void xmrig::Pool::adjust(const Algorithm &algorithm) -{ - if (!isValid()) { - return; - } - - if (!m_algorithm.isValid()) { - m_algorithm.setAlgo(algorithm.algo()); - adjustVariant(algorithm.variant()); - } - - rebuild(); -} - - -void xmrig::Pool::setAlgo(const xmrig::Algorithm &algorithm) -{ - m_algorithm = algorithm; - - rebuild(); -} - - #ifdef APP_DEBUG void xmrig::Pool::print() const { @@ -391,134 +334,3 @@ bool xmrig::Pool::parseIPv6(const char *addr) return true; } - - -void xmrig::Pool::addVariant(xmrig::Variant variant) -{ - const xmrig::Algorithm algorithm(m_algorithm.algo(), variant); - if (!algorithm.isValid() || m_algorithm == algorithm) { - return; - } - - m_algorithms.push_back(algorithm); -} - - -void xmrig::Pool::adjustVariant(const xmrig::Variant variantHint) -{ -# ifndef XMRIG_PROXY_PROJECT - using namespace xmrig; - - if (m_host.contains(".nicehash.com")) { - m_flags.set(FLAG_NICEHASH, true); - m_keepAlive = false; - bool valid = true; - - switch (m_port) { - case 3355: - case 33355: - valid = m_algorithm.algo() == CRYPTONIGHT && m_host.contains("cryptonight."); - m_algorithm.setVariant(VARIANT_0); - break; - - case 3363: - case 33363: - valid = m_algorithm.algo() == CRYPTONIGHT && m_host.contains("cryptonightv7."); - m_algorithm.setVariant(VARIANT_1); - break; - - case 3364: - valid = m_algorithm.algo() == CRYPTONIGHT_HEAVY && m_host.contains("cryptonightheavy."); - m_algorithm.setVariant(VARIANT_0); - break; - - case 3367: - case 33367: - valid = m_algorithm.algo() == CRYPTONIGHT && m_host.contains("cryptonightv8."); - m_algorithm.setVariant(VARIANT_2); - break; - - default: - break; - } - - if (!valid) { - m_algorithm.setAlgo(INVALID_ALGO); - } - - m_flags.set(FLAG_TLS, m_port > 33000); - return; - } - - if (m_host.contains(".minergate.com")) { - m_keepAlive = false; - bool valid = true; - m_algorithm.setVariant(VARIANT_1); - - if (m_host.contains("xmr.pool.")) { - valid = m_algorithm.algo() == CRYPTONIGHT; - m_algorithm.setVariant(m_port == 45700 ? VARIANT_AUTO : VARIANT_0); - } - else if (m_host.contains("aeon.pool.") && m_port == 45690) { - valid = m_algorithm.algo() == CRYPTONIGHT_LITE; - m_algorithm.setVariant(VARIANT_1); - } - - if (!valid) { - m_algorithm.setAlgo(INVALID_ALGO); - } - - return; - } - - if (variantHint != VARIANT_AUTO) { - m_algorithm.setVariant(variantHint); - return; - } - - if (m_algorithm.variant() != VARIANT_AUTO) { - return; - } - - if (m_algorithm.algo() == CRYPTONIGHT_HEAVY) { - m_algorithm.setVariant(VARIANT_0); - } - else if (m_algorithm.algo() == CRYPTONIGHT_LITE) { - m_algorithm.setVariant(VARIANT_1); - } -# endif -} - - -void xmrig::Pool::rebuild() -{ - m_algorithms.clear(); - - if (!m_algorithm.isValid()) { - return; - } - - m_algorithms.push_back(m_algorithm); - -# ifndef XMRIG_PROXY_PROJECT - addVariant(VARIANT_4); - addVariant(VARIANT_WOW); - addVariant(VARIANT_2); - addVariant(VARIANT_1); - addVariant(VARIANT_0); - addVariant(VARIANT_HALF); - addVariant(VARIANT_XTL); - addVariant(VARIANT_TUBE); - addVariant(VARIANT_MSR); - addVariant(VARIANT_XHV); - addVariant(VARIANT_XAO); - addVariant(VARIANT_RTO); - addVariant(VARIANT_GPU); - addVariant(VARIANT_RWZ); - addVariant(VARIANT_ZLS); - addVariant(VARIANT_DOUBLE); - addVariant(VARIANT_RX_WOW); - addVariant(VARIANT_RX_LOKI); - addVariant(VARIANT_AUTO); -# endif -} diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h index 5348271a..36c3ed1b 100644 --- a/src/base/net/stratum/Pool.h +++ b/src/base/net/stratum/Pool.h @@ -69,13 +69,11 @@ public: bool tls = false ); - inline Algorithm &algorithm() { return m_algorithm; } inline bool isDaemon() const { return m_flags.test(FLAG_DAEMON); } inline bool isNicehash() const { return m_flags.test(FLAG_NICEHASH); } inline bool isTLS() const { return m_flags.test(FLAG_TLS); } inline bool isValid() const { return !m_host.isNull() && m_port > 0; } inline const Algorithm &algorithm() const { return m_algorithm; } - inline const Algorithms &algorithms() const { return m_algorithms; } inline const String &fingerprint() const { return m_fingerprint; } inline const String &host() const { return m_host; } inline const String &password() const { return !m_password.isNull() ? m_password : kDefaultPassword; } @@ -85,6 +83,7 @@ public: inline int keepAlive() const { return m_keepAlive; } inline uint16_t port() const { return m_port; } inline uint64_t pollInterval() const { return m_pollInterval; } + inline void setAlgo(const Algorithm &algorithm) { m_algorithm = algorithm; } inline void setPassword(const String &password) { m_password = password; } inline void setRigId(const String &rigId) { m_rigId = rigId; } inline void setUser(const String &user) { m_user = user; } @@ -92,13 +91,10 @@ public: inline bool operator!=(const Pool &other) const { return !isEqual(other); } inline bool operator==(const Pool &other) const { return isEqual(other); } - bool isCompatible(const Algorithm &algorithm) const; bool isEnabled() const; bool isEqual(const Pool &other) const; bool parse(const char *url); rapidjson::Value toJSON(rapidjson::Document &doc) const; - void adjust(const Algorithm &algorithm); - void setAlgo(const Algorithm &algorithm); # ifdef APP_DEBUG void print() const; @@ -109,12 +105,8 @@ private: inline void setKeepAlive(int keepAlive) { m_keepAlive = keepAlive >= 0 ? keepAlive : 0; } bool parseIPv6(const char *addr); - void addVariant(Variant variant); - void adjustVariant(const Variant variantHint); - void rebuild(); Algorithm m_algorithm; - Algorithms m_algorithms; int m_keepAlive; std::bitset m_flags; String m_fingerprint; diff --git a/src/base/net/stratum/Pools.cpp b/src/base/net/stratum/Pools.cpp index 638ba5ea..4641ecd4 100644 --- a/src/base/net/stratum/Pools.cpp +++ b/src/base/net/stratum/Pools.cpp @@ -24,6 +24,7 @@ #include "base/io/log/Log.h" +#include "base/kernel/interfaces/IJsonReader.h" #include "base/net/stratum/Pools.h" #include "base/net/stratum/strategies/FailoverStrategy.h" #include "base/net/stratum/strategies/SinglePoolStrategy.h" @@ -103,18 +104,11 @@ size_t xmrig::Pools::active() const } -void xmrig::Pools::adjust(const Algorithm &algorithm) -{ - for (Pool &pool : m_data) { - pool.adjust(algorithm); - } -} - - -void xmrig::Pools::load(const rapidjson::Value &pools) +void xmrig::Pools::load(const IJsonReader &reader) { m_data.clear(); + const rapidjson::Value &pools = reader.getArray("pools"); if (!pools.IsArray()) { return; } @@ -129,6 +123,11 @@ void xmrig::Pools::load(const rapidjson::Value &pools) m_data.push_back(std::move(pool)); } } + + setDonateLevel(reader.getInt("donate-level", kDefaultDonateLevel)); + setProxyDonate(reader.getInt("donate-over-proxy", PROXY_DONATE_AUTO)); + setRetries(reader.getInt("retries")); + setRetryPause(reader.getInt("retry-pause")); } @@ -136,11 +135,11 @@ void xmrig::Pools::print() const { size_t i = 1; for (const Pool &pool : m_data) { - Log::print(GREEN_BOLD(" * ") WHITE_BOLD("POOL #%-7zu") CSI "1;%dm%s" CLEAR " variant " WHITE_BOLD("%s"), + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("POOL #%-7zu") CSI "1;%dm%s" CLEAR " algo " WHITE_BOLD("%s"), i, (pool.isEnabled() ? (pool.isTLS() ? 32 : 36) : 31), pool.url().data(), - pool.algorithm().variantName() + pool.algorithm().isValid() ? pool.algorithm().shortName() : "auto" ); i++; diff --git a/src/base/net/stratum/Pools.h b/src/base/net/stratum/Pools.h index 6a63f166..70e17225 100644 --- a/src/base/net/stratum/Pools.h +++ b/src/base/net/stratum/Pools.h @@ -35,6 +35,7 @@ namespace xmrig { +class IJsonReader; class IStrategy; class IStrategyListener; @@ -63,15 +64,15 @@ public: IStrategy *createStrategy(IStrategyListener *listener) const; rapidjson::Value toJSON(rapidjson::Document &doc) const; size_t active() const; - void adjust(const Algorithm &algorithm); - void load(const rapidjson::Value &pools); + void load(const IJsonReader &reader); void print() const; + +private: void setDonateLevel(int level); void setProxyDonate(int value); void setRetries(int retries); void setRetryPause(int retryPause); -private: int m_donateLevel; int m_retries; int m_retryPause; diff --git a/src/base/net/stratum/strategies/FailoverStrategy.cpp b/src/base/net/stratum/strategies/FailoverStrategy.cpp index d5247229..48be2ba3 100644 --- a/src/base/net/stratum/strategies/FailoverStrategy.cpp +++ b/src/base/net/stratum/strategies/FailoverStrategy.cpp @@ -24,9 +24,9 @@ #include "base/kernel/interfaces/IStrategyListener.h" +#include "base/kernel/Platform.h" #include "base/net/stratum/Client.h" #include "base/net/stratum/strategies/FailoverStrategy.h" -#include "common/Platform.h" #ifdef XMRIG_FEATURE_HTTP @@ -113,7 +113,7 @@ void xmrig::FailoverStrategy::resume() } -void xmrig::FailoverStrategy::setAlgo(const xmrig::Algorithm &algo) +void xmrig::FailoverStrategy::setAlgo(const Algorithm &algo) { for (IClient *client : m_pools) { client->setAlgo(algo); @@ -163,6 +163,12 @@ void xmrig::FailoverStrategy::onClose(IClient *client, int failures) } +void xmrig::FailoverStrategy::onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) +{ + m_listener->onLogin(this, client, doc, params); +} + + void xmrig::FailoverStrategy::onJobReceived(IClient *client, const Job &job, const rapidjson::Value &) { if (m_active == client->id()) { @@ -196,3 +202,9 @@ void xmrig::FailoverStrategy::onResultAccepted(IClient *client, const SubmitResu { m_listener->onResultAccepted(this, client, result, error); } + + +void xmrig::FailoverStrategy::onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok) +{ + m_listener->onVerifyAlgorithm(this, client, algorithm, ok); +} diff --git a/src/base/net/stratum/strategies/FailoverStrategy.h b/src/base/net/stratum/strategies/FailoverStrategy.h index b1fe8bac..283d4916 100644 --- a/src/base/net/stratum/strategies/FailoverStrategy.h +++ b/src/base/net/stratum/strategies/FailoverStrategy.h @@ -51,9 +51,8 @@ public: void add(const Pool &pool); protected: - inline bool isActive() const override { return m_active >= 0; } - inline IClient *client() const override { return isActive() ? active() : m_pools[m_index]; } - inline void onLogin(IClient *, rapidjson::Document &, rapidjson::Value &) override {} + inline bool isActive() const override { return m_active >= 0; } + inline IClient *client() const override { return isActive() ? active() : m_pools[m_index]; } int64_t submit(const JobResult &result) override; void connect() override; @@ -64,8 +63,10 @@ protected: void onClose(IClient *client, int failures) override; void onJobReceived(IClient *client, const Job &job, const rapidjson::Value ¶ms) override; + void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; void onLoginSuccess(IClient *client) override; void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override; + void onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok) override; private: inline IClient *active() const { return m_pools[static_cast(m_active)]; } diff --git a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp index f432514e..c923e1c2 100644 --- a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp +++ b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp @@ -24,9 +24,9 @@ #include "base/kernel/interfaces/IStrategyListener.h" +#include "base/kernel/Platform.h" #include "base/net/stratum/Client.h" #include "base/net/stratum/strategies/SinglePoolStrategy.h" -#include "common/Platform.h" #ifdef XMRIG_FEATURE_HTTP @@ -84,7 +84,7 @@ void xmrig::SinglePoolStrategy::resume() } -void xmrig::SinglePoolStrategy::setAlgo(const xmrig::Algorithm &algo) +void xmrig::SinglePoolStrategy::setAlgo(const Algorithm &algo) { m_client->setAlgo(algo); } @@ -119,6 +119,12 @@ void xmrig::SinglePoolStrategy::onJobReceived(IClient *client, const Job &job, c } +void xmrig::SinglePoolStrategy::onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) +{ + m_listener->onLogin(this, client, doc, params); +} + + void xmrig::SinglePoolStrategy::onLoginSuccess(IClient *client) { m_active = true; @@ -130,3 +136,9 @@ void xmrig::SinglePoolStrategy::onResultAccepted(IClient *client, const SubmitRe { m_listener->onResultAccepted(this, client, result, error); } + + +void xmrig::SinglePoolStrategy::onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok) +{ + m_listener->onVerifyAlgorithm(this, client, algorithm, ok); +} diff --git a/src/base/net/stratum/strategies/SinglePoolStrategy.h b/src/base/net/stratum/strategies/SinglePoolStrategy.h index af0bd7d6..ea808193 100644 --- a/src/base/net/stratum/strategies/SinglePoolStrategy.h +++ b/src/base/net/stratum/strategies/SinglePoolStrategy.h @@ -45,9 +45,8 @@ public: ~SinglePoolStrategy() override; protected: - inline bool isActive() const override { return m_active; } - inline IClient *client() const override { return m_client; } - inline void onLogin(IClient *, rapidjson::Document &, rapidjson::Value &) override {} + inline bool isActive() const override { return m_active; } + inline IClient *client() const override { return m_client; } int64_t submit(const JobResult &result) override; void connect() override; @@ -58,8 +57,10 @@ protected: void onClose(IClient *client, int failures) override; void onJobReceived(IClient *client, const Job &job, const rapidjson::Value ¶ms) override; + void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; void onLoginSuccess(IClient *client) override; void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override; + void onVerifyAlgorithm(const IClient *client, const Algorithm &algorithm, bool *ok) override; private: bool m_active; diff --git a/src/base/tools/Chrono.h b/src/base/tools/Chrono.h index d3c14602..e464f361 100644 --- a/src/base/tools/Chrono.h +++ b/src/base/tools/Chrono.h @@ -35,6 +35,14 @@ namespace xmrig { class Chrono { public: + static inline uint64_t highResolutionMSecs() + { + using namespace std::chrono; + + return static_cast(time_point_cast(high_resolution_clock::now()).time_since_epoch().count()); + } + + static inline uint64_t steadyMSecs() { using namespace std::chrono; diff --git a/src/common/cpu/Cpu.cpp b/src/common/cpu/Cpu.cpp deleted file mode 100644 index b1bb28ac..00000000 --- a/src/common/cpu/Cpu.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * - * - * 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 . - */ - - -#include - - -#include "common/cpu/BasicCpuInfo.h" -#include "common/cpu/Cpu.h" - - -static xmrig::ICpuInfo *cpuInfo = nullptr; - - -xmrig::ICpuInfo *xmrig::Cpu::info() -{ - assert(cpuInfo != nullptr); - - return cpuInfo; -} - - -void xmrig::Cpu::init() -{ - assert(cpuInfo == nullptr); - - cpuInfo = new BasicCpuInfo(); -} - - -void xmrig::Cpu::release() -{ - assert(cpuInfo != nullptr); - - delete cpuInfo; - cpuInfo = nullptr; -} diff --git a/src/common/xmrig.h b/src/common/xmrig.h deleted file mode 100644 index cbfe330e..00000000 --- a/src/common/xmrig.h +++ /dev/null @@ -1,124 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * 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 . - */ - -#ifndef XMRIG_XMRIG_H -#define XMRIG_XMRIG_H - - -namespace xmrig -{ - - -enum Algo { - INVALID_ALGO = -1, - CRYPTONIGHT, /* CryptoNight (2 MB) */ - CRYPTONIGHT_LITE, /* CryptoNight (1 MB) */ - CRYPTONIGHT_HEAVY, /* CryptoNight (4 MB) */ - CRYPTONIGHT_PICO, /* CryptoNight (256 KB) */ - RANDOM_X, /* RandomX */ - ALGO_MAX -}; - - -//--av=1 For CPUs with hardware AES. -//--av=2 Lower power mode (double hash) of 1. -//--av=3 Software AES implementation. -//--av=4 Lower power mode (double hash) of 3. -enum AlgoVariant { - AV_AUTO, // --av=0 Automatic mode. - AV_SINGLE, // --av=1 Single hash mode - AV_DOUBLE, // --av=2 Double hash mode - AV_SINGLE_SOFT, // --av=3 Single hash mode (Software AES) - AV_DOUBLE_SOFT, // --av=4 Double hash mode (Software AES) - AV_TRIPLE, // --av=5 Triple hash mode - AV_QUAD, // --av=6 Quard hash mode - AV_PENTA, // --av=7 Penta hash mode - AV_TRIPLE_SOFT, // --av=8 Triple hash mode (Software AES) - AV_QUAD_SOFT, // --av=9 Quard hash mode (Software AES) - AV_PENTA_SOFT, // --av=10 Penta hash mode (Software AES) - AV_MAX -}; - - -enum Variant { - VARIANT_AUTO = -1, // Autodetect - VARIANT_0 = 0, // Original CryptoNight or CryptoNight-Heavy - VARIANT_1 = 1, // CryptoNight variant 1 also known as Monero7 and CryptoNightV7 - VARIANT_TUBE = 2, // Modified CryptoNight-Heavy (TUBE only) - VARIANT_XTL = 3, // Modified CryptoNight variant 1 (Stellite only) - VARIANT_MSR = 4, // Modified CryptoNight variant 1 (Masari only) - VARIANT_XHV = 5, // Modified CryptoNight-Heavy (Haven Protocol only) - VARIANT_XAO = 6, // Modified CryptoNight variant 0 (Alloy only) - VARIANT_RTO = 7, // Modified CryptoNight variant 1 (Arto only) - VARIANT_2 = 8, // CryptoNight variant 2 - VARIANT_HALF = 9, // CryptoNight variant 2 with half iterations (Masari/Stellite) - VARIANT_TRTL = 10, // CryptoNight Turtle (TRTL) - VARIANT_GPU = 11, // CryptoNight-GPU (Ryo) - VARIANT_WOW = 12, // CryptoNightR (Wownero) - VARIANT_4 = 13, // CryptoNightR (Monero's variant 4) - VARIANT_RWZ = 14, // CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation (Graft) - VARIANT_ZLS = 15, // CryptoNight variant 2 with 3/4 iterations (Zelerius) - VARIANT_DOUBLE = 16, // CryptoNight variant 2 with double iterations (X-CASH) - VARIANT_RX_WOW = 17, // RandomX (Wownero) - VARIANT_RX_LOKI = 18, // RandomX (Loki) - VARIANT_MAX -}; - - -enum AlgoVerify { - VERIFY_HW_AES = 1, - VERIFY_SOFT_AES = 2 -}; - - -enum AesMode { - AES_AUTO, - AES_HW, - AES_SOFT -}; - - -enum OclVendor { - OCL_VENDOR_UNKNOWN = -2, - OCL_VENDOR_MANUAL = -1, - OCL_VENDOR_AMD = 0, - OCL_VENDOR_NVIDIA = 1, - OCL_VENDOR_INTEL = 2 -}; - - -enum Assembly { - ASM_NONE, - ASM_AUTO, - ASM_INTEL, - ASM_RYZEN, - ASM_BULLDOZER, - ASM_MAX -}; - - -} /* namespace xmrig */ - - -#endif /* XMRIG_XMRIG_H */ diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index 493b3e11..54c9ee34 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -26,15 +26,14 @@ #include -#include "common/cpu/Cpu.h" -#include "common/Platform.h" +#include "backend/cpu/Cpu.h" #include "core/Controller.h" +#include "core/Miner.h" #include "net/Network.h" xmrig::Controller::Controller(Process *process) : - Base(process), - m_network(nullptr) + Base(process) { } @@ -69,6 +68,8 @@ void xmrig::Controller::start() { Base::start(); + m_miner = new Miner(this); + network()->connect(); } @@ -79,6 +80,19 @@ void xmrig::Controller::stop() delete m_network; m_network = nullptr; + + m_miner->stop(); + + delete m_miner; + m_miner = nullptr; +} + + +xmrig::Miner *xmrig::Controller::miner() const +{ + assert(m_miner != nullptr); + + return m_miner; } diff --git a/src/core/Controller.h b/src/core/Controller.h index 02f9ca92..da7ba368 100644 --- a/src/core/Controller.h +++ b/src/core/Controller.h @@ -32,6 +32,8 @@ namespace xmrig { +class Job; +class Miner; class Network; @@ -46,10 +48,12 @@ public: void start() override; void stop() override; + Miner *miner() const; Network *network() const; private: - Network *m_network; + Miner *m_miner = nullptr; + Network *m_network = nullptr; }; diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp new file mode 100644 index 00000000..df83c5e9 --- /dev/null +++ b/src/core/Miner.cpp @@ -0,0 +1,442 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include +#include + + +#include "backend/common/Hashrate.h" +#include "backend/cpu/Cpu.h" +#include "backend/cpu/CpuBackend.h" +#include "base/io/log/Log.h" +#include "base/kernel/Platform.h" +#include "base/net/stratum/Job.h" +#include "base/tools/Timer.h" +#include "core/config/Config.h" +#include "core/Controller.h" +#include "core/Miner.h" +#include "crypto/common/Nonce.h" +#include "rapidjson/document.h" +#include "version.h" + + +#ifdef XMRIG_FEATURE_API +# include "api/Api.h" +# include "api/interfaces/IApiRequest.h" +#endif + + +namespace xmrig { + + +class MinerPrivate +{ +public: + inline MinerPrivate(Controller *controller) : controller(controller) + { + uv_rwlock_init(&rwlock); + } + + + inline ~MinerPrivate() + { + uv_rwlock_destroy(&rwlock); + + delete timer; + + for (IBackend *backend : backends) { + delete backend; + } + } + + + bool isEnabled(const Algorithm &algorithm) const + { + for (IBackend *backend : backends) { + if (backend->isEnabled(algorithm)) { + return true; + } + } + + return false; + } + + + inline void rebuild() + { + algorithms.clear(); + + for (int i = 0; i < Algorithm::MAX; ++i) { + const Algorithm algo(static_cast(i)); + + if (isEnabled(algo)) { + algorithms.push_back(algo); + } + } + } + + + inline void handleJobChange(bool reset) + { + active = true; + + for (IBackend *backend : backends) { + backend->setJob(job); + } + + if (reset) { + Nonce::reset(job.index()); + } + else { + Nonce::touch(); + } + + if (enabled) { + Nonce::pause(false);; + } + + if (ticks == 0) { + ticks++; + timer->start(500, 500); + } + } + + +# ifdef XMRIG_FEATURE_API + void getMiner(rapidjson::Value &reply, rapidjson::Document &doc, int version) const + { + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Value cpu(kObjectType); + cpu.AddMember("brand", StringRef(Cpu::info()->brand()), allocator); + cpu.AddMember("aes", Cpu::info()->hasAES(), allocator); + cpu.AddMember("x64", Cpu::info()->isX64(), allocator); + cpu.AddMember("sockets", static_cast(Cpu::info()->sockets()), allocator); + + reply.AddMember("version", APP_VERSION, allocator); + reply.AddMember("kind", APP_KIND, allocator); + reply.AddMember("ua", StringRef(Platform::userAgent()), allocator); + reply.AddMember("cpu", cpu, allocator); + + if (version == 1) { + reply.AddMember("hugepages", false, allocator); + } + + reply.AddMember("donate_level", controller->config()->pools().donateLevel(), allocator); + + Value algo(kArrayType); + + for (const Algorithm &a : algorithms) { + algo.PushBack(StringRef(a.shortName()), allocator); + } + + reply.AddMember("algorithms", algo, allocator); + } + + + void getHashrate(rapidjson::Value &reply, rapidjson::Document &doc, int version) const + { + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Value hashrate(kObjectType); + Value total(kArrayType); + Value threads(kArrayType); + + double t[3] = { 0.0 }; + + for (IBackend *backend : backends) { + const Hashrate *hr = backend->hashrate(); + if (!hr) { + continue; + } + + t[0] += hr->calc(Hashrate::ShortInterval); + t[1] += hr->calc(Hashrate::MediumInterval); + t[2] += hr->calc(Hashrate::LargeInterval); + + if (version > 1) { + continue; + } + + for (size_t i = 0; i < hr->threads(); i++) { + Value thread(kArrayType); + thread.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); + thread.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); + thread.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); + + threads.PushBack(thread, allocator); + } + } + + total.PushBack(Hashrate::normalize(t[0]), allocator); + total.PushBack(Hashrate::normalize(t[1]), allocator); + total.PushBack(Hashrate::normalize(t[2]), allocator); + + hashrate.AddMember("total", total, allocator); + hashrate.AddMember("highest", Hashrate::normalize(maxHashrate), allocator); + + if (version == 1) { + hashrate.AddMember("threads", threads, allocator); + } + + reply.AddMember("hashrate", hashrate, allocator); + } + + + void getBackends(rapidjson::Value &reply, rapidjson::Document &doc) const + { + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + reply.SetArray(); + + for (IBackend *backend : backends) { + reply.PushBack(backend->toJSON(doc), allocator); + } + } +# endif + + + Algorithms algorithms; + bool active = false; + bool enabled = true; + Controller *controller; + double maxHashrate = 0.0; + Job job; + std::vector backends; + String userJobId; + Timer *timer = nullptr; + uint64_t ticks = 0; + uv_rwlock_t rwlock; +}; + + +} // namespace xmrig + + + +xmrig::Miner::Miner(Controller *controller) + : d_ptr(new MinerPrivate(controller)) +{ + controller->addListener(this); + +# ifdef XMRIG_FEATURE_API + controller->api()->addListener(this); +# endif + + d_ptr->timer = new Timer(this); + + d_ptr->backends.push_back(new CpuBackend(controller)); + + d_ptr->rebuild(); +} + + +xmrig::Miner::~Miner() +{ + delete d_ptr; +} + + +bool xmrig::Miner::isEnabled() const +{ + return d_ptr->enabled; +} + + +bool xmrig::Miner::isEnabled(const Algorithm &algorithm) const +{ + return std::find(d_ptr->algorithms.begin(), d_ptr->algorithms.end(), algorithm) != d_ptr->algorithms.end(); +} + + +const xmrig::Algorithms &xmrig::Miner::algorithms() const +{ + return d_ptr->algorithms; +} + + +const std::vector &xmrig::Miner::backends() const +{ + return d_ptr->backends; +} + + +xmrig::Job xmrig::Miner::job() const +{ + uv_rwlock_rdlock(&d_ptr->rwlock); + Job job = d_ptr->job; + uv_rwlock_rdunlock(&d_ptr->rwlock); + + return job; +} + + +void xmrig::Miner::pause() +{ + d_ptr->active = false; + + Nonce::pause(true); + Nonce::touch(); +} + + +void xmrig::Miner::printHashrate(bool details) +{ + char num[8 * 4] = { 0 }; + double speed[3] = { 0.0 }; + + for (IBackend *backend : d_ptr->backends) { + const Hashrate *hashrate = backend->hashrate(); + if (hashrate) { + speed[0] += hashrate->calc(Hashrate::ShortInterval); + speed[1] += hashrate->calc(Hashrate::MediumInterval); + speed[2] += hashrate->calc(Hashrate::LargeInterval); + } + + backend->printHashrate(details); + } + + LOG_INFO(WHITE_BOLD("speed") " 10s/60s/15m " CYAN_BOLD("%s") CYAN(" %s %s ") CYAN_BOLD("H/s") " max " CYAN_BOLD("%s H/s"), + Hashrate::format(speed[0], num, sizeof(num) / 4), + Hashrate::format(speed[1], num + 8, sizeof(num) / 4), + Hashrate::format(speed[2], num + 8 * 2, sizeof(num) / 4 ), + Hashrate::format(d_ptr->maxHashrate, num + 8 * 3, sizeof(num) / 4) + ); +} + + +void xmrig::Miner::setEnabled(bool enabled) +{ + if (d_ptr->enabled == enabled) { + return; + } + + d_ptr->enabled = enabled; + + if (enabled) { + LOG_INFO(GREEN_BOLD("resumed")); + } + else { + LOG_INFO(YELLOW_BOLD("paused") ", press " MAGENTA_BG_BOLD(" r ") " to resume"); + } + + if (!d_ptr->active) { + return; + } + + Nonce::pause(!enabled); + Nonce::touch(); +} + + +void xmrig::Miner::setJob(const Job &job, bool donate) +{ + uv_rwlock_wrlock(&d_ptr->rwlock); + + const uint8_t index = donate ? 1 : 0; + const bool reset = !(d_ptr->job.index() == 1 && index == 0 && d_ptr->userJobId == job.id()); + + d_ptr->job = job; + d_ptr->job.setIndex(index); + + if (index == 0) { + d_ptr->userJobId = job.id(); + } + + uv_rwlock_wrunlock(&d_ptr->rwlock); + + d_ptr->handleJobChange(reset); +} + + +void xmrig::Miner::stop() +{ + Nonce::stop(); + + for (IBackend *backend : d_ptr->backends) { + backend->stop(); + } +} + + +void xmrig::Miner::onConfigChanged(Config *config, Config *previousConfig) +{ + d_ptr->rebuild(); + + if (config->pools() != previousConfig->pools() && config->pools().active() > 0) { + return; + } + + const Job job = this->job(); + + for (IBackend *backend : d_ptr->backends) { + backend->setJob(job); + } +} + + +void xmrig::Miner::onTimer(const Timer *) +{ + double maxHashrate = 0.0; + + for (IBackend *backend : d_ptr->backends) { + backend->tick(d_ptr->ticks); + + if (backend->hashrate()) { + maxHashrate += backend->hashrate()->calc(Hashrate::ShortInterval); + } + } + + d_ptr->maxHashrate = std::max(d_ptr->maxHashrate, maxHashrate); + + if ((d_ptr->ticks % (d_ptr->controller->config()->printTime() * 2)) == 0) { + printHashrate(false); + } + + d_ptr->ticks++; +} + + +#ifdef XMRIG_FEATURE_API +void xmrig::Miner::onRequest(IApiRequest &request) +{ + if (request.method() == IApiRequest::METHOD_GET) { + if (request.type() == IApiRequest::REQ_SUMMARY) { + request.accept(); + + d_ptr->getMiner(request.reply(), request.doc(), request.version()); + d_ptr->getHashrate(request.reply(), request.doc(), request.version()); + } + else if (request.url() == "/2/backends") { + request.accept(); + + d_ptr->getBackends(request.reply(), request.doc()); + } + } +} +#endif diff --git a/src/core/Miner.h b/src/core/Miner.h new file mode 100644 index 00000000..035c0205 --- /dev/null +++ b/src/core/Miner.h @@ -0,0 +1,80 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_MINER_H +#define XMRIG_MINER_H + + +#include + + +#include "api/interfaces/IApiListener.h" +#include "base/kernel/interfaces/IBaseListener.h" +#include "base/kernel/interfaces/ITimerListener.h" +#include "crypto/common/Algorithm.h" + + +namespace xmrig { + + +class Controller; +class Job; +class MinerPrivate; +class IBackend; + + +class Miner : public ITimerListener, public IBaseListener, public IApiListener +{ +public: + Miner(Controller *controller); + ~Miner() override; + + bool isEnabled() const; + bool isEnabled(const Algorithm &algorithm) const; + const Algorithms &algorithms() const; + const std::vector &backends() const; + Job job() const; + void pause(); + void printHashrate(bool details); + void setEnabled(bool enabled); + void setJob(const Job &job, bool donate); + void stop(); + +protected: + void onConfigChanged(Config *config, Config *previousConfig) override; + void onTimer(const Timer *timer) override; + +# ifdef XMRIG_FEATURE_API + void onRequest(IApiRequest &request) override; +# endif + +private: + MinerPrivate *d_ptr; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_MINER_H */ diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 450f587e..d6336b67 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -28,60 +28,30 @@ #include +#include "backend/cpu/Cpu.h" #include "base/io/log/Log.h" #include "base/kernel/interfaces/IJsonReader.h" -#include "common/cpu/Cpu.h" #include "core/config/Config.h" -#include "crypto/cn/Asm.h" -#include "crypto/cn/CryptoNight_constants.h" +#include "crypto/common/Assembly.h" #include "rapidjson/document.h" #include "rapidjson/filewritestream.h" #include "rapidjson/prettywriter.h" -#include "workers/CpuThread.h" -static char affinity_tmp[20] = { 0 }; - - -xmrig::Config::Config() : - m_aesMode(AES_AUTO), - m_algoVariant(AV_AUTO), - m_assembly(ASM_AUTO), - m_hugePages(true), - m_safe(false), - m_shouldSave(false), - m_maxCpuUsage(100), - m_priority(-1) +xmrig::Config::Config() : BaseConfig() { } -bool xmrig::Config::isHwAES() const -{ - return (m_aesMode == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aesMode) == AES_HW; -} - - bool xmrig::Config::read(const IJsonReader &reader, const char *fileName) { if (!BaseConfig::read(reader, fileName)) { return false; } - m_hugePages = reader.getBool("huge-pages", true); - m_safe = reader.getBool("safe"); + m_cpu.read(reader.getValue("cpu")); - setAesMode(reader.getValue("hw-aes")); - setAlgoVariant(reader.getInt("av")); - setMaxCpuUsage(reader.getInt("max-cpu-usage", 100)); - setPriority(reader.getInt("cpu-priority", -1)); - setThreads(reader.getValue("threads")); - -# ifndef XMRIG_NO_ASM - setAssembly(reader.getValue("asm")); -# endif - - return finalize(); + return true; } @@ -93,200 +63,24 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const auto &allocator = doc.GetAllocator(); - doc.AddMember("algo", StringRef(algorithm().name()), allocator); - Value api(kObjectType); api.AddMember("id", m_apiId.toJSON(), allocator); api.AddMember("worker-id", m_apiWorkerId.toJSON(), allocator); - doc.AddMember("api", api, allocator); - doc.AddMember("http", m_http.toJSON(doc), allocator); -# ifndef XMRIG_NO_ASM - doc.AddMember("asm", Asm::toJSON(m_assembly), allocator); -# endif - - doc.AddMember("autosave", isAutoSave(), allocator); - doc.AddMember("av", algoVariant(), allocator); - doc.AddMember("background", isBackground(), allocator); - doc.AddMember("colors", Log::colors, allocator); - - if (affinity() != -1L) { - snprintf(affinity_tmp, sizeof(affinity_tmp) - 1, "0x%" PRIX64, affinity()); - doc.AddMember("cpu-affinity", StringRef(affinity_tmp), allocator); - } - else { - doc.AddMember("cpu-affinity", kNullType, allocator); - } - - doc.AddMember("cpu-priority", priority() != -1 ? Value(priority()) : Value(kNullType), allocator); + doc.AddMember("api", api, allocator); + doc.AddMember("autosave", isAutoSave(), allocator); + doc.AddMember("background", isBackground(), allocator); + doc.AddMember("colors", Log::colors, allocator); + doc.AddMember("cpu", m_cpu.toJSON(doc), allocator); doc.AddMember("donate-level", m_pools.donateLevel(), allocator); doc.AddMember("donate-over-proxy", m_pools.proxyDonate(), allocator); - doc.AddMember("huge-pages", isHugePages(), allocator); - doc.AddMember("hw-aes", m_aesMode == AES_AUTO ? Value(kNullType) : Value(m_aesMode == AES_HW), allocator); + doc.AddMember("http", m_http.toJSON(doc), allocator); doc.AddMember("log-file", m_logFile.toJSON(), allocator); - doc.AddMember("max-cpu-usage", m_maxCpuUsage, allocator); doc.AddMember("pools", m_pools.toJSON(doc), allocator); doc.AddMember("print-time", printTime(), allocator); doc.AddMember("retries", m_pools.retries(), allocator); doc.AddMember("retry-pause", m_pools.retryPause(), allocator); - doc.AddMember("safe", m_safe, allocator); - - if (threadsMode() != Simple) { - Value threads(kArrayType); - - for (const IThread *thread : m_threads.list) { - threads.PushBack(thread->toConfig(doc), allocator); - } - - doc.AddMember("threads", threads, allocator); - } - else { - doc.AddMember("threads", threadsCount(), allocator); - } - - doc.AddMember("user-agent", m_userAgent.toJSON(), allocator); - doc.AddMember("syslog", isSyslog(), allocator); - doc.AddMember("watch", m_watch, allocator); + doc.AddMember("syslog", isSyslog(), allocator); + doc.AddMember("user-agent", m_userAgent.toJSON(), allocator); + doc.AddMember("watch", m_watch, allocator); } - - -bool xmrig::Config::finalize() -{ - if (!m_threads.cpu.empty()) { - m_threads.mode = Advanced; - - for (size_t i = 0; i < m_threads.cpu.size(); ++i) { - m_threads.list.push_back(CpuThread::createFromData(i, m_algorithm.algo(), m_threads.cpu[i], m_priority, !isHwAES())); - } - - return true; - } - - const AlgoVariant av = getAlgoVariant(); - m_threads.mode = m_threads.count ? Simple : Automatic; - - const Variant v = m_algorithm.variant(); - const size_t size = CpuThread::multiway(av) * cn_select_memory(m_algorithm.algo(), v) / 1024; - - if (!m_threads.count) { - m_threads.count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); - } - else if (m_safe) { - const size_t count = Cpu::info()->optimalThreadsCount(size, m_maxCpuUsage); - if (m_threads.count > count) { - m_threads.count = count; - } - } - - for (size_t i = 0; i < m_threads.count; ++i) { - m_threads.list.push_back(CpuThread::createFromAV(i, m_algorithm.algo(), av, m_threads.mask, m_priority, m_assembly)); - } - - m_shouldSave = m_threads.mode == Automatic; - - return true; -} - - -void xmrig::Config::setAesMode(const rapidjson::Value &aesMode) -{ - if (aesMode.IsBool()) { - m_aesMode = aesMode.GetBool() ? AES_HW : AES_SOFT; - } -} - - -void xmrig::Config::setAlgoVariant(int av) -{ - if (av >= AV_AUTO && av < AV_MAX) { - m_algoVariant = static_cast(av); - } -} - - -void xmrig::Config::setMaxCpuUsage(int max) -{ - if (max > 0 && max <= 100) { - m_maxCpuUsage = max; - } -} - - -void xmrig::Config::setPriority(int priority) -{ - if (priority >= 0 && priority <= 5) { - m_priority = priority; - } -} - - -void xmrig::Config::setThreads(const rapidjson::Value &threads) -{ - if (threads.IsArray()) { - m_threads.cpu.clear(); - - for (const rapidjson::Value &value : threads.GetArray()) { - if (!value.IsObject()) { - continue; - } - - if (value.HasMember("low_power_mode")) { - auto data = CpuThread::parse(value); - - if (data.valid) { - m_threads.cpu.push_back(std::move(data)); - } - } - } - } - else if (threads.IsUint()) { - const unsigned count = threads.GetUint(); - if (count < 1024) { - m_threads.count = count; - } - } -} - - -xmrig::AlgoVariant xmrig::Config::getAlgoVariant() const -{ -# ifdef XMRIG_ALGO_CN_LITE - if (m_algorithm.algo() == xmrig::CRYPTONIGHT_LITE) { - return getAlgoVariantLite(); - } -# endif - - if (m_algoVariant <= AV_AUTO || m_algoVariant >= AV_MAX) { - return Cpu::info()->hasAES() ? AV_SINGLE : AV_SINGLE_SOFT; - } - - if (m_safe && !Cpu::info()->hasAES() && m_algoVariant <= AV_DOUBLE) { - return static_cast(m_algoVariant + 2); - } - - return m_algoVariant; -} - - -#ifdef XMRIG_ALGO_CN_LITE -xmrig::AlgoVariant xmrig::Config::getAlgoVariantLite() const -{ - if (m_algoVariant <= AV_AUTO || m_algoVariant >= AV_MAX) { - return Cpu::info()->hasAES() ? AV_DOUBLE : AV_DOUBLE_SOFT; - } - - if (m_safe && !Cpu::info()->hasAES() && m_algoVariant <= AV_DOUBLE) { - return static_cast(m_algoVariant + 2); - } - - return m_algoVariant; -} -#endif - - -#ifndef XMRIG_NO_ASM -void xmrig::Config::setAssembly(const rapidjson::Value &assembly) -{ - m_assembly = Asm::parse(assembly); -} -#endif diff --git a/src/core/config/Config.h b/src/core/config/Config.h index 1d8a42d9..e6b5c735 100644 --- a/src/core/config/Config.h +++ b/src/core/config/Config.h @@ -5,7 +5,8 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * 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 @@ -26,103 +27,37 @@ #include -#include +#include "backend/cpu/CpuConfig.h" #include "base/kernel/config/BaseConfig.h" -#include "common/xmrig.h" #include "rapidjson/fwd.h" -#include "workers/CpuThread.h" namespace xmrig { -class ConfigLoader; class IThread; -class IConfigListener; -class Process; -/** - * @brief The Config class - * - * Options with dynamic reload: - * colors - * debug - * verbose - * custom-diff (only for new connections) - * api/worker-id - * pools/ - */ class Config : public BaseConfig { public: - enum ThreadsMode { - Automatic, - Simple, - Advanced - }; - - Config(); - bool isHwAES() const; bool read(const IJsonReader &reader, const char *fileName) override; void getJSON(rapidjson::Document &doc) const override; - inline AlgoVariant algoVariant() const { return m_algoVariant; } - inline Assembly assembly() const { return m_assembly; } - inline bool isHugePages() const { return m_hugePages; } - inline bool isShouldSave() const { return (m_shouldSave || m_upgrade) && isAutoSave(); } - inline const std::vector &threads() const { return m_threads.list; } - inline int priority() const { return m_priority; } - inline int threadsCount() const { return static_cast(m_threads.list.size()); } - inline int64_t affinity() const { return m_threads.mask; } - inline ThreadsMode threadsMode() const { return m_threads.mode; } + inline bool isShouldSave() const { return (m_shouldSave || m_upgrade || m_cpu.isShouldSave()) && isAutoSave(); } + inline const CpuConfig &cpu() const { return m_cpu; } private: - bool finalize(); - void setAesMode(const rapidjson::Value &aesMode); - void setAlgoVariant(int av); - void setMaxCpuUsage(int max); - void setPriority(int priority); - void setThreads(const rapidjson::Value &threads); - - AlgoVariant getAlgoVariant() const; -# ifdef XMRIG_ALGO_CN_LITE - AlgoVariant getAlgoVariantLite() const; -# endif - -# ifndef XMRIG_NO_ASM - void setAssembly(const rapidjson::Value &assembly); -# endif - - - struct Threads - { - inline Threads() : mask(-1L), count(0), mode(Automatic) {} - - int64_t mask; - size_t count; - std::vector cpu; - std::vector list; - ThreadsMode mode; - }; - - - AesMode m_aesMode; - AlgoVariant m_algoVariant; - Assembly m_assembly; - bool m_hugePages; - bool m_safe; - bool m_shouldSave; - int m_maxCpuUsage; - int m_priority; - Threads m_threads; + bool m_shouldSave = false; + CpuConfig m_cpu; }; } /* namespace xmrig */ + #endif /* XMRIG_CONFIG_H */ diff --git a/src/core/config/ConfigTransform.cpp b/src/core/config/ConfigTransform.cpp index 7d313726..38bb42a1 100644 --- a/src/core/config/ConfigTransform.cpp +++ b/src/core/config/ConfigTransform.cpp @@ -23,27 +23,189 @@ */ -#include "core/config/ConfigTransform.h" #include "base/kernel/interfaces/IConfig.h" +#include "core/config/ConfigTransform.h" +#include "crypto/cn/CnHash.h" -xmrig::ConfigTransform::ConfigTransform() +namespace xmrig { + +static const char *kAffinity = "affinity"; +static const char *kAsterisk = "*"; +static const char *kCpu = "cpu"; +static const char *kIntensity = "intensity"; + + +static inline uint64_t intensity(uint64_t av) +{ + switch (av) { + case CnHash::AV_SINGLE: + case CnHash::AV_SINGLE_SOFT: + return 1; + + case CnHash::AV_DOUBLE_SOFT: + case CnHash::AV_DOUBLE: + return 2; + + case CnHash::AV_TRIPLE_SOFT: + case CnHash::AV_TRIPLE: + return 3; + + case CnHash::AV_QUAD_SOFT: + case CnHash::AV_QUAD: + return 4; + + case CnHash::AV_PENTA_SOFT: + case CnHash::AV_PENTA: + return 5; + + default: + break; + } + + return 1; +} + + +static inline bool isHwAes(uint64_t av) +{ + return av == CnHash::AV_SINGLE || av == CnHash::AV_DOUBLE || (av > CnHash::AV_DOUBLE_SOFT && av < CnHash::AV_TRIPLE_SOFT); +} + + +static inline int64_t affinity(uint64_t index, int64_t affinity) +{ + if (affinity == -1L) { + return -1L; + } + + size_t idx = 0; + + for (size_t i = 0; i < 64; i++) { + if (!(static_cast(affinity) & (1ULL << i))) { + continue; + } + + if (idx == index) { + return static_cast(i); + } + + idx++; + } + + return -1L; +} + + +} + + +xmrig::ConfigTransform::ConfigTransform() : BaseTransform() +{ +} + + +void xmrig::ConfigTransform::finalize(rapidjson::Document &doc) +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + BaseTransform::finalize(doc); + + if (m_threads) { + if (!doc.HasMember(kCpu)) { + doc.AddMember(StringRef(kCpu), Value(kObjectType), allocator); + } + + Value threads(kArrayType); + + if (m_intensity > 1) { + for (uint64_t i = 0; i < m_threads; ++i) { + Value thread(kObjectType); + thread.AddMember(StringRef(kIntensity), m_intensity, allocator); + thread.AddMember(StringRef(kAffinity), affinity(i, m_affinity), allocator); + + threads.PushBack(thread, doc.GetAllocator()); + } + } + else { + for (uint64_t i = 0; i < m_threads; ++i) { + threads.PushBack(affinity(i, m_affinity), doc.GetAllocator()); + } + } + + doc[kCpu].AddMember(StringRef(kAsterisk), threads, doc.GetAllocator()); + } } void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const char *arg) { BaseTransform::transform(doc, key, arg); + + switch (key) { + case IConfig::AVKey: /* --av */ + case IConfig::CPUPriorityKey: /* --cpu-priority */ + case IConfig::ThreadsKey: /* --threads */ + return transformUint64(doc, key, static_cast(strtol(arg, nullptr, 10))); + + case IConfig::HugePagesKey: /* --no-huge-pages */ + return transformBoolean(doc, key, false); + + case IConfig::CPUAffinityKey: /* --cpu-affinity */ + { + const char *p = strstr(arg, "0x"); + return transformUint64(doc, key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10)); + } + +# ifndef XMRIG_NO_ASM + case IConfig::AssemblyKey: /* --asm */ + return set(doc, kCpu, "asm", arg); +# endif + + default: + break; + } } void xmrig::ConfigTransform::transformBoolean(rapidjson::Document &doc, int key, bool enable) { + switch (key) { + case IConfig::HugePagesKey: /* --no-huge-pages */ + return set(doc, kCpu, "huge-pages", enable); + + default: + break; + } } void xmrig::ConfigTransform::transformUint64(rapidjson::Document &doc, int key, uint64_t arg) { + using namespace rapidjson; + + switch (key) { + case IConfig::CPUAffinityKey: /* --cpu-affinity */ + m_affinity = static_cast(arg); + break; + + case IConfig::ThreadsKey: /* --threads */ + m_threads = arg; + break; + + case IConfig::AVKey: /* --av */ + m_intensity = intensity(arg); + set(doc, kCpu, "hw-aes", isHwAes(arg)); + break; + + case IConfig::CPUPriorityKey: /* --cpu-priority */ + return set(doc, kCpu, "priority", arg); + + default: + break; + } } + diff --git a/src/core/config/ConfigTransform.h b/src/core/config/ConfigTransform.h index 2d291d8f..440a7169 100644 --- a/src/core/config/ConfigTransform.h +++ b/src/core/config/ConfigTransform.h @@ -5,7 +5,8 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * 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 @@ -37,11 +38,16 @@ public: ConfigTransform(); protected: + void finalize(rapidjson::Document &doc) override; void transform(rapidjson::Document &doc, int key, const char *arg) override; private: void transformBoolean(rapidjson::Document &doc, int key, bool enable); void transformUint64(rapidjson::Document &doc, int key, uint64_t arg); + + int64_t m_affinity = -1; + uint64_t m_intensity = 1; + uint64_t m_threads = 0; }; diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h index ca06a703..fdd15c96 100644 --- a/src/core/config/Config_platform.h +++ b/src/core/config/Config_platform.h @@ -62,16 +62,13 @@ static const option options[] = { { "dry-run", 0, nullptr, IConfig::DryRunKey }, { "keepalive", 0, nullptr, IConfig::KeepAliveKey }, { "log-file", 1, nullptr, IConfig::LogFileKey }, - { "max-cpu-usage", 1, nullptr, IConfig::MaxCPUUsageKey }, { "nicehash", 0, nullptr, IConfig::NicehashKey }, { "no-color", 0, nullptr, IConfig::ColorKey }, { "no-huge-pages", 0, nullptr, IConfig::HugePagesKey }, - { "variant", 1, nullptr, IConfig::VariantKey }, { "pass", 1, nullptr, IConfig::PasswordKey }, { "print-time", 1, nullptr, IConfig::PrintTimeKey }, { "retries", 1, nullptr, IConfig::RetriesKey }, { "retry-pause", 1, nullptr, IConfig::RetryPauseKey }, - { "safe", 0, nullptr, IConfig::SafeKey }, { "syslog", 0, nullptr, IConfig::SyslogKey }, { "threads", 1, nullptr, IConfig::ThreadsKey }, { "url", 1, nullptr, IConfig::UrlKey }, @@ -84,43 +81,10 @@ static const option options[] = { { "asm", 1, nullptr, IConfig::AssemblyKey }, { "daemon", 0, nullptr, IConfig::DaemonKey }, { "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey }, - -# ifdef XMRIG_DEPRECATED - { "api-port", 1, nullptr, IConfig::ApiPort }, - { "api-access-token", 1, nullptr, IConfig::ApiAccessTokenKey }, - { "api-no-restricted", 0, nullptr, IConfig::ApiRestrictedKey }, - { "api-ipv6", 0, nullptr, IConfig::ApiIPv6Key }, -# endif - { nullptr, 0, nullptr, 0 } }; -static struct option const config_options[] = { - { "algo", 1, nullptr, IConfig::AlgorithmKey }, - { "av", 1, nullptr, IConfig::AVKey }, - { "background", 0, nullptr, IConfig::BackgroundKey }, - { "colors", 0, nullptr, IConfig::ColorKey }, - { "cpu-affinity", 1, nullptr, IConfig::CPUAffinityKey }, - { "cpu-priority", 1, nullptr, IConfig::CPUPriorityKey }, - { "donate-level", 1, nullptr, IConfig::DonateLevelKey }, - { "donate-over-proxy", 1, nullptr, IConfig::ProxyDonateKey }, - { "dry-run", 0, nullptr, IConfig::DryRunKey }, - { "huge-pages", 0, nullptr, IConfig::HugePagesKey }, - { "log-file", 1, nullptr, IConfig::LogFileKey }, - { "max-cpu-usage", 1, nullptr, IConfig::MaxCPUUsageKey }, - { "print-time", 1, nullptr, IConfig::PrintTimeKey }, - { "retries", 1, nullptr, IConfig::RetriesKey }, - { "retry-pause", 1, nullptr, IConfig::RetryPauseKey }, - { "safe", 0, nullptr, IConfig::SafeKey }, - { "syslog", 0, nullptr, IConfig::SyslogKey }, - { "threads", 1, nullptr, IConfig::ThreadsKey }, - { "user-agent", 1, nullptr, IConfig::UserAgentKey }, - { "asm", 1, nullptr, IConfig::AssemblyKey }, - { nullptr, 0, nullptr, 0 } -}; - - } // namespace xmrig diff --git a/src/core/config/usage.h b/src/core/config/usage.h index 42cbc24a..2d0d5623 100644 --- a/src/core/config/usage.h +++ b/src/core/config/usage.h @@ -36,18 +36,28 @@ static char const usage[] = "\ Usage: " APP_ID " [OPTIONS]\n\ Options:\n\ -a, --algo=ALGO specify the algorithm to use\n\ - cryptonight\n" + cn/r, cn/2, cn/1, cn/0, cn/double, cn/half, cn/fast,\n\ + cn/rwz, cn/zls, cn/xao, cn/rto" +#ifdef XMRIG_ALGO_CN_GPU +", cn/gpu,\n" +#else +",\n" +#endif #ifdef XMRIG_ALGO_CN_LITE "\ - cryptonight-lite\n" + cn-lite/1,\n" #endif #ifdef XMRIG_ALGO_CN_HEAVY "\ - cryptonight-heavy\n" + cn-heavy/xhv, cn-heavy/tube, cn-heavy/0,\n" #endif #ifdef XMRIG_ALGO_CN_PICO "\ - cryptonight-pico\n" + cn-pico,\n" +#endif +#ifdef XMRIG_ALGO_RANDOMX +"\ + rx/wow, rx/loki\n" #endif "\ -o, --url=URL URL of mining server\n\ @@ -76,7 +86,6 @@ Options:\n\ --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\ --no-huge-pages disable huge pages support\n\ --no-color disable colored output\n\ - --variant algorithm PoW variant\n\ --donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\ --user-agent set custom user-agent string for pool\n\ -B, --background run the miner in the background\n\ @@ -87,8 +96,6 @@ Options:\n\ -S, --syslog use system log for output messages\n" # endif "\ - --max-cpu-usage=N maximum CPU usage for automatic threads mode (default: 100)\n\ - --safe safe adjust threads and av settings for current CPU\n\ --asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer.\n\ --print-time=N print hashrate report every N seconds\n" #ifdef XMRIG_FEATURE_HTTP diff --git a/src/crypto/cn/CnAlgo.h b/src/crypto/cn/CnAlgo.h new file mode 100644 index 00000000..ed64331a --- /dev/null +++ b/src/crypto/cn/CnAlgo.h @@ -0,0 +1,222 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_CN_ALGO_H +#define XMRIG_CN_ALGO_H + + +#include +#include + + +#include "crypto/common/Algorithm.h" + + +namespace xmrig +{ + + +template +class CnAlgo +{ +public: + constexpr inline CnAlgo() + { + static_assert(ALGO != Algorithm::INVALID && m_memory[ALGO] > 0, "invalid CRYPTONIGHT algorithm"); + static_assert(sizeof(m_memory) / sizeof(m_memory)[0] == Algorithm::MAX, "memory table size mismatch"); + static_assert(sizeof(m_iterations) / sizeof(m_iterations)[0] == Algorithm::MAX, "iterations table size mismatch"); + static_assert(sizeof(m_base) / sizeof(m_base)[0] == Algorithm::MAX, "iterations table size mismatch"); + } + + constexpr inline Algorithm::Id base() const { return m_base[ALGO]; } + constexpr inline bool isHeavy() const { return memory() == CN_MEMORY * 2; } + constexpr inline bool isR() const { return ALGO == Algorithm::CN_R || ALGO == Algorithm::CN_WOW; } + constexpr inline size_t memory() const { return m_memory[ALGO]; } + constexpr inline uint32_t iterations() const { return m_iterations[ALGO]; } + constexpr inline uint32_t mask() const { return ((memory() - 1) / 16) * 16; } + + inline static size_t memory(Algorithm::Id algo) + { + switch (Algorithm::family(algo)) { + case Algorithm::CN: + return CN_MEMORY; + + case Algorithm::CN_LITE: + return CN_MEMORY / 2; + + case Algorithm::CN_HEAVY: + return CN_MEMORY * 2; + + case Algorithm::CN_PICO: + return CN_MEMORY / 8; + + default: + break; + } + + return 0; + } + + inline static uint32_t mask(Algorithm::Id algo) + { +# ifdef XMRIG_ALGO_CN_GPU + if (algo == Algorithm::CN_GPU) { + return 0x1FFFC0; + } +# endif + +# ifdef XMRIG_ALGO_CN_PICO + if (algo == Algorithm::CN_PICO_0) { + return 0x1FFF0; + } +# endif + + return ((memory(algo) - 1) / 16) * 16; + } + +private: + constexpr const static size_t CN_MEMORY = 0x200000; + constexpr const static uint32_t CN_ITER = 0x80000; + + constexpr const static size_t m_memory[] = { + CN_MEMORY, // CN_0 + CN_MEMORY, // CN_1 + CN_MEMORY, // CN_2 + CN_MEMORY, // CN_R + CN_MEMORY, // CN_WOW + CN_MEMORY, // CN_FAST + CN_MEMORY, // CN_HALF + CN_MEMORY, // CN_XAO + CN_MEMORY, // CN_RTO + CN_MEMORY, // CN_RWZ + CN_MEMORY, // CN_ZLS + CN_MEMORY, // CN_DOUBLE +# ifdef XMRIG_ALGO_CN_GPU + CN_MEMORY, // CN_GPU +# endif +# ifdef XMRIG_ALGO_CN_LITE + CN_MEMORY / 2, // CN_LITE_0 + CN_MEMORY / 2, // CN_LITE_1 +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + CN_MEMORY * 2, // CN_HEAVY_0 + CN_MEMORY * 2, // CN_HEAVY_TUBE + CN_MEMORY * 2, // CN_HEAVY_XHV +# endif +# ifdef XMRIG_ALGO_CN_PICO + CN_MEMORY / 8, // CN_PICO_0 +# endif +# ifdef XMRIG_ALGO_RANDOMX + 0, // RX_0 + 0, // RX_WOW + 0, // RX_LOKI +# endif + }; + + constexpr const static uint32_t m_iterations[] = { + CN_ITER, // CN_0 + CN_ITER, // CN_1 + CN_ITER, // CN_2 + CN_ITER, // CN_R + CN_ITER, // CN_WOW + CN_ITER / 2, // CN_FAST + CN_ITER / 2, // CN_HALF + CN_ITER * 2, // CN_XAO + CN_ITER, // CN_RTO + 0x60000, // CN_RWZ + 0x60000, // CN_ZLS + CN_ITER * 2, // CN_DOUBLE +# ifdef XMRIG_ALGO_CN_GPU + 0xC000, // CN_GPU +# endif +# ifdef XMRIG_ALGO_CN_LITE + CN_ITER / 2, // CN_LITE_0 + CN_ITER / 2, // CN_LITE_1 +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + CN_ITER / 2, // CN_HEAVY_0 + CN_ITER / 2, // CN_HEAVY_TUBE + CN_ITER / 2, // CN_HEAVY_XHV +# endif +# ifdef XMRIG_ALGO_CN_PICO + CN_ITER / 8, // CN_PICO_0 +# endif +# ifdef XMRIG_ALGO_RANDOMX + 0, // RX_0 + 0, // RX_WOW + 0, // RX_LOKI +# endif + }; + + constexpr const static Algorithm::Id m_base[] = { + Algorithm::CN_0, // CN_0 + Algorithm::CN_1, // CN_1 + Algorithm::CN_2, // CN_2 + Algorithm::CN_2, // CN_R + Algorithm::CN_2, // CN_WOW + Algorithm::CN_1, // CN_FAST + Algorithm::CN_2, // CN_HALF + Algorithm::CN_0, // CN_XAO + Algorithm::CN_1, // CN_RTO + Algorithm::CN_2, // CN_RWZ + Algorithm::CN_2, // CN_ZLS + Algorithm::CN_2, // CN_DOUBLE +# ifdef XMRIG_ALGO_CN_GPU + Algorithm::CN_GPU, // CN_GPU +# endif +# ifdef XMRIG_ALGO_CN_LITE + Algorithm::CN_0, // CN_LITE_0 + Algorithm::CN_1, // CN_LITE_1 +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + Algorithm::CN_0, // CN_HEAVY_0 + Algorithm::CN_1, // CN_HEAVY_TUBE + Algorithm::CN_0, // CN_HEAVY_XHV +# endif +# ifdef XMRIG_ALGO_CN_PICO + Algorithm::CN_2, // CN_PICO_0, +# endif +# ifdef XMRIG_ALGO_RANDOMX + Algorithm::INVALID, // RX_0 + Algorithm::INVALID, // RX_WOW + Algorithm::INVALID, // RX_LOKI +# endif + }; +}; + + +#ifdef XMRIG_ALGO_CN_GPU +template<> constexpr inline uint32_t CnAlgo::mask() const { return 0x1FFFC0; } +#endif + +#ifdef XMRIG_ALGO_CN_PICO +template<> constexpr inline uint32_t CnAlgo::mask() const { return 0x1FFF0; } +#endif + + +} /* namespace xmrig */ + + +#endif /* XMRIG_CN_ALGO_H */ diff --git a/src/Mem.cpp b/src/crypto/cn/CnCtx.cpp similarity index 66% rename from src/Mem.cpp rename to src/crypto/cn/CnCtx.cpp index 4ae1971f..5d41bca0 100644 --- a/src/Mem.cpp +++ b/src/crypto/cn/CnCtx.cpp @@ -4,7 +4,7 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , + * Copyright 2017-2019 XMR-Stak , * Copyright 2018 Lee Clagett * Copyright 2018-2019 SChernykh * Copyright 2016-2019 XMRig , @@ -23,59 +23,38 @@ * along with this program. If not, see . */ - #include -#include "crypto/cn/CryptoNight_constants.h" +#include "crypto/cn/CnCtx.h" #include "crypto/cn/CryptoNight.h" +#include "crypto/common/Algorithm.h" #include "crypto/common/portable/mm_malloc.h" #include "crypto/common/VirtualMemory.h" -#include "Mem.h" -bool Mem::m_enabled = true; -int Mem::m_flags = 0; - - -MemInfo Mem::create(cryptonight_ctx **ctx, xmrig::Algo algorithm, size_t count) +void xmrig::CnCtx::create(cryptonight_ctx **ctx, uint8_t *memory, size_t size, size_t count) { - using namespace xmrig; - - MemInfo info; - info.size = cn_select_memory(algorithm) * count; - - constexpr const size_t align_size = 2 * 1024 * 1024; - info.size = ((info.size + align_size - 1) / align_size) * align_size; - info.pages = info.size / align_size; - - allocate(info, m_enabled); - for (size_t i = 0; i < count; ++i) { cryptonight_ctx *c = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 4096)); - c->memory = info.memory + (i * cn_select_memory(algorithm)); + c->memory = memory + (i * size); - c->generated_code = reinterpret_cast(xmrig::VirtualMemory::allocateExecutableMemory(0x4000)); - c->generated_code_data.variant = xmrig::VARIANT_MAX; + c->generated_code = reinterpret_cast(VirtualMemory::allocateExecutableMemory(0x4000)); + c->generated_code_data.algo = Algorithm::INVALID; c->generated_code_data.height = std::numeric_limits::max(); ctx[i] = c; } - - return info; } -void Mem::release(cryptonight_ctx **ctx, size_t count, MemInfo &info) +void xmrig::CnCtx::release(cryptonight_ctx **ctx, size_t count) { - if (info.memory == nullptr) { + if (ctx[0] == nullptr) { return; } - release(info); - for (size_t i = 0; i < count; ++i) { _mm_free(ctx[i]); } } - diff --git a/src/crypto/cn/Asm.h b/src/crypto/cn/CnCtx.h similarity index 62% rename from src/crypto/cn/Asm.h rename to src/crypto/cn/CnCtx.h index 3b755fd6..7b0adbec 100644 --- a/src/crypto/cn/Asm.h +++ b/src/crypto/cn/CnCtx.h @@ -4,8 +4,10 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * 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 @@ -21,30 +23,30 @@ * along with this program. If not, see . */ -#ifndef XMRIG_ASM_H -#define XMRIG_ASM_H +#ifndef XMRIG_CN_CTX_H +#define XMRIG_CN_CTX_H -#include "common/xmrig.h" -#include "rapidjson/fwd.h" +#include +#include -namespace xmrig { +struct cryptonight_ctx; -class Asm +namespace xmrig +{ + + +class CnCtx { public: - static Assembly parse(const char *assembly, Assembly defaultValue = ASM_AUTO); - static Assembly parse(const rapidjson::Value &value, Assembly defaultValue = ASM_AUTO); - static const char *toString(Assembly assembly); - static rapidjson::Value toJSON(Assembly assembly); - - inline static Assembly parse(bool enable) { return enable ? ASM_AUTO : ASM_NONE; } + static void create(cryptonight_ctx **ctx, uint8_t *memory, size_t size, size_t count); + static void release(cryptonight_ctx **ctx, size_t count); }; } /* namespace xmrig */ -#endif /* XMRIG_ASM_H */ +#endif /* XMRIG_CN_CTX_H */ diff --git a/src/crypto/cn/CnHash.cpp b/src/crypto/cn/CnHash.cpp new file mode 100644 index 00000000..a2f8880c --- /dev/null +++ b/src/crypto/cn/CnHash.cpp @@ -0,0 +1,272 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#include + + +#include "backend/cpu/Cpu.h" +#include "crypto/cn/CnHash.h" +#include "crypto/common/VirtualMemory.h" + + +#if defined(XMRIG_ARM) +# include "crypto/cn/CryptoNight_arm.h" +#else +# include "crypto/cn/CryptoNight_x86.h" +#endif + + +#define ADD_FN(algo) \ + m_map[algo][AV_SINGLE][Assembly::NONE] = cryptonight_single_hash; \ + m_map[algo][AV_SINGLE_SOFT][Assembly::NONE] = cryptonight_single_hash; \ + m_map[algo][AV_DOUBLE][Assembly::NONE] = cryptonight_double_hash; \ + m_map[algo][AV_DOUBLE_SOFT][Assembly::NONE] = cryptonight_double_hash; \ + m_map[algo][AV_TRIPLE][Assembly::NONE] = cryptonight_triple_hash; \ + m_map[algo][AV_TRIPLE_SOFT][Assembly::NONE] = cryptonight_triple_hash; \ + m_map[algo][AV_QUAD][Assembly::NONE] = cryptonight_quad_hash; \ + m_map[algo][AV_QUAD_SOFT][Assembly::NONE] = cryptonight_quad_hash; \ + m_map[algo][AV_PENTA][Assembly::NONE] = cryptonight_penta_hash; \ + m_map[algo][AV_PENTA_SOFT][Assembly::NONE] = cryptonight_penta_hash; + + +#ifdef XMRIG_FEATURE_ASM +# define ADD_FN_ASM(algo) \ + m_map[algo][AV_SINGLE][Assembly::INTEL] = cryptonight_single_hash_asm; \ + m_map[algo][AV_SINGLE][Assembly::RYZEN] = cryptonight_single_hash_asm; \ + m_map[algo][AV_SINGLE][Assembly::BULLDOZER] = cryptonight_single_hash_asm; \ + m_map[algo][AV_DOUBLE][Assembly::INTEL] = cryptonight_double_hash_asm; \ + m_map[algo][AV_DOUBLE][Assembly::RYZEN] = cryptonight_double_hash_asm; \ + m_map[algo][AV_DOUBLE][Assembly::BULLDOZER] = cryptonight_double_hash_asm; + + +extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx **ctx); +extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx **ctx); +extern "C" void cnv2_mainloop_bulldozer_asm(cryptonight_ctx **ctx); +extern "C" void cnv2_double_mainloop_sandybridge_asm(cryptonight_ctx **ctx); + + +namespace xmrig { + + +cn_mainloop_fun cn_half_mainloop_ivybridge_asm = nullptr; +cn_mainloop_fun cn_half_mainloop_ryzen_asm = nullptr; +cn_mainloop_fun cn_half_mainloop_bulldozer_asm = nullptr; +cn_mainloop_fun cn_half_double_mainloop_sandybridge_asm = nullptr; + +cn_mainloop_fun cn_trtl_mainloop_ivybridge_asm = nullptr; +cn_mainloop_fun cn_trtl_mainloop_ryzen_asm = nullptr; +cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm = nullptr; +cn_mainloop_fun cn_trtl_double_mainloop_sandybridge_asm = nullptr; + +cn_mainloop_fun cn_zls_mainloop_ivybridge_asm = nullptr; +cn_mainloop_fun cn_zls_mainloop_ryzen_asm = nullptr; +cn_mainloop_fun cn_zls_mainloop_bulldozer_asm = nullptr; +cn_mainloop_fun cn_zls_double_mainloop_sandybridge_asm = nullptr; + +cn_mainloop_fun cn_double_mainloop_ivybridge_asm = nullptr; +cn_mainloop_fun cn_double_mainloop_ryzen_asm = nullptr; +cn_mainloop_fun cn_double_mainloop_bulldozer_asm = nullptr; +cn_mainloop_fun cn_double_double_mainloop_sandybridge_asm = nullptr; + + +template +static void patchCode(T dst, U src, const uint32_t iterations, const uint32_t mask = CnAlgo().mask()) +{ + const uint8_t* p = reinterpret_cast(src); + + // Workaround for Visual Studio placing trampoline in debug builds. +# if defined(_MSC_VER) + if (p[0] == 0xE9) { + p += *(int32_t*)(p + 1) + 5; + } +# endif + + size_t size = 0; + while (*(uint32_t*)(p + size) != 0xDEADC0DE) { + ++size; + } + + size += sizeof(uint32_t); + + memcpy((void*) dst, (const void*) src, size); + + uint8_t* patched_data = reinterpret_cast(dst); + for (size_t i = 0; i + sizeof(uint32_t) <= size; ++i) { + switch (*(uint32_t*)(patched_data + i)) { + case CnAlgo().iterations(): + *(uint32_t*)(patched_data + i) = iterations; + break; + + case CnAlgo().mask(): + *(uint32_t*)(patched_data + i) = mask; + break; + } + } +} + + +static void patchAsmVariants() +{ + const int allocation_size = 65536; + uint8_t *base = static_cast(VirtualMemory::allocateExecutableMemory(allocation_size)); + + cn_half_mainloop_ivybridge_asm = reinterpret_cast (base + 0x0000); + cn_half_mainloop_ryzen_asm = reinterpret_cast (base + 0x1000); + cn_half_mainloop_bulldozer_asm = reinterpret_cast (base + 0x2000); + cn_half_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0x3000); + +# ifdef XMRIG_ALGO_CN_PICO + cn_trtl_mainloop_ivybridge_asm = reinterpret_cast (base + 0x4000); + cn_trtl_mainloop_ryzen_asm = reinterpret_cast (base + 0x5000); + cn_trtl_mainloop_bulldozer_asm = reinterpret_cast (base + 0x6000); + cn_trtl_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0x7000); +# endif + + cn_zls_mainloop_ivybridge_asm = reinterpret_cast (base + 0x8000); + cn_zls_mainloop_ryzen_asm = reinterpret_cast (base + 0x9000); + cn_zls_mainloop_bulldozer_asm = reinterpret_cast (base + 0xA000); + cn_zls_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0xB000); + + cn_double_mainloop_ivybridge_asm = reinterpret_cast (base + 0xC000); + cn_double_mainloop_ryzen_asm = reinterpret_cast (base + 0xD000); + cn_double_mainloop_bulldozer_asm = reinterpret_cast (base + 0xE000); + cn_double_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0xF000); + + { + constexpr uint32_t ITER = CnAlgo().iterations(); + + patchCode(cn_half_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, ITER); + patchCode(cn_half_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, ITER); + patchCode(cn_half_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, ITER); + patchCode(cn_half_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, ITER); + } + +# ifdef XMRIG_ALGO_CN_PICO + { + constexpr uint32_t ITER = CnAlgo().iterations(); + constexpr uint32_t MASK = CnAlgo().mask(); + + patchCode(cn_trtl_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, ITER, MASK); + patchCode(cn_trtl_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, ITER, MASK); + patchCode(cn_trtl_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, ITER, MASK); + patchCode(cn_trtl_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, ITER, MASK); + } +# endif + + { + constexpr uint32_t ITER = CnAlgo().iterations(); + + patchCode(cn_zls_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, ITER); + patchCode(cn_zls_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, ITER); + patchCode(cn_zls_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, ITER); + patchCode(cn_zls_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, ITER); + } + + { + constexpr uint32_t ITER = CnAlgo().iterations(); + + patchCode(cn_double_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, ITER); + patchCode(cn_double_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, ITER); + patchCode(cn_double_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, ITER); + patchCode(cn_double_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, ITER); + } + + VirtualMemory::protectExecutableMemory(base, allocation_size); + VirtualMemory::flushInstructionCache(base, allocation_size); +} +} // namespace xmrig +#else +# define ADD_FN_ASM(algo) +#endif + + +static const xmrig::CnHash cnHash; + + +xmrig::CnHash::CnHash() +{ + ADD_FN(Algorithm::CN_0); + ADD_FN(Algorithm::CN_1); + ADD_FN(Algorithm::CN_2); + ADD_FN(Algorithm::CN_R); + ADD_FN(Algorithm::CN_WOW); + ADD_FN(Algorithm::CN_FAST); + ADD_FN(Algorithm::CN_HALF); + ADD_FN(Algorithm::CN_XAO); + ADD_FN(Algorithm::CN_RTO); + ADD_FN(Algorithm::CN_RWZ); + ADD_FN(Algorithm::CN_ZLS); + ADD_FN(Algorithm::CN_DOUBLE); + + ADD_FN_ASM(Algorithm::CN_2); + ADD_FN_ASM(Algorithm::CN_HALF); + ADD_FN_ASM(Algorithm::CN_R); + ADD_FN_ASM(Algorithm::CN_WOW); + ADD_FN_ASM(Algorithm::CN_RWZ); + ADD_FN_ASM(Algorithm::CN_ZLS); + ADD_FN_ASM(Algorithm::CN_DOUBLE); + +# ifdef XMRIG_ALGO_CN_GPU + m_map[Algorithm::CN_GPU][AV_SINGLE][Assembly::NONE] = cryptonight_single_hash_gpu; + m_map[Algorithm::CN_GPU][AV_SINGLE_SOFT][Assembly::NONE] = cryptonight_single_hash_gpu; +# endif + +# ifdef XMRIG_ALGO_CN_LITE + ADD_FN(Algorithm::CN_LITE_0); + ADD_FN(Algorithm::CN_LITE_1); +# endif + +# ifdef XMRIG_ALGO_CN_HEAVY + ADD_FN(Algorithm::CN_HEAVY_0); + ADD_FN(Algorithm::CN_HEAVY_TUBE); + ADD_FN(Algorithm::CN_HEAVY_XHV); +# endif + +# ifdef XMRIG_ALGO_CN_PICO + ADD_FN(Algorithm::CN_PICO_0); + ADD_FN_ASM(Algorithm::CN_PICO_0); +# endif + +# ifdef XMRIG_FEATURE_ASM + patchAsmVariants(); +# endif +} + + +xmrig::cn_hash_fun xmrig::CnHash::fn(const Algorithm &algorithm, AlgoVariant av, Assembly::Id assembly) +{ + if (!algorithm.isValid()) { + return nullptr; + } + +# ifdef XMRIG_FEATURE_ASM + cn_hash_fun fun = cnHash.m_map[algorithm][av][Cpu::assembly(assembly)]; + if (fun) { + return fun; + } +# endif + + return cnHash.m_map[algorithm][av][Assembly::NONE]; +} diff --git a/src/crypto/cn/CnHash.h b/src/crypto/cn/CnHash.h new file mode 100644 index 00000000..e4a7ebd2 --- /dev/null +++ b/src/crypto/cn/CnHash.h @@ -0,0 +1,78 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_CN_HASH_H +#define XMRIG_CN_HASH_H + + +#include +#include + + +#include "crypto/cn/CnAlgo.h" +#include "crypto/common/Assembly.h" + + +struct cryptonight_ctx; + + +namespace xmrig +{ + +typedef void (*cn_hash_fun)(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx **ctx, uint64_t height); +typedef void (*cn_mainloop_fun)(cryptonight_ctx **ctx); + + +class CnHash +{ +public: + enum AlgoVariant { + AV_AUTO, // --av=0 Automatic mode. + AV_SINGLE, // --av=1 Single hash mode + AV_DOUBLE, // --av=2 Double hash mode + AV_SINGLE_SOFT, // --av=3 Single hash mode (Software AES) + AV_DOUBLE_SOFT, // --av=4 Double hash mode (Software AES) + AV_TRIPLE, // --av=5 Triple hash mode + AV_QUAD, // --av=6 Quard hash mode + AV_PENTA, // --av=7 Penta hash mode + AV_TRIPLE_SOFT, // --av=8 Triple hash mode (Software AES) + AV_QUAD_SOFT, // --av=9 Quard hash mode (Software AES) + AV_PENTA_SOFT, // --av=10 Penta hash mode (Software AES) + AV_MAX + }; + + CnHash(); + + static cn_hash_fun fn(const Algorithm &algorithm, AlgoVariant av, Assembly::Id assembly); + +private: + cn_hash_fun m_map[Algorithm::MAX][AV_MAX][Assembly::MAX] = {}; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_CN_HASH_H */ diff --git a/src/crypto/cn/CryptoNight.h b/src/crypto/cn/CryptoNight.h index f50966ed..434c34f8 100644 --- a/src/crypto/cn/CryptoNight.h +++ b/src/crypto/cn/CryptoNight.h @@ -42,10 +42,10 @@ typedef void(*cn_mainloop_fun_ms_abi)(cryptonight_ctx**) ABI_ATTRIBUTE; struct cryptonight_r_data { - int variant; + int algo; uint64_t height; - bool match(const int v, const uint64_t h) const { return (v == variant) && (h == height); } + bool match(const int a, const uint64_t h) const { return (a == algo) && (h == height); } }; diff --git a/src/crypto/cn/CryptoNight_arm.h b/src/crypto/cn/CryptoNight_arm.h index d9be454b..02266634 100644 --- a/src/crypto/cn/CryptoNight_arm.h +++ b/src/crypto/cn/CryptoNight_arm.h @@ -28,12 +28,12 @@ #define XMRIG_CRYPTONIGHT_ARM_H -#include "common/crypto/keccak.h" -#include "crypto/common/portable/mm_malloc.h" -#include "crypto/cn/CryptoNight_constants.h" +#include "crypto/cn/CnAlgo.h" #include "crypto/cn/CryptoNight_monero.h" #include "crypto/cn/CryptoNight.h" #include "crypto/cn/soft_aes.h" +#include "crypto/common/keccak.h" +#include "crypto/common/portable/mm_malloc.h" extern "C" @@ -226,9 +226,14 @@ inline void mix_and_propagate(__m128i& x0, __m128i& x1, __m128i& x2, __m128i& x3 } -template +namespace xmrig { + + +template static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) { + constexpr CnAlgo props; + __m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7; __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9; @@ -243,7 +248,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) xin6 = _mm_load_si128(input + 10); xin7 = _mm_load_si128(input + 11); - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (props.isHeavy()) { for (size_t i = 0; i < 16; i++) { aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); @@ -260,7 +265,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } } - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); @@ -284,37 +289,17 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } -#ifdef XMRIG_ALGO_CN_GPU -template -void cn_explode_scratchpad_gpu(const uint8_t *input, uint8_t *output) -{ - constexpr size_t hash_size = 200; // 25x8 bytes - alignas(16) uint64_t hash[25]; - - for (uint64_t i = 0; i < MEM / 512; i++) - { - memcpy(hash, input, hash_size); - hash[0] ^= i; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 160); - output += 160; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 176); - output += 176; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 176); - output += 176; - } -} -#endif - - -template +template static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) { + constexpr CnAlgo props; + +# ifdef XMRIG_ALGO_CN_GPU + constexpr bool IS_HEAVY = props.isHeavy() || ALGO == Algorithm::CN_GPU; +# else + constexpr bool IS_HEAVY = props.isHeavy(); +# endif + __m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7; __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9; @@ -329,8 +314,7 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) xout6 = _mm_load_si128(output + 10); xout7 = _mm_load_si128(output + 11); - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) - { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0); xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1); xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2); @@ -351,13 +335,13 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (IS_HEAVY) { mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7); } } - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { + if (IS_HEAVY) { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0); xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1); xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2); @@ -408,6 +392,9 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) } +} /* namespace xmrig */ + + static inline __m128i aes_round_tweak_div(const __m128i &in, const __m128i &key) { alignas(16) uint32_t k[4]; @@ -430,13 +417,18 @@ static inline __m128i aes_round_tweak_div(const __m128i &in, const __m128i &key) } -template +namespace xmrig { + + +template static inline void cryptonight_monero_tweak(const uint8_t* l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i& cx) { + constexpr CnAlgo props; + uint64_t* mem_out = (uint64_t*)&l[idx]; - if (BASE == xmrig::VARIANT_2) { - VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + if (props.base() == Algorithm::CN_2) { + VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); _mm_store_si128((__m128i *)mem_out, _mm_xor_si128(bx0, cx)); } else { __m128i tmp = _mm_xor_si128(bx0, cx); @@ -446,7 +438,7 @@ static inline void cryptonight_monero_tweak(const uint8_t* l, uint64_t idx, __m1 uint8_t x = vh >> 24; static const uint16_t table = 0x7531; - const uint8_t index = (((x >> (VARIANT == xmrig::VARIANT_XTL ? 4 : 3)) & 6) | (x & 1)) << 1; + const uint8_t index = (((x >> (3)) & 6) | (x & 1)) << 1; vh ^= ((table >> index) & 0x3) << 28; mem_out[1] = vh; @@ -454,24 +446,28 @@ static inline void cryptonight_monero_tweak(const uint8_t* l, uint64_t idx, __m1 } -template +template inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 32); return; } - xmrig::keccak(input, size, ctx[0]->state); + keccak(input, size, ctx[0]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[0]->state), reinterpret_cast<__m128i *>(ctx[0]->memory)); - cn_explode_scratchpad((__m128i*) ctx[0]->state, (__m128i*) ctx[0]->memory); - - const uint8_t* l0 = ctx[0]->memory; + uint8_t* l0 = ctx[0]->memory; uint64_t* h0 = reinterpret_cast(ctx[0]->state); VARIANT1_INIT(0); @@ -480,19 +476,19 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si uint64_t al0 = h0[0] ^ h0[4]; uint64_t ah0 = h0[1] ^ h0[5]; - __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); - __m128i bx1 = _mm_set_epi64x(h0[9] ^ h0[11], h0[8] ^ h0[10]); + __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); + __m128i bx1 = _mm_set_epi64x(h0[9] ^ h0[11], h0[8] ^ h0[10]); uint64_t idx0 = al0; - for (size_t i = 0; i < ITERATIONS; i++) { + for (size_t i = 0; i < props.iterations(); i++) { __m128i cx; - if (VARIANT == xmrig::VARIANT_TUBE || !SOFT_AES) { - cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); + if (IS_CN_HEAVY_TUBE || !SOFT_AES) { + cx = _mm_load_si128(reinterpret_cast(&l0[idx0 & MASK])); } const __m128i ax0 = _mm_set_epi64x(ah0, al0); - if (VARIANT == xmrig::VARIANT_TUBE) { + if (IS_CN_HEAVY_TUBE) { cx = aes_round_tweak_div(cx, ax0); } else if (SOFT_AES) { @@ -502,8 +498,8 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si cx = _mm_aesenc_si128(cx, ax0); } - if (BASE == xmrig::VARIANT_1 || BASE == xmrig::VARIANT_2) { - cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx0, bx1, cx); + if (BASE == Algorithm::CN_1 || BASE == Algorithm::CN_2) { + cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx0, bx1, cx); } else { _mm_store_si128((__m128i *)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); } @@ -514,10 +510,10 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx0, bx1); - if (VARIANT == xmrig::VARIANT_4) { + if (ALGO == Algorithm::CN_R) { al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); } @@ -528,11 +524,11 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx0, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx0, bx1, cx, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } @@ -541,9 +537,9 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l0[idx0 & MASK])[0] = al0; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (BASE == xmrig::VARIANT_1) { + } else if (BASE == Algorithm::CN_1) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; @@ -553,7 +549,8 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si ah0 ^= ch; idx0 = al0; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { const int64x2_t x = vld1q_s64(reinterpret_cast(&l0[idx0 & MASK])); const int64_t n = vgetq_lane_s64(x, 0); const int32_t d = vgetq_lane_s32(x, 2); @@ -561,77 +558,113 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si ((int64_t*)&l0[idx0 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { idx0 = (~d) ^ q; } else { idx0 = d ^ q; } } +# endif - if (BASE == xmrig::VARIANT_2) { + if (BASE == Algorithm::CN_2) { bx1 = bx0; } bx0 = cx; } - cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); - - xmrig::keccakf(h0, 24); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i *>(ctx[0]->state)); + keccakf(h0, 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); } +} /* namespace xmrig */ + + #ifdef XMRIG_ALGO_CN_GPU template void cn_gpu_inner_arm(const uint8_t *spad, uint8_t *lpad); -template +namespace xmrig { + + +template +void cn_explode_scratchpad_gpu(const uint8_t *input, uint8_t *output) +{ + constexpr size_t hash_size = 200; // 25x8 bytes + alignas(16) uint64_t hash[25]; + + for (uint64_t i = 0; i < MEM / 512; i++) { + memcpy(hash, input, hash_size); + hash[0] ^= i; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 160); + output += 160; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + } +} + + +template inline void cryptonight_single_hash_gpu(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::CRYPTONIGHT_GPU_MASK; - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr CnAlgo props; - static_assert(MASK > 0 && ITERATIONS > 0 && MEM > 0, "unsupported algorithm/variant"); - - xmrig::keccak(input, size, ctx[0]->state); - cn_explode_scratchpad_gpu(ctx[0]->state, ctx[0]->memory); + keccak(input, size, ctx[0]->state); + cn_explode_scratchpad_gpu(ctx[0]->state, ctx[0]->memory); fesetround(FE_TONEAREST); - cn_gpu_inner_arm(ctx[0]->state, ctx[0]->memory); + cn_gpu_inner_arm(ctx[0]->state, ctx[0]->memory); - cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); - - xmrig::keccakf((uint64_t*) ctx[0]->state, 24); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i *>(ctx[0]->state)); + keccakf(reinterpret_cast(ctx[0]->state), 24); memcpy(output, ctx[0]->state, 32); } + +} /* namespace xmrig */ #endif -template +namespace xmrig { + + +template inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 64); return; } - xmrig::keccak(input, size, ctx[0]->state); - xmrig::keccak(input + size, size, ctx[1]->state); + keccak(input, size, ctx[0]->state); + keccak(input + size, size, ctx[1]->state); - const uint8_t* l0 = ctx[0]->memory; - const uint8_t* l1 = ctx[1]->memory; - uint64_t* h0 = reinterpret_cast(ctx[0]->state); - uint64_t* h1 = reinterpret_cast(ctx[1]->state); + uint8_t *l0 = ctx[0]->memory; + uint8_t *l1 = ctx[1]->memory; + uint64_t *h0 = reinterpret_cast(ctx[0]->state); + uint64_t *h1 = reinterpret_cast(ctx[1]->state); VARIANT1_INIT(0); VARIANT1_INIT(1); @@ -640,8 +673,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si VARIANT4_RANDOM_MATH_INIT(0); VARIANT4_RANDOM_MATH_INIT(1); - cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0); - cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1); + cn_explode_scratchpad(reinterpret_cast(h0), reinterpret_cast<__m128i *>(l0)); + cn_explode_scratchpad(reinterpret_cast(h1), reinterpret_cast<__m128i *>(l1)); uint64_t al0 = h0[0] ^ h0[4]; uint64_t al1 = h1[0] ^ h1[4]; @@ -656,16 +689,16 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si uint64_t idx0 = al0; uint64_t idx1 = al1; - for (size_t i = 0; i < ITERATIONS; i++) { + for (size_t i = 0; i < props.iterations(); i++) { __m128i cx0, cx1; - if (VARIANT == xmrig::VARIANT_TUBE || !SOFT_AES) { + if (IS_CN_HEAVY_TUBE || !SOFT_AES) { cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]); } const __m128i ax0 = _mm_set_epi64x(ah0, al0); const __m128i ax1 = _mm_set_epi64x(ah1, al1); - if (VARIANT == xmrig::VARIANT_TUBE) { + if (IS_CN_HEAVY_TUBE) { cx0 = aes_round_tweak_div(cx0, ax0); cx1 = aes_round_tweak_div(cx1, ax1); } @@ -678,9 +711,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cx1 = _mm_aesenc_si128(cx1, ax1); } - if (BASE == xmrig::VARIANT_1 || (BASE == xmrig::VARIANT_2)) { - cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx00, bx01, cx0); - cryptonight_monero_tweak(l1, idx1 & MASK, ax1, bx10, bx11, cx1); + if (BASE == Algorithm::CN_1 || BASE == Algorithm::CN_2) { + cryptonight_monero_tweak(l0, idx0 & MASK, ax0, bx00, bx01, cx0); + cryptonight_monero_tweak(l1, idx1 & MASK, ax1, bx10, bx11, cx1); } else { _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx00, cx0)); _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx10, cx1)); @@ -693,10 +726,10 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx00, bx01); - if (VARIANT == xmrig::VARIANT_4) { + if (ALGO == Algorithm::CN_R) { al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); } @@ -707,11 +740,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx0, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx00, bx01, cx0, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } @@ -720,9 +753,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l0[idx0 & MASK])[0] = al0; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (BASE == xmrig::VARIANT_1) { + } else if (BASE == Algorithm::CN_1) { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; @@ -732,7 +765,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ah0 ^= ch; idx0 = al0; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { const int64x2_t x = vld1q_s64(reinterpret_cast(&l0[idx0 & MASK])); const int64_t n = vgetq_lane_s64(x, 0); const int32_t d = vgetq_lane_s32(x, 2); @@ -740,21 +774,22 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((int64_t*)&l0[idx0 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { idx0 = (~d) ^ q; } else { idx0 = d ^ q; } } +# endif cl = ((uint64_t*) &l1[idx1 & MASK])[0]; ch = ((uint64_t*) &l1[idx1 & MASK])[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(1, al1, ah1, cl, bx10, bx11); - if (VARIANT == xmrig::VARIANT_4) { + if (ALGO == Algorithm::CN_R) { al1 ^= r1[2] | ((uint64_t)(r1[3]) << 32); ah1 ^= r1[0] | ((uint64_t)(r1[1]) << 32); } @@ -765,11 +800,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx1, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l1, idx1 & MASK, ax1, bx10, bx11, cx1, 0); } else { - VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } @@ -778,9 +813,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l1[idx1 & MASK])[0] = al1; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1 ^ al1; - } else if (BASE == xmrig::VARIANT_1) { + } else if (BASE == Algorithm::CN_1) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1; } else { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1; @@ -790,7 +825,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ah1 ^= ch; idx1 = al1; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { const int64x2_t x = vld1q_s64(reinterpret_cast(&l1[idx1 & MASK])); const int64_t n = vgetq_lane_s64(x, 0); const int32_t d = vgetq_lane_s32(x, 2); @@ -798,47 +834,54 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((int64_t*)&l1[idx1 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { idx1 = (~d) ^ q; } else { idx1 = d ^ q; } } - if (BASE == xmrig::VARIANT_2) { +# endif + + if (BASE == Algorithm::CN_2) { bx01 = bx00; bx11 = bx10; } + bx00 = cx0; bx10 = cx1; } - cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0); - cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1); + cn_implode_scratchpad(reinterpret_cast(l0), reinterpret_cast<__m128i *>(h0)); + cn_implode_scratchpad(reinterpret_cast(l1), reinterpret_cast<__m128i *>(h1)); - xmrig::keccakf(h0, 24); - xmrig::keccakf(h1, 24); + keccakf(h0, 24); + keccakf(h1, 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); extra_hashes[ctx[1]->state[0] & 3](ctx[1]->state, 200, output + 32); } -template +template inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) { } -template +template inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) { } -template +template inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx, uint64_t height) { } -#endif /* __CRYPTONIGHT_ARM_H__ */ + +} /* namespace xmrig */ + + +#endif /* XMRIG_CRYPTONIGHT_ARM_H */ diff --git a/src/crypto/cn/CryptoNight_constants.h b/src/crypto/cn/CryptoNight_constants.h deleted file mode 100644 index d06369b4..00000000 --- a/src/crypto/cn/CryptoNight_constants.h +++ /dev/null @@ -1,254 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2019 XMR-Stak , - * Copyright 2018 Lee Clagett - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * 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 . - */ - -#ifndef XMRIG_CRYPTONIGHT_CONSTANTS_H -#define XMRIG_CRYPTONIGHT_CONSTANTS_H - - -#include -#include - - -#include "common/xmrig.h" - - -namespace xmrig -{ - -constexpr const size_t CRYPTONIGHT_MEMORY = 2 * 1024 * 1024; -constexpr const uint32_t CRYPTONIGHT_MASK = 0x1FFFF0; -constexpr const uint32_t CRYPTONIGHT_ITER = 0x80000; -constexpr const uint32_t CRYPTONIGHT_HALF_ITER = 0x40000; -constexpr const uint32_t CRYPTONIGHT_XAO_ITER = 0x100000; -constexpr const uint32_t CRYPTONIGHT_DOUBLE_ITER = 0x100000; -constexpr const uint32_t CRYPTONIGHT_WALTZ_ITER = 0x60000; -constexpr const uint32_t CRYPTONIGHT_ZLS_ITER = 0x60000; - -constexpr const uint32_t CRYPTONIGHT_GPU_ITER = 0xC000; -constexpr const uint32_t CRYPTONIGHT_GPU_MASK = 0x1FFFC0; - -constexpr const size_t CRYPTONIGHT_LITE_MEMORY = 1 * 1024 * 1024; -constexpr const uint32_t CRYPTONIGHT_LITE_MASK = 0xFFFF0; -constexpr const uint32_t CRYPTONIGHT_LITE_ITER = 0x40000; - -constexpr const size_t CRYPTONIGHT_HEAVY_MEMORY = 4 * 1024 * 1024; -constexpr const uint32_t CRYPTONIGHT_HEAVY_MASK = 0x3FFFF0; -constexpr const uint32_t CRYPTONIGHT_HEAVY_ITER = 0x40000; - -constexpr const size_t CRYPTONIGHT_PICO_MEMORY = 256 * 1024; -constexpr const uint32_t CRYPTONIGHT_PICO_MASK = 0x1FFF0; -constexpr const uint32_t CRYPTONIGHT_PICO_ITER = 0x40000; -constexpr const uint32_t CRYPTONIGHT_TRTL_ITER = 0x10000; - - -template inline constexpr size_t cn_select_memory() { return 0; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_MEMORY; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_LITE_MEMORY; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_HEAVY_MEMORY; } -template<> inline constexpr size_t cn_select_memory() { return CRYPTONIGHT_PICO_MEMORY; } - - -inline size_t cn_select_memory(Algo algorithm, Variant v = VARIANT_AUTO) -{ - switch(algorithm) - { - case CRYPTONIGHT: - return CRYPTONIGHT_MEMORY; - - case CRYPTONIGHT_LITE: - return CRYPTONIGHT_LITE_MEMORY; - - case CRYPTONIGHT_HEAVY: - return CRYPTONIGHT_HEAVY_MEMORY; - - case CRYPTONIGHT_PICO: - return CRYPTONIGHT_PICO_MEMORY; - - case RANDOM_X: - return (v == VARIANT_RX_WOW) ? CRYPTONIGHT_LITE_MEMORY : CRYPTONIGHT_MEMORY; - - default: - break; - } - - return 0; -} - - -template inline constexpr uint32_t cn_select_mask() { return 0; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_MASK; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_LITE_MASK; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_HEAVY_MASK; } -template<> inline constexpr uint32_t cn_select_mask() { return CRYPTONIGHT_PICO_MASK; } - - -inline uint32_t cn_select_mask(Algo algorithm) -{ - switch(algorithm) - { - case CRYPTONIGHT: - return CRYPTONIGHT_MASK; - - case CRYPTONIGHT_LITE: - return CRYPTONIGHT_LITE_MASK; - - case CRYPTONIGHT_HEAVY: - return CRYPTONIGHT_HEAVY_MASK; - - case CRYPTONIGHT_PICO: - return CRYPTONIGHT_PICO_MASK; - - default: - break; - } - - return 0; -} - - -template inline constexpr uint32_t cn_select_iter() { return 0; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HALF_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HALF_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_XAO_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_GPU_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_WALTZ_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_ZLS_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_DOUBLE_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_LITE_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_HEAVY_ITER; } -template<> inline constexpr uint32_t cn_select_iter() { return CRYPTONIGHT_TRTL_ITER; } - - -inline uint32_t cn_select_iter(Algo algorithm, Variant variant) -{ - switch (variant) { - case VARIANT_MSR: - case VARIANT_HALF: - return CRYPTONIGHT_HALF_ITER; - - case VARIANT_GPU: - return CRYPTONIGHT_GPU_ITER; - - case VARIANT_RTO: - case VARIANT_DOUBLE: - return CRYPTONIGHT_XAO_ITER; - - case VARIANT_TRTL: - return CRYPTONIGHT_TRTL_ITER; - - case VARIANT_RWZ: - case VARIANT_ZLS: - return CRYPTONIGHT_WALTZ_ITER; - - default: - break; - } - - switch(algorithm) - { - case CRYPTONIGHT: - return CRYPTONIGHT_ITER; - - case CRYPTONIGHT_LITE: - return CRYPTONIGHT_LITE_ITER; - - case CRYPTONIGHT_HEAVY: - return CRYPTONIGHT_HEAVY_ITER; - - case CRYPTONIGHT_PICO: - return CRYPTONIGHT_TRTL_ITER; - - default: - break; - } - - return 0; -} - - -template inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_0; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_1; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_GPU; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } -template<> inline constexpr Variant cn_base_variant() { return VARIANT_2; } - - -inline Variant cn_base_variant(Variant variant) -{ - switch (variant) { - case VARIANT_0: - case VARIANT_XHV: - case VARIANT_XAO: - return VARIANT_0; - - case VARIANT_1: - case VARIANT_TUBE: - case VARIANT_XTL: - case VARIANT_MSR: - case VARIANT_RTO: - return VARIANT_1; - - case VARIANT_GPU: - return VARIANT_GPU; - - default: - break; - } - - return VARIANT_2; -} - - -template inline constexpr bool cn_is_cryptonight_r() { return false; } -template<> inline constexpr bool cn_is_cryptonight_r() { return true; } -template<> inline constexpr bool cn_is_cryptonight_r() { return true; } - -} /* namespace xmrig */ - - -#endif /* XMRIG_CRYPTONIGHT_CONSTANTS_H */ diff --git a/src/crypto/cn/CryptoNight_monero.h b/src/crypto/cn/CryptoNight_monero.h index 94a18c45..dc012bdc 100644 --- a/src/crypto/cn/CryptoNight_monero.h +++ b/src/crypto/cn/CryptoNight_monero.h @@ -33,21 +33,21 @@ #ifndef XMRIG_ARM # define VARIANT1_INIT(part) \ uint64_t tweak1_2_##part = 0; \ - if (BASE == xmrig::VARIANT_1) { \ + if (BASE == Algorithm::CN_1) { \ tweak1_2_##part = (*reinterpret_cast(input + 35 + part * size) ^ \ *(reinterpret_cast(ctx[part]->state) + 24)); \ } #else # define VARIANT1_INIT(part) \ uint64_t tweak1_2_##part = 0; \ - if (BASE == xmrig::VARIANT_1) { \ + if (BASE == Algorithm::CN_1) { \ memcpy(&tweak1_2_##part, input + 35 + part * size, sizeof tweak1_2_##part); \ tweak1_2_##part ^= *(reinterpret_cast(ctx[part]->state) + 24); \ } #endif #define VARIANT1_1(p) \ - if (BASE == xmrig::VARIANT_1) { \ + if (BASE == Algorithm::CN_1) { \ const uint8_t tmp = reinterpret_cast(p)[11]; \ static const uint32_t table = 0x75310; \ const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \ @@ -55,20 +55,20 @@ } #define VARIANT1_2(p, part) \ - if (BASE == xmrig::VARIANT_1) { \ + if (BASE == Algorithm::CN_1) { \ (p) ^= tweak1_2_##part; \ } #ifndef XMRIG_ARM # define VARIANT2_INIT(part) \ - __m128i division_result_xmm_##part = _mm_cvtsi64_si128(h##part[12]); \ - __m128i sqrt_result_xmm_##part = _mm_cvtsi64_si128(h##part[13]); + __m128i division_result_xmm_##part = _mm_cvtsi64_si128(static_cast(h##part[12])); \ + __m128i sqrt_result_xmm_##part = _mm_cvtsi64_si128(static_cast(h##part[13])); #ifdef _MSC_VER -# define VARIANT2_SET_ROUNDING_MODE() if (BASE == xmrig::VARIANT_2) { _control87(RC_DOWN, MCW_RC); } +# define VARIANT2_SET_ROUNDING_MODE() if (BASE == Algorithm::CN_2) { _control87(RC_DOWN, MCW_RC); } #else -# define VARIANT2_SET_ROUNDING_MODE() if (BASE == xmrig::VARIANT_2) { fesetround(FE_DOWNWARD); } +# define VARIANT2_SET_ROUNDING_MODE() if (BASE == Algorithm::CN_2) { fesetround(FE_DOWNWARD); } #endif # define VARIANT2_INTEGER_MATH(part, cl, cx) \ @@ -91,7 +91,7 @@ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10)), _mm_add_epi64(chunk3, _b1)); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20)), _mm_add_epi64(chunk1, _b)); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30)), _mm_add_epi64(chunk2, _a)); \ - if (VARIANT == xmrig::VARIANT_4) { \ + if (ALGO == Algorithm::CN_R) { \ _c = _mm_xor_si128(_mm_xor_si128(_c, chunk3), _mm_xor_si128(chunk1, chunk2)); \ } \ } while (0) @@ -141,7 +141,7 @@ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b1))); \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b))); \ vst1q_u64((uint64_t*)((base_ptr) + ((offset) ^ 0x30)), vaddq_u64(chunk2, vreinterpretq_u64_u8(_a))); \ - if (VARIANT == xmrig::VARIANT_4) { \ + if (ALGO == Algorithm::CN_R) { \ _c = veorq_u64(veorq_u64(_c, chunk3), veorq_u64(chunk1, chunk2)); \ } \ } while (0) @@ -178,23 +178,22 @@ #endif #endif -#include "common/xmrig.h" #include "crypto/cn/r/variant4_random_math.h" #define VARIANT4_RANDOM_MATH_INIT(part) \ uint32_t r##part[9]; \ struct V4_Instruction code##part[256]; \ - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { \ - r##part[0] = (uint32_t)(h##part[12]); \ - r##part[1] = (uint32_t)(h##part[12] >> 32); \ - r##part[2] = (uint32_t)(h##part[13]); \ - r##part[3] = (uint32_t)(h##part[13] >> 32); \ + if (props.isR()) { \ + r##part[0] = static_cast(h##part[12]); \ + r##part[1] = static_cast(h##part[12] >> 32); \ + r##part[2] = static_cast(h##part[13]); \ + r##part[3] = static_cast(h##part[13] >> 32); \ } \ - v4_random_math_init(code##part, height); + v4_random_math_init(code##part, height); #define VARIANT4_RANDOM_MATH(part, al, ah, cl, bx0, bx1) \ - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { \ - cl ^= (r##part[0] + r##part[1]) | ((uint64_t)(r##part[2] + r##part[3]) << 32); \ + if (props.isR()) { \ + cl ^= (r##part[0] + r##part[1]) | (static_cast(r##part[2] + r##part[3]) << 32); \ r##part[4] = static_cast(al); \ r##part[5] = static_cast(ah); \ r##part[6] = static_cast(_mm_cvtsi128_si32(bx0)); \ diff --git a/src/crypto/cn/CryptoNight_test.h b/src/crypto/cn/CryptoNight_test.h index 2429fc17..77cbbb8e 100644 --- a/src/crypto/cn/CryptoNight_test.h +++ b/src/crypto/cn/CryptoNight_test.h @@ -156,21 +156,6 @@ const static uint8_t test_output_v2[160] = { }; -// "cn/xtl" Stellite (XTL) -const static uint8_t test_output_xtl[160] = { - 0x8F, 0xE5, 0xF0, 0x5F, 0x02, 0x2A, 0x61, 0x7D, 0xE5, 0x3F, 0x79, 0x36, 0x4B, 0x25, 0xCB, 0xC3, - 0xC0, 0x8E, 0x0E, 0x1F, 0xE3, 0xBE, 0x48, 0x57, 0x07, 0x03, 0xFE, 0xE1, 0xEC, 0x0E, 0xB0, 0xB1, - 0x21, 0x26, 0xFF, 0x98, 0xE6, 0x86, 0x08, 0x5B, 0xC9, 0x96, 0x44, 0xA3, 0xB8, 0x4E, 0x28, 0x90, - 0x76, 0xED, 0xAD, 0xB9, 0xAA, 0xAC, 0x01, 0x94, 0x1D, 0xBE, 0x3E, 0xEA, 0xAD, 0xEE, 0xB2, 0xCF, - 0xB0, 0x43, 0x4B, 0x88, 0xFC, 0xB2, 0xF3, 0x82, 0x9D, 0xD7, 0xDF, 0x51, 0x97, 0x2C, 0x5A, 0xE3, - 0xC7, 0x16, 0x0B, 0xC8, 0x7C, 0xB7, 0x2F, 0x1C, 0x55, 0x33, 0xCA, 0xE1, 0xEE, 0x08, 0xA4, 0x86, - 0x60, 0xED, 0x6E, 0x9D, 0x2D, 0x05, 0x0D, 0x7D, 0x02, 0x49, 0x23, 0x39, 0x7C, 0xC3, 0x6D, 0x3D, - 0x05, 0x51, 0x28, 0xF1, 0x9B, 0x3C, 0xDF, 0xC4, 0xEA, 0x8A, 0xA6, 0x6A, 0x3C, 0x8B, 0xE2, 0xAF, - 0x47, 0x00, 0xFC, 0x36, 0xED, 0x50, 0xBB, 0xD2, 0x2E, 0x63, 0x4B, 0x93, 0x11, 0x0C, 0xA7, 0xBA, - 0x32, 0x6E, 0x47, 0x4D, 0xCE, 0xCC, 0x82, 0x54, 0x1D, 0x06, 0xF8, 0x06, 0x86, 0xBD, 0x22, 0x48 -}; - - // "cn/half" const static uint8_t test_output_half[160] = { 0x5D, 0x4F, 0xBC, 0x35, 0x60, 0x97, 0xEA, 0x64, 0x40, 0xB0, 0x88, 0x8E, 0xDE, 0xB6, 0x35, 0xDD, diff --git a/src/crypto/cn/CryptoNight_x86.h b/src/crypto/cn/CryptoNight_x86.h index 8d6792d2..ae51cd18 100644 --- a/src/crypto/cn/CryptoNight_x86.h +++ b/src/crypto/cn/CryptoNight_x86.h @@ -35,12 +35,12 @@ #endif -#include "common/cpu/Cpu.h" -#include "common/crypto/keccak.h" -#include "crypto/cn/CryptoNight.h" -#include "crypto/cn/CryptoNight_constants.h" +#include "backend/cpu/Cpu.h" +#include "crypto/cn/CnAlgo.h" #include "crypto/cn/CryptoNight_monero.h" +#include "crypto/cn/CryptoNight.h" #include "crypto/cn/soft_aes.h" +#include "crypto/common/keccak.h" extern "C" @@ -303,9 +303,14 @@ inline void mix_and_propagate(__m128i& x0, __m128i& x1, __m128i& x2, __m128i& x3 } -template +namespace xmrig { + + +template static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) { + constexpr CnAlgo props; + __m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7; __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9; @@ -320,7 +325,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) xin6 = _mm_load_si128(input + 10); xin7 = _mm_load_si128(input + 11); - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (props.isHeavy()) { for (size_t i = 0; i < 16; i++) { aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); @@ -337,7 +342,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } } - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); @@ -361,37 +366,17 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } -#ifdef XMRIG_ALGO_CN_GPU -template -void cn_explode_scratchpad_gpu(const uint8_t *input, uint8_t *output) -{ - constexpr size_t hash_size = 200; // 25x8 bytes - alignas(16) uint64_t hash[25]; - - for (uint64_t i = 0; i < MEM / 512; i++) - { - memcpy(hash, input, hash_size); - hash[0] ^= i; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 160); - output += 160; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 176); - output += 176; - - xmrig::keccakf(hash, 24); - memcpy(output, hash, 176); - output += 176; - } -} -#endif - - -template +template static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) { + constexpr CnAlgo props; + +# ifdef XMRIG_ALGO_CN_GPU + constexpr bool IS_HEAVY = props.isHeavy() || ALGO == Algorithm::CN_GPU; +# else + constexpr bool IS_HEAVY = props.isHeavy(); +# endif + __m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7; __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9; @@ -406,8 +391,7 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) xout6 = _mm_load_si128(output + 10); xout7 = _mm_load_si128(output + 11); - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) - { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0); xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1); xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2); @@ -428,13 +412,13 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + if (IS_HEAVY) { mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7); } } - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { + if (IS_HEAVY) { + for (size_t i = 0; i < props.memory() / sizeof(__m128i); i += 8) { xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0); xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1); xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2); @@ -485,6 +469,9 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) } +} /* namespace xmrig */ + + static inline __m128i aes_round_tweak_div(const __m128i &in, const __m128i &key) { alignas(16) uint32_t k[4]; @@ -527,12 +514,21 @@ static inline __m128i int_sqrt_v2(const uint64_t n0) } -template -static inline void cryptonight_monero_tweak(uint64_t* mem_out, const uint8_t* l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i& cx) +void wow_soft_aes_compile_code(const V4_Instruction *code, int code_size, void *machine_code, xmrig::Assembly ASM); +void v4_soft_aes_compile_code(const V4_Instruction *code, int code_size, void *machine_code, xmrig::Assembly ASM); + + +namespace xmrig { + + +template +static inline void cryptonight_monero_tweak(uint64_t *mem_out, const uint8_t *l, uint64_t idx, __m128i ax0, __m128i bx0, __m128i bx1, __m128i& cx) { - if (BASE == xmrig::VARIANT_2) { - VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); - _mm_store_si128((__m128i *)mem_out, _mm_xor_si128(bx0, cx)); + constexpr CnAlgo props; + + if (props.base() == Algorithm::CN_2) { + VARIANT2_SHUFFLE(l, idx, ax0, bx0, bx1, cx, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); + _mm_store_si128(reinterpret_cast<__m128i *>(mem_out), _mm_xor_si128(bx0, cx)); } else { __m128i tmp = _mm_xor_si128(bx0, cx); mem_out[0] = _mm_cvtsi128_si64(tmp); @@ -542,107 +538,105 @@ static inline void cryptonight_monero_tweak(uint64_t* mem_out, const uint8_t* l, uint8_t x = static_cast(vh >> 24); static const uint16_t table = 0x7531; - const uint8_t index = (((x >> (VARIANT == xmrig::VARIANT_XTL ? 4 : 3)) & 6) | (x & 1)) << 1; + const uint8_t index = (((x >> (3)) & 6) | (x & 1)) << 1; vh ^= ((table >> index) & 0x3) << 28; mem_out[1] = vh; } } -void wow_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); -void v4_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); -template +template inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - static_assert(MASK > 0 && ITERATIONS > 0 && MEM > 0, "unsupported algorithm/variant"); +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; +# endif - if (BASE == xmrig::VARIANT_1 && size < 43) { + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 32); return; } - xmrig::keccak(input, size, ctx[0]->state); + keccak(input, size, ctx[0]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[0]->state), reinterpret_cast<__m128i *>(ctx[0]->memory)); - cn_explode_scratchpad((__m128i*) ctx[0]->state, (__m128i*) ctx[0]->memory); + uint64_t *h0 = reinterpret_cast(ctx[0]->state); + uint8_t *l0 = ctx[0]->memory; - uint64_t* h0 = reinterpret_cast(ctx[0]->state); - -#ifndef XMRIG_NO_ASM - if (SOFT_AES && xmrig::cn_is_cryptonight_r()) - { - if (!ctx[0]->generated_code_data.match(VARIANT, height)) { +# ifdef XMRIG_FEATURE_ASM + if (SOFT_AES && props.isR()) { + if (!ctx[0]->generated_code_data.match(ALGO, height)) { V4_Instruction code[256]; - const int code_size = v4_random_math_init(code, height); + const int code_size = v4_random_math_init(code, height); - if (VARIANT == xmrig::VARIANT_WOW) - wow_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), xmrig::ASM_NONE); - else if (VARIANT == xmrig::VARIANT_4) - v4_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), xmrig::ASM_NONE); + if (ALGO == Algorithm::CN_WOW) { + wow_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), Assembly::NONE); + } + else if (ALGO == Algorithm::CN_R) { + v4_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), Assembly::NONE); + } - ctx[0]->generated_code_data.variant = VARIANT; - ctx[0]->generated_code_data.height = height; + ctx[0]->generated_code_data = { ALGO, height }; } - ctx[0]->saes_table = (const uint32_t*)saes_table; + ctx[0]->saes_table = reinterpret_cast(saes_table); ctx[0]->generated_code(ctx); } else { -#endif - - const uint8_t* l0 = ctx[0]->memory; +# endif VARIANT1_INIT(0); VARIANT2_INIT(0); VARIANT2_SET_ROUNDING_MODE(); VARIANT4_RANDOM_MATH_INIT(0); - uint64_t al0 = h0[0] ^ h0[4]; - uint64_t ah0 = h0[1] ^ h0[5]; - __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); - __m128i bx1 = _mm_set_epi64x(h0[9] ^ h0[11], h0[8] ^ h0[10]); - + uint64_t al0 = h0[0] ^ h0[4]; + uint64_t ah0 = h0[1] ^ h0[5]; uint64_t idx0 = al0; + __m128i bx0 = _mm_set_epi64x(static_cast(h0[3] ^ h0[7]), static_cast(h0[2] ^ h0[6])); + __m128i bx1 = _mm_set_epi64x(static_cast(h0[9] ^ h0[11]), static_cast(h0[8] ^ h0[10])); - for (size_t i = 0; i < ITERATIONS; i++) { + for (size_t i = 0; i < props.iterations(); i++) { __m128i cx; - if (VARIANT == xmrig::VARIANT_TUBE || !SOFT_AES) { - cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); + if (IS_CN_HEAVY_TUBE || !SOFT_AES) { + cx = _mm_load_si128(reinterpret_cast(&l0[idx0 & MASK])); } - const __m128i ax0 = _mm_set_epi64x(ah0, al0); - if (VARIANT == xmrig::VARIANT_TUBE) { + const __m128i ax0 = _mm_set_epi64x(static_cast(ah0), static_cast(al0)); + if (IS_CN_HEAVY_TUBE) { cx = aes_round_tweak_div(cx, ax0); } else if (SOFT_AES) { - cx = soft_aesenc((uint32_t*)&l0[idx0 & MASK], ax0, (const uint32_t*)saes_table); + cx = soft_aesenc(&l0[idx0 & MASK], ax0, reinterpret_cast(saes_table)); } else { cx = _mm_aesenc_si128(cx, ax0); } - if (BASE == xmrig::VARIANT_1 || BASE == xmrig::VARIANT_2) { - cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx0, bx1, cx); + if (BASE == Algorithm::CN_1 || BASE == Algorithm::CN_2) { + cryptonight_monero_tweak(reinterpret_cast(&l0[idx0 & MASK]), l0, idx0 & MASK, ax0, bx0, bx1, cx); } else { - _mm_store_si128((__m128i *)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); + _mm_store_si128(reinterpret_cast<__m128i *>(&l0[idx0 & MASK]), _mm_xor_si128(bx0, cx)); } - idx0 = _mm_cvtsi128_si64(cx); + idx0 = static_cast(_mm_cvtsi128_si64(cx)); uint64_t hi, lo, cl, ch; - cl = ((uint64_t*) &l0[idx0 & MASK])[0]; - ch = ((uint64_t*) &l0[idx0 & MASK])[1]; + cl = (reinterpret_cast(&l0[idx0 & MASK]))[0]; + ch = (reinterpret_cast(&l0[idx0 & MASK]))[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx0, bx1); - if (VARIANT == xmrig::VARIANT_4) { - al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); - ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); + if (ALGO == Algorithm::CN_R) { + al0 ^= r0[2] | (static_cast(r0[3]) << 32); + ah0 ^= r0[0] | (static_cast(r0[1]) << 32); } } else { VARIANT2_INTEGER_MATH(0, cl, cx); @@ -651,63 +645,67 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx0, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx0, bx1, cx, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx0, bx1, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } al0 += hi; ah0 += lo; - ((uint64_t*)&l0[idx0 & MASK])[0] = al0; + reinterpret_cast(&l0[idx0 & MASK])[0] = al0; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { - ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (BASE == xmrig::VARIANT_1) { - ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { + reinterpret_cast(&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; + } else if (BASE == Algorithm::CN_1) { + reinterpret_cast(&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { - ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; + reinterpret_cast(&l0[idx0 & MASK])[1] = ah0; } al0 ^= cl; ah0 ^= ch; idx0 = al0; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { int64_t n = ((int64_t*)&l0[idx0 & MASK])[0]; int32_t d = ((int32_t*)&l0[idx0 & MASK])[2]; int64_t q = n / (d | 0x5); ((int64_t*)&l0[idx0 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { d = ~d; } idx0 = d ^ q; } +# endif - if (BASE == xmrig::VARIANT_2) { + if (BASE == Algorithm::CN_2) { bx1 = bx0; } bx0 = cx; } -#ifndef XMRIG_NO_ASM +# ifdef XMRIG_FEATURE_ASM } -#endif - - cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); +# endif - xmrig::keccakf(h0, 24); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i *>(ctx[0]->state)); + keccakf(h0, 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); } +} /* namespace xmrig */ + + #ifdef XMRIG_ALGO_CN_GPU template void cn_gpu_inner_avx(const uint8_t *spad, uint8_t *lpad); @@ -717,17 +715,41 @@ template void cn_gpu_inner_ssse3(const uint8_t *spad, uint8_t *lpad); -template -inline void cryptonight_single_hash_gpu(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) +namespace xmrig { + + +template +void cn_explode_scratchpad_gpu(const uint8_t *input, uint8_t *output) { - constexpr size_t MASK = xmrig::CRYPTONIGHT_GPU_MASK; - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr size_t hash_size = 200; // 25x8 bytes + alignas(16) uint64_t hash[25]; - static_assert(MASK > 0 && ITERATIONS > 0 && MEM > 0, "unsupported algorithm/variant"); + for (uint64_t i = 0; i < MEM / 512; i++) { + memcpy(hash, input, hash_size); + hash[0] ^= i; - xmrig::keccak(input, size, ctx[0]->state); - cn_explode_scratchpad_gpu(ctx[0]->state, ctx[0]->memory); + xmrig::keccakf(hash, 24); + memcpy(output, hash, 160); + output += 160; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + + xmrig::keccakf(hash, 24); + memcpy(output, hash, 176); + output += 176; + } +} + + +template +inline void cryptonight_single_hash_gpu(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t) +{ + constexpr CnAlgo props; + + keccak(input, size, ctx[0]->state); + cn_explode_scratchpad_gpu(ctx[0]->state, ctx[0]->memory); # ifdef _MSC_VER _control87(RC_NEAR, MCW_RC); @@ -736,20 +758,22 @@ inline void cryptonight_single_hash_gpu(const uint8_t *__restrict__ input, size_ # endif if (xmrig::Cpu::info()->hasAVX2()) { - cn_gpu_inner_avx(ctx[0]->state, ctx[0]->memory); + cn_gpu_inner_avx(ctx[0]->state, ctx[0]->memory); } else { - cn_gpu_inner_ssse3(ctx[0]->state, ctx[0]->memory); + cn_gpu_inner_ssse3(ctx[0]->state, ctx[0]->memory); } - cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); - - xmrig::keccakf((uint64_t*) ctx[0]->state, 24); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i *>(ctx[0]->state)); + keccakf(reinterpret_cast(ctx[0]->state), 24); memcpy(output, ctx[0]->state, 32); } + + +} /* namespace xmrig */ #endif -#ifndef XMRIG_NO_ASM +#ifdef XMRIG_FEATURE_ASM extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx **ctx); extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx **ctx); extern "C" void cnv2_mainloop_bulldozer_asm(cryptonight_ctx **ctx); @@ -757,212 +781,246 @@ extern "C" void cnv2_double_mainloop_sandybridge_asm(cryptonight_ctx **ctx); extern "C" void cnv2_rwz_mainloop_asm(cryptonight_ctx **ctx); extern "C" void cnv2_rwz_double_mainloop_asm(cryptonight_ctx **ctx); -extern xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ivybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ryzen_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_bulldozer_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_half_double_mainloop_sandybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ivybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ryzen_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_trtl_double_mainloop_sandybridge_asm; +namespace xmrig { -extern xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ivybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ryzen_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_bulldozer_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_zls_double_mainloop_sandybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ivybridge_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ryzen_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_bulldozer_asm; -extern xmrig::CpuThread::cn_mainloop_fun cn_double_double_mainloop_sandybridge_asm; +typedef void (*cn_mainloop_fun)(cryptonight_ctx **ctx); + + +extern cn_mainloop_fun cn_half_mainloop_ivybridge_asm; +extern cn_mainloop_fun cn_half_mainloop_ryzen_asm; +extern cn_mainloop_fun cn_half_mainloop_bulldozer_asm; +extern cn_mainloop_fun cn_half_double_mainloop_sandybridge_asm; + +extern cn_mainloop_fun cn_trtl_mainloop_ivybridge_asm; +extern cn_mainloop_fun cn_trtl_mainloop_ryzen_asm; +extern cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm; +extern cn_mainloop_fun cn_trtl_double_mainloop_sandybridge_asm; + +extern cn_mainloop_fun cn_zls_mainloop_ivybridge_asm; +extern cn_mainloop_fun cn_zls_mainloop_ryzen_asm; +extern cn_mainloop_fun cn_zls_mainloop_bulldozer_asm; +extern cn_mainloop_fun cn_zls_double_mainloop_sandybridge_asm; + +extern cn_mainloop_fun cn_double_mainloop_ivybridge_asm; +extern cn_mainloop_fun cn_double_mainloop_ryzen_asm; +extern cn_mainloop_fun cn_double_mainloop_bulldozer_asm; +extern cn_mainloop_fun cn_double_double_mainloop_sandybridge_asm; + + +} // namespace xmrig + void wow_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); void v4_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); void wow_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); void v4_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); -template + +template void cn_r_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) { v4_compile_code(code, code_size, machine_code, ASM); } -template + +template void cn_r_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) { v4_compile_code_double(code, code_size, machine_code, ASM); } + template<> -void cn_r_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +void cn_r_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) { wow_compile_code(code, code_size, machine_code, ASM); } + template<> -void cn_r_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) +void cn_r_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) { wow_compile_code_double(code, code_size, machine_code, ASM); } -template + +namespace xmrig { + + +template inline void cryptonight_single_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr CnAlgo props; - if (xmrig::cn_is_cryptonight_r() && !ctx[0]->generated_code_data.match(VARIANT, height)) { + if (props.isR() && !ctx[0]->generated_code_data.match(ALGO, height)) { V4_Instruction code[256]; - const int code_size = v4_random_math_init(code, height); - cn_r_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM); - ctx[0]->generated_code_data.variant = VARIANT; - ctx[0]->generated_code_data.height = height; + const int code_size = v4_random_math_init(code, height); + cn_r_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM); + + ctx[0]->generated_code_data = { ALGO, height }; } - xmrig::keccak(input, size, ctx[0]->state); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); + keccak(input, size, ctx[0]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); - if (VARIANT == xmrig::VARIANT_2) { - if (ASM == xmrig::ASM_INTEL) { + if (ALGO == Algorithm::CN_2) { + if (ASM == Assembly::INTEL) { cnv2_mainloop_ivybridge_asm(ctx); } - else if (ASM == xmrig::ASM_RYZEN) { + else if (ASM == Assembly::RYZEN) { cnv2_mainloop_ryzen_asm(ctx); } else { cnv2_mainloop_bulldozer_asm(ctx); } } - else if (VARIANT == xmrig::VARIANT_HALF) { - if (ASM == xmrig::ASM_INTEL) { + else if (ALGO == Algorithm::CN_HALF) { + if (ASM == Assembly::INTEL) { cn_half_mainloop_ivybridge_asm(ctx); } - else if (ASM == xmrig::ASM_RYZEN) { + else if (ASM == Assembly::RYZEN) { cn_half_mainloop_ryzen_asm(ctx); } else { cn_half_mainloop_bulldozer_asm(ctx); } } - else if (VARIANT == xmrig::VARIANT_TRTL) { - if (ASM == xmrig::ASM_INTEL) { +# ifdef XMRIG_ALGO_CN_PICO + else if (ALGO == Algorithm::CN_PICO_0) { + if (ASM == Assembly::INTEL) { cn_trtl_mainloop_ivybridge_asm(ctx); } - else if (ASM == xmrig::ASM_RYZEN) { + else if (ASM == Assembly::RYZEN) { cn_trtl_mainloop_ryzen_asm(ctx); } else { cn_trtl_mainloop_bulldozer_asm(ctx); } } - else if (VARIANT == xmrig::VARIANT_RWZ) { +# endif + else if (ALGO == Algorithm::CN_RWZ) { cnv2_rwz_mainloop_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_ZLS) { - if (ASM == xmrig::ASM_INTEL) { + else if (ALGO == Algorithm::CN_ZLS) { + if (ASM == Assembly::INTEL) { cn_zls_mainloop_ivybridge_asm(ctx); } - else if (ASM == xmrig::ASM_RYZEN) { + else if (ASM == Assembly::RYZEN) { cn_zls_mainloop_ryzen_asm(ctx); } else { cn_zls_mainloop_bulldozer_asm(ctx); } } - else if (VARIANT == xmrig::VARIANT_DOUBLE) { - if (ASM == xmrig::ASM_INTEL) { + else if (ALGO == Algorithm::CN_DOUBLE) { + if (ASM == Assembly::INTEL) { cn_double_mainloop_ivybridge_asm(ctx); } - else if (ASM == xmrig::ASM_RYZEN) { + else if (ASM == Assembly::RYZEN) { cn_double_mainloop_ryzen_asm(ctx); } else { cn_double_mainloop_bulldozer_asm(ctx); } } - else if (xmrig::cn_is_cryptonight_r()) { + else if (props.isR()) { ctx[0]->generated_code(ctx); } - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); - xmrig::keccakf(reinterpret_cast(ctx[0]->state), 24); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); + keccakf(reinterpret_cast(ctx[0]->state), 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); } -template +template inline void cryptonight_double_hash_asm(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MEM = xmrig::cn_select_memory(); + constexpr CnAlgo props; - if (xmrig::cn_is_cryptonight_r() && !ctx[0]->generated_code_data.match(VARIANT, height)) { + if (props.isR() && !ctx[0]->generated_code_data.match(ALGO, height)) { V4_Instruction code[256]; - const int code_size = v4_random_math_init(code, height); - cn_r_compile_code_double(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM); - ctx[0]->generated_code_data.variant = VARIANT; - ctx[0]->generated_code_data.height = height; + const int code_size = v4_random_math_init(code, height); + cn_r_compile_code_double(code, code_size, reinterpret_cast(ctx[0]->generated_code), ASM); + + ctx[0]->generated_code_data = { ALGO, height }; } - xmrig::keccak(input, size, ctx[0]->state); - xmrig::keccak(input + size, size, ctx[1]->state); + keccak(input, size, ctx[0]->state); + keccak(input + size, size, ctx[1]->state); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[1]->state), reinterpret_cast<__m128i*>(ctx[1]->memory)); + cn_explode_scratchpad(reinterpret_cast(ctx[0]->state), reinterpret_cast<__m128i*>(ctx[0]->memory)); + cn_explode_scratchpad(reinterpret_cast(ctx[1]->state), reinterpret_cast<__m128i*>(ctx[1]->memory)); - if (VARIANT == xmrig::VARIANT_2) { + if (ALGO == Algorithm::CN_2) { cnv2_double_mainloop_sandybridge_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_HALF) { + else if (ALGO == Algorithm::CN_HALF) { cn_half_double_mainloop_sandybridge_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_TRTL) { +# ifdef XMRIG_ALGO_CN_PICO + else if (ALGO == Algorithm::CN_PICO_0) { cn_trtl_double_mainloop_sandybridge_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_RWZ) { +# endif + else if (ALGO == Algorithm::CN_RWZ) { cnv2_rwz_double_mainloop_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_ZLS) { + else if (ALGO == Algorithm::CN_ZLS) { cn_zls_double_mainloop_sandybridge_asm(ctx); } - else if (VARIANT == xmrig::VARIANT_DOUBLE) { + else if (ALGO == Algorithm::CN_DOUBLE) { cn_double_double_mainloop_sandybridge_asm(ctx); } - else if (xmrig::cn_is_cryptonight_r()) { + else if (props.isR()) { ctx[0]->generated_code(ctx); } - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[1]->memory), reinterpret_cast<__m128i*>(ctx[1]->state)); + cn_implode_scratchpad(reinterpret_cast(ctx[0]->memory), reinterpret_cast<__m128i*>(ctx[0]->state)); + cn_implode_scratchpad(reinterpret_cast(ctx[1]->memory), reinterpret_cast<__m128i*>(ctx[1]->state)); - xmrig::keccakf(reinterpret_cast(ctx[0]->state), 24); - xmrig::keccakf(reinterpret_cast(ctx[1]->state), 24); + keccakf(reinterpret_cast(ctx[0]->state), 24); + keccakf(reinterpret_cast(ctx[1]->state), 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); extra_hashes[ctx[1]->state[0] & 3](ctx[1]->state, 200, output + 32); } + + +} /* namespace xmrig */ #endif -template +namespace xmrig { + + +template inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 64); return; } - xmrig::keccak(input, size, ctx[0]->state); - xmrig::keccak(input + size, size, ctx[1]->state); + keccak(input, size, ctx[0]->state); + keccak(input + size, size, ctx[1]->state); - const uint8_t* l0 = ctx[0]->memory; - const uint8_t* l1 = ctx[1]->memory; - uint64_t* h0 = reinterpret_cast(ctx[0]->state); - uint64_t* h1 = reinterpret_cast(ctx[1]->state); + uint8_t *l0 = ctx[0]->memory; + uint8_t *l1 = ctx[1]->memory; + uint64_t *h0 = reinterpret_cast(ctx[0]->state); + uint64_t *h1 = reinterpret_cast(ctx[1]->state); VARIANT1_INIT(0); VARIANT1_INIT(1); @@ -972,8 +1030,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si VARIANT4_RANDOM_MATH_INIT(0); VARIANT4_RANDOM_MATH_INIT(1); - cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0); - cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1); + cn_explode_scratchpad(reinterpret_cast(h0), reinterpret_cast<__m128i *>(l0)); + cn_explode_scratchpad(reinterpret_cast(h1), reinterpret_cast<__m128i *>(l1)); uint64_t al0 = h0[0] ^ h0[4]; uint64_t al1 = h1[0] ^ h1[4]; @@ -988,31 +1046,31 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si uint64_t idx0 = al0; uint64_t idx1 = al1; - for (size_t i = 0; i < ITERATIONS; i++) { + for (size_t i = 0; i < props.iterations(); i++) { __m128i cx0, cx1; - if (VARIANT == xmrig::VARIANT_TUBE || !SOFT_AES) { - cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); - cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]); + if (IS_CN_HEAVY_TUBE || !SOFT_AES) { + cx0 = _mm_load_si128(reinterpret_cast(&l0[idx0 & MASK])); + cx1 = _mm_load_si128(reinterpret_cast(&l1[idx1 & MASK])); } const __m128i ax0 = _mm_set_epi64x(ah0, al0); const __m128i ax1 = _mm_set_epi64x(ah1, al1); - if (VARIANT == xmrig::VARIANT_TUBE) { + if (IS_CN_HEAVY_TUBE) { cx0 = aes_round_tweak_div(cx0, ax0); cx1 = aes_round_tweak_div(cx1, ax1); } else if (SOFT_AES) { - cx0 = soft_aesenc((uint32_t*)&l0[idx0 & MASK], ax0, (const uint32_t*)saes_table); - cx1 = soft_aesenc((uint32_t*)&l1[idx1 & MASK], ax1, (const uint32_t*)saes_table); + cx0 = soft_aesenc(&l0[idx0 & MASK], ax0, reinterpret_cast(saes_table)); + cx1 = soft_aesenc(&l1[idx1 & MASK], ax1, reinterpret_cast(saes_table)); } else { cx0 = _mm_aesenc_si128(cx0, ax0); cx1 = _mm_aesenc_si128(cx1, ax1); } - if (BASE == xmrig::VARIANT_1 || (BASE == xmrig::VARIANT_2)) { - cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx00, bx01, cx0); - cryptonight_monero_tweak((uint64_t*)&l1[idx1 & MASK], l1, idx1 & MASK, ax1, bx10, bx11, cx1); + if (BASE == Algorithm::CN_1 || BASE == Algorithm::CN_2) { + cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], l0, idx0 & MASK, ax0, bx00, bx01, cx0); + cryptonight_monero_tweak((uint64_t*)&l1[idx1 & MASK], l1, idx1 & MASK, ax1, bx10, bx11, cx1); } else { _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx00, cx0)); _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx10, cx1)); @@ -1025,10 +1083,10 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cl = ((uint64_t*) &l0[idx0 & MASK])[0]; ch = ((uint64_t*) &l0[idx0 & MASK])[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(0, al0, ah0, cl, bx00, bx01); - if (VARIANT == xmrig::VARIANT_4) { + if (ALGO == Algorithm::CN_R) { al0 ^= r0[2] | ((uint64_t)(r0[3]) << 32); ah0 ^= r0[0] | ((uint64_t)(r0[1]) << 32); } @@ -1039,11 +1097,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx0, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l0, idx0 & MASK, ax0, bx00, bx01, cx0, 0); } else { - VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l0, idx0 & MASK, ax0, bx00, bx01, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } @@ -1052,9 +1110,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l0[idx0 & MASK])[0] = al0; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { ((uint64_t*) &l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; - } else if (BASE == xmrig::VARIANT_1) { + } else if (BASE == Algorithm::CN_1) { ((uint64_t*) &l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; } else { ((uint64_t*) &l0[idx0 & MASK])[1] = ah0; @@ -1064,27 +1122,29 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ah0 ^= ch; idx0 = al0; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { int64_t n = ((int64_t*)&l0[idx0 & MASK])[0]; int32_t d = ((int32_t*)&l0[idx0 & MASK])[2]; int64_t q = n / (d | 0x5); ((int64_t*)&l0[idx0 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { d = ~d; } idx0 = d ^ q; } +# endif cl = ((uint64_t*) &l1[idx1 & MASK])[0]; ch = ((uint64_t*) &l1[idx1 & MASK])[1]; - if (BASE == xmrig::VARIANT_2) { - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { + if (BASE == Algorithm::CN_2) { + if (props.isR()) { VARIANT4_RANDOM_MATH(1, al1, ah1, cl, bx10, bx11); - if (VARIANT == xmrig::VARIANT_4) { + if (ALGO == Algorithm::CN_R) { al1 ^= r1[2] | ((uint64_t)(r1[3]) << 32); ah1 ^= r1[0] | ((uint64_t)(r1[1]) << 32); } @@ -1095,11 +1155,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si lo = __umul128(idx1, cl, &hi); - if (BASE == xmrig::VARIANT_2) { - if (VARIANT == xmrig::VARIANT_4) { + if (BASE == Algorithm::CN_2) { + if (ALGO == Algorithm::CN_R) { VARIANT2_SHUFFLE(l1, idx1 & MASK, ax1, bx10, bx11, cx1, 0); } else { - VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); + VARIANT2_SHUFFLE2(l1, idx1 & MASK, ax1, bx10, bx11, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); } } @@ -1108,9 +1168,9 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ((uint64_t*)&l1[idx1 & MASK])[0] = al1; - if (BASE == xmrig::VARIANT_1 && (VARIANT == xmrig::VARIANT_TUBE || VARIANT == xmrig::VARIANT_RTO)) { + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1 ^ al1; - } else if (BASE == xmrig::VARIANT_1) { + } else if (BASE == Algorithm::CN_1) { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1; } else { ((uint64_t*)&l1[idx1 & MASK])[1] = ah1; @@ -1120,21 +1180,23 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ah1 ^= ch; idx1 = al1; - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { +# ifdef XMRIG_ALGO_CN_HEAVY + if (props.isHeavy()) { int64_t n = ((int64_t*)&l1[idx1 & MASK])[0]; int32_t d = ((int32_t*)&l1[idx1 & MASK])[2]; int64_t q = n / (d | 0x5); ((int64_t*)&l1[idx1 & MASK])[0] = n ^ q; - if (VARIANT == xmrig::VARIANT_XHV) { + if (ALGO == Algorithm::CN_HEAVY_XHV) { d = ~d; } idx1 = d ^ q; } +# endif - if (BASE == xmrig::VARIANT_2) { + if (BASE == Algorithm::CN_2) { bx01 = bx00; bx11 = bx10; } @@ -1143,11 +1205,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si bx10 = cx1; } - cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0); - cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1); + cn_implode_scratchpad(reinterpret_cast(l0), reinterpret_cast<__m128i *>(h0)); + cn_implode_scratchpad(reinterpret_cast(l1), reinterpret_cast<__m128i *>(h1)); - xmrig::keccakf(h0, 24); - xmrig::keccakf(h1, 24); + keccakf(h0, 24); + keccakf(h1, 24); extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); extra_hashes[ctx[1]->state[0] & 3](ctx[1]->state, 200, output + 32); @@ -1159,20 +1221,20 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si c = _mm_load_si128(ptr); -#define CN_STEP2(a, b0, b1, c, l, ptr, idx) \ - if (VARIANT == xmrig::VARIANT_TUBE) { \ - c = aes_round_tweak_div(c, a); \ - } \ - else if (SOFT_AES) { \ - c = soft_aesenc(&c, a, (const uint32_t*)saes_table); \ - } else { \ - c = _mm_aesenc_si128(c, a); \ - } \ - \ - if (BASE == xmrig::VARIANT_1 || BASE == xmrig::VARIANT_2) { \ - cryptonight_monero_tweak((uint64_t*)ptr, l, idx & MASK, a, b0, b1, c); \ - } else { \ - _mm_store_si128(ptr, _mm_xor_si128(b0, c)); \ +#define CN_STEP2(a, b0, b1, c, l, ptr, idx) \ + if (IS_CN_HEAVY_TUBE) { \ + c = aes_round_tweak_div(c, a); \ + } \ + else if (SOFT_AES) { \ + c = soft_aesenc(&c, a, (const uint32_t*)saes_table); \ + } else { \ + c = _mm_aesenc_si128(c, a); \ + } \ + \ + if (BASE == Algorithm::CN_1 || BASE == Algorithm::CN_2) { \ + cryptonight_monero_tweak((uint64_t*)ptr, l, idx & MASK, a, b0, b1, c); \ + } else { \ + _mm_store_si128(ptr, _mm_xor_si128(b0, c)); \ } @@ -1183,62 +1245,60 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si uint64_t ch##part = ((uint64_t*)ptr)[1]; -#define CN_STEP4(part, a, b0, b1, c, l, mc, ptr, idx) \ - uint64_t al##part, ah##part; \ - if (BASE == xmrig::VARIANT_2) { \ - if ((VARIANT == xmrig::VARIANT_WOW) || (VARIANT == xmrig::VARIANT_4)) { \ - al##part = _mm_cvtsi128_si64(a); \ - ah##part = _mm_cvtsi128_si64(_mm_srli_si128(a, 8)); \ - VARIANT4_RANDOM_MATH(part, al##part, ah##part, cl##part, b0, b1); \ - if (VARIANT == xmrig::VARIANT_4) { \ - al##part ^= r##part[2] | ((uint64_t)(r##part[3]) << 32); \ - ah##part ^= r##part[0] | ((uint64_t)(r##part[1]) << 32); \ - } \ - } else { \ - VARIANT2_INTEGER_MATH(part, cl##part, c); \ - } \ - } \ - lo = __umul128(idx, cl##part, &hi); \ - if (BASE == xmrig::VARIANT_2) { \ - if (VARIANT == xmrig::VARIANT_4) { \ - VARIANT2_SHUFFLE(l, idx & MASK, a, b0, b1, c, 0); \ - } else { \ - VARIANT2_SHUFFLE2(l, idx & MASK, a, b0, b1, hi, lo, (VARIANT == xmrig::VARIANT_RWZ ? 1 : 0)); \ - } \ - } \ - if (VARIANT == xmrig::VARIANT_4) { \ - a = _mm_set_epi64x(ah##part, al##part); \ - } \ - a = _mm_add_epi64(a, _mm_set_epi64x(lo, hi)); \ - \ - if (BASE == xmrig::VARIANT_1) { \ - _mm_store_si128(ptr, _mm_xor_si128(a, mc)); \ - \ - if (VARIANT == xmrig::VARIANT_TUBE || \ - VARIANT == xmrig::VARIANT_RTO) { \ - ((uint64_t*)ptr)[1] ^= ((uint64_t*)ptr)[0]; \ - } \ - } else { \ - _mm_store_si128(ptr, a); \ - } \ - \ - a = _mm_xor_si128(a, _mm_set_epi64x(ch##part, cl##part)); \ - idx = _mm_cvtsi128_si64(a); \ - \ - if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { \ - int64_t n = ((int64_t*)&l[idx & MASK])[0]; \ - int32_t d = ((int32_t*)&l[idx & MASK])[2]; \ - int64_t q = n / (d | 0x5); \ - ((int64_t*)&l[idx & MASK])[0] = n ^ q; \ - if (VARIANT == xmrig::VARIANT_XHV) { \ - d = ~d; \ - } \ - \ - idx = d ^ q; \ - } \ - if (BASE == xmrig::VARIANT_2) { \ - b1 = b0; \ - } \ +#define CN_STEP4(part, a, b0, b1, c, l, mc, ptr, idx) \ + uint64_t al##part, ah##part; \ + if (BASE == Algorithm::CN_2) { \ + if (props.isR()) { \ + al##part = _mm_cvtsi128_si64(a); \ + ah##part = _mm_cvtsi128_si64(_mm_srli_si128(a, 8)); \ + VARIANT4_RANDOM_MATH(part, al##part, ah##part, cl##part, b0, b1); \ + if (ALGO == Algorithm::CN_R) { \ + al##part ^= r##part[2] | ((uint64_t)(r##part[3]) << 32); \ + ah##part ^= r##part[0] | ((uint64_t)(r##part[1]) << 32); \ + } \ + } else { \ + VARIANT2_INTEGER_MATH(part, cl##part, c); \ + } \ + } \ + lo = __umul128(idx, cl##part, &hi); \ + if (BASE == Algorithm::CN_2) { \ + if (ALGO == Algorithm::CN_R) { \ + VARIANT2_SHUFFLE(l, idx & MASK, a, b0, b1, c, 0); \ + } else { \ + VARIANT2_SHUFFLE2(l, idx & MASK, a, b0, b1, hi, lo, (ALGO == Algorithm::CN_RWZ ? 1 : 0)); \ + } \ + } \ + if (ALGO == Algorithm::CN_R) { \ + a = _mm_set_epi64x(ah##part, al##part); \ + } \ + a = _mm_add_epi64(a, _mm_set_epi64x(lo, hi)); \ + \ + if (BASE == Algorithm::CN_1) { \ + _mm_store_si128(ptr, _mm_xor_si128(a, mc)); \ + \ + if (IS_CN_HEAVY_TUBE || ALGO == Algorithm::CN_RTO) { \ + ((uint64_t*)ptr)[1] ^= ((uint64_t*)ptr)[0]; \ + } \ + } else { \ + _mm_store_si128(ptr, a); \ + } \ + \ + a = _mm_xor_si128(a, _mm_set_epi64x(ch##part, cl##part)); \ + idx = _mm_cvtsi128_si64(a); \ + if (props.isHeavy()) { \ + int64_t n = ((int64_t*)&l[idx & MASK])[0]; \ + int32_t d = ((int32_t*)&l[idx & MASK])[2]; \ + int64_t q = n / (d | 0x5); \ + ((int64_t*)&l[idx & MASK])[0] = n ^ q; \ + if (IS_CN_HEAVY_XHV) { \ + d = ~d; \ + } \ + \ + idx = d ^ q; \ + } \ + if (BASE == Algorithm::CN_2) { \ + b1 = b0; \ + } \ b0 = c; @@ -1246,11 +1306,11 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si __m128i mc##n; \ __m128i division_result_xmm_##n; \ __m128i sqrt_result_xmm_##n; \ - if (BASE == xmrig::VARIANT_1) { \ + if (BASE == Algorithm::CN_1) { \ mc##n = _mm_set_epi64x(*reinterpret_cast(input + n * size + 35) ^ \ *(reinterpret_cast((ctx)->state) + 24), 0); \ } \ - if (BASE == xmrig::VARIANT_2) { \ + if (BASE == Algorithm::CN_2) { \ division_result_xmm_##n = _mm_cvtsi64_si128(h##n[12]); \ sqrt_result_xmm_##n = _mm_cvtsi64_si128(h##n[13]); \ } \ @@ -1261,22 +1321,29 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si VARIANT4_RANDOM_MATH_INIT(n); -template +template inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; + constexpr bool IS_CN_HEAVY_XHV = ALGO == Algorithm::CN_HEAVY_XHV; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; + constexpr bool IS_CN_HEAVY_XHV = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 32 * 3); return; } for (size_t i = 0; i < 3; i++) { - xmrig::keccak(input + size * i, size, ctx[i]->state); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); + keccak(input + size * i, size, ctx[i]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); } uint8_t* l0 = ctx[0]->memory; @@ -1296,7 +1363,7 @@ inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t si idx1 = _mm_cvtsi128_si64(ax1); idx2 = _mm_cvtsi128_si64(ax2); - for (size_t i = 0; i < ITERATIONS; i++) { + for (size_t i = 0; i < props.iterations(); i++) { uint64_t hi, lo; __m128i *ptr0, *ptr1, *ptr2; @@ -1318,29 +1385,36 @@ inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t si } for (size_t i = 0; i < 3; i++) { - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); - xmrig::keccakf(reinterpret_cast(ctx[i]->state), 24); + cn_implode_scratchpad(reinterpret_cast(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); + keccakf(reinterpret_cast(ctx[i]->state), 24); extra_hashes[ctx[i]->state[0] & 3](ctx[i]->state, 200, output + 32 * i); } } -template +template inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; + constexpr bool IS_CN_HEAVY_XHV = ALGO == Algorithm::CN_HEAVY_XHV; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; + constexpr bool IS_CN_HEAVY_XHV = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 32 * 4); return; } for (size_t i = 0; i < 4; i++) { - xmrig::keccak(input + size * i, size, ctx[i]->state); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); + keccak(input + size * i, size, ctx[i]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); } uint8_t* l0 = ctx[0]->memory; @@ -1364,8 +1438,7 @@ inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size idx2 = _mm_cvtsi128_si64(ax2); idx3 = _mm_cvtsi128_si64(ax3); - for (size_t i = 0; i < ITERATIONS; i++) - { + for (size_t i = 0; i < props.iterations(); i++) { uint64_t hi, lo; __m128i *ptr0, *ptr1, *ptr2, *ptr3; @@ -1391,29 +1464,36 @@ inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size } for (size_t i = 0; i < 4; i++) { - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); - xmrig::keccakf(reinterpret_cast(ctx[i]->state), 24); + cn_implode_scratchpad(reinterpret_cast(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); + keccakf(reinterpret_cast(ctx[i]->state), 24); extra_hashes[ctx[i]->state[0] & 3](ctx[i]->state, 200, output + 32 * i); } } -template +template inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t height) { - constexpr size_t MASK = xmrig::cn_select_mask(); - constexpr size_t ITERATIONS = xmrig::cn_select_iter(); - constexpr size_t MEM = xmrig::cn_select_memory(); - constexpr xmrig::Variant BASE = xmrig::cn_base_variant(); + constexpr CnAlgo props; + constexpr size_t MASK = props.mask(); + constexpr Algorithm::Id BASE = props.base(); - if (BASE == xmrig::VARIANT_1 && size < 43) { +# ifdef XMRIG_ALGO_CN_HEAVY + constexpr bool IS_CN_HEAVY_TUBE = ALGO == Algorithm::CN_HEAVY_TUBE; + constexpr bool IS_CN_HEAVY_XHV = ALGO == Algorithm::CN_HEAVY_XHV; +# else + constexpr bool IS_CN_HEAVY_TUBE = false; + constexpr bool IS_CN_HEAVY_XHV = false; +# endif + + if (BASE == Algorithm::CN_1 && size < 43) { memset(output, 0, 32 * 5); return; } for (size_t i = 0; i < 5; i++) { - xmrig::keccak(input + size * i, size, ctx[i]->state); - cn_explode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); + keccak(input + size * i, size, ctx[i]->state); + cn_explode_scratchpad(reinterpret_cast(ctx[i]->state), reinterpret_cast<__m128i*>(ctx[i]->memory)); } uint8_t* l0 = ctx[0]->memory; @@ -1441,8 +1521,7 @@ inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t siz idx3 = _mm_cvtsi128_si64(ax3); idx4 = _mm_cvtsi128_si64(ax4); - for (size_t i = 0; i < ITERATIONS; i++) - { + for (size_t i = 0; i < props.iterations(); i++) { uint64_t hi, lo; __m128i *ptr0, *ptr1, *ptr2, *ptr3, *ptr4; @@ -1472,10 +1551,14 @@ inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t siz } for (size_t i = 0; i < 5; i++) { - cn_implode_scratchpad(reinterpret_cast<__m128i*>(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); - xmrig::keccakf(reinterpret_cast(ctx[i]->state), 24); + cn_implode_scratchpad(reinterpret_cast(ctx[i]->memory), reinterpret_cast<__m128i*>(ctx[i]->state)); + keccakf(reinterpret_cast(ctx[i]->state), 24); extra_hashes[ctx[i]->state[0] & 3](ctx[i]->state, 200, output + 32 * i); } } + +} /* namespace xmrig */ + + #endif /* XMRIG_CRYPTONIGHT_X86_H */ diff --git a/src/crypto/cn/gpu/cn_gpu_arm.cpp b/src/crypto/cn/gpu/cn_gpu_arm.cpp index a1df0cc7..520d3fc8 100644 --- a/src/crypto/cn/gpu/cn_gpu_arm.cpp +++ b/src/crypto/cn/gpu/cn_gpu_arm.cpp @@ -26,7 +26,7 @@ #include -#include "crypto/cn/CryptoNight_constants.h" +#include "crypto/cn/CnAlgo.h" inline void vandq_f32(float32x4_t &v, uint32_t v2) @@ -237,4 +237,4 @@ void cn_gpu_inner_arm(const uint8_t *spad, uint8_t *lpad) } } -template void cn_gpu_inner_arm(const uint8_t* spad, uint8_t* lpad); +template void cn_gpu_inner_arm().iterations(), xmrig::CnAlgo().mask()>(const uint8_t* spad, uint8_t* lpad); diff --git a/src/crypto/cn/gpu/cn_gpu_avx.cpp b/src/crypto/cn/gpu/cn_gpu_avx.cpp index 382be570..38da9714 100644 --- a/src/crypto/cn/gpu/cn_gpu_avx.cpp +++ b/src/crypto/cn/gpu/cn_gpu_avx.cpp @@ -22,7 +22,9 @@ * along with this program. If not, see . */ -#include "crypto/cn/CryptoNight_constants.h" + +#include "crypto/cn/CnAlgo.h" + #ifdef __GNUC__ # include @@ -206,4 +208,4 @@ void cn_gpu_inner_avx(const uint8_t* spad, uint8_t* lpad) } } -template void cn_gpu_inner_avx(const uint8_t* spad, uint8_t* lpad); +template void cn_gpu_inner_avx().iterations(), xmrig::CnAlgo().mask()>(const uint8_t* spad, uint8_t* lpad); diff --git a/src/crypto/cn/gpu/cn_gpu_ssse3.cpp b/src/crypto/cn/gpu/cn_gpu_ssse3.cpp index 42a11a1d..7cca096e 100644 --- a/src/crypto/cn/gpu/cn_gpu_ssse3.cpp +++ b/src/crypto/cn/gpu/cn_gpu_ssse3.cpp @@ -22,7 +22,9 @@ * along with this program. If not, see . */ -#include "crypto/cn/CryptoNight_constants.h" + +#include "crypto/cn/CnAlgo.h" + #ifdef __GNUC__ # include @@ -207,4 +209,4 @@ void cn_gpu_inner_ssse3(const uint8_t* spad, uint8_t* lpad) } } -template void cn_gpu_inner_ssse3(const uint8_t* spad, uint8_t* lpad); +template void cn_gpu_inner_ssse3().iterations(), xmrig::CnAlgo().mask()>(const uint8_t* spad, uint8_t* lpad); diff --git a/src/crypto/cn/r/CryptonightR_gen.cpp b/src/crypto/cn/r/CryptonightR_gen.cpp index 8491a33b..3b80f805 100644 --- a/src/crypto/cn/r/CryptonightR_gen.cpp +++ b/src/crypto/cn/r/CryptonightR_gen.cpp @@ -29,8 +29,8 @@ typedef void(*void_func)(); #include "crypto/cn/asm/CryptonightR_template.h" +#include "crypto/common/Assembly.h" #include "crypto/common/VirtualMemory.h" -#include "Mem.h" static inline void add_code(uint8_t* &p, void (*p1)(), void (*p2)()) @@ -42,7 +42,7 @@ static inline void add_code(uint8_t* &p, void (*p1)(), void (*p2)()) } } -static inline void add_random_math(uint8_t* &p, const V4_Instruction* code, int code_size, const void_func* instructions, const void_func* instructions_mov, bool is_64_bit, xmrig::Assembly ASM) +static inline void add_random_math(uint8_t* &p, const V4_Instruction* code, int code_size, const void_func* instructions, const void_func* instructions_mov, bool is_64_bit, xmrig::Assembly::Id ASM) { uint32_t prev_rot_src = (uint32_t)(-1); @@ -76,7 +76,7 @@ static inline void add_random_math(uint8_t* &p, const V4_Instruction* code, int void_func begin = instructions[c]; - if ((ASM = xmrig::ASM_BULLDOZER) && (inst.opcode == MUL) && !is_64_bit) { + if ((ASM = xmrig::Assembly::BULLDOZER) && (inst.opcode == MUL) && !is_64_bit) { // AMD Bulldozer has latency 4 for 32-bit IMUL and 6 for 64-bit IMUL // Always use 32-bit IMUL for AMD Bulldozer in 32-bit mode - skip prefix 0x48 and change 0x49 to 0x41 uint8_t* prefix = reinterpret_cast(begin); diff --git a/src/crypto/cn/r/variant4_random_math.h b/src/crypto/cn/r/variant4_random_math.h index c384df7a..48f0f6ce 100644 --- a/src/crypto/cn/r/variant4_random_math.h +++ b/src/crypto/cn/r/variant4_random_math.h @@ -1,6 +1,13 @@ #ifndef VARIANT4_RANDOM_MATH_H #define VARIANT4_RANDOM_MATH_H + +#include + + +#include "crypto/common/Algorithm.h" + + extern "C" { #include "crypto/cn/c_blake256.h" @@ -182,7 +189,7 @@ static FORCEINLINE void check_data(size_t* data_index, const size_t bytes_needed // Generates as many random math operations as possible with given latency and ALU restrictions // "code" array must have space for NUM_INSTRUCTIONS_MAX+1 instructions -template +template static int v4_random_math_init(struct V4_Instruction* code, const uint64_t height) { // MUL is 3 cycles, 3-way addition and rotations are 2 cycles, SUB/XOR are 1 cycle @@ -204,8 +211,7 @@ static int v4_random_math_init(struct V4_Instruction* code, const uint64_t heigh memset(data, 0, sizeof(data)); uint64_t tmp = SWAP64LE(height); memcpy(data, &tmp, sizeof(uint64_t)); - if (VARIANT == xmrig::VARIANT_4) - { + if (ALGO == xmrig::Algorithm::CN_R) { data[20] = -38; } @@ -249,7 +255,7 @@ static int v4_random_math_init(struct V4_Instruction* code, const uint64_t heigh code_size = 0; int total_iterations = 0; - r8_used = (VARIANT == xmrig::VARIANT_WOW); + r8_used = (ALGO == xmrig::Algorithm::CN_WOW); // Generate random code to achieve minimal required latency for our abstract CPU // Try to get this latency for all 4 registers @@ -291,10 +297,9 @@ static int v4_random_math_init(struct V4_Instruction* code, const uint64_t heigh int b = src_index; // Don't do ADD/SUB/XOR with the same register - if (((opcode == ADD) || (opcode == SUB) || (opcode == XOR)) && (a == b)) - { + if (((opcode == ADD) || (opcode == SUB) || (opcode == XOR)) && (a == b)) { // a is always < 4, so we don't need to check bounds here - b = (VARIANT == xmrig::VARIANT_WOW) ? (a + 4) : 8; + b = (ALGO == xmrig::Algorithm::CN_WOW) ? (a + 4) : 8; src_index = b; } diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index 1bc2a5a6..2c259d32 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -30,11 +30,13 @@ #include +#include "crypto/cn/CnAlgo.h" #include "crypto/common/Algorithm.h" +#include "crypto/rx/RxAlgo.h" +#include "rapidjson/document.h" #ifdef _MSC_VER -# define strncasecmp _strnicmp # define strcasecmp _stricmp #endif @@ -44,265 +46,183 @@ #endif -struct AlgoData +namespace xmrig { + + +struct AlgoName { const char *name; const char *shortName; - xmrig::Algo algo; - xmrig::Variant variant; + const Algorithm::Id id; }; -static AlgoData const algorithms[] = { - { "cryptonight", "cn", xmrig::CRYPTONIGHT, xmrig::VARIANT_AUTO }, - { "cryptonight/0", "cn/0", xmrig::CRYPTONIGHT, xmrig::VARIANT_0 }, - { "cryptonight/1", "cn/1", xmrig::CRYPTONIGHT, xmrig::VARIANT_1 }, - { "cryptonight/xtl", "cn/xtl", xmrig::CRYPTONIGHT, xmrig::VARIANT_XTL }, - { "cryptonight/msr", "cn/msr", xmrig::CRYPTONIGHT, xmrig::VARIANT_MSR }, - { "cryptonight/xao", "cn/xao", xmrig::CRYPTONIGHT, xmrig::VARIANT_XAO }, - { "cryptonight/rto", "cn/rto", xmrig::CRYPTONIGHT, xmrig::VARIANT_RTO }, - { "cryptonight/2", "cn/2", xmrig::CRYPTONIGHT, xmrig::VARIANT_2 }, - { "cryptonight/half", "cn/half", xmrig::CRYPTONIGHT, xmrig::VARIANT_HALF }, - { "cryptonight/xtlv9", "cn/xtlv9", xmrig::CRYPTONIGHT, xmrig::VARIANT_HALF }, - { "cryptonight/wow", "cn/wow", xmrig::CRYPTONIGHT, xmrig::VARIANT_WOW }, - { "cryptonight/r", "cn/r", xmrig::CRYPTONIGHT, xmrig::VARIANT_4 }, - { "cryptonight/rwz", "cn/rwz", xmrig::CRYPTONIGHT, xmrig::VARIANT_RWZ }, - { "cryptonight/zls", "cn/zls", xmrig::CRYPTONIGHT, xmrig::VARIANT_ZLS }, - { "cryptonight/double", "cn/double", xmrig::CRYPTONIGHT, xmrig::VARIANT_DOUBLE }, +static AlgoName const algorithm_names[] = { + { "cryptonight/0", "cn/0", Algorithm::CN_0 }, + { "cryptonight", "cn", Algorithm::CN_0 }, + { "cryptonight/1", "cn/1", Algorithm::CN_1 }, + { "cryptonight-monerov7", nullptr, Algorithm::CN_1 }, + { "cryptonight_v7", nullptr, Algorithm::CN_1 }, + { "cryptonight/2", "cn/2", Algorithm::CN_2 }, + { "cryptonight-monerov8", nullptr, Algorithm::CN_2 }, + { "cryptonight_v8", nullptr, Algorithm::CN_2 }, + { "cryptonight/r", "cn/r", Algorithm::CN_R }, + { "cryptonight_r", nullptr, Algorithm::CN_R }, + { "cryptonight/wow", "cn/wow", Algorithm::CN_WOW }, + { "cryptonight/fast", "cn/fast", Algorithm::CN_FAST }, + { "cryptonight/msr", "cn/msr", Algorithm::CN_FAST }, + { "cryptonight/half", "cn/half", Algorithm::CN_HALF }, + { "cryptonight/xao", "cn/xao", Algorithm::CN_XAO }, + { "cryptonight_alloy", nullptr, Algorithm::CN_XAO }, + { "cryptonight/rto", "cn/rto", Algorithm::CN_RTO }, + { "cryptonight/rwz", "cn/rwz", Algorithm::CN_RWZ }, + { "cryptonight/zls", "cn/zls", Algorithm::CN_ZLS }, + { "cryptonight/double", "cn/double", Algorithm::CN_DOUBLE }, +# ifdef XMRIG_ALGO_CN_GPU + { "cryptonight/gpu", "cn/gpu", Algorithm::CN_GPU }, + { "cryptonight_gpu", nullptr, Algorithm::CN_GPU }, +# endif +# ifdef XMRIG_ALGO_CN_LITE + { "cryptonight-lite/0", "cn-lite/0", Algorithm::CN_LITE_0 }, + { "cryptonight-lite/1", "cn-lite/1", Algorithm::CN_LITE_1 }, + { "cryptonight-lite", "cn-lite", Algorithm::CN_LITE_1 }, + { "cryptonight-light", "cn-light", Algorithm::CN_LITE_1 }, + { "cryptonight_lite", nullptr, Algorithm::CN_LITE_1 }, + { "cryptonight-aeonv7", nullptr, Algorithm::CN_LITE_1 }, + { "cryptonight_lite_v7", nullptr, Algorithm::CN_LITE_1 }, +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + { "cryptonight-heavy/0", "cn-heavy/0", Algorithm::CN_HEAVY_0 }, + { "cryptonight-heavy", "cn-heavy", Algorithm::CN_HEAVY_0 }, + { "cryptonight_heavy", nullptr, Algorithm::CN_HEAVY_0 }, + { "cryptonight-heavy/xhv", "cn-heavy/xhv", Algorithm::CN_HEAVY_XHV }, + { "cryptonight_haven", nullptr, Algorithm::CN_HEAVY_XHV }, + { "cryptonight-heavy/tube", "cn-heavy/tube", Algorithm::CN_HEAVY_TUBE }, + { "cryptonight-bittube2", nullptr, Algorithm::CN_HEAVY_TUBE }, +# endif +# ifdef XMRIG_ALGO_CN_PICO + { "cryptonight-pico", "cn-pico", Algorithm::CN_PICO_0 }, + { "cryptonight-pico/trtl", "cn-pico/trtl", Algorithm::CN_PICO_0 }, + { "cryptonight-turtle", "cn-trtl", Algorithm::CN_PICO_0 }, + { "cryptonight-ultralite", "cn-ultralite", Algorithm::CN_PICO_0 }, + { "cryptonight_turtle", "cn_turtle", Algorithm::CN_PICO_0 }, +# endif +# ifdef XMRIG_ALGO_RANDOMX + { "randomx/0", "rx/0", Algorithm::RX_0 }, + { "RandomX", "rx", Algorithm::RX_0 }, + { "randomx/wow", "rx/wow", Algorithm::RX_WOW }, + { "RandomWOW", nullptr, Algorithm::RX_WOW }, + { "randomx/loki", "rx/loki", Algorithm::RX_LOKI }, + { "RandomXL", nullptr, Algorithm::RX_LOKI }, +# endif +}; + + +} /* namespace xmrig */ + + +rapidjson::Value xmrig::Algorithm::toJSON() const +{ + using namespace rapidjson; + + return isValid() ? Value(StringRef(shortName())) : Value(kNullType); +} + + +size_t xmrig::Algorithm::memory() const +{ + const Family f = family(); + assert(f != UNKNOWN); + + if (f < RANDOM_X) { + return CnAlgo<>::memory(m_id); + } # ifdef XMRIG_ALGO_RANDOMX - { "randomx/wow", "rx/wow", xmrig::RANDOM_X, xmrig::VARIANT_RX_WOW }, - { "randomx/loki", "rx/loki", xmrig::RANDOM_X, xmrig::VARIANT_RX_LOKI }, - { "randomx", "rx", xmrig::RANDOM_X, xmrig::VARIANT_RX_WOW }, + if (f == RANDOM_X) { + return RxAlgo::l3(m_id); + } # endif + return 0; +} + + +xmrig::Algorithm::Family xmrig::Algorithm::family(Id id) +{ + switch (id) { + case CN_0: + case CN_1: + case CN_2: + case CN_R: + case CN_WOW: + case CN_FAST: + case CN_HALF: + case CN_XAO: + case CN_RTO: + case CN_RWZ: + case CN_ZLS: + case CN_DOUBLE: +# ifdef XMRIG_ALGO_CN_GPU + case CN_GPU: +# endif + return CN; + # ifdef XMRIG_ALGO_CN_LITE - { "cryptonight-lite", "cn-lite", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_AUTO }, - { "cryptonight-light", "cn-light", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_AUTO }, - { "cryptonight-lite/0", "cn-lite/0", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_0 }, - { "cryptonight-lite/1", "cn-lite/1", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_1 }, + case CN_LITE_0: + case CN_LITE_1: + return CN_LITE; # endif # ifdef XMRIG_ALGO_CN_HEAVY - { "cryptonight-heavy", "cn-heavy", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_AUTO }, - { "cryptonight-heavy/0", "cn-heavy/0", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_0 }, - { "cryptonight-heavy/xhv", "cn-heavy/xhv", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_XHV }, - { "cryptonight-heavy/tube", "cn-heavy/tube", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_TUBE }, + case CN_HEAVY_0: + case CN_HEAVY_TUBE: + case CN_HEAVY_XHV: + return CN_HEAVY; # endif # ifdef XMRIG_ALGO_CN_PICO - { "cryptonight-pico/trtl", "cn-pico/trtl", xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, - { "cryptonight-pico", "cn-pico", xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, - { "cryptonight-turtle", "cn-trtl", xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, - { "cryptonight-ultralite", "cn-ultralite", xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, - { "cryptonight_turtle", "cn_turtle", xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, + case CN_PICO_0: + return CN_PICO; # endif -# ifdef XMRIG_ALGO_CN_GPU - { "cryptonight/gpu", "cn/gpu", xmrig::CRYPTONIGHT, xmrig::VARIANT_GPU }, +# ifdef XMRIG_ALGO_RANDOMX + case RX_0: + case RX_WOW: + case RX_LOKI: + return RANDOM_X; # endif -}; - -#ifdef XMRIG_PROXY_PROJECT -static AlgoData const xmrStakAlgorithms[] = { - { "cryptonight-monerov7", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_1 }, - { "cryptonight_v7", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_1 }, - { "cryptonight-monerov8", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_2 }, - { "cryptonight_v8", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_2 }, - { "cryptonight_v7_stellite", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_XTL }, - { "cryptonight_lite", nullptr, xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_0 }, - { "cryptonight-aeonv7", nullptr, xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_1 }, - { "cryptonight_lite_v7", nullptr, xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_1 }, - { "cryptonight_heavy", nullptr, xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_0 }, - { "cryptonight_haven", nullptr, xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_XHV }, - { "cryptonight_masari", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_MSR }, - { "cryptonight_masari", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_MSR }, - { "cryptonight-bittube2", nullptr, xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_TUBE }, // bittube-miner - { "cryptonight_alloy", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_XAO }, // xmr-stak-alloy - { "cryptonight_turtle", nullptr, xmrig::CRYPTONIGHT_PICO, xmrig::VARIANT_TRTL }, - { "cryptonight_gpu", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_GPU }, - { "cryptonight_r", nullptr, xmrig::CRYPTONIGHT, xmrig::VARIANT_4 }, -}; -#endif - - -static const char *variants[] = { - "0", - "1", - "tube", - "xtl", - "msr", - "xhv", - "xao", - "rto", - "2", - "half", - "trtl", - "gpu", - "wow", - "r", - "rwz", - "zls", - "double", - "rx/wow", - "rx/loki", -}; - - -static_assert(xmrig::VARIANT_MAX == ARRAY_SIZE(variants), "variants size mismatch"); - - -bool xmrig::Algorithm::isValid() const -{ - if (m_algo == INVALID_ALGO) { - return false; + case INVALID: + case MAX: + return UNKNOWN; } - for (size_t i = 0; i < ARRAY_SIZE(algorithms); i++) { - if (algorithms[i].algo == m_algo && algorithms[i].variant == m_variant) { - return true; + return UNKNOWN; +} + + +xmrig::Algorithm::Id xmrig::Algorithm::parse(const char *name) +{ + if (name == nullptr || strlen(name) < 1) { + return INVALID; + } + + for (size_t i = 0; i < ARRAY_SIZE(algorithm_names); i++) { + if ((strcasecmp(name, algorithm_names[i].name) == 0) || (algorithm_names[i].shortName != nullptr && strcasecmp(name, algorithm_names[i].shortName) == 0)) { + return algorithm_names[i].id; } } - return false; + return INVALID; } -const char *xmrig::Algorithm::variantName() const -{ - if (m_variant == VARIANT_AUTO) { - return "auto"; - } - - return variants[m_variant]; -} - - -void xmrig::Algorithm::parseAlgorithm(const char *algo) -{ - m_algo = INVALID_ALGO; - m_variant = VARIANT_AUTO; - -// assert(algo != nullptr); - if (algo == nullptr || strlen(algo) < 1) { - return; - } - - if (*algo == '!') { - m_flags |= Forced; - - return parseAlgorithm(algo + 1); - } - - for (size_t i = 0; i < ARRAY_SIZE(algorithms); i++) { - if ((strcasecmp(algo, algorithms[i].name) == 0) || (strcasecmp(algo, algorithms[i].shortName) == 0)) { - m_algo = algorithms[i].algo; - m_variant = algorithms[i].variant; - break; - } - } - - if (m_algo == INVALID_ALGO) { - assert(false); - } -} - - -void xmrig::Algorithm::parseVariant(const char *variant) -{ - m_variant = VARIANT_AUTO; - - if (variant == nullptr || strlen(variant) < 1) { - return; - } - - if (*variant == '!') { - m_flags |= Forced; - - return parseVariant(variant + 1); - } - - for (size_t i = 0; i < ARRAY_SIZE(variants); i++) { - if (strcasecmp(variant, variants[i]) == 0) { - m_variant = static_cast(i); - - if (m_variant == VARIANT_RX_WOW || m_variant == VARIANT_RX_LOKI) { // FIXME - m_algo = RANDOM_X; - } - - return; - } - } - - if (strcasecmp(variant, "xtlv9") == 0) { - m_variant = VARIANT_HALF; - } -} - - -void xmrig::Algorithm::parseVariant(int variant) -{ - assert(variant >= -1 && variant <= 2); - - switch (variant) { - case -1: - case 0: - case 1: - m_variant = static_cast(variant); - break; - - case 2: - m_variant = VARIANT_2; - break; - - default: - break; - } -} - - -void xmrig::Algorithm::setAlgo(Algo algo) -{ - m_algo = algo; - - if (m_algo == CRYPTONIGHT_PICO && m_variant == VARIANT_AUTO) { - m_variant = xmrig::VARIANT_TRTL; - } -} - - -#ifdef XMRIG_PROXY_PROJECT -void xmrig::Algorithm::parseXmrStakAlgorithm(const char *algo) -{ - m_algo = INVALID_ALGO; - m_variant = VARIANT_AUTO; - - assert(algo != nullptr); - if (algo == nullptr) { - return; - } - - for (size_t i = 0; i < ARRAY_SIZE(xmrStakAlgorithms); i++) { - if (strcasecmp(algo, xmrStakAlgorithms[i].name) == 0) { - m_algo = xmrStakAlgorithms[i].algo; - m_variant = xmrStakAlgorithms[i].variant; - break; - } - } - - if (m_algo == INVALID_ALGO) { - assert(false); - } -} -#endif - - const char *xmrig::Algorithm::name(bool shortName) const { - for (size_t i = 0; i < ARRAY_SIZE(algorithms); i++) { - if (algorithms[i].algo == m_algo && algorithms[i].variant == m_variant) { - return shortName ? algorithms[i].shortName : algorithms[i].name; + for (size_t i = 0; i < ARRAY_SIZE(algorithm_names); i++) { + if (algorithm_names[i].id == m_id) { + return shortName ? algorithm_names[i].shortName : algorithm_names[i].name; } } diff --git a/src/crypto/common/Algorithm.h b/src/crypto/common/Algorithm.h index 664552aa..a1d8ded2 100644 --- a/src/crypto/common/Algorithm.h +++ b/src/crypto/common/Algorithm.h @@ -30,7 +30,7 @@ #include -#include "common/xmrig.h" +#include "rapidjson/fwd.h" namespace xmrig { @@ -39,65 +39,86 @@ namespace xmrig { class Algorithm { public: - enum Flags { - None = 0, - Forced = 1 + enum Id : int { + INVALID = -1, + CN_0, // "cn/0" Original CryptoNight + CN_1, // "cn/1" CryptoNight variant 1 also known as Monero7 and CryptoNightV7 + CN_2, // "cn/2" CryptoNight variant 2 + CN_R, // "cn/r" CryptoNightR (Monero's variant 4) + CN_WOW, // "cn/wow" CryptoNightR (Wownero) + CN_FAST, // "cn/fast" CryptoNight variant 1 with half iterations + CN_HALF, // "cn/half" CryptoNight variant 2 with half iterations (Masari/Stellite) + CN_XAO, // "cn/xao" Modified CryptoNight variant 0 (Alloy only) + CN_RTO, // "cn/rto" Modified CryptoNight variant 1 (Arto only) + CN_RWZ, // "cn/rwz" CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation (Graft) + CN_ZLS, // "cn/zls" CryptoNight variant 2 with 3/4 iterations (Zelerius) + CN_DOUBLE, // "cn/double" CryptoNight variant 2 with double iterations (X-CASH) +# ifdef XMRIG_ALGO_CN_GPU + CN_GPU, // "cn/gpu" CryptoNight-GPU (Ryo) +# endif +# ifdef XMRIG_ALGO_CN_LITE + CN_LITE_0, // "cn-lite/0" CryptoNight-Lite (1 MB) variant 0 + CN_LITE_1, // "cn-lite/1" CryptoNight-Lite (1 MB) variant 1 +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + CN_HEAVY_0, // "cn-heavy/0" CryptoNight-Heavy (4 MB) + CN_HEAVY_TUBE, // "cn-heavy/tube" Modified CryptoNight-Heavy (TUBE only) + CN_HEAVY_XHV, // "cn-heavy/xhv" Modified CryptoNight-Heavy (Haven Protocol only) +# endif +# ifdef XMRIG_ALGO_CN_PICO + CN_PICO_0, // "cn-pico" CryptoNight Turtle (TRTL) +# endif +# ifdef XMRIG_ALGO_RANDOMX + RX_0, // "rx/0" RandomX (reference configuration) + RX_WOW, // "rx/wow" RandomWOW (Wownero) + RX_LOKI, // "rx/loki" RandomXL (Loki) +# endif + MAX }; - inline Algorithm() : - m_algo(INVALID_ALGO), - m_flags(0), - m_variant(VARIANT_AUTO) - {} + enum Family : int { + UNKNOWN, + CN, + CN_LITE, + CN_HEAVY, + CN_PICO, + RANDOM_X + }; - inline Algorithm(Algo algo, Variant variant) : - m_flags(0), - m_variant(variant) - { - setAlgo(algo); - } + inline Algorithm() {} + inline Algorithm(const char *algo) : m_id(parse(algo)) {} + inline Algorithm(Id id) : m_id(id) {} - inline Algorithm(const char *algo) : - m_flags(0) - { - parseAlgorithm(algo); - } - - inline Algo algo() const { return m_algo; } - inline bool isEqual(const Algorithm &other) const { return m_algo == other.m_algo && m_variant == other.m_variant; } - inline bool isForced() const { return m_flags & Forced; } + inline bool isEqual(const Algorithm &other) const { return m_id == other.m_id; } + inline bool isValid() const { return m_id != INVALID; } inline const char *name() const { return name(false); } inline const char *shortName() const { return name(true); } - inline int flags() const { return m_flags; } - inline Variant variant() const { return m_variant; } - inline void setVariant(Variant variant) { m_variant = variant; } + inline Family family() const { return family(m_id); } + inline Id id() const { return m_id; } + inline bool operator!=(Algorithm::Id id) const { return m_id != id; } inline bool operator!=(const Algorithm &other) const { return !isEqual(other); } + inline bool operator==(Algorithm::Id id) const { return m_id == id; } inline bool operator==(const Algorithm &other) const { return isEqual(other); } + inline operator Algorithm::Id() const { return m_id; } - bool isValid() const; - const char *variantName() const; - void parseAlgorithm(const char *algo); - void parseVariant(const char *variant); - void parseVariant(int variant); - void setAlgo(Algo algo); + rapidjson::Value toJSON() const; + size_t memory() const; -# ifdef XMRIG_PROXY_PROJECT - void parseXmrStakAlgorithm(const char *algo); -# endif + static Family family(Id id); + static Id parse(const char *name); private: const char *name(bool shortName) const; - Algo m_algo; - int m_flags; - Variant m_variant; + Id m_id = INVALID; }; -typedef std::vector Algorithms; +typedef std::vector Algorithms; } /* namespace xmrig */ -#endif /* __ALGORITHM_H__ */ + +#endif /* XMRIG_ALGORITHM_H */ diff --git a/src/crypto/cn/Asm.cpp b/src/crypto/common/Assembly.cpp similarity index 72% rename from src/crypto/cn/Asm.cpp rename to src/crypto/common/Assembly.cpp index 331c133d..44bf0a94 100644 --- a/src/crypto/cn/Asm.cpp +++ b/src/crypto/common/Assembly.cpp @@ -6,7 +6,8 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018 SChernykh - * Copyright 2016-2018 XMRig , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , * * 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 @@ -28,15 +29,17 @@ #ifdef _MSC_VER -# define strncasecmp _strnicmp # define strcasecmp _stricmp #endif -#include "crypto/cn/Asm.h" +#include "crypto/common/Assembly.h" #include "rapidjson/document.h" +namespace xmrig { + + static const char *asmNames[] = { "none", "auto", @@ -46,11 +49,13 @@ static const char *asmNames[] = { }; -xmrig::Assembly xmrig::Asm::parse(const char *assembly, Assembly defaultValue) +} /* namespace xmrig */ + + +xmrig::Assembly::Id xmrig::Assembly::parse(const char *assembly, Id defaultValue) { constexpr size_t const size = sizeof(asmNames) / sizeof((asmNames)[0]); - assert(assembly != nullptr); - assert(ASM_MAX == size); + static_assert(size == MAX, "asmNames size mismatch"); if (assembly == nullptr) { return defaultValue; @@ -58,7 +63,7 @@ xmrig::Assembly xmrig::Asm::parse(const char *assembly, Assembly defaultValue) for (size_t i = 0; i < size; i++) { if (strcasecmp(assembly, asmNames[i]) == 0) { - return static_cast(i); + return static_cast(i); } } @@ -66,10 +71,10 @@ xmrig::Assembly xmrig::Asm::parse(const char *assembly, Assembly defaultValue) } -xmrig::Assembly xmrig::Asm::parse(const rapidjson::Value &value, Assembly defaultValue) +xmrig::Assembly::Id xmrig::Assembly::parse(const rapidjson::Value &value, Id defaultValue) { if (value.IsBool()) { - return parse(value.GetBool()); + return value.GetBool() ? AUTO : NONE; } if (value.IsString()) { @@ -80,23 +85,23 @@ xmrig::Assembly xmrig::Asm::parse(const rapidjson::Value &value, Assembly defaul } -const char *xmrig::Asm::toString(Assembly assembly) +const char *xmrig::Assembly::toString() const { - return asmNames[assembly]; + return asmNames[m_id]; } -rapidjson::Value xmrig::Asm::toJSON(Assembly assembly) +rapidjson::Value xmrig::Assembly::toJSON() const { using namespace rapidjson; - if (assembly == ASM_NONE) { + if (m_id == NONE) { return Value(false); } - if (assembly == ASM_AUTO) { + if (m_id == AUTO) { return Value(true); } - return Value(StringRef(toString(assembly))); + return Value(StringRef(toString())); } diff --git a/src/crypto/common/Assembly.h b/src/crypto/common/Assembly.h new file mode 100644 index 00000000..5ea29e11 --- /dev/null +++ b/src/crypto/common/Assembly.h @@ -0,0 +1,75 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_ASSEMBLY_H +#define XMRIG_ASSEMBLY_H + + +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +class Assembly +{ +public: + enum Id : int { + NONE, + AUTO, + INTEL, + RYZEN, + BULLDOZER, + MAX + }; + + + inline Assembly() {} + inline Assembly(Id id) : m_id(id) {} + inline Assembly(const char *assembly) : m_id(parse(assembly)) {} + inline Assembly(const rapidjson::Value &value) : m_id(parse(value)) {} + + static Id parse(const char *assembly, Id defaultValue = AUTO); + static Id parse(const rapidjson::Value &value, Id defaultValue = AUTO); + + const char *toString() const; + rapidjson::Value toJSON() const; + + inline bool isEqual(const Assembly &other) const { return m_id == other.m_id; } + + inline bool operator!=(Assembly::Id id) const { return m_id != id; } + inline bool operator!=(const Assembly &other) const { return !isEqual(other); } + inline bool operator==(Assembly::Id id) const { return m_id == id; } + inline bool operator==(const Assembly &other) const { return isEqual(other); } + inline operator Assembly::Id() const { return m_id; } + +private: + Id m_id = AUTO; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_ASSEMBLY_H */ diff --git a/src/crypto/common/Nonce.cpp b/src/crypto/common/Nonce.cpp new file mode 100644 index 00000000..45c7001a --- /dev/null +++ b/src/crypto/common/Nonce.cpp @@ -0,0 +1,106 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include + + +#include "crypto/common/Nonce.h" + + +namespace xmrig { + + +std::atomic Nonce::m_paused; +std::atomic Nonce::m_sequence[Nonce::MAX]; +uint32_t Nonce::m_nonces[2] = { 0, 0 }; + + +static uv_mutex_t mutex; +static Nonce nonce; + + +} // namespace xmrig + + +xmrig::Nonce::Nonce() +{ + m_paused = true; + + for (int i = 0; i < MAX; ++i) { + m_sequence[i] = 1; + } + + uv_mutex_init(&mutex); +} + + +uint32_t xmrig::Nonce::next(uint8_t index, uint32_t nonce, uint32_t reserveCount, bool nicehash) +{ + uint32_t next; + + uv_mutex_lock(&mutex); + + if (nicehash) { + next = (nonce & 0xFF000000) | m_nonces[index]; + } + else { + next = m_nonces[index]; + } + + m_nonces[index] += reserveCount; + + uv_mutex_unlock(&mutex); + + return next; +} + + +void xmrig::Nonce::reset(uint8_t index) +{ + uv_mutex_lock(&mutex); + + m_nonces[index] = 0; + touch(); + + uv_mutex_unlock(&mutex); +} + + +void xmrig::Nonce::stop() +{ + pause(false); + + for (int i = 0; i < MAX; ++i) { + m_sequence[i] = 0; + } +} + + +void xmrig::Nonce::touch() +{ + for (int i = 0; i < MAX; ++i) { + m_sequence[i]++; + } +} diff --git a/src/crypto/common/Nonce.h b/src/crypto/common/Nonce.h new file mode 100644 index 00000000..401139fd --- /dev/null +++ b/src/crypto/common/Nonce.h @@ -0,0 +1,70 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_NONCE_H +#define XMRIG_NONCE_H + + +#include + + +namespace xmrig { + + +class Nonce +{ +public: + enum Backend { + CPU, + OPENCL, + CUDA, + MAX + }; + + + Nonce(); + + static inline bool isOutdated(Backend backend, uint64_t sequence) { return m_sequence[backend].load(std::memory_order_relaxed) != sequence; } + static inline bool isPaused() { return m_paused.load(std::memory_order_relaxed); } + static inline uint64_t sequence(Backend backend) { return m_sequence[backend].load(std::memory_order_relaxed); } + static inline void pause(bool paused) { m_paused = paused; } + static inline void stop(Backend backend) { m_sequence[backend] = 0; } + static inline void touch(Backend backend) { m_sequence[backend]++; } + + static uint32_t next(uint8_t index, uint32_t nonce, uint32_t reserveCount, bool nicehash); + static void reset(uint8_t index); + static void stop(); + static void touch(); + +private: + static std::atomic m_paused; + static std::atomic m_sequence[MAX]; + static uint32_t m_nonces[2]; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_NONCE_H */ diff --git a/src/crypto/common/VirtualMemory.h b/src/crypto/common/VirtualMemory.h index e8acb017..44f77a23 100644 --- a/src/crypto/common/VirtualMemory.h +++ b/src/crypto/common/VirtualMemory.h @@ -30,6 +30,7 @@ #include #include +#include namespace xmrig { @@ -38,12 +39,42 @@ namespace xmrig { class VirtualMemory { public: + inline VirtualMemory() {} + VirtualMemory(size_t size, bool hugePages = true, size_t align = 64); + ~VirtualMemory(); + + inline bool isHugePages() const { return m_flags & HUGEPAGES; } + inline size_t size() const { return m_size; } + inline uint8_t *scratchpad() const { return m_scratchpad; } + + inline std::pair hugePages() const + { + return std::pair(isHugePages() ? (align(size()) / 2097152) : 0, align(size()) / 2097152); + } + static void *allocateExecutableMemory(size_t size); static void *allocateLargePagesMemory(size_t size); static void flushInstructionCache(void *p, size_t size); static void freeLargePagesMemory(void *p, size_t size); + static void init(bool hugePages); static void protectExecutableMemory(void *p, size_t size); static void unprotectExecutableMemory(void *p, size_t size); + + static inline bool isHugepagesAvailable() { return (m_globalFlags & HUGEPAGES_AVAILABLE) != 0; } + static inline constexpr size_t align(size_t pos, size_t align = 2097152) { return ((pos - 1) / align + 1) * align; } + +private: + enum Flags { + HUGEPAGES_AVAILABLE = 1, + HUGEPAGES = 2, + LOCK = 4 + }; + + static int m_globalFlags; + + int m_flags = 0; + size_t m_size = 0; + uint8_t *m_scratchpad = nullptr; }; diff --git a/src/crypto/common/VirtualMemory_unix.cpp b/src/crypto/common/VirtualMemory_unix.cpp index beac976d..310a043a 100644 --- a/src/crypto/common/VirtualMemory_unix.cpp +++ b/src/crypto/common/VirtualMemory_unix.cpp @@ -29,6 +29,7 @@ #include +#include "crypto/common/portable/mm_malloc.h" #include "crypto/common/VirtualMemory.h" @@ -37,6 +38,50 @@ #endif +int xmrig::VirtualMemory::m_globalFlags = 0; + + +xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) : + m_size(VirtualMemory::align(size)) +{ + if (hugePages) { + m_scratchpad = static_cast(allocateLargePagesMemory(m_size)); + if (m_scratchpad) { + m_flags |= HUGEPAGES; + + madvise(m_scratchpad, size, MADV_RANDOM | MADV_WILLNEED); + + if (mlock(m_scratchpad, m_size) == 0) { + m_flags |= LOCK; + } + + return; + } + } + + m_scratchpad = static_cast(_mm_malloc(m_size, align)); +} + + +xmrig::VirtualMemory::~VirtualMemory() +{ + if (!m_scratchpad) { + return; + } + + if (isHugePages()) { + if (m_flags & LOCK) { + munlock(m_scratchpad, m_size); + } + + freeLargePagesMemory(m_scratchpad, m_size); + } + else { + _mm_free(m_scratchpad); + } +} + + void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size) { @@ -78,6 +123,14 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t size) } +void xmrig::VirtualMemory::init(bool hugePages) +{ + if (hugePages) { + m_globalFlags = HUGEPAGES | HUGEPAGES_AVAILABLE; + } +} + + void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size) { mprotect(p, size, PROT_READ | PROT_EXEC); diff --git a/src/crypto/common/VirtualMemory_win.cpp b/src/crypto/common/VirtualMemory_win.cpp index dd6be14f..7bdb6365 100644 --- a/src/crypto/common/VirtualMemory_win.cpp +++ b/src/crypto/common/VirtualMemory_win.cpp @@ -27,17 +27,151 @@ #include #include +#include +#include +#include "base/io/log/Log.h" +#include "crypto/common/portable/mm_malloc.h" #include "crypto/common/VirtualMemory.h" -namespace xmrig { +/***************************************************************** +SetLockPagesPrivilege: a function to obtain or +release the privilege of locking physical pages. -constexpr size_t align(size_t pos, size_t align) { - return ((pos - 1) / align + 1) * align; +Inputs: + +HANDLE hProcess: Handle for the process for which the +privilege is needed + +BOOL bEnable: Enable (TRUE) or disable? + +Return value: TRUE indicates success, FALSE failure. + +*****************************************************************/ +/** + * AWE Example: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366531(v=vs.85).aspx + * Creating a File Mapping Using Large Pages: https://msdn.microsoft.com/en-us/library/aa366543(VS.85).aspx + */ +static BOOL SetLockPagesPrivilege() { + HANDLE token; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token) != TRUE) { + return FALSE; + } + + TOKEN_PRIVILEGES tp; + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (LookupPrivilegeValue(nullptr, SE_LOCK_MEMORY_NAME, &(tp.Privileges[0].Luid)) != TRUE) { + return FALSE; + } + + BOOL rc = AdjustTokenPrivileges(token, FALSE, (PTOKEN_PRIVILEGES) &tp, 0, nullptr, nullptr); + if (rc != TRUE || GetLastError() != ERROR_SUCCESS) { + return FALSE; + } + + CloseHandle(token); + + return TRUE; } + +static LSA_UNICODE_STRING StringToLsaUnicodeString(LPCTSTR string) { + LSA_UNICODE_STRING lsaString; + + DWORD dwLen = (DWORD) wcslen(string); + lsaString.Buffer = (LPWSTR) string; + lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR)); + lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR)); + return lsaString; +} + + +static BOOL ObtainLockPagesPrivilege() { + HANDLE token; + PTOKEN_USER user = nullptr; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) == TRUE) { + DWORD size = 0; + + GetTokenInformation(token, TokenUser, nullptr, 0, &size); + if (size) { + user = (PTOKEN_USER) LocalAlloc(LPTR, size); + } + + GetTokenInformation(token, TokenUser, user, size, &size); + CloseHandle(token); + } + + if (!user) { + return FALSE; + } + + LSA_HANDLE handle; + LSA_OBJECT_ATTRIBUTES attributes; + ZeroMemory(&attributes, sizeof(attributes)); + + BOOL result = FALSE; + if (LsaOpenPolicy(nullptr, &attributes, POLICY_ALL_ACCESS, &handle) == 0) { + LSA_UNICODE_STRING str = StringToLsaUnicodeString(_T(SE_LOCK_MEMORY_NAME)); + + if (LsaAddAccountRights(handle, user->User.Sid, &str, 1) == 0) { + LOG_NOTICE("Huge pages support was successfully enabled, but reboot required to use it"); + result = TRUE; + } + + LsaClose(handle); + } + + LocalFree(user); + return result; +} + + +static BOOL TrySetLockPagesPrivilege() { + if (SetLockPagesPrivilege()) { + return TRUE; + } + + return ObtainLockPagesPrivilege() && SetLockPagesPrivilege(); +} + + +int xmrig::VirtualMemory::m_globalFlags = 0; + + +xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) : + m_size(VirtualMemory::align(size)) +{ + if (hugePages) { + m_scratchpad = static_cast(allocateLargePagesMemory(m_size)); + if (m_scratchpad) { + m_flags |= HUGEPAGES; + + return; + } + } + + m_scratchpad = static_cast(_mm_malloc(m_size, align)); +} + + +xmrig::VirtualMemory::~VirtualMemory() +{ + if (!m_scratchpad) { + return; + } + + if (isHugePages()) { + freeLargePagesMemory(m_scratchpad, m_size); + } + else { + _mm_free(m_scratchpad); + } } @@ -72,6 +206,20 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t) } +void xmrig::VirtualMemory::init(bool hugePages) +{ + if (!hugePages) { + return; + } + + m_globalFlags = HUGEPAGES; + + if (TrySetLockPagesPrivilege()) { + m_globalFlags |= HUGEPAGES_AVAILABLE; + } +} + + void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size) { DWORD oldProtect; diff --git a/src/common/crypto/keccak.cpp b/src/crypto/common/keccak.cpp similarity index 99% rename from src/common/crypto/keccak.cpp rename to src/crypto/common/keccak.cpp index 0219ce36..132ae0a8 100644 --- a/src/common/crypto/keccak.cpp +++ b/src/crypto/common/keccak.cpp @@ -27,7 +27,7 @@ #include -#include "common/crypto/keccak.h" +#include "crypto/common/keccak.h" #define HASH_DATA_AREA 136 diff --git a/src/common/crypto/keccak.h b/src/crypto/common/keccak.h similarity index 100% rename from src/common/crypto/keccak.h rename to src/crypto/common/keccak.h diff --git a/src/crypto/randomx/argon2_core.c b/src/crypto/randomx/argon2_core.c index e9174222..4b8fa43d 100644 --- a/src/crypto/randomx/argon2_core.c +++ b/src/crypto/randomx/argon2_core.c @@ -90,12 +90,12 @@ static void load_block(block *dst, const void *input) { } } -static void store_block(void *output, const block *src) { - unsigned i; - for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { - store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]); - } -} +//static void store_block(void *output, const block *src) { +// unsigned i; +// for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { +// store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]); +// } +//} /***************Memory functions*****************/ @@ -484,7 +484,6 @@ void rxa2_initial_hash(uint8_t *blockhash, argon2_context *context, argon2_type int rxa2_argon_initialize(argon2_instance_t *instance, argon2_context *context) { uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; - int result = ARGON2_OK; if (instance == NULL || context == NULL) return ARGON2_INCORRECT_PARAMETER; diff --git a/src/crypto/randomx/bytecode_machine.hpp b/src/crypto/randomx/bytecode_machine.hpp index 3b05f378..810f854a 100644 --- a/src/crypto/randomx/bytecode_machine.hpp +++ b/src/crypto/randomx/bytecode_machine.hpp @@ -90,7 +90,7 @@ namespace randomx { } static void executeBytecode(InstructionByteCode* bytecode, uint8_t* scratchpad, ProgramConfiguration& config) { - for (int pc = 0; pc < RandomX_CurrentConfig.ProgramSize; ++pc) { + for (int pc = 0; pc < static_cast(RandomX_CurrentConfig.ProgramSize); ++pc) { auto& ibc = bytecode[pc]; executeInstruction(ibc, pc, scratchpad, config); } diff --git a/src/crypto/randomx/dataset.cpp b/src/crypto/randomx/dataset.cpp index 3951b55b..b094b1cb 100644 --- a/src/crypto/randomx/dataset.cpp +++ b/src/crypto/randomx/dataset.cpp @@ -121,7 +121,7 @@ namespace randomx { cache->reciprocalCache.clear(); randomx::Blake2Generator gen(key, keySize); - for (int i = 0; i < RandomX_CurrentConfig.CacheAccesses; ++i) { + for (uint32_t i = 0; i < RandomX_CurrentConfig.CacheAccesses; ++i) { randomx::generateSuperscalar(cache->programs[i], gen); for (unsigned j = 0; j < cache->programs[i].getSize(); ++j) { auto& instr = cache->programs[i](j); diff --git a/src/crypto/randomx/jit_compiler_x86.cpp b/src/crypto/randomx/jit_compiler_x86.cpp index 8870a018..6f04e28a 100644 --- a/src/crypto/randomx/jit_compiler_x86.cpp +++ b/src/crypto/randomx/jit_compiler_x86.cpp @@ -194,7 +194,7 @@ namespace randomx { static const uint8_t NOP7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t NOP8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }; - static const uint8_t* NOPX[] = { NOP1, NOP2, NOP3, NOP4, NOP5, NOP6, NOP7, NOP8 }; +// static const uint8_t* NOPX[] = { NOP1, NOP2, NOP3, NOP4, NOP5, NOP6, NOP7, NOP8 }; size_t JitCompilerX86::getCodeSize() { return codePos - prologueSize; diff --git a/src/crypto/randomx/randomx.cpp b/src/crypto/randomx/randomx.cpp index dde838b9..9e88bc6d 100644 --- a/src/crypto/randomx/randomx.cpp +++ b/src/crypto/randomx/randomx.cpp @@ -233,7 +233,7 @@ RandomX_ConfigurationBase RandomX_CurrentConfig; extern "C" { randomx_cache *randomx_alloc_cache(randomx_flags flags) { - randomx_cache *cache; + randomx_cache *cache = nullptr; try { cache = new randomx_cache(); @@ -297,7 +297,7 @@ extern "C" { } randomx_dataset *randomx_alloc_dataset(randomx_flags flags) { - randomx_dataset *dataset; + randomx_dataset *dataset = nullptr; try { dataset = new randomx_dataset(); @@ -345,7 +345,7 @@ extern "C" { delete dataset; } - randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset) { + randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset, uint8_t *scratchpad) { assert(cache != nullptr || (flags & RANDOMX_FLAG_FULL_MEM)); assert(cache == nullptr || cache->isInitialized()); assert(dataset != nullptr || !(flags & RANDOMX_FLAG_FULL_MEM)); @@ -353,7 +353,7 @@ extern "C" { randomx_vm *vm = nullptr; try { - switch (flags & (RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES)) { + switch (flags & (RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES)) { case RANDOMX_FLAG_DEFAULT: vm = new randomx::InterpretedLightVmDefault(); break; @@ -386,49 +386,19 @@ extern "C" { vm = new randomx::CompiledVmHardAes(); break; - case RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::InterpretedLightVmLargePage(); - break; - - case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::InterpretedVmLargePage(); - break; - - case RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::CompiledLightVmLargePage(); - break; - - case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::CompiledVmLargePage(); - break; - - case RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::InterpretedLightVmLargePageHardAes(); - break; - - case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::InterpretedVmLargePageHardAes(); - break; - - case RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::CompiledLightVmLargePageHardAes(); - break; - - case RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT | RANDOMX_FLAG_HARD_AES | RANDOMX_FLAG_LARGE_PAGES: - vm = new randomx::CompiledVmLargePageHardAes(); - break; - default: UNREACHABLE; } - if(cache != nullptr) + if (cache != nullptr) { vm->setCache(cache); + } - if(dataset != nullptr) + if (dataset != nullptr) { vm->setDataset(dataset); + } - vm->allocate(); + vm->setScratchpad(scratchpad); } catch (std::exception &ex) { delete vm; @@ -460,14 +430,12 @@ extern "C" { assert(inputSize == 0 || input != nullptr); assert(output != nullptr); alignas(16) uint64_t tempHash[8]; - int blakeResult = blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0); - assert(blakeResult == 0); + blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0); machine->initScratchpad(&tempHash); machine->resetRoundingMode(); - for (int chain = 0; chain < RandomX_CurrentConfig.ProgramCount - 1; ++chain) { + for (uint32_t chain = 0; chain < RandomX_CurrentConfig.ProgramCount - 1; ++chain) { machine->run(&tempHash); - blakeResult = blake2b(tempHash, sizeof(tempHash), machine->getRegisterFile(), sizeof(randomx::RegisterFile), nullptr, 0); - assert(blakeResult == 0); + blake2b(tempHash, sizeof(tempHash), machine->getRegisterFile(), sizeof(randomx::RegisterFile), nullptr, 0); } machine->run(&tempHash); machine->getFinalResult(output, RANDOMX_HASH_SIZE); diff --git a/src/crypto/randomx/randomx.h b/src/crypto/randomx/randomx.h index cd07ac64..d688189f 100644 --- a/src/crypto/randomx/randomx.h +++ b/src/crypto/randomx/randomx.h @@ -286,7 +286,7 @@ RANDOMX_EXPORT void randomx_release_dataset(randomx_dataset *dataset); * (3) cache parameter is NULL and RANDOMX_FLAG_FULL_MEM is not set * (4) dataset parameter is NULL and RANDOMX_FLAG_FULL_MEM is set */ -RANDOMX_EXPORT randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset); +RANDOMX_EXPORT randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset, uint8_t *scratchpad); /** * Reinitializes a virtual machine with a new Cache. This function should be called anytime diff --git a/src/crypto/randomx/superscalar.cpp b/src/crypto/randomx/superscalar.cpp index da605622..0ca1fe69 100644 --- a/src/crypto/randomx/superscalar.cpp +++ b/src/crypto/randomx/superscalar.cpp @@ -500,7 +500,7 @@ namespace randomx { // * either the last instruction applied to the register or its source must be different than this instruction // - this avoids optimizable instruction sequences such as "xor r1, r2; xor r1, r2" or "ror r, C1; ror r, C2" or "add r, C1; add r, C2" // * register r5 cannot be the destination of the IADD_RS instruction (limitation of the x86 lea instruction) - for (unsigned i = 0; i < 8; ++i) { + for (int i = 0; i < 8; ++i) { if (registers[i].latency <= cycle && (canReuse_ || i != src_) && (allowChainedMul || opGroup_ != SuperscalarInstructionType::IMUL_R || registers[i].lastOpGroup != SuperscalarInstructionType::IMUL_R) && (registers[i].lastOpGroup != opGroup_ || registers[i].lastOpPar != opGroupPar_) && (info_->getType() != SuperscalarInstructionType::IADD_RS || i != RegisterNeedsDisplacement)) availableRegisters.push_back(i); } @@ -581,7 +581,7 @@ namespace randomx { static int scheduleUop(ExecutionPort::type uop, ExecutionPort::type(&portBusy)[CYCLE_MAP_SIZE][3], int cycle) { //The scheduling here is done optimistically by checking port availability in order P5 -> P0 -> P1 to not overload //port P1 (multiplication) by instructions that can go to any port. - for (; cycle < RandomX_CurrentConfig.SuperscalarLatency + 4; ++cycle) { + for (; cycle < static_cast(RandomX_CurrentConfig.SuperscalarLatency) + 4; ++cycle) { if ((uop & ExecutionPort::P5) != 0 && !portBusy[cycle][2]) { if (commit) { if (trace) std::cout << "; P5 at cycle " << cycle << std::endl; @@ -626,7 +626,7 @@ namespace randomx { } else { //macro-ops with 2 uOPs are scheduled conservatively by requiring both uOPs to execute in the same cycle - for (; cycle < RandomX_CurrentConfig.SuperscalarLatency + 4; ++cycle) { + for (; cycle < static_cast(RandomX_CurrentConfig.SuperscalarLatency) + 4; ++cycle) { int cycle1 = scheduleUop(mop.getUop1(), portBusy, cycle); int cycle2 = scheduleUop(mop.getUop2(), portBusy, cycle); @@ -669,7 +669,7 @@ namespace randomx { //Since a decode cycle produces on average 3.45 macro-ops and there are only 3 ALU ports, execution ports are always //saturated first. The cycle limit is present only to guarantee loop termination. //Program size is limited to SuperscalarMaxSize instructions. - for (decodeCycle = 0; decodeCycle < RandomX_CurrentConfig.SuperscalarLatency && !portsSaturated && programSize < 3 * RandomX_CurrentConfig.SuperscalarLatency + 2; ++decodeCycle) { + for (decodeCycle = 0; decodeCycle < static_cast(RandomX_CurrentConfig.SuperscalarLatency) && !portsSaturated && programSize < 3 * static_cast(RandomX_CurrentConfig.SuperscalarLatency) + 2; ++decodeCycle) { //select a decode configuration decodeBuffer = decodeBuffer->fetchNext(currentInstruction.getType(), decodeCycle, mulCount, gen); @@ -683,7 +683,7 @@ namespace randomx { //if we have issued all macro-ops for the current RandomX instruction, create a new instruction if (macroOpIndex >= currentInstruction.getInfo().getSize()) { - if (portsSaturated || programSize >= 3 * RandomX_CurrentConfig.SuperscalarLatency + 2) + if (portsSaturated || programSize >= 3 * static_cast(RandomX_CurrentConfig.SuperscalarLatency) + 2) break; //select an instruction so that the first macro-op fits into the current slot currentInstruction.createForSlot(gen, decodeBuffer->getCounts()[bufferIndex], decodeBuffer->getIndex(), decodeBuffer->getSize() == bufferIndex + 1, bufferIndex == 0); @@ -777,7 +777,7 @@ namespace randomx { macroOpCount++; //terminating condition - if (scheduleCycle >= RandomX_CurrentConfig.SuperscalarLatency) { + if (scheduleCycle >= static_cast(RandomX_CurrentConfig.SuperscalarLatency)) { portsSaturated = true; } cycle = topCycle; diff --git a/src/crypto/randomx/virtual_machine.cpp b/src/crypto/randomx/virtual_machine.cpp index caa1efbf..6560dc95 100644 --- a/src/crypto/randomx/virtual_machine.cpp +++ b/src/crypto/randomx/virtual_machine.cpp @@ -95,43 +95,35 @@ void randomx_vm::initialize() { namespace randomx { - alignas(16) volatile static rx_vec_i128 aesDummy; - - template - VmBase::~VmBase() { - Allocator::freeMemory(scratchpad, RANDOMX_SCRATCHPAD_L3_MAX_SIZE); + template + VmBase::~VmBase() { } - template - void VmBase::allocate() { - if (datasetPtr == nullptr) + template + void VmBase::setScratchpad(uint8_t *scratchpad) { + if (datasetPtr == nullptr) { throw std::invalid_argument("Cache/Dataset not set"); - if (!softAes) { //if hardware AES is not supported, it's better to fail now than to return a ticking bomb - rx_vec_i128 tmp = rx_load_vec_i128((const rx_vec_i128*)&aesDummy); - tmp = rx_aesenc_vec_i128(tmp, tmp); - rx_store_vec_i128((rx_vec_i128*)&aesDummy, tmp); } - scratchpad = (uint8_t*)Allocator::allocMemory(RANDOMX_SCRATCHPAD_L3_MAX_SIZE); + + this->scratchpad = scratchpad; } - template - void VmBase::getFinalResult(void* out, size_t outSize) { + template + void VmBase::getFinalResult(void* out, size_t outSize) { hashAes1Rx4(scratchpad, ScratchpadSize, ®.a); blake2b(out, outSize, ®, sizeof(RegisterFile), nullptr, 0); } - template - void VmBase::initScratchpad(void* seed) { + template + void VmBase::initScratchpad(void* seed) { fillAes1Rx4(seed, ScratchpadSize, scratchpad); } - template - void VmBase::generateProgram(void* seed) { + template + void VmBase::generateProgram(void* seed) { fillAes4Rx4(seed, sizeof(program), &program); } - template class VmBase, false>; - template class VmBase, true>; - template class VmBase; - template class VmBase; -} \ No newline at end of file + template class VmBase; + template class VmBase; +} diff --git a/src/crypto/randomx/virtual_machine.hpp b/src/crypto/randomx/virtual_machine.hpp index 488994df..cba79d72 100644 --- a/src/crypto/randomx/virtual_machine.hpp +++ b/src/crypto/randomx/virtual_machine.hpp @@ -33,26 +33,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "program.hpp" /* Global namespace for C binding */ -class randomx_vm { +class randomx_vm +{ public: virtual ~randomx_vm() = 0; - virtual void allocate() = 0; + virtual void setScratchpad(uint8_t *scratchpad) = 0; virtual void getFinalResult(void* out, size_t outSize) = 0; virtual void setDataset(randomx_dataset* dataset) { } virtual void setCache(randomx_cache* cache) { } virtual void initScratchpad(void* seed) = 0; virtual void run(void* seed) = 0; void resetRoundingMode(); + randomx::RegisterFile *getRegisterFile() { return ® } + const void* getScratchpad() { return scratchpad; } + const randomx::Program& getProgram() { return program; } + protected: void initialize(); alignas(64) randomx::Program program; @@ -69,15 +74,17 @@ protected: namespace randomx { - template - class VmBase : public randomx_vm { + template + class VmBase : public randomx_vm + { public: ~VmBase() override; - void allocate() override; + void setScratchpad(uint8_t *scratchpad) override; void initScratchpad(void* seed) override; void getFinalResult(void* out, size_t outSize) override; + protected: void generateProgram(void* seed); }; -} \ No newline at end of file +} diff --git a/src/crypto/randomx/vm_compiled.cpp b/src/crypto/randomx/vm_compiled.cpp index 7f621a33..4d14c793 100644 --- a/src/crypto/randomx/vm_compiled.cpp +++ b/src/crypto/randomx/vm_compiled.cpp @@ -34,27 +34,25 @@ namespace randomx { static_assert(sizeof(MemoryRegisters) == 2 * sizeof(addr_t) + sizeof(uintptr_t), "Invalid alignment of struct randomx::MemoryRegisters"); static_assert(sizeof(RegisterFile) == 256, "Invalid alignment of struct randomx::RegisterFile"); - template - void CompiledVm::setDataset(randomx_dataset* dataset) { + template + void CompiledVm::setDataset(randomx_dataset* dataset) { datasetPtr = dataset; } - template - void CompiledVm::run(void* seed) { - VmBase::generateProgram(seed); + template + void CompiledVm::run(void* seed) { + VmBase::generateProgram(seed); randomx_vm::initialize(); compiler.generateProgram(program, config); mem.memory = datasetPtr->memory + datasetOffset; execute(); } - template - void CompiledVm::execute() { + template + void CompiledVm::execute() { compiler.getProgramFunc()(reg, mem, scratchpad, RandomX_CurrentConfig.ProgramIterations); } - template class CompiledVm, false>; - template class CompiledVm, true>; - template class CompiledVm; - template class CompiledVm; -} \ No newline at end of file + template class CompiledVm; + template class CompiledVm; +} diff --git a/src/crypto/randomx/vm_compiled.hpp b/src/crypto/randomx/vm_compiled.hpp index 856f00d8..05b34b9c 100644 --- a/src/crypto/randomx/vm_compiled.hpp +++ b/src/crypto/randomx/vm_compiled.hpp @@ -37,8 +37,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - class CompiledVm : public VmBase { + template + class CompiledVm : public VmBase + { public: void* operator new(size_t size) { void* ptr = AlignedAllocator::allocMemory(size); @@ -46,27 +47,28 @@ namespace randomx { throw std::bad_alloc(); return ptr; } + void operator delete(void* ptr) { AlignedAllocator::freeMemory(ptr, sizeof(CompiledVm)); } + void setDataset(randomx_dataset* dataset) override; void run(void* seed) override; - using VmBase::mem; - using VmBase::program; - using VmBase::config; - using VmBase::reg; - using VmBase::scratchpad; - using VmBase::datasetPtr; - using VmBase::datasetOffset; + using VmBase::mem; + using VmBase::program; + using VmBase::config; + using VmBase::reg; + using VmBase::scratchpad; + using VmBase::datasetPtr; + using VmBase::datasetOffset; + protected: void execute(); JitCompiler compiler; }; - using CompiledVmDefault = CompiledVm, true>; - using CompiledVmHardAes = CompiledVm, false>; - using CompiledVmLargePage = CompiledVm; - using CompiledVmLargePageHardAes = CompiledVm; + using CompiledVmDefault = CompiledVm; + using CompiledVmHardAes = CompiledVm; } diff --git a/src/crypto/randomx/vm_compiled_light.cpp b/src/crypto/randomx/vm_compiled_light.cpp index c083f4aa..6009216b 100644 --- a/src/crypto/randomx/vm_compiled_light.cpp +++ b/src/crypto/randomx/vm_compiled_light.cpp @@ -32,23 +32,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - void CompiledLightVm::setCache(randomx_cache* cache) { + template + void CompiledLightVm::setCache(randomx_cache* cache) { cachePtr = cache; mem.memory = cache->memory; compiler.generateSuperscalarHash(cache->programs, cache->reciprocalCache); } - template - void CompiledLightVm::run(void* seed) { - VmBase::generateProgram(seed); + template + void CompiledLightVm::run(void* seed) { + VmBase::generateProgram(seed); randomx_vm::initialize(); compiler.generateProgramLight(program, config, datasetOffset); - CompiledVm::execute(); + CompiledVm::execute(); } - template class CompiledLightVm, false>; - template class CompiledLightVm, true>; - template class CompiledLightVm; - template class CompiledLightVm; -} \ No newline at end of file + template class CompiledLightVm; + template class CompiledLightVm; +} diff --git a/src/crypto/randomx/vm_compiled_light.hpp b/src/crypto/randomx/vm_compiled_light.hpp index 6af82bbe..6cd3cb20 100644 --- a/src/crypto/randomx/vm_compiled_light.hpp +++ b/src/crypto/randomx/vm_compiled_light.hpp @@ -33,8 +33,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - class CompiledLightVm : public CompiledVm { + template + class CompiledLightVm : public CompiledVm + { public: void* operator new(size_t size) { void* ptr = AlignedAllocator::allocMemory(size); @@ -42,23 +43,23 @@ namespace randomx { throw std::bad_alloc(); return ptr; } + void operator delete(void* ptr) { AlignedAllocator::freeMemory(ptr, sizeof(CompiledLightVm)); } + void setCache(randomx_cache* cache) override; void setDataset(randomx_dataset* dataset) override { } void run(void* seed) override; - using CompiledVm::mem; - using CompiledVm::compiler; - using CompiledVm::program; - using CompiledVm::config; - using CompiledVm::cachePtr; - using CompiledVm::datasetOffset; + using CompiledVm::mem; + using CompiledVm::compiler; + using CompiledVm::program; + using CompiledVm::config; + using CompiledVm::cachePtr; + using CompiledVm::datasetOffset; }; - using CompiledLightVmDefault = CompiledLightVm, true>; - using CompiledLightVmHardAes = CompiledLightVm, false>; - using CompiledLightVmLargePage = CompiledLightVm; - using CompiledLightVmLargePageHardAes = CompiledLightVm; -} \ No newline at end of file + using CompiledLightVmDefault = CompiledLightVm; + using CompiledLightVmHardAes = CompiledLightVm; +} diff --git a/src/crypto/randomx/vm_interpreted.cpp b/src/crypto/randomx/vm_interpreted.cpp index 236d3efe..f4c1e05c 100644 --- a/src/crypto/randomx/vm_interpreted.cpp +++ b/src/crypto/randomx/vm_interpreted.cpp @@ -33,21 +33,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - void InterpretedVm::setDataset(randomx_dataset* dataset) { + template + void InterpretedVm::setDataset(randomx_dataset* dataset) { datasetPtr = dataset; mem.memory = dataset->memory; } - template - void InterpretedVm::run(void* seed) { - VmBase::generateProgram(seed); + template + void InterpretedVm::run(void* seed) { + VmBase::generateProgram(seed); randomx_vm::initialize(); execute(); } - template - void InterpretedVm::execute() { + template + void InterpretedVm::execute() { NativeRegisterFile nreg; @@ -106,20 +106,18 @@ namespace randomx { rx_store_vec_f128(®.e[i].lo, nreg.e[i]); } - template - void InterpretedVm::datasetRead(uint64_t address, int_reg_t(&r)[RegistersCount]) { + template + void InterpretedVm::datasetRead(uint64_t address, int_reg_t(&r)[RegistersCount]) { uint64_t* datasetLine = (uint64_t*)(mem.memory + address); for (int i = 0; i < RegistersCount; ++i) r[i] ^= datasetLine[i]; } - template - void InterpretedVm::datasetPrefetch(uint64_t address) { + template + void InterpretedVm::datasetPrefetch(uint64_t address) { rx_prefetch_nta(mem.memory + address); } - template class InterpretedVm, false>; - template class InterpretedVm, true>; - template class InterpretedVm; - template class InterpretedVm; -} \ No newline at end of file + template class InterpretedVm; + template class InterpretedVm; +} diff --git a/src/crypto/randomx/vm_interpreted.hpp b/src/crypto/randomx/vm_interpreted.hpp index 99c88852..1dc9ab6d 100644 --- a/src/crypto/randomx/vm_interpreted.hpp +++ b/src/crypto/randomx/vm_interpreted.hpp @@ -38,38 +38,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - class InterpretedVm : public VmBase, public BytecodeMachine { + template + class InterpretedVm : public VmBase, public BytecodeMachine { public: - using VmBase::mem; - using VmBase::scratchpad; - using VmBase::program; - using VmBase::config; - using VmBase::reg; - using VmBase::datasetPtr; - using VmBase::datasetOffset; + using VmBase::mem; + using VmBase::scratchpad; + using VmBase::program; + using VmBase::config; + using VmBase::reg; + using VmBase::datasetPtr; + using VmBase::datasetOffset; + void* operator new(size_t size) { void* ptr = AlignedAllocator::allocMemory(size); if (ptr == nullptr) throw std::bad_alloc(); return ptr; } + void operator delete(void* ptr) { AlignedAllocator::freeMemory(ptr, sizeof(InterpretedVm)); } + void run(void* seed) override; void setDataset(randomx_dataset* dataset) override; + protected: virtual void datasetRead(uint64_t blockNumber, int_reg_t(&r)[RegistersCount]); virtual void datasetPrefetch(uint64_t blockNumber); + private: void execute(); InstructionByteCode bytecode[RANDOMX_PROGRAM_MAX_SIZE]; }; - using InterpretedVmDefault = InterpretedVm, true>; - using InterpretedVmHardAes = InterpretedVm, false>; - using InterpretedVmLargePage = InterpretedVm; - using InterpretedVmLargePageHardAes = InterpretedVm; -} \ No newline at end of file + using InterpretedVmDefault = InterpretedVm; + using InterpretedVmHardAes = InterpretedVm; +} diff --git a/src/crypto/randomx/vm_interpreted_light.cpp b/src/crypto/randomx/vm_interpreted_light.cpp index c54b32f6..9c97187b 100644 --- a/src/crypto/randomx/vm_interpreted_light.cpp +++ b/src/crypto/randomx/vm_interpreted_light.cpp @@ -31,14 +31,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - void InterpretedLightVm::setCache(randomx_cache* cache) { + template + void InterpretedLightVm::setCache(randomx_cache* cache) { cachePtr = cache; mem.memory = cache->memory; } - template - void InterpretedLightVm::datasetRead(uint64_t address, int_reg_t(&r)[8]) { + template + void InterpretedLightVm::datasetRead(uint64_t address, int_reg_t(&r)[8]) { uint32_t itemNumber = address / CacheLineSize; int_reg_t rl[8]; @@ -48,8 +48,6 @@ namespace randomx { r[q] ^= rl[q]; } - template class InterpretedLightVm, false>; - template class InterpretedLightVm, true>; - template class InterpretedLightVm; - template class InterpretedLightVm; + template class InterpretedLightVm; + template class InterpretedLightVm; } diff --git a/src/crypto/randomx/vm_interpreted_light.hpp b/src/crypto/randomx/vm_interpreted_light.hpp index 02d678f6..1a35c580 100644 --- a/src/crypto/randomx/vm_interpreted_light.hpp +++ b/src/crypto/randomx/vm_interpreted_light.hpp @@ -33,29 +33,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace randomx { - template - class InterpretedLightVm : public InterpretedVm { + template + class InterpretedLightVm : public InterpretedVm { public: - using VmBase::mem; - using VmBase::cachePtr; + using VmBase::mem; + using VmBase::cachePtr; + void* operator new(size_t size) { void* ptr = AlignedAllocator::allocMemory(size); if (ptr == nullptr) throw std::bad_alloc(); return ptr; } + void operator delete(void* ptr) { AlignedAllocator::freeMemory(ptr, sizeof(InterpretedLightVm)); } + void setDataset(randomx_dataset* dataset) override { } void setCache(randomx_cache* cache) override; + protected: void datasetRead(uint64_t address, int_reg_t(&r)[8]) override; void datasetPrefetch(uint64_t address) override { } }; - using InterpretedLightVmDefault = InterpretedLightVm, true>; - using InterpretedLightVmHardAes = InterpretedLightVm, false>; - using InterpretedLightVmLargePage = InterpretedLightVm; - using InterpretedLightVmLargePageHardAes = InterpretedLightVm; + using InterpretedLightVmDefault = InterpretedLightVm; + using InterpretedLightVmHardAes = InterpretedLightVm; } diff --git a/src/crypto/rx/Rx.cpp b/src/crypto/rx/Rx.cpp new file mode 100644 index 00000000..4125d81f --- /dev/null +++ b/src/crypto/rx/Rx.cpp @@ -0,0 +1,159 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include +#include + + +#include "backend/cpu/Cpu.h" +#include "base/io/log/Log.h" +#include "base/tools/Buffer.h" +#include "base/tools/Chrono.h" +#include "crypto/rx/Rx.h" +#include "crypto/rx/RxCache.h" +#include "crypto/rx/RxDataset.h" + + +namespace xmrig { + + +class RxPrivate +{ +public: + inline RxPrivate() + { + uv_mutex_init(&mutex); + } + + + inline ~RxPrivate() + { + delete dataset; + uv_mutex_destroy(&mutex); + } + + + inline void lock() { uv_mutex_lock(&mutex); } + inline void unlock() { uv_mutex_unlock(&mutex); } + + + RxDataset *dataset = nullptr; + uint32_t initThreads = std::thread::hardware_concurrency(); + uv_mutex_t mutex; +}; + + +static RxPrivate *d_ptr = new RxPrivate(); +static const char *tag = BLUE_BG(" rx "); + + +} // namespace xmrig + + + +xmrig::RxDataset *xmrig::Rx::dataset() +{ + d_ptr->lock(); + RxDataset *dataset = d_ptr->dataset; + d_ptr->unlock(); + + return dataset; +} + + +xmrig::RxDataset *xmrig::Rx::dataset(const uint8_t *seed, const Algorithm &algorithm, bool hugePages) +{ + d_ptr->lock(); + + if (!d_ptr->dataset) { + const uint64_t ts = Chrono::steadyMSecs(); + + LOG_INFO("%s" MAGENTA_BOLD(" allocate") CYAN_BOLD(" %zu MiB") BLACK_BOLD(" (%zu+%zu) for RandomX dataset & cache"), + tag, + (RxDataset::size() + RxCache::size()) / 1024 / 1024, + RxDataset::size() / 1024 / 1024, + RxCache::size() / 1024 / 1024 + ); + + d_ptr->dataset = new RxDataset(hugePages); + + if (d_ptr->dataset->get() != nullptr) { + const auto hugePages = d_ptr->dataset->hugePages(); + const double percent = hugePages.first == 0 ? 0.0 : static_cast(hugePages.first) / hugePages.second * 100.0; + + LOG_INFO("%s" GREEN(" allocate done") " huge pages %s%u/%u %1.0f%%" CLEAR " %sJIT" BLACK_BOLD(" (%" PRIu64 " ms)"), + tag, + (hugePages.first == hugePages.second ? GREEN_BOLD_S : (hugePages.first == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), + hugePages.first, + hugePages.second, + percent, + d_ptr->dataset->cache()->isJIT() ? GREEN_BOLD_S "+" : RED_BOLD_S "-", + Chrono::steadyMSecs() - ts + ); + } + else { + LOG_WARN(CLEAR "%s" YELLOW_BOLD_S " failed to allocate RandomX dataset, switching to slow mode", tag); + } + } + + if (!d_ptr->dataset->isReady(seed, algorithm)) { + const uint64_t ts = Chrono::steadyMSecs(); + + if (d_ptr->dataset->get() != nullptr) { + LOG_INFO("%s" MAGENTA_BOLD(" init dataset") " algo " WHITE_BOLD("%s (") CYAN_BOLD("%u") WHITE_BOLD(" threads)") BLACK_BOLD(" seed %s..."), + tag, + algorithm.shortName(), + d_ptr->initThreads, + Buffer::toHex(seed, 8).data() + ); + } + else { + LOG_INFO("%s" MAGENTA_BOLD(" init cache") " algo " WHITE_BOLD("%s") BLACK_BOLD(" seed %s..."), + tag, + algorithm.shortName(), + Buffer::toHex(seed, 8).data() + ); + } + + d_ptr->dataset->init(seed, algorithm, d_ptr->initThreads); + + LOG_INFO("%s" GREEN(" init done") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, Chrono::steadyMSecs() - ts); + } + + RxDataset *dataset = d_ptr->dataset; + d_ptr->unlock(); + + return dataset; +} + + +void xmrig::Rx::stop() +{ + delete d_ptr; + + d_ptr = nullptr; +} diff --git a/src/crypto/rx/Rx.h b/src/crypto/rx/Rx.h new file mode 100644 index 00000000..63bb2e14 --- /dev/null +++ b/src/crypto/rx/Rx.h @@ -0,0 +1,54 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_RX_H +#define XMRIG_RX_H + + +#include + + +namespace xmrig +{ + + +class Algorithm; +class RxDataset; + + +class Rx +{ +public: + static RxDataset *dataset(); + static RxDataset *dataset(const uint8_t *seed, const Algorithm &algorithm, bool hugePages = true); + static void stop(); +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_RX_H */ diff --git a/src/crypto/rx/RxAlgo.cpp b/src/crypto/rx/RxAlgo.cpp new file mode 100644 index 00000000..b0e92e6e --- /dev/null +++ b/src/crypto/rx/RxAlgo.cpp @@ -0,0 +1,69 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include "crypto/randomx/randomx.h" +#include "crypto/rx/RxAlgo.h" + + +xmrig::Algorithm::Id xmrig::RxAlgo::apply(Algorithm::Id algorithm) +{ + switch (algorithm) { + case Algorithm::RX_WOW: + randomx_apply_config(RandomX_WowneroConfig); + break; + + case Algorithm::RX_LOKI: + randomx_apply_config(RandomX_LokiConfig); + break; + + default: + randomx_apply_config(RandomX_MoneroConfig); + break; + } + + return algorithm; +} + + +size_t xmrig::RxAlgo::l3(Algorithm::Id algorithm) +{ + switch (algorithm) { + case Algorithm::RX_0: + return RandomX_MoneroConfig.ScratchpadL3_Size; + + case Algorithm::RX_WOW: + return RandomX_WowneroConfig.ScratchpadL3_Size; + + case Algorithm::RX_LOKI: + return RandomX_LokiConfig.ScratchpadL3_Size; + + default: + break; + } + + return 0; +} diff --git a/src/crypto/rx/RxAlgo.h b/src/crypto/rx/RxAlgo.h new file mode 100644 index 00000000..dd3f0aa7 --- /dev/null +++ b/src/crypto/rx/RxAlgo.h @@ -0,0 +1,56 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_RX_ALGO_H +#define XMRIG_RX_ALGO_H + + +#include +#include + + +#include "crypto/common/Algorithm.h" + + +struct RandomX_ConfigurationBase; + + +namespace xmrig +{ + + +class RxAlgo +{ +public: + static Algorithm::Id apply(Algorithm::Id algorithm); + static size_t l3(Algorithm::Id algorithm); +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_RX_ALGO_H */ diff --git a/src/crypto/rx/RxCache.cpp b/src/crypto/rx/RxCache.cpp new file mode 100644 index 00000000..a5e9efb3 --- /dev/null +++ b/src/crypto/rx/RxCache.cpp @@ -0,0 +1,81 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include "crypto/randomx/randomx.h" +#include "crypto/rx/RxCache.h" + + +static_assert(RANDOMX_FLAG_JIT == 8, "RANDOMX_FLAG_JIT flag mismatch"); +static_assert(RANDOMX_FLAG_LARGE_PAGES == 1, "RANDOMX_FLAG_LARGE_PAGES flag mismatch"); + + + +xmrig::RxCache::RxCache(bool hugePages) : + m_seed() +{ + if (hugePages) { + m_flags = RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES; + m_cache = randomx_alloc_cache(static_cast(m_flags)); + } + + if (!m_cache) { + m_flags = RANDOMX_FLAG_JIT; + m_cache = randomx_alloc_cache(static_cast(m_flags)); + } + + if (!m_cache) { + m_flags = RANDOMX_FLAG_DEFAULT; + m_cache = randomx_alloc_cache(static_cast(m_flags)); + } +} + + +xmrig::RxCache::~RxCache() +{ + if (m_cache) { + randomx_release_cache(m_cache); + } +} + + +bool xmrig::RxCache::init(const void *seed) +{ + if (isReady(seed)) { + return false; + } + + memcpy(m_seed, seed, sizeof(m_seed)); + randomx_init_cache(m_cache, m_seed, sizeof(m_seed)); + + return true; +} + + +bool xmrig::RxCache::isReady(const void *seed) const +{ + return memcmp(m_seed, seed, sizeof(m_seed)) == 0; +} diff --git a/src/crypto/rx/RxCache.h b/src/crypto/rx/RxCache.h new file mode 100644 index 00000000..c48924a1 --- /dev/null +++ b/src/crypto/rx/RxCache.h @@ -0,0 +1,70 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_RX_CACHE_H +#define XMRIG_RX_CACHE_H + + +#include + + +#include "crypto/randomx/configuration.h" + + +struct randomx_cache; + + +namespace xmrig +{ + + +class RxCache +{ +public: + RxCache(bool hugePages = true); + ~RxCache(); + + inline bool isHugePages() const { return m_flags & 1; } + inline bool isJIT() const { return m_flags & 8; } + inline const uint8_t *seed() const { return m_seed; } + inline randomx_cache *get() const { return m_cache; } + + bool init(const void *seed); + bool isReady(const void *seed) const; + + static inline constexpr size_t size() { return RANDOMX_CACHE_MAX_SIZE; } + +private: + int m_flags = 0; + randomx_cache *m_cache = nullptr; + uint8_t m_seed[32]; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_RX_CACHE_H */ diff --git a/src/crypto/rx/RxDataset.cpp b/src/crypto/rx/RxDataset.cpp new file mode 100644 index 00000000..603cf578 --- /dev/null +++ b/src/crypto/rx/RxDataset.cpp @@ -0,0 +1,128 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include + + +#include "crypto/common/VirtualMemory.h" +#include "crypto/randomx/randomx.h" +#include "crypto/rx/RxAlgo.h" +#include "crypto/rx/RxCache.h" +#include "crypto/rx/RxDataset.h" + + +static_assert(RANDOMX_FLAG_LARGE_PAGES == 1, "RANDOMX_FLAG_LARGE_PAGES flag mismatch"); + + +xmrig::RxDataset::RxDataset(bool hugePages) +{ + if (hugePages) { + m_flags = RANDOMX_FLAG_LARGE_PAGES; + m_dataset = randomx_alloc_dataset(static_cast(m_flags)); + } + + if (!m_dataset) { + m_flags = RANDOMX_FLAG_DEFAULT; + m_dataset = randomx_alloc_dataset(static_cast(m_flags)); + } + + m_cache = new RxCache(hugePages); +} + + +xmrig::RxDataset::~RxDataset() +{ + if (m_dataset) { + randomx_release_dataset(m_dataset); + } + + delete m_cache; +} + + +bool xmrig::RxDataset::init(const void *seed, const Algorithm &algorithm, uint32_t numThreads) +{ + if (isReady(seed, algorithm)) { + return false; + } + + if (m_algorithm != algorithm) { + m_algorithm = RxAlgo::apply(algorithm); + } + + cache()->init(seed); + + if (!get()) { + return true; + } + + const uint32_t datasetItemCount = randomx_dataset_item_count(); + + if (numThreads > 1) { + std::vector threads; + threads.reserve(numThreads); + + for (uint32_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); + } + + for (uint32_t i = 0; i < numThreads; ++i) { + threads[i].join(); + } + } + else { + randomx_init_dataset(m_dataset, m_cache->get(), 0, datasetItemCount); + } + + return true; +} + + +bool xmrig::RxDataset::isReady(const void *seed, const Algorithm &algorithm) const +{ + return algorithm == m_algorithm && cache()->isReady(seed); +} + + +std::pair xmrig::RxDataset::hugePages() const +{ + constexpr size_t twoMiB = 2u * 1024u * 1024u; + constexpr const size_t total = (VirtualMemory::align(size(), twoMiB) + VirtualMemory::align(RxCache::size(), twoMiB)) / twoMiB; + + size_t count = 0; + if (isHugePages()) { + count += VirtualMemory::align(size(), twoMiB) / twoMiB; + } + + if (m_cache->isHugePages()) { + count += VirtualMemory::align(RxCache::size(), twoMiB) / twoMiB; + } + + return std::pair(count, total); +} diff --git a/src/crypto/rx/RxDataset.h b/src/crypto/rx/RxDataset.h new file mode 100644 index 00000000..7944d52c --- /dev/null +++ b/src/crypto/rx/RxDataset.h @@ -0,0 +1,72 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_RX_DATASET_H +#define XMRIG_RX_DATASET_H + + +#include "crypto/common/Algorithm.h" +#include "crypto/randomx/configuration.h" + + +struct randomx_dataset; + + +namespace xmrig +{ + + +class RxCache; + + +class RxDataset +{ +public: + RxDataset(bool hugePages = true); + ~RxDataset(); + + inline bool isHugePages() const { return m_flags & 1; } + inline randomx_dataset *get() const { return m_dataset; } + inline RxCache *cache() const { return m_cache; } + + bool init(const void *seed, const Algorithm &algorithm, uint32_t numThreads); + bool isReady(const void *seed, const Algorithm &algorithm) const; + std::pair hugePages() const; + + static inline constexpr size_t size() { return RANDOMX_DATASET_MAX_SIZE; } + +private: + Algorithm m_algorithm; + int m_flags = 0; + randomx_dataset *m_dataset = nullptr; + RxCache *m_cache = nullptr; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_RX_DATASET_H */ diff --git a/src/crypto/rx/RxVm.cpp b/src/crypto/rx/RxVm.cpp new file mode 100644 index 00000000..6426443a --- /dev/null +++ b/src/crypto/rx/RxVm.cpp @@ -0,0 +1,57 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include "crypto/randomx/randomx.h" +#include "crypto/rx/RxCache.h" +#include "crypto/rx/RxDataset.h" +#include "crypto/rx/RxVm.h" + + +xmrig::RxVm::RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes) +{ + if (!softAes) { + m_flags |= RANDOMX_FLAG_HARD_AES; + } + + if (dataset->get()) { + m_flags |= RANDOMX_FLAG_FULL_MEM; + } + + if (dataset->cache()->isJIT()) { + m_flags |= RANDOMX_FLAG_JIT; + } + + m_vm = randomx_create_vm(static_cast(m_flags), dataset->cache()->get(), dataset->get(), scratchpad); +} + + +xmrig::RxVm::~RxVm() +{ + if (m_vm) { + randomx_destroy_vm(m_vm); + } +} diff --git a/src/crypto/rx/RxVm.h b/src/crypto/rx/RxVm.h new file mode 100644 index 00000000..d7e617e4 --- /dev/null +++ b/src/crypto/rx/RxVm.h @@ -0,0 +1,61 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2019 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 tevador + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_RX_VM_H +#define XMRIG_RX_VM_H + + +#include + + +struct randomx_vm; + + +namespace xmrig +{ + + +class RxDataset; + + +class RxVm +{ +public: + RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes); + ~RxVm(); + + inline randomx_vm *get() const { return m_vm; } + +private: + int m_flags = 0; + randomx_vm *m_vm = nullptr; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_RX_CACHE_H */ diff --git a/src/net/JobResult.h b/src/net/JobResult.h index 9fe1238e..2c2fded5 100644 --- a/src/net/JobResult.h +++ b/src/net/JobResult.h @@ -41,43 +41,31 @@ namespace xmrig { class JobResult { public: - inline JobResult() : poolId(0), nonce(0), diff(0) {} - inline JobResult(int poolId, const String &jobId, const String &clientId, uint32_t nonce, const uint8_t *result, uint64_t diff, const Algorithm &algorithm) : - algorithm(algorithm), - poolId(poolId), - clientId(clientId), - jobId(jobId), + inline JobResult() {} + + inline JobResult(const Job &job, uint32_t nonce, const uint8_t *result) : + algorithm(job.algorithm()), + clientId(job.clientId()), + jobId(job.id()), nonce(nonce), - diff(diff) + diff(job.diff()), + index(job.index()) { - memcpy(this->result, result, sizeof(this->result)); + memcpy(m_result, result, sizeof(m_result)); } + inline const uint8_t *result() const { return m_result; } + inline uint64_t actualDiff() const { return Job::toDiff(reinterpret_cast(m_result)[3]); } - inline JobResult(const Job &job) : poolId(0), nonce(0), diff(0) - { - jobId = job.id(); - clientId = job.clientId(); - poolId = job.poolId(); - diff = job.diff(); - nonce = *job.nonce(); - algorithm = job.algorithm(); - } + const Algorithm algorithm; + const String clientId; + const String jobId; + const uint32_t nonce = 0; + const uint64_t diff = 0; + const uint8_t index = 0; - - inline uint64_t actualDiff() const - { - return Job::toDiff(reinterpret_cast(result)[3]); - } - - - Algorithm algorithm; - int poolId; - String clientId; - String jobId; - uint32_t nonce; - uint64_t diff; - uint8_t result[32]; +private: + uint8_t m_result[32]; }; diff --git a/src/net/JobResults.cpp b/src/net/JobResults.cpp new file mode 100644 index 00000000..bf0b5e86 --- /dev/null +++ b/src/net/JobResults.cpp @@ -0,0 +1,141 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * 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 . + */ + + +#include +#include +#include + + +#include "base/tools/Handle.h" +#include "net/interfaces/IJobResultListener.h" +#include "net/JobResult.h" +#include "net/JobResults.h" + + +namespace xmrig { + + +class JobResultsPrivate +{ +public: + inline JobResultsPrivate() + { + uv_mutex_init(&m_mutex); + + m_async = new uv_async_t; + m_async->data = this; + + uv_async_init(uv_default_loop(), m_async, JobResultsPrivate::onResult); + } + + + inline ~JobResultsPrivate() + { + Handle::close(m_async); + + uv_mutex_destroy(&m_mutex); + } + + + void setListener(IJobResultListener *listener) + { + m_listener = listener; + } + + + void submit(const JobResult &result) + { + uv_mutex_lock(&m_mutex); + m_queue.push_back(result); + uv_mutex_unlock(&m_mutex); + + uv_async_send(m_async); + } + + +private: + static void onResult(uv_async_t *handle) + { + static_cast(handle->data)->submit(); + } + + + inline void submit() + { + std::list results; + + uv_mutex_lock(&m_mutex); + while (!m_queue.empty()) { + results.push_back(std::move(m_queue.front())); + m_queue.pop_front(); + } + uv_mutex_unlock(&m_mutex); + + for (auto result : results) { + m_listener->onJobResult(result); + } + + results.clear(); + } + + + IJobResultListener *m_listener = nullptr; + std::list m_queue; + uv_async_t *m_async; + uv_mutex_t m_mutex; +}; + + +static JobResultsPrivate *handler = new JobResultsPrivate(); + + +} // namespace xmrig + + + +void xmrig::JobResults::setListener(IJobResultListener *listener) +{ + assert(handler != nullptr && listener != nullptr); + + handler->setListener(listener); +} + + +void xmrig::JobResults::stop() +{ + delete handler; + + handler = nullptr; +} + + +void xmrig::JobResults::submit(const JobResult &result) +{ + assert(handler != nullptr); + + if (handler) { + handler->submit(result); + } +} diff --git a/src/workers/ThreadHandle.cpp b/src/net/JobResults.h similarity index 75% rename from src/workers/ThreadHandle.cpp rename to src/net/JobResults.h index 43ff950c..e7082acb 100644 --- a/src/workers/ThreadHandle.cpp +++ b/src/net/JobResults.h @@ -5,6 +5,7 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett * Copyright 2018-2019 SChernykh * Copyright 2016-2019 XMRig , * @@ -22,26 +23,27 @@ * along with this program. If not, see . */ - -#include "workers/ThreadHandle.h" +#ifndef XMRIG_JOBRESULTS_H +#define XMRIG_JOBRESULTS_H -ThreadHandle::ThreadHandle(xmrig::IThread *config, uint32_t offset, size_t totalWays) : - m_worker(nullptr), - m_totalWays(totalWays), - m_offset(offset), - m_config(config) +namespace xmrig { + + +class IJobResultListener; +class JobResult; + + +class JobResults { -} +public: + static void setListener(IJobResultListener *listener); + static void stop(); + static void submit(const JobResult &result); +}; -void ThreadHandle::join() -{ - uv_thread_join(&m_thread); -} +} // namespace xmrig -void ThreadHandle::start(void (*callback) (void *)) -{ - uv_thread_create(&m_thread, callback, this); -} +#endif /* XMRIG_JOBRESULTS_H */ diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 1ab42236..547a8638 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -27,7 +27,9 @@ #pragma warning(disable:4244) #endif +#include #include +#include #include #include @@ -40,10 +42,12 @@ #include "base/tools/Timer.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "core/Miner.h" +#include "net/JobResult.h" +#include "net/JobResults.h" #include "net/Network.h" #include "net/strategies/DonateStrategy.h" #include "rapidjson/document.h" -#include "workers/Workers.h" #ifdef XMRIG_FEATURE_API @@ -57,7 +61,7 @@ xmrig::Network::Network(Controller *controller) : m_donate(nullptr), m_timer(nullptr) { - Workers::setListener(this); + JobResults::setListener(this); controller->addListener(this); # ifdef XMRIG_FEATURE_API @@ -77,6 +81,8 @@ xmrig::Network::Network(Controller *controller) : xmrig::Network::~Network() { + JobResults::stop(); + delete m_timer; if (m_donate) { @@ -141,7 +147,7 @@ void xmrig::Network::onJob(IStrategy *strategy, IClient *client, const Job &job) void xmrig::Network::onJobResult(const JobResult &result) { - if (result.poolId == -1 && m_donate) { + if (result.index == 1 && m_donate) { m_donate->submit(result); return; } @@ -150,6 +156,30 @@ void xmrig::Network::onJobResult(const JobResult &result) } +void xmrig::Network::onLogin(IStrategy *, IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Algorithms algorithms = m_controller->miner()->algorithms(); + const Algorithm algorithm = client->pool().algorithm(); + if (algorithm.isValid()) { + const size_t index = static_cast(std::distance(algorithms.begin(), std::find(algorithms.begin(), algorithms.end(), algorithm))); + if (index > 0 && index < algorithms.size()) { + std::swap(algorithms[0], algorithms[index]); + } + } + + Value algo(kArrayType); + + for (const auto &a : algorithms) { + algo.PushBack(StringRef(a.shortName()), allocator); + } + + params.AddMember("algo", algo, allocator); +} + + void xmrig::Network::onPause(IStrategy *strategy) { if (m_donate && m_donate == strategy) { @@ -160,24 +190,12 @@ void xmrig::Network::onPause(IStrategy *strategy) if (!m_strategy->isActive()) { LOG_ERR("no active pools, stop mining"); m_state.stop(); - return Workers::pause(); + + return m_controller->miner()->pause(); } } -void xmrig::Network::onRequest(IApiRequest &request) -{ -# ifdef XMRIG_FEATURE_API - if (request.method() == IApiRequest::METHOD_GET && (request.url() == "/1/summary" || request.url() == "/api.json")) { - request.accept(); - - getResults(request.reply(), request.doc()); - getConnection(request.reply(), request.doc()); - } -# endif -} - - void xmrig::Network::onResultAccepted(IStrategy *, IClient *, const SubmitResult &result, const char *error) { m_state.add(result, error); @@ -193,6 +211,29 @@ void xmrig::Network::onResultAccepted(IStrategy *, IClient *, const SubmitResult } +void xmrig::Network::onVerifyAlgorithm(IStrategy *, const IClient *, const Algorithm &algorithm, bool *ok) +{ + if (!m_controller->miner()->isEnabled(algorithm)) { + *ok = false; + + return; + } +} + + +#ifdef XMRIG_FEATURE_API +void xmrig::Network::onRequest(IApiRequest &request) +{ + if (request.type() == IApiRequest::REQ_SUMMARY) { + request.accept(); + + getResults(request.reply(), request.doc(), request.version()); + getConnection(request.reply(), request.doc(), request.version()); + } +} +#endif + + void xmrig::Network::setJob(IClient *client, const Job &job, bool donate) { if (job.height()) { @@ -209,7 +250,7 @@ void xmrig::Network::setJob(IClient *client, const Job &job, bool donate) } m_state.diff = job.diff(); - Workers::setJob(job, donate); + m_controller->miner()->setJob(job, donate); } @@ -226,13 +267,12 @@ void xmrig::Network::tick() #ifdef XMRIG_FEATURE_API -void xmrig::Network::getConnection(rapidjson::Value &reply, rapidjson::Document &doc) const +void xmrig::Network::getConnection(rapidjson::Value &reply, rapidjson::Document &doc, int version) const { using namespace rapidjson; auto &allocator = doc.GetAllocator(); - const Algorithm &algo = m_strategy->client()->job().algorithm(); - reply.AddMember("algo", StringRef((algo.isValid() ? algo : m_controller->config()->algorithm()).shortName()), allocator); + reply.AddMember("algo", StringRef(m_strategy->client()->job().algorithm().shortName()), allocator); Value connection(kObjectType); connection.AddMember("pool", StringRef(m_state.pool), allocator); @@ -242,13 +282,16 @@ void xmrig::Network::getConnection(rapidjson::Value &reply, rapidjson::Document connection.AddMember("failures", m_state.failures, allocator); connection.AddMember("tls", m_state.tls().toJSON(), allocator); connection.AddMember("tls-fingerprint", m_state.fingerprint().toJSON(), allocator); - connection.AddMember("error_log", Value(kArrayType), allocator); + + if (version == 1) { + connection.AddMember("error_log", Value(kArrayType), allocator); + } reply.AddMember("connection", connection, allocator); } -void xmrig::Network::getResults(rapidjson::Value &reply, rapidjson::Document &doc) const +void xmrig::Network::getResults(rapidjson::Value &reply, rapidjson::Document &doc, int version) const { using namespace rapidjson; auto &allocator = doc.GetAllocator(); @@ -266,8 +309,11 @@ void xmrig::Network::getResults(rapidjson::Value &reply, rapidjson::Document &do best.PushBack(m_state.topDiff[i], allocator); } - results.AddMember("best", best, allocator); - results.AddMember("error_log", Value(kArrayType), allocator); + results.AddMember("best", best, allocator); + + if (version == 1) { + results.AddMember("error_log", Value(kArrayType), allocator); + } reply.AddMember("results", results, allocator); } diff --git a/src/net/Network.h b/src/net/Network.h index eaec9472..ddf6d6f3 100644 --- a/src/net/Network.h +++ b/src/net/Network.h @@ -63,9 +63,14 @@ protected: void onConfigChanged(Config *config, Config *previousConfig) override; void onJob(IStrategy *strategy, IClient *client, const Job &job) override; void onJobResult(const JobResult &result) override; + void onLogin(IStrategy *strategy, IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; void onPause(IStrategy *strategy) override; - void onRequest(IApiRequest &request) override; void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) override; + void onVerifyAlgorithm(IStrategy *strategy, const IClient *client, const Algorithm &algorithm, bool *ok) override; + +# ifdef XMRIG_FEATURE_API + void onRequest(IApiRequest &request) override; +# endif private: constexpr static int kTickInterval = 1 * 1000; @@ -74,8 +79,8 @@ private: void tick(); # ifdef XMRIG_FEATURE_API - void getConnection(rapidjson::Value &reply, rapidjson::Document &doc) const; - void getResults(rapidjson::Value &reply, rapidjson::Document &doc) const; + void getConnection(rapidjson::Value &reply, rapidjson::Document &doc, int version) const; + void getResults(rapidjson::Value &reply, rapidjson::Document &doc, int version) const; # endif Controller *m_controller; diff --git a/src/interfaces/IJobResultListener.h b/src/net/interfaces/IJobResultListener.h similarity index 100% rename from src/interfaces/IJobResultListener.h rename to src/net/interfaces/IJobResultListener.h diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index fb958a4c..4393cd46 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -23,20 +23,22 @@ */ +#include #include +#include +#include "base/kernel/Platform.h" #include "base/net/stratum/Client.h" #include "base/net/stratum/Job.h" #include "base/net/stratum/strategies/FailoverStrategy.h" #include "base/net/stratum/strategies/SinglePoolStrategy.h" #include "base/tools/Buffer.h" #include "base/tools/Timer.h" -#include "common/crypto/keccak.h" -#include "common/Platform.h" -#include "common/xmrig.h" #include "core/config/Config.h" #include "core/Controller.h" +#include "core/Miner.h" +#include "crypto/common/keccak.h" #include "net/Network.h" #include "net/strategies/DonateStrategy.h" #include "rapidjson/document.h" @@ -58,10 +60,10 @@ static const char *kDonateHostTls = "donate.ssl.xmrig.com"; xmrig::DonateStrategy::DonateStrategy(Controller *controller, IStrategyListener *listener) : m_tls(false), m_userId(), - m_proxy(nullptr), m_donateTime(static_cast(controller->config()->pools().donateLevel()) * 60 * 1000), m_idleTime((100 - static_cast(controller->config()->pools().donateLevel())) * 60 * 1000), m_controller(controller), + m_proxy(nullptr), m_strategy(nullptr), m_listener(listener), m_state(STATE_NEW), @@ -79,10 +81,6 @@ xmrig::DonateStrategy::DonateStrategy(Controller *controller, IStrategyListener # endif m_pools.push_back(Pool(kDonateHost, 3333, m_userId, nullptr, 0, true)); - for (Pool &pool : m_pools) { - pool.adjust(Algorithm(controller->config()->algorithm().algo(), VARIANT_AUTO)); - } - if (m_pools.size() > 1) { m_strategy = new FailoverStrategy(m_pools, 1, 2, this, true); } @@ -130,6 +128,8 @@ void xmrig::DonateStrategy::connect() void xmrig::DonateStrategy::setAlgo(const xmrig::Algorithm &algo) { + m_algorithm = algo; + m_strategy->setAlgo(algo); } @@ -186,13 +186,14 @@ void xmrig::DonateStrategy::onClose(IClient *, int failures) void xmrig::DonateStrategy::onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) { + using namespace rapidjson; auto &allocator = doc.GetAllocator(); # ifdef XMRIG_FEATURE_TLS if (m_tls) { char buf[40] = { 0 }; snprintf(buf, sizeof(buf), "stratum+ssl://%s", m_pools[0].url().data()); - params.AddMember("url", rapidjson::Value(buf, allocator), allocator); + params.AddMember("url", Value(buf, allocator), allocator); } else { params.AddMember("url", m_pools[1].url().toJSON(), allocator); @@ -200,6 +201,14 @@ void xmrig::DonateStrategy::onLogin(IClient *, rapidjson::Document &doc, rapidjs # else params.AddMember("url", m_pools[0].url().toJSON(), allocator); # endif + + setAlgorithms(doc, params); +} + + +void xmrig::DonateStrategy::onLogin(IStrategy *, IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) +{ + setAlgorithms(doc, params); } @@ -251,6 +260,27 @@ void xmrig::DonateStrategy::idle(double min, double max) } +void xmrig::DonateStrategy::setAlgorithms(rapidjson::Document &doc, rapidjson::Value ¶ms) +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Algorithms algorithms = m_controller->miner()->algorithms(); + const size_t index = static_cast(std::distance(algorithms.begin(), std::find(algorithms.begin(), algorithms.end(), m_algorithm))); + if (index > 0 && index < algorithms.size()) { + std::swap(algorithms[0], algorithms[index]); + } + + Value algo(kArrayType); + + for (const auto &a : algorithms) { + algo.PushBack(StringRef(a.shortName()), allocator); + } + + params.AddMember("algo", algo, allocator); +} + + void xmrig::DonateStrategy::setJob(IClient *client, const Job &job) { if (isActive()) { diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h index c9fc312d..134127bf 100644 --- a/src/net/strategies/DonateStrategy.h +++ b/src/net/strategies/DonateStrategy.h @@ -57,6 +57,8 @@ protected: inline void onJobReceived(IClient *client, const Job &job, const rapidjson::Value &) override { setJob(client, job); } inline void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); } inline void onResultAccepted(IStrategy *, IClient *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); } + inline void onVerifyAlgorithm(const IClient *, const Algorithm &, bool *) override {} + inline void onVerifyAlgorithm(IStrategy *, const IClient *, const Algorithm &, bool *) override {} inline void resume() override {} int64_t submit(const JobResult &result) override; @@ -70,6 +72,7 @@ protected: void onClose(IClient *client, int failures) override; void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; + void onLogin(IStrategy *strategy, IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; void onLoginSuccess(IClient *client) override; void onTimer(const Timer *timer) override; @@ -87,16 +90,18 @@ private: Client *createProxy(); void idle(double min, double max); + void setAlgorithms(rapidjson::Document &doc, rapidjson::Value ¶ms); void setJob(IClient *client, const Job &job); void setResult(IClient *client, const SubmitResult &result, const char *error); void setState(State state); + Algorithm m_algorithm; bool m_tls; char m_userId[65]; - IClient *m_proxy; const uint64_t m_donateTime; const uint64_t m_idleTime; Controller *m_controller; + IClient *m_proxy; IStrategy *m_strategy; IStrategyListener *m_listener; State m_state; diff --git a/src/workers/CpuThread.cpp b/src/workers/CpuThread.cpp deleted file mode 100644 index 7e5a039f..00000000 --- a/src/workers/CpuThread.cpp +++ /dev/null @@ -1,778 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * 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 . - */ - -#include - - -#include "base/io/log/Log.h" -#include "common/cpu/Cpu.h" -#include "crypto/cn/Asm.h" -#include "crypto/common/VirtualMemory.h" -#include "Mem.h" -#include "rapidjson/document.h" -#include "workers/CpuThread.h" - - -#if defined(XMRIG_ARM) -# include "crypto/cn/CryptoNight_arm.h" -#else -# include "crypto/cn/CryptoNight_x86.h" -#endif - - -xmrig::CpuThread::CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly) : - m_algorithm(algorithm), - m_av(av), - m_assembly(assembly), - m_prefetch(prefetch), - m_softAES(softAES), - m_priority(priority), - m_affinity(affinity), - m_multiway(multiway), - m_index(index) -{ -} - - -#ifndef XMRIG_NO_ASM -template -static void patchCode(T dst, U src, const uint32_t iterations, const uint32_t mask) -{ - const uint8_t* p = reinterpret_cast(src); - - // Workaround for Visual Studio placing trampoline in debug builds. -# if defined(_MSC_VER) - if (p[0] == 0xE9) { - p += *(int32_t*)(p + 1) + 5; - } -# endif - - size_t size = 0; - while (*(uint32_t*)(p + size) != 0xDEADC0DE) { - ++size; - } - size += sizeof(uint32_t); - - memcpy((void*) dst, (const void*) src, size); - - uint8_t* patched_data = reinterpret_cast(dst); - for (size_t i = 0; i + sizeof(uint32_t) <= size; ++i) { - switch (*(uint32_t*)(patched_data + i)) { - case xmrig::CRYPTONIGHT_ITER: - *(uint32_t*)(patched_data + i) = iterations; - break; - - case xmrig::CRYPTONIGHT_MASK: - *(uint32_t*)(patched_data + i) = mask; - break; - } - } -} - - -extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx **ctx); -extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx **ctx); -extern "C" void cnv2_mainloop_bulldozer_asm(cryptonight_ctx **ctx); -extern "C" void cnv2_double_mainloop_sandybridge_asm(cryptonight_ctx **ctx); - - -xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ivybridge_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_ryzen_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_half_mainloop_bulldozer_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_half_double_mainloop_sandybridge_asm = nullptr; - -xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ivybridge_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_ryzen_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_trtl_mainloop_bulldozer_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_trtl_double_mainloop_sandybridge_asm = nullptr; - -xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ivybridge_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_ryzen_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_zls_mainloop_bulldozer_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_zls_double_mainloop_sandybridge_asm = nullptr; - -xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ivybridge_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_ryzen_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_double_mainloop_bulldozer_asm = nullptr; -xmrig::CpuThread::cn_mainloop_fun cn_double_double_mainloop_sandybridge_asm = nullptr; - - -void xmrig::CpuThread::patchAsmVariants() -{ - const int allocation_size = 65536; - uint8_t *base = static_cast(VirtualMemory::allocateExecutableMemory(allocation_size)); - - cn_half_mainloop_ivybridge_asm = reinterpret_cast (base + 0x0000); - cn_half_mainloop_ryzen_asm = reinterpret_cast (base + 0x1000); - cn_half_mainloop_bulldozer_asm = reinterpret_cast (base + 0x2000); - cn_half_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0x3000); - - cn_trtl_mainloop_ivybridge_asm = reinterpret_cast (base + 0x4000); - cn_trtl_mainloop_ryzen_asm = reinterpret_cast (base + 0x5000); - cn_trtl_mainloop_bulldozer_asm = reinterpret_cast (base + 0x6000); - cn_trtl_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0x7000); - - cn_zls_mainloop_ivybridge_asm = reinterpret_cast (base + 0x8000); - cn_zls_mainloop_ryzen_asm = reinterpret_cast (base + 0x9000); - cn_zls_mainloop_bulldozer_asm = reinterpret_cast (base + 0xA000); - cn_zls_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0xB000); - - cn_double_mainloop_ivybridge_asm = reinterpret_cast (base + 0xC000); - cn_double_mainloop_ryzen_asm = reinterpret_cast (base + 0xD000); - cn_double_mainloop_bulldozer_asm = reinterpret_cast (base + 0xE000); - cn_double_double_mainloop_sandybridge_asm = reinterpret_cast (base + 0xF000); - - patchCode(cn_half_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_half_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_half_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_half_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_HALF_ITER, xmrig::CRYPTONIGHT_MASK); - - patchCode(cn_trtl_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); - patchCode(cn_trtl_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); - patchCode(cn_trtl_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); - patchCode(cn_trtl_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_TRTL_ITER, xmrig::CRYPTONIGHT_PICO_MASK); - - patchCode(cn_zls_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_zls_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_zls_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_zls_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_ZLS_ITER, xmrig::CRYPTONIGHT_MASK); - - patchCode(cn_double_mainloop_ivybridge_asm, cnv2_mainloop_ivybridge_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_double_mainloop_ryzen_asm, cnv2_mainloop_ryzen_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_double_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); - patchCode(cn_double_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); - - VirtualMemory::protectExecutableMemory(base, allocation_size); - VirtualMemory::flushInstructionCache(base, allocation_size); -} -#endif - - -bool xmrig::CpuThread::isSoftAES(AlgoVariant av) -{ - return av == AV_SINGLE_SOFT || av == AV_DOUBLE_SOFT || av > AV_PENTA; -} - - -#ifndef XMRIG_NO_ASM -template -static inline void add_asm_func(xmrig::CpuThread::cn_hash_fun(&asm_func_map)[xmrig::ALGO_MAX][xmrig::AV_MAX][xmrig::VARIANT_MAX][xmrig::ASM_MAX]) -{ - asm_func_map[algo][xmrig::AV_SINGLE][variant][xmrig::ASM_INTEL] = cryptonight_single_hash_asm; - asm_func_map[algo][xmrig::AV_SINGLE][variant][xmrig::ASM_RYZEN] = cryptonight_single_hash_asm; - asm_func_map[algo][xmrig::AV_SINGLE][variant][xmrig::ASM_BULLDOZER] = cryptonight_single_hash_asm; - - asm_func_map[algo][xmrig::AV_DOUBLE][variant][xmrig::ASM_INTEL] = cryptonight_double_hash_asm; - asm_func_map[algo][xmrig::AV_DOUBLE][variant][xmrig::ASM_RYZEN] = cryptonight_double_hash_asm; - asm_func_map[algo][xmrig::AV_DOUBLE][variant][xmrig::ASM_BULLDOZER] = cryptonight_double_hash_asm; -} -#endif - -xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant av, Variant variant, Assembly assembly) -{ - assert(variant >= VARIANT_0 && variant < VARIANT_MAX); - -# ifndef XMRIG_NO_ASM - if (assembly == ASM_AUTO) { - assembly = Cpu::info()->assembly(); - } - - static cn_hash_fun asm_func_map[ALGO_MAX][AV_MAX][VARIANT_MAX][ASM_MAX] = {}; - static bool asm_func_map_initialized = false; - - if (!asm_func_map_initialized) { - add_asm_func(asm_func_map); - add_asm_func(asm_func_map); - add_asm_func(asm_func_map); - add_asm_func(asm_func_map); - -# ifdef XMRIG_ALGO_CN_PICO - add_asm_func(asm_func_map); -# endif - - add_asm_func(asm_func_map); - add_asm_func(asm_func_map); - add_asm_func(asm_func_map); - - asm_func_map_initialized = true; - } - - cn_hash_fun fun = asm_func_map[algorithm][av][variant][assembly]; - if (fun) { - return fun; - } -# endif - - constexpr const size_t count = VARIANT_MAX * 10 * ALGO_MAX; - - static const cn_hash_fun func_table[] = { - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - -# ifdef XMRIG_ALGO_CN_GPU - cryptonight_single_hash_gpu, - nullptr, - cryptonight_single_hash_gpu, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, -# else - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU -# endif - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI - -# ifdef XMRIG_ALGO_CN_LITE - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI -# else - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI -# endif - -# ifdef XMRIG_ALGO_CN_HEAVY - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI -# else - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI -# endif - -# ifdef XMRIG_ALGO_CN_PICO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_single_hash, - cryptonight_double_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - cryptonight_triple_hash, - cryptonight_quad_hash, - cryptonight_penta_hash, - - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI -# else - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI -# endif - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_0 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_1 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TUBE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_MSR - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XHV - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_XAO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RTO - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_2 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_HALF - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_TRTL - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_GPU - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_4 - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RWZ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_ZLS - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_DOUBLE - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_WOW - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // VARIANT_RX_LOKI - }; - - static_assert(count == sizeof(func_table) / sizeof(func_table[0]), "func_table size mismatch"); - - const size_t index = VARIANT_MAX * 10 * algorithm + 10 * variant + av - 1; - -# ifndef NDEBUG - cn_hash_fun func = func_table[index]; - - assert(index < sizeof(func_table) / sizeof(func_table[0])); - assert(func != nullptr); - - return func; -# else - return func_table[index]; -# endif -} - - -xmrig::CpuThread *xmrig::CpuThread::createFromAV(size_t index, Algo algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly) -{ - assert(av > AV_AUTO && av < AV_MAX); - - int64_t cpuId = -1L; - - if (affinity != -1L) { - size_t idx = 0; - - for (size_t i = 0; i < 64; i++) { - if (!(affinity & (1ULL << i))) { - continue; - } - - if (idx == index) { - cpuId = i; - break; - } - - idx++; - } - } - - return new CpuThread(index, algorithm, av, multiway(av), cpuId, priority, isSoftAES(av), false, assembly); -} - - -xmrig::CpuThread *xmrig::CpuThread::createFromData(size_t index, Algo algorithm, const CpuThread::Data &data, int priority, bool softAES) -{ - int av = AV_AUTO; - const Multiway multiway = data.multiway; - - if (multiway <= DoubleWay) { - av = softAES ? (multiway + 2) : multiway; - } - else { - av = softAES ? (multiway + 5) : (multiway + 2); - } - - assert(av > AV_AUTO && av < AV_MAX); - - return new CpuThread(index, algorithm, static_cast(av), multiway, data.affinity, priority, softAES, false, data.assembly); -} - - -xmrig::CpuThread::Data xmrig::CpuThread::parse(const rapidjson::Value &object) -{ - Data data; - - const auto &multiway = object["low_power_mode"]; - if (multiway.IsBool()) { - data.multiway = multiway.IsTrue() ? DoubleWay : SingleWay; - data.valid = true; - } - else if (multiway.IsUint()) { - data.setMultiway(multiway.GetInt()); - } - - if (!data.valid) { - return data; - } - - const auto &affinity = object["affine_to_cpu"]; - if (affinity.IsUint64()) { - data.affinity = affinity.GetInt64(); - } - -# ifndef XMRIG_NO_ASM - data.assembly = Asm::parse(object["asm"]); -# endif - - return data; -} - - -xmrig::IThread::Multiway xmrig::CpuThread::multiway(AlgoVariant av) -{ - switch (av) { - case AV_SINGLE: - case AV_SINGLE_SOFT: - return SingleWay; - - case AV_DOUBLE_SOFT: - case AV_DOUBLE: - return DoubleWay; - - case AV_TRIPLE_SOFT: - case AV_TRIPLE: - return TripleWay; - - case AV_QUAD_SOFT: - case AV_QUAD: - return QuadWay; - - case AV_PENTA_SOFT: - case AV_PENTA: - return PentaWay; - - default: - break; - } - - return SingleWay; -} - - -#ifdef APP_DEBUG -void xmrig::CpuThread::print() const -{ - LOG_DEBUG(GREEN_BOLD("CPU thread: ") " index " WHITE_BOLD("%zu") ", multiway " WHITE_BOLD("%d") ", av " WHITE_BOLD("%d") ",", - index(), static_cast(multiway()), static_cast(m_av)); - -# ifndef XMRIG_NO_ASM - LOG_DEBUG(" assembly: %s, affine_to_cpu: %" PRId64, Asm::toString(m_assembly), affinity()); -# else - LOG_DEBUG(" affine_to_cpu: %" PRId64, affinity()); -# endif -} -#endif - - -#ifdef XMRIG_FEATURE_API -rapidjson::Value xmrig::CpuThread::toAPI(rapidjson::Document &doc) const -{ - using namespace rapidjson; - - Value obj(kObjectType); - auto &allocator = doc.GetAllocator(); - - obj.AddMember("type", "cpu", allocator); - obj.AddMember("av", m_av, allocator); - obj.AddMember("low_power_mode", multiway(), allocator); - obj.AddMember("affine_to_cpu", affinity(), allocator); - obj.AddMember("priority", priority(), allocator); - obj.AddMember("soft_aes", isSoftAES(), allocator); - - return obj; -} -#endif - - -rapidjson::Value xmrig::CpuThread::toConfig(rapidjson::Document &doc) const -{ - using namespace rapidjson; - - Value obj(kObjectType); - auto &allocator = doc.GetAllocator(); - - obj.AddMember("low_power_mode", multiway(), allocator); - obj.AddMember("affine_to_cpu", affinity() == -1L ? Value(kFalseType) : Value(affinity()), allocator); - -# ifndef XMRIG_NO_ASM - obj.AddMember("asm", Asm::toJSON(m_assembly), allocator); -# endif - - return obj; -} diff --git a/src/workers/CpuThread.h b/src/workers/CpuThread.h deleted file mode 100644 index 2af421be..00000000 --- a/src/workers/CpuThread.h +++ /dev/null @@ -1,115 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * 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 . - */ - -#ifndef XMRIG_CPUTHREAD_H -#define XMRIG_CPUTHREAD_H - - -#include "common/xmrig.h" -#include "interfaces/IThread.h" - - -struct cryptonight_ctx; - - -namespace xmrig { - - -class CpuThread : public IThread -{ -public: - struct Data - { - inline Data() : assembly(ASM_AUTO), valid(false), affinity(-1L), multiway(SingleWay) {} - - inline void setMultiway(int value) - { - if (value >= SingleWay && value <= PentaWay) { - multiway = static_cast(value); - valid = true; - } - } - - Assembly assembly; - bool valid; - int64_t affinity; - Multiway multiway; - }; - - - CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch, Assembly assembly); - - typedef void (*cn_hash_fun)(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx **ctx, uint64_t height); - typedef void (*cn_mainloop_fun)(cryptonight_ctx **ctx); - -# ifndef XMRIG_NO_ASM - static void patchAsmVariants(); -# endif - - static bool isSoftAES(AlgoVariant av); - static cn_hash_fun fn(Algo algorithm, AlgoVariant av, Variant variant, Assembly assembly); - static CpuThread *createFromAV(size_t index, Algo algorithm, AlgoVariant av, int64_t affinity, int priority, Assembly assembly); - static CpuThread *createFromData(size_t index, Algo algorithm, const CpuThread::Data &data, int priority, bool softAES); - static Data parse(const rapidjson::Value &object); - static Multiway multiway(AlgoVariant av); - - inline bool isPrefetch() const { return m_prefetch; } - inline bool isSoftAES() const { return m_softAES; } - inline cn_hash_fun fn(Variant variant) const { return fn(m_algorithm, m_av, variant, m_assembly); } - - inline Algo algorithm() const override { return m_algorithm; } - inline int priority() const override { return m_priority; } - inline int64_t affinity() const override { return m_affinity; } - inline Multiway multiway() const override { return m_multiway; } - inline size_t index() const override { return m_index; } - inline Type type() const override { return CPU; } - -protected: -# ifdef APP_DEBUG - void print() const override; -# endif - -# ifdef XMRIG_FEATURE_API - rapidjson::Value toAPI(rapidjson::Document &doc) const override; -# endif - - rapidjson::Value toConfig(rapidjson::Document &doc) const override; - -private: - const Algo m_algorithm; - const AlgoVariant m_av; - const Assembly m_assembly; - const bool m_prefetch; - const bool m_softAES; - const int m_priority; - const int64_t m_affinity; - const Multiway m_multiway; - const size_t m_index; -}; - - -} /* namespace xmrig */ - - -#endif /* XMRIG_CPUTHREAD_H */ diff --git a/src/workers/MultiWorker.cpp b/src/workers/MultiWorker.cpp deleted file mode 100644 index 86ff3fc4..00000000 --- a/src/workers/MultiWorker.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018 Lee Clagett - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * 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 . - */ - - -#include - - -#include "crypto/cn/CryptoNight_test.h" -#include "workers/CpuThread.h" -#include "workers/MultiWorker.h" -#include "workers/Workers.h" - - -template -MultiWorker::MultiWorker(ThreadHandle *handle) - : Worker(handle) -{ - if (m_thread->algorithm() != xmrig::RANDOM_X) { - m_memory = Mem::create(m_ctx, m_thread->algorithm(), N); - } -} - - -template -MultiWorker::~MultiWorker() -{ - Mem::release(m_ctx, N, m_memory); - -# ifdef XMRIG_ALGO_RANDOMX - if (m_rx_vm) { - randomx_destroy_vm(m_rx_vm); - } -# endif -} - - -#ifdef XMRIG_ALGO_RANDOMX -template -void MultiWorker::allocateRandomX_VM() -{ - if (!m_rx_vm) { - int flags = RANDOMX_FLAG_LARGE_PAGES | RANDOMX_FLAG_FULL_MEM | RANDOMX_FLAG_JIT; - if (!m_thread->isSoftAES()) { - flags |= RANDOMX_FLAG_HARD_AES; - } - - m_rx_vm = randomx_create_vm(static_cast(flags), nullptr, Workers::getDataset()); - if (!m_rx_vm) { - m_rx_vm = randomx_create_vm(static_cast(flags - RANDOMX_FLAG_LARGE_PAGES), nullptr, Workers::getDataset()); - } - } -} -#endif - - -template -bool MultiWorker::selfTest() -{ - using namespace xmrig; - - if (m_thread->algorithm() == CRYPTONIGHT) { - const bool rc = verify(VARIANT_0, test_output_v0) && - verify(VARIANT_1, test_output_v1) && - verify(VARIANT_2, test_output_v2) && - verify(VARIANT_XTL, test_output_xtl) && - verify(VARIANT_MSR, test_output_msr) && - verify(VARIANT_XAO, test_output_xao) && - verify(VARIANT_RTO, test_output_rto) && - verify(VARIANT_HALF, test_output_half) && - verify2(VARIANT_WOW, test_output_wow) && - verify2(VARIANT_4, test_output_r) && - verify(VARIANT_RWZ, test_output_rwz) && - verify(VARIANT_ZLS, test_output_zls) && - verify(VARIANT_DOUBLE, test_output_double); - -# ifdef XMRIG_ALGO_CN_GPU - if (!rc || N > 1) { - return rc; - } - - return verify(VARIANT_GPU, test_output_gpu); -# else - return rc; -# endif - } - -# ifdef XMRIG_ALGO_CN_LITE - if (m_thread->algorithm() == CRYPTONIGHT_LITE) { - return verify(VARIANT_0, test_output_v0_lite) && - verify(VARIANT_1, test_output_v1_lite); - } -# endif - -# ifdef XMRIG_ALGO_CN_HEAVY - if (m_thread->algorithm() == CRYPTONIGHT_HEAVY) { - return verify(VARIANT_0, test_output_v0_heavy) && - verify(VARIANT_XHV, test_output_xhv_heavy) && - verify(VARIANT_TUBE, test_output_tube_heavy); - } -# endif - -# ifdef XMRIG_ALGO_CN_PICO - if (m_thread->algorithm() == CRYPTONIGHT_PICO) { - return verify(VARIANT_TRTL, test_output_pico_trtl); - } -# endif - -# ifdef XMRIG_ALGO_RANDOMX - if (m_thread->algorithm() == RANDOM_X) { - return true; - } -# endif - - return false; -} - - -template -void MultiWorker::start() -{ - while (Workers::sequence() > 0) { - if (Workers::isPaused()) { - do { - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - } - while (Workers::isPaused()); - - if (Workers::sequence() == 0) { - break; - } - - consumeJob(); - } - - while (!Workers::isOutdated(m_sequence)) { - if ((m_count & 0x7) == 0) { - storeStats(); - } - - const xmrig::Variant v = m_state.job.algorithm().variant(); - -# ifdef XMRIG_ALGO_RANDOMX - if ((v == xmrig::VARIANT_RX_WOW) || (v == xmrig::VARIANT_RX_LOKI)) { - allocateRandomX_VM(); - Workers::updateDataset(m_state.job.seedHash(), v, m_totalWays); - randomx_calculate_hash(m_rx_vm, m_state.blob, m_state.job.size(), m_hash); - } - else -# endif - { - m_thread->fn(v)(m_state.blob, m_state.job.size(), m_hash, m_ctx, m_state.job.height()); - } - - for (size_t i = 0; i < N; ++i) { - if (*reinterpret_cast(m_hash + (i * 32) + 24) < m_state.job.target()) { - Workers::submit(xmrig::JobResult(m_state.job.poolId(), m_state.job.id(), m_state.job.clientId(), *nonce(i), m_hash + (i * 32), m_state.job.diff(), m_state.job.algorithm())); - } - - *nonce(i) += 1; - } - - m_count += N; - - std::this_thread::yield(); - } - - consumeJob(); - } -} - - -template -bool MultiWorker::resume(const xmrig::Job &job) -{ - if (m_state.job.poolId() == -1 && job.poolId() >= 0 && job.id() == m_pausedState.job.id()) { - m_state = m_pausedState; - return true; - } - - return false; -} - - -template -bool MultiWorker::verify(xmrig::Variant variant, const uint8_t *referenceValue) -{ - - xmrig::CpuThread::cn_hash_fun func = m_thread->fn(variant); - if (!func) { - return false; - } - - func(test_input, 76, m_hash, m_ctx, 0); - return memcmp(m_hash, referenceValue, sizeof m_hash) == 0; -} - - -template -bool MultiWorker::verify2(xmrig::Variant variant, const uint8_t *referenceValue) -{ - xmrig::CpuThread::cn_hash_fun func = m_thread->fn(variant); - if (!func) { - return false; - } - - for (size_t i = 0; i < (sizeof(cn_r_test_input) / sizeof(cn_r_test_input[0])); ++i) { - const size_t size = cn_r_test_input[i].size; - for (size_t k = 0; k < N; ++k) { - memcpy(m_state.blob + (k * size), cn_r_test_input[i].data, size); - } - - func(m_state.blob, size, m_hash, m_ctx, cn_r_test_input[i].height); - - for (size_t k = 0; k < N; ++k) { - if (memcmp(m_hash + k * 32, referenceValue + i * 32, sizeof m_hash / N) != 0) { - return false; - } - } - } - - return true; -} - - -template<> -bool MultiWorker<1>::verify2(xmrig::Variant variant, const uint8_t *referenceValue) -{ - xmrig::CpuThread::cn_hash_fun func = m_thread->fn(variant); - if (!func) { - return false; - } - - for (size_t i = 0; i < (sizeof(cn_r_test_input) / sizeof(cn_r_test_input[0])); ++i) { - func(cn_r_test_input[i].data, cn_r_test_input[i].size, m_hash, m_ctx, cn_r_test_input[i].height); - - if (memcmp(m_hash, referenceValue + i * 32, sizeof m_hash) != 0) { - return false; - } - } - - return true; -} - - -template -void MultiWorker::consumeJob() -{ - xmrig::Job job = Workers::job(); - m_sequence = Workers::sequence(); - if (m_state.job == job) { - return; - } - - save(job); - - if (resume(job)) { - return; - } - - m_state.job = job; - - const size_t size = m_state.job.size(); - memcpy(m_state.blob, m_state.job.blob(), m_state.job.size()); - - if (N > 1) { - for (size_t i = 1; i < N; ++i) { - memcpy(m_state.blob + (i * size), m_state.blob, size); - } - } - - for (size_t i = 0; i < N; ++i) { - if (m_state.job.isNicehash()) { - *nonce(i) = (*nonce(i) & 0xff000000U) + (0xffffffU / m_totalWays * (m_offset + i)); - } - else { - *nonce(i) = 0xffffffffU / m_totalWays * (m_offset + i); - } - } -} - - -template -void MultiWorker::save(const xmrig::Job &job) -{ - if (job.poolId() == -1 && m_state.job.poolId() >= 0) { - m_pausedState = m_state; - } -} - - -template class MultiWorker<1>; -template class MultiWorker<2>; -template class MultiWorker<3>; -template class MultiWorker<4>; -template class MultiWorker<5>; diff --git a/src/workers/Worker.cpp b/src/workers/Worker.cpp deleted file mode 100644 index 234e7bfd..00000000 --- a/src/workers/Worker.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2016-2018 XMRig , - * - * 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 . - */ - -#include - - -#include "common/cpu/Cpu.h" -#include "common/Platform.h" -#include "workers/CpuThread.h" -#include "workers/ThreadHandle.h" -#include "workers/Worker.h" - - -Worker::Worker(ThreadHandle *handle) : - m_id(handle->threadId()), - m_totalWays(handle->totalWays()), - m_offset(handle->offset()), - m_hashCount(0), - m_timestamp(0), - m_count(0), - m_sequence(0), - m_thread(static_cast(handle->config())) -{ - if (xmrig::Cpu::info()->threads() > 1 && m_thread->affinity() != -1L) { - Platform::setThreadAffinity(m_thread->affinity()); - } - - Platform::setThreadPriority(m_thread->priority()); -} - - -void Worker::storeStats() -{ - using namespace std::chrono; - - const uint64_t timestamp = time_point_cast(high_resolution_clock::now()).time_since_epoch().count(); - m_hashCount.store(m_count, std::memory_order_relaxed); - m_timestamp.store(timestamp, std::memory_order_relaxed); -} diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp deleted file mode 100644 index a913ee51..00000000 --- a/src/workers/Workers.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * 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 . - */ - -#include -#include -#include - - -#include "api/Api.h" -#include "base/io/log/Log.h" -#include "base/tools/Handle.h" -#include "core/config/Config.h" -#include "core/Controller.h" -#include "crypto/cn/CryptoNight_constants.h" -#include "interfaces/IJobResultListener.h" -#include "interfaces/IThread.h" -#include "Mem.h" -#include "rapidjson/document.h" -#include "workers/Hashrate.h" -#include "workers/MultiWorker.h" -#include "workers/ThreadHandle.h" -#include "workers/Workers.h" - - -bool Workers::m_active = false; -bool Workers::m_enabled = true; -Hashrate *Workers::m_hashrate = nullptr; -xmrig::IJobResultListener *Workers::m_listener = nullptr; -xmrig::Job Workers::m_job; -Workers::LaunchStatus Workers::m_status; -std::atomic Workers::m_paused; -std::atomic Workers::m_sequence; -std::list Workers::m_queue; -std::vector Workers::m_workers; -uint64_t Workers::m_ticks = 0; -uv_async_t *Workers::m_async = nullptr; -uv_mutex_t Workers::m_mutex; -uv_rwlock_t Workers::m_rwlock; -uv_timer_t *Workers::m_timer = nullptr; -xmrig::Controller *Workers::m_controller = nullptr; - -#ifdef XMRIG_ALGO_RANDOMX -uv_rwlock_t Workers::m_rx_dataset_lock; -randomx_cache *Workers::m_rx_cache = nullptr; -randomx_dataset *Workers::m_rx_dataset = nullptr; -uint8_t Workers::m_rx_seed_hash[32] = {}; -xmrig::Variant Workers::m_rx_variant = xmrig::VARIANT_MAX; -std::atomic Workers::m_rx_dataset_init_thread_counter = {}; -#endif - - -xmrig::Job Workers::job() -{ - uv_rwlock_rdlock(&m_rwlock); - xmrig::Job job = m_job; - uv_rwlock_rdunlock(&m_rwlock); - - return job; -} - - -size_t Workers::hugePages() -{ - uv_mutex_lock(&m_mutex); - const size_t hugePages = m_status.hugePages; - uv_mutex_unlock(&m_mutex); - - return hugePages; -} - - -size_t Workers::threads() -{ - uv_mutex_lock(&m_mutex); - const size_t threads = m_status.threads; - uv_mutex_unlock(&m_mutex); - - return threads; -} - - -void Workers::printHashrate(bool detail) -{ - assert(m_controller != nullptr); - if (!m_controller) { - return; - } - - if (detail) { - char num1[8] = { 0 }; - char num2[8] = { 0 }; - char num3[8] = { 0 }; - - xmrig::Log::print(WHITE_BOLD_S "| THREAD | AFFINITY | 10s H/s | 60s H/s | 15m H/s |"); - - size_t i = 0; - for (const xmrig::IThread *thread : m_controller->config()->threads()) { - xmrig::Log::print("| %6zu | %8" PRId64 " | %7s | %7s | %7s |", - thread->index(), - thread->affinity(), - Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::ShortInterval), num1, sizeof num1), - Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::MediumInterval), num2, sizeof num2), - Hashrate::format(m_hashrate->calc(thread->index(), Hashrate::LargeInterval), num3, sizeof num3) - ); - - i++; - } - } - - m_hashrate->print(); -} - - -void Workers::setEnabled(bool enabled) -{ - if (m_enabled == enabled) { - return; - } - - m_enabled = enabled; - if (!m_active) { - return; - } - - m_paused = enabled ? 0 : 1; - m_sequence++; -} - - -void Workers::setJob(const xmrig::Job &job, bool donate) -{ - uv_rwlock_wrlock(&m_rwlock); - m_job = job; - - if (donate) { - m_job.setPoolId(-1); - } - uv_rwlock_wrunlock(&m_rwlock); - - m_active = true; - if (!m_enabled) { - return; - } - - m_sequence++; - m_paused = 0; -} - - -void Workers::start(xmrig::Controller *controller) -{ -# ifdef APP_DEBUG - LOG_NOTICE("THREADS ------------------------------------------------------------------"); - for (const xmrig::IThread *thread : controller->config()->threads()) { - thread->print(); - } - LOG_NOTICE("--------------------------------------------------------------------------"); -# endif - -# ifndef XMRIG_NO_ASM - xmrig::CpuThread::patchAsmVariants(); -# endif - - m_controller = controller; - - const std::vector &threads = controller->config()->threads(); - m_status.algo = controller->config()->algorithm().algo(); - m_status.variant = controller->config()->algorithm().variant(); - m_status.threads = threads.size(); - - for (const xmrig::IThread *thread : threads) { - m_status.ways += thread->multiway(); - } - - m_hashrate = new Hashrate(threads.size(), controller); - - uv_mutex_init(&m_mutex); - uv_rwlock_init(&m_rwlock); - -# ifdef XMRIG_ALGO_RANDOMX - uv_rwlock_init(&m_rx_dataset_lock); -# endif - - m_sequence = 1; - m_paused = 1; - - m_async = new uv_async_t; - uv_async_init(uv_default_loop(), m_async, Workers::onResult); - - m_timer = new uv_timer_t; - uv_timer_init(uv_default_loop(), m_timer); - uv_timer_start(m_timer, Workers::onTick, 500, 500); - - uint32_t offset = 0; - - for (xmrig::IThread *thread : threads) { - ThreadHandle *handle = new ThreadHandle(thread, offset, m_status.ways); - offset += thread->multiway(); - - m_workers.push_back(handle); - handle->start(Workers::onReady); - } -} - - -void Workers::stop() -{ - xmrig::Handle::close(m_timer); - xmrig::Handle::close(m_async); - m_hashrate->stop(); - - m_paused = 0; - m_sequence = 0; - - for (size_t i = 0; i < m_workers.size(); ++i) { - m_workers[i]->join(); - } -} - - -void Workers::submit(const xmrig::JobResult &result) -{ - uv_mutex_lock(&m_mutex); - m_queue.push_back(result); - uv_mutex_unlock(&m_mutex); - - uv_async_send(m_async); -} - - -#ifdef XMRIG_FEATURE_API -void Workers::threadsSummary(rapidjson::Document &doc) -{ - uv_mutex_lock(&m_mutex); - const uint64_t pages[2] = { m_status.hugePages, m_status.pages }; - const uint64_t memory = m_status.ways * xmrig::cn_select_memory(m_status.algo, m_status.variant); - uv_mutex_unlock(&m_mutex); - - auto &allocator = doc.GetAllocator(); - - rapidjson::Value hugepages(rapidjson::kArrayType); - hugepages.PushBack(pages[0], allocator); - hugepages.PushBack(pages[1], allocator); - - doc.AddMember("hugepages", hugepages, allocator); - doc.AddMember("memory", memory, allocator); -} -#endif - - -void Workers::onReady(void *arg) -{ - auto handle = static_cast(arg); - - IWorker *worker = nullptr; - - switch (handle->config()->multiway()) { - case 1: - worker = new MultiWorker<1>(handle); - break; - - case 2: - worker = new MultiWorker<2>(handle); - break; - - case 3: - worker = new MultiWorker<3>(handle); - break; - - case 4: - worker = new MultiWorker<4>(handle); - break; - - case 5: - worker = new MultiWorker<5>(handle); - break; - - default: - break; - } - - handle->setWorker(worker); - - if (!worker->selfTest()) { - LOG_ERR("thread %zu error: \"hash self-test failed\".", handle->worker()->id()); - - return; - } - - start(worker); -} - - -void Workers::onResult(uv_async_t *) -{ - std::list results; - - uv_mutex_lock(&m_mutex); - while (!m_queue.empty()) { - results.push_back(std::move(m_queue.front())); - m_queue.pop_front(); - } - uv_mutex_unlock(&m_mutex); - - for (auto result : results) { - m_listener->onJobResult(result); - } - - results.clear(); -} - - -void Workers::onTick(uv_timer_t *) -{ - for (ThreadHandle *handle : m_workers) { - if (!handle->worker()) { - return; - } - - m_hashrate->add(handle->threadId(), handle->worker()->hashCount(), handle->worker()->timestamp()); - } - - if ((m_ticks++ & 0xF) == 0) { - m_hashrate->updateHighest(); - } -} - - -void Workers::start(IWorker *worker) -{ - const Worker *w = static_cast(worker); - - uv_mutex_lock(&m_mutex); - m_status.started++; - m_status.pages += w->memory().pages; - m_status.hugePages += w->memory().hugePages; - - if (m_status.started == m_status.threads) { - const double percent = (double) m_status.hugePages / m_status.pages * 100.0; - const size_t memory = m_status.ways * xmrig::cn_select_memory(m_status.algo, m_status.variant) / 1024; - -# ifdef XMRIG_ALGO_RANDOMX - if (m_status.algo == xmrig::RANDOM_X) { - LOG_INFO(GREEN_BOLD("READY (CPU)") " threads " CYAN_BOLD("%zu(%zu)") " memory " CYAN_BOLD("%zu KB") "", - m_status.threads, m_status.ways, memory); - } else -# endif - { - LOG_INFO(GREEN_BOLD("READY (CPU)") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") "", - m_status.threads, m_status.ways, - (m_status.hugePages == m_status.pages ? GREEN_BOLD_S : (m_status.hugePages == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), - m_status.hugePages, m_status.pages, percent, memory); - } - } - - uv_mutex_unlock(&m_mutex); - - worker->start(); -} - - -#ifdef XMRIG_ALGO_RANDOMX -void Workers::updateDataset(const uint8_t* seed_hash, xmrig::Variant variant, const uint32_t num_threads) -{ - // Check if we need to update cache and dataset - if ((memcmp(m_rx_seed_hash, seed_hash, sizeof(m_rx_seed_hash)) == 0) && (m_rx_variant == variant)) - return; - - const uint32_t thread_id = m_rx_dataset_init_thread_counter++; - LOG_DEBUG("Thread %u started updating RandomX dataset", thread_id); - - // Wait for all threads to get here - do { - if (m_sequence.load(std::memory_order_relaxed) == 0) { - // Exit immediately if workers were stopped - return; - } - std::this_thread::yield(); - } while (m_rx_dataset_init_thread_counter.load() != num_threads); - - // One of the threads updates cache - uv_rwlock_wrlock(&m_rx_dataset_lock); - - if (m_rx_variant != variant) { - switch (variant) { - case xmrig::VARIANT_RX_WOW: - randomx_apply_config(RandomX_WowneroConfig); - break; - case xmrig::VARIANT_RX_LOKI: - randomx_apply_config(RandomX_LokiConfig); - break; - default: - randomx_apply_config(RandomX_MoneroConfig); - break; - } - m_rx_variant = variant; - } - - if (memcmp(m_rx_seed_hash, seed_hash, sizeof(m_rx_seed_hash)) != 0) { - memcpy(m_rx_seed_hash, seed_hash, sizeof(m_rx_seed_hash)); - randomx_init_cache(m_rx_cache, m_rx_seed_hash, sizeof(m_rx_seed_hash)); - } - - uv_rwlock_wrunlock(&m_rx_dataset_lock); - - // All threads update dataset - const uint32_t a = (randomx_dataset_item_count() * thread_id) / num_threads; - const uint32_t b = (randomx_dataset_item_count() * (thread_id + 1)) / num_threads; - randomx_init_dataset(m_rx_dataset, m_rx_cache, a, b - a); - - LOG_DEBUG("Thread %u finished updating RandomX dataset", thread_id); - - // Wait for all threads to complete - --m_rx_dataset_init_thread_counter; - do { - if (m_sequence.load(std::memory_order_relaxed) == 0) { - // Exit immediately if workers were stopped - return; - } - std::this_thread::yield(); - } while (m_rx_dataset_init_thread_counter.load() != 0); -} - -randomx_dataset* Workers::getDataset() -{ - if (m_rx_dataset) - return m_rx_dataset; - - uv_rwlock_wrlock(&m_rx_dataset_lock); - if (!m_rx_dataset) { - randomx_dataset* dataset = randomx_alloc_dataset(RANDOMX_FLAG_LARGE_PAGES); - if (!dataset) { - dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT); - } - m_rx_cache = randomx_alloc_cache(static_cast(RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES)); - if (!m_rx_cache) { - m_rx_cache = randomx_alloc_cache(RANDOMX_FLAG_JIT); - } - m_rx_dataset = dataset; - } - uv_rwlock_wrunlock(&m_rx_dataset_lock); - - return m_rx_dataset; -} -#endif diff --git a/src/workers/Workers.h b/src/workers/Workers.h deleted file mode 100644 index 3a52073c..00000000 --- a/src/workers/Workers.h +++ /dev/null @@ -1,140 +0,0 @@ -/* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh - * Copyright 2016-2019 XMRig , - * - * 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 . - */ - -#ifndef XMRIG_WORKERS_H -#define XMRIG_WORKERS_H - - -#include -#include -#include -#include - -#ifdef XMRIG_ALGO_RANDOMX -# include -#endif - -#include "base/net/stratum/Job.h" -#include "net/JobResult.h" -#include "rapidjson/fwd.h" - - -class Hashrate; -class IWorker; -class ThreadHandle; - - -namespace xmrig { - class Controller; - class IJobResultListener; -} - - -class Workers -{ -public: - static xmrig::Job job(); - static size_t hugePages(); - static size_t threads(); - static void printHashrate(bool detail); - static void setEnabled(bool enabled); - static void setJob(const xmrig::Job &job, bool donate); - static void start(xmrig::Controller *controller); - static void stop(); - static void submit(const xmrig::JobResult &result); - - static inline bool isEnabled() { return m_enabled; } - static inline bool isOutdated(uint64_t sequence) { return m_sequence.load(std::memory_order_relaxed) != sequence; } - static inline bool isPaused() { return m_paused.load(std::memory_order_relaxed) == 1; } - static inline Hashrate *hashrate() { return m_hashrate; } - static inline uint64_t sequence() { return m_sequence.load(std::memory_order_relaxed); } - static inline void pause() { m_active = false; m_paused = 1; m_sequence++; } - static inline void setListener(xmrig::IJobResultListener *listener) { m_listener = listener; } - -# ifdef XMRIG_FEATURE_API - static void threadsSummary(rapidjson::Document &doc); -# endif - -# ifdef XMRIG_ALGO_RANDOMX - static void updateDataset(const uint8_t* seed_hash, xmrig::Variant variant, uint32_t num_threads); - static randomx_dataset* getDataset(); -# endif - -private: - static void onReady(void *arg); - static void onResult(uv_async_t *handle); - static void onTick(uv_timer_t *handle); - static void start(IWorker *worker); - - class LaunchStatus - { - public: - inline LaunchStatus() : - hugePages(0), - pages(0), - started(0), - threads(0), - ways(0), - algo(xmrig::CRYPTONIGHT), - variant(xmrig::VARIANT_AUTO) - {} - - size_t hugePages; - size_t pages; - size_t started; - size_t threads; - size_t ways; - xmrig::Algo algo; - xmrig::Variant variant; - }; - - static bool m_active; - static bool m_enabled; - static Hashrate *m_hashrate; - static xmrig::IJobResultListener *m_listener; - static xmrig::Job m_job; - static LaunchStatus m_status; - static std::atomic m_paused; - static std::atomic m_sequence; - static std::list m_queue; - static std::vector m_workers; - static uint64_t m_ticks; - static uv_async_t *m_async; - static uv_mutex_t m_mutex; - static uv_rwlock_t m_rwlock; - static uv_timer_t *m_timer; - static xmrig::Controller *m_controller; - -# ifdef XMRIG_ALGO_RANDOMX - static uv_rwlock_t m_rx_dataset_lock; - static randomx_cache *m_rx_cache; - static randomx_dataset *m_rx_dataset; - static uint8_t m_rx_seed_hash[32]; - static xmrig::Variant m_rx_variant; - static std::atomic m_rx_dataset_init_thread_counter; -# endif -}; - - -#endif /* XMRIG_WORKERS_H */