Skip to content

Commit f9d0cdc

Browse files
committed
Add configurable SI decimal vs IEC binary unit prefixes
1 parent dd9d7b1 commit f9d0cdc

12 files changed

Lines changed: 76 additions & 42 deletions

DiskIOMeter.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ in the source distribution for its full text.
1414
#include "CRT.h"
1515
#include "Machine.h"
1616
#include "Macros.h"
17+
#include "Meter.h"
1718
#include "Object.h"
1819
#include "Platform.h"
1920
#include "RichString.h"
2021
#include "Row.h"
22+
#include "Settings.h"
2123
#include "XUtils.h"
2224

2325

@@ -40,6 +42,7 @@ static double cached_read_diff;
4042
static char cached_read_diff_str[6];
4143
static double cached_write_diff;
4244
static char cached_write_diff_str[6];
45+
static const char* cached_disk_unit_suffix = "iB/s";
4346
static uint64_t cached_num_disks;
4447
static double cached_utilisation_diff;
4548
static double cached_utilisation_norm;
@@ -75,6 +78,7 @@ static void DiskIOUpdateCache(const Machine* host) {
7578
static uint64_t cached_msTimeSpend_total;
7679

7780
if (status != RATESTATUS_INIT) {
81+
const bool decimal = host->settings->decimalUnits;
7882
uint64_t diff;
7983

8084
if (data.totalBytesRead > cached_read_total) {
@@ -84,7 +88,7 @@ static void DiskIOUpdateCache(const Machine* host) {
8488
diff = 0;
8589
}
8690
cached_read_diff = diff;
87-
Meter_humanUnit(cached_read_diff_str, cached_read_diff / ONE_K, sizeof(cached_read_diff_str));
91+
cached_disk_unit_suffix = Meter_ioRateUnit(cached_read_diff_str, sizeof(cached_read_diff_str), cached_read_diff, decimal);
8892

8993
if (data.totalBytesWritten > cached_write_total) {
9094
diff = data.totalBytesWritten - cached_write_total;
@@ -93,7 +97,7 @@ static void DiskIOUpdateCache(const Machine* host) {
9397
diff = 0;
9498
}
9599
cached_write_diff = diff;
96-
Meter_humanUnit(cached_write_diff_str, cached_write_diff / ONE_K, sizeof(cached_write_diff_str));
100+
Meter_ioRateUnit(cached_write_diff_str, sizeof(cached_write_diff_str), cached_write_diff, decimal);
97101

98102
cached_num_disks = data.numDisks;
99103
cached_utilisation_diff = 0.0;
@@ -133,7 +137,7 @@ static void DiskIORateMeter_updateValues(Meter* this) {
133137
break;
134138
}
135139

136-
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "r:%siB/s w:%siB/s", cached_read_diff_str, cached_write_diff_str);
140+
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "r:%s%s w:%s%s", cached_read_diff_str, cached_disk_unit_suffix, cached_write_diff_str, cached_disk_unit_suffix);
137141
}
138142

139143
static void DiskIORateMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
@@ -153,11 +157,11 @@ static void DiskIORateMeter_display(ATTR_UNUSED const Object* cast, RichString*
153157

154158
RichString_appendAscii(out, CRT_colors[METER_TEXT], "read: ");
155159
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], cached_read_diff_str);
156-
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");
160+
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], cached_disk_unit_suffix);
157161

158162
RichString_appendAscii(out, CRT_colors[METER_TEXT], " write: ");
159163
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], cached_write_diff_str);
160-
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
164+
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], cached_disk_unit_suffix);
161165
}
162166

163167
static void DiskIOTimeMeter_updateValues(Meter* this) {

DisplayOptionsPanel.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager*
314314
Panel_add(super, (Object*) CheckItem_newByRef("Highlight new and old processes", &(settings->highlightChanges)));
315315
Panel_add(super, (Object*) NumberItem_newByRef("- Highlight time (in seconds)", &(settings->highlightDelaySecs), 0, 1, 24 * 60 * 60));
316316
Panel_add(super, (Object*) NumberItem_newByRef("Hide main function bar (0 - off, 1 - on ESC until next input, 2 - permanently)", &(settings->hideFunctionBar), 0, 0, 2));
317+
Panel_add(super, (Object*) CheckItem_newByRef("Display I/O rates in decimal SI units (KB/s, MB/s, GB/s) instead of binary IEC (KiB/s, MiB/s, GiB/s)", &(settings->decimalUnits)));
317318
#ifdef HAVE_LIBHWLOC
318319
Panel_add(super, (Object*) CheckItem_newByRef("Show topology when selecting affinity by default", &(settings->topologyAffinity)));
319320
#endif

Meter.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,25 @@ int Meter_humanUnit(char* buffer, double value, size_t size) {
504504
return xSnprintf(buffer, size, "%.*f%c", precision, value, unitPrefixes[i]);
505505
}
506506

507+
const char* Meter_ioRateUnit(char* buffer, size_t size, double bytesPerSec, bool decimal) {
508+
if (!decimal) {
509+
Meter_humanUnit(buffer, bytesPerSec / ONE_K, size);
510+
return "iB/s";
511+
}
512+
513+
double val = bytesPerSec / ONE_DECIMAL_K;
514+
size_t i = 0;
515+
while (val >= ONE_DECIMAL_K && i < ARRAYSIZE(unitPrefixes) - 1) {
516+
val /= ONE_DECIMAL_K;
517+
++i;
518+
}
519+
int precision = 0;
520+
if (i > 0)
521+
precision = val <= 99.9 ? (val <= 9.99 ? 2 : 1) : 0;
522+
xSnprintf(buffer, size, "%.*f%c", precision, val, unitPrefixes[i]);
523+
return "B/s";
524+
}
525+
507526
void Meter_delete(Object* cast) {
508527
if (!cast)
509528
return;

Meter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ Meter* Meter_new(const Machine* host, unsigned int param, const MeterClass* type
143143
Example output strings: "0K", "1023K", "98.7M" and "1.23G" */
144144
int Meter_humanUnit(char* buffer, double value, size_t size);
145145

146+
/* Formats 'bytesPerSec' into a string and returns the unit suffix
147+
("iB/s" for IEC binary, "B/s" for SI decimal). */
148+
const char* Meter_ioRateUnit(char* buffer, size_t size, double bytesPerSec, bool decimal);
149+
146150
void Meter_delete(Object* cast);
147151

148152
void Meter_setCaption(Meter* this, const char* caption);

NetworkIOMeter.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ in the source distribution for its full text.
1919
#include "Platform.h"
2020
#include "RichString.h"
2121
#include "Row.h"
22+
#include "Settings.h"
2223
#include "XUtils.h"
2324

2425

@@ -34,6 +35,7 @@ static uint32_t cached_rxp_diff;
3435
static double cached_txb_diff;
3536
static char cached_txb_diff_str[6];
3637
static uint32_t cached_txp_diff;
38+
static const char* cached_unit_suffix = "iB/s";
3739

3840
static void NetworkIOMeter_updateValues(Meter* this) {
3941
const Machine* host = this->host;
@@ -66,6 +68,7 @@ static void NetworkIOMeter_updateValues(Meter* this) {
6668
static uint64_t cached_txp_total;
6769

6870
if (status != RATESTATUS_INIT) {
71+
const bool decimal = host->settings->decimalUnits;
6972
uint64_t diff;
7073

7174
if (data.bytesReceived > cached_rxb_total) {
@@ -75,7 +78,7 @@ static void NetworkIOMeter_updateValues(Meter* this) {
7578
} else {
7679
cached_rxb_diff = 0;
7780
}
78-
Meter_humanUnit(cached_rxb_diff_str, cached_rxb_diff / ONE_K, sizeof(cached_rxb_diff_str));
81+
cached_unit_suffix = Meter_ioRateUnit(cached_rxb_diff_str, sizeof(cached_rxb_diff_str), cached_rxb_diff, decimal);
7982

8083
if (data.packetsReceived > cached_rxp_total) {
8184
diff = data.packetsReceived - cached_rxp_total;
@@ -92,7 +95,7 @@ static void NetworkIOMeter_updateValues(Meter* this) {
9295
} else {
9396
cached_txb_diff = 0;
9497
}
95-
Meter_humanUnit(cached_txb_diff_str, cached_txb_diff / ONE_K, sizeof(cached_txb_diff_str));
98+
Meter_ioRateUnit(cached_txb_diff_str, sizeof(cached_txb_diff_str), cached_txb_diff, decimal);
9699

97100
if (data.packetsTransmitted > cached_txp_total) {
98101
diff = data.packetsTransmitted - cached_txp_total;
@@ -125,8 +128,8 @@ static void NetworkIOMeter_updateValues(Meter* this) {
125128
return;
126129
}
127130

128-
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "rx:%siB/s tx:%siB/s (%u/%upps)",
129-
cached_rxb_diff_str, cached_txb_diff_str, cached_rxp_diff, cached_txp_diff);
131+
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "rx:%s%s tx:%s%s (%u/%upps)",
132+
cached_rxb_diff_str, cached_unit_suffix, cached_txb_diff_str, cached_unit_suffix, cached_rxp_diff, cached_txp_diff);
130133
}
131134

132135
static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
@@ -148,11 +151,11 @@ static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* o
148151

149152
RichString_writeAscii(out, CRT_colors[METER_TEXT], "rx: ");
150153
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], cached_rxb_diff_str);
151-
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");
154+
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], cached_unit_suffix);
152155

153156
RichString_appendAscii(out, CRT_colors[METER_TEXT], " tx: ");
154157
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], cached_txb_diff_str);
155-
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
158+
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], cached_unit_suffix);
156159

157160
RichString_appendAscii(out, CRT_colors[METER_TEXT], " (");
158161
int len = xSnprintf(buffer, sizeof(buffer), "%u", (unsigned int)cached_rxp_diff);

Row.c

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ void Row_printNanoseconds(RichString* str, unsigned long long totalNanoseconds,
459459
Row_printTime(str, totalHundredths, coloring);
460460
}
461461

462-
void Row_printRate(RichString* str, double rate, bool coloring) {
462+
void Row_printRate(RichString* str, double rate, bool coloring, bool decimal) {
463463
char buffer[16];
464464

465465
int largeNumberColor = CRT_colors[LARGE_NUMBER];
@@ -474,28 +474,26 @@ void Row_printRate(RichString* str, double rate, bool coloring) {
474474

475475
if (!isNonnegative(rate)) {
476476
RichString_appendAscii(str, shadowColor, " N/A ");
477-
} else if (rate < 0.005) {
478-
int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate);
479-
RichString_appendnAscii(str, shadowColor, buffer, len);
480-
} else if (rate < ONE_K) {
481-
int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate);
482-
RichString_appendnAscii(str, baseColor, buffer, len);
483-
} else if (rate < ONE_M) {
484-
int len = snprintf(buffer, sizeof(buffer), "%7.2f K/s ", rate / ONE_K);
485-
RichString_appendnAscii(str, baseColor, buffer, len);
486-
} else if (rate < ONE_G) {
487-
int len = snprintf(buffer, sizeof(buffer), "%7.2f M/s ", rate / ONE_M);
488-
RichString_appendnAscii(str, megabytesColor, buffer, len);
489-
} else if (rate < ONE_T) {
490-
int len = snprintf(buffer, sizeof(buffer), "%7.2f G/s ", rate / ONE_G);
491-
RichString_appendnAscii(str, largeNumberColor, buffer, len);
492-
} else if (rate < ONE_P) {
493-
int len = snprintf(buffer, sizeof(buffer), "%7.2f T/s ", rate / ONE_T);
494-
RichString_appendnAscii(str, largeNumberColor, buffer, len);
495-
} else {
496-
int len = snprintf(buffer, sizeof(buffer), "%7.2f P/s ", rate / ONE_P);
497-
RichString_appendnAscii(str, largeNumberColor, buffer, len);
477+
return;
498478
}
479+
480+
static const char prefixes[] = { 'B', 'K', 'M', 'G', 'T', 'P' };
481+
const int colors[ARRAYSIZE(prefixes)] = {
482+
baseColor, baseColor, megabytesColor,
483+
largeNumberColor, largeNumberColor, largeNumberColor
484+
};
485+
486+
const double base = decimal ? ONE_DECIMAL_K : ONE_K;
487+
size_t i = 0;
488+
double scaled = rate;
489+
while (scaled >= base && i + 1 < ARRAYSIZE(prefixes)) {
490+
scaled /= base;
491+
i++;
492+
}
493+
494+
int color = (rate < 0.005) ? shadowColor : colors[i];
495+
int len = snprintf(buffer, sizeof(buffer), "%7.2f %c/s ", scaled, prefixes[i]);
496+
RichString_appendnAscii(str, color, buffer, len);
499497
}
500498

501499
void Row_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width) {

Row.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ void Row_printTime(RichString* str, unsigned long long totalHundredths, bool col
157157
/* Takes time in nanoseconds. Prints 9 columns. */
158158
void Row_printNanoseconds(RichString* str, unsigned long long totalNanoseconds, bool coloring);
159159

160-
/* Takes rate in bare unit (base 1024) per second. Prints 12 columns. */
161-
void Row_printRate(RichString* str, double rate, bool coloring);
160+
/* Takes rate in bytes per second. Uses base 1000 (SI) when 'decimal', else base 1024 (IEC). Prints 12 columns. */
161+
void Row_printRate(RichString* str, double rate, bool coloring, bool decimal);
162162

163163
int Row_printPercentage(float val, char* buffer, size_t n, uint8_t width, int* attr);
164164

Settings.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,8 @@ static bool Settings_read(Settings* this, const char* fileName, const Machine* h
523523
didReadMeters = true;
524524
} else if (String_eq(option[0], "hide_function_bar")) {
525525
this->hideFunctionBar = atoi(option[1]);
526+
} else if (String_eq(option[0], "decimal_units")) {
527+
this->decimalUnits = !!atoi(option[1]);
526528
#ifdef HAVE_LIBHWLOC
527529
} else if (String_eq(option[0], "topology_affinity")) {
528530
this->topologyAffinity = !!atoi(option[1]);
@@ -723,6 +725,7 @@ int Settings_write(const Settings* this, bool onCrash) {
723725
#endif
724726
printSettingInteger("delay", (int) this->delay);
725727
printSettingInteger("hide_function_bar", (int) this->hideFunctionBar);
728+
printSettingInteger("decimal_units", this->decimalUnits);
726729
#ifdef HAVE_LIBHWLOC
727730
printSettingInteger("topology_affinity", this->topologyAffinity);
728731
#endif
@@ -873,6 +876,7 @@ Settings* Settings_new(const Machine* host, Hashtable* dynamicMeters, Hashtable*
873876
free_and_xStrdup(&this->filename, this->initialFilename);
874877

875878
this->colorScheme = 0;
879+
this->decimalUnits = false;
876880
#ifdef HAVE_GETMOUSE
877881
this->enableMouse = true;
878882
#endif

Settings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ typedef struct Settings_ {
107107
bool enableMouse;
108108
#endif
109109
int hideFunctionBar; // 0 - off, 1 - on ESC until next input, 2 - permanently
110+
bool decimalUnits; // I/O rates: false = IEC binary (KiB/s, ...), true = SI decimal (KB/s, ...)
110111
#ifdef HAVE_LIBHWLOC
111112
bool topologyAffinity;
112113
#endif

linux/LinuxProcess.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,9 @@ static void LinuxProcess_rowWriteField(const Row* super, RichString* str, Proces
274274
case RBYTES: Row_printBytes(str, lp->io_read_bytes, coloring); return;
275275
case WBYTES: Row_printBytes(str, lp->io_write_bytes, coloring); return;
276276
case CNCLWB: Row_printBytes(str, lp->io_cancelled_write_bytes, coloring); return;
277-
case IO_READ_RATE: Row_printRate(str, lp->io_rate_read_bps, coloring); return;
278-
case IO_WRITE_RATE: Row_printRate(str, lp->io_rate_write_bps, coloring); return;
279-
case IO_RATE: Row_printRate(str, LinuxProcess_totalIORate(lp), coloring); return;
277+
case IO_READ_RATE: Row_printRate(str, lp->io_rate_read_bps, coloring, host->settings->decimalUnits); return;
278+
case IO_WRITE_RATE: Row_printRate(str, lp->io_rate_write_bps, coloring, host->settings->decimalUnits); return;
279+
case IO_RATE: Row_printRate(str, LinuxProcess_totalIORate(lp), coloring, host->settings->decimalUnits); return;
280280
#ifdef HAVE_OPENVZ
281281
case CTID: xSnprintf(buffer, n, "%-8s ", lp->ctid ? lp->ctid : ""); break;
282282
case VPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, lp->vpid); break;

0 commit comments

Comments
 (0)