add test for RX 7000 fan curve temperature parsing

This commit is contained in:
Jussi Kuokkanen 2024-01-28 14:43:26 +02:00
parent 4d18b0cdfb
commit 31230172d7
5 changed files with 88 additions and 16 deletions

View File

@ -427,11 +427,16 @@ std::vector<TreeNode<DeviceNode>> getFanSpeedWriteRX7000(AMDGPUData data) {
if (!contents.has_value())
return {};
// We don't care acout the temps, since we set all points to desired speed
// We don't care acout the temp range, since we set all points to desired speed
auto speedRange = fromFanCurveContents(*contents);
if (!speedRange.has_value())
return {};
// Only fetch temperatures once
auto temps = fanCurveTempsFromContents(*contents);
if (temps.empty())
return {};
// Doesn't make sense with what we do
auto getFunc = [] { return std::nullopt; };
@ -443,27 +448,16 @@ std::vector<TreeNode<DeviceNode>> getFanSpeedWriteRX7000(AMDGPUData data) {
if (speedRange->min > target || speedRange->max < target)
return AssignmentError::OutOfRange;
// TODO: do we even need to care about setting same temperature?
// Might be slow to do this every assignment
auto lines = pstateSectionLines("OD_FAN_CURVE", *contents);
// Write all curve points to same value
std::ofstream file{fanCurvePath};
if (lines.empty() || !file.good())
return AssignmentError::UnknownError;
for (int i = 0; i < lines.size(); i++) {
// Write all curve points to same value
auto words = fplus::split_one_of(std::string{" "}, false, lines[i]);
if (words.size() < 3)
return AssignmentError::UnknownError;
// Essentially cut off the 'C' in '65C'
auto temp = std::atoi(words[1].c_str());
for (int i = 0; i < temps.size(); i++) {
char cmdString[32];
// TODO: docs say PWM but internet says percentage
snprintf(cmdString, 32, "%i %i %i", i, temp, target);
snprintf(cmdString, 32, "%i %i %i", i, temps[i], target);
if (!(file << cmdString))
return AssignmentError::UnknownError;
}
if (file << "c")
return std::nullopt;
return AssignmentError::UnknownError;

View File

@ -83,6 +83,19 @@ std::optional<Range<int>> fromFanCurveContents(const std::string &contentsRaw) {
return parsePstateRangeLine("FAN_CURVE(fan_speed)", contents);
}
std::vector<int> fanCurveTempsFromContents(const std::string &contents) {
auto lines = pstateSectionLines("OD_FAN_CURVE", contents);
std::vector<int> retval;
for (auto &line : lines) {
auto value = parseLineValue(line);
if (!value.has_value())
return {};
retval.push_back(*value);
}
return retval;
}
std::optional<std::pair<int, int>> parseLineValuePair(const std::string &line) {
auto words = fplus::split_one_of(std::string{" "}, false, line);

View File

@ -48,6 +48,7 @@ std::optional<TuxClocker::Device::Range<int>> parsePstateRangeLineWithRead(
std::string title, AMDGPUData data);
std::optional<TuxClocker::Device::Range<int>> fromFanCurveContents(const std::string &contents);
std::vector<int> fanCurveTempsFromContents(const std::string &contents);
std::optional<std::pair<int, int>> parseLineValuePair(const std::string &line);

49
src/test/Tests.cpp Normal file
View File

@ -0,0 +1,49 @@
#include <AMDUtils.hpp>
#include <fplus/fplus.hpp>
#include <iostream>
#include <Utils.hpp>
using namespace TuxClocker::Device;
const char *fanCurvePath = PROJECT_ROOT "/doc/amd-pptables/rx7000-fancurve";
const char *fileErrorMessage = "Couldn't read sample file";
int test(std::vector<std::function<int()>> funcs) {
for (int i = 0; i < funcs.size() - 1; i++) {
auto ret = funcs[i]();
if (ret != 0)
return ret;
}
return funcs.back()();
}
int failWith(const char *message) {
std::cerr << message << "\n";
return 1;
}
int fanCurveParse() {
auto contents = fileContents(fanCurvePath);
if (!contents.has_value())
return failWith(fileErrorMessage);
auto range = fromFanCurveContents(*contents);
if (!range.has_value())
return failWith("Couldn't parse fan speed range");
return !(range->min == 15 && range->max == 100);
}
int fanCurvePointParse() {
auto contents = fileContents(fanCurvePath);
if (!contents.has_value())
return failWith(fileErrorMessage);
std::vector<int> expectedTemps = {0, 45, 50, 55, 65};
auto temps = fanCurveTempsFromContents(*contents);
return !(expectedTemps == temps);
}
int main() {
return test({fanCurveParse, fanCurvePointParse});
}

15
src/test/meson.build Normal file
View File

@ -0,0 +1,15 @@
incdir_tests = [ incdir, '../plugins/' ]
# https://github.com/mesonbuild/meson/issues/2518
# TODO: remove the if when this issue is fixed
if get_option('test')
amdtests = executable('amdtest',
'Tests.cpp', '../plugins/AMDUtils.cpp', '../plugins/Utils.cpp',
# Find sample AMD files
cpp_args : '-DPROJECT_ROOT="@0@"'.format(meson.source_root()),
include_directories : [ incdir_tests, fplus_inc ],
dependencies : [ libdrm_amdgpu, libdrm_dep, boost_dep ])
test('AMD parsing', amdtests,
protocol : 'exitcode')
endif