Add power CPU consumption monitoring on linux

This commit is contained in:
Yurii Shkrobut 2023-08-09 16:04:20 +03:00
parent 1b126f55e3
commit dcd3642718
7 changed files with 82 additions and 3 deletions

View file

@ -119,6 +119,8 @@ namespace Config {
{"show_uptime", "#* Shows the system uptime in the CPU box."},
{"show_cpu_watts", "#* Shows the CPU package current power consumption in watts."},
{"check_temp", "#* Show cpu temperature."},
{"cpu_sensor", "#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors."},
@ -239,6 +241,7 @@ namespace Config {
{"cpu_single_graph", false},
{"cpu_bottom", false},
{"show_uptime", true},
{"show_cpu_watts", true},
{"check_temp", true},
{"show_coretemp", true},
{"show_cpu_freq", true},

View file

@ -705,6 +705,17 @@ namespace Cpu {
}
}
//? Package power
if (Config::getB("show_cpu_watts") && supports_watts && cy < b_height - 1 and b_columns > 1) {
string cwatts_pre;
string cwatts_post;
if (b_column_size == 2 and show_temps) { cwatts_pre = "Package Power:"; cwatts_post = "Watts"; }
else if (b_column_size == 2 or (b_column_size == 1 and show_temps)) { cwatts_pre = "Pkg Power:"; cwatts_post = "W"; }
else if (b_column_size == 1 or (b_column_size == 0 and show_temps)) { cwatts_pre = "PP:"; cwatts_post = "W"; }
string cwatts = fmt::format("{} {:.2f} {}", cwatts_pre, cpu.usage_watts, cwatts_post);
out += Mv::to(b_y + b_height - 2, b_x + 1) + Theme::c("main_fg") + cwatts;
}
//? Load average
if (cy < b_height - 1 and cc <= b_columns) {
string lavg_pre;

View file

@ -402,6 +402,13 @@ namespace Menu {
"\"/uptime\" in the formatting.",
"",
"True or False."},
{"show_cpu_watts",
"Shows the CPU power consumption in watts.",
"",
"Note: Root permissions are required",
"Supports only Intel x86 CPUs on Linux",
"",
"True or False."},
},
{
{"mem_below_net",

View file

@ -89,7 +89,7 @@ namespace Shared {
namespace Cpu {
extern string box;
extern int x, y, width, height, min_width, min_height;
extern bool shown, redraw, got_sensors, cpu_temp_only, has_battery;
extern bool shown, redraw, got_sensors, cpu_temp_only, has_battery, supports_watts;
extern string cpuName, cpuHz;
extern vector<string> available_fields;
extern vector<string> available_sensors;
@ -113,6 +113,7 @@ namespace Cpu {
vector<deque<long long>> temp;
long long temp_max = 0;
array<double, 3> load_avg;
float usage_watts = 0;
};
//* Collect cpu stats and temperatures

View file

@ -77,7 +77,7 @@ namespace Cpu {
vector<string> available_fields = {"total"};
vector<string> available_sensors = {"Auto"};
cpu_info current_cpu;
bool got_sensors = false, cpu_temp_only = false;
bool got_sensors = false, cpu_temp_only = false, supports_watts = false;
//* Populate found_sensors map
bool get_sensors();

View file

@ -56,6 +56,18 @@ using namespace Tools;
using namespace std::literals; // for operator""s
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
namespace
{
long long get_monotonicTimeUSec()
{
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
return time.tv_sec * 1000000 + time.tv_nsec / 1000;
}
}
namespace Cpu {
vector<long long> core_old_totals;
vector<long long> core_old_idles;
@ -65,6 +77,7 @@ namespace Cpu {
fs::path freq_path = "/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq";
bool got_sensors{}; // defaults to false
bool cpu_temp_only{}; // defaults to false
bool supports_watts = true;
//* Populate found_sensors map
bool get_sensors();
@ -666,6 +679,47 @@ namespace Cpu {
return {percent, seconds, status};
}
long long get_cpuConsumptionUJoules()
{
long long consumption = -1;
const auto rapl_power_usage_path = "/sys/class/powercap/intel-rapl:0/energy_uj";
std::ifstream file(rapl_power_usage_path);
if(file.good())
{
file >> consumption;
}
return consumption;
}
float get_cpuConsumptionWatts()
{
static long long previous_usage = 0;
static long long previous_timestamp = 0;
if (previous_usage == 0)
{
previous_usage = get_cpuConsumptionUJoules();
previous_timestamp = get_monotonicTimeUSec();
supports_watts = (previous_usage > 0);
return 0;
}
if (!supports_watts)
{
return -1;
}
auto current_timestamp = get_monotonicTimeUSec();
auto current_usage = get_cpuConsumptionUJoules();
auto watts = (float)(current_usage - previous_usage) / (float)(current_timestamp - previous_timestamp);
previous_timestamp = current_timestamp;
previous_usage = current_usage;
return watts;
}
auto collect(bool no_update) -> cpu_info& {
if (Runner::stopping or (no_update and not current_cpu.cpu_percent.at("total").empty())) return current_cpu;
auto& cpu = current_cpu;
@ -803,6 +857,9 @@ namespace Cpu {
if (Config::getB("show_battery") and has_battery)
current_bat = get_battery();
if (Config::getB("show_cpu_watts") and supports_watts)
current_cpu.usage_watts = get_cpuConsumptionWatts();
return cpu;
}
}

View file

@ -74,7 +74,7 @@ namespace Cpu {
vector<string> available_sensors = {"Auto"};
cpu_info current_cpu;
fs::path freq_path = "/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq";
bool got_sensors = false, cpu_temp_only = false;
bool got_sensors = false, cpu_temp_only = false, supports_watts = false;
int core_offset = 0;
//* Populate found_sensors map