Skip to content

Commit

Permalink
ZFS arcstats for Linux
Browse files Browse the repository at this point in the history
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".
  • Loading branch information
overhacked committed Jul 8, 2019
1 parent a93edde commit 070fe90
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 23 deletions.
6 changes: 4 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
66 changes: 66 additions & 0 deletions linux/LinuxProcessList.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down
13 changes: 13 additions & 0 deletions linux/LinuxProcessList.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
19 changes: 19 additions & 0 deletions linux/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -126,6 +127,7 @@ MeterClass* Platform_meterTypes[] = {
&LeftCPUs2Meter_class,
&RightCPUs2Meter_class,
&BlankMeter_class,
&ZfsArcMeter_class,
NULL
};

Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions linux/Platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
47 changes: 26 additions & 21 deletions zfs/ZfsArcMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down

0 comments on commit 070fe90

Please sign in to comment.