diff --git a/src/backend/opencl/OclGenerator.h b/src/backend/opencl/OclGenerator.h new file mode 100644 index 000000000..9a04a0597 --- /dev/null +++ b/src/backend/opencl/OclGenerator.h @@ -0,0 +1,43 @@ +/* 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_OCLGENERATOR_H +#define XMRIG_OCLGENERATOR_H + + +namespace xmrig { + + +class Algorithm; +class OclDevice; +class OclThreads; + + +using ocl_gen_config_fun = bool (*)(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads); + + +} // namespace xmrig + + +#endif /* XMRIG_OCLGENERATOR_H */ diff --git a/src/backend/opencl/OclThread.h b/src/backend/opencl/OclThread.h index 63f4afe5b..1de7c35d3 100644 --- a/src/backend/opencl/OclThread.h +++ b/src/backend/opencl/OclThread.h @@ -40,12 +40,13 @@ class OclThread { public: OclThread() = delete; - OclThread(uint32_t index, uint32_t intensity, uint32_t worksize, uint32_t stridedIndex, uint32_t memChunk, uint32_t threads, const Algorithm &algorithm) : + OclThread(uint32_t index, uint32_t intensity, uint32_t worksize, uint32_t stridedIndex, uint32_t memChunk, uint32_t threads, uint32_t unrollFactor, const Algorithm &algorithm) : m_algorithm(algorithm), m_threads(threads, -1), m_index(index), m_memChunk(memChunk), m_stridedIndex(stridedIndex), + m_unrollFactor(unrollFactor), m_worksize(worksize) { setIntensity(intensity); diff --git a/src/backend/opencl/generators/ocl_generic_cn_generator.cpp b/src/backend/opencl/generators/ocl_generic_cn_generator.cpp new file mode 100644 index 000000000..a6d598517 --- /dev/null +++ b/src/backend/opencl/generators/ocl_generic_cn_generator.cpp @@ -0,0 +1,115 @@ +/* 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/opencl/OclThreads.h" +#include "backend/opencl/wrappers/OclDevice.h" +#include "crypto/cn/CnAlgo.h" +#include "crypto/common/Algorithm.h" + + +namespace xmrig { + + +constexpr const size_t oneMiB = 1024u * 1024u; + + +static inline uint32_t getMaxThreads(const OclDevice &device, const Algorithm &algorithm) +{ + if (device.vendorId() == OCL_VENDOR_NVIDIA && (device.name().contains("P100") || device.name().contains("V100"))) { + return 40000u; + } + + return ((algorithm.l3() <= oneMiB) ? 2u : 1u) * 1000u; +} + + +static inline uint32_t getPossibleIntensity(const OclDevice &device, const Algorithm &algorithm) +{ + const uint32_t maxThreads = getMaxThreads(device, algorithm); + const size_t minFreeMem = (maxThreads == 40000u ? 512u : 128u) * oneMiB; + const size_t availableMem = device.freeMem() - minFreeMem; + const size_t perThread = algorithm.l3() + 224u; + const auto maxIntensity = static_cast(availableMem / perThread); + + return std::min(maxThreads, maxIntensity); +} + + +static uint32_t getIntensity(const OclDevice &device, const Algorithm &algorithm) +{ + if (device.type() == OclDevice::Raven) { + return 0; + } + + const uint32_t maxIntensity = getPossibleIntensity(device, algorithm); + + uint32_t intensity = (maxIntensity / (8 * device.computeUnits())) * device.computeUnits() * 8; + if (intensity == 0) { + return 0; + } + + if (device.vendorId() == OCL_VENDOR_AMD && (device.type() == OclDevice::Lexa || device.type() == OclDevice::Baffin || device.computeUnits() <= 16)) { + intensity /= 2; + + if (algorithm.family() == Algorithm::CN_HEAVY) { + intensity /= 2; + } + } + + return intensity; +} + + +static uint32_t getStridedIndex(const OclDevice &device, const Algorithm &algorithm) +{ + if (device.vendorId() != OCL_VENDOR_AMD) { + return 0; + } + + return CnAlgo<>::base(algorithm) == Algorithm::CN_2 ? 2 : 1; +} + + +bool ocl_generic_cn_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads) +{ + if (!algorithm.isCN()) { + return false; + } + + const uint32_t intensity = getIntensity(device, algorithm); + if (intensity == 0) { + return false; + } + + const uint32_t threadCount = ((device.globalMem() - intensity * 2 * algorithm.l3()) > 128 * oneMiB) ? 2 : 1; + + threads.add(OclThread(device.index(), intensity, 8, getStridedIndex(device, algorithm), 2, threadCount, 8, algorithm)); + + return true; +} + + +} // namespace xmrig diff --git a/src/backend/opencl/generators/ocl_vega_cn_generator.cpp b/src/backend/opencl/generators/ocl_vega_cn_generator.cpp new file mode 100644 index 000000000..f9e51b18a --- /dev/null +++ b/src/backend/opencl/generators/ocl_vega_cn_generator.cpp @@ -0,0 +1,132 @@ +/* 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/opencl/OclThreads.h" +#include "backend/opencl/wrappers/OclDevice.h" +#include "crypto/cn/CnAlgo.h" +#include "crypto/common/Algorithm.h" + + +namespace xmrig { + + +constexpr const size_t oneMiB = 1024u * 1024u; + + +static inline bool isMatch(const OclDevice &device, const Algorithm &algorithm) +{ + return algorithm.isCN() && + device.vendorId() == OCL_VENDOR_AMD && + (device.type() == OclDevice::Vega_10 || device.type() == OclDevice::Vega_20); +} + + +static inline uint32_t getMaxThreads(const OclDevice &device, const Algorithm &algorithm) +{ + const uint32_t ratio = (algorithm.l3() <= oneMiB) ? 2u : 1u; + + if (device.type() == OclDevice::Vega_10) { + if (device.computeUnits() == 56 && algorithm.family() == Algorithm::CN && CnAlgo<>::base(algorithm) == Algorithm::CN_2) { + return 1792u; + } + } + + return ratio * 2024u; +} + + +static inline uint32_t getPossibleIntensity(const OclDevice &device, const Algorithm &algorithm) +{ + const uint32_t maxThreads = getMaxThreads(device, algorithm); + const size_t availableMem = device.freeMem() - (128u * oneMiB); + const size_t perThread = algorithm.l3() + 224u; + const auto maxIntensity = static_cast(availableMem / perThread); + + return std::min(maxThreads, maxIntensity); +} + + +static inline uint32_t getIntensity(const OclDevice &device, const Algorithm &algorithm) +{ + const uint32_t maxIntensity = getPossibleIntensity(device, algorithm); + + if (device.type() == OclDevice::Vega_10) { + if (algorithm.family() == Algorithm::CN_HEAVY && device.computeUnits() == 64 && maxIntensity > 976) { + return 976; + } + } + + return maxIntensity / device.computeUnits() * device.computeUnits(); +} + + +static inline uint32_t getWorksize(const Algorithm &algorithm) +{ + if (algorithm.family() == Algorithm::CN_PICO) { + return 64; + } + + if (CnAlgo<>::base(algorithm) == Algorithm::CN_2) { + return 16; + } + + return 8; +} + + +static uint32_t getStridedIndex(const Algorithm &algorithm) +{ + return CnAlgo<>::base(algorithm) == Algorithm::CN_2 ? 2 : 1; +} + + +static inline uint32_t getMemChunk(const Algorithm &algorithm) +{ + return CnAlgo<>::base(algorithm) == Algorithm::CN_2 ? 1 : 2; +} + + +bool ocl_vega_cn_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads) +{ + if (!isMatch(device, algorithm)) { + return false; + } + + const uint32_t intensity = getIntensity(device, algorithm); + if (intensity == 0) { + return false; + } + + const uint32_t worksize = getWorksize(algorithm); + const uint32_t memChunk = getMemChunk(algorithm); + + threads.add(OclThread(device.index(), intensity, worksize, getStridedIndex(algorithm), memChunk, 2, 8, algorithm)); + + return true; +} + + +} // namespace xmrig diff --git a/src/backend/opencl/opencl.cmake b/src/backend/opencl/opencl.cmake index 547d5be7b..8974e8c4d 100644 --- a/src/backend/opencl/opencl.cmake +++ b/src/backend/opencl/opencl.cmake @@ -5,6 +5,8 @@ if (WITH_OPENCL) set(HEADERS_BACKEND_OPENCL src/backend/opencl/cl/OclSource.h + src/backend/opencl/generators/ocl_generic_cn_generator.cpp + src/backend/opencl/generators/ocl_vega_cn_generator.cpp src/backend/opencl/interfaces/IOclRunner.h src/backend/opencl/kernels/Cn0Kernel.h src/backend/opencl/kernels/Cn1Kernel.h @@ -13,6 +15,7 @@ if (WITH_OPENCL) src/backend/opencl/OclBackend.h src/backend/opencl/OclCache.h src/backend/opencl/OclConfig.h + src/backend/opencl/OclGenerator.h src/backend/opencl/OclInterleave.h src/backend/opencl/OclLaunchData.h src/backend/opencl/OclThread.h diff --git a/src/backend/opencl/wrappers/OclDevice.cpp b/src/backend/opencl/wrappers/OclDevice.cpp index 184ab2401..e95c9d43a 100644 --- a/src/backend/opencl/wrappers/OclDevice.cpp +++ b/src/backend/opencl/wrappers/OclDevice.cpp @@ -23,11 +23,10 @@ */ -#include - - -#include "backend/opencl/OclThreads.h" #include "backend/opencl/wrappers/OclDevice.h" + +#include "backend/opencl/OclGenerator.h" +#include "backend/opencl/OclThreads.h" #include "backend/opencl/wrappers/OclLib.h" #include "base/io/log/Log.h" #include "crypto/cn/CnAlgo.h" @@ -35,6 +34,9 @@ #include "rapidjson/document.h" +#include + + typedef union { struct { cl_uint type; cl_uint data[5]; } raw; @@ -45,7 +47,14 @@ typedef union namespace xmrig { -constexpr const size_t oneMiB = 1024u * 1024u; +extern bool ocl_vega_cn_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads); +extern bool ocl_generic_cn_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads); + + +ocl_gen_config_fun generators[] = { + ocl_vega_cn_generator, + ocl_generic_cn_generator +}; static OclVendor getVendorId(const String &vendor) @@ -176,119 +185,9 @@ uint32_t xmrig::OclDevice::clock() const void xmrig::OclDevice::generate(const Algorithm &algorithm, OclThreads &threads) const { - uint32_t intensity = getIntensity(algorithm); - if (intensity == 0) { - return; - } - - const uint32_t worksize = getWorksize(algorithm); - const uint32_t stridedIndex = getStridedIndex(algorithm); - const uint32_t memChunk = getMemChunk(algorithm); - const uint32_t threadCount = ((globalMem() - intensity * 2 * algorithm.l3()) > 128 * oneMiB) ? 2 : 1; - - threads.add(OclThread(index(), intensity, worksize, stridedIndex, memChunk, threadCount, algorithm)); -} - - -uint32_t xmrig::OclDevice::getIntensity(const Algorithm &algorithm) const -{ - if(m_type == Raven) { - return 0; - } - - const uint32_t maxIntensity = getPossibleIntensity(algorithm); - - if (m_type == Vega_10) { - if (algorithm.family() == Algorithm::CN_HEAVY && m_computeUnits && maxIntensity > 976) { - return 976; - } - - return maxIntensity / m_computeUnits * m_computeUnits; - } - - uint32_t intensity = (maxIntensity / (8 * m_computeUnits)) * m_computeUnits * 8; - if (intensity == 0) { - return 0; - } - - if (m_vendorId == OCL_VENDOR_AMD && (m_type == Lexa || m_type == Baffin || m_computeUnits <= 16)) { - intensity /= 2; - - if (algorithm.family() == Algorithm::CN_HEAVY) { - intensity /= 2; + for (auto fn : generators) { + if (fn(*this, algorithm, threads)) { + return; } } - - return intensity; -} - - -uint32_t xmrig::OclDevice::getMaxThreads(const Algorithm &algorithm) const -{ - if (m_vendorId == OCL_VENDOR_NVIDIA && (m_name.contains("P100") || m_name.contains("V100"))) { - return 40000u; - } - - const uint32_t ratio = (algorithm.l3() <= oneMiB) ? 2u : 1u; - if (m_type == Vega_10 || m_type == Vega_20) { - if (computeUnits() == 56 && isCNv2(algorithm)) { - return 1792u; - } - - return ratio * 2024u; - } - - return ratio * 1000u; -} - - -uint32_t xmrig::OclDevice::getMemChunk(const Algorithm &algorithm) const -{ - if ((m_type == Vega_10 || m_type == Vega_20) && (algorithm.family() == Algorithm::CN_PICO || isCNv2(algorithm))) { - return 1; - } - - return 2; -} - - -uint32_t xmrig::OclDevice::getPossibleIntensity(const Algorithm &algorithm) const -{ - const uint32_t maxThreads = getMaxThreads(algorithm); - const size_t minFreeMem = (maxThreads == 40000u ? 512u : 128u) * oneMiB; - const size_t availableMem = freeMem() - minFreeMem; - const size_t perThread = algorithm.l3() + 224u; - const auto maxIntensity = static_cast(availableMem / perThread); - - return std::min(maxThreads, maxIntensity); -} - - -uint32_t xmrig::OclDevice::getStridedIndex(const Algorithm &algorithm) const -{ - if (m_vendorId == OCL_VENDOR_NVIDIA) { - return 0; - } - - if (algorithm.family() == Algorithm::CN_PICO || isCNv2(algorithm)) { - return 2; - } - - return 1; -} - - -uint32_t xmrig::OclDevice::getWorksize(const Algorithm &algorithm) const -{ - if (m_type == Vega_10 || m_type == Vega_20) { - if (algorithm.family() == Algorithm::CN_PICO) { - return 64; - } - - if (isCNv2(algorithm)) { - return 16; - } - } - - return 8; } diff --git a/src/backend/opencl/wrappers/OclDevice.h b/src/backend/opencl/wrappers/OclDevice.h index 8b502da95..0790199d5 100644 --- a/src/backend/opencl/wrappers/OclDevice.h +++ b/src/backend/opencl/wrappers/OclDevice.h @@ -76,17 +76,11 @@ public: inline const String &name() const { return m_name; } inline const String &vendor() const { return m_vendor; } inline OclVendor vendorId() const { return m_vendorId; } + inline Type type() const { return m_type; } inline uint32_t computeUnits() const { return m_computeUnits; } inline uint32_t index() const { return m_index; } private: - uint32_t getIntensity(const Algorithm &algorithm) const; - uint32_t getMaxThreads(const Algorithm &algorithm) const; - uint32_t getMemChunk(const Algorithm &algorithm) const; - uint32_t getPossibleIntensity(const Algorithm &algorithm) const; - uint32_t getStridedIndex(const Algorithm &algorithm) const; - uint32_t getWorksize(const Algorithm &algorithm) const; - bool m_topology = false; cl_device_id m_id = nullptr; cl_platform_id m_platform = nullptr; diff --git a/src/crypto/cn/CnHash.cpp b/src/crypto/cn/CnHash.cpp index 29e5346c3..c6fe944e6 100644 --- a/src/crypto/cn/CnHash.cpp +++ b/src/crypto/cn/CnHash.cpp @@ -23,7 +23,7 @@ * along with this program. If not, see . */ -#include +#include #include "backend/cpu/Cpu.h" @@ -66,12 +66,6 @@ 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 { @@ -99,7 +93,7 @@ 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); + auto p = reinterpret_cast(src); // Workaround for Visual Studio placing trampoline in debug builds. # if defined(_MSC_VER) @@ -117,7 +111,7 @@ static void patchCode(T dst, U src, const uint32_t iterations, const uint32_t ma memcpy((void*) dst, (const void*) src, size); - uint8_t* patched_data = reinterpret_cast(dst); + auto 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(): @@ -135,7 +129,7 @@ static void patchCode(T dst, U src, const uint32_t iterations, const uint32_t ma static void patchAsmVariants() { const int allocation_size = 65536; - uint8_t *base = static_cast(VirtualMemory::allocateExecutableMemory(allocation_size)); + auto 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); diff --git a/src/crypto/cn/CnHash.h b/src/crypto/cn/CnHash.h index e4a7ebd22..92f4df942 100644 --- a/src/crypto/cn/CnHash.h +++ b/src/crypto/cn/CnHash.h @@ -27,8 +27,8 @@ #define XMRIG_CN_HASH_H -#include -#include +#include +#include #include "crypto/cn/CnAlgo.h" @@ -41,8 +41,8 @@ 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); +using cn_hash_fun = void (*)(const uint8_t *, size_t, uint8_t *, cryptonight_ctx **, uint64_t); +using cn_mainloop_fun = void (*)(cryptonight_ctx **); class CnHash diff --git a/src/crypto/common/Algorithm.h b/src/crypto/common/Algorithm.h index 93abb6558..cc0206770 100644 --- a/src/crypto/common/Algorithm.h +++ b/src/crypto/common/Algorithm.h @@ -81,6 +81,7 @@ public: inline Algorithm(const char *algo) : m_id(parse(algo)) {} inline Algorithm(Id id) : m_id(id) {} + inline bool isCN() const { auto f = family(); return f == CN || f == CN_LITE || f == CN_HEAVY || f == CN_PICO; } 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); }