summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Göttsche <cgzones@googlemail.com>2020-09-13 19:46:34 +0200
committercgzones <cgzones@googlemail.com>2020-10-03 19:01:38 +0200
commite5184599814a3210497035e9942f154945f2b02f (patch)
tree35b02f22092f4d561adb4be1e98a2847338cb92c
parent6f387008cba414abdf695ae0eccdc0501bd36a1d (diff)
Add DiskIOMeter for IO read/write usage
-rw-r--r--CRT.c18
-rw-r--r--CRT.h3
-rw-r--r--DiskIOMeter.c92
-rw-r--r--DiskIOMeter.h14
-rw-r--r--Makefile.am4
-rw-r--r--darwin/Platform.c5
-rw-r--r--darwin/Platform.h2
-rw-r--r--dragonflybsd/Platform.c5
-rw-r--r--dragonflybsd/Platform.h2
-rw-r--r--freebsd/Platform.c5
-rw-r--r--freebsd/Platform.h2
-rw-r--r--linux/Platform.c51
-rw-r--r--linux/Platform.h2
-rw-r--r--openbsd/Platform.c5
-rw-r--r--openbsd/Platform.h2
-rw-r--r--solaris/Platform.c5
-rw-r--r--solaris/Platform.h2
-rw-r--r--unsupported/Platform.c4
-rw-r--r--unsupported/Platform.h2
19 files changed, 223 insertions, 2 deletions
diff --git a/CRT.c b/CRT.c
index c0faf886..69372298 100644
--- a/CRT.c
+++ b/CRT.c
@@ -145,6 +145,9 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[ZFS_OTHER] = ColorPair(Magenta,Black),
[ZFS_COMPRESSED] = ColorPair(Blue,Black),
[ZFS_RATIO] = ColorPair(Magenta,Black),
+ [DISKIO_UTIL_HIGH] = A_BOLD | ColorPair(White,Black),
+ [DISKIO_READ] = ColorPair(Green,Black),
+ [DISKIO_WRITE] = ColorPair(Blue,Black),
},
[COLORSCHEME_MONOCHROME] = {
[RESET_COLOR] = A_NORMAL,
@@ -215,6 +218,9 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[ZFS_OTHER] = A_DIM,
[ZFS_COMPRESSED] = A_BOLD,
[ZFS_RATIO] = A_BOLD,
+ [DISKIO_UTIL_HIGH] = A_BOLD,
+ [DISKIO_READ] = A_NORMAL,
+ [DISKIO_WRITE] = A_NORMAL,
},
[COLORSCHEME_BLACKONWHITE] = {
[RESET_COLOR] = ColorPair(Black,White),
@@ -285,6 +291,9 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[ZFS_OTHER] = ColorPair(Magenta,White),
[ZFS_COMPRESSED] = ColorPair(Cyan,White),
[ZFS_RATIO] = ColorPair(Magenta,White),
+ [DISKIO_UTIL_HIGH] = A_BOLD | ColorPair(Yellow,White),
+ [DISKIO_READ] = ColorPair(Green,White),
+ [DISKIO_WRITE] = ColorPair(Blue,White),
},
[COLORSCHEME_LIGHTTERMINAL] = {
[RESET_COLOR] = ColorPair(Blue,Black),
@@ -355,6 +364,9 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[ZFS_OTHER] = A_BOLD | ColorPair(Magenta,Black),
[ZFS_COMPRESSED] = ColorPair(Cyan,Black),
[ZFS_RATIO] = A_BOLD | ColorPair(Magenta,Black),
+ [DISKIO_UTIL_HIGH] = A_BOLD | ColorPair(Yellow,Black),
+ [DISKIO_READ] = ColorPair(Green,Black),
+ [DISKIO_WRITE] = ColorPair(Blue,Black),
},
[COLORSCHEME_MIDNIGHT] = {
[RESET_COLOR] = ColorPair(White,Blue),
@@ -425,6 +437,9 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[ZFS_OTHER] = A_BOLD | ColorPair(Magenta,Blue),
[ZFS_COMPRESSED] = A_BOLD | ColorPair(White,Blue),
[ZFS_RATIO] = A_BOLD | ColorPair(Magenta,Blue),
+ [DISKIO_UTIL_HIGH] = A_BOLD | ColorPair(White,Blue),
+ [DISKIO_READ] = ColorPair(Green,Blue),
+ [DISKIO_WRITE] = ColorPair(Black,Blue),
},
[COLORSCHEME_BLACKNIGHT] = {
[RESET_COLOR] = ColorPair(Cyan,Black),
@@ -495,6 +510,9 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[ZFS_OTHER] = ColorPair(Magenta,Black),
[ZFS_COMPRESSED] = ColorPair(Blue,Black),
[ZFS_RATIO] = ColorPair(Magenta,Black),
+ [DISKIO_UTIL_HIGH] = A_BOLD | ColorPair(Green,Black),
+ [DISKIO_READ] = ColorPair(Green,Black),
+ [DISKIO_WRITE] = ColorPair(Blue,Black),
},
[COLORSCHEME_BROKENGRAY] = { 0 } // dynamically generated.
};
diff --git a/CRT.h b/CRT.h
index f21488fe..4eeb9a46 100644
--- a/CRT.h
+++ b/CRT.h
@@ -106,6 +106,9 @@ typedef enum ColorElements_ {
ZFS_OTHER,
ZFS_COMPRESSED,
ZFS_RATIO,
+ DISKIO_UTIL_HIGH,
+ DISKIO_READ,
+ DISKIO_WRITE,
LAST_COLORELEMENT
} ColorElements;
diff --git a/DiskIOMeter.c b/DiskIOMeter.c
new file mode 100644
index 00000000..8c3f1455
--- /dev/null
+++ b/DiskIOMeter.c
@@ -0,0 +1,92 @@
+/*
+htop - DiskIOMeter.c
+(C) 2020 Christian Göttsche
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "DiskIOMeter.h"
+
+#include <math.h>
+
+#include "CRT.h"
+#include "Platform.h"
+
+
+static const int DiskIOMeter_attributes[] = {
+ DISKIO_UTIL_HIGH,
+ DISKIO_READ,
+ DISKIO_WRITE,
+};
+
+static unsigned long int cached_read_diff = 0;
+static unsigned long int cached_write_diff = 0;
+static double cached_utilisation_diff = 0.0;
+
+static void DiskIOMeter_updateValues(Meter* this, char* buffer, int len) {
+ static unsigned long int cached_read_total = 0;
+ static unsigned long int cached_write_total = 0;
+ static unsigned long int cached_msTimeSpend_total = 0;
+ static unsigned long long int cached_last_update = 0;
+
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ unsigned long long int timeInMilliSeconds = (unsigned long long int)tv.tv_sec * 1000 + (unsigned long long int)tv.tv_usec / 1000;
+
+ /* update only every 500ms */
+ if (timeInMilliSeconds - cached_last_update > 500) {
+ unsigned long int bytesRead, bytesWrite, msTimeSpend;
+
+ Platform_getDiskIO(&bytesRead, &bytesWrite, &msTimeSpend);
+
+ cached_read_diff = (bytesRead - cached_read_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
+ cached_read_total = bytesRead;
+
+ cached_write_diff = (bytesWrite - cached_write_total) / 1024; /* Meter_humanUnit() expects unit in kilo */
+ cached_write_total = bytesWrite;
+
+ cached_utilisation_diff = 100 * (double)(msTimeSpend - cached_msTimeSpend_total) / (timeInMilliSeconds - cached_last_update);
+ cached_last_update = timeInMilliSeconds;
+ cached_msTimeSpend_total = msTimeSpend;
+ }
+
+ 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(buffer, len, "%sB %sB %.1f%%", bufferRead, bufferWrite, cached_utilisation_diff);
+}
+
+static void DIskIOMeter_display(ATTR_UNUSED Object* cast, RichString* out) {
+ char buffer[16];
+
+ int color = cached_utilisation_diff > 40.0 ? DISKIO_UTIL_HIGH : METER_VALUE;
+ xSnprintf(buffer, sizeof(buffer), "%.1f%%", cached_utilisation_diff);
+ RichString_write(out, CRT_colors[color], buffer);
+
+ RichString_append(out, CRT_colors[METER_TEXT], " read: ");
+ Meter_humanUnit(buffer, cached_read_diff, sizeof(buffer));
+ RichString_append(out, CRT_colors[DISKIO_READ], buffer);
+
+ RichString_append(out, CRT_colors[METER_TEXT], " write: ");
+ Meter_humanUnit(buffer, cached_write_diff, sizeof(buffer));
+ RichString_append(out, CRT_colors[DISKIO_WRITE], buffer);
+}
+
+MeterClass DiskIOMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = DIskIOMeter_display
+ },
+ .updateValues = DiskIOMeter_updateValues,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 1,
+ .total = 100.0,
+ .attributes = DiskIOMeter_attributes,
+ .name = "DiskIO",
+ .uiName = "Disk IO",
+ .caption = "Disk IO: "
+};
diff --git a/DiskIOMeter.h b/DiskIOMeter.h
new file mode 100644
index 00000000..6aca5c2d
--- /dev/null
+++ b/DiskIOMeter.h
@@ -0,0 +1,14 @@
+#ifndef HEADER_DiskIOMeter
+#define HEADER_DiskIOMeter
+/*
+ h top - DiskIOMeter*.h
+(C) 2020 Christian Göttsche
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "Meter.h"
+
+extern MeterClass DiskIOMeter_class;
+
+#endif /* HEADER_DiskIOMeter */
diff --git a/Makefile.am b/Makefile.am
index 441ea80e..ea9a2e42 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -15,8 +15,8 @@ AM_LDFLAGS =
AM_CPPFLAGS = -DNDEBUG
myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \
-ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c MainPanel.c \
-DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \
+ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c DiskIOMeter.c DiskIOMeter.h \
+MainPanel.c DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \
LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \
BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \
SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c \
diff --git a/darwin/Platform.c b/darwin/Platform.c
index 747ffefb..5aa50a65 100644
--- a/darwin/Platform.c
+++ b/darwin/Platform.c
@@ -305,3 +305,8 @@ char* Platform_getProcessEnv(pid_t pid) {
return env;
}
+
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend) {
+ // TODO
+ *bytesRead = *bytesWrite = *msTimeSpend = 0;
+}
diff --git a/darwin/Platform.h b/darwin/Platform.h
index 6c038587..3a6f119f 100644
--- a/darwin/Platform.h
+++ b/darwin/Platform.h
@@ -48,4 +48,6 @@ void Platform_setZfsCompressedArcValues(Meter* this);
char* Platform_getProcessEnv(pid_t pid);
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend);
+
#endif
diff --git a/dragonflybsd/Platform.c b/dragonflybsd/Platform.c
index 7d16eda1..36ab2c21 100644
--- a/dragonflybsd/Platform.c
+++ b/dragonflybsd/Platform.c
@@ -205,3 +205,8 @@ char* Platform_getProcessEnv(pid_t pid) {
(void)pid; // prevent unused warning
return NULL;
}
+
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend) {
+ // TODO
+ *bytesRead = *bytesWrite = *msTimeSpend = 0;
+}
diff --git a/dragonflybsd/Platform.h b/dragonflybsd/Platform.h
index 14a249e1..c0a60233 100644
--- a/dragonflybsd/Platform.h
+++ b/dragonflybsd/Platform.h
@@ -42,4 +42,6 @@ void Platform_setTasksValues(Meter* this);
char* Platform_getProcessEnv(pid_t pid);
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend);
+
#endif
diff --git a/freebsd/Platform.c b/freebsd/Platform.c
index 318b3e12..36256f9a 100644
--- a/freebsd/Platform.c
+++ b/freebsd/Platform.c
@@ -220,3 +220,8 @@ char* Platform_getProcessEnv(pid_t pid) {
// TODO
return NULL;
}
+
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend) {
+ // TODO
+ *bytesRead = *bytesWrite = *msTimeSpend = 0;
+}
diff --git a/freebsd/Platform.h b/freebsd/Platform.h
index e58e99d0..780d23e6 100644
--- a/freebsd/Platform.h
+++ b/freebsd/Platform.h
@@ -45,4 +45,6 @@ void Platform_setTasksValues(Meter* this);
char* Platform_getProcessEnv(pid_t pid);
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend);
+
#endif
diff --git a/linux/Platform.c b/linux/Platform.c
index 58bc3bea..78313b2d 100644
--- a/linux/Platform.c
+++ b/linux/Platform.c
@@ -14,6 +14,7 @@ in the source distribution for its full text.
#include "Meter.h"
#include "CPUMeter.h"
+#include "DiskIOMeter.h"
#include "MemoryMeter.h"
#include "SwapMeter.h"
#include "TasksMeter.h"
@@ -25,12 +26,14 @@ in the source distribution for its full text.
#include "zfs/ZfsArcMeter.h"
#include "zfs/ZfsCompressedArcMeter.h"
#include "LinuxProcess.h"
+#include "StringUtils.h"
#include <math.h>
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, (int)M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
@@ -131,6 +134,7 @@ MeterClass* Platform_meterTypes[] = {
&PressureStallMemoryFullMeter_class,
&ZfsArcMeter_class,
&ZfsCompressedArcMeter_class,
+ &DiskIOMeter_class,
NULL
};
@@ -281,3 +285,50 @@ void Platform_getPressureStall(const char *file, bool some, double* ten, double*
assert(total == 3);
fclose(fd);
}
+
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend) {
+ FILE *fd = fopen(PROCDIR "/diskstats", "r");
+ if (!fd) {
+ *bytesRead = 0;
+ *bytesWrite = 0;
+ *msTimeSpend = 0;
+ return;
+ }
+ unsigned long int read_sum = 0, write_sum = 0, timeSpend_sum = 0;
+ char lineBuffer[256];
+ while (fgets(lineBuffer, sizeof(lineBuffer), fd)) {
+ char diskname[32];
+ unsigned long int read_tmp, write_tmp, timeSpend_tmp;
+ if (sscanf(lineBuffer, "%*d %*d %31s %*u %*u %lu %*u %*u %*u %lu %*u %*u %lu", diskname, &read_tmp, &write_tmp, &timeSpend_tmp) == 4) {
+ if (String_startsWith(diskname, "dm-"))
+ continue;
+
+ /* only count root disks, e.g. do not count IO from sda and sda1 twice */
+ if ((diskname[0] == 's' || diskname[0] == 'h')
+ && diskname[1] == 'd'
+ && isalpha((unsigned char)diskname[2])
+ && isdigit((unsigned char)diskname[3]))
+ continue;
+
+ /* only count root disks, e.g. do not count IO from mmcblk0 and mmcblk0p1 twice */
+ if (diskname[0] == 'm'
+ && diskname[1] == 'm'
+ && diskname[2] == 'c'
+ && diskname[3] == 'b'
+ && diskname[4] == 'l'
+ && diskname[5] == 'k'
+ && isdigit((unsigned char)diskname[6])
+ && diskname[7] == 'p')
+ continue;
+
+ read_sum += read_tmp;
+ write_sum += write_tmp;
+ timeSpend_sum += timeSpend_tmp;
+ }
+ }
+ fclose(fd);
+ /* multiply with sector size */
+ *bytesRead = 512 * read_sum;
+ *bytesWrite = 512 * write_sum;
+ *msTimeSpend = timeSpend_sum;
+}
diff --git a/linux/Platform.h b/linux/Platform.h
index 5060ea24..68b18f28 100644
--- a/linux/Platform.h
+++ b/linux/Platform.h
@@ -44,4 +44,6 @@ char* Platform_getProcessEnv(pid_t pid);
void Platform_getPressureStall(const char *file, bool some, double* ten, double* sixty, double* threehundred);
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend);
+
#endif
diff --git a/openbsd/Platform.c b/openbsd/Platform.c
index 2c8bc7ae..ce370994 100644
--- a/openbsd/Platform.c
+++ b/openbsd/Platform.c
@@ -286,3 +286,8 @@ char* Platform_getProcessEnv(pid_t pid) {
(void) kvm_close(kt);
return env;
}
+
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend) {
+ // TODO
+ *bytesRead = *bytesWrite = *msTimeSpend = 0;
+}
diff --git a/openbsd/Platform.h b/openbsd/Platform.h
index 9e742bf3..e5e09ce0 100644
--- a/openbsd/Platform.h
+++ b/openbsd/Platform.h
@@ -43,4 +43,6 @@ void Platform_setTasksValues(Meter* this);
char* Platform_getProcessEnv(pid_t pid);
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend);
+
#endif
diff --git a/solaris/Platform.c b/solaris/Platform.c
index 05b44462..2114215e 100644
--- a/solaris/Platform.c
+++ b/solaris/Platform.c
@@ -258,3 +258,8 @@ char* Platform_getProcessEnv(pid_t pid) {
strncpy( envBuilder.env + envBuilder.size, "\0", 1);
return envBuilder.env;
}
+
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend) {
+ // TODO
+ *bytesRead = *bytesWrite = *msTimeSpend = 0;
+}
diff --git a/solaris/Platform.h b/solaris/Platform.h
index 29cc7964..d3dddb72 100644
--- a/solaris/Platform.h
+++ b/solaris/Platform.h
@@ -63,4 +63,6 @@ void Platform_setZfsCompressedArcValues(Meter* this);
char* Platform_getProcessEnv(pid_t pid);
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend);
+
#endif
diff --git a/unsupported/Platform.c b/unsupported/Platform.c
index b095e126..6a6b0131 100644
--- a/unsupported/Platform.c
+++ b/unsupported/Platform.c
@@ -135,3 +135,7 @@ char* Platform_getProcessEnv(pid_t pid) {
(void) pid;
return NULL;
}
+
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend) {
+ *bytesRead = *bytesWrite = *msTimeSpend = 0;
+}
diff --git a/unsupported/Platform.h b/unsupported/Platform.h
index fca7fc47..cdce6f38 100644
--- a/unsupported/Platform.h
+++ b/unsupported/Platform.h
@@ -47,4 +47,6 @@ bool Process_isThread(Process* this);
char* Platform_getProcessEnv(pid_t pid);
+void Platform_getDiskIO(unsigned long int *bytesRead, unsigned long int *bytesWrite, unsigned long int *msTimeSpend);
+
#endif

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