5851f672ac
Change-Id: Iad3024a5a640d33377cfae436134fda9f358397b Reviewed-on: https://cl.tvl.fyi/c/depot/+/1703 Tested-by: BuildkiteCI Reviewed-by: multi <depot@in-addr.xyz>
287 lines
9.7 KiB
Diff
287 lines
9.7 KiB
Diff
From 070fe90461182743fabb029415fc1bc59be14f3f Mon Sep 17 00:00:00 2001
|
|
From: Ross Williams <ross@ross-williams.net>
|
|
Date: Sun, 7 Jul 2019 02:37:02 +0000
|
|
Subject: [PATCH 3/9] ZFS arcstats for Linux
|
|
|
|
If no pools are imported (ARC size == 0) or the
|
|
ZFS module is not in the kernel (/proc/spl/kstat/zfs/arcstats
|
|
does not exist), then the Meter reports "Unavailable".
|
|
---
|
|
Makefile.am | 6 ++--
|
|
linux/LinuxProcessList.c | 66 ++++++++++++++++++++++++++++++++++++++++
|
|
linux/LinuxProcessList.h | 13 ++++++++
|
|
linux/Platform.c | 19 ++++++++++++
|
|
linux/Platform.h | 2 ++
|
|
zfs/ZfsArcMeter.c | 47 +++++++++++++++-------------
|
|
6 files changed, 130 insertions(+), 23 deletions(-)
|
|
|
|
diff --git a/Makefile.am b/Makefile.am
|
|
index ad23d19..b850815 100644
|
|
--- a/Makefile.am
|
|
+++ b/Makefile.am
|
|
@@ -52,14 +52,16 @@ linux_platform_headers = \
|
|
linux/LinuxProcess.h \
|
|
linux/LinuxProcessList.h \
|
|
linux/LinuxCRT.h \
|
|
- linux/Battery.h
|
|
+ linux/Battery.h \
|
|
+ $(zfs_platform_headers)
|
|
|
|
all_platform_headers += $(linux_platform_headers)
|
|
|
|
if HTOP_LINUX
|
|
AM_CFLAGS += -rdynamic
|
|
myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \
|
|
-linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c
|
|
+linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c \
|
|
+$(zfs_platform_sources)
|
|
|
|
myhtopplatheaders = $(linux_platform_headers)
|
|
endif
|
|
diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c
|
|
index 5f38540..4d19185 100644
|
|
--- a/linux/LinuxProcessList.c
|
|
+++ b/linux/LinuxProcessList.c
|
|
@@ -94,6 +94,15 @@ typedef struct LinuxProcessList_ {
|
|
struct nl_sock *netlink_socket;
|
|
int netlink_family;
|
|
#endif
|
|
+
|
|
+ int zfsArcEnabled;
|
|
+ unsigned long long int memZfsArc;
|
|
+ unsigned long long int zfsArcMax;
|
|
+ unsigned long long int zfsArcMFU;
|
|
+ unsigned long long int zfsArcMRU;
|
|
+ unsigned long long int zfsArcAnon;
|
|
+ unsigned long long int zfsArcHeader;
|
|
+ unsigned long long int zfsArcOther;
|
|
} LinuxProcessList;
|
|
|
|
#ifndef PROCDIR
|
|
@@ -108,6 +117,10 @@ typedef struct LinuxProcessList_ {
|
|
#define PROCMEMINFOFILE PROCDIR "/meminfo"
|
|
#endif
|
|
|
|
+#ifndef PROCARCSTATSFILE
|
|
+#define PROCARCSTATSFILE PROCDIR "/spl/kstat/zfs/arcstats"
|
|
+#endif
|
|
+
|
|
#ifndef PROCTTYDRIVERSFILE
|
|
#define PROCTTYDRIVERSFILE PROCDIR "/tty/drivers"
|
|
#endif
|
|
@@ -964,6 +977,58 @@ static inline void LinuxProcessList_scanMemoryInfo(ProcessList* this) {
|
|
fclose(file);
|
|
}
|
|
|
|
+static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) {
|
|
+ unsigned long long int dbufSize;
|
|
+ unsigned long long int dnodeSize;
|
|
+ unsigned long long int bonusSize;
|
|
+
|
|
+ FILE* file = fopen(PROCARCSTATSFILE, "r");
|
|
+ if (file == NULL) {
|
|
+ lpl->zfsArcEnabled = 0;
|
|
+ return;
|
|
+ }
|
|
+ char buffer[128];
|
|
+ while (fgets(buffer, 128, file)) {
|
|
+ #define tryRead(label, variable) do { if (String_startsWith(buffer, label) && sscanf(buffer + strlen(label), " %*2u %32llu", variable)) { break; } } while(0)
|
|
+ switch (buffer[0]) {
|
|
+ case 'c':
|
|
+ tryRead("c_max", &lpl->zfsArcMax);
|
|
+ break;
|
|
+ case 's':
|
|
+ tryRead("size", &lpl->memZfsArc);
|
|
+ break;
|
|
+ case 'h':
|
|
+ tryRead("hdr_size", &lpl->zfsArcHeader);
|
|
+ break;
|
|
+ case 'd':
|
|
+ tryRead("dbuf_size", &dbufSize);
|
|
+ tryRead("dnode_size", &dnodeSize);
|
|
+ break;
|
|
+ case 'b':
|
|
+ tryRead("bonus_size", &bonusSize);
|
|
+ break;
|
|
+ case 'a':
|
|
+ tryRead("anon_size", &lpl->zfsArcAnon);
|
|
+ break;
|
|
+ case 'm':
|
|
+ tryRead("mfu_size", &lpl->zfsArcMFU);
|
|
+ tryRead("mru_size", &lpl->zfsArcMRU);
|
|
+ break;
|
|
+ }
|
|
+ #undef tryRead
|
|
+ }
|
|
+ fclose(file);
|
|
+
|
|
+ lpl->zfsArcEnabled = (lpl->memZfsArc > 0 ? 1 : 0);
|
|
+ lpl->memZfsArc /= 1024;
|
|
+ lpl->zfsArcMax /= 1024;
|
|
+ lpl->zfsArcMFU /= 1024;
|
|
+ lpl->zfsArcMRU /= 1024;
|
|
+ lpl->zfsArcAnon /= 1024;
|
|
+ lpl->zfsArcHeader /= 1024;
|
|
+ lpl->zfsArcOther = (dbufSize + dnodeSize + bonusSize) / 1024;
|
|
+}
|
|
+
|
|
static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) {
|
|
|
|
FILE* file = fopen(PROCSTATFILE, "r");
|
|
@@ -1038,6 +1103,7 @@ void ProcessList_goThroughEntries(ProcessList* super) {
|
|
LinuxProcessList* this = (LinuxProcessList*) super;
|
|
|
|
LinuxProcessList_scanMemoryInfo(super);
|
|
+ LinuxProcessList_scanZfsArcstats(this);
|
|
double period = LinuxProcessList_scanCPUTime(this);
|
|
|
|
struct timeval tv;
|
|
diff --git a/linux/LinuxProcessList.h b/linux/LinuxProcessList.h
|
|
index f30b487..749231e 100644
|
|
--- a/linux/LinuxProcessList.h
|
|
+++ b/linux/LinuxProcessList.h
|
|
@@ -67,6 +67,15 @@ typedef struct LinuxProcessList_ {
|
|
struct nl_sock *netlink_socket;
|
|
int netlink_family;
|
|
#endif
|
|
+
|
|
+ int zfsArcEnabled;
|
|
+ unsigned long long int memZfsArc;
|
|
+ unsigned long long int zfsArcMax;
|
|
+ unsigned long long int zfsArcMFU;
|
|
+ unsigned long long int zfsArcMRU;
|
|
+ unsigned long long int zfsArcAnon;
|
|
+ unsigned long long int zfsArcHeader;
|
|
+ unsigned long long int zfsArcOther;
|
|
} LinuxProcessList;
|
|
|
|
#ifndef PROCDIR
|
|
@@ -81,6 +90,10 @@ typedef struct LinuxProcessList_ {
|
|
#define PROCMEMINFOFILE PROCDIR "/meminfo"
|
|
#endif
|
|
|
|
+#ifndef PROCARCSTATSFILE
|
|
+#define PROCARCSTATSFILE PROCDIR "/spl/kstat/zfs/arcstats"
|
|
+#endif
|
|
+
|
|
#ifndef PROCTTYDRIVERSFILE
|
|
#define PROCTTYDRIVERSFILE PROCDIR "/tty/drivers"
|
|
#endif
|
|
diff --git a/linux/Platform.c b/linux/Platform.c
|
|
index ab90ca7..4e73c61 100644
|
|
--- a/linux/Platform.c
|
|
+++ b/linux/Platform.c
|
|
@@ -21,6 +21,7 @@ in the source distribution for its full text.
|
|
#include "UptimeMeter.h"
|
|
#include "ClockMeter.h"
|
|
#include "HostnameMeter.h"
|
|
+#include "zfs/ZfsArcMeter.h"
|
|
#include "LinuxProcess.h"
|
|
|
|
#include <math.h>
|
|
@@ -126,6 +127,7 @@ MeterClass* Platform_meterTypes[] = {
|
|
&LeftCPUs2Meter_class,
|
|
&RightCPUs2Meter_class,
|
|
&BlankMeter_class,
|
|
+ &ZfsArcMeter_class,
|
|
NULL
|
|
};
|
|
|
|
@@ -213,6 +215,23 @@ void Platform_setSwapValues(Meter* this) {
|
|
this->values[0] = pl->usedSwap;
|
|
}
|
|
|
|
+void Platform_setZfsArcValues(Meter* this) {
|
|
+ LinuxProcessList* lpl = (LinuxProcessList*) this->pl;
|
|
+
|
|
+ this->total = lpl->zfsArcMax;
|
|
+ this->values[0] = lpl->zfsArcMFU;
|
|
+ this->values[1] = lpl->zfsArcMRU;
|
|
+ this->values[2] = lpl->zfsArcAnon;
|
|
+ this->values[3] = lpl->zfsArcHeader;
|
|
+ this->values[4] = lpl->zfsArcOther;
|
|
+
|
|
+ // "Hide" the last value so it can
|
|
+ // only be accessed by index and is not
|
|
+ // displayed by the Bar or Graph style
|
|
+ Meter_setItems(this, 5);
|
|
+ this->values[5] = lpl->memZfsArc;
|
|
+}
|
|
+
|
|
char* Platform_getProcessEnv(pid_t pid) {
|
|
char procname[32+1];
|
|
xSnprintf(procname, 32, "/proc/%d/environ", pid);
|
|
diff --git a/linux/Platform.h b/linux/Platform.h
|
|
index b0456e5..e775181 100644
|
|
--- a/linux/Platform.h
|
|
+++ b/linux/Platform.h
|
|
@@ -43,6 +43,8 @@ void Platform_setMemoryValues(Meter* this);
|
|
|
|
void Platform_setSwapValues(Meter* this);
|
|
|
|
+void Platform_setZfsArcValues(Meter* this);
|
|
+
|
|
char* Platform_getProcessEnv(pid_t pid);
|
|
|
|
#endif
|
|
diff --git a/zfs/ZfsArcMeter.c b/zfs/ZfsArcMeter.c
|
|
index e12c46e..ebd8099 100644
|
|
--- a/zfs/ZfsArcMeter.c
|
|
+++ b/zfs/ZfsArcMeter.c
|
|
@@ -41,27 +41,32 @@ static void ZfsArcMeter_display(Object* cast, RichString* out) {
|
|
char buffer[50];
|
|
Meter* this = (Meter*)cast;
|
|
|
|
- RichString_write(out, CRT_colors[METER_TEXT], ":");
|
|
- Meter_humanUnit(buffer, this->total, 50);
|
|
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
|
- Meter_humanUnit(buffer, this->values[5], 50);
|
|
- RichString_append(out, CRT_colors[METER_TEXT], " Used:");
|
|
- RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
|
- Meter_humanUnit(buffer, this->values[0], 50);
|
|
- RichString_append(out, CRT_colors[METER_TEXT], " MFU:");
|
|
- RichString_append(out, CRT_colors[ZFS_MFU], buffer);
|
|
- Meter_humanUnit(buffer, this->values[1], 50);
|
|
- RichString_append(out, CRT_colors[METER_TEXT], " MRU:");
|
|
- RichString_append(out, CRT_colors[ZFS_MRU], buffer);
|
|
- Meter_humanUnit(buffer, this->values[2], 50);
|
|
- RichString_append(out, CRT_colors[METER_TEXT], " Anon:");
|
|
- RichString_append(out, CRT_colors[ZFS_ANON], buffer);
|
|
- Meter_humanUnit(buffer, this->values[3], 50);
|
|
- RichString_append(out, CRT_colors[METER_TEXT], " Hdr:");
|
|
- RichString_append(out, CRT_colors[ZFS_HEADER], buffer);
|
|
- Meter_humanUnit(buffer, this->values[4], 50);
|
|
- RichString_append(out, CRT_colors[METER_TEXT], " Oth:");
|
|
- RichString_append(out, CRT_colors[ZFS_OTHER], buffer);
|
|
+ if (this->values[5] > 0) {
|
|
+ RichString_write(out, CRT_colors[METER_TEXT], ":");
|
|
+ Meter_humanUnit(buffer, this->total, 50);
|
|
+ RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
|
+ Meter_humanUnit(buffer, this->values[5], 50);
|
|
+ RichString_append(out, CRT_colors[METER_TEXT], " Used:");
|
|
+ RichString_append(out, CRT_colors[METER_VALUE], buffer);
|
|
+ Meter_humanUnit(buffer, this->values[0], 50);
|
|
+ RichString_append(out, CRT_colors[METER_TEXT], " MFU:");
|
|
+ RichString_append(out, CRT_colors[ZFS_MFU], buffer);
|
|
+ Meter_humanUnit(buffer, this->values[1], 50);
|
|
+ RichString_append(out, CRT_colors[METER_TEXT], " MRU:");
|
|
+ RichString_append(out, CRT_colors[ZFS_MRU], buffer);
|
|
+ Meter_humanUnit(buffer, this->values[2], 50);
|
|
+ RichString_append(out, CRT_colors[METER_TEXT], " Anon:");
|
|
+ RichString_append(out, CRT_colors[ZFS_ANON], buffer);
|
|
+ Meter_humanUnit(buffer, this->values[3], 50);
|
|
+ RichString_append(out, CRT_colors[METER_TEXT], " Hdr:");
|
|
+ RichString_append(out, CRT_colors[ZFS_HEADER], buffer);
|
|
+ Meter_humanUnit(buffer, this->values[4], 50);
|
|
+ RichString_append(out, CRT_colors[METER_TEXT], " Oth:");
|
|
+ RichString_append(out, CRT_colors[ZFS_OTHER], buffer);
|
|
+ } else {
|
|
+ RichString_write(out, CRT_colors[METER_TEXT], " ");
|
|
+ RichString_append(out, CRT_colors[FAILED_SEARCH], "Unavailable");
|
|
+ }
|
|
}
|
|
|
|
MeterClass ZfsArcMeter_class = {
|
|
--
|
|
2.20.1
|
|
|