summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorExplorer09 <explorer09@gmail.com>2023-07-29 16:24:12 +0800
committerBenBE <BenBE@geshi.org>2023-08-18 12:52:28 +0200
commitb416433fbe7ccf935ad4e268396aa423143c2318 (patch)
tree55a38c76f4f0091ed6b06d7369706bd2f1f6f61e
parentc6fd64fce8502a4e557711abe9fee394763ac52c (diff)
Replace isnan() with better comparisons (isgreater(), etc.)
The standard isnan() function is defined to never throw FP exceptions even when the argument is a "signaling" NaN. This makes isnan() more expensive than (x != x) expression unless the compiler flag '-fno-signaling-nans' is given. Introduce functions isNaN(), isNonnegative(), isPositive(), sumPositiveValues() and compareRealNumbers(), and replace isnan() in htop's codebase with the new functions. These functions utilize isgreater() and isgreaterequal() comparisons, which do not throw FP exceptions on "quiet" NaNs, which htop uses extensively. With isnan() removed, there is no need to suppress the warning '-Wno-c11-extensions' in FreeBSD. Remove the code from 'configure.ac'. Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
-rw-r--r--BatteryMeter.c3
-rw-r--r--CPUMeter.c26
-rw-r--r--FileDescriptorMeter.c11
-rw-r--r--Macros.h20
-rw-r--r--MemoryMeter.c10
-rw-r--r--Meter.c5
-rw-r--r--Process.c4
-rw-r--r--SwapMeter.c5
-rw-r--r--XUtils.c13
-rw-r--r--XUtils.h5
-rw-r--r--configure.ac42
-rw-r--r--dragonflybsd/Platform.c7
-rw-r--r--freebsd/FreeBSDMachine.c17
-rw-r--r--generic/fdstat_sysctl.c3
-rw-r--r--linux/HugePageMeter.c2
-rw-r--r--linux/LibSensors.c20
-rw-r--r--linux/LinuxMachine.c3
-rw-r--r--linux/LinuxProcess.c46
-rw-r--r--linux/Platform.c25
-rw-r--r--pcp/PCPProcess.c52
-rw-r--r--pcp/Platform.c20
-rw-r--r--solaris/Platform.c6
22 files changed, 204 insertions, 141 deletions
diff --git a/BatteryMeter.c b/BatteryMeter.c
index 33d17b73..24b2e682 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 <math.h>
#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 a946aa7d..c12bb72c 100644
--- a/CPUMeter.c
+++ b/CPUMeter.c
@@ -9,11 +9,11 @@ in the source distribution for its full text.
#include "CPUMeter.h"
-#include <math.h>
#include <stdlib.h>
#include <string.h>
#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 2d939d66..92dc99ae 100644
--- a/FileDescriptorMeter.c
+++ b/FileDescriptorMeter.c
@@ -12,6 +12,7 @@ in the source distribution for its full text.
#include <string.h>
#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 0f95347b..459102a3 100644
--- a/Macros.h
+++ b/Macros.h
@@ -2,6 +2,8 @@
#define HEADER_Macros
#include <assert.h> // IWYU pragma: keep
+#include <math.h>
+#include <stdbool.h>
#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 28c0be27..c7d99f88 100644
--- a/MemoryMeter.c
+++ b/MemoryMeter.c
@@ -11,6 +11,7 @@ in the source distribution for its full text.
#include <stddef.h>
#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 cf0fe36a..27e4cd0c 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 57763b86..7e2d11af 100644
--- a/Process.c
+++ b/Process.c
@@ -757,7 +757,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);
@@ -790,7 +790,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 84e58a26..1055a6e7 100644
--- a/SwapMeter.c
+++ b/SwapMeter.c
@@ -13,6 +13,7 @@ in the source distribution for its full text.
#include <stddef.h>
#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 f54ad49f..9b7735f6 100644
--- a/XUtils.c
+++ b/XUtils.c
@@ -19,6 +19,7 @@ in the source distribution for its full text.
#include <unistd.h>
#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 64583db8..68e370b0 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 8f8606c2..07c3ee85 100644
--- a/configure.ac
+++ b/configure.ac
@@ -203,21 +203,42 @@ 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 <math.h>
+#include <math.h>
]],
[[
- 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)],
- [
+ [flag_finite_math_only=unknown
+ if test "$cross_compiling" = yes; then
+ AC_COMPILE_IFELSE([
+ AC_LANG_SOURCE([[
+/* __FINITE_MATH_ONLY__ is documented in Clang. */
+#ifdef __FINITE_MATH_ONLY__
+#error "should not enable -ffinite-math-only"
+#endif
+ ]])],
+ AC_MSG_RESULT([assume yes (cross compiling)]),
+ flag_finite_math_only=yes)
+ elif ./conftest$EXEEXT >&AS_MESSAGE_LOG_FD; then
+ flag_finite_math_only=no
+ AC_MSG_RESULT(yes)
+ else
+ flag_finite_math_only=yes
+ fi
+ if test "$flag_finite_math_only" = yes; then
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 +721,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 36307e93..51d89467 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, this->curItems);
+ 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 26da667a..f5d228c8 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 49e8e362..432114c2 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 ec3804ee..62f8e7eb 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 cd24b797..891dd01a 100644
--- a/linux/LibSensors.c
+++ b/linux/LibSensors.c
@@ -202,7 +202,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++;
@@ -222,7 +222,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];
@@ -231,22 +231,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 68b73185..21fd4bd1 100644
--- a/linux/LinuxMachine.c
+++ b/linux/LinuxMachine.c
@@ -27,6 +27,7 @@ in the source distribution for its full text.
#include <time.h>
#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 b815c5b5..0a88644c 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,14 @@ 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;
+/* Compares floating point values for ordering data entries. In this function,
+ NaN is considered "less than" any other floating point value (regardless of
+ sign), and two NaNs are considered "equal" regardless of payload. */
+static int compareRealNumbers(double a, double b) {
+ int result = isgreater(a, b) - isgreater(b, a);
+ if (result)
+ return result;
+ return !isNaN(a) - !isNaN(b);
}
static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
@@ -358,11 +362,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/linux/Platform.c b/linux/Platform.c
index e0b633ba..c81b3697 100644
--- a/linux/Platform.c
+++ b/linux/Platform.c
@@ -322,23 +322,26 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
v[CPU_METER_KERNEL] = cpuData->systemPeriod / total * 100.0;
v[CPU_METER_IRQ] = cpuData->irqPeriod / total * 100.0;
v[CPU_METER_SOFTIRQ] = cpuData->softIrqPeriod / total * 100.0;
+ this->curItems = 5;
+
v[CPU_METER_STEAL] = cpuData->stealPeriod / total * 100.0;
v[CPU_METER_GUEST] = cpuData->guestPeriod / total * 100.0;
- v[CPU_METER_IOWAIT] = cpuData->ioWaitPeriod / total * 100.0;
- this->curItems = 8;
- percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ] + v[CPU_METER_SOFTIRQ];
if (settings->accountGuestInCPUMeter) {
- percent += v[CPU_METER_STEAL] + v[CPU_METER_GUEST];
+ this->curItems = 7;
}
+
+ v[CPU_METER_IOWAIT] = cpuData->ioWaitPeriod / total * 100.0;
} else {
v[CPU_METER_KERNEL] = cpuData->systemAllPeriod / total * 100.0;
v[CPU_METER_IRQ] = (cpuData->stealPeriod + cpuData->guestPeriod) / total * 100.0;
this->curItems = 4;
- percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ];
}
- percent = CLAMP(percent, 0.0, 100.0);
- if (isnan(percent)) {
- percent = 0.0;
+
+ percent = sumPositiveValues(v, this->curItems);
+ percent = MINIMUM(percent, 100.0);
+
+ if (settings->detailedCPUTime) {
+ this->curItems = 8;
}
v[CPU_METER_FREQUENCY] = cpuData->frequency;
@@ -842,7 +845,7 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
}
}
- if (!now && full && !isnan(capacityLevel))
+ if (!now && full && isNonnegative(capacityLevel))
totalRemain += capacityLevel * fullCharge;
} else if (type == AC) {
@@ -882,12 +885,12 @@ void Platform_getBattery(double* percent, ACPresence* isOnAC) {
if (Platform_Battery_method == BAT_PROC) {
Platform_Battery_getProcData(percent, isOnAC);
- if (isnan(*percent))
+ if (!isNonnegative(*percent))
Platform_Battery_method = BAT_SYS;
}
if (Platform_Battery_method == BAT_SYS) {
Platform_Battery_getSysData(percent, isOnAC);
- if (isnan(*percent))
+ if (!isNonnegative(*percent))
Platform_Battery_method = BAT_ERR;
}
if (Platform_Battery_method == BAT_ERR) {
diff --git a/pcp/PCPProcess.c b/pcp/PCPProcess.c
index 5e025a1c..2cb27814 100644
--- a/pcp/PCPProcess.c
+++ b/pcp/PCPProcess.c
@@ -104,13 +104,26 @@ void Process_delete(Object* cast) {
}
static void PCPProcess_printDelay(float delay_percent, char* buffer, size_t n) {
- if (isnan(delay_percent)) {
- xSnprintf(buffer, n, " N/A ");
- } else {
+ if (isNonnegative(delay_percent)) {
xSnprintf(buffer, n, "%4.1f ", delay_percent);
+ } else {
+ xSnprintf(buffer, n, " N/A ");
}
}
+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,14 @@ 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;
+/* Compares floating point values for ordering data entries. In this function,
+ NaN is considered "less than" any other floating point value (regardless of
+ sign), and two NaNs are considered "equal" regardless of payload. */
+static int compareRealNumbers(double a, double b) {
+ int result = isgreater(a, b) - isgreater(b, a);
+ if (result)
+ return result;
+ return !isNaN(a) - !isNaN(b);
}
static int PCPProcess_compareByKey(const Process* v1, const Process* v2, ProcessField key) {
@@ -249,11 +253,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/pcp/Platform.c b/pcp/Platform.c
index 12e0f4d7..13746fc2 100644
--- a/pcp/Platform.c
+++ b/pcp/Platform.c
@@ -497,24 +497,28 @@ static double Platform_setOneCPUValues(Meter* this, const Settings* settings, pm
v[CPU_METER_KERNEL] = values[CPU_SYSTEM_PERIOD].ull / total * 100.0;
v[CPU_METER_IRQ] = values[CPU_IRQ_PERIOD].ull / total * 100.0;
v[CPU_METER_SOFTIRQ] = values[CPU_SOFTIRQ_PERIOD].ull / total * 100.0;
+ this->curItems = 5;
+
v[CPU_METER_STEAL] = values[CPU_STEAL_PERIOD].ull / total * 100.0;
v[CPU_METER_GUEST] = values[CPU_GUEST_PERIOD].ull / total * 100.0;
- v[CPU_METER_IOWAIT] = values[CPU_IOWAIT_PERIOD].ull / total * 100.0;
- this->curItems = 8;
- percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ] + v[CPU_METER_SOFTIRQ];
if (settings->accountGuestInCPUMeter) {
- percent += v[CPU_METER_STEAL] + v[CPU_METER_GUEST];
+ this->curItems = 7;
}
+
+ v[CPU_METER_IOWAIT] = values[CPU_IOWAIT_PERIOD].ull / total * 100.0;
} else {
v[CPU_METER_KERNEL] = values[CPU_SYSTEM_ALL_PERIOD].ull / total * 100.0;
value = values[CPU_STEAL_PERIOD].ull + values[CPU_GUEST_PERIOD].ull;
v[CPU_METER_IRQ] = value / total * 100.0;
this->curItems = 4;
- percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ];
}
- percent = CLAMP(percent, 0.0, 100.0);
- if (isnan(percent))
- percent = 0.0;
+
+ percent = sumPositiveValues(v, this->curItems);
+ percent = MINIMUM(percent, 100.0);
+
+ if (settings->detailedCPUTime) {
+ this->curItems = 8;
+ }
v[CPU_METER_FREQUENCY] = values[CPU_FREQUENCY].d;
v[CPU_METER_TEMPERATURE] = NAN;
diff --git a/solaris/Platform.c b/solaris/Platform.c
index 95c50b4d..f14ae2e9 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, this->curItems);
+ percent = MINIMUM(percent, 100.0);
v[CPU_METER_FREQUENCY] = cpuData->frequency;
v[CPU_METER_TEMPERATURE] = NAN;

© 2014-2024 Faster IT GmbH | imprint | privacy policy