add optional python-hwdata dependency to get AMD GPU names

This commit is contained in:
Jussi Kuokkanen 2023-11-12 00:01:22 +02:00
parent ae13f1a59d
commit 49fea845f8
7 changed files with 136 additions and 6 deletions

View File

@ -4,3 +4,5 @@ option('daemon', type: 'boolean', value: 'true', description: 'Build daemon')
option('plugins', type: 'boolean', value: 'true', description: 'Build plugins') option('plugins', type: 'boolean', value: 'true', description: 'Build plugins')
option('library', type: 'boolean', value: 'true', description: 'Build library') option('library', type: 'boolean', value: 'true', description: 'Build library')
option('gui', type: 'boolean', value: 'true', description: 'Build Qt GUI') option('gui', type: 'boolean', value: 'true', description: 'Build Qt GUI')
option('require-python-hwdata', type: 'boolean', value: 'false',
description: 'Require python-hwdata for prettier AMD GPU names')

View File

@ -13,6 +13,10 @@
#include <libdrm/amdgpu_drm.h> #include <libdrm/amdgpu_drm.h>
#include <libintl.h> #include <libintl.h>
#ifdef WITH_HWDATA
#include <HWData.hpp>
#endif
#define _(String) gettext(String) #define _(String) gettext(String)
extern int errno; extern int errno;
@ -1242,6 +1246,20 @@ std::vector<TreeNode<DeviceNode>> getUtilizationsRoot(AMDGPUData data) {
} }
std::vector<TreeNode<DeviceNode>> getGPUName(AMDGPUData data) { std::vector<TreeNode<DeviceNode>> getGPUName(AMDGPUData data) {
#ifdef WITH_HWDATA
// Get GPU name from hwdata
static auto pciObj = getPciObject();
auto pciData = fromUeventFile(data.deviceFilename);
if (pciObj.has_value() && pciData.has_value()) {
auto name = hwdataName(*pciObj, *pciData);
if (name.has_value())
return {DeviceNode{
.name = *name,
.interface = std::nullopt,
.hash = md5(data.identifier),
}};
}
#endif
auto name = amdgpu_get_marketing_name(data.devHandle); auto name = amdgpu_get_marketing_name(data.devHandle);
if (name) { if (name) {
return {DeviceNode{ return {DeviceNode{
@ -1319,6 +1337,10 @@ private:
}; };
TreeNode<DeviceNode> AMDPlugin::deviceRootNode() { TreeNode<DeviceNode> AMDPlugin::deviceRootNode() {
#ifdef WITH_HWDATA
PythonInstance p;
#endif
TreeNode<DeviceNode> root; TreeNode<DeviceNode> root;
auto dataVec = fromFilesystem(); auto dataVec = fromFilesystem();

View File

@ -192,6 +192,7 @@ std::optional<AMDGPUData> fromRenderDFile(const fs::directory_entry &entry) {
.devPath = devPath, .devPath = devPath,
.devHandle = dev, .devHandle = dev,
.pciId = std::to_string(info.device_id), .pciId = std::to_string(info.device_id),
.deviceFilename = filename,
.identifier = identifier, .identifier = identifier,
.ppTableType = tableType, .ppTableType = tableType,
}; };

View File

@ -31,6 +31,8 @@ struct AMDGPUData {
amdgpu_device_handle devHandle; amdgpu_device_handle devHandle;
// PCIe device ID // PCIe device ID
std::string pciId; std::string pciId;
// Eg. renderD128
std::string deviceFilename;
// Device ID + GPU index // Device ID + GPU index
std::string identifier; std::string identifier;
std::optional<PPTableType> ppTableType; std::optional<PPTableType> ppTableType;

63
src/plugins/HWData.cpp Normal file
View File

@ -0,0 +1,63 @@
#include "HWData.hpp"
#include <fplus/fplus.hpp>
#include <Utils.hpp>
std::optional<PciData> fromUeventFile(const std::string &deviceFilename) {
/*
DRIVER=nvidia
PCI_CLASS=30000
PCI_ID=10DE:1B80
PCI_SUBSYS_ID=1458:3702
PCI_SLOT_NAME=0000:01:00.0
MODALIAS=pci:v000010DEd00001B80sv00001458sd00003702bc03sc00i00
*/
char path[64];
snprintf(path, 64, "/sys/class/drm/%s/device/uevent", deviceFilename.c_str());
auto contents = fileContents(path);
if (!contents.has_value())
return std::nullopt;
auto isNewline = [](char c) { return c == '\n'; };
auto lines = fplus::split_by(isNewline, false, *contents);
if (lines.size() > 5) {
auto idWords = fplus::split_one_of(std::string{"=:"}, false, lines[2]);
auto subsysWords = fplus::split_one_of(std::string{"="}, false, lines[3]);
if (idWords.size() > 2 && subsysWords.size() > 1) {
auto device = fplus::to_lower_case(idWords[2]);
auto subsystem = fplus::to_lower_case(subsysWords[1]);
return PciData{device, subsystem};
}
}
return std::nullopt;
}
std::optional<PyObject *> getPciObject() {
auto modName = PyUnicode_FromString("hwdata");
auto mod = PyImport_Import(modName);
if (mod) {
auto pciObj = PyObject_GetAttrString(mod, "PCI");
if (pciObj)
return pciObj;
}
return std::nullopt;
}
std::optional<std::string> hwdataName(PyObject *pciObj, PciData data) {
// Vendor is always '1002' aka AMD
auto subsysStr = PyObject_CallMethod(
pciObj, "get_subsystem", "sss", "1002", data.device.c_str(), data.subsystem.c_str());
if (subsysStr && PyUnicode_Check(subsysStr))
return PyUnicode_AsUTF8(subsysStr);
// Try to get device name
auto devStr = PyObject_CallMethod(pciObj, "get_device", "ss", "1002", data.device.c_str());
if (devStr && PyUnicode_Check(devStr))
return PyUnicode_AsUTF8(devStr);
return std::nullopt;
}

19
src/plugins/HWData.hpp Normal file
View File

@ -0,0 +1,19 @@
#include <optional>
#include <Python.h>
#include <string>
// Reduces the places we need to ifdef by destroying automatically
class PythonInstance {
public:
PythonInstance() { Py_Initialize(); }
~PythonInstance() { Py_Finalize(); }
};
struct PciData {
std::string device;
std::string subsystem;
};
std::optional<PciData> fromUeventFile(const std::string &deviceFilename);
std::optional<PyObject *> getPciObject();
std::optional<std::string> hwdataName(PyObject *pciObj, PciData);

View File

@ -1,17 +1,38 @@
libdrm_amdgpu = cc.find_library('drm_amdgpu', required : false)
libdrm_dep = dependency('libdrm', required : false)
patterns_inc = include_directories('../include/deps/patterns/include/mpark') patterns_inc = include_directories('../include/deps/patterns/include/mpark')
fplus_inc = include_directories('../include/deps/FunctionalPlus/include') fplus_inc = include_directories('../include/deps/FunctionalPlus/include')
libdrm_amdgpu = cc.find_library('drm_amdgpu', required : false)
libdrm_dep = dependency('libdrm', required : false)
python = import('python')
python_with_hwdata = python.find_installation('python3',
modules : ['hwdata'],
required : get_option('require-python-hwdata'))
hwdata_version = run_command('python3', '-c',
'from importlib.metadata import version; print(version(\'hwdata\'))').stdout().strip()
if libdrm_dep.found() and libdrm_amdgpu.found() if libdrm_dep.found() and libdrm_amdgpu.found()
shared_library('amd', 'AMD.cpp', 'AMDUtils.cpp', 'Utils.cpp', sources = ['AMD.cpp', 'AMDUtils.cpp', 'Utils.cpp']
cpp_args = []
deps = [ libdrm_amdgpu, libdrm_dep, boost_dep ]
if (python_with_hwdata.found())
if (hwdata_version.version_compare('<2.4.1'))
warning('python-hwdata 2.4.1 is recommended for PCI.get_subsystem')
endif
# Makes us link to libpython
deps += python_with_hwdata.dependency(embed : true)
cpp_args += '-DWITH_HWDATA'
sources += 'HWData.cpp'
endif
shared_library('amd',
sources,
override_options : ['cpp_std=c++17'], override_options : ['cpp_std=c++17'],
include_directories : [incdir, patterns_inc, fplus_inc], include_directories : [incdir, patterns_inc, fplus_inc],
dependencies : [ libdrm_amdgpu, libdrm_dep, boost_dep ], dependencies : deps,
install_dir : get_option('libdir') / 'tuxclocker' / 'plugins', install_dir : get_option('libdir') / 'tuxclocker' / 'plugins',
install : true, install : true,
link_with : libtuxclocker) cpp_args : cpp_args,
link_with : libtuxclocker)
endif endif
libnvml = cc.find_library('nvidia-ml', required : false) libnvml = cc.find_library('nvidia-ml', required : false)