mirror of
https://github.com/Lurkki14/tuxclocker.git
synced 2025-02-25 18:55:24 -06:00
daemon, lib: add StaticReadable
This commit is contained in:
parent
ad81d8d13c
commit
f2629b1360
@ -75,13 +75,22 @@ private:
|
||||
std::optional<std::string> m_unit;
|
||||
};
|
||||
|
||||
struct StaticReadable {
|
||||
ReadableValue value;
|
||||
std::optional<std::string> unit;
|
||||
class StaticReadable {
|
||||
public:
|
||||
StaticReadable(ReadableValue value, std::optional<std::string> unit) {
|
||||
m_value = value;
|
||||
m_unit = unit;
|
||||
}
|
||||
ReadableValue value() {return m_value;}
|
||||
std::optional<std::string> unit() {return m_unit;}
|
||||
private:
|
||||
ReadableValue m_value;
|
||||
std::optional<std::string> m_unit;
|
||||
};
|
||||
|
||||
// DeviceNode has a name, and optionally implements one of [Assignable, DynamicReadable]
|
||||
using DeviceInterface = std::variant<Assignable, DynamicReadable>;
|
||||
/* DeviceNode has a name, and optionally implements one of
|
||||
[Assignable, DynamicReadable, StaticReadable] */
|
||||
using DeviceInterface = std::variant<Assignable, DynamicReadable, StaticReadable>;
|
||||
|
||||
struct DeviceNode {
|
||||
std::string name;
|
||||
|
@ -59,6 +59,28 @@ struct UnspecializedReadable {
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
// Create StaticReadable nodes
|
||||
static std::vector<DeviceNode> staticToDeviceNodes(
|
||||
std::vector<UnspecializedReadable<T>> rawNodes, T data, std::string uuid) {
|
||||
std::vector<DeviceNode> retval;
|
||||
|
||||
for (const auto &rawNode : rawNodes) {
|
||||
if_let(pattern(as<ReadableValue>(arg)) = rawNode.func(data)) =
|
||||
[=, &retval] (ReadableValue value) {
|
||||
auto staticReadable = StaticReadable(
|
||||
value, rawNode.unit
|
||||
);
|
||||
auto devNode = DeviceNode{
|
||||
.name = rawNode.nodeName,
|
||||
.interface = staticReadable,
|
||||
.hash = rawNode.hash(uuid, data)
|
||||
};
|
||||
retval.push_back(devNode);
|
||||
};
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -105,8 +127,10 @@ private:
|
||||
static std::variant<ReadError, ReadableValue> nvmlRead(nvmlDevice_t dev,
|
||||
std::function<nvmlReturn_t(nvmlDevice_t, In*)> readFunc,
|
||||
std::optional<std::function<Out(In)>> transformFunc = std::nullopt);
|
||||
template <typename Out>
|
||||
static std::variant<ReadError, ReadableValue> nvctlRead(uint index,
|
||||
std::function<Bool(uint, int*)> readFunc);
|
||||
std::function<Bool(uint, int*)> readFunc,
|
||||
std::optional<std::function<Out(int)>> transformFunc = std::nullopt);
|
||||
std::optional<AssignmentError> nvctlWrite(uint index, int mask,
|
||||
int target, int attribute, int value);
|
||||
uint nvctrlPerfModes(uint index);
|
||||
@ -128,15 +152,18 @@ std::variant<ReadError, ReadableValue> NvidiaPlugin::nvmlRead(nvmlDevice_t dev,
|
||||
return transformFunc.value()(value);
|
||||
}
|
||||
|
||||
template <typename Out>
|
||||
std::variant<ReadError, ReadableValue> NvidiaPlugin::nvctlRead(uint index,
|
||||
std::function<Bool(uint, int*)> readFunc) {
|
||||
std::function<Bool(uint, int*)> readFunc,
|
||||
std::optional<std::function<Out(int)>> transformFunc) {
|
||||
int val;
|
||||
if (!readFunc(index, &val)) {
|
||||
// TODO: Get error from X error handler here
|
||||
return ReadError::UnknownError;
|
||||
}
|
||||
// All sensor readings through this make sense as uint
|
||||
return static_cast<uint>(val);
|
||||
if (transformFunc.has_value())
|
||||
return transformFunc.value()(val);
|
||||
return static_cast<Out>(val);
|
||||
}
|
||||
|
||||
std::optional<AssignmentError> NvidiaPlugin::nvctlWrite(uint index,
|
||||
@ -233,9 +260,11 @@ NvidiaPlugin::NvidiaPlugin() : m_dpy() {
|
||||
std::vector<UnspecializedReadable<uint>> rawNVCTRLNodes = {
|
||||
{
|
||||
[&](uint index) {
|
||||
return nvctlRead(index, [&](uint index, int *value) {
|
||||
return nvctlRead<double>(index, [&](uint index, int *value) {
|
||||
return XNVCTRLQueryTargetAttribute(m_dpy, NV_CTRL_TARGET_TYPE_GPU,
|
||||
index, 0, NV_CTRL_GPU_CURRENT_CORE_VOLTAGE, value);
|
||||
}, [](int value) {
|
||||
return static_cast<double>(value) / 1000;
|
||||
});
|
||||
},
|
||||
"mV",
|
||||
@ -247,18 +276,6 @@ NvidiaPlugin::NvidiaPlugin() : m_dpy() {
|
||||
};
|
||||
|
||||
std::vector<UnspecializedReadable<nvmlDevice_t>> rawNVMLNodes = {
|
||||
{
|
||||
[](nvmlDevice_t dev) {
|
||||
return nvmlRead<uint, uint>(dev, [](nvmlDevice_t dev, uint *value) {
|
||||
return nvmlDeviceGetTemperature(dev, NVML_TEMPERATURE_GPU, value);
|
||||
}, std::nullopt);
|
||||
},
|
||||
"°C",
|
||||
"Temperature",
|
||||
[](std::string uuid, nvmlDevice_t) {
|
||||
return md5(uuid + "Temperature");
|
||||
}
|
||||
},
|
||||
{
|
||||
[](nvmlDevice_t dev) {
|
||||
return nvmlRead<uint, double>(dev, [](nvmlDevice_t dev,
|
||||
@ -440,6 +457,50 @@ NvidiaPlugin::NvidiaPlugin() : m_dpy() {
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<UnspecializedReadable<nvmlDevice_t>> rawNVMLTempInfoNodes = {
|
||||
{
|
||||
[](nvmlDevice_t dev) {
|
||||
return nvmlRead<uint, uint>(dev, [](nvmlDevice_t dev, uint *value) {
|
||||
return nvmlDeviceGetTemperatureThreshold(dev,
|
||||
NVML_TEMPERATURE_THRESHOLD_SHUTDOWN, value);
|
||||
}, std::nullopt);
|
||||
},
|
||||
"C",
|
||||
"Shutdown Temperature",
|
||||
[](std::string uuid, nvmlDevice_t) {
|
||||
return md5(uuid + "Shutdown Temperature");
|
||||
}
|
||||
},
|
||||
{
|
||||
[](nvmlDevice_t dev) {
|
||||
return nvmlRead<uint, uint>(dev, [](nvmlDevice_t dev, uint *value) {
|
||||
return nvmlDeviceGetTemperatureThreshold(dev,
|
||||
NVML_TEMPERATURE_THRESHOLD_SLOWDOWN, value);
|
||||
}, std::nullopt);
|
||||
},
|
||||
"C",
|
||||
"Slowdown Temperature",
|
||||
[](std::string uuid, nvmlDevice_t) {
|
||||
return md5(uuid + "Slowdown Temperature");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<UnspecializedReadable<nvmlDevice_t>> rawNVMLTempNodes = {
|
||||
{
|
||||
[](nvmlDevice_t dev) {
|
||||
return nvmlRead<uint, uint>(dev, [](nvmlDevice_t dev, uint *value) {
|
||||
return nvmlDeviceGetTemperature(dev, NVML_TEMPERATURE_GPU, value);
|
||||
}, std::nullopt);
|
||||
},
|
||||
"°C",
|
||||
"Temperature",
|
||||
[](std::string uuid, nvmlDevice_t) {
|
||||
return md5(uuid + "Temperature");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct NVCtrlFanInfo {
|
||||
uint gpuIndex;
|
||||
int fanIndex;
|
||||
@ -552,91 +613,106 @@ NvidiaPlugin::NvidiaPlugin() : m_dpy() {
|
||||
gi++;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// [GPUOpt] -> [TreeNode DeviceNode]
|
||||
// Map GPU data to device nodes
|
||||
TreeNode<DeviceNode> rootNode;
|
||||
auto gpuNodes = fp::transform([&](auto nvOpt) {
|
||||
TreeNode<DeviceNode> gpuRoot = TreeNode(DeviceNode{
|
||||
.name = nvOpt.name,
|
||||
.hash = md5(nvOpt.uuid)
|
||||
});
|
||||
TreeNode<DeviceNode> gpuRoot = TreeNode(DeviceNode{
|
||||
.name = nvOpt.name,
|
||||
.hash = md5(nvOpt.uuid)
|
||||
});
|
||||
|
||||
std::vector<DeviceNode> nvmlFanNodes;
|
||||
// Get nvml nodes if there is a device
|
||||
if_let(pattern(some(arg)) = nvOpt.devHandle) = [&](auto dev) {
|
||||
for (auto &node : UnspecializedReadable<nvmlDevice_t>::toDeviceNodes(
|
||||
rawNVMLNodes, dev, nvOpt.uuid))
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
for (auto &node : UnspecializedAssignable<nvmlDevice_t>::toDeviceNodes(
|
||||
rawNVMLAssignables, dev, nvOpt.uuid))
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
std::vector<DeviceNode> nvmlFanNodes;
|
||||
// Get nvml nodes if there is a device
|
||||
if_let(pattern(some(arg)) = nvOpt.devHandle) = [&](auto dev) {
|
||||
for (auto &node : UnspecializedReadable<nvmlDevice_t>::toDeviceNodes(
|
||||
rawNVMLNodes, dev, nvOpt.uuid))
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
for (auto &node : UnspecializedAssignable<nvmlDevice_t>::toDeviceNodes(
|
||||
rawNVMLAssignables, dev, nvOpt.uuid))
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
for (uint i = 0; i < nvmlFanCount(dev); i++) {
|
||||
NVMLFanInfo info{dev, i};
|
||||
for (auto &node : UnspecializedReadable<NVMLFanInfo>::toDeviceNodes(
|
||||
rawNVMLFanReadables, info, nvOpt.uuid))
|
||||
nvmlFanNodes.push_back(node);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<DeviceNode> nvctrlFanNodes;
|
||||
// Same for NVCtrl
|
||||
if_let(pattern(some(arg)) = nvOpt.index) = [&](auto index) {
|
||||
for (auto &node : UnspecializedReadable<uint>::toDeviceNodes(rawNVCTRLNodes, index,
|
||||
nvOpt.uuid))
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
auto clockInfo = NVClockInfo{nvctrlPerfModes(index), index};
|
||||
for (auto &node : UnspecializedAssignable<NVClockInfo>::toDeviceNodes(
|
||||
rawNVCTRLClockAssignables, clockInfo, nvOpt.uuid))
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
for (auto &node : UnspecializedAssignable<uint>::toDeviceNodes(
|
||||
rawNVCTRLAssignables, index, nvOpt.uuid))
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
for (int i = 0; i < nvctrlFanCount(index); i++) {
|
||||
NVCtrlFanInfo info{index, i};
|
||||
for (auto &node : UnspecializedAssignable<NVCtrlFanInfo>::toDeviceNodes(
|
||||
rawNVCTRLFanAssignables, info, nvOpt.uuid))
|
||||
nvctrlFanNodes.push_back(node);
|
||||
}
|
||||
};
|
||||
TreeNode<DeviceNode> fanRoot = TreeNode(DeviceNode{
|
||||
.name = "Fans",
|
||||
.hash = md5(nvOpt.uuid + "Fans")
|
||||
});
|
||||
// Use a common subparent for readable and assignable fan nodes, if n > 1
|
||||
auto maxFanCount = std::max(nvmlFanNodes.size(), nvctrlFanNodes.size());
|
||||
if (1) {
|
||||
for (uint i = 0; i < maxFanCount; i++) {
|
||||
auto subFanRoot = TreeNode<DeviceNode>(DeviceNode{
|
||||
.name = std::to_string(i),
|
||||
.hash = md5(nvOpt.uuid + "Fan" + std::to_string(i))
|
||||
});
|
||||
if (i < nvctrlFanNodes.size())
|
||||
subFanRoot.appendChild(nvctrlFanNodes[i]);
|
||||
if (i < nvmlFanNodes.size())
|
||||
subFanRoot.appendChild(nvmlFanNodes[i]);
|
||||
fanRoot.appendChild(subFanRoot);
|
||||
}
|
||||
gpuRoot.appendChild(fanRoot);
|
||||
}
|
||||
else {
|
||||
// Add as direct children to GPU
|
||||
for (auto &node : nvmlFanNodes)
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
for (auto &node : nvctrlFanNodes)
|
||||
gpuRoot.appendChild(node);
|
||||
for (uint i = 0; i < nvmlFanCount(dev); i++) {
|
||||
NVMLFanInfo info{dev, i};
|
||||
for (auto &node : UnspecializedReadable<NVMLFanInfo>::toDeviceNodes(
|
||||
rawNVMLFanReadables, info, nvOpt.uuid))
|
||||
nvmlFanNodes.push_back(node);
|
||||
}
|
||||
auto tempInfoRoot = TreeNode(DeviceNode{
|
||||
.name = "Temperatures",
|
||||
.hash = md5(nvOpt.uuid + "Temperatures")
|
||||
});
|
||||
auto tempNodes = UnspecializedReadable<nvmlDevice_t>::toDeviceNodes(
|
||||
rawNVMLTempNodes, dev, nvOpt.uuid);
|
||||
|
||||
return gpuRoot;
|
||||
}, optDataVec);
|
||||
auto tempInfoNodes = UnspecializedReadable<nvmlDevice_t>::staticToDeviceNodes(
|
||||
rawNVMLTempInfoNodes, dev, nvOpt.uuid);
|
||||
|
||||
if (!tempNodes.empty() || !tempInfoNodes.empty()) {
|
||||
for (auto &infoNode : tempInfoNodes)
|
||||
tempInfoRoot.appendChild(infoNode);
|
||||
for (auto &tempNode : tempNodes)
|
||||
tempInfoRoot.appendChild(tempNode);
|
||||
|
||||
gpuRoot.appendChild(tempInfoRoot);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<DeviceNode> nvctrlFanNodes;
|
||||
// Same for NVCtrl
|
||||
if_let(pattern(some(arg)) = nvOpt.index) = [&](auto index) {
|
||||
for (auto &node : UnspecializedReadable<uint>::toDeviceNodes(rawNVCTRLNodes, index,
|
||||
nvOpt.uuid))
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
auto clockInfo = NVClockInfo{nvctrlPerfModes(index), index};
|
||||
for (auto &node : UnspecializedAssignable<NVClockInfo>::toDeviceNodes(
|
||||
rawNVCTRLClockAssignables, clockInfo, nvOpt.uuid))
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
for (auto &node : UnspecializedAssignable<uint>::toDeviceNodes(
|
||||
rawNVCTRLAssignables, index, nvOpt.uuid))
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
for (int i = 0; i < nvctrlFanCount(index); i++) {
|
||||
NVCtrlFanInfo info{index, i};
|
||||
for (auto &node : UnspecializedAssignable<NVCtrlFanInfo>::toDeviceNodes(
|
||||
rawNVCTRLFanAssignables, info, nvOpt.uuid))
|
||||
nvctrlFanNodes.push_back(node);
|
||||
}
|
||||
};
|
||||
TreeNode<DeviceNode> fanRoot = TreeNode(DeviceNode{
|
||||
.name = "Fans",
|
||||
.hash = md5(nvOpt.uuid + "Fans")
|
||||
});
|
||||
// Use a common subparent for readable and assignable fan nodes, if n > 1
|
||||
auto maxFanCount = std::max(nvmlFanNodes.size(), nvctrlFanNodes.size());
|
||||
if (1) {
|
||||
for (uint i = 0; i < maxFanCount; i++) {
|
||||
auto subFanRoot = TreeNode<DeviceNode>(DeviceNode{
|
||||
.name = std::to_string(i),
|
||||
.hash = md5(nvOpt.uuid + "Fan" + std::to_string(i))
|
||||
});
|
||||
if (i < nvctrlFanNodes.size())
|
||||
subFanRoot.appendChild(nvctrlFanNodes[i]);
|
||||
if (i < nvmlFanNodes.size())
|
||||
subFanRoot.appendChild(nvmlFanNodes[i]);
|
||||
fanRoot.appendChild(subFanRoot);
|
||||
}
|
||||
gpuRoot.appendChild(fanRoot);
|
||||
}
|
||||
else {
|
||||
// Add as direct children to GPU
|
||||
for (auto &node : nvmlFanNodes)
|
||||
gpuRoot.appendChild(node);
|
||||
|
||||
for (auto &node : nvctrlFanNodes)
|
||||
gpuRoot.appendChild(node);
|
||||
}
|
||||
|
||||
return gpuRoot;
|
||||
}, optDataVec);
|
||||
|
||||
for (auto &gpuNode : gpuNodes) rootNode.appendChild(gpuNode);
|
||||
m_rootDeviceNode = rootNode;
|
||||
|
@ -18,14 +18,18 @@ public:
|
||||
static std::optional<QDBusAbstractAdaptor*> adaptor(QObject *obj,
|
||||
DeviceInterface iface) {
|
||||
std::optional<QDBusAbstractAdaptor*> retval = std::nullopt;
|
||||
match(iface)
|
||||
(pattern(as<DynamicReadable>(arg)) = [&](auto dr) {
|
||||
match(iface) (
|
||||
pattern(as<StaticReadable>(arg)) = [&](auto sr) {
|
||||
retval = new StaticReadableAdaptor(obj, sr);
|
||||
},
|
||||
pattern(as<DynamicReadable>(arg)) = [&](auto dr) {
|
||||
retval = new DynamicReadableAdaptor(obj, dr);
|
||||
},
|
||||
pattern(as<Assignable>(arg)) = [&](auto a) {
|
||||
retval = new AssignableAdaptor(obj, a);
|
||||
},
|
||||
pattern(_) = []{});
|
||||
pattern(_) = []{}
|
||||
);
|
||||
return retval;
|
||||
}
|
||||
};
|
||||
|
@ -198,3 +198,35 @@ private:
|
||||
TreeNode<TCDBus::DeviceNode> m_rootNode;
|
||||
QVector<TCDBus::FlatTreeNode<TCDBus::DeviceNode>> m_flatTree;
|
||||
};
|
||||
|
||||
class StaticReadableAdaptor : public QDBusAbstractAdaptor {
|
||||
public:
|
||||
StaticReadableAdaptor(QObject *obj, StaticReadable readable)
|
||||
: QDBusAbstractAdaptor(obj), m_readable(readable) {
|
||||
qDBusRegisterMetaType<TCDBus::Result<QString>>();
|
||||
// Unwrap the value and store in QDBusVariant
|
||||
match(m_readable.value()) (
|
||||
pattern(as<uint>(arg)) = [this](auto i) {
|
||||
m_value = QDBusVariant(QVariant(i));
|
||||
}
|
||||
);
|
||||
|
||||
m_unit = (m_readable.unit().has_value()) ? TCDBus::Result<QString>{
|
||||
false,
|
||||
QString::fromStdString(m_readable.unit().value())
|
||||
} : TCDBus::Result<QString>{
|
||||
true, ""
|
||||
};
|
||||
}
|
||||
QDBusVariant value_() {return m_value;}
|
||||
TCDBus::Result<QString> unit_() {return m_unit;}
|
||||
private:
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.tuxclocker.StaticReadable")
|
||||
Q_PROPERTY(TCDBus::Result<QString> unit READ unit_)
|
||||
Q_PROPERTY(QDBusVariant value READ value_)
|
||||
|
||||
StaticReadable m_readable;
|
||||
TCDBus::Result<QString> m_unit;
|
||||
QDBusVariant m_value;
|
||||
};
|
||||
|
@ -50,6 +50,9 @@ int main(int argc, char **argv) {
|
||||
pattern(as<DynamicReadableAdaptor>(_)) = [&] {
|
||||
ifaceName = "org.tuxclocker.DynamicReadable";
|
||||
},
|
||||
pattern(as<StaticReadableAdaptor>(_)) = [&] {
|
||||
ifaceName = "org.tuxclocker.StaticReadable";
|
||||
},
|
||||
pattern(_) = [] {});
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user