Skip to content
This repository was archived by the owner on Apr 24, 2022. It is now read-only.

Hardware Monitoring for NVML, ADL and AMDGPU SysFS #319

Merged
merged 8 commits into from
Nov 27, 2017
9 changes: 9 additions & 0 deletions libethash-cl/CLMiner.cpp
Original file line number Diff line number Diff line change
@@ -352,6 +352,12 @@ HwMonitor CLMiner::hwmon()
wrap_adl_get_tempC(adlh, index, &tempC);
wrap_adl_get_fanpcnt(adlh, index, &fanpcnt);
}
#if defined(__linux)
if (sysfsh) {
wrap_amdsysfs_get_tempC(sysfsh, index, &tempC);
wrap_amdsysfs_get_fanpcnt(sysfsh, index, &fanpcnt);
}
#endif
hw.tempC = tempC;
hw.fanP = fanpcnt;
return hw;
@@ -384,6 +390,9 @@ bool CLMiner::init(const h256& seed)
{
platformId = OPENCL_PLATFORM_AMD;
adlh = wrap_adl_create();
#if defined(__linux)
sysfsh = wrap_amdsysfs_create();
#endif
}
else if (platformName == "Clover")
{
7 changes: 6 additions & 1 deletion libethash-cl/CLMiner.h
Original file line number Diff line number Diff line change
@@ -10,6 +10,9 @@
#include <libethcore/Miner.h>
#include <libhwmon/wrapnvml.h>
#include <libhwmon/wrapadl.h>
#if defined(__linux)
#include <libhwmon/wrapamdsysfs.h>
#endif

#define CL_USE_DEPRECATED_OPENCL_1_2_APIS true
#define CL_HPP_ENABLE_EXCEPTIONS true
@@ -104,7 +107,9 @@ class CLMiner: public Miner

wrap_nvml_handle *nvmlh = NULL;
wrap_adl_handle *adlh = NULL;

#if defined(__linux)
wrap_amdsysfs_handle *sysfsh = NULL;
#endif
};

}
1 change: 1 addition & 0 deletions libhwmon/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ set(SOURCES
wraphelper.h
wrapnvml.h wrapnvml.cpp
wrapadl.h wrapadl.cpp
wrapamdsysfs.h wrapamdsysfs.cpp
)

add_library(hwmon ${SOURCES})
3 changes: 1 addition & 2 deletions libhwmon/wrapadl.cpp
Original file line number Diff line number Diff line change
@@ -12,15 +12,14 @@
extern "C" {
#endif

void* __stdcall ADL_Main_Memory_Alloc(int iSize)
void* ADL_API_CALL ADL_Main_Memory_Alloc(int iSize)
{
void* lpBuffer = malloc(iSize);
return lpBuffer;
}

wrap_adl_handle * wrap_adl_create()
{
int i = 0;
wrap_adl_handle *adlh = NULL;

#if defined(_WIN64)
10 changes: 9 additions & 1 deletion libhwmon/wrapadl.h
Original file line number Diff line number Diff line change
@@ -18,7 +18,15 @@ typedef enum wrap_adlReturn_enum {
typedef void * wrap_adlDevice_t;

// Some ADL defines and structs from adl sdk
typedef void* (__stdcall *ADL_MAIN_MALLOC_CALLBACK)(int);
#if defined (__MSC_VER)
#define ADL_API_CALL __cdecl
#elif defined (_WIN32) || defined (__WIN32__)
#define ADL_API_CALL __stdcall
#else
#define ADL_API_CALL
#endif

typedef void* (ADL_API_CALL *ADL_MAIN_MALLOC_CALLBACK)(int);

#define ADL_MAX_PATH 256
typedef struct AdapterInfo
209 changes: 209 additions & 0 deletions libhwmon/wrapamdsysfs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
* Wrapper for AMD SysFS on linux, using adapted code from amdcovc by matszpk
*
* By Philipp Andreas - [email protected]
*/
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string>
#include <cstring>
#include <climits>
#include <limits>
#include <cstdint>
#include <algorithm>
#include <fstream>
#include <sys/types.h>
#if defined(__linux)
#include <dirent.h>
#endif
#include "wrapamdsysfs.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 = NULL;

#if defined(__linux)
sysfsh = (wrap_amdsysfs_handle *)calloc(1, sizeof(wrap_amdsysfs_handle));

DIR* dirp = opendir("/sys/class/drm");
if (dirp == nullptr)
return NULL;

unsigned int gpucount = 0;
struct dirent* dire;
while ((dire = readdir(dirp)) != nullptr)
{
if (::strncmp(dire->d_name, "card", 4) != 0)
continue; // is not card directory
const char* p;
for (p = dire->d_name + 4; ::isdigit(*p); p++);
if (*p != 0)
continue; // is not card directory
unsigned int v = ::strtoul(dire->d_name + 4, nullptr, 10);
gpucount = std::max(gpucount, v + 1);
}
if (errno != 0)
{
closedir(dirp);
return NULL;
}
closedir(dirp);

sysfsh->card_sysfs_device_id = (int*)calloc(gpucount, sizeof(int));
sysfsh->sysfs_hwmon_id = (int*)calloc(gpucount, sizeof(int));

// filter AMD GPU cards and create mappings
char dbuf[120];
int cardIndex = 0;
for (unsigned int i = 0; i < gpucount; i++)
{
sysfsh->card_sysfs_device_id[cardIndex] = -1;
sysfsh->sysfs_hwmon_id[cardIndex] = -1;

snprintf(dbuf, 120, "/sys/class/drm/card%u/device/vendor", i);
unsigned int vendorId = 0;
if (!getFileContentValue(dbuf, vendorId))
continue;
if (vendorId != 4098) // if not AMD
continue;

sysfsh->card_sysfs_device_id[cardIndex] = i;
cardIndex++;
}

// Number of AMD cards found we do not care about non AMD cards
sysfsh->sysfs_gpucount = cardIndex;

// Get hwmon directory index
for (int i = 0; i < sysfsh->sysfs_gpucount; i++)
{
int sysfsIdx = sysfsh->card_sysfs_device_id[i];

// Should not happen
if (sysfsIdx < 0) {
free(sysfsh);
return NULL;
}

// search hwmon
errno = 0;
snprintf(dbuf, 120, "/sys/class/drm/card%u/device/hwmon", sysfsIdx);
DIR* dirp = opendir(dbuf);
if (dirp == nullptr) {
free(sysfsh);
return NULL;
}
errno = 0;
struct dirent* dire;
unsigned int hwmonIndex = UINT_MAX;
while ((dire = readdir(dirp)) != nullptr)
{
if (::strncmp(dire->d_name, "hwmon", 5) != 0)
continue; // is not hwmon directory
const char* p;
for (p = dire->d_name + 5; ::isdigit(*p); p++);
if (*p != 0)
continue; // is not hwmon directory
errno = 0;
unsigned int v = ::strtoul(dire->d_name + 5, nullptr, 10);
hwmonIndex = std::min(hwmonIndex, v);
}
if (errno != 0)
{
closedir(dirp);
free(sysfsh);
return NULL;
}
closedir(dirp);
if (hwmonIndex == UINT_MAX) {
free(sysfsh);
return NULL;
}

sysfsh->sysfs_hwmon_id[i] = hwmonIndex;
}
#endif

return sysfsh;
}
int wrap_amdsysfs_destory(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)
{
int gpuindex = sysfsh->card_sysfs_device_id[index];
if (gpuindex < 0 || index >= sysfsh->sysfs_gpucount)
return -1;

int hwmonindex = sysfsh->sysfs_hwmon_id[index];
if (hwmonindex < 0)
return -1;

char dbuf[120];
snprintf(dbuf, 120, "/sys/class/drm/card%u/device/hwmon/hwmon%u/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)
{
int gpuindex = sysfsh->card_sysfs_device_id[index];
if (gpuindex < 0 || index >= sysfsh->sysfs_gpucount)
return -1;

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%u/device/hwmon/hwmon%u/pwm1",
gpuindex, hwmonindex);
getFileContentValue(dbuf, pwm);

snprintf(dbuf, 120, "/sys/class/drm/card%u/device/hwmon/hwmon%u/pwm1_max",
gpuindex, hwmonindex);
getFileContentValue(dbuf, pwmMax);

snprintf(dbuf, 120, "/sys/class/drm/card%u/device/hwmon/hwmon%u/pwm1_min",
gpuindex, hwmonindex);
getFileContentValue(dbuf, pwmMin);

*fanpcnt = double(pwm - pwmMin) / double(pwmMax - pwmMin) * 100.0;
return 0;
}
25 changes: 25 additions & 0 deletions libhwmon/wrapamdsysfs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Wrapper for AMD SysFS on linux, using adapted code from amdcovc by matszpk
*
* By Philipp Andreas - [email protected]
*/

#ifndef _WRAPAMDSYSFS_H_
#define _WRAPAMDSYSFS_H_

typedef struct {
int sysfs_gpucount;
int *card_sysfs_device_id; /* map cardidx to filesystem card idx */
int *sysfs_hwmon_id; /* filesystem card idx to filesystem hwmon idx */
} wrap_amdsysfs_handle;

wrap_amdsysfs_handle * wrap_amdsysfs_create();
int wrap_amdsysfs_destory(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);

#endif