commit 36eab3868f97d25133045830f5e8180714da8ed4 Author: unrealdragon Date: Fri Jun 5 20:38:03 2026 +0530 My Custom Fan App for PH16-71 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..45b1a19 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +Build/* +build/* +*.sh +.qtcreator/* + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..61ce1f5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.16) + +project(helloworld VERSION 1.0.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Boost CONFIG) +find_package(Qt6 REQUIRED COMPONENTS Core) + +qt_add_executable(CustomFanApp main.cpp) + +target_link_libraries(CustomFanApp PRIVATE Qt6::Core) diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..fde1195 --- /dev/null +++ b/main.cpp @@ -0,0 +1,325 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +std::string get_current_time() { + const auto now = std::chrono::system_clock::now(); + std::time_t ctime_now = std::chrono::system_clock::to_time_t(now); + std::stringstream ss; + ss << "[" << std::put_time(std::localtime(&ctime_now), "%d-%m-%y %H:%M:%S") << "] "; + return ss.str(); +} + + +std::string get_platform_profile() { + std::fstream platform_profile("/sys/firmware/acpi/platform_profile", std::fstream::in); + std::string temp; + platform_profile >> temp; + return temp; +} + +int read_fans() { + std::fstream dev_reader("/dev/acer-fan-8", std::fstream::in); + std::string current_value; + std::string data; + int fan_value = -1; + char ch[2]; + dev_reader.read(ch, 1); + ch[1] = '\0'; + current_value = ch; + std::stringstream s2; + s2 << current_value; + s2.flush(); + s2 >> fan_value; + s2.flush(); + return fan_value; +} + +void deactivate_fans() { + const char *ab = "0"; + auto file = open("/dev/acer-fan-8", O_WRONLY); + if (file < 0) { + std::cout << get_current_time() << "Open failed" << std::endl; + fprintf(stderr, "errno = %d (%s)\n", errno, strerror(errno)); + return; + } + write(file, ab, strlen(ab)); + close(file); + std::cout << get_current_time() << "Fans slowed." << std::endl; +} + +void activate_fans() { + const char *ab = "1"; + auto file = open("/dev/acer-fan-8", O_WRONLY); + if (file < 0) { + std::cout << "Open failed" << std::endl; + fprintf(stderr, "errno = %d (%s)\n", errno, strerror(errno)); + return; + } + write(file, ab, strlen(ab)); + close(file); + std::cout << get_current_time() << "Fans activated." << std::endl; +} + +std::vector read_cpu_temp(std::vector paths) { + std::vector cpu_temps; + for(auto &i: paths) { + std::filesystem::path file_path = std::filesystem::path(i) / "temp"; + std::fstream filein(file_path, std::fstream::in); + if(!filein.is_open()) { + std::cout << "Failed to open file: " << file_path << std::endl; + } + std::stringstream ss; + std::string temp; + int current_temp; + while(std::getline(filein, temp)) { + ss << temp; + } + filein.flush(); + filein.close(); + ss >> current_temp; + ss.flush(); + cpu_temps.push_back(current_temp); + } + return cpu_temps; +} + +int read_gpu_temp() { + QProcess *proc = new QProcess(); + QStringList args; + args << "--query-gpu=temperature.gpu" << "--format=csv,noheader" << "-f" << "nvidia-temp.txt"; + proc->start("nvidia-smi", args); + proc->waitForFinished(); + delete proc; + std::fstream temp_in("nvidia-temp.txt", std::fstream::in); + if(!temp_in.is_open()) { + std::cout << "Could not read temperature info from nvidia smi exiting..." << std::endl; + exit(-1); + } + std::string string_temperature; + std::string temp; + int int_temperature = -1; + while(std::getline(temp_in, temp)) { + string_temperature += temp; + } + temp_in.close(); + std::stringstream ss; + ss << string_temperature; + ss.flush(); + ss >> int_temperature; + ss.flush(); + return int_temperature; +} + +void write_cpu(std::filesystem::path path, std::string text) { + auto file = open(path.c_str(), O_WRONLY); + if (file < 0) { + std::cout << "Open failed" << std::endl; + fprintf(stderr, "errno = %d (%s)\n", errno, strerror(errno)); + return; + } + write(file, text.c_str(), strlen(text.c_str())); + close(file); +} + +bool slow_cpus() { + int low = 16; + int high = 31; + std::string cpu_base_freq_path = "/sys/devices/system/cpu/cpu{}/cpufreq/scaling_max_freq"; + std::string cpu_base_gov_path = "/sys/devices/system/cpu/cpu{}/cpufreq/energy_performance_preference"; + for(int i=low;i<=high;i++) + { + std::string cpu_freq_path = std::vformat(cpu_base_freq_path, std::make_format_args(i)); + std::string cpu_gov_path = std::vformat(cpu_base_gov_path, std::make_format_args(i)); + write_cpu(cpu_freq_path, "2400000"); + write_cpu(cpu_gov_path, "balance_power"); + std::cout << get_current_time() << std::vformat("Changed CPU {} to 2.4GHz and cpu gov to balance power.", std::make_format_args(i)) << std::endl;; + } + return true; +} + +bool reactivate_slowed_cpus() { + int low = 16; + int high = 31; + std::string cpu_base_freq_path = "/sys/devices/system/cpu/cpu{}/cpufreq/scaling_max_freq"; + std::string cpu_base_gov_path = "/sys/devices/system/cpu/cpu{}/cpufreq/energy_performance_preference"; + for(int i=low;i<=high;i++) + { + std::string cpu_freq_path = std::vformat(cpu_base_freq_path, std::make_format_args(i)); + std::string cpu_gov_path = std::vformat(cpu_base_gov_path, std::make_format_args(i)); + write_cpu(cpu_freq_path, "3900000"); + write_cpu(cpu_gov_path, "performance"); + std::cout << get_current_time() << std::vformat("Changed CPU {} to 3.9GHz and cpu gov to performance.", std::make_format_args(i)) << std::endl; + } + return false; +} + +int main(int argc, char *argv[]) { + + std::stringstream sr; + sr << argv[0]; + sr.flush(); + std::string log_path = "/home/ud/logs/CustomFanApp.log"; + std::cout << "Log path: " << log_path << std::endl; + uintmax_t log_size = 0; + uintmax_t max_size = 10 * 1024 * 1024; // MB + int cpu_slow_threshold = 70; // CPU Temperature at which to reduce clock speed of E-Cores and change them to power-save + int cpu_fast_when_slowed_threshold = 62; + if(argc >= 3) { + std::stringstream ss; + ss << argv[2]; + ss >> cpu_slow_threshold; + ss.flush(); + ss.clear(); + } + if(argc >= 4) { + std::stringstream ss; + ss << argv[3]; + ss >> cpu_fast_when_slowed_threshold; + ss.flush(); + ss.clear(); + } + + bool cpu_slowed = false; + + if(std::filesystem::exists(log_path)) { + log_size = std::filesystem::file_size(log_path); + std::cout << "Current log file size: " << log_size << std::endl; + } + std::fstream log_out; + if(log_size > max_size) + { + log_out.open(log_path, std::fstream::out); + if(!log_out.is_open()) { + std::cerr << "Could not open log file!" << std::endl; + } + else { + std::cout.rdbuf(log_out.rdbuf()); + std::cout << get_current_time() << "---- Truncating log file size > 10 Mb. ----" << std::endl; + } + } + else { + log_out.open(log_path, std::fstream::app); + if(!log_out.is_open()) { + std::cerr << "Could not open log file!" << std::endl; + } + else { + std::cout.rdbuf(log_out.rdbuf()); + } + } + + QCoreApplication app(argc, argv); + QTimer log_flusher; + log_flusher.setSingleShot(false); + log_flusher.setInterval(5000); + QObject::connect(&log_flusher, &QTimer::timeout, [&](){ + log_out.flush(); + std::cout.flush(); + }); + + log_flusher.start(); + QObject::connect(&app, &QCoreApplication::aboutToQuit, [&log_out](){ + log_out << "-------- Exiting --------" << std::endl; + log_out.close(); + }); + + std::cout << "-------- Starting app --------" << std::endl; + std::cout << "Current path: " << std::filesystem::current_path() << "\n"; + using namespace std::chrono_literals; + auto polling_interval = 1s; + int threshold; + if(argc < 2) { + threshold = 60; + } + else { + std::stringstream ss; + ss << argv[1]; + ss >> threshold; + ss.flush(); + ss.clear(); + } + std::cout << "App threshold set at: " << threshold << std::endl; + std::vector thermal_zones_paths; + + std::filesystem::path base_path = "/sys/class/thermal/"; + + std::filesystem::directory_iterator iter(base_path); + + for(auto &i: iter) { + if (i.path().filename().string().find("thermal_zone") == 0) { + thermal_zones_paths.push_back(i.path().string()); + } + } + for(int i=0;i cpu_temps = read_cpu_temp(thermal_zones_paths); + float average_cpu_temp = std::accumulate(cpu_temps.begin(), cpu_temps.end(), 0) / cpu_temps.size(); + int cpu_temp = std::ceil(average_cpu_temp) / 1000; + // Get platform profile + std::string profile = get_platform_profile(); + std::cout << get_current_time() << "GPU temp: " << gpu_temp << " CPU temp: " << cpu_temp << " Performace profile: " << profile << std::endl; + if((gpu_temp >= threshold || cpu_temp >= threshold) && (profile == "performance" || profile == "" )) { + int fan_value = read_fans(); + if(fan_value == 0) { + activate_fans(); + } + } + else { + int fan_value = read_fans(); + if(fan_value == 1) { + deactivate_fans(); + } + } + if(cpu_temp >= cpu_slow_threshold) { + if(!cpu_slowed) { + cpu_slowed = slow_cpus(); + } + } + else { + if(cpu_slowed && cpu_temp <= cpu_fast_when_slowed_threshold) { + cpu_slowed = reactivate_slowed_cpus(); + } + } + if(profile != "performance") + std::cout << get_current_time() << "Fans will only be activated to max speed in performace profile." << std::endl; + QCoreApplication::processEvents(); + std::this_thread::sleep_for(polling_interval); + } + return app.exec(); +} + diff --git a/nvidia-temp.txt b/nvidia-temp.txt new file mode 100644 index 0000000..e1617e8 --- /dev/null +++ b/nvidia-temp.txt @@ -0,0 +1 @@ +57