add AMD core pstate editing

This commit is contained in:
Jussi Kuokkanen 2023-11-03 18:14:04 +02:00
parent e4e3fa95bb
commit 8a904bffcd

View File

@ -24,6 +24,11 @@ using namespace TuxClocker;
using AssignmentFunction = std::function<std::optional<AssignmentError>(AssignmentArgument)>; using AssignmentFunction = std::function<std::optional<AssignmentError>(AssignmentArgument)>;
enum VoltFreqType {
MemoryPState,
CorePState
};
EnumerationVec performanceLevelEnumVec = {{_("Automatic"), 0}, {_("Lowest"), 1}, {_("Highest"), 2}, EnumerationVec performanceLevelEnumVec = {{_("Automatic"), 0}, {_("Lowest"), 1}, {_("Highest"), 2},
{_("Manual"), 3}, {_("Base Levels"), 4}, {_("Lowest Core Clock"), 5}, {_("Manual"), 3}, {_("Base Levels"), 4}, {_("Lowest Core Clock"), 5},
{_("Lowest Memory Clock"), 6}, {_("Highest Clocks"), 7}}; {_("Lowest Memory Clock"), 6}, {_("Highest Clocks"), 7}};
@ -66,6 +71,125 @@ std::optional<AssignmentError> withManualPerformanceLevel(
return func(a); return func(a);
} }
// Shared function to get memory and core clock pstate assignables
std::optional<Assignable> vfPointClockAssignable(
VoltFreqType vfType, uint pointIndex, Range<int> range, AMDGPUData data) {
// Eg. the 's' in s 0 400 500
const char *typeString;
const char *sectionHeader;
switch (vfType) {
case MemoryPState: {
typeString = "m";
sectionHeader = "OD_MCLK";
break;
}
case CorePState: {
typeString = "s";
sectionHeader = "OD_SCLK";
break;
}
}
auto getFunc = [=]() -> std::optional<AssignmentArgument> {
auto vfPoint = vfPointWithRead(sectionHeader, pointIndex, data);
if (!vfPoint.has_value())
return std::nullopt;
return vfPoint->clock;
};
if (!getFunc().has_value())
return std::nullopt;
auto setFunc = [=](AssignmentArgument a) -> std::optional<AssignmentError> {
if (!std::holds_alternative<int>(a))
return AssignmentError::InvalidType;
auto target = std::get<int>(a);
if (target < range.min || target > range.max)
return AssignmentError::OutOfRange;
auto vfPoint = vfPointWithRead(sectionHeader, pointIndex, data);
if (!vfPoint.has_value())
return AssignmentError::UnknownError;
std::ofstream file{data.hwmonPath + "/pp_od_clk_voltage"};
char cmdString[32];
snprintf(
cmdString, 32, "%s %u %i %i", typeString, pointIndex, target, vfPoint->voltage);
if (file << cmdString && file << "c")
return std::nullopt;
return AssignmentError::UnknownError;
};
auto setWithPerfLevel = [=](AssignmentArgument a) -> std::optional<AssignmentError> {
return withManualPerformanceLevel(setFunc, a, data);
};
return Assignable{setWithPerfLevel, range, getFunc, _("MHz")};
}
std::optional<Assignable> vfPointVoltageAssignable(
VoltFreqType vfType, uint pointIndex, Range<int> range, AMDGPUData data) {
// Eg. the 's' in s 0 400 500
const char *typeString;
const char *sectionHeader;
switch (vfType) {
case MemoryPState: {
typeString = "m";
sectionHeader = "OD_MCLK";
break;
}
case CorePState: {
typeString = "s";
sectionHeader = "OD_SCLK";
break;
}
}
auto getFunc = [=]() -> std::optional<AssignmentArgument> {
auto vfPoint = vfPointWithRead(sectionHeader, pointIndex, data);
if (!vfPoint.has_value())
return std::nullopt;
return vfPoint->voltage;
};
if (!getFunc().has_value())
return std::nullopt;
auto setFunc = [=](AssignmentArgument a) -> std::optional<AssignmentError> {
if (!std::holds_alternative<int>(a))
return AssignmentError::InvalidType;
auto target = std::get<int>(a);
if (target < range.min || target > range.max)
return AssignmentError::OutOfRange;
auto vfPoint = vfPointWithRead(sectionHeader, pointIndex, data);
if (!vfPoint.has_value())
return AssignmentError::UnknownError;
std::ofstream file{data.hwmonPath + "/pp_od_clk_voltage"};
char cmdString[32];
snprintf(
cmdString, 32, "%s %u %i %i", typeString, pointIndex, vfPoint->clock, target);
if (file << cmdString && file << "c")
return std::nullopt;
return AssignmentError::UnknownError;
};
auto setWithPerfLevel = [=](AssignmentArgument a) -> std::optional<AssignmentError> {
return withManualPerformanceLevel(setFunc, a, data);
};
return Assignable{setWithPerfLevel, range, getFunc, _("mV")};
}
std::vector<TreeNode<DeviceNode>> getTemperature(AMDGPUData data) { std::vector<TreeNode<DeviceNode>> getTemperature(AMDGPUData data) {
auto func = [=]() -> ReadResult { auto func = [=]() -> ReadResult {
uint temp; uint temp;
@ -464,6 +588,71 @@ std::vector<TreeNode<DeviceNode>> getVoltFreqVolt(AMDGPUData data) {
return {}; return {};
} }
std::vector<TreeNode<DeviceNode>> getCorePStateFreq(AMDGPUData data) {
static amdgpu_device_handle latestDev = nullptr;
static int pointId = 0;
std::vector<TreeNode<DeviceNode>> retval = {};
if (data.devHandle != latestDev)
// Start from zero for new device
pointId = 0;
latestDev = data.devHandle;
auto range = parsePstateRangeLineWithRead("SCLK", data);
if (!range.has_value()) {
pointId++;
return {};
}
// Make a copy so the lambda keeps using the right id
auto id = pointId;
auto assignable = vfPointClockAssignable(CorePState, id, *range, data);
pointId++;
if (!assignable.has_value())
return {};
return {DeviceNode{
.name = _("Core Clock"),
.interface = *assignable,
.hash = md5(data.pciId + "CorePStateFreq" + std::to_string(id)),
}};
}
std::vector<TreeNode<DeviceNode>> getCorePStateVolt(AMDGPUData data) {
static amdgpu_device_handle latestDev = nullptr;
static int pointId = 0;
std::vector<TreeNode<DeviceNode>> retval = {};
if (data.devHandle != latestDev)
// Start from zero for new device
pointId = 0;
latestDev = data.devHandle;
auto range = parsePstateRangeLineWithRead("VDDC", data);
if (!range.has_value()) {
pointId++;
return {};
}
// Make a copy so the lambda keeps using the right id
auto id = pointId;
auto assignable = vfPointVoltageAssignable(CorePState, id, *range, data);
pointId++;
if (!assignable.has_value())
return {};
return {DeviceNode{
.name = _("Core Voltage"),
.interface = *assignable,
.hash = md5(data.pciId + "CorePStateVolt" + std::to_string(id)),
}};
}
std::vector<TreeNode<DeviceNode>> getVoltFreqNodes(AMDGPUData data) { std::vector<TreeNode<DeviceNode>> getVoltFreqNodes(AMDGPUData data) {
// Root item for voltage and frequency of a point // Root item for voltage and frequency of a point
std::vector<TreeNode<DeviceNode>> retval; std::vector<TreeNode<DeviceNode>> retval;
@ -491,6 +680,32 @@ std::vector<TreeNode<DeviceNode>> getVoltFreqNodes(AMDGPUData data) {
return retval; return retval;
} }
std::vector<TreeNode<DeviceNode>> getCorePStateNodes(AMDGPUData data) {
// Root item for voltage and frequency of a pstate
std::vector<TreeNode<DeviceNode>> retval;
if (!data.ppTableType.has_value() || *data.ppTableType != Vega10)
return {};
auto path = data.hwmonPath + "/pp_od_clk_voltage";
auto tableContents = fileContents(path);
if (!tableContents.has_value())
return {};
auto lines = pstateSectionLines("OD_SCLK", *tableContents);
char name[32];
for (int i = 0; i < lines.size(); i++) {
snprintf(name, 32, "%s %i", _("State"), i);
DeviceNode node{
.name = name,
.interface = std::nullopt,
.hash = md5(data.pciId + "PState" + std::to_string(i)),
};
retval.push_back(node);
}
return retval;
}
std::vector<TreeNode<DeviceNode>> getVoltageRead(AMDGPUData data) { std::vector<TreeNode<DeviceNode>> getVoltageRead(AMDGPUData data) {
auto func = [=](int sensorType) -> ReadResult { auto func = [=](int sensorType) -> ReadResult {
uint volt; uint volt;
@ -593,6 +808,17 @@ std::vector<TreeNode<DeviceNode>> getPowerRoot(AMDGPUData data) {
}}; }};
} }
std::vector<TreeNode<DeviceNode>> getCorePStateRoot(AMDGPUData data) {
if (!data.ppTableType.has_value() || *data.ppTableType != Vega10)
return {};
return {DeviceNode{
.name = _("Core Performance States"),
.interface = std::nullopt,
.hash = md5(data.pciId + "Core Performance States"),
}};
}
std::vector<TreeNode<DeviceNode>> getGPUName(AMDGPUData data) { std::vector<TreeNode<DeviceNode>> getGPUName(AMDGPUData data) {
auto name = amdgpu_get_marketing_name(data.devHandle); auto name = amdgpu_get_marketing_name(data.devHandle);
if (name) { if (name) {
@ -630,6 +856,12 @@ auto gpuTree = TreeConstructor<AMDGPUData, DeviceNode>{
{getVoltFreqFreq, {}}, {getVoltFreqFreq, {}},
{getVoltFreqVolt, {}} {getVoltFreqVolt, {}}
}} }}
}},
{getCorePStateRoot, {
{getCorePStateNodes, {
{getCorePStateFreq, {}},
{getCorePStateVolt, {}}
}}
}} }}
}} }}
} }