Skip to content

Commit

Permalink
Show CPU temperature in CPU meter
Browse files Browse the repository at this point in the history
Show the CPU temperature in the CPU meter, like CPU frequency, instead
of spending a whole line on a single (temperature) number.
  • Loading branch information
cgzones committed Sep 28, 2020
1 parent 9ee7256 commit c445a5a
Show file tree
Hide file tree
Showing 18 changed files with 186 additions and 11 deletions.
50 changes: 40 additions & 10 deletions CPUMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,42 @@ 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[30] = { 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';
}

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());
}

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(Object* cast, RichString* out) {
Expand Down Expand Up @@ -109,6 +126,19 @@ static void CPUMeter_display(Object* cast, RichString* out) {
RichString_append(out, CRT_colors[CPU_GUEST], buffer);
}
}

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);
}
}

static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
Expand Down
3 changes: 2 additions & 1 deletion CPUMeter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 int CPUMeter_attributes[];
Expand Down
8 changes: 8 additions & 0 deletions CRT.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ bool CRT_utf8 = false;

#endif

const char* CRT_degreeSign() {
#ifdef HAVE_LIBNCURSESW
if (CRT_utf8)
return "\xc2\xb0";
#endif
return "";
}

const char **CRT_treeStr = CRT_treeStrAscii;

static bool CRT_hasColors;
Expand Down
2 changes: 2 additions & 0 deletions CRT.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ void CRT_handleSIGSEGV(int sgn);

extern const char *CRT_treeStrAscii[TREE_STR_COUNT];

const char* CRT_degreeSign(void);

#ifdef HAVE_LIBNCURSESW

extern const char *CRT_treeStrUtf8[TREE_STR_COUNT];
Expand Down
2 changes: 2 additions & 0 deletions DisplayOptionsPanel.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ 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)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Also show CPU temperature"), &(settings->showCPUTemperature)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Enable the mouse"), &(settings->enableMouse)));
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show temperature in degree Fahrenheit"), &(settings->degreeFahrenheit)));
#ifdef HAVE_LIBHWLOC
Panel_add(super, (Object*) CheckItem_newByRef(xStrdup("Show topology when selecting affinity by default"), &(settings->topologyAffinity)));
#endif
Expand Down
8 changes: 8 additions & 0 deletions Settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ static bool Settings_read(Settings* this, const char* fileName) {
this->showCPUUsage = atoi(option[1]);
} else if (String_eq(option[0], "show_cpu_frequency")) {
this->showCPUFrequency = atoi(option[1]);
} else if (String_eq(option[0], "show_cpu_temperature")) {
this->showCPUTemperature = atoi(option[1]);
} 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")) {
Expand All @@ -195,6 +197,8 @@ static bool Settings_read(Settings* this, const char* fileName) {
} else if (String_eq(option[0], "right_meter_modes")) {
Settings_readMeterModes(this, option[1], 1);
didReadMeters = true;
} else if (String_eq(option[0], "degree_fahrenheit")) {
this->degreeFahrenheit = atoi(option[1]);
#ifdef HAVE_LIBHWLOC
} else if (String_eq(option[0], "topology_affinity")) {
this->topologyAffinity = !!atoi(option[1]);
Expand Down Expand Up @@ -269,6 +273,7 @@ bool Settings_write(Settings* this) {
fprintf(fd, "cpu_count_from_zero=%d\n", (int) this->countCPUsFromZero);
fprintf(fd, "show_cpu_usage=%d\n", (int) this->showCPUUsage);
fprintf(fd, "show_cpu_frequency=%d\n", (int) this->showCPUFrequency);
fprintf(fd, "show_cpu_temperature=%d\n", (int) this->showCPUTemperature);
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);
Expand All @@ -278,6 +283,7 @@ bool Settings_write(Settings* this) {
fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0);
fprintf(fd, "right_meters="); writeMeters(this, fd, 1);
fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1);
fprintf(fd, "degree_fahrenheit=%d\n", (int) this->degreeFahrenheit);
#ifdef HAVE_LIBHWLOC
fprintf(fd, "topology_affinity=%d\n", (int) this->topologyAffinity);
#endif
Expand All @@ -302,10 +308,12 @@ Settings* Settings_new(int cpuCount) {
this->countCPUsFromZero = false;
this->showCPUUsage = true;
this->showCPUFrequency = false;
this->showCPUTemperature = false;
this->updateProcessNames = false;
this->cpuCount = cpuCount;
this->showProgramPath = true;
this->highlightThreads = true;
this->degreeFahrenheit = false;
#ifdef HAVE_LIBHWLOC
this->topologyAffinity = false;
#endif
Expand Down
2 changes: 2 additions & 0 deletions Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ typedef struct Settings_ {
bool detailedCPUTime;
bool showCPUUsage;
bool showCPUFrequency;
bool showCPUTemperature;
bool treeView;
bool showProgramPath;
bool hideThreads;
Expand All @@ -49,6 +50,7 @@ typedef struct Settings_ {
bool accountGuestInCPUMeter;
bool headerMargin;
bool enableMouse;
bool degreeFahrenheit;
#ifdef HAVE_LIBHWLOC
bool topologyAffinity;
#endif
Expand Down
11 changes: 11 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,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\
Expand Down Expand Up @@ -348,4 +358,5 @@ AC_MSG_RESULT([
hwlock: $enable_hwloc
setuid: $enable_setuid
linux delay accounting: $enable_delayacct
sensors: $enable_sensors
])
1 change: 1 addition & 0 deletions darwin/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,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);
}
Expand Down
1 change: 1 addition & 0 deletions dragonflybsd/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ double Platform_setCPUValues(Meter* this, int cpu) {
if (isnan(percent)) percent = 0.0;

v[CPU_METER_FREQUENCY] = NAN;
v[CPU_METER_TEMPERATURE] = NAN;

return percent;
}
Expand Down
1 change: 1 addition & 0 deletions freebsd/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ double Platform_setCPUValues(Meter* this, int cpu) {
if (isnan(percent)) percent = 0.0;

v[CPU_METER_FREQUENCY] = NAN;
v[CPU_METER_TEMPERATURE] = NAN;

return percent;
}
Expand Down
12 changes: 12 additions & 0 deletions htop.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ in the source distribution for its full text.
#include <time.h>
#include <unistd.h>

#ifdef HAVE_LIBSENSORS
#include <sensors/sensors.h>
#endif

//#link m

static void printVersionFlag(void) {
Expand Down Expand Up @@ -235,6 +239,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);

Expand Down Expand Up @@ -270,6 +278,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);
Expand Down
76 changes: 76 additions & 0 deletions linux/LinuxProcessList.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ in the source distribution for its full text.
#include <linux/taskstats.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.
size_t alreadyRead = 0;
Expand Down Expand Up @@ -1234,6 +1239,71 @@ 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)) {
for (int i = 0; i <= cpuCount; i++)
this->cpus[i].temperature = this->cpus[0].temperature;

return;
}

/* Half the temperatures, probably HT/SMT - copy to second half */
if (r >= 1 && r == 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) {
LinuxProcessList* this = (LinuxProcessList*) super;
const Settings* settings = super->settings;
Expand All @@ -1245,6 +1315,12 @@ void ProcessList_goThroughEntries(ProcessList* super) {
if (settings->showCPUFrequency)
LinuxProcessList_scanCPUFrequency(this);

#ifdef HAVE_LIBSENSORS
if (settings->showCPUTemperature)
LinuxProcessList_scanCPUTemperature(this);
#endif


struct timeval tv;
gettimeofday(&tv, NULL);
LinuxProcessList_recurseProcTree(this, PROCDIR, NULL, period, tv);
Expand Down
4 changes: 4 additions & 0 deletions linux/LinuxProcessList.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ typedef struct CPUData_ {
unsigned long long int guestPeriod;

double frequency;

#ifdef HAVE_LIBSENSORS
double temperature;
#endif
} CPUData;

typedef struct TtyDriver_ {
Expand Down
11 changes: 11 additions & 0 deletions linux/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ in the source distribution for its full text.
#include "zfs/ZfsArcMeter.h"
#include "zfs/ZfsCompressedArcMeter.h"
#include "LinuxProcess.h"
#include "StringUtils.h"

#include <math.h>
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, (int)M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
Expand Down Expand Up @@ -200,6 +202,15 @@ double Platform_setCPUValues(Meter* this, int cpu) {

v[CPU_METER_FREQUENCY] = cpuData->frequency;

#ifdef HAVE_LIBSENSORS
if (this->pl->settings->showCPUTemperature)
v[CPU_METER_TEMPERATURE] = cpuData->temperature;
else
v[CPU_METER_TEMPERATURE] = NAN;
#else
v[CPU_METER_TEMPERATURE] = NAN;
#endif

return percent;
}

Expand Down
Loading

0 comments on commit c445a5a

Please sign in to comment.