/* --------------------------------------------------------------------- * Luiz Carlos doleron @ 2021 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero Public License for more details. * ---------------------------------------------------------------------- */ #ifndef _GET_CPU_USAGE_LINUX_ #define _GET_CPU_USAGE_LINUX_ #include #include #include #include namespace get_system_usage_linux { struct CPU_stats { // see http://www.linuxhowtos.org/manpages/5/proc.htm int user; int nice; int system; int idle; int iowait; int irq; int softirq; int steal; int guest; int guest_nice; int get_total_idle() const { return idle + iowait; } int get_total_active() const { return user + nice + system + irq + softirq + steal + guest + guest_nice; } }; struct Memory_stats { int total_memory; int available_memory; int total_swap; int free_swap; float get_memory_usage() { const float result = static_cast(total_memory - available_memory) / total_memory; return result; } float get_swap_usage() { const float result = static_cast(total_swap - free_swap) / total_swap; return result; } }; inline CPU_stats read_cpu_data() { CPU_stats result; std::ifstream proc_stat("/proc/stat"); if (proc_stat.good()) { std::string line; getline(proc_stat, line); unsigned int *stats_p = (unsigned int *)&result; std::stringstream iss(line); std::string cpu; iss >> cpu; while (iss >> *stats_p) { stats_p++; }; } proc_stat.close(); return result; } inline int get_val(const std::string &target, const std::string &content) { int result = -1; std::size_t start = content.find(target); if (start != std::string::npos) { int begin = start + target.length(); std::size_t end = content.find("kB", start); std::string substr = content.substr(begin, end - begin); result = std::stoi(substr); } return result; } inline Memory_stats read_memory_data() { Memory_stats result; std::ifstream proc_meminfo("/proc/meminfo"); if (proc_meminfo.good()) { std::string content((std::istreambuf_iterator(proc_meminfo)), std::istreambuf_iterator()); result.total_memory = get_val("MemTotal:", content); result.total_swap = get_val("SwapTotal:", content); result.free_swap = get_val("SwapFree:", content); result.available_memory = get_val("MemAvailable:", content); } proc_meminfo.close(); return result; } inline float get_cpu_usage(const CPU_stats &first, const CPU_stats &second) { const float active_time = static_cast(second.get_total_active() - first.get_total_active()); const float idle_time = static_cast(second.get_total_idle() - first.get_total_idle()); const float total_time = active_time + idle_time; return active_time / total_time; } inline float get_disk_usage(const std::string & disk) { struct statvfs diskData; statvfs(disk.c_str(), &diskData); auto total = diskData.f_blocks; auto free = diskData.f_bfree; auto diff = total - free; float result = static_cast(diff) / total; return result; } //see https://unix.stackexchange.com/questions/304845/discrepancy-between-number-of-cores-and-thermal-zones-in-sys-class-thermal/342023 inline int find_thermalzone_index() { int result = 0; bool stop = false; // 20 must stop anyway for (int i = 0; !stop && i < 20; ++i) { std::ifstream thermal_file("/sys/class/thermal/thermal_zone" + std::to_string(i) + "/type"); if (thermal_file.good()) { std::string line; getline(thermal_file, line); if (line.compare("x86_pkg_temp") == 0) { result = i; stop = true; } } else { stop = true; } thermal_file.close(); } return result; } inline int get_thermalzone_temperature(int thermal_index) { int result = -1; std::ifstream thermal_file("/sys/class/thermal/thermal_zone" + std::to_string(thermal_index) + "/temp"); if (thermal_file.good()) { std::string line; getline(thermal_file, line); std::stringstream iss(line); iss >> result; } else { throw std::invalid_argument(std::to_string(thermal_index) + " doesn't refer to a valid thermal zone."); } thermal_file.close(); return result; } } #endif