diff --git a/react/src/JackHostStatus.tsx b/react/src/JackHostStatus.tsx index 52b92dc..1f5c1f5 100644 --- a/react/src/JackHostStatus.tsx +++ b/react/src/JackHostStatus.tsx @@ -49,6 +49,18 @@ function fmtCpuFreq(freq: number): string { return freq + " KHz"; } +function areSameFrequency(max: number, min: number): boolean { + return true; + // // x86 cpus can show incredibly minor frequency variations between CPUs + // if (min === 0) return false; + // let ratio = max/min; + // if (ratio < 1.2) + // { + // return true; + // } + // return false; +} + export default class JackHostStatus { deserialize(input: any): JackHostStatus { this.active = input.active; @@ -92,12 +104,12 @@ export default class JackHostStatus { ( { - (status.cpuFreqMax === status.cpuFreqMin) ? + (areSameFrequency(status.cpuFreqMax,status.cpuFreqMin)) ? ( {status.governor} {fmtCpuFreq(status.cpuFreqMax)} ) : ( - {status.governor} {fmtCpuFreq(status.cpuFreqMax)}-{fmtCpuFreq(status.cpuFreqMax)} + {status.governor} {fmtCpuFreq(status.cpuFreqMin)}-{fmtCpuFreq(status.cpuFreqMax)} ) } diff --git a/src/AudioHost.cpp b/src/AudioHost.cpp index 5c238aa..2e6d1d2 100644 --- a/src/AudioHost.cpp +++ b/src/AudioHost.cpp @@ -32,6 +32,7 @@ #include #include "PluginHost.hpp" #include "PatchPropertyWriter.hpp" +#include "CpuTemperatureMonitor.hpp" using namespace pipedal; @@ -387,6 +388,7 @@ private: std::mutex atomConverterMutex; AtomConverter atomConverter; + CpuTemperatureMonitor::ptr cpuTemperatureMonitor; static constexpr size_t DEFERRED_MIDI_BUFFER_SIZE = 1024; uint8_t deferredMidiMessages[DEFERRED_MIDI_BUFFER_SIZE]; @@ -1231,6 +1233,8 @@ public: { realtimeAtomBuffer.resize(32 * 1024); lv2_atom_forge_init(&inputWriterForge, pHost->GetMapFeature().GetMap()); + + cpuTemperatureMonitor = CpuTemperatureMonitor::Get(); } virtual ~AudioHostImpl() { @@ -2032,21 +2036,6 @@ public: this->hostWriter.ParameterRequest(pParameterRequest); } - static int32_t GetRaspberryPiTemperature() - { - try - { - std::ifstream f("/sys/class/thermal/thermal_zone0/temp"); - int32_t temp; - f >> temp; - return temp; - } - catch (std::exception &) - { - return -1000000; - } - } - virtual JackHostStatus getJackStatus() { CleanRestartThreads(false); @@ -2062,7 +2051,7 @@ public: result.msSinceLastUnderrun_ = (uint64_t)dt; - result.temperaturemC_ = GetRaspberryPiTemperature(); + result.temperaturemC_ = (int32_t)(std::round(cpuTemperatureMonitor->GetTemperatureC()*1000)); result.active_ = IsAudioRunning(); result.restarting_ = this->restarting; @@ -2071,7 +2060,7 @@ public: { result.cpuUsage_ = audioDriver->CpuUse(); } - GetCpuFrequency(&result.cpuFreqMax_, &result.cpuFreqMin_); + GetCpuFrequency(&result.cpuFreqMin_, &result.cpuFreqMax_); result.hasCpuGovernor_ = HasCpuGovernor(); if (result.hasCpuGovernor_) { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dea5baa..f343f9e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -158,6 +158,7 @@ else() endif() set (PIPEDAL_SOURCES + CpuTemperatureMonitor.cpp CpuTemperatureMonitor.hpp SchedulerPriority.hpp SchedulerPriority.cpp ModFileTypes.cpp ModFileTypes.hpp PatchPropertyWriter.hpp diff --git a/src/CpuTemperatureMonitor.cpp b/src/CpuTemperatureMonitor.cpp new file mode 100644 index 0000000..6b9f8e9 --- /dev/null +++ b/src/CpuTemperatureMonitor.cpp @@ -0,0 +1,118 @@ +// Copyright (c) 2022 Robin Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#include "CpuTemperatureMonitor.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace pipedal; + + + +static constexpr std::string_view THERMAL_PATH = "/sys/class/thermal/"; + + +static std::optional readFile(const fs::path& path) { + std::ifstream file(path); + if (!file) { + return std::nullopt; + } + + std::string content; + std::getline(file, content); + return content; +} + + +static bool isCpuThermal(const fs::path &zone_path) { + auto type = readFile(zone_path / "type"); + return type && (*type == "cpu-thermal") || (*type == "x86_pkg_temp"); +} + + + + +class CpuTemperatureMonitorImpl: public CpuTemperatureMonitor { +private: + std::vector cpuZones; +public: + explicit CpuTemperatureMonitorImpl(std::vector&&cpuZones) + : cpuZones(std::move(cpuZones)) { + } + + + virtual float GetTemperatureC() override { + float result = INVALID_TEMPERATURE*1000; + + for (const auto&cpuZone: cpuZones) + { + + std::ifstream file(cpuZone / "temp"); + if (file) { + float v; + file >> v; + if (file) + { + if (v > result) + { + result = v; + } + } + } + } + return result/1000; + } +}; + +static std::vector findCpuThermalZones() { + std::vector cpu_zones; + std::error_code ec; + + for (const auto& entry : fs::directory_iterator(THERMAL_PATH, ec)) { + if (ec) { + std::cerr << "Error reading directory: " << ec.message() << '\n'; + continue; + } + + const auto& path = entry.path(); + if (path.filename().string().find("thermal_zone") == 0) { + if (isCpuThermal(path)) { + cpu_zones.push_back(path); + } + } + } + return cpu_zones; +} + + +CpuTemperatureMonitor::ptr CpuTemperatureMonitor::Get() +{ + + std::vector cpuZones = findCpuThermalZones(); + + return std::make_unique(std::move(cpuZones)); +} diff --git a/src/CpuTemperatureMonitor.hpp b/src/CpuTemperatureMonitor.hpp new file mode 100644 index 0000000..ec0f869 --- /dev/null +++ b/src/CpuTemperatureMonitor.hpp @@ -0,0 +1,43 @@ +// Copyright (c) 2024 Robin Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#pragma once + + +#include +#include +#include + +namespace pipedal { + + class CpuTemperatureMonitor { + protected: + CpuTemperatureMonitor() { } + public: + virtual ~CpuTemperatureMonitor() {}; + + static constexpr float INVALID_TEMPERATURE = -400; + using ptr = std::unique_ptr; + + static ptr Get(); // may return empty pointer. + + // degrees Celcius * 1000; + virtual float GetTemperatureC() = 0; + + }; +} \ No newline at end of file