/* 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-2020 SChernykh * Copyright 2016-2020 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/cuda/wrappers/CudaLib.h" #include "base/io/Env.h" #include "base/io/log/Log.h" #include "crypto/rx/RxAlgo.h" namespace xmrig { enum Version : uint32_t { ApiVersion, DriverVersion, RuntimeVersion }; static uv_lib_t cudaLib; static const char *kAlloc = "alloc"; static const char *kAstroBWTHash = "astroBWTHash"; static const char *kAstroBWTPrepare = "astroBWTPrepare"; static const char *kCnHash = "cnHash"; static const char *kDeviceCount = "deviceCount"; static const char *kDeviceInfo = "deviceInfo"; static const char *kDeviceInfo_v2 = "deviceInfo_v2"; static const char *kDeviceInit = "deviceInit"; static const char *kDeviceInt = "deviceInt"; static const char *kDeviceName = "deviceName"; static const char *kDeviceUint = "deviceUint"; static const char *kDeviceUlong = "deviceUlong"; static const char *kInit = "init"; static const char *kLastError = "lastError"; static const char *kPluginVersion = "pluginVersion"; static const char *kRelease = "release"; static const char *kRxHash = "rxHash"; static const char *kRxPrepare = "rxPrepare"; static const char *kKawPowHash = "KawPowHash"; static const char *kKawPowPrepare = "KawPowPrepare"; static const char *kSetJob = "setJob"; static const char *kSetJob_v2 = "setJob_v2"; static const char *kVersion = "version"; using alloc_t = nvid_ctx * (*)(uint32_t, int32_t, int32_t); using astroBWTHash_t = bool (*)(nvid_ctx *, uint32_t, uint64_t, uint32_t *, uint32_t *); using astroBWTPrepare_t = bool (*)(nvid_ctx *, uint32_t); using cnHash_t = bool (*)(nvid_ctx *, uint32_t, uint64_t, uint64_t, uint32_t *, uint32_t *); using deviceCount_t = uint32_t (*)(); using deviceInfo_t = int32_t (*)(nvid_ctx *, int32_t, int32_t, int32_t, int32_t); using deviceInfo_v2_t = bool (*)(nvid_ctx *, int32_t, int32_t, const char *, int32_t); using deviceInit_t = bool (*)(nvid_ctx *); using deviceInt_t = int32_t (*)(nvid_ctx *, CudaLib::DeviceProperty); using deviceName_t = const char * (*)(nvid_ctx *); using deviceUint_t = uint32_t (*)(nvid_ctx *, CudaLib::DeviceProperty); using deviceUlong_t = uint64_t (*)(nvid_ctx *, CudaLib::DeviceProperty); using init_t = void (*)(); using lastError_t = const char * (*)(nvid_ctx *); using pluginVersion_t = const char * (*)(); using release_t = void (*)(nvid_ctx *); using rxHash_t = bool (*)(nvid_ctx *, uint32_t, uint64_t, uint32_t *, uint32_t *); using rxPrepare_t = bool (*)(nvid_ctx *, const void *, size_t, bool, uint32_t); using KawPowHash_t = bool (*)(nvid_ctx *, uint8_t*, uint64_t, uint32_t *, uint32_t *); using KawPowPrepare_t = bool (*)(nvid_ctx *, const void *, size_t, size_t, uint32_t, const uint64_t*); using setJob_t = bool (*)(nvid_ctx *, const void *, size_t, int32_t); using setJob_v2_t = bool (*)(nvid_ctx *, const void *, size_t, const char *); using version_t = uint32_t (*)(Version); static alloc_t pAlloc = nullptr; static astroBWTHash_t pAstroBWTHash = nullptr; static astroBWTPrepare_t pAstroBWTPrepare = nullptr; static cnHash_t pCnHash = nullptr; static deviceCount_t pDeviceCount = nullptr; static deviceInfo_t pDeviceInfo = nullptr; static deviceInfo_v2_t pDeviceInfo_v2 = nullptr; static deviceInit_t pDeviceInit = nullptr; static deviceInt_t pDeviceInt = nullptr; static deviceName_t pDeviceName = nullptr; static deviceUint_t pDeviceUint = nullptr; static deviceUlong_t pDeviceUlong = nullptr; static init_t pInit = nullptr; static lastError_t pLastError = nullptr; static pluginVersion_t pPluginVersion = nullptr; static release_t pRelease = nullptr; static rxHash_t pRxHash = nullptr; static rxPrepare_t pRxPrepare = nullptr; static KawPowHash_t pKawPowHash = nullptr; static KawPowPrepare_t pKawPowPrepare = nullptr; static setJob_t pSetJob = nullptr; static setJob_v2_t pSetJob_v2 = nullptr; static version_t pVersion = nullptr; #define DLSYM(x) if (uv_dlsym(&cudaLib, k##x, reinterpret_cast(&p##x)) == -1) { throw std::runtime_error("symbol not found (" #x ")"); } bool CudaLib::m_initialized = false; bool CudaLib::m_ready = false; String CudaLib::m_loader; } // namespace xmrig bool xmrig::CudaLib::init(const char *fileName) { if (!m_initialized) { m_loader = fileName == nullptr ? defaultLoader() : Env::expand(fileName); m_ready = uv_dlopen(m_loader, &cudaLib) == 0 && load(); m_initialized = true; } return m_ready; } const char *xmrig::CudaLib::lastError() noexcept { return uv_dlerror(&cudaLib); } void xmrig::CudaLib::close() { uv_dlclose(&cudaLib); } bool xmrig::CudaLib::astroBWTHash(nvid_ctx *ctx, uint32_t startNonce, uint64_t target, uint32_t *rescount, uint32_t *resnonce) noexcept { return pAstroBWTHash(ctx, startNonce, target, rescount, resnonce); } bool xmrig::CudaLib::astroBWTPrepare(nvid_ctx *ctx, uint32_t batchSize) noexcept { return pAstroBWTPrepare(ctx, batchSize); } bool xmrig::CudaLib::cnHash(nvid_ctx *ctx, uint32_t startNonce, uint64_t height, uint64_t target, uint32_t *rescount, uint32_t *resnonce) { return pCnHash(ctx, startNonce, height, target, rescount, resnonce); } bool xmrig::CudaLib::deviceInfo(nvid_ctx *ctx, int32_t blocks, int32_t threads, const Algorithm &algorithm, int32_t dataset_host) noexcept { const Algorithm algo = RxAlgo::id(algorithm); if (pDeviceInfo_v2) { return pDeviceInfo_v2(ctx, blocks, threads, algo.isValid() ? algo.shortName() : nullptr, dataset_host); } return pDeviceInfo(ctx, blocks, threads, algo, dataset_host) == 0; } bool xmrig::CudaLib::deviceInit(nvid_ctx *ctx) noexcept { return pDeviceInit(ctx); } bool xmrig::CudaLib::rxHash(nvid_ctx *ctx, uint32_t startNonce, uint64_t target, uint32_t *rescount, uint32_t *resnonce) noexcept { return pRxHash(ctx, startNonce, target, rescount, resnonce); } bool xmrig::CudaLib::rxPrepare(nvid_ctx *ctx, const void *dataset, size_t datasetSize, bool dataset_host, uint32_t batchSize) noexcept { return pRxPrepare(ctx, dataset, datasetSize, dataset_host, batchSize); } bool xmrig::CudaLib::KawPowHash(nvid_ctx *ctx, uint8_t* job_blob, uint64_t target, uint32_t *rescount, uint32_t *resnonce) noexcept { return pKawPowHash(ctx, job_blob, target, rescount, resnonce); } bool xmrig::CudaLib::KawPowPrepare(nvid_ctx *ctx, const void* cache, size_t cache_size, size_t dag_size, uint32_t height, const uint64_t* dag_sizes) noexcept { return pKawPowPrepare(ctx, cache, cache_size, dag_size, height, dag_sizes); } bool xmrig::CudaLib::setJob(nvid_ctx *ctx, const void *data, size_t size, const Algorithm &algorithm) noexcept { const Algorithm algo = RxAlgo::id(algorithm); if (pSetJob_v2) { return pSetJob_v2(ctx, data, size, algo.shortName()); } return pSetJob(ctx, data, size, algo); } const char *xmrig::CudaLib::deviceName(nvid_ctx *ctx) noexcept { return pDeviceName(ctx); } const char *xmrig::CudaLib::lastError(nvid_ctx *ctx) noexcept { return pLastError(ctx); } const char *xmrig::CudaLib::pluginVersion() noexcept { return pPluginVersion(); } int32_t xmrig::CudaLib::deviceInt(nvid_ctx *ctx, DeviceProperty property) noexcept { return pDeviceInt(ctx, property); } nvid_ctx *xmrig::CudaLib::alloc(uint32_t id, int32_t bfactor, int32_t bsleep) noexcept { return pAlloc(id, bfactor, bsleep); } std::string xmrig::CudaLib::version(uint32_t version) { return std::to_string(version / 1000) + "." + std::to_string((version % 1000) / 10); } std::vector xmrig::CudaLib::devices(int32_t bfactor, int32_t bsleep, const std::vector &hints) noexcept { const uint32_t count = deviceCount(); if (!count) { return {}; } std::vector out; out.reserve(count); if (hints.empty()) { for (uint32_t i = 0; i < count; ++i) { CudaDevice device(i, bfactor, bsleep); if (device.isValid()) { out.emplace_back(std::move(device)); } } } else { for (const uint32_t i : hints) { if (i >= count) { continue; } CudaDevice device(i, bfactor, bsleep); if (device.isValid()) { out.emplace_back(std::move(device)); } } } return out; } uint32_t xmrig::CudaLib::deviceCount() noexcept { return pDeviceCount(); } uint32_t xmrig::CudaLib::deviceUint(nvid_ctx *ctx, DeviceProperty property) noexcept { return pDeviceUint(ctx, property); } uint32_t xmrig::CudaLib::driverVersion() noexcept { return pVersion(DriverVersion); } uint32_t xmrig::CudaLib::runtimeVersion() noexcept { return pVersion(RuntimeVersion); } uint64_t xmrig::CudaLib::deviceUlong(nvid_ctx *ctx, DeviceProperty property) noexcept { return pDeviceUlong(ctx, property); } void xmrig::CudaLib::release(nvid_ctx *ctx) noexcept { pRelease(ctx); } bool xmrig::CudaLib::load() { if (uv_dlsym(&cudaLib, kVersion, reinterpret_cast(&pVersion)) == -1) { return false; } if (pVersion(ApiVersion) != 6u) { return false; } uv_dlsym(&cudaLib, kDeviceInfo_v2, reinterpret_cast(&pDeviceInfo_v2)); uv_dlsym(&cudaLib, kSetJob_v2, reinterpret_cast(&pSetJob_v2)); try { DLSYM(Alloc); DLSYM(CnHash); DLSYM(DeviceCount); DLSYM(DeviceInit); DLSYM(DeviceInt); DLSYM(DeviceName); DLSYM(DeviceUint); DLSYM(DeviceUlong); DLSYM(Init); DLSYM(LastError); DLSYM(PluginVersion); DLSYM(Release); DLSYM(RxHash); DLSYM(RxPrepare); DLSYM(AstroBWTHash); DLSYM(AstroBWTPrepare); DLSYM(KawPowHash); DLSYM(KawPowPrepare); DLSYM(Version); if (!pDeviceInfo_v2) { DLSYM(DeviceInfo); } if (!pSetJob_v2) { DLSYM(SetJob); } } catch (std::exception &ex) { LOG_ERR("Error loading CUDA library: %s", ex.what()); return false; } pInit(); return true; } xmrig::String xmrig::CudaLib::defaultLoader() { # if defined(__APPLE__) return "/System/Library/Frameworks/OpenCL.framework/OpenCL"; // FIXME # elif defined(_WIN32) return "xmrig-cuda.dll"; # else return "libxmrig-cuda.so"; # endif }