Show CPU temperature in CPU meter

Show the CPU temperature in the CPU meter, like CPU frequency, instead
of using an extra Meter.
This commit is contained in:
Christian Göttsche 2020-09-10 19:56:33 +02:00
parent 309f1d7282
commit 1b225cd7a0
19 changed files with 220 additions and 23 deletions

View File

@ -12,11 +12,11 @@ jobs:
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-linux-affinity --disable-taskstats --disable-unicode
run: ./configure --enable-werror --enable-linux-affinity --disable-taskstats --disable-unicode --disable-sensors
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-linux-affinity --disable-taskstats --disable-unicode"
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-linux-affinity --disable-taskstats --disable-unicode --disable-sensors"
build-ubuntu-latest-minimal-clang:
runs-on: ubuntu-latest
@ -34,26 +34,26 @@ jobs:
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-linux-affinity --disable-taskstats --disable-unicode
run: ./configure --enable-werror --enable-linux-affinity --disable-taskstats --disable-unicode --disable-sensors
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-linux-affinity --disable-taskstats --disable-unicode"
run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-werror --enable-linux-affinity --disable-taskstats --disable-unicode --disable-sensors"
build-ubuntu-latest-full-featured-gcc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: sudo apt-get install libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev
run: sudo apt-get install libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct
run: ./configure --enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --enable-sensors
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct'
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --enable-sensors'
build-ubuntu-latest-full-featured-clang:
runs-on: ubuntu-latest
@ -67,15 +67,15 @@ jobs:
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install clang-10 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev
run: sudo apt-get install clang-10 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: ./configure --enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct
run: ./configure --enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --enable-sensors
- name: Build
run: make -k
- name: Distcheck
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct'
run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --enable-sensors'
build-ubuntu-latest-clang-analyzer:
runs-on: ubuntu-latest
@ -89,11 +89,11 @@ jobs:
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main' -y
sudo apt-get update -q
- name: Install Dependencies
run: sudo apt-get install clang-11 clang-tools-11 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev
run: sudo apt-get install clang-11 clang-tools-11 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
run: scan-build-11 -analyze-headers --status-bugs ./configure --enable-debug --enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct
run: scan-build-11 -analyze-headers --status-bugs ./configure --enable-debug --enable-werror --enable-openvz --enable-cgroup --enable-vserver --enable-ancient-vserver --enable-taskstats --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --enable-sensors
- name: Build
run: scan-build-11 -analyze-headers --status-bugs make -j"$(nproc)"

View File

@ -56,25 +56,44 @@ static void CPUMeter_updateValues(Meter* this, char* buffer, int size) {
return;
}
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
char cpuUsageBuffer[8] = { 0 };
char cpuFrequencyBuffer[16] = { 0 };
char cpuTemperatureBuffer[16] = { 0 };
double percent = Platform_setCPUValues(this, cpu);
if (this->pl->settings->showCPUUsage) {
xSnprintf(cpuUsageBuffer, sizeof(cpuUsageBuffer), "%5.1f%%", percent);
}
if (this->pl->settings->showCPUFrequency) {
double cpuFrequency = this->values[CPU_METER_FREQUENCY];
char cpuFrequencyBuffer[16];
if (isnan(cpuFrequency)) {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A");
} else {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz", (unsigned)cpuFrequency);
}
if (this->pl->settings->showCPUUsage) {
xSnprintf(buffer, size, "%5.1f%% %s", percent, cpuFrequencyBuffer);
} else {
xSnprintf(buffer, size, "%s", cpuFrequencyBuffer);
}
} else if (this->pl->settings->showCPUUsage) {
xSnprintf(buffer, size, "%5.1f%%", percent);
} else if (size > 0) {
buffer[0] = '\0';
#ifdef HAVE_LIBSENSORS
if (this->pl->settings->showCPUTemperature) {
double cpuTemperature = this->values[CPU_METER_TEMPERATURE];
if (isnan(cpuTemperature))
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A");
else if (this->pl->settings->degreeFahrenheit)
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%3d%sF", (int)(cpuTemperature * 9 / 5 + 32), CRT_degreeSign);
else
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%d%sC", (int)cpuTemperature, CRT_degreeSign);
}
#endif
xSnprintf(buffer, size, "%s%s%s%s%s",
cpuUsageBuffer,
(cpuUsageBuffer[0] && (cpuFrequencyBuffer[0] || cpuTemperatureBuffer[0])) ? " " : "",
cpuFrequencyBuffer,
(cpuFrequencyBuffer[0] && cpuTemperatureBuffer[0]) ? " " : "",
cpuTemperatureBuffer);
}
static void CPUMeter_display(const Object* cast, RichString* out) {
@ -127,6 +146,22 @@ static void CPUMeter_display(const Object* cast, RichString* out) {
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
}
}
#ifdef HAVE_LIBSENSORS
if (this->pl->settings->showCPUTemperature) {
char cpuTemperatureBuffer[10];
double cpuTemperature = this->values[CPU_METER_TEMPERATURE];
if (isnan(cpuTemperature)) {
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A");
} else if (this->pl->settings->degreeFahrenheit) {
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sF", cpuTemperature * 9 / 5 + 32, CRT_degreeSign);
} else {
xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sC", cpuTemperature, CRT_degreeSign);
}
RichString_append(out, CRT_colors[METER_TEXT], "temp:");
RichString_append(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer);
}
#endif
}
static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {

View File

@ -19,7 +19,8 @@ typedef enum {
CPU_METER_GUEST = 6,
CPU_METER_IOWAIT = 7,
CPU_METER_FREQUENCY = 8,
CPU_METER_ITEMCOUNT = 9, // number of entries in this enum
CPU_METER_TEMPERATURE = 9,
CPU_METER_ITEMCOUNT = 10, // number of entries in this enum
} CPUMeterValues;
extern const MeterClass CPUMeter_class;

19
CRT.c
View File

@ -74,6 +74,23 @@ const char* const* CRT_treeStr = CRT_treeStrAscii;
int CRT_delay;
const char* CRT_degreeSign;
static const char* initDegreeSign(void) {
#ifdef HAVE_LIBNCURSESW
if (CRT_utf8)
return "\xc2\xb0";
#endif
static char buffer[4];
// this might fail if the current locale does not support wide characters
int r = snprintf(buffer, sizeof(buffer), "%lc", 176);
if (r > 0)
return buffer;
return "";
}
const int* CRT_colors;
int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
@ -718,6 +735,8 @@ void CRT_init(int delay, int colorScheme, bool allowUnicode) {
if (CRT_pageSize == -1)
CRT_fatalError("Fatal error: Can not get PAGE_SIZE by sysconf(_SC_PAGESIZE)");
CRT_pageSizeKB = CRT_pageSize / 1024;
CRT_degreeSign = initDegreeSign();
}
void CRT_done() {

1
CRT.h
View File

@ -129,6 +129,7 @@ void CRT_handleSIGSEGV(int signal) ATTR_NORETURN;
#define KEY_RECLICK KEY_F(22)
#define KEY_ALT(x) (KEY_F(64 - 26) + ((x) - 'A'))
extern const char* CRT_degreeSign;
#ifdef HAVE_LIBNCURSESW

View File

@ -92,6 +92,10 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Add guest time in CPU meter percentage"), &(settings->accountGuestInCPUMeter)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU percentage numerically"), &(settings->showCPUUsage)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU frequency"), &(settings->showCPUFrequency)));
#ifdef HAVE_LIBSENSORS
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU temperature"), &(settings->showCPUTemperature)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show temperature in degree Fahrenheit"), &(settings->degreeFahrenheit)));
#endif
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Enable the mouse"), &(settings->enableMouse)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Highlight new and old processes"), &(settings->highlightChanges)));
#ifdef HAVE_LIBHWLOC

View File

@ -177,6 +177,12 @@ static bool Settings_read(Settings* this, const char* fileName, int initialCpuCo
this->showCPUUsage = atoi(option[1]);
} else if (String_eq(option[0], "show_cpu_frequency")) {
this->showCPUFrequency = atoi(option[1]);
#ifdef HAVE_LIBSENSORS
} else if (String_eq(option[0], "show_cpu_temperature")) {
this->showCPUTemperature = atoi(option[1]);
} else if (String_eq(option[0], "degree_fahrenheit")) {
this->degreeFahrenheit = atoi(option[1]);
#endif
} else if (String_eq(option[0], "update_process_names")) {
this->updateProcessNames = atoi(option[1]);
} else if (String_eq(option[0], "account_guest_in_cpu_meter")) {
@ -277,6 +283,10 @@ bool Settings_write(Settings* this) {
fprintf(fd, "cpu_count_from_one=%d\n", (int) this->countCPUsFromOne);
fprintf(fd, "show_cpu_usage=%d\n", (int) this->showCPUUsage);
fprintf(fd, "show_cpu_frequency=%d\n", (int) this->showCPUFrequency);
#ifdef HAVE_LIBSENSORS
fprintf(fd, "show_cpu_temperature=%d\n", (int) this->showCPUTemperature);
fprintf(fd, "degree_fahrenheit=%d\n", (int) this->degreeFahrenheit);
#endif
fprintf(fd, "update_process_names=%d\n", (int) this->updateProcessNames);
fprintf(fd, "account_guest_in_cpu_meter=%d\n", (int) this->accountGuestInCPUMeter);
fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme);
@ -309,6 +319,10 @@ Settings* Settings_new(int initialCpuCount) {
this->countCPUsFromOne = false;
this->showCPUUsage = true;
this->showCPUFrequency = false;
#ifdef HAVE_LIBSENSORS
this->showCPUTemperature = false;
this->degreeFahrenheit = false;
#endif
this->updateProcessNames = false;
this->showProgramPath = true;
this->highlightThreads = true;

View File

@ -38,6 +38,10 @@ typedef struct Settings_ {
bool detailedCPUTime;
bool showCPUUsage;
bool showCPUFrequency;
#ifdef HAVE_LIBSENSORS
bool showCPUTemperature;
bool degreeFahrenheit;
#endif
bool treeView;
bool showProgramPath;
bool shadowOtherUsers;

View File

@ -308,6 +308,16 @@ then
])
fi
AC_ARG_ENABLE(sensors, [AS_HELP_STRING([--enable-sensors], [enable libsensors support for reading temperature data.])],, enable_sensors="check")
if test "x$enable_sensors" = xyes; then
AC_CHECK_LIB([sensors], [sensors_get_value], [], [missing_libraries="$missing_libraries libsensors"])
AC_CHECK_HEADERS([sensors/sensors.h], [], [missing_headers="$missing_headers $ac_header"])
elif test "x$enable_sensors" = xcheck; then
enable_sensors=yes
AC_CHECK_LIB([sensors], [sensors_get_value], [], [enable_sensors=no])
AC_CHECK_HEADERS([sensors/sensors.h], [], [enable_sensors=no])
fi
AM_CFLAGS="\
-Wall\
-Wcast-align\
@ -386,6 +396,7 @@ AC_MSG_RESULT([
(Linux) taskstats: $enable_taskstats
(Linux) affinity: $enable_linux_affinity
(Linux) delay accounting: $enable_delayacct
(Linux) sensors: $enable_sensors
unicode: $enable_unicode
hwloc: $enable_hwloc
setuid: $enable_setuid

View File

@ -224,6 +224,7 @@ double Platform_setCPUValues(Meter* mtr, int cpu) {
total = mtr->values[CPU_METER_NICE] + mtr->values[CPU_METER_NORMAL] + mtr->values[CPU_METER_KERNEL];
mtr->values[CPU_METER_FREQUENCY] = NAN;
mtr->values[CPU_METER_TEMPERATURE] = NAN;
return CLAMP(total, 0.0, 100.0);
}

View File

@ -179,6 +179,7 @@ double Platform_setCPUValues(Meter* this, int cpu) {
percent = isnan(percent) ? 0.0 : CLAMP(percent, 0.0, 100.0);
v[CPU_METER_FREQUENCY] = NAN;
v[CPU_METER_TEMPERATURE] = NAN;
return percent;
}

View File

@ -190,6 +190,7 @@ double Platform_setCPUValues(Meter* this, int cpu) {
percent = CLAMP(percent, 0.0, 100.0);
v[CPU_METER_FREQUENCY] = NAN;
v[CPU_METER_TEMPERATURE] = NAN;
return percent;
}

12
htop.c
View File

@ -36,6 +36,10 @@ in the source distribution for its full text.
#include "XUtils.h"
#ifdef HAVE_LIBSENSORS
#include <sensors/sensors.h>
#endif
//#link m
static void printVersionFlag(void) {
@ -317,6 +321,10 @@ int main(int argc, char** argv) {
CRT_init(settings->delay, settings->colorScheme, flags.allowUnicode);
#ifdef HAVE_LIBSENSORS
sensors_init(NULL);
#endif
MainPanel* panel = MainPanel_new();
ProcessList_setPanel(pl, (Panel*) panel);
@ -357,6 +365,10 @@ int main(int argc, char** argv) {
attroff(CRT_colors[RESET_COLOR]);
refresh();
#ifdef HAVE_LIBSENSORS
sensors_cleanup();
#endif
CRT_done();
if (settings->changed)
Settings_write(settings);

View File

@ -50,6 +50,10 @@ in the source distribution for its full text.
#include <sys/sysmacros.h>
#endif
#ifdef HAVE_LIBSENSORS
#include <sensors/sensors.h>
#endif
static ssize_t xread(int fd, void* buf, size_t count) {
// Read some bytes. Retry on EINTR and when we don't get as many bytes as we requested.
@ -1505,6 +1509,75 @@ static void LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) {
scanCPUFreqencyFromCPUinfo(this);
}
#ifdef HAVE_LIBSENSORS
static int getCPUTemperatures(CPUData* cpus, int cpuCount) {
int tempCount = 0;
int n = 0;
for (const sensors_chip_name *chip = sensors_get_detected_chips(NULL, &n); chip; chip = sensors_get_detected_chips(NULL, &n)) {
char buffer[32];
sensors_snprintf_chip_name(buffer, sizeof(buffer), chip);
if (!String_startsWith(buffer, "coretemp") && !String_startsWith(buffer, "cpu_thermal"))
continue;
int m = 0;
for (const sensors_feature *feature = sensors_get_features(chip, &m); feature; feature = sensors_get_features(chip, &m)) {
if (feature->type != SENSORS_FEATURE_TEMP)
continue;
if (feature->number > cpuCount)
continue;
const sensors_subfeature *sub_feature = sensors_get_subfeature(chip, feature, SENSORS_SUBFEATURE_TEMP_INPUT);
if (sub_feature) {
double temp;
int r = sensors_get_value(chip, sub_feature->number, &temp);
if (r != 0)
continue;
cpus[feature->number].temperature = temp;
tempCount++;
}
}
}
return tempCount;
}
static void LinuxProcessList_scanCPUTemperature(LinuxProcessList* this) {
const int cpuCount = this->super.cpuCount;
for (int i = 0; i <= cpuCount; i++) {
this->cpus[i].temperature = NAN;
}
int r = getCPUTemperatures(this->cpus, cpuCount);
/* No temperature - nothing to do */
if (r == 0)
return;
/* Only package temperature - copy to all cpus */
if (r == 1 && !isnan(this->cpus[0].temperature)) {
double packageTemp = this->cpus[0].temperature;
for (int i = 1; i <= cpuCount; i++) {
this->cpus[i].temperature = packageTemp;
}
return;
}
/* Half the temperatures, probably HT/SMT - copy to second half */
if (r >= 2 && (r - 1) == (cpuCount / 2)) {
for (int i = cpuCount / 2 + 1; i <= cpuCount; i++) {
this->cpus[i].temperature = this->cpus[i/2].temperature;
}
return;
}
}
#endif
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
LinuxProcessList* this = (LinuxProcessList*) super;
const Settings* settings = super->settings;
@ -1520,6 +1593,11 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
LinuxProcessList_scanCPUFrequency(this);
}
#ifdef HAVE_LIBSENSORS
if (settings->showCPUTemperature)
LinuxProcessList_scanCPUTemperature(this);
#endif
// in pause mode only gather global data for meters (CPU/memory/...)
if (pauseProcessUpdate) {
return;

View File

@ -47,6 +47,10 @@ typedef struct CPUData_ {
unsigned long long int guestPeriod;
double frequency;
#ifdef HAVE_LIBSENSORS
double temperature;
#endif
} CPUData;
typedef struct TtyDriver_ {

View File

@ -241,6 +241,12 @@ double Platform_setCPUValues(Meter* this, int cpu) {
v[CPU_METER_FREQUENCY] = cpuData->frequency;
#ifdef HAVE_LIBSENSORS
v[CPU_METER_TEMPERATURE] = cpuData->temperature;
#else
v[CPU_METER_TEMPERATURE] = NAN;
#endif
return percent;
}

View File

@ -187,6 +187,9 @@ double Platform_setCPUValues(Meter* this, int cpu) {
if (isnan(totalPercent)) {
totalPercent = 0.0;
}
v[CPU_METER_TEMPERATURE] = NAN;
return totalPercent;
}

View File

@ -203,6 +203,7 @@ double Platform_setCPUValues(Meter* this, int cpu) {
percent = isnan(percent) ? 0.0 : CLAMP(percent, 0.0, 100.0);
v[CPU_METER_FREQUENCY] = NAN;
v[CPU_METER_TEMPERATURE] = NAN;
return percent;
}

View File

@ -119,6 +119,7 @@ double Platform_setCPUValues(Meter* this, int cpu) {
double* v = this->values;
v[CPU_METER_FREQUENCY] = NAN;
v[CPU_METER_TEMPERATURE] = NAN;
return 0.0;
}