diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a195f6e0..849c1257e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ option(WITH_ASM "Enable ASM PoW implementations" ON) option(WITH_EMBEDDED_CONFIG "Enable internal embedded JSON config" OFF) option(WITH_OPENCL "Enable OpenCL backend" ON) option(WITH_CUDA "Enable CUDA backend" ON) +option(WITH_NVML "Enable NVML (NVIDIA Management Library) support (only if CUDA backend enabled)" ON) option(WITH_STRICT_CACHE "Enable strict checks for OpenCL cache" ON) option(WITH_INTERLEAVE_DEBUG_LOG "Enable debug log for threads interleave" OFF) diff --git a/README.md b/README.md index cffb28c7a..fa2e814ad 100644 --- a/README.md +++ b/README.md @@ -84,11 +84,13 @@ OpenCL backend: CUDA backend: --cuda enable CUDA mining backend --cuda-loader=PATH path to CUDA plugin (xmrig-cuda.dll or libxmrig-cuda.so) + --no-nvml disable NVML (NVIDIA Management Library) support Logging: -S, --syslog use system log for output messages -l, --log-file=FILE log all output to a file --print-time=N print hashrate report every N seconds + --health-print-time=N print health report every N seconds --no-color disable colored output Misc: diff --git a/src/App.cpp b/src/App.cpp index 7db2ace28..04b054515 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -98,29 +98,12 @@ int xmrig::App::exec() void xmrig::App::onConsoleCommand(char command) { - switch (command) { - case 'h': - case 'H': - m_controller->miner()->printHashrate(true); - break; - - case 'p': - case 'P': - m_controller->miner()->setEnabled(false); - break; - - case 'r': - case 'R': - m_controller->miner()->setEnabled(true); - break; - - case 3: + if (command == 3) { LOG_WARN("Ctrl+C received, exiting"); close(); - break; - - default: - break; + } + else { + m_controller->miner()->execCommand(command); } } diff --git a/src/Summary.cpp b/src/Summary.cpp index 2b8939a7a..2055e972a 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -126,9 +126,9 @@ static void print_threads(Config *config) static void print_commands(Config *) { if (Log::colors) { - Log::print(GREEN_BOLD(" * ") WHITE_BOLD("COMMANDS ") MAGENTA_BOLD("h") WHITE_BOLD("ashrate, ") - MAGENTA_BOLD("p") WHITE_BOLD("ause, ") - MAGENTA_BOLD("r") WHITE_BOLD("esume")); + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("COMMANDS ") MAGENTA_BG(WHITE_BOLD_S "h") WHITE_BOLD("ashrate, ") + MAGENTA_BG(WHITE_BOLD_S "p") WHITE_BOLD("ause, ") + MAGENTA_BG(WHITE_BOLD_S "r") WHITE_BOLD("esume")); } else { Log::print(" * COMMANDS 'h' hashrate, 'p' pause, 'r' resume"); diff --git a/src/backend/common/interfaces/IBackend.h b/src/backend/common/interfaces/IBackend.h index f90732293..c6e05bcfb 100644 --- a/src/backend/common/interfaces/IBackend.h +++ b/src/backend/common/interfaces/IBackend.h @@ -53,6 +53,7 @@ public: virtual const Hashrate *hashrate() const = 0; virtual const String &profileName() const = 0; virtual const String &type() const = 0; + virtual void execCommand(char command) = 0; virtual void prepare(const Job &nextJob) = 0; virtual void printHashrate(bool details) = 0; virtual void setJob(const Job &job) = 0; diff --git a/src/backend/cpu/CpuBackend.h b/src/backend/cpu/CpuBackend.h index d5d9fbf6c..d0e2267a2 100644 --- a/src/backend/cpu/CpuBackend.h +++ b/src/backend/cpu/CpuBackend.h @@ -50,6 +50,8 @@ public: ~CpuBackend() override; protected: + inline void execCommand(char) override {} + bool isEnabled() const override; bool isEnabled(const Algorithm &algorithm) const override; const Hashrate *hashrate() const override; diff --git a/src/backend/cuda/CudaBackend.cpp b/src/backend/cuda/CudaBackend.cpp index db0d512e3..feb1dd93f 100644 --- a/src/backend/cuda/CudaBackend.cpp +++ b/src/backend/cuda/CudaBackend.cpp @@ -51,6 +51,13 @@ #endif +#ifdef XMRIG_FEATURE_NVML +#include "backend/cuda/wrappers/NvmlLib.h" + +namespace xmrig { static const char *kNvmlLabel = "NVML"; } +#endif + + namespace xmrig { @@ -58,15 +65,16 @@ extern template class Threads<CudaThreads>; constexpr const size_t oneMiB = 1024u * 1024u; +static const char *kLabel = "CUDA"; static const char *tag = GREEN_BG_BOLD(WHITE_BOLD_S " nv "); static const String kType = "cuda"; static std::mutex mutex; -static void printDisabled(const char *reason) +static void printDisabled(const char *label, const char *reason) { - Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") RED_BOLD("disabled") "%s", "CUDA", reason); + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") RED_BOLD("disabled") "%s", label, reason); } @@ -129,29 +137,49 @@ public: void init(const CudaConfig &cuda) { if (!cuda.isEnabled()) { - return printDisabled(""); + return printDisabled(kLabel, ""); } if (!CudaLib::init(cuda.loader())) { - return printDisabled(RED_S " (failed to load CUDA plugin)"); + return printDisabled(kLabel, RED_S " (failed to load CUDA plugin)"); } runtimeVersion = CudaLib::runtimeVersion(); driverVersion = CudaLib::driverVersion(); if (!runtimeVersion || !driverVersion || !CudaLib::deviceCount()) { - return printDisabled(RED_S " (no devices)"); + return printDisabled(kLabel, RED_S " (no devices)"); } if (!devices.empty()) { return; } - Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s") "/" WHITE_BOLD("%s") BLACK_BOLD("/%s"), "CUDA", + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s") "/" WHITE_BOLD("%s") BLACK_BOLD("/%s"), kLabel, CudaLib::version(runtimeVersion).c_str(), CudaLib::version(driverVersion).c_str(), CudaLib::pluginVersion()); devices = CudaLib::devices(cuda.bfactor(), cuda.bsleep()); +# ifdef XMRIG_FEATURE_NVML + if (cuda.isNvmlEnabled()) { + if (NvmlLib::init(cuda.nvmlLoader())) { + NvmlLib::assign(devices); + + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s") "/" GREEN_BOLD("%s") " press " MAGENTA_BG(WHITE_BOLD_S "e") " for health report", + kNvmlLabel, + NvmlLib::version(), + NvmlLib::driverVersion() + ); + } + else { + printDisabled(kLabel, RED_S " (failed to load NVML)"); + } + } + else { + printDisabled(kNvmlLabel, ""); + } +# endif + for (const CudaDevice &device : devices) { Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("#%zu") YELLOW(" %s") GREEN_BOLD(" %s ") WHITE_BOLD("%u/%u MHz") " smx:" WHITE_BOLD("%u") " arch:" WHITE_BOLD("%u%u") " mem:" CYAN("%zu/%zu") " MB", "CUDA GPU", @@ -205,6 +233,38 @@ public: } +# ifdef XMRIG_FEATURE_NVML + void printHealth() + { + for (const auto &device : devices) { + const auto health = NvmlLib::health(device.nvmlDevice()); + + std::string clocks; + if (health.clock && health.memClock) { + clocks += " " + std::to_string(health.clock) + "/" + std::to_string(health.memClock) + " MHz"; + } + + std::string fans; + if (!health.fanSpeed.empty()) { + for (uint32_t i = 0; i < health.fanSpeed.size(); ++i) { + fans += " fan" + std::to_string(i) + ":" CYAN_BOLD_S + std::to_string(health.fanSpeed[i]) + "%" CLEAR; + } + } + + LOG_INFO(CYAN_BOLD("#%u") YELLOW(" %s") MAGENTA_BOLD("%4uW") CSI "1;%um %2uC" CLEAR WHITE_BOLD("%s") "%s", + device.index(), + device.topology().toString().data(), + health.power, + health.temperature < 60 ? 32 : (health.temperature > 85 ? 31 : 33), + health.temperature, + clocks.c_str(), + fans.c_str() + ); + } + } +# endif + + Algorithm algo; Controller *controller; CudaLaunchStatus status; @@ -238,6 +298,10 @@ xmrig::CudaBackend::~CudaBackend() delete d_ptr; CudaLib::close(); + +# ifdef XMRIG_FEATURE_NVML + NvmlLib::close(); +# endif } @@ -271,6 +335,16 @@ const xmrig::String &xmrig::CudaBackend::type() const } +void xmrig::CudaBackend::execCommand(char command) +{ +# ifdef XMRIG_FEATURE_NVML + if (command == 'e' || command == 'E') { + d_ptr->printHealth(); + } +# endif +} + + void xmrig::CudaBackend::prepare(const Job &) { } @@ -378,6 +452,13 @@ void xmrig::CudaBackend::stop() void xmrig::CudaBackend::tick(uint64_t ticks) { d_ptr->workers.tick(ticks); + +# ifdef XMRIG_FEATURE_NVML + auto seconds = d_ptr->controller->config()->healthPrintTime(); + if (seconds && ticks && (ticks % (seconds * 2)) == 0) { + d_ptr->printHealth(); + } +# endif } @@ -394,10 +475,18 @@ rapidjson::Value xmrig::CudaBackend::toJSON(rapidjson::Document &doc) const out.AddMember("profile", profileName().toJSON(), allocator); Value versions(kObjectType); - versions.AddMember("runtime", Value(CudaLib::version(d_ptr->runtimeVersion).c_str(), allocator), allocator); - versions.AddMember("driver", Value(CudaLib::version(d_ptr->driverVersion).c_str(), allocator), allocator); - versions.AddMember("plugin", String(CudaLib::pluginVersion()).toJSON(doc), allocator); - out.AddMember("versions", versions, allocator); + versions.AddMember("cuda-runtime", Value(CudaLib::version(d_ptr->runtimeVersion).c_str(), allocator), allocator); + versions.AddMember("cuda-driver", Value(CudaLib::version(d_ptr->driverVersion).c_str(), allocator), allocator); + versions.AddMember("plugin", String(CudaLib::pluginVersion()).toJSON(doc), allocator); + +# ifdef XMRIG_FEATURE_NVML + if (NvmlLib::isReady()) { + versions.AddMember("nvml", StringRef(NvmlLib::version()), allocator); + versions.AddMember("driver", StringRef(NvmlLib::driverVersion()), allocator); + } +# endif + + out.AddMember("versions", versions, allocator); if (d_ptr->threads.empty() || !hashrate()) { return out; diff --git a/src/backend/cuda/CudaBackend.h b/src/backend/cuda/CudaBackend.h index 0d2a2395d..cf0bb6217 100644 --- a/src/backend/cuda/CudaBackend.h +++ b/src/backend/cuda/CudaBackend.h @@ -56,6 +56,7 @@ protected: const Hashrate *hashrate() const override; const String &profileName() const override; const String &type() const override; + void execCommand(char command) override; void prepare(const Job &nextJob) override; void printHashrate(bool details) override; void setJob(const Job &job) override; diff --git a/src/backend/cuda/CudaConfig.cpp b/src/backend/cuda/CudaConfig.cpp index 19817c65b..49a28d114 100644 --- a/src/backend/cuda/CudaConfig.cpp +++ b/src/backend/cuda/CudaConfig.cpp @@ -40,6 +40,10 @@ static const char *kDevicesHint = "devices-hint"; static const char *kEnabled = "enabled"; static const char *kLoader = "loader"; +#ifdef XMRIG_FEATURE_NVML +static const char *kNvml = "nvml"; +#endif + extern template class Threads<CudaThreads>; @@ -57,6 +61,15 @@ rapidjson::Value xmrig::CudaConfig::toJSON(rapidjson::Document &doc) const obj.AddMember(StringRef(kEnabled), m_enabled, allocator); obj.AddMember(StringRef(kLoader), m_loader.toJSON(), allocator); +# ifdef XMRIG_FEATURE_NVML + if (m_nvmlLoader.isNull()) { + obj.AddMember(StringRef(kNvml), m_nvml, allocator); + } + else { + obj.AddMember(StringRef(kNvml), m_nvmlLoader.toJSON(), allocator); + } +# endif + m_threads.toJSON(obj, doc); return obj; @@ -95,6 +108,16 @@ void xmrig::CudaConfig::read(const rapidjson::Value &value) setDevicesHint(Json::getString(value, kDevicesHint)); +# ifdef XMRIG_FEATURE_NVML + auto &nvml = Json::getValue(value, kNvml); + if (nvml.IsString()) { + m_nvmlLoader = nvml.GetString(); + } + else if (nvml.IsBool()) { + m_nvml = nvml.GetBool(); + } +# endif + m_threads.read(value); generate(); diff --git a/src/backend/cuda/CudaConfig.h b/src/backend/cuda/CudaConfig.h index 4367d8267..77be3dd41 100644 --- a/src/backend/cuda/CudaConfig.h +++ b/src/backend/cuda/CudaConfig.h @@ -50,6 +50,11 @@ public: inline int32_t bfactor() const { return m_bfactor; } inline int32_t bsleep() const { return m_bsleep; } +# ifdef XMRIG_FEATURE_NVML + inline bool isNvmlEnabled() const { return m_nvml; } + inline const String &nvmlLoader() const { return m_nvmlLoader; } +# endif + private: void generate(); void setDevicesHint(const char *devicesHint); @@ -67,6 +72,11 @@ private: int32_t m_bfactor = 0; int32_t m_bsleep = 0; # endif + +# ifdef XMRIG_FEATURE_NVML + bool m_nvml = true; + String m_nvmlLoader; +# endif }; diff --git a/src/backend/cuda/cuda.cmake b/src/backend/cuda/cuda.cmake index 764acd0f0..58ba3f5a5 100644 --- a/src/backend/cuda/cuda.cmake +++ b/src/backend/cuda/cuda.cmake @@ -30,8 +30,23 @@ if (WITH_CUDA) src/backend/cuda/wrappers/CudaDevice.cpp src/backend/cuda/wrappers/CudaLib.cpp ) + + if (WITH_NVML AND NOT APPLE) + add_definitions(/DXMRIG_FEATURE_NVML) + + list(APPEND HEADERS_BACKEND_CUDA + src/backend/cuda/wrappers/nvml_lite.h + src/backend/cuda/wrappers/NvmlHealth.h + src/backend/cuda/wrappers/NvmlLib.h + ) + + list(APPEND SOURCES_BACKEND_CUDA src/backend/cuda/wrappers/NvmlLib.cpp) + else() + remove_definitions(/DXMRIG_FEATURE_NVML) + endif() else() remove_definitions(/DXMRIG_FEATURE_CUDA) + remove_definitions(/DXMRIG_FEATURE_NVML) set(HEADERS_BACKEND_CUDA "") set(SOURCES_BACKEND_CUDA "") diff --git a/src/backend/cuda/wrappers/CudaDevice.cpp b/src/backend/cuda/wrappers/CudaDevice.cpp index 740a063c5..efacc800e 100644 --- a/src/backend/cuda/wrappers/CudaDevice.cpp +++ b/src/backend/cuda/wrappers/CudaDevice.cpp @@ -30,6 +30,9 @@ #include "crypto/common/Algorithm.h" #include "rapidjson/document.h" +#ifdef XMRIG_FEATURE_NVML +# include "backend/cuda/wrappers/NvmlLib.h" +#endif #include <algorithm> @@ -125,5 +128,25 @@ void xmrig::CudaDevice::toJSON(rapidjson::Value &out, rapidjson::Document &doc) out.AddMember("global_mem", static_cast<uint64_t>(globalMemSize()), allocator); out.AddMember("clock", clock(), allocator); out.AddMember("memory_clock", memoryClock(), allocator); + +# ifdef XMRIG_FEATURE_NVML + if (m_nvmlDevice) { + auto data = NvmlLib::health(m_nvmlDevice); + + Value health(kObjectType); + health.AddMember("temperature", data.temperature, allocator); + health.AddMember("power", data.power, allocator); + health.AddMember("clock", data.clock, allocator); + health.AddMember("mem_clock", data.memClock, allocator); + + Value fanSpeed(kArrayType); + for (auto speed : data.fanSpeed) { + fanSpeed.PushBack(speed, allocator); + } + health.AddMember("fan_speed", fanSpeed, allocator); + + out.AddMember("health", health, allocator); + } +# endif } #endif diff --git a/src/backend/cuda/wrappers/CudaDevice.h b/src/backend/cuda/wrappers/CudaDevice.h index 07866c82e..8c624c852 100644 --- a/src/backend/cuda/wrappers/CudaDevice.h +++ b/src/backend/cuda/wrappers/CudaDevice.h @@ -30,7 +30,8 @@ #include "base/tools/String.h" -using nvid_ctx = struct nvid_ctx; +using nvid_ctx = struct nvid_ctx; +using nvmlDevice_t = struct nvmlDevice_st *; namespace xmrig { @@ -57,11 +58,16 @@ public: uint32_t smx() const; void generate(const Algorithm &algorithm, CudaThreads &threads) const; - inline bool isValid() const { return m_ctx != nullptr; } - inline const PciTopology &topology() const { return m_topology; } - inline const String &name() const { return m_name; } - inline uint32_t arch() const { return (computeCapability(true) * 10) + computeCapability(false); } - inline uint32_t index() const { return m_index; } + inline bool isValid() const { return m_ctx != nullptr; } + inline const PciTopology &topology() const { return m_topology; } + inline const String &name() const { return m_name; } + inline uint32_t arch() const { return (computeCapability(true) * 10) + computeCapability(false); } + inline uint32_t index() const { return m_index; } + +# ifdef XMRIG_FEATURE_NVML + inline nvmlDevice_t nvmlDevice() const { return m_nvmlDevice; } + inline void setNvmlDevice(nvmlDevice_t device) { m_nvmlDevice = device; } +# endif # ifdef XMRIG_FEATURE_API void toJSON(rapidjson::Value &out, rapidjson::Document &doc) const; @@ -75,6 +81,10 @@ private: nvid_ctx *m_ctx = nullptr; PciTopology m_topology; String m_name; + +# ifdef XMRIG_FEATURE_NVML + nvmlDevice_t m_nvmlDevice = nullptr; +# endif }; diff --git a/src/backend/cuda/wrappers/CudaLib.cpp b/src/backend/cuda/wrappers/CudaLib.cpp index 5f3018d36..7264d67d5 100644 --- a/src/backend/cuda/wrappers/CudaLib.cpp +++ b/src/backend/cuda/wrappers/CudaLib.cpp @@ -28,7 +28,6 @@ #include "backend/cuda/wrappers/CudaLib.h" -#include "base/io/log/Log.h" namespace xmrig { diff --git a/src/backend/cuda/wrappers/NvmlHealth.h b/src/backend/cuda/wrappers/NvmlHealth.h new file mode 100644 index 000000000..58c1d3eb1 --- /dev/null +++ b/src/backend/cuda/wrappers/NvmlHealth.h @@ -0,0 +1,43 @@ +/* XMRig + * Copyright 2010 Jeff Garzik <jgarzik@pobox.com> + * Copyright 2012-2014 pooler <pooler@litecoinpool.org> + * Copyright 2014 Lucas Jones <https://github.com/lucasjones> + * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> + * Copyright 2016 Jay D Dee <jayddee246@gmail.com> + * Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt> + * Copyright 2018-2019 SChernykh <https://github.com/SChernykh> + * Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef XMRIG_NVMLHEALTH_H +#define XMRIG_NVMLHEALTH_H + + +#include <cstdint> +#include <vector> + + +struct NvmlHealth +{ + std::vector<uint32_t> fanSpeed; + uint32_t clock = 0; + uint32_t memClock = 0; + uint32_t power = 0; + uint32_t temperature = 0; +}; + + +#endif /* XMRIG_NVMLHEALTH_H */ diff --git a/src/backend/cuda/wrappers/NvmlLib.cpp b/src/backend/cuda/wrappers/NvmlLib.cpp new file mode 100644 index 000000000..cb05bdc17 --- /dev/null +++ b/src/backend/cuda/wrappers/NvmlLib.cpp @@ -0,0 +1,227 @@ +/* XMRig + * Copyright 2010 Jeff Garzik <jgarzik@pobox.com> + * Copyright 2012-2014 pooler <pooler@litecoinpool.org> + * Copyright 2014 Lucas Jones <https://github.com/lucasjones> + * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> + * Copyright 2016 Jay D Dee <jayddee246@gmail.com> + * Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt> + * Copyright 2018-2019 SChernykh <https://github.com/SChernykh> + * Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + + +#include <stdexcept> +#include <uv.h> + + +#include "backend/cuda/wrappers/NvmlLib.h" +#include "backend/cuda/wrappers/nvml_lite.h" +#include "base/io/log/Log.h" + + + +namespace xmrig { + + +static uv_lib_t nvmlLib; + + +static const char *kNvmlDeviceGetClockInfo = "nvmlDeviceGetClockInfo"; +static const char *kNvmlDeviceGetCount = "nvmlDeviceGetCount_v2"; +static const char *kNvmlDeviceGetFanSpeed = "nvmlDeviceGetFanSpeed"; +static const char *kNvmlDeviceGetFanSpeed_v2 = "nvmlDeviceGetFanSpeed_v2"; +static const char *kNvmlDeviceGetHandleByIndex = "nvmlDeviceGetHandleByIndex_v2"; +static const char *kNvmlDeviceGetPciInfo = "nvmlDeviceGetPciInfo_v2"; +static const char *kNvmlDeviceGetPowerUsage = "nvmlDeviceGetPowerUsage"; +static const char *kNvmlDeviceGetTemperature = "nvmlDeviceGetTemperature"; +static const char *kNvmlInit = "nvmlInit_v2"; +static const char *kNvmlShutdown = "nvmlShutdown"; +static const char *kNvmlSystemGetDriverVersion = "nvmlSystemGetDriverVersion"; +static const char *kNvmlSystemGetNVMLVersion = "nvmlSystemGetNVMLVersion"; +static const char *kSymbolNotFound = "symbol not found"; + + +static nvmlReturn_t (*pNvmlDeviceGetClockInfo)(nvmlDevice_t device, uint32_t type, uint32_t *clock) = nullptr; +static nvmlReturn_t (*pNvmlDeviceGetCount)(uint32_t *deviceCount) = nullptr; +static nvmlReturn_t (*pNvmlDeviceGetFanSpeed_v2)(nvmlDevice_t device, uint32_t fan, uint32_t *speed) = nullptr; +static nvmlReturn_t (*pNvmlDeviceGetFanSpeed)(nvmlDevice_t device, uint32_t *speed) = nullptr; +static nvmlReturn_t (*pNvmlDeviceGetHandleByIndex)(uint32_t index, nvmlDevice_t *device) = nullptr; +static nvmlReturn_t (*pNvmlDeviceGetPciInfo)(nvmlDevice_t device, nvmlPciInfo_t *pci) = nullptr; +static nvmlReturn_t (*pNvmlDeviceGetPowerUsage)(nvmlDevice_t device, uint32_t *power) = nullptr; +static nvmlReturn_t (*pNvmlDeviceGetTemperature)(nvmlDevice_t device, uint32_t sensorType, uint32_t *temp) = nullptr; +static nvmlReturn_t (*pNvmlInit)() = nullptr; +static nvmlReturn_t (*pNvmlShutdown)() = nullptr; +static nvmlReturn_t (*pNvmlSystemGetDriverVersion)(char *version, uint32_t length) = nullptr; +static nvmlReturn_t (*pNvmlSystemGetNVMLVersion)(char *version, uint32_t length) = nullptr; + + +#define DLSYM(x) if (uv_dlsym(&nvmlLib, k##x, reinterpret_cast<void**>(&p##x)) == -1) { throw std::runtime_error(kSymbolNotFound); } + + +bool NvmlLib::m_initialized = false; +bool NvmlLib::m_ready = false; +char NvmlLib::m_driverVersion[80] = { 0 }; +char NvmlLib::m_nvmlVersion[80] = { 0 }; +String NvmlLib::m_loader; + + +} // namespace xmrig + + +bool xmrig::NvmlLib::init(const char *fileName) +{ + if (!m_initialized) { + m_loader = fileName; + m_ready = dlopen() && load(); + m_initialized = true; + } + + return m_ready; +} + + +const char *xmrig::NvmlLib::lastError() noexcept +{ + return uv_dlerror(&nvmlLib); +} + + +void xmrig::NvmlLib::close() +{ + if (m_ready) { + pNvmlShutdown(); + } + + uv_dlclose(&nvmlLib); +} + + +bool xmrig::NvmlLib::assign(std::vector<CudaDevice> &devices) +{ + uint32_t count = 0; + if (pNvmlDeviceGetCount(&count) != NVML_SUCCESS) { + return false; + } + + for (uint32_t i = 0; i < count; i++) { + nvmlDevice_t nvmlDevice; + if (pNvmlDeviceGetHandleByIndex(i, &nvmlDevice) != NVML_SUCCESS) { + continue; + } + + nvmlPciInfo_t pci; + if (pNvmlDeviceGetPciInfo(nvmlDevice, &pci) != NVML_SUCCESS) { + continue; + } + + for (auto &device : devices) { + if (device.topology().bus() == pci.bus && device.topology().device() == pci.device) { + device.setNvmlDevice(nvmlDevice); + } + } + } + + return true; +} + + +NvmlHealth xmrig::NvmlLib::health(nvmlDevice_t device) +{ + if (!device) { + return {}; + } + + NvmlHealth health; + pNvmlDeviceGetTemperature(device, NVML_TEMPERATURE_GPU, &health.temperature); + pNvmlDeviceGetPowerUsage(device, &health.power); + pNvmlDeviceGetClockInfo(device, NVML_CLOCK_SM, &health.clock); + pNvmlDeviceGetClockInfo(device, NVML_CLOCK_MEM, &health.memClock); + + if (health.power) { + health.power /= 1000; + } + + uint32_t speed = 0; + + if (pNvmlDeviceGetFanSpeed_v2) { + uint32_t i = 0; + + while (pNvmlDeviceGetFanSpeed_v2(device, i, &speed) == NVML_SUCCESS) { + health.fanSpeed.push_back(speed); + ++i; + } + + } + else { + pNvmlDeviceGetFanSpeed(device, &speed); + + health.fanSpeed.push_back(speed); + } + + return health; +} + + +bool xmrig::NvmlLib::dlopen() +{ + if (!m_loader.isNull()) { + return uv_dlopen(m_loader, &nvmlLib) == 0; + } + +# ifdef _WIN32 + if (uv_dlopen("nvml.dll", &nvmlLib) == 0) { + return true; + } + + char path[MAX_PATH] = { 0 }; + ExpandEnvironmentStringsA("%PROGRAMFILES%\\NVIDIA Corporation\\NVSMI\\nvml.dll", path, sizeof(path)); + + return uv_dlopen(path, &nvmlLib) == 0; +# else + return uv_dlopen("libnvidia-ml.so", &nvmlLib) == 0; +# endif +} + + +bool xmrig::NvmlLib::load() +{ + try { + DLSYM(NvmlDeviceGetClockInfo); + DLSYM(NvmlDeviceGetCount); + DLSYM(NvmlDeviceGetFanSpeed); + DLSYM(NvmlDeviceGetHandleByIndex); + DLSYM(NvmlDeviceGetPciInfo); + DLSYM(NvmlDeviceGetPowerUsage); + DLSYM(NvmlDeviceGetTemperature); + DLSYM(NvmlInit); + DLSYM(NvmlShutdown); + DLSYM(NvmlSystemGetDriverVersion); + DLSYM(NvmlSystemGetNVMLVersion); + } catch (std::exception &ex) { + return false; + } + + uv_dlsym(&nvmlLib, kNvmlDeviceGetFanSpeed_v2, reinterpret_cast<void**>(&pNvmlDeviceGetFanSpeed_v2)); + + if (pNvmlInit() != NVML_SUCCESS) { + return false; + } + + pNvmlSystemGetDriverVersion(m_driverVersion, sizeof(m_driverVersion)); + pNvmlSystemGetNVMLVersion(m_nvmlVersion, sizeof(m_nvmlVersion)); + + return true; +} diff --git a/src/backend/cuda/wrappers/NvmlLib.h b/src/backend/cuda/wrappers/NvmlLib.h new file mode 100644 index 000000000..85b80d0ca --- /dev/null +++ b/src/backend/cuda/wrappers/NvmlLib.h @@ -0,0 +1,66 @@ +/* XMRig + * Copyright 2010 Jeff Garzik <jgarzik@pobox.com> + * Copyright 2012-2014 pooler <pooler@litecoinpool.org> + * Copyright 2014 Lucas Jones <https://github.com/lucasjones> + * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> + * Copyright 2016 Jay D Dee <jayddee246@gmail.com> + * Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt> + * Copyright 2018-2019 SChernykh <https://github.com/SChernykh> + * Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef XMRIG_NVMLLIB_H +#define XMRIG_NVMLLIB_H + + +#include "backend/cuda/wrappers/CudaDevice.h" +#include "backend/cuda/wrappers/NvmlHealth.h" + + +namespace xmrig { + + +class NvmlLib +{ +public: + static bool init(const char *fileName = nullptr); + static const char *lastError() noexcept; + static void close(); + + static bool assign(std::vector<CudaDevice> &devices); + static NvmlHealth health(nvmlDevice_t device); + + static inline bool isInitialized() noexcept { return m_initialized; } + static inline bool isReady() noexcept { return m_ready; } + static inline const char *driverVersion() noexcept { return m_driverVersion; } + static inline const char *version() noexcept { return m_nvmlVersion; } + +private: + static bool dlopen(); + static bool load(); + + static bool m_initialized; + static bool m_ready; + static char m_driverVersion[80]; + static char m_nvmlVersion[80]; + static String m_loader; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_NVMLLIB_H */ diff --git a/src/backend/cuda/wrappers/nvml_lite.h b/src/backend/cuda/wrappers/nvml_lite.h new file mode 100644 index 000000000..4472847c3 --- /dev/null +++ b/src/backend/cuda/wrappers/nvml_lite.h @@ -0,0 +1,55 @@ +/* XMRig + * Copyright 2010 Jeff Garzik <jgarzik@pobox.com> + * Copyright 2012-2014 pooler <pooler@litecoinpool.org> + * Copyright 2014 Lucas Jones <https://github.com/lucasjones> + * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> + * Copyright 2016 Jay D Dee <jayddee246@gmail.com> + * Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt> + * Copyright 2018-2019 SChernykh <https://github.com/SChernykh> + * Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef XMRIG_NVML_LITE_H +#define XMRIG_NVML_LITE_H + + +#include <cstdint> + + +#define NVML_SUCCESS 0 +#define NVML_TEMPERATURE_GPU 0 +#define NVML_CLOCK_SM 1 +#define NVML_CLOCK_MEM 2 + + +using nvmlReturn_t = uint32_t; +using nvmlDevice_t = struct nvmlDevice_st *; + + +struct nvmlPciInfo_t +{ + char busIdLegacy[16]{}; + unsigned int domain = 0; + unsigned int bus = 0; + unsigned int device = 0; + unsigned int pciDeviceId = 0; + unsigned int pciSubSystemId = 0; + + char busId[32]{}; +}; + + +#endif /* XMRIG_NVML_LITE_H */ diff --git a/src/backend/opencl/OclBackend.h b/src/backend/opencl/OclBackend.h index 57f5db38d..59bea0aa5 100644 --- a/src/backend/opencl/OclBackend.h +++ b/src/backend/opencl/OclBackend.h @@ -51,6 +51,8 @@ public: ~OclBackend() override; protected: + inline void execCommand(char) override {} + bool isEnabled() const override; bool isEnabled(const Algorithm &algorithm) const override; const Hashrate *hashrate() const override; diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h index ccee47c67..7167e0bb7 100644 --- a/src/base/kernel/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -135,7 +135,9 @@ public: CudaAffinityKey = 1205, CudaMaxUsageKey = 1206, CudaKey = 1207, - CudaLoaderKey = 1208 + CudaLoaderKey = 1208, + NvmlKey = 1209, + HealthPrintTimeKey = 1210, }; virtual ~IConfig() = default; diff --git a/src/config.json b/src/config.json index 9c6d459e2..fbc60474a 100644 --- a/src/config.json +++ b/src/config.json @@ -41,6 +41,9 @@ "cuda": { "enabled": false, "loader": null, + "nvml": true, + "cn/0": false, + "cn-lite/0": false }, "donate-level": 5, "donate-over-proxy": 1, @@ -63,6 +66,7 @@ } ], "print-time": 60, + "health-print-time": 60, "retries": 5, "retry-pause": 5, "syslog": false, diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 0caf298f8..20ff3fd73 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -328,6 +328,34 @@ xmrig::Job xmrig::Miner::job() const } +void xmrig::Miner::execCommand(char command) +{ + switch (command) { + case 'h': + case 'H': + printHashrate(true); + break; + + case 'p': + case 'P': + setEnabled(false); + break; + + case 'r': + case 'R': + setEnabled(true); + break; + + default: + break; + } + + for (auto backend : d_ptr->backends) { + backend->execCommand(command); + } +} + + void xmrig::Miner::pause() { d_ptr->active = false; @@ -393,7 +421,7 @@ void xmrig::Miner::setJob(const Job &job, bool donate) } # ifdef XMRIG_ALGO_RANDOMX - if (d_ptr->algorithm.family() == Algorithm::RANDOM_X && job.algorithm().family() == Algorithm::RANDOM_X && !Rx::isReady(job)) { + if (job.algorithm().family() == Algorithm::RANDOM_X && !Rx::isReady(job)) { stop(); } # endif @@ -466,7 +494,8 @@ void xmrig::Miner::onTimer(const Timer *) d_ptr->maxHashrate[d_ptr->algorithm] = std::max(d_ptr->maxHashrate[d_ptr->algorithm], maxHashrate); - if ((d_ptr->ticks % (d_ptr->controller->config()->printTime() * 2)) == 0) { + auto seconds = d_ptr->controller->config()->printTime(); + if (seconds && (d_ptr->ticks % (seconds * 2)) == 0) { printHashrate(false); } diff --git a/src/core/Miner.h b/src/core/Miner.h index 6f4149c30..f40e37f69 100644 --- a/src/core/Miner.h +++ b/src/core/Miner.h @@ -59,6 +59,7 @@ public: const Algorithms &algorithms() const; const std::vector<IBackend *> &backends() const; Job job() const; + void execCommand(char command); void pause(); void printHashrate(bool details); void setEnabled(bool enabled); diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 4fd88b90e..a445961f1 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -70,6 +70,11 @@ static const char *kCuda = "cuda"; #endif +#if defined(XMRIG_FEATURE_NVML) +static const char *kHealthPrintTime = "health-print-time"; +#endif + + class ConfigPrivate { public: @@ -86,6 +91,10 @@ public: # ifdef XMRIG_FEATURE_CUDA CudaConfig cuda; # endif + +# if defined(XMRIG_FEATURE_NVML) + uint32_t healthPrintTime = 60; +# endif }; } @@ -133,6 +142,14 @@ const xmrig::RxConfig &xmrig::Config::rx() const #endif +#if defined(XMRIG_FEATURE_NVML) +uint32_t xmrig::Config::healthPrintTime() const +{ + return d_ptr->healthPrintTime; +} +#endif + + bool xmrig::Config::isShouldSave() const { if (!isAutoSave()) { @@ -177,6 +194,10 @@ bool xmrig::Config::read(const IJsonReader &reader, const char *fileName) d_ptr->cuda.read(reader.getValue(kCuda)); # endif +# ifdef XMRIG_FEATURE_NVML + d_ptr->healthPrintTime = reader.getUint(kHealthPrintTime, d_ptr->healthPrintTime); +# endif + return true; } @@ -213,14 +234,17 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const doc.AddMember(StringRef(kCuda), cuda().toJSON(doc), allocator); # endif - doc.AddMember("donate-level", m_pools.donateLevel(), allocator); - doc.AddMember("donate-over-proxy", m_pools.proxyDonate(), allocator); - doc.AddMember("log-file", m_logFile.toJSON(), 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("syslog", isSyslog(), allocator); - doc.AddMember("user-agent", m_userAgent.toJSON(), allocator); - doc.AddMember("watch", m_watch, allocator); + doc.AddMember("donate-level", m_pools.donateLevel(), allocator); + doc.AddMember("donate-over-proxy", m_pools.proxyDonate(), allocator); + doc.AddMember("log-file", m_logFile.toJSON(), allocator); + doc.AddMember("pools", m_pools.toJSON(doc), allocator); + doc.AddMember("print-time", printTime(), allocator); +# if defined(XMRIG_FEATURE_NVML) + doc.AddMember(StringRef(kHealthPrintTime), healthPrintTime(), allocator); +# endif + doc.AddMember("retries", m_pools.retries(), allocator); + doc.AddMember("retry-pause", m_pools.retryPause(), allocator); + doc.AddMember("syslog", isSyslog(), allocator); + doc.AddMember("user-agent", m_userAgent.toJSON(), allocator); + doc.AddMember("watch", m_watch, allocator); } diff --git a/src/core/config/Config.h b/src/core/config/Config.h index 8becc0b80..5eb91ecae 100644 --- a/src/core/config/Config.h +++ b/src/core/config/Config.h @@ -67,6 +67,10 @@ public: const RxConfig &rx() const; # endif +# if defined(XMRIG_FEATURE_NVML) + uint32_t healthPrintTime() const; +# endif + bool isShouldSave() const; bool read(const IJsonReader &reader, const char *fileName) override; void getJSON(rapidjson::Document &doc) const override; diff --git a/src/core/config/ConfigTransform.cpp b/src/core/config/ConfigTransform.cpp index 51f594e8b..ffd3fbd8e 100644 --- a/src/core/config/ConfigTransform.cpp +++ b/src/core/config/ConfigTransform.cpp @@ -193,6 +193,14 @@ void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const return set(doc, kCuda, "loader", arg); # endif +# ifdef XMRIG_FEATURE_NVML + case IConfig::NvmlKey: /* --no-nvml */ + return set(doc, kCuda, "nvml", false); + + case IConfig::HealthPrintTimeKey: /* --health-print-time */ + return set(doc, "health-print-time", static_cast<uint64_t>(strtol(arg, nullptr, 10))); +# endif + default: break; } diff --git a/src/core/config/Config_default.h b/src/core/config/Config_default.h index e7d39299f..afd3638bb 100644 --- a/src/core/config/Config_default.h +++ b/src/core/config/Config_default.h @@ -75,6 +75,9 @@ R"===( "cuda": { "enabled": false, "loader": null, + "nvml": true, + "cn/0": false, + "cn-lite/0": false }, "donate-level": 5, "donate-over-proxy": 1, @@ -97,6 +100,7 @@ R"===( } ], "print-time": 60, + "health-print-time": 60, "retries": 5, "retry-pause": 5, "syslog": false, diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h index 371e58fa8..3309bebaf 100644 --- a/src/core/config/Config_platform.h +++ b/src/core/config/Config_platform.h @@ -107,6 +107,10 @@ static const option options[] = { # ifdef XMRIG_FEATURE_CUDA { "cuda", 0, nullptr, IConfig::CudaKey }, { "cuda-loader", 1, nullptr, IConfig::CudaLoaderKey }, +# endif +# ifdef XMRIG_FEATURE_NVML + { "no-nvml", 0, nullptr, IConfig::NvmlKey }, + { "health-print-time", 1, nullptr, IConfig::HealthPrintTimeKey }, # endif { nullptr, 0, nullptr, 0 } }; diff --git a/src/core/config/usage.h b/src/core/config/usage.h index c95526f78..d9ef23169 100644 --- a/src/core/config/usage.h +++ b/src/core/config/usage.h @@ -113,6 +113,9 @@ static inline const std::string &usage() u += " --cuda enable CUDA mining backend\n"; u += " --cuda-loader=PATH path to CUDA plugin (xmrig-cuda.dll or libxmrig-cuda.so)\n"; # endif +# ifdef XMRIG_FEATURE_NVML + u += " --no-nvml disable NVML (NVIDIA Management Library) support\n"; +# endif u += "\nLogging:\n"; @@ -122,6 +125,9 @@ static inline const std::string &usage() u += " -l, --log-file=FILE log all output to a file\n"; u += " --print-time=N print hashrate report every N seconds\n"; +# ifdef XMRIG_FEATURE_NVML + u += " --health-print-time=N print health report every N seconds\n"; +# endif u += " --no-color disable colored output\n"; u += "\nMisc:\n"; diff --git a/src/crypto/common/Nonce.cpp b/src/crypto/common/Nonce.cpp index e79cb310e..897045caf 100644 --- a/src/crypto/common/Nonce.cpp +++ b/src/crypto/common/Nonce.cpp @@ -48,8 +48,8 @@ xmrig::Nonce::Nonce() { m_paused = true; - for (int i = 0; i < MAX; ++i) { - m_sequence[i] = 1; + for (auto &i : m_sequence) { + i = 1; } } @@ -85,15 +85,15 @@ void xmrig::Nonce::stop() { pause(false); - for (int i = 0; i < MAX; ++i) { - m_sequence[i] = 0; + for (auto &i : m_sequence) { + i = 0; } } void xmrig::Nonce::touch() { - for (int i = 0; i < MAX; ++i) { - m_sequence[i]++; + for (auto &i : m_sequence) { + i++; } }