diff --git a/src/plugins/AMD.cpp b/src/plugins/AMD.cpp index 39522dc..ca6e6ed 100644 --- a/src/plugins/AMD.cpp +++ b/src/plugins/AMD.cpp @@ -427,11 +427,16 @@ std::vector> 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> 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; diff --git a/src/plugins/AMDUtils.cpp b/src/plugins/AMDUtils.cpp index a8c479f..0d0f0e3 100644 --- a/src/plugins/AMDUtils.cpp +++ b/src/plugins/AMDUtils.cpp @@ -83,6 +83,19 @@ std::optional> fromFanCurveContents(const std::string &contentsRaw) { return parsePstateRangeLine("FAN_CURVE(fan_speed)", contents); } +std::vector fanCurveTempsFromContents(const std::string &contents) { + auto lines = pstateSectionLines("OD_FAN_CURVE", contents); + + std::vector retval; + for (auto &line : lines) { + auto value = parseLineValue(line); + if (!value.has_value()) + return {}; + retval.push_back(*value); + } + return retval; +} + std::optional> parseLineValuePair(const std::string &line) { auto words = fplus::split_one_of(std::string{" "}, false, line); diff --git a/src/plugins/AMDUtils.hpp b/src/plugins/AMDUtils.hpp index f6a290f..71563c0 100644 --- a/src/plugins/AMDUtils.hpp +++ b/src/plugins/AMDUtils.hpp @@ -48,6 +48,7 @@ std::optional> parsePstateRangeLineWithRead( std::string title, AMDGPUData data); std::optional> fromFanCurveContents(const std::string &contents); +std::vector fanCurveTempsFromContents(const std::string &contents); std::optional> parseLineValuePair(const std::string &line); diff --git a/src/test/Tests.cpp b/src/test/Tests.cpp new file mode 100644 index 0000000..e65c2e1 --- /dev/null +++ b/src/test/Tests.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +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> 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 expectedTemps = {0, 45, 50, 55, 65}; + auto temps = fanCurveTempsFromContents(*contents); + return !(expectedTemps == temps); +} + +int main() { + return test({fanCurveParse, fanCurvePointParse}); +} diff --git a/src/test/meson.build b/src/test/meson.build new file mode 100644 index 0000000..57014bd --- /dev/null +++ b/src/test/meson.build @@ -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