AMD: code for checking available readables

This commit is contained in:
Jussi Kuokkanen 2020-03-22 15:19:55 +02:00
parent 15fa1332f8
commit 9054680f09
4 changed files with 107 additions and 8 deletions

View File

@ -31,7 +31,7 @@ struct Enumeration {
};
using AssignmentArgument = std::variant<int, double, uint>;
using ReadableValue = std::variant<int, double>;
using ReadableValue = std::variant<int, uint, double>;
using RangeInfo = std::variant<Range<int>, Range<double>>;
using AssignableInfo = std::variant<RangeInfo, std::vector<Enumeration>>;
@ -49,6 +49,7 @@ private:
class DynamicReadable {
public:
DynamicReadable() {}
DynamicReadable(const std::function<std::variant<ReadError, ReadableValue>()> readFunc) {
m_readFunc = readFunc;
}
@ -57,6 +58,7 @@ public:
}
private:
std::function<std::variant<ReadError, ReadableValue>()> m_readFunc;
std::optional<std::string> m_unit;
};
// DeviceNode has a name, and optionally implements one of [Assignable, DynamicReadable]

View File

@ -0,0 +1,32 @@
#pragma once
#include <functional>
#include <tuple>
namespace TuxClocker {
// Creates a function with no arguments from a function that takes some from inputs to the function and the function
template<typename T, typename... Args>
auto specializeFunction(Args... args, std::function<T(Args...)> func) {
return [args = std::make_tuple(std::move(args)...), &func]() {
return std::apply([&func](auto ...args) {
func(args...);
}, std::move(args));
};
}
template<template<typename> typename List, typename In, typename Out>
List<Out> map(List<In> list, std::function<Out(In)> func) {
List<Out> retval;
std::transform(list.begin(), list.end(), std::back_inserter(retval), func);
return retval;
}
template<typename List, typename T>
List filter(List list, std::function<bool(T)> func) {
List retval;
std::copy_if(list.begin(), list.end(), std::back_inserter(retval), func);
return retval;
}
};

View File

@ -1,3 +1,5 @@
#include <Functional.hpp>
#include <patterns.hpp>
#include <Plugin.hpp>
#include <errno.h>
@ -21,13 +23,14 @@ extern int errno;
#define DEVICE_FILE_PREFIX DRM_DIR_NAME "/" DRM_RENDER_MINOR_NAME
#define RENDERD_OFFSET 128
using namespace mpark::patterns;
using namespace TuxClocker::Plugin;
using namespace TuxClocker::Device;
using namespace TuxClocker;
namespace fs = std::filesystem;
struct AMDAssignableInfo {
struct AMDGPUInfo {
// Thus is Linux only
std::optional<std::string> hwmonPath;
amdgpu_device_handle devHandle;
@ -42,15 +45,32 @@ public:
~AMDPlugin();
private:
TreeNode<DeviceNode> m_rootNode;
std::vector<AMDAssignableInfo> m_assignableInfoVec;
std::vector<AMDGPUInfo> m_GPUInfoVec;
template <typename T>
static std::variant<ReadError, ReadableValue> libdrmRead(amdgpu_device_handle dev,
uint query,
std::optional<std::function<T(T)>> transformFunc = std::nullopt);
};
AMDPlugin::~AMDPlugin() {
for (auto info : m_assignableInfoVec) {
for (auto info : m_GPUInfoVec) {
amdgpu_device_deinitialize(info.devHandle);
}
}
template <typename T>
std::variant<ReadError, ReadableValue>AMDPlugin::libdrmRead(amdgpu_device_handle dev,
uint query,
std::optional<std::function<T(T)>> transformFunc) {
T value;
auto retval = amdgpu_query_sensor_info(dev, query, sizeof(T), &value);
if (retval != 0) return ReadError::UnknownError;
if (!transformFunc.has_value()) return value;
return transformFunc.value()(value);
}
AMDPlugin::AMDPlugin() {
/*Assignable a([](auto arg) {
return std::nullopt;
@ -78,9 +98,10 @@ AMDPlugin::AMDPlugin() {
auto v_ptr = drmGetVersion(fd);
amdgpu_device_handle dev;
uint32_t m, n;
int devInitRetval;
if (fd > 0 &&
v_ptr &&
amdgpu_device_initialize(fd, &m, &n, &dev) == 0 &&
(devInitRetval = amdgpu_device_initialize(fd, &m, &n, &dev)) == 0 &&
std::string(v_ptr->name).find(_AMDGPU_NAME) != std::string::npos) {
// Device uses amdgpu
// Find hwmon path if available
@ -98,11 +119,53 @@ AMDPlugin::AMDPlugin() {
}
// This exception is only abnormal to get on Linux
catch (fs::filesystem_error &e) {}
m_assignableInfoVec.push_back(AMDAssignableInfo{hwmonPath, dev});
m_GPUInfoVec.push_back(AMDGPUInfo{hwmonPath, dev});
continue;
}
if (devInitRetval == 0) amdgpu_device_deinitialize(dev);
close(fd);
drmFreeVersion(v_ptr);
}
// Add nodes with successful queries to device node
// Data structure for mapping to DynamicReadables
struct UnspecializedReadable {
std::function<std::variant<ReadError, ReadableValue>(AMDGPUInfo)> func;
std::optional<std::string> unit;
};
// List of query functions for DynamicReadables
std::vector<UnspecializedReadable> rawNodes = {
{
[&](AMDGPUInfo info) {
return libdrmRead<uint>(info.devHandle,
AMDGPU_INFO_SENSOR_GPU_TEMP,
std::function<uint(uint)>([](uint val) {return val / 1000;}));
},
std::nullopt
}
};
for (auto info : m_GPUInfoVec) {
auto availableReadables = filter(rawNodes,
std::function<bool(UnspecializedReadable)>([info](UnspecializedReadable ur) {
auto result = ur.func(info);
// Check if this node returns an error or not
match(result)(pattern(as<ReadError>(_)) = []{return false;},
pattern(_) = []{return true;});
return true;
}));
auto specializedNodes = map(availableReadables,
std::function<DynamicReadable(UnspecializedReadable)>(
[info] (UnspecializedReadable ur) {
//auto specializedFunc = specializeFunction<std::variant<ReadError,
//ReadableValue>, AMDGPUInfo>(info, ur.func);
return DynamicReadable([info, ur]() {
return ur.func(info);
});
}));
}
}
TreeNode<DeviceNode> AMDPlugin::deviceRootNode() {

View File

@ -1,11 +1,13 @@
libdrm_amdgpu = cppc.find_library('libdrm_amdgpu', required : false)
libdrm_dep = dependency('libdrm', required : false)
patterns_inc = include_directories('../include/deps/patterns/include/mpark')
if libdrm_dep.found() and libdrm_amdgpu.found()
shared_library('amd', 'AMD.cpp',
override_options : ['cpp_std=c++17'],
include_directories : incdir,
dependencies : [libdrm_amdgpu, libdrm_dep],
include_directories : [incdir, patterns_inc],
dependencies : [libdrm_amdgpu, libdrm_dep, boost_dep],
install_dir : get_option('libdir') / 'tuxclocker' / 'plugins',
install : true)
endif