progminer zano miner fork https://github.com/hyle-team/progminer
This commit is contained in:
21
zano/libhwmon/CMakeLists.txt
Normal file
21
zano/libhwmon/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
set(SOURCES
|
||||
wraphelper.cpp wraphelper.h
|
||||
wrapnvml.h wrapnvml.cpp
|
||||
wrapadl.h wrapadl.cpp
|
||||
wrapamdsysfs.h wrapamdsysfs.cpp
|
||||
)
|
||||
|
||||
add_library(hwmon ${SOURCES})
|
||||
set(HWMON_LINK_LIBRARIES devcore)
|
||||
|
||||
if (UNIX)
|
||||
list(APPEND HWMON_LINK_LIBRARIES dl)
|
||||
endif ()
|
||||
|
||||
target_link_libraries(hwmon ${HWMON_LINK_LIBRARIES})
|
||||
target_include_directories(hwmon PRIVATE ..)
|
||||
|
||||
if (ETHASHCUDA)
|
||||
find_package(CUDA REQUIRED)
|
||||
target_include_directories(hwmon PUBLIC ${CUDA_INCLUDE_DIRS})
|
||||
endif()
|
255
zano/libhwmon/wrapadl.cpp
Normal file
255
zano/libhwmon/wrapadl.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Wrapper for ADL, inspired by wrapnvml from John E. Stone
|
||||
*
|
||||
* By Philipp Andreas - github@smurfy.de
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include "wrapadl.h"
|
||||
#include "wraphelper.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void* ADL_API_CALL ADL_Main_Memory_Alloc(int iSize)
|
||||
{
|
||||
void* lpBuffer = malloc(iSize);
|
||||
return lpBuffer;
|
||||
}
|
||||
|
||||
wrap_adl_handle* wrap_adl_create()
|
||||
{
|
||||
wrap_adl_handle* adlh = nullptr;
|
||||
|
||||
#if defined(_WIN32)
|
||||
/* Windows */
|
||||
#define libatiadlxx "atiadlxx.dll"
|
||||
#elif defined(__linux) && (defined(__i386__) || defined(__ARM_ARCH_7A__))
|
||||
/* 32-bit linux assumed */
|
||||
#define libatiadlxx "libatiadlxx.so"
|
||||
#elif defined(__linux)
|
||||
/* 64-bit linux assumed */
|
||||
#define libatiadlxx "libatiadlxx.so"
|
||||
#else
|
||||
#define libatiadlxx ""
|
||||
#warning "Unrecognized platform: need ADL DLL path for this platform..."
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
char tmp[512];
|
||||
ExpandEnvironmentStringsA(libatiadlxx, tmp, sizeof(tmp));
|
||||
#else
|
||||
char tmp[512] = libatiadlxx;
|
||||
#endif
|
||||
|
||||
void* adl_dll = wrap_dlopen(tmp);
|
||||
if (adl_dll == nullptr)
|
||||
{
|
||||
cwarn << "Failed to obtain all required ADL function pointers";
|
||||
cwarn << "AMD hardware monitoring disabled";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
adlh = (wrap_adl_handle*)calloc(1, sizeof(wrap_adl_handle));
|
||||
|
||||
adlh->adl_dll = adl_dll;
|
||||
|
||||
adlh->adlMainControlCreate = (wrap_adlReturn_t(*)(ADL_MAIN_MALLOC_CALLBACK, int))wrap_dlsym(
|
||||
adlh->adl_dll, "ADL_Main_Control_Create");
|
||||
adlh->adlAdapterNumberOfAdapters =
|
||||
(wrap_adlReturn_t(*)(int*))wrap_dlsym(adlh->adl_dll, "ADL_Adapter_NumberOfAdapters_Get");
|
||||
adlh->adlAdapterAdapterInfoGet = (wrap_adlReturn_t(*)(LPAdapterInfo, int))wrap_dlsym(
|
||||
adlh->adl_dll, "ADL_Adapter_AdapterInfo_Get");
|
||||
adlh->adlAdapterAdapterIdGet =
|
||||
(wrap_adlReturn_t(*)(int, int*))wrap_dlsym(adlh->adl_dll, "ADL_Adapter_ID_Get");
|
||||
adlh->adlOverdrive5TemperatureGet = (wrap_adlReturn_t(*)(int, int, ADLTemperature*))wrap_dlsym(
|
||||
adlh->adl_dll, "ADL_Overdrive5_Temperature_Get");
|
||||
adlh->adlOverdrive5FanSpeedGet = (wrap_adlReturn_t(*)(int, int, ADLFanSpeedValue*))wrap_dlsym(
|
||||
adlh->adl_dll, "ADL_Overdrive5_FanSpeed_Get");
|
||||
adlh->adlMainControlRefresh =
|
||||
(wrap_adlReturn_t(*)(void))wrap_dlsym(adlh->adl_dll, "ADL_Main_Control_Refresh");
|
||||
adlh->adlMainControlDestroy =
|
||||
(wrap_adlReturn_t(*)(void))wrap_dlsym(adlh->adl_dll, "ADL_Main_Control_Destroy");
|
||||
adlh->adl2MainControlCreate = (wrap_adlReturn_t(*)(ADL_MAIN_MALLOC_CALLBACK, int,
|
||||
ADL_CONTEXT_HANDLE*))wrap_dlsym(adlh->adl_dll, "ADL2_Main_Control_Create");
|
||||
adlh->adl2MainControlDestroy = (wrap_adlReturn_t(*)(ADL_CONTEXT_HANDLE))wrap_dlsym(
|
||||
adlh->adl_dll, "ADL_Main_Control_Destroy");
|
||||
adlh->adl2Overdrive6CurrentPowerGet = (wrap_adlReturn_t(*)(ADL_CONTEXT_HANDLE, int, int,
|
||||
int*))wrap_dlsym(adlh->adl_dll, "ADL2_Overdrive6_CurrentPower_Get");
|
||||
adlh->adl2MainControlRefresh = (wrap_adlReturn_t(*)(ADL_CONTEXT_HANDLE))wrap_dlsym(
|
||||
adlh->adl_dll, "ADL2_Main_Control_Refresh");
|
||||
|
||||
|
||||
if (adlh->adlMainControlCreate == nullptr || adlh->adlMainControlDestroy == nullptr ||
|
||||
adlh->adlMainControlRefresh == nullptr || adlh->adlAdapterNumberOfAdapters == nullptr ||
|
||||
adlh->adlAdapterAdapterInfoGet == nullptr || adlh->adlAdapterAdapterIdGet == nullptr ||
|
||||
adlh->adlOverdrive5TemperatureGet == nullptr || adlh->adlOverdrive5FanSpeedGet == nullptr ||
|
||||
adlh->adl2MainControlCreate == nullptr || adlh->adl2MainControlRefresh == nullptr ||
|
||||
adlh->adl2MainControlDestroy == nullptr || adlh->adl2Overdrive6CurrentPowerGet == nullptr)
|
||||
{
|
||||
cwarn << "Failed to obtain all required ADL function pointers";
|
||||
cwarn << "AMD hardware monitoring disabled";
|
||||
|
||||
wrap_dlclose(adlh->adl_dll);
|
||||
free(adlh);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
adlh->adlMainControlCreate(ADL_Main_Memory_Alloc, 1);
|
||||
adlh->adlMainControlRefresh();
|
||||
|
||||
adlh->context = nullptr;
|
||||
|
||||
adlh->adl2MainControlCreate(ADL_Main_Memory_Alloc, 1, &(adlh->context));
|
||||
adlh->adl2MainControlRefresh(adlh->context);
|
||||
|
||||
int logicalGpuCount = 0;
|
||||
adlh->adlAdapterNumberOfAdapters(&logicalGpuCount);
|
||||
|
||||
adlh->phys_logi_device_id = (int*)calloc(logicalGpuCount, sizeof(int));
|
||||
|
||||
adlh->adl_gpucount = 0;
|
||||
int last_adapter = 0;
|
||||
if (logicalGpuCount > 0)
|
||||
{
|
||||
adlh->log_gpucount = logicalGpuCount;
|
||||
adlh->devs = (LPAdapterInfo)malloc(sizeof(AdapterInfo) * logicalGpuCount);
|
||||
memset(adlh->devs, '\0', sizeof(AdapterInfo) * logicalGpuCount);
|
||||
|
||||
adlh->devs->iSize = sizeof(adlh->devs);
|
||||
|
||||
int res = adlh->adlAdapterAdapterInfoGet(adlh->devs, sizeof(AdapterInfo) * logicalGpuCount);
|
||||
if (res != WRAPADL_OK)
|
||||
{
|
||||
cwarn << "Failed to obtain using adlAdapterAdapterInfoGet().";
|
||||
cwarn << "AMD hardware monitoring disabled";
|
||||
|
||||
wrap_dlclose(adlh->adl_dll);
|
||||
free(adlh);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (int i = 0; i < logicalGpuCount; i++)
|
||||
{
|
||||
int adapterIndex = adlh->devs[i].iAdapterIndex;
|
||||
int adapterID = 0;
|
||||
|
||||
res = adlh->adlAdapterAdapterIdGet(adapterIndex, &adapterID);
|
||||
|
||||
if (res != WRAPADL_OK)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
adlh->phys_logi_device_id[adlh->adl_gpucount] = adapterIndex;
|
||||
|
||||
if (adapterID == last_adapter)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
last_adapter = adapterID;
|
||||
adlh->adl_gpucount++;
|
||||
}
|
||||
}
|
||||
|
||||
return adlh;
|
||||
}
|
||||
|
||||
int wrap_adl_destroy(wrap_adl_handle* adlh)
|
||||
{
|
||||
adlh->adlMainControlDestroy();
|
||||
adlh->adl2MainControlDestroy(adlh->context);
|
||||
wrap_dlclose(adlh->adl_dll);
|
||||
free(adlh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_adl_get_gpucount(wrap_adl_handle* adlh, int* gpucount)
|
||||
{
|
||||
*gpucount = adlh->adl_gpucount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_adl_get_gpu_name(wrap_adl_handle* adlh, int gpuindex, char* namebuf, int bufsize)
|
||||
{
|
||||
if (gpuindex < 0 || gpuindex >= adlh->adl_gpucount)
|
||||
return -1;
|
||||
|
||||
memcpy(namebuf, adlh->devs[adlh->phys_logi_device_id[gpuindex]].strAdapterName, bufsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_adl_get_gpu_pci_id(wrap_adl_handle* adlh, int gpuindex, char* idbuf, int bufsize)
|
||||
{
|
||||
if (gpuindex < 0 || gpuindex >= adlh->adl_gpucount)
|
||||
return -1;
|
||||
|
||||
char buf[256];
|
||||
sprintf(buf, "%04x:%02x:%02x",
|
||||
0, // Is probably 0
|
||||
adlh->devs[adlh->phys_logi_device_id[gpuindex]].iBusNumber,
|
||||
adlh->devs[adlh->phys_logi_device_id[gpuindex]].iDeviceNumber);
|
||||
memcpy(idbuf, buf, bufsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_adl_get_tempC(wrap_adl_handle* adlh, int gpuindex, unsigned int* tempC)
|
||||
{
|
||||
|
||||
if (gpuindex < 0 || gpuindex >= adlh->adl_gpucount)
|
||||
return -1;
|
||||
|
||||
ADLTemperature* temperature = new ADLTemperature();
|
||||
|
||||
if (adlh->adlOverdrive5TemperatureGet(adlh->phys_logi_device_id[gpuindex], 0, temperature) !=
|
||||
WRAPADL_OK)
|
||||
return -1;
|
||||
|
||||
*tempC = unsigned(temperature->iTemperature / 1000);
|
||||
delete temperature;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_adl_get_fanpcnt(wrap_adl_handle* adlh, int gpuindex, unsigned int* fanpcnt)
|
||||
{
|
||||
|
||||
if (gpuindex < 0 || gpuindex >= adlh->adl_gpucount)
|
||||
return -1;
|
||||
|
||||
ADLFanSpeedValue* fan = new ADLFanSpeedValue();
|
||||
fan->iSpeedType = 1;
|
||||
|
||||
if (adlh->adlOverdrive5FanSpeedGet(adlh->phys_logi_device_id[gpuindex], 0, fan) != WRAPADL_OK)
|
||||
return -1;
|
||||
|
||||
*fanpcnt = unsigned(fan->iFanSpeed);
|
||||
delete fan;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_adl_get_power_usage(wrap_adl_handle* adlh, int gpuindex, unsigned int* miliwatts)
|
||||
{
|
||||
|
||||
if (gpuindex < 0 || gpuindex >= adlh->adl_gpucount)
|
||||
return -1;
|
||||
|
||||
int power = 0;
|
||||
if (adlh->adl2Overdrive6CurrentPowerGet(
|
||||
adlh->context, adlh->phys_logi_device_id[gpuindex], 0, &power) != WRAPADL_OK)
|
||||
return -1;
|
||||
|
||||
*miliwatts = (unsigned int)(power * 3.90625);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
156
zano/libhwmon/wrapadl.h
Normal file
156
zano/libhwmon/wrapadl.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Wrapper for ADL, inspired by wrapnvml from John E. Stone
|
||||
*
|
||||
* By Philipp Andreas - github@smurfy.de
|
||||
* ADL power by Davesmacer
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum wrap_adlReturn_enum { WRAPADL_OK = 0 } wrap_adlReturn_t;
|
||||
|
||||
// Some ADL defines and structs from adl sdk
|
||||
#if defined(__MSC_VER)
|
||||
#define ADL_API_CALL __cdecl
|
||||
#elif defined(_WIN32)
|
||||
#define ADL_API_CALL __stdcall
|
||||
#else
|
||||
#define ADL_API_CALL
|
||||
#endif
|
||||
|
||||
typedef void*(ADL_API_CALL* ADL_MAIN_MALLOC_CALLBACK)(int);
|
||||
/// \brief Handle to ADL client context.
|
||||
///
|
||||
/// ADL clients obtain context handle from initial call to \ref ADL2_Main_Control_Create.
|
||||
/// Clients have to pass the handle to each subsequent ADL call and finally destroy
|
||||
/// the context with call to \ref ADL2_Main_Control_Destroy
|
||||
/// \nosubgrouping
|
||||
typedef void* ADL_CONTEXT_HANDLE;
|
||||
|
||||
#define ADL_MAX_PATH 256
|
||||
typedef struct AdapterInfo
|
||||
{
|
||||
/// \ALL_STRUCT_MEM
|
||||
|
||||
/// Size of the structure.
|
||||
int iSize;
|
||||
/// The ADL index handle. One GPU may be associated with one or two index handles
|
||||
int iAdapterIndex;
|
||||
/// The unique device ID associated with this adapter.
|
||||
char strUDID[ADL_MAX_PATH];
|
||||
/// The BUS number associated with this adapter.
|
||||
int iBusNumber;
|
||||
/// The driver number associated with this adapter.
|
||||
int iDeviceNumber;
|
||||
/// The function number.
|
||||
int iFunctionNumber;
|
||||
/// The vendor ID associated with this adapter.
|
||||
int iVendorID;
|
||||
/// Adapter name.
|
||||
char strAdapterName[ADL_MAX_PATH];
|
||||
/// Display name. For example, "\\Display0" for Windows or ":0:0" for Linux.
|
||||
char strDisplayName[ADL_MAX_PATH];
|
||||
/// Present or not; 1 if present and 0 if not present.It the logical adapter is present, the
|
||||
/// display name such as \\.\Display1 can be found from OS
|
||||
int iPresent;
|
||||
// @}
|
||||
|
||||
#if defined(_WIN32)
|
||||
/// \WIN_STRUCT_MEM
|
||||
|
||||
/// Exist or not; 1 is exist and 0 is not present.
|
||||
int iExist;
|
||||
/// Driver registry path.
|
||||
char strDriverPath[ADL_MAX_PATH];
|
||||
/// Driver registry path Ext for.
|
||||
char strDriverPathExt[ADL_MAX_PATH];
|
||||
/// PNP string from Windows.
|
||||
char strPNPString[ADL_MAX_PATH];
|
||||
/// It is generated from EnumDisplayDevices.
|
||||
int iOSDisplayIndex;
|
||||
// @}
|
||||
#endif /* (_WIN32) */
|
||||
|
||||
#if defined(LINUX)
|
||||
/// \LNX_STRUCT_MEM
|
||||
|
||||
/// Internal X screen number from GPUMapInfo (DEPRICATED use XScreenInfo)
|
||||
int iXScreenNum;
|
||||
/// Internal driver index from GPUMapInfo
|
||||
int iDrvIndex;
|
||||
/// \deprecated Internal x config file screen identifier name. Use XScreenInfo instead.
|
||||
char strXScreenConfigName[ADL_MAX_PATH];
|
||||
|
||||
// @}
|
||||
#endif /* (LINUX) */
|
||||
} AdapterInfo, *LPAdapterInfo;
|
||||
|
||||
typedef struct ADLTemperature
|
||||
{
|
||||
/// Must be set to the size of the structure
|
||||
int iSize;
|
||||
/// Temperature in millidegrees Celsius.
|
||||
int iTemperature;
|
||||
} ADLTemperature;
|
||||
|
||||
typedef struct ADLFanSpeedValue
|
||||
{
|
||||
/// Must be set to the size of the structure
|
||||
int iSize;
|
||||
/// Possible valies: \ref ADL_DL_FANCTRL_SPEED_TYPE_PERCENT or \ref
|
||||
/// ADL_DL_FANCTRL_SPEED_TYPE_RPM
|
||||
int iSpeedType;
|
||||
/// Fan speed value
|
||||
int iFanSpeed;
|
||||
/// The only flag for now is: \ref ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED
|
||||
int iFlags;
|
||||
} ADLFanSpeedValue;
|
||||
|
||||
/*
|
||||
* Handle to hold the function pointers for the entry points we need,
|
||||
* and the shared library itself.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
void* adl_dll;
|
||||
int adl_gpucount;
|
||||
int log_gpucount;
|
||||
int* phys_logi_device_id;
|
||||
LPAdapterInfo devs;
|
||||
ADL_CONTEXT_HANDLE context;
|
||||
wrap_adlReturn_t (*adlMainControlCreate)(ADL_MAIN_MALLOC_CALLBACK, int);
|
||||
wrap_adlReturn_t (*adlAdapterNumberOfAdapters)(int*);
|
||||
wrap_adlReturn_t (*adlAdapterAdapterInfoGet)(LPAdapterInfo, int);
|
||||
wrap_adlReturn_t (*adlAdapterAdapterIdGet)(int, int*);
|
||||
wrap_adlReturn_t (*adlOverdrive5TemperatureGet)(int, int, ADLTemperature*);
|
||||
wrap_adlReturn_t (*adlOverdrive5FanSpeedGet)(int, int, ADLFanSpeedValue*);
|
||||
wrap_adlReturn_t (*adlMainControlRefresh)(void);
|
||||
wrap_adlReturn_t (*adlMainControlDestroy)(void);
|
||||
wrap_adlReturn_t (*adl2MainControlCreate)(ADL_MAIN_MALLOC_CALLBACK, int, ADL_CONTEXT_HANDLE*);
|
||||
wrap_adlReturn_t (*adl2MainControlDestroy)(ADL_CONTEXT_HANDLE);
|
||||
wrap_adlReturn_t (*adl2Overdrive6CurrentPowerGet)(ADL_CONTEXT_HANDLE, int, int, int*);
|
||||
wrap_adlReturn_t (*adl2MainControlRefresh)(ADL_CONTEXT_HANDLE);
|
||||
} wrap_adl_handle;
|
||||
|
||||
wrap_adl_handle* wrap_adl_create();
|
||||
int wrap_adl_destroy(wrap_adl_handle* adlh);
|
||||
|
||||
int wrap_adl_get_gpucount(wrap_adl_handle* adlh, int* gpucount);
|
||||
|
||||
int wrap_adl_get_gpu_name(wrap_adl_handle* adlh, int gpuindex, char* namebuf, int bufsize);
|
||||
|
||||
int wrap_adl_get_gpu_pci_id(wrap_adl_handle* adlh, int gpuindex, char* idbuf, int bufsize);
|
||||
|
||||
int wrap_adl_get_tempC(wrap_adl_handle* adlh, int gpuindex, unsigned int* tempC);
|
||||
|
||||
int wrap_adl_get_fanpcnt(wrap_adl_handle* adlh, int gpuindex, unsigned int* fanpcnt);
|
||||
|
||||
int wrap_adl_get_power_usage(wrap_adl_handle* adlh, int gpuindex, unsigned int* milliwatts);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
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;
|
||||
}
|
40
zano/libhwmon/wrapamdsysfs.h
Normal file
40
zano/libhwmon/wrapamdsysfs.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Wrapper for AMD SysFS on linux, using adapted code from amdcovc by matszpk
|
||||
*
|
||||
* By Philipp Andreas - github@smurfy.de
|
||||
Reworked and simplified by Andrea Lanfranchi (github @AndreaLanfranchi)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int sysfs_gpucount;
|
||||
unsigned int* sysfs_device_id;
|
||||
unsigned int* sysfs_hwmon_id;
|
||||
unsigned int* sysfs_pci_domain_id;
|
||||
unsigned int* sysfs_pci_bus_id;
|
||||
unsigned int* sysfs_pci_device_id;
|
||||
} wrap_amdsysfs_handle;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int DeviceId = -1;
|
||||
int HwMonId = -1;
|
||||
int PciDomain = -1;
|
||||
int PciBus = -1;
|
||||
int PciDevice = -1;
|
||||
|
||||
} pciInfo;
|
||||
|
||||
wrap_amdsysfs_handle* wrap_amdsysfs_create();
|
||||
int wrap_amdsysfs_destroy(wrap_amdsysfs_handle* sysfsh);
|
||||
|
||||
int wrap_amdsysfs_get_gpucount(wrap_amdsysfs_handle* sysfsh, int* gpucount);
|
||||
|
||||
int wrap_amdsysfs_get_tempC(wrap_amdsysfs_handle* sysfsh, int index, unsigned int* tempC);
|
||||
|
||||
int wrap_amdsysfs_get_fanpcnt(wrap_amdsysfs_handle* sysfsh, int index, unsigned int* fanpcnt);
|
||||
|
||||
int wrap_amdsysfs_get_power_usage(
|
||||
wrap_amdsysfs_handle* sysfsh, int index, unsigned int* milliwatts);
|
35
zano/libhwmon/wraphelper.cpp
Normal file
35
zano/libhwmon/wraphelper.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Wrappers to emulate dlopen() on other systems like Windows
|
||||
*/
|
||||
|
||||
#include "wraphelper.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
void* wrap_dlopen(const char* filename)
|
||||
{
|
||||
return (void*)LoadLibrary(filename);
|
||||
}
|
||||
void* wrap_dlsym(void* h, const char* sym)
|
||||
{
|
||||
return (void*)GetProcAddress((HINSTANCE)h, sym);
|
||||
}
|
||||
int wrap_dlclose(void* h)
|
||||
{
|
||||
/* FreeLibrary returns non-zero on success */
|
||||
return (!FreeLibrary((HINSTANCE)h));
|
||||
}
|
||||
#else
|
||||
/* assume we can use dlopen itself... */
|
||||
void* wrap_dlopen(const char* filename)
|
||||
{
|
||||
return dlopen(filename, RTLD_NOW);
|
||||
}
|
||||
void* wrap_dlsym(void* h, const char* sym)
|
||||
{
|
||||
return dlsym(h, sym);
|
||||
}
|
||||
int wrap_dlclose(void* h)
|
||||
{
|
||||
return dlclose(h);
|
||||
}
|
||||
#endif
|
20
zano/libhwmon/wraphelper.h
Normal file
20
zano/libhwmon/wraphelper.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Wrappers to emulate dlopen() on other systems like Windows
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libdevcore/Log.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
void* wrap_dlopen(const char* filename);
|
||||
void* wrap_dlsym(void* h, const char* sym);
|
||||
int wrap_dlclose(void* h);
|
||||
#else
|
||||
/* assume we can use dlopen itself... */
|
||||
#include <dlfcn.h>
|
||||
void* wrap_dlopen(const char* filename);
|
||||
void* wrap_dlsym(void* h, const char* sym);
|
||||
int wrap_dlclose(void* h);
|
||||
#endif
|
197
zano/libhwmon/wrapnvml.cpp
Normal file
197
zano/libhwmon/wrapnvml.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* A trivial little dlopen()-based wrapper library for the
|
||||
* NVIDIA NVML library, to allow runtime discovery of NVML on an
|
||||
* arbitrary system. This is all very hackish and simple-minded, but
|
||||
* it serves my immediate needs in the short term until NVIDIA provides
|
||||
* a static NVML wrapper library themselves, hopefully in
|
||||
* CUDA 6.5 or maybe sometime shortly after.
|
||||
*
|
||||
* This trivial code is made available under the "new" 3-clause BSD license,
|
||||
* and/or any of the GPL licenses you prefer.
|
||||
* Feel free to use the code and modify as you see fit.
|
||||
*
|
||||
* John E. Stone - john.stone@gmail.com
|
||||
*
|
||||
* Modified to work with progminer by
|
||||
*
|
||||
* Philipp Andreas - github@smurfy.de
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "wrapnvml.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
wrap_nvml_handle* wrap_nvml_create()
|
||||
{
|
||||
wrap_nvml_handle* nvmlh = nullptr;
|
||||
|
||||
/*
|
||||
* We use hard-coded library installation locations for the time being...
|
||||
* No idea where or if libnvidia-ml.so is installed on MacOS X, a
|
||||
* deep scouring of the filesystem on one of the Mac CUDA build boxes
|
||||
* I used turned up nothing, so for now it's not going to work on OSX.
|
||||
*/
|
||||
#if defined(_WIN32)
|
||||
/* Windows */
|
||||
#define libnvidia_ml "%PROGRAMFILES%/NVIDIA Corporation/NVSMI/nvml.dll"
|
||||
#elif defined(__linux) && (defined(__i386__) || defined(__ARM_ARCH_7A__))
|
||||
/* In rpm based linux distributions link name is with extension .1 */
|
||||
/* 32-bit linux assumed */
|
||||
#define libnvidia_ml "libnvidia-ml.so.1"
|
||||
#elif defined(__linux)
|
||||
/* 64-bit linux assumed */
|
||||
#define libnvidia_ml "libnvidia-ml.so.1"
|
||||
#else
|
||||
#define libnvidia_ml ""
|
||||
#warning "Unrecognized platform: need NVML DLL path for this platform..."
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
char tmp[512];
|
||||
ExpandEnvironmentStringsA(libnvidia_ml, tmp, sizeof(tmp));
|
||||
#else
|
||||
char tmp[512] = libnvidia_ml;
|
||||
#endif
|
||||
|
||||
void* nvml_dll = wrap_dlopen(tmp);
|
||||
if (nvml_dll == nullptr)
|
||||
{
|
||||
cwarn << "Failed to obtain all required NVML function pointers";
|
||||
cwarn << "NVIDIA hardware monitoring disabled";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
nvmlh = (wrap_nvml_handle*)calloc(1, sizeof(wrap_nvml_handle));
|
||||
|
||||
nvmlh->nvml_dll = nvml_dll;
|
||||
|
||||
nvmlh->nvmlInit = (wrap_nvmlReturn_t(*)(void))wrap_dlsym(nvmlh->nvml_dll, "nvmlInit");
|
||||
nvmlh->nvmlDeviceGetCount =
|
||||
(wrap_nvmlReturn_t(*)(int*))wrap_dlsym(nvmlh->nvml_dll, "nvmlDeviceGetCount_v2");
|
||||
nvmlh->nvmlDeviceGetHandleByIndex = (wrap_nvmlReturn_t(*)(int, wrap_nvmlDevice_t*))wrap_dlsym(
|
||||
nvmlh->nvml_dll, "nvmlDeviceGetHandleByIndex_v2");
|
||||
nvmlh->nvmlDeviceGetPciInfo = (wrap_nvmlReturn_t(*)(
|
||||
wrap_nvmlDevice_t, wrap_nvmlPciInfo_t*))wrap_dlsym(nvmlh->nvml_dll, "nvmlDeviceGetPciInfo");
|
||||
nvmlh->nvmlDeviceGetName = (wrap_nvmlReturn_t(*)(wrap_nvmlDevice_t, char*, int))wrap_dlsym(
|
||||
nvmlh->nvml_dll, "nvmlDeviceGetName");
|
||||
nvmlh->nvmlDeviceGetTemperature = (wrap_nvmlReturn_t(*)(wrap_nvmlDevice_t, int,
|
||||
unsigned int*))wrap_dlsym(nvmlh->nvml_dll, "nvmlDeviceGetTemperature");
|
||||
nvmlh->nvmlDeviceGetFanSpeed = (wrap_nvmlReturn_t(*)(
|
||||
wrap_nvmlDevice_t, unsigned int*))wrap_dlsym(nvmlh->nvml_dll, "nvmlDeviceGetFanSpeed");
|
||||
nvmlh->nvmlDeviceGetPowerUsage = (wrap_nvmlReturn_t(*)(
|
||||
wrap_nvmlDevice_t, unsigned int*))wrap_dlsym(nvmlh->nvml_dll, "nvmlDeviceGetPowerUsage");
|
||||
nvmlh->nvmlShutdown = (wrap_nvmlReturn_t(*)())wrap_dlsym(nvmlh->nvml_dll, "nvmlShutdown");
|
||||
|
||||
if (nvmlh->nvmlInit == nullptr || nvmlh->nvmlShutdown == nullptr ||
|
||||
nvmlh->nvmlDeviceGetCount == nullptr || nvmlh->nvmlDeviceGetHandleByIndex == nullptr ||
|
||||
nvmlh->nvmlDeviceGetPciInfo == nullptr || nvmlh->nvmlDeviceGetName == nullptr ||
|
||||
nvmlh->nvmlDeviceGetTemperature == nullptr || nvmlh->nvmlDeviceGetFanSpeed == nullptr ||
|
||||
nvmlh->nvmlDeviceGetPowerUsage == nullptr)
|
||||
{
|
||||
cwarn << "Failed to obtain all required NVML function pointers";
|
||||
cwarn << "NVIDIA hardware monitoring disabled";
|
||||
|
||||
wrap_dlclose(nvmlh->nvml_dll);
|
||||
free(nvmlh);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nvmlh->nvmlInit();
|
||||
nvmlh->nvmlDeviceGetCount(&nvmlh->nvml_gpucount);
|
||||
|
||||
nvmlh->devs = (wrap_nvmlDevice_t*)calloc(nvmlh->nvml_gpucount, sizeof(wrap_nvmlDevice_t));
|
||||
nvmlh->nvml_pci_domain_id = (unsigned int*)calloc(nvmlh->nvml_gpucount, sizeof(unsigned int));
|
||||
nvmlh->nvml_pci_bus_id = (unsigned int*)calloc(nvmlh->nvml_gpucount, sizeof(unsigned int));
|
||||
nvmlh->nvml_pci_device_id = (unsigned int*)calloc(nvmlh->nvml_gpucount, sizeof(unsigned int));
|
||||
|
||||
/* Obtain GPU device handles we're going to need repeatedly... */
|
||||
for (int i = 0; i < nvmlh->nvml_gpucount; i++)
|
||||
{
|
||||
nvmlh->nvmlDeviceGetHandleByIndex(i, &nvmlh->devs[i]);
|
||||
}
|
||||
|
||||
/* Query PCI info for each NVML device, and build table for mapping of */
|
||||
/* CUDA device IDs to NVML device IDs and vice versa */
|
||||
for (int i = 0; i < nvmlh->nvml_gpucount; i++)
|
||||
{
|
||||
wrap_nvmlPciInfo_t pciinfo;
|
||||
nvmlh->nvmlDeviceGetPciInfo(nvmlh->devs[i], &pciinfo);
|
||||
nvmlh->nvml_pci_domain_id[i] = pciinfo.domain;
|
||||
nvmlh->nvml_pci_bus_id[i] = pciinfo.bus;
|
||||
nvmlh->nvml_pci_device_id[i] = pciinfo.device;
|
||||
}
|
||||
|
||||
return nvmlh;
|
||||
}
|
||||
|
||||
|
||||
int wrap_nvml_destroy(wrap_nvml_handle* nvmlh)
|
||||
{
|
||||
nvmlh->nvmlShutdown();
|
||||
|
||||
wrap_dlclose(nvmlh->nvml_dll);
|
||||
free(nvmlh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_nvml_get_gpucount(wrap_nvml_handle* nvmlh, int* gpucount)
|
||||
{
|
||||
*gpucount = nvmlh->nvml_gpucount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_nvml_get_gpu_name(wrap_nvml_handle* nvmlh, int gpuindex, char* namebuf, int bufsize)
|
||||
{
|
||||
if (gpuindex < 0 || gpuindex >= nvmlh->nvml_gpucount)
|
||||
return -1;
|
||||
|
||||
if (nvmlh->nvmlDeviceGetName(nvmlh->devs[gpuindex], namebuf, bufsize) != WRAPNVML_SUCCESS)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_nvml_get_tempC(wrap_nvml_handle* nvmlh, int gpuindex, unsigned int* tempC)
|
||||
{
|
||||
if (gpuindex < 0 || gpuindex >= nvmlh->nvml_gpucount)
|
||||
return -1;
|
||||
|
||||
if (nvmlh->nvmlDeviceGetTemperature(
|
||||
nvmlh->devs[gpuindex], 0u /* NVML_TEMPERATURE_GPU */, tempC) != WRAPNVML_SUCCESS)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_nvml_get_fanpcnt(wrap_nvml_handle* nvmlh, int gpuindex, unsigned int* fanpcnt)
|
||||
{
|
||||
if (gpuindex < 0 || gpuindex >= nvmlh->nvml_gpucount)
|
||||
return -1;
|
||||
|
||||
if (nvmlh->nvmlDeviceGetFanSpeed(nvmlh->devs[gpuindex], fanpcnt) != WRAPNVML_SUCCESS)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrap_nvml_get_power_usage(wrap_nvml_handle* nvmlh, int gpuindex, unsigned int* milliwatts)
|
||||
{
|
||||
if (gpuindex < 0 || gpuindex >= nvmlh->nvml_gpucount)
|
||||
return -1;
|
||||
|
||||
if (nvmlh->nvmlDeviceGetPowerUsage(nvmlh->devs[gpuindex], milliwatts) != WRAPNVML_SUCCESS)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
110
zano/libhwmon/wrapnvml.h
Normal file
110
zano/libhwmon/wrapnvml.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* A trivial little dlopen()-based wrapper library for the
|
||||
* NVIDIA NVML library, to allow runtime discovery of NVML on an
|
||||
* arbitrary system. This is all very hackish and simple-minded, but
|
||||
* it serves my immediate needs in the short term until NVIDIA provides
|
||||
* a static NVML wrapper library themselves, hopefully in
|
||||
* CUDA 6.5 or maybe sometime shortly after.
|
||||
*
|
||||
* This trivial code is made available under the "new" 3-clause BSD license,
|
||||
* and/or any of the GPL licenses you prefer.
|
||||
* Feel free to use the code and modify as you see fit.
|
||||
*
|
||||
* John E. Stone - john.stone@gmail.com
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wraphelper.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Ugly hacks to avoid dependencies on the real nvml.h until it starts
|
||||
* getting included with the CUDA toolkit or a GDK that's got a known
|
||||
* install location, etc.
|
||||
*/
|
||||
typedef enum wrap_nvmlReturn_enum { WRAPNVML_SUCCESS = 0 } wrap_nvmlReturn_t;
|
||||
|
||||
typedef void* wrap_nvmlDevice_t;
|
||||
|
||||
/* our own version of the PCI info struct */
|
||||
typedef struct
|
||||
{
|
||||
char bus_id_str[16]; /* string form of bus info */
|
||||
unsigned int domain;
|
||||
unsigned int bus;
|
||||
unsigned int device;
|
||||
unsigned int pci_device_id; /* combined device and vendor id */
|
||||
unsigned int pci_subsystem_id;
|
||||
unsigned int res0; /* NVML internal use only */
|
||||
unsigned int res1;
|
||||
unsigned int res2;
|
||||
unsigned int res3;
|
||||
} wrap_nvmlPciInfo_t;
|
||||
|
||||
|
||||
/*
|
||||
* Handle to hold the function pointers for the entry points we need,
|
||||
* and the shared library itself.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
void* nvml_dll;
|
||||
int nvml_gpucount;
|
||||
unsigned int* nvml_pci_domain_id;
|
||||
unsigned int* nvml_pci_bus_id;
|
||||
unsigned int* nvml_pci_device_id;
|
||||
wrap_nvmlDevice_t* devs;
|
||||
wrap_nvmlReturn_t (*nvmlInit)(void);
|
||||
wrap_nvmlReturn_t (*nvmlDeviceGetCount)(int*);
|
||||
wrap_nvmlReturn_t (*nvmlDeviceGetHandleByIndex)(int, wrap_nvmlDevice_t*);
|
||||
wrap_nvmlReturn_t (*nvmlDeviceGetPciInfo)(wrap_nvmlDevice_t, wrap_nvmlPciInfo_t*);
|
||||
wrap_nvmlReturn_t (*nvmlDeviceGetName)(wrap_nvmlDevice_t, char*, int);
|
||||
wrap_nvmlReturn_t (*nvmlDeviceGetTemperature)(wrap_nvmlDevice_t, int, unsigned int*);
|
||||
wrap_nvmlReturn_t (*nvmlDeviceGetFanSpeed)(wrap_nvmlDevice_t, unsigned int*);
|
||||
wrap_nvmlReturn_t (*nvmlDeviceGetPowerUsage)(wrap_nvmlDevice_t, unsigned int*);
|
||||
wrap_nvmlReturn_t (*nvmlShutdown)(void);
|
||||
} wrap_nvml_handle;
|
||||
|
||||
|
||||
wrap_nvml_handle* wrap_nvml_create();
|
||||
int wrap_nvml_destroy(wrap_nvml_handle* nvmlh);
|
||||
|
||||
/*
|
||||
* Query the number of GPUs seen by NVML
|
||||
*/
|
||||
int wrap_nvml_get_gpucount(wrap_nvml_handle* nvmlh, int* gpucount);
|
||||
|
||||
/*
|
||||
* query the name of the GPU model from the CUDA device ID
|
||||
*
|
||||
*/
|
||||
int wrap_nvml_get_gpu_name(wrap_nvml_handle* nvmlh, int gpuindex, char* namebuf, int bufsize);
|
||||
|
||||
/*
|
||||
* Query the current GPU temperature (Celsius), from the CUDA device ID
|
||||
*/
|
||||
int wrap_nvml_get_tempC(wrap_nvml_handle* nvmlh, int gpuindex, unsigned int* tempC);
|
||||
|
||||
/*
|
||||
* Query the current GPU fan speed (percent) from the CUDA device ID
|
||||
*/
|
||||
int wrap_nvml_get_fanpcnt(wrap_nvml_handle* nvmlh, int gpuindex, unsigned int* fanpcnt);
|
||||
|
||||
/*
|
||||
* Query the current GPU power usage in milliwatts from the CUDA device ID
|
||||
*
|
||||
* This feature is only available on recent GPU generations and may be
|
||||
* limited in some cases only to Tesla series GPUs.
|
||||
* If the query is run on an unsupported GPU, this routine will return -1.
|
||||
*/
|
||||
int wrap_nvml_get_power_usage(wrap_nvml_handle* nvmlh, int gpuindex, unsigned int* milliwatts);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user