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

Meter_humanUnit() rewrite and *IOMeter code improvements #1321

Merged
merged 11 commits into from
Nov 24, 2023
96 changes: 49 additions & 47 deletions DiskIOMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,22 @@ static const int DiskIOMeter_attributes[] = {
};

static MeterRateStatus status = RATESTATUS_INIT;
static uint32_t cached_read_diff;
static uint32_t cached_write_diff;
static char cached_read_diff_str[6];
static char cached_write_diff_str[6];
static double cached_utilisation_diff;

static void DiskIOMeter_updateValues(Meter* this) {
const Machine* host = this->host;

static uint64_t cached_last_update;
uint64_t passedTimeInMs = host->realtimeMs - cached_last_update;
bool hasNewData = false;
DiskIOData data;

/* update only every 500ms to have a sane span for rate calculation */
if (passedTimeInMs > 500) {
static uint64_t cached_read_total;
static uint64_t cached_write_total;
static uint64_t cached_msTimeSpend_total;
uint64_t diff;

DiskIOData data;
if (!Platform_getDiskIO(&data)) {
hasNewData = Platform_getDiskIO(&data);
if (!hasNewData) {
status = RATESTATUS_NODATA;
} else if (cached_last_update == 0) {
status = RATESTATUS_INIT;
Expand All @@ -56,41 +53,54 @@ static void DiskIOMeter_updateValues(Meter* this) {
}

cached_last_update = host->realtimeMs;
}

if (status == RATESTATUS_NODATA) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "no data");
return;
}
if (hasNewData) {
static uint64_t cached_read_total;
static uint64_t cached_write_total;
static uint64_t cached_msTimeSpend_total;

if (data.totalBytesRead > cached_read_total) {
diff = data.totalBytesRead - cached_read_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to B/s */
diff /= ONE_K; /* convert to KiB/s */
cached_read_diff = (uint32_t)diff;
} else {
cached_read_diff = 0;
if (status != RATESTATUS_INIT) {
uint64_t diff;

if (data.totalBytesRead > cached_read_total) {
diff = data.totalBytesRead - cached_read_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to B/s */
diff /= ONE_K; /* convert to KiB/s */
} else {
diff = 0;
}
Meter_humanUnit(cached_read_diff_str, diff, sizeof(cached_read_diff_str));

if (data.totalBytesWritten > cached_write_total) {
diff = data.totalBytesWritten - cached_write_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to B/s */
diff /= ONE_K; /* convert to KiB/s */
} else {
diff = 0;
}
Meter_humanUnit(cached_write_diff_str, diff, sizeof(cached_write_diff_str));

if (data.totalMsTimeSpend > cached_msTimeSpend_total) {
diff = data.totalMsTimeSpend - cached_msTimeSpend_total;
cached_utilisation_diff = 100.0 * (double)diff / passedTimeInMs;
cached_utilisation_diff = MINIMUM(cached_utilisation_diff, 100.0);
} else {
cached_utilisation_diff = 0.0;
}
}
cached_read_total = data.totalBytesRead;

if (data.totalBytesWritten > cached_write_total) {
diff = data.totalBytesWritten - cached_write_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to B/s */
diff /= ONE_K; /* convert to KiB/s */
cached_write_diff = (uint32_t)diff;
} else {
cached_write_diff = 0;
}
cached_read_total = data.totalBytesRead;
cached_write_total = data.totalBytesWritten;

if (data.totalMsTimeSpend > cached_msTimeSpend_total) {
diff = data.totalMsTimeSpend - cached_msTimeSpend_total;
cached_utilisation_diff = 100.0 * (double)diff / passedTimeInMs;
} else {
cached_utilisation_diff = 0.0;
}
cached_msTimeSpend_total = data.totalMsTimeSpend;
}

this->values[0] = cached_utilisation_diff;

if (status == RATESTATUS_NODATA) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "no data");
return;
}
if (status == RATESTATUS_INIT) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "init");
return;
Expand All @@ -100,13 +110,7 @@ static void DiskIOMeter_updateValues(Meter* this) {
return;
}

this->values[0] = cached_utilisation_diff;
this->total = MAXIMUM(this->values[0], 100.0); /* fix total after (initial) spike */

char bufferRead[12], bufferWrite[12];
Meter_humanUnit(bufferRead, cached_read_diff, sizeof(bufferRead));
Meter_humanUnit(bufferWrite, cached_write_diff, sizeof(bufferWrite));
snprintf(this->txtBuffer, sizeof(this->txtBuffer), "r:%siB/s w:%siB/s %.1f%%", bufferRead, bufferWrite, cached_utilisation_diff);
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "r:%siB/s w:%siB/s %.1f%%", cached_read_diff_str, cached_write_diff_str, cached_utilisation_diff);
}

static void DiskIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
Expand All @@ -132,13 +136,11 @@ static void DiskIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out)
RichString_appendnAscii(out, CRT_colors[color], buffer, len);

RichString_appendAscii(out, CRT_colors[METER_TEXT], " read: ");
Meter_humanUnit(buffer, cached_read_diff, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], buffer);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], cached_read_diff_str);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");

RichString_appendAscii(out, CRT_colors[METER_TEXT], " write: ");
Meter_humanUnit(buffer, cached_write_diff, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], cached_write_diff_str);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");
}

Expand Down
46 changes: 27 additions & 19 deletions Meter.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,32 +51,40 @@ Meter* Meter_new(const Machine* host, unsigned int param, const MeterClass* type
return this;
}

int Meter_humanUnit(char* buffer, unsigned long int value, size_t size) {
const char* prefix = "KMGTPEZY";
unsigned long int powi = 1;
unsigned int powj = 1, precision = 2;

for (;;) {
if (value / 1024 < powi)
break;

if (prefix[1] == '\0')
/* Converts 'value' in kibibytes into a human readable string.
Example output strings: "0K", "1023K", "98.7M" and "1.23G" */
int Meter_humanUnit(char* buffer, double value, size_t size) {
Explorer09 marked this conversation as resolved.
Show resolved Hide resolved
size_t i = 0;

assert(value >= 0.0);
while (value >= ONE_K) {
if (i >= ARRAYSIZE(unitPrefixes) - 1) {
if (value > 9999.0) {
return xSnprintf(buffer, size, "inf");
}
break;
}

powi *= 1024;
++prefix;
value /= ONE_K;
++i;
}

if (*prefix == 'K')
precision = 0;
int precision = 0;

for (; precision > 0; precision--) {
powj *= 10;
if (value / powi < powj)
break;
if (i > 0) {
// Fraction digits for mebibytes and above
precision = value <= 99.9 ? (value <= 9.99 ? 2 : 1) : 0;

// Round up if 'value' is in range (99.9, 100) or (9.99, 10)
if (precision < 2) {
double limit = precision == 1 ? 10.0 : 100.0;
if (value < limit) {
value = limit;
}
}
}

return snprintf(buffer, size, "%.*f%c", precision, (double) value / powi, *prefix);
return xSnprintf(buffer, size, "%.*f%c", precision, value, unitPrefixes[i]);
}

void Meter_delete(Object* cast) {
Expand Down
4 changes: 3 additions & 1 deletion Meter.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ extern const MeterClass Meter_class;

Meter* Meter_new(const Machine* host, unsigned int param, const MeterClass* type);

int Meter_humanUnit(char* buffer, unsigned long int value, size_t size);
/* Converts 'value' in kibibytes into a human readable string.
Example output strings: "0K", "1023K", "98.7M" and "1.23G" */
int Meter_humanUnit(char* buffer, double value, size_t size);

void Meter_delete(Object* cast);

Expand Down
128 changes: 66 additions & 62 deletions NetworkIOMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,25 @@ static const int NetworkIOMeter_attributes[] = {
};

static MeterRateStatus status = RATESTATUS_INIT;
static uint32_t cached_rxb_diff;
static double cached_rxb_diff;
static char cached_rxb_diff_str[6];
static uint32_t cached_rxp_diff;
static uint32_t cached_txb_diff;
static double cached_txb_diff;
static char cached_txb_diff_str[6];
static uint32_t cached_txp_diff;

static void NetworkIOMeter_updateValues(Meter* this) {
const Machine* host = this->host;
static uint64_t cached_last_update = 0;

static uint64_t cached_last_update = 0;
uint64_t passedTimeInMs = host->realtimeMs - cached_last_update;
bool hasNewData = false;
NetworkIOData data;

/* update only every 500ms to have a sane span for rate calculation */
if (passedTimeInMs > 500) {
static uint64_t cached_rxb_total;
static uint64_t cached_rxp_total;
static uint64_t cached_txb_total;
static uint64_t cached_txp_total;
uint64_t diff;

NetworkIOData data;
if (!Platform_getNetworkIO(&data)) {
hasNewData = Platform_getNetworkIO(&data);
if (!hasNewData) {
status = RATESTATUS_NODATA;
} else if (cached_last_update == 0) {
status = RATESTATUS_INIT;
Expand All @@ -58,51 +56,68 @@ static void NetworkIOMeter_updateValues(Meter* this) {
}

cached_last_update = host->realtimeMs;
}

if (status == RATESTATUS_NODATA) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "no data");
return;
}
if (hasNewData) {
static uint64_t cached_rxb_total;
static uint64_t cached_rxp_total;
static uint64_t cached_txb_total;
static uint64_t cached_txp_total;

if (data.bytesReceived > cached_rxb_total) {
diff = data.bytesReceived - cached_rxb_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to B/s */
diff /= ONE_K; /* convert to KiB/s */
cached_rxb_diff = (uint32_t)diff;
} else {
cached_rxb_diff = 0;
if (status != RATESTATUS_INIT) {
uint64_t diff;

if (data.bytesReceived > cached_rxb_total) {
diff = data.bytesReceived - cached_rxb_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to B/s */
cached_rxb_diff = diff;
} else {
cached_rxb_diff = 0;
}
Meter_humanUnit(cached_rxb_diff_str, cached_rxb_diff / ONE_K, sizeof(cached_rxb_diff_str));

if (data.packetsReceived > cached_rxp_total) {
diff = data.packetsReceived - cached_rxp_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to pkts/s */
cached_rxp_diff = (uint32_t)diff;
} else {
cached_rxp_diff = 0;
}

if (data.bytesTransmitted > cached_txb_total) {
diff = data.bytesTransmitted - cached_txb_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to B/s */
cached_txb_diff = diff;
} else {
cached_txb_diff = 0;
}
Meter_humanUnit(cached_txb_diff_str, cached_txb_diff / ONE_K, sizeof(cached_txb_diff_str));

if (data.packetsTransmitted > cached_txp_total) {
diff = data.packetsTransmitted - cached_txp_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to pkts/s */
cached_txp_diff = (uint32_t)diff;
} else {
cached_txp_diff = 0;
}
}
cached_rxb_total = data.bytesReceived;

if (data.packetsReceived > cached_rxp_total) {
diff = data.packetsReceived - cached_rxp_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to B/s */
cached_rxp_diff = (uint32_t)diff;
} else {
cached_rxp_diff = 0;
}
cached_rxb_total = data.bytesReceived;
cached_rxp_total = data.packetsReceived;

if (data.bytesTransmitted > cached_txb_total) {
diff = data.bytesTransmitted - cached_txb_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to B/s */
diff /= ONE_K; /* convert to KiB/s */
cached_txb_diff = (uint32_t)diff;
} else {
cached_txb_diff = 0;
}
cached_txb_total = data.bytesTransmitted;

if (data.packetsTransmitted > cached_txp_total) {
diff = data.packetsTransmitted - cached_txp_total;
diff = (1000 * diff) / passedTimeInMs; /* convert to B/s */
cached_txp_diff = (uint32_t)diff;
} else {
cached_txp_diff = 0;
}
cached_txp_total = data.packetsTransmitted;
}

this->values[0] = cached_rxb_diff;
this->values[1] = cached_txb_diff;
if (cached_rxb_diff + cached_txb_diff > this->total) {
this->total = cached_rxb_diff + cached_txb_diff;
}

if (status == RATESTATUS_NODATA) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "no data");
return;
}
if (status == RATESTATUS_INIT) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "init");
return;
Expand All @@ -112,17 +127,8 @@ static void NetworkIOMeter_updateValues(Meter* this) {
return;
}

this->values[0] = cached_rxb_diff;
this->values[1] = cached_txb_diff;
if (cached_rxb_diff + cached_txb_diff > this->total) {
this->total = cached_rxb_diff + cached_txb_diff;
}

char bufferBytesReceived[12], bufferBytesTransmitted[12];
Meter_humanUnit(bufferBytesReceived, cached_rxb_diff, sizeof(bufferBytesReceived));
Meter_humanUnit(bufferBytesTransmitted, cached_txb_diff, sizeof(bufferBytesTransmitted));
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "rx:%siB/s tx:%siB/s %d/%dpkts/s",
bufferBytesReceived, bufferBytesTransmitted, cached_rxp_diff, cached_txp_diff);
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "rx:%siB/s tx:%siB/s %u/%upkts/s",
cached_rxb_diff_str, cached_txb_diff_str, cached_rxp_diff, cached_txp_diff);
}

static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
Expand All @@ -144,13 +150,11 @@ static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* o
int len;

RichString_writeAscii(out, CRT_colors[METER_TEXT], "rx: ");
Meter_humanUnit(buffer, cached_rxb_diff, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], buffer);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], cached_rxb_diff_str);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], "iB/s");

RichString_appendAscii(out, CRT_colors[METER_TEXT], " tx: ");
Meter_humanUnit(buffer, cached_txb_diff, sizeof(buffer));
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], buffer);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], cached_txb_diff_str);
RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s");

len = xSnprintf(buffer, sizeof(buffer), " (%u/%u pkts/s) ", cached_rxp_diff, cached_txp_diff);
Expand Down
Loading