feat: Introduce cpu frequency display modes

This commit is contained in:
Emilio B. Pedrollo
2025-09-30 15:28:42 -03:00
committed by Jakob P. Liljenberg
parent 4f661d5404
commit 040171400a
6 changed files with 118 additions and 26 deletions

View File

@@ -1429,6 +1429,9 @@ base_10_sizes = False
#* Show CPU frequency.
show_cpu_freq = True
#* How to calculate CPU frequency, available values: "first", "range", "lowest", "highest" and "average".
freq_mode = "first"
#* Draw a clock at top of screen, formatting according to strftime, empty string to disable.
#* Special formatting: /host = hostname | /user = username | /uptime = system uptime
clock_format = "%H:%M"

View File

@@ -150,7 +150,9 @@ namespace Config {
{"base_10_sizes", "#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024."},
{"show_cpu_freq", "#* Show CPU frequency."},
#ifdef __linux__
{"freq_mode", "#* How to calculate CPU frequency, available values: \"first\", \"range\", \"lowest\", \"highest\" and \"average\"."},
#endif
{"clock_format", "#* Draw a clock at top of screen, formatting according to strftime, empty string to disable.\n"
"#* Special formatting: /host = hostname | /user = username | /uptime = system uptime"},
@@ -243,6 +245,9 @@ namespace Config {
{"selected_battery", "Auto"},
{"cpu_core_map", ""},
{"temp_scale", "celsius"},
#ifdef __linux__
{"freq_mode", "first"},
#endif
{"clock_format", "%X"},
{"custom_cpu_name", ""},
{"disks_filter", ""},

View File

@@ -50,6 +50,9 @@ namespace Config {
#endif
};
const vector<string> temp_scales = { "celsius", "fahrenheit", "kelvin", "rankine" };
#ifdef __linux__
const vector<string> freq_modes = { "first", "range", "lowest", "highest", "average" };
#endif
#ifdef GPU_SUPPORT
const vector<string> show_gpu_values = { "Auto", "On", "Off" };
#endif

View File

@@ -812,9 +812,16 @@ namespace Cpu {
+ Theme::c("graph_text") + "up" + Mv::r(1) + upstr;
}
#ifdef __linux__
const bool freq_range = Config::getS("freq_mode") == "range";
#else
const bool freq_range = false;
#endif
//? Cpu clock and cpu meter
if (Config::getB("show_cpu_freq") and not cpuHz.empty())
out += Mv::to(b_y, b_x + b_width - 10) + Fx::ub + Theme::c("div_line") + Symbols::h_line * (7 - cpuHz.size())
out += Mv::to(b_y, b_x + b_width - (freq_range ? 20 : 10)) + Fx::ub + Theme::c("div_line")
+ Symbols::h_line * ((freq_range ? 17 : 7) - cpuHz.size())
+ Symbols::title_left + Fx::b + Theme::c("title") + cpuHz + Fx::ub + Theme::c("div_line") + Symbols::title_right;
out += Mv::to(b_y + 1, b_x + 1) + Theme::c("main_fg") + Fx::b + "CPU " + cpu_meter(safeVal(cpu.cpu_percent, "total"s).back())
@@ -2117,9 +2124,14 @@ namespace Draw {
auto& custom = Config::getS("custom_cpu_name");
static const bool hasCpuHz = not Cpu::get_cpuHz().empty();
#ifdef __linux__
static const bool freq_range = Config::getS("freq_mode") == "range";
#else
static const bool freq_range = false;
#endif
const string cpu_title = uresize(
(custom.empty() ? Cpu::cpuName : custom),
b_width - (Config::getB("show_cpu_freq") and hasCpuHz ? 14 : 4)
b_width - (Config::getB("show_cpu_freq") and hasCpuHz ? (freq_range ? 24 : 14) : 5)
);
box += createBox(b_x, b_y, b_width, b_height, "", false, cpu_title);
}

View File

@@ -500,6 +500,22 @@ namespace Menu {
"",
"Can cause slowdowns on systems with many",
"cores and certain kernel versions."},
#ifdef __linux__
{"freq_mode",
"How the CPU frequency will be displayed.",
"",
"First, get the frequency from the first",
"core.",
"",
"Range, show the lowest and the highest",
"frequency.",
"",
"Lowest, the lowest frequency.",
"",
"Highest, the highest frequency.",
"",
"Average, sum and divide."},
#endif
{"custom_cpu_name",
"Custom cpu model name in cpu percentage box.",
"",
@@ -1202,6 +1218,9 @@ static int optionsMenu(const string& key) {
{"color_theme", std::cref(Theme::themes)},
{"log_level", std::cref(Logger::log_levels)},
{"temp_scale", std::cref(Config::temp_scales)},
#ifdef __linux__
{"freq_mode", std::cref(Config::freq_modes)},
#endif
{"proc_sorting", std::cref(Proc::sort_vector)},
{"graph_symbol", std::cref(Config::valid_graph_symbols)},
{"graph_symbol_cpu", std::cref(Config::valid_graph_symbols_def)},

View File

@@ -93,10 +93,10 @@ long long get_monotonicTimeUSec()
namespace Cpu {
vector<long long> core_old_totals;
vector<long long> core_old_idles;
vector<fs::path> core_freq;
vector<string> available_fields = {"Auto", "total"};
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{};
bool cpu_temp_only{};
bool supports_watts = true;
@@ -289,11 +289,19 @@ namespace Shared {
}
//? Init for namespace Cpu
if (not fs::exists(Cpu::freq_path) or access(Cpu::freq_path.c_str(), R_OK) == -1) Cpu::freq_path.clear();
Cpu::current_cpu.core_percent.insert(Cpu::current_cpu.core_percent.begin(), Shared::coreCount, {});
Cpu::current_cpu.temp.insert(Cpu::current_cpu.temp.begin(), Shared::coreCount + 1, {});
Cpu::core_old_totals.insert(Cpu::core_old_totals.begin(), Shared::coreCount, 0);
Cpu::core_old_idles.insert(Cpu::core_old_idles.begin(), Shared::coreCount, 0);
for (int i = 0; i < Shared::coreCount; ++i) {
Cpu::core_freq.push_back("/sys/devices/system/cpu/cpufreq/policy" + to_string(i) + "/scaling_cur_freq");
if (not fs::exists(Cpu::core_freq[i]) or access(Cpu::core_freq[i].c_str(), R_OK) == -1) {
Cpu::core_freq[i].clear();
Cpu::core_freq.pop_back();
}
}
Cpu::collect();
if (Runner::coreNum_reset) Runner::coreNum_reset = false;
for (auto& [field, vec] : Cpu::current_cpu.cpu_percent) {
@@ -552,6 +560,26 @@ namespace Cpu {
}
}
static string normalize_frequency(double hz) {
string str;
if (hz > 999999) {
str = fmt::format("{:.1f}", hz / 1'000'000);
str.resize(3);
if (str.back() == '.') str.pop_back();
str += " THz";
}
else if (hz > 999) {
str = fmt::format("{:.1f}", hz / 1'000);
str.resize(3);
if (str.back() == '.') str.pop_back();
str += " GHz";
}
else {
str = fmt::format("{:.0f} MHz", hz);
}
return str;
}
string get_cpuHz() {
static int failed{};
@@ -559,13 +587,49 @@ namespace Cpu {
return ""s;
string cpuhz;
const auto &freq_mode = Config::getS("freq_mode");
try {
double hz{};
//? Try to get freq from /sys/devices/system/cpu/cpufreq/policy first (faster)
if (not freq_path.empty()) {
hz = stod(readfile(freq_path, "0.0")) / 1000;
if (hz <= 0.0 and ++failed >= 2)
freq_path.clear();
double hz = 0.0;
// Read frequencies from all CPU cores
vector<double> frequencies;
unsigned long cpu_count = freq_mode == "first" ? std::min(static_cast<size_t>(1),Cpu::core_freq.size()) : Cpu::core_freq.size();
for (unsigned int i = 0; i < cpu_count; ++i) {
if (not Cpu::core_freq[i].empty()) {
double core_hz = stod(readfile(Cpu::core_freq[i], "0.0")) / 1000;
if (core_hz <= 0.0 and ++failed >= 2) {
Cpu::core_freq[i].clear();
Cpu::core_freq.erase(Cpu::core_freq.begin() + i--);
} else {
frequencies.push_back(core_hz);
}
}
}
if (not frequencies.empty()) {
if (freq_mode == "first") {
hz = frequencies.front();
}
if (freq_mode == "average") {
hz = std::accumulate(frequencies.begin(), frequencies.end(), 0.0) / static_cast<double>(frequencies.size());
}
else if (freq_mode == "highest") {
hz = *std::max_element(frequencies.begin(), frequencies.end());
}
else if (freq_mode == "lowest") {
hz = *std::min_element(frequencies.begin(), frequencies.end());
}
else if (freq_mode == "range") {
auto [min_hz,max_hz] = std::minmax_element(frequencies.begin(), frequencies.end());
// Format as range
string min_str, max_str;
min_str = normalize_frequency(*min_hz);
max_str = normalize_frequency(*max_hz);
return min_str + " - " + max_str;
}
}
//? If freq from /sys failed or is missing try to use /proc/cpuinfo
if (hz <= 0.0) {
@@ -588,21 +652,7 @@ namespace Cpu {
if (hz <= 1 or hz >= 999999999)
throw std::runtime_error("Failed to read /sys/devices/system/cpu/cpufreq/policy and /proc/cpuinfo.");
if (hz > 999999) {
cpuhz = fmt::format("{:.1f}", hz / 1'000'000);
cpuhz.resize(3);
if (cpuhz.back() == '.') cpuhz.pop_back();
cpuhz += " THz";
}
else if (hz > 999) {
cpuhz = fmt::format("{:.1f}", hz / 1'000);
cpuhz.resize(3);
if (cpuhz.back() == '.') cpuhz.pop_back();
cpuhz += " GHz";
}
else {
cpuhz = fmt::format("{:.0f} MHz", hz);
}
cpuhz = normalize_frequency(hz);
}
catch (const std::exception& e) {