#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(); }