summaryrefslogtreecommitdiffstats
path: root/linux
diff options
context:
space:
mode:
authorRoss Williams <ross@ross-williams.net>2019-07-07 02:37:02 +0000
committerRoss Williams <ross@ross-williams.net>2019-07-07 22:57:15 -0400
commit070fe90461182743fabb029415fc1bc59be14f3f (patch)
treec1ce5424b6676e2b81ae568f748f3eb5dbea09ea /linux
parenta93edde1a21e533472b5d443002032260b5bd066 (diff)
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".
Diffstat (limited to 'linux')
-rw-r--r--linux/LinuxProcessList.c66
-rw-r--r--linux/LinuxProcessList.h13
-rw-r--r--linux/Platform.c19
-rw-r--r--linux/Platform.h2
4 files changed, 100 insertions, 0 deletions
diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c
index 5f38540c..4d19185c 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 f30b487d..749231e1 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 ab90ca74..4e73c61e 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 b0456e5b..e775181e 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

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