From 2c52a5a352167c37cbc5f854e15ec261c67e1cb7 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 30 Jan 2021 02:42:59 +0700 Subject: [PATCH] #2066 Fixed AMD GPUs health data readings. --- src/backend/common/misc/PciTopology.h | 26 +++---- src/backend/opencl/wrappers/AdlLib_linux.cpp | 82 +++++++++++++++----- 2 files changed, 75 insertions(+), 33 deletions(-) diff --git a/src/backend/common/misc/PciTopology.h b/src/backend/common/misc/PciTopology.h index ee531f50..af1844c9 100644 --- a/src/backend/common/misc/PciTopology.h +++ b/src/backend/common/misc/PciTopology.h @@ -1,13 +1,6 @@ /* 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 , + * Copyright (c) 2018-2021 SChernykh + * Copyright (c) 2016-2021 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 @@ -42,10 +35,15 @@ public: PciTopology() = default; PciTopology(uint32_t bus, uint32_t device, uint32_t function) : m_valid(true), m_bus(bus), m_device(device), m_function(function) {} - inline bool isValid() const { return m_valid; } - inline uint8_t bus() const { return m_bus; } - inline uint8_t device() const { return m_device; } - inline uint8_t function() const { return m_function; } + inline bool isEqual(const PciTopology &other) const { return m_valid == other.m_valid && toUint32() == other.toUint32(); } + inline bool isValid() const { return m_valid; } + inline uint8_t bus() const { return m_bus; } + inline uint8_t device() const { return m_device; } + inline uint8_t function() const { return m_function; } + + inline bool operator!=(const PciTopology &other) const { return !isEqual(other); } + inline bool operator<(const PciTopology &other) const { return toUint32() < other.toUint32(); } + inline bool operator==(const PciTopology &other) const { return isEqual(other); } String toString() const { @@ -60,6 +58,8 @@ public: } private: + inline uint32_t toUint32() const { return m_bus << 16 | m_device << 8 | m_function; } + bool m_valid = false; uint8_t m_bus = 0; uint8_t m_device = 0; diff --git a/src/backend/opencl/wrappers/AdlLib_linux.cpp b/src/backend/opencl/wrappers/AdlLib_linux.cpp index 3a0738ee..7d7adb31 100644 --- a/src/backend/opencl/wrappers/AdlLib_linux.cpp +++ b/src/backend/opencl/wrappers/AdlLib_linux.cpp @@ -20,10 +20,13 @@ #include "backend/opencl/wrappers/AdlLib.h" +#include "3rdparty/fmt/core.h" #include "backend/opencl/wrappers/OclDevice.h" +#include #include +#include #include #include #include @@ -35,18 +38,27 @@ namespace xmrig { bool AdlLib::m_initialized = false; bool AdlLib::m_ready = false; static const std::string kPrefix = "/sys/bus/pci/drivers/amdgpu/"; +static std::map hwmon_cache; -static inline bool sysfs_is_file(const std::string &path) +static inline bool sysfs_is_file(const char *path) { struct stat sb; - return stat(path.c_str(), &sb) == 0 && ((sb.st_mode & S_IFMT) == S_IFREG); + return stat(path, &sb) == 0 && ((sb.st_mode & S_IFMT) == S_IFREG); } -static inline bool sysfs_is_amdgpu(const std::string &path) +static inline int dir_filter(const struct dirent *dirp) { + return strlen(dirp->d_name) > 5 ? 1 : 0; +} + + +static bool sysfs_is_amdgpu(const char *path, char *buf, const char *filename) +{ + strcpy(buf, filename); + if (!sysfs_is_file(path)) { return false; } @@ -63,8 +75,10 @@ static inline bool sysfs_is_amdgpu(const std::string &path) } -uint32_t sysfs_read(const std::string &path) +static uint32_t sysfs_read(const char *path, char *buf, const char *filename) { + strcpy(buf, filename); + std::ifstream file(path); if (!file.is_open()) { return 0; @@ -77,18 +91,44 @@ uint32_t sysfs_read(const std::string &path) } -static inline std::string sysfs_prefix(const PciTopology &topology) +static size_t sysfs_prefix(char path[PATH_MAX], const PciTopology &topology) { - const std::string path = kPrefix + "0000:" + topology.toString().data() + "/hwmon/hwmon"; + const auto it = hwmon_cache.find(topology); + if (it != hwmon_cache.end()) { + strcpy(path, it->second.data()); - for (uint32_t i = 1; i < 100; ++i) { - const std::string prefix = path + std::to_string(i) + "/"; - if (sysfs_is_amdgpu(prefix + "name") && (sysfs_read(prefix + "temp1_input") || sysfs_read(prefix + "power1_average"))) { - return prefix; - } + return it->second.size(); } - return {}; + char *base = fmt::format_to(path, "{}0000:{}/hwmon/", kPrefix, topology.toString()); + *base = '\0'; + char *end = nullptr; + + struct dirent **namelist; + int n = scandir(path, &namelist, dir_filter, nullptr); + if (n < 0) { + return {}; + } + + while (n--) { + if (!end) { + char *tmp = fmt::format_to(base, "{}/", namelist[n]->d_name); + end = (sysfs_is_amdgpu(path, tmp, "name") && (sysfs_read(path, tmp, "temp1_input") || sysfs_read(path, tmp, "power1_average"))) ? tmp : nullptr; + } + + free(namelist[n]); + } + + free(namelist); + + if (end) { + *end = '\0'; + hwmon_cache.insert({ topology, path }); + + return end - path; + } + + return 0; } @@ -124,20 +164,22 @@ AdlHealth xmrig::AdlLib::health(const OclDevice &device) return {}; } - const auto prefix = sysfs_prefix(device.topology()); - if (prefix.empty()) { + static char path[PATH_MAX]{}; + + char *buf = path + sysfs_prefix(path, device.topology()); + if (buf == path) { return {}; } AdlHealth health; - health.clock = sysfs_read(prefix + "freq1_input") / 1000000; - health.memClock = sysfs_read(prefix + "freq2_input") / 1000000; - health.power = sysfs_read(prefix + "power1_average") / 1000000; - health.rpm = sysfs_read(prefix + "fan1_input"); - health.temperature = sysfs_read(prefix + "temp2_input") / 1000; + health.clock = sysfs_read(path, buf, "freq1_input") / 1000000; + health.memClock = sysfs_read(path, buf, "freq2_input") / 1000000; + health.power = sysfs_read(path, buf, "power1_average") / 1000000; + health.rpm = sysfs_read(path, buf, "fan1_input"); + health.temperature = sysfs_read(path, buf, "temp2_input") / 1000; if (!health.temperature) { - health.temperature = sysfs_read(prefix + "temp1_input") / 1000; + health.temperature = sysfs_read(path, buf, "temp1_input") / 1000; } return health;