From f2ae10963f28d3fd0bd57c3a8044818747c82a8c Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sat, 7 Sep 2024 12:42:56 +0800 Subject: [PATCH] DiskIOMeter: draw normalized utilization; show utilization above 100% The utilization percentage of DiskIOMeter is an accumulated total of all disks, and for multiple disks, utilization above 100% is possible. The maximum utilization should be "100% * number of disks". Set the bar and graph of the meter to draw with that maximum. Thanks to Nathan Scott for providing the PCP portion of the patch. Resolves #1374. Co-authored-by: Nathan Scott Signed-off-by: Kang-Che Sung --- DiskIOMeter.c | 14 +++++++++----- DiskIOMeter.h | 1 + darwin/Platform.c | 4 ++++ dragonflybsd/Platform.c | 3 +++ freebsd/Platform.c | 3 +++ linux/Platform.c | 3 +++ netbsd/Platform.c | 3 +++ pcp/Metric.h | 1 + pcp/Platform.c | 4 ++++ 9 files changed, 31 insertions(+), 5 deletions(-) diff --git a/DiskIOMeter.c b/DiskIOMeter.c index 8af7d9563..4bb689fac 100644 --- a/DiskIOMeter.c +++ b/DiskIOMeter.c @@ -31,6 +31,7 @@ static MeterRateStatus status = RATESTATUS_INIT; static char cached_read_diff_str[6]; static char cached_write_diff_str[6]; static double cached_utilisation_diff; +static double cached_utilisation_norm; static void DiskIOMeter_updateValues(Meter* this) { const Machine* host = this->host; @@ -82,12 +83,15 @@ static void DiskIOMeter_updateValues(Meter* this) { } Meter_humanUnit(cached_write_diff_str, diff, sizeof(cached_write_diff_str)); + cached_utilisation_diff = 0.0; + cached_utilisation_norm = 0.0; 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; + if (data.numDisks > 0) { + cached_utilisation_norm = (double)diff / (passedTimeInMs * data.numDisks); + cached_utilisation_norm = MINIMUM(cached_utilisation_norm, 1.0); + } } } @@ -96,7 +100,7 @@ static void DiskIOMeter_updateValues(Meter* this) { cached_msTimeSpend_total = data.totalMsTimeSpend; } - this->values[0] = cached_utilisation_diff; + this->values[0] = cached_utilisation_norm; if (status == RATESTATUS_NODATA) { xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "no data"); @@ -154,7 +158,7 @@ const MeterClass DiskIOMeter_class = { .defaultMode = TEXT_METERMODE, .supportedModes = METERMODE_DEFAULT_SUPPORTED, .maxItems = 1, - .total = 100.0, + .total = 1.0, .attributes = DiskIOMeter_attributes, .name = "DiskIO", .uiName = "Disk IO", diff --git a/DiskIOMeter.h b/DiskIOMeter.h index 5ac9c4849..b49adaf3a 100644 --- a/DiskIOMeter.h +++ b/DiskIOMeter.h @@ -16,6 +16,7 @@ typedef struct DiskIOData_ { uint64_t totalBytesRead; uint64_t totalBytesWritten; uint64_t totalMsTimeSpend; + uint64_t numDisks; } DiskIOData; extern const MeterClass DiskIOMeter_class; diff --git a/darwin/Platform.c b/darwin/Platform.c index ba31a59f8..21ef316ce 100644 --- a/darwin/Platform.c +++ b/darwin/Platform.c @@ -405,6 +405,7 @@ bool Platform_getDiskIO(DiskIOData* data) { return false; unsigned long long int read_sum = 0, write_sum = 0, timeSpend_sum = 0; + unsigned long long int numDisks = 0; io_registry_entry_t drive; while ((drive = IOIteratorNext(drive_list)) != 0) { @@ -433,6 +434,8 @@ bool Platform_getDiskIO(DiskIOData* data) { continue; } + numDisks++; + CFNumberRef number; unsigned long long int value; @@ -471,6 +474,7 @@ bool Platform_getDiskIO(DiskIOData* data) { data->totalBytesRead = read_sum; data->totalBytesWritten = write_sum; data->totalMsTimeSpend = timeSpend_sum / 1e6; /* Convert from ns to ms */ + data->numDisks = numDisks; if (drive_list) IOObjectRelease(drive_list); diff --git a/dragonflybsd/Platform.c b/dragonflybsd/Platform.c index f3412ef9e..ddd211771 100644 --- a/dragonflybsd/Platform.c +++ b/dragonflybsd/Platform.c @@ -280,6 +280,7 @@ bool Platform_getDiskIO(DiskIOData* data) { uint64_t bytesReadSum = 0; uint64_t bytesWriteSum = 0; uint64_t busyMsTimeSum = 0; + uint64_t numDisks = 0; for (int i = 0; i < dev_stats.dinfo->numdevs; i++) { const struct devstat* device = &dev_stats.dinfo->devices[dev_sel[i].position]; @@ -301,11 +302,13 @@ bool Platform_getDiskIO(DiskIOData* data) { bytesReadSum += device->bytes_read; bytesWriteSum += device->bytes_written; busyMsTimeSum += (device->busy_time.tv_sec * 1000 + device->busy_time.tv_usec / 1000); + numDisks++; } data->totalBytesRead = bytesReadSum; data->totalBytesWritten = bytesWriteSum; data->totalMsTimeSpend = busyMsTimeSum; + data->numDisks = numDisks; free(dev_stats.dinfo); return true; diff --git a/freebsd/Platform.c b/freebsd/Platform.c index 153374b84..487b715f0 100644 --- a/freebsd/Platform.c +++ b/freebsd/Platform.c @@ -313,6 +313,7 @@ bool Platform_getDiskIO(DiskIOData* data) { int count = current.dinfo->numdevs; unsigned long long int bytesReadSum = 0, bytesWriteSum = 0, timeSpendSum = 0; + unsigned long long int numDisks = 0; // get data for (int i = 0; i < count; i++) { @@ -330,11 +331,13 @@ bool Platform_getDiskIO(DiskIOData* data) { bytesReadSum += bytes_read; bytesWriteSum += bytes_write; timeSpendSum += 1000 * busy_time; + numDisks++; } data->totalBytesRead = bytesReadSum; data->totalBytesWritten = bytesWriteSum; data->totalMsTimeSpend = timeSpendSum; + data->numDisks = numDisks; return true; } diff --git a/linux/Platform.c b/linux/Platform.c index c59be6840..daa6fb6bd 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -614,6 +614,7 @@ bool Platform_getDiskIO(DiskIOData* data) { char lastTopDisk[32] = { '\0' }; unsigned long long int read_sum = 0, write_sum = 0, timeSpend_sum = 0; + unsigned long long int numDisks = 0; char lineBuffer[256]; while (fgets(lineBuffer, sizeof(lineBuffer), fp)) { char diskname[32]; @@ -635,6 +636,7 @@ bool Platform_getDiskIO(DiskIOData* data) { read_sum += read_tmp; write_sum += write_tmp; timeSpend_sum += timeSpend_tmp; + numDisks++; } } fclose(fp); @@ -642,6 +644,7 @@ bool Platform_getDiskIO(DiskIOData* data) { data->totalBytesRead = 512 * read_sum; data->totalBytesWritten = 512 * write_sum; data->totalMsTimeSpend = timeSpend_sum; + data->numDisks = numDisks; return true; } diff --git a/netbsd/Platform.c b/netbsd/Platform.c index f458c239f..9941eca9f 100644 --- a/netbsd/Platform.c +++ b/netbsd/Platform.c @@ -384,6 +384,7 @@ bool Platform_getDiskIO(DiskIOData* data) { uint64_t bytesReadSum = 0; uint64_t bytesWriteSum = 0; uint64_t busyTimeSum = 0; + uint64_t numDisks = 0; for (size_t i = 0, count = size / sizeof(struct io_sysctl); i < count; i++) { /* ignore NFS activity */ @@ -393,11 +394,13 @@ bool Platform_getDiskIO(DiskIOData* data) { bytesReadSum += iostats[i].rbytes; bytesWriteSum += iostats[i].wbytes; busyTimeSum += iostats[i].busysum_usec; + numDisks++; } data->totalBytesRead = bytesReadSum; data->totalBytesWritten = bytesWriteSum; data->totalMsTimeSpend = busyTimeSum / 1000; + data->numDisks = numDisks; free(iostats); return true; diff --git a/pcp/Metric.h b/pcp/Metric.h index e72f6e19b..449ab7c8f 100644 --- a/pcp/Metric.h +++ b/pcp/Metric.h @@ -26,6 +26,7 @@ typedef enum Metric_ { PCP_CONTROL_THREADS, /* proc.control.perclient.threads */ PCP_HINV_NCPU, /* hinv.ncpu */ + PCP_HINV_NDISK, /* hinv.ndisk */ PCP_HINV_CPUCLOCK, /* hinv.cpu.clock */ PCP_UNAME_SYSNAME, /* kernel.uname.sysname */ PCP_UNAME_RELEASE, /* kernel.uname.release */ diff --git a/pcp/Platform.c b/pcp/Platform.c index 0db8b84b0..9a0aa16f7 100644 --- a/pcp/Platform.c +++ b/pcp/Platform.c @@ -127,6 +127,7 @@ static const char* Platform_metricNames[] = { [PCP_CONTROL_THREADS] = "proc.control.perclient.threads", [PCP_HINV_NCPU] = "hinv.ncpu", + [PCP_HINV_NDISK] = "hinv.ndisk", [PCP_HINV_CPUCLOCK] = "hinv.cpu.clock", [PCP_UNAME_SYSNAME] = "kernel.uname.sysname", [PCP_UNAME_RELEASE] = "kernel.uname.release", @@ -385,6 +386,7 @@ bool Platform_init(void) { Metric_enable(PCP_PID_MAX, true); Metric_enable(PCP_BOOTTIME, true); Metric_enable(PCP_HINV_NCPU, true); + Metric_enable(PCP_HINV_NDISK, true); Metric_enable(PCP_PERCPU_SYSTEM, true); Metric_enable(PCP_UNAME_SYSNAME, true); Metric_enable(PCP_UNAME_RELEASE, true); @@ -753,6 +755,8 @@ bool Platform_getDiskIO(DiskIOData* data) { data->totalBytesWritten = value.ull; if (Metric_values(PCP_DISK_ACTIVE, &value, 1, PM_TYPE_U64) != NULL) data->totalMsTimeSpend = value.ull; + if (Metric_values(PCP_HINV_NDISK, &value, 1, PM_TYPE_U64) != NULL) + data->numDisks = value.ull; return true; }