progminer zano miner fork https://github.com/hyle-team/progminer
This commit is contained in:
288
zano/libhwmon/wrapamdsysfs.cpp
Normal file
288
zano/libhwmon/wrapamdsysfs.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Wrapper for AMD SysFS on linux, using adapted code from amdcovc by matszpk
|
||||
*
|
||||
* By Philipp Andreas - github@smurfy.de
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#if defined(__linux)
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include "wrapamdsysfs.h"
|
||||
#include "wraphelper.h"
|
||||
|
||||
static bool getFileContentValue(const char* filename, unsigned int& value)
|
||||
{
|
||||
value = 0;
|
||||
std::ifstream ifs(filename, std::ios::binary);
|
||||
std::string line;
|
||||
std::getline(ifs, line);
|
||||
char* p = (char*)line.c_str();
|
||||
char* p2;
|
||||
errno = 0;
|
||||
value = strtoul(p, &p2, 0);
|
||||
if (errno != 0)
|
||||
return false;
|
||||
return (p != p2);
|
||||
}
|
||||
|
||||
wrap_amdsysfs_handle* wrap_amdsysfs_create()
|
||||
{
|
||||
wrap_amdsysfs_handle* sysfsh = nullptr;
|
||||
|
||||
#if defined(__linux)
|
||||
namespace fs = boost::filesystem;
|
||||
std::vector<pciInfo> devices; // Used to collect devices
|
||||
|
||||
char dbuf[120];
|
||||
// Check directory exist
|
||||
fs::path drm_dir("/sys/class/drm");
|
||||
if (!fs::exists(drm_dir) || !fs::is_directory(drm_dir))
|
||||
return nullptr;
|
||||
|
||||
// Regex patterns to identify directory elements
|
||||
std::regex cardPattern("^card[0-9]{1,}$");
|
||||
std::regex hwmonPattern("^hwmon[0-9]{1,}$");
|
||||
|
||||
// Loop directory contents
|
||||
for (fs::directory_iterator dirEnt(drm_dir); dirEnt != fs::directory_iterator(); ++dirEnt)
|
||||
{
|
||||
// Skip non relevant entries
|
||||
if (!fs::is_directory(dirEnt->path()) ||
|
||||
!std::regex_match(dirEnt->path().filename().string(), cardPattern))
|
||||
continue;
|
||||
|
||||
std::string devName = dirEnt->path().filename().string();
|
||||
unsigned int devIndex = std::stoi(devName.substr(4), nullptr, 10);
|
||||
unsigned int vendorId = 0;
|
||||
unsigned int hwmonIndex = UINT_MAX;
|
||||
|
||||
// Get AMD cards only (vendor 4098)
|
||||
fs::path vendor_file("/sys/class/drm/" + devName + "/device/vendor");
|
||||
snprintf(dbuf, 120, "/sys/class/drm/%s/device/vendor", devName.c_str());
|
||||
if (!fs::exists(vendor_file) || !fs::is_regular_file(vendor_file) ||
|
||||
!getFileContentValue(dbuf, vendorId) || vendorId != 4098)
|
||||
continue;
|
||||
|
||||
// Check it has dependant hwmon directory
|
||||
fs::path hwmon_dir("/sys/class/drm/" + devName + "/device/hwmon");
|
||||
if (!fs::exists(hwmon_dir) || !fs::is_directory(hwmon_dir))
|
||||
continue;
|
||||
|
||||
// Loop subelements in hwmon directory
|
||||
for (fs::directory_iterator hwmonEnt(hwmon_dir); hwmonEnt != fs::directory_iterator();
|
||||
++hwmonEnt)
|
||||
{
|
||||
// Skip non relevant entries
|
||||
if (!fs::is_directory(hwmonEnt->path()) ||
|
||||
!std::regex_match(hwmonEnt->path().filename().string(), hwmonPattern))
|
||||
continue;
|
||||
|
||||
unsigned int v = std::stoi(hwmonEnt->path().filename().string().substr(5), nullptr, 10);
|
||||
hwmonIndex = std::min(hwmonIndex, v);
|
||||
}
|
||||
if (hwmonIndex == UINT_MAX)
|
||||
continue;
|
||||
|
||||
// Detect Pci Id
|
||||
fs::path uevent_file("/sys/class/drm/" + devName + "/device/uevent");
|
||||
if (!fs::exists(uevent_file) || !fs::is_regular_file(uevent_file))
|
||||
continue;
|
||||
|
||||
snprintf(dbuf, 120, "/sys/class/drm/card%d/device/uevent", devIndex);
|
||||
std::ifstream ifs(dbuf, std::ios::binary);
|
||||
std::string line;
|
||||
int PciDomain = -1, PciBus = -1, PciDevice = -1, PciFunction = -1;
|
||||
while (std::getline(ifs, line))
|
||||
{
|
||||
if (line.length() > 24 && line.substr(0, 13) == "PCI_SLOT_NAME")
|
||||
{
|
||||
std::string pciId = line.substr(14);
|
||||
std::vector<std::string> pciIdParts;
|
||||
boost::split(pciIdParts, pciId, [](char c) { return (c == ':' || c == '.'); });
|
||||
|
||||
try
|
||||
{
|
||||
PciDomain = std::stoi(pciIdParts.at(0), nullptr, 10);
|
||||
PciBus = std::stoi(pciIdParts.at(1), nullptr, 10);
|
||||
PciDevice = std::stoi(pciIdParts.at(2), nullptr, 10);
|
||||
PciFunction = std::stoi(pciIdParts.at(3), nullptr, 10);
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
PciDomain = PciBus = PciDevice = PciFunction = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got an error skip
|
||||
if (PciDomain == -1)
|
||||
continue;
|
||||
|
||||
// We got all information needed
|
||||
// push in the list of collected devices
|
||||
pciInfo pInfo = pciInfo();
|
||||
pInfo.DeviceId = devIndex;
|
||||
pInfo.HwMonId = hwmonIndex;
|
||||
pInfo.PciDomain = PciDomain;
|
||||
pInfo.PciBus = PciBus;
|
||||
pInfo.PciDevice = PciDevice;
|
||||
devices.push_back(pInfo);
|
||||
}
|
||||
|
||||
// Nothing collected - exit
|
||||
if (!devices.size())
|
||||
{
|
||||
cwarn << "Failed to obtain all required AMD file pointers";
|
||||
cwarn << "AMD hardware monitoring disabled";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int gpucount = devices.size();
|
||||
sysfsh = (wrap_amdsysfs_handle*)calloc(1, sizeof(wrap_amdsysfs_handle));
|
||||
if (sysfsh == nullptr)
|
||||
{
|
||||
cwarn << "Failed allocate memory";
|
||||
cwarn << "AMD hardware monitoring disabled";
|
||||
return sysfsh;
|
||||
}
|
||||
sysfsh->sysfs_gpucount = gpucount;
|
||||
sysfsh->sysfs_device_id = (unsigned int*)calloc(gpucount, sizeof(unsigned int));
|
||||
sysfsh->sysfs_hwmon_id = (unsigned int*)calloc(gpucount, sizeof(unsigned int));
|
||||
sysfsh->sysfs_pci_domain_id = (unsigned int*)calloc(gpucount, sizeof(unsigned int));
|
||||
sysfsh->sysfs_pci_bus_id = (unsigned int*)calloc(gpucount, sizeof(unsigned int));
|
||||
sysfsh->sysfs_pci_device_id = (unsigned int*)calloc(gpucount, sizeof(unsigned int));
|
||||
|
||||
gpucount = 0;
|
||||
for (auto const& device : devices)
|
||||
{
|
||||
sysfsh->sysfs_device_id[gpucount] = device.DeviceId;
|
||||
sysfsh->sysfs_hwmon_id[gpucount] = device.HwMonId;
|
||||
sysfsh->sysfs_pci_domain_id[gpucount] = device.PciDomain;
|
||||
sysfsh->sysfs_pci_bus_id[gpucount] = device.PciBus;
|
||||
sysfsh->sysfs_pci_device_id[gpucount] = device.PciDevice;
|
||||
gpucount++;
|
||||
}
|
||||
|
||||
#endif
|
||||
return sysfsh;
|
||||
}
|
||||
|
||||
int wrap_amdsysfs_destroy(wrap_amdsysfs_handle* sysfsh)
|
||||
{
|
||||
free(sysfsh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_amdsysfs_get_gpucount(wrap_amdsysfs_handle* sysfsh, int* gpucount)
|
||||
{
|
||||
*gpucount = sysfsh->sysfs_gpucount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_amdsysfs_get_tempC(wrap_amdsysfs_handle* sysfsh, int index, unsigned int* tempC)
|
||||
{
|
||||
if (index < 0 || index >= sysfsh->sysfs_gpucount)
|
||||
return -1;
|
||||
|
||||
int gpuindex = sysfsh->sysfs_device_id[index];
|
||||
|
||||
int hwmonindex = sysfsh->sysfs_hwmon_id[index];
|
||||
if (hwmonindex < 0)
|
||||
return -1;
|
||||
|
||||
char dbuf[120];
|
||||
snprintf(
|
||||
dbuf, 120, "/sys/class/drm/card%d/device/hwmon/hwmon%d/temp1_input", gpuindex, hwmonindex);
|
||||
|
||||
unsigned int temp = 0;
|
||||
getFileContentValue(dbuf, temp);
|
||||
|
||||
if (temp > 0)
|
||||
*tempC = temp / 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_amdsysfs_get_fanpcnt(wrap_amdsysfs_handle* sysfsh, int index, unsigned int* fanpcnt)
|
||||
{
|
||||
if (index < 0 || index >= sysfsh->sysfs_gpucount)
|
||||
return -1;
|
||||
|
||||
int gpuindex = sysfsh->sysfs_device_id[index];
|
||||
int hwmonindex = sysfsh->sysfs_hwmon_id[index];
|
||||
if (hwmonindex < 0)
|
||||
return -1;
|
||||
|
||||
unsigned int pwm = 0, pwmMax = 255, pwmMin = 0;
|
||||
|
||||
char dbuf[120];
|
||||
snprintf(dbuf, 120, "/sys/class/drm/card%d/device/hwmon/hwmon%d/pwm1", gpuindex, hwmonindex);
|
||||
getFileContentValue(dbuf, pwm);
|
||||
|
||||
snprintf(
|
||||
dbuf, 120, "/sys/class/drm/card%d/device/hwmon/hwmon%d/pwm1_max", gpuindex, hwmonindex);
|
||||
getFileContentValue(dbuf, pwmMax);
|
||||
|
||||
snprintf(
|
||||
dbuf, 120, "/sys/class/drm/card%d/device/hwmon/hwmon%d/pwm1_min", gpuindex, hwmonindex);
|
||||
getFileContentValue(dbuf, pwmMin);
|
||||
|
||||
*fanpcnt = (unsigned int)(double(pwm - pwmMin) / double(pwmMax - pwmMin) * 100.0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_amdsysfs_get_power_usage(wrap_amdsysfs_handle* sysfsh, int index, unsigned int* milliwatts)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (index < 0 || index >= sysfsh->sysfs_gpucount)
|
||||
return -1;
|
||||
|
||||
int gpuindex = sysfsh->sysfs_device_id[index];
|
||||
|
||||
char dbuf[120];
|
||||
snprintf(dbuf, 120, "/sys/kernel/debug/dri/%d/amdgpu_pm_info", gpuindex);
|
||||
|
||||
std::ifstream ifs(dbuf, std::ios::binary);
|
||||
std::string line;
|
||||
|
||||
while (std::getline(ifs, line))
|
||||
{
|
||||
std::smatch sm;
|
||||
std::regex regex(R"(([\d|\.]+) W \(average GPU\))");
|
||||
if (std::regex_search(line, sm, regex))
|
||||
{
|
||||
if (sm.size() == 2)
|
||||
{
|
||||
double watt = atof(sm.str(1).c_str());
|
||||
*milliwatts = (unsigned int)(watt * 1000);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
cwarn << "Error in amdsysfs_get_power_usage: " << ex.what();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
Reference in New Issue
Block a user