diff --git a/BatteryMeter.c b/BatteryMeter.c index 33d17b734..24b2e6825 100644 --- a/BatteryMeter.c +++ b/BatteryMeter.c @@ -12,6 +12,7 @@ This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com). #include #include "CRT.h" +#include "Macros.h" #include "Object.h" #include "Platform.h" #include "XUtils.h" @@ -27,7 +28,7 @@ static void BatteryMeter_updateValues(Meter* this) { Platform_getBattery(&percent, &isOnAC); - if (isnan(percent)) { + if (!isNonnegative(percent)) { this->values[0] = NAN; xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "N/A"); return; diff --git a/CPUMeter.c b/CPUMeter.c index a946aa7d7..c12bb72c6 100644 --- a/CPUMeter.c +++ b/CPUMeter.c @@ -9,11 +9,11 @@ in the source distribution for its full text. #include "CPUMeter.h" -#include #include #include #include "CRT.h" +#include "Macros.h" #include "Object.h" #include "Platform.h" #include "ProcessList.h" @@ -71,7 +71,7 @@ static void CPUMeter_updateValues(Meter* this) { } double percent = Platform_setCPUValues(this, cpu); - if (isnan(percent)) { + if (!isNonnegative(percent)) { xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "offline"); return; } @@ -86,17 +86,17 @@ static void CPUMeter_updateValues(Meter* this) { if (settings->showCPUFrequency) { double cpuFrequency = this->values[CPU_METER_FREQUENCY]; - if (isnan(cpuFrequency)) { - xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A"); - } else { + if (isNonnegative(cpuFrequency)) { xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz", (unsigned)cpuFrequency); + } else { + xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A"); } } #ifdef BUILD_WITH_CPU_TEMP if (settings->showCPUTemperature) { double cpuTemperature = this->values[CPU_METER_TEMPERATURE]; - if (isnan(cpuTemperature)) + if (isNaN(cpuTemperature)) xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A"); else if (settings->degreeFahrenheit) xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%3d%sF", (int)(cpuTemperature * 9 / 5 + 32), CRT_degreeSign); @@ -146,12 +146,12 @@ static void CPUMeter_display(const Object* cast, RichString* out) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "si:"); RichString_appendnAscii(out, CRT_colors[CPU_SOFTIRQ], buffer, len); - if (!isnan(this->values[CPU_METER_STEAL])) { + if (isNonnegative(this->values[CPU_METER_STEAL])) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_STEAL]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "st:"); RichString_appendnAscii(out, CRT_colors[CPU_STEAL], buffer, len); } - if (!isnan(this->values[CPU_METER_GUEST])) { + if (isNonnegative(this->values[CPU_METER_GUEST])) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_GUEST]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "gu:"); RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, len); @@ -166,7 +166,7 @@ static void CPUMeter_display(const Object* cast, RichString* out) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "low:"); RichString_appendnAscii(out, CRT_colors[CPU_NICE_TEXT], buffer, len); - if (!isnan(this->values[CPU_METER_IRQ])) { + if (isNonnegative(this->values[CPU_METER_IRQ])) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "vir:"); RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, len); @@ -176,10 +176,10 @@ static void CPUMeter_display(const Object* cast, RichString* out) { if (settings->showCPUFrequency) { char cpuFrequencyBuffer[10]; double cpuFrequency = this->values[CPU_METER_FREQUENCY]; - if (isnan(cpuFrequency)) { - len = xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A "); - } else { + if (isNonnegative(cpuFrequency)) { len = xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz ", (unsigned)cpuFrequency); + } else { + len = xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A "); } RichString_appendAscii(out, CRT_colors[METER_TEXT], "freq: "); RichString_appendnWide(out, CRT_colors[METER_VALUE], cpuFrequencyBuffer, len); @@ -189,7 +189,7 @@ static void CPUMeter_display(const Object* cast, RichString* out) { if (settings->showCPUTemperature) { char cpuTemperatureBuffer[10]; double cpuTemperature = this->values[CPU_METER_TEMPERATURE]; - if (isnan(cpuTemperature)) { + if (isNaN(cpuTemperature)) { len = xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "N/A"); } else if (settings->degreeFahrenheit) { len = xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sF", cpuTemperature * 9 / 5 + 32, CRT_degreeSign); diff --git a/FileDescriptorMeter.c b/FileDescriptorMeter.c index 2d939d66d..92dc99ae3 100644 --- a/FileDescriptorMeter.c +++ b/FileDescriptorMeter.c @@ -12,6 +12,7 @@ in the source distribution for its full text. #include #include "CRT.h" +#include "Macros.h" #include "Meter.h" #include "Object.h" #include "Platform.h" @@ -19,7 +20,7 @@ in the source distribution for its full text. #include "XUtils.h" -#define FD_EFFECTIVE_UNLIMITED(x) ((x) > (1<<30)) +#define FD_EFFECTIVE_UNLIMITED(x) (!isgreaterequal((double)(1<<30), (x))) static const int FileDescriptorMeter_attributes[] = { FILE_DESCRIPTOR_USED, @@ -67,9 +68,9 @@ static void FileDescriptorMeter_updateValues(Meter* this) { } } - if (isnan(this->values[0])) { + if (!isNonnegative(this->values[0])) { xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "unknown/unknown"); - } else if (isnan(this->values[1]) || FD_EFFECTIVE_UNLIMITED(this->values[1])) { + } else if (FD_EFFECTIVE_UNLIMITED(this->values[1])) { xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.0lf/unlimited", this->values[0]); } else { xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.0lf/%.0lf", this->values[0], this->values[1]); @@ -81,7 +82,7 @@ static void FileDescriptorMeter_display(const Object* cast, RichString* out) { char buffer[50]; int len; - if (isnan(this->values[0])) { + if (!isNonnegative(this->values[0])) { RichString_appendAscii(out, CRT_colors[METER_TEXT], "unknown"); return; } @@ -91,7 +92,7 @@ static void FileDescriptorMeter_display(const Object* cast, RichString* out) { RichString_appendnAscii(out, CRT_colors[FILE_DESCRIPTOR_USED], buffer, len); RichString_appendAscii(out, CRT_colors[METER_TEXT], " max: "); - if (isnan(this->values[1]) || FD_EFFECTIVE_UNLIMITED(this->values[1])) { + if (FD_EFFECTIVE_UNLIMITED(this->values[1])) { RichString_appendAscii(out, CRT_colors[FILE_DESCRIPTOR_MAX], "unlimited"); } else { len = xSnprintf(buffer, sizeof(buffer), "%.0lf", this->values[1]); diff --git a/Macros.h b/Macros.h index 0f95347b7..459102a37 100644 --- a/Macros.h +++ b/Macros.h @@ -2,6 +2,8 @@ #define HEADER_Macros #include // IWYU pragma: keep +#include +#include #ifndef MINIMUM #define MINIMUM(a, b) ((a) < (b) ? (a) : (b)) @@ -98,6 +100,24 @@ #define IGNORE_WCASTQUAL_END #endif +/* Cheaper function for checking NaNs. Unlike the standard isnan(), this may + throw an FP exception on a "signaling" NaN. + (ISO/IEC TS 18661-1 and the C23 standard stated that isnan() throws no + exceptions even with a "signaling" NaN) */ +static inline bool isNaN(double x) { + return !isgreaterequal(x, x); +} + +/* Checks if x is nonnegative. Returns false if x is NaN. */ +static inline bool isNonnegative(double x) { + return isgreaterequal(x, 0.0); +} + +/* Checks if x is positive. Returns false if x is NaN. */ +static inline bool isPositive(double x) { + return isgreater(x, 0.0); +} + /* This subtraction is used by Linux / NetBSD / OpenBSD for calculation of CPU usage items. */ static inline unsigned long long saturatingSub(unsigned long long a, unsigned long long b) { return a > b ? a - b : 0; diff --git a/MemoryMeter.c b/MemoryMeter.c index 28c0be277..c7d99f885 100644 --- a/MemoryMeter.c +++ b/MemoryMeter.c @@ -11,6 +11,7 @@ in the source distribution for its full text. #include #include "CRT.h" +#include "Macros.h" #include "Object.h" #include "Platform.h" #include "RichString.h" @@ -42,9 +43,8 @@ static void MemoryMeter_updateValues(Meter* this) { /* we actually want to show "used + compressed" */ double used = this->values[MEMORY_METER_USED]; - if (!isnan(this->values[MEMORY_METER_COMPRESSED])) { + if (isPositive(this->values[MEMORY_METER_COMPRESSED])) used += this->values[MEMORY_METER_COMPRESSED]; - } written = Meter_humanUnit(buffer, used, size); METER_BUFFER_CHECK(buffer, size, written); @@ -71,14 +71,14 @@ static void MemoryMeter_display(const Object* cast, RichString* out) { RichString_appendAscii(out, CRT_colors[MEMORY_BUFFERS_TEXT], buffer); /* shared memory is not supported on all platforms */ - if (!isnan(this->values[MEMORY_METER_SHARED])) { + if (isNonnegative(this->values[MEMORY_METER_SHARED])) { Meter_humanUnit(buffer, this->values[MEMORY_METER_SHARED], sizeof(buffer)); RichString_appendAscii(out, CRT_colors[METER_TEXT], " shared:"); RichString_appendAscii(out, CRT_colors[MEMORY_SHARED], buffer); } /* compressed memory is not supported on all platforms */ - if (!isnan(this->values[MEMORY_METER_COMPRESSED])) { + if (isNonnegative(this->values[MEMORY_METER_COMPRESSED])) { Meter_humanUnit(buffer, this->values[MEMORY_METER_COMPRESSED], sizeof(buffer)); RichString_appendAscii(out, CRT_colors[METER_TEXT], " compressed:"); RichString_appendAscii(out, CRT_colors[MEMORY_COMPRESSED], buffer); @@ -89,7 +89,7 @@ static void MemoryMeter_display(const Object* cast, RichString* out) { RichString_appendAscii(out, CRT_colors[MEMORY_CACHE], buffer); /* available memory is not supported on all platforms */ - if (!isnan(this->values[MEMORY_METER_AVAILABLE])) { + if (isNonnegative(this->values[MEMORY_METER_AVAILABLE])) { Meter_humanUnit(buffer, this->values[MEMORY_METER_AVAILABLE], sizeof(buffer)); RichString_appendAscii(out, CRT_colors[METER_TEXT], " available:"); RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer); diff --git a/Meter.c b/Meter.c index cf0fe36ac..27e4cd0c0 100644 --- a/Meter.c +++ b/Meter.c @@ -333,10 +333,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { if (Meter_comprisedValues(this)) { data->values[nValues - 1] = (this->curItems > 0) ? this->values[this->curItems - 1] : 0.0; } else { - double value = 0.0; - for (uint8_t i = 0; i < this->curItems; i++) - value += !isnan(this->values[i]) ? this->values[i] : 0; - data->values[nValues - 1] = value; + data->values[nValues - 1] = sumPositiveValues(this->values, this->curItems); } } diff --git a/Process.c b/Process.c index b59cf7c91..b0a8ed3af 100644 --- a/Process.c +++ b/Process.c @@ -754,7 +754,7 @@ void Process_printRate(RichString* str, double rate, bool coloring) { processMegabytesColor = CRT_colors[PROCESS]; } - if (isnan(rate)) { + if (!isNonnegative(rate)) { RichString_appendAscii(str, shadowColor, " N/A "); } else if (rate < 0.005) { int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate); @@ -787,7 +787,7 @@ void Process_printLeftAlignedField(RichString* str, int attr, const char* conten } void Process_printPercentage(float val, char* buffer, size_t n, uint8_t width, int* attr) { - if (val >= 0) { + if (isNonnegative(val)) { if (val < 0.05F) *attr = CRT_colors[PROCESS_SHADOW]; else if (val >= 99.9F) diff --git a/SwapMeter.c b/SwapMeter.c index 84e58a26e..1055a6e70 100644 --- a/SwapMeter.c +++ b/SwapMeter.c @@ -13,6 +13,7 @@ in the source distribution for its full text. #include #include "CRT.h" +#include "Macros.h" #include "Object.h" #include "Platform.h" #include "RichString.h" @@ -51,13 +52,13 @@ static void SwapMeter_display(const Object* cast, RichString* out) { RichString_appendAscii(out, CRT_colors[METER_TEXT], " used:"); RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer); - if (!isnan(this->values[SWAP_METER_CACHE])) { + if (isNonnegative(this->values[SWAP_METER_CACHE])) { Meter_humanUnit(buffer, this->values[SWAP_METER_CACHE], sizeof(buffer)); RichString_appendAscii(out, CRT_colors[METER_TEXT], " cache:"); RichString_appendAscii(out, CRT_colors[SWAP_CACHE], buffer); } - if (!isnan(this->values[SWAP_METER_FRONTSWAP])) { + if (isNonnegative(this->values[SWAP_METER_FRONTSWAP])) { Meter_humanUnit(buffer, this->values[SWAP_METER_FRONTSWAP], sizeof(buffer)); RichString_appendAscii(out, CRT_colors[METER_TEXT], " frontswap:"); RichString_appendAscii(out, CRT_colors[SWAP_FRONTSWAP], buffer); diff --git a/XUtils.c b/XUtils.c index f54ad49f8..9b7735f66 100644 --- a/XUtils.c +++ b/XUtils.c @@ -19,6 +19,7 @@ in the source distribution for its full text. #include #include "CRT.h" +#include "Macros.h" void fail(void) { @@ -337,3 +338,15 @@ ssize_t full_write(int fd, const void* buf, size_t count) { return written; } + +/* Computes the sum of all positive floating point values in an array. + NaN values in the array are skipped. The returned sum will always be + nonnegative. */ +double sumPositiveValues(const double* array, size_t count) { + double sum = 0.0; + for (size_t i = 0; i < count; i++) { + if (isPositive(array[i])) + sum += array[i]; + } + return sum; +} diff --git a/XUtils.h b/XUtils.h index 64583db8b..68e370b0c 100644 --- a/XUtils.h +++ b/XUtils.h @@ -82,4 +82,9 @@ ssize_t xReadfileat(openat_arg_t dirfd, const char* pathname, void* buffer, size ATTR_ACCESS3_R(2, 3) ssize_t full_write(int fd, const void* buf, size_t count); +/* Computes the sum of all positive floating point values in an array. + NaN values in the array are skipped. The returned sum will always be + nonnegative. */ +double sumPositiveValues(const double* array, size_t count); + #endif diff --git a/configure.ac b/configure.ac index 8f8606c2d..cc113311a 100644 --- a/configure.ac +++ b/configure.ac @@ -203,21 +203,29 @@ AC_COMPILE_IFELSE([ CFLAGS="$old_CFLAGS" AC_MSG_CHECKING(for NaN support) -AC_RUN_IFELSE([ +dnl Note: AC_RUN_IFELSE does not try compiling the program at all when +dnl $cross_compiling is 'yes'. +AC_LINK_IFELSE([ AC_LANG_PROGRAM( [[ - #include +#include ]], [[ - double x = NAN; return !isnan(x); + double x = NAN; + /* Both should evaluate to false -> 0 (exit success) */ + return isgreater(x, x) || isgreaterequal(x, x); ]] )], - [AC_MSG_RESULT(yes)], - [ + [if test "$cross_compiling" = yes; then + AC_MSG_RESULT([assume yes (cross compiling)]) + elif ./conftest$EXEEXT >&AS_MESSAGE_LOG_FD; then + AC_MSG_RESULT(yes) + else AC_MSG_RESULT(no) - AC_MSG_WARN([Compiler does not respect NaN, some functionality might break; consider using '-fno-finite-math-only']) - ], - [AC_MSG_RESULT(skipped)]) + AC_MSG_WARN([runtime behavior with NaN is not compliant - some functionality might break; consider using '-fno-finite-math-only']) + fi], + [AC_MSG_RESULT(no) + AC_MSG_ERROR([can not find required macros: NAN, isgreater() and isgreaterequal()])]) # ---------------------------------------------------------------------- @@ -700,11 +708,6 @@ AM_CFLAGS="\ -Wunused\ -Wwrite-strings" -# FreeBSD uses C11 _Generic in its isnan implementation, even with -std=c99 -if test "$my_htop_platform" = freebsd; then - AM_CFLAGS="$AM_CFLAGS -Wno-c11-extensions" -fi - dnl https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html AC_DEFUN([AX_CHECK_COMPILE_FLAG], [ diff --git a/dragonflybsd/Platform.c b/dragonflybsd/Platform.c index 36307e931..63662990a 100644 --- a/dragonflybsd/Platform.c +++ b/dragonflybsd/Platform.c @@ -23,6 +23,7 @@ in the source distribution for its full text. #include "FileDescriptorMeter.h" #include "HostnameMeter.h" #include "LoadAverageMeter.h" +#include "Macros.h" #include "MemoryMeter.h" #include "MemorySwapMeter.h" #include "ProcessList.h" @@ -30,6 +31,7 @@ in the source distribution for its full text. #include "SysArchMeter.h" #include "TasksMeter.h" #include "UptimeMeter.h" +#include "XUtils.h" #include "dragonflybsd/DragonFlyBSDProcess.h" #include "dragonflybsd/DragonFlyBSDProcessList.h" #include "generic/fdstat_sysctl.h" @@ -193,14 +195,13 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) { v[CPU_METER_KERNEL] = cpuData->systemPercent; v[CPU_METER_IRQ] = cpuData->irqPercent; this->curItems = 4; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ]; } else { v[CPU_METER_KERNEL] = cpuData->systemAllPercent; this->curItems = 3; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL]; } - percent = isnan(percent) ? 0.0 : CLAMP(percent, 0.0, 100.0); + percent = sumPositiveValues(&v[CPU_METER_NICE], this->curItems - CPU_METER_NICE); + percent = MINIMUM(percent, 100.0); v[CPU_METER_FREQUENCY] = NAN; v[CPU_METER_TEMPERATURE] = NAN; diff --git a/freebsd/FreeBSDMachine.c b/freebsd/FreeBSDMachine.c index 26da667a2..f5d228c82 100644 --- a/freebsd/FreeBSDMachine.c +++ b/freebsd/FreeBSDMachine.c @@ -281,24 +281,21 @@ static inline void FreeBSDMachine_scanCPU(Machine* super) { // propagate frequency to all cores if only supplied for CPU 0 if (cpus > 1) { if (super->settings->showCPUTemperature) { - double maxTemp = NAN; + double maxTemp = -HUGE_VAL; for (unsigned int i = 1; i < maxcpu; i++) { - const double coreTemp = this->cpus[i].temperature; - if (isnan(coreTemp)) - continue; - - maxTemp = MAXIMUM(maxTemp, coreTemp); + if (isgreater(this->cpus[i].temperature, maxTemp)) { + maxTemp = this->cpus[i].temperature; + this->cpus[0].temperature = maxTemp; + } } - - this->cpus[0].temperature = maxTemp; } if (super->settings->showCPUFrequency) { const double coreZeroFreq = this->cpus[1].frequency; double freqSum = coreZeroFreq; - if (!isnan(coreZeroFreq)) { + if (isNonnegative(coreZeroFreq)) { for (unsigned int i = 2; i < maxcpu; i++) { - if (isnan(this->cpus[i].frequency)) + if (!isNonnegative(this->cpus[i].frequency)) this->cpus[i].frequency = coreZeroFreq; freqSum += this->cpus[i].frequency; diff --git a/generic/fdstat_sysctl.c b/generic/fdstat_sysctl.c index 49e8e362a..432114c20 100644 --- a/generic/fdstat_sysctl.c +++ b/generic/fdstat_sysctl.c @@ -43,9 +43,6 @@ static void Generic_getFileDescriptors_sysctl_internal( len = sizeof(open_fd); if (sysctlname_numfiles && sysctlbyname(sysctlname_numfiles, &open_fd, &len, NULL, 0) == 0) { *used = open_fd; - } - - if (!isnan(*used)) { return; } diff --git a/linux/HugePageMeter.c b/linux/HugePageMeter.c index ec3804eee..62f8e7eb4 100644 --- a/linux/HugePageMeter.c +++ b/linux/HugePageMeter.c @@ -80,7 +80,7 @@ static void HugePageMeter_display(const Object* cast, RichString* out) { RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer); for (unsigned i = 0; i < ARRAYSIZE(HugePageMeter_active_labels); i++) { - if (isnan(this->values[i])) { + if (!HugePageMeter_active_labels[i]) { break; } RichString_appendAscii(out, CRT_colors[METER_TEXT], HugePageMeter_active_labels[i]); diff --git a/linux/LibSensors.c b/linux/LibSensors.c index ff084b648..cbacc7ed4 100644 --- a/linux/LibSensors.c +++ b/linux/LibSensors.c @@ -200,7 +200,7 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, uns continue; /* If already set, e.g. Ryzen reporting platform temperature for each die, use the bigger one */ - if (isnan(data[tempID])) { + if (isNaN(data[tempID])) { data[tempID] = temp; if (tempID > 0) coreTempCount++; @@ -220,7 +220,7 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, uns } /* Only package temperature - copy to all cores */ - if (coreTempCount == 0 && !isnan(data[0])) { + if (coreTempCount == 0 && !isNaN(data[0])) { for (unsigned int i = 1; i <= existingCPUs; i++) data[i] = data[0]; @@ -229,22 +229,20 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, uns } /* No package temperature - set to max core temperature */ - if (isnan(data[0]) && coreTempCount != 0) { - double maxTemp = NAN; + if (coreTempCount > 0 && isNaN(data[0])) { + double maxTemp = -HUGE_VAL; for (unsigned int i = 1; i <= existingCPUs; i++) { - if (isnan(data[i])) - continue; - - maxTemp = MAXIMUM(maxTemp, data[i]); + if (isgreater(data[i], maxTemp)) { + maxTemp = data[i]; + data[0] = data[i]; + } } - data[0] = maxTemp; - /* Check for further adjustments */ } /* Only temperature for core 0, maybe Ryzen - copy to all other cores */ - if (coreTempCount == 1 && !isnan(data[1])) { + if (coreTempCount == 1 && !isNaN(data[1])) { for (unsigned int i = 2; i <= existingCPUs; i++) data[i] = data[1]; diff --git a/linux/LinuxMachine.c b/linux/LinuxMachine.c index 68b731850..21fd4bd16 100644 --- a/linux/LinuxMachine.c +++ b/linux/LinuxMachine.c @@ -27,6 +27,7 @@ in the source distribution for its full text. #include #include "Compat.h" +#include "Macros.h" #include "XUtils.h" #include "linux/LinuxMachine.h" #include "linux/Platform.h" // needed for GNU/hurd to get PATH_MAX // IWYU pragma: keep @@ -601,7 +602,7 @@ static void scanCPUFrequencyFromCPUinfo(LinuxMachine* this) { CPUData* cpuData = &(this->cpuData[cpuid + 1]); /* do not override sysfs data */ - if (isnan(cpuData->frequency)) { + if (!isNonnegative(cpuData->frequency)) { cpuData->frequency = frequency; } numCPUsWithFrequency++; diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c index b815c5b55..a4f74249b 100644 --- a/linux/LinuxProcess.c +++ b/linux/LinuxProcess.c @@ -192,6 +192,19 @@ bool LinuxProcess_changeAutogroupPriorityBy(Process* this, Arg delta) { return success; } +static double LinuxProcess_totalIORate(const LinuxProcess* lp) { + double totalRate = NAN; + if (isNonnegative(lp->io_rate_read_bps)) { + totalRate = lp->io_rate_read_bps; + if (isNonnegative(lp->io_rate_write_bps)) { + totalRate += lp->io_rate_write_bps; + } + } else if (isNonnegative(lp->io_rate_write_bps)) { + totalRate = lp->io_rate_write_bps; + } + return totalRate; +} + static void LinuxProcess_writeField(const Process* this, RichString* str, ProcessField field) { const LinuxProcess* lp = (const LinuxProcess*) this; const LinuxMachine* lhost = (const LinuxMachine*) this->host; @@ -230,19 +243,7 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces case CNCLWB: Process_printBytes(str, lp->io_cancelled_write_bytes, coloring); return; case IO_READ_RATE: Process_printRate(str, lp->io_rate_read_bps, coloring); return; case IO_WRITE_RATE: Process_printRate(str, lp->io_rate_write_bps, coloring); return; - case IO_RATE: { - double totalRate; - if (!isnan(lp->io_rate_read_bps) && !isnan(lp->io_rate_write_bps)) - totalRate = lp->io_rate_read_bps + lp->io_rate_write_bps; - else if (!isnan(lp->io_rate_read_bps)) - totalRate = lp->io_rate_read_bps; - else if (!isnan(lp->io_rate_write_bps)) - totalRate = lp->io_rate_write_bps; - else - totalRate = NAN; - Process_printRate(str, totalRate, coloring); - return; - } + case IO_RATE: Process_printRate(str, LinuxProcess_totalIORate(lp), coloring); return; #ifdef HAVE_OPENVZ case CTID: xSnprintf(buffer, n, "%-8s ", lp->ctid ? lp->ctid : ""); break; case VPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, lp->vpid); break; @@ -309,11 +310,13 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces RichString_appendAscii(str, attr, buffer); } -static double adjustNaN(double num) { - if (isnan(num)) - return -0.0005; - - return num; +static int compareRealNumbers(double a, double b) { + // NaN is considered "less than" any real float value in this function. + // Two NaNs are considered "equal" here. + int result = (int)isgreater(a, b) - isgreater(b, a); + if (result) + return result; + return (int)!isNaN(a) - !isNaN(b); } static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) { @@ -358,11 +361,11 @@ static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, Proce case CNCLWB: return SPACESHIP_NUMBER(p1->io_cancelled_write_bytes, p2->io_cancelled_write_bytes); case IO_READ_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_read_bps), adjustNaN(p2->io_rate_read_bps)); + return compareRealNumbers(p1->io_rate_read_bps, p2->io_rate_read_bps); case IO_WRITE_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_write_bps), adjustNaN(p2->io_rate_write_bps)); + return compareRealNumbers(p1->io_rate_write_bps, p2->io_rate_write_bps); case IO_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_read_bps) + adjustNaN(p1->io_rate_write_bps), adjustNaN(p2->io_rate_read_bps) + adjustNaN(p2->io_rate_write_bps)); + return compareRealNumbers(LinuxProcess_totalIORate(p1), LinuxProcess_totalIORate(p2)); #ifdef HAVE_OPENVZ case CTID: return SPACESHIP_NULLSTR(p1->ctid, p2->ctid); diff --git a/pcp/PCPProcess.c b/pcp/PCPProcess.c index 5e025a1cd..382d3927e 100644 --- a/pcp/PCPProcess.c +++ b/pcp/PCPProcess.c @@ -111,6 +111,19 @@ static void PCPProcess_printDelay(float delay_percent, char* buffer, size_t n) { } } +static double PCPProcess_totalIORate(const PCPProcess* pp) { + double totalRate = NAN; + if (isNonnegative(pp->io_rate_read_bps)) { + totalRate = pp->io_rate_read_bps; + if (isNonnegative(pp->io_rate_write_bps)) { + totalRate += pp->io_rate_write_bps; + } + } else if (isNonnegative(pp->io_rate_write_bps)) { + totalRate = pp->io_rate_write_bps; + } + return totalRate; +} + static void PCPProcess_writeField(const Process* this, RichString* str, ProcessField field) { const PCPProcess* pp = (const PCPProcess*) this; bool coloring = this->host->settings->highlightMegabytes; @@ -141,19 +154,7 @@ static void PCPProcess_writeField(const Process* this, RichString* str, ProcessF case CNCLWB: Process_printBytes(str, pp->io_cancelled_write_bytes, coloring); return; case IO_READ_RATE: Process_printRate(str, pp->io_rate_read_bps, coloring); return; case IO_WRITE_RATE: Process_printRate(str, pp->io_rate_write_bps, coloring); return; - case IO_RATE: { - double totalRate = NAN; - if (!isnan(pp->io_rate_read_bps) && !isnan(pp->io_rate_write_bps)) - totalRate = pp->io_rate_read_bps + pp->io_rate_write_bps; - else if (!isnan(pp->io_rate_read_bps)) - totalRate = pp->io_rate_read_bps; - else if (!isnan(pp->io_rate_write_bps)) - totalRate = pp->io_rate_write_bps; - else - totalRate = NAN; - Process_printRate(str, totalRate, coloring); - return; - } + case IO_RATE: Process_printRate(str, PCPProcess_totalIORate(pp), coloring); return; case CGROUP: xSnprintf(buffer, n, "%-10s ", pp->cgroup ? pp->cgroup : ""); break; case OOM: xSnprintf(buffer, n, "%4u ", pp->oom); break; case PERCENT_CPU_DELAY: @@ -198,11 +199,13 @@ static void PCPProcess_writeField(const Process* this, RichString* str, ProcessF RichString_appendWide(str, attr, buffer); } -static double adjustNaN(double num) { - if (isnan(num)) - return -0.0005; - - return num; +static int compareRealNumbers(double a, double b) { + // NaN is considered "less than" any real float value in this function. + // Two NaNs are considered "equal" here. + int result = (int)isgreater(a, b) - isgreater(b, a); + if (result) + return result; + return (int)!isNaN(a) - !isNaN(b); } static int PCPProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) { @@ -249,11 +252,11 @@ static int PCPProcess_compareByKey(const Process* v1, const Process* v2, Process case CNCLWB: return SPACESHIP_NUMBER(p1->io_cancelled_write_bytes, p2->io_cancelled_write_bytes); case IO_READ_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_read_bps), adjustNaN(p2->io_rate_read_bps)); + return compareRealNumbers(p1->io_rate_read_bps, p2->io_rate_read_bps); case IO_WRITE_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_write_bps), adjustNaN(p2->io_rate_write_bps)); + return compareRealNumbers(p1->io_rate_write_bps, p2->io_rate_write_bps); case IO_RATE: - return SPACESHIP_NUMBER(adjustNaN(p1->io_rate_read_bps) + adjustNaN(p1->io_rate_write_bps), adjustNaN(p2->io_rate_read_bps) + adjustNaN(p2->io_rate_write_bps)); + return compareRealNumbers(PCPProcess_totalIORate(p1), PCPProcess_totalIORate(p2)); case CGROUP: return SPACESHIP_NULLSTR(p1->cgroup, p2->cgroup); case OOM: diff --git a/solaris/Platform.c b/solaris/Platform.c index 95c50b4d7..182bc033a 100644 --- a/solaris/Platform.c +++ b/solaris/Platform.c @@ -34,6 +34,7 @@ in the source distribution for its full text. #include "HostnameMeter.h" #include "SysArchMeter.h" #include "UptimeMeter.h" +#include "XUtils.h" #include "solaris/SolarisMachine.h" @@ -221,14 +222,13 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) { v[CPU_METER_KERNEL] = cpuData->systemPercent; v[CPU_METER_IRQ] = cpuData->irqPercent; this->curItems = 4; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ]; } else { v[CPU_METER_KERNEL] = cpuData->systemAllPercent; this->curItems = 3; - percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL]; } - percent = isnan(percent) ? 0.0 : CLAMP(percent, 0.0, 100.0); + percent = sumPositiveValues(&v[CPU_METER_NICE], this->curItems - CPU_METER_NICE); + percent = MINIMUM(percent, 100.0); v[CPU_METER_FREQUENCY] = cpuData->frequency; v[CPU_METER_TEMPERATURE] = NAN;