Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace isnan() with better comparisons (isgreater(), etc.) #1271

Merged
merged 7 commits into from
Aug 18, 2023
3 changes: 2 additions & 1 deletion BatteryMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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;
Expand Down
26 changes: 13 additions & 13 deletions CPUMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down
11 changes: 6 additions & 5 deletions FileDescriptorMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ 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"
#include "RichString.h"
#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,
Expand Down Expand Up @@ -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]);
Expand All @@ -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;
}
Expand All @@ -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]);
Expand Down
20 changes: 20 additions & 0 deletions Macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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) {
BenBE marked this conversation as resolved.
Show resolved Hide resolved
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;
Expand Down
10 changes: 5 additions & 5 deletions MemoryMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down
5 changes: 1 addition & 4 deletions Meter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
8 changes: 4 additions & 4 deletions Process.c
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,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);
Expand Down Expand Up @@ -791,8 +791,8 @@ void Process_printLeftAlignedField(RichString* str, int attr, const char* conten
RichString_appendChr(str, attr, ' ', width + 1 - columns);
}

void Process_printPercentage(float val, char* buffer, int n, uint8_t width, int* attr) {
if (val >= 0) {
void Process_printPercentage(float val, char* buffer, size_t n, uint8_t width, int* attr) {
if (isNonnegative(val)) {
BenBE marked this conversation as resolved.
Show resolved Hide resolved
if (val < 0.05F)
*attr = CRT_colors[PROCESS_SHADOW];
else if (val >= 99.9F)
Expand Down Expand Up @@ -1184,7 +1184,7 @@ int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField
switch (key) {
case PERCENT_CPU:
case PERCENT_NORM_CPU:
return SPACESHIP_NUMBER(p1->percent_cpu, p2->percent_cpu);
return compareRealNumbers(p1->percent_cpu, p2->percent_cpu);
case PERCENT_MEM:
return SPACESHIP_NUMBER(p1->m_resident, p2->m_resident);
case COMM:
Expand Down
2 changes: 1 addition & 1 deletion Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ void Process_fillStarttimeBuffer(Process* this);

void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width);

void Process_printPercentage(float val, char* buffer, int n, uint8_t width, int* attr);
void Process_printPercentage(float val, char* buffer, size_t n, uint8_t width, int* attr);

void Process_display(const Object* cast, RichString* out);

Expand Down
5 changes: 3 additions & 2 deletions SwapMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions XUtils.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ in the source distribution for its full text.
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "CRT.h"
#include "Macros.h"


void fail(void) {
Expand Down Expand Up @@ -337,3 +339,25 @@ ssize_t full_write(int fd, const void* buf, size_t count) {

return written;
}

/* 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. */
int compareRealNumbers(double a, double b) {
int result = isgreater(a, b) - isgreater(b, a);
if (result)
return result;
return !isNaN(a) - !isNaN(b);
}

/* 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;
}
10 changes: 10 additions & 0 deletions XUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,14 @@ 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);

/* 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. */
int compareRealNumbers(double a, double b);

/* 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
Loading