#!/bin/sh # Replacement for the tool of the same name from cpufrequtils which seems # to be dead. Currently shows only some of the information (the rest could # be added rather easily, but is of less interest to the author), but in # a tabular format which seems more readable, especially with many cores. # # The other commonly used tool of that package, cpufreq-set, can be replaced # with simply writing to /sys, e.g. using tee like this (bash syntax): # # sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor > /dev/null <<< ondemand # sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq > /dev/null <<< 2400000 # # In the common case of setting all cores at once, this is even easier to use # by using a wildcard, whereas cpufreq-set can only set a single core, # so needs to be called in a loop for all cores. # # Copyright 2025 Frank Heckenbach # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation, either version 3 of # the License, or (at your option) any later version. # # 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . exec gawk ' function max(x, y) { return x > y ? x : y; } function table(value, alignment, x, y) { x = _table["x"] + 0; y = _table["y"] + 0; _table[x "," y] = value; _table[x "~" y] = alignment; _table["w" x] = max(_table["w" x], length (value)); _table["x"] = x + 1; } function table_row() { _table["#" (_table["y"] + 0)] = _table["x"]; _table["x"] = 0; _table["y"] = _table["y"] + 1; } function table_output ( i, j) { if (_table["x"] > 0) table_row(); for (j = 0; j < _table["y"]; j++) { for (i = 0; i < _table["#" j]; i++) printf (_table[i "~" j] == "r" ? "%s%*s" : "%s%-*s", i ? " " : "", _table["w" i], _table[i "," j]); print ""; } } function tospeed (s) { return sprintf ("%.1f", s / 1000000); } function value (n) { r = ""; getline r < ("/sys/devices/system/cpu/cpu" cpu "/cpufreq/" n); return r; } function speed (n) { return tospeed(value(n)); } function trim (v) { return gensub (/ $/, "", 1, v); } function mark (v, c) { t = gensub (c, "*&*", 1, v); return t != v ? t : v " ?" c "?"; } BEGIN { table("CPU", "r"); table("GHz", "r"); table("Hardware"); table("Governor (*current*)"); table("Range GHz", "r"); table_row(); } /cpu[0-9]+/ { cpu = gensub (/.*cpu([0-9]+).*/, "\\1", 1); $0 = value("scaling_available_frequencies"); f = ""; for (i = 1; i <= NF; i++) f = tospeed($i) " " f; if (!f) f = "-"; fmin = value("cpuinfo_min_freq"); if (fmin != $NF) f = "(" tospeed(fmin) ") " f; fmax = value("cpuinfo_max_freq"); if (fmax != $1 ) f = f " (" tospeed(fmax) ")"; table(cpu, "r"); table(speed("scaling_cur_freq"), "r"); table(trim(f)); table(trim(mark(value("scaling_available_governors"), value("scaling_governor")))); table(speed("scaling_min_freq") " - " speed("scaling_max_freq"), "r"); table_row(); } END { table_output(); } ' /proc/stat